aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2014-05-14 14:22:09 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-05-14 19:40:06 -0400
commitf09f98d3240b7ed2dd84ef6d84ff86df9d61e0f5 (patch)
tree868ecf353dd23426271b88dc39a16c29f1d4d2a2 /drivers/input/touchscreen
parent6decea7c5438e2955f64e2513ec9a2fac7602a7d (diff)
Input: sun4i-ts - add support for temperature sensor
The sun4i resisitive touchscreen controller also comes with a built-in temperature sensor. This commit adds support for it. This commit also introduces a new "ts-attached" device-tree property, when this is not set, the input part of the driver won't register. This way the internal temperature sensor can be used to measure the SoC temperature independent of there actually being a touchscreen attached to the controller. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r--drivers/input/touchscreen/Kconfig1
-rw-r--r--drivers/input/touchscreen/sun4i-ts.c139
2 files changed, 109 insertions, 31 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 41f8b596dc42..746d3c568e49 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -900,6 +900,7 @@ config TOUCHSCREEN_STMPE
900config TOUCHSCREEN_SUN4I 900config TOUCHSCREEN_SUN4I
901 tristate "Allwinner sun4i resistive touchscreen controller support" 901 tristate "Allwinner sun4i resistive touchscreen controller support"
902 depends on ARCH_SUNXI || COMPILE_TEST 902 depends on ARCH_SUNXI || COMPILE_TEST
903 depends on HWMON
903 help 904 help
904 This selects support for the resistive touchscreen controller 905 This selects support for the resistive touchscreen controller
905 found on Allwinner sunxi SoCs. 906 found on Allwinner sunxi SoCs.
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
index fc03a5fcd8f8..2ba826024954 100644
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -3,6 +3,9 @@
3 * 3 *
4 * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com> 4 * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com>
5 * 5 *
6 * The hwmon parts are based on work by Corentin LABBE which is:
7 * Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com>
8 *
6 * This program is free software; you can redistribute it and/or modify 9 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or 11 * the Free Software Foundation; either version 2 of the License, or
@@ -30,6 +33,7 @@
30 */ 33 */
31 34
32#include <linux/err.h> 35#include <linux/err.h>
36#include <linux/hwmon.h>
33#include <linux/init.h> 37#include <linux/init.h>
34#include <linux/input.h> 38#include <linux/input.h>
35#include <linux/interrupt.h> 39#include <linux/interrupt.h>
@@ -106,14 +110,12 @@ struct sun4i_ts_data {
106 void __iomem *base; 110 void __iomem *base;
107 unsigned int irq; 111 unsigned int irq;
108 bool ignore_fifo_data; 112 bool ignore_fifo_data;
113 int temp_data;
109}; 114};
110 115
111static irqreturn_t sun4i_ts_irq(int irq, void *dev_id) 116static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
112{ 117{
113 struct sun4i_ts_data *ts = dev_id; 118 u32 x, y;
114 u32 reg_val, x, y;
115
116 reg_val = readl(ts->base + TP_INT_FIFOS);
117 119
118 if (reg_val & FIFO_DATA_PENDING) { 120 if (reg_val & FIFO_DATA_PENDING) {
119 x = readl(ts->base + TP_DATA); 121 x = readl(ts->base + TP_DATA);
@@ -139,6 +141,20 @@ static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
139 input_report_key(ts->input, BTN_TOUCH, 0); 141 input_report_key(ts->input, BTN_TOUCH, 0);
140 input_sync(ts->input); 142 input_sync(ts->input);
141 } 143 }
144}
145
146static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
147{
148 struct sun4i_ts_data *ts = dev_id;
149 u32 reg_val;
150
151 reg_val = readl(ts->base + TP_INT_FIFOS);
152
153 if (reg_val & TEMP_DATA_PENDING)
154 ts->temp_data = readl(ts->base + TEMP_DATA);
155
156 if (ts->input)
157 sun4i_ts_irq_handle_input(ts, reg_val);
142 158
143 writel(reg_val, ts->base + TP_INT_FIFOS); 159 writel(reg_val, ts->base + TP_INT_FIFOS);
144 160
@@ -149,9 +165,9 @@ static int sun4i_ts_open(struct input_dev *dev)
149{ 165{
150 struct sun4i_ts_data *ts = input_get_drvdata(dev); 166 struct sun4i_ts_data *ts = input_get_drvdata(dev);
151 167
152 /* Flush, set trig level to 1, enable data and up irqs */ 168 /* Flush, set trig level to 1, enable temp, data and up irqs */
153 writel(DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | TP_UP_IRQ_EN(1), 169 writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) |
154 ts->base + TP_INT_FIFOC); 170 TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
155 171
156 return 0; 172 return 0;
157} 173}
@@ -160,15 +176,46 @@ static void sun4i_ts_close(struct input_dev *dev)
160{ 176{
161 struct sun4i_ts_data *ts = input_get_drvdata(dev); 177 struct sun4i_ts_data *ts = input_get_drvdata(dev);
162 178
163 /* Deactivate all IRQs */ 179 /* Deactivate all input IRQs */
164 writel(0, ts->base + TP_INT_FIFOC); 180 writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
181}
182
183static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
184 char *buf)
185{
186 struct sun4i_ts_data *ts = dev_get_drvdata(dev);
187
188 /* No temp_data until the first irq */
189 if (ts->temp_data == -1)
190 return -EAGAIN;
191
192 return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
193}
194
195static ssize_t show_temp_label(struct device *dev,
196 struct device_attribute *devattr, char *buf)
197{
198 return sprintf(buf, "SoC temperature\n");
165} 199}
166 200
201static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
202static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL);
203
204static struct attribute *sun4i_ts_attrs[] = {
205 &dev_attr_temp1_input.attr,
206 &dev_attr_temp1_label.attr,
207 NULL
208};
209ATTRIBUTE_GROUPS(sun4i_ts);
210
167static int sun4i_ts_probe(struct platform_device *pdev) 211static int sun4i_ts_probe(struct platform_device *pdev)
168{ 212{
169 struct sun4i_ts_data *ts; 213 struct sun4i_ts_data *ts;
170 struct device *dev = &pdev->dev; 214 struct device *dev = &pdev->dev;
215 struct device_node *np = dev->of_node;
216 struct device *hwmon;
171 int error; 217 int error;
218 bool ts_attached;
172 219
173 ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); 220 ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
174 if (!ts) 221 if (!ts)
@@ -176,24 +223,28 @@ static int sun4i_ts_probe(struct platform_device *pdev)
176 223
177 ts->dev = dev; 224 ts->dev = dev;
178 ts->ignore_fifo_data = true; 225 ts->ignore_fifo_data = true;
179 226 ts->temp_data = -1;
180 ts->input = devm_input_allocate_device(dev); 227
181 if (!ts->input) 228 ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
182 return -ENOMEM; 229 if (ts_attached) {
183 230 ts->input = devm_input_allocate_device(dev);
184 ts->input->name = pdev->name; 231 if (!ts->input)
185 ts->input->phys = "sun4i_ts/input0"; 232 return -ENOMEM;
186 ts->input->open = sun4i_ts_open; 233
187 ts->input->close = sun4i_ts_close; 234 ts->input->name = pdev->name;
188 ts->input->id.bustype = BUS_HOST; 235 ts->input->phys = "sun4i_ts/input0";
189 ts->input->id.vendor = 0x0001; 236 ts->input->open = sun4i_ts_open;
190 ts->input->id.product = 0x0001; 237 ts->input->close = sun4i_ts_close;
191 ts->input->id.version = 0x0100; 238 ts->input->id.bustype = BUS_HOST;
192 ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); 239 ts->input->id.vendor = 0x0001;
193 __set_bit(BTN_TOUCH, ts->input->keybit); 240 ts->input->id.product = 0x0001;
194 input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0); 241 ts->input->id.version = 0x0100;
195 input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0); 242 ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
196 input_set_drvdata(ts->input, ts); 243 __set_bit(BTN_TOUCH, ts->input->keybit);
244 input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
245 input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
246 input_set_drvdata(ts->input, ts);
247 }
197 248
198 ts->base = devm_ioremap_resource(dev, 249 ts->base = devm_ioremap_resource(dev,
199 platform_get_resource(pdev, IORESOURCE_MEM, 0)); 250 platform_get_resource(pdev, IORESOURCE_MEM, 0));
@@ -232,14 +283,39 @@ static int sun4i_ts_probe(struct platform_device *pdev)
232 writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), 283 writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
233 ts->base + TP_CTRL1); 284 ts->base + TP_CTRL1);
234 285
235 error = input_register_device(ts->input); 286 hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
236 if (error) 287 ts, sun4i_ts_groups);
237 return error; 288 if (IS_ERR(hwmon))
289 return PTR_ERR(hwmon);
290
291 writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
292
293 if (ts_attached) {
294 error = input_register_device(ts->input);
295 if (error) {
296 writel(0, ts->base + TP_INT_FIFOC);
297 return error;
298 }
299 }
238 300
239 platform_set_drvdata(pdev, ts); 301 platform_set_drvdata(pdev, ts);
240 return 0; 302 return 0;
241} 303}
242 304
305static int sun4i_ts_remove(struct platform_device *pdev)
306{
307 struct sun4i_ts_data *ts = platform_get_drvdata(pdev);
308
309 /* Explicit unregister to avoid open/close changing the imask later */
310 if (ts->input)
311 input_unregister_device(ts->input);
312
313 /* Deactivate all IRQs */
314 writel(0, ts->base + TP_INT_FIFOC);
315
316 return 0;
317}
318
243static const struct of_device_id sun4i_ts_of_match[] = { 319static const struct of_device_id sun4i_ts_of_match[] = {
244 { .compatible = "allwinner,sun4i-a10-ts", }, 320 { .compatible = "allwinner,sun4i-a10-ts", },
245 { /* sentinel */ } 321 { /* sentinel */ }
@@ -253,6 +329,7 @@ static struct platform_driver sun4i_ts_driver = {
253 .of_match_table = of_match_ptr(sun4i_ts_of_match), 329 .of_match_table = of_match_ptr(sun4i_ts_of_match),
254 }, 330 },
255 .probe = sun4i_ts_probe, 331 .probe = sun4i_ts_probe,
332 .remove = sun4i_ts_remove,
256}; 333};
257 334
258module_platform_driver(sun4i_ts_driver); 335module_platform_driver(sun4i_ts_driver);