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