blob: aeaedad9b3c4827ed73f1f8fc306ee94cd27cd05 [file] [log] [blame]
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -08001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/platform_device.h>
18#include <linux/errno.h>
19#include <linux/mfd/pm8xxx/core.h>
20#include <linux/mfd/pm8xxx/ccadc.h>
21#include <linux/interrupt.h>
22#include <linux/ioport.h>
23#include <linux/debugfs.h>
24#include <linux/slab.h>
25#include <linux/delay.h>
26
27#define CCADC_ANA_PARAM 0x240
28#define CCADC_DIG_PARAM 0x241
29#define CCADC_RSV 0x242
30#define CCADC_DATA0 0x244
31#define CCADC_DATA1 0x245
32#define CCADC_OFFSET_TRIM1 0x34A
33#define CCADC_OFFSET_TRIM0 0x34B
34#define CCADC_FULLSCALE_TRIM1 0x34C
35#define CCADC_FULLSCALE_TRIM0 0x34D
36
37/* note : TRIM1 is the msb and TRIM0 is the lsb */
38#define ADC_ARB_SECP_CNTRL 0x190
39#define ADC_ARB_SECP_AMUX_CNTRL 0x191
40#define ADC_ARB_SECP_ANA_PARAM 0x192
41#define ADC_ARB_SECP_DIG_PARAM 0x193
42#define ADC_ARB_SECP_RSV 0x194
43#define ADC_ARB_SECP_DATA1 0x195
44#define ADC_ARB_SECP_DATA0 0x196
45
46#define ADC_ARB_BMS_CNTRL 0x18D
47
48#define START_CONV_BIT BIT(7)
49#define EOC_CONV_BIT BIT(6)
50#define SEL_CCADC_BIT BIT(1)
51#define EN_ARB_BIT BIT(0)
52
53#define CCADC_CALIB_DIG_PARAM 0xE3
54#define CCADC_CALIB_RSV_GND 0x40
55#define CCADC_CALIB_RSV_25MV 0x80
56#define CCADC_CALIB_ANA_PARAM 0x1B
57#define SAMPLE_COUNT 16
58#define ADC_WAIT_COUNT 10
59
60#define CCADC_MAX_25MV 30000
61#define CCADC_MIN_25MV 20000
62#define CCADC_MAX_0UV -4000
63#define CCADC_MIN_0UV -7000
64
65#define CCADC_INTRINSIC_OFFSET 0xC000
66
67struct pm8xxx_ccadc_chip {
68 struct device *dev;
69 struct dentry *dent;
70 u16 ccadc_offset;
71 int ccadc_gain_uv;
72 unsigned int revision;
73 int eoc_irq;
74 int r_sense;
75};
76
77static struct pm8xxx_ccadc_chip *the_chip;
78
Abhijeet Dharmapurikared8e5fb2011-12-07 14:31:26 -080079#ifdef DEBUG
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -080080static s64 microvolt_to_ccadc_reading_v1(s64 uv)
81{
82 return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
83 CCADC_READING_RESOLUTION_N_V1);
84}
85
86static s64 microvolt_to_ccadc_reading_v2(s64 uv)
87{
88 return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
89 CCADC_READING_RESOLUTION_N_V2);
90}
91
92static s64 microvolt_to_ccadc_reading(struct pm8xxx_ccadc_chip *chip, s64 cc)
93{
94 /*
95 * resolution (the value of a single bit) was changed after revision 2.0
96 * for more accurate readings
97 */
98 return (the_chip->revision < PM8XXX_REVISION_8921_2p0) ?
99 microvolt_to_ccadc_reading_v1((s64)cc) :
100 microvolt_to_ccadc_reading_v2((s64)cc);
101}
Abhijeet Dharmapurikared8e5fb2011-12-07 14:31:26 -0800102#endif
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800103
104static int cc_adjust_for_offset(u16 raw)
105{
106 /* this has the intrinsic offset */
107 return (int)raw - the_chip->ccadc_offset;
108}
109
110#define GAIN_REFERENCE_UV 25000
111/*
112 * gain compensation for ccadc readings - common for vsense based and
113 * couloumb counter based readings
114 */
115s64 pm8xxx_cc_adjust_for_gain(s64 uv)
116{
117 if (the_chip == NULL || the_chip->ccadc_gain_uv == 0)
118 return uv;
119
120 return div_s64(uv * GAIN_REFERENCE_UV, the_chip->ccadc_gain_uv);
121}
122EXPORT_SYMBOL(pm8xxx_cc_adjust_for_gain);
123
124static int pm_ccadc_masked_write(struct pm8xxx_ccadc_chip *chip, u16 addr,
125 u8 mask, u8 val)
126{
127 int rc;
128 u8 reg;
129
130 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
131 if (rc) {
132 pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
133 return rc;
134 }
135 reg &= ~mask;
136 reg |= val & mask;
137 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
138 if (rc) {
139 pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
140 return rc;
141 }
142 return 0;
143}
144
145#define REG_SBI_CONFIG 0x04F
146#define PAGE3_ENABLE_MASK 0x6
147static int calib_ccadc_enable_trim_access(struct pm8xxx_ccadc_chip *chip,
148 u8 *sbi_config)
149{
150 u8 reg;
151 int rc;
152
153 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
154 if (rc) {
155 pr_err("error = %d reading sbi config reg\n", rc);
156 return rc;
157 }
158
159 reg = *sbi_config | PAGE3_ENABLE_MASK;
160 return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
161}
162
163static int calib_ccadc_restore_trim_access(struct pm8xxx_ccadc_chip *chip,
164 u8 sbi_config)
165{
166 return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
167}
168
169static int calib_ccadc_enable_arbiter(struct pm8xxx_ccadc_chip *chip)
170{
171 int rc;
172
173 /* enable Arbiter, must be sent twice */
174 rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
175 SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
176 if (rc < 0) {
177 pr_err("error = %d enabling arbiter for offset\n", rc);
178 return rc;
179 }
180 rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
181 SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
182 if (rc < 0) {
183 pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
184 return rc;
185 }
186 return 0;
187}
188
189static int calib_start_conv(struct pm8xxx_ccadc_chip *chip,
190 u16 *result)
191{
192 int rc, i;
193 u8 data_msb, data_lsb, reg;
194
195 /* Start conversion */
196 rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
197 START_CONV_BIT, START_CONV_BIT);
198 if (rc < 0) {
199 pr_err("error = %d starting offset meas\n", rc);
200 return rc;
201 }
202
203 /* Wait for End of conversion */
204 for (i = 0; i < ADC_WAIT_COUNT; i++) {
205 rc = pm8xxx_readb(chip->dev->parent,
206 ADC_ARB_SECP_CNTRL, &reg);
207 if (rc < 0) {
208 pr_err("error = %d read eoc for offset\n", rc);
209 return rc;
210 }
211 if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
212 msleep(60);
213 else
214 break;
215 }
216 if (i == ADC_WAIT_COUNT) {
217 pr_err("waited too long for offset eoc\n");
218 return rc;
219 }
220
221 rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
222 if (rc < 0) {
223 pr_err("error = %d reading offset lsb\n", rc);
224 return rc;
225 }
226
227 rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
228 if (rc < 0) {
229 pr_err("error = %d reading offset msb\n", rc);
230 return rc;
231 }
232
233 *result = (data_msb << 8) | data_lsb;
234 return 0;
235}
236
237static int calib_ccadc_read_trim(struct pm8xxx_ccadc_chip *chip,
238 int addr, u8 *data_msb, u8 *data_lsb)
239{
240 int rc;
241 u8 sbi_config;
242
243 calib_ccadc_enable_trim_access(chip, &sbi_config);
244 rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
245 if (rc < 0) {
246 pr_err("error = %d read msb\n", rc);
247 return rc;
248 }
249 rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
250 if (rc < 0) {
251 pr_err("error = %d read lsb\n", rc);
252 return rc;
253 }
254 calib_ccadc_restore_trim_access(chip, sbi_config);
255 return 0;
256}
257
258static void calib_ccadc_read_offset_and_gain(struct pm8xxx_ccadc_chip *chip,
259 int *gain, u16 *offset)
260{
261 s8 data_msb;
262 u8 data_lsb;
263 int rc;
264
265 rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
266 &data_msb, &data_lsb);
267 *gain = (data_msb << 8) | data_lsb;
268
269 rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
270 &data_msb, &data_lsb);
271 *offset = (data_msb << 8) | data_lsb;
272
273 pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", *gain, *offset);
274 *gain = pm8xxx_ccadc_reading_to_microvolt(chip->revision,
275 (s64)*gain - *offset);
276 pr_debug("gain uv = %duV offset=0x%x\n", *gain, *offset);
277}
278
279#define CCADC_PROGRAM_TRIM_COUNT 2
280#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT 4
281#define ADC_ARB_BMS_CNTRL_CONV_MASK 0x03
282#define BMS_CONV_IN_PROGRESS 0x2
283
284static int calib_ccadc_program_trim(struct pm8xxx_ccadc_chip *chip,
285 int addr, u8 data_msb, u8 data_lsb,
286 int wait)
287{
288 int i, rc, loop;
289 u8 cntrl, sbi_config;
290 bool in_progress = 0;
291
292 loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
293
294 calib_ccadc_enable_trim_access(chip, &sbi_config);
295
296 for (i = 0; i < loop; i++) {
297 rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
298 if (rc < 0) {
299 pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
300 return rc;
301 }
302
303 /* break if a ccadc conversion is not happening */
304 in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
305 & ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
306
307 if (!in_progress)
308 break;
309 }
310
311 if (in_progress) {
312 pr_debug("conv in progress cannot write trim,returing EBUSY\n");
313 return -EBUSY;
314 }
315
316 rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
317 if (rc < 0) {
318 pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
319 return rc;
320 }
321 rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
322 if (rc < 0) {
323 pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
324 return rc;
325 }
326 calib_ccadc_restore_trim_access(chip, sbi_config);
327 return 0;
328}
329
330void pm8xxx_calib_ccadc(void)
331{
332 u8 data_msb, data_lsb, sec_cntrl;
Abhijeet Dharmapurikared8e5fb2011-12-07 14:31:26 -0800333 int result_offset, result_gain;
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800334 u16 result;
335 int i, rc;
336
337 rc = pm8xxx_readb(the_chip->dev->parent,
338 ADC_ARB_SECP_CNTRL, &sec_cntrl);
339 if (rc < 0) {
340 pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
341 return;
342 }
343
344 rc = calib_ccadc_enable_arbiter(the_chip);
345 if (rc < 0) {
346 pr_err("error = %d enabling arbiter for offset\n", rc);
347 goto bail;
348 }
349
350 /*
351 * Set decimation ratio to 4k, lower ratio may be used in order to speed
352 * up, pending verification through bench
353 */
354 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
355 CCADC_CALIB_DIG_PARAM);
356 if (rc < 0) {
357 pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
358 goto bail;
359 }
360
361 result_offset = 0;
362 for (i = 0; i < SAMPLE_COUNT; i++) {
363 /* Short analog inputs to CCADC internally to ground */
364 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
365 CCADC_CALIB_RSV_GND);
366 if (rc < 0) {
367 pr_err("error = %d selecting gnd voltage\n", rc);
368 goto bail;
369 }
370
371 /* Enable CCADC */
372 rc = pm8xxx_writeb(the_chip->dev->parent,
373 ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
374 if (rc < 0) {
375 pr_err("error = %d enabling ccadc\n", rc);
376 goto bail;
377 }
378
379 rc = calib_start_conv(the_chip, &result);
380 if (rc < 0) {
381 pr_err("error = %d for zero volt measurement\n", rc);
382 goto bail;
383 }
384
385 result_offset += result;
386 }
387
388 result_offset = result_offset / SAMPLE_COUNT;
389
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800390
Abhijeet Dharmapurikared8e5fb2011-12-07 14:31:26 -0800391 pr_debug("offset result_offset = 0x%x, voltage = %llduV\n",
392 result_offset,
393 pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
394 ((s64)result_offset - CCADC_INTRINSIC_OFFSET)));
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800395
396 the_chip->ccadc_offset = result_offset;
397 data_msb = the_chip->ccadc_offset >> 8;
398 data_lsb = the_chip->ccadc_offset;
399
400 rc = calib_ccadc_program_trim(the_chip, CCADC_OFFSET_TRIM1,
401 data_msb, data_lsb, 1);
402 if (rc) {
403 pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
404 rc, data_msb, data_lsb);
405 /* enable the interrupt and write it when it fires */
406 enable_irq(the_chip->eoc_irq);
407 }
408
409 rc = calib_ccadc_enable_arbiter(the_chip);
410 if (rc < 0) {
411 pr_err("error = %d enabling arbiter for gain\n", rc);
412 goto bail;
413 }
414
415 /*
416 * Set decimation ratio to 4k, lower ratio may be used in order to speed
417 * up, pending verification through bench
418 */
419 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
420 CCADC_CALIB_DIG_PARAM);
421 if (rc < 0) {
422 pr_err("error = %d enabling decimation ration for gain\n", rc);
423 goto bail;
424 }
425
426 result_gain = 0;
427 for (i = 0; i < SAMPLE_COUNT; i++) {
428 rc = pm8xxx_writeb(the_chip->dev->parent,
429 ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
430 if (rc < 0) {
431 pr_err("error = %d selecting 25mV for gain\n", rc);
432 goto bail;
433 }
434
435 /* Enable CCADC */
436 rc = pm8xxx_writeb(the_chip->dev->parent,
437 ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
438 if (rc < 0) {
439 pr_err("error = %d enabling ccadc\n", rc);
440 goto bail;
441 }
442
443 rc = calib_start_conv(the_chip, &result);
444 if (rc < 0) {
445 pr_err("error = %d for adc reading 25mV\n", rc);
446 goto bail;
447 }
448
449 result_gain += result;
450 }
451 result_gain = result_gain / SAMPLE_COUNT;
452
453 /*
454 * result_offset includes INTRINSIC OFFSET
455 * the_chip->ccadc_gain_uv will be the actual voltage
456 * measured for 25000UV
457 */
458 the_chip->ccadc_gain_uv = pm8xxx_ccadc_reading_to_microvolt(
459 the_chip->revision,
460 ((s64)result_gain - result_offset));
461
462 pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
463 result_gain, the_chip->ccadc_gain_uv);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800464
465 data_msb = result_gain >> 8;
466 data_lsb = result_gain;
467 rc = calib_ccadc_program_trim(the_chip, CCADC_FULLSCALE_TRIM1,
468 data_msb, data_lsb, 0);
469 if (rc)
470 pr_debug("error = %d programming gain trim\n", rc);
471bail:
472 pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
473}
474EXPORT_SYMBOL(pm8xxx_calib_ccadc);
475
476static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
477{
478 u8 data_msb, data_lsb;
479 struct pm8xxx_ccadc_chip *chip = data;
480 int rc;
481
482 pr_debug("irq = %d triggered\n", irq);
483 data_msb = chip->ccadc_offset >> 8;
484 data_lsb = chip->ccadc_offset;
485
486 rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
487 data_msb, data_lsb, 0);
488 disable_irq_nosync(chip->eoc_irq);
489
490 return IRQ_HANDLED;
491}
492
493#define CCADC_IBAT_DIG_PARAM 0xA3
494#define CCADC_IBAT_RSV 0x10
495#define CCADC_IBAT_ANA_PARAM 0x1A
496static int ccadc_get_rsense_voltage(int *voltage_uv)
497{
498 u16 raw;
499 int result;
500 int rc = 0;
501
502 rc = calib_ccadc_enable_arbiter(the_chip);
503 if (rc < 0) {
504 pr_err("error = %d enabling arbiter for offset\n", rc);
505 return rc;
506 }
507
508 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
509 CCADC_IBAT_DIG_PARAM);
510 if (rc < 0) {
511 pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
512 return rc;
513 }
514
515 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
516 CCADC_IBAT_RSV);
517 if (rc < 0) {
518 pr_err("error = %d selecting rsense\n", rc);
519 return rc;
520 }
521
522 rc = pm8xxx_writeb(the_chip->dev->parent,
523 ADC_ARB_SECP_ANA_PARAM, CCADC_IBAT_ANA_PARAM);
524 if (rc < 0) {
525 pr_err("error = %d enabling ccadc\n", rc);
526 return rc;
527 }
528
529 rc = calib_start_conv(the_chip, &raw);
530 if (rc < 0) {
531 pr_err("error = %d for zero volt measurement\n", rc);
532 return rc;
533 }
534
535 pr_debug("Vsense raw = 0x%x\n", raw);
536 result = cc_adjust_for_offset(raw);
537 pr_debug("Vsense after offset raw = 0x%x offset=0x%x\n",
538 result,
539 the_chip->ccadc_offset);
540 *voltage_uv = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
541 ((s64)result));
542 pr_debug("Vsense before gain = %d uV\n", *voltage_uv);
543 *voltage_uv = pm8xxx_cc_adjust_for_gain(*voltage_uv);
544
545 pr_debug("Vsense = %d uV\n", *voltage_uv);
546 return 0;
547}
548
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800549int pm8xxx_ccadc_get_battery_current(int *bat_current_ua)
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800550{
551 int voltage_uv, rc;
552
553 rc = ccadc_get_rsense_voltage(&voltage_uv);
554 if (rc) {
555 pr_err("cant get voltage across rsense rc = %d\n", rc);
556 return rc;
557 }
558
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800559 *bat_current_ua = voltage_uv * 1000/the_chip->r_sense;
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800560 /*
561 * ccadc reads +ve current when the battery is charging
562 * We need to return -ve if the battery is charging
563 */
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800564 *bat_current_ua = -1 * (*bat_current_ua);
565 pr_debug("bat current = %d ma\n", *bat_current_ua);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800566 return 0;
567}
568EXPORT_SYMBOL(pm8xxx_ccadc_get_battery_current);
569
570static int get_reg(void *data, u64 * val)
571{
572 int addr = (int)data;
573 int ret;
574 u8 temp;
575
576 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
577 if (ret) {
578 pr_err("pm8xxx_readb to %x value = %d errored = %d\n",
579 addr, temp, ret);
580 return -EAGAIN;
581 }
582 *val = temp;
583 return 0;
584}
585
586static int set_reg(void *data, u64 val)
587{
588 int addr = (int)data;
589 int ret;
590 u8 temp;
591
592 temp = (u8) val;
593 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
594 if (ret) {
595 pr_err("pm8xxx_writeb to %x value = %d errored = %d\n",
596 addr, temp, ret);
597 return -EAGAIN;
598 }
599 return 0;
600}
601DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
602
603static int get_calc(void *data, u64 * val)
604{
605 int ibat, rc;
606
607 rc = pm8xxx_ccadc_get_battery_current(&ibat);
608 *val = ibat;
609 return rc;
610}
611DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%lld\n");
612
613static void create_debugfs_entries(struct pm8xxx_ccadc_chip *chip)
614{
615 chip->dent = debugfs_create_dir("pm8xxx-ccadc", NULL);
616
617 if (IS_ERR(chip->dent)) {
618 pr_err("ccadc couldnt create debugfs dir\n");
619 return;
620 }
621
622 debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
623 (void *)CCADC_ANA_PARAM, &reg_fops);
624 debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
625 (void *)CCADC_DIG_PARAM, &reg_fops);
626 debugfs_create_file("CCADC_RSV", 0644, chip->dent,
627 (void *)CCADC_RSV, &reg_fops);
628 debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
629 (void *)CCADC_DATA0, &reg_fops);
630 debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
631 (void *)CCADC_DATA1, &reg_fops);
632 debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
633 (void *)CCADC_OFFSET_TRIM1, &reg_fops);
634 debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
635 (void *)CCADC_OFFSET_TRIM0, &reg_fops);
636 debugfs_create_file("CCADC_FULLSCALE_TRIM1", 0644, chip->dent,
637 (void *)CCADC_FULLSCALE_TRIM1, &reg_fops);
638 debugfs_create_file("CCADC_FULLSCALE_TRIM0", 0644, chip->dent,
639 (void *)CCADC_FULLSCALE_TRIM0, &reg_fops);
640
641 debugfs_create_file("show_ibatt", 0644, chip->dent,
642 (void *)0, &calc_fops);
643}
644
645static int __devinit pm8xxx_ccadc_probe(struct platform_device *pdev)
646{
647 int rc = 0;
648 struct pm8xxx_ccadc_chip *chip;
649 struct resource *res;
650 const struct pm8xxx_ccadc_platform_data *pdata
651 = pdev->dev.platform_data;
652
653 if (!pdata) {
654 pr_err("missing platform data\n");
655 return -EINVAL;
656 }
657 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
658 "PM8921_BMS_CCADC_EOC");
659 if (!res) {
660 pr_err("failed to get irq\n");
661 return -EINVAL;
662 }
663
664 chip = kzalloc(sizeof(struct pm8xxx_ccadc_chip), GFP_KERNEL);
665 if (!chip) {
666 pr_err("Cannot allocate pm_bms_chip\n");
667 return -ENOMEM;
668 }
669 chip->dev = &pdev->dev;
670 chip->revision = pm8xxx_get_revision(chip->dev->parent);
671 chip->eoc_irq = res->start;
672 chip->r_sense = pdata->r_sense;
673
Abhijeet Dharmapurikar97d40902011-11-30 12:12:51 -0800674 calib_ccadc_read_offset_and_gain(chip,
675 &chip->ccadc_gain_uv,
676 &chip->ccadc_offset);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800677 rc = request_irq(chip->eoc_irq,
678 pm8921_bms_ccadc_eoc_handler, IRQF_TRIGGER_RISING,
679 "bms_eoc_ccadc", chip);
680 if (rc) {
681 pr_err("failed to request %d irq rc= %d\n", chip->eoc_irq, rc);
682 goto free_chip;
683 }
Abhijeet Dharmapurikar97d40902011-11-30 12:12:51 -0800684 disable_irq_nosync(chip->eoc_irq);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800685
686 platform_set_drvdata(pdev, chip);
687 the_chip = chip;
688
689 create_debugfs_entries(chip);
690
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800691 return 0;
692
693free_chip:
694 kfree(chip);
695 return rc;
696}
697
698static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev)
699{
700 struct pm8xxx_ccadc_chip *chip = platform_get_drvdata(pdev);
701
702 debugfs_remove_recursive(chip->dent);
703 the_chip = NULL;
704 kfree(chip);
705 return 0;
706}
707
708static struct platform_driver pm8xxx_ccadc_driver = {
709 .probe = pm8xxx_ccadc_probe,
710 .remove = __devexit_p(pm8xxx_ccadc_remove),
711 .driver = {
712 .name = PM8XXX_CCADC_DEV_NAME,
713 .owner = THIS_MODULE,
714 },
715};
716
717static int __init pm8xxx_ccadc_init(void)
718{
719 return platform_driver_register(&pm8xxx_ccadc_driver);
720}
721
722static void __exit pm8xxx_ccadc_exit(void)
723{
724 platform_driver_unregister(&pm8xxx_ccadc_driver);
725}
726
727module_init(pm8xxx_ccadc_init);
728module_exit(pm8xxx_ccadc_exit);
729
730MODULE_LICENSE("GPL v2");
731MODULE_DESCRIPTION("PMIC8XXX ccadc driver");
732MODULE_VERSION("1.0");
733MODULE_ALIAS("platform:" PM8XXX_CCADC_DEV_NAME);