• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * zylonite-wm97xx.c  --  Zylonite Continuous Touch screen driver
3  *
4  * Copyright 2004, 2007, 2008 Wolfson Microelectronics PLC.
5  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
6  * Parts Copyright : Ian Molton <spyro@f2s.com>
7  *                   Andrew Zabolotny <zap@homelink.ru>
8  *
9  *  This program is free software; you can redistribute  it and/or modify it
10  *  under  the terms of  the GNU General  Public License as published by the
11  *  Free Software Foundation;  either version 2 of the  License, or (at your
12  *  option) any later version.
13  *
14  * Notes:
15  *     This is a wm97xx extended touch driver supporting interrupt driven
16  *     and continuous operation on Marvell Zylonite development systems
17  *     (which have a WM9713 on board).
18  */
19 
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/kernel.h>
23 #include <linux/delay.h>
24 #include <linux/gpio.h>
25 #include <linux/irq.h>
26 #include <linux/interrupt.h>
27 #include <linux/io.h>
28 #include <linux/wm97xx.h>
29 
30 #include <mach/hardware.h>
31 #include <mach/mfp.h>
32 #include <mach/regs-ac97.h>
33 
34 struct continuous {
35 	u16 id;    /* codec id */
36 	u8 code;   /* continuous code */
37 	u8 reads;  /* number of coord reads per read cycle */
38 	u32 speed; /* number of coords per second */
39 };
40 
41 #define WM_READS(sp) ((sp / HZ) + 1)
42 
43 static const struct continuous cinfo[] = {
44 	{ WM9713_ID2, 0, WM_READS(94),  94  },
45 	{ WM9713_ID2, 1, WM_READS(120), 120 },
46 	{ WM9713_ID2, 2, WM_READS(154), 154 },
47 	{ WM9713_ID2, 3, WM_READS(188), 188 },
48 };
49 
50 /* continuous speed index */
51 static int sp_idx;
52 
53 /*
54  * Pen sampling frequency (Hz) in continuous mode.
55  */
56 static int cont_rate = 200;
57 module_param(cont_rate, int, 0);
58 MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
59 
60 /*
61  * Pressure readback.
62  *
63  * Set to 1 to read back pen down pressure
64  */
65 static int pressure;
66 module_param(pressure, int, 0);
67 MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
68 
69 /*
70  * AC97 touch data slot.
71  *
72  * Touch screen readback data ac97 slot
73  */
74 static int ac97_touch_slot = 5;
75 module_param(ac97_touch_slot, int, 0);
76 MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
77 
78 
79 /* flush AC97 slot 5 FIFO machines */
wm97xx_acc_pen_up(struct wm97xx * wm)80 static void wm97xx_acc_pen_up(struct wm97xx *wm)
81 {
82 	int i;
83 
84 	msleep(1);
85 
86 	for (i = 0; i < 16; i++)
87 		MODR;
88 }
89 
wm97xx_acc_pen_down(struct wm97xx * wm)90 static int wm97xx_acc_pen_down(struct wm97xx *wm)
91 {
92 	u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
93 	int reads = 0;
94 	static u16 last, tries;
95 
96 	/* When the AC97 queue has been drained we need to allow time
97 	 * to buffer up samples otherwise we end up spinning polling
98 	 * for samples.  The controller can't have a suitably low
99 	 * threshold set to use the notifications it gives.
100 	 */
101 	msleep(1);
102 
103 	if (tries > 5) {
104 		tries = 0;
105 		return RC_PENUP;
106 	}
107 
108 	x = MODR;
109 	if (x == last) {
110 		tries++;
111 		return RC_AGAIN;
112 	}
113 	last = x;
114 	do {
115 		if (reads)
116 			x = MODR;
117 		y = MODR;
118 		if (pressure)
119 			p = MODR;
120 
121 		dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
122 			x, y, p);
123 
124 		/* are samples valid */
125 		if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
126 		    (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
127 		    (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
128 			goto up;
129 
130 		/* coordinate is good */
131 		tries = 0;
132 		input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
133 		input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
134 		input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
135 		input_report_key(wm->input_dev, BTN_TOUCH, (p != 0));
136 		input_sync(wm->input_dev);
137 		reads++;
138 	} while (reads < cinfo[sp_idx].reads);
139 up:
140 	return RC_PENDOWN | RC_AGAIN;
141 }
142 
wm97xx_acc_startup(struct wm97xx * wm)143 static int wm97xx_acc_startup(struct wm97xx *wm)
144 {
145 	int idx;
146 
147 	/* check we have a codec */
148 	if (wm->ac97 == NULL)
149 		return -ENODEV;
150 
151 	/* Go you big red fire engine */
152 	for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
153 		if (wm->id != cinfo[idx].id)
154 			continue;
155 		sp_idx = idx;
156 		if (cont_rate <= cinfo[idx].speed)
157 			break;
158 	}
159 	wm->acc_rate = cinfo[sp_idx].code;
160 	wm->acc_slot = ac97_touch_slot;
161 	dev_info(wm->dev,
162 		 "zylonite accelerated touchscreen driver, %d samples/sec\n",
163 		 cinfo[sp_idx].speed);
164 
165 	return 0;
166 }
167 
wm97xx_irq_enable(struct wm97xx * wm,int enable)168 static void wm97xx_irq_enable(struct wm97xx *wm, int enable)
169 {
170 	if (enable)
171 		enable_irq(wm->pen_irq);
172 	else
173 		disable_irq_nosync(wm->pen_irq);
174 }
175 
176 static struct wm97xx_mach_ops zylonite_mach_ops = {
177 	.acc_enabled	= 1,
178 	.acc_pen_up	= wm97xx_acc_pen_up,
179 	.acc_pen_down	= wm97xx_acc_pen_down,
180 	.acc_startup	= wm97xx_acc_startup,
181 	.irq_enable	= wm97xx_irq_enable,
182 	.irq_gpio	= WM97XX_GPIO_2,
183 };
184 
zylonite_wm97xx_probe(struct platform_device * pdev)185 static int zylonite_wm97xx_probe(struct platform_device *pdev)
186 {
187 	struct wm97xx *wm = platform_get_drvdata(pdev);
188 	int gpio_touch_irq;
189 
190 	if (cpu_is_pxa320())
191 		gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO15);
192 	else
193 		gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26);
194 
195 	wm->pen_irq = gpio_to_irq(gpio_touch_irq);
196 	irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
197 
198 	wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
199 			   WM97XX_GPIO_POL_HIGH,
200 			   WM97XX_GPIO_STICKY,
201 			   WM97XX_GPIO_WAKE);
202 	wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
203 			   WM97XX_GPIO_POL_HIGH,
204 			   WM97XX_GPIO_NOTSTICKY,
205 			   WM97XX_GPIO_NOWAKE);
206 
207 	return wm97xx_register_mach_ops(wm, &zylonite_mach_ops);
208 }
209 
zylonite_wm97xx_remove(struct platform_device * pdev)210 static int zylonite_wm97xx_remove(struct platform_device *pdev)
211 {
212 	struct wm97xx *wm = platform_get_drvdata(pdev);
213 
214 	wm97xx_unregister_mach_ops(wm);
215 
216 	return 0;
217 }
218 
219 static struct platform_driver zylonite_wm97xx_driver = {
220 	.probe	= zylonite_wm97xx_probe,
221 	.remove	= zylonite_wm97xx_remove,
222 	.driver	= {
223 		.name	= "wm97xx-touch",
224 	},
225 };
226 module_platform_driver(zylonite_wm97xx_driver);
227 
228 /* Module information */
229 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
230 MODULE_DESCRIPTION("wm97xx continuous touch driver for Zylonite");
231 MODULE_LICENSE("GPL");
232