sun8i_thermal.c (16536B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Thermal sensor driver for Allwinner SOC 4 * Copyright (C) 2019 Yangtao Li 5 * 6 * Based on the work of Icenowy Zheng <icenowy@aosc.io> 7 * Based on the work of Ondrej Jirman <megous@megous.com> 8 * Based on the work of Josef Gajdusek <atx@atx.name> 9 */ 10 11#include <linux/bitmap.h> 12#include <linux/clk.h> 13#include <linux/device.h> 14#include <linux/interrupt.h> 15#include <linux/module.h> 16#include <linux/nvmem-consumer.h> 17#include <linux/of_device.h> 18#include <linux/platform_device.h> 19#include <linux/regmap.h> 20#include <linux/reset.h> 21#include <linux/slab.h> 22#include <linux/thermal.h> 23 24#include "thermal_hwmon.h" 25 26#define MAX_SENSOR_NUM 4 27 28#define FT_TEMP_MASK GENMASK(11, 0) 29#define TEMP_CALIB_MASK GENMASK(11, 0) 30#define CALIBRATE_DEFAULT 0x800 31 32#define SUN8I_THS_CTRL0 0x00 33#define SUN8I_THS_CTRL2 0x40 34#define SUN8I_THS_IC 0x44 35#define SUN8I_THS_IS 0x48 36#define SUN8I_THS_MFC 0x70 37#define SUN8I_THS_TEMP_CALIB 0x74 38#define SUN8I_THS_TEMP_DATA 0x80 39 40#define SUN50I_THS_CTRL0 0x00 41#define SUN50I_H6_THS_ENABLE 0x04 42#define SUN50I_H6_THS_PC 0x08 43#define SUN50I_H6_THS_DIC 0x10 44#define SUN50I_H6_THS_DIS 0x20 45#define SUN50I_H6_THS_MFC 0x30 46#define SUN50I_H6_THS_TEMP_CALIB 0xa0 47#define SUN50I_H6_THS_TEMP_DATA 0xc0 48 49#define SUN8I_THS_CTRL0_T_ACQ0(x) (GENMASK(15, 0) & (x)) 50#define SUN8I_THS_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) & (x)) << 16) 51#define SUN8I_THS_DATA_IRQ_STS(x) BIT(x + 8) 52 53#define SUN50I_THS_CTRL0_T_ACQ(x) ((GENMASK(15, 0) & (x)) << 16) 54#define SUN50I_THS_FILTER_EN BIT(2) 55#define SUN50I_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x)) 56#define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12) 57#define SUN50I_H6_THS_DATA_IRQ_STS(x) BIT(x) 58 59/* millidegree celsius */ 60 61struct tsensor { 62 struct ths_device *tmdev; 63 struct thermal_zone_device *tzd; 64 int id; 65}; 66 67struct ths_thermal_chip { 68 bool has_mod_clk; 69 bool has_bus_clk_reset; 70 int sensor_num; 71 int offset; 72 int scale; 73 int ft_deviation; 74 int temp_data_base; 75 int (*calibrate)(struct ths_device *tmdev, 76 u16 *caldata, int callen); 77 int (*init)(struct ths_device *tmdev); 78 unsigned long (*irq_ack)(struct ths_device *tmdev); 79 int (*calc_temp)(struct ths_device *tmdev, 80 int id, int reg); 81}; 82 83struct ths_device { 84 const struct ths_thermal_chip *chip; 85 struct device *dev; 86 struct regmap *regmap; 87 struct reset_control *reset; 88 struct clk *bus_clk; 89 struct clk *mod_clk; 90 struct tsensor sensor[MAX_SENSOR_NUM]; 91}; 92 93/* Temp Unit: millidegree Celsius */ 94static int sun8i_ths_calc_temp(struct ths_device *tmdev, 95 int id, int reg) 96{ 97 return tmdev->chip->offset - (reg * tmdev->chip->scale / 10); 98} 99 100static int sun50i_h5_calc_temp(struct ths_device *tmdev, 101 int id, int reg) 102{ 103 if (reg >= 0x500) 104 return -1191 * reg / 10 + 223000; 105 else if (!id) 106 return -1452 * reg / 10 + 259000; 107 else 108 return -1590 * reg / 10 + 276000; 109} 110 111static int sun8i_ths_get_temp(void *data, int *temp) 112{ 113 struct tsensor *s = data; 114 struct ths_device *tmdev = s->tmdev; 115 int val = 0; 116 117 regmap_read(tmdev->regmap, tmdev->chip->temp_data_base + 118 0x4 * s->id, &val); 119 120 /* ths have no data yet */ 121 if (!val) 122 return -EAGAIN; 123 124 *temp = tmdev->chip->calc_temp(tmdev, s->id, val); 125 /* 126 * According to the original sdk, there are some platforms(rarely) 127 * that add a fixed offset value after calculating the temperature 128 * value. We can't simply put it on the formula for calculating the 129 * temperature above, because the formula for calculating the 130 * temperature above is also used when the sensor is calibrated. If 131 * do this, the correct calibration formula is hard to know. 132 */ 133 *temp += tmdev->chip->ft_deviation; 134 135 return 0; 136} 137 138static const struct thermal_zone_of_device_ops ths_ops = { 139 .get_temp = sun8i_ths_get_temp, 140}; 141 142static const struct regmap_config config = { 143 .reg_bits = 32, 144 .val_bits = 32, 145 .reg_stride = 4, 146 .fast_io = true, 147 .max_register = 0xfc, 148}; 149 150static unsigned long sun8i_h3_irq_ack(struct ths_device *tmdev) 151{ 152 unsigned long irq_bitmap = 0; 153 int i, state; 154 155 regmap_read(tmdev->regmap, SUN8I_THS_IS, &state); 156 157 for (i = 0; i < tmdev->chip->sensor_num; i++) { 158 if (state & SUN8I_THS_DATA_IRQ_STS(i)) { 159 regmap_write(tmdev->regmap, SUN8I_THS_IS, 160 SUN8I_THS_DATA_IRQ_STS(i)); 161 bitmap_set(&irq_bitmap, i, 1); 162 } 163 } 164 165 return irq_bitmap; 166} 167 168static unsigned long sun50i_h6_irq_ack(struct ths_device *tmdev) 169{ 170 unsigned long irq_bitmap = 0; 171 int i, state; 172 173 regmap_read(tmdev->regmap, SUN50I_H6_THS_DIS, &state); 174 175 for (i = 0; i < tmdev->chip->sensor_num; i++) { 176 if (state & SUN50I_H6_THS_DATA_IRQ_STS(i)) { 177 regmap_write(tmdev->regmap, SUN50I_H6_THS_DIS, 178 SUN50I_H6_THS_DATA_IRQ_STS(i)); 179 bitmap_set(&irq_bitmap, i, 1); 180 } 181 } 182 183 return irq_bitmap; 184} 185 186static irqreturn_t sun8i_irq_thread(int irq, void *data) 187{ 188 struct ths_device *tmdev = data; 189 unsigned long irq_bitmap = tmdev->chip->irq_ack(tmdev); 190 int i; 191 192 for_each_set_bit(i, &irq_bitmap, tmdev->chip->sensor_num) { 193 thermal_zone_device_update(tmdev->sensor[i].tzd, 194 THERMAL_EVENT_UNSPECIFIED); 195 } 196 197 return IRQ_HANDLED; 198} 199 200static int sun8i_h3_ths_calibrate(struct ths_device *tmdev, 201 u16 *caldata, int callen) 202{ 203 int i; 204 205 if (!caldata[0] || callen < 2 * tmdev->chip->sensor_num) 206 return -EINVAL; 207 208 for (i = 0; i < tmdev->chip->sensor_num; i++) { 209 int offset = (i % 2) << 4; 210 211 regmap_update_bits(tmdev->regmap, 212 SUN8I_THS_TEMP_CALIB + (4 * (i >> 1)), 213 0xfff << offset, 214 caldata[i] << offset); 215 } 216 217 return 0; 218} 219 220static int sun50i_h6_ths_calibrate(struct ths_device *tmdev, 221 u16 *caldata, int callen) 222{ 223 struct device *dev = tmdev->dev; 224 int i, ft_temp; 225 226 if (!caldata[0] || callen < 2 + 2 * tmdev->chip->sensor_num) 227 return -EINVAL; 228 229 /* 230 * efuse layout: 231 * 232 * 0 11 16 32 233 * +-------+-------+-------+ 234 * |temp| |sensor0|sensor1| 235 * +-------+-------+-------+ 236 * 237 * The calibration data on the H6 is the ambient temperature and 238 * sensor values that are filled during the factory test stage. 239 * 240 * The unit of stored FT temperature is 0.1 degreee celusis. 241 * 242 * We need to calculate a delta between measured and caluclated 243 * register values and this will become a calibration offset. 244 */ 245 ft_temp = (caldata[0] & FT_TEMP_MASK) * 100; 246 247 for (i = 0; i < tmdev->chip->sensor_num; i++) { 248 int sensor_reg = caldata[i + 1] & TEMP_CALIB_MASK; 249 int cdata, offset; 250 int sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg); 251 252 /* 253 * Calibration data is CALIBRATE_DEFAULT - (calculated 254 * temperature from sensor reading at factory temperature 255 * minus actual factory temperature) * 14.88 (scale from 256 * temperature to register values) 257 */ 258 cdata = CALIBRATE_DEFAULT - 259 ((sensor_temp - ft_temp) * 10 / tmdev->chip->scale); 260 if (cdata & ~TEMP_CALIB_MASK) { 261 /* 262 * Calibration value more than 12-bit, but calibration 263 * register is 12-bit. In this case, ths hardware can 264 * still work without calibration, although the data 265 * won't be so accurate. 266 */ 267 dev_warn(dev, "sensor%d is not calibrated.\n", i); 268 continue; 269 } 270 271 offset = (i % 2) * 16; 272 regmap_update_bits(tmdev->regmap, 273 SUN50I_H6_THS_TEMP_CALIB + (i / 2 * 4), 274 0xfff << offset, 275 cdata << offset); 276 } 277 278 return 0; 279} 280 281static int sun8i_ths_calibrate(struct ths_device *tmdev) 282{ 283 struct nvmem_cell *calcell; 284 struct device *dev = tmdev->dev; 285 u16 *caldata; 286 size_t callen; 287 int ret = 0; 288 289 calcell = devm_nvmem_cell_get(dev, "calibration"); 290 if (IS_ERR(calcell)) { 291 if (PTR_ERR(calcell) == -EPROBE_DEFER) 292 return -EPROBE_DEFER; 293 /* 294 * Even if the external calibration data stored in sid is 295 * not accessible, the THS hardware can still work, although 296 * the data won't be so accurate. 297 * 298 * The default value of calibration register is 0x800 for 299 * every sensor, and the calibration value is usually 0x7xx 300 * or 0x8xx, so they won't be away from the default value 301 * for a lot. 302 * 303 * So here we do not return error if the calibration data is 304 * not available, except the probe needs deferring. 305 */ 306 goto out; 307 } 308 309 caldata = nvmem_cell_read(calcell, &callen); 310 if (IS_ERR(caldata)) { 311 ret = PTR_ERR(caldata); 312 goto out; 313 } 314 315 tmdev->chip->calibrate(tmdev, caldata, callen); 316 317 kfree(caldata); 318out: 319 return ret; 320} 321 322static int sun8i_ths_resource_init(struct ths_device *tmdev) 323{ 324 struct device *dev = tmdev->dev; 325 struct platform_device *pdev = to_platform_device(dev); 326 void __iomem *base; 327 int ret; 328 329 base = devm_platform_ioremap_resource(pdev, 0); 330 if (IS_ERR(base)) 331 return PTR_ERR(base); 332 333 tmdev->regmap = devm_regmap_init_mmio(dev, base, &config); 334 if (IS_ERR(tmdev->regmap)) 335 return PTR_ERR(tmdev->regmap); 336 337 if (tmdev->chip->has_bus_clk_reset) { 338 tmdev->reset = devm_reset_control_get(dev, NULL); 339 if (IS_ERR(tmdev->reset)) 340 return PTR_ERR(tmdev->reset); 341 342 tmdev->bus_clk = devm_clk_get(&pdev->dev, "bus"); 343 if (IS_ERR(tmdev->bus_clk)) 344 return PTR_ERR(tmdev->bus_clk); 345 } 346 347 if (tmdev->chip->has_mod_clk) { 348 tmdev->mod_clk = devm_clk_get(&pdev->dev, "mod"); 349 if (IS_ERR(tmdev->mod_clk)) 350 return PTR_ERR(tmdev->mod_clk); 351 } 352 353 ret = reset_control_deassert(tmdev->reset); 354 if (ret) 355 return ret; 356 357 ret = clk_prepare_enable(tmdev->bus_clk); 358 if (ret) 359 goto assert_reset; 360 361 ret = clk_set_rate(tmdev->mod_clk, 24000000); 362 if (ret) 363 goto bus_disable; 364 365 ret = clk_prepare_enable(tmdev->mod_clk); 366 if (ret) 367 goto bus_disable; 368 369 ret = sun8i_ths_calibrate(tmdev); 370 if (ret) 371 goto mod_disable; 372 373 return 0; 374 375mod_disable: 376 clk_disable_unprepare(tmdev->mod_clk); 377bus_disable: 378 clk_disable_unprepare(tmdev->bus_clk); 379assert_reset: 380 reset_control_assert(tmdev->reset); 381 382 return ret; 383} 384 385static int sun8i_h3_thermal_init(struct ths_device *tmdev) 386{ 387 int val; 388 389 /* average over 4 samples */ 390 regmap_write(tmdev->regmap, SUN8I_THS_MFC, 391 SUN50I_THS_FILTER_EN | 392 SUN50I_THS_FILTER_TYPE(1)); 393 /* 394 * clkin = 24MHz 395 * filter_samples = 4 396 * period = 0.25s 397 * 398 * x = period * clkin / 4096 / filter_samples - 1 399 * = 365 400 */ 401 val = GENMASK(7 + tmdev->chip->sensor_num, 8); 402 regmap_write(tmdev->regmap, SUN8I_THS_IC, 403 SUN50I_H6_THS_PC_TEMP_PERIOD(365) | val); 404 /* 405 * T_acq = 20us 406 * clkin = 24MHz 407 * 408 * x = T_acq * clkin - 1 409 * = 479 410 */ 411 regmap_write(tmdev->regmap, SUN8I_THS_CTRL0, 412 SUN8I_THS_CTRL0_T_ACQ0(479)); 413 val = GENMASK(tmdev->chip->sensor_num - 1, 0); 414 regmap_write(tmdev->regmap, SUN8I_THS_CTRL2, 415 SUN8I_THS_CTRL2_T_ACQ1(479) | val); 416 417 return 0; 418} 419 420/* 421 * Without this undocumented value, the returned temperatures would 422 * be higher than real ones by about 20C. 423 */ 424#define SUN50I_H6_CTRL0_UNK 0x0000002f 425 426static int sun50i_h6_thermal_init(struct ths_device *tmdev) 427{ 428 int val; 429 430 /* 431 * T_acq = 20us 432 * clkin = 24MHz 433 * 434 * x = T_acq * clkin - 1 435 * = 479 436 */ 437 regmap_write(tmdev->regmap, SUN50I_THS_CTRL0, 438 SUN50I_H6_CTRL0_UNK | SUN50I_THS_CTRL0_T_ACQ(479)); 439 /* average over 4 samples */ 440 regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC, 441 SUN50I_THS_FILTER_EN | 442 SUN50I_THS_FILTER_TYPE(1)); 443 /* 444 * clkin = 24MHz 445 * filter_samples = 4 446 * period = 0.25s 447 * 448 * x = period * clkin / 4096 / filter_samples - 1 449 * = 365 450 */ 451 regmap_write(tmdev->regmap, SUN50I_H6_THS_PC, 452 SUN50I_H6_THS_PC_TEMP_PERIOD(365)); 453 /* enable sensor */ 454 val = GENMASK(tmdev->chip->sensor_num - 1, 0); 455 regmap_write(tmdev->regmap, SUN50I_H6_THS_ENABLE, val); 456 /* thermal data interrupt enable */ 457 val = GENMASK(tmdev->chip->sensor_num - 1, 0); 458 regmap_write(tmdev->regmap, SUN50I_H6_THS_DIC, val); 459 460 return 0; 461} 462 463static int sun8i_ths_register(struct ths_device *tmdev) 464{ 465 int i; 466 467 for (i = 0; i < tmdev->chip->sensor_num; i++) { 468 tmdev->sensor[i].tmdev = tmdev; 469 tmdev->sensor[i].id = i; 470 tmdev->sensor[i].tzd = 471 devm_thermal_zone_of_sensor_register(tmdev->dev, 472 i, 473 &tmdev->sensor[i], 474 &ths_ops); 475 if (IS_ERR(tmdev->sensor[i].tzd)) 476 return PTR_ERR(tmdev->sensor[i].tzd); 477 478 if (devm_thermal_add_hwmon_sysfs(tmdev->sensor[i].tzd)) 479 dev_warn(tmdev->dev, 480 "Failed to add hwmon sysfs attributes\n"); 481 } 482 483 return 0; 484} 485 486static int sun8i_ths_probe(struct platform_device *pdev) 487{ 488 struct ths_device *tmdev; 489 struct device *dev = &pdev->dev; 490 int ret, irq; 491 492 tmdev = devm_kzalloc(dev, sizeof(*tmdev), GFP_KERNEL); 493 if (!tmdev) 494 return -ENOMEM; 495 496 tmdev->dev = dev; 497 tmdev->chip = of_device_get_match_data(&pdev->dev); 498 if (!tmdev->chip) 499 return -EINVAL; 500 501 platform_set_drvdata(pdev, tmdev); 502 503 ret = sun8i_ths_resource_init(tmdev); 504 if (ret) 505 return ret; 506 507 irq = platform_get_irq(pdev, 0); 508 if (irq < 0) 509 return irq; 510 511 ret = tmdev->chip->init(tmdev); 512 if (ret) 513 return ret; 514 515 ret = sun8i_ths_register(tmdev); 516 if (ret) 517 return ret; 518 519 /* 520 * Avoid entering the interrupt handler, the thermal device is not 521 * registered yet, we deffer the registration of the interrupt to 522 * the end. 523 */ 524 ret = devm_request_threaded_irq(dev, irq, NULL, 525 sun8i_irq_thread, 526 IRQF_ONESHOT, "ths", tmdev); 527 if (ret) 528 return ret; 529 530 return 0; 531} 532 533static int sun8i_ths_remove(struct platform_device *pdev) 534{ 535 struct ths_device *tmdev = platform_get_drvdata(pdev); 536 537 clk_disable_unprepare(tmdev->mod_clk); 538 clk_disable_unprepare(tmdev->bus_clk); 539 reset_control_assert(tmdev->reset); 540 541 return 0; 542} 543 544static const struct ths_thermal_chip sun8i_a83t_ths = { 545 .sensor_num = 3, 546 .scale = 705, 547 .offset = 191668, 548 .temp_data_base = SUN8I_THS_TEMP_DATA, 549 .calibrate = sun8i_h3_ths_calibrate, 550 .init = sun8i_h3_thermal_init, 551 .irq_ack = sun8i_h3_irq_ack, 552 .calc_temp = sun8i_ths_calc_temp, 553}; 554 555static const struct ths_thermal_chip sun8i_h3_ths = { 556 .sensor_num = 1, 557 .scale = 1211, 558 .offset = 217000, 559 .has_mod_clk = true, 560 .has_bus_clk_reset = true, 561 .temp_data_base = SUN8I_THS_TEMP_DATA, 562 .calibrate = sun8i_h3_ths_calibrate, 563 .init = sun8i_h3_thermal_init, 564 .irq_ack = sun8i_h3_irq_ack, 565 .calc_temp = sun8i_ths_calc_temp, 566}; 567 568static const struct ths_thermal_chip sun8i_r40_ths = { 569 .sensor_num = 2, 570 .offset = 251086, 571 .scale = 1130, 572 .has_mod_clk = true, 573 .has_bus_clk_reset = true, 574 .temp_data_base = SUN8I_THS_TEMP_DATA, 575 .calibrate = sun8i_h3_ths_calibrate, 576 .init = sun8i_h3_thermal_init, 577 .irq_ack = sun8i_h3_irq_ack, 578 .calc_temp = sun8i_ths_calc_temp, 579}; 580 581static const struct ths_thermal_chip sun50i_a64_ths = { 582 .sensor_num = 3, 583 .offset = 260890, 584 .scale = 1170, 585 .has_mod_clk = true, 586 .has_bus_clk_reset = true, 587 .temp_data_base = SUN8I_THS_TEMP_DATA, 588 .calibrate = sun8i_h3_ths_calibrate, 589 .init = sun8i_h3_thermal_init, 590 .irq_ack = sun8i_h3_irq_ack, 591 .calc_temp = sun8i_ths_calc_temp, 592}; 593 594static const struct ths_thermal_chip sun50i_a100_ths = { 595 .sensor_num = 3, 596 .has_bus_clk_reset = true, 597 .ft_deviation = 8000, 598 .offset = 187744, 599 .scale = 672, 600 .temp_data_base = SUN50I_H6_THS_TEMP_DATA, 601 .calibrate = sun50i_h6_ths_calibrate, 602 .init = sun50i_h6_thermal_init, 603 .irq_ack = sun50i_h6_irq_ack, 604 .calc_temp = sun8i_ths_calc_temp, 605}; 606 607static const struct ths_thermal_chip sun50i_h5_ths = { 608 .sensor_num = 2, 609 .has_mod_clk = true, 610 .has_bus_clk_reset = true, 611 .temp_data_base = SUN8I_THS_TEMP_DATA, 612 .calibrate = sun8i_h3_ths_calibrate, 613 .init = sun8i_h3_thermal_init, 614 .irq_ack = sun8i_h3_irq_ack, 615 .calc_temp = sun50i_h5_calc_temp, 616}; 617 618static const struct ths_thermal_chip sun50i_h6_ths = { 619 .sensor_num = 2, 620 .has_bus_clk_reset = true, 621 .ft_deviation = 7000, 622 .offset = 187744, 623 .scale = 672, 624 .temp_data_base = SUN50I_H6_THS_TEMP_DATA, 625 .calibrate = sun50i_h6_ths_calibrate, 626 .init = sun50i_h6_thermal_init, 627 .irq_ack = sun50i_h6_irq_ack, 628 .calc_temp = sun8i_ths_calc_temp, 629}; 630 631static const struct of_device_id of_ths_match[] = { 632 { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths }, 633 { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths }, 634 { .compatible = "allwinner,sun8i-r40-ths", .data = &sun8i_r40_ths }, 635 { .compatible = "allwinner,sun50i-a64-ths", .data = &sun50i_a64_ths }, 636 { .compatible = "allwinner,sun50i-a100-ths", .data = &sun50i_a100_ths }, 637 { .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths }, 638 { .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths }, 639 { /* sentinel */ }, 640}; 641MODULE_DEVICE_TABLE(of, of_ths_match); 642 643static struct platform_driver ths_driver = { 644 .probe = sun8i_ths_probe, 645 .remove = sun8i_ths_remove, 646 .driver = { 647 .name = "sun8i-thermal", 648 .of_match_table = of_ths_match, 649 }, 650}; 651module_platform_driver(ths_driver); 652 653MODULE_DESCRIPTION("Thermal sensor driver for Allwinner SOC"); 654MODULE_LICENSE("GPL v2");