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;
302e0a5172eSKuninori Morimoto 
303e0a5172eSKuninori Morimoto 	priv = container_of(work, struct rcar_thermal_priv, work.work);
304e0a5172eSKuninori Morimoto 
305e0a5172eSKuninori Morimoto 	rcar_thermal_update_temp(priv);
306e0a5172eSKuninori Morimoto 	rcar_thermal_irq_enable(priv);
307e0a5172eSKuninori Morimoto 	thermal_zone_device_update(priv->zone);
308e0a5172eSKuninori Morimoto }
309e0a5172eSKuninori Morimoto 
310e0a5172eSKuninori Morimoto static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
311e0a5172eSKuninori Morimoto {
312e0a5172eSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
313e0a5172eSKuninori Morimoto 
314e0a5172eSKuninori Morimoto 	status = (status >> rcar_id_to_shift(priv)) & 0x3;
315e0a5172eSKuninori Morimoto 
316e0a5172eSKuninori Morimoto 	if (status & 0x3) {
317e0a5172eSKuninori Morimoto 		dev_dbg(dev, "thermal%d %s%s\n",
318e0a5172eSKuninori Morimoto 			priv->id,
319e0a5172eSKuninori Morimoto 			(status & 0x2) ? "Rising " : "",
320e0a5172eSKuninori Morimoto 			(status & 0x1) ? "Falling" : "");
321e0a5172eSKuninori Morimoto 	}
322e0a5172eSKuninori Morimoto 
323e0a5172eSKuninori Morimoto 	return status;
324e0a5172eSKuninori Morimoto }
325e0a5172eSKuninori Morimoto 
326e0a5172eSKuninori Morimoto static irqreturn_t rcar_thermal_irq(int irq, void *data)
327e0a5172eSKuninori Morimoto {
328e0a5172eSKuninori Morimoto 	struct rcar_thermal_common *common = data;
329e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv;
330e0a5172eSKuninori Morimoto 	unsigned long flags;
331e0a5172eSKuninori Morimoto 	u32 status, mask;
332e0a5172eSKuninori Morimoto 
333e0a5172eSKuninori Morimoto 	spin_lock_irqsave(&common->lock, flags);
334e0a5172eSKuninori Morimoto 
335e0a5172eSKuninori Morimoto 	mask	= rcar_thermal_common_read(common, INTMSK);
336e0a5172eSKuninori Morimoto 	status	= rcar_thermal_common_read(common, STR);
337e0a5172eSKuninori Morimoto 	rcar_thermal_common_write(common, STR, 0x000F0F0F & mask);
338e0a5172eSKuninori Morimoto 
339e0a5172eSKuninori Morimoto 	spin_unlock_irqrestore(&common->lock, flags);
340e0a5172eSKuninori Morimoto 
341e0a5172eSKuninori Morimoto 	status = status & ~mask;
342e0a5172eSKuninori Morimoto 
343e0a5172eSKuninori Morimoto 	/*
344e0a5172eSKuninori Morimoto 	 * check the status
345e0a5172eSKuninori Morimoto 	 */
346e0a5172eSKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
347e0a5172eSKuninori Morimoto 		if (rcar_thermal_had_changed(priv, status)) {
348e0a5172eSKuninori Morimoto 			rcar_thermal_irq_disable(priv);
349e0a5172eSKuninori Morimoto 			schedule_delayed_work(&priv->work,
350e0a5172eSKuninori Morimoto 					      msecs_to_jiffies(300));
351e0a5172eSKuninori Morimoto 		}
352e0a5172eSKuninori Morimoto 	}
353e0a5172eSKuninori Morimoto 
354e0a5172eSKuninori Morimoto 	return IRQ_HANDLED;
355e0a5172eSKuninori Morimoto }
356e0a5172eSKuninori Morimoto 
357e0a5172eSKuninori Morimoto /*
3581e426ffdSKuninori Morimoto  *		platform functions
3591e426ffdSKuninori Morimoto  */
3601e426ffdSKuninori Morimoto static int rcar_thermal_probe(struct platform_device *pdev)
3611e426ffdSKuninori Morimoto {
3623676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common;
3631e426ffdSKuninori Morimoto 	struct rcar_thermal_priv *priv;
3643676d1ddSKuninori Morimoto 	struct device *dev = &pdev->dev;
3653676d1ddSKuninori Morimoto 	struct resource *res, *irq;
3663676d1ddSKuninori Morimoto 	int mres = 0;
3673676d1ddSKuninori Morimoto 	int i;
368fb84d990SDevendra Naga 	int ret = -ENODEV;
369e0a5172eSKuninori Morimoto 	int idle = IDLE_INTERVAL;
3701e426ffdSKuninori Morimoto 
3713676d1ddSKuninori Morimoto 	common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
3723676d1ddSKuninori Morimoto 	if (!common) {
3733676d1ddSKuninori Morimoto 		dev_err(dev, "Could not allocate common\n");
3743676d1ddSKuninori Morimoto 		return -ENOMEM;
3753676d1ddSKuninori Morimoto 	}
3763676d1ddSKuninori Morimoto 
3773676d1ddSKuninori Morimoto 	INIT_LIST_HEAD(&common->head);
378e0a5172eSKuninori Morimoto 	spin_lock_init(&common->lock);
3793676d1ddSKuninori Morimoto 	common->dev = dev;
3803676d1ddSKuninori Morimoto 
38151d45d25SKuninori Morimoto 	pm_runtime_enable(dev);
38251d45d25SKuninori Morimoto 	pm_runtime_get_sync(dev);
38351d45d25SKuninori Morimoto 
3843676d1ddSKuninori Morimoto 	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3853676d1ddSKuninori Morimoto 	if (irq) {
386e0a5172eSKuninori Morimoto 		int ret;
387e0a5172eSKuninori Morimoto 
3883676d1ddSKuninori Morimoto 		/*
3893676d1ddSKuninori Morimoto 		 * platform has IRQ support.
3903676d1ddSKuninori Morimoto 		 * Then, drier use common register
3913676d1ddSKuninori Morimoto 		 */
3921e426ffdSKuninori Morimoto 
393e0a5172eSKuninori Morimoto 		ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
394e0a5172eSKuninori Morimoto 				       dev_name(dev), common);
395e0a5172eSKuninori Morimoto 		if (ret) {
396e0a5172eSKuninori Morimoto 			dev_err(dev, "irq request failed\n ");
397e0a5172eSKuninori Morimoto 			return ret;
398e0a5172eSKuninori Morimoto 		}
399e0a5172eSKuninori Morimoto 
4003676d1ddSKuninori Morimoto 		/*
4013676d1ddSKuninori Morimoto 		 * rcar_has_irq_support() will be enabled
4023676d1ddSKuninori Morimoto 		 */
403c28f692cSWolfram Sang 		res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
4045095526fSSachin Kamat 		common->base = devm_ioremap_resource(dev, res);
4055095526fSSachin Kamat 		if (IS_ERR(common->base))
4065095526fSSachin Kamat 			return PTR_ERR(common->base);
407e0a5172eSKuninori Morimoto 
408e0a5172eSKuninori Morimoto 		/* enable temperature comparation */
409e0a5172eSKuninori Morimoto 		rcar_thermal_common_write(common, ENR, 0x00030303);
410e0a5172eSKuninori Morimoto 
4116fe495e0SGeert Uytterhoeven 		idle = 0; /* polling delay is not needed */
4123676d1ddSKuninori Morimoto 	}
4133676d1ddSKuninori Morimoto 
4143676d1ddSKuninori Morimoto 	for (i = 0;; i++) {
4153676d1ddSKuninori Morimoto 		res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
4163676d1ddSKuninori Morimoto 		if (!res)
4173676d1ddSKuninori Morimoto 			break;
4183676d1ddSKuninori Morimoto 
4193676d1ddSKuninori Morimoto 		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
4201e426ffdSKuninori Morimoto 		if (!priv) {
4213676d1ddSKuninori Morimoto 			dev_err(dev, "Could not allocate priv\n");
4221dc20828SKuninori Morimoto 			ret = -ENOMEM;
4231dc20828SKuninori Morimoto 			goto error_unregister;
4241e426ffdSKuninori Morimoto 		}
4251e426ffdSKuninori Morimoto 
4265095526fSSachin Kamat 		priv->base = devm_ioremap_resource(dev, res);
4271dc20828SKuninori Morimoto 		if (IS_ERR(priv->base)) {
4281dc20828SKuninori Morimoto 			ret = PTR_ERR(priv->base);
4291dc20828SKuninori Morimoto 			goto error_unregister;
4301dc20828SKuninori Morimoto 		}
4311e426ffdSKuninori Morimoto 
4323676d1ddSKuninori Morimoto 		priv->common = common;
433e0a5172eSKuninori Morimoto 		priv->id = i;
4343676d1ddSKuninori Morimoto 		mutex_init(&priv->lock);
4353676d1ddSKuninori Morimoto 		INIT_LIST_HEAD(&priv->list);
436e0a5172eSKuninori Morimoto 		INIT_DELAYED_WORK(&priv->work, rcar_thermal_work);
437e0a5172eSKuninori Morimoto 		rcar_thermal_update_temp(priv);
4383676d1ddSKuninori Morimoto 
4393676d1ddSKuninori Morimoto 		priv->zone = thermal_zone_device_register("rcar_thermal",
4403676d1ddSKuninori Morimoto 						1, 0, priv,
441d2a73e22Skuninori.morimoto.gx@renesas.com 						&rcar_thermal_zone_ops, NULL, 0,
442e0a5172eSKuninori Morimoto 						idle);
4433676d1ddSKuninori Morimoto 		if (IS_ERR(priv->zone)) {
4443676d1ddSKuninori Morimoto 			dev_err(dev, "can't register thermal zone\n");
445fb84d990SDevendra Naga 			ret = PTR_ERR(priv->zone);
4463676d1ddSKuninori Morimoto 			goto error_unregister;
4471e426ffdSKuninori Morimoto 		}
4481e426ffdSKuninori Morimoto 
449e0a5172eSKuninori Morimoto 		if (rcar_has_irq_support(priv))
450e0a5172eSKuninori Morimoto 			rcar_thermal_irq_enable(priv);
4511dc20828SKuninori Morimoto 
4521dc20828SKuninori Morimoto 		list_move_tail(&priv->list, &common->head);
4533676d1ddSKuninori Morimoto 	}
4541e426ffdSKuninori Morimoto 
4553676d1ddSKuninori Morimoto 	platform_set_drvdata(pdev, common);
4563676d1ddSKuninori Morimoto 
4573db46c93SLaurent Pinchart 	dev_info(dev, "%d sensor probed\n", i);
4581e426ffdSKuninori Morimoto 
4591e426ffdSKuninori Morimoto 	return 0;
4603676d1ddSKuninori Morimoto 
4613676d1ddSKuninori Morimoto error_unregister:
4621dc20828SKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
4633676d1ddSKuninori Morimoto 		thermal_zone_device_unregister(priv->zone);
4641dc20828SKuninori Morimoto 		if (rcar_has_irq_support(priv))
4651dc20828SKuninori Morimoto 			rcar_thermal_irq_disable(priv);
4661dc20828SKuninori Morimoto 	}
4673676d1ddSKuninori Morimoto 
46851d45d25SKuninori Morimoto 	pm_runtime_put_sync(dev);
46951d45d25SKuninori Morimoto 	pm_runtime_disable(dev);
47051d45d25SKuninori Morimoto 
471fb84d990SDevendra Naga 	return ret;
4721e426ffdSKuninori Morimoto }
4731e426ffdSKuninori Morimoto 
4741e426ffdSKuninori Morimoto static int rcar_thermal_remove(struct platform_device *pdev)
4751e426ffdSKuninori Morimoto {
4763676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common = platform_get_drvdata(pdev);
47751d45d25SKuninori Morimoto 	struct device *dev = &pdev->dev;
4783676d1ddSKuninori Morimoto 	struct rcar_thermal_priv *priv;
4791e426ffdSKuninori Morimoto 
4801dc20828SKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
4813676d1ddSKuninori Morimoto 		thermal_zone_device_unregister(priv->zone);
4821dc20828SKuninori Morimoto 		if (rcar_has_irq_support(priv))
4831dc20828SKuninori Morimoto 			rcar_thermal_irq_disable(priv);
4841dc20828SKuninori Morimoto 	}
4853676d1ddSKuninori Morimoto 
48651d45d25SKuninori Morimoto 	pm_runtime_put_sync(dev);
48751d45d25SKuninori Morimoto 	pm_runtime_disable(dev);
48851d45d25SKuninori Morimoto 
4891e426ffdSKuninori Morimoto 	return 0;
4901e426ffdSKuninori Morimoto }
4911e426ffdSKuninori Morimoto 
492f5b6d45fSArnd Bergmann static const struct of_device_id rcar_thermal_dt_ids[] = {
49376cc1887SKuninori Morimoto 	{ .compatible = "renesas,rcar-thermal", },
49476cc1887SKuninori Morimoto 	{},
49576cc1887SKuninori Morimoto };
49676cc1887SKuninori Morimoto MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
49776cc1887SKuninori Morimoto 
4981e426ffdSKuninori Morimoto static struct platform_driver rcar_thermal_driver = {
4991e426ffdSKuninori Morimoto 	.driver	= {
5001e426ffdSKuninori Morimoto 		.name	= "rcar_thermal",
50176cc1887SKuninori Morimoto 		.of_match_table = rcar_thermal_dt_ids,
5021e426ffdSKuninori Morimoto 	},
5031e426ffdSKuninori Morimoto 	.probe		= rcar_thermal_probe,
5041e426ffdSKuninori Morimoto 	.remove		= rcar_thermal_remove,
5051e426ffdSKuninori Morimoto };
5061e426ffdSKuninori Morimoto module_platform_driver(rcar_thermal_driver);
5071e426ffdSKuninori Morimoto 
5081e426ffdSKuninori Morimoto MODULE_LICENSE("GPL");
5091e426ffdSKuninori Morimoto MODULE_DESCRIPTION("R-Car THS/TSC thermal sensor driver");
5101e426ffdSKuninori Morimoto MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
511