aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/thermal/imx_thermal.c140
1 files changed, 127 insertions, 13 deletions
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index c9a55b0214e5..1d6c801c1eb9 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -12,6 +12,7 @@
12#include <linux/delay.h> 12#include <linux/delay.h>
13#include <linux/device.h> 13#include <linux/device.h>
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/interrupt.h>
15#include <linux/io.h> 16#include <linux/io.h>
16#include <linux/kernel.h> 17#include <linux/kernel.h>
17#include <linux/mfd/syscon.h> 18#include <linux/mfd/syscon.h>
@@ -31,6 +32,8 @@
31#define MISC0_REFTOP_SELBIASOFF (1 << 3) 32#define MISC0_REFTOP_SELBIASOFF (1 << 3)
32 33
33#define TEMPSENSE0 0x0180 34#define TEMPSENSE0 0x0180
35#define TEMPSENSE0_ALARM_VALUE_SHIFT 20
36#define TEMPSENSE0_ALARM_VALUE_MASK (0xfff << TEMPSENSE0_ALARM_VALUE_SHIFT)
34#define TEMPSENSE0_TEMP_CNT_SHIFT 8 37#define TEMPSENSE0_TEMP_CNT_SHIFT 8
35#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT) 38#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT)
36#define TEMPSENSE0_FINISHED (1 << 2) 39#define TEMPSENSE0_FINISHED (1 << 2)
@@ -66,33 +69,62 @@ struct imx_thermal_data {
66 int c1, c2; /* See formula in imx_get_sensor_data() */ 69 int c1, c2; /* See formula in imx_get_sensor_data() */
67 unsigned long temp_passive; 70 unsigned long temp_passive;
68 unsigned long temp_critical; 71 unsigned long temp_critical;
72 unsigned long alarm_temp;
73 unsigned long last_temp;
74 bool irq_enabled;
75 int irq;
69}; 76};
70 77
78static void imx_set_alarm_temp(struct imx_thermal_data *data,
79 signed long alarm_temp)
80{
81 struct regmap *map = data->tempmon;
82 int alarm_value;
83
84 data->alarm_temp = alarm_temp;
85 alarm_value = (alarm_temp - data->c2) / data->c1;
86 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_ALARM_VALUE_MASK);
87 regmap_write(map, TEMPSENSE0 + REG_SET, alarm_value <<
88 TEMPSENSE0_ALARM_VALUE_SHIFT);
89}
90
71static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp) 91static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
72{ 92{
73 struct imx_thermal_data *data = tz->devdata; 93 struct imx_thermal_data *data = tz->devdata;
74 struct regmap *map = data->tempmon; 94 struct regmap *map = data->tempmon;
75 static unsigned long last_temp;
76 unsigned int n_meas; 95 unsigned int n_meas;
96 bool wait;
77 u32 val; 97 u32 val;
78 98
79 /* 99 if (data->mode == THERMAL_DEVICE_ENABLED) {
80 * Every time we measure the temperature, we will power on the 100 /* Check if a measurement is currently in progress */
81 * temperature sensor, enable measurements, take a reading, 101 regmap_read(map, TEMPSENSE0, &val);
82 * disable measurements, power off the temperature sensor. 102 wait = !(val & TEMPSENSE0_FINISHED);
83 */ 103 } else {
84 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); 104 /*
85 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); 105 * Every time we measure the temperature, we will power on the
106 * temperature sensor, enable measurements, take a reading,
107 * disable measurements, power off the temperature sensor.
108 */
109 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
110 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
111
112 wait = true;
113 }
86 114
87 /* 115 /*
88 * According to the temp sensor designers, it may require up to ~17us 116 * According to the temp sensor designers, it may require up to ~17us
89 * to complete a measurement. 117 * to complete a measurement.
90 */ 118 */
91 usleep_range(20, 50); 119 if (wait)
120 usleep_range(20, 50);
92 121
93 regmap_read(map, TEMPSENSE0, &val); 122 regmap_read(map, TEMPSENSE0, &val);
94 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP); 123
95 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); 124 if (data->mode != THERMAL_DEVICE_ENABLED) {
125 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
126 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
127 }
96 128
97 if ((val & TEMPSENSE0_FINISHED) == 0) { 129 if ((val & TEMPSENSE0_FINISHED) == 0) {
98 dev_dbg(&tz->device, "temp measurement never finished\n"); 130 dev_dbg(&tz->device, "temp measurement never finished\n");
@@ -104,9 +136,24 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
104 /* See imx_get_sensor_data() for formula derivation */ 136 /* See imx_get_sensor_data() for formula derivation */
105 *temp = data->c2 + data->c1 * n_meas; 137 *temp = data->c2 + data->c1 * n_meas;
106 138
107 if (*temp != last_temp) { 139 /* Update alarm value to next higher trip point */
140 if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive)
141 imx_set_alarm_temp(data, data->temp_critical);
142 if (data->alarm_temp == data->temp_critical && *temp < data->temp_passive) {
143 imx_set_alarm_temp(data, data->temp_passive);
144 dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
145 data->alarm_temp / 1000);
146 }
147
148 if (*temp != data->last_temp) {
108 dev_dbg(&tz->device, "millicelsius: %ld\n", *temp); 149 dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
109 last_temp = *temp; 150 data->last_temp = *temp;
151 }
152
153 /* Reenable alarm IRQ if temperature below alarm temperature */
154 if (!data->irq_enabled && *temp < data->alarm_temp) {
155 data->irq_enabled = true;
156 enable_irq(data->irq);
110 } 157 }
111 158
112 return 0; 159 return 0;
@@ -126,13 +173,30 @@ static int imx_set_mode(struct thermal_zone_device *tz,
126 enum thermal_device_mode mode) 173 enum thermal_device_mode mode)
127{ 174{
128 struct imx_thermal_data *data = tz->devdata; 175 struct imx_thermal_data *data = tz->devdata;
176 struct regmap *map = data->tempmon;
129 177
130 if (mode == THERMAL_DEVICE_ENABLED) { 178 if (mode == THERMAL_DEVICE_ENABLED) {
131 tz->polling_delay = IMX_POLLING_DELAY; 179 tz->polling_delay = IMX_POLLING_DELAY;
132 tz->passive_delay = IMX_PASSIVE_DELAY; 180 tz->passive_delay = IMX_PASSIVE_DELAY;
181
182 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
183 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
184
185 if (!data->irq_enabled) {
186 data->irq_enabled = true;
187 enable_irq(data->irq);
188 }
133 } else { 189 } else {
190 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
191 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
192
134 tz->polling_delay = 0; 193 tz->polling_delay = 0;
135 tz->passive_delay = 0; 194 tz->passive_delay = 0;
195
196 if (data->irq_enabled) {
197 disable_irq(data->irq);
198 data->irq_enabled = false;
199 }
136 } 200 }
137 201
138 data->mode = mode; 202 data->mode = mode;
@@ -181,6 +245,8 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
181 245
182 data->temp_passive = temp; 246 data->temp_passive = temp;
183 247
248 imx_set_alarm_temp(data, temp);
249
184 return 0; 250 return 0;
185} 251}
186 252
@@ -299,11 +365,34 @@ static int imx_get_sensor_data(struct platform_device *pdev)
299 return 0; 365 return 0;
300} 366}
301 367
368static irqreturn_t imx_thermal_alarm_irq(int irq, void *dev)
369{
370 struct imx_thermal_data *data = dev;
371
372 disable_irq_nosync(irq);
373 data->irq_enabled = false;
374
375 return IRQ_WAKE_THREAD;
376}
377
378static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
379{
380 struct imx_thermal_data *data = dev;
381
382 dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
383 data->alarm_temp / 1000);
384
385 thermal_zone_device_update(data->tz);
386
387 return IRQ_HANDLED;
388}
389
302static int imx_thermal_probe(struct platform_device *pdev) 390static int imx_thermal_probe(struct platform_device *pdev)
303{ 391{
304 struct imx_thermal_data *data; 392 struct imx_thermal_data *data;
305 struct cpumask clip_cpus; 393 struct cpumask clip_cpus;
306 struct regmap *map; 394 struct regmap *map;
395 int measure_freq;
307 int ret; 396 int ret;
308 397
309 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 398 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
@@ -318,6 +407,18 @@ static int imx_thermal_probe(struct platform_device *pdev)
318 } 407 }
319 data->tempmon = map; 408 data->tempmon = map;
320 409
410 data->irq = platform_get_irq(pdev, 0);
411 if (data->irq < 0)
412 return data->irq;
413
414 ret = devm_request_threaded_irq(&pdev->dev, data->irq,
415 imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
416 0, "imx_thermal", data);
417 if (ret < 0) {
418 dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
419 return ret;
420 }
421
321 platform_set_drvdata(pdev, data); 422 platform_set_drvdata(pdev, data);
322 423
323 ret = imx_get_sensor_data(pdev); 424 ret = imx_get_sensor_data(pdev);
@@ -356,6 +457,15 @@ static int imx_thermal_probe(struct platform_device *pdev)
356 return ret; 457 return ret;
357 } 458 }
358 459
460 /* Enable measurements at ~ 10 Hz */
461 regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
462 measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
463 regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq);
464 imx_set_alarm_temp(data, data->temp_passive);
465 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
466 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
467
468 data->irq_enabled = true;
359 data->mode = THERMAL_DEVICE_ENABLED; 469 data->mode = THERMAL_DEVICE_ENABLED;
360 470
361 return 0; 471 return 0;
@@ -364,6 +474,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
364static int imx_thermal_remove(struct platform_device *pdev) 474static int imx_thermal_remove(struct platform_device *pdev)
365{ 475{
366 struct imx_thermal_data *data = platform_get_drvdata(pdev); 476 struct imx_thermal_data *data = platform_get_drvdata(pdev);
477 struct regmap *map = data->tempmon;
478
479 /* Disable measurements */
480 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
367 481
368 thermal_zone_device_unregister(data->tz); 482 thermal_zone_device_unregister(data->tz);
369 cpufreq_cooling_unregister(data->cdev); 483 cpufreq_cooling_unregister(data->cdev);