1c9545790SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
21e426ffdSKuninori Morimoto /*
31e426ffdSKuninori Morimoto  *  R-Car THS/TSC thermal sensor driver
41e426ffdSKuninori Morimoto  *
51e426ffdSKuninori Morimoto  * Copyright (C) 2012 Renesas Solutions Corp.
61e426ffdSKuninori Morimoto  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
71e426ffdSKuninori Morimoto  */
81e426ffdSKuninori Morimoto #include <linux/delay.h>
91e426ffdSKuninori Morimoto #include <linux/err.h>
10e0a5172eSKuninori Morimoto #include <linux/irq.h>
11e0a5172eSKuninori Morimoto #include <linux/interrupt.h>
121e426ffdSKuninori Morimoto #include <linux/io.h>
131e426ffdSKuninori Morimoto #include <linux/module.h>
148b477ea5SKuninori Morimoto #include <linux/of_device.h>
151e426ffdSKuninori Morimoto #include <linux/platform_device.h>
1651d45d25SKuninori Morimoto #include <linux/pm_runtime.h>
17d2a73e22Skuninori.morimoto.gx@renesas.com #include <linux/reboot.h>
181e426ffdSKuninori Morimoto #include <linux/slab.h>
191e426ffdSKuninori Morimoto #include <linux/spinlock.h>
201e426ffdSKuninori Morimoto #include <linux/thermal.h>
211e426ffdSKuninori Morimoto 
2264a411e8SKuninori Morimoto #include "thermal_hwmon.h"
2364a411e8SKuninori Morimoto 
24d2a73e22Skuninori.morimoto.gx@renesas.com #define IDLE_INTERVAL	5000
25d2a73e22Skuninori.morimoto.gx@renesas.com 
26e0a5172eSKuninori Morimoto #define COMMON_STR	0x00
27e0a5172eSKuninori Morimoto #define COMMON_ENR	0x04
28e0a5172eSKuninori Morimoto #define COMMON_INTMSK	0x0c
29e0a5172eSKuninori Morimoto 
30e0a5172eSKuninori Morimoto #define REG_POSNEG	0x20
31e0a5172eSKuninori Morimoto #define REG_FILONOFF	0x28
32e9137a58SKuninori Morimoto #define REG_THSCR	0x2c
33e9137a58SKuninori Morimoto #define REG_THSSR	0x30
34e0a5172eSKuninori Morimoto #define REG_INTCTRL	0x34
351e426ffdSKuninori Morimoto 
361e426ffdSKuninori Morimoto /* THSCR */
37f8f53e18SKuninori Morimoto #define CPCTL	(1 << 12)
381e426ffdSKuninori Morimoto 
391e426ffdSKuninori Morimoto /* THSSR */
401e426ffdSKuninori Morimoto #define CTEMP	0x3f
411e426ffdSKuninori Morimoto 
423676d1ddSKuninori Morimoto struct rcar_thermal_common {
433676d1ddSKuninori Morimoto 	void __iomem *base;
443676d1ddSKuninori Morimoto 	struct device *dev;
453676d1ddSKuninori Morimoto 	struct list_head head;
46e0a5172eSKuninori Morimoto 	spinlock_t lock;
473676d1ddSKuninori Morimoto };
481e426ffdSKuninori Morimoto 
491969d9dcSYoshihiro Kaneko struct rcar_thermal_chip {
501969d9dcSYoshihiro Kaneko 	unsigned int use_of_thermal : 1;
511969d9dcSYoshihiro Kaneko 	unsigned int has_filonoff : 1;
521969d9dcSYoshihiro Kaneko 	unsigned int irq_per_ch : 1;
531969d9dcSYoshihiro Kaneko 	unsigned int needs_suspend_resume : 1;
541969d9dcSYoshihiro Kaneko 	unsigned int nirqs;
551969d9dcSYoshihiro Kaneko };
561969d9dcSYoshihiro Kaneko 
571969d9dcSYoshihiro Kaneko static const struct rcar_thermal_chip rcar_thermal = {
581969d9dcSYoshihiro Kaneko 	.use_of_thermal = 0,
591969d9dcSYoshihiro Kaneko 	.has_filonoff = 1,
601969d9dcSYoshihiro Kaneko 	.irq_per_ch = 0,
611969d9dcSYoshihiro Kaneko 	.needs_suspend_resume = 0,
621969d9dcSYoshihiro Kaneko 	.nirqs = 1,
631969d9dcSYoshihiro Kaneko };
641969d9dcSYoshihiro Kaneko 
651969d9dcSYoshihiro Kaneko static const struct rcar_thermal_chip rcar_gen2_thermal = {
661969d9dcSYoshihiro Kaneko 	.use_of_thermal = 1,
671969d9dcSYoshihiro Kaneko 	.has_filonoff = 1,
681969d9dcSYoshihiro Kaneko 	.irq_per_ch = 0,
691969d9dcSYoshihiro Kaneko 	.needs_suspend_resume = 0,
701969d9dcSYoshihiro Kaneko 	.nirqs = 1,
711969d9dcSYoshihiro Kaneko };
721969d9dcSYoshihiro Kaneko 
731969d9dcSYoshihiro Kaneko static const struct rcar_thermal_chip rcar_gen3_thermal = {
741969d9dcSYoshihiro Kaneko 	.use_of_thermal = 1,
751969d9dcSYoshihiro Kaneko 	.has_filonoff = 0,
761969d9dcSYoshihiro Kaneko 	.irq_per_ch = 1,
771969d9dcSYoshihiro Kaneko 	.needs_suspend_resume = 1,
781969d9dcSYoshihiro Kaneko 	/*
791969d9dcSYoshihiro Kaneko 	 * The Gen3 chip has 3 interrupts, but this driver uses only 2
801969d9dcSYoshihiro Kaneko 	 * interrupts to detect a temperature change, rise or fall.
811969d9dcSYoshihiro Kaneko 	 */
821969d9dcSYoshihiro Kaneko 	.nirqs = 2,
831969d9dcSYoshihiro Kaneko };
841969d9dcSYoshihiro Kaneko 
851e426ffdSKuninori Morimoto struct rcar_thermal_priv {
861e426ffdSKuninori Morimoto 	void __iomem *base;
873676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common;
883676d1ddSKuninori Morimoto 	struct thermal_zone_device *zone;
891969d9dcSYoshihiro Kaneko 	const struct rcar_thermal_chip *chip;
90e0a5172eSKuninori Morimoto 	struct delayed_work work;
91b2bbc6a2SKuninori Morimoto 	struct mutex lock;
923676d1ddSKuninori Morimoto 	struct list_head list;
93e0a5172eSKuninori Morimoto 	int id;
94913015c6SYoshihiro Shimoda 	u32 ctemp;
951e426ffdSKuninori Morimoto };
961e426ffdSKuninori Morimoto 
973676d1ddSKuninori Morimoto #define rcar_thermal_for_each_priv(pos, common)	\
983676d1ddSKuninori Morimoto 	list_for_each_entry(pos, &common->head, list)
993676d1ddSKuninori Morimoto 
100c499703eSKuninori Morimoto #define MCELSIUS(temp)			((temp) * 1000)
1019dde8f86SKuninori Morimoto #define rcar_zone_to_priv(zone)		((zone)->devdata)
1023676d1ddSKuninori Morimoto #define rcar_priv_to_dev(priv)		((priv)->common->dev)
1033676d1ddSKuninori Morimoto #define rcar_has_irq_support(priv)	((priv)->common->base)
104e0a5172eSKuninori Morimoto #define rcar_id_to_shift(priv)		((priv)->id * 8)
105e0a5172eSKuninori Morimoto 
106ca1e4558SKuninori Morimoto static const struct of_device_id rcar_thermal_dt_ids[] = {
1071969d9dcSYoshihiro Kaneko 	{
1081969d9dcSYoshihiro Kaneko 		.compatible = "renesas,rcar-thermal",
1091969d9dcSYoshihiro Kaneko 		.data = &rcar_thermal,
1101969d9dcSYoshihiro Kaneko 	},
1111969d9dcSYoshihiro Kaneko 	{
1121969d9dcSYoshihiro Kaneko 		.compatible = "renesas,rcar-gen2-thermal",
1131969d9dcSYoshihiro Kaneko 		 .data = &rcar_gen2_thermal,
1141969d9dcSYoshihiro Kaneko 	},
1151969d9dcSYoshihiro Kaneko 	{
1161969d9dcSYoshihiro Kaneko 		.compatible = "renesas,thermal-r8a77995",
1171969d9dcSYoshihiro Kaneko 		.data = &rcar_gen3_thermal,
1181969d9dcSYoshihiro Kaneko 	},
119ca1e4558SKuninori Morimoto 	{},
120ca1e4558SKuninori Morimoto };
121ca1e4558SKuninori Morimoto MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
122ca1e4558SKuninori Morimoto 
1231e426ffdSKuninori Morimoto /*
1241e426ffdSKuninori Morimoto  *		basic functions
1251e426ffdSKuninori Morimoto  */
126e9137a58SKuninori Morimoto #define rcar_thermal_common_read(c, r) \
127e9137a58SKuninori Morimoto 	_rcar_thermal_common_read(c, COMMON_ ##r)
128e9137a58SKuninori Morimoto static u32 _rcar_thermal_common_read(struct rcar_thermal_common *common,
129e9137a58SKuninori Morimoto 				     u32 reg)
130e9137a58SKuninori Morimoto {
131e9137a58SKuninori Morimoto 	return ioread32(common->base + reg);
132e9137a58SKuninori Morimoto }
133e9137a58SKuninori Morimoto 
134e9137a58SKuninori Morimoto #define rcar_thermal_common_write(c, r, d) \
135e9137a58SKuninori Morimoto 	_rcar_thermal_common_write(c, COMMON_ ##r, d)
136e9137a58SKuninori Morimoto static void _rcar_thermal_common_write(struct rcar_thermal_common *common,
137e9137a58SKuninori Morimoto 				       u32 reg, u32 data)
138e9137a58SKuninori Morimoto {
139e9137a58SKuninori Morimoto 	iowrite32(data, common->base + reg);
140e9137a58SKuninori Morimoto }
141e9137a58SKuninori Morimoto 
142e9137a58SKuninori Morimoto #define rcar_thermal_common_bset(c, r, m, d) \
143e9137a58SKuninori Morimoto 	_rcar_thermal_common_bset(c, COMMON_ ##r, m, d)
144e9137a58SKuninori Morimoto static void _rcar_thermal_common_bset(struct rcar_thermal_common *common,
145e9137a58SKuninori Morimoto 				      u32 reg, u32 mask, u32 data)
146e9137a58SKuninori Morimoto {
147e9137a58SKuninori Morimoto 	u32 val;
148e9137a58SKuninori Morimoto 
149e9137a58SKuninori Morimoto 	val = ioread32(common->base + reg);
150e9137a58SKuninori Morimoto 	val &= ~mask;
151e9137a58SKuninori Morimoto 	val |= (data & mask);
152e9137a58SKuninori Morimoto 	iowrite32(val, common->base + reg);
153e9137a58SKuninori Morimoto }
154e9137a58SKuninori Morimoto 
155e9137a58SKuninori Morimoto #define rcar_thermal_read(p, r) _rcar_thermal_read(p, REG_ ##r)
156e9137a58SKuninori Morimoto static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
1571e426ffdSKuninori Morimoto {
158b2bbc6a2SKuninori Morimoto 	return ioread32(priv->base + reg);
1591e426ffdSKuninori Morimoto }
1601e426ffdSKuninori Morimoto 
161e9137a58SKuninori Morimoto #define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, REG_ ##r, d)
162e9137a58SKuninori Morimoto static void _rcar_thermal_write(struct rcar_thermal_priv *priv,
1631e426ffdSKuninori Morimoto 				u32 reg, u32 data)
1641e426ffdSKuninori Morimoto {
1651e426ffdSKuninori Morimoto 	iowrite32(data, priv->base + reg);
1661e426ffdSKuninori Morimoto }
1671e426ffdSKuninori Morimoto 
168e9137a58SKuninori Morimoto #define rcar_thermal_bset(p, r, m, d) _rcar_thermal_bset(p, REG_ ##r, m, d)
169e9137a58SKuninori Morimoto static void _rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
1701e426ffdSKuninori Morimoto 			       u32 mask, u32 data)
1711e426ffdSKuninori Morimoto {
1721e426ffdSKuninori Morimoto 	u32 val;
1731e426ffdSKuninori Morimoto 
1741e426ffdSKuninori Morimoto 	val = ioread32(priv->base + reg);
1751e426ffdSKuninori Morimoto 	val &= ~mask;
1761e426ffdSKuninori Morimoto 	val |= (data & mask);
1771e426ffdSKuninori Morimoto 	iowrite32(val, priv->base + reg);
1781e426ffdSKuninori Morimoto }
1791e426ffdSKuninori Morimoto 
1801e426ffdSKuninori Morimoto /*
1811e426ffdSKuninori Morimoto  *		zone device functions
1821e426ffdSKuninori Morimoto  */
183e0a5172eSKuninori Morimoto static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
1841e426ffdSKuninori Morimoto {
185f8f53e18SKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
186f8f53e18SKuninori Morimoto 	int i;
187913015c6SYoshihiro Shimoda 	u32 ctemp, old, new;
188f0e68fc3SWei Yongjun 	int ret = -EINVAL;
1891e426ffdSKuninori Morimoto 
190b2bbc6a2SKuninori Morimoto 	mutex_lock(&priv->lock);
191b2bbc6a2SKuninori Morimoto 
1921e426ffdSKuninori Morimoto 	/*
193f8f53e18SKuninori Morimoto 	 * TSC decides a value of CPTAP automatically,
194f8f53e18SKuninori Morimoto 	 * and this is the conditions which validate interrupt.
1951e426ffdSKuninori Morimoto 	 */
196f8f53e18SKuninori Morimoto 	rcar_thermal_bset(priv, THSCR, CPCTL, CPCTL);
1971e426ffdSKuninori Morimoto 
198f8f53e18SKuninori Morimoto 	ctemp = 0;
199f8f53e18SKuninori Morimoto 	old = ~0;
200f8f53e18SKuninori Morimoto 	for (i = 0; i < 128; i++) {
2011e426ffdSKuninori Morimoto 		/*
2021e426ffdSKuninori Morimoto 		 * we need to wait 300us after changing comparator offset
2031e426ffdSKuninori Morimoto 		 * to get stable temperature.
2041e426ffdSKuninori Morimoto 		 * see "Usage Notes" on datasheet
2051e426ffdSKuninori Morimoto 		 */
2061e426ffdSKuninori Morimoto 		udelay(300);
2071e426ffdSKuninori Morimoto 
208f8f53e18SKuninori Morimoto 		new = rcar_thermal_read(priv, THSSR) & CTEMP;
209f8f53e18SKuninori Morimoto 		if (new == old) {
210f8f53e18SKuninori Morimoto 			ctemp = new;
2111e426ffdSKuninori Morimoto 			break;
2121e426ffdSKuninori Morimoto 		}
213f8f53e18SKuninori Morimoto 		old = new;
2141e426ffdSKuninori Morimoto 	}
2151e426ffdSKuninori Morimoto 
216f8f53e18SKuninori Morimoto 	if (!ctemp) {
217f8f53e18SKuninori Morimoto 		dev_err(dev, "thermal sensor was broken\n");
218f0e68fc3SWei Yongjun 		goto err_out_unlock;
219f8f53e18SKuninori Morimoto 	}
220f8f53e18SKuninori Morimoto 
221e0a5172eSKuninori Morimoto 	/*
222e0a5172eSKuninori Morimoto 	 * enable IRQ
223e0a5172eSKuninori Morimoto 	 */
224e0a5172eSKuninori Morimoto 	if (rcar_has_irq_support(priv)) {
2251969d9dcSYoshihiro Kaneko 		if (priv->chip->has_filonoff)
226e0a5172eSKuninori Morimoto 			rcar_thermal_write(priv, FILONOFF, 0);
227f8f53e18SKuninori Morimoto 
228e0a5172eSKuninori Morimoto 		/* enable Rising/Falling edge interrupt */
229e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, POSNEG,  0x1);
230e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, INTCTRL, (((ctemp - 0) << 8) |
231e0a5172eSKuninori Morimoto 						   ((ctemp - 1) << 0)));
232e0a5172eSKuninori Morimoto 	}
233e0a5172eSKuninori Morimoto 
234e0a5172eSKuninori Morimoto 	dev_dbg(dev, "thermal%d  %d -> %d\n", priv->id, priv->ctemp, ctemp);
235e0a5172eSKuninori Morimoto 
236e0a5172eSKuninori Morimoto 	priv->ctemp = ctemp;
237f0e68fc3SWei Yongjun 	ret = 0;
238f0e68fc3SWei Yongjun err_out_unlock:
239e0a5172eSKuninori Morimoto 	mutex_unlock(&priv->lock);
240f0e68fc3SWei Yongjun 	return ret;
241e0a5172eSKuninori Morimoto }
242e0a5172eSKuninori Morimoto 
2438b477ea5SKuninori Morimoto static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv,
2448b477ea5SKuninori Morimoto 					 int *temp)
245e0a5172eSKuninori Morimoto {
2465440c40bSKuninori Morimoto 	int tmp;
247a1ade565SKuninori Morimoto 	int ret;
248e0a5172eSKuninori Morimoto 
249a1ade565SKuninori Morimoto 	ret = rcar_thermal_update_temp(priv);
250a1ade565SKuninori Morimoto 	if (ret < 0)
251a1ade565SKuninori Morimoto 		return ret;
252e0a5172eSKuninori Morimoto 
253e0a5172eSKuninori Morimoto 	mutex_lock(&priv->lock);
2545440c40bSKuninori Morimoto 	tmp =  MCELSIUS((priv->ctemp * 5) - 65);
255b2bbc6a2SKuninori Morimoto 	mutex_unlock(&priv->lock);
256b2bbc6a2SKuninori Morimoto 
2575440c40bSKuninori Morimoto 	if ((tmp < MCELSIUS(-45)) || (tmp > MCELSIUS(125))) {
2585440c40bSKuninori Morimoto 		struct device *dev = rcar_priv_to_dev(priv);
2595440c40bSKuninori Morimoto 
2605440c40bSKuninori Morimoto 		dev_err(dev, "it couldn't measure temperature correctly\n");
2615440c40bSKuninori Morimoto 		return -EIO;
2625440c40bSKuninori Morimoto 	}
2635440c40bSKuninori Morimoto 
2645440c40bSKuninori Morimoto 	*temp = tmp;
2655440c40bSKuninori Morimoto 
2661e426ffdSKuninori Morimoto 	return 0;
2671e426ffdSKuninori Morimoto }
2681e426ffdSKuninori Morimoto 
2698b477ea5SKuninori Morimoto static int rcar_thermal_of_get_temp(void *data, int *temp)
2708b477ea5SKuninori Morimoto {
2718b477ea5SKuninori Morimoto 	struct rcar_thermal_priv *priv = data;
2728b477ea5SKuninori Morimoto 
2738b477ea5SKuninori Morimoto 	return rcar_thermal_get_current_temp(priv, temp);
2748b477ea5SKuninori Morimoto }
2758b477ea5SKuninori Morimoto 
2768b477ea5SKuninori Morimoto static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp)
2778b477ea5SKuninori Morimoto {
2788b477ea5SKuninori Morimoto 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
2798b477ea5SKuninori Morimoto 
2808b477ea5SKuninori Morimoto 	return rcar_thermal_get_current_temp(priv, temp);
2818b477ea5SKuninori Morimoto }
2828b477ea5SKuninori Morimoto 
283d2a73e22Skuninori.morimoto.gx@renesas.com static int rcar_thermal_get_trip_type(struct thermal_zone_device *zone,
284d2a73e22Skuninori.morimoto.gx@renesas.com 				      int trip, enum thermal_trip_type *type)
285d2a73e22Skuninori.morimoto.gx@renesas.com {
286d2a73e22Skuninori.morimoto.gx@renesas.com 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
2873676d1ddSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
288d2a73e22Skuninori.morimoto.gx@renesas.com 
289d2a73e22Skuninori.morimoto.gx@renesas.com 	/* see rcar_thermal_get_temp() */
290d2a73e22Skuninori.morimoto.gx@renesas.com 	switch (trip) {
291d2a73e22Skuninori.morimoto.gx@renesas.com 	case 0: /* +90 <= temp */
292d2a73e22Skuninori.morimoto.gx@renesas.com 		*type = THERMAL_TRIP_CRITICAL;
293d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
294d2a73e22Skuninori.morimoto.gx@renesas.com 	default:
2953676d1ddSKuninori Morimoto 		dev_err(dev, "rcar driver trip error\n");
296d2a73e22Skuninori.morimoto.gx@renesas.com 		return -EINVAL;
297d2a73e22Skuninori.morimoto.gx@renesas.com 	}
298d2a73e22Skuninori.morimoto.gx@renesas.com 
299d2a73e22Skuninori.morimoto.gx@renesas.com 	return 0;
300d2a73e22Skuninori.morimoto.gx@renesas.com }
301d2a73e22Skuninori.morimoto.gx@renesas.com 
302d2a73e22Skuninori.morimoto.gx@renesas.com static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone,
30317e8351aSSascha Hauer 				      int trip, int *temp)
304d2a73e22Skuninori.morimoto.gx@renesas.com {
305d2a73e22Skuninori.morimoto.gx@renesas.com 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
3063676d1ddSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
307d2a73e22Skuninori.morimoto.gx@renesas.com 
308d2a73e22Skuninori.morimoto.gx@renesas.com 	/* see rcar_thermal_get_temp() */
309d2a73e22Skuninori.morimoto.gx@renesas.com 	switch (trip) {
310d2a73e22Skuninori.morimoto.gx@renesas.com 	case 0: /* +90 <= temp */
311d2a73e22Skuninori.morimoto.gx@renesas.com 		*temp = MCELSIUS(90);
312d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
313d2a73e22Skuninori.morimoto.gx@renesas.com 	default:
3143676d1ddSKuninori Morimoto 		dev_err(dev, "rcar driver trip error\n");
315d2a73e22Skuninori.morimoto.gx@renesas.com 		return -EINVAL;
316d2a73e22Skuninori.morimoto.gx@renesas.com 	}
317d2a73e22Skuninori.morimoto.gx@renesas.com 
318d2a73e22Skuninori.morimoto.gx@renesas.com 	return 0;
319d2a73e22Skuninori.morimoto.gx@renesas.com }
320d2a73e22Skuninori.morimoto.gx@renesas.com 
321d2a73e22Skuninori.morimoto.gx@renesas.com static int rcar_thermal_notify(struct thermal_zone_device *zone,
322d2a73e22Skuninori.morimoto.gx@renesas.com 			       int trip, enum thermal_trip_type type)
323d2a73e22Skuninori.morimoto.gx@renesas.com {
324d2a73e22Skuninori.morimoto.gx@renesas.com 	struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
3253676d1ddSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
326d2a73e22Skuninori.morimoto.gx@renesas.com 
327d2a73e22Skuninori.morimoto.gx@renesas.com 	switch (type) {
328d2a73e22Skuninori.morimoto.gx@renesas.com 	case THERMAL_TRIP_CRITICAL:
329d2a73e22Skuninori.morimoto.gx@renesas.com 		/* FIXME */
3303676d1ddSKuninori Morimoto 		dev_warn(dev, "Thermal reached to critical temperature\n");
331d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
332d2a73e22Skuninori.morimoto.gx@renesas.com 	default:
333d2a73e22Skuninori.morimoto.gx@renesas.com 		break;
334d2a73e22Skuninori.morimoto.gx@renesas.com 	}
335d2a73e22Skuninori.morimoto.gx@renesas.com 
336d2a73e22Skuninori.morimoto.gx@renesas.com 	return 0;
337d2a73e22Skuninori.morimoto.gx@renesas.com }
338d2a73e22Skuninori.morimoto.gx@renesas.com 
3398b477ea5SKuninori Morimoto static const struct thermal_zone_of_device_ops rcar_thermal_zone_of_ops = {
3408b477ea5SKuninori Morimoto 	.get_temp	= rcar_thermal_of_get_temp,
3418b477ea5SKuninori Morimoto };
3428b477ea5SKuninori Morimoto 
3431e426ffdSKuninori Morimoto static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
3441e426ffdSKuninori Morimoto 	.get_temp	= rcar_thermal_get_temp,
345d2a73e22Skuninori.morimoto.gx@renesas.com 	.get_trip_type	= rcar_thermal_get_trip_type,
346d2a73e22Skuninori.morimoto.gx@renesas.com 	.get_trip_temp	= rcar_thermal_get_trip_temp,
347d2a73e22Skuninori.morimoto.gx@renesas.com 	.notify		= rcar_thermal_notify,
3481e426ffdSKuninori Morimoto };
3491e426ffdSKuninori Morimoto 
3501e426ffdSKuninori Morimoto /*
351e0a5172eSKuninori Morimoto  *		interrupt
352e0a5172eSKuninori Morimoto  */
353e0a5172eSKuninori Morimoto #define rcar_thermal_irq_enable(p)	_rcar_thermal_irq_ctrl(p, 1)
354e0a5172eSKuninori Morimoto #define rcar_thermal_irq_disable(p)	_rcar_thermal_irq_ctrl(p, 0)
355e0a5172eSKuninori Morimoto static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
356e0a5172eSKuninori Morimoto {
357e0a5172eSKuninori Morimoto 	struct rcar_thermal_common *common = priv->common;
358e0a5172eSKuninori Morimoto 	unsigned long flags;
359e0a5172eSKuninori Morimoto 	u32 mask = 0x3 << rcar_id_to_shift(priv); /* enable Rising/Falling */
360e0a5172eSKuninori Morimoto 
361ffbcdf8aSKuninori Morimoto 	if (!rcar_has_irq_support(priv))
362ffbcdf8aSKuninori Morimoto 		return;
363ffbcdf8aSKuninori Morimoto 
364e0a5172eSKuninori Morimoto 	spin_lock_irqsave(&common->lock, flags);
365e0a5172eSKuninori Morimoto 
366e0a5172eSKuninori Morimoto 	rcar_thermal_common_bset(common, INTMSK, mask, enable ? 0 : mask);
367e0a5172eSKuninori Morimoto 
368e0a5172eSKuninori Morimoto 	spin_unlock_irqrestore(&common->lock, flags);
369e0a5172eSKuninori Morimoto }
370e0a5172eSKuninori Morimoto 
371e0a5172eSKuninori Morimoto static void rcar_thermal_work(struct work_struct *work)
372e0a5172eSKuninori Morimoto {
373e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv;
37417e8351aSSascha Hauer 	int cctemp, nctemp;
375a1ade565SKuninori Morimoto 	int ret;
376e0a5172eSKuninori Morimoto 
377e0a5172eSKuninori Morimoto 	priv = container_of(work, struct rcar_thermal_priv, work.work);
378e0a5172eSKuninori Morimoto 
3798b477ea5SKuninori Morimoto 	ret = rcar_thermal_get_current_temp(priv, &cctemp);
3808b477ea5SKuninori Morimoto 	if (ret < 0)
3818b477ea5SKuninori Morimoto 		return;
3828b477ea5SKuninori Morimoto 
383a1ade565SKuninori Morimoto 	ret = rcar_thermal_update_temp(priv);
384a1ade565SKuninori Morimoto 	if (ret < 0)
385a1ade565SKuninori Morimoto 		return;
386a1ade565SKuninori Morimoto 
387e0a5172eSKuninori Morimoto 	rcar_thermal_irq_enable(priv);
3889477165eSPatrick Titiano 
3898b477ea5SKuninori Morimoto 	ret = rcar_thermal_get_current_temp(priv, &nctemp);
3908b477ea5SKuninori Morimoto 	if (ret < 0)
3918b477ea5SKuninori Morimoto 		return;
3928b477ea5SKuninori Morimoto 
3939477165eSPatrick Titiano 	if (nctemp != cctemp)
3940e70f466SSrinivas Pandruvada 		thermal_zone_device_update(priv->zone,
3950e70f466SSrinivas Pandruvada 					   THERMAL_EVENT_UNSPECIFIED);
396e0a5172eSKuninori Morimoto }
397e0a5172eSKuninori Morimoto 
398e0a5172eSKuninori Morimoto static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
399e0a5172eSKuninori Morimoto {
400e0a5172eSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
401e0a5172eSKuninori Morimoto 
402e0a5172eSKuninori Morimoto 	status = (status >> rcar_id_to_shift(priv)) & 0x3;
403e0a5172eSKuninori Morimoto 
404206c0cbaSPatrick Titiano 	if (status) {
405e0a5172eSKuninori Morimoto 		dev_dbg(dev, "thermal%d %s%s\n",
406e0a5172eSKuninori Morimoto 			priv->id,
407e0a5172eSKuninori Morimoto 			(status & 0x2) ? "Rising " : "",
408e0a5172eSKuninori Morimoto 			(status & 0x1) ? "Falling" : "");
409e0a5172eSKuninori Morimoto 	}
410e0a5172eSKuninori Morimoto 
411e0a5172eSKuninori Morimoto 	return status;
412e0a5172eSKuninori Morimoto }
413e0a5172eSKuninori Morimoto 
414e0a5172eSKuninori Morimoto static irqreturn_t rcar_thermal_irq(int irq, void *data)
415e0a5172eSKuninori Morimoto {
416e0a5172eSKuninori Morimoto 	struct rcar_thermal_common *common = data;
417e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv;
418e0a5172eSKuninori Morimoto 	unsigned long flags;
419e0a5172eSKuninori Morimoto 	u32 status, mask;
420e0a5172eSKuninori Morimoto 
421e0a5172eSKuninori Morimoto 	spin_lock_irqsave(&common->lock, flags);
422e0a5172eSKuninori Morimoto 
423e0a5172eSKuninori Morimoto 	mask	= rcar_thermal_common_read(common, INTMSK);
424e0a5172eSKuninori Morimoto 	status	= rcar_thermal_common_read(common, STR);
425e0a5172eSKuninori Morimoto 	rcar_thermal_common_write(common, STR, 0x000F0F0F & mask);
426e0a5172eSKuninori Morimoto 
427e0a5172eSKuninori Morimoto 	spin_unlock_irqrestore(&common->lock, flags);
428e0a5172eSKuninori Morimoto 
429e0a5172eSKuninori Morimoto 	status = status & ~mask;
430e0a5172eSKuninori Morimoto 
431e0a5172eSKuninori Morimoto 	/*
432e0a5172eSKuninori Morimoto 	 * check the status
433e0a5172eSKuninori Morimoto 	 */
434e0a5172eSKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
435e0a5172eSKuninori Morimoto 		if (rcar_thermal_had_changed(priv, status)) {
436e0a5172eSKuninori Morimoto 			rcar_thermal_irq_disable(priv);
437e0a5172eSKuninori Morimoto 			schedule_delayed_work(&priv->work,
438e0a5172eSKuninori Morimoto 					      msecs_to_jiffies(300));
439e0a5172eSKuninori Morimoto 		}
440e0a5172eSKuninori Morimoto 	}
441e0a5172eSKuninori Morimoto 
442e0a5172eSKuninori Morimoto 	return IRQ_HANDLED;
443e0a5172eSKuninori Morimoto }
444e0a5172eSKuninori Morimoto 
445e0a5172eSKuninori Morimoto /*
4461e426ffdSKuninori Morimoto  *		platform functions
4471e426ffdSKuninori Morimoto  */
44884f0e490SKuninori Morimoto static int rcar_thermal_remove(struct platform_device *pdev)
44984f0e490SKuninori Morimoto {
45084f0e490SKuninori Morimoto 	struct rcar_thermal_common *common = platform_get_drvdata(pdev);
45184f0e490SKuninori Morimoto 	struct device *dev = &pdev->dev;
45284f0e490SKuninori Morimoto 	struct rcar_thermal_priv *priv;
45384f0e490SKuninori Morimoto 
45484f0e490SKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
45584f0e490SKuninori Morimoto 		rcar_thermal_irq_disable(priv);
4561969d9dcSYoshihiro Kaneko 		if (priv->chip->use_of_thermal)
45764a411e8SKuninori Morimoto 			thermal_remove_hwmon_sysfs(priv->zone);
458d4b23c5cSBui Duc Phuc 		else
45984f0e490SKuninori Morimoto 			thermal_zone_device_unregister(priv->zone);
46084f0e490SKuninori Morimoto 	}
46184f0e490SKuninori Morimoto 
46284f0e490SKuninori Morimoto 	pm_runtime_put(dev);
46384f0e490SKuninori Morimoto 	pm_runtime_disable(dev);
46484f0e490SKuninori Morimoto 
46584f0e490SKuninori Morimoto 	return 0;
46684f0e490SKuninori Morimoto }
46784f0e490SKuninori Morimoto 
4681e426ffdSKuninori Morimoto static int rcar_thermal_probe(struct platform_device *pdev)
4691e426ffdSKuninori Morimoto {
4703676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common;
4711e426ffdSKuninori Morimoto 	struct rcar_thermal_priv *priv;
4723676d1ddSKuninori Morimoto 	struct device *dev = &pdev->dev;
4733676d1ddSKuninori Morimoto 	struct resource *res, *irq;
4741969d9dcSYoshihiro Kaneko 	const struct rcar_thermal_chip *chip = of_device_get_match_data(dev);
4753676d1ddSKuninori Morimoto 	int mres = 0;
4763676d1ddSKuninori Morimoto 	int i;
477fb84d990SDevendra Naga 	int ret = -ENODEV;
478e0a5172eSKuninori Morimoto 	int idle = IDLE_INTERVAL;
47911313746SYoshihiro Shimoda 	u32 enr_bits = 0;
4801e426ffdSKuninori Morimoto 
4813676d1ddSKuninori Morimoto 	common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
482b0a60d88SJingoo Han 	if (!common)
4833676d1ddSKuninori Morimoto 		return -ENOMEM;
4843676d1ddSKuninori Morimoto 
48584f0e490SKuninori Morimoto 	platform_set_drvdata(pdev, common);
48684f0e490SKuninori Morimoto 
4873676d1ddSKuninori Morimoto 	INIT_LIST_HEAD(&common->head);
488e0a5172eSKuninori Morimoto 	spin_lock_init(&common->lock);
4893676d1ddSKuninori Morimoto 	common->dev = dev;
4903676d1ddSKuninori Morimoto 
49151d45d25SKuninori Morimoto 	pm_runtime_enable(dev);
49251d45d25SKuninori Morimoto 	pm_runtime_get_sync(dev);
49351d45d25SKuninori Morimoto 
4941969d9dcSYoshihiro Kaneko 	for (i = 0; i < chip->nirqs; i++) {
4953676d1ddSKuninori Morimoto 		irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
4961969d9dcSYoshihiro Kaneko 		if (!irq)
4971969d9dcSYoshihiro Kaneko 			continue;
4981969d9dcSYoshihiro Kaneko 		if (!common->base) {
4993676d1ddSKuninori Morimoto 			/*
5003676d1ddSKuninori Morimoto 			 * platform has IRQ support.
501ee853addSGeert Uytterhoeven 			 * Then, driver uses common registers
5023676d1ddSKuninori Morimoto 			 * rcar_has_irq_support() will be enabled
5033676d1ddSKuninori Morimoto 			 */
5041969d9dcSYoshihiro Kaneko 			res = platform_get_resource(pdev, IORESOURCE_MEM,
5051969d9dcSYoshihiro Kaneko 						    mres++);
5065095526fSSachin Kamat 			common->base = devm_ioremap_resource(dev, res);
5075095526fSSachin Kamat 			if (IS_ERR(common->base))
5085095526fSSachin Kamat 				return PTR_ERR(common->base);
509e0a5172eSKuninori Morimoto 
5106fe495e0SGeert Uytterhoeven 			idle = 0; /* polling delay is not needed */
5113676d1ddSKuninori Morimoto 		}
5123676d1ddSKuninori Morimoto 
5131969d9dcSYoshihiro Kaneko 		ret = devm_request_irq(dev, irq->start, rcar_thermal_irq,
5141969d9dcSYoshihiro Kaneko 				       IRQF_SHARED, dev_name(dev), common);
5151969d9dcSYoshihiro Kaneko 		if (ret) {
5161969d9dcSYoshihiro Kaneko 			dev_err(dev, "irq request failed\n ");
5171969d9dcSYoshihiro Kaneko 			goto error_unregister;
5181969d9dcSYoshihiro Kaneko 		}
5191969d9dcSYoshihiro Kaneko 
5201969d9dcSYoshihiro Kaneko 		/* update ENR bits */
5211969d9dcSYoshihiro Kaneko 		if (chip->irq_per_ch)
5221969d9dcSYoshihiro Kaneko 			enr_bits |= 1 << i;
5231969d9dcSYoshihiro Kaneko 	}
5241969d9dcSYoshihiro Kaneko 
5253676d1ddSKuninori Morimoto 	for (i = 0;; i++) {
5263676d1ddSKuninori Morimoto 		res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
5273676d1ddSKuninori Morimoto 		if (!res)
5283676d1ddSKuninori Morimoto 			break;
5293676d1ddSKuninori Morimoto 
5303676d1ddSKuninori Morimoto 		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5311e426ffdSKuninori Morimoto 		if (!priv) {
5321dc20828SKuninori Morimoto 			ret = -ENOMEM;
5331dc20828SKuninori Morimoto 			goto error_unregister;
5341e426ffdSKuninori Morimoto 		}
5351e426ffdSKuninori Morimoto 
5365095526fSSachin Kamat 		priv->base = devm_ioremap_resource(dev, res);
5371dc20828SKuninori Morimoto 		if (IS_ERR(priv->base)) {
5381dc20828SKuninori Morimoto 			ret = PTR_ERR(priv->base);
5391dc20828SKuninori Morimoto 			goto error_unregister;
5401dc20828SKuninori Morimoto 		}
5411e426ffdSKuninori Morimoto 
5423676d1ddSKuninori Morimoto 		priv->common = common;
543e0a5172eSKuninori Morimoto 		priv->id = i;
5441969d9dcSYoshihiro Kaneko 		priv->chip = chip;
5453676d1ddSKuninori Morimoto 		mutex_init(&priv->lock);
5463676d1ddSKuninori Morimoto 		INIT_LIST_HEAD(&priv->list);
547e0a5172eSKuninori Morimoto 		INIT_DELAYED_WORK(&priv->work, rcar_thermal_work);
548a1ade565SKuninori Morimoto 		ret = rcar_thermal_update_temp(priv);
549a1ade565SKuninori Morimoto 		if (ret < 0)
550a1ade565SKuninori Morimoto 			goto error_unregister;
5513676d1ddSKuninori Morimoto 
5521969d9dcSYoshihiro Kaneko 		if (chip->use_of_thermal)
5535e325868SEduardo Valentin 			priv->zone = devm_thermal_zone_of_sensor_register(
5548b477ea5SKuninori Morimoto 						dev, i, priv,
5558b477ea5SKuninori Morimoto 						&rcar_thermal_zone_of_ops);
5568b477ea5SKuninori Morimoto 		else
5578b477ea5SKuninori Morimoto 			priv->zone = thermal_zone_device_register(
5588b477ea5SKuninori Morimoto 						"rcar_thermal",
5593676d1ddSKuninori Morimoto 						1, 0, priv,
560d2a73e22Skuninori.morimoto.gx@renesas.com 						&rcar_thermal_zone_ops, NULL, 0,
561e0a5172eSKuninori Morimoto 						idle);
5623676d1ddSKuninori Morimoto 		if (IS_ERR(priv->zone)) {
5633676d1ddSKuninori Morimoto 			dev_err(dev, "can't register thermal zone\n");
564fb84d990SDevendra Naga 			ret = PTR_ERR(priv->zone);
56587260d3fSDirk Behme 			priv->zone = NULL;
5663676d1ddSKuninori Morimoto 			goto error_unregister;
5671e426ffdSKuninori Morimoto 		}
5681e426ffdSKuninori Morimoto 
5691969d9dcSYoshihiro Kaneko 		if (chip->use_of_thermal) {
57064a411e8SKuninori Morimoto 			/*
57164a411e8SKuninori Morimoto 			 * thermal_zone doesn't enable hwmon as default,
57264a411e8SKuninori Morimoto 			 * but, enable it here to keep compatible
57364a411e8SKuninori Morimoto 			 */
57464a411e8SKuninori Morimoto 			priv->zone->tzp->no_hwmon = false;
57564a411e8SKuninori Morimoto 			ret = thermal_add_hwmon_sysfs(priv->zone);
57664a411e8SKuninori Morimoto 			if (ret)
57764a411e8SKuninori Morimoto 				goto error_unregister;
57864a411e8SKuninori Morimoto 		}
57964a411e8SKuninori Morimoto 
580e0a5172eSKuninori Morimoto 		rcar_thermal_irq_enable(priv);
5811dc20828SKuninori Morimoto 
5821dc20828SKuninori Morimoto 		list_move_tail(&priv->list, &common->head);
58311313746SYoshihiro Shimoda 
58411313746SYoshihiro Shimoda 		/* update ENR bits */
5851969d9dcSYoshihiro Kaneko 		if (!chip->irq_per_ch)
58611313746SYoshihiro Shimoda 			enr_bits |= 3 << (i * 8);
5873676d1ddSKuninori Morimoto 	}
5881e426ffdSKuninori Morimoto 
589542cdf40SSimon Horman 	if (common->base && enr_bits)
59011313746SYoshihiro Shimoda 		rcar_thermal_common_write(common, ENR, enr_bits);
59111313746SYoshihiro Shimoda 
5923db46c93SLaurent Pinchart 	dev_info(dev, "%d sensor probed\n", i);
5931e426ffdSKuninori Morimoto 
5941e426ffdSKuninori Morimoto 	return 0;
5953676d1ddSKuninori Morimoto 
5963676d1ddSKuninori Morimoto error_unregister:
59784f0e490SKuninori Morimoto 	rcar_thermal_remove(pdev);
59851d45d25SKuninori Morimoto 
599fb84d990SDevendra Naga 	return ret;
6001e426ffdSKuninori Morimoto }
6011e426ffdSKuninori Morimoto 
6021969d9dcSYoshihiro Kaneko #ifdef CONFIG_PM_SLEEP
6031969d9dcSYoshihiro Kaneko static int rcar_thermal_suspend(struct device *dev)
6041969d9dcSYoshihiro Kaneko {
6051969d9dcSYoshihiro Kaneko 	struct rcar_thermal_common *common = dev_get_drvdata(dev);
6061969d9dcSYoshihiro Kaneko 	struct rcar_thermal_priv *priv = list_first_entry(&common->head,
6071969d9dcSYoshihiro Kaneko 							  typeof(*priv), list);
6081969d9dcSYoshihiro Kaneko 
6091969d9dcSYoshihiro Kaneko 	if (priv->chip->needs_suspend_resume) {
6101969d9dcSYoshihiro Kaneko 		rcar_thermal_common_write(common, ENR, 0);
6111969d9dcSYoshihiro Kaneko 		rcar_thermal_irq_disable(priv);
6121969d9dcSYoshihiro Kaneko 		rcar_thermal_bset(priv, THSCR, CPCTL, 0);
6131969d9dcSYoshihiro Kaneko 	}
6141969d9dcSYoshihiro Kaneko 
6151969d9dcSYoshihiro Kaneko 	return 0;
6161969d9dcSYoshihiro Kaneko }
6171969d9dcSYoshihiro Kaneko 
6181969d9dcSYoshihiro Kaneko static int rcar_thermal_resume(struct device *dev)
6191969d9dcSYoshihiro Kaneko {
6201969d9dcSYoshihiro Kaneko 	struct rcar_thermal_common *common = dev_get_drvdata(dev);
6211969d9dcSYoshihiro Kaneko 	struct rcar_thermal_priv *priv = list_first_entry(&common->head,
6221969d9dcSYoshihiro Kaneko 							  typeof(*priv), list);
6231969d9dcSYoshihiro Kaneko 	int ret;
6241969d9dcSYoshihiro Kaneko 
6251969d9dcSYoshihiro Kaneko 	if (priv->chip->needs_suspend_resume) {
6261969d9dcSYoshihiro Kaneko 		ret = rcar_thermal_update_temp(priv);
6271969d9dcSYoshihiro Kaneko 		if (ret < 0)
6281969d9dcSYoshihiro Kaneko 			return ret;
6291969d9dcSYoshihiro Kaneko 		rcar_thermal_irq_enable(priv);
6301969d9dcSYoshihiro Kaneko 		rcar_thermal_common_write(common, ENR, 0x03);
6311969d9dcSYoshihiro Kaneko 	}
6321969d9dcSYoshihiro Kaneko 
6331969d9dcSYoshihiro Kaneko 	return 0;
6341969d9dcSYoshihiro Kaneko }
6351969d9dcSYoshihiro Kaneko #endif
6361969d9dcSYoshihiro Kaneko 
6371969d9dcSYoshihiro Kaneko static SIMPLE_DEV_PM_OPS(rcar_thermal_pm_ops, rcar_thermal_suspend,
6381969d9dcSYoshihiro Kaneko 			 rcar_thermal_resume);
6391969d9dcSYoshihiro Kaneko 
6401e426ffdSKuninori Morimoto static struct platform_driver rcar_thermal_driver = {
6411e426ffdSKuninori Morimoto 	.driver	= {
6421e426ffdSKuninori Morimoto 		.name	= "rcar_thermal",
6431969d9dcSYoshihiro Kaneko 		.pm = &rcar_thermal_pm_ops,
64476cc1887SKuninori Morimoto 		.of_match_table = rcar_thermal_dt_ids,
6451e426ffdSKuninori Morimoto 	},
6461e426ffdSKuninori Morimoto 	.probe		= rcar_thermal_probe,
6471e426ffdSKuninori Morimoto 	.remove		= rcar_thermal_remove,
6481e426ffdSKuninori Morimoto };
6491e426ffdSKuninori Morimoto module_platform_driver(rcar_thermal_driver);
6501e426ffdSKuninori Morimoto 
651c9545790SKuninori Morimoto MODULE_LICENSE("GPL v2");
6521e426ffdSKuninori Morimoto MODULE_DESCRIPTION("R-Car THS/TSC thermal sensor driver");
6531e426ffdSKuninori Morimoto MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
654