Merge tag 'modules-for-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/jeyu...
[linux-2.6-block.git] / drivers / thermal / qcom / tsens-8960.c
CommitLineData
2d71d8de 1// SPDX-License-Identifier: GPL-2.0
20d4fd84
RN
2/*
3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
20d4fd84
RN
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
69b628ac 59static int suspend_8960(struct tsens_priv *priv)
20d4fd84
RN
60{
61 int ret;
62 unsigned int mask;
69b628ac 63 struct regmap *map = priv->tm_map;
20d4fd84 64
69b628ac 65 ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold);
20d4fd84
RN
66 if (ret)
67 return ret;
68
69b628ac 69 ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control);
20d4fd84
RN
70 if (ret)
71 return ret;
72
69b628ac 73 if (priv->num_sensors > 1)
20d4fd84
RN
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
69b628ac 85static int resume_8960(struct tsens_priv *priv)
20d4fd84
RN
86{
87 int ret;
69b628ac 88 struct regmap *map = priv->tm_map;
20d4fd84
RN
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 */
69b628ac 98 if (priv->num_sensors > 1) {
20d4fd84
RN
99 ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
100 if (ret)
101 return ret;
102 }
103
69b628ac 104 ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold);
20d4fd84
RN
105 if (ret)
106 return ret;
107
69b628ac 108 ret = regmap_write(map, CNTL_ADDR, priv->ctx.control);
20d4fd84
RN
109 if (ret)
110 return ret;
111
112 return 0;
113}
114
69b628ac 115static int enable_8960(struct tsens_priv *priv, int id)
20d4fd84
RN
116{
117 int ret;
118 u32 reg, mask;
119
69b628ac 120 ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg);
20d4fd84
RN
121 if (ret)
122 return ret;
123
124 mask = BIT(id + SENSOR0_SHIFT);
69b628ac 125 ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
20d4fd84
RN
126 if (ret)
127 return ret;
128
69b628ac 129 if (priv->num_sensors > 1)
20d4fd84
RN
130 reg |= mask | SLP_CLK_ENA | EN;
131 else
132 reg |= mask | SLP_CLK_ENA_8660 | EN;
133
69b628ac 134 ret = regmap_write(priv->tm_map, CNTL_ADDR, reg);
20d4fd84
RN
135 if (ret)
136 return ret;
137
138 return 0;
139}
140
69b628ac 141static void disable_8960(struct tsens_priv *priv)
20d4fd84
RN
142{
143 int ret;
144 u32 reg_cntl;
145 u32 mask;
146
69b628ac 147 mask = GENMASK(priv->num_sensors - 1, 0);
20d4fd84
RN
148 mask <<= SENSOR0_SHIFT;
149 mask |= EN;
150
69b628ac 151 ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg_cntl);
20d4fd84
RN
152 if (ret)
153 return;
154
155 reg_cntl &= ~mask;
156
69b628ac 157 if (priv->num_sensors > 1)
20d4fd84
RN
158 reg_cntl &= ~SLP_CLK_ENA;
159 else
160 reg_cntl &= ~SLP_CLK_ENA_8660;
161
69b628ac 162 regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
20d4fd84
RN
163}
164
69b628ac 165static int init_8960(struct tsens_priv *priv)
20d4fd84
RN
166{
167 int ret, i;
168 u32 reg_cntl;
169
69b628ac
AK
170 priv->tm_map = dev_get_regmap(priv->dev, NULL);
171 if (!priv->tm_map)
20d4fd84
RN
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 */
69b628ac 180 for (i = 0; i < priv->num_sensors; i++) {
20d4fd84 181 if (i >= 5)
69b628ac
AK
182 priv->sensor[i].status = S0_STATUS_ADDR + 40;
183 priv->sensor[i].status += i * 4;
20d4fd84
RN
184 }
185
186 reg_cntl = SW_RST;
69b628ac 187 ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
20d4fd84
RN
188 if (ret)
189 return ret;
190
69b628ac 191 if (priv->num_sensors > 1) {
20d4fd84
RN
192 reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
193 reg_cntl &= ~SW_RST;
69b628ac 194 ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
20d4fd84
RN
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
69b628ac
AK
202 reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
203 ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
20d4fd84
RN
204 if (ret)
205 return ret;
206
207 reg_cntl |= EN;
69b628ac 208 ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
20d4fd84
RN
209 if (ret)
210 return ret;
211
212 return 0;
213}
214
69b628ac 215static int calibrate_8960(struct tsens_priv *priv)
20d4fd84
RN
216{
217 int i;
218 char *data;
219
69b628ac
AK
220 ssize_t num_read = priv->num_sensors;
221 struct tsens_sensor *s = priv->sensor;
20d4fd84 222
69b628ac 223 data = qfprom_read(priv->dev, "calib");
20d4fd84 224 if (IS_ERR(data))
69b628ac 225 data = qfprom_read(priv->dev, "calib_backup");
20d4fd84
RN
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 return 0;
233}
234
235/* Temperature on y axis and ADC-code on x-axis */
236static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
237{
238 int slope, offset;
239
240 slope = thermal_zone_get_slope(s->tzd);
241 offset = CAL_MDEGC - slope * s->offset;
242
243 return adc_code * slope + offset;
244}
245
69b628ac 246static int get_temp_8960(struct tsens_priv *priv, int id, int *temp)
20d4fd84
RN
247{
248 int ret;
249 u32 code, trdy;
69b628ac 250 const struct tsens_sensor *s = &priv->sensor[id];
20d4fd84
RN
251 unsigned long timeout;
252
253 timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
254 do {
69b628ac 255 ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
20d4fd84
RN
256 if (ret)
257 return ret;
258 if (!(trdy & TRDY_MASK))
259 continue;
69b628ac 260 ret = regmap_read(priv->tm_map, s->status, &code);
20d4fd84
RN
261 if (ret)
262 return ret;
263 *temp = code_to_mdegC(code, s);
264 return 0;
265 } while (time_before(jiffies, timeout));
266
267 return -ETIMEDOUT;
268}
269
032d4057 270static const struct tsens_ops ops_8960 = {
20d4fd84
RN
271 .init = init_8960,
272 .calibrate = calibrate_8960,
273 .get_temp = get_temp_8960,
274 .enable = enable_8960,
275 .disable = disable_8960,
276 .suspend = suspend_8960,
277 .resume = resume_8960,
278};
279
3c040ce0 280const struct tsens_plat_data data_8960 = {
20d4fd84
RN
281 .num_sensors = 11,
282 .ops = &ops_8960,
283};