diff options
Diffstat (limited to 'drivers/thermal/imx_thermal.c')
-rw-r--r-- | drivers/thermal/imx_thermal.c | 91 |
1 files changed, 78 insertions, 13 deletions
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 2c516f2eebed..461bf3d033a0 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/mfd/syscon.h> | 19 | #include <linux/mfd/syscon.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/of_device.h> | ||
22 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
23 | #include <linux/regmap.h> | 24 | #include <linux/regmap.h> |
24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
@@ -31,6 +32,11 @@ | |||
31 | 32 | ||
32 | #define MISC0 0x0150 | 33 | #define MISC0 0x0150 |
33 | #define MISC0_REFTOP_SELBIASOFF (1 << 3) | 34 | #define MISC0_REFTOP_SELBIASOFF (1 << 3) |
35 | #define MISC1 0x0160 | ||
36 | #define MISC1_IRQ_TEMPHIGH (1 << 29) | ||
37 | /* Below LOW and PANIC bits are only for TEMPMON_IMX6SX */ | ||
38 | #define MISC1_IRQ_TEMPLOW (1 << 28) | ||
39 | #define MISC1_IRQ_TEMPPANIC (1 << 27) | ||
34 | 40 | ||
35 | #define TEMPSENSE0 0x0180 | 41 | #define TEMPSENSE0 0x0180 |
36 | #define TEMPSENSE0_ALARM_VALUE_SHIFT 20 | 42 | #define TEMPSENSE0_ALARM_VALUE_SHIFT 20 |
@@ -43,6 +49,12 @@ | |||
43 | 49 | ||
44 | #define TEMPSENSE1 0x0190 | 50 | #define TEMPSENSE1 0x0190 |
45 | #define TEMPSENSE1_MEASURE_FREQ 0xffff | 51 | #define TEMPSENSE1_MEASURE_FREQ 0xffff |
52 | /* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */ | ||
53 | #define TEMPSENSE2 0x0290 | ||
54 | #define TEMPSENSE2_LOW_VALUE_SHIFT 0 | ||
55 | #define TEMPSENSE2_LOW_VALUE_MASK 0xfff | ||
56 | #define TEMPSENSE2_PANIC_VALUE_SHIFT 16 | ||
57 | #define TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000 | ||
46 | 58 | ||
47 | #define OCOTP_ANA1 0x04e0 | 59 | #define OCOTP_ANA1 0x04e0 |
48 | 60 | ||
@@ -66,6 +78,21 @@ enum imx_thermal_trip { | |||
66 | #define FACTOR1 15976 | 78 | #define FACTOR1 15976 |
67 | #define FACTOR2 4297157 | 79 | #define FACTOR2 4297157 |
68 | 80 | ||
81 | #define TEMPMON_IMX6Q 1 | ||
82 | #define TEMPMON_IMX6SX 2 | ||
83 | |||
84 | struct thermal_soc_data { | ||
85 | u32 version; | ||
86 | }; | ||
87 | |||
88 | static struct thermal_soc_data thermal_imx6q_data = { | ||
89 | .version = TEMPMON_IMX6Q, | ||
90 | }; | ||
91 | |||
92 | static struct thermal_soc_data thermal_imx6sx_data = { | ||
93 | .version = TEMPMON_IMX6SX, | ||
94 | }; | ||
95 | |||
69 | struct imx_thermal_data { | 96 | struct imx_thermal_data { |
70 | struct thermal_zone_device *tz; | 97 | struct thermal_zone_device *tz; |
71 | struct thermal_cooling_device *cdev; | 98 | struct thermal_cooling_device *cdev; |
@@ -79,8 +106,21 @@ struct imx_thermal_data { | |||
79 | bool irq_enabled; | 106 | bool irq_enabled; |
80 | int irq; | 107 | int irq; |
81 | struct clk *thermal_clk; | 108 | struct clk *thermal_clk; |
109 | const struct thermal_soc_data *socdata; | ||
82 | }; | 110 | }; |
83 | 111 | ||
112 | static void imx_set_panic_temp(struct imx_thermal_data *data, | ||
113 | signed long panic_temp) | ||
114 | { | ||
115 | struct regmap *map = data->tempmon; | ||
116 | int critical_value; | ||
117 | |||
118 | critical_value = (data->c2 - panic_temp) / data->c1; | ||
119 | regmap_write(map, TEMPSENSE2 + REG_CLR, TEMPSENSE2_PANIC_VALUE_MASK); | ||
120 | regmap_write(map, TEMPSENSE2 + REG_SET, critical_value << | ||
121 | TEMPSENSE2_PANIC_VALUE_SHIFT); | ||
122 | } | ||
123 | |||
84 | static void imx_set_alarm_temp(struct imx_thermal_data *data, | 124 | static void imx_set_alarm_temp(struct imx_thermal_data *data, |
85 | signed long alarm_temp) | 125 | signed long alarm_temp) |
86 | { | 126 | { |
@@ -142,13 +182,17 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp) | |||
142 | /* See imx_get_sensor_data() for formula derivation */ | 182 | /* See imx_get_sensor_data() for formula derivation */ |
143 | *temp = data->c2 - n_meas * data->c1; | 183 | *temp = data->c2 - n_meas * data->c1; |
144 | 184 | ||
145 | /* Update alarm value to next higher trip point */ | 185 | /* Update alarm value to next higher trip point for TEMPMON_IMX6Q */ |
146 | if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive) | 186 | if (data->socdata->version == TEMPMON_IMX6Q) { |
147 | imx_set_alarm_temp(data, data->temp_critical); | 187 | if (data->alarm_temp == data->temp_passive && |
148 | if (data->alarm_temp == data->temp_critical && *temp < data->temp_passive) { | 188 | *temp >= data->temp_passive) |
149 | imx_set_alarm_temp(data, data->temp_passive); | 189 | imx_set_alarm_temp(data, data->temp_critical); |
150 | dev_dbg(&tz->device, "thermal alarm off: T < %lu\n", | 190 | if (data->alarm_temp == data->temp_critical && |
151 | data->alarm_temp / 1000); | 191 | *temp < data->temp_passive) { |
192 | imx_set_alarm_temp(data, data->temp_passive); | ||
193 | dev_dbg(&tz->device, "thermal alarm off: T < %lu\n", | ||
194 | data->alarm_temp / 1000); | ||
195 | } | ||
152 | } | 196 | } |
153 | 197 | ||
154 | if (*temp != data->last_temp) { | 198 | if (*temp != data->last_temp) { |
@@ -398,8 +442,17 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev) | |||
398 | return IRQ_HANDLED; | 442 | return IRQ_HANDLED; |
399 | } | 443 | } |
400 | 444 | ||
445 | static const struct of_device_id of_imx_thermal_match[] = { | ||
446 | { .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, }, | ||
447 | { .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, }, | ||
448 | { /* end */ } | ||
449 | }; | ||
450 | MODULE_DEVICE_TABLE(of, of_imx_thermal_match); | ||
451 | |||
401 | static int imx_thermal_probe(struct platform_device *pdev) | 452 | static int imx_thermal_probe(struct platform_device *pdev) |
402 | { | 453 | { |
454 | const struct of_device_id *of_id = | ||
455 | of_match_device(of_imx_thermal_match, &pdev->dev); | ||
403 | struct imx_thermal_data *data; | 456 | struct imx_thermal_data *data; |
404 | struct cpumask clip_cpus; | 457 | struct cpumask clip_cpus; |
405 | struct regmap *map; | 458 | struct regmap *map; |
@@ -418,6 +471,20 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
418 | } | 471 | } |
419 | data->tempmon = map; | 472 | data->tempmon = map; |
420 | 473 | ||
474 | data->socdata = of_id->data; | ||
475 | |||
476 | /* make sure the IRQ flag is clear before enabling irq on i.MX6SX */ | ||
477 | if (data->socdata->version == TEMPMON_IMX6SX) { | ||
478 | regmap_write(map, MISC1 + REG_CLR, MISC1_IRQ_TEMPHIGH | | ||
479 | MISC1_IRQ_TEMPLOW | MISC1_IRQ_TEMPPANIC); | ||
480 | /* | ||
481 | * reset value of LOW ALARM is incorrect, set it to lowest | ||
482 | * value to avoid false trigger of low alarm. | ||
483 | */ | ||
484 | regmap_write(map, TEMPSENSE2 + REG_SET, | ||
485 | TEMPSENSE2_LOW_VALUE_MASK); | ||
486 | } | ||
487 | |||
421 | data->irq = platform_get_irq(pdev, 0); | 488 | data->irq = platform_get_irq(pdev, 0); |
422 | if (data->irq < 0) | 489 | if (data->irq < 0) |
423 | return data->irq; | 490 | return data->irq; |
@@ -489,6 +556,10 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
489 | measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */ | 556 | measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */ |
490 | regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq); | 557 | regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq); |
491 | imx_set_alarm_temp(data, data->temp_passive); | 558 | imx_set_alarm_temp(data, data->temp_passive); |
559 | |||
560 | if (data->socdata->version == TEMPMON_IMX6SX) | ||
561 | imx_set_panic_temp(data, data->temp_critical); | ||
562 | |||
492 | regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); | 563 | regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); |
493 | regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); | 564 | regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); |
494 | 565 | ||
@@ -550,12 +621,6 @@ static int imx_thermal_resume(struct device *dev) | |||
550 | static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops, | 621 | static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops, |
551 | imx_thermal_suspend, imx_thermal_resume); | 622 | imx_thermal_suspend, imx_thermal_resume); |
552 | 623 | ||
553 | static const struct of_device_id of_imx_thermal_match[] = { | ||
554 | { .compatible = "fsl,imx6q-tempmon", }, | ||
555 | { /* end */ } | ||
556 | }; | ||
557 | MODULE_DEVICE_TABLE(of, of_imx_thermal_match); | ||
558 | |||
559 | static struct platform_driver imx_thermal = { | 624 | static struct platform_driver imx_thermal = { |
560 | .driver = { | 625 | .driver = { |
561 | .name = "imx_thermal", | 626 | .name = "imx_thermal", |