blob: 1ba02770153af93bbed864777ca653a829e659e0 [file] [log] [blame]
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +10001/*
2 * R-Car THS/TSC thermal sensor driver
3 *
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20#include <linux/delay.h>
21#include <linux/err.h>
22#include <linux/io.h>
23#include <linux/module.h>
24#include <linux/platform_device.h>
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -080025#include <linux/reboot.h>
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100026#include <linux/slab.h>
27#include <linux/spinlock.h>
28#include <linux/thermal.h>
29
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -080030#define IDLE_INTERVAL 5000
31
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100032#define THSCR 0x2c
33#define THSSR 0x30
34
35/* THSCR */
Kuninori Morimotof8f53e12013-01-31 09:03:11 +000036#define CPCTL (1 << 12)
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100037
38/* THSSR */
39#define CTEMP 0x3f
40
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +000041struct rcar_thermal_common {
42 void __iomem *base;
43 struct device *dev;
44 struct list_head head;
45};
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100046
47struct rcar_thermal_priv {
48 void __iomem *base;
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +000049 struct rcar_thermal_common *common;
50 struct thermal_zone_device *zone;
Kuninori Morimotob2bbc6a2013-01-31 09:03:22 +000051 struct mutex lock;
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +000052 struct list_head list;
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100053};
54
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +000055#define rcar_thermal_for_each_priv(pos, common) \
56 list_for_each_entry(pos, &common->head, list)
57
Kuninori Morimotoc4997032012-11-26 02:32:06 +000058#define MCELSIUS(temp) ((temp) * 1000)
Kuninori Morimoto9dde8f82013-01-31 09:02:51 +000059#define rcar_zone_to_priv(zone) ((zone)->devdata)
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +000060#define rcar_priv_to_dev(priv) ((priv)->common->dev)
61#define rcar_has_irq_support(priv) ((priv)->common->base)
Kuninori Morimotoc4997032012-11-26 02:32:06 +000062
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100063/*
64 * basic functions
65 */
66static u32 rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
67{
Kuninori Morimotob2bbc6a2013-01-31 09:03:22 +000068 return ioread32(priv->base + reg);
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100069}
70
71#if 0 /* no user at this point */
72static void rcar_thermal_write(struct rcar_thermal_priv *priv,
73 u32 reg, u32 data)
74{
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100075 iowrite32(data, priv->base + reg);
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100076}
77#endif
78
79static void rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
80 u32 mask, u32 data)
81{
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100082 u32 val;
83
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100084 val = ioread32(priv->base + reg);
85 val &= ~mask;
86 val |= (data & mask);
87 iowrite32(val, priv->base + reg);
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +100088}
89
90/*
91 * zone device functions
92 */
93static int rcar_thermal_get_temp(struct thermal_zone_device *zone,
94 unsigned long *temp)
95{
Kuninori Morimotod12250e2012-11-26 02:32:20 +000096 struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
Kuninori Morimotof8f53e12013-01-31 09:03:11 +000097 struct device *dev = rcar_priv_to_dev(priv);
98 int i;
99 int ctemp, old, new;
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000100
Kuninori Morimotob2bbc6a2013-01-31 09:03:22 +0000101 mutex_lock(&priv->lock);
102
Kuninori Morimotof8f53e12013-01-31 09:03:11 +0000103 /*
104 * TSC decides a value of CPTAP automatically,
105 * and this is the conditions which validate interrupt.
106 */
107 rcar_thermal_bset(priv, THSCR, CPCTL, CPCTL);
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000108
Kuninori Morimotof8f53e12013-01-31 09:03:11 +0000109 ctemp = 0;
110 old = ~0;
111 for (i = 0; i < 128; i++) {
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000112 /*
113 * we need to wait 300us after changing comparator offset
114 * to get stable temperature.
115 * see "Usage Notes" on datasheet
116 */
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000117 udelay(300);
118
Kuninori Morimotof8f53e12013-01-31 09:03:11 +0000119 new = rcar_thermal_read(priv, THSSR) & CTEMP;
120 if (new == old) {
121 ctemp = new;
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000122 break;
123 }
Kuninori Morimotof8f53e12013-01-31 09:03:11 +0000124 old = new;
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000125 }
126
Kuninori Morimotof8f53e12013-01-31 09:03:11 +0000127 if (!ctemp) {
128 dev_err(dev, "thermal sensor was broken\n");
129 return -EINVAL;
130 }
131
132 *temp = MCELSIUS((ctemp * 5) - 65);
133
Kuninori Morimotob2bbc6a2013-01-31 09:03:22 +0000134 mutex_unlock(&priv->lock);
135
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000136 return 0;
137}
138
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -0800139static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
140 int trip, enum thermal_trip_type *type)
141{
142 struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000143 struct device *dev = rcar_priv_to_dev(priv);
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -0800144
145 /* see rcar_thermal_get_temp() */
146 switch (trip) {
147 case 0: /* +90 <= temp */
148 *type = THERMAL_TRIP_CRITICAL;
149 break;
150 default:
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000151 dev_err(dev, "rcar driver trip error\n");
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -0800152 return -EINVAL;
153 }
154
155 return 0;
156}
157
158static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone,
159 int trip, unsigned long *temp)
160{
161 struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000162 struct device *dev = rcar_priv_to_dev(priv);
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -0800163
164 /* see rcar_thermal_get_temp() */
165 switch (trip) {
166 case 0: /* +90 <= temp */
167 *temp = MCELSIUS(90);
168 break;
169 default:
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000170 dev_err(dev, "rcar driver trip error\n");
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -0800171 return -EINVAL;
172 }
173
174 return 0;
175}
176
177static int rcar_thermal_notify(struct thermal_zone_device *zone,
178 int trip, enum thermal_trip_type type)
179{
180 struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000181 struct device *dev = rcar_priv_to_dev(priv);
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -0800182
183 switch (type) {
184 case THERMAL_TRIP_CRITICAL:
185 /* FIXME */
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000186 dev_warn(dev, "Thermal reached to critical temperature\n");
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -0800187 machine_power_off();
188 break;
189 default:
190 break;
191 }
192
193 return 0;
194}
195
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000196static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
kuninori.morimoto.gx@renesas.comd2a73e22012-12-02 18:48:41 -0800197 .get_temp = rcar_thermal_get_temp,
198 .get_trip_type = rcar_thermal_get_trip_type,
199 .get_trip_temp = rcar_thermal_get_trip_temp,
200 .notify = rcar_thermal_notify,
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000201};
202
203/*
204 * platform functions
205 */
206static int rcar_thermal_probe(struct platform_device *pdev)
207{
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000208 struct rcar_thermal_common *common;
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000209 struct rcar_thermal_priv *priv;
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000210 struct device *dev = &pdev->dev;
211 struct resource *res, *irq;
212 int mres = 0;
213 int i;
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000214
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000215 common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
216 if (!common) {
217 dev_err(dev, "Could not allocate common\n");
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000218 return -ENOMEM;
219 }
220
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000221 INIT_LIST_HEAD(&common->head);
222 common->dev = dev;
223
224 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
225 if (irq) {
226 /*
227 * platform has IRQ support.
228 * Then, drier use common register
229 */
230 res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
231 if (!res) {
232 dev_err(dev, "Could not get platform resource\n");
233 return -ENODEV;
234 }
235
236 /*
237 * rcar_has_irq_support() will be enabled
238 */
239 common->base = devm_request_and_ioremap(dev, res);
240 if (!common->base) {
241 dev_err(dev, "Unable to ioremap thermal register\n");
242 return -ENOMEM;
243 }
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000244 }
245
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000246 for (i = 0;; i++) {
247 res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
248 if (!res)
249 break;
250
251 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
252 if (!priv) {
253 dev_err(dev, "Could not allocate priv\n");
254 return -ENOMEM;
255 }
256
257 priv->base = devm_request_and_ioremap(dev, res);
258 if (!priv->base) {
259 dev_err(dev, "Unable to ioremap priv register\n");
260 return -ENOMEM;
261 }
262
263 priv->common = common;
264 mutex_init(&priv->lock);
265 INIT_LIST_HEAD(&priv->list);
266
267 priv->zone = thermal_zone_device_register("rcar_thermal",
268 1, 0, priv,
269 &rcar_thermal_zone_ops, NULL, 0,
270 IDLE_INTERVAL);
271 if (IS_ERR(priv->zone)) {
272 dev_err(dev, "can't register thermal zone\n");
273 goto error_unregister;
274 }
275
276 list_move_tail(&priv->list, &common->head);
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000277 }
278
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000279 platform_set_drvdata(pdev, common);
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000280
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000281 dev_info(dev, "%d sensor proved\n", i);
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000282
283 return 0;
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000284
285error_unregister:
286 rcar_thermal_for_each_priv(priv, common)
287 thermal_zone_device_unregister(priv->zone);
288
289 return -ENODEV;
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000290}
291
292static int rcar_thermal_remove(struct platform_device *pdev)
293{
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000294 struct rcar_thermal_common *common = platform_get_drvdata(pdev);
295 struct rcar_thermal_priv *priv;
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000296
Kuninori Morimoto3676d1d2013-01-31 09:03:33 +0000297 rcar_thermal_for_each_priv(priv, common)
298 thermal_zone_device_unregister(priv->zone);
299
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000300 platform_set_drvdata(pdev, NULL);
301
Kuninori Morimoto1e426ff2012-07-21 10:53:48 +1000302 return 0;
303}
304
305static struct platform_driver rcar_thermal_driver = {
306 .driver = {
307 .name = "rcar_thermal",
308 },
309 .probe = rcar_thermal_probe,
310 .remove = rcar_thermal_remove,
311};
312module_platform_driver(rcar_thermal_driver);
313
314MODULE_LICENSE("GPL");
315MODULE_DESCRIPTION("R-Car THS/TSC thermal sensor driver");
316MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");