1/* 2 * Samsung S3C24XX touchscreen driver 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the term of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * 18 * Copyright 2004 Arnaud Patard <arnaud.patard@rtp-net.org> 19 * Copyright 2008 Ben Dooks <ben-linux@fluff.org> 20 * Copyright 2009 Simtec Electronics <linux@simtec.co.uk> 21 * 22 * Additional work by Herbert Pötzl <herbert@13thfloor.at> and 23 * Harald Welte <laforge@openmoko.org> 24 */ 25 26#include <linux/errno.h> 27#include <linux/kernel.h> 28#include <linux/module.h> 29#include <linux/gpio.h> 30#include <linux/input.h> 31#include <linux/init.h> 32#include <linux/delay.h> 33#include <linux/interrupt.h> 34#include <linux/platform_device.h> 35#include <linux/clk.h> 36#include <linux/io.h> 37 38#include <plat/adc.h> 39#include <plat/regs-adc.h> 40#include <plat/ts.h> 41 42#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0)) 43 44#define INT_DOWN (0) 45#define INT_UP (1 << 8) 46 47#define WAIT4INT (S3C2410_ADCTSC_YM_SEN | \ 48 S3C2410_ADCTSC_YP_SEN | \ 49 S3C2410_ADCTSC_XP_SEN | \ 50 S3C2410_ADCTSC_XY_PST(3)) 51 52#define AUTOPST (S3C2410_ADCTSC_YM_SEN | \ 53 S3C2410_ADCTSC_YP_SEN | \ 54 S3C2410_ADCTSC_XP_SEN | \ 55 S3C2410_ADCTSC_AUTO_PST | \ 56 S3C2410_ADCTSC_XY_PST(0)) 57 58#define FEAT_PEN_IRQ (1 << 0) /* HAS ADCCLRINTPNDNUP */ 59 60/* Per-touchscreen data. */ 61 62/** 63 * struct s3c2410ts - driver touchscreen state. 64 * @client: The ADC client we registered with the core driver. 65 * @dev: The device we are bound to. 66 * @input: The input device we registered with the input subsystem. 67 * @clock: The clock for the adc. 68 * @io: Pointer to the IO base. 69 * @xp: The accumulated X position data. 70 * @yp: The accumulated Y position data. 71 * @irq_tc: The interrupt number for pen up/down interrupt 72 * @count: The number of samples collected. 73 * @shift: The log2 of the maximum count to read in one go. 74 * @features: The features supported by the TSADC MOdule. 75 */ 76struct s3c2410ts { 77 struct s3c_adc_client *client; 78 struct device *dev; 79 struct input_dev *input; 80 struct clk *clock; 81 void __iomem *io; 82 unsigned long xp; 83 unsigned long yp; 84 int irq_tc; 85 int count; 86 int shift; 87 int features; 88}; 89 90static struct s3c2410ts ts; 91 92/** 93 * get_down - return the down state of the pen 94 * @data0: The data read from ADCDAT0 register. 95 * @data1: The data read from ADCDAT1 register. 96 * 97 * Return non-zero if both readings show that the pen is down. 98 */ 99static inline bool get_down(unsigned long data0, unsigned long data1) 100{ 101 /* returns true if both data values show stylus down */ 102 return (!(data0 & S3C2410_ADCDAT0_UPDOWN) && 103 !(data1 & S3C2410_ADCDAT0_UPDOWN)); 104} 105 106static void touch_timer_fire(unsigned long data) 107{ 108 unsigned long data0; 109 unsigned long data1; 110 bool down; 111 112 data0 = readl(ts.io + S3C2410_ADCDAT0); 113 data1 = readl(ts.io + S3C2410_ADCDAT1); 114 115 down = get_down(data0, data1); 116 117 if (down) { 118 if (ts.count == (1 << ts.shift)) { 119 ts.xp >>= ts.shift; 120 ts.yp >>= ts.shift; 121 122 dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n", 123 __func__, ts.xp, ts.yp, ts.count); 124 125 input_report_abs(ts.input, ABS_X, ts.xp); 126 input_report_abs(ts.input, ABS_Y, ts.yp); 127 128 input_report_key(ts.input, BTN_TOUCH, 1); 129 input_sync(ts.input); 130 131 ts.xp = 0; 132 ts.yp = 0; 133 ts.count = 0; 134 } 135 136 s3c_adc_start(ts.client, 0, 1 << ts.shift); 137 } else { 138 ts.xp = 0; 139 ts.yp = 0; 140 ts.count = 0; 141 142 input_report_key(ts.input, BTN_TOUCH, 0); 143 input_sync(ts.input); 144 145 writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); 146 } 147} 148 149static DEFINE_TIMER(touch_timer, touch_timer_fire, 0, 0); 150 151/** 152 * stylus_irq - touchscreen stylus event interrupt 153 * @irq: The interrupt number 154 * @dev_id: The device ID. 155 * 156 * Called when the IRQ_TC is fired for a pen up or down event. 157 */ 158static irqreturn_t stylus_irq(int irq, void *dev_id) 159{ 160 unsigned long data0; 161 unsigned long data1; 162 bool down; 163 164 data0 = readl(ts.io + S3C2410_ADCDAT0); 165 data1 = readl(ts.io + S3C2410_ADCDAT1); 166 167 down = get_down(data0, data1); 168 169 /* TODO we should never get an interrupt with down set while 170 * the timer is running, but maybe we ought to verify that the 171 * timer isn't running anyways. */ 172 173 if (down) 174 s3c_adc_start(ts.client, 0, 1 << ts.shift); 175 else 176 dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count); 177 178 if (ts.features & FEAT_PEN_IRQ) { 179 /* Clear pen down/up interrupt */ 180 writel(0x0, ts.io + S3C64XX_ADCCLRINTPNDNUP); 181 } 182 183 return IRQ_HANDLED; 184} 185 186/** 187 * s3c24xx_ts_conversion - ADC conversion callback 188 * @client: The client that was registered with the ADC core. 189 * @data0: The reading from ADCDAT0. 190 * @data1: The reading from ADCDAT1. 191 * @left: The number of samples left. 192 * 193 * Called when a conversion has finished. 194 */ 195static void s3c24xx_ts_conversion(struct s3c_adc_client *client, 196 unsigned data0, unsigned data1, 197 unsigned *left) 198{ 199 dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1); 200 201 ts.xp += data0; 202 ts.yp += data1; 203 204 ts.count++; 205 206 /* From tests, it seems that it is unlikely to get a pen-up 207 * event during the conversion process which means we can 208 * ignore any pen-up events with less than the requisite 209 * count done. 210 * 211 * In several thousand conversions, no pen-ups where detected 212 * before count completed. 213 */ 214} 215 216/** 217 * s3c24xx_ts_select - ADC selection callback. 218 * @client: The client that was registered with the ADC core. 219 * @select: The reason for select. 220 * 221 * Called when the ADC core selects (or deslects) us as a client. 222 */ 223static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select) 224{ 225 if (select) { 226 writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, 227 ts.io + S3C2410_ADCTSC); 228 } else { 229 mod_timer(&touch_timer, jiffies+1); 230 writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC); 231 } 232} 233 234/** 235 * s3c2410ts_probe - device core probe entry point 236 * @pdev: The device we are being bound to. 237 * 238 * Initialise, find and allocate any resources we need to run and then 239 * register with the ADC and input systems. 240 */ 241static int __devinit s3c2410ts_probe(struct platform_device *pdev) 242{ 243 struct s3c2410_ts_mach_info *info; 244 struct device *dev = &pdev->dev; 245 struct input_dev *input_dev; 246 struct resource *res; 247 int ret = -EINVAL; 248 249 /* Initialise input stuff */ 250 memset(&ts, 0, sizeof(struct s3c2410ts)); 251 252 ts.dev = dev; 253 254 info = pdev->dev.platform_data; 255 if (!info) { 256 dev_err(dev, "no platform data, cannot attach\n"); 257 return -EINVAL; 258 } 259 260 dev_dbg(dev, "initialising touchscreen\n"); 261 262 ts.clock = clk_get(dev, "adc"); 263 if (IS_ERR(ts.clock)) { 264 dev_err(dev, "cannot get adc clock source\n"); 265 return -ENOENT; 266 } 267 268 clk_enable(ts.clock); 269 dev_dbg(dev, "got and enabled clocks\n"); 270 271 ts.irq_tc = ret = platform_get_irq(pdev, 0); 272 if (ret < 0) { 273 dev_err(dev, "no resource for interrupt\n"); 274 goto err_clk; 275 } 276 277 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 278 if (!res) { 279 dev_err(dev, "no resource for registers\n"); 280 ret = -ENOENT; 281 goto err_clk; 282 } 283 284 ts.io = ioremap(res->start, resource_size(res)); 285 if (ts.io == NULL) { 286 dev_err(dev, "cannot map registers\n"); 287 ret = -ENOMEM; 288 goto err_clk; 289 } 290 291 /* inititalise the gpio */ 292 if (info->cfg_gpio) 293 info->cfg_gpio(to_platform_device(ts.dev)); 294 295 ts.client = s3c_adc_register(pdev, s3c24xx_ts_select, 296 s3c24xx_ts_conversion, 1); 297 if (IS_ERR(ts.client)) { 298 dev_err(dev, "failed to register adc client\n"); 299 ret = PTR_ERR(ts.client); 300 goto err_iomap; 301 } 302 303 /* Initialise registers */ 304 if ((info->delay & 0xffff) > 0) 305 writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); 306 307 writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); 308 309 input_dev = input_allocate_device(); 310 if (!input_dev) { 311 dev_err(dev, "Unable to allocate the input device !!\n"); 312 ret = -ENOMEM; 313 goto err_iomap; 314 } 315 316 ts.input = input_dev; 317 ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 318 ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 319 input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0); 320 input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0); 321 322 ts.input->name = "S3C24XX TouchScreen"; 323 ts.input->id.bustype = BUS_HOST; 324 ts.input->id.vendor = 0xDEAD; 325 ts.input->id.product = 0xBEEF; 326 ts.input->id.version = 0x0102; 327 328 ts.shift = info->oversampling_shift; 329 ts.features = platform_get_device_id(pdev)->driver_data; 330 331 ret = request_irq(ts.irq_tc, stylus_irq, 0, 332 "s3c2410_ts_pen", ts.input); 333 if (ret) { 334 dev_err(dev, "cannot get TC interrupt\n"); 335 goto err_inputdev; 336 } 337 338 dev_info(dev, "driver attached, registering input device\n"); 339 340 /* All went ok, so register to the input system */ 341 ret = input_register_device(ts.input); 342 if (ret < 0) { 343 dev_err(dev, "failed to register input device\n"); 344 ret = -EIO; 345 goto err_tcirq; 346 } 347 348 return 0; 349 350 err_tcirq: 351 free_irq(ts.irq_tc, ts.input); 352 err_inputdev: 353 input_free_device(ts.input); 354 err_iomap: 355 iounmap(ts.io); 356 err_clk: 357 del_timer_sync(&touch_timer); 358 clk_put(ts.clock); 359 return ret; 360} 361 362/** 363 * s3c2410ts_remove - device core removal entry point 364 * @pdev: The device we are being removed from. 365 * 366 * Free up our state ready to be removed. 367 */ 368static int __devexit s3c2410ts_remove(struct platform_device *pdev) 369{ 370 free_irq(ts.irq_tc, ts.input); 371 del_timer_sync(&touch_timer); 372 373 clk_disable(ts.clock); 374 clk_put(ts.clock); 375 376 input_unregister_device(ts.input); 377 iounmap(ts.io); 378 379 return 0; 380} 381 382#ifdef CONFIG_PM 383static int s3c2410ts_suspend(struct device *dev) 384{ 385 writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC); 386 disable_irq(ts.irq_tc); 387 clk_disable(ts.clock); 388 389 return 0; 390} 391 392static int s3c2410ts_resume(struct device *dev) 393{ 394 struct platform_device *pdev = to_platform_device(dev); 395 struct s3c2410_ts_mach_info *info = pdev->dev.platform_data; 396 397 clk_enable(ts.clock); 398 enable_irq(ts.irq_tc); 399 400 /* Initialise registers */ 401 if ((info->delay & 0xffff) > 0) 402 writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY); 403 404 writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); 405 406 return 0; 407} 408 409static struct dev_pm_ops s3c_ts_pmops = { 410 .suspend = s3c2410ts_suspend, 411 .resume = s3c2410ts_resume, 412}; 413#endif 414 415static struct platform_device_id s3cts_driver_ids[] = { 416 { "s3c2410-ts", 0 }, 417 { "s3c2440-ts", 0 }, 418 { "s3c64xx-ts", FEAT_PEN_IRQ }, 419 { } 420}; 421MODULE_DEVICE_TABLE(platform, s3cts_driver_ids); 422 423static struct platform_driver s3c_ts_driver = { 424 .driver = { 425 .name = "samsung-ts", 426 .owner = THIS_MODULE, 427#ifdef CONFIG_PM 428 .pm = &s3c_ts_pmops, 429#endif 430 }, 431 .id_table = s3cts_driver_ids, 432 .probe = s3c2410ts_probe, 433 .remove = __devexit_p(s3c2410ts_remove), 434}; 435module_platform_driver(s3c_ts_driver); 436 437MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, " 438 "Ben Dooks <ben@simtec.co.uk>, " 439 "Simtec Electronics <linux@simtec.co.uk>"); 440MODULE_DESCRIPTION("S3C24XX Touchscreen driver"); 441MODULE_LICENSE("GPL v2"); 442