409 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.4 */5 6#include <linux/bitfield.h>7#include <linux/nvmem-consumer.h>8#include <linux/platform_device.h>9#include "tsens.h"10 11/* ----- SROT ------ */12#define SROT_CTRL_OFF 0x000013 14/* ----- TM ------ */15#define TM_INT_EN_OFF 0x000016#define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF 0x000417#define TM_Sn_STATUS_OFF 0x003018#define TM_TRDY_OFF 0x005c19 20/* extra data for 8974 */21#define BKP_SEL 0x322#define BKP_REDUN_SEL 0xe000000023 24#define BIT_APPEND 0x325 26static struct tsens_legacy_calibration_format tsens_8916_nvmem = {27 .base_len = 7,28 .base_shift = 3,29 .sp_len = 5,30 .mode = { 0, 29, 1 },31 .invalid = { 0, 31, 1 },32 .base = { { 0, 0 }, { 1, 25 } },33 .sp = {34 { { 0, 7 }, { 0, 12 } },35 { { 0, 17 }, { 0, 22 } },36 { { 0, 27 }, { 1, 0 } },37 { { 1, 5 }, { 1, 10 } },38 { { 1, 15 }, { 1, 20 } },39 },40};41 42static struct tsens_legacy_calibration_format tsens_8974_nvmem = {43 .base_len = 8,44 .base_shift = 2,45 .sp_len = 6,46 .mode = { 1, 30 },47 .invalid = { 3, 30 },48 .base = { { 0, 0 }, { 2, 12 } },49 .sp = {50 { { 0, 8 }, { 2, 20 } },51 { { 0, 14 }, { 2, 26 } },52 { { 0, 20 }, { 3, 0 } },53 { { 0, 26 }, { 3, 6 } },54 { { 1, 0 }, { 3, 12 } },55 { { 1, 6 }, { 3, 18 } },56 { { 1, 12 }, { 3, 24 } },57 { { 1, 18 }, { 4, 0 } },58 { { 1, 24 }, { 4, 6 } },59 { { 2, 0 }, { 4, 12 } },60 { { 2, 6 }, { 4, 18 } },61 },62};63 64static struct tsens_legacy_calibration_format tsens_8974_backup_nvmem = {65 .base_len = 8,66 .base_shift = 2,67 .sp_len = 6,68 .mode = { 4, 30, 1 },69 .invalid = { 5, 30, 1 },70 .base = { { 0, 0 }, { 2, 18 } },71 .sp = {72 { { 0, 8 }, { 2, 26 } },73 { { 0, 14 }, { 3, 0 } },74 { { 0, 20 }, { 3, 6 } },75 { { 0, 26 }, { 3, 12 } },76 { { 1, 0 }, { 3, 18 } },77 { { 1, 6 }, { 3, 24, 1 } },78 { { 1, 12 }, { 4, 0, 1 } },79 { { 1, 18 }, { 4, 6, 1 } },80 { { 2, 0 }, { 4, 12, 1 } },81 { { 2, 6 }, { 4, 18, 1 } },82 { { 2, 12 }, { 4, 24, 1 } },83 },84};85 86static int calibrate_8916(struct tsens_priv *priv)87{88 u32 p1[5], p2[5];89 u32 *qfprom_cdata, *qfprom_csel;90 int mode, ret;91 92 ret = tsens_calibrate_nvmem(priv, 3);93 if (!ret)94 return 0;95 96 qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");97 if (IS_ERR(qfprom_cdata))98 return PTR_ERR(qfprom_cdata);99 100 qfprom_csel = (u32 *)qfprom_read(priv->dev, "calib_sel");101 if (IS_ERR(qfprom_csel)) {102 kfree(qfprom_cdata);103 return PTR_ERR(qfprom_csel);104 }105 106 mode = tsens_read_calibration_legacy(priv, &tsens_8916_nvmem,107 p1, p2,108 qfprom_cdata, qfprom_csel);109 110 compute_intercept_slope(priv, p1, p2, mode);111 kfree(qfprom_cdata);112 kfree(qfprom_csel);113 114 return 0;115}116 117static void fixup_8974_points(int mode, u32 *p1, u32 *p2)118{119 int i;120 121 if (mode == NO_PT_CALIB) {122 p1[0] += 2;123 p1[1] += 9;124 p1[2] += 3;125 p1[3] += 9;126 p1[4] += 5;127 p1[5] += 9;128 p1[6] += 7;129 p1[7] += 10;130 p1[8] += 8;131 p1[9] += 9;132 p1[10] += 8;133 } else {134 for (i = 0; i < 11; i++) {135 /*136 * ONE_PT_CALIB requires using addition here instead of137 * using OR operation.138 */139 p1[i] += BIT_APPEND;140 p2[i] += BIT_APPEND;141 }142 }143 144}145 146static int calibrate_8974_nvmem(struct tsens_priv *priv)147{148 u32 p1[11], p2[11];149 u32 backup;150 int ret, mode;151 152 ret = nvmem_cell_read_variable_le_u32(priv->dev, "use_backup", &backup);153 if (ret == -ENOENT)154 dev_warn(priv->dev, "Please migrate to separate nvmem cells for calibration data\n");155 if (ret < 0)156 return ret;157 158 mode = tsens_read_calibration(priv, 2, p1, p2, backup == BKP_SEL);159 if (mode < 0)160 return mode;161 162 fixup_8974_points(mode, p1, p2);163 164 compute_intercept_slope(priv, p1, p2, mode);165 166 return 0;167}168 169static int calibrate_8974(struct tsens_priv *priv)170{171 u32 p1[11], p2[11];172 u32 *calib, *bkp;173 u32 calib_redun_sel;174 int mode, ret;175 176 ret = calibrate_8974_nvmem(priv);177 if (ret == 0)178 return 0;179 180 calib = (u32 *)qfprom_read(priv->dev, "calib");181 if (IS_ERR(calib))182 return PTR_ERR(calib);183 184 bkp = (u32 *)qfprom_read(priv->dev, "calib_backup");185 if (IS_ERR(bkp)) {186 kfree(calib);187 return PTR_ERR(bkp);188 }189 190 calib_redun_sel = FIELD_GET(BKP_REDUN_SEL, bkp[1]);191 192 if (calib_redun_sel == BKP_SEL)193 mode = tsens_read_calibration_legacy(priv, &tsens_8974_backup_nvmem,194 p1, p2,195 bkp, calib);196 else197 mode = tsens_read_calibration_legacy(priv, &tsens_8974_nvmem,198 p1, p2,199 calib, NULL);200 201 fixup_8974_points(mode, p1, p2);202 203 compute_intercept_slope(priv, p1, p2, mode);204 kfree(calib);205 kfree(bkp);206 207 return 0;208}209 210static int __init init_8226(struct tsens_priv *priv)211{212 priv->sensor[0].slope = 2901;213 priv->sensor[1].slope = 2846;214 priv->sensor[2].slope = 3038;215 priv->sensor[3].slope = 2955;216 priv->sensor[4].slope = 2901;217 priv->sensor[5].slope = 2846;218 219 return init_common(priv);220}221 222static int __init init_8909(struct tsens_priv *priv)223{224 int i;225 226 for (i = 0; i < priv->num_sensors; ++i)227 priv->sensor[i].slope = 3000;228 229 priv->sensor[0].p1_calib_offset = 0;230 priv->sensor[0].p2_calib_offset = 0;231 priv->sensor[1].p1_calib_offset = -10;232 priv->sensor[1].p2_calib_offset = -6;233 priv->sensor[2].p1_calib_offset = 0;234 priv->sensor[2].p2_calib_offset = 0;235 priv->sensor[3].p1_calib_offset = -9;236 priv->sensor[3].p2_calib_offset = -9;237 priv->sensor[4].p1_calib_offset = -8;238 priv->sensor[4].p2_calib_offset = -10;239 240 return init_common(priv);241}242 243static int __init init_8939(struct tsens_priv *priv) {244 priv->sensor[0].slope = 2911;245 priv->sensor[1].slope = 2789;246 priv->sensor[2].slope = 2906;247 priv->sensor[3].slope = 2763;248 priv->sensor[4].slope = 2922;249 priv->sensor[5].slope = 2867;250 priv->sensor[6].slope = 2833;251 priv->sensor[7].slope = 2838;252 priv->sensor[8].slope = 2840;253 /* priv->sensor[9].slope = 2852; */254 255 return init_common(priv);256}257 258static int __init init_9607(struct tsens_priv *priv)259{260 int i;261 262 for (i = 0; i < priv->num_sensors; ++i)263 priv->sensor[i].slope = 3000;264 265 priv->sensor[0].p1_calib_offset = 1;266 priv->sensor[0].p2_calib_offset = 1;267 priv->sensor[1].p1_calib_offset = -4;268 priv->sensor[1].p2_calib_offset = -2;269 priv->sensor[2].p1_calib_offset = 4;270 priv->sensor[2].p2_calib_offset = 8;271 priv->sensor[3].p1_calib_offset = -3;272 priv->sensor[3].p2_calib_offset = -5;273 priv->sensor[4].p1_calib_offset = -4;274 priv->sensor[4].p2_calib_offset = -4;275 276 return init_common(priv);277}278 279/* v0.1: 8226, 8909, 8916, 8939, 8974, 9607 */280 281static struct tsens_features tsens_v0_1_feat = {282 .ver_major = VER_0_1,283 .crit_int = 0,284 .combo_int = 0,285 .adc = 1,286 .srot_split = 1,287 .max_sensors = 11,288 .trip_min_temp = -40000,289 .trip_max_temp = 120000,290};291 292static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = {293 /* ----- SROT ------ */294 /* No VERSION information */295 296 /* CTRL_OFFSET */297 [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0),298 [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1),299 300 /* ----- TM ------ */301 /* INTERRUPT ENABLE */302 [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 0),303 304 /* UPPER/LOWER TEMPERATURE THRESHOLDS */305 REG_FIELD_FOR_EACH_SENSOR11(LOW_THRESH, TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 0, 9),306 REG_FIELD_FOR_EACH_SENSOR11(UP_THRESH, TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 10, 19),307 308 /* UPPER/LOWER INTERRUPTS [CLEAR/STATUS] */309 REG_FIELD_FOR_EACH_SENSOR11(LOW_INT_CLEAR, TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 20, 20),310 REG_FIELD_FOR_EACH_SENSOR11(UP_INT_CLEAR, TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF, 21, 21),311 312 /* NO CRITICAL INTERRUPT SUPPORT on v0.1 */313 314 /* Sn_STATUS */315 REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 9),316 /* No VALID field on v0.1 */317 /* xxx_STATUS bits: 1 == threshold violated */318 REG_FIELD_FOR_EACH_SENSOR11(MIN_STATUS, TM_Sn_STATUS_OFF, 10, 10),319 REG_FIELD_FOR_EACH_SENSOR11(LOWER_STATUS, TM_Sn_STATUS_OFF, 11, 11),320 REG_FIELD_FOR_EACH_SENSOR11(UPPER_STATUS, TM_Sn_STATUS_OFF, 12, 12),321 /* No CRITICAL field on v0.1 */322 REG_FIELD_FOR_EACH_SENSOR11(MAX_STATUS, TM_Sn_STATUS_OFF, 13, 13),323 324 /* TRDY: 1=ready, 0=in progress */325 [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),326};327 328static const struct tsens_ops ops_8226 = {329 .init = init_8226,330 .calibrate = tsens_calibrate_common,331 .get_temp = get_temp_common,332};333 334struct tsens_plat_data data_8226 = {335 .num_sensors = 6,336 .ops = &ops_8226,337 .feat = &tsens_v0_1_feat,338 .fields = tsens_v0_1_regfields,339};340 341static const struct tsens_ops ops_8909 = {342 .init = init_8909,343 .calibrate = tsens_calibrate_common,344 .get_temp = get_temp_common,345};346 347struct tsens_plat_data data_8909 = {348 .num_sensors = 5,349 .ops = &ops_8909,350 .feat = &tsens_v0_1_feat,351 .fields = tsens_v0_1_regfields,352};353 354static const struct tsens_ops ops_8916 = {355 .init = init_common,356 .calibrate = calibrate_8916,357 .get_temp = get_temp_common,358};359 360struct tsens_plat_data data_8916 = {361 .num_sensors = 5,362 .ops = &ops_8916,363 .hw_ids = (unsigned int []){0, 1, 2, 4, 5 },364 365 .feat = &tsens_v0_1_feat,366 .fields = tsens_v0_1_regfields,367};368 369static const struct tsens_ops ops_8939 = {370 .init = init_8939,371 .calibrate = tsens_calibrate_common,372 .get_temp = get_temp_common,373};374 375struct tsens_plat_data data_8939 = {376 .num_sensors = 9,377 .ops = &ops_8939,378 .hw_ids = (unsigned int []){ 0, 1, 2, 3, 5, 6, 7, 8, 9, /* 10 */ },379 380 .feat = &tsens_v0_1_feat,381 .fields = tsens_v0_1_regfields,382};383 384static const struct tsens_ops ops_8974 = {385 .init = init_common,386 .calibrate = calibrate_8974,387 .get_temp = get_temp_common,388};389 390struct tsens_plat_data data_8974 = {391 .num_sensors = 11,392 .ops = &ops_8974,393 .feat = &tsens_v0_1_feat,394 .fields = tsens_v0_1_regfields,395};396 397static const struct tsens_ops ops_9607 = {398 .init = init_9607,399 .calibrate = tsens_calibrate_common,400 .get_temp = get_temp_common,401};402 403struct tsens_plat_data data_9607 = {404 .num_sensors = 5,405 .ops = &ops_9607,406 .feat = &tsens_v0_1_feat,407 .fields = tsens_v0_1_regfields,408};409