]>
Commit | Line | Data |
---|---|---|
9883b64d GKH |
1 | From f81197b8a31b8fb287ae57f597b5b6841e1ece92 Mon Sep 17 00:00:00 2001 |
2 | From: Kristina Martšenko <kristina.martsenko@gmail.com> | |
3 | Date: Sun, 25 Jan 2015 18:28:19 +0200 | |
4 | Subject: iio: mxs-lradc: separate touchscreen and buffer virtual channels | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | From: Kristina Martšenko <kristina.martsenko@gmail.com> | |
10 | ||
11 | commit f81197b8a31b8fb287ae57f597b5b6841e1ece92 upstream. | |
12 | ||
13 | The touchscreen was initially designed [1] to map all of its physical | |
14 | channels to one virtual channel, leaving buffered capture to use the | |
15 | remaining 7 virtual channels. When the touchscreen was reimplemented | |
16 | [2], it was made to use four virtual channels, which overlap and | |
17 | conflict with the channels the buffer uses. | |
18 | ||
19 | As a result, when the buffer is enabled, the touchscreen's virtual | |
20 | channels are remapped to whichever physical channels the buffer was | |
21 | configured with, causing the touchscreen to read those instead of the | |
22 | touch measurement channels. Effectively the touchscreen stops working. | |
23 | ||
24 | So here we separate the channels again, giving the touchscreen 2 virtual | |
25 | channels and the buffer 6. We can't give the touchscreen just 1 channel | |
26 | as before, as the current pressure calculation requires 2 channels to be | |
27 | read at the same time. | |
28 | ||
29 | This makes the touchscreen continue to work during buffered capture. It | |
30 | has been tested on i.MX28, but not on i.MX23. | |
31 | ||
32 | [1] 06ddd353f5c8 ("iio: mxs: Implement support for touchscreen") | |
33 | [2] dee05308f602 ("Staging/iio/adc/touchscreen/MXS: add interrupt driven | |
34 | touch detection") | |
35 | ||
36 | Signed-off-by: Kristina Martšenko <kristina.martsenko@gmail.com> | |
37 | Reviewed-by: Marek Vasut <marex@denx.de> | |
38 | Signed-off-by: Jonathan Cameron <jic23@kernel.org> | |
39 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
40 | ||
41 | --- | |
42 | drivers/staging/iio/adc/mxs-lradc.c | 166 ++++++++++++++++-------------------- | |
43 | 1 file changed, 75 insertions(+), 91 deletions(-) | |
44 | ||
45 | --- a/drivers/staging/iio/adc/mxs-lradc.c | |
46 | +++ b/drivers/staging/iio/adc/mxs-lradc.c | |
47 | @@ -214,11 +214,14 @@ struct mxs_lradc { | |
48 | unsigned long is_divided; | |
49 | ||
50 | /* | |
51 | - * Touchscreen LRADC channels receives a private slot in the CTRL4 | |
52 | - * register, the slot #7. Therefore only 7 slots instead of 8 in the | |
53 | - * CTRL4 register can be mapped to LRADC channels when using the | |
54 | - * touchscreen. | |
55 | - * | |
56 | + * When the touchscreen is enabled, we give it two private virtual | |
57 | + * channels: #6 and #7. This means that only 6 virtual channels (instead | |
58 | + * of 8) will be available for buffered capture. | |
59 | + */ | |
60 | +#define TOUCHSCREEN_VCHANNEL1 7 | |
61 | +#define TOUCHSCREEN_VCHANNEL2 6 | |
62 | + | |
63 | + /* | |
64 | * Furthermore, certain LRADC channels are shared between touchscreen | |
65 | * and/or touch-buttons and generic LRADC block. Therefore when using | |
66 | * either of these, these channels are not available for the regular | |
67 | @@ -342,6 +345,9 @@ struct mxs_lradc { | |
68 | #define LRADC_CTRL4 0x140 | |
69 | #define LRADC_CTRL4_LRADCSELECT_MASK(n) (0xf << ((n) * 4)) | |
70 | #define LRADC_CTRL4_LRADCSELECT_OFFSET(n) ((n) * 4) | |
71 | +#define LRADC_CTRL4_LRADCSELECT(n, x) \ | |
72 | + (((x) << LRADC_CTRL4_LRADCSELECT_OFFSET(n)) & \ | |
73 | + LRADC_CTRL4_LRADCSELECT_MASK(n)) | |
74 | ||
75 | #define LRADC_RESOLUTION 12 | |
76 | #define LRADC_SINGLE_SAMPLE_MASK ((1 << LRADC_RESOLUTION) - 1) | |
77 | @@ -416,6 +422,14 @@ static bool mxs_lradc_check_touch_event( | |
78 | LRADC_STATUS_TOUCH_DETECT_RAW); | |
79 | } | |
80 | ||
81 | +static void mxs_lradc_map_channel(struct mxs_lradc *lradc, unsigned vch, | |
82 | + unsigned ch) | |
83 | +{ | |
84 | + mxs_lradc_reg_clear(lradc, LRADC_CTRL4_LRADCSELECT_MASK(vch), | |
85 | + LRADC_CTRL4); | |
86 | + mxs_lradc_reg_set(lradc, LRADC_CTRL4_LRADCSELECT(vch, ch), LRADC_CTRL4); | |
87 | +} | |
88 | + | |
89 | static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch) | |
90 | { | |
91 | /* | |
92 | @@ -443,12 +457,8 @@ static void mxs_lradc_setup_ts_channel(s | |
93 | LRADC_DELAY_DELAY(lradc->over_sample_delay - 1), | |
94 | LRADC_DELAY(3)); | |
95 | ||
96 | - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) | | |
97 | - LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) | | |
98 | - LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1); | |
99 | + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch), LRADC_CTRL1); | |
100 | ||
101 | - /* wake us again, when the complete conversion is done */ | |
102 | - mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch), LRADC_CTRL1); | |
103 | /* | |
104 | * after changing the touchscreen plates setting | |
105 | * the signals need some initial time to settle. Start the | |
106 | @@ -502,12 +512,8 @@ static void mxs_lradc_setup_ts_pressure( | |
107 | LRADC_DELAY_DELAY(lradc->over_sample_delay - 1), | |
108 | LRADC_DELAY(3)); | |
109 | ||
110 | - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(2) | | |
111 | - LRADC_CTRL1_LRADC_IRQ(3) | LRADC_CTRL1_LRADC_IRQ(4) | | |
112 | - LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1); | |
113 | + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(ch2), LRADC_CTRL1); | |
114 | ||
115 | - /* wake us again, when the conversions are done */ | |
116 | - mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(ch2), LRADC_CTRL1); | |
117 | /* | |
118 | * after changing the touchscreen plates setting | |
119 | * the signals need some initial time to settle. Start the | |
120 | @@ -573,36 +579,6 @@ static unsigned mxs_lradc_read_ts_pressu | |
121 | #define TS_CH_XM 4 | |
122 | #define TS_CH_YM 5 | |
123 | ||
124 | -static int mxs_lradc_read_ts_channel(struct mxs_lradc *lradc) | |
125 | -{ | |
126 | - u32 reg; | |
127 | - int val; | |
128 | - | |
129 | - reg = readl(lradc->base + LRADC_CTRL1); | |
130 | - | |
131 | - /* only channels 3 to 5 are of interest here */ | |
132 | - if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YP)) { | |
133 | - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YP) | | |
134 | - LRADC_CTRL1_LRADC_IRQ(TS_CH_YP), LRADC_CTRL1); | |
135 | - val = mxs_lradc_read_raw_channel(lradc, TS_CH_YP); | |
136 | - } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_XM)) { | |
137 | - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_XM) | | |
138 | - LRADC_CTRL1_LRADC_IRQ(TS_CH_XM), LRADC_CTRL1); | |
139 | - val = mxs_lradc_read_raw_channel(lradc, TS_CH_XM); | |
140 | - } else if (reg & LRADC_CTRL1_LRADC_IRQ(TS_CH_YM)) { | |
141 | - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ_EN(TS_CH_YM) | | |
142 | - LRADC_CTRL1_LRADC_IRQ(TS_CH_YM), LRADC_CTRL1); | |
143 | - val = mxs_lradc_read_raw_channel(lradc, TS_CH_YM); | |
144 | - } else { | |
145 | - return -EIO; | |
146 | - } | |
147 | - | |
148 | - mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2)); | |
149 | - mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3)); | |
150 | - | |
151 | - return val; | |
152 | -} | |
153 | - | |
154 | /* | |
155 | * YP(open)--+-------------+ | |
156 | * | |--+ | |
157 | @@ -646,7 +622,8 @@ static void mxs_lradc_prepare_x_pos(stru | |
158 | mxs_lradc_reg_set(lradc, mxs_lradc_drive_x_plate(lradc), LRADC_CTRL0); | |
159 | ||
160 | lradc->cur_plate = LRADC_SAMPLE_X; | |
161 | - mxs_lradc_setup_ts_channel(lradc, TS_CH_YP); | |
162 | + mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YP); | |
163 | + mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1); | |
164 | } | |
165 | ||
166 | /* | |
167 | @@ -667,7 +644,8 @@ static void mxs_lradc_prepare_y_pos(stru | |
168 | mxs_lradc_reg_set(lradc, mxs_lradc_drive_y_plate(lradc), LRADC_CTRL0); | |
169 | ||
170 | lradc->cur_plate = LRADC_SAMPLE_Y; | |
171 | - mxs_lradc_setup_ts_channel(lradc, TS_CH_XM); | |
172 | + mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_XM); | |
173 | + mxs_lradc_setup_ts_channel(lradc, TOUCHSCREEN_VCHANNEL1); | |
174 | } | |
175 | ||
176 | /* | |
177 | @@ -688,7 +666,10 @@ static void mxs_lradc_prepare_pressure(s | |
178 | mxs_lradc_reg_set(lradc, mxs_lradc_drive_pressure(lradc), LRADC_CTRL0); | |
179 | ||
180 | lradc->cur_plate = LRADC_SAMPLE_PRESSURE; | |
181 | - mxs_lradc_setup_ts_pressure(lradc, TS_CH_XP, TS_CH_YM); | |
182 | + mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL1, TS_CH_YM); | |
183 | + mxs_lradc_map_channel(lradc, TOUCHSCREEN_VCHANNEL2, TS_CH_XP); | |
184 | + mxs_lradc_setup_ts_pressure(lradc, TOUCHSCREEN_VCHANNEL2, | |
185 | + TOUCHSCREEN_VCHANNEL1); | |
186 | } | |
187 | ||
188 | static void mxs_lradc_enable_touch_detection(struct mxs_lradc *lradc) | |
189 | @@ -701,6 +682,19 @@ static void mxs_lradc_enable_touch_detec | |
190 | mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); | |
191 | } | |
192 | ||
193 | +static void mxs_lradc_start_touch_event(struct mxs_lradc *lradc) | |
194 | +{ | |
195 | + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, | |
196 | + LRADC_CTRL1); | |
197 | + mxs_lradc_reg_set(lradc, | |
198 | + LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1); | |
199 | + /* | |
200 | + * start with the Y-pos, because it uses nearly the same plate | |
201 | + * settings like the touch detection | |
202 | + */ | |
203 | + mxs_lradc_prepare_y_pos(lradc); | |
204 | +} | |
205 | + | |
206 | static void mxs_lradc_report_ts_event(struct mxs_lradc *lradc) | |
207 | { | |
208 | input_report_abs(lradc->ts_input, ABS_X, lradc->ts_x_pos); | |
209 | @@ -718,10 +712,12 @@ static void mxs_lradc_complete_touch_eve | |
210 | * start a dummy conversion to burn time to settle the signals | |
211 | * note: we are not interested in the conversion's value | |
212 | */ | |
213 | - mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(5)); | |
214 | - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_LRADC_IRQ(5), LRADC_CTRL1); | |
215 | - mxs_lradc_reg_set(lradc, LRADC_CTRL1_LRADC_IRQ_EN(5), LRADC_CTRL1); | |
216 | - mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << 5) | | |
217 | + mxs_lradc_reg_wrt(lradc, 0, LRADC_CH(TOUCHSCREEN_VCHANNEL1)); | |
218 | + mxs_lradc_reg_clear(lradc, | |
219 | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | | |
220 | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1); | |
221 | + mxs_lradc_reg_wrt(lradc, | |
222 | + LRADC_DELAY_TRIGGER(1 << TOUCHSCREEN_VCHANNEL1) | | |
223 | LRADC_DELAY_KICK | LRADC_DELAY_DELAY(10), /* waste 5 ms */ | |
224 | LRADC_DELAY(2)); | |
225 | } | |
226 | @@ -753,59 +749,45 @@ static void mxs_lradc_finish_touch_event | |
227 | ||
228 | /* if it is released, wait for the next touch via IRQ */ | |
229 | lradc->cur_plate = LRADC_TOUCH; | |
230 | - mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1); | |
231 | + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(2)); | |
232 | + mxs_lradc_reg_wrt(lradc, 0, LRADC_DELAY(3)); | |
233 | + mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ | | |
234 | + LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) | | |
235 | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1), LRADC_CTRL1); | |
236 | mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); | |
237 | } | |
238 | ||
239 | /* touchscreen's state machine */ | |
240 | static void mxs_lradc_handle_touch(struct mxs_lradc *lradc) | |
241 | { | |
242 | - int val; | |
243 | - | |
244 | switch (lradc->cur_plate) { | |
245 | case LRADC_TOUCH: | |
246 | - /* | |
247 | - * start with the Y-pos, because it uses nearly the same plate | |
248 | - * settings like the touch detection | |
249 | - */ | |
250 | - if (mxs_lradc_check_touch_event(lradc)) { | |
251 | - mxs_lradc_reg_clear(lradc, | |
252 | - LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, | |
253 | - LRADC_CTRL1); | |
254 | - mxs_lradc_prepare_y_pos(lradc); | |
255 | - } | |
256 | + if (mxs_lradc_check_touch_event(lradc)) | |
257 | + mxs_lradc_start_touch_event(lradc); | |
258 | mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, | |
259 | LRADC_CTRL1); | |
260 | return; | |
261 | ||
262 | case LRADC_SAMPLE_Y: | |
263 | - val = mxs_lradc_read_ts_channel(lradc); | |
264 | - if (val < 0) { | |
265 | - mxs_lradc_enable_touch_detection(lradc); /* re-start */ | |
266 | - return; | |
267 | - } | |
268 | - lradc->ts_y_pos = val; | |
269 | + lradc->ts_y_pos = mxs_lradc_read_raw_channel(lradc, | |
270 | + TOUCHSCREEN_VCHANNEL1); | |
271 | mxs_lradc_prepare_x_pos(lradc); | |
272 | return; | |
273 | ||
274 | case LRADC_SAMPLE_X: | |
275 | - val = mxs_lradc_read_ts_channel(lradc); | |
276 | - if (val < 0) { | |
277 | - mxs_lradc_enable_touch_detection(lradc); /* re-start */ | |
278 | - return; | |
279 | - } | |
280 | - lradc->ts_x_pos = val; | |
281 | + lradc->ts_x_pos = mxs_lradc_read_raw_channel(lradc, | |
282 | + TOUCHSCREEN_VCHANNEL1); | |
283 | mxs_lradc_prepare_pressure(lradc); | |
284 | return; | |
285 | ||
286 | case LRADC_SAMPLE_PRESSURE: | |
287 | - lradc->ts_pressure = | |
288 | - mxs_lradc_read_ts_pressure(lradc, TS_CH_XP, TS_CH_YM); | |
289 | + lradc->ts_pressure = mxs_lradc_read_ts_pressure(lradc, | |
290 | + TOUCHSCREEN_VCHANNEL2, | |
291 | + TOUCHSCREEN_VCHANNEL1); | |
292 | mxs_lradc_complete_touch_event(lradc); | |
293 | return; | |
294 | ||
295 | case LRADC_SAMPLE_VALID: | |
296 | - val = mxs_lradc_read_ts_channel(lradc); /* ignore the value */ | |
297 | mxs_lradc_finish_touch_event(lradc, 1); | |
298 | break; | |
299 | } | |
300 | @@ -1083,9 +1065,8 @@ static void mxs_lradc_disable_ts(struct | |
301 | { | |
302 | /* stop all interrupts from firing */ | |
303 | mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN | | |
304 | - LRADC_CTRL1_LRADC_IRQ_EN(2) | LRADC_CTRL1_LRADC_IRQ_EN(3) | | |
305 | - LRADC_CTRL1_LRADC_IRQ_EN(4) | LRADC_CTRL1_LRADC_IRQ_EN(5), | |
306 | - LRADC_CTRL1); | |
307 | + LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL1) | | |
308 | + LRADC_CTRL1_LRADC_IRQ_EN(TOUCHSCREEN_VCHANNEL2), LRADC_CTRL1); | |
309 | ||
310 | /* Power-down touchscreen touch-detect circuitry. */ | |
311 | mxs_lradc_reg_clear(lradc, mxs_lradc_plate_mask(lradc), LRADC_CTRL0); | |
312 | @@ -1151,26 +1132,29 @@ static irqreturn_t mxs_lradc_handle_irq( | |
313 | struct iio_dev *iio = data; | |
314 | struct mxs_lradc *lradc = iio_priv(iio); | |
315 | unsigned long reg = readl(lradc->base + LRADC_CTRL1); | |
316 | + uint32_t clr_irq = mxs_lradc_irq_mask(lradc); | |
317 | const uint32_t ts_irq_mask = | |
318 | LRADC_CTRL1_TOUCH_DETECT_IRQ | | |
319 | - LRADC_CTRL1_LRADC_IRQ(2) | | |
320 | - LRADC_CTRL1_LRADC_IRQ(3) | | |
321 | - LRADC_CTRL1_LRADC_IRQ(4) | | |
322 | - LRADC_CTRL1_LRADC_IRQ(5); | |
323 | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | | |
324 | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2); | |
325 | ||
326 | if (!(reg & mxs_lradc_irq_mask(lradc))) | |
327 | return IRQ_NONE; | |
328 | ||
329 | - if (lradc->use_touchscreen && (reg & ts_irq_mask)) | |
330 | + if (lradc->use_touchscreen && (reg & ts_irq_mask)) { | |
331 | mxs_lradc_handle_touch(lradc); | |
332 | ||
333 | + /* Make sure we don't clear the next conversion's interrupt. */ | |
334 | + clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | | |
335 | + LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2)); | |
336 | + } | |
337 | + | |
338 | if (iio_buffer_enabled(iio)) | |
339 | iio_trigger_poll(iio->trig); | |
340 | else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) | |
341 | complete(&lradc->completion); | |
342 | ||
343 | - mxs_lradc_reg_clear(lradc, reg & mxs_lradc_irq_mask(lradc), | |
344 | - LRADC_CTRL1); | |
345 | + mxs_lradc_reg_clear(lradc, reg & clr_irq, LRADC_CTRL1); | |
346 | ||
347 | return IRQ_HANDLED; | |
348 | } | |
349 | @@ -1346,7 +1330,7 @@ static bool mxs_lradc_validate_scan_mask | |
350 | if (lradc->use_touchbutton) | |
351 | rsvd_chans++; | |
352 | if (lradc->use_touchscreen) | |
353 | - rsvd_chans++; | |
354 | + rsvd_chans += 2; | |
355 | ||
356 | /* Test for attempts to map channels with special mode of operation. */ | |
357 | if (bitmap_intersects(mask, &rsvd_mask, LRADC_MAX_TOTAL_CHANS)) |