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