aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal/rcar_thermal.c
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2013-01-31 04:04:48 -0500
committerZhang Rui <rui.zhang@intel.com>2013-02-06 01:13:59 -0500
commite0a5172e9eec7f0d3c476e013c51dab62f3fc666 (patch)
tree56423e2ccf4bb3682d15e458b4cc58b0129a6332 /drivers/thermal/rcar_thermal.c
parente9137a582fcbe36d9dedb8d7f6902a059154b14e (diff)
thermal: rcar: add interrupt support
This patch adds interrupt support for R-Car thermal driver. New generation R-Car thermal sensor interrupt controller was different from old generation. This patch supports new generation sensor only, since the old generation interrupt controller had never been used before, and will never be used in the future. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Diffstat (limited to 'drivers/thermal/rcar_thermal.c')
-rw-r--r--drivers/thermal/rcar_thermal.c159
1 files changed, 150 insertions, 9 deletions
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index cf6aa98956b9..80aae3cf65eb 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -19,6 +19,8 @@
19 */ 19 */
20#include <linux/delay.h> 20#include <linux/delay.h>
21#include <linux/err.h> 21#include <linux/err.h>
22#include <linux/irq.h>
23#include <linux/interrupt.h>
22#include <linux/io.h> 24#include <linux/io.h>
23#include <linux/module.h> 25#include <linux/module.h>
24#include <linux/platform_device.h> 26#include <linux/platform_device.h>
@@ -29,8 +31,15 @@
29 31
30#define IDLE_INTERVAL 5000 32#define IDLE_INTERVAL 5000
31 33
34#define COMMON_STR 0x00
35#define COMMON_ENR 0x04
36#define COMMON_INTMSK 0x0c
37
38#define REG_POSNEG 0x20
39#define REG_FILONOFF 0x28
32#define REG_THSCR 0x2c 40#define REG_THSCR 0x2c
33#define REG_THSSR 0x30 41#define REG_THSSR 0x30
42#define REG_INTCTRL 0x34
34 43
35/* THSCR */ 44/* THSCR */
36#define CPCTL (1 << 12) 45#define CPCTL (1 << 12)
@@ -42,14 +51,18 @@ struct rcar_thermal_common {
42 void __iomem *base; 51 void __iomem *base;
43 struct device *dev; 52 struct device *dev;
44 struct list_head head; 53 struct list_head head;
54 spinlock_t lock;
45}; 55};
46 56
47struct rcar_thermal_priv { 57struct rcar_thermal_priv {
48 void __iomem *base; 58 void __iomem *base;
49 struct rcar_thermal_common *common; 59 struct rcar_thermal_common *common;
50 struct thermal_zone_device *zone; 60 struct thermal_zone_device *zone;
61 struct delayed_work work;
51 struct mutex lock; 62 struct mutex lock;
52 struct list_head list; 63 struct list_head list;
64 int id;
65 int ctemp;
53}; 66};
54 67
55#define rcar_thermal_for_each_priv(pos, common) \ 68#define rcar_thermal_for_each_priv(pos, common) \
@@ -59,11 +72,17 @@ struct rcar_thermal_priv {
59#define rcar_zone_to_priv(zone) ((zone)->devdata) 72#define rcar_zone_to_priv(zone) ((zone)->devdata)
60#define rcar_priv_to_dev(priv) ((priv)->common->dev) 73#define rcar_priv_to_dev(priv) ((priv)->common->dev)
61#define rcar_has_irq_support(priv) ((priv)->common->base) 74#define rcar_has_irq_support(priv) ((priv)->common->base)
75#define rcar_id_to_shift(priv) ((priv)->id * 8)
76
77#ifdef DEBUG
78# define rcar_force_update_temp(priv) 1
79#else
80# define rcar_force_update_temp(priv) 0
81#endif
62 82
63/* 83/*
64 * basic functions 84 * basic functions
65 */ 85 */
66#if 0
67#define rcar_thermal_common_read(c, r) \ 86#define rcar_thermal_common_read(c, r) \
68 _rcar_thermal_common_read(c, COMMON_ ##r) 87 _rcar_thermal_common_read(c, COMMON_ ##r)
69static u32 _rcar_thermal_common_read(struct rcar_thermal_common *common, 88static u32 _rcar_thermal_common_read(struct rcar_thermal_common *common,
@@ -92,7 +111,6 @@ static void _rcar_thermal_common_bset(struct rcar_thermal_common *common,
92 val |= (data & mask); 111 val |= (data & mask);
93 iowrite32(val, common->base + reg); 112 iowrite32(val, common->base + reg);
94} 113}
95#endif
96 114
97#define rcar_thermal_read(p, r) _rcar_thermal_read(p, REG_ ##r) 115#define rcar_thermal_read(p, r) _rcar_thermal_read(p, REG_ ##r)
98static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg) 116static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
@@ -100,14 +118,12 @@ static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
100 return ioread32(priv->base + reg); 118 return ioread32(priv->base + reg);
101} 119}
102 120
103#if 0 /* no user at this point */
104#define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, REG_ ##r, d) 121#define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, REG_ ##r, d)
105static void _rcar_thermal_write(struct rcar_thermal_priv *priv, 122static void _rcar_thermal_write(struct rcar_thermal_priv *priv,
106 u32 reg, u32 data) 123 u32 reg, u32 data)
107{ 124{
108 iowrite32(data, priv->base + reg); 125 iowrite32(data, priv->base + reg);
109} 126}
110#endif
111 127
112#define rcar_thermal_bset(p, r, m, d) _rcar_thermal_bset(p, REG_ ##r, m, d) 128#define rcar_thermal_bset(p, r, m, d) _rcar_thermal_bset(p, REG_ ##r, m, d)
113static void _rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg, 129static void _rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
@@ -124,10 +140,8 @@ static void _rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
124/* 140/*
125 * zone device functions 141 * zone device functions
126 */ 142 */
127static int rcar_thermal_get_temp(struct thermal_zone_device *zone, 143static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
128 unsigned long *temp)
129{ 144{
130 struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
131 struct device *dev = rcar_priv_to_dev(priv); 145 struct device *dev = rcar_priv_to_dev(priv);
132 int i; 146 int i;
133 int ctemp, old, new; 147 int ctemp, old, new;
@@ -163,13 +177,42 @@ static int rcar_thermal_get_temp(struct thermal_zone_device *zone,
163 return -EINVAL; 177 return -EINVAL;
164 } 178 }
165 179
166 *temp = MCELSIUS((ctemp * 5) - 65); 180 /*
181 * enable IRQ
182 */
183 if (rcar_has_irq_support(priv)) {
184 rcar_thermal_write(priv, FILONOFF, 0);
185
186 /* enable Rising/Falling edge interrupt */
187 rcar_thermal_write(priv, POSNEG, 0x1);
188 rcar_thermal_write(priv, INTCTRL, (((ctemp - 0) << 8) |
189 ((ctemp - 1) << 0)));
190 }
191
192 dev_dbg(dev, "thermal%d %d -> %d\n", priv->id, priv->ctemp, ctemp);
193
194 priv->ctemp = ctemp;
167 195
168 mutex_unlock(&priv->lock); 196 mutex_unlock(&priv->lock);
169 197
170 return 0; 198 return 0;
171} 199}
172 200
201static int rcar_thermal_get_temp(struct thermal_zone_device *zone,
202 unsigned long *temp)
203{
204 struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
205
206 if (!rcar_has_irq_support(priv) || rcar_force_update_temp(priv))
207 rcar_thermal_update_temp(priv);
208
209 mutex_lock(&priv->lock);
210 *temp = MCELSIUS((priv->ctemp * 5) - 65);
211 mutex_unlock(&priv->lock);
212
213 return 0;
214}
215
173static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone, 216static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
174 int trip, enum thermal_trip_type *type) 217 int trip, enum thermal_trip_type *type)
175{ 218{
@@ -235,6 +278,82 @@ static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
235}; 278};
236 279
237/* 280/*
281 * interrupt
282 */
283#define rcar_thermal_irq_enable(p) _rcar_thermal_irq_ctrl(p, 1)
284#define rcar_thermal_irq_disable(p) _rcar_thermal_irq_ctrl(p, 0)
285static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
286{
287 struct rcar_thermal_common *common = priv->common;
288 unsigned long flags;
289 u32 mask = 0x3 << rcar_id_to_shift(priv); /* enable Rising/Falling */
290
291 spin_lock_irqsave(&common->lock, flags);
292
293 rcar_thermal_common_bset(common, INTMSK, mask, enable ? 0 : mask);
294
295 spin_unlock_irqrestore(&common->lock, flags);
296}
297
298static void rcar_thermal_work(struct work_struct *work)
299{
300 struct rcar_thermal_priv *priv;
301
302 priv = container_of(work, struct rcar_thermal_priv, work.work);
303
304 rcar_thermal_update_temp(priv);
305 rcar_thermal_irq_enable(priv);
306 thermal_zone_device_update(priv->zone);
307}
308
309static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
310{
311 struct device *dev = rcar_priv_to_dev(priv);
312
313 status = (status >> rcar_id_to_shift(priv)) & 0x3;
314
315 if (status & 0x3) {
316 dev_dbg(dev, "thermal%d %s%s\n",
317 priv->id,
318 (status & 0x2) ? "Rising " : "",
319 (status & 0x1) ? "Falling" : "");
320 }
321
322 return status;
323}
324
325static irqreturn_t rcar_thermal_irq(int irq, void *data)
326{
327 struct rcar_thermal_common *common = data;
328 struct rcar_thermal_priv *priv;
329 unsigned long flags;
330 u32 status, mask;
331
332 spin_lock_irqsave(&common->lock, flags);
333
334 mask = rcar_thermal_common_read(common, INTMSK);
335 status = rcar_thermal_common_read(common, STR);
336 rcar_thermal_common_write(common, STR, 0x000F0F0F & mask);
337
338 spin_unlock_irqrestore(&common->lock, flags);
339
340 status = status & ~mask;
341
342 /*
343 * check the status
344 */
345 rcar_thermal_for_each_priv(priv, common) {
346 if (rcar_thermal_had_changed(priv, status)) {
347 rcar_thermal_irq_disable(priv);
348 schedule_delayed_work(&priv->work,
349 msecs_to_jiffies(300));
350 }
351 }
352
353 return IRQ_HANDLED;
354}
355
356/*
238 * platform functions 357 * platform functions
239 */ 358 */
240static int rcar_thermal_probe(struct platform_device *pdev) 359static int rcar_thermal_probe(struct platform_device *pdev)
@@ -245,6 +364,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
245 struct resource *res, *irq; 364 struct resource *res, *irq;
246 int mres = 0; 365 int mres = 0;
247 int i; 366 int i;
367 int idle = IDLE_INTERVAL;
248 368
249 common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL); 369 common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
250 if (!common) { 370 if (!common) {
@@ -253,10 +373,13 @@ static int rcar_thermal_probe(struct platform_device *pdev)
253 } 373 }
254 374
255 INIT_LIST_HEAD(&common->head); 375 INIT_LIST_HEAD(&common->head);
376 spin_lock_init(&common->lock);
256 common->dev = dev; 377 common->dev = dev;
257 378
258 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 379 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
259 if (irq) { 380 if (irq) {
381 int ret;
382
260 /* 383 /*
261 * platform has IRQ support. 384 * platform has IRQ support.
262 * Then, drier use common register 385 * Then, drier use common register
@@ -267,6 +390,13 @@ static int rcar_thermal_probe(struct platform_device *pdev)
267 return -ENODEV; 390 return -ENODEV;
268 } 391 }
269 392
393 ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
394 dev_name(dev), common);
395 if (ret) {
396 dev_err(dev, "irq request failed\n ");
397 return ret;
398 }
399
270 /* 400 /*
271 * rcar_has_irq_support() will be enabled 401 * rcar_has_irq_support() will be enabled
272 */ 402 */
@@ -275,6 +405,11 @@ static int rcar_thermal_probe(struct platform_device *pdev)
275 dev_err(dev, "Unable to ioremap thermal register\n"); 405 dev_err(dev, "Unable to ioremap thermal register\n");
276 return -ENOMEM; 406 return -ENOMEM;
277 } 407 }
408
409 /* enable temperature comparation */
410 rcar_thermal_common_write(common, ENR, 0x00030303);
411
412 idle = 0; /* polling delaye is not needed */
278 } 413 }
279 414
280 for (i = 0;; i++) { 415 for (i = 0;; i++) {
@@ -295,19 +430,25 @@ static int rcar_thermal_probe(struct platform_device *pdev)
295 } 430 }
296 431
297 priv->common = common; 432 priv->common = common;
433 priv->id = i;
298 mutex_init(&priv->lock); 434 mutex_init(&priv->lock);
299 INIT_LIST_HEAD(&priv->list); 435 INIT_LIST_HEAD(&priv->list);
436 INIT_DELAYED_WORK(&priv->work, rcar_thermal_work);
437 rcar_thermal_update_temp(priv);
300 438
301 priv->zone = thermal_zone_device_register("rcar_thermal", 439 priv->zone = thermal_zone_device_register("rcar_thermal",
302 1, 0, priv, 440 1, 0, priv,
303 &rcar_thermal_zone_ops, NULL, 0, 441 &rcar_thermal_zone_ops, NULL, 0,
304 IDLE_INTERVAL); 442 idle);
305 if (IS_ERR(priv->zone)) { 443 if (IS_ERR(priv->zone)) {
306 dev_err(dev, "can't register thermal zone\n"); 444 dev_err(dev, "can't register thermal zone\n");
307 goto error_unregister; 445 goto error_unregister;
308 } 446 }
309 447
310 list_move_tail(&priv->list, &common->head); 448 list_move_tail(&priv->list, &common->head);
449
450 if (rcar_has_irq_support(priv))
451 rcar_thermal_irq_enable(priv);
311 } 452 }
312 453
313 platform_set_drvdata(pdev, common); 454 platform_set_drvdata(pdev, common);