0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/cpufreq.h>
0013 #include <linux/delay.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/module.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/io.h>
0018 #include <linux/of_device.h>
0019
0020 #include "thermal_core.h"
0021
0022 #define HI6220_TEMP0_LAG (0x0)
0023 #define HI6220_TEMP0_TH (0x4)
0024 #define HI6220_TEMP0_RST_TH (0x8)
0025 #define HI6220_TEMP0_CFG (0xC)
0026 #define HI6220_TEMP0_CFG_SS_MSK (0xF000)
0027 #define HI6220_TEMP0_CFG_HDAK_MSK (0x30)
0028 #define HI6220_TEMP0_EN (0x10)
0029 #define HI6220_TEMP0_INT_EN (0x14)
0030 #define HI6220_TEMP0_INT_CLR (0x18)
0031 #define HI6220_TEMP0_RST_MSK (0x1C)
0032 #define HI6220_TEMP0_VALUE (0x28)
0033
0034 #define HI3660_OFFSET(chan) ((chan) * 0x40)
0035 #define HI3660_TEMP(chan) (HI3660_OFFSET(chan) + 0x1C)
0036 #define HI3660_TH(chan) (HI3660_OFFSET(chan) + 0x20)
0037 #define HI3660_LAG(chan) (HI3660_OFFSET(chan) + 0x28)
0038 #define HI3660_INT_EN(chan) (HI3660_OFFSET(chan) + 0x2C)
0039 #define HI3660_INT_CLR(chan) (HI3660_OFFSET(chan) + 0x30)
0040
0041 #define HI6220_TEMP_BASE (-60000)
0042 #define HI6220_TEMP_RESET (100000)
0043 #define HI6220_TEMP_STEP (785)
0044 #define HI6220_TEMP_LAG (3500)
0045
0046 #define HI3660_TEMP_BASE (-63780)
0047 #define HI3660_TEMP_STEP (205)
0048 #define HI3660_TEMP_LAG (4000)
0049
0050 #define HI6220_CLUSTER0_SENSOR 2
0051 #define HI6220_CLUSTER1_SENSOR 1
0052
0053 #define HI3660_LITTLE_SENSOR 0
0054 #define HI3660_BIG_SENSOR 1
0055 #define HI3660_G3D_SENSOR 2
0056 #define HI3660_MODEM_SENSOR 3
0057
0058 struct hisi_thermal_data;
0059
0060 struct hisi_thermal_sensor {
0061 struct hisi_thermal_data *data;
0062 struct thermal_zone_device *tzd;
0063 const char *irq_name;
0064 uint32_t id;
0065 uint32_t thres_temp;
0066 };
0067
0068 struct hisi_thermal_ops {
0069 int (*get_temp)(struct hisi_thermal_sensor *sensor);
0070 int (*enable_sensor)(struct hisi_thermal_sensor *sensor);
0071 int (*disable_sensor)(struct hisi_thermal_sensor *sensor);
0072 int (*irq_handler)(struct hisi_thermal_sensor *sensor);
0073 int (*probe)(struct hisi_thermal_data *data);
0074 };
0075
0076 struct hisi_thermal_data {
0077 const struct hisi_thermal_ops *ops;
0078 struct hisi_thermal_sensor *sensor;
0079 struct platform_device *pdev;
0080 struct clk *clk;
0081 void __iomem *regs;
0082 int nr_sensors;
0083 };
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103 static inline int hi6220_thermal_step_to_temp(int step)
0104 {
0105 return HI6220_TEMP_BASE + (step * HI6220_TEMP_STEP);
0106 }
0107
0108 static inline int hi6220_thermal_temp_to_step(int temp)
0109 {
0110 return DIV_ROUND_UP(temp - HI6220_TEMP_BASE, HI6220_TEMP_STEP);
0111 }
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 static inline int hi3660_thermal_step_to_temp(int step)
0122 {
0123 return HI3660_TEMP_BASE + step * HI3660_TEMP_STEP;
0124 }
0125
0126 static inline int hi3660_thermal_temp_to_step(int temp)
0127 {
0128 return DIV_ROUND_UP(temp - HI3660_TEMP_BASE, HI3660_TEMP_STEP);
0129 }
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 static inline void hi6220_thermal_set_lag(void __iomem *addr, int value)
0163 {
0164 writel(DIV_ROUND_UP(value, HI6220_TEMP_STEP) & 0x1F,
0165 addr + HI6220_TEMP0_LAG);
0166 }
0167
0168 static inline void hi6220_thermal_alarm_clear(void __iomem *addr, int value)
0169 {
0170 writel(value, addr + HI6220_TEMP0_INT_CLR);
0171 }
0172
0173 static inline void hi6220_thermal_alarm_enable(void __iomem *addr, int value)
0174 {
0175 writel(value, addr + HI6220_TEMP0_INT_EN);
0176 }
0177
0178 static inline void hi6220_thermal_alarm_set(void __iomem *addr, int temp)
0179 {
0180 writel(hi6220_thermal_temp_to_step(temp) | 0x0FFFFFF00,
0181 addr + HI6220_TEMP0_TH);
0182 }
0183
0184 static inline void hi6220_thermal_reset_set(void __iomem *addr, int temp)
0185 {
0186 writel(hi6220_thermal_temp_to_step(temp), addr + HI6220_TEMP0_RST_TH);
0187 }
0188
0189 static inline void hi6220_thermal_reset_enable(void __iomem *addr, int value)
0190 {
0191 writel(value, addr + HI6220_TEMP0_RST_MSK);
0192 }
0193
0194 static inline void hi6220_thermal_enable(void __iomem *addr, int value)
0195 {
0196 writel(value, addr + HI6220_TEMP0_EN);
0197 }
0198
0199 static inline int hi6220_thermal_get_temperature(void __iomem *addr)
0200 {
0201 return hi6220_thermal_step_to_temp(readl(addr + HI6220_TEMP0_VALUE));
0202 }
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213 static inline void hi3660_thermal_set_lag(void __iomem *addr,
0214 int id, int value)
0215 {
0216 writel(DIV_ROUND_UP(value, HI3660_TEMP_STEP) & 0x7F,
0217 addr + HI3660_LAG(id));
0218 }
0219
0220 static inline void hi3660_thermal_alarm_clear(void __iomem *addr,
0221 int id, int value)
0222 {
0223 writel(value, addr + HI3660_INT_CLR(id));
0224 }
0225
0226 static inline void hi3660_thermal_alarm_enable(void __iomem *addr,
0227 int id, int value)
0228 {
0229 writel(value, addr + HI3660_INT_EN(id));
0230 }
0231
0232 static inline void hi3660_thermal_alarm_set(void __iomem *addr,
0233 int id, int value)
0234 {
0235 writel(value, addr + HI3660_TH(id));
0236 }
0237
0238 static inline int hi3660_thermal_get_temperature(void __iomem *addr, int id)
0239 {
0240 return hi3660_thermal_step_to_temp(readl(addr + HI3660_TEMP(id)));
0241 }
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253 static inline void hi6220_thermal_sensor_select(void __iomem *addr, int sensor)
0254 {
0255 writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_SS_MSK) |
0256 (sensor << 12), addr + HI6220_TEMP0_CFG);
0257 }
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269 static inline void hi6220_thermal_hdak_set(void __iomem *addr, int value)
0270 {
0271 writel((readl(addr + HI6220_TEMP0_CFG) & ~HI6220_TEMP0_CFG_HDAK_MSK) |
0272 (value << 4), addr + HI6220_TEMP0_CFG);
0273 }
0274
0275 static int hi6220_thermal_irq_handler(struct hisi_thermal_sensor *sensor)
0276 {
0277 struct hisi_thermal_data *data = sensor->data;
0278
0279 hi6220_thermal_alarm_clear(data->regs, 1);
0280 return 0;
0281 }
0282
0283 static int hi3660_thermal_irq_handler(struct hisi_thermal_sensor *sensor)
0284 {
0285 struct hisi_thermal_data *data = sensor->data;
0286
0287 hi3660_thermal_alarm_clear(data->regs, sensor->id, 1);
0288 return 0;
0289 }
0290
0291 static int hi6220_thermal_get_temp(struct hisi_thermal_sensor *sensor)
0292 {
0293 struct hisi_thermal_data *data = sensor->data;
0294
0295 return hi6220_thermal_get_temperature(data->regs);
0296 }
0297
0298 static int hi3660_thermal_get_temp(struct hisi_thermal_sensor *sensor)
0299 {
0300 struct hisi_thermal_data *data = sensor->data;
0301
0302 return hi3660_thermal_get_temperature(data->regs, sensor->id);
0303 }
0304
0305 static int hi6220_thermal_disable_sensor(struct hisi_thermal_sensor *sensor)
0306 {
0307 struct hisi_thermal_data *data = sensor->data;
0308
0309
0310 hi6220_thermal_enable(data->regs, 0);
0311 hi6220_thermal_alarm_enable(data->regs, 0);
0312 hi6220_thermal_reset_enable(data->regs, 0);
0313
0314 clk_disable_unprepare(data->clk);
0315
0316 return 0;
0317 }
0318
0319 static int hi3660_thermal_disable_sensor(struct hisi_thermal_sensor *sensor)
0320 {
0321 struct hisi_thermal_data *data = sensor->data;
0322
0323
0324 hi3660_thermal_alarm_enable(data->regs, sensor->id, 0);
0325 return 0;
0326 }
0327
0328 static int hi6220_thermal_enable_sensor(struct hisi_thermal_sensor *sensor)
0329 {
0330 struct hisi_thermal_data *data = sensor->data;
0331 int ret;
0332
0333
0334 ret = clk_prepare_enable(data->clk);
0335 if (ret)
0336 return ret;
0337
0338
0339 hi6220_thermal_reset_enable(data->regs, 0);
0340 hi6220_thermal_enable(data->regs, 0);
0341
0342
0343 hi6220_thermal_sensor_select(data->regs, sensor->id);
0344
0345
0346 hi6220_thermal_hdak_set(data->regs, 0);
0347
0348
0349 hi6220_thermal_set_lag(data->regs, HI6220_TEMP_LAG);
0350
0351
0352 hi6220_thermal_alarm_set(data->regs, sensor->thres_temp);
0353
0354 hi6220_thermal_reset_set(data->regs, HI6220_TEMP_RESET);
0355
0356
0357 hi6220_thermal_reset_enable(data->regs, 1);
0358 hi6220_thermal_enable(data->regs, 1);
0359
0360 hi6220_thermal_alarm_clear(data->regs, 0);
0361 hi6220_thermal_alarm_enable(data->regs, 1);
0362
0363 return 0;
0364 }
0365
0366 static int hi3660_thermal_enable_sensor(struct hisi_thermal_sensor *sensor)
0367 {
0368 unsigned int value;
0369 struct hisi_thermal_data *data = sensor->data;
0370
0371
0372 hi3660_thermal_alarm_enable(data->regs, sensor->id, 0);
0373
0374
0375 hi3660_thermal_set_lag(data->regs, sensor->id, HI3660_TEMP_LAG);
0376
0377
0378 value = hi3660_thermal_temp_to_step(sensor->thres_temp);
0379 hi3660_thermal_alarm_set(data->regs, sensor->id, value);
0380
0381
0382 hi3660_thermal_alarm_clear(data->regs, sensor->id, 1);
0383 hi3660_thermal_alarm_enable(data->regs, sensor->id, 1);
0384
0385 return 0;
0386 }
0387
0388 static int hi6220_thermal_probe(struct hisi_thermal_data *data)
0389 {
0390 struct platform_device *pdev = data->pdev;
0391 struct device *dev = &pdev->dev;
0392 int ret;
0393
0394 data->clk = devm_clk_get(dev, "thermal_clk");
0395 if (IS_ERR(data->clk)) {
0396 ret = PTR_ERR(data->clk);
0397 if (ret != -EPROBE_DEFER)
0398 dev_err(dev, "failed to get thermal clk: %d\n", ret);
0399 return ret;
0400 }
0401
0402 data->sensor = devm_kzalloc(dev, sizeof(*data->sensor), GFP_KERNEL);
0403 if (!data->sensor)
0404 return -ENOMEM;
0405
0406 data->sensor[0].id = HI6220_CLUSTER0_SENSOR;
0407 data->sensor[0].irq_name = "tsensor_intr";
0408 data->sensor[0].data = data;
0409 data->nr_sensors = 1;
0410
0411 return 0;
0412 }
0413
0414 static int hi3660_thermal_probe(struct hisi_thermal_data *data)
0415 {
0416 struct platform_device *pdev = data->pdev;
0417 struct device *dev = &pdev->dev;
0418
0419 data->nr_sensors = 1;
0420
0421 data->sensor = devm_kzalloc(dev, sizeof(*data->sensor) *
0422 data->nr_sensors, GFP_KERNEL);
0423 if (!data->sensor)
0424 return -ENOMEM;
0425
0426 data->sensor[0].id = HI3660_BIG_SENSOR;
0427 data->sensor[0].irq_name = "tsensor_a73";
0428 data->sensor[0].data = data;
0429
0430 data->sensor[1].id = HI3660_LITTLE_SENSOR;
0431 data->sensor[1].irq_name = "tsensor_a53";
0432 data->sensor[1].data = data;
0433
0434 return 0;
0435 }
0436
0437 static int hisi_thermal_get_temp(void *__data, int *temp)
0438 {
0439 struct hisi_thermal_sensor *sensor = __data;
0440 struct hisi_thermal_data *data = sensor->data;
0441
0442 *temp = data->ops->get_temp(sensor);
0443
0444 dev_dbg(&data->pdev->dev, "tzd=%p, id=%d, temp=%d, thres=%d\n",
0445 sensor->tzd, sensor->id, *temp, sensor->thres_temp);
0446
0447 return 0;
0448 }
0449
0450 static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = {
0451 .get_temp = hisi_thermal_get_temp,
0452 };
0453
0454 static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev)
0455 {
0456 struct hisi_thermal_sensor *sensor = dev;
0457 struct hisi_thermal_data *data = sensor->data;
0458 int temp = 0;
0459
0460 data->ops->irq_handler(sensor);
0461
0462 hisi_thermal_get_temp(sensor, &temp);
0463
0464 if (temp >= sensor->thres_temp) {
0465 dev_crit(&data->pdev->dev,
0466 "sensor <%d> THERMAL ALARM: %d > %d\n",
0467 sensor->id, temp, sensor->thres_temp);
0468
0469 thermal_zone_device_update(sensor->tzd,
0470 THERMAL_EVENT_UNSPECIFIED);
0471
0472 } else {
0473 dev_crit(&data->pdev->dev,
0474 "sensor <%d> THERMAL ALARM stopped: %d < %d\n",
0475 sensor->id, temp, sensor->thres_temp);
0476 }
0477
0478 return IRQ_HANDLED;
0479 }
0480
0481 static int hisi_thermal_register_sensor(struct platform_device *pdev,
0482 struct hisi_thermal_sensor *sensor)
0483 {
0484 int ret, i;
0485 const struct thermal_trip *trip;
0486
0487 sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev,
0488 sensor->id, sensor,
0489 &hisi_of_thermal_ops);
0490 if (IS_ERR(sensor->tzd)) {
0491 ret = PTR_ERR(sensor->tzd);
0492 sensor->tzd = NULL;
0493 dev_err(&pdev->dev, "failed to register sensor id %d: %d\n",
0494 sensor->id, ret);
0495 return ret;
0496 }
0497
0498 trip = of_thermal_get_trip_points(sensor->tzd);
0499
0500 for (i = 0; i < of_thermal_get_ntrips(sensor->tzd); i++) {
0501 if (trip[i].type == THERMAL_TRIP_PASSIVE) {
0502 sensor->thres_temp = trip[i].temperature;
0503 break;
0504 }
0505 }
0506
0507 return 0;
0508 }
0509
0510 static const struct hisi_thermal_ops hi6220_ops = {
0511 .get_temp = hi6220_thermal_get_temp,
0512 .enable_sensor = hi6220_thermal_enable_sensor,
0513 .disable_sensor = hi6220_thermal_disable_sensor,
0514 .irq_handler = hi6220_thermal_irq_handler,
0515 .probe = hi6220_thermal_probe,
0516 };
0517
0518 static const struct hisi_thermal_ops hi3660_ops = {
0519 .get_temp = hi3660_thermal_get_temp,
0520 .enable_sensor = hi3660_thermal_enable_sensor,
0521 .disable_sensor = hi3660_thermal_disable_sensor,
0522 .irq_handler = hi3660_thermal_irq_handler,
0523 .probe = hi3660_thermal_probe,
0524 };
0525
0526 static const struct of_device_id of_hisi_thermal_match[] = {
0527 {
0528 .compatible = "hisilicon,tsensor",
0529 .data = &hi6220_ops,
0530 },
0531 {
0532 .compatible = "hisilicon,hi3660-tsensor",
0533 .data = &hi3660_ops,
0534 },
0535 { }
0536 };
0537 MODULE_DEVICE_TABLE(of, of_hisi_thermal_match);
0538
0539 static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
0540 bool on)
0541 {
0542 struct thermal_zone_device *tzd = sensor->tzd;
0543
0544 if (on)
0545 thermal_zone_device_enable(tzd);
0546 else
0547 thermal_zone_device_disable(tzd);
0548 }
0549
0550 static int hisi_thermal_probe(struct platform_device *pdev)
0551 {
0552 struct hisi_thermal_data *data;
0553 struct device *dev = &pdev->dev;
0554 struct resource *res;
0555 int i, ret;
0556
0557 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0558 if (!data)
0559 return -ENOMEM;
0560
0561 data->pdev = pdev;
0562 platform_set_drvdata(pdev, data);
0563 data->ops = of_device_get_match_data(dev);
0564
0565 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0566 data->regs = devm_ioremap_resource(dev, res);
0567 if (IS_ERR(data->regs))
0568 return PTR_ERR(data->regs);
0569
0570 ret = data->ops->probe(data);
0571 if (ret)
0572 return ret;
0573
0574 for (i = 0; i < data->nr_sensors; i++) {
0575 struct hisi_thermal_sensor *sensor = &data->sensor[i];
0576
0577 ret = hisi_thermal_register_sensor(pdev, sensor);
0578 if (ret) {
0579 dev_err(dev, "failed to register thermal sensor: %d\n",
0580 ret);
0581 return ret;
0582 }
0583
0584 ret = platform_get_irq(pdev, 0);
0585 if (ret < 0)
0586 return ret;
0587
0588 ret = devm_request_threaded_irq(dev, ret, NULL,
0589 hisi_thermal_alarm_irq_thread,
0590 IRQF_ONESHOT, sensor->irq_name,
0591 sensor);
0592 if (ret < 0) {
0593 dev_err(dev, "Failed to request alarm irq: %d\n", ret);
0594 return ret;
0595 }
0596
0597 ret = data->ops->enable_sensor(sensor);
0598 if (ret) {
0599 dev_err(dev, "Failed to setup the sensor: %d\n", ret);
0600 return ret;
0601 }
0602
0603 hisi_thermal_toggle_sensor(sensor, true);
0604 }
0605
0606 return 0;
0607 }
0608
0609 static int hisi_thermal_remove(struct platform_device *pdev)
0610 {
0611 struct hisi_thermal_data *data = platform_get_drvdata(pdev);
0612 int i;
0613
0614 for (i = 0; i < data->nr_sensors; i++) {
0615 struct hisi_thermal_sensor *sensor = &data->sensor[i];
0616
0617 hisi_thermal_toggle_sensor(sensor, false);
0618 data->ops->disable_sensor(sensor);
0619 }
0620
0621 return 0;
0622 }
0623
0624 static int hisi_thermal_suspend(struct device *dev)
0625 {
0626 struct hisi_thermal_data *data = dev_get_drvdata(dev);
0627 int i;
0628
0629 for (i = 0; i < data->nr_sensors; i++)
0630 data->ops->disable_sensor(&data->sensor[i]);
0631
0632 return 0;
0633 }
0634
0635 static int hisi_thermal_resume(struct device *dev)
0636 {
0637 struct hisi_thermal_data *data = dev_get_drvdata(dev);
0638 int i, ret = 0;
0639
0640 for (i = 0; i < data->nr_sensors; i++)
0641 ret |= data->ops->enable_sensor(&data->sensor[i]);
0642
0643 return ret;
0644 }
0645
0646 static DEFINE_SIMPLE_DEV_PM_OPS(hisi_thermal_pm_ops,
0647 hisi_thermal_suspend, hisi_thermal_resume);
0648
0649 static struct platform_driver hisi_thermal_driver = {
0650 .driver = {
0651 .name = "hisi_thermal",
0652 .pm = pm_sleep_ptr(&hisi_thermal_pm_ops),
0653 .of_match_table = of_hisi_thermal_match,
0654 },
0655 .probe = hisi_thermal_probe,
0656 .remove = hisi_thermal_remove,
0657 };
0658
0659 module_platform_driver(hisi_thermal_driver);
0660
0661 MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
0662 MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
0663 MODULE_DESCRIPTION("HiSilicon thermal driver");
0664 MODULE_LICENSE("GPL v2");