0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <linux/module.h>
0021 #include <linux/moduleparam.h>
0022 #include <linux/kernel.h>
0023 #include <linux/delay.h>
0024 #include <linux/gpio/consumer.h>
0025 #include <linux/irq.h>
0026 #include <linux/interrupt.h>
0027 #include <linux/io.h>
0028 #include <linux/soc/pxa/cpu.h>
0029 #include <linux/wm97xx.h>
0030
0031 #include <sound/pxa2xx-lib.h>
0032
0033 #include <asm/mach-types.h>
0034
0035 struct continuous {
0036 u16 id;
0037 u8 code;
0038 u8 reads;
0039 u32 speed;
0040 };
0041
0042 #define WM_READS(sp) ((sp / HZ) + 1)
0043
0044 static const struct continuous cinfo[] = {
0045 { WM9705_ID2, 0, WM_READS(94), 94 },
0046 { WM9705_ID2, 1, WM_READS(188), 188 },
0047 { WM9705_ID2, 2, WM_READS(375), 375 },
0048 { WM9705_ID2, 3, WM_READS(750), 750 },
0049 { WM9712_ID2, 0, WM_READS(94), 94 },
0050 { WM9712_ID2, 1, WM_READS(188), 188 },
0051 { WM9712_ID2, 2, WM_READS(375), 375 },
0052 { WM9712_ID2, 3, WM_READS(750), 750 },
0053 { WM9713_ID2, 0, WM_READS(94), 94 },
0054 { WM9713_ID2, 1, WM_READS(120), 120 },
0055 { WM9713_ID2, 2, WM_READS(154), 154 },
0056 { WM9713_ID2, 3, WM_READS(188), 188 },
0057 };
0058
0059
0060 static int sp_idx;
0061 static struct gpio_desc *gpiod_irq;
0062
0063
0064
0065
0066 static int cont_rate = 200;
0067 module_param(cont_rate, int, 0);
0068 MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
0069
0070
0071
0072
0073
0074
0075
0076 static int pen_int;
0077 module_param(pen_int, int, 0);
0078 MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
0079
0080
0081
0082
0083
0084
0085 static int pressure;
0086 module_param(pressure, int, 0);
0087 MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
0088
0089
0090
0091
0092
0093
0094 static int ac97_touch_slot = 5;
0095 module_param(ac97_touch_slot, int, 0);
0096 MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
0097
0098
0099
0100 static void wm97xx_acc_pen_up(struct wm97xx *wm)
0101 {
0102 unsigned int count;
0103
0104 msleep(1);
0105
0106 if (cpu_is_pxa27x()) {
0107 while (pxa2xx_ac97_read_misr() & (1 << 2))
0108 pxa2xx_ac97_read_modr();
0109 } else if (cpu_is_pxa3xx()) {
0110 for (count = 0; count < 16; count++)
0111 pxa2xx_ac97_read_modr();
0112 }
0113 }
0114
0115 static int wm97xx_acc_pen_down(struct wm97xx *wm)
0116 {
0117 u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
0118 int reads = 0;
0119 static u16 last, tries;
0120
0121
0122
0123
0124
0125
0126 msleep(1);
0127
0128 if (tries > 5) {
0129 tries = 0;
0130 return RC_PENUP;
0131 }
0132
0133 x = pxa2xx_ac97_read_modr();
0134 if (x == last) {
0135 tries++;
0136 return RC_AGAIN;
0137 }
0138 last = x;
0139 do {
0140 if (reads)
0141 x = pxa2xx_ac97_read_modr();
0142 y = pxa2xx_ac97_read_modr();
0143 if (pressure)
0144 p = pxa2xx_ac97_read_modr();
0145
0146 dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
0147 x, y, p);
0148
0149
0150 if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
0151 (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
0152 (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
0153 goto up;
0154
0155
0156 tries = 0;
0157 input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
0158 input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
0159 input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
0160 input_report_key(wm->input_dev, BTN_TOUCH, (p != 0));
0161 input_sync(wm->input_dev);
0162 reads++;
0163 } while (reads < cinfo[sp_idx].reads);
0164 up:
0165 return RC_PENDOWN | RC_AGAIN;
0166 }
0167
0168 static int wm97xx_acc_startup(struct wm97xx *wm)
0169 {
0170 int idx = 0, ret = 0;
0171
0172
0173 if (wm->ac97 == NULL)
0174 return -ENODEV;
0175
0176
0177 for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
0178 if (wm->id != cinfo[idx].id)
0179 continue;
0180 sp_idx = idx;
0181 if (cont_rate <= cinfo[idx].speed)
0182 break;
0183 }
0184 wm->acc_rate = cinfo[sp_idx].code;
0185 wm->acc_slot = ac97_touch_slot;
0186 dev_info(wm->dev,
0187 "mainstone accelerated touchscreen driver, %d samples/sec\n",
0188 cinfo[sp_idx].speed);
0189
0190
0191 if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) {
0192 pen_int = 1;
0193
0194
0195 wm->variant = WM97xx_WM1613;
0196 } else if (machine_is_zylonite()) {
0197 pen_int = 1;
0198 }
0199
0200 if (pen_int) {
0201 gpiod_irq = gpiod_get(wm->dev, "touch", GPIOD_IN);
0202 if (IS_ERR(gpiod_irq))
0203 pen_int = 0;
0204 }
0205
0206 if (pen_int) {
0207 wm->pen_irq = gpiod_to_irq(gpiod_irq);
0208 irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
0209 }
0210
0211
0212 if (pen_int) {
0213 switch (wm->id) {
0214 case WM9705_ID2:
0215 break;
0216 case WM9712_ID2:
0217 case WM9713_ID2:
0218
0219 wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
0220 WM97XX_GPIO_POL_HIGH,
0221 WM97XX_GPIO_STICKY,
0222 WM97XX_GPIO_WAKE);
0223 wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
0224 WM97XX_GPIO_POL_HIGH,
0225 WM97XX_GPIO_NOTSTICKY,
0226 WM97XX_GPIO_NOWAKE);
0227 break;
0228 default:
0229 dev_err(wm->dev,
0230 "pen down irq not supported on this device\n");
0231 pen_int = 0;
0232 break;
0233 }
0234 }
0235
0236 return ret;
0237 }
0238
0239 static void wm97xx_acc_shutdown(struct wm97xx *wm)
0240 {
0241
0242 if (pen_int) {
0243 if (gpiod_irq)
0244 gpiod_put(gpiod_irq);
0245 wm->pen_irq = 0;
0246 }
0247 }
0248
0249 static struct wm97xx_mach_ops mainstone_mach_ops = {
0250 .acc_enabled = 1,
0251 .acc_pen_up = wm97xx_acc_pen_up,
0252 .acc_pen_down = wm97xx_acc_pen_down,
0253 .acc_startup = wm97xx_acc_startup,
0254 .acc_shutdown = wm97xx_acc_shutdown,
0255 .irq_gpio = WM97XX_GPIO_2,
0256 };
0257
0258 static int mainstone_wm97xx_probe(struct platform_device *pdev)
0259 {
0260 struct wm97xx *wm = platform_get_drvdata(pdev);
0261
0262 return wm97xx_register_mach_ops(wm, &mainstone_mach_ops);
0263 }
0264
0265 static int mainstone_wm97xx_remove(struct platform_device *pdev)
0266 {
0267 struct wm97xx *wm = platform_get_drvdata(pdev);
0268
0269 wm97xx_unregister_mach_ops(wm);
0270
0271 return 0;
0272 }
0273
0274 static struct platform_driver mainstone_wm97xx_driver = {
0275 .probe = mainstone_wm97xx_probe,
0276 .remove = mainstone_wm97xx_remove,
0277 .driver = {
0278 .name = "wm97xx-touch",
0279 },
0280 };
0281 module_platform_driver(mainstone_wm97xx_driver);
0282
0283
0284 MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
0285 MODULE_DESCRIPTION("wm97xx continuous touch driver for mainstone");
0286 MODULE_LICENSE("GPL");