1 /* 2 * Touchscreen driver for Dialog Semiconductor DA9034 3 * 4 * Copyright (C) 2006-2008 Marvell International Ltd. 5 * Fengwei Yin <fengwei.yin@marvell.com> 6 * Eric Miao <eric.miao@marvell.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/module.h> 14 #include <linux/kernel.h> 15 #include <linux/init.h> 16 #include <linux/delay.h> 17 #include <linux/platform_device.h> 18 #include <linux/input.h> 19 #include <linux/workqueue.h> 20 #include <linux/mfd/da903x.h> 21 22 #define DA9034_MANUAL_CTRL 0x50 23 #define DA9034_LDO_ADC_EN (1 << 4) 24 25 #define DA9034_AUTO_CTRL1 0x51 26 27 #define DA9034_AUTO_CTRL2 0x52 28 #define DA9034_AUTO_TSI_EN (1 << 3) 29 #define DA9034_PEN_DETECT (1 << 4) 30 31 #define DA9034_TSI_CTRL1 0x53 32 #define DA9034_TSI_CTRL2 0x54 33 #define DA9034_TSI_X_MSB 0x6c 34 #define DA9034_TSI_Y_MSB 0x6d 35 #define DA9034_TSI_XY_LSB 0x6e 36 37 enum { 38 STATE_IDLE, /* wait for pendown */ 39 STATE_BUSY, /* TSI busy sampling */ 40 STATE_STOP, /* sample available */ 41 STATE_WAIT, /* Wait to start next sample */ 42 }; 43 44 enum { 45 EVENT_PEN_DOWN, 46 EVENT_PEN_UP, 47 EVENT_TSI_READY, 48 EVENT_TIMEDOUT, 49 }; 50 51 struct da9034_touch { 52 struct device *da9034_dev; 53 struct input_dev *input_dev; 54 55 struct delayed_work tsi_work; 56 struct notifier_block notifier; 57 58 int state; 59 60 int interval_ms; 61 int x_inverted; 62 int y_inverted; 63 64 int last_x; 65 int last_y; 66 }; 67 68 static inline int is_pen_down(struct da9034_touch *touch) 69 { 70 return da903x_query_status(touch->da9034_dev, DA9034_STATUS_PEN_DOWN); 71 } 72 73 static inline int detect_pen_down(struct da9034_touch *touch, int on) 74 { 75 if (on) 76 return da903x_set_bits(touch->da9034_dev, 77 DA9034_AUTO_CTRL2, DA9034_PEN_DETECT); 78 else 79 return da903x_clr_bits(touch->da9034_dev, 80 DA9034_AUTO_CTRL2, DA9034_PEN_DETECT); 81 } 82 83 static int read_tsi(struct da9034_touch *touch) 84 { 85 uint8_t _x, _y, _v; 86 int ret; 87 88 ret = da903x_read(touch->da9034_dev, DA9034_TSI_X_MSB, &_x); 89 if (ret) 90 return ret; 91 92 ret = da903x_read(touch->da9034_dev, DA9034_TSI_Y_MSB, &_y); 93 if (ret) 94 return ret; 95 96 ret = da903x_read(touch->da9034_dev, DA9034_TSI_XY_LSB, &_v); 97 if (ret) 98 return ret; 99 100 touch->last_x = ((_x << 2) & 0x3fc) | (_v & 0x3); 101 touch->last_y = ((_y << 2) & 0x3fc) | ((_v & 0xc) >> 2); 102 103 return 0; 104 } 105 106 static inline int start_tsi(struct da9034_touch *touch) 107 { 108 return da903x_set_bits(touch->da9034_dev, 109 DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN); 110 } 111 112 static inline int stop_tsi(struct da9034_touch *touch) 113 { 114 return da903x_clr_bits(touch->da9034_dev, 115 DA9034_AUTO_CTRL2, DA9034_AUTO_TSI_EN); 116 } 117 118 static inline void report_pen_down(struct da9034_touch *touch) 119 { 120 int x = touch->last_x; 121 int y = touch->last_y; 122 123 x &= 0xfff; 124 if (touch->x_inverted) 125 x = 1024 - x; 126 y &= 0xfff; 127 if (touch->y_inverted) 128 y = 1024 - y; 129 130 input_report_abs(touch->input_dev, ABS_X, x); 131 input_report_abs(touch->input_dev, ABS_Y, y); 132 input_report_key(touch->input_dev, BTN_TOUCH, 1); 133 134 input_sync(touch->input_dev); 135 } 136 137 static inline void report_pen_up(struct da9034_touch *touch) 138 { 139 input_report_key(touch->input_dev, BTN_TOUCH, 0); 140 input_sync(touch->input_dev); 141 } 142 143 static void da9034_event_handler(struct da9034_touch *touch, int event) 144 { 145 int err; 146 147 switch (touch->state) { 148 case STATE_IDLE: 149 if (event != EVENT_PEN_DOWN) 150 break; 151 152 /* Enable auto measurement of the TSI, this will 153 * automatically disable pen down detection 154 */ 155 err = start_tsi(touch); 156 if (err) 157 goto err_reset; 158 159 touch->state = STATE_BUSY; 160 break; 161 162 case STATE_BUSY: 163 if (event != EVENT_TSI_READY) 164 break; 165 166 err = read_tsi(touch); 167 if (err) 168 goto err_reset; 169 170 /* Disable auto measurement of the TSI, so that 171 * pen down status will be available 172 */ 173 err = stop_tsi(touch); 174 if (err) 175 goto err_reset; 176 177 touch->state = STATE_STOP; 178 break; 179 180 case STATE_STOP: 181 if (event == EVENT_PEN_DOWN) { 182 report_pen_down(touch); 183 schedule_delayed_work(&touch->tsi_work, 184 msecs_to_jiffies(touch->interval_ms)); 185 touch->state = STATE_WAIT; 186 } 187 188 if (event == EVENT_PEN_UP) { 189 report_pen_up(touch); 190 touch->state = STATE_IDLE; 191 } 192 193 input_sync(touch->input_dev); 194 break; 195 196 case STATE_WAIT: 197 if (event != EVENT_TIMEDOUT) 198 break; 199 200 if (is_pen_down(touch)) { 201 start_tsi(touch); 202 touch->state = STATE_BUSY; 203 } else 204 touch->state = STATE_IDLE; 205 break; 206 } 207 return; 208 209 err_reset: 210 touch->state = STATE_IDLE; 211 stop_tsi(touch); 212 detect_pen_down(touch, 1); 213 } 214 215 static void da9034_tsi_work(struct work_struct *work) 216 { 217 struct da9034_touch *touch = 218 container_of(work, struct da9034_touch, tsi_work.work); 219 220 da9034_event_handler(touch, EVENT_TIMEDOUT); 221 } 222 223 static int da9034_touch_notifier(struct notifier_block *nb, 224 unsigned long event, void *data) 225 { 226 struct da9034_touch *touch = 227 container_of(nb, struct da9034_touch, notifier); 228 229 if (event & DA9034_EVENT_PEN_DOWN) { 230 if (is_pen_down(touch)) 231 da9034_event_handler(touch, EVENT_PEN_DOWN); 232 else 233 da9034_event_handler(touch, EVENT_PEN_UP); 234 } 235 236 if (event & DA9034_EVENT_TSI_READY) 237 da9034_event_handler(touch, EVENT_TSI_READY); 238 239 return 0; 240 } 241 242 static int da9034_touch_open(struct input_dev *dev) 243 { 244 struct da9034_touch *touch = input_get_drvdata(dev); 245 int ret; 246 247 ret = da903x_register_notifier(touch->da9034_dev, &touch->notifier, 248 DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY); 249 if (ret) 250 return -EBUSY; 251 252 /* Enable ADC LDO */ 253 ret = da903x_set_bits(touch->da9034_dev, 254 DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN); 255 if (ret) 256 return ret; 257 258 /* TSI_DELAY: 3 slots, TSI_SKIP: 3 slots */ 259 ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL1, 0x1b); 260 if (ret) 261 return ret; 262 263 ret = da903x_write(touch->da9034_dev, DA9034_TSI_CTRL2, 0x00); 264 if (ret) 265 return ret; 266 267 touch->state = STATE_IDLE; 268 detect_pen_down(touch, 1); 269 270 return 0; 271 } 272 273 static void da9034_touch_close(struct input_dev *dev) 274 { 275 struct da9034_touch *touch = input_get_drvdata(dev); 276 277 da903x_unregister_notifier(touch->da9034_dev, &touch->notifier, 278 DA9034_EVENT_PEN_DOWN | DA9034_EVENT_TSI_READY); 279 280 cancel_delayed_work_sync(&touch->tsi_work); 281 282 touch->state = STATE_IDLE; 283 stop_tsi(touch); 284 detect_pen_down(touch, 0); 285 286 /* Disable ADC LDO */ 287 da903x_clr_bits(touch->da9034_dev, 288 DA9034_MANUAL_CTRL, DA9034_LDO_ADC_EN); 289 } 290 291 292 static int __devinit da9034_touch_probe(struct platform_device *pdev) 293 { 294 struct da9034_touch_pdata *pdata = pdev->dev.platform_data; 295 struct da9034_touch *touch; 296 struct input_dev *input_dev; 297 int ret; 298 299 touch = kzalloc(sizeof(struct da9034_touch), GFP_KERNEL); 300 if (touch == NULL) { 301 dev_err(&pdev->dev, "failed to allocate driver data\n"); 302 return -ENOMEM; 303 } 304 305 touch->da9034_dev = pdev->dev.parent; 306 307 if (pdata) { 308 touch->interval_ms = pdata->interval_ms; 309 touch->x_inverted = pdata->x_inverted; 310 touch->y_inverted = pdata->y_inverted; 311 } else 312 /* fallback into default */ 313 touch->interval_ms = 10; 314 315 INIT_DELAYED_WORK(&touch->tsi_work, da9034_tsi_work); 316 touch->notifier.notifier_call = da9034_touch_notifier; 317 318 input_dev = input_allocate_device(); 319 if (!input_dev) { 320 dev_err(&pdev->dev, "failed to allocate input device\n"); 321 ret = -ENOMEM; 322 goto err_free_touch; 323 } 324 325 input_dev->name = pdev->name; 326 input_dev->open = da9034_touch_open; 327 input_dev->close = da9034_touch_close; 328 input_dev->dev.parent = &pdev->dev; 329 330 __set_bit(EV_ABS, input_dev->evbit); 331 __set_bit(ABS_X, input_dev->absbit); 332 __set_bit(ABS_Y, input_dev->absbit); 333 input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0); 334 input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0); 335 336 __set_bit(EV_KEY, input_dev->evbit); 337 __set_bit(BTN_TOUCH, input_dev->keybit); 338 339 touch->input_dev = input_dev; 340 input_set_drvdata(input_dev, touch); 341 342 ret = input_register_device(input_dev); 343 if (ret) 344 goto err_free_input; 345 346 platform_set_drvdata(pdev, touch); 347 return 0; 348 349 err_free_input: 350 input_free_device(input_dev); 351 err_free_touch: 352 kfree(touch); 353 return ret; 354 } 355 356 static int __devexit da9034_touch_remove(struct platform_device *pdev) 357 { 358 struct da9034_touch *touch = platform_get_drvdata(pdev); 359 360 input_unregister_device(touch->input_dev); 361 kfree(touch); 362 363 return 0; 364 } 365 366 static struct platform_driver da9034_touch_driver = { 367 .driver = { 368 .name = "da9034-touch", 369 .owner = THIS_MODULE, 370 }, 371 .probe = da9034_touch_probe, 372 .remove = __devexit_p(da9034_touch_remove), 373 }; 374 375 static int __init da9034_touch_init(void) 376 { 377 return platform_driver_register(&da9034_touch_driver); 378 } 379 module_init(da9034_touch_init); 380 381 static void __exit da9034_touch_exit(void) 382 { 383 platform_driver_unregister(&da9034_touch_driver); 384 } 385 module_exit(da9034_touch_exit); 386 387 MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9034"); 388 MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"); 389 MODULE_LICENSE("GPL"); 390 MODULE_ALIAS("platform:da9034-touch"); 391