diff options
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/sun4i-ts.c | 139 |
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 | |||
900 | config TOUCHSCREEN_SUN4I | 900 | config 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 | ||
111 | static irqreturn_t sun4i_ts_irq(int irq, void *dev_id) | 116 | static 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 | |||
146 | static 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 | |||
183 | static 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 | |||
195 | static 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 | ||
201 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); | ||
202 | static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL); | ||
203 | |||
204 | static struct attribute *sun4i_ts_attrs[] = { | ||
205 | &dev_attr_temp1_input.attr, | ||
206 | &dev_attr_temp1_label.attr, | ||
207 | NULL | ||
208 | }; | ||
209 | ATTRIBUTE_GROUPS(sun4i_ts); | ||
210 | |||
167 | static int sun4i_ts_probe(struct platform_device *pdev) | 211 | static 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 | ||
305 | static 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 | |||
243 | static const struct of_device_id sun4i_ts_of_match[] = { | 319 | static 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 | ||
258 | module_platform_driver(sun4i_ts_driver); | 335 | module_platform_driver(sun4i_ts_driver); |