aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc/qcom-vadc-common.c
diff options
context:
space:
mode:
authorSiddartha Mohanadoss <smohanad@codeaurora.org>2018-08-02 21:43:53 -0400
committerJonathan Cameron <Jonathan.Cameron@huawei.com>2018-08-18 13:11:43 -0400
commite13d757279bbc59776c8435fb94e54b5a58bdd0b (patch)
tree82a059a180b0dae280fe34239114a15ee4f6be18 /drivers/iio/adc/qcom-vadc-common.c
parent2fca585502716c25c52ad4fe54207f80762bc7b4 (diff)
iio: adc: Add QCOM SPMI PMIC5 ADC driver
This patch adds support for QCOM SPMI PMIC5 family of ADC driver that supports hardware based offset and gain compensation. The ADC peripheral can measure both voltage and current channels whose input signal is connected to the PMIC ADC AMUX. The register set and configuration has been refreshed compared to the prior QCOM PMIC ADC family. Register ADC5 as part of the IIO framework. Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Diffstat (limited to 'drivers/iio/adc/qcom-vadc-common.c')
-rw-r--r--drivers/iio/adc/qcom-vadc-common.c189
1 files changed, 184 insertions, 5 deletions
diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c
index fe3d7826783c..dcd7fb5b9fb2 100644
--- a/drivers/iio/adc/qcom-vadc-common.c
+++ b/drivers/iio/adc/qcom-vadc-common.c
@@ -47,8 +47,79 @@ static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
47 {44, 125} 47 {44, 125}
48}; 48};
49 49
50/*
51 * Voltage to temperature table for 100k pull up for NTCG104EF104 with
52 * 1.875V reference.
53 */
54static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
55 { 1831, -40000 },
56 { 1814, -35000 },
57 { 1791, -30000 },
58 { 1761, -25000 },
59 { 1723, -20000 },
60 { 1675, -15000 },
61 { 1616, -10000 },
62 { 1545, -5000 },
63 { 1463, 0 },
64 { 1370, 5000 },
65 { 1268, 10000 },
66 { 1160, 15000 },
67 { 1049, 20000 },
68 { 937, 25000 },
69 { 828, 30000 },
70 { 726, 35000 },
71 { 630, 40000 },
72 { 544, 45000 },
73 { 467, 50000 },
74 { 399, 55000 },
75 { 340, 60000 },
76 { 290, 65000 },
77 { 247, 70000 },
78 { 209, 75000 },
79 { 179, 80000 },
80 { 153, 85000 },
81 { 130, 90000 },
82 { 112, 95000 },
83 { 96, 100000 },
84 { 82, 105000 },
85 { 71, 110000 },
86 { 62, 115000 },
87 { 53, 120000 },
88 { 46, 125000 },
89};
90
91static int qcom_vadc_scale_hw_calib_volt(
92 const struct vadc_prescale_ratio *prescale,
93 const struct adc5_data *data,
94 u16 adc_code, int *result_uv);
95static int qcom_vadc_scale_hw_calib_therm(
96 const struct vadc_prescale_ratio *prescale,
97 const struct adc5_data *data,
98 u16 adc_code, int *result_mdec);
99static int qcom_vadc_scale_hw_smb_temp(
100 const struct vadc_prescale_ratio *prescale,
101 const struct adc5_data *data,
102 u16 adc_code, int *result_mdec);
103static int qcom_vadc_scale_hw_chg5_temp(
104 const struct vadc_prescale_ratio *prescale,
105 const struct adc5_data *data,
106 u16 adc_code, int *result_mdec);
107static int qcom_vadc_scale_hw_calib_die_temp(
108 const struct vadc_prescale_ratio *prescale,
109 const struct adc5_data *data,
110 u16 adc_code, int *result_mdec);
111
112static struct qcom_adc5_scale_type scale_adc5_fn[] = {
113 [SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt},
114 [SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm},
115 [SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm},
116 [SCALE_HW_CALIB_PMIC_THERM] = {qcom_vadc_scale_hw_calib_die_temp},
117 [SCALE_HW_CALIB_PM5_CHG_TEMP] = {qcom_vadc_scale_hw_chg5_temp},
118 [SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp},
119};
120
50static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts, 121static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
51 u32 tablesize, s32 input, s64 *output) 122 u32 tablesize, s32 input, int *output)
52{ 123{
53 bool descending = 1; 124 bool descending = 1;
54 u32 i = 0; 125 u32 i = 0;
@@ -128,7 +199,7 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
128 bool absolute, u16 adc_code, 199 bool absolute, u16 adc_code,
129 int *result_mdec) 200 int *result_mdec)
130{ 201{
131 s64 voltage = 0, result = 0; 202 s64 voltage = 0;
132 int ret; 203 int ret;
133 204
134 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); 205 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
@@ -138,12 +209,11 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
138 209
139 ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb, 210 ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
140 ARRAY_SIZE(adcmap_100k_104ef_104fb), 211 ARRAY_SIZE(adcmap_100k_104ef_104fb),
141 voltage, &result); 212 voltage, result_mdec);
142 if (ret) 213 if (ret)
143 return ret; 214 return ret;
144 215
145 result *= 1000; 216 *result_mdec *= 1000;
146 *result_mdec = result;
147 217
148 return 0; 218 return 0;
149} 219}
@@ -191,6 +261,99 @@ static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
191 return 0; 261 return 0;
192} 262}
193 263
264static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
265 const struct vadc_prescale_ratio *prescale,
266 const struct adc5_data *data,
267 unsigned int factor)
268{
269 s64 voltage, temp, adc_vdd_ref_mv = 1875;
270
271 /*
272 * The normal data range is between 0V to 1.875V. On cases where
273 * we read low voltage values, the ADC code can go beyond the
274 * range and the scale result is incorrect so we clamp the values
275 * for the cases where the code represents a value below 0V
276 */
277 if (adc_code > VADC5_MAX_CODE)
278 adc_code = 0;
279
280 /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
281 voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
282 voltage = div64_s64(voltage, data->full_scale_code_volt);
283 if (voltage > 0) {
284 voltage *= prescale->den;
285 temp = prescale->num * factor;
286 voltage = div64_s64(voltage, temp);
287 } else {
288 voltage = 0;
289 }
290
291 return (int) voltage;
292}
293
294static int qcom_vadc_scale_hw_calib_volt(
295 const struct vadc_prescale_ratio *prescale,
296 const struct adc5_data *data,
297 u16 adc_code, int *result_uv)
298{
299 *result_uv = qcom_vadc_scale_code_voltage_factor(adc_code,
300 prescale, data, 1);
301
302 return 0;
303}
304
305static int qcom_vadc_scale_hw_calib_therm(
306 const struct vadc_prescale_ratio *prescale,
307 const struct adc5_data *data,
308 u16 adc_code, int *result_mdec)
309{
310 int voltage;
311
312 voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
313 prescale, data, 1000);
314
315 /* Map voltage to temperature from look-up table */
316 return qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
317 ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
318 voltage, result_mdec);
319}
320
321static int qcom_vadc_scale_hw_calib_die_temp(
322 const struct vadc_prescale_ratio *prescale,
323 const struct adc5_data *data,
324 u16 adc_code, int *result_mdec)
325{
326 *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
327 prescale, data, 2);
328 *result_mdec -= KELVINMIL_CELSIUSMIL;
329
330 return 0;
331}
332
333static int qcom_vadc_scale_hw_smb_temp(
334 const struct vadc_prescale_ratio *prescale,
335 const struct adc5_data *data,
336 u16 adc_code, int *result_mdec)
337{
338 *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code * 100,
339 prescale, data, PMIC5_SMB_TEMP_SCALE_FACTOR);
340 *result_mdec = PMIC5_SMB_TEMP_CONSTANT - *result_mdec;
341
342 return 0;
343}
344
345static int qcom_vadc_scale_hw_chg5_temp(
346 const struct vadc_prescale_ratio *prescale,
347 const struct adc5_data *data,
348 u16 adc_code, int *result_mdec)
349{
350 *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
351 prescale, data, 4);
352 *result_mdec = PMIC5_CHG_TEMP_SCALE_FACTOR - *result_mdec;
353
354 return 0;
355}
356
194int qcom_vadc_scale(enum vadc_scale_fn_type scaletype, 357int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
195 const struct vadc_linear_graph *calib_graph, 358 const struct vadc_linear_graph *calib_graph,
196 const struct vadc_prescale_ratio *prescale, 359 const struct vadc_prescale_ratio *prescale,
@@ -221,6 +384,22 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
221} 384}
222EXPORT_SYMBOL(qcom_vadc_scale); 385EXPORT_SYMBOL(qcom_vadc_scale);
223 386
387int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
388 const struct vadc_prescale_ratio *prescale,
389 const struct adc5_data *data,
390 u16 adc_code, int *result)
391{
392 if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
393 scaletype < SCALE_HW_CALIB_INVALID)) {
394 pr_err("Invalid scale type %d\n", scaletype);
395 return -EINVAL;
396 }
397
398 return scale_adc5_fn[scaletype].scale_fn(prescale, data,
399 adc_code, result);
400}
401EXPORT_SYMBOL(qcom_adc5_hw_scale);
402
224int qcom_vadc_decimation_from_dt(u32 value) 403int qcom_vadc_decimation_from_dt(u32 value)
225{ 404{
226 if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN || 405 if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||