]>
Commit | Line | Data |
---|---|---|
c610afaa | 1 | /* |
10c8251c | 2 | * Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved. |
c610afaa II |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 and | |
6 | * only version 2 as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | */ | |
13 | ||
10c8251c | 14 | #include <linux/bitops.h> |
c610afaa II |
15 | #include <linux/delay.h> |
16 | #include <linux/err.h> | |
17 | #include <linux/iio/consumer.h> | |
18 | #include <linux/interrupt.h> | |
19 | #include <linux/module.h> | |
20 | #include <linux/of.h> | |
21 | #include <linux/of_device.h> | |
22 | #include <linux/platform_device.h> | |
23 | #include <linux/regmap.h> | |
24 | #include <linux/thermal.h> | |
25 | ||
26 | #define QPNP_TM_REG_TYPE 0x04 | |
27 | #define QPNP_TM_REG_SUBTYPE 0x05 | |
28 | #define QPNP_TM_REG_STATUS 0x08 | |
29 | #define QPNP_TM_REG_SHUTDOWN_CTRL1 0x40 | |
30 | #define QPNP_TM_REG_ALARM_CTRL 0x46 | |
31 | ||
32 | #define QPNP_TM_TYPE 0x09 | |
10c8251c DC |
33 | #define QPNP_TM_SUBTYPE_GEN1 0x08 |
34 | #define QPNP_TM_SUBTYPE_GEN2 0x09 | |
c610afaa | 35 | |
10c8251c DC |
36 | #define STATUS_GEN1_STAGE_MASK GENMASK(1, 0) |
37 | #define STATUS_GEN2_STATE_MASK GENMASK(6, 4) | |
38 | #define STATUS_GEN2_STATE_SHIFT 4 | |
c610afaa | 39 | |
10c8251c DC |
40 | #define SHUTDOWN_CTRL1_OVERRIDE_MASK GENMASK(7, 6) |
41 | #define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0) | |
c610afaa | 42 | |
10c8251c | 43 | #define ALARM_CTRL_FORCE_ENABLE BIT(7) |
c610afaa II |
44 | |
45 | /* | |
46 | * Trip point values based on threshold control | |
47 | * 0 = {105 C, 125 C, 145 C} | |
48 | * 1 = {110 C, 130 C, 150 C} | |
49 | * 2 = {115 C, 135 C, 155 C} | |
50 | * 3 = {120 C, 140 C, 160 C} | |
51 | */ | |
52 | #define TEMP_STAGE_STEP 20000 /* Stage step: 20.000 C */ | |
53 | #define TEMP_STAGE_HYSTERESIS 2000 | |
54 | ||
55 | #define TEMP_THRESH_MIN 105000 /* Threshold Min: 105 C */ | |
56 | #define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */ | |
57 | ||
58 | #define THRESH_MIN 0 | |
59 | ||
60 | /* Temperature in Milli Celsius reported during stage 0 if no ADC is present */ | |
61 | #define DEFAULT_TEMP 37000 | |
62 | ||
63 | struct qpnp_tm_chip { | |
64 | struct regmap *map; | |
65 | struct thermal_zone_device *tz_dev; | |
10c8251c | 66 | unsigned int subtype; |
c610afaa II |
67 | long temp; |
68 | unsigned int thresh; | |
69 | unsigned int stage; | |
70 | unsigned int prev_stage; | |
71 | unsigned int base; | |
72 | struct iio_channel *adc; | |
73 | }; | |
74 | ||
10c8251c DC |
75 | /* This array maps from GEN2 alarm state to GEN1 alarm stage */ |
76 | static const unsigned int alarm_state_map[8] = {0, 1, 1, 2, 2, 3, 3, 3}; | |
77 | ||
c610afaa II |
78 | static int qpnp_tm_read(struct qpnp_tm_chip *chip, u16 addr, u8 *data) |
79 | { | |
80 | unsigned int val; | |
81 | int ret; | |
82 | ||
83 | ret = regmap_read(chip->map, chip->base + addr, &val); | |
84 | if (ret < 0) | |
85 | return ret; | |
86 | ||
87 | *data = val; | |
88 | return 0; | |
89 | } | |
90 | ||
91 | static int qpnp_tm_write(struct qpnp_tm_chip *chip, u16 addr, u8 data) | |
92 | { | |
93 | return regmap_write(chip->map, chip->base + addr, data); | |
94 | } | |
95 | ||
10c8251c DC |
96 | /** |
97 | * qpnp_tm_get_temp_stage() - return over-temperature stage | |
98 | * @chip: Pointer to the qpnp_tm chip | |
99 | * | |
100 | * Return: stage (GEN1) or state (GEN2) on success, or errno on failure. | |
101 | */ | |
102 | static int qpnp_tm_get_temp_stage(struct qpnp_tm_chip *chip) | |
103 | { | |
104 | int ret; | |
105 | u8 reg = 0; | |
106 | ||
107 | ret = qpnp_tm_read(chip, QPNP_TM_REG_STATUS, ®); | |
108 | if (ret < 0) | |
109 | return ret; | |
110 | ||
111 | if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) | |
112 | ret = reg & STATUS_GEN1_STAGE_MASK; | |
113 | else | |
114 | ret = (reg & STATUS_GEN2_STATE_MASK) >> STATUS_GEN2_STATE_SHIFT; | |
115 | ||
116 | return ret; | |
117 | } | |
118 | ||
c610afaa II |
119 | /* |
120 | * This function updates the internal temp value based on the | |
121 | * current thermal stage and threshold as well as the previous stage | |
122 | */ | |
123 | static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) | |
124 | { | |
10c8251c | 125 | unsigned int stage, stage_new, stage_old; |
c610afaa | 126 | int ret; |
c610afaa | 127 | |
10c8251c | 128 | ret = qpnp_tm_get_temp_stage(chip); |
c610afaa II |
129 | if (ret < 0) |
130 | return ret; | |
10c8251c | 131 | stage = ret; |
c610afaa | 132 | |
10c8251c DC |
133 | if (chip->subtype == QPNP_TM_SUBTYPE_GEN1) { |
134 | stage_new = stage; | |
135 | stage_old = chip->stage; | |
136 | } else { | |
137 | stage_new = alarm_state_map[stage]; | |
138 | stage_old = alarm_state_map[chip->stage]; | |
139 | } | |
c610afaa | 140 | |
10c8251c | 141 | if (stage_new > stage_old) { |
c610afaa | 142 | /* increasing stage, use lower bound */ |
10c8251c | 143 | chip->temp = (stage_new - 1) * TEMP_STAGE_STEP + |
c610afaa II |
144 | chip->thresh * TEMP_THRESH_STEP + |
145 | TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; | |
10c8251c | 146 | } else if (stage_new < stage_old) { |
c610afaa | 147 | /* decreasing stage, use upper bound */ |
10c8251c | 148 | chip->temp = stage_new * TEMP_STAGE_STEP + |
c610afaa II |
149 | chip->thresh * TEMP_THRESH_STEP - |
150 | TEMP_STAGE_HYSTERESIS + TEMP_THRESH_MIN; | |
151 | } | |
152 | ||
153 | chip->stage = stage; | |
154 | ||
155 | return 0; | |
156 | } | |
157 | ||
17e8351a | 158 | static int qpnp_tm_get_temp(void *data, int *temp) |
c610afaa II |
159 | { |
160 | struct qpnp_tm_chip *chip = data; | |
161 | int ret, mili_celsius; | |
162 | ||
163 | if (!temp) | |
164 | return -EINVAL; | |
165 | ||
7a4ca51b | 166 | if (!chip->adc) { |
c610afaa II |
167 | ret = qpnp_tm_update_temp_no_adc(chip); |
168 | if (ret < 0) | |
169 | return ret; | |
170 | } else { | |
171 | ret = iio_read_channel_processed(chip->adc, &mili_celsius); | |
172 | if (ret < 0) | |
173 | return ret; | |
174 | ||
175 | chip->temp = mili_celsius; | |
176 | } | |
177 | ||
178 | *temp = chip->temp < 0 ? 0 : chip->temp; | |
179 | ||
180 | return 0; | |
181 | } | |
182 | ||
183 | static const struct thermal_zone_of_device_ops qpnp_tm_sensor_ops = { | |
184 | .get_temp = qpnp_tm_get_temp, | |
185 | }; | |
186 | ||
187 | static irqreturn_t qpnp_tm_isr(int irq, void *data) | |
188 | { | |
189 | struct qpnp_tm_chip *chip = data; | |
190 | ||
0e70f466 | 191 | thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED); |
c610afaa II |
192 | |
193 | return IRQ_HANDLED; | |
194 | } | |
195 | ||
196 | /* | |
197 | * This function initializes the internal temp value based on only the | |
198 | * current thermal stage and threshold. Setup threshold control and | |
199 | * disable shutdown override. | |
200 | */ | |
201 | static int qpnp_tm_init(struct qpnp_tm_chip *chip) | |
202 | { | |
10c8251c | 203 | unsigned int stage; |
c610afaa | 204 | int ret; |
10c8251c | 205 | u8 reg = 0; |
c610afaa | 206 | |
10c8251c DC |
207 | ret = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, ®); |
208 | if (ret < 0) | |
209 | return ret; | |
210 | ||
211 | chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK; | |
c610afaa II |
212 | chip->temp = DEFAULT_TEMP; |
213 | ||
10c8251c | 214 | ret = qpnp_tm_get_temp_stage(chip); |
c610afaa II |
215 | if (ret < 0) |
216 | return ret; | |
10c8251c | 217 | chip->stage = ret; |
c610afaa | 218 | |
10c8251c DC |
219 | stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1 |
220 | ? chip->stage : alarm_state_map[chip->stage]; | |
c610afaa | 221 | |
10c8251c | 222 | if (stage) |
c610afaa | 223 | chip->temp = chip->thresh * TEMP_THRESH_STEP + |
10c8251c | 224 | (stage - 1) * TEMP_STAGE_STEP + |
c610afaa II |
225 | TEMP_THRESH_MIN; |
226 | ||
227 | /* | |
228 | * Set threshold and disable software override of stage 2 and 3 | |
229 | * shutdowns. | |
230 | */ | |
10c8251c DC |
231 | chip->thresh = THRESH_MIN; |
232 | reg &= ~(SHUTDOWN_CTRL1_OVERRIDE_MASK | SHUTDOWN_CTRL1_THRESHOLD_MASK); | |
233 | reg |= chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK; | |
c610afaa II |
234 | ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg); |
235 | if (ret < 0) | |
236 | return ret; | |
237 | ||
238 | /* Enable the thermal alarm PMIC module in always-on mode. */ | |
239 | reg = ALARM_CTRL_FORCE_ENABLE; | |
240 | ret = qpnp_tm_write(chip, QPNP_TM_REG_ALARM_CTRL, reg); | |
241 | ||
242 | return ret; | |
243 | } | |
244 | ||
245 | static int qpnp_tm_probe(struct platform_device *pdev) | |
246 | { | |
247 | struct qpnp_tm_chip *chip; | |
248 | struct device_node *node; | |
249 | u8 type, subtype; | |
cd323b2b | 250 | u32 res; |
c610afaa II |
251 | int ret, irq; |
252 | ||
253 | node = pdev->dev.of_node; | |
254 | ||
255 | chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); | |
256 | if (!chip) | |
257 | return -ENOMEM; | |
258 | ||
259 | dev_set_drvdata(&pdev->dev, chip); | |
260 | ||
261 | chip->map = dev_get_regmap(pdev->dev.parent, NULL); | |
262 | if (!chip->map) | |
263 | return -ENXIO; | |
264 | ||
cd323b2b | 265 | ret = of_property_read_u32(node, "reg", &res); |
c610afaa II |
266 | if (ret < 0) |
267 | return ret; | |
268 | ||
269 | irq = platform_get_irq(pdev, 0); | |
270 | if (irq < 0) | |
271 | return irq; | |
272 | ||
273 | /* ADC based measurements are optional */ | |
7a4ca51b DL |
274 | chip->adc = devm_iio_channel_get(&pdev->dev, "thermal"); |
275 | if (IS_ERR(chip->adc)) { | |
276 | ret = PTR_ERR(chip->adc); | |
277 | chip->adc = NULL; | |
278 | if (ret == -EPROBE_DEFER) | |
279 | return ret; | |
280 | } | |
c610afaa | 281 | |
cd323b2b | 282 | chip->base = res; |
c610afaa II |
283 | |
284 | ret = qpnp_tm_read(chip, QPNP_TM_REG_TYPE, &type); | |
285 | if (ret < 0) { | |
286 | dev_err(&pdev->dev, "could not read type\n"); | |
7a4ca51b | 287 | return ret; |
c610afaa II |
288 | } |
289 | ||
290 | ret = qpnp_tm_read(chip, QPNP_TM_REG_SUBTYPE, &subtype); | |
291 | if (ret < 0) { | |
292 | dev_err(&pdev->dev, "could not read subtype\n"); | |
7a4ca51b | 293 | return ret; |
c610afaa II |
294 | } |
295 | ||
10c8251c DC |
296 | if (type != QPNP_TM_TYPE || (subtype != QPNP_TM_SUBTYPE_GEN1 |
297 | && subtype != QPNP_TM_SUBTYPE_GEN2)) { | |
c610afaa II |
298 | dev_err(&pdev->dev, "invalid type 0x%02x or subtype 0x%02x\n", |
299 | type, subtype); | |
7a4ca51b | 300 | return -ENODEV; |
c610afaa II |
301 | } |
302 | ||
10c8251c DC |
303 | chip->subtype = subtype; |
304 | ||
c610afaa II |
305 | ret = qpnp_tm_init(chip); |
306 | if (ret < 0) { | |
307 | dev_err(&pdev->dev, "init failed\n"); | |
7a4ca51b | 308 | return ret; |
c610afaa II |
309 | } |
310 | ||
311 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, qpnp_tm_isr, | |
312 | IRQF_ONESHOT, node->name, chip); | |
313 | if (ret < 0) | |
7a4ca51b | 314 | return ret; |
c610afaa | 315 | |
e936491e | 316 | chip->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, chip, |
c610afaa II |
317 | &qpnp_tm_sensor_ops); |
318 | if (IS_ERR(chip->tz_dev)) { | |
319 | dev_err(&pdev->dev, "failed to register sensor\n"); | |
7a4ca51b | 320 | return PTR_ERR(chip->tz_dev); |
c610afaa II |
321 | } |
322 | ||
323 | return 0; | |
c610afaa II |
324 | } |
325 | ||
326 | static const struct of_device_id qpnp_tm_match_table[] = { | |
327 | { .compatible = "qcom,spmi-temp-alarm" }, | |
328 | { } | |
329 | }; | |
330 | MODULE_DEVICE_TABLE(of, qpnp_tm_match_table); | |
331 | ||
332 | static struct platform_driver qpnp_tm_driver = { | |
333 | .driver = { | |
334 | .name = "spmi-temp-alarm", | |
335 | .of_match_table = qpnp_tm_match_table, | |
336 | }, | |
337 | .probe = qpnp_tm_probe, | |
c610afaa II |
338 | }; |
339 | module_platform_driver(qpnp_tm_driver); | |
340 | ||
341 | MODULE_ALIAS("platform:spmi-temp-alarm"); | |
342 | MODULE_DESCRIPTION("QPNP PMIC Temperature Alarm driver"); | |
343 | MODULE_LICENSE("GPL v2"); |