Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

input: Touchscreen driver for TPS6507x

Add touch screen input driver for TPS6507x family of multi-function
chips. Uses the TPS6507x MFD driver. No interrupt support due to
testing limitations of current hardware.

Signed-off-by: Todd Fischer <todd.fischer@ridgerun.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Todd Fischer and committed by
Samuel Ortiz
75259966 31dd6a26

+443
+13
drivers/input/touchscreen/Kconfig
··· 590 590 591 591 To compile this driver as a module, choose M here: the 592 592 module will be called pcap_ts. 593 + 594 + config TOUCHSCREEN_TPS6507X 595 + tristate "TPS6507x based touchscreens" 596 + depends on I2C 597 + help 598 + Say Y here if you have a TPS6507x based touchscreen 599 + controller. 600 + 601 + If unsure, say N. 602 + 603 + To compile this driver as a module, choose M here: the 604 + module will be called tps6507x_ts. 605 + 593 606 endif
+1
drivers/input/touchscreen/Makefile
··· 46 46 obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o 47 47 obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o 48 48 obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o 49 + obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
+400
drivers/input/touchscreen/tps6507x-ts.c
··· 1 + /* 2 + * drivers/input/touchscreen/tps6507x_ts.c 3 + * 4 + * Touchscreen driver for the tps6507x chip. 5 + * 6 + * Copyright (c) 2009 RidgeRun (todd.fischer@ridgerun.com) 7 + * 8 + * Credits: 9 + * 10 + * Using code from tsc2007, MtekVision Co., Ltd. 11 + * 12 + * For licencing details see kernel-base/COPYING 13 + * 14 + * TPS65070, TPS65073, TPS650731, and TPS650732 support 15 + * 10 bit touch screen interface. 16 + */ 17 + 18 + #include <linux/module.h> 19 + #include <linux/workqueue.h> 20 + #include <linux/slab.h> 21 + #include <linux/input.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/mfd/tps6507x.h> 24 + #include <linux/input/tps6507x-ts.h> 25 + #include <linux/delay.h> 26 + 27 + #define TSC_DEFAULT_POLL_PERIOD 30 /* ms */ 28 + #define TPS_DEFAULT_MIN_PRESSURE 0x30 29 + #define MAX_10BIT ((1 << 10) - 1) 30 + 31 + #define TPS6507X_ADCONFIG_CONVERT_TS (TPS6507X_ADCONFIG_AD_ENABLE | \ 32 + TPS6507X_ADCONFIG_START_CONVERSION | \ 33 + TPS6507X_ADCONFIG_INPUT_REAL_TSC) 34 + #define TPS6507X_ADCONFIG_POWER_DOWN_TS (TPS6507X_ADCONFIG_INPUT_REAL_TSC) 35 + 36 + struct ts_event { 37 + u16 x; 38 + u16 y; 39 + u16 pressure; 40 + }; 41 + 42 + struct tps6507x_ts { 43 + struct input_dev *input_dev; 44 + struct device *dev; 45 + char phys[32]; 46 + struct workqueue_struct *wq; 47 + struct delayed_work work; 48 + unsigned polling; /* polling is active */ 49 + struct ts_event tc; 50 + struct tps6507x_dev *mfd; 51 + u16 model; 52 + unsigned pendown; 53 + int irq; 54 + void (*clear_penirq)(void); 55 + unsigned long poll_period; /* ms */ 56 + u16 min_pressure; 57 + int vref; /* non-zero to leave vref on */ 58 + }; 59 + 60 + static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data) 61 + { 62 + int err; 63 + 64 + err = tsc->mfd->read_dev(tsc->mfd, reg, 1, data); 65 + 66 + if (err) 67 + return err; 68 + 69 + return 0; 70 + } 71 + 72 + static int tps6507x_write_u8(struct tps6507x_ts *tsc, u8 reg, u8 data) 73 + { 74 + return tsc->mfd->write_dev(tsc->mfd, reg, 1, &data); 75 + } 76 + 77 + static s32 tps6507x_adc_conversion(struct tps6507x_ts *tsc, 78 + u8 tsc_mode, u16 *value) 79 + { 80 + s32 ret; 81 + u8 adc_status; 82 + u8 result; 83 + 84 + /* Route input signal to A/D converter */ 85 + 86 + ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE, tsc_mode); 87 + if (ret) { 88 + dev_err(tsc->dev, "TSC mode read failed\n"); 89 + goto err; 90 + } 91 + 92 + /* Start A/D conversion */ 93 + 94 + ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG, 95 + TPS6507X_ADCONFIG_CONVERT_TS); 96 + if (ret) { 97 + dev_err(tsc->dev, "ADC config write failed\n"); 98 + return ret; 99 + } 100 + 101 + do { 102 + ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADCONFIG, 103 + &adc_status); 104 + if (ret) { 105 + dev_err(tsc->dev, "ADC config read failed\n"); 106 + goto err; 107 + } 108 + } while (adc_status & TPS6507X_ADCONFIG_START_CONVERSION); 109 + 110 + ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_2, &result); 111 + if (ret) { 112 + dev_err(tsc->dev, "ADC result 2 read failed\n"); 113 + goto err; 114 + } 115 + 116 + *value = (result & TPS6507X_REG_ADRESULT_2_MASK) << 8; 117 + 118 + ret = tps6507x_read_u8(tsc, TPS6507X_REG_ADRESULT_1, &result); 119 + if (ret) { 120 + dev_err(tsc->dev, "ADC result 1 read failed\n"); 121 + goto err; 122 + } 123 + 124 + *value |= result; 125 + 126 + dev_dbg(tsc->dev, "TSC channel %d = 0x%X\n", tsc_mode, *value); 127 + 128 + err: 129 + return ret; 130 + } 131 + 132 + /* Need to call tps6507x_adc_standby() after using A/D converter for the 133 + * touch screen interrupt to work properly. 134 + */ 135 + 136 + static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc) 137 + { 138 + s32 ret; 139 + s32 loops = 0; 140 + u8 val; 141 + 142 + ret = tps6507x_write_u8(tsc, TPS6507X_REG_ADCONFIG, 143 + TPS6507X_ADCONFIG_INPUT_TSC); 144 + if (ret) 145 + return ret; 146 + 147 + ret = tps6507x_write_u8(tsc, TPS6507X_REG_TSCMODE, 148 + TPS6507X_TSCMODE_STANDBY); 149 + if (ret) 150 + return ret; 151 + 152 + ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val); 153 + if (ret) 154 + return ret; 155 + 156 + while (val & TPS6507X_REG_TSC_INT) { 157 + mdelay(10); 158 + ret = tps6507x_read_u8(tsc, TPS6507X_REG_INT, &val); 159 + if (ret) 160 + return ret; 161 + loops++; 162 + } 163 + 164 + return ret; 165 + } 166 + 167 + static void tps6507x_ts_handler(struct work_struct *work) 168 + { 169 + struct tps6507x_ts *tsc = container_of(work, 170 + struct tps6507x_ts, work.work); 171 + struct input_dev *input_dev = tsc->input_dev; 172 + int pendown; 173 + int schd; 174 + int poll = 0; 175 + s32 ret; 176 + 177 + ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE, 178 + &tsc->tc.pressure); 179 + if (ret) 180 + goto done; 181 + 182 + pendown = tsc->tc.pressure > tsc->min_pressure; 183 + 184 + if (unlikely(!pendown && tsc->pendown)) { 185 + dev_dbg(tsc->dev, "UP\n"); 186 + input_report_key(input_dev, BTN_TOUCH, 0); 187 + input_report_abs(input_dev, ABS_PRESSURE, 0); 188 + input_sync(input_dev); 189 + tsc->pendown = 0; 190 + } 191 + 192 + if (pendown) { 193 + 194 + if (!tsc->pendown) { 195 + dev_dbg(tsc->dev, "DOWN\n"); 196 + input_report_key(input_dev, BTN_TOUCH, 1); 197 + } else 198 + dev_dbg(tsc->dev, "still down\n"); 199 + 200 + ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_X_POSITION, 201 + &tsc->tc.x); 202 + if (ret) 203 + goto done; 204 + 205 + ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_Y_POSITION, 206 + &tsc->tc.y); 207 + if (ret) 208 + goto done; 209 + 210 + input_report_abs(input_dev, ABS_X, tsc->tc.x); 211 + input_report_abs(input_dev, ABS_Y, tsc->tc.y); 212 + input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure); 213 + input_sync(input_dev); 214 + tsc->pendown = 1; 215 + poll = 1; 216 + } 217 + 218 + done: 219 + /* always poll if not using interrupts */ 220 + poll = 1; 221 + 222 + if (poll) { 223 + schd = queue_delayed_work(tsc->wq, &tsc->work, 224 + tsc->poll_period * HZ / 1000); 225 + if (schd) 226 + tsc->polling = 1; 227 + else { 228 + tsc->polling = 0; 229 + dev_err(tsc->dev, "re-schedule failed"); 230 + } 231 + } else 232 + tsc->polling = 0; 233 + 234 + ret = tps6507x_adc_standby(tsc); 235 + } 236 + 237 + static int tps6507x_ts_probe(struct platform_device *pdev) 238 + { 239 + int error; 240 + struct tps6507x_ts *tsc; 241 + struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); 242 + struct touchscreen_init_data *init_data; 243 + struct input_dev *input_dev; 244 + struct tps6507x_board *tps_board; 245 + int schd; 246 + 247 + /** 248 + * tps_board points to pmic related constants 249 + * coming from the board-evm file. 250 + */ 251 + 252 + tps_board = (struct tps6507x_board *)tps6507x_dev->dev->platform_data; 253 + 254 + if (!tps_board) { 255 + dev_err(tps6507x_dev->dev, 256 + "Could not find tps6507x platform data\n"); 257 + return -EIO; 258 + } 259 + 260 + /** 261 + * init_data points to array of regulator_init structures 262 + * coming from the board-evm file. 263 + */ 264 + 265 + init_data = tps_board->tps6507x_ts_init_data; 266 + 267 + tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL); 268 + if (!tsc) { 269 + dev_err(tps6507x_dev->dev, "failed to allocate driver data\n"); 270 + error = -ENOMEM; 271 + goto err0; 272 + } 273 + 274 + tps6507x_dev->ts = tsc; 275 + tsc->mfd = tps6507x_dev; 276 + tsc->dev = tps6507x_dev->dev; 277 + input_dev = input_allocate_device(); 278 + if (!input_dev) { 279 + dev_err(tsc->dev, "Failed to allocate input device.\n"); 280 + error = -ENOMEM; 281 + goto err1; 282 + } 283 + 284 + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 285 + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 286 + 287 + input_set_abs_params(input_dev, ABS_X, 0, MAX_10BIT, 0, 0); 288 + input_set_abs_params(input_dev, ABS_Y, 0, MAX_10BIT, 0, 0); 289 + input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0); 290 + 291 + input_dev->name = "TPS6507x Touchscreen"; 292 + input_dev->id.bustype = BUS_I2C; 293 + input_dev->dev.parent = tsc->dev; 294 + 295 + snprintf(tsc->phys, sizeof(tsc->phys), 296 + "%s/input0", dev_name(tsc->dev)); 297 + input_dev->phys = tsc->phys; 298 + 299 + dev_dbg(tsc->dev, "device: %s\n", input_dev->phys); 300 + 301 + input_set_drvdata(input_dev, tsc); 302 + 303 + tsc->input_dev = input_dev; 304 + 305 + INIT_DELAYED_WORK(&tsc->work, tps6507x_ts_handler); 306 + tsc->wq = create_workqueue("TPS6507x Touchscreen"); 307 + 308 + if (init_data) { 309 + tsc->poll_period = init_data->poll_period; 310 + tsc->vref = init_data->vref; 311 + tsc->min_pressure = init_data->min_pressure; 312 + input_dev->id.vendor = init_data->vendor; 313 + input_dev->id.product = init_data->product; 314 + input_dev->id.version = init_data->version; 315 + } else { 316 + tsc->poll_period = TSC_DEFAULT_POLL_PERIOD; 317 + tsc->min_pressure = TPS_DEFAULT_MIN_PRESSURE; 318 + } 319 + 320 + error = tps6507x_adc_standby(tsc); 321 + if (error) 322 + goto err2; 323 + 324 + error = input_register_device(input_dev); 325 + if (error) 326 + goto err2; 327 + 328 + schd = queue_delayed_work(tsc->wq, &tsc->work, 329 + tsc->poll_period * HZ / 1000); 330 + 331 + if (schd) 332 + tsc->polling = 1; 333 + else { 334 + tsc->polling = 0; 335 + dev_err(tsc->dev, "schedule failed"); 336 + goto err2; 337 + } 338 + 339 + return 0; 340 + 341 + err2: 342 + cancel_delayed_work(&tsc->work); 343 + flush_workqueue(tsc->wq); 344 + destroy_workqueue(tsc->wq); 345 + tsc->wq = 0; 346 + input_free_device(input_dev); 347 + err1: 348 + kfree(tsc); 349 + tps6507x_dev->ts = NULL; 350 + err0: 351 + return error; 352 + } 353 + 354 + static int __devexit tps6507x_ts_remove(struct platform_device *pdev) 355 + { 356 + struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); 357 + struct tps6507x_ts *tsc = tps6507x_dev->ts; 358 + struct input_dev *input_dev = tsc->input_dev; 359 + 360 + if (!tsc) 361 + return 0; 362 + 363 + cancel_delayed_work(&tsc->work); 364 + flush_workqueue(tsc->wq); 365 + destroy_workqueue(tsc->wq); 366 + tsc->wq = 0; 367 + 368 + input_free_device(input_dev); 369 + 370 + tps6507x_dev->ts = NULL; 371 + kfree(tsc); 372 + 373 + return 0; 374 + } 375 + 376 + static struct platform_driver tps6507x_ts_driver = { 377 + .driver = { 378 + .name = "tps6507x-ts", 379 + .owner = THIS_MODULE, 380 + }, 381 + .probe = tps6507x_ts_probe, 382 + .remove = __devexit_p(tps6507x_ts_remove), 383 + }; 384 + 385 + static int __init tps6507x_ts_init(void) 386 + { 387 + return platform_driver_register(&tps6507x_ts_driver); 388 + } 389 + module_init(tps6507x_ts_init); 390 + 391 + static void __exit tps6507x_ts_exit(void) 392 + { 393 + platform_driver_unregister(&tps6507x_ts_driver); 394 + } 395 + module_exit(tps6507x_ts_exit); 396 + 397 + MODULE_AUTHOR("Todd Fischer <todd.fischer@ridgerun.com>"); 398 + MODULE_DESCRIPTION("TPS6507x - TouchScreen driver"); 399 + MODULE_LICENSE("GPL v2"); 400 + MODULE_ALIAS("platform:tps6507x-tsc");
+3
drivers/mfd/tps6507x.c
··· 26 26 { 27 27 .name = "tps6507x-pmic", 28 28 }, 29 + { 30 + .name = "tps6507x-ts", 31 + }, 29 32 }; 30 33 31 34
+24
include/linux/input/tps6507x-ts.h
··· 1 + /* linux/i2c/tps6507x-ts.h 2 + * 3 + * Functions to access TPS65070 touch screen chip. 4 + * 5 + * Copyright (c) 2009 RidgeRun (todd.fischer@ridgerun.com) 6 + * 7 + * 8 + * For licencing details see kernel-base/COPYING 9 + */ 10 + 11 + #ifndef __LINUX_I2C_TPS6507X_TS_H 12 + #define __LINUX_I2C_TPS6507X_TS_H 13 + 14 + /* Board specific touch screen initial values */ 15 + struct touchscreen_init_data { 16 + int poll_period; /* ms */ 17 + int vref; /* non-zero to leave vref on */ 18 + __u16 min_pressure; /* min reading to be treated as a touch */ 19 + __u16 vendor; 20 + __u16 product; 21 + __u16 version; 22 + }; 23 + 24 + #endif /* __LINUX_I2C_TPS6507X_TS_H */
+2
include/linux/mfd/tps6507x.h
··· 142 142 143 143 struct tps6507x_board { 144 144 struct regulator_init_data *tps6507x_pmic_init_data; 145 + struct touchscreen_init_data *tps6507x_ts_init_data; 145 146 }; 146 147 147 148 /** ··· 163 162 164 163 /* Client devices */ 165 164 struct tps6507x_pmic *pmic; 165 + struct tps6507x_ts *ts; 166 166 }; 167 167 168 168 #endif /* __LINUX_MFD_TPS6507X_H */