11e426ffdSKuninori Morimoto /*
21e426ffdSKuninori Morimoto  *  R-Car THS/TSC thermal sensor driver
31e426ffdSKuninori Morimoto  *
41e426ffdSKuninori Morimoto  * Copyright (C) 2012 Renesas Solutions Corp.
51e426ffdSKuninori Morimoto  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
61e426ffdSKuninori Morimoto  *
71e426ffdSKuninori Morimoto  *  This program is free software; you can redistribute it and/or modify
81e426ffdSKuninori Morimoto  *  it under the terms of the GNU General Public License as published by
91e426ffdSKuninori Morimoto  *  the Free Software Foundation; version 2 of the License.
101e426ffdSKuninori Morimoto  *
111e426ffdSKuninori Morimoto  *  This program is distributed in the hope that it will be useful, but
121e426ffdSKuninori Morimoto  *  WITHOUT ANY WARRANTY; without even the implied warranty of
131e426ffdSKuninori Morimoto  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
141e426ffdSKuninori Morimoto  *  General Public License for more details.
151e426ffdSKuninori Morimoto  *
161e426ffdSKuninori Morimoto  *  You should have received a copy of the GNU General Public License along
171e426ffdSKuninori Morimoto  *  with this program; if not, write to the Free Software Foundation, Inc.,
181e426ffdSKuninori Morimoto  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
191e426ffdSKuninori Morimoto  */
201e426ffdSKuninori Morimoto #include <linux/delay.h>
211e426ffdSKuninori Morimoto #include <linux/err.h>
22e0a5172eSKuninori Morimoto #include <linux/irq.h>
23e0a5172eSKuninori Morimoto #include <linux/interrupt.h>
241e426ffdSKuninori Morimoto #include <linux/io.h>
251e426ffdSKuninori Morimoto #include <linux/module.h>
261e426ffdSKuninori Morimoto #include <linux/platform_device.h>
2751d45d25SKuninori Morimoto #include <linux/pm_runtime.h>
28d2a73e22Skuninori.morimoto.gx@renesas.com #include <linux/reboot.h>
291e426ffdSKuninori Morimoto #include <linux/slab.h>
301e426ffdSKuninori Morimoto #include <linux/spinlock.h>
311e426ffdSKuninori Morimoto #include <linux/thermal.h>
321e426ffdSKuninori Morimoto 
33d2a73e22Skuninori.morimoto.gx@renesas.com #define IDLE_INTERVAL	5000
34d2a73e22Skuninori.morimoto.gx@renesas.com 
35e0a5172eSKuninori Morimoto #define COMMON_STR	0x00
36e0a5172eSKuninori Morimoto #define COMMON_ENR	0x04
37e0a5172eSKuninori Morimoto #define COMMON_INTMSK	0x0c
38e0a5172eSKuninori Morimoto 
39e0a5172eSKuninori Morimoto #define REG_POSNEG	0x20
40e0a5172eSKuninori Morimoto #define REG_FILONOFF	0x28
41e9137a58SKuninori Morimoto #define REG_THSCR	0x2c
42e9137a58SKuninori Morimoto #define REG_THSSR	0x30
43e0a5172eSKuninori Morimoto #define REG_INTCTRL	0x34
441e426ffdSKuninori Morimoto 
451e426ffdSKuninori Morimoto /* THSCR */
46f8f53e18SKuninori Morimoto #define CPCTL	(1 << 12)
471e426ffdSKuninori Morimoto 
481e426ffdSKuninori Morimoto /* THSSR */
491e426ffdSKuninori Morimoto #define CTEMP	0x3f
501e426ffdSKuninori Morimoto 
513676d1ddSKuninori Morimoto struct rcar_thermal_common {
523676d1ddSKuninori Morimoto 	void __iomem *base;
533676d1ddSKuninori Morimoto 	struct device *dev;
543676d1ddSKuninori Morimoto 	struct list_head head;
55e0a5172eSKuninori Morimoto 	spinlock_t lock;
563676d1ddSKuninori Morimoto };
571e426ffdSKuninori Morimoto 
581e426ffdSKuninori Morimoto struct rcar_thermal_priv {
591e426ffdSKuninori Morimoto 	void __iomem *base;
603676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common;
613676d1ddSKuninori Morimoto 	struct thermal_zone_device *zone;
62e0a5172eSKuninori Morimoto 	struct delayed_work work;
63b2bbc6a2SKuninori Morimoto 	struct mutex lock;
643676d1ddSKuninori Morimoto 	struct list_head list;
65e0a5172eSKuninori Morimoto 	int id;
66913015c6SYoshihiro Shimoda 	u32 ctemp;
671e426ffdSKuninori Morimoto };
681e426ffdSKuninori Morimoto 
693676d1ddSKuninori Morimoto #define rcar_thermal_for_each_priv(pos, common)	\
703676d1ddSKuninori Morimoto 	list_for_each_entry(pos, &common->head, list)
713676d1ddSKuninori Morimoto 
72c499703eSKuninori Morimoto #define MCELSIUS(temp)			((temp) * 1000)
739dde8f86SKuninori Morimoto #define rcar_zone_to_priv(zone)		((zone)->devdata)
743676d1ddSKuninori Morimoto #define rcar_priv_to_dev(priv)		((priv)->common->dev)
753676d1ddSKuninori Morimoto #define rcar_has_irq_support(priv)	((priv)->common->base)
76e0a5172eSKuninori Morimoto #define rcar_id_to_shift(priv)		((priv)->id * 8)
77e0a5172eSKuninori Morimoto 
78e0a5172eSKuninori Morimoto #ifdef DEBUG
79e0a5172eSKuninori Morimoto # define rcar_force_update_temp(priv)	1
80e0a5172eSKuninori Morimoto #else
81e0a5172eSKuninori Morimoto # define rcar_force_update_temp(priv)	0
82e0a5172eSKuninori Morimoto #endif
83c499703eSKuninori Morimoto 
84ca1e4558SKuninori Morimoto static const struct of_device_id rcar_thermal_dt_ids[] = {
85ca1e4558SKuninori Morimoto 	{ .compatible = "renesas,rcar-thermal", },
86ca1e4558SKuninori Morimoto 	{},
87ca1e4558SKuninori Morimoto };
88ca1e4558SKuninori Morimoto MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
89ca1e4558SKuninori Morimoto 
901e426ffdSKuninori Morimoto /*
911e426ffdSKuninori Morimoto  *		basic functions
921e426ffdSKuninori Morimoto  */
93e9137a58SKuninori Morimoto #define rcar_thermal_common_read(c, r) \
94e9137a58SKuninori Morimoto 	_rcar_thermal_common_read(c, COMMON_ ##r)
95e9137a58SKuninori Morimoto static u32 _rcar_thermal_common_read(struct rcar_thermal_common *common,
96e9137a58SKuninori Morimoto 				     u32 reg)
97e9137a58SKuninori Morimoto {
98e9137a58SKuninori Morimoto 	return ioread32(common->base + reg);
99e9137a58SKuninori Morimoto }
100e9137a58SKuninori Morimoto 
101e9137a58SKuninori Morimoto #define rcar_thermal_common_write(c, r, d) \
102e9137a58SKuninori Morimoto 	_rcar_thermal_common_write(c, COMMON_ ##r, d)
103e9137a58SKuninori Morimoto static void _rcar_thermal_common_write(struct rcar_thermal_common *common,
104e9137a58SKuninori Morimoto 				       u32 reg, u32 data)
105e9137a58SKuninori Morimoto {
106e9137a58SKuninori Morimoto 	iowrite32(data, common->base + reg);
107e9137a58SKuninori Morimoto }
108e9137a58SKuninori Morimoto 
109e9137a58SKuninori Morimoto #define rcar_thermal_common_bset(c, r, m, d) \
110e9137a58SKuninori Morimoto 	_rcar_thermal_common_bset(c, COMMON_ ##r, m, d)
111e9137a58SKuninori Morimoto static void _rcar_thermal_common_bset(struct rcar_thermal_common *common,
112e9137a58SKuninori Morimoto 				      u32 reg, u32 mask, u32 data)
113e9137a58SKuninori Morimoto {
114e9137a58SKuninori Morimoto 	u32 val;
115e9137a58SKuninori Morimoto 
116e9137a58SKuninori Morimoto 	val = ioread32(common->base + reg);
117e9137a58SKuninori Morimoto 	val &= ~mask;
118e9137a58SKuninori Morimoto 	val |= (data & mask);
119e9137a58SKuninori Morimoto 	iowrite32(val, common->base + reg);
120e9137a58SKuninori Morimoto }
121e9137a58SKuninori Morimoto 
122e9137a58SKuninori Morimoto #define rcar_thermal_read(p, r) _rcar_thermal_read(p, REG_ ##r)
123e9137a58SKuninori Morimoto static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
1241e426ffdSKuninori Morimoto {
125b2bbc6a2SKuninori Morimoto 	return ioread32(priv->base + reg);
1261e426ffdSKuninori Morimoto }
1271e426ffdSKuninori Morimoto 
128e9137a58SKuninori Morimoto #define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, REG_ ##r, d)
129e9137a58SKuninori Morimoto static void _rcar_thermal_write(struct rcar_thermal_priv *priv,
1301e426ffdSKuninori Morimoto 				u32 reg, u32 data)
1311e426ffdSKuninori Morimoto {
1321e426ffdSKuninori Morimoto 	iowrite32(data, priv->base + reg);
1331e426ffdSKuninori Morimoto }
1341e426ffdSKuninori Morimoto 
135e9137a58SKuninori Morimoto #define rcar_thermal_bset(p, r, m, d) _rcar_thermal_bset(p, REG_ ##r, m, d)
136e9137a58SKuninori Morimoto static void _rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
1371e426ffdSKuninori Morimoto 			       u32 mask, u32 data)
1381e426ffdSKuninori Morimoto {
1391e426ffdSKuninori Morimoto 	u32 val;
1401e426ffdSKuninori Morimoto 
1411e426ffdSKuninori Morimoto 	val = ioread32(priv->base + reg);
1421e426ffdSKuninori Morimoto 	val &= ~mask;
1431e426ffdSKuninori Morimoto 	val |= (data & mask);
1441e426ffdSKuninori Morimoto 	iowrite32(val, priv->base + reg);
1451e426ffdSKuninori Morimoto }
1461e426ffdSKuninori Morimoto 
1471e426ffdSKuninori Morimoto /*
1481e426ffdSKuninori Morimoto  *		zone device functions
1491e426ffdSKuninori Morimoto  */
150e0a5172eSKuninori Morimoto static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
1511e426ffdSKuninori Morimoto {
152f8f53e18SKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
153f8f53e18SKuninori Morimoto 	int i;
154913015c6SYoshihiro Shimoda 	u32 ctemp, old, new;
155f0e68fc3SWei Yongjun 	int ret = -EINVAL;
1561e426ffdSKuninori Morimoto 
157b2bbc6a2SKuninori Morimoto 	mutex_lock(&priv->lock);
158b2bbc6a2SKuninori Morimoto 
1591e426ffdSKuninori Morimoto 	/*
160f8f53e18SKuninori Morimoto 	 * TSC decides a value of CPTAP automatically,
161f8f53e18SKuninori Morimoto 	 * and this is the conditions which validate interrupt.
1621e426ffdSKuninori Morimoto 	 */
163f8f53e18SKuninori Morimoto 	rcar_thermal_bset(priv, THSCR, CPCTL, CPCTL);
1641e426ffdSKuninori Morimoto 
165f8f53e18SKuninori Morimoto 	ctemp = 0;
166f8f53e18SKuninori Morimoto 	old = ~0;
167f8f53e18SKuninori Morimoto 	for (i = 0; i < 128; i++) {
1681e426ffdSKuninori Morimoto 		/*
1691e426ffdSKuninori Morimoto 		 * we need to wait 300us after changing comparator offset
1701e426ffdSKuninori Morimoto 		 * to get stable temperature.
1711e426ffdSKuninori Morimoto 		 * see "Usage Notes" on datasheet
1721e426ffdSKuninori Morimoto 		 */
1731e426ffdSKuninori Morimoto 		udelay(300);
1741e426ffdSKuninori Morimoto 
175f8f53e18SKuninori Morimoto 		new = rcar_thermal_read(priv, THSSR) & CTEMP;
176f8f53e18SKuninori Morimoto 		if (new == old) {
177f8f53e18SKuninori Morimoto 			ctemp = new;
1781e426ffdSKuninori Morimoto 			break;
1791e426ffdSKuninori Morimoto 		}
180f8f53e18SKuninori Morimoto 		old = new;
1811e426ffdSKuninori Morimoto 	}
1821e426ffdSKuninori Morimoto 
183f8f53e18SKuninori Morimoto 	if (!ctemp) {
184f8f53e18SKuninori Morimoto 		dev_err(dev, "thermal sensor was broken\n");
185f0e68fc3SWei Yongjun 		goto err_out_unlock;
186f8f53e18SKuninori Morimoto 	}
187f8f53e18SKuninori Morimoto 
188e0a5172eSKuninori Morimoto 	/*
189e0a5172eSKuninori Morimoto 	 * enable IRQ
190e0a5172eSKuninori Morimoto 	 */
191e0a5172eSKuninori Morimoto 	if (rcar_has_irq_support(priv)) {
192e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, FILONOFF, 0);
193f8f53e18SKuninori Morimoto 
194e0a5172eSKuninori Morimoto 		/* enable Rising/Falling edge interrupt */
195e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, POSNEG,  0x1);
196e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, INTCTRL, (((ctemp - 0) << 8) |
197e0a5172eSKuninori Morimoto 						   ((ctemp - 1) << 0)));
198e0a5172eSKuninori Morimoto 	}
199e0a5172eSKuninori Morimoto 
200e0a5172eSKuninori Morimoto 	dev_dbg(dev, "thermal%d  %d -> %d\n", priv->id, priv->ctemp, ctemp);
201e0a5172eSKuninori Morimoto 
202e0a5172eSKuninori Morimoto 	priv->ctemp = ctemp;
203f0e68fc3SWei Yongjun 	ret = 0;
204f0e68fc3SWei Yongjun err_out_unlock:
205e0a5172eSKuninori Morimoto 	mutex_unlock(&priv->lock);
206f0e68fc3SWei Yongjun 	return ret;
207e0a5172eSKuninori Morimoto }
208e0a5172eSKuninori Morimoto 
20917e8351aSSascha Hauer static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp)
210e0a5172eSKuninori Morimoto {
211e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
212e0a5172eSKuninori Morimoto 
213e0a5172eSKuninori Morimoto 	if (!rcar_has_irq_support(priv) || rcar_force_update_temp(priv))
214e0a5172eSKuninori Morimoto 		rcar_thermal_update_temp(priv);
215e0a5172eSKuninori Morimoto 
216e0a5172eSKuninori Morimoto 	mutex_lock(&priv->lock);
217e0a5172eSKuninori Morimoto 	*temp =  MCELSIUS((priv->ctemp * 5) - 65);
218b2bbc6a2SKuninori Morimoto 	mutex_unlock(&priv->lock);
219b2bbc6a2SKuninori Morimoto 
2201e426ffdSKuninori Morimoto 	return 0;
2211e426ffdSKuninori Morimoto }
2221e426ffdSKuninori Morimoto 
223d2a73e22Skuninori.morimoto.gx@renesas.com static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
224d2a73e22Skuninori.morimoto.gx@renesas.com 				      int trip, enum thermal_trip_type *type)
225d2a73e22Skuninori.morimoto.gx@renesas.com {
226d2a73e22Skuninori.morimoto.gx@renesas.com 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
2273676d1ddSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
228d2a73e22Skuninori.morimoto.gx@renesas.com 
229d2a73e22Skuninori.morimoto.gx@renesas.com 	/* see rcar_thermal_get_temp() */
230d2a73e22Skuninori.morimoto.gx@renesas.com 	switch (trip) {
231d2a73e22Skuninori.morimoto.gx@renesas.com 	case 0: /* +90 <= temp */
232d2a73e22Skuninori.morimoto.gx@renesas.com 		*type = THERMAL_TRIP_CRITICAL;
233d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
234d2a73e22Skuninori.morimoto.gx@renesas.com 	default:
2353676d1ddSKuninori Morimoto 		dev_err(dev, "rcar driver trip error\n");
236d2a73e22Skuninori.morimoto.gx@renesas.com 		return -EINVAL;
237d2a73e22Skuninori.morimoto.gx@renesas.com 	}
238d2a73e22Skuninori.morimoto.gx@renesas.com 
239d2a73e22Skuninori.morimoto.gx@renesas.com 	return 0;
240d2a73e22Skuninori.morimoto.gx@renesas.com }
241d2a73e22Skuninori.morimoto.gx@renesas.com 
242d2a73e22Skuninori.morimoto.gx@renesas.com static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone,
24317e8351aSSascha Hauer 				      int trip, int *temp)
244d2a73e22Skuninori.morimoto.gx@renesas.com {
245d2a73e22Skuninori.morimoto.gx@renesas.com 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
2463676d1ddSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
247d2a73e22Skuninori.morimoto.gx@renesas.com 
248d2a73e22Skuninori.morimoto.gx@renesas.com 	/* see rcar_thermal_get_temp() */
249d2a73e22Skuninori.morimoto.gx@renesas.com 	switch (trip) {
250d2a73e22Skuninori.morimoto.gx@renesas.com 	case 0: /* +90 <= temp */
251d2a73e22Skuninori.morimoto.gx@renesas.com 		*temp = MCELSIUS(90);
252d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
253d2a73e22Skuninori.morimoto.gx@renesas.com 	default:
2543676d1ddSKuninori Morimoto 		dev_err(dev, "rcar driver trip error\n");
255d2a73e22Skuninori.morimoto.gx@renesas.com 		return -EINVAL;
256d2a73e22Skuninori.morimoto.gx@renesas.com 	}
257d2a73e22Skuninori.morimoto.gx@renesas.com 
258d2a73e22Skuninori.morimoto.gx@renesas.com 	return 0;
259d2a73e22Skuninori.morimoto.gx@renesas.com }
260d2a73e22Skuninori.morimoto.gx@renesas.com 
261d2a73e22Skuninori.morimoto.gx@renesas.com static int rcar_thermal_notify(struct thermal_zone_device *zone,
262d2a73e22Skuninori.morimoto.gx@renesas.com 			       int trip, enum thermal_trip_type type)
263d2a73e22Skuninori.morimoto.gx@renesas.com {
264d2a73e22Skuninori.morimoto.gx@renesas.com 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
2653676d1ddSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
266d2a73e22Skuninori.morimoto.gx@renesas.com 
267d2a73e22Skuninori.morimoto.gx@renesas.com 	switch (type) {
268d2a73e22Skuninori.morimoto.gx@renesas.com 	case THERMAL_TRIP_CRITICAL:
269d2a73e22Skuninori.morimoto.gx@renesas.com 		/* FIXME */
2703676d1ddSKuninori Morimoto 		dev_warn(dev, "Thermal reached to critical temperature\n");
271d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
272d2a73e22Skuninori.morimoto.gx@renesas.com 	default:
273d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
274d2a73e22Skuninori.morimoto.gx@renesas.com 	}
275d2a73e22Skuninori.morimoto.gx@renesas.com 
276d2a73e22Skuninori.morimoto.gx@renesas.com 	return 0;
277d2a73e22Skuninori.morimoto.gx@renesas.com }
278d2a73e22Skuninori.morimoto.gx@renesas.com 
2791e426ffdSKuninori Morimoto static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
2801e426ffdSKuninori Morimoto 	.get_temp	= rcar_thermal_get_temp,
281d2a73e22Skuninori.morimoto.gx@renesas.com 	.get_trip_type	= rcar_thermal_get_trip_type,
282d2a73e22Skuninori.morimoto.gx@renesas.com 	.get_trip_temp	= rcar_thermal_get_trip_temp,
283d2a73e22Skuninori.morimoto.gx@renesas.com 	.notify		= rcar_thermal_notify,
2841e426ffdSKuninori Morimoto };
2851e426ffdSKuninori Morimoto 
2861e426ffdSKuninori Morimoto /*
287e0a5172eSKuninori Morimoto  *		interrupt
288e0a5172eSKuninori Morimoto  */
289e0a5172eSKuninori Morimoto #define rcar_thermal_irq_enable(p)	_rcar_thermal_irq_ctrl(p, 1)
290e0a5172eSKuninori Morimoto #define rcar_thermal_irq_disable(p)	_rcar_thermal_irq_ctrl(p, 0)
291e0a5172eSKuninori Morimoto static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
292e0a5172eSKuninori Morimoto {
293e0a5172eSKuninori Morimoto 	struct rcar_thermal_common *common = priv->common;
294e0a5172eSKuninori Morimoto 	unsigned long flags;
295e0a5172eSKuninori Morimoto 	u32 mask = 0x3 << rcar_id_to_shift(priv); /* enable Rising/Falling */
296e0a5172eSKuninori Morimoto 
297e0a5172eSKuninori Morimoto 	spin_lock_irqsave(&common->lock, flags);
298e0a5172eSKuninori Morimoto 
299e0a5172eSKuninori Morimoto 	rcar_thermal_common_bset(common, INTMSK, mask, enable ? 0 : mask);
300e0a5172eSKuninori Morimoto 
301e0a5172eSKuninori Morimoto 	spin_unlock_irqrestore(&common->lock, flags);
302e0a5172eSKuninori Morimoto }
303e0a5172eSKuninori Morimoto 
304e0a5172eSKuninori Morimoto static void rcar_thermal_work(struct work_struct *work)
305e0a5172eSKuninori Morimoto {
306e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv;
30717e8351aSSascha Hauer 	int cctemp, nctemp;
308e0a5172eSKuninori Morimoto 
309e0a5172eSKuninori Morimoto 	priv = container_of(work, struct rcar_thermal_priv, work.work);
310e0a5172eSKuninori Morimoto 
3119477165eSPatrick Titiano 	rcar_thermal_get_temp(priv->zone, &cctemp);
312e0a5172eSKuninori Morimoto 	rcar_thermal_update_temp(priv);
313e0a5172eSKuninori Morimoto 	rcar_thermal_irq_enable(priv);
3149477165eSPatrick Titiano 
3159477165eSPatrick Titiano 	rcar_thermal_get_temp(priv->zone, &nctemp);
3169477165eSPatrick Titiano 	if (nctemp != cctemp)
317e0a5172eSKuninori Morimoto 		thermal_zone_device_update(priv->zone);
318e0a5172eSKuninori Morimoto }
319e0a5172eSKuninori Morimoto 
320e0a5172eSKuninori Morimoto static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
321e0a5172eSKuninori Morimoto {
322e0a5172eSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
323e0a5172eSKuninori Morimoto 
324e0a5172eSKuninori Morimoto 	status = (status >> rcar_id_to_shift(priv)) & 0x3;
325e0a5172eSKuninori Morimoto 
326206c0cbaSPatrick Titiano 	if (status) {
327e0a5172eSKuninori Morimoto 		dev_dbg(dev, "thermal%d %s%s\n",
328e0a5172eSKuninori Morimoto 			priv->id,
329e0a5172eSKuninori Morimoto 			(status & 0x2) ? "Rising " : "",
330e0a5172eSKuninori Morimoto 			(status & 0x1) ? "Falling" : "");
331e0a5172eSKuninori Morimoto 	}
332e0a5172eSKuninori Morimoto 
333e0a5172eSKuninori Morimoto 	return status;
334e0a5172eSKuninori Morimoto }
335e0a5172eSKuninori Morimoto 
336e0a5172eSKuninori Morimoto static irqreturn_t rcar_thermal_irq(int irq, void *data)
337e0a5172eSKuninori Morimoto {
338e0a5172eSKuninori Morimoto 	struct rcar_thermal_common *common = data;
339e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv;
340e0a5172eSKuninori Morimoto 	unsigned long flags;
341e0a5172eSKuninori Morimoto 	u32 status, mask;
342e0a5172eSKuninori Morimoto 
343e0a5172eSKuninori Morimoto 	spin_lock_irqsave(&common->lock, flags);
344e0a5172eSKuninori Morimoto 
345e0a5172eSKuninori Morimoto 	mask	= rcar_thermal_common_read(common, INTMSK);
346e0a5172eSKuninori Morimoto 	status	= rcar_thermal_common_read(common, STR);
347e0a5172eSKuninori Morimoto 	rcar_thermal_common_write(common, STR, 0x000F0F0F & mask);
348e0a5172eSKuninori Morimoto 
349e0a5172eSKuninori Morimoto 	spin_unlock_irqrestore(&common->lock, flags);
350e0a5172eSKuninori Morimoto 
351e0a5172eSKuninori Morimoto 	status = status & ~mask;
352e0a5172eSKuninori Morimoto 
353e0a5172eSKuninori Morimoto 	/*
354e0a5172eSKuninori Morimoto 	 * check the status
355e0a5172eSKuninori Morimoto 	 */
356e0a5172eSKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
357e0a5172eSKuninori Morimoto 		if (rcar_thermal_had_changed(priv, status)) {
358e0a5172eSKuninori Morimoto 			rcar_thermal_irq_disable(priv);
359e0a5172eSKuninori Morimoto 			schedule_delayed_work(&priv->work,
360e0a5172eSKuninori Morimoto 					      msecs_to_jiffies(300));
361e0a5172eSKuninori Morimoto 		}
362e0a5172eSKuninori Morimoto 	}
363e0a5172eSKuninori Morimoto 
364e0a5172eSKuninori Morimoto 	return IRQ_HANDLED;
365e0a5172eSKuninori Morimoto }
366e0a5172eSKuninori Morimoto 
367e0a5172eSKuninori Morimoto /*
3681e426ffdSKuninori Morimoto  *		platform functions
3691e426ffdSKuninori Morimoto  */
37084f0e490SKuninori Morimoto static int rcar_thermal_remove(struct platform_device *pdev)
37184f0e490SKuninori Morimoto {
37284f0e490SKuninori Morimoto 	struct rcar_thermal_common *common = platform_get_drvdata(pdev);
37384f0e490SKuninori Morimoto 	struct device *dev = &pdev->dev;
37484f0e490SKuninori Morimoto 	struct rcar_thermal_priv *priv;
37584f0e490SKuninori Morimoto 
37684f0e490SKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
37784f0e490SKuninori Morimoto 		if (rcar_has_irq_support(priv))
37884f0e490SKuninori Morimoto 			rcar_thermal_irq_disable(priv);
37984f0e490SKuninori Morimoto 		thermal_zone_device_unregister(priv->zone);
38084f0e490SKuninori Morimoto 	}
38184f0e490SKuninori Morimoto 
38284f0e490SKuninori Morimoto 	pm_runtime_put(dev);
38384f0e490SKuninori Morimoto 	pm_runtime_disable(dev);
38484f0e490SKuninori Morimoto 
38584f0e490SKuninori Morimoto 	return 0;
38684f0e490SKuninori Morimoto }
38784f0e490SKuninori Morimoto 
3881e426ffdSKuninori Morimoto static int rcar_thermal_probe(struct platform_device *pdev)
3891e426ffdSKuninori Morimoto {
3903676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common;
3911e426ffdSKuninori Morimoto 	struct rcar_thermal_priv *priv;
3923676d1ddSKuninori Morimoto 	struct device *dev = &pdev->dev;
3933676d1ddSKuninori Morimoto 	struct resource *res, *irq;
3943676d1ddSKuninori Morimoto 	int mres = 0;
3953676d1ddSKuninori Morimoto 	int i;
396fb84d990SDevendra Naga 	int ret = -ENODEV;
397e0a5172eSKuninori Morimoto 	int idle = IDLE_INTERVAL;
39811313746SYoshihiro Shimoda 	u32 enr_bits = 0;
3991e426ffdSKuninori Morimoto 
4003676d1ddSKuninori Morimoto 	common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
401b0a60d88SJingoo Han 	if (!common)
4023676d1ddSKuninori Morimoto 		return -ENOMEM;
4033676d1ddSKuninori Morimoto 
40484f0e490SKuninori Morimoto 	platform_set_drvdata(pdev, common);
40584f0e490SKuninori Morimoto 
4063676d1ddSKuninori Morimoto 	INIT_LIST_HEAD(&common->head);
407e0a5172eSKuninori Morimoto 	spin_lock_init(&common->lock);
4083676d1ddSKuninori Morimoto 	common->dev = dev;
4093676d1ddSKuninori Morimoto 
41051d45d25SKuninori Morimoto 	pm_runtime_enable(dev);
41151d45d25SKuninori Morimoto 	pm_runtime_get_sync(dev);
41251d45d25SKuninori Morimoto 
4133676d1ddSKuninori Morimoto 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4143676d1ddSKuninori Morimoto 	if (irq) {
4153676d1ddSKuninori Morimoto 		/*
4163676d1ddSKuninori Morimoto 		 * platform has IRQ support.
417ee853addSGeert Uytterhoeven 		 * Then, driver uses common registers
4183676d1ddSKuninori Morimoto 		 * rcar_has_irq_support() will be enabled
4193676d1ddSKuninori Morimoto 		 */
420c28f692cSWolfram Sang 		res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
4215095526fSSachin Kamat 		common->base = devm_ioremap_resource(dev, res);
4225095526fSSachin Kamat 		if (IS_ERR(common->base))
4235095526fSSachin Kamat 			return PTR_ERR(common->base);
424e0a5172eSKuninori Morimoto 
4256fe495e0SGeert Uytterhoeven 		idle = 0; /* polling delay is not needed */
4263676d1ddSKuninori Morimoto 	}
4273676d1ddSKuninori Morimoto 
4283676d1ddSKuninori Morimoto 	for (i = 0;; i++) {
4293676d1ddSKuninori Morimoto 		res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
4303676d1ddSKuninori Morimoto 		if (!res)
4313676d1ddSKuninori Morimoto 			break;
4323676d1ddSKuninori Morimoto 
4333676d1ddSKuninori Morimoto 		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
4341e426ffdSKuninori Morimoto 		if (!priv) {
4351dc20828SKuninori Morimoto 			ret = -ENOMEM;
4361dc20828SKuninori Morimoto 			goto error_unregister;
4371e426ffdSKuninori Morimoto 		}
4381e426ffdSKuninori Morimoto 
4395095526fSSachin Kamat 		priv->base = devm_ioremap_resource(dev, res);
4401dc20828SKuninori Morimoto 		if (IS_ERR(priv->base)) {
4411dc20828SKuninori Morimoto 			ret = PTR_ERR(priv->base);
4421dc20828SKuninori Morimoto 			goto error_unregister;
4431dc20828SKuninori Morimoto 		}
4441e426ffdSKuninori Morimoto 
4453676d1ddSKuninori Morimoto 		priv->common = common;
446e0a5172eSKuninori Morimoto 		priv->id = i;
4473676d1ddSKuninori Morimoto 		mutex_init(&priv->lock);
4483676d1ddSKuninori Morimoto 		INIT_LIST_HEAD(&priv->list);
449e0a5172eSKuninori Morimoto 		INIT_DELAYED_WORK(&priv->work, rcar_thermal_work);
450e0a5172eSKuninori Morimoto 		rcar_thermal_update_temp(priv);
4513676d1ddSKuninori Morimoto 
4523676d1ddSKuninori Morimoto 		priv->zone = thermal_zone_device_register("rcar_thermal",
4533676d1ddSKuninori Morimoto 						1, 0, priv,
454d2a73e22Skuninori.morimoto.gx@renesas.com 						&rcar_thermal_zone_ops, NULL, 0,
455e0a5172eSKuninori Morimoto 						idle);
4563676d1ddSKuninori Morimoto 		if (IS_ERR(priv->zone)) {
4573676d1ddSKuninori Morimoto 			dev_err(dev, "can't register thermal zone\n");
458fb84d990SDevendra Naga 			ret = PTR_ERR(priv->zone);
4593676d1ddSKuninori Morimoto 			goto error_unregister;
4601e426ffdSKuninori Morimoto 		}
4611e426ffdSKuninori Morimoto 
462e0a5172eSKuninori Morimoto 		if (rcar_has_irq_support(priv))
463e0a5172eSKuninori Morimoto 			rcar_thermal_irq_enable(priv);
4641dc20828SKuninori Morimoto 
4651dc20828SKuninori Morimoto 		list_move_tail(&priv->list, &common->head);
46611313746SYoshihiro Shimoda 
46711313746SYoshihiro Shimoda 		/* update ENR bits */
46811313746SYoshihiro Shimoda 		enr_bits |= 3 << (i * 8);
4693676d1ddSKuninori Morimoto 	}
4701e426ffdSKuninori Morimoto 
47111313746SYoshihiro Shimoda 	/* enable temperature comparation */
4720b37a83aSGeert Uytterhoeven 	if (irq) {
4730b37a83aSGeert Uytterhoeven 		ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
4740b37a83aSGeert Uytterhoeven 				       dev_name(dev), common);
4750b37a83aSGeert Uytterhoeven 		if (ret) {
4760b37a83aSGeert Uytterhoeven 			dev_err(dev, "irq request failed\n ");
4770b37a83aSGeert Uytterhoeven 			goto error_unregister;
4780b37a83aSGeert Uytterhoeven 		}
4790b37a83aSGeert Uytterhoeven 
48011313746SYoshihiro Shimoda 		rcar_thermal_common_write(common, ENR, enr_bits);
4810b37a83aSGeert Uytterhoeven 	}
48211313746SYoshihiro Shimoda 
4833db46c93SLaurent Pinchart 	dev_info(dev, "%d sensor probed\n", i);
4841e426ffdSKuninori Morimoto 
4851e426ffdSKuninori Morimoto 	return 0;
4863676d1ddSKuninori Morimoto 
4873676d1ddSKuninori Morimoto error_unregister:
48884f0e490SKuninori Morimoto 	rcar_thermal_remove(pdev);
48951d45d25SKuninori Morimoto 
490fb84d990SDevendra Naga 	return ret;
4911e426ffdSKuninori Morimoto }
4921e426ffdSKuninori Morimoto 
4931e426ffdSKuninori Morimoto static struct platform_driver rcar_thermal_driver = {
4941e426ffdSKuninori Morimoto 	.driver	= {
4951e426ffdSKuninori Morimoto 		.name	= "rcar_thermal",
49676cc1887SKuninori Morimoto 		.of_match_table = rcar_thermal_dt_ids,
4971e426ffdSKuninori Morimoto 	},
4981e426ffdSKuninori Morimoto 	.probe		= rcar_thermal_probe,
4991e426ffdSKuninori Morimoto 	.remove		= rcar_thermal_remove,
5001e426ffdSKuninori Morimoto };
5011e426ffdSKuninori Morimoto module_platform_driver(rcar_thermal_driver);
5021e426ffdSKuninori Morimoto 
5031e426ffdSKuninori Morimoto MODULE_LICENSE("GPL");
5041e426ffdSKuninori Morimoto MODULE_DESCRIPTION("R-Car THS/TSC thermal sensor driver");
5051e426ffdSKuninori Morimoto MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
506