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