diff options
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/sun4i-ts.c | 54 |
1 files changed, 50 insertions, 4 deletions
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index 28a06749ae42..9ae53d4289fb 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include <linux/err.h> | 35 | #include <linux/err.h> |
36 | #include <linux/hwmon.h> | 36 | #include <linux/hwmon.h> |
37 | #include <linux/thermal.h> | ||
37 | #include <linux/init.h> | 38 | #include <linux/init.h> |
38 | #include <linux/input.h> | 39 | #include <linux/input.h> |
39 | #include <linux/interrupt.h> | 40 | #include <linux/interrupt.h> |
@@ -107,6 +108,7 @@ | |||
107 | struct sun4i_ts_data { | 108 | struct sun4i_ts_data { |
108 | struct device *dev; | 109 | struct device *dev; |
109 | struct input_dev *input; | 110 | struct input_dev *input; |
111 | struct thermal_zone_device *tz; | ||
110 | void __iomem *base; | 112 | void __iomem *base; |
111 | unsigned int irq; | 113 | unsigned int irq; |
112 | bool ignore_fifo_data; | 114 | bool ignore_fifo_data; |
@@ -180,16 +182,48 @@ static void sun4i_ts_close(struct input_dev *dev) | |||
180 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); | 182 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); |
181 | } | 183 | } |
182 | 184 | ||
185 | static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp) | ||
186 | { | ||
187 | /* No temp_data until the first irq */ | ||
188 | if (ts->temp_data == -1) | ||
189 | return -EAGAIN; | ||
190 | |||
191 | /* | ||
192 | * The user manuals do not contain the formula for calculating | ||
193 | * the temperature. The formula used here is from the AXP209, | ||
194 | * which is designed by X-Powers, an affiliate of Allwinner: | ||
195 | * | ||
196 | * temperature = -144.7 + (value * 0.1) | ||
197 | * | ||
198 | * This should be replaced with the correct one if such information | ||
199 | * becomes available. | ||
200 | */ | ||
201 | *temp = (ts->temp_data - 1447) * 100; | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int sun4i_get_tz_temp(void *data, long *temp) | ||
207 | { | ||
208 | return sun4i_get_temp(data, temp); | ||
209 | } | ||
210 | |||
211 | static struct thermal_zone_of_device_ops sun4i_ts_tz_ops = { | ||
212 | .get_temp = sun4i_get_tz_temp, | ||
213 | }; | ||
214 | |||
183 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, | 215 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, |
184 | char *buf) | 216 | char *buf) |
185 | { | 217 | { |
186 | struct sun4i_ts_data *ts = dev_get_drvdata(dev); | 218 | struct sun4i_ts_data *ts = dev_get_drvdata(dev); |
219 | long temp; | ||
220 | int error; | ||
187 | 221 | ||
188 | /* No temp_data until the first irq */ | 222 | error = sun4i_get_temp(ts, &temp); |
189 | if (ts->temp_data == -1) | 223 | if (error) |
190 | return -EAGAIN; | 224 | return error; |
191 | 225 | ||
192 | return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100); | 226 | return sprintf(buf, "%ld\n", temp); |
193 | } | 227 | } |
194 | 228 | ||
195 | static ssize_t show_temp_label(struct device *dev, | 229 | static ssize_t show_temp_label(struct device *dev, |
@@ -283,17 +317,27 @@ static int sun4i_ts_probe(struct platform_device *pdev) | |||
283 | writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), | 317 | writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), |
284 | ts->base + TP_CTRL1); | 318 | ts->base + TP_CTRL1); |
285 | 319 | ||
320 | /* | ||
321 | * The thermal core does not register hwmon devices for DT-based | ||
322 | * thermal zone sensors, such as this one. | ||
323 | */ | ||
286 | hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts", | 324 | hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts", |
287 | ts, sun4i_ts_groups); | 325 | ts, sun4i_ts_groups); |
288 | if (IS_ERR(hwmon)) | 326 | if (IS_ERR(hwmon)) |
289 | return PTR_ERR(hwmon); | 327 | return PTR_ERR(hwmon); |
290 | 328 | ||
329 | ts->tz = thermal_zone_of_sensor_register(ts->dev, 0, ts, | ||
330 | &sun4i_ts_tz_ops); | ||
331 | if (IS_ERR(ts->tz)) | ||
332 | ts->tz = NULL; | ||
333 | |||
291 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); | 334 | writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); |
292 | 335 | ||
293 | if (ts_attached) { | 336 | if (ts_attached) { |
294 | error = input_register_device(ts->input); | 337 | error = input_register_device(ts->input); |
295 | if (error) { | 338 | if (error) { |
296 | writel(0, ts->base + TP_INT_FIFOC); | 339 | writel(0, ts->base + TP_INT_FIFOC); |
340 | thermal_zone_of_sensor_unregister(ts->dev, ts->tz); | ||
297 | return error; | 341 | return error; |
298 | } | 342 | } |
299 | } | 343 | } |
@@ -310,6 +354,8 @@ static int sun4i_ts_remove(struct platform_device *pdev) | |||
310 | if (ts->input) | 354 | if (ts->input) |
311 | input_unregister_device(ts->input); | 355 | input_unregister_device(ts->input); |
312 | 356 | ||
357 | thermal_zone_of_sensor_unregister(ts->dev, ts->tz); | ||
358 | |||
313 | /* Deactivate all IRQs */ | 359 | /* Deactivate all IRQs */ |
314 | writel(0, ts->base + TP_INT_FIFOC); | 360 | writel(0, ts->base + TP_INT_FIFOC); |
315 | 361 | ||