1*dc67521cSJohn Madieu // SPDX-License-Identifier: GPL-2.0 2*dc67521cSJohn Madieu /* 3*dc67521cSJohn Madieu * Renesas RZ/G3E TSU Temperature Sensor Unit 4*dc67521cSJohn Madieu * 5*dc67521cSJohn Madieu * Copyright (C) 2025 Renesas Electronics Corporation 6*dc67521cSJohn Madieu */ 7*dc67521cSJohn Madieu #include <linux/clk.h> 8*dc67521cSJohn Madieu #include <linux/cleanup.h> 9*dc67521cSJohn Madieu #include <linux/delay.h> 10*dc67521cSJohn Madieu #include <linux/err.h> 11*dc67521cSJohn Madieu #include <linux/interrupt.h> 12*dc67521cSJohn Madieu #include <linux/io.h> 13*dc67521cSJohn Madieu #include <linux/iopoll.h> 14*dc67521cSJohn Madieu #include <linux/kernel.h> 15*dc67521cSJohn Madieu #include <linux/mfd/syscon.h> 16*dc67521cSJohn Madieu #include <linux/module.h> 17*dc67521cSJohn Madieu #include <linux/of.h> 18*dc67521cSJohn Madieu #include <linux/platform_device.h> 19*dc67521cSJohn Madieu #include <linux/pm_runtime.h> 20*dc67521cSJohn Madieu #include <linux/regmap.h> 21*dc67521cSJohn Madieu #include <linux/reset.h> 22*dc67521cSJohn Madieu #include <linux/thermal.h> 23*dc67521cSJohn Madieu #include <linux/units.h> 24*dc67521cSJohn Madieu 25*dc67521cSJohn Madieu #include "../thermal_hwmon.h" 26*dc67521cSJohn Madieu 27*dc67521cSJohn Madieu /* TSU Register offsets and bits */ 28*dc67521cSJohn Madieu #define TSU_SSUSR 0x00 29*dc67521cSJohn Madieu #define TSU_SSUSR_EN_TS BIT(0) 30*dc67521cSJohn Madieu #define TSU_SSUSR_ADC_PD_TS BIT(1) 31*dc67521cSJohn Madieu #define TSU_SSUSR_SOC_TS_EN BIT(2) 32*dc67521cSJohn Madieu 33*dc67521cSJohn Madieu #define TSU_STRGR 0x04 34*dc67521cSJohn Madieu #define TSU_STRGR_ADST BIT(0) 35*dc67521cSJohn Madieu 36*dc67521cSJohn Madieu #define TSU_SOSR1 0x08 37*dc67521cSJohn Madieu #define TSU_SOSR1_ADCT_8 0x03 38*dc67521cSJohn Madieu #define TSU_SOSR1_ADCS BIT(4) 39*dc67521cSJohn Madieu #define TSU_SOSR1_OUTSEL BIT(9) 40*dc67521cSJohn Madieu 41*dc67521cSJohn Madieu #define TSU_SCRR 0x10 42*dc67521cSJohn Madieu #define TSU_SCRR_OUT12BIT_TS GENMASK(11, 0) 43*dc67521cSJohn Madieu 44*dc67521cSJohn Madieu #define TSU_SSR 0x14 45*dc67521cSJohn Madieu #define TSU_SSR_CONV BIT(0) 46*dc67521cSJohn Madieu 47*dc67521cSJohn Madieu #define TSU_CMSR 0x18 48*dc67521cSJohn Madieu #define TSU_CMSR_CMPEN BIT(0) 49*dc67521cSJohn Madieu 50*dc67521cSJohn Madieu #define TSU_LLSR 0x1C 51*dc67521cSJohn Madieu #define TSU_ULSR 0x20 52*dc67521cSJohn Madieu 53*dc67521cSJohn Madieu #define TSU_SISR 0x30 54*dc67521cSJohn Madieu #define TSU_SISR_ADF BIT(0) 55*dc67521cSJohn Madieu #define TSU_SISR_CMPF BIT(1) 56*dc67521cSJohn Madieu 57*dc67521cSJohn Madieu #define TSU_SIER 0x34 58*dc67521cSJohn Madieu #define TSU_SIER_CMPIE BIT(1) 59*dc67521cSJohn Madieu 60*dc67521cSJohn Madieu #define TSU_SICR 0x38 61*dc67521cSJohn Madieu #define TSU_SICR_ADCLR BIT(0) 62*dc67521cSJohn Madieu #define TSU_SICR_CMPCLR BIT(1) 63*dc67521cSJohn Madieu 64*dc67521cSJohn Madieu /* Temperature calculation constants from datasheet */ 65*dc67521cSJohn Madieu #define TSU_TEMP_D (-41) 66*dc67521cSJohn Madieu #define TSU_TEMP_E 126 67*dc67521cSJohn Madieu #define TSU_CODE_MAX 0xFFF 68*dc67521cSJohn Madieu 69*dc67521cSJohn Madieu /* Timing specifications from datasheet */ 70*dc67521cSJohn Madieu #define TSU_POWERUP_TIME_US 120 /* 120T at 1MHz sensor clock per datasheet */ 71*dc67521cSJohn Madieu #define TSU_CONV_TIME_US 50 /* Per sample conversion time */ 72*dc67521cSJohn Madieu #define TSU_POLL_DELAY_US 10 /* Polling interval */ 73*dc67521cSJohn Madieu #define TSU_MIN_CLOCK_RATE 24000000 /* TSU_PCLK minimum 24MHz */ 74*dc67521cSJohn Madieu 75*dc67521cSJohn Madieu /** 76*dc67521cSJohn Madieu * struct rzg3e_thermal_priv - RZ/G3E TSU private data 77*dc67521cSJohn Madieu * @base: TSU register base 78*dc67521cSJohn Madieu * @dev: device pointer 79*dc67521cSJohn Madieu * @syscon: regmap for calibration values 80*dc67521cSJohn Madieu * @zone: thermal zone device 81*dc67521cSJohn Madieu * @rstc: reset control 82*dc67521cSJohn Madieu * @trmval0: calibration value 0 (b) 83*dc67521cSJohn Madieu * @trmval1: calibration value 1 (c) 84*dc67521cSJohn Madieu * @trim_offset: offset for trim registers in syscon 85*dc67521cSJohn Madieu * @lock: protects hardware access during conversions 86*dc67521cSJohn Madieu */ 87*dc67521cSJohn Madieu struct rzg3e_thermal_priv { 88*dc67521cSJohn Madieu void __iomem *base; 89*dc67521cSJohn Madieu struct device *dev; 90*dc67521cSJohn Madieu struct regmap *syscon; 91*dc67521cSJohn Madieu struct thermal_zone_device *zone; 92*dc67521cSJohn Madieu struct reset_control *rstc; 93*dc67521cSJohn Madieu u16 trmval0; 94*dc67521cSJohn Madieu u16 trmval1; 95*dc67521cSJohn Madieu u32 trim_offset; 96*dc67521cSJohn Madieu struct mutex lock; 97*dc67521cSJohn Madieu }; 98*dc67521cSJohn Madieu 99*dc67521cSJohn Madieu static int rzg3e_thermal_power_on(struct rzg3e_thermal_priv *priv) 100*dc67521cSJohn Madieu { 101*dc67521cSJohn Madieu u32 val; 102*dc67521cSJohn Madieu int ret; 103*dc67521cSJohn Madieu 104*dc67521cSJohn Madieu /* Clear any pending interrupts */ 105*dc67521cSJohn Madieu writel(TSU_SICR_ADCLR | TSU_SICR_CMPCLR, priv->base + TSU_SICR); 106*dc67521cSJohn Madieu 107*dc67521cSJohn Madieu /* Disable all interrupts during setup */ 108*dc67521cSJohn Madieu writel(0, priv->base + TSU_SIER); 109*dc67521cSJohn Madieu 110*dc67521cSJohn Madieu /* 111*dc67521cSJohn Madieu * Power-on sequence per datasheet 7.11.9.1: 112*dc67521cSJohn Madieu * SOC_TS_EN must be set at same time or before EN_TS and ADC_PD_TS 113*dc67521cSJohn Madieu */ 114*dc67521cSJohn Madieu val = TSU_SSUSR_SOC_TS_EN | TSU_SSUSR_EN_TS; 115*dc67521cSJohn Madieu writel(val, priv->base + TSU_SSUSR); 116*dc67521cSJohn Madieu 117*dc67521cSJohn Madieu /* Wait for sensor stabilization per datasheet 7.11.7.1 */ 118*dc67521cSJohn Madieu usleep_range(TSU_POWERUP_TIME_US, TSU_POWERUP_TIME_US + 10); 119*dc67521cSJohn Madieu 120*dc67521cSJohn Madieu /* Configure for average mode with 8 samples */ 121*dc67521cSJohn Madieu val = TSU_SOSR1_OUTSEL | TSU_SOSR1_ADCT_8; 122*dc67521cSJohn Madieu writel(val, priv->base + TSU_SOSR1); 123*dc67521cSJohn Madieu 124*dc67521cSJohn Madieu /* Ensure we're in single scan mode (default) */ 125*dc67521cSJohn Madieu val = readl(priv->base + TSU_SOSR1); 126*dc67521cSJohn Madieu if (val & TSU_SOSR1_ADCS) { 127*dc67521cSJohn Madieu dev_err(priv->dev, "Invalid scan mode setting\n"); 128*dc67521cSJohn Madieu return -EINVAL; 129*dc67521cSJohn Madieu } 130*dc67521cSJohn Madieu 131*dc67521cSJohn Madieu /* Wait for any ongoing conversion to complete */ 132*dc67521cSJohn Madieu ret = readl_poll_timeout(priv->base + TSU_SSR, val, 133*dc67521cSJohn Madieu !(val & TSU_SSR_CONV), 134*dc67521cSJohn Madieu TSU_POLL_DELAY_US, 135*dc67521cSJohn Madieu USEC_PER_MSEC); 136*dc67521cSJohn Madieu if (ret) { 137*dc67521cSJohn Madieu dev_err(priv->dev, "Timeout waiting for conversion\n"); 138*dc67521cSJohn Madieu return ret; 139*dc67521cSJohn Madieu } 140*dc67521cSJohn Madieu 141*dc67521cSJohn Madieu return 0; 142*dc67521cSJohn Madieu } 143*dc67521cSJohn Madieu 144*dc67521cSJohn Madieu static void rzg3e_thermal_power_off(struct rzg3e_thermal_priv *priv) 145*dc67521cSJohn Madieu { 146*dc67521cSJohn Madieu /* Disable all interrupts */ 147*dc67521cSJohn Madieu writel(0, priv->base + TSU_SIER); 148*dc67521cSJohn Madieu 149*dc67521cSJohn Madieu /* Clear pending interrupts */ 150*dc67521cSJohn Madieu writel(TSU_SICR_ADCLR | TSU_SICR_CMPCLR, priv->base + TSU_SICR); 151*dc67521cSJohn Madieu 152*dc67521cSJohn Madieu /* Power down sequence per datasheet */ 153*dc67521cSJohn Madieu writel(TSU_SSUSR_ADC_PD_TS, priv->base + TSU_SSUSR); 154*dc67521cSJohn Madieu } 155*dc67521cSJohn Madieu 156*dc67521cSJohn Madieu /* 157*dc67521cSJohn Madieu * Convert 12-bit sensor code to temperature in millicelsius 158*dc67521cSJohn Madieu * Formula from datasheet 7.11.7.8: 159*dc67521cSJohn Madieu * T(°C) = ((e - d) / (c - b)) * (a - b) + d 160*dc67521cSJohn Madieu * where: a = sensor code, b = trmval0, c = trmval1, d = -41, e = 126 161*dc67521cSJohn Madieu */ 162*dc67521cSJohn Madieu static int rzg3e_thermal_code_to_temp(struct rzg3e_thermal_priv *priv, u16 code) 163*dc67521cSJohn Madieu { 164*dc67521cSJohn Madieu int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE; 165*dc67521cSJohn Madieu int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE; 166*dc67521cSJohn Madieu s64 numerator, denominator; 167*dc67521cSJohn Madieu int temp_mc; 168*dc67521cSJohn Madieu 169*dc67521cSJohn Madieu numerator = (temp_e_mc - temp_d_mc) * (s64)(code - priv->trmval0); 170*dc67521cSJohn Madieu denominator = priv->trmval1 - priv->trmval0; 171*dc67521cSJohn Madieu 172*dc67521cSJohn Madieu temp_mc = div64_s64(numerator, denominator) + temp_d_mc; 173*dc67521cSJohn Madieu 174*dc67521cSJohn Madieu return clamp(temp_mc, temp_d_mc, temp_e_mc); 175*dc67521cSJohn Madieu } 176*dc67521cSJohn Madieu 177*dc67521cSJohn Madieu /* 178*dc67521cSJohn Madieu * Convert temperature in millicelsius to 12-bit sensor code 179*dc67521cSJohn Madieu * Formula from datasheet 7.11.7.9 (inverse of above) 180*dc67521cSJohn Madieu */ 181*dc67521cSJohn Madieu static u16 rzg3e_thermal_temp_to_code(struct rzg3e_thermal_priv *priv, int temp_mc) 182*dc67521cSJohn Madieu { 183*dc67521cSJohn Madieu int temp_e_mc = TSU_TEMP_E * MILLIDEGREE_PER_DEGREE; 184*dc67521cSJohn Madieu int temp_d_mc = TSU_TEMP_D * MILLIDEGREE_PER_DEGREE; 185*dc67521cSJohn Madieu s64 numerator, denominator; 186*dc67521cSJohn Madieu s64 code; 187*dc67521cSJohn Madieu 188*dc67521cSJohn Madieu numerator = (temp_mc - temp_d_mc) * (priv->trmval1 - priv->trmval0); 189*dc67521cSJohn Madieu denominator = temp_e_mc - temp_d_mc; 190*dc67521cSJohn Madieu 191*dc67521cSJohn Madieu code = div64_s64(numerator, denominator) + priv->trmval0; 192*dc67521cSJohn Madieu 193*dc67521cSJohn Madieu return clamp_val(code, 0, TSU_CODE_MAX); 194*dc67521cSJohn Madieu } 195*dc67521cSJohn Madieu 196*dc67521cSJohn Madieu static int rzg3e_thermal_get_temp(struct thermal_zone_device *tz, int *temp) 197*dc67521cSJohn Madieu { 198*dc67521cSJohn Madieu struct rzg3e_thermal_priv *priv = thermal_zone_device_priv(tz); 199*dc67521cSJohn Madieu u32 status, code; 200*dc67521cSJohn Madieu int ret, timeout; 201*dc67521cSJohn Madieu 202*dc67521cSJohn Madieu ret = pm_runtime_resume_and_get(priv->dev); 203*dc67521cSJohn Madieu if (ret < 0) 204*dc67521cSJohn Madieu return ret; 205*dc67521cSJohn Madieu 206*dc67521cSJohn Madieu guard(mutex)(&priv->lock); 207*dc67521cSJohn Madieu 208*dc67521cSJohn Madieu /* Clear any previous conversion status */ 209*dc67521cSJohn Madieu writel(TSU_SICR_ADCLR, priv->base + TSU_SICR); 210*dc67521cSJohn Madieu 211*dc67521cSJohn Madieu /* Start single conversion */ 212*dc67521cSJohn Madieu writel(TSU_STRGR_ADST, priv->base + TSU_STRGR); 213*dc67521cSJohn Madieu 214*dc67521cSJohn Madieu /* Wait for conversion completion - 8 samples at ~50us each */ 215*dc67521cSJohn Madieu timeout = TSU_CONV_TIME_US * 8 * 2; /* Double for margin */ 216*dc67521cSJohn Madieu ret = readl_poll_timeout(priv->base + TSU_SISR, status, 217*dc67521cSJohn Madieu status & TSU_SISR_ADF, 218*dc67521cSJohn Madieu TSU_POLL_DELAY_US, timeout); 219*dc67521cSJohn Madieu if (ret) { 220*dc67521cSJohn Madieu dev_err(priv->dev, "Conversion timeout (status=0x%08x)\n", status); 221*dc67521cSJohn Madieu goto out; 222*dc67521cSJohn Madieu } 223*dc67521cSJohn Madieu 224*dc67521cSJohn Madieu /* Read the averaged result and clear the complete flag */ 225*dc67521cSJohn Madieu code = readl(priv->base + TSU_SCRR) & TSU_SCRR_OUT12BIT_TS; 226*dc67521cSJohn Madieu writel(TSU_SICR_ADCLR, priv->base + TSU_SICR); 227*dc67521cSJohn Madieu 228*dc67521cSJohn Madieu /* Convert to temperature */ 229*dc67521cSJohn Madieu *temp = rzg3e_thermal_code_to_temp(priv, code); 230*dc67521cSJohn Madieu 231*dc67521cSJohn Madieu dev_dbg(priv->dev, "temp=%d mC (%d.%03d°C), code=0x%03x\n", 232*dc67521cSJohn Madieu *temp, *temp / 1000, abs(*temp) % 1000, code); 233*dc67521cSJohn Madieu 234*dc67521cSJohn Madieu out: 235*dc67521cSJohn Madieu pm_runtime_mark_last_busy(priv->dev); 236*dc67521cSJohn Madieu pm_runtime_put_autosuspend(priv->dev); 237*dc67521cSJohn Madieu return ret; 238*dc67521cSJohn Madieu } 239*dc67521cSJohn Madieu 240*dc67521cSJohn Madieu static int rzg3e_thermal_set_trips(struct thermal_zone_device *tz, 241*dc67521cSJohn Madieu int low, int high) 242*dc67521cSJohn Madieu { 243*dc67521cSJohn Madieu struct rzg3e_thermal_priv *priv = thermal_zone_device_priv(tz); 244*dc67521cSJohn Madieu u16 low_code, high_code; 245*dc67521cSJohn Madieu u32 val; 246*dc67521cSJohn Madieu int ret; 247*dc67521cSJohn Madieu 248*dc67521cSJohn Madieu /* Hardware requires low < high */ 249*dc67521cSJohn Madieu if (low >= high) 250*dc67521cSJohn Madieu return -EINVAL; 251*dc67521cSJohn Madieu 252*dc67521cSJohn Madieu ret = pm_runtime_resume_and_get(priv->dev); 253*dc67521cSJohn Madieu if (ret < 0) 254*dc67521cSJohn Madieu return ret; 255*dc67521cSJohn Madieu 256*dc67521cSJohn Madieu guard(mutex)(&priv->lock); 257*dc67521cSJohn Madieu 258*dc67521cSJohn Madieu /* Convert temperatures to codes */ 259*dc67521cSJohn Madieu low_code = rzg3e_thermal_temp_to_code(priv, low); 260*dc67521cSJohn Madieu high_code = rzg3e_thermal_temp_to_code(priv, high); 261*dc67521cSJohn Madieu 262*dc67521cSJohn Madieu dev_dbg(priv->dev, "set_trips: low=%d high=%d (codes: 0x%03x/0x%03x)\n", 263*dc67521cSJohn Madieu low, high, low_code, high_code); 264*dc67521cSJohn Madieu 265*dc67521cSJohn Madieu /* Disable comparison during reconfiguration */ 266*dc67521cSJohn Madieu writel(0, priv->base + TSU_SIER); 267*dc67521cSJohn Madieu writel(0, priv->base + TSU_CMSR); 268*dc67521cSJohn Madieu 269*dc67521cSJohn Madieu /* Clear any pending comparison interrupts */ 270*dc67521cSJohn Madieu writel(TSU_SICR_CMPCLR, priv->base + TSU_SICR); 271*dc67521cSJohn Madieu 272*dc67521cSJohn Madieu /* Set trip points */ 273*dc67521cSJohn Madieu writel(low_code, priv->base + TSU_LLSR); 274*dc67521cSJohn Madieu writel(high_code, priv->base + TSU_ULSR); 275*dc67521cSJohn Madieu 276*dc67521cSJohn Madieu /* 277*dc67521cSJohn Madieu * Ensure OUTSEL is set for comparison per datasheet 7.11.7.4 278*dc67521cSJohn Madieu * Comparison uses averaged data 279*dc67521cSJohn Madieu */ 280*dc67521cSJohn Madieu val = readl(priv->base + TSU_SOSR1); 281*dc67521cSJohn Madieu val |= TSU_SOSR1_OUTSEL; 282*dc67521cSJohn Madieu writel(val, priv->base + TSU_SOSR1); 283*dc67521cSJohn Madieu 284*dc67521cSJohn Madieu /* Enable comparison with "out of range" mode (CMPCOND=0) */ 285*dc67521cSJohn Madieu writel(TSU_CMSR_CMPEN, priv->base + TSU_CMSR); 286*dc67521cSJohn Madieu 287*dc67521cSJohn Madieu /* Unmask compare IRQ and start a conversion to evaluate window */ 288*dc67521cSJohn Madieu writel(TSU_SIER_CMPIE, priv->base + TSU_SIER); 289*dc67521cSJohn Madieu writel(TSU_STRGR_ADST, priv->base + TSU_STRGR); 290*dc67521cSJohn Madieu 291*dc67521cSJohn Madieu pm_runtime_mark_last_busy(priv->dev); 292*dc67521cSJohn Madieu pm_runtime_put_autosuspend(priv->dev); 293*dc67521cSJohn Madieu 294*dc67521cSJohn Madieu return 0; 295*dc67521cSJohn Madieu } 296*dc67521cSJohn Madieu 297*dc67521cSJohn Madieu static irqreturn_t rzg3e_thermal_irq_thread(int irq, void *data) 298*dc67521cSJohn Madieu { 299*dc67521cSJohn Madieu struct rzg3e_thermal_priv *priv = data; 300*dc67521cSJohn Madieu 301*dc67521cSJohn Madieu dev_dbg(priv->dev, "Temperature threshold crossed\n"); 302*dc67521cSJohn Madieu 303*dc67521cSJohn Madieu /* Notify thermal framework to re-evaluate trip points */ 304*dc67521cSJohn Madieu thermal_zone_device_update(priv->zone, THERMAL_TRIP_VIOLATED); 305*dc67521cSJohn Madieu 306*dc67521cSJohn Madieu return IRQ_HANDLED; 307*dc67521cSJohn Madieu } 308*dc67521cSJohn Madieu 309*dc67521cSJohn Madieu static irqreturn_t rzg3e_thermal_irq(int irq, void *data) 310*dc67521cSJohn Madieu { 311*dc67521cSJohn Madieu struct rzg3e_thermal_priv *priv = data; 312*dc67521cSJohn Madieu u32 status; 313*dc67521cSJohn Madieu 314*dc67521cSJohn Madieu status = readl(priv->base + TSU_SISR); 315*dc67521cSJohn Madieu 316*dc67521cSJohn Madieu /* Check if comparison interrupt occurred */ 317*dc67521cSJohn Madieu if (status & TSU_SISR_CMPF) { 318*dc67521cSJohn Madieu /* Clear irq flag and disable interrupt until reconfigured */ 319*dc67521cSJohn Madieu writel(TSU_SICR_CMPCLR, priv->base + TSU_SICR); 320*dc67521cSJohn Madieu writel(0, priv->base + TSU_SIER); 321*dc67521cSJohn Madieu 322*dc67521cSJohn Madieu return IRQ_WAKE_THREAD; 323*dc67521cSJohn Madieu } 324*dc67521cSJohn Madieu 325*dc67521cSJohn Madieu return IRQ_NONE; 326*dc67521cSJohn Madieu } 327*dc67521cSJohn Madieu 328*dc67521cSJohn Madieu static const struct thermal_zone_device_ops rzg3e_tz_ops = { 329*dc67521cSJohn Madieu .get_temp = rzg3e_thermal_get_temp, 330*dc67521cSJohn Madieu .set_trips = rzg3e_thermal_set_trips, 331*dc67521cSJohn Madieu }; 332*dc67521cSJohn Madieu 333*dc67521cSJohn Madieu static int rzg3e_thermal_get_calibration(struct rzg3e_thermal_priv *priv) 334*dc67521cSJohn Madieu { 335*dc67521cSJohn Madieu u32 val; 336*dc67521cSJohn Madieu int ret; 337*dc67521cSJohn Madieu 338*dc67521cSJohn Madieu /* Read calibration values from syscon */ 339*dc67521cSJohn Madieu ret = regmap_read(priv->syscon, priv->trim_offset, &val); 340*dc67521cSJohn Madieu if (ret) 341*dc67521cSJohn Madieu return ret; 342*dc67521cSJohn Madieu priv->trmval0 = val & GENMASK(11, 0); 343*dc67521cSJohn Madieu 344*dc67521cSJohn Madieu ret = regmap_read(priv->syscon, priv->trim_offset + 4, &val); 345*dc67521cSJohn Madieu if (ret) 346*dc67521cSJohn Madieu return ret; 347*dc67521cSJohn Madieu priv->trmval1 = val & GENMASK(11, 0); 348*dc67521cSJohn Madieu 349*dc67521cSJohn Madieu /* Validate calibration data */ 350*dc67521cSJohn Madieu if (!priv->trmval0 || !priv->trmval1 || 351*dc67521cSJohn Madieu priv->trmval0 == priv->trmval1 || 352*dc67521cSJohn Madieu priv->trmval0 == 0xFFF || priv->trmval1 == 0xFFF) { 353*dc67521cSJohn Madieu dev_err(priv->dev, "Invalid calibration: b=0x%03x, c=0x%03x\n", 354*dc67521cSJohn Madieu priv->trmval0, priv->trmval1); 355*dc67521cSJohn Madieu return -EINVAL; 356*dc67521cSJohn Madieu } 357*dc67521cSJohn Madieu 358*dc67521cSJohn Madieu dev_dbg(priv->dev, "Calibration: b=0x%03x (%u), c=0x%03x (%u)\n", 359*dc67521cSJohn Madieu priv->trmval0, priv->trmval0, priv->trmval1, priv->trmval1); 360*dc67521cSJohn Madieu 361*dc67521cSJohn Madieu return 0; 362*dc67521cSJohn Madieu } 363*dc67521cSJohn Madieu 364*dc67521cSJohn Madieu static int rzg3e_thermal_parse_dt(struct rzg3e_thermal_priv *priv) 365*dc67521cSJohn Madieu { 366*dc67521cSJohn Madieu struct device_node *np = priv->dev->of_node; 367*dc67521cSJohn Madieu u32 offset; 368*dc67521cSJohn Madieu 369*dc67521cSJohn Madieu priv->syscon = syscon_regmap_lookup_by_phandle_args(np, "renesas,tsu-trim", 1, &offset); 370*dc67521cSJohn Madieu if (IS_ERR(priv->syscon)) 371*dc67521cSJohn Madieu return dev_err_probe(priv->dev, PTR_ERR(priv->syscon), 372*dc67521cSJohn Madieu "Failed to parse renesas,tsu-trim\n"); 373*dc67521cSJohn Madieu 374*dc67521cSJohn Madieu priv->trim_offset = offset; 375*dc67521cSJohn Madieu return 0; 376*dc67521cSJohn Madieu } 377*dc67521cSJohn Madieu 378*dc67521cSJohn Madieu static int rzg3e_thermal_probe(struct platform_device *pdev) 379*dc67521cSJohn Madieu { 380*dc67521cSJohn Madieu struct device *dev = &pdev->dev; 381*dc67521cSJohn Madieu struct rzg3e_thermal_priv *priv; 382*dc67521cSJohn Madieu struct clk *clk; 383*dc67521cSJohn Madieu int irq, ret; 384*dc67521cSJohn Madieu 385*dc67521cSJohn Madieu priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 386*dc67521cSJohn Madieu if (!priv) 387*dc67521cSJohn Madieu return -ENOMEM; 388*dc67521cSJohn Madieu 389*dc67521cSJohn Madieu priv->dev = dev; 390*dc67521cSJohn Madieu ret = devm_mutex_init(dev, &priv->lock); 391*dc67521cSJohn Madieu if (ret) 392*dc67521cSJohn Madieu return ret; 393*dc67521cSJohn Madieu platform_set_drvdata(pdev, priv); 394*dc67521cSJohn Madieu 395*dc67521cSJohn Madieu priv->base = devm_platform_ioremap_resource(pdev, 0); 396*dc67521cSJohn Madieu if (IS_ERR(priv->base)) 397*dc67521cSJohn Madieu return PTR_ERR(priv->base); 398*dc67521cSJohn Madieu 399*dc67521cSJohn Madieu /* Parse device tree for trim register info */ 400*dc67521cSJohn Madieu ret = rzg3e_thermal_parse_dt(priv); 401*dc67521cSJohn Madieu if (ret) 402*dc67521cSJohn Madieu return ret; 403*dc67521cSJohn Madieu 404*dc67521cSJohn Madieu /* Get clock to verify frequency - clock is managed by power domain */ 405*dc67521cSJohn Madieu clk = devm_clk_get(dev, NULL); 406*dc67521cSJohn Madieu if (IS_ERR(clk)) 407*dc67521cSJohn Madieu return dev_err_probe(dev, PTR_ERR(clk), 408*dc67521cSJohn Madieu "Failed to get clock\n"); 409*dc67521cSJohn Madieu 410*dc67521cSJohn Madieu if (clk_get_rate(clk) < TSU_MIN_CLOCK_RATE) 411*dc67521cSJohn Madieu return dev_err_probe(dev, -EINVAL, 412*dc67521cSJohn Madieu "Clock rate %lu Hz too low (min %u Hz)\n", 413*dc67521cSJohn Madieu clk_get_rate(clk), TSU_MIN_CLOCK_RATE); 414*dc67521cSJohn Madieu 415*dc67521cSJohn Madieu priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL); 416*dc67521cSJohn Madieu if (IS_ERR(priv->rstc)) 417*dc67521cSJohn Madieu return dev_err_probe(dev, PTR_ERR(priv->rstc), 418*dc67521cSJohn Madieu "Failed to get/deassert reset control\n"); 419*dc67521cSJohn Madieu 420*dc67521cSJohn Madieu /* Get calibration data */ 421*dc67521cSJohn Madieu ret = rzg3e_thermal_get_calibration(priv); 422*dc67521cSJohn Madieu if (ret) 423*dc67521cSJohn Madieu return dev_err_probe(dev, ret, 424*dc67521cSJohn Madieu "Failed to get valid calibration data\n"); 425*dc67521cSJohn Madieu 426*dc67521cSJohn Madieu /* Get comparison interrupt */ 427*dc67521cSJohn Madieu irq = platform_get_irq_byname(pdev, "adcmpi"); 428*dc67521cSJohn Madieu if (irq < 0) 429*dc67521cSJohn Madieu return irq; 430*dc67521cSJohn Madieu 431*dc67521cSJohn Madieu /* Enable runtime PM */ 432*dc67521cSJohn Madieu pm_runtime_set_autosuspend_delay(dev, 1000); 433*dc67521cSJohn Madieu pm_runtime_use_autosuspend(dev); 434*dc67521cSJohn Madieu devm_pm_runtime_enable(dev); 435*dc67521cSJohn Madieu 436*dc67521cSJohn Madieu /* Initial hardware setup */ 437*dc67521cSJohn Madieu ret = pm_runtime_resume_and_get(dev); 438*dc67521cSJohn Madieu if (ret < 0) 439*dc67521cSJohn Madieu return dev_err_probe(dev, ret, "Runtime resume failed\n"); 440*dc67521cSJohn Madieu 441*dc67521cSJohn Madieu /* Register thermal zone - this will trigger DT parsing */ 442*dc67521cSJohn Madieu priv->zone = devm_thermal_of_zone_register(dev, 0, priv, &rzg3e_tz_ops); 443*dc67521cSJohn Madieu if (IS_ERR(priv->zone)) { 444*dc67521cSJohn Madieu ret = PTR_ERR(priv->zone); 445*dc67521cSJohn Madieu dev_err(dev, "Failed to register thermal zone: %d\n", ret); 446*dc67521cSJohn Madieu goto err_pm_put; 447*dc67521cSJohn Madieu } 448*dc67521cSJohn Madieu 449*dc67521cSJohn Madieu /* Request threaded IRQ for comparison interrupt */ 450*dc67521cSJohn Madieu ret = devm_request_threaded_irq(dev, irq, rzg3e_thermal_irq, 451*dc67521cSJohn Madieu rzg3e_thermal_irq_thread, 452*dc67521cSJohn Madieu IRQF_ONESHOT, "rzg3e_thermal", priv); 453*dc67521cSJohn Madieu if (ret) { 454*dc67521cSJohn Madieu dev_err(dev, "Failed to request IRQ: %d\n", ret); 455*dc67521cSJohn Madieu goto err_pm_put; 456*dc67521cSJohn Madieu } 457*dc67521cSJohn Madieu 458*dc67521cSJohn Madieu /* Add hwmon sysfs interface */ 459*dc67521cSJohn Madieu ret = devm_thermal_add_hwmon_sysfs(dev, priv->zone); 460*dc67521cSJohn Madieu if (ret) 461*dc67521cSJohn Madieu dev_warn(dev, "Failed to add hwmon sysfs attributes\n"); 462*dc67521cSJohn Madieu 463*dc67521cSJohn Madieu pm_runtime_mark_last_busy(dev); 464*dc67521cSJohn Madieu pm_runtime_put_autosuspend(dev); 465*dc67521cSJohn Madieu 466*dc67521cSJohn Madieu dev_info(dev, "RZ/G3E thermal sensor registered\n"); 467*dc67521cSJohn Madieu 468*dc67521cSJohn Madieu return 0; 469*dc67521cSJohn Madieu 470*dc67521cSJohn Madieu err_pm_put: 471*dc67521cSJohn Madieu pm_runtime_put_sync(dev); 472*dc67521cSJohn Madieu return ret; 473*dc67521cSJohn Madieu } 474*dc67521cSJohn Madieu 475*dc67521cSJohn Madieu static int rzg3e_thermal_runtime_suspend(struct device *dev) 476*dc67521cSJohn Madieu { 477*dc67521cSJohn Madieu struct rzg3e_thermal_priv *priv = dev_get_drvdata(dev); 478*dc67521cSJohn Madieu 479*dc67521cSJohn Madieu rzg3e_thermal_power_off(priv); 480*dc67521cSJohn Madieu return 0; 481*dc67521cSJohn Madieu } 482*dc67521cSJohn Madieu 483*dc67521cSJohn Madieu static int rzg3e_thermal_runtime_resume(struct device *dev) 484*dc67521cSJohn Madieu { 485*dc67521cSJohn Madieu struct rzg3e_thermal_priv *priv = dev_get_drvdata(dev); 486*dc67521cSJohn Madieu 487*dc67521cSJohn Madieu return rzg3e_thermal_power_on(priv); 488*dc67521cSJohn Madieu } 489*dc67521cSJohn Madieu 490*dc67521cSJohn Madieu static int rzg3e_thermal_suspend(struct device *dev) 491*dc67521cSJohn Madieu { 492*dc67521cSJohn Madieu struct rzg3e_thermal_priv *priv = dev_get_drvdata(dev); 493*dc67521cSJohn Madieu 494*dc67521cSJohn Madieu /* If device is active, power it off */ 495*dc67521cSJohn Madieu if (pm_runtime_active(dev)) 496*dc67521cSJohn Madieu rzg3e_thermal_power_off(priv); 497*dc67521cSJohn Madieu 498*dc67521cSJohn Madieu /* Assert reset to ensure clean state after resume */ 499*dc67521cSJohn Madieu reset_control_assert(priv->rstc); 500*dc67521cSJohn Madieu 501*dc67521cSJohn Madieu return 0; 502*dc67521cSJohn Madieu } 503*dc67521cSJohn Madieu 504*dc67521cSJohn Madieu static int rzg3e_thermal_resume(struct device *dev) 505*dc67521cSJohn Madieu { 506*dc67521cSJohn Madieu struct rzg3e_thermal_priv *priv = dev_get_drvdata(dev); 507*dc67521cSJohn Madieu int ret; 508*dc67521cSJohn Madieu 509*dc67521cSJohn Madieu /* Deassert reset */ 510*dc67521cSJohn Madieu ret = reset_control_deassert(priv->rstc); 511*dc67521cSJohn Madieu if (ret) { 512*dc67521cSJohn Madieu dev_err(dev, "Failed to deassert reset: %d\n", ret); 513*dc67521cSJohn Madieu return ret; 514*dc67521cSJohn Madieu } 515*dc67521cSJohn Madieu 516*dc67521cSJohn Madieu /* If device was active before suspend, power it back on */ 517*dc67521cSJohn Madieu if (pm_runtime_active(dev)) 518*dc67521cSJohn Madieu return rzg3e_thermal_power_on(priv); 519*dc67521cSJohn Madieu 520*dc67521cSJohn Madieu return 0; 521*dc67521cSJohn Madieu } 522*dc67521cSJohn Madieu 523*dc67521cSJohn Madieu static const struct dev_pm_ops rzg3e_thermal_pm_ops = { 524*dc67521cSJohn Madieu RUNTIME_PM_OPS(rzg3e_thermal_runtime_suspend, 525*dc67521cSJohn Madieu rzg3e_thermal_runtime_resume, NULL) 526*dc67521cSJohn Madieu SYSTEM_SLEEP_PM_OPS(rzg3e_thermal_suspend, rzg3e_thermal_resume) 527*dc67521cSJohn Madieu }; 528*dc67521cSJohn Madieu 529*dc67521cSJohn Madieu static const struct of_device_id rzg3e_thermal_dt_ids[] = { 530*dc67521cSJohn Madieu { .compatible = "renesas,r9a09g047-tsu" }, 531*dc67521cSJohn Madieu { /* sentinel */ } 532*dc67521cSJohn Madieu }; 533*dc67521cSJohn Madieu MODULE_DEVICE_TABLE(of, rzg3e_thermal_dt_ids); 534*dc67521cSJohn Madieu 535*dc67521cSJohn Madieu static struct platform_driver rzg3e_thermal_driver = { 536*dc67521cSJohn Madieu .driver = { 537*dc67521cSJohn Madieu .name = "rzg3e_thermal", 538*dc67521cSJohn Madieu .of_match_table = rzg3e_thermal_dt_ids, 539*dc67521cSJohn Madieu .pm = pm_ptr(&rzg3e_thermal_pm_ops), 540*dc67521cSJohn Madieu }, 541*dc67521cSJohn Madieu .probe = rzg3e_thermal_probe, 542*dc67521cSJohn Madieu }; 543*dc67521cSJohn Madieu module_platform_driver(rzg3e_thermal_driver); 544*dc67521cSJohn Madieu 545*dc67521cSJohn Madieu MODULE_DESCRIPTION("Renesas RZ/G3E TSU Thermal Sensor Driver"); 546*dc67521cSJohn Madieu MODULE_AUTHOR("John Madieu <john.madieu.xa@bp.renesas.com>"); 547*dc67521cSJohn Madieu MODULE_LICENSE("GPL"); 548