1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/bug.h> 3 #include <linux/kernel.h> 4 #include <linux/bitops.h> 5 #include <linux/math64.h> 6 #include <linux/log2.h> 7 #include <linux/err.h> 8 #include <linux/module.h> 9 #include <linux/units.h> 10 11 #include "qcom-vadc-common.h" 12 13 /* Voltage to temperature */ 14 static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = { 15 {1758, -40}, 16 {1742, -35}, 17 {1719, -30}, 18 {1691, -25}, 19 {1654, -20}, 20 {1608, -15}, 21 {1551, -10}, 22 {1483, -5}, 23 {1404, 0}, 24 {1315, 5}, 25 {1218, 10}, 26 {1114, 15}, 27 {1007, 20}, 28 {900, 25}, 29 {795, 30}, 30 {696, 35}, 31 {605, 40}, 32 {522, 45}, 33 {448, 50}, 34 {383, 55}, 35 {327, 60}, 36 {278, 65}, 37 {237, 70}, 38 {202, 75}, 39 {172, 80}, 40 {146, 85}, 41 {125, 90}, 42 {107, 95}, 43 {92, 100}, 44 {79, 105}, 45 {68, 110}, 46 {59, 115}, 47 {51, 120}, 48 {44, 125} 49 }; 50 51 /* 52 * Voltage to temperature table for 100k pull up for NTCG104EF104 with 53 * 1.875V reference. 54 */ 55 static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = { 56 { 1831, -40000 }, 57 { 1814, -35000 }, 58 { 1791, -30000 }, 59 { 1761, -25000 }, 60 { 1723, -20000 }, 61 { 1675, -15000 }, 62 { 1616, -10000 }, 63 { 1545, -5000 }, 64 { 1463, 0 }, 65 { 1370, 5000 }, 66 { 1268, 10000 }, 67 { 1160, 15000 }, 68 { 1049, 20000 }, 69 { 937, 25000 }, 70 { 828, 30000 }, 71 { 726, 35000 }, 72 { 630, 40000 }, 73 { 544, 45000 }, 74 { 467, 50000 }, 75 { 399, 55000 }, 76 { 340, 60000 }, 77 { 290, 65000 }, 78 { 247, 70000 }, 79 { 209, 75000 }, 80 { 179, 80000 }, 81 { 153, 85000 }, 82 { 130, 90000 }, 83 { 112, 95000 }, 84 { 96, 100000 }, 85 { 82, 105000 }, 86 { 71, 110000 }, 87 { 62, 115000 }, 88 { 53, 120000 }, 89 { 46, 125000 }, 90 }; 91 92 static int qcom_vadc_scale_hw_calib_volt( 93 const struct vadc_prescale_ratio *prescale, 94 const struct adc5_data *data, 95 u16 adc_code, int *result_uv); 96 static int qcom_vadc_scale_hw_calib_therm( 97 const struct vadc_prescale_ratio *prescale, 98 const struct adc5_data *data, 99 u16 adc_code, int *result_mdec); 100 static int qcom_vadc_scale_hw_smb_temp( 101 const struct vadc_prescale_ratio *prescale, 102 const struct adc5_data *data, 103 u16 adc_code, int *result_mdec); 104 static int qcom_vadc_scale_hw_chg5_temp( 105 const struct vadc_prescale_ratio *prescale, 106 const struct adc5_data *data, 107 u16 adc_code, int *result_mdec); 108 static int qcom_vadc_scale_hw_calib_die_temp( 109 const struct vadc_prescale_ratio *prescale, 110 const struct adc5_data *data, 111 u16 adc_code, int *result_mdec); 112 113 static struct qcom_adc5_scale_type scale_adc5_fn[] = { 114 [SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt}, 115 [SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm}, 116 [SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm}, 117 [SCALE_HW_CALIB_PMIC_THERM] = {qcom_vadc_scale_hw_calib_die_temp}, 118 [SCALE_HW_CALIB_PM5_CHG_TEMP] = {qcom_vadc_scale_hw_chg5_temp}, 119 [SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp}, 120 }; 121 122 static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts, 123 u32 tablesize, s32 input, int *output) 124 { 125 bool descending = 1; 126 u32 i = 0; 127 128 if (!pts) 129 return -EINVAL; 130 131 /* Check if table is descending or ascending */ 132 if (tablesize > 1) { 133 if (pts[0].x < pts[1].x) 134 descending = 0; 135 } 136 137 while (i < tablesize) { 138 if ((descending) && (pts[i].x < input)) { 139 /* table entry is less than measured*/ 140 /* value and table is descending, stop */ 141 break; 142 } else if ((!descending) && 143 (pts[i].x > input)) { 144 /* table entry is greater than measured*/ 145 /*value and table is ascending, stop */ 146 break; 147 } 148 i++; 149 } 150 151 if (i == 0) { 152 *output = pts[0].y; 153 } else if (i == tablesize) { 154 *output = pts[tablesize - 1].y; 155 } else { 156 /* result is between search_index and search_index-1 */ 157 /* interpolate linearly */ 158 *output = (((s32)((pts[i].y - pts[i - 1].y) * 159 (input - pts[i - 1].x)) / 160 (pts[i].x - pts[i - 1].x)) + 161 pts[i - 1].y); 162 } 163 164 return 0; 165 } 166 167 static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph, 168 u16 adc_code, 169 bool absolute, 170 s64 *scale_voltage) 171 { 172 *scale_voltage = (adc_code - calib_graph->gnd); 173 *scale_voltage *= calib_graph->dx; 174 *scale_voltage = div64_s64(*scale_voltage, calib_graph->dy); 175 if (absolute) 176 *scale_voltage += calib_graph->dx; 177 178 if (*scale_voltage < 0) 179 *scale_voltage = 0; 180 } 181 182 static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph, 183 const struct vadc_prescale_ratio *prescale, 184 bool absolute, u16 adc_code, 185 int *result_uv) 186 { 187 s64 voltage = 0, result = 0; 188 189 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); 190 191 voltage = voltage * prescale->den; 192 result = div64_s64(voltage, prescale->num); 193 *result_uv = result; 194 195 return 0; 196 } 197 198 static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph, 199 const struct vadc_prescale_ratio *prescale, 200 bool absolute, u16 adc_code, 201 int *result_mdec) 202 { 203 s64 voltage = 0; 204 int ret; 205 206 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); 207 208 if (absolute) 209 voltage = div64_s64(voltage, 1000); 210 211 ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb, 212 ARRAY_SIZE(adcmap_100k_104ef_104fb), 213 voltage, result_mdec); 214 if (ret) 215 return ret; 216 217 *result_mdec *= 1000; 218 219 return 0; 220 } 221 222 static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph, 223 const struct vadc_prescale_ratio *prescale, 224 bool absolute, 225 u16 adc_code, int *result_mdec) 226 { 227 s64 voltage = 0; 228 u64 temp; /* Temporary variable for do_div */ 229 230 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); 231 232 if (voltage > 0) { 233 temp = voltage * prescale->den; 234 do_div(temp, prescale->num * 2); 235 voltage = temp; 236 } else { 237 voltage = 0; 238 } 239 240 *result_mdec = milli_kelvin_to_millicelsius(voltage); 241 242 return 0; 243 } 244 245 static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph, 246 const struct vadc_prescale_ratio *prescale, 247 bool absolute, 248 u16 adc_code, int *result_mdec) 249 { 250 s64 voltage = 0, result = 0; 251 252 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); 253 254 voltage = voltage * prescale->den; 255 voltage = div64_s64(voltage, prescale->num); 256 voltage = ((PMI_CHG_SCALE_1) * (voltage * 2)); 257 voltage = (voltage + PMI_CHG_SCALE_2); 258 result = div64_s64(voltage, 1000000); 259 *result_mdec = result; 260 261 return 0; 262 } 263 264 static 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 294 static 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 305 static 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 321 static 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 = milli_kelvin_to_millicelsius(*result_mdec); 329 330 return 0; 331 } 332 333 static 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 345 static 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 357 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype, 358 const struct vadc_linear_graph *calib_graph, 359 const struct vadc_prescale_ratio *prescale, 360 bool absolute, 361 u16 adc_code, int *result) 362 { 363 switch (scaletype) { 364 case SCALE_DEFAULT: 365 return qcom_vadc_scale_volt(calib_graph, prescale, 366 absolute, adc_code, 367 result); 368 case SCALE_THERM_100K_PULLUP: 369 case SCALE_XOTHERM: 370 return qcom_vadc_scale_therm(calib_graph, prescale, 371 absolute, adc_code, 372 result); 373 case SCALE_PMIC_THERM: 374 return qcom_vadc_scale_die_temp(calib_graph, prescale, 375 absolute, adc_code, 376 result); 377 case SCALE_PMI_CHG_TEMP: 378 return qcom_vadc_scale_chg_temp(calib_graph, prescale, 379 absolute, adc_code, 380 result); 381 default: 382 return -EINVAL; 383 } 384 } 385 EXPORT_SYMBOL(qcom_vadc_scale); 386 387 int 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 } 401 EXPORT_SYMBOL(qcom_adc5_hw_scale); 402 403 int qcom_vadc_decimation_from_dt(u32 value) 404 { 405 if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN || 406 value > VADC_DECIMATION_MAX) 407 return -EINVAL; 408 409 return __ffs64(value / VADC_DECIMATION_MIN); 410 } 411 EXPORT_SYMBOL(qcom_vadc_decimation_from_dt); 412 413 MODULE_LICENSE("GPL v2"); 414 MODULE_DESCRIPTION("Qualcomm ADC common functionality"); 415