blob: 79124f7bf81951e597d6445ffb4e37b7575dc4a4 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* 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/pm8921-bms.h>
20#include <linux/mfd/pm8xxx/core.h>
Abhijeet Dharmapurikarc448d982011-06-28 20:48:36 -070021#include <linux/mfd/pm8921-adc.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/interrupt.h>
23#include <linux/bitops.h>
24#include <linux/debugfs.h>
25#include <linux/slab.h>
26
27#define BMS_CONTROL 0x224
28#define BMS_OUTPUT0 0x230
29#define BMS_OUTPUT1 0x231
30#define BMS_TEST1 0x237
31#define CCADC_ANA_PARAM 0x240
32#define CCADC_DIG_PARAM 0x241
33#define CCADC_RSV 0x242
34#define CCADC_DATA0 0x244
35#define CCADC_DATA1 0x245
36#define CCADC_OFFSET_TRIM1 0x34A
37#define CCADC_OFFSET_TRIM0 0x34B
38
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -070039#define ADC_ARB_SECP_CNTRL 0x190
40#define ADC_ARB_SECP_AMUX_CNTRL 0x191
41#define ADC_ARB_SECP_ANA_PARAM 0x192
42#define ADC_ARB_SECP_RSV 0x194
43#define ADC_ARB_SECP_DATA1 0x195
44#define ADC_ARB_SECP_DATA0 0x196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045
46enum pmic_bms_interrupts {
47 PM8921_BMS_SBI_WRITE_OK,
48 PM8921_BMS_CC_THR,
49 PM8921_BMS_VSENSE_THR,
50 PM8921_BMS_VSENSE_FOR_R,
51 PM8921_BMS_OCV_FOR_R,
52 PM8921_BMS_GOOD_OCV,
53 PM8921_BMS_VSENSE_AVG,
54 PM_BMS_MAX_INTS,
55};
56
57/**
58 * struct pm8921_bms_chip -device information
59 * @dev: device pointer to access the parent
60 * @dent: debugfs directory
61 * @r_sense: batt sense resistance value
62 * @i_test: peak current
63 * @v_failure: battery dead voltage
64 * @fcc: battery capacity
65 *
66 */
67struct pm8921_bms_chip {
68 struct device *dev;
69 struct dentry *dent;
70 unsigned int r_sense;
71 unsigned int i_test;
72 unsigned int v_failure;
73 unsigned int fcc;
74 struct single_row_lut *fcc_temp_lut;
75 struct single_row_lut *fcc_sf_lut;
76 struct pc_temp_ocv_lut *pc_temp_ocv_lut;
77 struct pc_sf_lut *pc_sf_lut;
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -070078 struct work_struct calib_hkadc_work;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079 unsigned int calib_delay_ms;
Abhijeet Dharmapurikarfa77f1a2011-06-27 21:11:51 -070080 unsigned int revision;
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -070081 unsigned int xoadc_v0625;
82 unsigned int xoadc_v125;
Abhijeet Dharmapurikarc448d982011-06-28 20:48:36 -070083 unsigned int batt_temp_channel;
84 unsigned int vbat_channel;
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -070085 unsigned int ref625mv_channel;
86 unsigned int ref1p25v_channel;
Abhijeet Dharmapurikare922bbb2011-09-01 13:05:06 -070087 unsigned int batt_id_channel;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088 unsigned int pmic_bms_irq[PM_BMS_MAX_INTS];
89 DECLARE_BITMAP(enabled_irqs, PM_BMS_MAX_INTS);
90};
91
92static struct pm8921_bms_chip *the_chip;
93
94#define DEFAULT_RBATT_MOHMS 128
95#define DEFAULT_UNUSABLE_CHARGE_MAH 10
96#define DEFAULT_OCV_MICROVOLTS 3900000
97#define DEFAULT_REMAINING_CHARGE_MAH 990
98#define DEFAULT_COULUMB_COUNTER 0
99#define DEFAULT_CHARGE_CYCLES 0
100
101static int last_rbatt = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102static int last_ocv_uv = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103static int last_soc = -EINVAL;
104
105static int last_chargecycles = DEFAULT_CHARGE_CYCLES;
106static int last_charge_increase;
107
108module_param(last_rbatt, int, 0644);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109module_param(last_ocv_uv, int, 0644);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110module_param(last_chargecycles, int, 0644);
111module_param(last_charge_increase, int, 0644);
112
113static int pm_bms_get_rt_status(struct pm8921_bms_chip *chip, int irq_id)
114{
115 return pm8xxx_read_irq_stat(chip->dev->parent,
116 chip->pmic_bms_irq[irq_id]);
117}
118
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -0700119static void pm8921_bms_enable_irq(struct pm8921_bms_chip *chip, int interrupt)
120{
121 if (!__test_and_set_bit(interrupt, chip->enabled_irqs)) {
122 dev_dbg(chip->dev, "%s %d\n", __func__,
123 chip->pmic_bms_irq[interrupt]);
124 enable_irq(chip->pmic_bms_irq[interrupt]);
125 }
126}
127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128static void pm8921_bms_disable_irq(struct pm8921_bms_chip *chip, int interrupt)
129{
130 if (__test_and_clear_bit(interrupt, chip->enabled_irqs)) {
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700131 pr_debug("%d\n", chip->pmic_bms_irq[interrupt]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 disable_irq_nosync(chip->pmic_bms_irq[interrupt]);
133 }
134}
135
136static int pm_bms_masked_write(struct pm8921_bms_chip *chip, u16 addr,
137 u8 mask, u8 val)
138{
139 int rc;
140 u8 reg;
141
142 rc = pm8xxx_readb(chip->dev->parent, addr, &reg);
143 if (rc) {
144 pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
145 return rc;
146 }
147 reg &= ~mask;
148 reg |= val & mask;
149 rc = pm8xxx_writeb(chip->dev->parent, addr, reg);
150 if (rc) {
151 pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
152 return rc;
153 }
154 return 0;
155}
156
157#define SELECT_OUTPUT_DATA 0x1C
158#define SELECT_OUTPUT_TYPE_SHIFT 2
159#define OCV_FOR_RBATT 0x0
160#define VSENSE_FOR_RBATT 0x1
161#define VBATT_FOR_RBATT 0x2
162#define CC_MSB 0x3
163#define CC_LSB 0x4
164#define LAST_GOOD_OCV_VALUE 0x5
165#define VSENSE_AVG 0x6
166#define VBATT_AVG 0x7
167
168static int pm_bms_read_output_data(struct pm8921_bms_chip *chip, int type,
169 int16_t *result)
170{
171 int rc;
172 u8 reg;
173
174 if (!result) {
175 pr_err("result pointer null\n");
176 return -EINVAL;
177 }
178 *result = 0;
179 if (type < OCV_FOR_RBATT || type > VBATT_AVG) {
180 pr_err("invalid type %d asked to read\n", type);
181 return -EINVAL;
182 }
183 rc = pm_bms_masked_write(chip, BMS_CONTROL, SELECT_OUTPUT_DATA,
184 type << SELECT_OUTPUT_TYPE_SHIFT);
185 if (rc) {
186 pr_err("fail to select %d type in BMS_CONTROL rc = %d\n",
187 type, rc);
188 return rc;
189 }
190
191 rc = pm8xxx_readb(chip->dev->parent, BMS_OUTPUT0, &reg);
192 if (rc) {
193 pr_err("fail to read BMS_OUTPUT0 for type %d rc = %d\n",
194 type, rc);
195 return rc;
196 }
197 *result = reg;
198 rc = pm8xxx_readb(chip->dev->parent, BMS_OUTPUT1, &reg);
199 if (rc) {
200 pr_err("fail to read BMS_OUTPUT1 for type %d rc = %d\n",
201 type, rc);
202 return rc;
203 }
204 *result |= reg << 8;
205 pr_debug("type %d result %x", type, *result);
206 return 0;
207}
208
Abhijeet Dharmapurikard76311f2011-07-19 13:35:01 -0700209#define V_PER_BIT_MUL_FACTOR 293
210#define INTRINSIC_OFFSET 0x6000
211static int vbatt_to_microvolt(unsigned int a)
212{
213 if (a <= INTRINSIC_OFFSET)
214 return 0;
215
216 return (a - INTRINSIC_OFFSET) * V_PER_BIT_MUL_FACTOR;
217}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -0700219#define XOADC_CALIB_UV 625000
220static int adjust_xo_reading(struct pm8921_bms_chip *chip, unsigned int uv)
221{
222 u64 numerator = ((u64)uv - chip->xoadc_v0625) * XOADC_CALIB_UV;
223 u64 denominator = chip->xoadc_v125 - chip->xoadc_v0625;
224
225 if (denominator == 0)
226 return uv;
227 return XOADC_CALIB_UV + div_u64(numerator, denominator);
228}
229
Abhijeet Dharmapurikareed550b2011-07-18 22:35:24 -0700230#define CC_RESOLUTION_N_V1 1085069
231#define CC_RESOLUTION_D_V1 100000
232#define CC_RESOLUTION_N_V2 868056
233#define CC_RESOLUTION_D_V2 10000
234static s64 cc_to_microvolt_v1(s64 cc)
235{
236 return div_s64(cc * CC_RESOLUTION_N_V1, CC_RESOLUTION_D_V1);
237}
238
239static s64 cc_to_microvolt_v2(s64 cc)
240{
241 return div_s64(cc * CC_RESOLUTION_N_V2, CC_RESOLUTION_D_V2);
242}
243
244static s64 cc_to_microvolt(struct pm8921_bms_chip *chip, s64 cc)
245{
246 /*
247 * resolution (the value of a single bit) was changed after revision 2.0
248 * for more accurate readings
249 */
250 return (chip->revision < PM8XXX_REVISION_8901_2p0) ?
251 cc_to_microvolt_v1((s64)cc) :
252 cc_to_microvolt_v2((s64)cc);
253}
254
255#define CC_READING_TICKS 55
256#define SLEEP_CLK_HZ 32768
257#define SECONDS_PER_HOUR 3600
258static s64 ccmicrovolt_to_uvh(s64 cc_uv)
259{
260 return div_s64(cc_uv * CC_READING_TICKS,
261 SLEEP_CLK_HZ * SECONDS_PER_HOUR);
262}
263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264/* returns the signed value read from the hardware */
265static int read_cc(struct pm8921_bms_chip *chip, int *result)
266{
267 int rc;
268 uint16_t msw, lsw;
269
270 rc = pm_bms_read_output_data(chip, CC_LSB, &lsw);
271 if (rc) {
272 pr_err("fail to read CC_LSB rc = %d\n", rc);
273 return rc;
274 }
275 rc = pm_bms_read_output_data(chip, CC_MSB, &msw);
276 if (rc) {
277 pr_err("fail to read CC_MSB rc = %d\n", rc);
278 return rc;
279 }
280 *result = msw << 16 | lsw;
281 pr_debug("msw = %04x lsw = %04x cc = %d\n", msw, lsw, *result);
282 return 0;
283}
284
285static int read_last_good_ocv(struct pm8921_bms_chip *chip, uint *result)
286{
287 int rc;
288 uint16_t reading;
289
290 rc = pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &reading);
291 if (rc) {
292 pr_err("fail to read LAST_GOOD_OCV_VALUE rc = %d\n", rc);
293 return rc;
294 }
Abhijeet Dharmapurikard76311f2011-07-19 13:35:01 -0700295 *result = vbatt_to_microvolt(reading);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296 pr_debug("raw = %04x ocv_microV = %u\n", reading, *result);
297 return 0;
298}
299
300static int read_vbatt_for_rbatt(struct pm8921_bms_chip *chip, uint *result)
301{
302 int rc;
303 uint16_t reading;
304
305 rc = pm_bms_read_output_data(chip, VBATT_FOR_RBATT, &reading);
306 if (rc) {
307 pr_err("fail to read VBATT_FOR_RBATT rc = %d\n", rc);
308 return rc;
309 }
Abhijeet Dharmapurikard76311f2011-07-19 13:35:01 -0700310 *result = vbatt_to_microvolt(reading);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311 pr_debug("raw = %04x vbatt_for_r_microV = %u\n", reading, *result);
312 return 0;
313}
314
315static int read_vsense_for_rbatt(struct pm8921_bms_chip *chip, uint *result)
316{
317 int rc;
318 uint16_t reading;
319
320 rc = pm_bms_read_output_data(chip, VSENSE_FOR_RBATT, &reading);
321 if (rc) {
322 pr_err("fail to read VSENSE_FOR_RBATT rc = %d\n", rc);
323 return rc;
324 }
Abhijeet Dharmapurikareed550b2011-07-18 22:35:24 -0700325 *result = cc_to_microvolt(chip, reading);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326 pr_debug("raw = %04x vsense_for_r_microV = %u\n", reading, *result);
327 return 0;
328}
329
330static int read_ocv_for_rbatt(struct pm8921_bms_chip *chip, uint *result)
331{
332 int rc;
333 uint16_t reading;
334
335 rc = pm_bms_read_output_data(chip, OCV_FOR_RBATT, &reading);
336 if (rc) {
337 pr_err("fail to read OCV_FOR_RBATT rc = %d\n", rc);
338 return rc;
339 }
Abhijeet Dharmapurikard76311f2011-07-19 13:35:01 -0700340 *result = vbatt_to_microvolt(reading);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341 pr_debug("read = %04x ocv_for_r_microV = %u\n", reading, *result);
342 return 0;
343}
344
Abhijeet Dharmapurikar2fb6f082011-06-28 17:10:27 -0700345static int read_vsense_avg(struct pm8921_bms_chip *chip, int *result)
346{
347 int rc;
348 int16_t reading;
349
350 rc = pm_bms_read_output_data(chip, VSENSE_AVG, &reading);
351 if (rc) {
352 pr_err("fail to read VSENSE_AVG rc = %d\n", rc);
353 return rc;
354 }
Abhijeet Dharmapurikareed550b2011-07-18 22:35:24 -0700355 *result = cc_to_microvolt(chip, reading);
Abhijeet Dharmapurikar2fb6f082011-06-28 17:10:27 -0700356 pr_debug("read = %04x vsense = %d\n", reading, *result);
357 return 0;
358}
359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360static int linear_interpolate(int y0, int x0, int y1, int x1, int x)
361{
362 if (y0 == y1 || x == x0)
363 return y0;
364 if (x1 == x0 || x == x1)
365 return y1;
366
367 return y0 + ((y1 - y0) * (x - x0) / (x1 - x0));
368}
369
370static int interpolate_single_lut(struct single_row_lut *lut, int x)
371{
372 int i, result;
373
374 if (x < lut->x[0]) {
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700375 pr_debug("x %d less than known range return y = %d lut = %pS\n",
376 x, lut->y[0], lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700377 return lut->y[0];
378 }
379 if (x > lut->x[lut->cols - 1]) {
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700380 pr_debug("x %d more than known range return y = %d lut = %pS\n",
381 x, lut->y[lut->cols - 1], lut);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 return lut->y[lut->cols - 1];
383 }
384
385 for (i = 0; i < lut->cols; i++)
386 if (x <= lut->x[i])
387 break;
388 if (x == lut->x[i]) {
389 result = lut->y[i];
390 } else {
391 result = linear_interpolate(
392 lut->y[i - 1],
393 lut->x[i - 1],
394 lut->y[i],
395 lut->x[i],
396 x);
397 }
398 return result;
399}
400
401static int interpolate_fcc(struct pm8921_bms_chip *chip, int batt_temp)
402{
403 return interpolate_single_lut(chip->fcc_temp_lut, batt_temp);
404}
405
406static int interpolate_scalingfactor_fcc(struct pm8921_bms_chip *chip,
407 int cycles)
408{
409 return interpolate_single_lut(chip->fcc_sf_lut, cycles);
410}
411
412static int interpolate_scalingfactor_pc(struct pm8921_bms_chip *chip,
413 int cycles, int pc)
414{
415 int i, scalefactorrow1, scalefactorrow2, scalefactor, row1, row2;
416 int rows = chip->pc_sf_lut->rows;
417 int cols = chip->pc_sf_lut->cols;
418
419 if (pc > chip->pc_sf_lut->percent[0]) {
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700420 pr_debug("pc %d greater than known pc ranges for sfd\n", pc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 row1 = 0;
422 row2 = 0;
423 }
424 if (pc < chip->pc_sf_lut->percent[rows - 1]) {
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700425 pr_debug("pc %d less than known pc ranges for sf", pc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 row1 = rows - 1;
427 row2 = rows - 1;
428 }
429 for (i = 0; i < rows; i++) {
430 if (pc == chip->pc_sf_lut->percent[i]) {
431 row1 = i;
432 row2 = i;
433 break;
434 }
435 if (pc > chip->pc_sf_lut->percent[i]) {
436 row1 = i - 1;
437 row2 = i;
438 break;
439 }
440 }
441
442 if (cycles < chip->pc_sf_lut->cycles[0])
443 cycles = chip->pc_sf_lut->cycles[0];
444 if (cycles > chip->pc_sf_lut->cycles[cols - 1])
445 cycles = chip->pc_sf_lut->cycles[cols - 1];
446
447 for (i = 0; i < cols; i++)
448 if (cycles <= chip->pc_sf_lut->cycles[i])
449 break;
450 if (cycles == chip->pc_sf_lut->cycles[i]) {
451 scalefactor = linear_interpolate(
452 chip->pc_sf_lut->sf[row1][i],
453 chip->pc_sf_lut->percent[row1],
454 chip->pc_sf_lut->sf[row2][i],
455 chip->pc_sf_lut->percent[row2],
456 pc);
457 return scalefactor;
458 }
459
460 scalefactorrow1 = linear_interpolate(
461 chip->pc_sf_lut->sf[row1][i - 1],
462 chip->pc_sf_lut->cycles[i - 1],
463 chip->pc_sf_lut->sf[row1][i],
464 chip->pc_sf_lut->cycles[i],
465 cycles);
466
467 scalefactorrow2 = linear_interpolate(
468 chip->pc_sf_lut->sf[row2][i - 1],
469 chip->pc_sf_lut->cycles[i - 1],
470 chip->pc_sf_lut->sf[row2][i],
471 chip->pc_sf_lut->cycles[i],
472 cycles);
473
474 scalefactor = linear_interpolate(
475 scalefactorrow1,
476 chip->pc_sf_lut->percent[row1],
477 scalefactorrow2,
478 chip->pc_sf_lut->percent[row2],
479 pc);
480
481 return scalefactor;
482}
483
Abhijeet Dharmapurikar78d812f2011-07-21 19:57:21 -0700484static int is_between(int left, int right, int value)
485{
486 if (left >= right && left >= value && value >= right)
487 return 1;
488 if (left <= right && left <= value && value <= right)
489 return 1;
490
491 return 0;
492}
493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494static int interpolate_pc(struct pm8921_bms_chip *chip,
495 int batt_temp, int ocv)
496{
Abhijeet Dharmapurikar78d812f2011-07-21 19:57:21 -0700497 int i, j, pcj, pcj_minus_one, pc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498 int rows = chip->pc_temp_ocv_lut->rows;
499 int cols = chip->pc_temp_ocv_lut->cols;
500
501 if (batt_temp < chip->pc_temp_ocv_lut->temp[0]) {
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700502 pr_debug("batt_temp %d < known temp range for pc\n", batt_temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700503 batt_temp = chip->pc_temp_ocv_lut->temp[0];
504 }
505 if (batt_temp > chip->pc_temp_ocv_lut->temp[cols - 1]) {
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700506 pr_debug("batt_temp %d > known temp range for pc\n", batt_temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700507 batt_temp = chip->pc_temp_ocv_lut->temp[cols - 1];
508 }
509
510 for (j = 0; j < cols; j++)
511 if (batt_temp <= chip->pc_temp_ocv_lut->temp[j])
512 break;
513 if (batt_temp == chip->pc_temp_ocv_lut->temp[j]) {
514 /* found an exact match for temp in the table */
515 if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
516 return chip->pc_temp_ocv_lut->percent[0];
517 if (ocv <= chip->pc_temp_ocv_lut->ocv[rows - 1][j])
518 return chip->pc_temp_ocv_lut->percent[rows - 1];
519 for (i = 0; i < rows; i++) {
520 if (ocv >= chip->pc_temp_ocv_lut->ocv[i][j]) {
521 if (ocv == chip->pc_temp_ocv_lut->ocv[i][j])
522 return
523 chip->pc_temp_ocv_lut->percent[i];
524 pc = linear_interpolate(
525 chip->pc_temp_ocv_lut->percent[i],
526 chip->pc_temp_ocv_lut->ocv[i][j],
527 chip->pc_temp_ocv_lut->percent[i - 1],
528 chip->pc_temp_ocv_lut->ocv[i - 1][j],
529 ocv);
530 return pc;
531 }
532 }
533 }
534
Abhijeet Dharmapurikar78d812f2011-07-21 19:57:21 -0700535 /*
536 * batt_temp is within temperature for
537 * column j-1 and j
538 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
540 return chip->pc_temp_ocv_lut->percent[0];
541 if (ocv <= chip->pc_temp_ocv_lut->ocv[rows - 1][j - 1])
542 return chip->pc_temp_ocv_lut->percent[rows - 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543
Abhijeet Dharmapurikar78d812f2011-07-21 19:57:21 -0700544 pcj_minus_one = 0;
545 pcj = 0;
546 for (i = 0; i < rows-1; i++) {
547 if (pcj == 0
548 && is_between(chip->pc_temp_ocv_lut->ocv[i][j],
549 chip->pc_temp_ocv_lut->ocv[i+1][j], ocv)) {
550 pcj = linear_interpolate(
551 chip->pc_temp_ocv_lut->percent[i],
552 chip->pc_temp_ocv_lut->ocv[i][j],
553 chip->pc_temp_ocv_lut->percent[i + 1],
554 chip->pc_temp_ocv_lut->ocv[i+1][j],
555 ocv);
556 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700557
Abhijeet Dharmapurikar78d812f2011-07-21 19:57:21 -0700558 if (pcj_minus_one == 0
559 && is_between(chip->pc_temp_ocv_lut->ocv[i][j-1],
560 chip->pc_temp_ocv_lut->ocv[i+1][j-1], ocv)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561
Abhijeet Dharmapurikar78d812f2011-07-21 19:57:21 -0700562 pcj_minus_one = linear_interpolate(
563 chip->pc_temp_ocv_lut->percent[i],
564 chip->pc_temp_ocv_lut->ocv[i][j-1],
565 chip->pc_temp_ocv_lut->percent[i + 1],
566 chip->pc_temp_ocv_lut->ocv[i+1][j-1],
567 ocv);
568 }
569
570 if (pcj && pcj_minus_one) {
571 pc = linear_interpolate(
572 pcj_minus_one,
573 chip->pc_temp_ocv_lut->temp[j-1],
574 pcj,
575 chip->pc_temp_ocv_lut->temp[j],
576 batt_temp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 return pc;
578 }
579 }
580
Abhijeet Dharmapurikar78d812f2011-07-21 19:57:21 -0700581 if (pcj)
582 return pcj;
583
584 if (pcj_minus_one)
585 return pcj_minus_one;
586
587 pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%",
588 ocv, batt_temp);
589 return 100;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590}
591
592static int calculate_rbatt(struct pm8921_bms_chip *chip)
593{
594 int rc;
595 unsigned int ocv, vsense, vbatt, r_batt;
596
597 rc = read_ocv_for_rbatt(chip, &ocv);
598 if (rc) {
599 pr_err("fail to read ocv_for_rbatt rc = %d\n", rc);
600 ocv = 0;
601 }
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -0700602 ocv = adjust_xo_reading(chip, ocv);
603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604 rc = read_vbatt_for_rbatt(chip, &vbatt);
605 if (rc) {
606 pr_err("fail to read vbatt_for_rbatt rc = %d\n", rc);
607 ocv = 0;
608 }
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -0700609 vbatt = adjust_xo_reading(chip, vbatt);
610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 rc = read_vsense_for_rbatt(chip, &vsense);
612 if (rc) {
613 pr_err("fail to read vsense_for_rbatt rc = %d\n", rc);
614 ocv = 0;
615 }
616 if (ocv == 0
617 || ocv == vbatt
618 || vsense == 0) {
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700619 pr_debug("rbatt readings unavailable ocv = %d, vbatt = %d,"
620 "vsen = %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 ocv, vbatt, vsense);
622 return -EINVAL;
623 }
624 r_batt = ((ocv - vbatt) * chip->r_sense) / vsense;
625 pr_debug("r_batt = %umilliOhms", r_batt);
626 return r_batt;
627}
628
629static int calculate_fcc(struct pm8921_bms_chip *chip, int batt_temp,
630 int chargecycles)
631{
632 int initfcc, result, scalefactor = 0;
633
634 initfcc = interpolate_fcc(chip, batt_temp);
635 pr_debug("intfcc = %umAh batt_temp = %d\n", initfcc, batt_temp);
636
637 scalefactor = interpolate_scalingfactor_fcc(chip, chargecycles);
638 pr_debug("scalefactor = %d batt_temp = %d\n", scalefactor, batt_temp);
639
640 /* Multiply the initial FCC value by the scale factor. */
641 result = (initfcc * scalefactor) / 100;
642 pr_debug("fcc mAh = %d\n", result);
643 return result;
644}
645
646static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv, int batt_temp,
647 int chargecycles)
648{
649 int pc, scalefactor;
650
651 pc = interpolate_pc(chip, batt_temp, ocv_uv / 1000);
652 pr_debug("pc = %u for ocv = %dmicroVolts batt_temp = %d\n",
653 pc, ocv_uv, batt_temp);
654
655 scalefactor = interpolate_scalingfactor_pc(chip, chargecycles, pc);
656 pr_debug("scalefactor = %u batt_temp = %d\n", scalefactor, batt_temp);
657
658 /* Multiply the initial FCC value by the scale factor. */
659 pc = (pc * scalefactor) / 100;
660 return pc;
661}
662
Abhijeet Dharmapurikarfa77f1a2011-06-27 21:11:51 -0700663static void calculate_cc_mah(struct pm8921_bms_chip *chip, int64_t *val,
Abhijeet Dharmapurikar52aa9682011-07-20 14:05:47 -0700664 int *coulumb_counter)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665{
666 int rc;
667 int64_t cc_voltage_uv, cc_uvh, cc_mah;
668
669 rc = read_cc(the_chip, coulumb_counter);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670 cc_voltage_uv = (int64_t)*coulumb_counter;
Abhijeet Dharmapurikarfa77f1a2011-06-27 21:11:51 -0700671 cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672 pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv);
Abhijeet Dharmapurikarfa77f1a2011-06-27 21:11:51 -0700673 cc_uvh = ccmicrovolt_to_uvh(cc_voltage_uv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700674 pr_debug("cc_uvh = %lld micro_volt_hour\n", cc_uvh);
675 cc_mah = div_s64(cc_uvh, chip->r_sense);
676 *val = cc_mah;
677}
678
Abhijeet Dharmapurikarc448d982011-06-28 20:48:36 -0700679static int get_battery_uvolts(struct pm8921_bms_chip *chip, int *uvolts)
680{
681 int rc;
682 struct pm8921_adc_chan_result result;
683
684 rc = pm8921_adc_read(chip->vbat_channel, &result);
685 if (rc) {
686 pr_err("error reading adc channel = %d, rc = %d\n",
687 chip->vbat_channel, rc);
688 return rc;
689 }
690 pr_debug("mvolts phy = %lld meas = 0x%llx", result.physical,
691 result.measurement);
692 *uvolts = (int)result.physical;
693 *uvolts = *uvolts * 1000;
694 return 0;
695}
696
Abhijeet Dharmapurikar020b37c2011-07-20 14:14:51 -0700697static int calculate_unusable_charge_mah(struct pm8921_bms_chip *chip,
698 int fcc, int batt_temp, int chargecycles)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700699{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700700 int rbatt, voltage_unusable_uv, pc_unusable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700701
702 rbatt = calculate_rbatt(chip);
703 if (rbatt < 0) {
704 rbatt = (last_rbatt < 0) ? DEFAULT_RBATT_MOHMS : last_rbatt;
Abhijeet Dharmapurikar020b37c2011-07-20 14:14:51 -0700705 pr_debug("rbatt unavailable assuming %d\n", rbatt);
706 } else {
707 last_rbatt = rbatt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709
710 /* calculate unusable charge */
711 voltage_unusable_uv = (rbatt * chip->i_test)
712 + (chip->v_failure * 1000);
713 pc_unusable = calculate_pc(chip, voltage_unusable_uv,
714 batt_temp, chargecycles);
Abhijeet Dharmapurikar020b37c2011-07-20 14:14:51 -0700715 pr_debug("rbatt = %umilliOhms unusable_v =%d unusable_pc = %d\n",
716 rbatt, voltage_unusable_uv, pc_unusable);
717 return (fcc * pc_unusable) / 100;
718}
Abhijeet Dharmapurikar52aa9682011-07-20 14:05:47 -0700719
Abhijeet Dharmapurikar020b37c2011-07-20 14:14:51 -0700720/* calculate remainging charge at the time of ocv */
721static int calculate_remaining_charge_mah(struct pm8921_bms_chip *chip, int fcc,
722 int batt_temp, int chargecycles)
723{
724 int rc, ocv, pc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725
726 /* calculate remainging charge */
Abhijeet Dharmapurikarc3532222011-07-20 14:48:02 -0700727 ocv = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728 rc = read_last_good_ocv(chip, &ocv);
Abhijeet Dharmapurikarc3532222011-07-20 14:48:02 -0700729 if (rc)
730 pr_debug("failed to read ocv rc = %d\n", rc);
731
732 if (ocv == 0) {
733 ocv = last_ocv_uv;
734 pr_debug("ocv not available using last_ocv_uv=%d\n", ocv);
Abhijeet Dharmapurikar020b37c2011-07-20 14:14:51 -0700735 } else {
Abhijeet Dharmapurikarc3532222011-07-20 14:48:02 -0700736 /* update the usespace param since a good ocv is available */
Abhijeet Dharmapurikar020b37c2011-07-20 14:14:51 -0700737 last_ocv_uv = ocv;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738 }
Abhijeet Dharmapurikar020b37c2011-07-20 14:14:51 -0700739
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700740 pc = calculate_pc(chip, ocv, batt_temp, chargecycles);
Abhijeet Dharmapurikar020b37c2011-07-20 14:14:51 -0700741 pr_debug("ocv = %d pc = %d\n", ocv, pc);
742 return (fcc * pc) / 100;
743}
744
745static int calculate_state_of_charge(struct pm8921_bms_chip *chip,
746 int batt_temp, int chargecycles)
747{
748 int remaining_usable_charge, fcc, unusable_charge;
749 int remaining_charge, soc, coulumb_counter;
750 int update_userspace = 1;
751 int64_t cc_mah;
752
753 fcc = calculate_fcc(chip, batt_temp, chargecycles);
754 pr_debug("FCC = %umAh batt_temp = %d, cycles = %d",
755 fcc, batt_temp, chargecycles);
756
757 unusable_charge = calculate_unusable_charge_mah(chip, fcc,
758 batt_temp, chargecycles);
759
760 pr_debug("UUC = %umAh", unusable_charge);
761
762 /* calculate remainging charge */
763 remaining_charge = calculate_remaining_charge_mah(chip, fcc, batt_temp,
764 chargecycles);
765 pr_debug("RC = %umAh\n", remaining_charge);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700766
767 /* calculate cc milli_volt_hour */
Abhijeet Dharmapurikar52aa9682011-07-20 14:05:47 -0700768 calculate_cc_mah(chip, &cc_mah, &coulumb_counter);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700769 pr_debug("cc_mah = %lldmAh cc = %d\n", cc_mah, coulumb_counter);
770
771 /* calculate remaining usable charge */
772 remaining_usable_charge = remaining_charge - cc_mah - unusable_charge;
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700773 pr_debug("RUC = %dmAh\n", remaining_usable_charge);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700774 if (remaining_usable_charge < 0) {
775 pr_err("bad rem_usb_chg cc_mah %lld, rem_chg %d unusb_chg %d\n",
776 cc_mah, remaining_charge, unusable_charge);
777 update_userspace = 0;
778 }
779
780 soc = (remaining_usable_charge * 100) / (fcc - unusable_charge);
781 if (soc > 100 || soc < 0) {
782 pr_err("bad soc rem_usb_chg %d fcc %d unusb_chg %d\n",
783 remaining_usable_charge, fcc, unusable_charge);
784 update_userspace = 0;
785 }
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700786 pr_debug("SOC = %u%%\n", soc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787
788 if (update_userspace) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789 last_soc = soc;
790 }
791 return soc;
792}
793
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -0700794#define XOADC_MAX_1P25V 1312500
795#define XOADC_MIN_1P25V 1187500
796#define XOADC_MAX_0P625V 656250
797#define XOADC_MIN_0P625V 593750
798
799#define HKADC_V_PER_BIT_MUL_FACTOR 977
800#define HKADC_V_PER_BIT_DIV_FACTOR 10
801static int calib_hkadc_convert_microvolt(unsigned int phy)
802{
803 return phy * HKADC_V_PER_BIT_MUL_FACTOR / HKADC_V_PER_BIT_DIV_FACTOR;
804}
805
806static void calib_hkadc(struct pm8921_bms_chip *chip)
807{
808 int voltage, rc;
809 struct pm8921_adc_chan_result result;
810
811 rc = pm8921_adc_read(the_chip->ref1p25v_channel, &result);
812 if (rc) {
813 pr_err("ADC failed for 1.25volts rc = %d\n", rc);
814 return;
815 }
816 voltage = calib_hkadc_convert_microvolt(result.physical);
817
818 pr_debug("result 1.25v = 0x%llx, voltage = %dmV adc_meas = %lld\n",
819 result.physical, voltage, result.measurement);
820
821 /* check for valid range */
822 if (voltage > XOADC_MAX_1P25V)
823 voltage = XOADC_MAX_1P25V;
824 else if (voltage < XOADC_MIN_1P25V)
825 voltage = XOADC_MIN_1P25V;
826 chip->xoadc_v125 = voltage;
827
828 rc = pm8921_adc_read(the_chip->ref625mv_channel, &result);
829 if (rc) {
830 pr_err("ADC failed for 1.25volts rc = %d\n", rc);
831 return;
832 }
833 voltage = calib_hkadc_convert_microvolt(result.physical);
834 pr_debug("result 0.625V = 0x%llx, voltage = %dmV adc_mead = %lld\n",
835 result.physical, voltage, result.measurement);
836 /* check for valid range */
837 if (voltage > XOADC_MAX_0P625V)
838 voltage = XOADC_MAX_0P625V;
839 else if (voltage < XOADC_MIN_0P625V)
840 voltage = XOADC_MIN_0P625V;
841
842 chip->xoadc_v0625 = voltage;
843}
844
845static void calibrate_hkadc_work(struct work_struct *work)
846{
847 struct pm8921_bms_chip *chip = container_of(work,
848 struct pm8921_bms_chip, calib_hkadc_work);
849
850 calib_hkadc(chip);
851}
852
Abhijeet Dharmapurikar2fb6f082011-06-28 17:10:27 -0700853int pm8921_bms_get_vsense_avg(int *result)
854{
855 if (the_chip)
856 return read_vsense_avg(the_chip, result);
857
858 pr_err("called before initialization\n");
859 return -EINVAL;
860}
861EXPORT_SYMBOL(pm8921_bms_get_vsense_avg);
862
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -0700863int pm8921_bms_get_battery_current(int *result)
864{
865 if (!the_chip) {
866 pr_err("called before initialization\n");
867 return -EINVAL;
868 }
869 if (the_chip->r_sense == 0) {
870 pr_err("r_sense is zero\n");
871 return -EINVAL;
872 }
873
874 read_vsense_avg(the_chip, result);
875 pr_debug("vsense=%d\n", *result);
Abhijeet Dharmapurikara7a1c6b2011-08-17 10:04:58 -0700876 /* cast for signed division */
877 *result = *result / (int)the_chip->r_sense;
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -0700878 return 0;
879}
880EXPORT_SYMBOL(pm8921_bms_get_battery_current);
881
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700882int pm8921_bms_get_percent_charge(void)
883{
Abhijeet Dharmapurikarc448d982011-06-28 20:48:36 -0700884 int batt_temp, rc;
885 struct pm8921_adc_chan_result result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886
Abhijeet Dharmapurikarc448d982011-06-28 20:48:36 -0700887 if (!the_chip) {
888 pr_err("called before initialization\n");
889 return -EINVAL;
890 }
891
892 rc = pm8921_adc_read(the_chip->batt_temp_channel, &result);
893 if (rc) {
894 pr_err("error reading adc channel = %d, rc = %d\n",
895 the_chip->batt_temp_channel, rc);
896 return rc;
897 }
898 pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
899 result.measurement);
900 batt_temp = (int)result.physical;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 return calculate_state_of_charge(the_chip,
902 batt_temp, last_chargecycles);
903}
904EXPORT_SYMBOL_GPL(pm8921_bms_get_percent_charge);
905
Abhijeet Dharmapurikar325bdc92011-09-07 20:45:49 -0700906int pm8921_bms_get_fcc(void)
907{
908 int batt_temp, rc;
909 struct pm8921_adc_chan_result result;
910
911 if (!the_chip) {
912 pr_err("called before initialization\n");
913 return -EINVAL;
914 }
915
916 rc = pm8921_adc_read(the_chip->batt_temp_channel, &result);
917 if (rc) {
918 pr_err("error reading adc channel = %d, rc = %d\n",
919 the_chip->batt_temp_channel, rc);
920 return rc;
921 }
922 pr_debug("batt_temp phy = %lld meas = 0x%llx", result.physical,
923 result.measurement);
924 batt_temp = (int)result.physical;
925 return calculate_fcc(the_chip, batt_temp, last_chargecycles);
926}
927EXPORT_SYMBOL_GPL(pm8921_bms_get_fcc);
928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929static int start_percent;
930static int end_percent;
931void pm8921_bms_charging_began(void)
932{
Abhijeet Dharmapurikarc448d982011-06-28 20:48:36 -0700933 start_percent = pm8921_bms_get_percent_charge();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934 pr_debug("start_percent = %u%%\n", start_percent);
935}
936EXPORT_SYMBOL_GPL(pm8921_bms_charging_began);
937
938void pm8921_bms_charging_end(void)
939{
Abhijeet Dharmapurikarc448d982011-06-28 20:48:36 -0700940 end_percent = pm8921_bms_get_percent_charge();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941 if (end_percent > start_percent) {
942 last_charge_increase = end_percent - start_percent;
943 if (last_charge_increase > 100) {
944 last_chargecycles++;
945 last_charge_increase = last_charge_increase % 100;
946 }
947 }
948 pr_debug("end_percent = %u%% last_charge_increase = %d"
949 "last_chargecycles = %d\n",
950 end_percent,
951 last_charge_increase,
952 last_chargecycles);
953}
954EXPORT_SYMBOL_GPL(pm8921_bms_charging_end);
955
956static irqreturn_t pm8921_bms_sbi_write_ok_handler(int irq, void *data)
957{
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700958 pr_debug("irq = %d triggered", irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959 return IRQ_HANDLED;
960}
961
962static irqreturn_t pm8921_bms_cc_thr_handler(int irq, void *data)
963{
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700964 pr_debug("irq = %d triggered", irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 return IRQ_HANDLED;
966}
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700967
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968static irqreturn_t pm8921_bms_vsense_thr_handler(int irq, void *data)
969{
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700970 pr_debug("irq = %d triggered", irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 return IRQ_HANDLED;
972}
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974static irqreturn_t pm8921_bms_vsense_for_r_handler(int irq, void *data)
975{
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700976 pr_debug("irq = %d triggered", irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977 return IRQ_HANDLED;
978}
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700979
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700980static irqreturn_t pm8921_bms_ocv_for_r_handler(int irq, void *data)
981{
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -0700982 struct pm8921_bms_chip *chip = data;
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700983
984 pr_debug("irq = %d triggered", irq);
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -0700985 schedule_work(&chip->calib_hkadc_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700986 return IRQ_HANDLED;
987}
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700989static irqreturn_t pm8921_bms_good_ocv_handler(int irq, void *data)
990{
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -0700991 struct pm8921_bms_chip *chip = data;
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700992
993 pr_debug("irq = %d triggered", irq);
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -0700994 schedule_work(&chip->calib_hkadc_work);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 return IRQ_HANDLED;
996}
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -0700997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998static irqreturn_t pm8921_bms_vsense_avg_handler(int irq, void *data)
999{
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -07001000 pr_debug("irq = %d triggered", irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001 return IRQ_HANDLED;
1002}
1003
1004struct pm_bms_irq_init_data {
1005 unsigned int irq_id;
1006 char *name;
1007 unsigned long flags;
1008 irqreturn_t (*handler)(int, void *);
1009};
1010
1011#define BMS_IRQ(_id, _flags, _handler) \
1012{ \
1013 .irq_id = _id, \
1014 .name = #_id, \
1015 .flags = _flags, \
1016 .handler = _handler, \
1017}
1018
1019struct pm_bms_irq_init_data bms_irq_data[] = {
1020 BMS_IRQ(PM8921_BMS_SBI_WRITE_OK, IRQF_TRIGGER_RISING,
1021 pm8921_bms_sbi_write_ok_handler),
1022 BMS_IRQ(PM8921_BMS_CC_THR, IRQF_TRIGGER_RISING,
1023 pm8921_bms_cc_thr_handler),
1024 BMS_IRQ(PM8921_BMS_VSENSE_THR, IRQF_TRIGGER_RISING,
1025 pm8921_bms_vsense_thr_handler),
1026 BMS_IRQ(PM8921_BMS_VSENSE_FOR_R, IRQF_TRIGGER_RISING,
1027 pm8921_bms_vsense_for_r_handler),
1028 BMS_IRQ(PM8921_BMS_OCV_FOR_R, IRQF_TRIGGER_RISING,
1029 pm8921_bms_ocv_for_r_handler),
1030 BMS_IRQ(PM8921_BMS_GOOD_OCV, IRQF_TRIGGER_RISING,
1031 pm8921_bms_good_ocv_handler),
1032 BMS_IRQ(PM8921_BMS_VSENSE_AVG, IRQF_TRIGGER_RISING,
1033 pm8921_bms_vsense_avg_handler),
1034};
1035
1036static void free_irqs(struct pm8921_bms_chip *chip)
1037{
1038 int i;
1039
1040 for (i = 0; i < PM_BMS_MAX_INTS; i++)
1041 if (chip->pmic_bms_irq[i]) {
1042 free_irq(chip->pmic_bms_irq[i], NULL);
1043 chip->pmic_bms_irq[i] = 0;
1044 }
1045}
1046
1047static int __devinit request_irqs(struct pm8921_bms_chip *chip,
1048 struct platform_device *pdev)
1049{
1050 struct resource *res;
1051 int ret, i;
1052
1053 ret = 0;
1054 bitmap_fill(chip->enabled_irqs, PM_BMS_MAX_INTS);
1055
1056 for (i = 0; i < ARRAY_SIZE(bms_irq_data); i++) {
1057 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1058 bms_irq_data[i].name);
1059 if (res == NULL) {
1060 pr_err("couldn't find %s\n", bms_irq_data[i].name);
1061 goto err_out;
1062 }
1063 ret = request_irq(res->start, bms_irq_data[i].handler,
1064 bms_irq_data[i].flags,
1065 bms_irq_data[i].name, chip);
1066 if (ret < 0) {
1067 pr_err("couldn't request %d (%s) %d\n", res->start,
1068 bms_irq_data[i].name, ret);
1069 goto err_out;
1070 }
1071 chip->pmic_bms_irq[bms_irq_data[i].irq_id] = res->start;
1072 pm8921_bms_disable_irq(chip, bms_irq_data[i].irq_id);
1073 }
1074 return 0;
1075
1076err_out:
1077 free_irqs(chip);
1078 return -EINVAL;
1079}
1080
1081#define EN_BMS_BIT BIT(7)
1082#define EN_PON_HS_BIT BIT(0)
1083static int __devinit pm8921_bms_hw_init(struct pm8921_bms_chip *chip)
1084{
1085 int rc;
1086
1087 rc = pm_bms_masked_write(chip, BMS_CONTROL,
1088 EN_BMS_BIT | EN_PON_HS_BIT, EN_BMS_BIT | EN_PON_HS_BIT);
1089 if (rc) {
1090 pr_err("failed to enable pon and bms addr = %d %d",
1091 BMS_CONTROL, rc);
1092 }
1093
1094 return 0;
1095}
1096
Abhijeet Dharmapurikarc3532222011-07-20 14:48:02 -07001097static void check_initial_ocv(struct pm8921_bms_chip *chip)
1098{
1099 int ocv, vbatt, rbatt, ibatt, rc;
1100
1101 /*
1102 * Check if a last_good_ocv is available,
1103 * if not compute it here at boot time.
1104 */
1105 rc = read_last_good_ocv(chip, &ocv);
1106 if (rc || ocv == 0) {
1107 rc = get_battery_uvolts(chip, &vbatt);
1108 if (rc) {
1109 pr_err("failed to read vbatt from adc rc = %d\n", rc);
1110 last_ocv_uv = DEFAULT_OCV_MICROVOLTS;
1111 return;
1112 }
1113
1114 rc = pm8921_bms_get_battery_current(&ibatt);
1115 if (rc) {
1116 pr_err("failed to read batt current rc = %d\n", rc);
1117 last_ocv_uv = DEFAULT_OCV_MICROVOLTS;
1118 return;
1119 }
1120
1121 rbatt = calculate_rbatt(the_chip);
1122 if (rbatt < 0)
1123 rbatt = DEFAULT_RBATT_MOHMS;
1124 last_ocv_uv = vbatt + ibatt * rbatt;
1125 }
1126 pr_debug("ocv = %d last_ocv_uv = %d\n", ocv, last_ocv_uv);
1127}
1128
Abhijeet Dharmapurikare922bbb2011-09-01 13:05:06 -07001129static int64_t read_battery_id(struct pm8921_bms_chip *chip)
1130{
1131 int rc;
1132 struct pm8921_adc_chan_result result;
1133
1134 rc = pm8921_adc_read(chip->batt_id_channel, &result);
1135 if (rc) {
1136 pr_err("error reading batt id channel = %d, rc = %d\n",
1137 chip->vbat_channel, rc);
1138 return rc;
1139 }
1140 pr_debug("batt_id phy = %lld meas = 0x%llx\n", result.physical,
1141 result.measurement);
1142 return result.physical;
1143}
1144
1145#define PALLADIUM_ID_MIN 2500
1146#define PALLADIUM_ID_MAX 4000
1147static int set_battery_data(struct pm8921_bms_chip *chip)
1148{
1149 int64_t battery_id;
1150
1151 battery_id = read_battery_id(chip);
1152
1153 if (battery_id < 0) {
1154 pr_err("cannot read battery id err = %lld\n", battery_id);
1155 return battery_id;
1156 }
1157
1158 if (is_between(PALLADIUM_ID_MIN, PALLADIUM_ID_MAX, battery_id)) {
1159 chip->fcc = palladium_1500_data.fcc;
1160 chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
1161 chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
1162 chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
1163 chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
1164 return 0;
1165 } else {
1166 pr_warn("invalid battery id, palladium 1500 assumed\n");
1167 chip->fcc = palladium_1500_data.fcc;
1168 chip->fcc_temp_lut = palladium_1500_data.fcc_temp_lut;
1169 chip->fcc_sf_lut = palladium_1500_data.fcc_sf_lut;
1170 chip->pc_temp_ocv_lut = palladium_1500_data.pc_temp_ocv_lut;
1171 chip->pc_sf_lut = palladium_1500_data.pc_sf_lut;
1172 return 0;
1173 }
1174}
1175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176enum {
1177 CALC_RBATT,
1178 CALC_FCC,
1179 CALC_PC,
1180 CALC_SOC,
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -07001181 CALIB_HKADC,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182};
1183
1184static int test_batt_temp = 5;
1185static int test_chargecycle = 150;
1186static int test_ocv = 3900000;
1187enum {
1188 TEST_BATT_TEMP,
1189 TEST_CHARGE_CYCLE,
1190 TEST_OCV,
1191};
1192static int get_test_param(void *data, u64 * val)
1193{
1194 switch ((int)data) {
1195 case TEST_BATT_TEMP:
1196 *val = test_batt_temp;
1197 break;
1198 case TEST_CHARGE_CYCLE:
1199 *val = test_chargecycle;
1200 break;
1201 case TEST_OCV:
1202 *val = test_ocv;
1203 break;
1204 default:
1205 return -EINVAL;
1206 }
1207 return 0;
1208}
1209static int set_test_param(void *data, u64 val)
1210{
1211 switch ((int)data) {
1212 case TEST_BATT_TEMP:
1213 test_batt_temp = (int)val;
1214 break;
1215 case TEST_CHARGE_CYCLE:
1216 test_chargecycle = (int)val;
1217 break;
1218 case TEST_OCV:
1219 test_ocv = (int)val;
1220 break;
1221 default:
1222 return -EINVAL;
1223 }
1224 return 0;
1225}
1226DEFINE_SIMPLE_ATTRIBUTE(temp_fops, get_test_param, set_test_param, "%llu\n");
1227
1228static int get_calc(void *data, u64 * val)
1229{
1230 int param = (int)data;
1231 int ret = 0;
1232
1233 *val = 0;
1234
1235 /* global irq number passed in via data */
1236 switch (param) {
1237 case CALC_RBATT:
1238 *val = calculate_rbatt(the_chip);
1239 break;
1240 case CALC_FCC:
1241 *val = calculate_fcc(the_chip, test_batt_temp,
1242 test_chargecycle);
1243 break;
1244 case CALC_PC:
1245 *val = calculate_pc(the_chip, test_ocv, test_batt_temp,
1246 test_chargecycle);
1247 break;
1248 case CALC_SOC:
1249 *val = calculate_state_of_charge(the_chip,
1250 test_batt_temp, test_chargecycle);
1251 break;
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -07001252 case CALIB_HKADC:
1253 /* reading this will trigger calibration */
1254 *val = 0;
1255 calib_hkadc(the_chip);
1256 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 default:
1258 ret = -EINVAL;
1259 }
1260 return ret;
1261}
1262DEFINE_SIMPLE_ATTRIBUTE(calc_fops, get_calc, NULL, "%llu\n");
1263
1264static int get_reading(void *data, u64 * val)
1265{
1266 int param = (int)data;
1267 int ret = 0;
1268
1269 *val = 0;
1270
1271 /* global irq number passed in via data */
1272 switch (param) {
1273 case CC_MSB:
1274 case CC_LSB:
1275 read_cc(the_chip, (int *)val);
1276 break;
1277 case LAST_GOOD_OCV_VALUE:
1278 read_last_good_ocv(the_chip, (uint *)val);
1279 break;
1280 case VBATT_FOR_RBATT:
1281 read_vbatt_for_rbatt(the_chip, (uint *)val);
1282 break;
1283 case VSENSE_FOR_RBATT:
1284 read_vsense_for_rbatt(the_chip, (uint *)val);
1285 break;
1286 case OCV_FOR_RBATT:
1287 read_ocv_for_rbatt(the_chip, (uint *)val);
1288 break;
Abhijeet Dharmapurikar2fb6f082011-06-28 17:10:27 -07001289 case VSENSE_AVG:
1290 read_vsense_avg(the_chip, (uint *)val);
1291 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292 default:
1293 ret = -EINVAL;
1294 }
1295 return ret;
1296}
Abhijeet Dharmapurikare0c3e5f2011-07-11 21:17:23 -07001297DEFINE_SIMPLE_ATTRIBUTE(reading_fops, get_reading, NULL, "%lld\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298
1299static int get_rt_status(void *data, u64 * val)
1300{
1301 int i = (int)data;
1302 int ret;
1303
1304 /* global irq number passed in via data */
1305 ret = pm_bms_get_rt_status(the_chip, i);
1306 *val = ret;
1307 return 0;
1308}
1309DEFINE_SIMPLE_ATTRIBUTE(rt_fops, get_rt_status, NULL, "%llu\n");
1310
1311static int get_reg(void *data, u64 * val)
1312{
1313 int addr = (int)data;
1314 int ret;
1315 u8 temp;
1316
1317 ret = pm8xxx_readb(the_chip->dev->parent, addr, &temp);
1318 if (ret) {
1319 pr_err("pm8xxx_readb to %x value = %d errored = %d\n",
1320 addr, temp, ret);
1321 return -EAGAIN;
1322 }
1323 *val = temp;
1324 return 0;
1325}
1326
1327static int set_reg(void *data, u64 val)
1328{
1329 int addr = (int)data;
1330 int ret;
1331 u8 temp;
1332
1333 temp = (u8) val;
1334 ret = pm8xxx_writeb(the_chip->dev->parent, addr, temp);
1335 if (ret) {
1336 pr_err("pm8xxx_writeb to %x value = %d errored = %d\n",
1337 addr, temp, ret);
1338 return -EAGAIN;
1339 }
1340 return 0;
1341}
1342DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_reg, set_reg, "0x%02llx\n");
1343
1344static void create_debugfs_entries(struct pm8921_bms_chip *chip)
1345{
1346 int i;
1347
1348 chip->dent = debugfs_create_dir("pm8921_bms", NULL);
1349
1350 if (IS_ERR(chip->dent)) {
1351 pr_err("pmic bms couldnt create debugfs dir\n");
1352 return;
1353 }
1354
1355 debugfs_create_file("BMS_CONTROL", 0644, chip->dent,
1356 (void *)BMS_CONTROL, &reg_fops);
1357 debugfs_create_file("BMS_OUTPUT0", 0644, chip->dent,
1358 (void *)BMS_OUTPUT0, &reg_fops);
1359 debugfs_create_file("BMS_OUTPUT1", 0644, chip->dent,
1360 (void *)BMS_OUTPUT1, &reg_fops);
1361 debugfs_create_file("BMS_TEST1", 0644, chip->dent,
1362 (void *)BMS_TEST1, &reg_fops);
1363 debugfs_create_file("CCADC_ANA_PARAM", 0644, chip->dent,
1364 (void *)CCADC_ANA_PARAM, &reg_fops);
1365 debugfs_create_file("CCADC_DIG_PARAM", 0644, chip->dent,
1366 (void *)CCADC_DIG_PARAM, &reg_fops);
1367 debugfs_create_file("CCADC_RSV", 0644, chip->dent,
1368 (void *)CCADC_RSV, &reg_fops);
1369 debugfs_create_file("CCADC_DATA0", 0644, chip->dent,
1370 (void *)CCADC_DATA0, &reg_fops);
1371 debugfs_create_file("CCADC_DATA1", 0644, chip->dent,
1372 (void *)CCADC_DATA1, &reg_fops);
1373 debugfs_create_file("CCADC_OFFSET_TRIM1", 0644, chip->dent,
1374 (void *)CCADC_OFFSET_TRIM1, &reg_fops);
1375 debugfs_create_file("CCADC_OFFSET_TRIM0", 0644, chip->dent,
1376 (void *)CCADC_OFFSET_TRIM0, &reg_fops);
1377
1378 debugfs_create_file("test_batt_temp", 0644, chip->dent,
1379 (void *)TEST_BATT_TEMP, &temp_fops);
1380 debugfs_create_file("test_chargecycle", 0644, chip->dent,
1381 (void *)TEST_CHARGE_CYCLE, &temp_fops);
1382 debugfs_create_file("test_ocv", 0644, chip->dent,
1383 (void *)TEST_OCV, &temp_fops);
1384
1385 debugfs_create_file("read_cc", 0644, chip->dent,
1386 (void *)CC_MSB, &reading_fops);
1387 debugfs_create_file("read_last_good_ocv", 0644, chip->dent,
1388 (void *)LAST_GOOD_OCV_VALUE, &reading_fops);
1389 debugfs_create_file("read_vbatt_for_rbatt", 0644, chip->dent,
1390 (void *)VBATT_FOR_RBATT, &reading_fops);
1391 debugfs_create_file("read_vsense_for_rbatt", 0644, chip->dent,
1392 (void *)VSENSE_FOR_RBATT, &reading_fops);
1393 debugfs_create_file("read_ocv_for_rbatt", 0644, chip->dent,
1394 (void *)OCV_FOR_RBATT, &reading_fops);
Abhijeet Dharmapurikar2fb6f082011-06-28 17:10:27 -07001395 debugfs_create_file("read_vsense_avg", 0644, chip->dent,
1396 (void *)VSENSE_AVG, &reading_fops);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001397
1398 debugfs_create_file("show_rbatt", 0644, chip->dent,
1399 (void *)CALC_RBATT, &calc_fops);
1400 debugfs_create_file("show_fcc", 0644, chip->dent,
1401 (void *)CALC_FCC, &calc_fops);
1402 debugfs_create_file("show_pc", 0644, chip->dent,
1403 (void *)CALC_PC, &calc_fops);
1404 debugfs_create_file("show_soc", 0644, chip->dent,
1405 (void *)CALC_SOC, &calc_fops);
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -07001406 debugfs_create_file("calib_hkadc", 0644, chip->dent,
1407 (void *)CALIB_HKADC, &calc_fops);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408
1409 for (i = 0; i < ARRAY_SIZE(bms_irq_data); i++) {
1410 if (chip->pmic_bms_irq[bms_irq_data[i].irq_id])
1411 debugfs_create_file(bms_irq_data[i].name, 0444,
1412 chip->dent,
1413 (void *)bms_irq_data[i].irq_id,
1414 &rt_fops);
1415 }
1416}
1417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418static int __devinit pm8921_bms_probe(struct platform_device *pdev)
1419{
1420 int rc = 0;
1421 struct pm8921_bms_chip *chip;
1422 const struct pm8921_bms_platform_data *pdata
1423 = pdev->dev.platform_data;
1424 if (!pdata) {
1425 pr_err("missing platform data\n");
1426 return -EINVAL;
1427 }
1428
Abhijeet Dharmapurikar15e853d2011-06-27 20:55:47 -07001429 chip = kzalloc(sizeof(struct pm8921_bms_chip), GFP_KERNEL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430 if (!chip) {
1431 pr_err("Cannot allocate pm_bms_chip\n");
1432 return -ENOMEM;
1433 }
1434
1435 chip->dev = &pdev->dev;
1436 chip->r_sense = pdata->r_sense;
1437 chip->i_test = pdata->i_test;
1438 chip->v_failure = pdata->v_failure;
1439 chip->calib_delay_ms = pdata->calib_delay_ms;
Abhijeet Dharmapurikare922bbb2011-09-01 13:05:06 -07001440 rc = set_battery_data(chip);
1441 if (rc) {
1442 pr_err("%s bad battery data %d\n", __func__, rc);
1443 return rc;
1444 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445
Abhijeet Dharmapurikarc448d982011-06-28 20:48:36 -07001446 chip->batt_temp_channel = pdata->bms_cdata.batt_temp_channel;
1447 chip->vbat_channel = pdata->bms_cdata.vbat_channel;
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -07001448 chip->ref625mv_channel = pdata->bms_cdata.ref625mv_channel;
1449 chip->ref1p25v_channel = pdata->bms_cdata.ref1p25v_channel;
Abhijeet Dharmapurikare922bbb2011-09-01 13:05:06 -07001450 chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
Abhijeet Dharmapurikarfa77f1a2011-06-27 21:11:51 -07001451 chip->revision = pm8xxx_get_revision(chip->dev->parent);
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -07001452 INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
Abhijeet Dharmapurikarc448d982011-06-28 20:48:36 -07001453
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 rc = pm8921_bms_hw_init(chip);
1455 if (rc) {
1456 pr_err("couldn't init hardware rc = %d\n", rc);
1457 goto free_chip;
1458 }
1459
1460 rc = request_irqs(chip, pdev);
1461 if (rc) {
1462 pr_err("couldn't register interrupts rc = %d\n", rc);
1463 goto free_chip;
1464 }
1465
1466 platform_set_drvdata(pdev, chip);
1467 the_chip = chip;
1468 create_debugfs_entries(chip);
1469
Abhijeet Dharmapurikarc3532222011-07-20 14:48:02 -07001470 check_initial_ocv(chip);
1471
Abhijeet Dharmapurikar76d4db92011-07-19 11:54:52 -07001472 /* enable the vbatt reading interrupts for scheduling hkadc calib */
1473 pm8921_bms_enable_irq(chip, PM8921_BMS_GOOD_OCV);
1474 pm8921_bms_enable_irq(chip, PM8921_BMS_OCV_FOR_R);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 return 0;
1476
1477free_chip:
1478 kfree(chip);
1479 return rc;
1480}
1481
1482static int __devexit pm8921_bms_remove(struct platform_device *pdev)
1483{
1484 struct pm8921_bms_chip *chip = platform_get_drvdata(pdev);
1485
1486 free_irqs(chip);
1487 platform_set_drvdata(pdev, NULL);
1488 the_chip = NULL;
1489 kfree(chip);
1490 return 0;
1491}
1492
1493static struct platform_driver pm8921_bms_driver = {
1494 .probe = pm8921_bms_probe,
1495 .remove = __devexit_p(pm8921_bms_remove),
1496 .driver = {
1497 .name = PM8921_BMS_DEV_NAME,
1498 .owner = THIS_MODULE,
1499 },
1500};
1501
1502static int __init pm8921_bms_init(void)
1503{
1504 return platform_driver_register(&pm8921_bms_driver);
1505}
1506
1507static void __exit pm8921_bms_exit(void)
1508{
1509 platform_driver_unregister(&pm8921_bms_driver);
1510}
1511
1512late_initcall(pm8921_bms_init);
1513module_exit(pm8921_bms_exit);
1514
1515MODULE_LICENSE("GPL v2");
1516MODULE_DESCRIPTION("PMIC8921 bms driver");
1517MODULE_VERSION("1.0");
1518MODULE_ALIAS("platform:" PM8921_BMS_DEV_NAME);