1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Thermal sensor driver for SpacemiT K1 SoC 4 * 5 * Copyright (C) 2026 Shuwei Wu <shuwei.wu@mailbox.org> 6 */ 7 #include <linux/bitfield.h> 8 #include <linux/clk.h> 9 #include <linux/err.h> 10 #include <linux/interrupt.h> 11 #include <linux/io.h> 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/platform_device.h> 16 #include <linux/reset.h> 17 #include <linux/slab.h> 18 #include <linux/thermal.h> 19 20 #include "../thermal_hwmon.h" 21 22 #define K1_TSENSOR_PCTRL_REG 0x00 23 #define K1_TSENSOR_PCTRL_ENABLE BIT(0) 24 #define K1_TSENSOR_PCTRL_TEMP_MODE BIT(3) 25 #define K1_TSENSOR_PCTRL_RAW_SEL BIT(7) 26 27 #define K1_TSENSOR_PCTRL_CTUNE GENMASK(11, 8) 28 #define K1_TSENSOR_PCTRL_SW_CTRL GENMASK(21, 18) 29 #define K1_TSENSOR_PCTRL_HW_AUTO_MODE BIT(23) 30 31 #define K1_TSENSOR_EN_REG 0x08 32 #define K1_TSENSOR_EN_ALL GENMASK(MAX_SENSOR_NUMBER - 1, 0) 33 34 #define K1_TSENSOR_TIME_REG 0x0C 35 #define K1_TSENSOR_TIME_WAIT_REF_CNT GENMASK(3, 0) 36 #define K1_TSENSOR_TIME_ADC_CNT_RST GENMASK(7, 4) 37 #define K1_TSENSOR_TIME_FILTER_PERIOD GENMASK(21, 20) 38 #define K1_TSENSOR_TIME_MASK GENMASK(23, 0) 39 40 #define K1_TSENSOR_INT_CLR_REG 0x10 41 #define K1_TSENSOR_INT_EN_REG 0x14 42 #define K1_TSENSOR_INT_STA_REG 0x18 43 44 #define K1_TSENSOR_INT_EN_MASK BIT(0) 45 #define K1_TSENSOR_INT_MASK(x) (GENMASK(2, 1) << ((x) * 2)) 46 47 #define K1_TSENSOR_DATA_BASE_REG 0x20 48 #define K1_TSENSOR_DATA_REG(x) (K1_TSENSOR_DATA_BASE_REG + ((x) / 2) * 4) 49 #define K1_TSENSOR_DATA_LOW_MASK GENMASK(15, 0) 50 #define K1_TSENSOR_DATA_HIGH_MASK GENMASK(31, 16) 51 52 #define K1_TSENSOR_THRSH_BASE_REG 0x40 53 #define K1_TSENSOR_THRSH_REG(x) (K1_TSENSOR_THRSH_BASE_REG + ((x) * 4)) 54 #define K1_TSENSOR_THRSH_LOW_MASK GENMASK(15, 0) 55 #define K1_TSENSOR_THRSH_HIGH_MASK GENMASK(31, 16) 56 57 #define MAX_SENSOR_NUMBER 5 58 59 /* Hardware offset value required for temperature calculation */ 60 #define TEMPERATURE_OFFSET 278 61 62 struct k1_tsensor_channel { 63 struct k1_tsensor *ts; 64 struct thermal_zone_device *tzd; 65 int id; 66 }; 67 68 struct k1_tsensor { 69 void __iomem *base; 70 struct k1_tsensor_channel ch[MAX_SENSOR_NUMBER]; 71 }; 72 73 static void k1_tsensor_init(struct k1_tsensor *ts) 74 { 75 u32 val; 76 77 /* Disable all the interrupts */ 78 writel(0xffffffff, ts->base + K1_TSENSOR_INT_EN_REG); 79 80 /* Configure ADC sampling time and filter period */ 81 val = readl(ts->base + K1_TSENSOR_TIME_REG); 82 val &= ~K1_TSENSOR_TIME_MASK; 83 val |= K1_TSENSOR_TIME_FILTER_PERIOD | 84 K1_TSENSOR_TIME_ADC_CNT_RST | 85 K1_TSENSOR_TIME_WAIT_REF_CNT; 86 writel(val, ts->base + K1_TSENSOR_TIME_REG); 87 88 /* 89 * Enable all sensors' auto mode, enable dither control, 90 * consecutive mode, and power up sensor. 91 */ 92 val = readl(ts->base + K1_TSENSOR_PCTRL_REG); 93 val &= ~K1_TSENSOR_PCTRL_SW_CTRL; 94 val &= ~K1_TSENSOR_PCTRL_CTUNE; 95 val |= K1_TSENSOR_PCTRL_RAW_SEL | 96 K1_TSENSOR_PCTRL_TEMP_MODE | 97 K1_TSENSOR_PCTRL_HW_AUTO_MODE | 98 K1_TSENSOR_PCTRL_ENABLE; 99 writel(val, ts->base + K1_TSENSOR_PCTRL_REG); 100 101 /* Enable each sensor */ 102 val = readl(ts->base + K1_TSENSOR_EN_REG); 103 val |= K1_TSENSOR_EN_ALL; 104 writel(val, ts->base + K1_TSENSOR_EN_REG); 105 } 106 107 static void k1_tsensor_enable_irq(struct k1_tsensor_channel *ch) 108 { 109 struct k1_tsensor *ts = ch->ts; 110 u32 val; 111 112 val = readl(ts->base + K1_TSENSOR_INT_CLR_REG); 113 val |= K1_TSENSOR_INT_MASK(ch->id); 114 writel(val, ts->base + K1_TSENSOR_INT_CLR_REG); 115 116 val = readl(ts->base + K1_TSENSOR_INT_EN_REG); 117 val &= ~K1_TSENSOR_INT_MASK(ch->id); 118 writel(val, ts->base + K1_TSENSOR_INT_EN_REG); 119 120 /* Enable thermal interrupt */ 121 val = readl(ts->base + K1_TSENSOR_INT_EN_REG); 122 val |= K1_TSENSOR_INT_EN_MASK; 123 writel(val, ts->base + K1_TSENSOR_INT_EN_REG); 124 } 125 126 /* 127 * The conversion formula used is: 128 * T(m°C) = (((raw_value & mask) >> shift) - TEMPERATURE_OFFSET) * 1000 129 */ 130 static int k1_tsensor_get_temp(struct thermal_zone_device *tz, int *temp) 131 { 132 struct k1_tsensor_channel *ch = thermal_zone_device_priv(tz); 133 struct k1_tsensor *ts = ch->ts; 134 u32 val; 135 136 val = readl(ts->base + K1_TSENSOR_DATA_REG(ch->id)); 137 if (ch->id % 2) 138 *temp = FIELD_GET(K1_TSENSOR_DATA_HIGH_MASK, val); 139 else 140 *temp = FIELD_GET(K1_TSENSOR_DATA_LOW_MASK, val); 141 142 *temp -= TEMPERATURE_OFFSET; 143 *temp *= 1000; 144 145 return 0; 146 } 147 148 /* 149 * For each sensor, the hardware threshold register is 32 bits: 150 * - Lower 16 bits [15:0] configure the low threshold temperature. 151 * - Upper 16 bits [31:16] configure the high threshold temperature. 152 */ 153 static int k1_tsensor_set_trips(struct thermal_zone_device *tz, int low, int high) 154 { 155 struct k1_tsensor_channel *ch = thermal_zone_device_priv(tz); 156 struct k1_tsensor *ts = ch->ts; 157 u32 val; 158 159 if (low >= high) 160 return -EINVAL; 161 162 low = clamp_val(low / 1000 + TEMPERATURE_OFFSET, TEMPERATURE_OFFSET, 163 FIELD_MAX(K1_TSENSOR_THRSH_LOW_MASK)); 164 high = clamp_val(high / 1000 + TEMPERATURE_OFFSET, TEMPERATURE_OFFSET, 165 FIELD_MAX(K1_TSENSOR_THRSH_HIGH_MASK)); 166 167 val = readl(ts->base + K1_TSENSOR_THRSH_REG(ch->id)); 168 169 val &= ~(K1_TSENSOR_THRSH_LOW_MASK | K1_TSENSOR_THRSH_HIGH_MASK); 170 val |= FIELD_PREP(K1_TSENSOR_THRSH_LOW_MASK, low); 171 val |= FIELD_PREP(K1_TSENSOR_THRSH_HIGH_MASK, high); 172 173 writel(val, ts->base + K1_TSENSOR_THRSH_REG(ch->id)); 174 175 return 0; 176 } 177 178 static const struct thermal_zone_device_ops k1_tsensor_ops = { 179 .get_temp = k1_tsensor_get_temp, 180 .set_trips = k1_tsensor_set_trips, 181 }; 182 183 static irqreturn_t k1_tsensor_irq_thread(int irq, void *data) 184 { 185 struct k1_tsensor *ts = (struct k1_tsensor *)data; 186 int mask, status, i; 187 188 status = readl(ts->base + K1_TSENSOR_INT_STA_REG); 189 190 for (i = 0; i < MAX_SENSOR_NUMBER; i++) { 191 if (status & K1_TSENSOR_INT_MASK(i)) { 192 mask = readl(ts->base + K1_TSENSOR_INT_CLR_REG); 193 mask |= K1_TSENSOR_INT_MASK(i); 194 writel(mask, ts->base + K1_TSENSOR_INT_CLR_REG); 195 thermal_zone_device_update(ts->ch[i].tzd, THERMAL_EVENT_UNSPECIFIED); 196 } 197 } 198 199 return IRQ_HANDLED; 200 } 201 202 static int k1_tsensor_probe(struct platform_device *pdev) 203 { 204 struct device *dev = &pdev->dev; 205 struct k1_tsensor *ts; 206 struct reset_control *reset; 207 struct clk *clk; 208 int i, irq, ret; 209 210 ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); 211 if (!ts) 212 return -ENOMEM; 213 214 ts->base = devm_platform_ioremap_resource(pdev, 0); 215 if (IS_ERR(ts->base)) 216 return dev_err_probe(dev, PTR_ERR(ts->base), "Failed to get reg\n"); 217 218 reset = devm_reset_control_get_exclusive_deasserted(dev, NULL); 219 if (IS_ERR(reset)) 220 return dev_err_probe(dev, PTR_ERR(reset), "Failed to get/deassert reset control\n"); 221 222 clk = devm_clk_get_enabled(dev, "core"); 223 if (IS_ERR(clk)) 224 return dev_err_probe(dev, PTR_ERR(clk), "Failed to get core clock\n"); 225 226 clk = devm_clk_get_enabled(dev, "bus"); 227 if (IS_ERR(clk)) 228 return dev_err_probe(dev, PTR_ERR(clk), "Failed to get bus clock\n"); 229 230 k1_tsensor_init(ts); 231 232 irq = platform_get_irq(pdev, 0); 233 if (irq < 0) 234 return irq; 235 236 ret = devm_request_threaded_irq(dev, irq, NULL, 237 k1_tsensor_irq_thread, 238 IRQF_ONESHOT, "k1_tsensor", ts); 239 if (ret < 0) 240 return ret; 241 242 for (i = 0; i < MAX_SENSOR_NUMBER; ++i) { 243 ts->ch[i].id = i; 244 ts->ch[i].ts = ts; 245 ts->ch[i].tzd = devm_thermal_of_zone_register(dev, i, ts->ch + i, &k1_tsensor_ops); 246 if (IS_ERR(ts->ch[i].tzd)) 247 return PTR_ERR(ts->ch[i].tzd); 248 249 /* Attach sysfs hwmon attributes for userspace monitoring */ 250 ret = devm_thermal_add_hwmon_sysfs(dev, ts->ch[i].tzd); 251 if (ret) 252 dev_warn(dev, "Failed to add hwmon sysfs attributes\n"); 253 254 k1_tsensor_enable_irq(ts->ch + i); 255 } 256 257 platform_set_drvdata(pdev, ts); 258 259 return 0; 260 } 261 262 static const struct of_device_id k1_tsensor_dt_ids[] = { 263 { .compatible = "spacemit,k1-tsensor" }, 264 { /* sentinel */ } 265 }; 266 267 MODULE_DEVICE_TABLE(of, k1_tsensor_dt_ids); 268 269 static struct platform_driver k1_tsensor_driver = { 270 .driver = { 271 .name = "k1_tsensor", 272 .of_match_table = k1_tsensor_dt_ids, 273 }, 274 .probe = k1_tsensor_probe, 275 }; 276 module_platform_driver(k1_tsensor_driver); 277 278 MODULE_DESCRIPTION("SpacemiT K1 Thermal Sensor Driver"); 279 MODULE_AUTHOR("Shuwei Wu <shuwei.wu@mailbox.org>"); 280 MODULE_LICENSE("GPL"); 281