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