hisi_thermal.c (17459B)
1/* 2 * HiSilicon thermal sensor driver 3 * 4 * Copyright (c) 2014-2015 HiSilicon Limited. 5 * Copyright (c) 2014-2015 Linaro Limited. 6 * 7 * Xinwei Kong <kong.kongxinwei@hisilicon.com> 8 * Leo Yan <leo.yan@linaro.org> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 * 14 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 15 * kind, whether express or implied; without even the implied warranty 16 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 */ 19 20#include <linux/cpufreq.h> 21#include <linux/delay.h> 22#include <linux/interrupt.h> 23#include <linux/module.h> 24#include <linux/platform_device.h> 25#include <linux/io.h> 26#include <linux/of_device.h> 27 28#include "thermal_core.h" 29 30#define HI6220_TEMP0_LAG (0x0) 31#define HI6220_TEMP0_TH (0x4) 32#define HI6220_TEMP0_RST_TH (0x8) 33#define HI6220_TEMP0_CFG (0xC) 34#define HI6220_TEMP0_CFG_SS_MSK (0xF000) 35#define HI6220_TEMP0_CFG_HDAK_MSK (0x30) 36#define HI6220_TEMP0_EN (0x10) 37#define HI6220_TEMP0_INT_EN (0x14) 38#define HI6220_TEMP0_INT_CLR (0x18) 39#define HI6220_TEMP0_RST_MSK (0x1C) 40#define HI6220_TEMP0_VALUE (0x28) 41 42#define HI3660_OFFSET(chan) ((chan) * 0x40) 43#define HI3660_TEMP(chan) (HI3660_OFFSET(chan) + 0x1C) 44#define HI3660_TH(chan) (HI3660_OFFSET(chan) + 0x20) 45#define HI3660_LAG(chan) (HI3660_OFFSET(chan) + 0x28) 46#define HI3660_INT_EN(chan) (HI3660_OFFSET(chan) + 0x2C) 47#define HI3660_INT_CLR(chan) (HI3660_OFFSET(chan) + 0x30) 48 49#define HI6220_TEMP_BASE (-60000) 50#define HI6220_TEMP_RESET (100000) 51#define HI6220_TEMP_STEP (785) 52#define HI6220_TEMP_LAG (3500) 53 54#define HI3660_TEMP_BASE (-63780) 55#define HI3660_TEMP_STEP (205) 56#define HI3660_TEMP_LAG (4000) 57 58#define HI6220_CLUSTER0_SENSOR 2 59#define HI6220_CLUSTER1_SENSOR 1 60 61#define HI3660_LITTLE_SENSOR 0 62#define HI3660_BIG_SENSOR 1 63#define HI3660_G3D_SENSOR 2 64#define HI3660_MODEM_SENSOR 3 65 66struct hisi_thermal_data; 67 68struct hisi_thermal_sensor { 69 struct hisi_thermal_data *data; 70 struct thermal_zone_device *tzd; 71 const char *irq_name; 72 uint32_t id; 73 uint32_t thres_temp; 74}; 75 76struct hisi_thermal_ops { 77 int (*get_temp)(struct hisi_thermal_sensor *sensor); 78 int (*enable_sensor)(struct hisi_thermal_sensor *sensor); 79 int (*disable_sensor)(struct hisi_thermal_sensor *sensor); 80 int (*irq_handler)(struct hisi_thermal_sensor *sensor); 81 int (*probe)(struct hisi_thermal_data *data); 82}; 83 84struct hisi_thermal_data { 85 const struct hisi_thermal_ops *ops; 86 struct hisi_thermal_sensor *sensor; 87 struct platform_device *pdev; 88 struct clk *clk; 89 void __iomem *regs; 90 int nr_sensors; 91}; 92 93/* 94 * The temperature computation on the tsensor is as follow: 95 * Unit: millidegree Celsius 96 * Step: 200/255 (0.7843) 97 * Temperature base: -60°C 98 * 99 * The register is programmed in temperature steps, every step is 785 100 * millidegree and begins at -60 000 m°C 101 * 102 * The temperature from the steps: 103 * 104 * Temp = TempBase + (steps x 785) 105 * 106 * and the steps from the temperature: 107 * 108 * steps = (Temp - TempBase) / 785 109 * 110 */ 111static inline int hi6220_thermal_step_to_temp(int step) 112{ 113 return HI6220_TEMP_BASE + (step * HI6220_TEMP_STEP); 114} 115 116static inline int hi6220_thermal_temp_to_step(int temp) 117{ 118 return DIV_ROUND_UP(temp - HI6220_TEMP_BASE, HI6220_TEMP_STEP); 119} 120 121/* 122 * for Hi3660, 123 * Step: 189/922 (0.205) 124 * Temperature base: -63.780°C 125 * 126 * The register is programmed in temperature steps, every step is 205 127 * millidegree and begins at -63 780 m°C 128 */ 129static inline int hi3660_thermal_step_to_temp(int step) 130{ 131 return HI3660_TEMP_BASE + step * HI3660_TEMP_STEP; 132} 133 134static inline int hi3660_thermal_temp_to_step(int temp) 135{ 136 return DIV_ROUND_UP(temp - HI3660_TEMP_BASE, HI3660_TEMP_STEP); 137} 138 139/* 140 * The lag register contains 5 bits encoding the temperature in steps. 141 * 142 * Each time the temperature crosses the threshold boundary, an 143 * interrupt is raised. It could be when the temperature is going 144 * above the threshold or below. However, if the temperature is 145 * fluctuating around this value due to the load, we can receive 146 * several interrupts which may not desired. 147 * 148 * We can setup a temperature representing the delta between the 149 * threshold and the current temperature when the temperature is 150 * decreasing. 151 * 152 * For instance: the lag register is 5°C, the threshold is 65°C, when 153 * the temperature reaches 65°C an interrupt is raised and when the 154 * temperature decrease to 65°C - 5°C another interrupt is raised. 155 * 156 * A very short lag can lead to an interrupt storm, a long lag 157 * increase the latency to react to the temperature changes. In our 158 * case, that is not really a problem as we are polling the 159 * temperature. 160 * 161 * [0:4] : lag register 162 * 163 * The temperature is coded in steps, cf. HI6220_TEMP_STEP. 164 * 165 * Min : 0x00 : 0.0 °C 166 * Max : 0x1F : 24.3 °C 167 * 168 * The 'value' parameter is in milliCelsius. 169 */ 170static inline void hi6220_thermal_set_lag(void __iomem *addr, int value) 171{ 172 writel(DIV_ROUND_UP(value, HI6220_TEMP_STEP) & 0x1F, 173 addr + HI6220_TEMP0_LAG); 174} 175 176static inline void hi6220_thermal_alarm_clear(void __iomem *addr, int value) 177{ 178 writel(value, addr + HI6220_TEMP0_INT_CLR); 179} 180 181static inline void hi6220_thermal_alarm_enable(void __iomem *addr, int value) 182{ 183 writel(value, addr + HI6220_TEMP0_INT_EN); 184} 185 186static inline void hi6220_thermal_alarm_set(void __iomem *addr, int temp) 187{ 188 writel(hi6220_thermal_temp_to_step(temp) | 0x0FFFFFF00, 189 addr + HI6220_TEMP0_TH); 190} 191 192static inline void hi6220_thermal_reset_set(void __iomem *addr, int temp) 193{ 194 writel(hi6220_thermal_temp_to_step(temp), addr + HI6220_TEMP0_RST_TH); 195} 196 197static inline void hi6220_thermal_reset_enable(void __iomem *addr, int value) 198{ 199 writel(value, addr + HI6220_TEMP0_RST_MSK); 200} 201 202static inline void hi6220_thermal_enable(void __iomem *addr, int value) 203{ 204 writel(value, addr + HI6220_TEMP0_EN); 205} 206 207static inline int hi6220_thermal_get_temperature(void __iomem *addr) 208{ 209 return hi6220_thermal_step_to_temp(readl(addr + HI6220_TEMP0_VALUE)); 210} 211 212/* 213 * [0:6] lag register 214 * 215 * The temperature is coded in steps, cf. HI3660_TEMP_STEP. 216 * 217 * Min : 0x00 : 0.0 °C 218 * Max : 0x7F : 26.0 °C 219 * 220 */ 221static inline void hi3660_thermal_set_lag(void __iomem *addr, 222 int id, int value) 223{ 224 writel(DIV_ROUND_UP(value, HI3660_TEMP_STEP) & 0x7F, 225 addr + HI3660_LAG(id)); 226} 227 228static inline void hi3660_thermal_alarm_clear(void __iomem *addr, 229 int id, int value) 230{ 231 writel(value, addr + HI3660_INT_CLR(id)); 232} 233 234static inline void hi3660_thermal_alarm_enable(void __iomem *addr, 235 int id, int value) 236{ 237 writel(value, addr + HI3660_INT_EN(id)); 238} 239 240static inline void hi3660_thermal_alarm_set(void __iomem *addr, 241 int id, int value) 242{ 243 writel(value, addr + HI3660_TH(id)); 244} 245 246static inline int hi3660_thermal_get_temperature(void __iomem *addr, int id) 247{ 248 return hi3660_thermal_step_to_temp(readl(addr + HI3660_TEMP(id))); 249} 250 251/* 252 * Temperature configuration register - Sensor selection 253 * 254 * Bits [19:12] 255 * 256 * 0x0: local sensor (default) 257 * 0x1: remote sensor 1 (ACPU cluster 1) 258 * 0x2: remote sensor 2 (ACPU cluster 0) 259 * 0x3: remote sensor 3 (G3D) 260 */ 261static inline void hi6220_thermal_sensor_select(void __iomem *addr, int sensor) 262{ 263 writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_SS_MSK) | 264 (sensor << 12), addr + HI6220_TEMP0_CFG); 265} 266 267/* 268 * Temperature configuration register - Hdak conversion polling interval 269 * 270 * Bits [5:4] 271 * 272 * 0x0 : 0.768 ms 273 * 0x1 : 6.144 ms 274 * 0x2 : 49.152 ms 275 * 0x3 : 393.216 ms 276 */ 277static inline void hi6220_thermal_hdak_set(void __iomem *addr, int value) 278{ 279 writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_HDAK_MSK) | 280 (value << 4), addr + HI6220_TEMP0_CFG); 281} 282 283static int hi6220_thermal_irq_handler(struct hisi_thermal_sensor *sensor) 284{ 285 struct hisi_thermal_data *data = sensor->data; 286 287 hi6220_thermal_alarm_clear(data->regs, 1); 288 return 0; 289} 290 291static int hi3660_thermal_irq_handler(struct hisi_thermal_sensor *sensor) 292{ 293 struct hisi_thermal_data *data = sensor->data; 294 295 hi3660_thermal_alarm_clear(data->regs, sensor->id, 1); 296 return 0; 297} 298 299static int hi6220_thermal_get_temp(struct hisi_thermal_sensor *sensor) 300{ 301 struct hisi_thermal_data *data = sensor->data; 302 303 return hi6220_thermal_get_temperature(data->regs); 304} 305 306static int hi3660_thermal_get_temp(struct hisi_thermal_sensor *sensor) 307{ 308 struct hisi_thermal_data *data = sensor->data; 309 310 return hi3660_thermal_get_temperature(data->regs, sensor->id); 311} 312 313static int hi6220_thermal_disable_sensor(struct hisi_thermal_sensor *sensor) 314{ 315 struct hisi_thermal_data *data = sensor->data; 316 317 /* disable sensor module */ 318 hi6220_thermal_enable(data->regs, 0); 319 hi6220_thermal_alarm_enable(data->regs, 0); 320 hi6220_thermal_reset_enable(data->regs, 0); 321 322 clk_disable_unprepare(data->clk); 323 324 return 0; 325} 326 327static int hi3660_thermal_disable_sensor(struct hisi_thermal_sensor *sensor) 328{ 329 struct hisi_thermal_data *data = sensor->data; 330 331 /* disable sensor module */ 332 hi3660_thermal_alarm_enable(data->regs, sensor->id, 0); 333 return 0; 334} 335 336static int hi6220_thermal_enable_sensor(struct hisi_thermal_sensor *sensor) 337{ 338 struct hisi_thermal_data *data = sensor->data; 339 int ret; 340 341 /* enable clock for tsensor */ 342 ret = clk_prepare_enable(data->clk); 343 if (ret) 344 return ret; 345 346 /* disable module firstly */ 347 hi6220_thermal_reset_enable(data->regs, 0); 348 hi6220_thermal_enable(data->regs, 0); 349 350 /* select sensor id */ 351 hi6220_thermal_sensor_select(data->regs, sensor->id); 352 353 /* setting the hdak time */ 354 hi6220_thermal_hdak_set(data->regs, 0); 355 356 /* setting lag value between current temp and the threshold */ 357 hi6220_thermal_set_lag(data->regs, HI6220_TEMP_LAG); 358 359 /* enable for interrupt */ 360 hi6220_thermal_alarm_set(data->regs, sensor->thres_temp); 361 362 hi6220_thermal_reset_set(data->regs, HI6220_TEMP_RESET); 363 364 /* enable module */ 365 hi6220_thermal_reset_enable(data->regs, 1); 366 hi6220_thermal_enable(data->regs, 1); 367 368 hi6220_thermal_alarm_clear(data->regs, 0); 369 hi6220_thermal_alarm_enable(data->regs, 1); 370 371 return 0; 372} 373 374static int hi3660_thermal_enable_sensor(struct hisi_thermal_sensor *sensor) 375{ 376 unsigned int value; 377 struct hisi_thermal_data *data = sensor->data; 378 379 /* disable interrupt */ 380 hi3660_thermal_alarm_enable(data->regs, sensor->id, 0); 381 382 /* setting lag value between current temp and the threshold */ 383 hi3660_thermal_set_lag(data->regs, sensor->id, HI3660_TEMP_LAG); 384 385 /* set interrupt threshold */ 386 value = hi3660_thermal_temp_to_step(sensor->thres_temp); 387 hi3660_thermal_alarm_set(data->regs, sensor->id, value); 388 389 /* enable interrupt */ 390 hi3660_thermal_alarm_clear(data->regs, sensor->id, 1); 391 hi3660_thermal_alarm_enable(data->regs, sensor->id, 1); 392 393 return 0; 394} 395 396static int hi6220_thermal_probe(struct hisi_thermal_data *data) 397{ 398 struct platform_device *pdev = data->pdev; 399 struct device *dev = &pdev->dev; 400 int ret; 401 402 data->clk = devm_clk_get(dev, "thermal_clk"); 403 if (IS_ERR(data->clk)) { 404 ret = PTR_ERR(data->clk); 405 if (ret != -EPROBE_DEFER) 406 dev_err(dev, "failed to get thermal clk: %d\n", ret); 407 return ret; 408 } 409 410 data->sensor = devm_kzalloc(dev, sizeof(*data->sensor), GFP_KERNEL); 411 if (!data->sensor) 412 return -ENOMEM; 413 414 data->sensor[0].id = HI6220_CLUSTER0_SENSOR; 415 data->sensor[0].irq_name = "tsensor_intr"; 416 data->sensor[0].data = data; 417 data->nr_sensors = 1; 418 419 return 0; 420} 421 422static int hi3660_thermal_probe(struct hisi_thermal_data *data) 423{ 424 struct platform_device *pdev = data->pdev; 425 struct device *dev = &pdev->dev; 426 427 data->nr_sensors = 1; 428 429 data->sensor = devm_kzalloc(dev, sizeof(*data->sensor) * 430 data->nr_sensors, GFP_KERNEL); 431 if (!data->sensor) 432 return -ENOMEM; 433 434 data->sensor[0].id = HI3660_BIG_SENSOR; 435 data->sensor[0].irq_name = "tsensor_a73"; 436 data->sensor[0].data = data; 437 438 data->sensor[1].id = HI3660_LITTLE_SENSOR; 439 data->sensor[1].irq_name = "tsensor_a53"; 440 data->sensor[1].data = data; 441 442 return 0; 443} 444 445static int hisi_thermal_get_temp(void *__data, int *temp) 446{ 447 struct hisi_thermal_sensor *sensor = __data; 448 struct hisi_thermal_data *data = sensor->data; 449 450 *temp = data->ops->get_temp(sensor); 451 452 dev_dbg(&data->pdev->dev, "tzd=%p, id=%d, temp=%d, thres=%d\n", 453 sensor->tzd, sensor->id, *temp, sensor->thres_temp); 454 455 return 0; 456} 457 458static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = { 459 .get_temp = hisi_thermal_get_temp, 460}; 461 462static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) 463{ 464 struct hisi_thermal_sensor *sensor = dev; 465 struct hisi_thermal_data *data = sensor->data; 466 int temp = 0; 467 468 data->ops->irq_handler(sensor); 469 470 hisi_thermal_get_temp(sensor, &temp); 471 472 if (temp >= sensor->thres_temp) { 473 dev_crit(&data->pdev->dev, 474 "sensor <%d> THERMAL ALARM: %d > %d\n", 475 sensor->id, temp, sensor->thres_temp); 476 477 thermal_zone_device_update(sensor->tzd, 478 THERMAL_EVENT_UNSPECIFIED); 479 480 } else { 481 dev_crit(&data->pdev->dev, 482 "sensor <%d> THERMAL ALARM stopped: %d < %d\n", 483 sensor->id, temp, sensor->thres_temp); 484 } 485 486 return IRQ_HANDLED; 487} 488 489static int hisi_thermal_register_sensor(struct platform_device *pdev, 490 struct hisi_thermal_sensor *sensor) 491{ 492 int ret, i; 493 const struct thermal_trip *trip; 494 495 sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 496 sensor->id, sensor, 497 &hisi_of_thermal_ops); 498 if (IS_ERR(sensor->tzd)) { 499 ret = PTR_ERR(sensor->tzd); 500 sensor->tzd = NULL; 501 dev_err(&pdev->dev, "failed to register sensor id %d: %d\n", 502 sensor->id, ret); 503 return ret; 504 } 505 506 trip = of_thermal_get_trip_points(sensor->tzd); 507 508 for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) { 509 if (trip[i].type == THERMAL_TRIP_PASSIVE) { 510 sensor->thres_temp = trip[i].temperature; 511 break; 512 } 513 } 514 515 return 0; 516} 517 518static const struct hisi_thermal_ops hi6220_ops = { 519 .get_temp = hi6220_thermal_get_temp, 520 .enable_sensor = hi6220_thermal_enable_sensor, 521 .disable_sensor = hi6220_thermal_disable_sensor, 522 .irq_handler = hi6220_thermal_irq_handler, 523 .probe = hi6220_thermal_probe, 524}; 525 526static const struct hisi_thermal_ops hi3660_ops = { 527 .get_temp = hi3660_thermal_get_temp, 528 .enable_sensor = hi3660_thermal_enable_sensor, 529 .disable_sensor = hi3660_thermal_disable_sensor, 530 .irq_handler = hi3660_thermal_irq_handler, 531 .probe = hi3660_thermal_probe, 532}; 533 534static const struct of_device_id of_hisi_thermal_match[] = { 535 { 536 .compatible = "hisilicon,tsensor", 537 .data = &hi6220_ops, 538 }, 539 { 540 .compatible = "hisilicon,hi3660-tsensor", 541 .data = &hi3660_ops, 542 }, 543 { /* end */ } 544}; 545MODULE_DEVICE_TABLE(of, of_hisi_thermal_match); 546 547static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor, 548 bool on) 549{ 550 struct thermal_zone_device *tzd = sensor->tzd; 551 552 if (on) 553 thermal_zone_device_enable(tzd); 554 else 555 thermal_zone_device_disable(tzd); 556} 557 558static int hisi_thermal_probe(struct platform_device *pdev) 559{ 560 struct hisi_thermal_data *data; 561 struct device *dev = &pdev->dev; 562 struct resource *res; 563 int i, ret; 564 565 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 566 if (!data) 567 return -ENOMEM; 568 569 data->pdev = pdev; 570 platform_set_drvdata(pdev, data); 571 data->ops = of_device_get_match_data(dev); 572 573 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 574 data->regs = devm_ioremap_resource(dev, res); 575 if (IS_ERR(data->regs)) 576 return PTR_ERR(data->regs); 577 578 ret = data->ops->probe(data); 579 if (ret) 580 return ret; 581 582 for (i = 0; i < data->nr_sensors; i++) { 583 struct hisi_thermal_sensor *sensor = &data->sensor[i]; 584 585 ret = hisi_thermal_register_sensor(pdev, sensor); 586 if (ret) { 587 dev_err(dev, "failed to register thermal sensor: %d\n", 588 ret); 589 return ret; 590 } 591 592 ret = platform_get_irq(pdev, 0); 593 if (ret < 0) 594 return ret; 595 596 ret = devm_request_threaded_irq(dev, ret, NULL, 597 hisi_thermal_alarm_irq_thread, 598 IRQF_ONESHOT, sensor->irq_name, 599 sensor); 600 if (ret < 0) { 601 dev_err(dev, "Failed to request alarm irq: %d\n", ret); 602 return ret; 603 } 604 605 ret = data->ops->enable_sensor(sensor); 606 if (ret) { 607 dev_err(dev, "Failed to setup the sensor: %d\n", ret); 608 return ret; 609 } 610 611 hisi_thermal_toggle_sensor(sensor, true); 612 } 613 614 return 0; 615} 616 617static int hisi_thermal_remove(struct platform_device *pdev) 618{ 619 struct hisi_thermal_data *data = platform_get_drvdata(pdev); 620 int i; 621 622 for (i = 0; i < data->nr_sensors; i++) { 623 struct hisi_thermal_sensor *sensor = &data->sensor[i]; 624 625 hisi_thermal_toggle_sensor(sensor, false); 626 data->ops->disable_sensor(sensor); 627 } 628 629 return 0; 630} 631 632static int hisi_thermal_suspend(struct device *dev) 633{ 634 struct hisi_thermal_data *data = dev_get_drvdata(dev); 635 int i; 636 637 for (i = 0; i < data->nr_sensors; i++) 638 data->ops->disable_sensor(&data->sensor[i]); 639 640 return 0; 641} 642 643static int hisi_thermal_resume(struct device *dev) 644{ 645 struct hisi_thermal_data *data = dev_get_drvdata(dev); 646 int i, ret = 0; 647 648 for (i = 0; i < data->nr_sensors; i++) 649 ret |= data->ops->enable_sensor(&data->sensor[i]); 650 651 return ret; 652} 653 654static DEFINE_SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops, 655 hisi_thermal_suspend, hisi_thermal_resume); 656 657static struct platform_driver hisi_thermal_driver = { 658 .driver = { 659 .name = "hisi_thermal", 660 .pm = pm_sleep_ptr(&hisi_thermal_pm_ops), 661 .of_match_table = of_hisi_thermal_match, 662 }, 663 .probe = hisi_thermal_probe, 664 .remove = hisi_thermal_remove, 665}; 666 667module_platform_driver(hisi_thermal_driver); 668 669MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>"); 670MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>"); 671MODULE_DESCRIPTION("HiSilicon thermal driver"); 672MODULE_LICENSE("GPL v2");