blob: 65bc654b4209ff4d58cc9784f9eaf9d1d235f72c [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;
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)
Abhijeet Dharmapurikarccfc4f32012-01-16 17:35:18 -0800212 msleep(20);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800213 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{
Abhijeet Dharmapurikar034a0342011-12-08 11:12:54 -0800261 u8 data_msb;
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800262 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));
Abhijeet Dharmapurikar034a0342011-12-08 11:12:54 -0800542 pr_debug("Vsense before gain of %d = %d uV\n", the_chip->ccadc_gain_uv,
543 *voltage_uv);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800544 *voltage_uv = pm8xxx_cc_adjust_for_gain(*voltage_uv);
545
546 pr_debug("Vsense = %d uV\n", *voltage_uv);
547 return 0;
548}
549
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800550int pm8xxx_ccadc_get_battery_current(int *bat_current_ua)
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800551{
Trilok Sonic6e541e2012-03-19 17:14:28 +0530552 int voltage_uv = 0, rc;
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800553
554 rc = ccadc_get_rsense_voltage(&voltage_uv);
555 if (rc) {
556 pr_err("cant get voltage across rsense rc = %d\n", rc);
557 return rc;
558 }
559
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800560 *bat_current_ua = voltage_uv * 1000/the_chip->r_sense;
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800561 /*
562 * ccadc reads +ve current when the battery is charging
563 * We need to return -ve if the battery is charging
564 */
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800565 *bat_current_ua = -1 * (*bat_current_ua);
566 pr_debug("bat current = %d ma\n", *bat_current_ua);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800567 return 0;
568}
569EXPORT_SYMBOL(pm8xxx_ccadc_get_battery_current);
570
571static int get_reg(void *data, u64 * val)
572{
573 int addr = (int)data;
574 int ret;
575 u8 temp;
576
577 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
578 if (ret) {
579 pr_err("pm8xxx_readb to %x value = %d errored = %d\n",
580 addr, temp, ret);
581 return -EAGAIN;
582 }
583 *val = temp;
584 return 0;
585}
586
587static int set_reg(void *data, u64 val)
588{
589 int addr = (int)data;
590 int ret;
591 u8 temp;
592
593 temp = (u8) val;
594 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
595 if (ret) {
596 pr_err("pm8xxx_writeb to %x value = %d errored = %d\n",
597 addr, temp, ret);
598 return -EAGAIN;
599 }
600 return 0;
601}
602DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
603
604static int get_calc(void *data, u64 * val)
605{
606 int ibat, rc;
607
608 rc = pm8xxx_ccadc_get_battery_current(&ibat);
609 *val = ibat;
610 return rc;
611}
612DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%lld\n");
613
614static void create_debugfs_entries(struct pm8xxx_ccadc_chip *chip)
615{
616 chip->dent = debugfs_create_dir("pm8xxx-ccadc", NULL);
617
618 if (IS_ERR(chip->dent)) {
619 pr_err("ccadc couldnt create debugfs dir\n");
620 return;
621 }
622
623 debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
624 (void *)CCADC_ANA_PARAM, &reg_fops);
625 debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
626 (void *)CCADC_DIG_PARAM, &reg_fops);
627 debugfs_create_file("CCADC_RSV", 0644, chip->dent,
628 (void *)CCADC_RSV, &reg_fops);
629 debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
630 (void *)CCADC_DATA0, &reg_fops);
631 debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
632 (void *)CCADC_DATA1, &reg_fops);
633 debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
634 (void *)CCADC_OFFSET_TRIM1, &reg_fops);
635 debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
636 (void *)CCADC_OFFSET_TRIM0, &reg_fops);
637 debugfs_create_file("CCADC_FULLSCALE_TRIM1", 0644, chip->dent,
638 (void *)CCADC_FULLSCALE_TRIM1, &reg_fops);
639 debugfs_create_file("CCADC_FULLSCALE_TRIM0", 0644, chip->dent,
640 (void *)CCADC_FULLSCALE_TRIM0, &reg_fops);
641
642 debugfs_create_file("show_ibatt", 0644, chip->dent,
643 (void *)0, &calc_fops);
644}
645
646static int __devinit pm8xxx_ccadc_probe(struct platform_device *pdev)
647{
648 int rc = 0;
649 struct pm8xxx_ccadc_chip *chip;
650 struct resource *res;
651 const struct pm8xxx_ccadc_platform_data *pdata
652 = pdev->dev.platform_data;
653
654 if (!pdata) {
655 pr_err("missing platform data\n");
656 return -EINVAL;
657 }
658 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
659 "PM8921_BMS_CCADC_EOC");
660 if (!res) {
661 pr_err("failed to get irq\n");
662 return -EINVAL;
663 }
664
665 chip = kzalloc(sizeof(struct pm8xxx_ccadc_chip), GFP_KERNEL);
666 if (!chip) {
667 pr_err("Cannot allocate pm_bms_chip\n");
668 return -ENOMEM;
669 }
670 chip->dev = &pdev->dev;
671 chip->revision = pm8xxx_get_revision(chip->dev->parent);
672 chip->eoc_irq = res->start;
673 chip->r_sense = pdata->r_sense;
674
Abhijeet Dharmapurikar97d40902011-11-30 12:12:51 -0800675 calib_ccadc_read_offset_and_gain(chip,
676 &chip->ccadc_gain_uv,
677 &chip->ccadc_offset);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800678 rc = request_irq(chip->eoc_irq,
679 pm8921_bms_ccadc_eoc_handler, IRQF_TRIGGER_RISING,
680 "bms_eoc_ccadc", chip);
681 if (rc) {
682 pr_err("failed to request %d irq rc= %d\n", chip->eoc_irq, rc);
683 goto free_chip;
684 }
Abhijeet Dharmapurikar97d40902011-11-30 12:12:51 -0800685 disable_irq_nosync(chip->eoc_irq);
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800686
687 platform_set_drvdata(pdev, chip);
688 the_chip = chip;
689
690 create_debugfs_entries(chip);
691
Abhijeet Dharmapurikar82d93982011-11-09 15:52:25 -0800692 return 0;
693
694free_chip:
695 kfree(chip);
696 return rc;
697}
698
699static int __devexit pm8xxx_ccadc_remove(struct platform_device *pdev)
700{
701 struct pm8xxx_ccadc_chip *chip = platform_get_drvdata(pdev);
702
703 debugfs_remove_recursive(chip->dent);
704 the_chip = NULL;
705 kfree(chip);
706 return 0;
707}
708
709static struct platform_driver pm8xxx_ccadc_driver = {
710 .probe = pm8xxx_ccadc_probe,
711 .remove = __devexit_p(pm8xxx_ccadc_remove),
712 .driver = {
713 .name = PM8XXX_CCADC_DEV_NAME,
714 .owner = THIS_MODULE,
715 },
716};
717
718static int __init pm8xxx_ccadc_init(void)
719{
720 return platform_driver_register(&pm8xxx_ccadc_driver);
721}
722
723static void __exit pm8xxx_ccadc_exit(void)
724{
725 platform_driver_unregister(&pm8xxx_ccadc_driver);
726}
727
728module_init(pm8xxx_ccadc_init);
729module_exit(pm8xxx_ccadc_exit);
730
731MODULE_LICENSE("GPL v2");
732MODULE_DESCRIPTION("PMIC8XXX ccadc driver");
733MODULE_VERSION("1.0");
734MODULE_ALIAS("platform:" PM8XXX_CCADC_DEV_NAME);