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