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;
66e0a5172eSKuninori Morimoto 	int 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 
841e426ffdSKuninori Morimoto /*
851e426ffdSKuninori Morimoto  *		basic functions
861e426ffdSKuninori Morimoto  */
87e9137a58SKuninori Morimoto #define rcar_thermal_common_read(c, r) \
88e9137a58SKuninori Morimoto 	_rcar_thermal_common_read(c, COMMON_ ##r)
89e9137a58SKuninori Morimoto static u32 _rcar_thermal_common_read(struct rcar_thermal_common *common,
90e9137a58SKuninori Morimoto 				     u32 reg)
91e9137a58SKuninori Morimoto {
92e9137a58SKuninori Morimoto 	return ioread32(common->base + reg);
93e9137a58SKuninori Morimoto }
94e9137a58SKuninori Morimoto 
95e9137a58SKuninori Morimoto #define rcar_thermal_common_write(c, r, d) \
96e9137a58SKuninori Morimoto 	_rcar_thermal_common_write(c, COMMON_ ##r, d)
97e9137a58SKuninori Morimoto static void _rcar_thermal_common_write(struct rcar_thermal_common *common,
98e9137a58SKuninori Morimoto 				       u32 reg, u32 data)
99e9137a58SKuninori Morimoto {
100e9137a58SKuninori Morimoto 	iowrite32(data, common->base + reg);
101e9137a58SKuninori Morimoto }
102e9137a58SKuninori Morimoto 
103e9137a58SKuninori Morimoto #define rcar_thermal_common_bset(c, r, m, d) \
104e9137a58SKuninori Morimoto 	_rcar_thermal_common_bset(c, COMMON_ ##r, m, d)
105e9137a58SKuninori Morimoto static void _rcar_thermal_common_bset(struct rcar_thermal_common *common,
106e9137a58SKuninori Morimoto 				      u32 reg, u32 mask, u32 data)
107e9137a58SKuninori Morimoto {
108e9137a58SKuninori Morimoto 	u32 val;
109e9137a58SKuninori Morimoto 
110e9137a58SKuninori Morimoto 	val = ioread32(common->base + reg);
111e9137a58SKuninori Morimoto 	val &= ~mask;
112e9137a58SKuninori Morimoto 	val |= (data & mask);
113e9137a58SKuninori Morimoto 	iowrite32(val, common->base + reg);
114e9137a58SKuninori Morimoto }
115e9137a58SKuninori Morimoto 
116e9137a58SKuninori Morimoto #define rcar_thermal_read(p, r) _rcar_thermal_read(p, REG_ ##r)
117e9137a58SKuninori Morimoto static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
1181e426ffdSKuninori Morimoto {
119b2bbc6a2SKuninori Morimoto 	return ioread32(priv->base + reg);
1201e426ffdSKuninori Morimoto }
1211e426ffdSKuninori Morimoto 
122e9137a58SKuninori Morimoto #define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, REG_ ##r, d)
123e9137a58SKuninori Morimoto static void _rcar_thermal_write(struct rcar_thermal_priv *priv,
1241e426ffdSKuninori Morimoto 				u32 reg, u32 data)
1251e426ffdSKuninori Morimoto {
1261e426ffdSKuninori Morimoto 	iowrite32(data, priv->base + reg);
1271e426ffdSKuninori Morimoto }
1281e426ffdSKuninori Morimoto 
129e9137a58SKuninori Morimoto #define rcar_thermal_bset(p, r, m, d) _rcar_thermal_bset(p, REG_ ##r, m, d)
130e9137a58SKuninori Morimoto static void _rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
1311e426ffdSKuninori Morimoto 			       u32 mask, u32 data)
1321e426ffdSKuninori Morimoto {
1331e426ffdSKuninori Morimoto 	u32 val;
1341e426ffdSKuninori Morimoto 
1351e426ffdSKuninori Morimoto 	val = ioread32(priv->base + reg);
1361e426ffdSKuninori Morimoto 	val &= ~mask;
1371e426ffdSKuninori Morimoto 	val |= (data & mask);
1381e426ffdSKuninori Morimoto 	iowrite32(val, priv->base + reg);
1391e426ffdSKuninori Morimoto }
1401e426ffdSKuninori Morimoto 
1411e426ffdSKuninori Morimoto /*
1421e426ffdSKuninori Morimoto  *		zone device functions
1431e426ffdSKuninori Morimoto  */
144e0a5172eSKuninori Morimoto static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
1451e426ffdSKuninori Morimoto {
146f8f53e18SKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
147f8f53e18SKuninori Morimoto 	int i;
148f8f53e18SKuninori Morimoto 	int ctemp, old, new;
149f0e68fc3SWei Yongjun 	int ret = -EINVAL;
1501e426ffdSKuninori Morimoto 
151b2bbc6a2SKuninori Morimoto 	mutex_lock(&priv->lock);
152b2bbc6a2SKuninori Morimoto 
1531e426ffdSKuninori Morimoto 	/*
154f8f53e18SKuninori Morimoto 	 * TSC decides a value of CPTAP automatically,
155f8f53e18SKuninori Morimoto 	 * and this is the conditions which validate interrupt.
1561e426ffdSKuninori Morimoto 	 */
157f8f53e18SKuninori Morimoto 	rcar_thermal_bset(priv, THSCR, CPCTL, CPCTL);
1581e426ffdSKuninori Morimoto 
159f8f53e18SKuninori Morimoto 	ctemp = 0;
160f8f53e18SKuninori Morimoto 	old = ~0;
161f8f53e18SKuninori Morimoto 	for (i = 0; i < 128; i++) {
1621e426ffdSKuninori Morimoto 		/*
1631e426ffdSKuninori Morimoto 		 * we need to wait 300us after changing comparator offset
1641e426ffdSKuninori Morimoto 		 * to get stable temperature.
1651e426ffdSKuninori Morimoto 		 * see "Usage Notes" on datasheet
1661e426ffdSKuninori Morimoto 		 */
1671e426ffdSKuninori Morimoto 		udelay(300);
1681e426ffdSKuninori Morimoto 
169f8f53e18SKuninori Morimoto 		new = rcar_thermal_read(priv, THSSR) & CTEMP;
170f8f53e18SKuninori Morimoto 		if (new == old) {
171f8f53e18SKuninori Morimoto 			ctemp = new;
1721e426ffdSKuninori Morimoto 			break;
1731e426ffdSKuninori Morimoto 		}
174f8f53e18SKuninori Morimoto 		old = new;
1751e426ffdSKuninori Morimoto 	}
1761e426ffdSKuninori Morimoto 
177f8f53e18SKuninori Morimoto 	if (!ctemp) {
178f8f53e18SKuninori Morimoto 		dev_err(dev, "thermal sensor was broken\n");
179f0e68fc3SWei Yongjun 		goto err_out_unlock;
180f8f53e18SKuninori Morimoto 	}
181f8f53e18SKuninori Morimoto 
182e0a5172eSKuninori Morimoto 	/*
183e0a5172eSKuninori Morimoto 	 * enable IRQ
184e0a5172eSKuninori Morimoto 	 */
185e0a5172eSKuninori Morimoto 	if (rcar_has_irq_support(priv)) {
186e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, FILONOFF, 0);
187f8f53e18SKuninori Morimoto 
188e0a5172eSKuninori Morimoto 		/* enable Rising/Falling edge interrupt */
189e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, POSNEG,  0x1);
190e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, INTCTRL, (((ctemp - 0) << 8) |
191e0a5172eSKuninori Morimoto 						   ((ctemp - 1) << 0)));
192e0a5172eSKuninori Morimoto 	}
193e0a5172eSKuninori Morimoto 
194e0a5172eSKuninori Morimoto 	dev_dbg(dev, "thermal%d  %d -> %d\n", priv->id, priv->ctemp, ctemp);
195e0a5172eSKuninori Morimoto 
196e0a5172eSKuninori Morimoto 	priv->ctemp = ctemp;
197f0e68fc3SWei Yongjun 	ret = 0;
198f0e68fc3SWei Yongjun err_out_unlock:
199e0a5172eSKuninori Morimoto 	mutex_unlock(&priv->lock);
200f0e68fc3SWei Yongjun 	return ret;
201e0a5172eSKuninori Morimoto }
202e0a5172eSKuninori Morimoto 
203e0a5172eSKuninori Morimoto static int rcar_thermal_get_temp(struct thermal_zone_device *zone,
204e0a5172eSKuninori Morimoto 				 unsigned long *temp)
205e0a5172eSKuninori Morimoto {
206e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
207e0a5172eSKuninori Morimoto 
208e0a5172eSKuninori Morimoto 	if (!rcar_has_irq_support(priv) || rcar_force_update_temp(priv))
209e0a5172eSKuninori Morimoto 		rcar_thermal_update_temp(priv);
210e0a5172eSKuninori Morimoto 
211e0a5172eSKuninori Morimoto 	mutex_lock(&priv->lock);
212e0a5172eSKuninori Morimoto 	*temp =  MCELSIUS((priv->ctemp * 5) - 65);
213b2bbc6a2SKuninori Morimoto 	mutex_unlock(&priv->lock);
214b2bbc6a2SKuninori Morimoto 
2151e426ffdSKuninori Morimoto 	return 0;
2161e426ffdSKuninori Morimoto }
2171e426ffdSKuninori Morimoto 
218d2a73e22Skuninori.morimoto.gx@renesas.com static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
219d2a73e22Skuninori.morimoto.gx@renesas.com 				      int trip, enum thermal_trip_type *type)
220d2a73e22Skuninori.morimoto.gx@renesas.com {
221d2a73e22Skuninori.morimoto.gx@renesas.com 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
2223676d1ddSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
223d2a73e22Skuninori.morimoto.gx@renesas.com 
224d2a73e22Skuninori.morimoto.gx@renesas.com 	/* see rcar_thermal_get_temp() */
225d2a73e22Skuninori.morimoto.gx@renesas.com 	switch (trip) {
226d2a73e22Skuninori.morimoto.gx@renesas.com 	case 0: /* +90 <= temp */
227d2a73e22Skuninori.morimoto.gx@renesas.com 		*type = THERMAL_TRIP_CRITICAL;
228d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
229d2a73e22Skuninori.morimoto.gx@renesas.com 	default:
2303676d1ddSKuninori Morimoto 		dev_err(dev, "rcar driver trip error\n");
231d2a73e22Skuninori.morimoto.gx@renesas.com 		return -EINVAL;
232d2a73e22Skuninori.morimoto.gx@renesas.com 	}
233d2a73e22Skuninori.morimoto.gx@renesas.com 
234d2a73e22Skuninori.morimoto.gx@renesas.com 	return 0;
235d2a73e22Skuninori.morimoto.gx@renesas.com }
236d2a73e22Skuninori.morimoto.gx@renesas.com 
237d2a73e22Skuninori.morimoto.gx@renesas.com static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone,
238d2a73e22Skuninori.morimoto.gx@renesas.com 				      int trip, unsigned long *temp)
239d2a73e22Skuninori.morimoto.gx@renesas.com {
240d2a73e22Skuninori.morimoto.gx@renesas.com 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
2413676d1ddSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
242d2a73e22Skuninori.morimoto.gx@renesas.com 
243d2a73e22Skuninori.morimoto.gx@renesas.com 	/* see rcar_thermal_get_temp() */
244d2a73e22Skuninori.morimoto.gx@renesas.com 	switch (trip) {
245d2a73e22Skuninori.morimoto.gx@renesas.com 	case 0: /* +90 <= temp */
246d2a73e22Skuninori.morimoto.gx@renesas.com 		*temp = MCELSIUS(90);
247d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
248d2a73e22Skuninori.morimoto.gx@renesas.com 	default:
2493676d1ddSKuninori Morimoto 		dev_err(dev, "rcar driver trip error\n");
250d2a73e22Skuninori.morimoto.gx@renesas.com 		return -EINVAL;
251d2a73e22Skuninori.morimoto.gx@renesas.com 	}
252d2a73e22Skuninori.morimoto.gx@renesas.com 
253d2a73e22Skuninori.morimoto.gx@renesas.com 	return 0;
254d2a73e22Skuninori.morimoto.gx@renesas.com }
255d2a73e22Skuninori.morimoto.gx@renesas.com 
256d2a73e22Skuninori.morimoto.gx@renesas.com static int rcar_thermal_notify(struct thermal_zone_device *zone,
257d2a73e22Skuninori.morimoto.gx@renesas.com 			       int trip, enum thermal_trip_type type)
258d2a73e22Skuninori.morimoto.gx@renesas.com {
259d2a73e22Skuninori.morimoto.gx@renesas.com 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
2603676d1ddSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
261d2a73e22Skuninori.morimoto.gx@renesas.com 
262d2a73e22Skuninori.morimoto.gx@renesas.com 	switch (type) {
263d2a73e22Skuninori.morimoto.gx@renesas.com 	case THERMAL_TRIP_CRITICAL:
264d2a73e22Skuninori.morimoto.gx@renesas.com 		/* FIXME */
2653676d1ddSKuninori Morimoto 		dev_warn(dev, "Thermal reached to critical temperature\n");
266d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
267d2a73e22Skuninori.morimoto.gx@renesas.com 	default:
268d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
269d2a73e22Skuninori.morimoto.gx@renesas.com 	}
270d2a73e22Skuninori.morimoto.gx@renesas.com 
271d2a73e22Skuninori.morimoto.gx@renesas.com 	return 0;
272d2a73e22Skuninori.morimoto.gx@renesas.com }
273d2a73e22Skuninori.morimoto.gx@renesas.com 
2741e426ffdSKuninori Morimoto static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
2751e426ffdSKuninori Morimoto 	.get_temp	= rcar_thermal_get_temp,
276d2a73e22Skuninori.morimoto.gx@renesas.com 	.get_trip_type	= rcar_thermal_get_trip_type,
277d2a73e22Skuninori.morimoto.gx@renesas.com 	.get_trip_temp	= rcar_thermal_get_trip_temp,
278d2a73e22Skuninori.morimoto.gx@renesas.com 	.notify		= rcar_thermal_notify,
2791e426ffdSKuninori Morimoto };
2801e426ffdSKuninori Morimoto 
2811e426ffdSKuninori Morimoto /*
282e0a5172eSKuninori Morimoto  *		interrupt
283e0a5172eSKuninori Morimoto  */
284e0a5172eSKuninori Morimoto #define rcar_thermal_irq_enable(p)	_rcar_thermal_irq_ctrl(p, 1)
285e0a5172eSKuninori Morimoto #define rcar_thermal_irq_disable(p)	_rcar_thermal_irq_ctrl(p, 0)
286e0a5172eSKuninori Morimoto static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
287e0a5172eSKuninori Morimoto {
288e0a5172eSKuninori Morimoto 	struct rcar_thermal_common *common = priv->common;
289e0a5172eSKuninori Morimoto 	unsigned long flags;
290e0a5172eSKuninori Morimoto 	u32 mask = 0x3 << rcar_id_to_shift(priv); /* enable Rising/Falling */
291e0a5172eSKuninori Morimoto 
292e0a5172eSKuninori Morimoto 	spin_lock_irqsave(&common->lock, flags);
293e0a5172eSKuninori Morimoto 
294e0a5172eSKuninori Morimoto 	rcar_thermal_common_bset(common, INTMSK, mask, enable ? 0 : mask);
295e0a5172eSKuninori Morimoto 
296e0a5172eSKuninori Morimoto 	spin_unlock_irqrestore(&common->lock, flags);
297e0a5172eSKuninori Morimoto }
298e0a5172eSKuninori Morimoto 
299e0a5172eSKuninori Morimoto static void rcar_thermal_work(struct work_struct *work)
300e0a5172eSKuninori Morimoto {
301e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv;
3029477165eSPatrick Titiano 	unsigned long cctemp, nctemp;
303e0a5172eSKuninori Morimoto 
304e0a5172eSKuninori Morimoto 	priv = container_of(work, struct rcar_thermal_priv, work.work);
305e0a5172eSKuninori Morimoto 
3069477165eSPatrick Titiano 	rcar_thermal_get_temp(priv->zone, &cctemp);
307e0a5172eSKuninori Morimoto 	rcar_thermal_update_temp(priv);
308e0a5172eSKuninori Morimoto 	rcar_thermal_irq_enable(priv);
3099477165eSPatrick Titiano 
3109477165eSPatrick Titiano 	rcar_thermal_get_temp(priv->zone, &nctemp);
3119477165eSPatrick Titiano 	if (nctemp != cctemp)
312e0a5172eSKuninori Morimoto 		thermal_zone_device_update(priv->zone);
313e0a5172eSKuninori Morimoto }
314e0a5172eSKuninori Morimoto 
315e0a5172eSKuninori Morimoto static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
316e0a5172eSKuninori Morimoto {
317e0a5172eSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
318e0a5172eSKuninori Morimoto 
319e0a5172eSKuninori Morimoto 	status = (status >> rcar_id_to_shift(priv)) & 0x3;
320e0a5172eSKuninori Morimoto 
321206c0cbaSPatrick Titiano 	if (status) {
322e0a5172eSKuninori Morimoto 		dev_dbg(dev, "thermal%d %s%s\n",
323e0a5172eSKuninori Morimoto 			priv->id,
324e0a5172eSKuninori Morimoto 			(status & 0x2) ? "Rising " : "",
325e0a5172eSKuninori Morimoto 			(status & 0x1) ? "Falling" : "");
326e0a5172eSKuninori Morimoto 	}
327e0a5172eSKuninori Morimoto 
328e0a5172eSKuninori Morimoto 	return status;
329e0a5172eSKuninori Morimoto }
330e0a5172eSKuninori Morimoto 
331e0a5172eSKuninori Morimoto static irqreturn_t rcar_thermal_irq(int irq, void *data)
332e0a5172eSKuninori Morimoto {
333e0a5172eSKuninori Morimoto 	struct rcar_thermal_common *common = data;
334e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv;
335e0a5172eSKuninori Morimoto 	unsigned long flags;
336e0a5172eSKuninori Morimoto 	u32 status, mask;
337e0a5172eSKuninori Morimoto 
338e0a5172eSKuninori Morimoto 	spin_lock_irqsave(&common->lock, flags);
339e0a5172eSKuninori Morimoto 
340e0a5172eSKuninori Morimoto 	mask	= rcar_thermal_common_read(common, INTMSK);
341e0a5172eSKuninori Morimoto 	status	= rcar_thermal_common_read(common, STR);
342e0a5172eSKuninori Morimoto 	rcar_thermal_common_write(common, STR, 0x000F0F0F & mask);
343e0a5172eSKuninori Morimoto 
344e0a5172eSKuninori Morimoto 	spin_unlock_irqrestore(&common->lock, flags);
345e0a5172eSKuninori Morimoto 
346e0a5172eSKuninori Morimoto 	status = status & ~mask;
347e0a5172eSKuninori Morimoto 
348e0a5172eSKuninori Morimoto 	/*
349e0a5172eSKuninori Morimoto 	 * check the status
350e0a5172eSKuninori Morimoto 	 */
351e0a5172eSKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
352e0a5172eSKuninori Morimoto 		if (rcar_thermal_had_changed(priv, status)) {
353e0a5172eSKuninori Morimoto 			rcar_thermal_irq_disable(priv);
354e0a5172eSKuninori Morimoto 			schedule_delayed_work(&priv->work,
355e0a5172eSKuninori Morimoto 					      msecs_to_jiffies(300));
356e0a5172eSKuninori Morimoto 		}
357e0a5172eSKuninori Morimoto 	}
358e0a5172eSKuninori Morimoto 
359e0a5172eSKuninori Morimoto 	return IRQ_HANDLED;
360e0a5172eSKuninori Morimoto }
361e0a5172eSKuninori Morimoto 
362e0a5172eSKuninori Morimoto /*
3631e426ffdSKuninori Morimoto  *		platform functions
3641e426ffdSKuninori Morimoto  */
3651e426ffdSKuninori Morimoto static int rcar_thermal_probe(struct platform_device *pdev)
3661e426ffdSKuninori Morimoto {
3673676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common;
3681e426ffdSKuninori Morimoto 	struct rcar_thermal_priv *priv;
3693676d1ddSKuninori Morimoto 	struct device *dev = &pdev->dev;
3703676d1ddSKuninori Morimoto 	struct resource *res, *irq;
3713676d1ddSKuninori Morimoto 	int mres = 0;
3723676d1ddSKuninori Morimoto 	int i;
373fb84d990SDevendra Naga 	int ret = -ENODEV;
374e0a5172eSKuninori Morimoto 	int idle = IDLE_INTERVAL;
3751e426ffdSKuninori Morimoto 
3763676d1ddSKuninori Morimoto 	common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
3773676d1ddSKuninori Morimoto 	if (!common) {
3783676d1ddSKuninori Morimoto 		dev_err(dev, "Could not allocate common\n");
3793676d1ddSKuninori Morimoto 		return -ENOMEM;
3803676d1ddSKuninori Morimoto 	}
3813676d1ddSKuninori Morimoto 
3823676d1ddSKuninori Morimoto 	INIT_LIST_HEAD(&common->head);
383e0a5172eSKuninori Morimoto 	spin_lock_init(&common->lock);
3843676d1ddSKuninori Morimoto 	common->dev = dev;
3853676d1ddSKuninori Morimoto 
38651d45d25SKuninori Morimoto 	pm_runtime_enable(dev);
38751d45d25SKuninori Morimoto 	pm_runtime_get_sync(dev);
38851d45d25SKuninori Morimoto 
3893676d1ddSKuninori Morimoto 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3903676d1ddSKuninori Morimoto 	if (irq) {
391e0a5172eSKuninori Morimoto 		int ret;
392e0a5172eSKuninori Morimoto 
3933676d1ddSKuninori Morimoto 		/*
3943676d1ddSKuninori Morimoto 		 * platform has IRQ support.
3953676d1ddSKuninori Morimoto 		 * Then, drier use common register
3963676d1ddSKuninori Morimoto 		 */
3971e426ffdSKuninori Morimoto 
398e0a5172eSKuninori Morimoto 		ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
399e0a5172eSKuninori Morimoto 				       dev_name(dev), common);
400e0a5172eSKuninori Morimoto 		if (ret) {
401e0a5172eSKuninori Morimoto 			dev_err(dev, "irq request failed\n ");
402e0a5172eSKuninori Morimoto 			return ret;
403e0a5172eSKuninori Morimoto 		}
404e0a5172eSKuninori Morimoto 
4053676d1ddSKuninori Morimoto 		/*
4063676d1ddSKuninori Morimoto 		 * rcar_has_irq_support() will be enabled
4073676d1ddSKuninori Morimoto 		 */
408c28f692cSWolfram Sang 		res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
4095095526fSSachin Kamat 		common->base = devm_ioremap_resource(dev, res);
4105095526fSSachin Kamat 		if (IS_ERR(common->base))
4115095526fSSachin Kamat 			return PTR_ERR(common->base);
412e0a5172eSKuninori Morimoto 
413e0a5172eSKuninori Morimoto 		/* enable temperature comparation */
414e0a5172eSKuninori Morimoto 		rcar_thermal_common_write(common, ENR, 0x00030303);
415e0a5172eSKuninori Morimoto 
4166fe495e0SGeert Uytterhoeven 		idle = 0; /* polling delay is not needed */
4173676d1ddSKuninori Morimoto 	}
4183676d1ddSKuninori Morimoto 
4193676d1ddSKuninori Morimoto 	for (i = 0;; i++) {
4203676d1ddSKuninori Morimoto 		res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
4213676d1ddSKuninori Morimoto 		if (!res)
4223676d1ddSKuninori Morimoto 			break;
4233676d1ddSKuninori Morimoto 
4243676d1ddSKuninori Morimoto 		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
4251e426ffdSKuninori Morimoto 		if (!priv) {
4263676d1ddSKuninori Morimoto 			dev_err(dev, "Could not allocate priv\n");
4271dc20828SKuninori Morimoto 			ret = -ENOMEM;
4281dc20828SKuninori Morimoto 			goto error_unregister;
4291e426ffdSKuninori Morimoto 		}
4301e426ffdSKuninori Morimoto 
4315095526fSSachin Kamat 		priv->base = devm_ioremap_resource(dev, res);
4321dc20828SKuninori Morimoto 		if (IS_ERR(priv->base)) {
4331dc20828SKuninori Morimoto 			ret = PTR_ERR(priv->base);
4341dc20828SKuninori Morimoto 			goto error_unregister;
4351dc20828SKuninori Morimoto 		}
4361e426ffdSKuninori Morimoto 
4373676d1ddSKuninori Morimoto 		priv->common = common;
438e0a5172eSKuninori Morimoto 		priv->id = i;
4393676d1ddSKuninori Morimoto 		mutex_init(&priv->lock);
4403676d1ddSKuninori Morimoto 		INIT_LIST_HEAD(&priv->list);
441e0a5172eSKuninori Morimoto 		INIT_DELAYED_WORK(&priv->work, rcar_thermal_work);
442e0a5172eSKuninori Morimoto 		rcar_thermal_update_temp(priv);
4433676d1ddSKuninori Morimoto 
4443676d1ddSKuninori Morimoto 		priv->zone = thermal_zone_device_register("rcar_thermal",
4453676d1ddSKuninori Morimoto 						1, 0, priv,
446d2a73e22Skuninori.morimoto.gx@renesas.com 						&rcar_thermal_zone_ops, NULL, 0,
447e0a5172eSKuninori Morimoto 						idle);
4483676d1ddSKuninori Morimoto 		if (IS_ERR(priv->zone)) {
4493676d1ddSKuninori Morimoto 			dev_err(dev, "can't register thermal zone\n");
450fb84d990SDevendra Naga 			ret = PTR_ERR(priv->zone);
4513676d1ddSKuninori Morimoto 			goto error_unregister;
4521e426ffdSKuninori Morimoto 		}
4531e426ffdSKuninori Morimoto 
454e0a5172eSKuninori Morimoto 		if (rcar_has_irq_support(priv))
455e0a5172eSKuninori Morimoto 			rcar_thermal_irq_enable(priv);
4561dc20828SKuninori Morimoto 
4571dc20828SKuninori Morimoto 		list_move_tail(&priv->list, &common->head);
4583676d1ddSKuninori Morimoto 	}
4591e426ffdSKuninori Morimoto 
4603676d1ddSKuninori Morimoto 	platform_set_drvdata(pdev, common);
4613676d1ddSKuninori Morimoto 
4623db46c93SLaurent Pinchart 	dev_info(dev, "%d sensor probed\n", i);
4631e426ffdSKuninori Morimoto 
4641e426ffdSKuninori Morimoto 	return 0;
4653676d1ddSKuninori Morimoto 
4663676d1ddSKuninori Morimoto error_unregister:
4671dc20828SKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
4683676d1ddSKuninori Morimoto 		thermal_zone_device_unregister(priv->zone);
4691dc20828SKuninori Morimoto 		if (rcar_has_irq_support(priv))
4701dc20828SKuninori Morimoto 			rcar_thermal_irq_disable(priv);
4711dc20828SKuninori Morimoto 	}
4723676d1ddSKuninori Morimoto 
47309be511cSGeert Uytterhoeven 	pm_runtime_put(dev);
47451d45d25SKuninori Morimoto 	pm_runtime_disable(dev);
47551d45d25SKuninori Morimoto 
476fb84d990SDevendra Naga 	return ret;
4771e426ffdSKuninori Morimoto }
4781e426ffdSKuninori Morimoto 
4791e426ffdSKuninori Morimoto static int rcar_thermal_remove(struct platform_device *pdev)
4801e426ffdSKuninori Morimoto {
4813676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common = platform_get_drvdata(pdev);
48251d45d25SKuninori Morimoto 	struct device *dev = &pdev->dev;
4833676d1ddSKuninori Morimoto 	struct rcar_thermal_priv *priv;
4841e426ffdSKuninori Morimoto 
4851dc20828SKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
4863676d1ddSKuninori Morimoto 		thermal_zone_device_unregister(priv->zone);
4871dc20828SKuninori Morimoto 		if (rcar_has_irq_support(priv))
4881dc20828SKuninori Morimoto 			rcar_thermal_irq_disable(priv);
4891dc20828SKuninori Morimoto 	}
4903676d1ddSKuninori Morimoto 
49109be511cSGeert Uytterhoeven 	pm_runtime_put(dev);
49251d45d25SKuninori Morimoto 	pm_runtime_disable(dev);
49351d45d25SKuninori Morimoto 
4941e426ffdSKuninori Morimoto 	return 0;
4951e426ffdSKuninori Morimoto }
4961e426ffdSKuninori Morimoto 
497f5b6d45fSArnd Bergmann static const struct of_device_id rcar_thermal_dt_ids[] = {
49876cc1887SKuninori Morimoto 	{ .compatible = "renesas,rcar-thermal", },
49976cc1887SKuninori Morimoto 	{},
50076cc1887SKuninori Morimoto };
50176cc1887SKuninori Morimoto MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
50276cc1887SKuninori Morimoto 
5031e426ffdSKuninori Morimoto static struct platform_driver rcar_thermal_driver = {
5041e426ffdSKuninori Morimoto 	.driver	= {
5051e426ffdSKuninori Morimoto 		.name	= "rcar_thermal",
50676cc1887SKuninori Morimoto 		.of_match_table = rcar_thermal_dt_ids,
5071e426ffdSKuninori Morimoto 	},
5081e426ffdSKuninori Morimoto 	.probe		= rcar_thermal_probe,
5091e426ffdSKuninori Morimoto 	.remove		= rcar_thermal_remove,
5101e426ffdSKuninori Morimoto };
5111e426ffdSKuninori Morimoto module_platform_driver(rcar_thermal_driver);
5121e426ffdSKuninori Morimoto 
5131e426ffdSKuninori Morimoto MODULE_LICENSE("GPL");
5141e426ffdSKuninori Morimoto MODULE_DESCRIPTION("R-Car THS/TSC thermal sensor driver");
5151e426ffdSKuninori Morimoto MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
516