0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/moduleparam.h>
0014 #include <linux/kernel.h>
0015 #include <linux/input.h>
0016 #include <linux/delay.h>
0017 #include <linux/bitops.h>
0018 #include <linux/wm97xx.h>
0019
0020 #define TS_NAME "wm97xx"
0021 #define WM9713_VERSION "1.00"
0022 #define DEFAULT_PRESSURE 0xb0c0
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 static int rpu = 8;
0038 module_param(rpu, int, 0);
0039 MODULE_PARM_DESC(rpu, "Set internal pull up resistor for pen detect.");
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 static int pil;
0052 module_param(pil, int, 0);
0053 MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
0054
0055
0056
0057
0058
0059
0060 static int pressure = DEFAULT_PRESSURE & 0xfff;
0061 module_param(pressure, int, 0);
0062 MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076 static int delay = 4;
0077 module_param(delay, int, 0);
0078 MODULE_PARM_DESC(delay, "Set adc sample delay.");
0079
0080
0081
0082
0083
0084
0085 static int five_wire;
0086 module_param(five_wire, int, 0);
0087 MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102 static int mask;
0103 module_param(mask, int, 0);
0104 MODULE_PARM_DESC(mask, "Set adc mask function.");
0105
0106
0107
0108
0109
0110
0111
0112 static int coord;
0113 module_param(coord, int, 0);
0114 MODULE_PARM_DESC(coord, "Polling coordinate mode");
0115
0116
0117
0118
0119 static const int delay_table[] = {
0120 21,
0121 42,
0122 84,
0123 167,
0124 333,
0125 667,
0126 1000,
0127 1333,
0128 2000,
0129 2667,
0130 3333,
0131 4000,
0132 4667,
0133 5333,
0134 6000,
0135 0
0136 };
0137
0138
0139
0140
0141
0142
0143 static inline void poll_delay(int d)
0144 {
0145 udelay(3 * AC97_LINK_FRAME + delay_table[d]);
0146 }
0147
0148
0149
0150
0151 static void wm9713_phy_init(struct wm97xx *wm)
0152 {
0153 u16 dig1 = 0, dig2, dig3;
0154
0155
0156 dig2 = WM97XX_DELAY(4) | WM97XX_SLT(5);
0157 dig3 = WM9712_RPU(1);
0158
0159
0160 if (rpu) {
0161 dig3 &= 0xffc0;
0162 dig3 |= WM9712_RPU(rpu);
0163 dev_info(wm->dev, "setting pen detect pull-up to %d Ohms\n",
0164 64000 / rpu);
0165 }
0166
0167
0168 if (five_wire) {
0169 dig3 |= WM9713_45W;
0170 dev_info(wm->dev, "setting 5-wire touchscreen mode.");
0171
0172 if (pil) {
0173 dev_warn(wm->dev,
0174 "Pressure measurement not supported in 5 "
0175 "wire mode, disabling\n");
0176 pil = 0;
0177 }
0178 }
0179
0180
0181 if (pil == 2) {
0182 dig3 |= WM9712_PIL;
0183 dev_info(wm->dev,
0184 "setting pressure measurement current to 400uA.");
0185 } else if (pil)
0186 dev_info(wm->dev,
0187 "setting pressure measurement current to 200uA.");
0188 if (!pil)
0189 pressure = 0;
0190
0191
0192 if (delay < 0 || delay > 15) {
0193 dev_info(wm->dev, "supplied delay out of range.");
0194 delay = 4;
0195 dev_info(wm->dev, "setting adc sample delay to %d u Secs.",
0196 delay_table[delay]);
0197 }
0198 dig2 &= 0xff0f;
0199 dig2 |= WM97XX_DELAY(delay);
0200
0201
0202 dig3 |= ((mask & 0x3) << 4);
0203 if (coord)
0204 dig3 |= WM9713_WAIT;
0205
0206 wm->misc = wm97xx_reg_read(wm, 0x5a);
0207
0208 wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
0209 wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
0210 wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
0211 wm97xx_reg_write(wm, AC97_GPIO_STICKY, 0x0);
0212 }
0213
0214 static void wm9713_dig_enable(struct wm97xx *wm, int enable)
0215 {
0216 u16 val;
0217
0218 if (enable) {
0219 val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
0220 wm97xx_reg_write(wm, AC97_EXTENDED_MID, val & 0x7fff);
0221 wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] |
0222 WM97XX_PRP_DET_DIG);
0223 wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
0224 } else {
0225 wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] &
0226 ~WM97XX_PRP_DET_DIG);
0227 val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
0228 wm97xx_reg_write(wm, AC97_EXTENDED_MID, val | 0x8000);
0229 }
0230 }
0231
0232 static void wm9713_dig_restore(struct wm97xx *wm)
0233 {
0234 wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig_save[0]);
0235 wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig_save[1]);
0236 wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig_save[2]);
0237 }
0238
0239 static void wm9713_aux_prepare(struct wm97xx *wm)
0240 {
0241 memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
0242 wm97xx_reg_write(wm, AC97_WM9713_DIG1, 0);
0243 wm97xx_reg_write(wm, AC97_WM9713_DIG2, 0);
0244 wm97xx_reg_write(wm, AC97_WM9713_DIG3, WM97XX_PRP_DET_DIG);
0245 }
0246
0247 static inline int is_pden(struct wm97xx *wm)
0248 {
0249 return wm->dig[2] & WM9713_PDEN;
0250 }
0251
0252
0253
0254
0255 static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
0256 {
0257 u16 dig1;
0258 int timeout = 5 * delay;
0259 bool wants_pen = adcsel & WM97XX_PEN_DOWN;
0260
0261 if (wants_pen && !wm->pen_probably_down) {
0262 u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
0263 if (!(data & WM97XX_PEN_DOWN))
0264 return RC_PENUP;
0265 wm->pen_probably_down = 1;
0266 }
0267
0268
0269 dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
0270 dig1 &= ~WM9713_ADCSEL_MASK;
0271
0272 dig1 |= 1 << ((adcsel & WM97XX_ADCSEL_MASK) >> 12);
0273
0274 if (wm->mach_ops && wm->mach_ops->pre_sample)
0275 wm->mach_ops->pre_sample(adcsel);
0276 wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | WM9713_POLL);
0277
0278
0279 poll_delay(delay);
0280
0281
0282 while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) &&
0283 timeout) {
0284 udelay(AC97_LINK_FRAME);
0285 timeout--;
0286 }
0287
0288 if (timeout <= 0) {
0289
0290 if (is_pden(wm))
0291 wm->pen_probably_down = 0;
0292 else
0293 dev_dbg(wm->dev, "adc sample timeout");
0294 return RC_PENUP;
0295 }
0296
0297 *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
0298 if (wm->mach_ops && wm->mach_ops->post_sample)
0299 wm->mach_ops->post_sample(adcsel);
0300
0301
0302 if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) {
0303 dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x",
0304 adcsel & WM97XX_ADCSEL_MASK,
0305 *sample & WM97XX_ADCSEL_MASK);
0306 return RC_PENUP;
0307 }
0308
0309 if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
0310 wm->pen_probably_down = 0;
0311 return RC_PENUP;
0312 }
0313
0314 return RC_VALID;
0315 }
0316
0317
0318
0319
0320 static int wm9713_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
0321 {
0322 u16 dig1;
0323 int timeout = 5 * delay;
0324
0325 if (!wm->pen_probably_down) {
0326 u16 val = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
0327 if (!(val & WM97XX_PEN_DOWN))
0328 return RC_PENUP;
0329 wm->pen_probably_down = 1;
0330 }
0331
0332
0333 dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
0334 dig1 &= ~WM9713_ADCSEL_MASK;
0335 if (pil)
0336 dig1 |= WM9713_ADCSEL_PRES;
0337
0338 if (wm->mach_ops && wm->mach_ops->pre_sample)
0339 wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
0340 wm97xx_reg_write(wm, AC97_WM9713_DIG1,
0341 dig1 | WM9713_POLL | WM9713_COO);
0342
0343
0344 poll_delay(delay);
0345 data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
0346
0347 while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL)
0348 && timeout) {
0349 udelay(AC97_LINK_FRAME);
0350 timeout--;
0351 }
0352
0353 if (timeout <= 0) {
0354
0355 if (is_pden(wm))
0356 wm->pen_probably_down = 0;
0357 else
0358 dev_dbg(wm->dev, "adc sample timeout");
0359 return RC_PENUP;
0360 }
0361
0362
0363 data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
0364 if (pil)
0365 data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
0366 else
0367 data->p = DEFAULT_PRESSURE;
0368
0369 if (wm->mach_ops && wm->mach_ops->post_sample)
0370 wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
0371
0372
0373 if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
0374 goto err;
0375 if (pil && !(data->p & WM97XX_ADCSEL_PRES))
0376 goto err;
0377
0378 if (!(data->x & WM97XX_PEN_DOWN) || !(data->y & WM97XX_PEN_DOWN)) {
0379 wm->pen_probably_down = 0;
0380 return RC_PENUP;
0381 }
0382 return RC_VALID;
0383 err:
0384 return 0;
0385 }
0386
0387
0388
0389
0390 static int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
0391 {
0392 int rc;
0393
0394 if (coord) {
0395 rc = wm9713_poll_coord(wm, data);
0396 if (rc != RC_VALID)
0397 return rc;
0398 } else {
0399 rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
0400 if (rc != RC_VALID)
0401 return rc;
0402 rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
0403 if (rc != RC_VALID)
0404 return rc;
0405 if (pil) {
0406 rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN,
0407 &data->p);
0408 if (rc != RC_VALID)
0409 return rc;
0410 } else
0411 data->p = DEFAULT_PRESSURE;
0412 }
0413 return RC_VALID;
0414 }
0415
0416
0417
0418
0419
0420 static int wm9713_acc_enable(struct wm97xx *wm, int enable)
0421 {
0422 u16 dig1, dig2, dig3;
0423 int ret = 0;
0424
0425 dig1 = wm->dig[0];
0426 dig2 = wm->dig[1];
0427 dig3 = wm->dig[2];
0428
0429 if (enable) {
0430
0431 if (wm->mach_ops->acc_startup &&
0432 (ret = wm->mach_ops->acc_startup(wm)) < 0)
0433 return ret;
0434
0435 dig1 &= ~WM9713_ADCSEL_MASK;
0436 dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X |
0437 WM9713_ADCSEL_Y;
0438 if (pil)
0439 dig1 |= WM9713_ADCSEL_PRES;
0440 dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK |
0441 WM97XX_CM_RATE_MASK);
0442 dig2 |= WM97XX_SLEN | WM97XX_DELAY(delay) |
0443 WM97XX_SLT(wm->acc_slot) | WM97XX_RATE(wm->acc_rate);
0444 dig3 |= WM9713_PDEN;
0445 } else {
0446 dig1 &= ~(WM9713_CTC | WM9713_COO);
0447 dig2 &= ~WM97XX_SLEN;
0448 dig3 &= ~WM9713_PDEN;
0449 if (wm->mach_ops->acc_shutdown)
0450 wm->mach_ops->acc_shutdown(wm);
0451 }
0452
0453 wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
0454 wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
0455 wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
0456
0457 return ret;
0458 }
0459
0460 struct wm97xx_codec_drv wm9713_codec = {
0461 .id = WM9713_ID2,
0462 .name = "wm9713",
0463 .poll_sample = wm9713_poll_sample,
0464 .poll_touch = wm9713_poll_touch,
0465 .acc_enable = wm9713_acc_enable,
0466 .phy_init = wm9713_phy_init,
0467 .dig_enable = wm9713_dig_enable,
0468 .dig_restore = wm9713_dig_restore,
0469 .aux_prepare = wm9713_aux_prepare,
0470 };
0471 EXPORT_SYMBOL_GPL(wm9713_codec);
0472
0473
0474 MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
0475 MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
0476 MODULE_LICENSE("GPL");