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 10 #include "qcom-vadc-common.h" 11 12 /* Voltage to temperature */ 13 static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = { 14 {1758, -40}, 15 {1742, -35}, 16 {1719, -30}, 17 {1691, -25}, 18 {1654, -20}, 19 {1608, -15}, 20 {1551, -10}, 21 {1483, -5}, 22 {1404, 0}, 23 {1315, 5}, 24 {1218, 10}, 25 {1114, 15}, 26 {1007, 20}, 27 {900, 25}, 28 {795, 30}, 29 {696, 35}, 30 {605, 40}, 31 {522, 45}, 32 {448, 50}, 33 {383, 55}, 34 {327, 60}, 35 {278, 65}, 36 {237, 70}, 37 {202, 75}, 38 {172, 80}, 39 {146, 85}, 40 {125, 90}, 41 {107, 95}, 42 {92, 100}, 43 {79, 105}, 44 {68, 110}, 45 {59, 115}, 46 {51, 120}, 47 {44, 125} 48 }; 49 50 /* 51 * Voltage to temperature table for 100k pull up for NTCG104EF104 with 52 * 1.875V reference. 53 */ 54 static 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 91 static 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); 95 static 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); 99 static 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); 103 static 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); 107 static 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 112 static 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 121 static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts, 122 u32 tablesize, s32 input, int *output) 123 { 124 bool descending = 1; 125 u32 i = 0; 126 127 if (!pts) 128 return -EINVAL; 129 130 /* Check if table is descending or ascending */ 131 if (tablesize > 1) { 132 if (pts[0].x < pts[1].x) 133 descending = 0; 134 } 135 136 while (i < tablesize) { 137 if ((descending) && (pts[i].x < input)) { 138 /* table entry is less than measured*/ 139 /* value and table is descending, stop */ 140 break; 141 } else if ((!descending) && 142 (pts[i].x > input)) { 143 /* table entry is greater than measured*/ 144 /*value and table is ascending, stop */ 145 break; 146 } 147 i++; 148 } 149 150 if (i == 0) { 151 *output = pts[0].y; 152 } else if (i == tablesize) { 153 *output = pts[tablesize - 1].y; 154 } else { 155 /* result is between search_index and search_index-1 */ 156 /* interpolate linearly */ 157 *output = (((s32)((pts[i].y - pts[i - 1].y) * 158 (input - pts[i - 1].x)) / 159 (pts[i].x - pts[i - 1].x)) + 160 pts[i - 1].y); 161 } 162 163 return 0; 164 } 165 166 static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph, 167 u16 adc_code, 168 bool absolute, 169 s64 *scale_voltage) 170 { 171 *scale_voltage = (adc_code - calib_graph->gnd); 172 *scale_voltage *= calib_graph->dx; 173 *scale_voltage = div64_s64(*scale_voltage, calib_graph->dy); 174 if (absolute) 175 *scale_voltage += calib_graph->dx; 176 177 if (*scale_voltage < 0) 178 *scale_voltage = 0; 179 } 180 181 static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph, 182 const struct vadc_prescale_ratio *prescale, 183 bool absolute, u16 adc_code, 184 int *result_uv) 185 { 186 s64 voltage = 0, result = 0; 187 188 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); 189 190 voltage = voltage * prescale->den; 191 result = div64_s64(voltage, prescale->num); 192 *result_uv = result; 193 194 return 0; 195 } 196 197 static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph, 198 const struct vadc_prescale_ratio *prescale, 199 bool absolute, u16 adc_code, 200 int *result_mdec) 201 { 202 s64 voltage = 0; 203 int ret; 204 205 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); 206 207 if (absolute) 208 voltage = div64_s64(voltage, 1000); 209 210 ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb, 211 ARRAY_SIZE(adcmap_100k_104ef_104fb), 212 voltage, result_mdec); 213 if (ret) 214 return ret; 215 216 *result_mdec *= 1000; 217 218 return 0; 219 } 220 221 static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph, 222 const struct vadc_prescale_ratio *prescale, 223 bool absolute, 224 u16 adc_code, int *result_mdec) 225 { 226 s64 voltage = 0; 227 u64 temp; /* Temporary variable for do_div */ 228 229 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage); 230 231 if (voltage > 0) { 232 temp = voltage * prescale->den; 233 do_div(temp, prescale->num * 2); 234 voltage = temp; 235 } else { 236 voltage = 0; 237 } 238 239 voltage -= KELVINMIL_CELSIUSMIL; 240 *result_mdec = 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 -= KELVINMIL_CELSIUSMIL; 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