1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Renesas RZ/G2L TSU Thermal Sensor Driver 4 * 5 * Copyright (C) 2021 Renesas Electronics Corporation 6 */ 7 #include <linux/delay.h> 8 #include <linux/err.h> 9 #include <linux/io.h> 10 #include <linux/iopoll.h> 11 #include <linux/math.h> 12 #include <linux/module.h> 13 #include <linux/of_device.h> 14 #include <linux/platform_device.h> 15 #include <linux/pm_runtime.h> 16 #include <linux/reset.h> 17 #include <linux/thermal.h> 18 #include <linux/units.h> 19 20 #include "thermal_hwmon.h" 21 22 #define CTEMP_MASK 0xFFF 23 24 /* default calibration values, if FUSE values are missing */ 25 #define SW_CALIB0_VAL 3148 26 #define SW_CALIB1_VAL 503 27 28 /* Register offsets */ 29 #define TSU_SM 0x00 30 #define TSU_ST 0x04 31 #define TSU_SAD 0x0C 32 #define TSU_SS 0x10 33 34 #define OTPTSUTRIM_REG(n) (0x18 + ((n) * 0x4)) 35 36 /* Sensor Mode Register(TSU_SM) */ 37 #define TSU_SM_EN_TS BIT(0) 38 #define TSU_SM_ADC_EN_TS BIT(1) 39 #define TSU_SM_NORMAL_MODE (TSU_SM_EN_TS | TSU_SM_ADC_EN_TS) 40 41 /* TSU_ST bits */ 42 #define TSU_ST_START BIT(0) 43 44 #define TSU_SS_CONV_RUNNING BIT(0) 45 46 #define TS_CODE_AVE_SCALE(x) ((x) * 1000000) 47 #define MCELSIUS(temp) ((temp) * MILLIDEGREE_PER_DEGREE) 48 #define TS_CODE_CAP_TIMES 8 /* Capture times */ 49 50 #define RZG2L_THERMAL_GRAN 500 /* milli Celsius */ 51 #define RZG2L_TSU_SS_TIMEOUT_US 1000 52 53 #define CURVATURE_CORRECTION_CONST 13 54 55 struct rzg2l_thermal_priv { 56 struct device *dev; 57 void __iomem *base; 58 struct thermal_zone_device *zone; 59 struct reset_control *rstc; 60 u32 calib0, calib1; 61 }; 62 63 static inline u32 rzg2l_thermal_read(struct rzg2l_thermal_priv *priv, u32 reg) 64 { 65 return ioread32(priv->base + reg); 66 } 67 68 static inline void rzg2l_thermal_write(struct rzg2l_thermal_priv *priv, u32 reg, 69 u32 data) 70 { 71 iowrite32(data, priv->base + reg); 72 } 73 74 static int rzg2l_thermal_get_temp(void *devdata, int *temp) 75 { 76 struct rzg2l_thermal_priv *priv = devdata; 77 u32 result = 0, dsensor, ts_code_ave; 78 int val, i; 79 80 for (i = 0; i < TS_CODE_CAP_TIMES ; i++) { 81 /* TSU repeats measurement at 20 microseconds intervals and 82 * automatically updates the results of measurement. As per 83 * the HW manual for measuring temperature we need to read 8 84 * values consecutively and then take the average. 85 * ts_code_ave = (ts_code[0] + ⋯ + ts_code[7]) / 8 86 */ 87 result += rzg2l_thermal_read(priv, TSU_SAD) & CTEMP_MASK; 88 usleep_range(20, 30); 89 } 90 91 ts_code_ave = result / TS_CODE_CAP_TIMES; 92 93 /* Calculate actual sensor value by applying curvature correction formula 94 * dsensor = ts_code_ave / (1 + ts_code_ave * 0.000013). Here we are doing 95 * integer calculation by scaling all the values by 1000000. 96 */ 97 dsensor = TS_CODE_AVE_SCALE(ts_code_ave) / 98 (TS_CODE_AVE_SCALE(1) + (ts_code_ave * CURVATURE_CORRECTION_CONST)); 99 100 /* The temperature Tj is calculated by the formula 101 * Tj = (dsensor − calib1) * 165/ (calib0 − calib1) − 40 102 * where calib0 and calib1 are the caliberation values. 103 */ 104 val = ((dsensor - priv->calib1) * (MCELSIUS(165) / 105 (priv->calib0 - priv->calib1))) - MCELSIUS(40); 106 107 *temp = roundup(val, RZG2L_THERMAL_GRAN); 108 109 return 0; 110 } 111 112 static const struct thermal_zone_of_device_ops rzg2l_tz_of_ops = { 113 .get_temp = rzg2l_thermal_get_temp, 114 }; 115 116 static int rzg2l_thermal_init(struct rzg2l_thermal_priv *priv) 117 { 118 u32 reg_val; 119 120 rzg2l_thermal_write(priv, TSU_SM, TSU_SM_NORMAL_MODE); 121 rzg2l_thermal_write(priv, TSU_ST, 0); 122 123 /* Before setting the START bit, TSU should be in normal operating 124 * mode. As per the HW manual, it will take 60 µs to place the TSU 125 * into normal operating mode. 126 */ 127 usleep_range(60, 80); 128 129 reg_val = rzg2l_thermal_read(priv, TSU_ST); 130 reg_val |= TSU_ST_START; 131 rzg2l_thermal_write(priv, TSU_ST, reg_val); 132 133 return readl_poll_timeout(priv->base + TSU_SS, reg_val, 134 reg_val == TSU_SS_CONV_RUNNING, 50, 135 RZG2L_TSU_SS_TIMEOUT_US); 136 } 137 138 static void rzg2l_thermal_reset_assert_pm_disable_put(struct platform_device *pdev) 139 { 140 struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev); 141 142 pm_runtime_put(&pdev->dev); 143 pm_runtime_disable(&pdev->dev); 144 reset_control_assert(priv->rstc); 145 } 146 147 static int rzg2l_thermal_remove(struct platform_device *pdev) 148 { 149 struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev); 150 151 thermal_remove_hwmon_sysfs(priv->zone); 152 rzg2l_thermal_reset_assert_pm_disable_put(pdev); 153 154 return 0; 155 } 156 157 static int rzg2l_thermal_probe(struct platform_device *pdev) 158 { 159 struct thermal_zone_device *zone; 160 struct rzg2l_thermal_priv *priv; 161 struct device *dev = &pdev->dev; 162 int ret; 163 164 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 165 if (!priv) 166 return -ENOMEM; 167 168 priv->base = devm_platform_ioremap_resource(pdev, 0); 169 if (IS_ERR(priv->base)) 170 return PTR_ERR(priv->base); 171 172 priv->dev = dev; 173 priv->rstc = devm_reset_control_get_exclusive(dev, NULL); 174 if (IS_ERR(priv->rstc)) 175 return dev_err_probe(dev, PTR_ERR(priv->rstc), 176 "failed to get cpg reset"); 177 178 ret = reset_control_deassert(priv->rstc); 179 if (ret) 180 return dev_err_probe(dev, ret, "failed to deassert"); 181 182 pm_runtime_enable(dev); 183 pm_runtime_get_sync(dev); 184 185 priv->calib0 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0)); 186 if (!priv->calib0) 187 priv->calib0 = SW_CALIB0_VAL; 188 189 priv->calib1 = rzg2l_thermal_read(priv, OTPTSUTRIM_REG(1)); 190 if (!priv->calib1) 191 priv->calib1 = SW_CALIB1_VAL; 192 193 platform_set_drvdata(pdev, priv); 194 ret = rzg2l_thermal_init(priv); 195 if (ret) { 196 dev_err(dev, "Failed to start TSU"); 197 goto err; 198 } 199 200 zone = devm_thermal_zone_of_sensor_register(dev, 0, priv, 201 &rzg2l_tz_of_ops); 202 if (IS_ERR(zone)) { 203 dev_err(dev, "Can't register thermal zone"); 204 ret = PTR_ERR(zone); 205 goto err; 206 } 207 208 priv->zone = zone; 209 priv->zone->tzp->no_hwmon = false; 210 ret = thermal_add_hwmon_sysfs(priv->zone); 211 if (ret) 212 goto err; 213 214 dev_dbg(dev, "TSU probed with %s caliberation values", 215 rzg2l_thermal_read(priv, OTPTSUTRIM_REG(0)) ? "hw" : "sw"); 216 217 return 0; 218 219 err: 220 rzg2l_thermal_reset_assert_pm_disable_put(pdev); 221 return ret; 222 } 223 224 static const struct of_device_id rzg2l_thermal_dt_ids[] = { 225 { .compatible = "renesas,rzg2l-tsu", }, 226 { /* sentinel */ } 227 }; 228 MODULE_DEVICE_TABLE(of, rzg2l_thermal_dt_ids); 229 230 static struct platform_driver rzg2l_thermal_driver = { 231 .driver = { 232 .name = "rzg2l_thermal", 233 .of_match_table = rzg2l_thermal_dt_ids, 234 }, 235 .probe = rzg2l_thermal_probe, 236 .remove = rzg2l_thermal_remove, 237 }; 238 module_platform_driver(rzg2l_thermal_driver); 239 240 MODULE_DESCRIPTION("Renesas RZ/G2L TSU Thermal Sensor Driver"); 241 MODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); 242 MODULE_LICENSE("GPL v2"); 243