xref: /linux/drivers/thermal/qcom/tsens-8960.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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 
suspend_8960(struct tsens_priv * priv)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 
resume_8960(struct tsens_priv * priv)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 
enable_8960(struct tsens_priv * priv,int id)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, &reg);
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 
disable_8960(struct tsens_priv * priv)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, &reg_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 
calibrate_8960(struct tsens_priv * priv)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