diff options
author | Johan Palsson <johan.palsson@stericsson.com> | 2011-03-05 05:46:37 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2011-03-23 05:42:04 -0400 |
commit | 586f3318adceee4857e82cafc3610070368754e3 (patch) | |
tree | bf770232e1c16fb865eb8b230603b55c0a77634c /drivers/mfd/ab8500-gpadc.c | |
parent | 633e0fa59072f5d78227191b212cb12ad3d21902 (diff) |
mfd: Calibrate ab8500 gpadc using OTP values
The GPADC found in the AB8500 needs to be calibrated to work
properly. This is done by writing a number of special OTP
(one-time-programmable) registers at production. This patch
makes sure that these values are used to calibrate the returned
value from the GPADC so that it is correct.
Signed-off-by: Johan Palsson <johan.palsson@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/ab8500-gpadc.c')
-rw-r--r-- | drivers/mfd/ab8500-gpadc.c | 286 |
1 files changed, 281 insertions, 5 deletions
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index b5b75b74e86c..a70201a74729 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * License Terms: GNU General Public License v2 | 4 | * License Terms: GNU General Public License v2 |
5 | * Author: Arun R Murthy <arun.murthy@stericsson.com> | 5 | * Author: Arun R Murthy <arun.murthy@stericsson.com> |
6 | * Author: Daniel Willerud <daniel.willerud@stericsson.com> | 6 | * Author: Daniel Willerud <daniel.willerud@stericsson.com> |
7 | * Author: Johan Palsson <johan.palsson@stericsson.com> | ||
7 | */ | 8 | */ |
8 | #include <linux/init.h> | 9 | #include <linux/init.h> |
9 | #include <linux/module.h> | 10 | #include <linux/module.h> |
@@ -36,6 +37,18 @@ | |||
36 | #define AB8500_GPADC_AUTODATAH_REG 0x08 | 37 | #define AB8500_GPADC_AUTODATAH_REG 0x08 |
37 | #define AB8500_GPADC_MUX_CTRL_REG 0x09 | 38 | #define AB8500_GPADC_MUX_CTRL_REG 0x09 |
38 | 39 | ||
40 | /* | ||
41 | * OTP register offsets | ||
42 | * Bank : 0x15 | ||
43 | */ | ||
44 | #define AB8500_GPADC_CAL_1 0x0F | ||
45 | #define AB8500_GPADC_CAL_2 0x10 | ||
46 | #define AB8500_GPADC_CAL_3 0x11 | ||
47 | #define AB8500_GPADC_CAL_4 0x12 | ||
48 | #define AB8500_GPADC_CAL_5 0x13 | ||
49 | #define AB8500_GPADC_CAL_6 0x14 | ||
50 | #define AB8500_GPADC_CAL_7 0x15 | ||
51 | |||
39 | /* gpadc constants */ | 52 | /* gpadc constants */ |
40 | #define EN_VINTCORE12 0x04 | 53 | #define EN_VINTCORE12 0x04 |
41 | #define EN_VTVOUT 0x02 | 54 | #define EN_VTVOUT 0x02 |
@@ -47,8 +60,46 @@ | |||
47 | #define DIS_ZERO 0x00 | 60 | #define DIS_ZERO 0x00 |
48 | #define GPADC_BUSY 0x01 | 61 | #define GPADC_BUSY 0x01 |
49 | 62 | ||
63 | /* GPADC constants from AB8500 spec, UM0836 */ | ||
64 | #define ADC_RESOLUTION 1024 | ||
65 | #define ADC_CH_BTEMP_MIN 0 | ||
66 | #define ADC_CH_BTEMP_MAX 1350 | ||
67 | #define ADC_CH_DIETEMP_MIN 0 | ||
68 | #define ADC_CH_DIETEMP_MAX 1350 | ||
69 | #define ADC_CH_CHG_V_MIN 0 | ||
70 | #define ADC_CH_CHG_V_MAX 20030 | ||
71 | #define ADC_CH_ACCDET2_MIN 0 | ||
72 | #define ADC_CH_ACCDET2_MAX 2500 | ||
73 | #define ADC_CH_VBAT_MIN 2300 | ||
74 | #define ADC_CH_VBAT_MAX 4800 | ||
75 | #define ADC_CH_CHG_I_MIN 0 | ||
76 | #define ADC_CH_CHG_I_MAX 1500 | ||
77 | #define ADC_CH_BKBAT_MIN 0 | ||
78 | #define ADC_CH_BKBAT_MAX 3200 | ||
79 | |||
80 | /* This is used to not lose precision when dividing to get gain and offset */ | ||
81 | #define CALIB_SCALE 1000 | ||
82 | |||
83 | enum cal_channels { | ||
84 | ADC_INPUT_VMAIN = 0, | ||
85 | ADC_INPUT_BTEMP, | ||
86 | ADC_INPUT_VBAT, | ||
87 | NBR_CAL_INPUTS, | ||
88 | }; | ||
89 | |||
90 | /** | ||
91 | * struct adc_cal_data - Table for storing gain and offset for the calibrated | ||
92 | * ADC channels | ||
93 | * @gain: Gain of the ADC channel | ||
94 | * @offset: Offset of the ADC channel | ||
95 | */ | ||
96 | struct adc_cal_data { | ||
97 | u64 gain; | ||
98 | u64 offset; | ||
99 | }; | ||
100 | |||
50 | /** | 101 | /** |
51 | * struct ab8500_gpadc - ab8500 GPADC device information | 102 | * struct ab8500_gpadc - AB8500 GPADC device information |
52 | * @dev: pointer to the struct device | 103 | * @dev: pointer to the struct device |
53 | * @node: a list of AB8500 GPADCs, hence prepared for | 104 | * @node: a list of AB8500 GPADCs, hence prepared for |
54 | reentrance | 105 | reentrance |
@@ -57,6 +108,7 @@ | |||
57 | * @ab8500_gpadc_lock: structure of type mutex | 108 | * @ab8500_gpadc_lock: structure of type mutex |
58 | * @regu: pointer to the struct regulator | 109 | * @regu: pointer to the struct regulator |
59 | * @irq: interrupt number that is used by gpadc | 110 | * @irq: interrupt number that is used by gpadc |
111 | * @cal_data array of ADC calibration data structs | ||
60 | */ | 112 | */ |
61 | struct ab8500_gpadc { | 113 | struct ab8500_gpadc { |
62 | struct device *dev; | 114 | struct device *dev; |
@@ -65,6 +117,7 @@ struct ab8500_gpadc { | |||
65 | struct mutex ab8500_gpadc_lock; | 117 | struct mutex ab8500_gpadc_lock; |
66 | struct regulator *regu; | 118 | struct regulator *regu; |
67 | int irq; | 119 | int irq; |
120 | struct adc_cal_data cal_data[NBR_CAL_INPUTS]; | ||
68 | }; | 121 | }; |
69 | 122 | ||
70 | static LIST_HEAD(ab8500_gpadc_list); | 123 | static LIST_HEAD(ab8500_gpadc_list); |
@@ -86,13 +139,102 @@ struct ab8500_gpadc *ab8500_gpadc_get(char *name) | |||
86 | } | 139 | } |
87 | EXPORT_SYMBOL(ab8500_gpadc_get); | 140 | EXPORT_SYMBOL(ab8500_gpadc_get); |
88 | 141 | ||
142 | static int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 input, | ||
143 | int ad_value) | ||
144 | { | ||
145 | int res; | ||
146 | |||
147 | switch (input) { | ||
148 | case MAIN_CHARGER_V: | ||
149 | /* For some reason we don't have calibrated data */ | ||
150 | if (!gpadc->cal_data[ADC_INPUT_VMAIN].gain) { | ||
151 | res = ADC_CH_CHG_V_MIN + (ADC_CH_CHG_V_MAX - | ||
152 | ADC_CH_CHG_V_MIN) * ad_value / | ||
153 | ADC_RESOLUTION; | ||
154 | break; | ||
155 | } | ||
156 | /* Here we can use the calibrated data */ | ||
157 | res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VMAIN].gain + | ||
158 | gpadc->cal_data[ADC_INPUT_VMAIN].offset) / CALIB_SCALE; | ||
159 | break; | ||
160 | |||
161 | case BAT_CTRL: | ||
162 | case BTEMP_BALL: | ||
163 | case ACC_DETECT1: | ||
164 | case ADC_AUX1: | ||
165 | case ADC_AUX2: | ||
166 | /* For some reason we don't have calibrated data */ | ||
167 | if (!gpadc->cal_data[ADC_INPUT_BTEMP].gain) { | ||
168 | res = ADC_CH_BTEMP_MIN + (ADC_CH_BTEMP_MAX - | ||
169 | ADC_CH_BTEMP_MIN) * ad_value / | ||
170 | ADC_RESOLUTION; | ||
171 | break; | ||
172 | } | ||
173 | /* Here we can use the calibrated data */ | ||
174 | res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_BTEMP].gain + | ||
175 | gpadc->cal_data[ADC_INPUT_BTEMP].offset) / CALIB_SCALE; | ||
176 | break; | ||
177 | |||
178 | case MAIN_BAT_V: | ||
179 | /* For some reason we don't have calibrated data */ | ||
180 | if (!gpadc->cal_data[ADC_INPUT_VBAT].gain) { | ||
181 | res = ADC_CH_VBAT_MIN + (ADC_CH_VBAT_MAX - | ||
182 | ADC_CH_VBAT_MIN) * ad_value / | ||
183 | ADC_RESOLUTION; | ||
184 | break; | ||
185 | } | ||
186 | /* Here we can use the calibrated data */ | ||
187 | res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VBAT].gain + | ||
188 | gpadc->cal_data[ADC_INPUT_VBAT].offset) / CALIB_SCALE; | ||
189 | break; | ||
190 | |||
191 | case DIE_TEMP: | ||
192 | res = ADC_CH_DIETEMP_MIN + | ||
193 | (ADC_CH_DIETEMP_MAX - ADC_CH_DIETEMP_MIN) * ad_value / | ||
194 | ADC_RESOLUTION; | ||
195 | break; | ||
196 | |||
197 | case ACC_DETECT2: | ||
198 | res = ADC_CH_ACCDET2_MIN + | ||
199 | (ADC_CH_ACCDET2_MAX - ADC_CH_ACCDET2_MIN) * ad_value / | ||
200 | ADC_RESOLUTION; | ||
201 | break; | ||
202 | |||
203 | case VBUS_V: | ||
204 | res = ADC_CH_CHG_V_MIN + | ||
205 | (ADC_CH_CHG_V_MAX - ADC_CH_CHG_V_MIN) * ad_value / | ||
206 | ADC_RESOLUTION; | ||
207 | break; | ||
208 | |||
209 | case MAIN_CHARGER_C: | ||
210 | case USB_CHARGER_C: | ||
211 | res = ADC_CH_CHG_I_MIN + | ||
212 | (ADC_CH_CHG_I_MAX - ADC_CH_CHG_I_MIN) * ad_value / | ||
213 | ADC_RESOLUTION; | ||
214 | break; | ||
215 | |||
216 | case BK_BAT_V: | ||
217 | res = ADC_CH_BKBAT_MIN + | ||
218 | (ADC_CH_BKBAT_MAX - ADC_CH_BKBAT_MIN) * ad_value / | ||
219 | ADC_RESOLUTION; | ||
220 | break; | ||
221 | |||
222 | default: | ||
223 | dev_err(gpadc->dev, | ||
224 | "unknown channel, not possible to convert\n"); | ||
225 | res = -EINVAL; | ||
226 | break; | ||
227 | |||
228 | } | ||
229 | return res; | ||
230 | } | ||
231 | |||
89 | /** | 232 | /** |
90 | * ab8500_gpadc_convert() - gpadc conversion | 233 | * ab8500_gpadc_convert() - gpadc conversion |
91 | * @input: analog input to be converted to digital data | 234 | * @input: analog input to be converted to digital data |
92 | * | 235 | * |
93 | * This function converts the selected analog i/p to digital | 236 | * This function converts the selected analog i/p to digital |
94 | * data. Thereafter calibration has to be made to obtain the | 237 | * data. |
95 | * data in the required quantity measurement. | ||
96 | */ | 238 | */ |
97 | int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) | 239 | int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) |
98 | { | 240 | { |
@@ -189,7 +331,8 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) | |||
189 | /* Disable VTVout LDO this is required for GPADC */ | 331 | /* Disable VTVout LDO this is required for GPADC */ |
190 | regulator_disable(gpadc->regu); | 332 | regulator_disable(gpadc->regu); |
191 | mutex_unlock(&gpadc->ab8500_gpadc_lock); | 333 | mutex_unlock(&gpadc->ab8500_gpadc_lock); |
192 | return data; | 334 | ret = ab8500_gpadc_ad_to_voltage(gpadc, input, data); |
335 | return ret; | ||
193 | 336 | ||
194 | out: | 337 | out: |
195 | /* | 338 | /* |
@@ -227,6 +370,138 @@ static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc) | |||
227 | return IRQ_HANDLED; | 370 | return IRQ_HANDLED; |
228 | } | 371 | } |
229 | 372 | ||
373 | static int otp_cal_regs[] = { | ||
374 | AB8500_GPADC_CAL_1, | ||
375 | AB8500_GPADC_CAL_2, | ||
376 | AB8500_GPADC_CAL_3, | ||
377 | AB8500_GPADC_CAL_4, | ||
378 | AB8500_GPADC_CAL_5, | ||
379 | AB8500_GPADC_CAL_6, | ||
380 | AB8500_GPADC_CAL_7, | ||
381 | }; | ||
382 | |||
383 | static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) | ||
384 | { | ||
385 | int i; | ||
386 | int ret[ARRAY_SIZE(otp_cal_regs)]; | ||
387 | u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)]; | ||
388 | |||
389 | int vmain_high, vmain_low; | ||
390 | int btemp_high, btemp_low; | ||
391 | int vbat_high, vbat_low; | ||
392 | |||
393 | /* First we read all OTP registers and store the error code */ | ||
394 | for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) { | ||
395 | ret[i] = abx500_get_register_interruptible(gpadc->dev, | ||
396 | AB8500_OTP_EMUL, otp_cal_regs[i], &gpadc_cal[i]); | ||
397 | if (ret[i] < 0) | ||
398 | dev_err(gpadc->dev, "%s: read otp reg 0x%02x failed\n", | ||
399 | __func__, otp_cal_regs[i]); | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * The ADC calibration data is stored in OTP registers. | ||
404 | * The layout of the calibration data is outlined below and a more | ||
405 | * detailed description can be found in UM0836 | ||
406 | * | ||
407 | * vm_h/l = vmain_high/low | ||
408 | * bt_h/l = btemp_high/low | ||
409 | * vb_h/l = vbat_high/low | ||
410 | * | ||
411 | * Data bits: | ||
412 | * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||
413 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
414 | * | | vm_h9 | vm_h8 | ||
415 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
416 | * | | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2 | ||
417 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
418 | * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9 | ||
419 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
420 | * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1 | ||
421 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
422 | * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8 | ||
423 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
424 | * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0 | ||
425 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
426 | * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 | | ||
427 | * |.......|.......|.......|.......|.......|.......|.......|....... | ||
428 | * | ||
429 | * | ||
430 | * Ideal output ADC codes corresponding to injected input voltages | ||
431 | * during manufacturing is: | ||
432 | * | ||
433 | * vmain_high: Vin = 19500mV / ADC ideal code = 997 | ||
434 | * vmain_low: Vin = 315mV / ADC ideal code = 16 | ||
435 | * btemp_high: Vin = 1300mV / ADC ideal code = 985 | ||
436 | * btemp_low: Vin = 21mV / ADC ideal code = 16 | ||
437 | * vbat_high: Vin = 4700mV / ADC ideal code = 982 | ||
438 | * vbat_low: Vin = 2380mV / ADC ideal code = 33 | ||
439 | */ | ||
440 | |||
441 | /* Calculate gain and offset for VMAIN if all reads succeeded */ | ||
442 | if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) { | ||
443 | vmain_high = (((gpadc_cal[0] & 0x03) << 8) | | ||
444 | ((gpadc_cal[1] & 0x3F) << 2) | | ||
445 | ((gpadc_cal[2] & 0xC0) >> 6)); | ||
446 | |||
447 | vmain_low = ((gpadc_cal[2] & 0x3E) >> 1); | ||
448 | |||
449 | gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE * | ||
450 | (19500 - 315) / (vmain_high - vmain_low); | ||
451 | |||
452 | gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * 19500 - | ||
453 | (CALIB_SCALE * (19500 - 315) / | ||
454 | (vmain_high - vmain_low)) * vmain_high; | ||
455 | } else { | ||
456 | gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0; | ||
457 | } | ||
458 | |||
459 | /* Calculate gain and offset for BTEMP if all reads succeeded */ | ||
460 | if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) { | ||
461 | btemp_high = (((gpadc_cal[2] & 0x01) << 9) | | ||
462 | (gpadc_cal[3] << 1) | | ||
463 | ((gpadc_cal[4] & 0x80) >> 7)); | ||
464 | |||
465 | btemp_low = ((gpadc_cal[4] & 0x7C) >> 2); | ||
466 | |||
467 | gpadc->cal_data[ADC_INPUT_BTEMP].gain = | ||
468 | CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low); | ||
469 | |||
470 | gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 - | ||
471 | (CALIB_SCALE * (1300 - 21) / | ||
472 | (btemp_high - btemp_low)) * btemp_high; | ||
473 | } else { | ||
474 | gpadc->cal_data[ADC_INPUT_BTEMP].gain = 0; | ||
475 | } | ||
476 | |||
477 | /* Calculate gain and offset for VBAT if all reads succeeded */ | ||
478 | if (!(ret[4] < 0 || ret[5] < 0 || ret[6] < 0)) { | ||
479 | vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]); | ||
480 | vbat_low = ((gpadc_cal[6] & 0xFC) >> 2); | ||
481 | |||
482 | gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE * | ||
483 | (4700 - 2380) / (vbat_high - vbat_low); | ||
484 | |||
485 | gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 - | ||
486 | (CALIB_SCALE * (4700 - 2380) / | ||
487 | (vbat_high - vbat_low)) * vbat_high; | ||
488 | } else { | ||
489 | gpadc->cal_data[ADC_INPUT_VBAT].gain = 0; | ||
490 | } | ||
491 | |||
492 | dev_dbg(gpadc->dev, "VMAIN gain %llu offset %llu\n", | ||
493 | gpadc->cal_data[ADC_INPUT_VMAIN].gain, | ||
494 | gpadc->cal_data[ADC_INPUT_VMAIN].offset); | ||
495 | |||
496 | dev_dbg(gpadc->dev, "BTEMP gain %llu offset %llu\n", | ||
497 | gpadc->cal_data[ADC_INPUT_BTEMP].gain, | ||
498 | gpadc->cal_data[ADC_INPUT_BTEMP].offset); | ||
499 | |||
500 | dev_dbg(gpadc->dev, "VBAT gain %llu offset %llu\n", | ||
501 | gpadc->cal_data[ADC_INPUT_VBAT].gain, | ||
502 | gpadc->cal_data[ADC_INPUT_VBAT].offset); | ||
503 | } | ||
504 | |||
230 | static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) | 505 | static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) |
231 | { | 506 | { |
232 | int ret = 0; | 507 | int ret = 0; |
@@ -269,6 +544,7 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) | |||
269 | dev_err(gpadc->dev, "failed to get vtvout LDO\n"); | 544 | dev_err(gpadc->dev, "failed to get vtvout LDO\n"); |
270 | goto fail_irq; | 545 | goto fail_irq; |
271 | } | 546 | } |
547 | ab8500_gpadc_read_calibration_data(gpadc); | ||
272 | list_add_tail(&gpadc->node, &ab8500_gpadc_list); | 548 | list_add_tail(&gpadc->node, &ab8500_gpadc_list); |
273 | dev_dbg(gpadc->dev, "probe success\n"); | 549 | dev_dbg(gpadc->dev, "probe success\n"); |
274 | return 0; | 550 | return 0; |
@@ -318,6 +594,6 @@ subsys_initcall_sync(ab8500_gpadc_init); | |||
318 | module_exit(ab8500_gpadc_exit); | 594 | module_exit(ab8500_gpadc_exit); |
319 | 595 | ||
320 | MODULE_LICENSE("GPL v2"); | 596 | MODULE_LICENSE("GPL v2"); |
321 | MODULE_AUTHOR("Arun R Murthy, Daniel Willerud"); | 597 | MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson"); |
322 | MODULE_ALIAS("platform:ab8500_gpadc"); | 598 | MODULE_ALIAS("platform:ab8500_gpadc"); |
323 | MODULE_DESCRIPTION("AB8500 GPADC driver"); | 599 | MODULE_DESCRIPTION("AB8500 GPADC driver"); |