diff options
-rw-r--r-- | Documentation/devicetree/bindings/input/touchscreen/sun4i.txt | 15 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 10 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/sun4i-ts.c | 262 |
4 files changed, 288 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt new file mode 100644 index 000000000000..881aea713fc3 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt | |||
@@ -0,0 +1,15 @@ | |||
1 | sun4i resistive touchscreen controller | ||
2 | -------------------------------------- | ||
3 | |||
4 | Required properties: | ||
5 | - compatible: "allwinner,sun4i-a10-ts" | ||
6 | - reg: mmio address range of the chip | ||
7 | - interrupts: interrupt to which the chip is connected | ||
8 | |||
9 | Example: | ||
10 | |||
11 | rtp: rtp@01c25000 { | ||
12 | compatible = "allwinner,sun4i-a10-ts"; | ||
13 | reg = <0x01c25000 0x100>; | ||
14 | interrupts = <29>; | ||
15 | }; | ||
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index e2f0264af5cc..41f8b596dc42 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -897,6 +897,16 @@ config TOUCHSCREEN_STMPE | |||
897 | To compile this driver as a module, choose M here: the | 897 | To compile this driver as a module, choose M here: the |
898 | module will be called stmpe-ts. | 898 | module will be called stmpe-ts. |
899 | 899 | ||
900 | config TOUCHSCREEN_SUN4I | ||
901 | tristate "Allwinner sun4i resistive touchscreen controller support" | ||
902 | depends on ARCH_SUNXI || COMPILE_TEST | ||
903 | help | ||
904 | This selects support for the resistive touchscreen controller | ||
905 | found on Allwinner sunxi SoCs. | ||
906 | |||
907 | To compile this driver as a module, choose M here: the | ||
908 | module will be called sun4i-ts. | ||
909 | |||
900 | config TOUCHSCREEN_SUR40 | 910 | config TOUCHSCREEN_SUR40 |
901 | tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" | 911 | tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" |
902 | depends on USB | 912 | depends on USB |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 4bc954b7c7c3..71a97559ce68 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -54,6 +54,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o | |||
54 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o | 54 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o |
55 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o | 55 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o |
56 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o | 56 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o |
57 | obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o | ||
57 | obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o | 58 | obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o |
58 | obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o | 59 | obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o |
59 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o | 60 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o |
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c new file mode 100644 index 000000000000..fc03a5fcd8f8 --- /dev/null +++ b/drivers/input/touchscreen/sun4i-ts.c | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * Allwinner sunxi resistive touchscreen controller driver | ||
3 | * | ||
4 | * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com> | ||
5 | * | ||
6 | * 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 | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * The sun4i-ts controller is capable of detecting a second touch, but when a | ||
19 | * second touch is present then the accuracy becomes so bad the reported touch | ||
20 | * location is not useable. | ||
21 | * | ||
22 | * The original android driver contains some complicated heuristics using the | ||
23 | * aprox. distance between the 2 touches to see if the user is making a pinch | ||
24 | * open / close movement, and then reports emulated multi-touch events around | ||
25 | * the last touch coordinate (as the dual-touch coordinates are worthless). | ||
26 | * | ||
27 | * These kinds of heuristics are just asking for trouble (and don't belong | ||
28 | * in the kernel). So this driver offers straight forward, reliable single | ||
29 | * touch functionality only. | ||
30 | */ | ||
31 | |||
32 | #include <linux/err.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/input.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/io.h> | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/of_platform.h> | ||
39 | #include <linux/platform_device.h> | ||
40 | #include <linux/slab.h> | ||
41 | |||
42 | #define TP_CTRL0 0x00 | ||
43 | #define TP_CTRL1 0x04 | ||
44 | #define TP_CTRL2 0x08 | ||
45 | #define TP_CTRL3 0x0c | ||
46 | #define TP_INT_FIFOC 0x10 | ||
47 | #define TP_INT_FIFOS 0x14 | ||
48 | #define TP_TPR 0x18 | ||
49 | #define TP_CDAT 0x1c | ||
50 | #define TEMP_DATA 0x20 | ||
51 | #define TP_DATA 0x24 | ||
52 | |||
53 | /* TP_CTRL0 bits */ | ||
54 | #define ADC_FIRST_DLY(x) ((x) << 24) /* 8 bits */ | ||
55 | #define ADC_FIRST_DLY_MODE(x) ((x) << 23) | ||
56 | #define ADC_CLK_SEL(x) ((x) << 22) | ||
57 | #define ADC_CLK_DIV(x) ((x) << 20) /* 3 bits */ | ||
58 | #define FS_DIV(x) ((x) << 16) /* 4 bits */ | ||
59 | #define T_ACQ(x) ((x) << 0) /* 16 bits */ | ||
60 | |||
61 | /* TP_CTRL1 bits */ | ||
62 | #define STYLUS_UP_DEBOUN(x) ((x) << 12) /* 8 bits */ | ||
63 | #define STYLUS_UP_DEBOUN_EN(x) ((x) << 9) | ||
64 | #define TOUCH_PAN_CALI_EN(x) ((x) << 6) | ||
65 | #define TP_DUAL_EN(x) ((x) << 5) | ||
66 | #define TP_MODE_EN(x) ((x) << 4) | ||
67 | #define TP_ADC_SELECT(x) ((x) << 3) | ||
68 | #define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */ | ||
69 | |||
70 | /* TP_CTRL2 bits */ | ||
71 | #define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */ | ||
72 | #define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */ | ||
73 | #define PRE_MEA_EN(x) ((x) << 24) | ||
74 | #define PRE_MEA_THRE_CNT(x) ((x) << 0) /* 24 bits */ | ||
75 | |||
76 | /* TP_CTRL3 bits */ | ||
77 | #define FILTER_EN(x) ((x) << 2) | ||
78 | #define FILTER_TYPE(x) ((x) << 0) /* 2 bits */ | ||
79 | |||
80 | /* TP_INT_FIFOC irq and fifo mask / control bits */ | ||
81 | #define TEMP_IRQ_EN(x) ((x) << 18) | ||
82 | #define OVERRUN_IRQ_EN(x) ((x) << 17) | ||
83 | #define DATA_IRQ_EN(x) ((x) << 16) | ||
84 | #define TP_DATA_XY_CHANGE(x) ((x) << 13) | ||
85 | #define FIFO_TRIG(x) ((x) << 8) /* 5 bits */ | ||
86 | #define DATA_DRQ_EN(x) ((x) << 7) | ||
87 | #define FIFO_FLUSH(x) ((x) << 4) | ||
88 | #define TP_UP_IRQ_EN(x) ((x) << 1) | ||
89 | #define TP_DOWN_IRQ_EN(x) ((x) << 0) | ||
90 | |||
91 | /* TP_INT_FIFOS irq and fifo status bits */ | ||
92 | #define TEMP_DATA_PENDING BIT(18) | ||
93 | #define FIFO_OVERRUN_PENDING BIT(17) | ||
94 | #define FIFO_DATA_PENDING BIT(16) | ||
95 | #define TP_IDLE_FLG BIT(2) | ||
96 | #define TP_UP_PENDING BIT(1) | ||
97 | #define TP_DOWN_PENDING BIT(0) | ||
98 | |||
99 | /* TP_TPR bits */ | ||
100 | #define TEMP_ENABLE(x) ((x) << 16) | ||
101 | #define TEMP_PERIOD(x) ((x) << 0) /* t = x * 256 * 16 / clkin */ | ||
102 | |||
103 | struct sun4i_ts_data { | ||
104 | struct device *dev; | ||
105 | struct input_dev *input; | ||
106 | void __iomem *base; | ||
107 | unsigned int irq; | ||
108 | bool ignore_fifo_data; | ||
109 | }; | ||
110 | |||
111 | static irqreturn_t sun4i_ts_irq(int irq, void *dev_id) | ||
112 | { | ||
113 | struct sun4i_ts_data *ts = dev_id; | ||
114 | u32 reg_val, x, y; | ||
115 | |||
116 | reg_val = readl(ts->base + TP_INT_FIFOS); | ||
117 | |||
118 | if (reg_val & FIFO_DATA_PENDING) { | ||
119 | x = readl(ts->base + TP_DATA); | ||
120 | y = readl(ts->base + TP_DATA); | ||
121 | /* The 1st location reported after an up event is unreliable */ | ||
122 | if (!ts->ignore_fifo_data) { | ||
123 | input_report_abs(ts->input, ABS_X, x); | ||
124 | input_report_abs(ts->input, ABS_Y, y); | ||
125 | /* | ||
126 | * The hardware has a separate down status bit, but | ||
127 | * that gets set before we get the first location, | ||
128 | * resulting in reporting a click on the old location. | ||
129 | */ | ||
130 | input_report_key(ts->input, BTN_TOUCH, 1); | ||
131 | input_sync(ts->input); | ||
132 | } else { | ||
133 | ts->ignore_fifo_data = false; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | if (reg_val & TP_UP_PENDING) { | ||
138 | ts->ignore_fifo_data = true; | ||
139 | input_report_key(ts->input, BTN_TOUCH, 0); | ||
140 | input_sync(ts->input); | ||
141 | } | ||
142 | |||
143 | writel(reg_val, ts->base + TP_INT_FIFOS); | ||
144 | |||
145 | return IRQ_HANDLED; | ||
146 | } | ||
147 | |||
148 | static int sun4i_ts_open(struct input_dev *dev) | ||
149 | { | ||
150 | struct sun4i_ts_data *ts = input_get_drvdata(dev); | ||
151 | |||
152 | /* Flush, set trig level to 1, enable data and up irqs */ | ||
153 | writel(DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | TP_UP_IRQ_EN(1), | ||
154 | ts->base + TP_INT_FIFOC); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static void sun4i_ts_close(struct input_dev *dev) | ||
160 | { | ||
161 | struct sun4i_ts_data *ts = input_get_drvdata(dev); | ||
162 | |||
163 | /* Deactivate all IRQs */ | ||
164 | writel(0, ts->base + TP_INT_FIFOC); | ||
165 | } | ||
166 | |||
167 | static int sun4i_ts_probe(struct platform_device *pdev) | ||
168 | { | ||
169 | struct sun4i_ts_data *ts; | ||
170 | struct device *dev = &pdev->dev; | ||
171 | int error; | ||
172 | |||
173 | ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL); | ||
174 | if (!ts) | ||
175 | return -ENOMEM; | ||
176 | |||
177 | ts->dev = dev; | ||
178 | ts->ignore_fifo_data = true; | ||
179 | |||
180 | ts->input = devm_input_allocate_device(dev); | ||
181 | if (!ts->input) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | ts->input->name = pdev->name; | ||
185 | ts->input->phys = "sun4i_ts/input0"; | ||
186 | ts->input->open = sun4i_ts_open; | ||
187 | ts->input->close = sun4i_ts_close; | ||
188 | ts->input->id.bustype = BUS_HOST; | ||
189 | ts->input->id.vendor = 0x0001; | ||
190 | ts->input->id.product = 0x0001; | ||
191 | ts->input->id.version = 0x0100; | ||
192 | ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); | ||
193 | __set_bit(BTN_TOUCH, ts->input->keybit); | ||
194 | input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0); | ||
195 | input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0); | ||
196 | input_set_drvdata(ts->input, ts); | ||
197 | |||
198 | ts->base = devm_ioremap_resource(dev, | ||
199 | platform_get_resource(pdev, IORESOURCE_MEM, 0)); | ||
200 | if (IS_ERR(ts->base)) | ||
201 | return PTR_ERR(ts->base); | ||
202 | |||
203 | ts->irq = platform_get_irq(pdev, 0); | ||
204 | error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts); | ||
205 | if (error) | ||
206 | return error; | ||
207 | |||
208 | /* | ||
209 | * Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192, | ||
210 | * t_acq = clkin / (16 * 64) | ||
211 | */ | ||
212 | writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63), | ||
213 | ts->base + TP_CTRL0); | ||
214 | |||
215 | /* | ||
216 | * sensitive_adjust = 15 : max, which is not all that sensitive, | ||
217 | * tp_mode = 0 : only x and y coordinates, as we don't use dual touch | ||
218 | */ | ||
219 | writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0), | ||
220 | ts->base + TP_CTRL2); | ||
221 | |||
222 | /* Enable median filter, type 1 : 5/3 */ | ||
223 | writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3); | ||
224 | |||
225 | /* Enable temperature measurement, period 1953 (2 seconds) */ | ||
226 | writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR); | ||
227 | |||
228 | /* | ||
229 | * Set stylus up debounce to aprox 10 ms, enable debounce, and | ||
230 | * finally enable tp mode. | ||
231 | */ | ||
232 | writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1), | ||
233 | ts->base + TP_CTRL1); | ||
234 | |||
235 | error = input_register_device(ts->input); | ||
236 | if (error) | ||
237 | return error; | ||
238 | |||
239 | platform_set_drvdata(pdev, ts); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static const struct of_device_id sun4i_ts_of_match[] = { | ||
244 | { .compatible = "allwinner,sun4i-a10-ts", }, | ||
245 | { /* sentinel */ } | ||
246 | }; | ||
247 | MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); | ||
248 | |||
249 | static struct platform_driver sun4i_ts_driver = { | ||
250 | .driver = { | ||
251 | .owner = THIS_MODULE, | ||
252 | .name = "sun4i-ts", | ||
253 | .of_match_table = of_match_ptr(sun4i_ts_of_match), | ||
254 | }, | ||
255 | .probe = sun4i_ts_probe, | ||
256 | }; | ||
257 | |||
258 | module_platform_driver(sun4i_ts_driver); | ||
259 | |||
260 | MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver"); | ||
261 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | ||
262 | MODULE_LICENSE("GPL"); | ||