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