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>
14*f6a756e8SRob Herring #include <linux/of.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;
5520386f0dSYoshihiro Kaneko 	unsigned int ctemp_bands;
561969d9dcSYoshihiro Kaneko };
571969d9dcSYoshihiro Kaneko 
581969d9dcSYoshihiro Kaneko static const struct rcar_thermal_chip rcar_thermal = {
591969d9dcSYoshihiro Kaneko 	.use_of_thermal = 0,
601969d9dcSYoshihiro Kaneko 	.has_filonoff = 1,
611969d9dcSYoshihiro Kaneko 	.irq_per_ch = 0,
621969d9dcSYoshihiro Kaneko 	.needs_suspend_resume = 0,
631969d9dcSYoshihiro Kaneko 	.nirqs = 1,
6420386f0dSYoshihiro Kaneko 	.ctemp_bands = 1,
651969d9dcSYoshihiro Kaneko };
661969d9dcSYoshihiro Kaneko 
671969d9dcSYoshihiro Kaneko static const struct rcar_thermal_chip rcar_gen2_thermal = {
681969d9dcSYoshihiro Kaneko 	.use_of_thermal = 1,
691969d9dcSYoshihiro Kaneko 	.has_filonoff = 1,
701969d9dcSYoshihiro Kaneko 	.irq_per_ch = 0,
711969d9dcSYoshihiro Kaneko 	.needs_suspend_resume = 0,
721969d9dcSYoshihiro Kaneko 	.nirqs = 1,
7320386f0dSYoshihiro Kaneko 	.ctemp_bands = 1,
741969d9dcSYoshihiro Kaneko };
751969d9dcSYoshihiro Kaneko 
761969d9dcSYoshihiro Kaneko static const struct rcar_thermal_chip rcar_gen3_thermal = {
771969d9dcSYoshihiro Kaneko 	.use_of_thermal = 1,
781969d9dcSYoshihiro Kaneko 	.has_filonoff = 0,
791969d9dcSYoshihiro Kaneko 	.irq_per_ch = 1,
801969d9dcSYoshihiro Kaneko 	.needs_suspend_resume = 1,
811969d9dcSYoshihiro Kaneko 	/*
821969d9dcSYoshihiro Kaneko 	 * The Gen3 chip has 3 interrupts, but this driver uses only 2
831969d9dcSYoshihiro Kaneko 	 * interrupts to detect a temperature change, rise or fall.
841969d9dcSYoshihiro Kaneko 	 */
851969d9dcSYoshihiro Kaneko 	.nirqs = 2,
8620386f0dSYoshihiro Kaneko 	.ctemp_bands = 2,
871969d9dcSYoshihiro Kaneko };
881969d9dcSYoshihiro Kaneko 
891e426ffdSKuninori Morimoto struct rcar_thermal_priv {
901e426ffdSKuninori Morimoto 	void __iomem *base;
913676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common;
923676d1ddSKuninori Morimoto 	struct thermal_zone_device *zone;
931969d9dcSYoshihiro Kaneko 	const struct rcar_thermal_chip *chip;
94e0a5172eSKuninori Morimoto 	struct delayed_work work;
95b2bbc6a2SKuninori Morimoto 	struct mutex lock;
963676d1ddSKuninori Morimoto 	struct list_head list;
97e0a5172eSKuninori Morimoto 	int id;
981e426ffdSKuninori Morimoto };
991e426ffdSKuninori Morimoto 
1003676d1ddSKuninori Morimoto #define rcar_thermal_for_each_priv(pos, common)	\
1013676d1ddSKuninori Morimoto 	list_for_each_entry(pos, &common->head, list)
1023676d1ddSKuninori Morimoto 
103c499703eSKuninori Morimoto #define MCELSIUS(temp)			((temp) * 1000)
1043676d1ddSKuninori Morimoto #define rcar_priv_to_dev(priv)		((priv)->common->dev)
1053676d1ddSKuninori Morimoto #define rcar_has_irq_support(priv)	((priv)->common->base)
106e0a5172eSKuninori Morimoto #define rcar_id_to_shift(priv)		((priv)->id * 8)
107e0a5172eSKuninori Morimoto 
108ca1e4558SKuninori Morimoto static const struct of_device_id rcar_thermal_dt_ids[] = {
1091969d9dcSYoshihiro Kaneko 	{
1101969d9dcSYoshihiro Kaneko 		.compatible = "renesas,rcar-thermal",
1111969d9dcSYoshihiro Kaneko 		.data = &rcar_thermal,
1121969d9dcSYoshihiro Kaneko 	},
1131969d9dcSYoshihiro Kaneko 	{
1141969d9dcSYoshihiro Kaneko 		.compatible = "renesas,rcar-gen2-thermal",
1151969d9dcSYoshihiro Kaneko 		 .data = &rcar_gen2_thermal,
1161969d9dcSYoshihiro Kaneko 	},
1171969d9dcSYoshihiro Kaneko 	{
118b8d3d112SFabrizio Castro 		.compatible = "renesas,thermal-r8a774c0",
119b8d3d112SFabrizio Castro 		.data = &rcar_gen3_thermal,
120b8d3d112SFabrizio Castro 	},
121b8d3d112SFabrizio Castro 	{
12292ca366eSSergei Shtylyov 		.compatible = "renesas,thermal-r8a77970",
12392ca366eSSergei Shtylyov 		.data = &rcar_gen3_thermal,
12492ca366eSSergei Shtylyov 	},
12592ca366eSSergei Shtylyov 	{
126e36e1300SYoshihiro Kaneko 		.compatible = "renesas,thermal-r8a77990",
127e36e1300SYoshihiro Kaneko 		.data = &rcar_gen3_thermal,
128e36e1300SYoshihiro Kaneko 	},
129e36e1300SYoshihiro Kaneko 	{
1301969d9dcSYoshihiro Kaneko 		.compatible = "renesas,thermal-r8a77995",
1311969d9dcSYoshihiro Kaneko 		.data = &rcar_gen3_thermal,
1321969d9dcSYoshihiro Kaneko 	},
133ca1e4558SKuninori Morimoto 	{},
134ca1e4558SKuninori Morimoto };
135ca1e4558SKuninori Morimoto MODULE_DEVICE_TABLE(of, rcar_thermal_dt_ids);
136ca1e4558SKuninori Morimoto 
1371e426ffdSKuninori Morimoto /*
1381e426ffdSKuninori Morimoto  *		basic functions
1391e426ffdSKuninori Morimoto  */
140e9137a58SKuninori Morimoto #define rcar_thermal_common_read(c, r) \
141e9137a58SKuninori Morimoto 	_rcar_thermal_common_read(c, COMMON_ ##r)
_rcar_thermal_common_read(struct rcar_thermal_common * common,u32 reg)142e9137a58SKuninori Morimoto static u32 _rcar_thermal_common_read(struct rcar_thermal_common *common,
143e9137a58SKuninori Morimoto 				     u32 reg)
144e9137a58SKuninori Morimoto {
145e9137a58SKuninori Morimoto 	return ioread32(common->base + reg);
146e9137a58SKuninori Morimoto }
147e9137a58SKuninori Morimoto 
148e9137a58SKuninori Morimoto #define rcar_thermal_common_write(c, r, d) \
149e9137a58SKuninori Morimoto 	_rcar_thermal_common_write(c, COMMON_ ##r, d)
_rcar_thermal_common_write(struct rcar_thermal_common * common,u32 reg,u32 data)150e9137a58SKuninori Morimoto static void _rcar_thermal_common_write(struct rcar_thermal_common *common,
151e9137a58SKuninori Morimoto 				       u32 reg, u32 data)
152e9137a58SKuninori Morimoto {
153e9137a58SKuninori Morimoto 	iowrite32(data, common->base + reg);
154e9137a58SKuninori Morimoto }
155e9137a58SKuninori Morimoto 
156e9137a58SKuninori Morimoto #define rcar_thermal_common_bset(c, r, m, d) \
157e9137a58SKuninori Morimoto 	_rcar_thermal_common_bset(c, COMMON_ ##r, m, d)
_rcar_thermal_common_bset(struct rcar_thermal_common * common,u32 reg,u32 mask,u32 data)158e9137a58SKuninori Morimoto static void _rcar_thermal_common_bset(struct rcar_thermal_common *common,
159e9137a58SKuninori Morimoto 				      u32 reg, u32 mask, u32 data)
160e9137a58SKuninori Morimoto {
161e9137a58SKuninori Morimoto 	u32 val;
162e9137a58SKuninori Morimoto 
163e9137a58SKuninori Morimoto 	val = ioread32(common->base + reg);
164e9137a58SKuninori Morimoto 	val &= ~mask;
165e9137a58SKuninori Morimoto 	val |= (data & mask);
166e9137a58SKuninori Morimoto 	iowrite32(val, common->base + reg);
167e9137a58SKuninori Morimoto }
168e9137a58SKuninori Morimoto 
169e9137a58SKuninori Morimoto #define rcar_thermal_read(p, r) _rcar_thermal_read(p, REG_ ##r)
_rcar_thermal_read(struct rcar_thermal_priv * priv,u32 reg)170e9137a58SKuninori Morimoto static u32 _rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
1711e426ffdSKuninori Morimoto {
172b2bbc6a2SKuninori Morimoto 	return ioread32(priv->base + reg);
1731e426ffdSKuninori Morimoto }
1741e426ffdSKuninori Morimoto 
175e9137a58SKuninori Morimoto #define rcar_thermal_write(p, r, d) _rcar_thermal_write(p, REG_ ##r, d)
_rcar_thermal_write(struct rcar_thermal_priv * priv,u32 reg,u32 data)176e9137a58SKuninori Morimoto static void _rcar_thermal_write(struct rcar_thermal_priv *priv,
1771e426ffdSKuninori Morimoto 				u32 reg, u32 data)
1781e426ffdSKuninori Morimoto {
1791e426ffdSKuninori Morimoto 	iowrite32(data, priv->base + reg);
1801e426ffdSKuninori Morimoto }
1811e426ffdSKuninori Morimoto 
182e9137a58SKuninori Morimoto #define rcar_thermal_bset(p, r, m, d) _rcar_thermal_bset(p, REG_ ##r, m, d)
_rcar_thermal_bset(struct rcar_thermal_priv * priv,u32 reg,u32 mask,u32 data)183e9137a58SKuninori Morimoto static void _rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
1841e426ffdSKuninori Morimoto 			       u32 mask, u32 data)
1851e426ffdSKuninori Morimoto {
1861e426ffdSKuninori Morimoto 	u32 val;
1871e426ffdSKuninori Morimoto 
1881e426ffdSKuninori Morimoto 	val = ioread32(priv->base + reg);
1891e426ffdSKuninori Morimoto 	val &= ~mask;
1901e426ffdSKuninori Morimoto 	val |= (data & mask);
1911e426ffdSKuninori Morimoto 	iowrite32(val, priv->base + reg);
1921e426ffdSKuninori Morimoto }
1931e426ffdSKuninori Morimoto 
1941e426ffdSKuninori Morimoto /*
1951e426ffdSKuninori Morimoto  *		zone device functions
1961e426ffdSKuninori Morimoto  */
rcar_thermal_update_temp(struct rcar_thermal_priv * priv)197e0a5172eSKuninori Morimoto static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
1981e426ffdSKuninori Morimoto {
199f8f53e18SKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
200b03628b7SNiklas Söderlund 	int old, new, ctemp = -EINVAL;
201b03628b7SNiklas Söderlund 	unsigned int i;
2021e426ffdSKuninori Morimoto 
203b2bbc6a2SKuninori Morimoto 	mutex_lock(&priv->lock);
204b2bbc6a2SKuninori Morimoto 
2051e426ffdSKuninori Morimoto 	/*
206f8f53e18SKuninori Morimoto 	 * TSC decides a value of CPTAP automatically,
207f8f53e18SKuninori Morimoto 	 * and this is the conditions which validate interrupt.
2081e426ffdSKuninori Morimoto 	 */
209f8f53e18SKuninori Morimoto 	rcar_thermal_bset(priv, THSCR, CPCTL, CPCTL);
2101e426ffdSKuninori Morimoto 
211f8f53e18SKuninori Morimoto 	old = ~0;
212f8f53e18SKuninori Morimoto 	for (i = 0; i < 128; i++) {
2131e426ffdSKuninori Morimoto 		/*
2141e426ffdSKuninori Morimoto 		 * we need to wait 300us after changing comparator offset
2151e426ffdSKuninori Morimoto 		 * to get stable temperature.
2161e426ffdSKuninori Morimoto 		 * see "Usage Notes" on datasheet
2171e426ffdSKuninori Morimoto 		 */
218263c8c4cSGeert Uytterhoeven 		usleep_range(300, 400);
2191e426ffdSKuninori Morimoto 
220f8f53e18SKuninori Morimoto 		new = rcar_thermal_read(priv, THSSR) & CTEMP;
221f8f53e18SKuninori Morimoto 		if (new == old) {
222f8f53e18SKuninori Morimoto 			ctemp = new;
2231e426ffdSKuninori Morimoto 			break;
2241e426ffdSKuninori Morimoto 		}
225f8f53e18SKuninori Morimoto 		old = new;
2261e426ffdSKuninori Morimoto 	}
2271e426ffdSKuninori Morimoto 
228b03628b7SNiklas Söderlund 	if (ctemp < 0) {
229f8f53e18SKuninori Morimoto 		dev_err(dev, "thermal sensor was broken\n");
230f0e68fc3SWei Yongjun 		goto err_out_unlock;
231f8f53e18SKuninori Morimoto 	}
232f8f53e18SKuninori Morimoto 
233e0a5172eSKuninori Morimoto 	/*
234e0a5172eSKuninori Morimoto 	 * enable IRQ
235e0a5172eSKuninori Morimoto 	 */
236e0a5172eSKuninori Morimoto 	if (rcar_has_irq_support(priv)) {
2371969d9dcSYoshihiro Kaneko 		if (priv->chip->has_filonoff)
238e0a5172eSKuninori Morimoto 			rcar_thermal_write(priv, FILONOFF, 0);
239f8f53e18SKuninori Morimoto 
240e0a5172eSKuninori Morimoto 		/* enable Rising/Falling edge interrupt */
241e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, POSNEG,  0x1);
242e0a5172eSKuninori Morimoto 		rcar_thermal_write(priv, INTCTRL, (((ctemp - 0) << 8) |
243e0a5172eSKuninori Morimoto 						   ((ctemp - 1) << 0)));
244e0a5172eSKuninori Morimoto 	}
245e0a5172eSKuninori Morimoto 
246f0e68fc3SWei Yongjun err_out_unlock:
247e0a5172eSKuninori Morimoto 	mutex_unlock(&priv->lock);
24857ed737fSNiklas Söderlund 
249b03628b7SNiklas Söderlund 	return ctemp;
250e0a5172eSKuninori Morimoto }
251e0a5172eSKuninori Morimoto 
rcar_thermal_get_current_temp(struct rcar_thermal_priv * priv,int * temp)2528b477ea5SKuninori Morimoto static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv,
2538b477ea5SKuninori Morimoto 					 int *temp)
254e0a5172eSKuninori Morimoto {
2550fa04202SNiklas Söderlund 	int ctemp;
256e0a5172eSKuninori Morimoto 
25757ed737fSNiklas Söderlund 	ctemp = rcar_thermal_update_temp(priv);
25857ed737fSNiklas Söderlund 	if (ctemp < 0)
25957ed737fSNiklas Söderlund 		return ctemp;
260e0a5172eSKuninori Morimoto 
261dff6d4f8SNiklas Söderlund 	/* Guaranteed operating range is -45C to 125C. */
2625440c40bSKuninori Morimoto 
2630fa04202SNiklas Söderlund 	if (priv->chip->ctemp_bands == 1)
2640fa04202SNiklas Söderlund 		*temp = MCELSIUS((ctemp * 5) - 65);
2650fa04202SNiklas Söderlund 	else if (ctemp < 24)
2660fa04202SNiklas Söderlund 		*temp = MCELSIUS(((ctemp * 55) - 720) / 10);
2670fa04202SNiklas Söderlund 	else
2680fa04202SNiklas Söderlund 		*temp = MCELSIUS((ctemp * 5) - 60);
2695440c40bSKuninori Morimoto 
2701e426ffdSKuninori Morimoto 	return 0;
2711e426ffdSKuninori Morimoto }
2721e426ffdSKuninori Morimoto 
rcar_thermal_get_temp(struct thermal_zone_device * zone,int * temp)2738b477ea5SKuninori Morimoto static int rcar_thermal_get_temp(struct thermal_zone_device *zone, int *temp)
2748b477ea5SKuninori Morimoto {
2755f68d078SDaniel Lezcano 	struct rcar_thermal_priv *priv = thermal_zone_device_priv(zone);
2768b477ea5SKuninori Morimoto 
2778b477ea5SKuninori Morimoto 	return rcar_thermal_get_current_temp(priv, temp);
2788b477ea5SKuninori Morimoto }
2798b477ea5SKuninori Morimoto 
2800b6a3e45SDaniel Lezcano static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
2812ebd4f2fSDaniel Lezcano 	.get_temp	= rcar_thermal_get_temp,
2828b477ea5SKuninori Morimoto };
2838b477ea5SKuninori Morimoto 
2840b6a3e45SDaniel Lezcano static struct thermal_trip trips[] = {
2850b6a3e45SDaniel Lezcano 	{ .type = THERMAL_TRIP_CRITICAL, .temperature = 90000 }
2861e426ffdSKuninori Morimoto };
2871e426ffdSKuninori Morimoto 
2881e426ffdSKuninori Morimoto /*
289e0a5172eSKuninori Morimoto  *		interrupt
290e0a5172eSKuninori Morimoto  */
291e0a5172eSKuninori Morimoto #define rcar_thermal_irq_enable(p)	_rcar_thermal_irq_ctrl(p, 1)
292e0a5172eSKuninori Morimoto #define rcar_thermal_irq_disable(p)	_rcar_thermal_irq_ctrl(p, 0)
_rcar_thermal_irq_ctrl(struct rcar_thermal_priv * priv,int enable)293e0a5172eSKuninori Morimoto static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
294e0a5172eSKuninori Morimoto {
295e0a5172eSKuninori Morimoto 	struct rcar_thermal_common *common = priv->common;
296e0a5172eSKuninori Morimoto 	unsigned long flags;
297e0a5172eSKuninori Morimoto 	u32 mask = 0x3 << rcar_id_to_shift(priv); /* enable Rising/Falling */
298e0a5172eSKuninori Morimoto 
299ffbcdf8aSKuninori Morimoto 	if (!rcar_has_irq_support(priv))
300ffbcdf8aSKuninori Morimoto 		return;
301ffbcdf8aSKuninori Morimoto 
302e0a5172eSKuninori Morimoto 	spin_lock_irqsave(&common->lock, flags);
303e0a5172eSKuninori Morimoto 
304e0a5172eSKuninori Morimoto 	rcar_thermal_common_bset(common, INTMSK, mask, enable ? 0 : mask);
305e0a5172eSKuninori Morimoto 
306e0a5172eSKuninori Morimoto 	spin_unlock_irqrestore(&common->lock, flags);
307e0a5172eSKuninori Morimoto }
308e0a5172eSKuninori Morimoto 
rcar_thermal_work(struct work_struct * work)309e0a5172eSKuninori Morimoto static void rcar_thermal_work(struct work_struct *work)
310e0a5172eSKuninori Morimoto {
311e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv;
312a1ade565SKuninori Morimoto 	int ret;
313e0a5172eSKuninori Morimoto 
314e0a5172eSKuninori Morimoto 	priv = container_of(work, struct rcar_thermal_priv, work.work);
315e0a5172eSKuninori Morimoto 
316a1ade565SKuninori Morimoto 	ret = rcar_thermal_update_temp(priv);
317a1ade565SKuninori Morimoto 	if (ret < 0)
318a1ade565SKuninori Morimoto 		return;
319a1ade565SKuninori Morimoto 
320e0a5172eSKuninori Morimoto 	rcar_thermal_irq_enable(priv);
3219477165eSPatrick Titiano 
3227617e771SNiklas Söderlund 	thermal_zone_device_update(priv->zone, THERMAL_EVENT_UNSPECIFIED);
323e0a5172eSKuninori Morimoto }
324e0a5172eSKuninori Morimoto 
rcar_thermal_had_changed(struct rcar_thermal_priv * priv,u32 status)325e0a5172eSKuninori Morimoto static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
326e0a5172eSKuninori Morimoto {
327e0a5172eSKuninori Morimoto 	struct device *dev = rcar_priv_to_dev(priv);
328e0a5172eSKuninori Morimoto 
329e0a5172eSKuninori Morimoto 	status = (status >> rcar_id_to_shift(priv)) & 0x3;
330e0a5172eSKuninori Morimoto 
331206c0cbaSPatrick Titiano 	if (status) {
332e0a5172eSKuninori Morimoto 		dev_dbg(dev, "thermal%d %s%s\n",
333e0a5172eSKuninori Morimoto 			priv->id,
334e0a5172eSKuninori Morimoto 			(status & 0x2) ? "Rising " : "",
335e0a5172eSKuninori Morimoto 			(status & 0x1) ? "Falling" : "");
336e0a5172eSKuninori Morimoto 	}
337e0a5172eSKuninori Morimoto 
338e0a5172eSKuninori Morimoto 	return status;
339e0a5172eSKuninori Morimoto }
340e0a5172eSKuninori Morimoto 
rcar_thermal_irq(int irq,void * data)341e0a5172eSKuninori Morimoto static irqreturn_t rcar_thermal_irq(int irq, void *data)
342e0a5172eSKuninori Morimoto {
343e0a5172eSKuninori Morimoto 	struct rcar_thermal_common *common = data;
344e0a5172eSKuninori Morimoto 	struct rcar_thermal_priv *priv;
345e0a5172eSKuninori Morimoto 	u32 status, mask;
346e0a5172eSKuninori Morimoto 
3474eb7d0cdSTian Tao 	spin_lock(&common->lock);
348e0a5172eSKuninori Morimoto 
349e0a5172eSKuninori Morimoto 	mask	= rcar_thermal_common_read(common, INTMSK);
350e0a5172eSKuninori Morimoto 	status	= rcar_thermal_common_read(common, STR);
351e0a5172eSKuninori Morimoto 	rcar_thermal_common_write(common, STR, 0x000F0F0F & mask);
352e0a5172eSKuninori Morimoto 
3534eb7d0cdSTian Tao 	spin_unlock(&common->lock);
354e0a5172eSKuninori Morimoto 
355e0a5172eSKuninori Morimoto 	status = status & ~mask;
356e0a5172eSKuninori Morimoto 
357e0a5172eSKuninori Morimoto 	/*
358e0a5172eSKuninori Morimoto 	 * check the status
359e0a5172eSKuninori Morimoto 	 */
360e0a5172eSKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
361e0a5172eSKuninori Morimoto 		if (rcar_thermal_had_changed(priv, status)) {
362e0a5172eSKuninori Morimoto 			rcar_thermal_irq_disable(priv);
3633a313862SGeert Uytterhoeven 			queue_delayed_work(system_freezable_wq, &priv->work,
364e0a5172eSKuninori Morimoto 					   msecs_to_jiffies(300));
365e0a5172eSKuninori Morimoto 		}
366e0a5172eSKuninori Morimoto 	}
367e0a5172eSKuninori Morimoto 
368e0a5172eSKuninori Morimoto 	return IRQ_HANDLED;
369e0a5172eSKuninori Morimoto }
370e0a5172eSKuninori Morimoto 
371e0a5172eSKuninori Morimoto /*
3721e426ffdSKuninori Morimoto  *		platform functions
3731e426ffdSKuninori Morimoto  */
rcar_thermal_remove(struct platform_device * pdev)37484f0e490SKuninori Morimoto static int rcar_thermal_remove(struct platform_device *pdev)
37584f0e490SKuninori Morimoto {
37684f0e490SKuninori Morimoto 	struct rcar_thermal_common *common = platform_get_drvdata(pdev);
37784f0e490SKuninori Morimoto 	struct device *dev = &pdev->dev;
37884f0e490SKuninori Morimoto 	struct rcar_thermal_priv *priv;
37984f0e490SKuninori Morimoto 
38084f0e490SKuninori Morimoto 	rcar_thermal_for_each_priv(priv, common) {
38184f0e490SKuninori Morimoto 		rcar_thermal_irq_disable(priv);
382697ee786SGeert Uytterhoeven 		cancel_delayed_work_sync(&priv->work);
3831969d9dcSYoshihiro Kaneko 		if (priv->chip->use_of_thermal)
38464a411e8SKuninori Morimoto 			thermal_remove_hwmon_sysfs(priv->zone);
385d4b23c5cSBui Duc Phuc 		else
38684f0e490SKuninori Morimoto 			thermal_zone_device_unregister(priv->zone);
38784f0e490SKuninori Morimoto 	}
38884f0e490SKuninori Morimoto 
38984f0e490SKuninori Morimoto 	pm_runtime_put(dev);
39084f0e490SKuninori Morimoto 	pm_runtime_disable(dev);
39184f0e490SKuninori Morimoto 
39284f0e490SKuninori Morimoto 	return 0;
39384f0e490SKuninori Morimoto }
39484f0e490SKuninori Morimoto 
rcar_thermal_probe(struct platform_device * pdev)3951e426ffdSKuninori Morimoto static int rcar_thermal_probe(struct platform_device *pdev)
3961e426ffdSKuninori Morimoto {
3973676d1ddSKuninori Morimoto 	struct rcar_thermal_common *common;
3981e426ffdSKuninori Morimoto 	struct rcar_thermal_priv *priv;
3993676d1ddSKuninori Morimoto 	struct device *dev = &pdev->dev;
4003277e022SLad Prabhakar 	struct resource *res;
4011969d9dcSYoshihiro Kaneko 	const struct rcar_thermal_chip *chip = of_device_get_match_data(dev);
4023676d1ddSKuninori Morimoto 	int mres = 0;
4033676d1ddSKuninori Morimoto 	int i;
404fb84d990SDevendra Naga 	int ret = -ENODEV;
405e0a5172eSKuninori Morimoto 	int idle = IDLE_INTERVAL;
40611313746SYoshihiro Shimoda 	u32 enr_bits = 0;
4071e426ffdSKuninori Morimoto 
4083676d1ddSKuninori Morimoto 	common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
409b0a60d88SJingoo Han 	if (!common)
4103676d1ddSKuninori Morimoto 		return -ENOMEM;
4113676d1ddSKuninori Morimoto 
41284f0e490SKuninori Morimoto 	platform_set_drvdata(pdev, common);
41384f0e490SKuninori Morimoto 
4143676d1ddSKuninori Morimoto 	INIT_LIST_HEAD(&common->head);
415e0a5172eSKuninori Morimoto 	spin_lock_init(&common->lock);
4163676d1ddSKuninori Morimoto 	common->dev = dev;
4173676d1ddSKuninori Morimoto 
41851d45d25SKuninori Morimoto 	pm_runtime_enable(dev);
41951d45d25SKuninori Morimoto 	pm_runtime_get_sync(dev);
42051d45d25SKuninori Morimoto 
4211969d9dcSYoshihiro Kaneko 	for (i = 0; i < chip->nirqs; i++) {
4223277e022SLad Prabhakar 		int irq;
4233277e022SLad Prabhakar 
4243277e022SLad Prabhakar 		ret = platform_get_irq_optional(pdev, i);
4253277e022SLad Prabhakar 		if (ret < 0 && ret != -ENXIO)
4263277e022SLad Prabhakar 			goto error_unregister;
4273277e022SLad Prabhakar 		if (ret > 0)
4283277e022SLad Prabhakar 			irq = ret;
4293277e022SLad Prabhakar 		else
4303277e022SLad Prabhakar 			break;
4313277e022SLad Prabhakar 
4321969d9dcSYoshihiro Kaneko 		if (!common->base) {
4333676d1ddSKuninori Morimoto 			/*
4343676d1ddSKuninori Morimoto 			 * platform has IRQ support.
435ee853addSGeert Uytterhoeven 			 * Then, driver uses common registers
4363676d1ddSKuninori Morimoto 			 * rcar_has_irq_support() will be enabled
4373676d1ddSKuninori Morimoto 			 */
4381969d9dcSYoshihiro Kaneko 			res = platform_get_resource(pdev, IORESOURCE_MEM,
4391969d9dcSYoshihiro Kaneko 						    mres++);
4405095526fSSachin Kamat 			common->base = devm_ioremap_resource(dev, res);
44139056e8aSNiklas Söderlund 			if (IS_ERR(common->base)) {
44239056e8aSNiklas Söderlund 				ret = PTR_ERR(common->base);
44339056e8aSNiklas Söderlund 				goto error_unregister;
44439056e8aSNiklas Söderlund 			}
445e0a5172eSKuninori Morimoto 
4466fe495e0SGeert Uytterhoeven 			idle = 0; /* polling delay is not needed */
4473676d1ddSKuninori Morimoto 		}
4483676d1ddSKuninori Morimoto 
4493277e022SLad Prabhakar 		ret = devm_request_irq(dev, irq, rcar_thermal_irq,
4501969d9dcSYoshihiro Kaneko 				       IRQF_SHARED, dev_name(dev), common);
4511969d9dcSYoshihiro Kaneko 		if (ret) {
4521969d9dcSYoshihiro Kaneko 			dev_err(dev, "irq request failed\n ");
4531969d9dcSYoshihiro Kaneko 			goto error_unregister;
4541969d9dcSYoshihiro Kaneko 		}
4551969d9dcSYoshihiro Kaneko 
4561969d9dcSYoshihiro Kaneko 		/* update ENR bits */
4571969d9dcSYoshihiro Kaneko 		if (chip->irq_per_ch)
4581969d9dcSYoshihiro Kaneko 			enr_bits |= 1 << i;
4591969d9dcSYoshihiro Kaneko 	}
4601969d9dcSYoshihiro Kaneko 
4613676d1ddSKuninori Morimoto 	for (i = 0;; i++) {
4623676d1ddSKuninori Morimoto 		res = platform_get_resource(pdev, IORESOURCE_MEM, mres++);
4633676d1ddSKuninori Morimoto 		if (!res)
4643676d1ddSKuninori Morimoto 			break;
4653676d1ddSKuninori Morimoto 
4663676d1ddSKuninori Morimoto 		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
4671e426ffdSKuninori Morimoto 		if (!priv) {
4681dc20828SKuninori Morimoto 			ret = -ENOMEM;
4691dc20828SKuninori Morimoto 			goto error_unregister;
4701e426ffdSKuninori Morimoto 		}
4711e426ffdSKuninori Morimoto 
4725095526fSSachin Kamat 		priv->base = devm_ioremap_resource(dev, res);
4731dc20828SKuninori Morimoto 		if (IS_ERR(priv->base)) {
4741dc20828SKuninori Morimoto 			ret = PTR_ERR(priv->base);
4751dc20828SKuninori Morimoto 			goto error_unregister;
4761dc20828SKuninori Morimoto 		}
4771e426ffdSKuninori Morimoto 
4783676d1ddSKuninori Morimoto 		priv->common = common;
479e0a5172eSKuninori Morimoto 		priv->id = i;
4801969d9dcSYoshihiro Kaneko 		priv->chip = chip;
4813676d1ddSKuninori Morimoto 		mutex_init(&priv->lock);
4823676d1ddSKuninori Morimoto 		INIT_LIST_HEAD(&priv->list);
483e0a5172eSKuninori Morimoto 		INIT_DELAYED_WORK(&priv->work, rcar_thermal_work);
484a1ade565SKuninori Morimoto 		ret = rcar_thermal_update_temp(priv);
485a1ade565SKuninori Morimoto 		if (ret < 0)
486a1ade565SKuninori Morimoto 			goto error_unregister;
4873676d1ddSKuninori Morimoto 
488392573b7SGeert Uytterhoeven 		if (chip->use_of_thermal) {
4892ebd4f2fSDaniel Lezcano 			priv->zone = devm_thermal_of_zone_register(
4908b477ea5SKuninori Morimoto 						dev, i, priv,
4910b6a3e45SDaniel Lezcano 						&rcar_thermal_zone_ops);
492392573b7SGeert Uytterhoeven 		} else {
4930b6a3e45SDaniel Lezcano 			priv->zone = thermal_zone_device_register_with_trips(
4940b6a3e45SDaniel Lezcano 				"rcar_thermal", trips, ARRAY_SIZE(trips), 0, priv,
495d2a73e22Skuninori.morimoto.gx@renesas.com 						&rcar_thermal_zone_ops, NULL, 0,
496e0a5172eSKuninori Morimoto 						idle);
497bbcf90c0SAndrzej Pietrasiewicz 
498bbcf90c0SAndrzej Pietrasiewicz 			ret = thermal_zone_device_enable(priv->zone);
499bbcf90c0SAndrzej Pietrasiewicz 			if (ret) {
500bbcf90c0SAndrzej Pietrasiewicz 				thermal_zone_device_unregister(priv->zone);
501bbcf90c0SAndrzej Pietrasiewicz 				priv->zone = ERR_PTR(ret);
502bbcf90c0SAndrzej Pietrasiewicz 			}
503bbcf90c0SAndrzej Pietrasiewicz 		}
5043676d1ddSKuninori Morimoto 		if (IS_ERR(priv->zone)) {
5053676d1ddSKuninori Morimoto 			dev_err(dev, "can't register thermal zone\n");
506fb84d990SDevendra Naga 			ret = PTR_ERR(priv->zone);
50787260d3fSDirk Behme 			priv->zone = NULL;
5083676d1ddSKuninori Morimoto 			goto error_unregister;
5091e426ffdSKuninori Morimoto 		}
5101e426ffdSKuninori Morimoto 
5111969d9dcSYoshihiro Kaneko 		if (chip->use_of_thermal) {
51264a411e8SKuninori Morimoto 			ret = thermal_add_hwmon_sysfs(priv->zone);
51364a411e8SKuninori Morimoto 			if (ret)
51464a411e8SKuninori Morimoto 				goto error_unregister;
51564a411e8SKuninori Morimoto 		}
51664a411e8SKuninori Morimoto 
517e0a5172eSKuninori Morimoto 		rcar_thermal_irq_enable(priv);
5181dc20828SKuninori Morimoto 
5191dc20828SKuninori Morimoto 		list_move_tail(&priv->list, &common->head);
52011313746SYoshihiro Shimoda 
52111313746SYoshihiro Shimoda 		/* update ENR bits */
5221969d9dcSYoshihiro Kaneko 		if (!chip->irq_per_ch)
52311313746SYoshihiro Shimoda 			enr_bits |= 3 << (i * 8);
5243676d1ddSKuninori Morimoto 	}
5251e426ffdSKuninori Morimoto 
526542cdf40SSimon Horman 	if (common->base && enr_bits)
52711313746SYoshihiro Shimoda 		rcar_thermal_common_write(common, ENR, enr_bits);
52811313746SYoshihiro Shimoda 
5293db46c93SLaurent Pinchart 	dev_info(dev, "%d sensor probed\n", i);
5301e426ffdSKuninori Morimoto 
5311e426ffdSKuninori Morimoto 	return 0;
5323676d1ddSKuninori Morimoto 
5333676d1ddSKuninori Morimoto error_unregister:
53484f0e490SKuninori Morimoto 	rcar_thermal_remove(pdev);
53551d45d25SKuninori Morimoto 
536fb84d990SDevendra Naga 	return ret;
5371e426ffdSKuninori Morimoto }
5381e426ffdSKuninori Morimoto 
5391969d9dcSYoshihiro Kaneko #ifdef CONFIG_PM_SLEEP
rcar_thermal_suspend(struct device * dev)5401969d9dcSYoshihiro Kaneko static int rcar_thermal_suspend(struct device *dev)
5411969d9dcSYoshihiro Kaneko {
5421969d9dcSYoshihiro Kaneko 	struct rcar_thermal_common *common = dev_get_drvdata(dev);
5431969d9dcSYoshihiro Kaneko 	struct rcar_thermal_priv *priv = list_first_entry(&common->head,
5441969d9dcSYoshihiro Kaneko 							  typeof(*priv), list);
5451969d9dcSYoshihiro Kaneko 
5461969d9dcSYoshihiro Kaneko 	if (priv->chip->needs_suspend_resume) {
5471969d9dcSYoshihiro Kaneko 		rcar_thermal_common_write(common, ENR, 0);
5481969d9dcSYoshihiro Kaneko 		rcar_thermal_irq_disable(priv);
5491969d9dcSYoshihiro Kaneko 		rcar_thermal_bset(priv, THSCR, CPCTL, 0);
5501969d9dcSYoshihiro Kaneko 	}
5511969d9dcSYoshihiro Kaneko 
5521969d9dcSYoshihiro Kaneko 	return 0;
5531969d9dcSYoshihiro Kaneko }
5541969d9dcSYoshihiro Kaneko 
rcar_thermal_resume(struct device * dev)5551969d9dcSYoshihiro Kaneko static int rcar_thermal_resume(struct device *dev)
5561969d9dcSYoshihiro Kaneko {
5571969d9dcSYoshihiro Kaneko 	struct rcar_thermal_common *common = dev_get_drvdata(dev);
5581969d9dcSYoshihiro Kaneko 	struct rcar_thermal_priv *priv = list_first_entry(&common->head,
5591969d9dcSYoshihiro Kaneko 							  typeof(*priv), list);
5601969d9dcSYoshihiro Kaneko 	int ret;
5611969d9dcSYoshihiro Kaneko 
5621969d9dcSYoshihiro Kaneko 	if (priv->chip->needs_suspend_resume) {
5631969d9dcSYoshihiro Kaneko 		ret = rcar_thermal_update_temp(priv);
5641969d9dcSYoshihiro Kaneko 		if (ret < 0)
5651969d9dcSYoshihiro Kaneko 			return ret;
5661969d9dcSYoshihiro Kaneko 		rcar_thermal_irq_enable(priv);
5671969d9dcSYoshihiro Kaneko 		rcar_thermal_common_write(common, ENR, 0x03);
5681969d9dcSYoshihiro Kaneko 	}
5691969d9dcSYoshihiro Kaneko 
5701969d9dcSYoshihiro Kaneko 	return 0;
5711969d9dcSYoshihiro Kaneko }
5721969d9dcSYoshihiro Kaneko #endif
5731969d9dcSYoshihiro Kaneko 
5741969d9dcSYoshihiro Kaneko static SIMPLE_DEV_PM_OPS(rcar_thermal_pm_ops, rcar_thermal_suspend,
5751969d9dcSYoshihiro Kaneko 			 rcar_thermal_resume);
5761969d9dcSYoshihiro Kaneko 
5771e426ffdSKuninori Morimoto static struct platform_driver rcar_thermal_driver = {
5781e426ffdSKuninori Morimoto 	.driver	= {
5791e426ffdSKuninori Morimoto 		.name	= "rcar_thermal",
5801969d9dcSYoshihiro Kaneko 		.pm = &rcar_thermal_pm_ops,
58176cc1887SKuninori Morimoto 		.of_match_table = rcar_thermal_dt_ids,
5821e426ffdSKuninori Morimoto 	},
5831e426ffdSKuninori Morimoto 	.probe		= rcar_thermal_probe,
5841e426ffdSKuninori Morimoto 	.remove		= rcar_thermal_remove,
5851e426ffdSKuninori Morimoto };
5861e426ffdSKuninori Morimoto module_platform_driver(rcar_thermal_driver);
5871e426ffdSKuninori Morimoto 
588c9545790SKuninori Morimoto MODULE_LICENSE("GPL v2");
5891e426ffdSKuninori Morimoto MODULE_DESCRIPTION("R-Car THS/TSC thermal sensor driver");
5901e426ffdSKuninori Morimoto MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
591