12d71d8deSAmit Kucheria // SPDX-License-Identifier: GPL-2.0 220d4fd84SRajendra Nayak /* 320d4fd84SRajendra Nayak * Copyright (c) 2015, The Linux Foundation. All rights reserved. 420d4fd84SRajendra Nayak */ 520d4fd84SRajendra Nayak 620d4fd84SRajendra Nayak #include <linux/platform_device.h> 720d4fd84SRajendra Nayak #include <linux/delay.h> 820d4fd84SRajendra Nayak #include <linux/bitops.h> 920d4fd84SRajendra Nayak #include <linux/regmap.h> 1020d4fd84SRajendra Nayak #include <linux/thermal.h> 1120d4fd84SRajendra Nayak #include "tsens.h" 1220d4fd84SRajendra Nayak 1320d4fd84SRajendra Nayak #define CONFIG_ADDR 0x3640 1420d4fd84SRajendra Nayak #define CONFIG_ADDR_8660 0x3620 1520d4fd84SRajendra Nayak /* CONFIG_ADDR bitmasks */ 1620d4fd84SRajendra Nayak #define CONFIG 0x9b 1720d4fd84SRajendra Nayak #define CONFIG_MASK 0xf 1820d4fd84SRajendra Nayak #define CONFIG_8660 1 1920d4fd84SRajendra Nayak #define CONFIG_SHIFT_8660 28 2020d4fd84SRajendra Nayak #define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) 2120d4fd84SRajendra Nayak 2220d4fd84SRajendra Nayak #define CNTL_ADDR 0x3620 2320d4fd84SRajendra Nayak /* CNTL_ADDR bitmasks */ 2420d4fd84SRajendra Nayak #define EN BIT(0) 2520d4fd84SRajendra Nayak #define SW_RST BIT(1) 262ebd0982SAnsuel Smith 273d08f029SAnsuel Smith #define MEASURE_PERIOD BIT(18) 2820d4fd84SRajendra Nayak #define SLP_CLK_ENA BIT(26) 2920d4fd84SRajendra Nayak #define SLP_CLK_ENA_8660 BIT(24) 3020d4fd84SRajendra Nayak #define SENSOR0_SHIFT 3 3120d4fd84SRajendra Nayak 3220d4fd84SRajendra Nayak #define THRESHOLD_ADDR 0x3624 3320d4fd84SRajendra Nayak 3420d4fd84SRajendra Nayak #define INT_STATUS_ADDR 0x363c 3520d4fd84SRajendra Nayak 36a0ed1411SAnsuel Smith #define S0_STATUS_OFF 0x3628 37a0ed1411SAnsuel Smith #define S1_STATUS_OFF 0x362c 38a0ed1411SAnsuel Smith #define S2_STATUS_OFF 0x3630 39a0ed1411SAnsuel Smith #define S3_STATUS_OFF 0x3634 40a0ed1411SAnsuel Smith #define S4_STATUS_OFF 0x3638 41a0ed1411SAnsuel Smith #define S5_STATUS_OFF 0x3664 /* Sensors 5-10 found on apq8064/msm8960 */ 42a0ed1411SAnsuel Smith #define S6_STATUS_OFF 0x3668 43a0ed1411SAnsuel Smith #define S7_STATUS_OFF 0x366c 44a0ed1411SAnsuel Smith #define S8_STATUS_OFF 0x3670 45a0ed1411SAnsuel Smith #define S9_STATUS_OFF 0x3674 46a0ed1411SAnsuel Smith #define S10_STATUS_OFF 0x3678 47a0ed1411SAnsuel Smith 48dfc1193dSAnsuel Smith /* Original slope - 350 to compensate mC to C inaccuracy */ 49dfc1193dSAnsuel Smith static u32 tsens_msm8960_slope[] = { 50dfc1193dSAnsuel Smith 826, 826, 804, 826, 51dfc1193dSAnsuel Smith 761, 782, 782, 849, 52dfc1193dSAnsuel Smith 782, 849, 782 53dfc1193dSAnsuel Smith }; 54dfc1193dSAnsuel Smith 5569b628acSAmit Kucheria static int suspend_8960(struct tsens_priv *priv) 5620d4fd84SRajendra Nayak { 5720d4fd84SRajendra Nayak int ret; 5820d4fd84SRajendra Nayak unsigned int mask; 5969b628acSAmit Kucheria struct regmap *map = priv->tm_map; 6020d4fd84SRajendra Nayak 6169b628acSAmit Kucheria ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold); 6220d4fd84SRajendra Nayak if (ret) 6320d4fd84SRajendra Nayak return ret; 6420d4fd84SRajendra Nayak 6569b628acSAmit Kucheria ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control); 6620d4fd84SRajendra Nayak if (ret) 6720d4fd84SRajendra Nayak return ret; 6820d4fd84SRajendra Nayak 6969b628acSAmit Kucheria if (priv->num_sensors > 1) 7020d4fd84SRajendra Nayak mask = SLP_CLK_ENA | EN; 7120d4fd84SRajendra Nayak else 7220d4fd84SRajendra Nayak mask = SLP_CLK_ENA_8660 | EN; 7320d4fd84SRajendra Nayak 7420d4fd84SRajendra Nayak ret = regmap_update_bits(map, CNTL_ADDR, mask, 0); 7520d4fd84SRajendra Nayak if (ret) 7620d4fd84SRajendra Nayak return ret; 7720d4fd84SRajendra Nayak 7820d4fd84SRajendra Nayak return 0; 7920d4fd84SRajendra Nayak } 8020d4fd84SRajendra Nayak 8169b628acSAmit Kucheria static int resume_8960(struct tsens_priv *priv) 8220d4fd84SRajendra Nayak { 8320d4fd84SRajendra Nayak int ret; 8469b628acSAmit Kucheria struct regmap *map = priv->tm_map; 8520d4fd84SRajendra Nayak 8620d4fd84SRajendra Nayak ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); 8720d4fd84SRajendra Nayak if (ret) 8820d4fd84SRajendra Nayak return ret; 8920d4fd84SRajendra Nayak 9020d4fd84SRajendra Nayak /* 9120d4fd84SRajendra Nayak * Separate CONFIG restore is not needed only for 8660 as 9220d4fd84SRajendra Nayak * config is part of CTRL Addr and its restored as such 9320d4fd84SRajendra Nayak */ 9469b628acSAmit Kucheria if (priv->num_sensors > 1) { 9520d4fd84SRajendra Nayak ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); 9620d4fd84SRajendra Nayak if (ret) 9720d4fd84SRajendra Nayak return ret; 9820d4fd84SRajendra Nayak } 9920d4fd84SRajendra Nayak 10069b628acSAmit Kucheria ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold); 10120d4fd84SRajendra Nayak if (ret) 10220d4fd84SRajendra Nayak return ret; 10320d4fd84SRajendra Nayak 10469b628acSAmit Kucheria ret = regmap_write(map, CNTL_ADDR, priv->ctx.control); 10520d4fd84SRajendra Nayak if (ret) 10620d4fd84SRajendra Nayak return ret; 10720d4fd84SRajendra Nayak 10820d4fd84SRajendra Nayak return 0; 10920d4fd84SRajendra Nayak } 11020d4fd84SRajendra Nayak 11169b628acSAmit Kucheria static int enable_8960(struct tsens_priv *priv, int id) 11220d4fd84SRajendra Nayak { 11320d4fd84SRajendra Nayak int ret; 1143d08f029SAnsuel Smith u32 reg, mask = BIT(id); 11520d4fd84SRajendra Nayak 11669b628acSAmit Kucheria ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); 11720d4fd84SRajendra Nayak if (ret) 11820d4fd84SRajendra Nayak return ret; 11920d4fd84SRajendra Nayak 1203d08f029SAnsuel Smith /* HARDWARE BUG: 1213d08f029SAnsuel Smith * On platforms with more than 6 sensors, all remaining sensors 1223d08f029SAnsuel Smith * must be enabled together, otherwise undefined results are expected. 1233d08f029SAnsuel Smith * (Sensor 6-7 disabled, Sensor 3 disabled...) In the original driver, 1243d08f029SAnsuel Smith * all the sensors are enabled in one step hence this bug is not 1253d08f029SAnsuel Smith * triggered. 1263d08f029SAnsuel Smith */ 1273d08f029SAnsuel Smith if (id > 5) 1283d08f029SAnsuel Smith mask = GENMASK(10, 6); 1293d08f029SAnsuel Smith 1303d08f029SAnsuel Smith mask <<= SENSOR0_SHIFT; 1313d08f029SAnsuel Smith 1323d08f029SAnsuel Smith /* Sensors already enabled. Skip. */ 1333d08f029SAnsuel Smith if ((reg & mask) == mask) 1343d08f029SAnsuel Smith return 0; 1353d08f029SAnsuel Smith 13669b628acSAmit Kucheria ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); 13720d4fd84SRajendra Nayak if (ret) 13820d4fd84SRajendra Nayak return ret; 13920d4fd84SRajendra Nayak 1403d08f029SAnsuel Smith reg |= MEASURE_PERIOD; 1413d08f029SAnsuel Smith 14269b628acSAmit Kucheria if (priv->num_sensors > 1) 14320d4fd84SRajendra Nayak reg |= mask | SLP_CLK_ENA | EN; 14420d4fd84SRajendra Nayak else 14520d4fd84SRajendra Nayak reg |= mask | SLP_CLK_ENA_8660 | EN; 14620d4fd84SRajendra Nayak 14769b628acSAmit Kucheria ret = regmap_write(priv->tm_map, CNTL_ADDR, reg); 14820d4fd84SRajendra Nayak if (ret) 14920d4fd84SRajendra Nayak return ret; 15020d4fd84SRajendra Nayak 15120d4fd84SRajendra Nayak return 0; 15220d4fd84SRajendra Nayak } 15320d4fd84SRajendra Nayak 15469b628acSAmit Kucheria static void disable_8960(struct tsens_priv *priv) 15520d4fd84SRajendra Nayak { 15620d4fd84SRajendra Nayak int ret; 15720d4fd84SRajendra Nayak u32 reg_cntl; 15820d4fd84SRajendra Nayak u32 mask; 15920d4fd84SRajendra Nayak 16069b628acSAmit Kucheria mask = GENMASK(priv->num_sensors - 1, 0); 16120d4fd84SRajendra Nayak mask <<= SENSOR0_SHIFT; 16220d4fd84SRajendra Nayak mask |= EN; 16320d4fd84SRajendra Nayak 16469b628acSAmit Kucheria ret = regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl); 16520d4fd84SRajendra Nayak if (ret) 16620d4fd84SRajendra Nayak return; 16720d4fd84SRajendra Nayak 16820d4fd84SRajendra Nayak reg_cntl &= ~mask; 16920d4fd84SRajendra Nayak 17069b628acSAmit Kucheria if (priv->num_sensors > 1) 17120d4fd84SRajendra Nayak reg_cntl &= ~SLP_CLK_ENA; 17220d4fd84SRajendra Nayak else 17320d4fd84SRajendra Nayak reg_cntl &= ~SLP_CLK_ENA_8660; 17420d4fd84SRajendra Nayak 17569b628acSAmit Kucheria regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); 17620d4fd84SRajendra Nayak } 17720d4fd84SRajendra Nayak 17869b628acSAmit Kucheria static int calibrate_8960(struct tsens_priv *priv) 17920d4fd84SRajendra Nayak { 18020d4fd84SRajendra Nayak int i; 18120d4fd84SRajendra Nayak char *data; 182dfc1193dSAnsuel Smith u32 p1[11]; 18320d4fd84SRajendra Nayak 18469b628acSAmit Kucheria data = qfprom_read(priv->dev, "calib"); 18520d4fd84SRajendra Nayak if (IS_ERR(data)) 18669b628acSAmit Kucheria data = qfprom_read(priv->dev, "calib_backup"); 18720d4fd84SRajendra Nayak if (IS_ERR(data)) 18820d4fd84SRajendra Nayak return PTR_ERR(data); 18920d4fd84SRajendra Nayak 190dfc1193dSAnsuel Smith for (i = 0; i < priv->num_sensors; i++) { 191dfc1193dSAnsuel Smith p1[i] = data[i]; 192dfc1193dSAnsuel Smith priv->sensor[i].slope = tsens_msm8960_slope[i]; 193dfc1193dSAnsuel Smith } 194dfc1193dSAnsuel Smith 195dfc1193dSAnsuel Smith compute_intercept_slope(priv, p1, NULL, ONE_PT_CALIB); 19620d4fd84SRajendra Nayak 1976b8249abSSrinivas Kandagatla kfree(data); 1986b8249abSSrinivas Kandagatla 19920d4fd84SRajendra Nayak return 0; 20020d4fd84SRajendra Nayak } 20120d4fd84SRajendra Nayak 202a0ed1411SAnsuel Smith static const struct reg_field tsens_8960_regfields[MAX_REGFIELDS] = { 203a0ed1411SAnsuel Smith /* ----- SROT ------ */ 204a0ed1411SAnsuel Smith /* No VERSION information */ 205a0ed1411SAnsuel Smith 206a0ed1411SAnsuel Smith /* CNTL */ 207a0ed1411SAnsuel Smith [TSENS_EN] = REG_FIELD(CNTL_ADDR, 0, 0), 208a0ed1411SAnsuel Smith [TSENS_SW_RST] = REG_FIELD(CNTL_ADDR, 1, 1), 209a0ed1411SAnsuel Smith /* 8960 has 5 sensors, 8660 has 11, we only handle 5 */ 210a0ed1411SAnsuel Smith [SENSOR_EN] = REG_FIELD(CNTL_ADDR, 3, 7), 211a0ed1411SAnsuel Smith 212a0ed1411SAnsuel Smith /* ----- TM ------ */ 213a0ed1411SAnsuel Smith /* INTERRUPT ENABLE */ 214a0ed1411SAnsuel Smith /* NO INTERRUPT ENABLE */ 215a0ed1411SAnsuel Smith 216a0ed1411SAnsuel Smith /* Single UPPER/LOWER TEMPERATURE THRESHOLD for all sensors */ 217a0ed1411SAnsuel Smith [LOW_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 0, 7), 218a0ed1411SAnsuel Smith [UP_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 8, 15), 219a0ed1411SAnsuel Smith /* MIN_THRESH_0 and MAX_THRESH_0 are not present in the regfield 220a0ed1411SAnsuel Smith * Recycle CRIT_THRESH_0 and 1 to set the required regs to hardcoded temp 221a0ed1411SAnsuel Smith * MIN_THRESH_0 -> CRIT_THRESH_1 222a0ed1411SAnsuel Smith * MAX_THRESH_0 -> CRIT_THRESH_0 223a0ed1411SAnsuel Smith */ 224a0ed1411SAnsuel Smith [CRIT_THRESH_1] = REG_FIELD(THRESHOLD_ADDR, 16, 23), 225a0ed1411SAnsuel Smith [CRIT_THRESH_0] = REG_FIELD(THRESHOLD_ADDR, 24, 31), 226a0ed1411SAnsuel Smith 227a0ed1411SAnsuel Smith /* UPPER/LOWER INTERRUPT [CLEAR/STATUS] */ 228a0ed1411SAnsuel Smith /* 1 == clear, 0 == normal operation */ 229a0ed1411SAnsuel Smith [LOW_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 9, 9), 230a0ed1411SAnsuel Smith [UP_INT_CLEAR_0] = REG_FIELD(CNTL_ADDR, 10, 10), 231a0ed1411SAnsuel Smith 232a0ed1411SAnsuel Smith /* NO CRITICAL INTERRUPT SUPPORT on 8960 */ 233a0ed1411SAnsuel Smith 234a0ed1411SAnsuel Smith /* Sn_STATUS */ 235a0ed1411SAnsuel Smith [LAST_TEMP_0] = REG_FIELD(S0_STATUS_OFF, 0, 7), 236a0ed1411SAnsuel Smith [LAST_TEMP_1] = REG_FIELD(S1_STATUS_OFF, 0, 7), 237a0ed1411SAnsuel Smith [LAST_TEMP_2] = REG_FIELD(S2_STATUS_OFF, 0, 7), 238a0ed1411SAnsuel Smith [LAST_TEMP_3] = REG_FIELD(S3_STATUS_OFF, 0, 7), 239a0ed1411SAnsuel Smith [LAST_TEMP_4] = REG_FIELD(S4_STATUS_OFF, 0, 7), 240a0ed1411SAnsuel Smith [LAST_TEMP_5] = REG_FIELD(S5_STATUS_OFF, 0, 7), 241a0ed1411SAnsuel Smith [LAST_TEMP_6] = REG_FIELD(S6_STATUS_OFF, 0, 7), 242a0ed1411SAnsuel Smith [LAST_TEMP_7] = REG_FIELD(S7_STATUS_OFF, 0, 7), 243a0ed1411SAnsuel Smith [LAST_TEMP_8] = REG_FIELD(S8_STATUS_OFF, 0, 7), 244a0ed1411SAnsuel Smith [LAST_TEMP_9] = REG_FIELD(S9_STATUS_OFF, 0, 7), 245a0ed1411SAnsuel Smith [LAST_TEMP_10] = REG_FIELD(S10_STATUS_OFF, 0, 7), 246a0ed1411SAnsuel Smith 247a0ed1411SAnsuel Smith /* No VALID field on 8960 */ 248a0ed1411SAnsuel Smith /* TSENS_INT_STATUS bits: 1 == threshold violated */ 249a0ed1411SAnsuel Smith [MIN_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 0, 0), 250a0ed1411SAnsuel Smith [LOWER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 1, 1), 251a0ed1411SAnsuel Smith [UPPER_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 2, 2), 252a0ed1411SAnsuel Smith /* No CRITICAL field on 8960 */ 253a0ed1411SAnsuel Smith [MAX_STATUS_0] = REG_FIELD(INT_STATUS_ADDR, 3, 3), 254a0ed1411SAnsuel Smith 255a0ed1411SAnsuel Smith /* TRDY: 1=ready, 0=in progress */ 256a0ed1411SAnsuel Smith [TRDY] = REG_FIELD(INT_STATUS_ADDR, 7, 7), 257a0ed1411SAnsuel Smith }; 258a0ed1411SAnsuel Smith 259032d4057SEduardo Valentin static const struct tsens_ops ops_8960 = { 260fdda131fSAnsuel Smith .init = init_common, 26120d4fd84SRajendra Nayak .calibrate = calibrate_8960, 262dfc1193dSAnsuel Smith .get_temp = get_temp_common, 26320d4fd84SRajendra Nayak .enable = enable_8960, 26420d4fd84SRajendra Nayak .disable = disable_8960, 26520d4fd84SRajendra Nayak .suspend = suspend_8960, 26620d4fd84SRajendra Nayak .resume = resume_8960, 26720d4fd84SRajendra Nayak }; 26820d4fd84SRajendra Nayak 26953e2a20eSAnsuel Smith static struct tsens_features tsens_8960_feat = { 27053e2a20eSAnsuel Smith .ver_major = VER_0, 27153e2a20eSAnsuel Smith .crit_int = 0, 2724360af35SRobert Marko .combo_int = 0, 27353e2a20eSAnsuel Smith .adc = 1, 27453e2a20eSAnsuel Smith .srot_split = 0, 27553e2a20eSAnsuel Smith .max_sensors = 11, 276*f63bacedSRobert Marko .trip_min_temp = -40000, 277*f63bacedSRobert Marko .trip_max_temp = 120000, 27853e2a20eSAnsuel Smith }; 27953e2a20eSAnsuel Smith 2800aef1ee5SAmit Kucheria struct tsens_plat_data data_8960 = { 28120d4fd84SRajendra Nayak .num_sensors = 11, 28220d4fd84SRajendra Nayak .ops = &ops_8960, 28353e2a20eSAnsuel Smith .feat = &tsens_8960_feat, 284a0ed1411SAnsuel Smith .fields = tsens_8960_regfields, 28520d4fd84SRajendra Nayak }; 286