1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/platform_device.h>
7#include <linux/delay.h>
8#include <linux/bitops.h>
9#include <linux/regmap.h>
10#include <linux/thermal.h>
11#include "tsens.h"
12
13#define CAL_MDEGC		30000
14
15#define CONFIG_ADDR		0x3640
16#define CONFIG_ADDR_8660	0x3620
17/* CONFIG_ADDR bitmasks */
18#define CONFIG			0x9b
19#define CONFIG_MASK		0xf
20#define CONFIG_8660		1
21#define CONFIG_SHIFT_8660	28
22#define CONFIG_MASK_8660	(3 << CONFIG_SHIFT_8660)
23
24#define STATUS_CNTL_ADDR_8064	0x3660
25#define CNTL_ADDR		0x3620
26/* CNTL_ADDR bitmasks */
27#define EN			BIT(0)
28#define SW_RST			BIT(1)
29#define SENSOR0_EN		BIT(3)
30#define SLP_CLK_ENA		BIT(26)
31#define SLP_CLK_ENA_8660	BIT(24)
32#define MEASURE_PERIOD		1
33#define SENSOR0_SHIFT		3
34
35/* INT_STATUS_ADDR bitmasks */
36#define MIN_STATUS_MASK		BIT(0)
37#define LOWER_STATUS_CLR	BIT(1)
38#define UPPER_STATUS_CLR	BIT(2)
39#define MAX_STATUS_MASK		BIT(3)
40
41#define THRESHOLD_ADDR		0x3624
42/* THRESHOLD_ADDR bitmasks */
43#define THRESHOLD_MAX_LIMIT_SHIFT	24
44#define THRESHOLD_MIN_LIMIT_SHIFT	16
45#define THRESHOLD_UPPER_LIMIT_SHIFT	8
46#define THRESHOLD_LOWER_LIMIT_SHIFT	0
47
48/* Initial temperature threshold values */
49#define LOWER_LIMIT_TH		0x50
50#define UPPER_LIMIT_TH		0xdf
51#define MIN_LIMIT_TH		0x0
52#define MAX_LIMIT_TH		0xff
53
54#define S0_STATUS_ADDR		0x3628
55#define INT_STATUS_ADDR		0x363c
56#define TRDY_MASK		BIT(7)
57#define TIMEOUT_US		100
58
59static int suspend_8960(struct tsens_priv *priv)
60{
61	int ret;
62	unsigned int mask;
63	struct regmap *map = priv->tm_map;
64
65	ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold);
66	if (ret)
67		return ret;
68
69	ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control);
70	if (ret)
71		return ret;
72
73	if (priv->num_sensors > 1)
74		mask = SLP_CLK_ENA | EN;
75	else
76		mask = SLP_CLK_ENA_8660 | EN;
77
78	ret = regmap_update_bits(map, CNTL_ADDR, mask, 0);
79	if (ret)
80		return ret;
81
82	return 0;
83}
84
85static int resume_8960(struct tsens_priv *priv)
86{
87	int ret;
88	struct regmap *map = priv->tm_map;
89
90	ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
91	if (ret)
92		return ret;
93
94	/*
95	 * Separate CONFIG restore is not needed only for 8660 as
96	 * config is part of CTRL Addr and its restored as such
97	 */
98	if (priv->num_sensors > 1) {
99		ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
100		if (ret)
101			return ret;
102	}
103
104	ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold);
105	if (ret)
106		return ret;
107
108	ret = regmap_write(map, CNTL_ADDR, priv->ctx.control);
109	if (ret)
110		return ret;
111
112	return 0;
113}
114
115static int enable_8960(struct tsens_priv *priv, int id)
116{
117	int ret;
118	u32 reg, mask;
119
120	ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg);
121	if (ret)
122		return ret;
123
124	mask = BIT(id + SENSOR0_SHIFT);
125	ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
126	if (ret)
127		return ret;
128
129	if (priv->num_sensors > 1)
130		reg |= mask | SLP_CLK_ENA | EN;
131	else
132		reg |= mask | SLP_CLK_ENA_8660 | EN;
133
134	ret = regmap_write(priv->tm_map, CNTL_ADDR, reg);
135	if (ret)
136		return ret;
137
138	return 0;
139}
140
141static void disable_8960(struct tsens_priv *priv)
142{
143	int ret;
144	u32 reg_cntl;
145	u32 mask;
146
147	mask = GENMASK(priv->num_sensors - 1, 0);
148	mask <<= SENSOR0_SHIFT;
149	mask |= EN;
150
151	ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg_cntl);
152	if (ret)
153		return;
154
155	reg_cntl &= ~mask;
156
157	if (priv->num_sensors > 1)
158		reg_cntl &= ~SLP_CLK_ENA;
159	else
160		reg_cntl &= ~SLP_CLK_ENA_8660;
161
162	regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
163}
164
165static int init_8960(struct tsens_priv *priv)
166{
167	int ret, i;
168	u32 reg_cntl;
169
170	priv->tm_map = dev_get_regmap(priv->dev, NULL);
171	if (!priv->tm_map)
172		return -ENODEV;
173
174	/*
175	 * The status registers for each sensor are discontiguous
176	 * because some SoCs have 5 sensors while others have more
177	 * but the control registers stay in the same place, i.e
178	 * directly after the first 5 status registers.
179	 */
180	for (i = 0; i < priv->num_sensors; i++) {
181		if (i >= 5)
182			priv->sensor[i].status = S0_STATUS_ADDR + 40;
183		priv->sensor[i].status += i * 4;
184	}
185
186	reg_cntl = SW_RST;
187	ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
188	if (ret)
189		return ret;
190
191	if (priv->num_sensors > 1) {
192		reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
193		reg_cntl &= ~SW_RST;
194		ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
195					 CONFIG_MASK, CONFIG);
196	} else {
197		reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
198		reg_cntl &= ~CONFIG_MASK_8660;
199		reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
200	}
201
202	reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
203	ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
204	if (ret)
205		return ret;
206
207	reg_cntl |= EN;
208	ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
209	if (ret)
210		return ret;
211
212	return 0;
213}
214
215static int calibrate_8960(struct tsens_priv *priv)
216{
217	int i;
218	char *data;
219
220	ssize_t num_read = priv->num_sensors;
221	struct tsens_sensor *s = priv->sensor;
222
223	data = qfprom_read(priv->dev, "calib");
224	if (IS_ERR(data))
225		data = qfprom_read(priv->dev, "calib_backup");
226	if (IS_ERR(data))
227		return PTR_ERR(data);
228
229	for (i = 0; i < num_read; i++, s++)
230		s->offset = data[i];
231
232	kfree(data);
233
234	return 0;
235}
236
237/* Temperature on y axis and ADC-code on x-axis */
238static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
239{
240	int slope, offset;
241
242	slope = thermal_zone_get_slope(s->tzd);
243	offset = CAL_MDEGC - slope * s->offset;
244
245	return adc_code * slope + offset;
246}
247
248static int get_temp_8960(const struct tsens_sensor *s, int *temp)
249{
250	int ret;
251	u32 code, trdy;
252	struct tsens_priv *priv = s->priv;
253	unsigned long timeout;
254
255	timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
256	do {
257		ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
258		if (ret)
259			return ret;
260		if (!(trdy & TRDY_MASK))
261			continue;
262		ret = regmap_read(priv->tm_map, s->status, &code);
263		if (ret)
264			return ret;
265		*temp = code_to_mdegC(code, s);
266		return 0;
267	} while (time_before(jiffies, timeout));
268
269	return -ETIMEDOUT;
270}
271
272static const struct tsens_ops ops_8960 = {
273	.init		= init_8960,
274	.calibrate	= calibrate_8960,
275	.get_temp	= get_temp_8960,
276	.enable		= enable_8960,
277	.disable	= disable_8960,
278	.suspend	= suspend_8960,
279	.resume		= resume_8960,
280};
281
282struct tsens_plat_data data_8960 = {
283	.num_sensors	= 11,
284	.ops		= &ops_8960,
285};
286