David Brazdil | 0f672f6 | 2019-12-10 10:32:29 +0000 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | /* |
| 3 | * Copyright (C) STMicroelectronics 2018 - All Rights Reserved |
| 4 | * Author: David Hernandez Sanchez <david.hernandezsanchez@st.com> for |
| 5 | * STMicroelectronics. |
| 6 | */ |
| 7 | |
| 8 | #include <linux/clk.h> |
| 9 | #include <linux/clk-provider.h> |
| 10 | #include <linux/delay.h> |
| 11 | #include <linux/err.h> |
| 12 | #include <linux/interrupt.h> |
| 13 | #include <linux/io.h> |
| 14 | #include <linux/iopoll.h> |
| 15 | #include <linux/module.h> |
| 16 | #include <linux/of.h> |
| 17 | #include <linux/of_address.h> |
| 18 | #include <linux/of_device.h> |
| 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/thermal.h> |
| 21 | |
| 22 | #include "../thermal_core.h" |
| 23 | #include "../thermal_hwmon.h" |
| 24 | |
| 25 | /* DTS register offsets */ |
| 26 | #define DTS_CFGR1_OFFSET 0x0 |
| 27 | #define DTS_T0VALR1_OFFSET 0x8 |
| 28 | #define DTS_RAMPVALR_OFFSET 0X10 |
| 29 | #define DTS_ITR1_OFFSET 0x14 |
| 30 | #define DTS_DR_OFFSET 0x1C |
| 31 | #define DTS_SR_OFFSET 0x20 |
| 32 | #define DTS_ITENR_OFFSET 0x24 |
| 33 | #define DTS_CIFR_OFFSET 0x28 |
| 34 | |
| 35 | /* DTS_CFGR1 register mask definitions */ |
| 36 | #define HSREF_CLK_DIV_MASK GENMASK(30, 24) |
| 37 | #define TS1_SMP_TIME_MASK GENMASK(19, 16) |
| 38 | #define TS1_INTRIG_SEL_MASK GENMASK(11, 8) |
| 39 | |
| 40 | /* DTS_T0VALR1 register mask definitions */ |
| 41 | #define TS1_T0_MASK GENMASK(17, 16) |
| 42 | #define TS1_FMT0_MASK GENMASK(15, 0) |
| 43 | |
| 44 | /* DTS_RAMPVALR register mask definitions */ |
| 45 | #define TS1_RAMP_COEFF_MASK GENMASK(15, 0) |
| 46 | |
| 47 | /* DTS_ITR1 register mask definitions */ |
| 48 | #define TS1_HITTHD_MASK GENMASK(31, 16) |
| 49 | #define TS1_LITTHD_MASK GENMASK(15, 0) |
| 50 | |
| 51 | /* DTS_DR register mask definitions */ |
| 52 | #define TS1_MFREQ_MASK GENMASK(15, 0) |
| 53 | |
| 54 | /* Less significant bit position definitions */ |
| 55 | #define TS1_T0_POS 16 |
| 56 | #define TS1_SMP_TIME_POS 16 |
| 57 | #define TS1_HITTHD_POS 16 |
| 58 | #define HSREF_CLK_DIV_POS 24 |
| 59 | |
| 60 | /* DTS_CFGR1 bit definitions */ |
| 61 | #define TS1_EN BIT(0) |
| 62 | #define TS1_START BIT(4) |
| 63 | #define REFCLK_SEL BIT(20) |
| 64 | #define REFCLK_LSE REFCLK_SEL |
| 65 | #define Q_MEAS_OPT BIT(21) |
| 66 | #define CALIBRATION_CONTROL Q_MEAS_OPT |
| 67 | |
| 68 | /* DTS_SR bit definitions */ |
| 69 | #define TS_RDY BIT(15) |
| 70 | /* Bit definitions below are common for DTS_SR, DTS_ITENR and DTS_CIFR */ |
| 71 | #define HIGH_THRESHOLD BIT(2) |
| 72 | #define LOW_THRESHOLD BIT(1) |
| 73 | |
| 74 | /* Constants */ |
| 75 | #define ADJUST 100 |
| 76 | #define ONE_MHZ 1000000 |
| 77 | #define POLL_TIMEOUT 5000 |
| 78 | #define STARTUP_TIME 40 |
| 79 | #define TS1_T0_VAL0 30 |
| 80 | #define TS1_T0_VAL1 130 |
| 81 | #define NO_HW_TRIG 0 |
| 82 | |
| 83 | /* The Thermal Framework expects millidegrees */ |
| 84 | #define mcelsius(temp) ((temp) * 1000) |
| 85 | |
| 86 | /* The Sensor expects oC degrees */ |
| 87 | #define celsius(temp) ((temp) / 1000) |
| 88 | |
| 89 | struct stm_thermal_sensor { |
| 90 | struct device *dev; |
| 91 | struct thermal_zone_device *th_dev; |
| 92 | enum thermal_device_mode mode; |
| 93 | struct clk *clk; |
| 94 | int high_temp; |
| 95 | int low_temp; |
| 96 | int temp_critical; |
| 97 | int temp_passive; |
| 98 | unsigned int low_temp_enabled; |
| 99 | int num_trips; |
| 100 | int irq; |
| 101 | unsigned int irq_enabled; |
| 102 | void __iomem *base; |
| 103 | int t0, fmt0, ramp_coeff; |
| 104 | }; |
| 105 | |
| 106 | static irqreturn_t stm_thermal_alarm_irq(int irq, void *sdata) |
| 107 | { |
| 108 | struct stm_thermal_sensor *sensor = sdata; |
| 109 | |
| 110 | disable_irq_nosync(irq); |
| 111 | sensor->irq_enabled = false; |
| 112 | |
| 113 | return IRQ_WAKE_THREAD; |
| 114 | } |
| 115 | |
| 116 | static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata) |
| 117 | { |
| 118 | u32 value; |
| 119 | struct stm_thermal_sensor *sensor = sdata; |
| 120 | |
| 121 | /* read IT reason in SR and clear flags */ |
| 122 | value = readl_relaxed(sensor->base + DTS_SR_OFFSET); |
| 123 | |
| 124 | if ((value & LOW_THRESHOLD) == LOW_THRESHOLD) |
| 125 | writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); |
| 126 | |
| 127 | if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD) |
| 128 | writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); |
| 129 | |
| 130 | thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED); |
| 131 | |
| 132 | return IRQ_HANDLED; |
| 133 | } |
| 134 | |
| 135 | static int stm_sensor_power_on(struct stm_thermal_sensor *sensor) |
| 136 | { |
| 137 | int ret; |
| 138 | u32 value; |
| 139 | |
| 140 | /* Enable sensor */ |
| 141 | value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); |
| 142 | value |= TS1_EN; |
| 143 | writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); |
| 144 | |
| 145 | /* |
| 146 | * The DTS block can be enabled by setting TSx_EN bit in |
| 147 | * DTS_CFGRx register. It requires a startup time of |
| 148 | * 40μs. Use 5 ms as arbitrary timeout. |
| 149 | */ |
| 150 | ret = readl_poll_timeout(sensor->base + DTS_SR_OFFSET, |
| 151 | value, (value & TS_RDY), |
| 152 | STARTUP_TIME, POLL_TIMEOUT); |
| 153 | if (ret) |
| 154 | return ret; |
| 155 | |
| 156 | /* Start continuous measuring */ |
| 157 | value = readl_relaxed(sensor->base + |
| 158 | DTS_CFGR1_OFFSET); |
| 159 | value |= TS1_START; |
| 160 | writel_relaxed(value, sensor->base + |
| 161 | DTS_CFGR1_OFFSET); |
| 162 | |
| 163 | return 0; |
| 164 | } |
| 165 | |
| 166 | static int stm_sensor_power_off(struct stm_thermal_sensor *sensor) |
| 167 | { |
| 168 | u32 value; |
| 169 | |
| 170 | /* Stop measuring */ |
| 171 | value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); |
| 172 | value &= ~TS1_START; |
| 173 | writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); |
| 174 | |
| 175 | /* Ensure stop is taken into account */ |
| 176 | usleep_range(STARTUP_TIME, POLL_TIMEOUT); |
| 177 | |
| 178 | /* Disable sensor */ |
| 179 | value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); |
| 180 | value &= ~TS1_EN; |
| 181 | writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); |
| 182 | |
| 183 | /* Ensure disable is taken into account */ |
| 184 | return readl_poll_timeout(sensor->base + DTS_SR_OFFSET, value, |
| 185 | !(value & TS_RDY), |
| 186 | STARTUP_TIME, POLL_TIMEOUT); |
| 187 | } |
| 188 | |
| 189 | static int stm_thermal_calibration(struct stm_thermal_sensor *sensor) |
| 190 | { |
| 191 | u32 value, clk_freq; |
| 192 | u32 prescaler; |
| 193 | |
| 194 | /* Figure out prescaler value for PCLK during calibration */ |
| 195 | clk_freq = clk_get_rate(sensor->clk); |
| 196 | if (!clk_freq) |
| 197 | return -EINVAL; |
| 198 | |
| 199 | prescaler = 0; |
| 200 | clk_freq /= ONE_MHZ; |
| 201 | if (clk_freq) { |
| 202 | while (prescaler <= clk_freq) |
| 203 | prescaler++; |
| 204 | } |
| 205 | |
| 206 | value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); |
| 207 | |
| 208 | /* Clear prescaler */ |
| 209 | value &= ~HSREF_CLK_DIV_MASK; |
| 210 | |
| 211 | /* Set prescaler. pclk_freq/prescaler < 1MHz */ |
| 212 | value |= (prescaler << HSREF_CLK_DIV_POS); |
| 213 | |
| 214 | /* Select PCLK as reference clock */ |
| 215 | value &= ~REFCLK_SEL; |
| 216 | |
| 217 | /* Set maximal sampling time for better precision */ |
| 218 | value |= TS1_SMP_TIME_MASK; |
| 219 | |
| 220 | /* Measure with calibration */ |
| 221 | value &= ~CALIBRATION_CONTROL; |
| 222 | |
| 223 | /* select trigger */ |
| 224 | value &= ~TS1_INTRIG_SEL_MASK; |
| 225 | value |= NO_HW_TRIG; |
| 226 | |
| 227 | writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); |
| 228 | |
| 229 | return 0; |
| 230 | } |
| 231 | |
| 232 | /* Fill in DTS structure with factory sensor values */ |
| 233 | static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor) |
| 234 | { |
| 235 | /* Retrieve engineering calibration temperature */ |
| 236 | sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) & |
| 237 | TS1_T0_MASK; |
| 238 | if (!sensor->t0) |
| 239 | sensor->t0 = TS1_T0_VAL0; |
| 240 | else |
| 241 | sensor->t0 = TS1_T0_VAL1; |
| 242 | |
| 243 | /* Retrieve fmt0 and put it on Hz */ |
| 244 | sensor->fmt0 = ADJUST * (readl_relaxed(sensor->base + |
| 245 | DTS_T0VALR1_OFFSET) & TS1_FMT0_MASK); |
| 246 | |
| 247 | /* Retrieve ramp coefficient */ |
| 248 | sensor->ramp_coeff = readl_relaxed(sensor->base + DTS_RAMPVALR_OFFSET) & |
| 249 | TS1_RAMP_COEFF_MASK; |
| 250 | |
| 251 | if (!sensor->fmt0 || !sensor->ramp_coeff) { |
| 252 | dev_err(sensor->dev, "%s: wrong setting\n", __func__); |
| 253 | return -EINVAL; |
| 254 | } |
| 255 | |
| 256 | dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC", |
| 257 | __func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff); |
| 258 | |
| 259 | return 0; |
| 260 | } |
| 261 | |
| 262 | static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor, |
| 263 | int temp, u32 *th) |
| 264 | { |
| 265 | int freqM; |
| 266 | u32 sampling_time; |
| 267 | |
| 268 | /* Retrieve the number of periods to sample */ |
| 269 | sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) & |
| 270 | TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS; |
| 271 | |
| 272 | /* Figure out the CLK_PTAT frequency for a given temperature */ |
| 273 | freqM = ((temp - sensor->t0) * sensor->ramp_coeff) |
| 274 | + sensor->fmt0; |
| 275 | |
| 276 | dev_dbg(sensor->dev, "%s: freqM for threshold = %d Hz", |
| 277 | __func__, freqM); |
| 278 | |
| 279 | /* Figure out the threshold sample number */ |
| 280 | *th = clk_get_rate(sensor->clk); |
| 281 | if (!*th) |
| 282 | return -EINVAL; |
| 283 | |
| 284 | *th = *th / freqM; |
| 285 | |
| 286 | *th *= sampling_time; |
| 287 | |
| 288 | return 0; |
| 289 | } |
| 290 | |
| 291 | static int stm_thermal_set_threshold(struct stm_thermal_sensor *sensor) |
| 292 | { |
| 293 | u32 value, th; |
| 294 | int ret; |
| 295 | |
| 296 | value = readl_relaxed(sensor->base + DTS_ITR1_OFFSET); |
| 297 | |
| 298 | /* Erase threshold content */ |
| 299 | value &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK); |
| 300 | |
| 301 | /* Retrieve the sample threshold number th for a given temperature */ |
| 302 | ret = stm_thermal_calculate_threshold(sensor, sensor->high_temp, &th); |
| 303 | if (ret) |
| 304 | return ret; |
| 305 | |
| 306 | value |= th & TS1_LITTHD_MASK; |
| 307 | |
| 308 | if (sensor->low_temp_enabled) { |
| 309 | /* Retrieve the sample threshold */ |
| 310 | ret = stm_thermal_calculate_threshold(sensor, sensor->low_temp, |
| 311 | &th); |
| 312 | if (ret) |
| 313 | return ret; |
| 314 | |
| 315 | value |= (TS1_HITTHD_MASK & (th << TS1_HITTHD_POS)); |
| 316 | } |
| 317 | |
| 318 | /* Write value on the Low interrupt threshold */ |
| 319 | writel_relaxed(value, sensor->base + DTS_ITR1_OFFSET); |
| 320 | |
| 321 | return 0; |
| 322 | } |
| 323 | |
| 324 | /* Disable temperature interrupt */ |
| 325 | static int stm_disable_irq(struct stm_thermal_sensor *sensor) |
| 326 | { |
| 327 | u32 value; |
| 328 | |
| 329 | /* Disable IT generation for low and high thresholds */ |
| 330 | value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET); |
| 331 | writel_relaxed(value & ~(LOW_THRESHOLD | HIGH_THRESHOLD), |
| 332 | sensor->base + DTS_ITENR_OFFSET); |
| 333 | |
| 334 | dev_dbg(sensor->dev, "%s: IT disabled on sensor side", __func__); |
| 335 | |
| 336 | return 0; |
| 337 | } |
| 338 | |
| 339 | /* Enable temperature interrupt */ |
| 340 | static int stm_enable_irq(struct stm_thermal_sensor *sensor) |
| 341 | { |
| 342 | u32 value; |
| 343 | |
| 344 | /* |
| 345 | * Code below enables High temperature threshold using a low threshold |
| 346 | * sampling value |
| 347 | */ |
| 348 | |
| 349 | /* Make sure LOW_THRESHOLD IT is clear before enabling */ |
| 350 | writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); |
| 351 | |
| 352 | /* Enable IT generation for low threshold */ |
| 353 | value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET); |
| 354 | value |= LOW_THRESHOLD; |
| 355 | |
| 356 | /* Enable the low temperature threshold if needed */ |
| 357 | if (sensor->low_temp_enabled) { |
| 358 | /* Make sure HIGH_THRESHOLD IT is clear before enabling */ |
| 359 | writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); |
| 360 | |
| 361 | /* Enable IT generation for high threshold */ |
| 362 | value |= HIGH_THRESHOLD; |
| 363 | } |
| 364 | |
| 365 | /* Enable thresholds */ |
| 366 | writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET); |
| 367 | |
| 368 | dev_dbg(sensor->dev, "%s: IT enabled on sensor side", __func__); |
| 369 | |
| 370 | return 0; |
| 371 | } |
| 372 | |
| 373 | static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor) |
| 374 | { |
| 375 | int ret; |
| 376 | |
| 377 | sensor->mode = THERMAL_DEVICE_DISABLED; |
| 378 | |
| 379 | ret = stm_sensor_power_off(sensor); |
| 380 | if (ret) |
| 381 | return ret; |
| 382 | |
| 383 | ret = stm_disable_irq(sensor); |
| 384 | if (ret) |
| 385 | return ret; |
| 386 | |
| 387 | ret = stm_thermal_set_threshold(sensor); |
| 388 | if (ret) |
| 389 | return ret; |
| 390 | |
| 391 | ret = stm_enable_irq(sensor); |
| 392 | if (ret) |
| 393 | return ret; |
| 394 | |
| 395 | ret = stm_sensor_power_on(sensor); |
| 396 | if (ret) |
| 397 | return ret; |
| 398 | |
| 399 | sensor->mode = THERMAL_DEVICE_ENABLED; |
| 400 | |
| 401 | return 0; |
| 402 | } |
| 403 | |
| 404 | /* Callback to get temperature from HW */ |
| 405 | static int stm_thermal_get_temp(void *data, int *temp) |
| 406 | { |
| 407 | struct stm_thermal_sensor *sensor = data; |
| 408 | u32 sampling_time; |
| 409 | int freqM, ret; |
| 410 | |
| 411 | if (sensor->mode != THERMAL_DEVICE_ENABLED) |
| 412 | return -EAGAIN; |
| 413 | |
| 414 | /* Retrieve the number of samples */ |
| 415 | ret = readl_poll_timeout(sensor->base + DTS_DR_OFFSET, freqM, |
| 416 | (freqM & TS1_MFREQ_MASK), STARTUP_TIME, |
| 417 | POLL_TIMEOUT); |
| 418 | |
| 419 | if (ret) |
| 420 | return ret; |
| 421 | |
| 422 | if (!freqM) |
| 423 | return -ENODATA; |
| 424 | |
| 425 | /* Retrieve the number of periods sampled */ |
| 426 | sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) & |
| 427 | TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS; |
| 428 | |
| 429 | /* Figure out the number of samples per period */ |
| 430 | freqM /= sampling_time; |
| 431 | |
| 432 | /* Figure out the CLK_PTAT frequency */ |
| 433 | freqM = clk_get_rate(sensor->clk) / freqM; |
| 434 | if (!freqM) |
| 435 | return -EINVAL; |
| 436 | |
| 437 | dev_dbg(sensor->dev, "%s: freqM=%d\n", __func__, freqM); |
| 438 | |
| 439 | /* Figure out the temperature in mili celsius */ |
| 440 | *temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) / |
| 441 | sensor->ramp_coeff)); |
| 442 | |
| 443 | dev_dbg(sensor->dev, "%s: temperature = %d millicelsius", |
| 444 | __func__, *temp); |
| 445 | |
| 446 | /* Update thresholds */ |
| 447 | if (sensor->num_trips > 1) { |
| 448 | /* Update alarm threshold value to next higher trip point */ |
| 449 | if (sensor->high_temp == sensor->temp_passive && |
| 450 | celsius(*temp) >= sensor->temp_passive) { |
| 451 | sensor->high_temp = sensor->temp_critical; |
| 452 | sensor->low_temp = sensor->temp_passive; |
| 453 | sensor->low_temp_enabled = true; |
| 454 | ret = stm_thermal_update_threshold(sensor); |
| 455 | if (ret) |
| 456 | return ret; |
| 457 | } |
| 458 | |
| 459 | if (sensor->high_temp == sensor->temp_critical && |
| 460 | celsius(*temp) < sensor->temp_passive) { |
| 461 | sensor->high_temp = sensor->temp_passive; |
| 462 | sensor->low_temp_enabled = false; |
| 463 | ret = stm_thermal_update_threshold(sensor); |
| 464 | if (ret) |
| 465 | return ret; |
| 466 | } |
| 467 | |
| 468 | /* |
| 469 | * Re-enable alarm IRQ if temperature below critical |
| 470 | * temperature |
| 471 | */ |
| 472 | if (!sensor->irq_enabled && |
| 473 | (celsius(*temp) < sensor->temp_critical)) { |
| 474 | sensor->irq_enabled = true; |
| 475 | enable_irq(sensor->irq); |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | return 0; |
| 480 | } |
| 481 | |
| 482 | /* Registers DTS irq to be visible by GIC */ |
| 483 | static int stm_register_irq(struct stm_thermal_sensor *sensor) |
| 484 | { |
| 485 | struct device *dev = sensor->dev; |
| 486 | struct platform_device *pdev = to_platform_device(dev); |
| 487 | int ret; |
| 488 | |
| 489 | sensor->irq = platform_get_irq(pdev, 0); |
| 490 | if (sensor->irq < 0) { |
| 491 | dev_err(dev, "%s: Unable to find IRQ\n", __func__); |
| 492 | return sensor->irq; |
| 493 | } |
| 494 | |
| 495 | ret = devm_request_threaded_irq(dev, sensor->irq, |
| 496 | stm_thermal_alarm_irq, |
| 497 | stm_thermal_alarm_irq_thread, |
| 498 | IRQF_ONESHOT, |
| 499 | dev->driver->name, sensor); |
| 500 | if (ret) { |
| 501 | dev_err(dev, "%s: Failed to register IRQ %d\n", __func__, |
| 502 | sensor->irq); |
| 503 | return ret; |
| 504 | } |
| 505 | |
| 506 | sensor->irq_enabled = true; |
| 507 | |
| 508 | dev_dbg(dev, "%s: thermal IRQ registered", __func__); |
| 509 | |
| 510 | return 0; |
| 511 | } |
| 512 | |
| 513 | static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor) |
| 514 | { |
| 515 | int ret; |
| 516 | |
| 517 | ret = stm_sensor_power_off(sensor); |
| 518 | if (ret) |
| 519 | return ret; |
| 520 | |
| 521 | clk_disable_unprepare(sensor->clk); |
| 522 | |
| 523 | return 0; |
| 524 | } |
| 525 | |
| 526 | static int stm_thermal_prepare(struct stm_thermal_sensor *sensor) |
| 527 | { |
| 528 | int ret; |
| 529 | struct device *dev = sensor->dev; |
| 530 | |
| 531 | ret = clk_prepare_enable(sensor->clk); |
| 532 | if (ret) |
| 533 | return ret; |
| 534 | |
| 535 | ret = stm_thermal_read_factory_settings(sensor); |
| 536 | if (ret) |
| 537 | goto thermal_unprepare; |
| 538 | |
| 539 | ret = stm_thermal_calibration(sensor); |
| 540 | if (ret) |
| 541 | goto thermal_unprepare; |
| 542 | |
| 543 | /* Set threshold(s) for IRQ */ |
| 544 | ret = stm_thermal_set_threshold(sensor); |
| 545 | if (ret) |
| 546 | goto thermal_unprepare; |
| 547 | |
| 548 | ret = stm_enable_irq(sensor); |
| 549 | if (ret) |
| 550 | goto thermal_unprepare; |
| 551 | |
| 552 | ret = stm_sensor_power_on(sensor); |
| 553 | if (ret) { |
| 554 | dev_err(dev, "%s: failed to power on sensor\n", __func__); |
| 555 | goto irq_disable; |
| 556 | } |
| 557 | |
| 558 | return 0; |
| 559 | |
| 560 | irq_disable: |
| 561 | stm_disable_irq(sensor); |
| 562 | |
| 563 | thermal_unprepare: |
| 564 | clk_disable_unprepare(sensor->clk); |
| 565 | |
| 566 | return ret; |
| 567 | } |
| 568 | |
| 569 | #ifdef CONFIG_PM_SLEEP |
| 570 | static int stm_thermal_suspend(struct device *dev) |
| 571 | { |
| 572 | int ret; |
| 573 | struct stm_thermal_sensor *sensor = dev_get_drvdata(dev); |
| 574 | |
| 575 | ret = stm_thermal_sensor_off(sensor); |
| 576 | if (ret) |
| 577 | return ret; |
| 578 | |
| 579 | sensor->mode = THERMAL_DEVICE_DISABLED; |
| 580 | |
| 581 | return 0; |
| 582 | } |
| 583 | |
| 584 | static int stm_thermal_resume(struct device *dev) |
| 585 | { |
| 586 | int ret; |
| 587 | struct stm_thermal_sensor *sensor = dev_get_drvdata(dev); |
| 588 | |
| 589 | ret = stm_thermal_prepare(sensor); |
| 590 | if (ret) |
| 591 | return ret; |
| 592 | |
| 593 | sensor->mode = THERMAL_DEVICE_ENABLED; |
| 594 | |
| 595 | return 0; |
| 596 | } |
| 597 | #endif /* CONFIG_PM_SLEEP */ |
| 598 | |
| 599 | SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume); |
| 600 | |
| 601 | static const struct thermal_zone_of_device_ops stm_tz_ops = { |
| 602 | .get_temp = stm_thermal_get_temp, |
| 603 | }; |
| 604 | |
| 605 | static const struct of_device_id stm_thermal_of_match[] = { |
| 606 | { .compatible = "st,stm32-thermal"}, |
| 607 | { /* sentinel */ } |
| 608 | }; |
| 609 | MODULE_DEVICE_TABLE(of, stm_thermal_of_match); |
| 610 | |
| 611 | static int stm_thermal_probe(struct platform_device *pdev) |
| 612 | { |
| 613 | struct stm_thermal_sensor *sensor; |
| 614 | struct resource *res; |
| 615 | const struct thermal_trip *trip; |
| 616 | void __iomem *base; |
| 617 | int ret, i; |
| 618 | |
| 619 | if (!pdev->dev.of_node) { |
| 620 | dev_err(&pdev->dev, "%s: device tree node not found\n", |
| 621 | __func__); |
| 622 | return -EINVAL; |
| 623 | } |
| 624 | |
| 625 | sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); |
| 626 | if (!sensor) |
| 627 | return -ENOMEM; |
| 628 | |
| 629 | platform_set_drvdata(pdev, sensor); |
| 630 | |
| 631 | sensor->dev = &pdev->dev; |
| 632 | |
| 633 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 634 | base = devm_ioremap_resource(&pdev->dev, res); |
| 635 | if (IS_ERR(base)) |
| 636 | return PTR_ERR(base); |
| 637 | |
| 638 | /* Populate sensor */ |
| 639 | sensor->base = base; |
| 640 | |
| 641 | sensor->clk = devm_clk_get(&pdev->dev, "pclk"); |
| 642 | if (IS_ERR(sensor->clk)) { |
| 643 | dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n", |
| 644 | __func__); |
| 645 | return PTR_ERR(sensor->clk); |
| 646 | } |
| 647 | |
| 648 | /* Register IRQ into GIC */ |
| 649 | ret = stm_register_irq(sensor); |
| 650 | if (ret) |
| 651 | return ret; |
| 652 | |
| 653 | sensor->th_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, |
| 654 | sensor, |
| 655 | &stm_tz_ops); |
| 656 | |
| 657 | if (IS_ERR(sensor->th_dev)) { |
| 658 | dev_err(&pdev->dev, "%s: thermal zone sensor registering KO\n", |
| 659 | __func__); |
| 660 | ret = PTR_ERR(sensor->th_dev); |
| 661 | return ret; |
| 662 | } |
| 663 | |
| 664 | if (!sensor->th_dev->ops->get_crit_temp) { |
| 665 | /* Critical point must be provided */ |
| 666 | ret = -EINVAL; |
| 667 | goto err_tz; |
| 668 | } |
| 669 | |
| 670 | ret = sensor->th_dev->ops->get_crit_temp(sensor->th_dev, |
| 671 | &sensor->temp_critical); |
| 672 | if (ret) { |
| 673 | dev_err(&pdev->dev, |
| 674 | "Not able to read critical_temp: %d\n", ret); |
| 675 | goto err_tz; |
| 676 | } |
| 677 | |
| 678 | sensor->temp_critical = celsius(sensor->temp_critical); |
| 679 | |
| 680 | /* Set thresholds for IRQ */ |
| 681 | sensor->high_temp = sensor->temp_critical; |
| 682 | |
| 683 | trip = of_thermal_get_trip_points(sensor->th_dev); |
| 684 | sensor->num_trips = of_thermal_get_ntrips(sensor->th_dev); |
| 685 | |
| 686 | /* Find out passive temperature if it exists */ |
| 687 | for (i = (sensor->num_trips - 1); i >= 0; i--) { |
| 688 | if (trip[i].type == THERMAL_TRIP_PASSIVE) { |
| 689 | sensor->temp_passive = celsius(trip[i].temperature); |
| 690 | /* Update high temperature threshold */ |
| 691 | sensor->high_temp = sensor->temp_passive; |
| 692 | } |
| 693 | } |
| 694 | |
| 695 | /* |
| 696 | * Ensure low_temp_enabled flag is disabled. |
| 697 | * By disabling low_temp_enabled, low threshold IT will not be |
| 698 | * configured neither enabled because it is not needed as high |
| 699 | * threshold is set on the lowest temperature trip point after |
| 700 | * probe. |
| 701 | */ |
| 702 | sensor->low_temp_enabled = false; |
| 703 | |
| 704 | /* Configure and enable HW sensor */ |
| 705 | ret = stm_thermal_prepare(sensor); |
| 706 | if (ret) { |
| 707 | dev_err(&pdev->dev, |
| 708 | "Not able to enable sensor: %d\n", ret); |
| 709 | goto err_tz; |
| 710 | } |
| 711 | |
| 712 | /* |
| 713 | * Thermal_zone doesn't enable hwmon as default, |
| 714 | * enable it here |
| 715 | */ |
| 716 | sensor->th_dev->tzp->no_hwmon = false; |
| 717 | ret = thermal_add_hwmon_sysfs(sensor->th_dev); |
| 718 | if (ret) |
| 719 | goto err_tz; |
| 720 | |
| 721 | sensor->mode = THERMAL_DEVICE_ENABLED; |
| 722 | |
| 723 | dev_info(&pdev->dev, "%s: Driver initialized successfully\n", |
| 724 | __func__); |
| 725 | |
| 726 | return 0; |
| 727 | |
| 728 | err_tz: |
| 729 | thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev); |
| 730 | return ret; |
| 731 | } |
| 732 | |
| 733 | static int stm_thermal_remove(struct platform_device *pdev) |
| 734 | { |
| 735 | struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev); |
| 736 | |
| 737 | stm_thermal_sensor_off(sensor); |
| 738 | thermal_remove_hwmon_sysfs(sensor->th_dev); |
| 739 | thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev); |
| 740 | |
| 741 | return 0; |
| 742 | } |
| 743 | |
| 744 | static struct platform_driver stm_thermal_driver = { |
| 745 | .driver = { |
| 746 | .name = "stm_thermal", |
| 747 | .pm = &stm_thermal_pm_ops, |
| 748 | .of_match_table = stm_thermal_of_match, |
| 749 | }, |
| 750 | .probe = stm_thermal_probe, |
| 751 | .remove = stm_thermal_remove, |
| 752 | }; |
| 753 | module_platform_driver(stm_thermal_driver); |
| 754 | |
| 755 | MODULE_DESCRIPTION("STMicroelectronics STM32 Thermal Sensor Driver"); |
| 756 | MODULE_AUTHOR("David Hernandez Sanchez <david.hernandezsanchez@st.com>"); |
| 757 | MODULE_LICENSE("GPL v2"); |
| 758 | MODULE_ALIAS("platform:stm_thermal"); |