merge of '178eac00dc5aa8338d42e8e203633bec7817bbf6'
[vuplus_openembedded] / packages / linux / linux-rp-2.6.24 / tosa / 0034-Driver-for-WM97xx-touchscreens-in-streaming-mode-on.patch
1 From 821604bad5ce1ef942eeb420afd9ea2c5c92875e Mon Sep 17 00:00:00 2001
2 From: Mark Brown <broonie@opensource.wolfsonmicro.com>
3 Date: Sat, 26 Jan 2008 21:14:19 +0300
4 Subject: [PATCH 34/64] Driver for WM97xx touchscreens in streaming mode on Mainstone
5
6 Signed-off-by: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
7 Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com>
8 Signed-off-by: Mike Arthur <mike.arthur@wolfsonmicro.com>
9 Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
10 Cc: Dmitry Baryshkov <dbaryshkov@gmail.com>
11 Cc: Stanley Cai <stanley.cai@intel.com>
12 Cc: Rodolfo Giometti <giometti@enneenne.com>
13 Cc: Russell King <rmk@arm.linux.org.uk>
14 Cc: Marc Kleine-Budde <mkl@pengutronix.de>
15 Cc: Ian Molton <spyro@f2s.com>
16 Cc: Vince Sanders <vince@kyllikki.org>
17 Cc: Andrew Zabolotny <zap@homelink.ru>
18 ---
19  drivers/input/touchscreen/mainstone-wm97xx.c |  298 ++++++++++++++++++++++++++
20  1 files changed, 298 insertions(+), 0 deletions(-)
21  create mode 100644 drivers/input/touchscreen/mainstone-wm97xx.c
22
23 diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
24 new file mode 100644
25 index 0000000..8e1c35d
26 --- /dev/null
27 +++ b/drivers/input/touchscreen/mainstone-wm97xx.c
28 @@ -0,0 +1,298 @@
29 +/*
30 + * mainstone-wm97xx.c  --  Mainstone Continuous Touch screen driver for
31 + *                         Wolfson WM97xx AC97 Codecs.
32 + *
33 + * Copyright 2004, 2007 Wolfson Microelectronics PLC.
34 + * Author: Liam Girdwood
35 + *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
36 + * Parts Copyright : Ian Molton <spyro@f2s.com>
37 + *                   Andrew Zabolotny <zap@homelink.ru>
38 + *
39 + *  This program is free software; you can redistribute  it and/or modify it
40 + *  under  the terms of  the GNU General  Public License as published by the
41 + *  Free Software Foundation;  either version 2 of the  License, or (at your
42 + *  option) any later version.
43 + *
44 + * Notes:
45 + *     This is a wm97xx extended touch driver to capture touch
46 + *     data in a continuous manner on the Intel XScale archictecture
47 + *
48 + *  Features:
49 + *       - codecs supported:- WM9705, WM9712, WM9713
50 + *       - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
51 + *
52 + */
53 +
54 +#include <linux/module.h>
55 +#include <linux/moduleparam.h>
56 +#include <linux/version.h>
57 +#include <linux/kernel.h>
58 +#include <linux/init.h>
59 +#include <linux/delay.h>
60 +#include <linux/irq.h>
61 +#include <linux/interrupt.h>
62 +#include <linux/wm97xx.h>
63 +#include <linux/io.h>
64 +#include <asm/arch/pxa-regs.h>
65 +
66 +#define VERSION                "0.13"
67 +
68 +struct continuous {
69 +       u16 id;    /* codec id */
70 +       u8 code;   /* continuous code */
71 +       u8 reads;  /* number of coord reads per read cycle */
72 +       u32 speed; /* number of coords per second */
73 +};
74 +
75 +#define WM_READS(sp) ((sp / HZ) + 1)
76 +
77 +static const struct continuous cinfo[] = {
78 +       {WM9705_ID2, 0, WM_READS(94), 94},
79 +       {WM9705_ID2, 1, WM_READS(188), 188},
80 +       {WM9705_ID2, 2, WM_READS(375), 375},
81 +       {WM9705_ID2, 3, WM_READS(750), 750},
82 +       {WM9712_ID2, 0, WM_READS(94), 94},
83 +       {WM9712_ID2, 1, WM_READS(188), 188},
84 +       {WM9712_ID2, 2, WM_READS(375), 375},
85 +       {WM9712_ID2, 3, WM_READS(750), 750},
86 +       {WM9713_ID2, 0, WM_READS(94), 94},
87 +       {WM9713_ID2, 1, WM_READS(120), 120},
88 +       {WM9713_ID2, 2, WM_READS(154), 154},
89 +       {WM9713_ID2, 3, WM_READS(188), 188},
90 +};
91 +
92 +/* continuous speed index */
93 +static int sp_idx;
94 +static u16 last, tries;
95 +
96 +/*
97 + * Pen sampling frequency (Hz) in continuous mode.
98 + */
99 +static int cont_rate = 200;
100 +module_param(cont_rate, int, 0);
101 +MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
102 +
103 +/*
104 + * Pen down detection.
105 + *
106 + * This driver can either poll or use an interrupt to indicate a pen down
107 + * event. If the irq request fails then it will fall back to polling mode.
108 + */
109 +static int pen_int;
110 +module_param(pen_int, int, 0);
111 +MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
112 +
113 +/*
114 + * Pressure readback.
115 + *
116 + * Set to 1 to read back pen down pressure
117 + */
118 +static int pressure;
119 +module_param(pressure, int, 0);
120 +MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
121 +
122 +/*
123 + * AC97 touch data slot.
124 + *
125 + * Touch screen readback data ac97 slot
126 + */
127 +static int ac97_touch_slot = 5;
128 +module_param(ac97_touch_slot, int, 0);
129 +MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
130 +
131 +
132 +/* flush AC97 slot 5 FIFO on pxa machines */
133 +#ifdef CONFIG_PXA27x
134 +static void wm97xx_acc_pen_up(struct wm97xx *wm)
135 +{
136 +       set_current_state(TASK_INTERRUPTIBLE);
137 +       schedule_timeout(1);
138 +
139 +       while (MISR & (1 << 2))
140 +               MODR;
141 +}
142 +#else
143 +static void wm97xx_acc_pen_up(struct wm97xx *wm)
144 +{
145 +       int count = 16;
146 +       set_current_state(TASK_INTERRUPTIBLE);
147 +       schedule_timeout(1);
148 +
149 +       while (count < 16) {
150 +               MODR;
151 +               count--;
152 +       }
153 +}
154 +#endif
155 +
156 +static int wm97xx_acc_pen_down(struct wm97xx *wm)
157 +{
158 +       u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
159 +       int reads = 0;
160 +
161 +       /* data is never immediately available after pen down irq */
162 +       set_current_state(TASK_INTERRUPTIBLE);
163 +       schedule_timeout(1);
164 +
165 +       if (tries > 5) {
166 +               tries = 0;
167 +               return RC_PENUP;
168 +       }
169 +
170 +       x = MODR;
171 +       if (x == last) {
172 +               tries++;
173 +               return RC_AGAIN;
174 +       }
175 +       last = x;
176 +       do {
177 +               if (reads)
178 +                       x = MODR;
179 +               y = MODR;
180 +               if (pressure)
181 +                       p = MODR;
182 +
183 +               /* are samples valid */
184 +               if ((x & 0x7000) != WM97XX_ADCSEL_X ||
185 +                       (y & 0x7000) != WM97XX_ADCSEL_Y ||
186 +                       (p & 0x7000) != WM97XX_ADCSEL_PRES)
187 +                       goto up;
188 +
189 +               /* coordinate is good */
190 +               tries = 0;
191 +               input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
192 +               input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
193 +               input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
194 +               input_sync(wm->input_dev);
195 +               reads++;
196 +       } while (reads < cinfo[sp_idx].reads);
197 +up:
198 +       return RC_PENDOWN | RC_AGAIN;
199 +}
200 +
201 +static int wm97xx_acc_startup(struct wm97xx *wm)
202 +{
203 +       int idx = 0;
204 +
205 +       /* check we have a codec */
206 +       if (wm->ac97 == NULL)
207 +               return -ENODEV;
208 +
209 +       /* Go you big red fire engine */
210 +       for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
211 +               if (wm->id != cinfo[idx].id)
212 +                       continue;
213 +               sp_idx = idx;
214 +               if (cont_rate <= cinfo[idx].speed)
215 +                       break;
216 +       }
217 +       wm->acc_rate = cinfo[sp_idx].code;
218 +       wm->acc_slot = ac97_touch_slot;
219 +       dev_info(wm->dev,
220 +                "mainstone accelerated touchscreen driver, %d samples/sec\n",
221 +                cinfo[sp_idx].speed);
222 +
223 +       /* codec specific irq config */
224 +       if (pen_int) {
225 +               switch (wm->id) {
226 +               case WM9705_ID2:
227 +                       wm->pen_irq = IRQ_GPIO(4);
228 +                       set_irq_type(IRQ_GPIO(4), IRQT_BOTHEDGE);
229 +                       break;
230 +               case WM9712_ID2:
231 +               case WM9713_ID2:
232 +                       /* enable pen down interrupt */
233 +                       /* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
234 +                       wm->pen_irq = MAINSTONE_AC97_IRQ;
235 +                       wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
236 +                                          WM97XX_GPIO_POL_HIGH,
237 +                                          WM97XX_GPIO_STICKY,
238 +                                          WM97XX_GPIO_WAKE);
239 +                       wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
240 +                                          WM97XX_GPIO_POL_HIGH,
241 +                                          WM97XX_GPIO_NOTSTICKY,
242 +                                          WM97XX_GPIO_NOWAKE);
243 +                       break;
244 +               default:
245 +                       dev_err(wm->dev,
246 +                               "pen down irq not supported on this device\n");
247 +                       pen_int = 0;
248 +                       break;
249 +               }
250 +       }
251 +
252 +       return 0;
253 +}
254 +
255 +static void wm97xx_acc_shutdown(struct wm97xx *wm)
256 +{
257 +       /* codec specific deconfig */
258 +       if (pen_int) {
259 +               switch (wm->id & 0xffff) {
260 +               case WM9705_ID2:
261 +                       wm->pen_irq = 0;
262 +                       break;
263 +               case WM9712_ID2:
264 +               case WM9713_ID2:
265 +                       /* disable interrupt */
266 +                       wm->pen_irq = 0;
267 +                       break;
268 +               }
269 +       }
270 +}
271 +
272 +static void wm97xx_irq_enable(struct wm97xx *wm, int enable)
273 +{
274 +       if (enable)
275 +               enable_irq(wm->pen_irq);
276 +       else
277 +               disable_irq(wm->pen_irq);
278 +}
279 +
280 +static struct wm97xx_mach_ops mainstone_mach_ops = {
281 +       .acc_enabled = 1,
282 +       .acc_pen_up = wm97xx_acc_pen_up,
283 +       .acc_pen_down = wm97xx_acc_pen_down,
284 +       .acc_startup = wm97xx_acc_startup,
285 +       .acc_shutdown = wm97xx_acc_shutdown,
286 +       .irq_enable = wm97xx_irq_enable,
287 +};
288 +
289 +static int mainstone_wm97xx_probe(struct platform_device *pdev)
290 +{
291 +       struct wm97xx *wm = platform_get_drvdata(pdev);
292 +       return wm97xx_register_mach_ops(wm, &mainstone_mach_ops);
293 +}
294 +
295 +static int mainstone_wm97xx_remove(struct platform_device *pdev)
296 +{
297 +       struct wm97xx *wm = platform_get_drvdata(pdev);
298 +       wm97xx_unregister_mach_ops(wm);
299 +       return 0;
300 +}
301 +
302 +static struct platform_driver mainstone_wm97xx_driver = {
303 +       .probe = mainstone_wm97xx_probe,
304 +       .remove = mainstone_wm97xx_remove,
305 +       .driver = {
306 +               .name = "wm97xx-touch",
307 +       },
308 +};
309 +
310 +static int __init mainstone_wm97xx_init(void)
311 +{
312 +       return platform_driver_register(&mainstone_wm97xx_driver);
313 +}
314 +
315 +static void __exit mainstone_wm97xx_exit(void)
316 +{
317 +       platform_driver_unregister(&mainstone_wm97xx_driver);
318 +}
319 +
320 +module_init(mainstone_wm97xx_init);
321 +module_exit(mainstone_wm97xx_exit);
322 +
323 +/* Module information */
324 +MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
325 +MODULE_DESCRIPTION("wm97xx continuous touch driver for mainstone");
326 +MODULE_LICENSE("GPL");
327 -- 
328 1.5.3.8
329