Commit | Line | Data |
---|---|---|
c9545790 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1e426ffd KM |
2 | /* |
3 | * R-Car THS/TSC thermal sensor driver | |
4 | * | |
5 | * Copyright (C) 2012 Renesas Solutions Corp. | |
6 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | |
1e426ffd KM |
7 | */ |
8 | #include <linux/delay.h> | |
9 | #include <linux/err.h> | |
e0a5172e KM |
10 | #include <linux/irq.h> |
11 | #include <linux/interrupt.h> | |
1e426ffd KM |
12 | #include <linux/io.h> |
13 | #include <linux/module.h> | |
8b477ea5 | 14 | #include <linux/of_device.h> |
1e426ffd | 15 | #include <linux/platform_device.h> |
51d45d25 | 16 | #include <linux/pm_runtime.h> |
d2a73e22 | 17 | #include <linux/reboot.h> |
1e426ffd KM |
18 | #include <linux/slab.h> |
19 | #include <linux/spinlock.h> | |
20 | #include <linux/thermal.h> | |
21 | ||
64a411e8 KM |
22 | #include "thermal_hwmon.h" |
23 | ||
d2a73e22 | 24 | #define IDLE_INTERVAL 5000 |
25 | ||
e0a5172e KM |
26 | #define COMMON_STR 0x00 |
27 | #define COMMON_ENR 0x04 | |
28 | #define COMMON_INTMSK 0x0c | |
29 | ||
30 | #define REG_POSNEG 0x20 | |
31 | #define REG_FILONOFF 0x28 | |
e9137a58 KM |
32 | #define REG_THSCR 0x2c |
33 | #define REG_THSSR 0x30 | |
e0a5172e | 34 | #define REG_INTCTRL 0x34 |
1e426ffd KM |
35 | |
36 | /* THSCR */ | |
f8f53e18 | 37 | #define CPCTL (1 << 12) |
1e426ffd KM |
38 | |
39 | /* THSSR */ | |
40 | #define CTEMP 0x3f | |
41 | ||
3676d1dd KM |
42 | struct rcar_thermal_common { |
43 | void __iomem *base; | |
44 | struct device *dev; | |
45 | struct list_head head; | |
e0a5172e | 46 | spinlock_t lock; |
3676d1dd | 47 | }; |
1e426ffd | 48 | |
1969d9dc YK |
49 | struct rcar_thermal_chip { |
50 | unsigned int use_of_thermal : 1; | |
51 | unsigned int has_filonoff : 1; | |
52 | unsigned int irq_per_ch : 1; | |
53 | unsigned int needs_suspend_resume : 1; | |
54 | unsigned int nirqs; | |
20386f0d | 55 | unsigned int ctemp_bands; |
1969d9dc YK |
56 | }; |
57 | ||
58 | static const struct rcar_thermal_chip rcar_thermal = { | |
59 | .use_of_thermal = 0, | |
60 | .has_filonoff = 1, | |
61 | .irq_per_ch = 0, | |
62 | .needs_suspend_resume = 0, | |
63 | .nirqs = 1, | |
20386f0d | 64 | .ctemp_bands = 1, |
1969d9dc YK |
65 | }; |
66 | ||
67 | static const struct rcar_thermal_chip rcar_gen2_thermal = { | |
68 | .use_of_thermal = 1, | |
69 | .has_filonoff = 1, | |
70 | .irq_per_ch = 0, | |
71 | .needs_suspend_resume = 0, | |
72 | .nirqs = 1, | |
20386f0d | 73 | .ctemp_bands = 1, |
1969d9dc YK |
74 | }; |
75 | ||
76 | static const struct rcar_thermal_chip rcar_gen3_thermal = { | |
77 | .use_of_thermal = 1, | |
78 | .has_filonoff = 0, | |
79 | .irq_per_ch = 1, | |
80 | .needs_suspend_resume = 1, | |
81 | /* | |
82 | * The Gen3 chip has 3 interrupts, but this driver uses only 2 | |
83 | * interrupts to detect a temperature change, rise or fall. | |
84 | */ | |
85 | .nirqs = 2, | |
20386f0d | 86 | .ctemp_bands = 2, |
1969d9dc YK |
87 | }; |
88 | ||
1e426ffd KM |
89 | struct rcar_thermal_priv { |
90 | void __iomem *base; | |
3676d1dd KM |
91 | struct rcar_thermal_common *common; |
92 | struct thermal_zone_device *zone; | |
1969d9dc | 93 | const struct rcar_thermal_chip *chip; |
e0a5172e | 94 | struct delayed_work work; |
b2bbc6a2 | 95 | struct mutex lock; |
3676d1dd | 96 | struct list_head list; |
e0a5172e | 97 | int id; |
913015c6 | 98 | u32 ctemp; |
1e426ffd KM |
99 | }; |
100 | ||
3676d1dd KM |
101 | #define rcar_thermal_for_each_priv(pos, common) \ |
102 | list_for_each_entry(pos, &common->head, list) | |
103 | ||
c499703e | 104 | #define MCELSIUS(temp) ((temp) * 1000) |
9dde8f86 | 105 | #define rcar_zone_to_priv(zone) ((zone)->devdata) |
3676d1dd KM |
106 | #define rcar_priv_to_dev(priv) ((priv)->common->dev) |
107 | #define rcar_has_irq_support(priv) ((priv)->common->base) | |
e0a5172e KM |
108 | #define rcar_id_to_shift(priv) ((priv)->id * 8) |
109 | ||
ca1e4558 | 110 | static const struct of_device_id rcar_thermal_dt_ids[] = { |
1969d9dc YK |
111 | { |
112 | .compatible = "renesas,rcar-thermal", | |
113 | .data = &rcar_thermal, | |
114 | }, | |
115 | { | |
116 | .compatible = "renesas,rcar-gen2-thermal", | |
117 | .data = &rcar_gen2_thermal, | |
118 | }, | |
b8d3d112 FC |
119 | { |
120 | .compatible = "renesas,thermal-r8a774c0", | |
121 | .data = &rcar_gen3_thermal, | |
122 | }, | |
92ca366e SS |
123 | { |
124 | .compatible = "renesas,thermal-r8a77970", | |
125 | .data = &rcar_gen3_thermal, | |
126 | }, | |
e36e1300 YK |
127 | { |
128 | .compatible = "renesas,thermal-r8a77990", | |
129 | .data = &rcar_gen3_thermal, | |
130 | }, | |
1969d9dc YK |
131 | { |
132 | .compatible = "renesas,thermal-r8a77995", | |
133 | .data = &rcar_gen3_thermal, | |
134 | }, | |
ca1e4558 KM |
135 | {}, |
136 | }; | |
137 | MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids); | |
138 | ||
1e426ffd KM |
139 | /* |
140 | * basic functions | |
141 | */ | |
e9137a58 KM |
142 | #define rcar_thermal_common_read(c, r) \ |
143 | _rcar_thermal_common_read(c, COMMON_ ##r) | |
144 | static u32 _rcar_thermal_common_read(struct rcar_thermal_common *common, | |
145 | u32 reg) | |
146 | { | |
147 | return ioread32(common->base + reg); | |
148 | } | |
149 | ||
150 | #define rcar_thermal_common_write(c, r, d) \ | |
151 | _rcar_thermal_common_write(c, COMMON_ ##r, d) | |
152 | static void _rcar_thermal_common_write(struct rcar_thermal_common *common, | |
153 | u32 reg, u32 data) | |
154 | { | |
155 | iowrite32(data, common->base + reg); | |
156 | } | |
157 | ||
158 | #define rcar_thermal_common_bset(c, r, m, d) \ | |
159 | _rcar_thermal_common_bset(c, COMMON_ ##r, m, d) | |
160 | static void _rcar_thermal_common_bset(struct rcar_thermal_common *common, | |
161 | u32 reg, u32 mask, u32 data) | |
162 | { | |
163 | u32 val; | |
164 | ||
165 | val = ioread32(common->base + reg); | |
166 | val &= ~mask; | |
167 | val |= (data & mask); | |
168 | iowrite32(val, common->base + reg); | |
169 | } | |
e9137a58 KM |
170 | |
171 | #define rcar_thermal_read(p, r) _rcar_thermal_read(p, REG_ ##r) | |
172 | static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg) | |
1e426ffd | 173 | { |
b2bbc6a2 | 174 | return ioread32(priv->base + reg); |
1e426ffd KM |
175 | } |
176 | ||
e9137a58 KM |
177 | #define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, REG_ ##r, d) |
178 | static void _rcar_thermal_write(struct rcar_thermal_priv *priv, | |
179 | u32 reg, u32 data) | |
1e426ffd | 180 | { |
1e426ffd | 181 | iowrite32(data, priv->base + reg); |
1e426ffd | 182 | } |
1e426ffd | 183 | |
e9137a58 KM |
184 | #define rcar_thermal_bset(p, r, m, d) _rcar_thermal_bset(p, REG_ ##r, m, d) |
185 | static void _rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg, | |
186 | u32 mask, u32 data) | |
1e426ffd | 187 | { |
1e426ffd KM |
188 | u32 val; |
189 | ||
1e426ffd KM |
190 | val = ioread32(priv->base + reg); |
191 | val &= ~mask; | |
192 | val |= (data & mask); | |
193 | iowrite32(val, priv->base + reg); | |
1e426ffd KM |
194 | } |
195 | ||
196 | /* | |
197 | * zone device functions | |
198 | */ | |
e0a5172e | 199 | static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv) |
1e426ffd | 200 | { |
f8f53e18 KM |
201 | struct device *dev = rcar_priv_to_dev(priv); |
202 | int i; | |
913015c6 | 203 | u32 ctemp, old, new; |
f0e68fc3 | 204 | int ret = -EINVAL; |
f8f53e18 | 205 | |
b2bbc6a2 KM |
206 | mutex_lock(&priv->lock); |
207 | ||
f8f53e18 KM |
208 | /* |
209 | * TSC decides a value of CPTAP automatically, | |
210 | * and this is the conditions which validate interrupt. | |
211 | */ | |
212 | rcar_thermal_bset(priv, THSCR, CPCTL, CPCTL); | |
213 | ||
214 | ctemp = 0; | |
215 | old = ~0; | |
216 | for (i = 0; i < 128; i++) { | |
1e426ffd KM |
217 | /* |
218 | * we need to wait 300us after changing comparator offset | |
219 | * to get stable temperature. | |
220 | * see "Usage Notes" on datasheet | |
221 | */ | |
1e426ffd KM |
222 | udelay(300); |
223 | ||
f8f53e18 KM |
224 | new = rcar_thermal_read(priv, THSSR) & CTEMP; |
225 | if (new == old) { | |
226 | ctemp = new; | |
1e426ffd KM |
227 | break; |
228 | } | |
f8f53e18 | 229 | old = new; |
1e426ffd KM |
230 | } |
231 | ||
f8f53e18 KM |
232 | if (!ctemp) { |
233 | dev_err(dev, "thermal sensor was broken\n"); | |
f0e68fc3 | 234 | goto err_out_unlock; |
f8f53e18 KM |
235 | } |
236 | ||
e0a5172e KM |
237 | /* |
238 | * enable IRQ | |
239 | */ | |
240 | if (rcar_has_irq_support(priv)) { | |
1969d9dc YK |
241 | if (priv->chip->has_filonoff) |
242 | rcar_thermal_write(priv, FILONOFF, 0); | |
e0a5172e KM |
243 | |
244 | /* enable Rising/Falling edge interrupt */ | |
245 | rcar_thermal_write(priv, POSNEG, 0x1); | |
246 | rcar_thermal_write(priv, INTCTRL, (((ctemp - 0) << 8) | | |
247 | ((ctemp - 1) << 0))); | |
248 | } | |
249 | ||
250 | dev_dbg(dev, "thermal%d %d -> %d\n", priv->id, priv->ctemp, ctemp); | |
251 | ||
252 | priv->ctemp = ctemp; | |
f0e68fc3 WY |
253 | ret = 0; |
254 | err_out_unlock: | |
b2bbc6a2 | 255 | mutex_unlock(&priv->lock); |
f0e68fc3 | 256 | return ret; |
1e426ffd KM |
257 | } |
258 | ||
8b477ea5 KM |
259 | static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv, |
260 | int *temp) | |
e0a5172e | 261 | { |
5440c40b | 262 | int tmp; |
a1ade565 | 263 | int ret; |
e0a5172e | 264 | |
a1ade565 KM |
265 | ret = rcar_thermal_update_temp(priv); |
266 | if (ret < 0) | |
267 | return ret; | |
e0a5172e KM |
268 | |
269 | mutex_lock(&priv->lock); | |
20386f0d YK |
270 | if (priv->chip->ctemp_bands == 1) |
271 | tmp = MCELSIUS((priv->ctemp * 5) - 65); | |
272 | else if (priv->ctemp < 24) | |
273 | tmp = MCELSIUS(((priv->ctemp * 55) - 720) / 10); | |
274 | else | |
275 | tmp = MCELSIUS((priv->ctemp * 5) - 60); | |
e0a5172e KM |
276 | mutex_unlock(&priv->lock); |
277 | ||
5440c40b KM |
278 | if ((tmp < MCELSIUS(-45)) || (tmp > MCELSIUS(125))) { |
279 | struct device *dev = rcar_priv_to_dev(priv); | |
280 | ||
281 | dev_err(dev, "it couldn't measure temperature correctly\n"); | |
282 | return -EIO; | |
283 | } | |
284 | ||
285 | *temp = tmp; | |
286 | ||
e0a5172e KM |
287 | return 0; |
288 | } | |
289 | ||
8b477ea5 KM |
290 | static int rcar_thermal_of_get_temp(void *data, int *temp) |
291 | { | |
292 | struct rcar_thermal_priv *priv = data; | |
293 | ||
294 | return rcar_thermal_get_current_temp(priv, temp); | |
295 | } | |
296 | ||
297 | static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp) | |
298 | { | |
299 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); | |
300 | ||
301 | return rcar_thermal_get_current_temp(priv, temp); | |
302 | } | |
303 | ||
d2a73e22 | 304 | static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone, |
305 | int trip, enum thermal_trip_type *type) | |
306 | { | |
307 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); | |
3676d1dd | 308 | struct device *dev = rcar_priv_to_dev(priv); |
d2a73e22 | 309 | |
310 | /* see rcar_thermal_get_temp() */ | |
311 | switch (trip) { | |
312 | case 0: /* +90 <= temp */ | |
313 | *type = THERMAL_TRIP_CRITICAL; | |
314 | break; | |
315 | default: | |
3676d1dd | 316 | dev_err(dev, "rcar driver trip error\n"); |
d2a73e22 | 317 | return -EINVAL; |
318 | } | |
319 | ||
320 | return 0; | |
321 | } | |
322 | ||
323 | static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone, | |
17e8351a | 324 | int trip, int *temp) |
d2a73e22 | 325 | { |
326 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); | |
3676d1dd | 327 | struct device *dev = rcar_priv_to_dev(priv); |
d2a73e22 | 328 | |
329 | /* see rcar_thermal_get_temp() */ | |
330 | switch (trip) { | |
331 | case 0: /* +90 <= temp */ | |
332 | *temp = MCELSIUS(90); | |
333 | break; | |
334 | default: | |
3676d1dd | 335 | dev_err(dev, "rcar driver trip error\n"); |
d2a73e22 | 336 | return -EINVAL; |
337 | } | |
338 | ||
339 | return 0; | |
340 | } | |
341 | ||
342 | static int rcar_thermal_notify(struct thermal_zone_device *zone, | |
343 | int trip, enum thermal_trip_type type) | |
344 | { | |
345 | struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone); | |
3676d1dd | 346 | struct device *dev = rcar_priv_to_dev(priv); |
d2a73e22 | 347 | |
348 | switch (type) { | |
349 | case THERMAL_TRIP_CRITICAL: | |
350 | /* FIXME */ | |
3676d1dd | 351 | dev_warn(dev, "Thermal reached to critical temperature\n"); |
d2a73e22 | 352 | break; |
353 | default: | |
354 | break; | |
355 | } | |
356 | ||
357 | return 0; | |
358 | } | |
359 | ||
8b477ea5 KM |
360 | static const struct thermal_zone_of_device_ops rcar_thermal_zone_of_ops = { |
361 | .get_temp = rcar_thermal_of_get_temp, | |
362 | }; | |
363 | ||
1e426ffd | 364 | static struct thermal_zone_device_ops rcar_thermal_zone_ops = { |
d2a73e22 | 365 | .get_temp = rcar_thermal_get_temp, |
366 | .get_trip_type = rcar_thermal_get_trip_type, | |
367 | .get_trip_temp = rcar_thermal_get_trip_temp, | |
368 | .notify = rcar_thermal_notify, | |
1e426ffd KM |
369 | }; |
370 | ||
e0a5172e KM |
371 | /* |
372 | * interrupt | |
373 | */ | |
374 | #define rcar_thermal_irq_enable(p) _rcar_thermal_irq_ctrl(p, 1) | |
375 | #define rcar_thermal_irq_disable(p) _rcar_thermal_irq_ctrl(p, 0) | |
376 | static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable) | |
377 | { | |
378 | struct rcar_thermal_common *common = priv->common; | |
379 | unsigned long flags; | |
380 | u32 mask = 0x3 << rcar_id_to_shift(priv); /* enable Rising/Falling */ | |
381 | ||
ffbcdf8a KM |
382 | if (!rcar_has_irq_support(priv)) |
383 | return; | |
384 | ||
e0a5172e KM |
385 | spin_lock_irqsave(&common->lock, flags); |
386 | ||
387 | rcar_thermal_common_bset(common, INTMSK, mask, enable ? 0 : mask); | |
388 | ||
389 | spin_unlock_irqrestore(&common->lock, flags); | |
390 | } | |
391 | ||
392 | static void rcar_thermal_work(struct work_struct *work) | |
393 | { | |
394 | struct rcar_thermal_priv *priv; | |
17e8351a | 395 | int cctemp, nctemp; |
a1ade565 | 396 | int ret; |
e0a5172e KM |
397 | |
398 | priv = container_of(work, struct rcar_thermal_priv, work.work); | |
399 | ||
8b477ea5 KM |
400 | ret = rcar_thermal_get_current_temp(priv, &cctemp); |
401 | if (ret < 0) | |
402 | return; | |
403 | ||
a1ade565 KM |
404 | ret = rcar_thermal_update_temp(priv); |
405 | if (ret < 0) | |
406 | return; | |
407 | ||
e0a5172e | 408 | rcar_thermal_irq_enable(priv); |
9477165e | 409 | |
8b477ea5 KM |
410 | ret = rcar_thermal_get_current_temp(priv, &nctemp); |
411 | if (ret < 0) | |
412 | return; | |
413 | ||
9477165e | 414 | if (nctemp != cctemp) |
0e70f466 SP |
415 | thermal_zone_device_update(priv->zone, |
416 | THERMAL_EVENT_UNSPECIFIED); | |
e0a5172e KM |
417 | } |
418 | ||
419 | static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status) | |
420 | { | |
421 | struct device *dev = rcar_priv_to_dev(priv); | |
422 | ||
423 | status = (status >> rcar_id_to_shift(priv)) & 0x3; | |
424 | ||
206c0cba | 425 | if (status) { |
e0a5172e KM |
426 | dev_dbg(dev, "thermal%d %s%s\n", |
427 | priv->id, | |
428 | (status & 0x2) ? "Rising " : "", | |
429 | (status & 0x1) ? "Falling" : ""); | |
430 | } | |
431 | ||
432 | return status; | |
433 | } | |
434 | ||
435 | static irqreturn_t rcar_thermal_irq(int irq, void *data) | |
436 | { | |
437 | struct rcar_thermal_common *common = data; | |
438 | struct rcar_thermal_priv *priv; | |
439 | unsigned long flags; | |
440 | u32 status, mask; | |
441 | ||
442 | spin_lock_irqsave(&common->lock, flags); | |
443 | ||
444 | mask = rcar_thermal_common_read(common, INTMSK); | |
445 | status = rcar_thermal_common_read(common, STR); | |
446 | rcar_thermal_common_write(common, STR, 0x000F0F0F & mask); | |
447 | ||
448 | spin_unlock_irqrestore(&common->lock, flags); | |
449 | ||
450 | status = status & ~mask; | |
451 | ||
452 | /* | |
453 | * check the status | |
454 | */ | |
455 | rcar_thermal_for_each_priv(priv, common) { | |
456 | if (rcar_thermal_had_changed(priv, status)) { | |
457 | rcar_thermal_irq_disable(priv); | |
3a313862 GU |
458 | queue_delayed_work(system_freezable_wq, &priv->work, |
459 | msecs_to_jiffies(300)); | |
e0a5172e KM |
460 | } |
461 | } | |
462 | ||
463 | return IRQ_HANDLED; | |
464 | } | |
465 | ||
1e426ffd KM |
466 | /* |
467 | * platform functions | |
468 | */ | |
84f0e490 KM |
469 | static int rcar_thermal_remove(struct platform_device *pdev) |
470 | { | |
471 | struct rcar_thermal_common *common = platform_get_drvdata(pdev); | |
472 | struct device *dev = &pdev->dev; | |
473 | struct rcar_thermal_priv *priv; | |
474 | ||
475 | rcar_thermal_for_each_priv(priv, common) { | |
ffbcdf8a | 476 | rcar_thermal_irq_disable(priv); |
697ee786 | 477 | cancel_delayed_work_sync(&priv->work); |
1969d9dc | 478 | if (priv->chip->use_of_thermal) |
64a411e8 | 479 | thermal_remove_hwmon_sysfs(priv->zone); |
d4b23c5c BDP |
480 | else |
481 | thermal_zone_device_unregister(priv->zone); | |
84f0e490 KM |
482 | } |
483 | ||
484 | pm_runtime_put(dev); | |
485 | pm_runtime_disable(dev); | |
486 | ||
487 | return 0; | |
488 | } | |
489 | ||
1e426ffd KM |
490 | static int rcar_thermal_probe(struct platform_device *pdev) |
491 | { | |
3676d1dd | 492 | struct rcar_thermal_common *common; |
1e426ffd | 493 | struct rcar_thermal_priv *priv; |
3676d1dd KM |
494 | struct device *dev = &pdev->dev; |
495 | struct resource *res, *irq; | |
1969d9dc | 496 | const struct rcar_thermal_chip *chip = of_device_get_match_data(dev); |
3676d1dd KM |
497 | int mres = 0; |
498 | int i; | |
fb84d990 | 499 | int ret = -ENODEV; |
e0a5172e | 500 | int idle = IDLE_INTERVAL; |
11313746 | 501 | u32 enr_bits = 0; |
1e426ffd | 502 | |
3676d1dd | 503 | common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL); |
b0a60d88 | 504 | if (!common) |
1e426ffd | 505 | return -ENOMEM; |
1e426ffd | 506 | |
84f0e490 KM |
507 | platform_set_drvdata(pdev, common); |
508 | ||
3676d1dd | 509 | INIT_LIST_HEAD(&common->head); |
e0a5172e | 510 | spin_lock_init(&common->lock); |
3676d1dd KM |
511 | common->dev = dev; |
512 | ||
51d45d25 KM |
513 | pm_runtime_enable(dev); |
514 | pm_runtime_get_sync(dev); | |
515 | ||
1969d9dc | 516 | for (i = 0; i < chip->nirqs; i++) { |
df016bbb | 517 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, i); |
1969d9dc YK |
518 | if (!irq) |
519 | continue; | |
520 | if (!common->base) { | |
521 | /* | |
522 | * platform has IRQ support. | |
523 | * Then, driver uses common registers | |
524 | * rcar_has_irq_support() will be enabled | |
525 | */ | |
526 | res = platform_get_resource(pdev, IORESOURCE_MEM, | |
527 | mres++); | |
528 | common->base = devm_ioremap_resource(dev, res); | |
529 | if (IS_ERR(common->base)) | |
530 | return PTR_ERR(common->base); | |
531 | ||
532 | idle = 0; /* polling delay is not needed */ | |
533 | } | |
e0a5172e | 534 | |
1969d9dc YK |
535 | ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, |
536 | IRQF_SHARED, dev_name(dev), common); | |
537 | if (ret) { | |
538 | dev_err(dev, "irq request failed\n "); | |
539 | goto error_unregister; | |
540 | } | |
541 | ||
542 | /* update ENR bits */ | |
543 | if (chip->irq_per_ch) | |
544 | enr_bits |= 1 << i; | |
1e426ffd KM |
545 | } |
546 | ||
3676d1dd KM |
547 | for (i = 0;; i++) { |
548 | res = platform_get_resource(pdev, IORESOURCE_MEM, mres++); | |
549 | if (!res) | |
550 | break; | |
551 | ||
552 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
553 | if (!priv) { | |
1dc20828 KM |
554 | ret = -ENOMEM; |
555 | goto error_unregister; | |
3676d1dd KM |
556 | } |
557 | ||
5095526f | 558 | priv->base = devm_ioremap_resource(dev, res); |
1dc20828 KM |
559 | if (IS_ERR(priv->base)) { |
560 | ret = PTR_ERR(priv->base); | |
561 | goto error_unregister; | |
562 | } | |
3676d1dd KM |
563 | |
564 | priv->common = common; | |
e0a5172e | 565 | priv->id = i; |
1969d9dc | 566 | priv->chip = chip; |
3676d1dd KM |
567 | mutex_init(&priv->lock); |
568 | INIT_LIST_HEAD(&priv->list); | |
e0a5172e | 569 | INIT_DELAYED_WORK(&priv->work, rcar_thermal_work); |
a1ade565 KM |
570 | ret = rcar_thermal_update_temp(priv); |
571 | if (ret < 0) | |
572 | goto error_unregister; | |
3676d1dd | 573 | |
1969d9dc | 574 | if (chip->use_of_thermal) |
5e325868 | 575 | priv->zone = devm_thermal_zone_of_sensor_register( |
8b477ea5 KM |
576 | dev, i, priv, |
577 | &rcar_thermal_zone_of_ops); | |
578 | else | |
579 | priv->zone = thermal_zone_device_register( | |
580 | "rcar_thermal", | |
3676d1dd KM |
581 | 1, 0, priv, |
582 | &rcar_thermal_zone_ops, NULL, 0, | |
e0a5172e | 583 | idle); |
3676d1dd KM |
584 | if (IS_ERR(priv->zone)) { |
585 | dev_err(dev, "can't register thermal zone\n"); | |
fb84d990 | 586 | ret = PTR_ERR(priv->zone); |
87260d3f | 587 | priv->zone = NULL; |
3676d1dd KM |
588 | goto error_unregister; |
589 | } | |
590 | ||
1969d9dc | 591 | if (chip->use_of_thermal) { |
64a411e8 KM |
592 | /* |
593 | * thermal_zone doesn't enable hwmon as default, | |
594 | * but, enable it here to keep compatible | |
595 | */ | |
596 | priv->zone->tzp->no_hwmon = false; | |
597 | ret = thermal_add_hwmon_sysfs(priv->zone); | |
598 | if (ret) | |
599 | goto error_unregister; | |
600 | } | |
601 | ||
ffbcdf8a | 602 | rcar_thermal_irq_enable(priv); |
1dc20828 KM |
603 | |
604 | list_move_tail(&priv->list, &common->head); | |
11313746 YS |
605 | |
606 | /* update ENR bits */ | |
1969d9dc YK |
607 | if (!chip->irq_per_ch) |
608 | enr_bits |= 3 << (i * 8); | |
1e426ffd KM |
609 | } |
610 | ||
542cdf40 | 611 | if (common->base && enr_bits) |
11313746 YS |
612 | rcar_thermal_common_write(common, ENR, enr_bits); |
613 | ||
3db46c93 | 614 | dev_info(dev, "%d sensor probed\n", i); |
1e426ffd KM |
615 | |
616 | return 0; | |
3676d1dd KM |
617 | |
618 | error_unregister: | |
84f0e490 | 619 | rcar_thermal_remove(pdev); |
51d45d25 | 620 | |
fb84d990 | 621 | return ret; |
1e426ffd KM |
622 | } |
623 | ||
1969d9dc YK |
624 | #ifdef CONFIG_PM_SLEEP |
625 | static int rcar_thermal_suspend(struct device *dev) | |
626 | { | |
627 | struct rcar_thermal_common *common = dev_get_drvdata(dev); | |
628 | struct rcar_thermal_priv *priv = list_first_entry(&common->head, | |
629 | typeof(*priv), list); | |
630 | ||
631 | if (priv->chip->needs_suspend_resume) { | |
632 | rcar_thermal_common_write(common, ENR, 0); | |
633 | rcar_thermal_irq_disable(priv); | |
634 | rcar_thermal_bset(priv, THSCR, CPCTL, 0); | |
635 | } | |
636 | ||
637 | return 0; | |
638 | } | |
639 | ||
640 | static int rcar_thermal_resume(struct device *dev) | |
641 | { | |
642 | struct rcar_thermal_common *common = dev_get_drvdata(dev); | |
643 | struct rcar_thermal_priv *priv = list_first_entry(&common->head, | |
644 | typeof(*priv), list); | |
645 | int ret; | |
646 | ||
647 | if (priv->chip->needs_suspend_resume) { | |
648 | ret = rcar_thermal_update_temp(priv); | |
649 | if (ret < 0) | |
650 | return ret; | |
651 | rcar_thermal_irq_enable(priv); | |
652 | rcar_thermal_common_write(common, ENR, 0x03); | |
653 | } | |
654 | ||
655 | return 0; | |
656 | } | |
657 | #endif | |
658 | ||
659 | static SIMPLE_DEV_PM_OPS(rcar_thermal_pm_ops, rcar_thermal_suspend, | |
660 | rcar_thermal_resume); | |
661 | ||
1e426ffd KM |
662 | static struct platform_driver rcar_thermal_driver = { |
663 | .driver = { | |
664 | .name = "rcar_thermal", | |
1969d9dc | 665 | .pm = &rcar_thermal_pm_ops, |
76cc1887 | 666 | .of_match_table = rcar_thermal_dt_ids, |
1e426ffd KM |
667 | }, |
668 | .probe = rcar_thermal_probe, | |
669 | .remove = rcar_thermal_remove, | |
670 | }; | |
671 | module_platform_driver(rcar_thermal_driver); | |
672 | ||
c9545790 | 673 | MODULE_LICENSE("GPL v2"); |
1e426ffd KM |
674 | MODULE_DESCRIPTION("R-Car THS/TSC thermal sensor driver"); |
675 | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); |