Commit 88f7cc4b04ec1f5fe208a31592c5281624f085cc
Committed by
Jacob Stiffler
1 parent
0c2a68cf4d
Exists in
smarc-ti-linux-3.14.y
and in
1 other branch
Input: ti_am335x_tsc - remove udelay in interrupt handler (mainline sync)
TI 3.14 Patch e823ec6f7b5555c65b2b89742fcd705014e8e467 was an early version of mainline patch 344d635b9a41b19837ccf8083a99ea688027019c. Backport the differences between these patches. Signed-off-by: Franklin S Cooper Jr <fcooper@ti.com>
Showing 1 changed file with 13 additions and 6 deletions Inline Diff
drivers/input/touchscreen/ti_am335x_tsc.c
1 | /* | 1 | /* |
2 | * TI Touch Screen driver | 2 | * TI Touch Screen driver |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | 4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License as | 7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation version 2. | 8 | * published by the Free Software Foundation version 2. |
9 | * | 9 | * |
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | 10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
11 | * kind, whether express or implied; without even the implied warranty | 11 | * kind, whether express or implied; without even the implied warranty |
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | 16 | ||
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/input.h> | 20 | #include <linux/input.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/of.h> | 27 | #include <linux/of.h> |
28 | #include <linux/of_device.h> | 28 | #include <linux/of_device.h> |
29 | 29 | ||
30 | #include <linux/mfd/ti_am335x_tscadc.h> | 30 | #include <linux/mfd/ti_am335x_tscadc.h> |
31 | 31 | ||
32 | #define ADCFSM_STEPID 0x10 | 32 | #define ADCFSM_STEPID 0x10 |
33 | #define SEQ_SETTLE 275 | 33 | #define SEQ_SETTLE 275 |
34 | #define MAX_12BIT ((1 << 12) - 1) | 34 | #define MAX_12BIT ((1 << 12) - 1) |
35 | 35 | ||
36 | static const int config_pins[] = { | 36 | static const int config_pins[] = { |
37 | STEPCONFIG_XPP, | 37 | STEPCONFIG_XPP, |
38 | STEPCONFIG_XNN, | 38 | STEPCONFIG_XNN, |
39 | STEPCONFIG_YPP, | 39 | STEPCONFIG_YPP, |
40 | STEPCONFIG_YNN, | 40 | STEPCONFIG_YNN, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | struct titsc { | 43 | struct titsc { |
44 | struct input_dev *input; | 44 | struct input_dev *input; |
45 | struct ti_tscadc_dev *mfd_tscadc; | 45 | struct ti_tscadc_dev *mfd_tscadc; |
46 | unsigned int irq; | 46 | unsigned int irq; |
47 | unsigned int wires; | 47 | unsigned int wires; |
48 | unsigned int x_plate_resistance; | 48 | unsigned int x_plate_resistance; |
49 | bool pen_down; | 49 | bool pen_down; |
50 | int coordinate_readouts; | 50 | int coordinate_readouts; |
51 | u32 config_inp[4]; | 51 | u32 config_inp[4]; |
52 | u32 bit_xp, bit_xn, bit_yp, bit_yn; | 52 | u32 bit_xp, bit_xn, bit_yp, bit_yn; |
53 | u32 inp_xp, inp_xn, inp_yp, inp_yn; | 53 | u32 inp_xp, inp_xn, inp_yp, inp_yn; |
54 | u32 step_mask; | 54 | u32 step_mask; |
55 | u32 charge_delay; | 55 | u32 charge_delay; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) | 58 | static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) |
59 | { | 59 | { |
60 | return readl(ts->mfd_tscadc->tscadc_base + reg); | 60 | return readl(ts->mfd_tscadc->tscadc_base + reg); |
61 | } | 61 | } |
62 | 62 | ||
63 | static void titsc_writel(struct titsc *tsc, unsigned int reg, | 63 | static void titsc_writel(struct titsc *tsc, unsigned int reg, |
64 | unsigned int val) | 64 | unsigned int val) |
65 | { | 65 | { |
66 | writel(val, tsc->mfd_tscadc->tscadc_base + reg); | 66 | writel(val, tsc->mfd_tscadc->tscadc_base + reg); |
67 | } | 67 | } |
68 | 68 | ||
69 | static int titsc_config_wires(struct titsc *ts_dev) | 69 | static int titsc_config_wires(struct titsc *ts_dev) |
70 | { | 70 | { |
71 | u32 analog_line[4]; | 71 | u32 analog_line[4]; |
72 | u32 wire_order[4]; | 72 | u32 wire_order[4]; |
73 | int i, bit_cfg; | 73 | int i, bit_cfg; |
74 | 74 | ||
75 | for (i = 0; i < 4; i++) { | 75 | for (i = 0; i < 4; i++) { |
76 | /* | 76 | /* |
77 | * Get the order in which TSC wires are attached | 77 | * Get the order in which TSC wires are attached |
78 | * w.r.t. each of the analog input lines on the EVM. | 78 | * w.r.t. each of the analog input lines on the EVM. |
79 | */ | 79 | */ |
80 | analog_line[i] = (ts_dev->config_inp[i] & 0xF0) >> 4; | 80 | analog_line[i] = (ts_dev->config_inp[i] & 0xF0) >> 4; |
81 | wire_order[i] = ts_dev->config_inp[i] & 0x0F; | 81 | wire_order[i] = ts_dev->config_inp[i] & 0x0F; |
82 | if (WARN_ON(analog_line[i] > 7)) | 82 | if (WARN_ON(analog_line[i] > 7)) |
83 | return -EINVAL; | 83 | return -EINVAL; |
84 | if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins))) | 84 | if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins))) |
85 | return -EINVAL; | 85 | return -EINVAL; |
86 | } | 86 | } |
87 | 87 | ||
88 | for (i = 0; i < 4; i++) { | 88 | for (i = 0; i < 4; i++) { |
89 | int an_line; | 89 | int an_line; |
90 | int wi_order; | 90 | int wi_order; |
91 | 91 | ||
92 | an_line = analog_line[i]; | 92 | an_line = analog_line[i]; |
93 | wi_order = wire_order[i]; | 93 | wi_order = wire_order[i]; |
94 | bit_cfg = config_pins[wi_order]; | 94 | bit_cfg = config_pins[wi_order]; |
95 | if (bit_cfg == 0) | 95 | if (bit_cfg == 0) |
96 | return -EINVAL; | 96 | return -EINVAL; |
97 | switch (wi_order) { | 97 | switch (wi_order) { |
98 | case 0: | 98 | case 0: |
99 | ts_dev->bit_xp = bit_cfg; | 99 | ts_dev->bit_xp = bit_cfg; |
100 | ts_dev->inp_xp = an_line; | 100 | ts_dev->inp_xp = an_line; |
101 | break; | 101 | break; |
102 | 102 | ||
103 | case 1: | 103 | case 1: |
104 | ts_dev->bit_xn = bit_cfg; | 104 | ts_dev->bit_xn = bit_cfg; |
105 | ts_dev->inp_xn = an_line; | 105 | ts_dev->inp_xn = an_line; |
106 | break; | 106 | break; |
107 | 107 | ||
108 | case 2: | 108 | case 2: |
109 | ts_dev->bit_yp = bit_cfg; | 109 | ts_dev->bit_yp = bit_cfg; |
110 | ts_dev->inp_yp = an_line; | 110 | ts_dev->inp_yp = an_line; |
111 | break; | 111 | break; |
112 | case 3: | 112 | case 3: |
113 | ts_dev->bit_yn = bit_cfg; | 113 | ts_dev->bit_yn = bit_cfg; |
114 | ts_dev->inp_yn = an_line; | 114 | ts_dev->inp_yn = an_line; |
115 | break; | 115 | break; |
116 | } | 116 | } |
117 | } | 117 | } |
118 | return 0; | 118 | return 0; |
119 | } | 119 | } |
120 | 120 | ||
121 | static void titsc_step_config(struct titsc *ts_dev) | 121 | static void titsc_step_config(struct titsc *ts_dev) |
122 | { | 122 | { |
123 | unsigned int config; | 123 | unsigned int config; |
124 | int i; | 124 | int i; |
125 | int end_step, first_step, tsc_steps; | 125 | int end_step, first_step, tsc_steps; |
126 | u32 stepenable; | 126 | u32 stepenable; |
127 | 127 | ||
128 | config = STEPCONFIG_MODE_HWSYNC | | 128 | config = STEPCONFIG_MODE_HWSYNC | |
129 | STEPCONFIG_AVG_16 | ts_dev->bit_xp; | 129 | STEPCONFIG_AVG_16 | ts_dev->bit_xp; |
130 | switch (ts_dev->wires) { | 130 | switch (ts_dev->wires) { |
131 | case 4: | 131 | case 4: |
132 | config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; | 132 | config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; |
133 | break; | 133 | break; |
134 | case 5: | 134 | case 5: |
135 | config |= ts_dev->bit_yn | | 135 | config |= ts_dev->bit_yn | |
136 | STEPCONFIG_INP_AN4 | ts_dev->bit_xn | | 136 | STEPCONFIG_INP_AN4 | ts_dev->bit_xn | |
137 | ts_dev->bit_yp; | 137 | ts_dev->bit_yp; |
138 | break; | 138 | break; |
139 | case 8: | 139 | case 8: |
140 | config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; | 140 | config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; |
141 | break; | 141 | break; |
142 | } | 142 | } |
143 | 143 | ||
144 | tsc_steps = ts_dev->coordinate_readouts * 2 + 2; | 144 | tsc_steps = ts_dev->coordinate_readouts * 2 + 2; |
145 | first_step = TOTAL_STEPS - tsc_steps; | 145 | first_step = TOTAL_STEPS - tsc_steps; |
146 | /* Steps 16 to 16-coordinate_readouts is for X */ | 146 | /* Steps 16 to 16-coordinate_readouts is for X */ |
147 | end_step = first_step + tsc_steps; | 147 | end_step = first_step + tsc_steps; |
148 | for (i = end_step - ts_dev->coordinate_readouts; i < end_step; i++) { | 148 | for (i = end_step - ts_dev->coordinate_readouts; i < end_step; i++) { |
149 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | 149 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); |
150 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | 150 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); |
151 | } | 151 | } |
152 | 152 | ||
153 | config = 0; | 153 | config = 0; |
154 | config = STEPCONFIG_MODE_HWSYNC | | 154 | config = STEPCONFIG_MODE_HWSYNC | |
155 | STEPCONFIG_AVG_16 | ts_dev->bit_yn | | 155 | STEPCONFIG_AVG_16 | ts_dev->bit_yn | |
156 | STEPCONFIG_INM_ADCREFM; | 156 | STEPCONFIG_INM_ADCREFM; |
157 | switch (ts_dev->wires) { | 157 | switch (ts_dev->wires) { |
158 | case 4: | 158 | case 4: |
159 | config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp); | 159 | config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp); |
160 | break; | 160 | break; |
161 | case 5: | 161 | case 5: |
162 | config |= ts_dev->bit_xp | STEPCONFIG_INP_AN4 | | 162 | config |= ts_dev->bit_xp | STEPCONFIG_INP_AN4 | |
163 | ts_dev->bit_xn | ts_dev->bit_yp; | 163 | ts_dev->bit_xn | ts_dev->bit_yp; |
164 | break; | 164 | break; |
165 | case 8: | 165 | case 8: |
166 | config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp); | 166 | config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp); |
167 | break; | 167 | break; |
168 | } | 168 | } |
169 | 169 | ||
170 | /* 1 ... coordinate_readouts is for Y */ | 170 | /* 1 ... coordinate_readouts is for Y */ |
171 | end_step = first_step + ts_dev->coordinate_readouts; | 171 | end_step = first_step + ts_dev->coordinate_readouts; |
172 | for (i = first_step; i < end_step; i++) { | 172 | for (i = first_step; i < end_step; i++) { |
173 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | 173 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); |
174 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | 174 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); |
175 | } | 175 | } |
176 | 176 | ||
177 | /* Make CHARGECONFIG same as IDLECONFIG */ | 177 | /* Make CHARGECONFIG same as IDLECONFIG */ |
178 | 178 | ||
179 | config = titsc_readl(ts_dev, REG_IDLECONFIG); | 179 | config = titsc_readl(ts_dev, REG_IDLECONFIG); |
180 | titsc_writel(ts_dev, REG_CHARGECONFIG, config); | 180 | titsc_writel(ts_dev, REG_CHARGECONFIG, config); |
181 | titsc_writel(ts_dev, REG_CHARGEDELAY, ts_dev->charge_delay); | 181 | titsc_writel(ts_dev, REG_CHARGEDELAY, ts_dev->charge_delay); |
182 | 182 | ||
183 | /* coordinate_readouts + 1 ... coordinate_readouts + 2 is for Z */ | 183 | /* coordinate_readouts + 1 ... coordinate_readouts + 2 is for Z */ |
184 | config = STEPCONFIG_MODE_HWSYNC | | 184 | config = STEPCONFIG_MODE_HWSYNC | |
185 | STEPCONFIG_AVG_16 | ts_dev->bit_yp | | 185 | STEPCONFIG_AVG_16 | ts_dev->bit_yp | |
186 | ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | | 186 | ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | |
187 | STEPCONFIG_INP(ts_dev->inp_xp); | 187 | STEPCONFIG_INP(ts_dev->inp_xp); |
188 | titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config); | 188 | titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config); |
189 | titsc_writel(ts_dev, REG_STEPDELAY(end_step), | 189 | titsc_writel(ts_dev, REG_STEPDELAY(end_step), |
190 | STEPCONFIG_OPENDLY); | 190 | STEPCONFIG_OPENDLY); |
191 | 191 | ||
192 | end_step++; | 192 | end_step++; |
193 | config |= STEPCONFIG_INP(ts_dev->inp_yn); | 193 | config |= STEPCONFIG_INP(ts_dev->inp_yn); |
194 | titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config); | 194 | titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config); |
195 | titsc_writel(ts_dev, REG_STEPDELAY(end_step), | 195 | titsc_writel(ts_dev, REG_STEPDELAY(end_step), |
196 | STEPCONFIG_OPENDLY); | 196 | STEPCONFIG_OPENDLY); |
197 | 197 | ||
198 | /* The steps end ... end - readouts * 2 + 2 and bit 0 for TS_Charge */ | 198 | /* The steps end ... end - readouts * 2 + 2 and bit 0 for TS_Charge */ |
199 | stepenable = 1; | 199 | stepenable = 1; |
200 | for (i = 0; i < tsc_steps; i++) | 200 | for (i = 0; i < tsc_steps; i++) |
201 | stepenable |= 1 << (first_step + i + 1); | 201 | stepenable |= 1 << (first_step + i + 1); |
202 | 202 | ||
203 | ts_dev->step_mask = stepenable; | 203 | ts_dev->step_mask = stepenable; |
204 | am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); | 204 | am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); |
205 | } | 205 | } |
206 | 206 | ||
207 | static void titsc_read_coordinates(struct titsc *ts_dev, | 207 | static void titsc_read_coordinates(struct titsc *ts_dev, |
208 | u32 *x, u32 *y, u32 *z1, u32 *z2) | 208 | u32 *x, u32 *y, u32 *z1, u32 *z2) |
209 | { | 209 | { |
210 | unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); | 210 | unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); |
211 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | 211 | unsigned int prev_val_x = ~0, prev_val_y = ~0; |
212 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | 212 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; |
213 | unsigned int read, diff; | 213 | unsigned int read, diff; |
214 | unsigned int i, channel; | 214 | unsigned int i, channel; |
215 | unsigned int creads = ts_dev->coordinate_readouts; | 215 | unsigned int creads = ts_dev->coordinate_readouts; |
216 | unsigned int first_step = TOTAL_STEPS - (creads * 2 + 2); | 216 | unsigned int first_step = TOTAL_STEPS - (creads * 2 + 2); |
217 | 217 | ||
218 | *z1 = *z2 = 0; | 218 | *z1 = *z2 = 0; |
219 | if (fifocount % (creads * 2 + 2)) | 219 | if (fifocount % (creads * 2 + 2)) |
220 | fifocount -= fifocount % (creads * 2 + 2); | 220 | fifocount -= fifocount % (creads * 2 + 2); |
221 | /* | 221 | /* |
222 | * Delta filter is used to remove large variations in sampled | 222 | * Delta filter is used to remove large variations in sampled |
223 | * values from ADC. The filter tries to predict where the next | 223 | * values from ADC. The filter tries to predict where the next |
224 | * coordinate could be. This is done by taking a previous | 224 | * coordinate could be. This is done by taking a previous |
225 | * coordinate and subtracting it form current one. Further the | 225 | * coordinate and subtracting it form current one. Further the |
226 | * algorithm compares the difference with that of a present value, | 226 | * algorithm compares the difference with that of a present value, |
227 | * if true the value is reported to the sub system. | 227 | * if true the value is reported to the sub system. |
228 | */ | 228 | */ |
229 | for (i = 0; i < fifocount; i++) { | 229 | for (i = 0; i < fifocount; i++) { |
230 | read = titsc_readl(ts_dev, REG_FIFO0); | 230 | read = titsc_readl(ts_dev, REG_FIFO0); |
231 | 231 | ||
232 | channel = (read & 0xf0000) >> 16; | 232 | channel = (read & 0xf0000) >> 16; |
233 | read &= 0xfff; | 233 | read &= 0xfff; |
234 | if (channel > first_step + creads + 2) { | 234 | if (channel > first_step + creads + 2) { |
235 | diff = abs(read - prev_val_x); | 235 | diff = abs(read - prev_val_x); |
236 | if (diff < prev_diff_x) { | 236 | if (diff < prev_diff_x) { |
237 | prev_diff_x = diff; | 237 | prev_diff_x = diff; |
238 | *x = read; | 238 | *x = read; |
239 | } | 239 | } |
240 | prev_val_x = read; | 240 | prev_val_x = read; |
241 | 241 | ||
242 | } else if (channel == first_step + creads + 1) { | 242 | } else if (channel == first_step + creads + 1) { |
243 | *z1 = read; | 243 | *z1 = read; |
244 | 244 | ||
245 | } else if (channel == first_step + creads + 2) { | 245 | } else if (channel == first_step + creads + 2) { |
246 | *z2 = read; | 246 | *z2 = read; |
247 | 247 | ||
248 | } else if (channel > first_step) { | 248 | } else if (channel > first_step) { |
249 | diff = abs(read - prev_val_y); | 249 | diff = abs(read - prev_val_y); |
250 | if (diff < prev_diff_y) { | 250 | if (diff < prev_diff_y) { |
251 | prev_diff_y = diff; | 251 | prev_diff_y = diff; |
252 | *y = read; | 252 | *y = read; |
253 | } | 253 | } |
254 | prev_val_y = read; | 254 | prev_val_y = read; |
255 | } | 255 | } |
256 | } | 256 | } |
257 | } | 257 | } |
258 | 258 | ||
259 | static irqreturn_t titsc_irq(int irq, void *dev) | 259 | static irqreturn_t titsc_irq(int irq, void *dev) |
260 | { | 260 | { |
261 | struct titsc *ts_dev = dev; | 261 | struct titsc *ts_dev = dev; |
262 | struct input_dev *input_dev = ts_dev->input; | 262 | struct input_dev *input_dev = ts_dev->input; |
263 | unsigned int status, irqclr = 0; | 263 | unsigned int fsm, status, irqclr = 0; |
264 | unsigned int x = 0, y = 0; | 264 | unsigned int x = 0, y = 0; |
265 | unsigned int z1, z2, z; | 265 | unsigned int z1, z2, z; |
266 | 266 | ||
267 | status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); | 267 | status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); |
268 | if (status & IRQENB_HW_PEN) { | 268 | if (status & IRQENB_HW_PEN) { |
269 | ts_dev->pen_down = true; | 269 | ts_dev->pen_down = true; |
270 | irqclr |= IRQENB_HW_PEN; | 270 | irqclr |= IRQENB_HW_PEN; |
271 | } | 271 | } |
272 | 272 | ||
273 | if (status & IRQENB_PENUP) { | 273 | if (status & IRQENB_PENUP) { |
274 | ts_dev->pen_down = false; | 274 | fsm = titsc_readl(ts_dev, REG_ADCFSM); |
275 | input_report_key(input_dev, BTN_TOUCH, 0); | 275 | if (fsm == ADCFSM_STEPID) { |
276 | input_report_abs(input_dev, ABS_PRESSURE, 0); | 276 | ts_dev->pen_down = false; |
277 | input_sync(input_dev); | 277 | input_report_key(input_dev, BTN_TOUCH, 0); |
278 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
279 | input_sync(input_dev); | ||
280 | } else { | ||
281 | ts_dev->pen_down = true; | ||
282 | } | ||
278 | irqclr |= IRQENB_PENUP; | 283 | irqclr |= IRQENB_PENUP; |
279 | } | 284 | } |
280 | 285 | ||
281 | if (status & IRQENB_EOS) | 286 | if (status & IRQENB_EOS) |
282 | irqclr |= IRQENB_EOS; | 287 | irqclr |= IRQENB_EOS; |
283 | 288 | ||
284 | /* | 289 | /* |
285 | * ADC and touchscreen share the IRQ line. | 290 | * ADC and touchscreen share the IRQ line. |
286 | * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only | 291 | * FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only |
287 | */ | 292 | */ |
288 | if (status & IRQENB_FIFO0THRES) { | 293 | if (status & IRQENB_FIFO0THRES) { |
289 | 294 | ||
290 | titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2); | 295 | titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2); |
291 | 296 | ||
292 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { | 297 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { |
293 | /* | 298 | /* |
294 | * Calculate pressure using formula | 299 | * Calculate pressure using formula |
295 | * Resistance(touch) = x plate resistance * | 300 | * Resistance(touch) = x plate resistance * |
296 | * x postion/4096 * ((z2 / z1) - 1) | 301 | * x postion/4096 * ((z2 / z1) - 1) |
297 | */ | 302 | */ |
298 | z = z1 - z2; | 303 | z = z1 - z2; |
299 | z *= x; | 304 | z *= x; |
300 | z *= ts_dev->x_plate_resistance; | 305 | z *= ts_dev->x_plate_resistance; |
301 | z /= z2; | 306 | z /= z2; |
302 | z = (z + 2047) >> 12; | 307 | z = (z + 2047) >> 12; |
303 | 308 | ||
304 | if (z <= MAX_12BIT) { | 309 | if (z <= MAX_12BIT) { |
305 | input_report_abs(input_dev, ABS_X, x); | 310 | input_report_abs(input_dev, ABS_X, x); |
306 | input_report_abs(input_dev, ABS_Y, y); | 311 | input_report_abs(input_dev, ABS_Y, y); |
307 | input_report_abs(input_dev, ABS_PRESSURE, z); | 312 | input_report_abs(input_dev, ABS_PRESSURE, z); |
308 | input_report_key(input_dev, BTN_TOUCH, 1); | 313 | input_report_key(input_dev, BTN_TOUCH, 1); |
309 | input_sync(input_dev); | 314 | input_sync(input_dev); |
310 | } | 315 | } |
311 | } | 316 | } |
312 | irqclr |= IRQENB_FIFO0THRES; | 317 | irqclr |= IRQENB_FIFO0THRES; |
313 | } | 318 | } |
314 | if (irqclr) { | 319 | if (irqclr) { |
315 | titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); | 320 | titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); |
316 | am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask); | 321 | if (status & IRQENB_EOS) |
322 | am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, | ||
323 | ts_dev->step_mask); | ||
317 | return IRQ_HANDLED; | 324 | return IRQ_HANDLED; |
318 | } | 325 | } |
319 | return IRQ_NONE; | 326 | return IRQ_NONE; |
320 | } | 327 | } |
321 | 328 | ||
322 | static int titsc_parse_dt(struct platform_device *pdev, | 329 | static int titsc_parse_dt(struct platform_device *pdev, |
323 | struct titsc *ts_dev) | 330 | struct titsc *ts_dev) |
324 | { | 331 | { |
325 | struct device_node *node = pdev->dev.of_node; | 332 | struct device_node *node = pdev->dev.of_node; |
326 | int err; | 333 | int err; |
327 | 334 | ||
328 | if (!node) | 335 | if (!node) |
329 | return -EINVAL; | 336 | return -EINVAL; |
330 | 337 | ||
331 | err = of_property_read_u32(node, "ti,wires", &ts_dev->wires); | 338 | err = of_property_read_u32(node, "ti,wires", &ts_dev->wires); |
332 | if (err < 0) | 339 | if (err < 0) |
333 | return err; | 340 | return err; |
334 | switch (ts_dev->wires) { | 341 | switch (ts_dev->wires) { |
335 | case 4: | 342 | case 4: |
336 | case 5: | 343 | case 5: |
337 | case 8: | 344 | case 8: |
338 | break; | 345 | break; |
339 | default: | 346 | default: |
340 | return -EINVAL; | 347 | return -EINVAL; |
341 | } | 348 | } |
342 | 349 | ||
343 | err = of_property_read_u32(node, "ti,x-plate-resistance", | 350 | err = of_property_read_u32(node, "ti,x-plate-resistance", |
344 | &ts_dev->x_plate_resistance); | 351 | &ts_dev->x_plate_resistance); |
345 | if (err < 0) | 352 | if (err < 0) |
346 | return err; | 353 | return err; |
347 | 354 | ||
348 | /* | 355 | /* |
349 | * Try with the new binding first. If it fails, try again with | 356 | * Try with the new binding first. If it fails, try again with |
350 | * bogus, miss-spelled version. | 357 | * bogus, miss-spelled version. |
351 | */ | 358 | */ |
352 | err = of_property_read_u32(node, "ti,coordinate-readouts", | 359 | err = of_property_read_u32(node, "ti,coordinate-readouts", |
353 | &ts_dev->coordinate_readouts); | 360 | &ts_dev->coordinate_readouts); |
354 | if (err < 0) | 361 | if (err < 0) |
355 | err = of_property_read_u32(node, "ti,coordiante-readouts", | 362 | err = of_property_read_u32(node, "ti,coordiante-readouts", |
356 | &ts_dev->coordinate_readouts); | 363 | &ts_dev->coordinate_readouts); |
357 | if (err < 0) | 364 | if (err < 0) |
358 | return err; | 365 | return err; |
359 | 366 | ||
360 | err = of_property_read_u32(node, "ti,charge-delay", | 367 | err = of_property_read_u32(node, "ti,charge-delay", |
361 | &ts_dev->charge_delay); | 368 | &ts_dev->charge_delay); |
362 | /* | 369 | /* |
363 | * If ti,charge-delay value is not specified, then use | 370 | * If ti,charge-delay value is not specified, then use |
364 | * CHARGEDLY_OPENDLY as the default value. | 371 | * CHARGEDLY_OPENDLY as the default value. |
365 | */ | 372 | */ |
366 | if (err < 0) { | 373 | if (err < 0) { |
367 | ts_dev->charge_delay = CHARGEDLY_OPENDLY; | 374 | ts_dev->charge_delay = CHARGEDLY_OPENDLY; |
368 | dev_warn(&pdev->dev, "ti,charge-delay not specified\n"); | 375 | dev_warn(&pdev->dev, "ti,charge-delay not specified\n"); |
369 | } | 376 | } |
370 | 377 | ||
371 | return of_property_read_u32_array(node, "ti,wire-config", | 378 | return of_property_read_u32_array(node, "ti,wire-config", |
372 | ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp)); | 379 | ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp)); |
373 | } | 380 | } |
374 | 381 | ||
375 | /* | 382 | /* |
376 | * The functions for inserting/removing driver as a module. | 383 | * The functions for inserting/removing driver as a module. |
377 | */ | 384 | */ |
378 | 385 | ||
379 | static int titsc_probe(struct platform_device *pdev) | 386 | static int titsc_probe(struct platform_device *pdev) |
380 | { | 387 | { |
381 | struct titsc *ts_dev; | 388 | struct titsc *ts_dev; |
382 | struct input_dev *input_dev; | 389 | struct input_dev *input_dev; |
383 | struct ti_tscadc_dev *tscadc_dev = ti_tscadc_dev_get(pdev); | 390 | struct ti_tscadc_dev *tscadc_dev = ti_tscadc_dev_get(pdev); |
384 | int err; | 391 | int err; |
385 | 392 | ||
386 | /* Allocate memory for device */ | 393 | /* Allocate memory for device */ |
387 | ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL); | 394 | ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL); |
388 | input_dev = input_allocate_device(); | 395 | input_dev = input_allocate_device(); |
389 | if (!ts_dev || !input_dev) { | 396 | if (!ts_dev || !input_dev) { |
390 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | 397 | dev_err(&pdev->dev, "failed to allocate memory.\n"); |
391 | err = -ENOMEM; | 398 | err = -ENOMEM; |
392 | goto err_free_mem; | 399 | goto err_free_mem; |
393 | } | 400 | } |
394 | 401 | ||
395 | tscadc_dev->tsc = ts_dev; | 402 | tscadc_dev->tsc = ts_dev; |
396 | ts_dev->mfd_tscadc = tscadc_dev; | 403 | ts_dev->mfd_tscadc = tscadc_dev; |
397 | ts_dev->input = input_dev; | 404 | ts_dev->input = input_dev; |
398 | ts_dev->irq = tscadc_dev->irq; | 405 | ts_dev->irq = tscadc_dev->irq; |
399 | 406 | ||
400 | err = titsc_parse_dt(pdev, ts_dev); | 407 | err = titsc_parse_dt(pdev, ts_dev); |
401 | if (err) { | 408 | if (err) { |
402 | dev_err(&pdev->dev, "Could not find valid DT data.\n"); | 409 | dev_err(&pdev->dev, "Could not find valid DT data.\n"); |
403 | goto err_free_mem; | 410 | goto err_free_mem; |
404 | } | 411 | } |
405 | 412 | ||
406 | err = request_irq(ts_dev->irq, titsc_irq, | 413 | err = request_irq(ts_dev->irq, titsc_irq, |
407 | IRQF_SHARED, pdev->dev.driver->name, ts_dev); | 414 | IRQF_SHARED, pdev->dev.driver->name, ts_dev); |
408 | if (err) { | 415 | if (err) { |
409 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | 416 | dev_err(&pdev->dev, "failed to allocate irq.\n"); |
410 | goto err_free_mem; | 417 | goto err_free_mem; |
411 | } | 418 | } |
412 | 419 | ||
413 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); | 420 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); |
414 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS); | 421 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS); |
415 | err = titsc_config_wires(ts_dev); | 422 | err = titsc_config_wires(ts_dev); |
416 | if (err) { | 423 | if (err) { |
417 | dev_err(&pdev->dev, "wrong i/p wire configuration\n"); | 424 | dev_err(&pdev->dev, "wrong i/p wire configuration\n"); |
418 | goto err_free_irq; | 425 | goto err_free_irq; |
419 | } | 426 | } |
420 | titsc_step_config(ts_dev); | 427 | titsc_step_config(ts_dev); |
421 | titsc_writel(ts_dev, REG_FIFO0THR, | 428 | titsc_writel(ts_dev, REG_FIFO0THR, |
422 | ts_dev->coordinate_readouts * 2 + 2 - 1); | 429 | ts_dev->coordinate_readouts * 2 + 2 - 1); |
423 | 430 | ||
424 | input_dev->name = "ti-tsc"; | 431 | input_dev->name = "ti-tsc"; |
425 | input_dev->dev.parent = &pdev->dev; | 432 | input_dev->dev.parent = &pdev->dev; |
426 | 433 | ||
427 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 434 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
428 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | 435 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); |
429 | 436 | ||
430 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); | 437 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); |
431 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); | 438 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); |
432 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); | 439 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); |
433 | 440 | ||
434 | /* register to the input system */ | 441 | /* register to the input system */ |
435 | err = input_register_device(input_dev); | 442 | err = input_register_device(input_dev); |
436 | if (err) | 443 | if (err) |
437 | goto err_free_irq; | 444 | goto err_free_irq; |
438 | 445 | ||
439 | platform_set_drvdata(pdev, ts_dev); | 446 | platform_set_drvdata(pdev, ts_dev); |
440 | return 0; | 447 | return 0; |
441 | 448 | ||
442 | err_free_irq: | 449 | err_free_irq: |
443 | free_irq(ts_dev->irq, ts_dev); | 450 | free_irq(ts_dev->irq, ts_dev); |
444 | err_free_mem: | 451 | err_free_mem: |
445 | input_free_device(input_dev); | 452 | input_free_device(input_dev); |
446 | kfree(ts_dev); | 453 | kfree(ts_dev); |
447 | return err; | 454 | return err; |
448 | } | 455 | } |
449 | 456 | ||
450 | static int titsc_remove(struct platform_device *pdev) | 457 | static int titsc_remove(struct platform_device *pdev) |
451 | { | 458 | { |
452 | struct titsc *ts_dev = platform_get_drvdata(pdev); | 459 | struct titsc *ts_dev = platform_get_drvdata(pdev); |
453 | u32 steps; | 460 | u32 steps; |
454 | 461 | ||
455 | free_irq(ts_dev->irq, ts_dev); | 462 | free_irq(ts_dev->irq, ts_dev); |
456 | 463 | ||
457 | /* total steps followed by the enable mask */ | 464 | /* total steps followed by the enable mask */ |
458 | steps = 2 * ts_dev->coordinate_readouts + 2; | 465 | steps = 2 * ts_dev->coordinate_readouts + 2; |
459 | steps = (1 << steps) - 1; | 466 | steps = (1 << steps) - 1; |
460 | am335x_tsc_se_clr(ts_dev->mfd_tscadc, steps); | 467 | am335x_tsc_se_clr(ts_dev->mfd_tscadc, steps); |
461 | 468 | ||
462 | input_unregister_device(ts_dev->input); | 469 | input_unregister_device(ts_dev->input); |
463 | 470 | ||
464 | kfree(ts_dev); | 471 | kfree(ts_dev); |
465 | return 0; | 472 | return 0; |
466 | } | 473 | } |
467 | 474 | ||
468 | #ifdef CONFIG_PM | 475 | #ifdef CONFIG_PM |
469 | static int titsc_suspend(struct device *dev) | 476 | static int titsc_suspend(struct device *dev) |
470 | { | 477 | { |
471 | struct titsc *ts_dev = dev_get_drvdata(dev); | 478 | struct titsc *ts_dev = dev_get_drvdata(dev); |
472 | struct ti_tscadc_dev *tscadc_dev; | 479 | struct ti_tscadc_dev *tscadc_dev; |
473 | unsigned int idle; | 480 | unsigned int idle; |
474 | 481 | ||
475 | tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); | 482 | tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); |
476 | if (device_may_wakeup(tscadc_dev->dev)) { | 483 | if (device_may_wakeup(tscadc_dev->dev)) { |
477 | idle = titsc_readl(ts_dev, REG_IRQENABLE); | 484 | idle = titsc_readl(ts_dev, REG_IRQENABLE); |
478 | titsc_writel(ts_dev, REG_IRQENABLE, | 485 | titsc_writel(ts_dev, REG_IRQENABLE, |
479 | (idle | IRQENB_HW_PEN)); | 486 | (idle | IRQENB_HW_PEN)); |
480 | titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | 487 | titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); |
481 | } | 488 | } |
482 | return 0; | 489 | return 0; |
483 | } | 490 | } |
484 | 491 | ||
485 | static int titsc_resume(struct device *dev) | 492 | static int titsc_resume(struct device *dev) |
486 | { | 493 | { |
487 | struct titsc *ts_dev = dev_get_drvdata(dev); | 494 | struct titsc *ts_dev = dev_get_drvdata(dev); |
488 | struct ti_tscadc_dev *tscadc_dev; | 495 | struct ti_tscadc_dev *tscadc_dev; |
489 | 496 | ||
490 | tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); | 497 | tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev)); |
491 | if (device_may_wakeup(tscadc_dev->dev)) { | 498 | if (device_may_wakeup(tscadc_dev->dev)) { |
492 | titsc_writel(ts_dev, REG_IRQWAKEUP, | 499 | titsc_writel(ts_dev, REG_IRQWAKEUP, |
493 | 0x00); | 500 | 0x00); |
494 | titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); | 501 | titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); |
495 | } | 502 | } |
496 | titsc_step_config(ts_dev); | 503 | titsc_step_config(ts_dev); |
497 | titsc_writel(ts_dev, REG_FIFO0THR, | 504 | titsc_writel(ts_dev, REG_FIFO0THR, |
498 | ts_dev->coordinate_readouts * 2 + 2 - 1); | 505 | ts_dev->coordinate_readouts * 2 + 2 - 1); |
499 | return 0; | 506 | return 0; |
500 | } | 507 | } |
501 | 508 | ||
502 | static const struct dev_pm_ops titsc_pm_ops = { | 509 | static const struct dev_pm_ops titsc_pm_ops = { |
503 | .suspend = titsc_suspend, | 510 | .suspend = titsc_suspend, |
504 | .resume = titsc_resume, | 511 | .resume = titsc_resume, |
505 | }; | 512 | }; |
506 | #define TITSC_PM_OPS (&titsc_pm_ops) | 513 | #define TITSC_PM_OPS (&titsc_pm_ops) |
507 | #else | 514 | #else |
508 | #define TITSC_PM_OPS NULL | 515 | #define TITSC_PM_OPS NULL |
509 | #endif | 516 | #endif |
510 | 517 | ||
511 | static const struct of_device_id ti_tsc_dt_ids[] = { | 518 | static const struct of_device_id ti_tsc_dt_ids[] = { |
512 | { .compatible = "ti,am3359-tsc", }, | 519 | { .compatible = "ti,am3359-tsc", }, |
513 | { } | 520 | { } |
514 | }; | 521 | }; |
515 | MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids); | 522 | MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids); |
516 | 523 | ||
517 | static struct platform_driver ti_tsc_driver = { | 524 | static struct platform_driver ti_tsc_driver = { |
518 | .probe = titsc_probe, | 525 | .probe = titsc_probe, |
519 | .remove = titsc_remove, | 526 | .remove = titsc_remove, |
520 | .driver = { | 527 | .driver = { |
521 | .name = "TI-am335x-tsc", | 528 | .name = "TI-am335x-tsc", |
522 | .owner = THIS_MODULE, | 529 | .owner = THIS_MODULE, |
523 | .pm = TITSC_PM_OPS, | 530 | .pm = TITSC_PM_OPS, |
524 | .of_match_table = ti_tsc_dt_ids, | 531 | .of_match_table = ti_tsc_dt_ids, |
525 | }, | 532 | }, |
526 | }; | 533 | }; |
527 | module_platform_driver(ti_tsc_driver); | 534 | module_platform_driver(ti_tsc_driver); |
528 | 535 | ||
529 | MODULE_DESCRIPTION("TI touchscreen controller driver"); | 536 | MODULE_DESCRIPTION("TI touchscreen controller driver"); |
530 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | 537 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); |
531 | MODULE_LICENSE("GPL"); | 538 | MODULE_LICENSE("GPL"); |
532 | 539 |