blob: 5e0f8ec6cf24aa60250608c76de40cfc06d32dcd [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
79static s64 microvolt_to_ccadc_reading_v1(s64 uv)
80{
81 return div_s64(uv * CCADC_READING_RESOLUTION_D_V1,
82 CCADC_READING_RESOLUTION_N_V1);
83}
84
85static s64 microvolt_to_ccadc_reading_v2(s64 uv)
86{
87 return div_s64(uv * CCADC_READING_RESOLUTION_D_V2,
88 CCADC_READING_RESOLUTION_N_V2);
89}
90
91static s64 microvolt_to_ccadc_reading(struct pm8xxx_ccadc_chip *chip, s64 cc)
92{
93 /*
94 * resolution (the value of a single bit) was changed after revision 2.0
95 * for more accurate readings
96 */
97 return (the_chip->revision < PM8XXX_REVISION_8921_2p0) ?
98 microvolt_to_ccadc_reading_v1((s64)cc) :
99 microvolt_to_ccadc_reading_v2((s64)cc);
100}
101
102static int cc_adjust_for_offset(u16 raw)
103{
104 /* this has the intrinsic offset */
105 return (int)raw - the_chip->ccadc_offset;
106}
107
108#define GAIN_REFERENCE_UV 25000
109/*
110 * gain compensation for ccadc readings - common for vsense based and
111 * couloumb counter based readings
112 */
113s64 pm8xxx_cc_adjust_for_gain(s64 uv)
114{
115 if (the_chip == NULL || the_chip->ccadc_gain_uv == 0)
116 return uv;
117
118 return div_s64(uv * GAIN_REFERENCE_UV, the_chip->ccadc_gain_uv);
119}
120EXPORT_SYMBOL(pm8xxx_cc_adjust_for_gain);
121
122static int pm_ccadc_masked_write(struct pm8xxx_ccadc_chip *chip, u16 addr,
123 u8 mask, u8 val)
124{
125 int rc;
126 u8 reg;
127
128 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
129 if (rc) {
130 pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
131 return rc;
132 }
133 reg &= ~mask;
134 reg |= val & mask;
135 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
136 if (rc) {
137 pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
138 return rc;
139 }
140 return 0;
141}
142
143#define REG_SBI_CONFIG 0x04F
144#define PAGE3_ENABLE_MASK 0x6
145static int calib_ccadc_enable_trim_access(struct pm8xxx_ccadc_chip *chip,
146 u8 *sbi_config)
147{
148 u8 reg;
149 int rc;
150
151 rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
152 if (rc) {
153 pr_err("error = %d reading sbi config reg\n", rc);
154 return rc;
155 }
156
157 reg = *sbi_config | PAGE3_ENABLE_MASK;
158 return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
159}
160
161static int calib_ccadc_restore_trim_access(struct pm8xxx_ccadc_chip *chip,
162 u8 sbi_config)
163{
164 return pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
165}
166
167static int calib_ccadc_enable_arbiter(struct pm8xxx_ccadc_chip *chip)
168{
169 int rc;
170
171 /* enable Arbiter, must be sent twice */
172 rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
173 SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
174 if (rc < 0) {
175 pr_err("error = %d enabling arbiter for offset\n", rc);
176 return rc;
177 }
178 rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
179 SEL_CCADC_BIT | EN_ARB_BIT, SEL_CCADC_BIT | EN_ARB_BIT);
180 if (rc < 0) {
181 pr_err("error = %d writing ADC_ARB_SECP_CNTRL\n", rc);
182 return rc;
183 }
184 return 0;
185}
186
187static int calib_start_conv(struct pm8xxx_ccadc_chip *chip,
188 u16 *result)
189{
190 int rc, i;
191 u8 data_msb, data_lsb, reg;
192
193 /* Start conversion */
194 rc = pm_ccadc_masked_write(chip, ADC_ARB_SECP_CNTRL,
195 START_CONV_BIT, START_CONV_BIT);
196 if (rc < 0) {
197 pr_err("error = %d starting offset meas\n", rc);
198 return rc;
199 }
200
201 /* Wait for End of conversion */
202 for (i = 0; i < ADC_WAIT_COUNT; i++) {
203 rc = pm8xxx_readb(chip->dev->parent,
204 ADC_ARB_SECP_CNTRL, &reg);
205 if (rc < 0) {
206 pr_err("error = %d read eoc for offset\n", rc);
207 return rc;
208 }
209 if ((reg & (START_CONV_BIT | EOC_CONV_BIT)) != EOC_CONV_BIT)
210 msleep(60);
211 else
212 break;
213 }
214 if (i == ADC_WAIT_COUNT) {
215 pr_err("waited too long for offset eoc\n");
216 return rc;
217 }
218
219 rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA0, &data_lsb);
220 if (rc < 0) {
221 pr_err("error = %d reading offset lsb\n", rc);
222 return rc;
223 }
224
225 rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_SECP_DATA1, &data_msb);
226 if (rc < 0) {
227 pr_err("error = %d reading offset msb\n", rc);
228 return rc;
229 }
230
231 *result = (data_msb << 8) | data_lsb;
232 return 0;
233}
234
235static int calib_ccadc_read_trim(struct pm8xxx_ccadc_chip *chip,
236 int addr, u8 *data_msb, u8 *data_lsb)
237{
238 int rc;
239 u8 sbi_config;
240
241 calib_ccadc_enable_trim_access(chip, &sbi_config);
242 rc = pm8xxx_readb(chip->dev->parent, addr, data_msb);
243 if (rc < 0) {
244 pr_err("error = %d read msb\n", rc);
245 return rc;
246 }
247 rc = pm8xxx_readb(chip->dev->parent, addr + 1, data_lsb);
248 if (rc < 0) {
249 pr_err("error = %d read lsb\n", rc);
250 return rc;
251 }
252 calib_ccadc_restore_trim_access(chip, sbi_config);
253 return 0;
254}
255
256static void calib_ccadc_read_offset_and_gain(struct pm8xxx_ccadc_chip *chip,
257 int *gain, u16 *offset)
258{
259 s8 data_msb;
260 u8 data_lsb;
261 int rc;
262
263 rc = calib_ccadc_read_trim(chip, CCADC_FULLSCALE_TRIM1,
264 &data_msb, &data_lsb);
265 *gain = (data_msb << 8) | data_lsb;
266
267 rc = calib_ccadc_read_trim(chip, CCADC_OFFSET_TRIM1,
268 &data_msb, &data_lsb);
269 *offset = (data_msb << 8) | data_lsb;
270
271 pr_debug("raw gain trim = 0x%x offset trim =0x%x\n", *gain, *offset);
272 *gain = pm8xxx_ccadc_reading_to_microvolt(chip->revision,
273 (s64)*gain - *offset);
274 pr_debug("gain uv = %duV offset=0x%x\n", *gain, *offset);
275}
276
277#define CCADC_PROGRAM_TRIM_COUNT 2
278#define ADC_ARB_BMS_CNTRL_CCADC_SHIFT 4
279#define ADC_ARB_BMS_CNTRL_CONV_MASK 0x03
280#define BMS_CONV_IN_PROGRESS 0x2
281
282static int calib_ccadc_program_trim(struct pm8xxx_ccadc_chip *chip,
283 int addr, u8 data_msb, u8 data_lsb,
284 int wait)
285{
286 int i, rc, loop;
287 u8 cntrl, sbi_config;
288 bool in_progress = 0;
289
290 loop = wait ? CCADC_PROGRAM_TRIM_COUNT : 0;
291
292 calib_ccadc_enable_trim_access(chip, &sbi_config);
293
294 for (i = 0; i < loop; i++) {
295 rc = pm8xxx_readb(chip->dev->parent, ADC_ARB_BMS_CNTRL, &cntrl);
296 if (rc < 0) {
297 pr_err("error = %d reading ADC_ARB_BMS_CNTRL\n", rc);
298 return rc;
299 }
300
301 /* break if a ccadc conversion is not happening */
302 in_progress = (((cntrl >> ADC_ARB_BMS_CNTRL_CCADC_SHIFT)
303 & ADC_ARB_BMS_CNTRL_CONV_MASK) == BMS_CONV_IN_PROGRESS);
304
305 if (!in_progress)
306 break;
307 }
308
309 if (in_progress) {
310 pr_debug("conv in progress cannot write trim,returing EBUSY\n");
311 return -EBUSY;
312 }
313
314 rc = pm8xxx_writeb(chip->dev->parent, addr, data_msb);
315 if (rc < 0) {
316 pr_err("error = %d write msb = 0x%x\n", rc, data_msb);
317 return rc;
318 }
319 rc = pm8xxx_writeb(chip->dev->parent, addr + 1, data_lsb);
320 if (rc < 0) {
321 pr_err("error = %d write lsb = 0x%x\n", rc, data_lsb);
322 return rc;
323 }
324 calib_ccadc_restore_trim_access(chip, sbi_config);
325 return 0;
326}
327
328void pm8xxx_calib_ccadc(void)
329{
330 u8 data_msb, data_lsb, sec_cntrl;
331 int result_offset, voltage_offset, result_gain;
332 u16 result;
333 int i, rc;
334
335 rc = pm8xxx_readb(the_chip->dev->parent,
336 ADC_ARB_SECP_CNTRL, &sec_cntrl);
337 if (rc < 0) {
338 pr_err("error = %d reading ADC_ARB_SECP_CNTRL\n", rc);
339 return;
340 }
341
342 rc = calib_ccadc_enable_arbiter(the_chip);
343 if (rc < 0) {
344 pr_err("error = %d enabling arbiter for offset\n", rc);
345 goto bail;
346 }
347
348 /*
349 * Set decimation ratio to 4k, lower ratio may be used in order to speed
350 * up, pending verification through bench
351 */
352 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
353 CCADC_CALIB_DIG_PARAM);
354 if (rc < 0) {
355 pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
356 goto bail;
357 }
358
359 result_offset = 0;
360 for (i = 0; i < SAMPLE_COUNT; i++) {
361 /* Short analog inputs to CCADC internally to ground */
362 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
363 CCADC_CALIB_RSV_GND);
364 if (rc < 0) {
365 pr_err("error = %d selecting gnd voltage\n", rc);
366 goto bail;
367 }
368
369 /* Enable CCADC */
370 rc = pm8xxx_writeb(the_chip->dev->parent,
371 ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
372 if (rc < 0) {
373 pr_err("error = %d enabling ccadc\n", rc);
374 goto bail;
375 }
376
377 rc = calib_start_conv(the_chip, &result);
378 if (rc < 0) {
379 pr_err("error = %d for zero volt measurement\n", rc);
380 goto bail;
381 }
382
383 result_offset += result;
384 }
385
386 result_offset = result_offset / SAMPLE_COUNT;
387
388 voltage_offset = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
389 ((s64)result_offset - CCADC_INTRINSIC_OFFSET));
390
391 pr_debug("offset result_offset = 0x%x, voltage = %d microVolts\n",
392 result_offset, voltage_offset);
393
394 /* Sanity Check */
395 if (voltage_offset > CCADC_MAX_0UV) {
396 pr_err("offset voltage = %d is huge limiting to %d\n",
397 voltage_offset, CCADC_MAX_0UV);
398 result_offset = CCADC_INTRINSIC_OFFSET
399 + microvolt_to_ccadc_reading(the_chip,
400 (s64)CCADC_MAX_0UV);
401 } else if (voltage_offset < CCADC_MIN_0UV) {
402 pr_err("offset voltage = %d is too low limiting to %d\n",
403 voltage_offset, CCADC_MIN_0UV);
404 result_offset = CCADC_INTRINSIC_OFFSET
405 + microvolt_to_ccadc_reading(the_chip,
406 (s64)CCADC_MIN_0UV);
407 }
408
409 the_chip->ccadc_offset = result_offset;
410 data_msb = the_chip->ccadc_offset >> 8;
411 data_lsb = the_chip->ccadc_offset;
412
413 rc = calib_ccadc_program_trim(the_chip, CCADC_OFFSET_TRIM1,
414 data_msb, data_lsb, 1);
415 if (rc) {
416 pr_debug("error = %d programming offset trim 0x%02x 0x%02x\n",
417 rc, data_msb, data_lsb);
418 /* enable the interrupt and write it when it fires */
419 enable_irq(the_chip->eoc_irq);
420 }
421
422 rc = calib_ccadc_enable_arbiter(the_chip);
423 if (rc < 0) {
424 pr_err("error = %d enabling arbiter for gain\n", rc);
425 goto bail;
426 }
427
428 /*
429 * Set decimation ratio to 4k, lower ratio may be used in order to speed
430 * up, pending verification through bench
431 */
432 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
433 CCADC_CALIB_DIG_PARAM);
434 if (rc < 0) {
435 pr_err("error = %d enabling decimation ration for gain\n", rc);
436 goto bail;
437 }
438
439 result_gain = 0;
440 for (i = 0; i < SAMPLE_COUNT; i++) {
441 rc = pm8xxx_writeb(the_chip->dev->parent,
442 ADC_ARB_SECP_RSV, CCADC_CALIB_RSV_25MV);
443 if (rc < 0) {
444 pr_err("error = %d selecting 25mV for gain\n", rc);
445 goto bail;
446 }
447
448 /* Enable CCADC */
449 rc = pm8xxx_writeb(the_chip->dev->parent,
450 ADC_ARB_SECP_ANA_PARAM, CCADC_CALIB_ANA_PARAM);
451 if (rc < 0) {
452 pr_err("error = %d enabling ccadc\n", rc);
453 goto bail;
454 }
455
456 rc = calib_start_conv(the_chip, &result);
457 if (rc < 0) {
458 pr_err("error = %d for adc reading 25mV\n", rc);
459 goto bail;
460 }
461
462 result_gain += result;
463 }
464 result_gain = result_gain / SAMPLE_COUNT;
465
466 /*
467 * result_offset includes INTRINSIC OFFSET
468 * the_chip->ccadc_gain_uv will be the actual voltage
469 * measured for 25000UV
470 */
471 the_chip->ccadc_gain_uv = pm8xxx_ccadc_reading_to_microvolt(
472 the_chip->revision,
473 ((s64)result_gain - result_offset));
474
475 pr_debug("gain result_gain = 0x%x, voltage = %d microVolts\n",
476 result_gain, the_chip->ccadc_gain_uv);
477 /* Sanity Check */
478 if (the_chip->ccadc_gain_uv > CCADC_MAX_25MV) {
479 pr_err("gain voltage = %d is huge limiting to %d\n",
480 the_chip->ccadc_gain_uv,
481 CCADC_MAX_25MV);
482 the_chip->ccadc_gain_uv = CCADC_MAX_25MV;
483 result_gain = result_offset +
484 microvolt_to_ccadc_reading(the_chip, CCADC_MAX_25MV);
485 } else if (the_chip->ccadc_gain_uv < CCADC_MIN_25MV) {
486 pr_err("gain voltage = %d is too low limiting to %d\n",
487 the_chip->ccadc_gain_uv,
488 CCADC_MIN_25MV);
489 the_chip->ccadc_gain_uv = CCADC_MIN_25MV;
490 result_gain = result_offset +
491 microvolt_to_ccadc_reading(the_chip, CCADC_MIN_25MV);
492 }
493
494 data_msb = result_gain >> 8;
495 data_lsb = result_gain;
496 rc = calib_ccadc_program_trim(the_chip, CCADC_FULLSCALE_TRIM1,
497 data_msb, data_lsb, 0);
498 if (rc)
499 pr_debug("error = %d programming gain trim\n", rc);
500bail:
501 pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_CNTRL, sec_cntrl);
502}
503EXPORT_SYMBOL(pm8xxx_calib_ccadc);
504
505static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
506{
507 u8 data_msb, data_lsb;
508 struct pm8xxx_ccadc_chip *chip = data;
509 int rc;
510
511 pr_debug("irq = %d triggered\n", irq);
512 data_msb = chip->ccadc_offset >> 8;
513 data_lsb = chip->ccadc_offset;
514
515 rc = calib_ccadc_program_trim(chip, CCADC_OFFSET_TRIM1,
516 data_msb, data_lsb, 0);
517 disable_irq_nosync(chip->eoc_irq);
518
519 return IRQ_HANDLED;
520}
521
522#define CCADC_IBAT_DIG_PARAM 0xA3
523#define CCADC_IBAT_RSV 0x10
524#define CCADC_IBAT_ANA_PARAM 0x1A
525static int ccadc_get_rsense_voltage(int *voltage_uv)
526{
527 u16 raw;
528 int result;
529 int rc = 0;
530
531 rc = calib_ccadc_enable_arbiter(the_chip);
532 if (rc < 0) {
533 pr_err("error = %d enabling arbiter for offset\n", rc);
534 return rc;
535 }
536
537 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_DIG_PARAM,
538 CCADC_IBAT_DIG_PARAM);
539 if (rc < 0) {
540 pr_err("error = %d writing ADC_ARB_SECP_DIG_PARAM\n", rc);
541 return rc;
542 }
543
544 rc = pm8xxx_writeb(the_chip->dev->parent, ADC_ARB_SECP_RSV,
545 CCADC_IBAT_RSV);
546 if (rc < 0) {
547 pr_err("error = %d selecting rsense\n", rc);
548 return rc;
549 }
550
551 rc = pm8xxx_writeb(the_chip->dev->parent,
552 ADC_ARB_SECP_ANA_PARAM, CCADC_IBAT_ANA_PARAM);
553 if (rc < 0) {
554 pr_err("error = %d enabling ccadc\n", rc);
555 return rc;
556 }
557
558 rc = calib_start_conv(the_chip, &raw);
559 if (rc < 0) {
560 pr_err("error = %d for zero volt measurement\n", rc);
561 return rc;
562 }
563
564 pr_debug("Vsense raw = 0x%x\n", raw);
565 result = cc_adjust_for_offset(raw);
566 pr_debug("Vsense after offset raw = 0x%x offset=0x%x\n",
567 result,
568 the_chip->ccadc_offset);
569 *voltage_uv = pm8xxx_ccadc_reading_to_microvolt(the_chip->revision,
570 ((s64)result));
571 pr_debug("Vsense before gain = %d uV\n", *voltage_uv);
572 *voltage_uv = pm8xxx_cc_adjust_for_gain(*voltage_uv);
573
574 pr_debug("Vsense = %d uV\n", *voltage_uv);
575 return 0;
576}
577
578int pm8xxx_ccadc_get_battery_current(int *bat_current)
579{
580 int voltage_uv, rc;
581
582 rc = ccadc_get_rsense_voltage(&voltage_uv);
583 if (rc) {
584 pr_err("cant get voltage across rsense rc = %d\n", rc);
585 return rc;
586 }
587
588 *bat_current = voltage_uv/the_chip->r_sense;
589 /*
590 * ccadc reads +ve current when the battery is charging
591 * We need to return -ve if the battery is charging
592 */
593 *bat_current = -1 * (*bat_current);
594 pr_debug("bat current = %d ma\n", *bat_current);
595 return 0;
596}
597EXPORT_SYMBOL(pm8xxx_ccadc_get_battery_current);
598
599static int get_reg(void *data, u64 * val)
600{
601 int addr = (int)data;
602 int ret;
603 u8 temp;
604
605 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
606 if (ret) {
607 pr_err("pm8xxx_readb to %x value = %d errored = %d\n",
608 addr, temp, ret);
609 return -EAGAIN;
610 }
611 *val = temp;
612 return 0;
613}
614
615static int set_reg(void *data, u64 val)
616{
617 int addr = (int)data;
618 int ret;
619 u8 temp;
620
621 temp = (u8) val;
622 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
623 if (ret) {
624 pr_err("pm8xxx_writeb to %x value = %d errored = %d\n",
625 addr, temp, ret);
626 return -EAGAIN;
627 }
628 return 0;
629}
630DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
631
632static int get_calc(void *data, u64 * val)
633{
634 int ibat, rc;
635
636 rc = pm8xxx_ccadc_get_battery_current(&ibat);
637 *val = ibat;
638 return rc;
639}
640DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%lld\n");
641
642static void create_debugfs_entries(struct pm8xxx_ccadc_chip *chip)
643{
644 chip->dent = debugfs_create_dir("pm8xxx-ccadc", NULL);
645
646 if (IS_ERR(chip->dent)) {
647 pr_err("ccadc couldnt create debugfs dir\n");
648 return;
649 }
650
651 debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
652 (void *)CCADC_ANA_PARAM, &reg_fops);
653 debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
654 (void *)CCADC_DIG_PARAM, &reg_fops);
655 debugfs_create_file("CCADC_RSV", 0644, chip->dent,
656 (void *)CCADC_RSV, &reg_fops);
657 debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
658 (void *)CCADC_DATA0, &reg_fops);
659 debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
660 (void *)CCADC_DATA1, &reg_fops);
661 debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
662 (void *)CCADC_OFFSET_TRIM1, &reg_fops);
663 debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
664 (void *)CCADC_OFFSET_TRIM0, &reg_fops);
665 debugfs_create_file("CCADC_FULLSCALE_TRIM1", 0644, chip->dent,
666 (void *)CCADC_FULLSCALE_TRIM1, &reg_fops);
667 debugfs_create_file("CCADC_FULLSCALE_TRIM0", 0644, chip->dent,
668 (void *)CCADC_FULLSCALE_TRIM0, &reg_fops);
669
670 debugfs_create_file("show_ibatt", 0644, chip->dent,
671 (void *)0, &calc_fops);
672}
673
674static int __devinit pm8xxx_ccadc_probe(struct platform_device *pdev)
675{
676 int rc = 0;
677 struct pm8xxx_ccadc_chip *chip;
678 struct resource *res;
679 const struct pm8xxx_ccadc_platform_data *pdata
680 = pdev->dev.platform_data;
681
682 if (!pdata) {
683 pr_err("missing platform data\n");
684 return -EINVAL;
685 }
686 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
687 "PM8921_BMS_CCADC_EOC");
688 if (!res) {
689 pr_err("failed to get irq\n");
690 return -EINVAL;
691 }
692
693 chip = kzalloc(sizeof(struct pm8xxx_ccadc_chip), GFP_KERNEL);
694 if (!chip) {
695 pr_err("Cannot allocate pm_bms_chip\n");
696 return -ENOMEM;
697 }
698 chip->dev = &pdev->dev;
699 chip->revision = pm8xxx_get_revision(chip->dev->parent);
700 chip->eoc_irq = res->start;
701 chip->r_sense = pdata->r_sense;
702
Abhijeet Dharmapurikar97d40902011-11-30 12:12:51 -0800703 calib_ccadc_read_offset_and_gain(chip,
704 &chip->ccadc_gain_uv,
705 &chip->ccadc_offset);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800706 rc = request_irq(chip->eoc_irq,
707 pm8921_bms_ccadc_eoc_handler, IRQF_TRIGGER_RISING,
708 "bms_eoc_ccadc", chip);
709 if (rc) {
710 pr_err("failed to request %d irq rc= %d\n", chip->eoc_irq, rc);
711 goto free_chip;
712 }
Abhijeet Dharmapurikar97d40902011-11-30 12:12:51 -0800713 disable_irq_nosync(chip->eoc_irq);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800714
715 platform_set_drvdata(pdev, chip);
716 the_chip = chip;
717
718 create_debugfs_entries(chip);
719
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800720 return 0;
721
722free_chip:
723 kfree(chip);
724 return rc;
725}
726
727static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev)
728{
729 struct pm8xxx_ccadc_chip *chip = platform_get_drvdata(pdev);
730
731 debugfs_remove_recursive(chip->dent);
732 the_chip = NULL;
733 kfree(chip);
734 return 0;
735}
736
737static struct platform_driver pm8xxx_ccadc_driver = {
738 .probe = pm8xxx_ccadc_probe,
739 .remove = __devexit_p(pm8xxx_ccadc_remove),
740 .driver = {
741 .name = PM8XXX_CCADC_DEV_NAME,
742 .owner = THIS_MODULE,
743 },
744};
745
746static int __init pm8xxx_ccadc_init(void)
747{
748 return platform_driver_register(&pm8xxx_ccadc_driver);
749}
750
751static void __exit pm8xxx_ccadc_exit(void)
752{
753 platform_driver_unregister(&pm8xxx_ccadc_driver);
754}
755
756module_init(pm8xxx_ccadc_init);
757module_exit(pm8xxx_ccadc_exit);
758
759MODULE_LICENSE("GPL v2");
760MODULE_DESCRIPTION("PMIC8XXX ccadc driver");
761MODULE_VERSION("1.0");
762MODULE_ALIAS("platform:" PM8XXX_CCADC_DEV_NAME);