0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/errno.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/input.h>
0017 #include <linux/delay.h>
0018 #include <linux/interrupt.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/clk.h>
0021 #include <linux/io.h>
0022
0023 #include <linux/soc/samsung/s3c-adc.h>
0024 #include <linux/platform_data/touchscreen-s3c2410.h>
0025
0026 #define S3C2410_ADCCON (0x00)
0027 #define S3C2410_ADCTSC (0x04)
0028 #define S3C2410_ADCDLY (0x08)
0029 #define S3C2410_ADCDAT0 (0x0C)
0030 #define S3C2410_ADCDAT1 (0x10)
0031 #define S3C64XX_ADCUPDN (0x14)
0032 #define S3C2443_ADCMUX (0x18)
0033 #define S3C64XX_ADCCLRINT (0x18)
0034 #define S5P_ADCMUX (0x1C)
0035 #define S3C64XX_ADCCLRINTPNDNUP (0x20)
0036
0037
0038 #define S3C2443_ADCTSC_UD_SEN (1 << 8)
0039 #define S3C2410_ADCTSC_YM_SEN (1<<7)
0040 #define S3C2410_ADCTSC_YP_SEN (1<<6)
0041 #define S3C2410_ADCTSC_XM_SEN (1<<5)
0042 #define S3C2410_ADCTSC_XP_SEN (1<<4)
0043 #define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3)
0044 #define S3C2410_ADCTSC_AUTO_PST (1<<2)
0045 #define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0)
0046
0047
0048 #define S3C2410_ADCDAT0_UPDOWN (1<<15)
0049 #define S3C2410_ADCDAT0_AUTO_PST (1<<14)
0050 #define S3C2410_ADCDAT0_XY_PST (0x3<<12)
0051 #define S3C2410_ADCDAT0_XPDATA_MASK (0x03FF)
0052
0053
0054 #define S3C2410_ADCDAT1_UPDOWN (1<<15)
0055 #define S3C2410_ADCDAT1_AUTO_PST (1<<14)
0056 #define S3C2410_ADCDAT1_XY_PST (0x3<<12)
0057 #define S3C2410_ADCDAT1_YPDATA_MASK (0x03FF)
0058
0059
0060 #define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
0061
0062 #define INT_DOWN (0)
0063 #define INT_UP (1 << 8)
0064
0065 #define WAIT4INT (S3C2410_ADCTSC_YM_SEN | \
0066 S3C2410_ADCTSC_YP_SEN | \
0067 S3C2410_ADCTSC_XP_SEN | \
0068 S3C2410_ADCTSC_XY_PST(3))
0069
0070 #define AUTOPST (S3C2410_ADCTSC_YM_SEN | \
0071 S3C2410_ADCTSC_YP_SEN | \
0072 S3C2410_ADCTSC_XP_SEN | \
0073 S3C2410_ADCTSC_AUTO_PST | \
0074 S3C2410_ADCTSC_XY_PST(0))
0075
0076 #define FEAT_PEN_IRQ (1 << 0)
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094 struct s3c2410ts {
0095 struct s3c_adc_client *client;
0096 struct device *dev;
0097 struct input_dev *input;
0098 struct clk *clock;
0099 void __iomem *io;
0100 unsigned long xp;
0101 unsigned long yp;
0102 int irq_tc;
0103 int count;
0104 int shift;
0105 int features;
0106 };
0107
0108 static struct s3c2410ts ts;
0109
0110
0111
0112
0113
0114
0115
0116
0117 static inline bool get_down(unsigned long data0, unsigned long data1)
0118 {
0119
0120 return (!(data0 & S3C2410_ADCDAT0_UPDOWN) &&
0121 !(data1 & S3C2410_ADCDAT0_UPDOWN));
0122 }
0123
0124 static void touch_timer_fire(struct timer_list *unused)
0125 {
0126 unsigned long data0;
0127 unsigned long data1;
0128 bool down;
0129
0130 data0 = readl(ts.io + S3C2410_ADCDAT0);
0131 data1 = readl(ts.io + S3C2410_ADCDAT1);
0132
0133 down = get_down(data0, data1);
0134
0135 if (down) {
0136 if (ts.count == (1 << ts.shift)) {
0137 ts.xp >>= ts.shift;
0138 ts.yp >>= ts.shift;
0139
0140 dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
0141 __func__, ts.xp, ts.yp, ts.count);
0142
0143 input_report_abs(ts.input, ABS_X, ts.xp);
0144 input_report_abs(ts.input, ABS_Y, ts.yp);
0145
0146 input_report_key(ts.input, BTN_TOUCH, 1);
0147 input_sync(ts.input);
0148
0149 ts.xp = 0;
0150 ts.yp = 0;
0151 ts.count = 0;
0152 }
0153
0154 s3c_adc_start(ts.client, 0, 1 << ts.shift);
0155 } else {
0156 ts.xp = 0;
0157 ts.yp = 0;
0158 ts.count = 0;
0159
0160 input_report_key(ts.input, BTN_TOUCH, 0);
0161 input_sync(ts.input);
0162
0163 writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
0164 }
0165 }
0166
0167 static DEFINE_TIMER(touch_timer, touch_timer_fire);
0168
0169
0170
0171
0172
0173
0174
0175
0176 static irqreturn_t stylus_irq(int irq, void *dev_id)
0177 {
0178 unsigned long data0;
0179 unsigned long data1;
0180 bool down;
0181
0182 data0 = readl(ts.io + S3C2410_ADCDAT0);
0183 data1 = readl(ts.io + S3C2410_ADCDAT1);
0184
0185 down = get_down(data0, data1);
0186
0187
0188
0189
0190
0191 if (down)
0192 s3c_adc_start(ts.client, 0, 1 << ts.shift);
0193 else
0194 dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count);
0195
0196 if (ts.features & FEAT_PEN_IRQ) {
0197
0198 writel(0x0, ts.io + S3C64XX_ADCCLRINTPNDNUP);
0199 }
0200
0201 return IRQ_HANDLED;
0202 }
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213 static void s3c24xx_ts_conversion(struct s3c_adc_client *client,
0214 unsigned data0, unsigned data1,
0215 unsigned *left)
0216 {
0217 dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1);
0218
0219 ts.xp += data0;
0220 ts.yp += data1;
0221
0222 ts.count++;
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241 static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select)
0242 {
0243 if (select) {
0244 writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
0245 ts.io + S3C2410_ADCTSC);
0246 } else {
0247 mod_timer(&touch_timer, jiffies+1);
0248 writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC);
0249 }
0250 }
0251
0252
0253
0254
0255
0256
0257
0258
0259 static int s3c2410ts_probe(struct platform_device *pdev)
0260 {
0261 struct s3c2410_ts_mach_info *info;
0262 struct device *dev = &pdev->dev;
0263 struct input_dev *input_dev;
0264 struct resource *res;
0265 int ret = -EINVAL;
0266
0267
0268 memset(&ts, 0, sizeof(struct s3c2410ts));
0269
0270 ts.dev = dev;
0271
0272 info = dev_get_platdata(dev);
0273 if (!info) {
0274 dev_err(dev, "no platform data, cannot attach\n");
0275 return -EINVAL;
0276 }
0277
0278 dev_dbg(dev, "initialising touchscreen\n");
0279
0280 ts.clock = clk_get(dev, "adc");
0281 if (IS_ERR(ts.clock)) {
0282 dev_err(dev, "cannot get adc clock source\n");
0283 return -ENOENT;
0284 }
0285
0286 ret = clk_prepare_enable(ts.clock);
0287 if (ret) {
0288 dev_err(dev, "Failed! to enabled clocks\n");
0289 goto err_clk_get;
0290 }
0291 dev_dbg(dev, "got and enabled clocks\n");
0292
0293 ts.irq_tc = ret = platform_get_irq(pdev, 0);
0294 if (ret < 0) {
0295 dev_err(dev, "no resource for interrupt\n");
0296 goto err_clk;
0297 }
0298
0299 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0300 if (!res) {
0301 dev_err(dev, "no resource for registers\n");
0302 ret = -ENOENT;
0303 goto err_clk;
0304 }
0305
0306 ts.io = ioremap(res->start, resource_size(res));
0307 if (ts.io == NULL) {
0308 dev_err(dev, "cannot map registers\n");
0309 ret = -ENOMEM;
0310 goto err_clk;
0311 }
0312
0313
0314 if (info->cfg_gpio)
0315 info->cfg_gpio(to_platform_device(ts.dev));
0316
0317 ts.client = s3c_adc_register(pdev, s3c24xx_ts_select,
0318 s3c24xx_ts_conversion, 1);
0319 if (IS_ERR(ts.client)) {
0320 dev_err(dev, "failed to register adc client\n");
0321 ret = PTR_ERR(ts.client);
0322 goto err_iomap;
0323 }
0324
0325
0326 if ((info->delay & 0xffff) > 0)
0327 writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
0328
0329 writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
0330
0331 input_dev = input_allocate_device();
0332 if (!input_dev) {
0333 dev_err(dev, "Unable to allocate the input device !!\n");
0334 ret = -ENOMEM;
0335 goto err_iomap;
0336 }
0337
0338 ts.input = input_dev;
0339 ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
0340 ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
0341 input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);
0342 input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);
0343
0344 ts.input->name = "S3C24XX TouchScreen";
0345 ts.input->id.bustype = BUS_HOST;
0346 ts.input->id.vendor = 0xDEAD;
0347 ts.input->id.product = 0xBEEF;
0348 ts.input->id.version = 0x0102;
0349
0350 ts.shift = info->oversampling_shift;
0351 ts.features = platform_get_device_id(pdev)->driver_data;
0352
0353 ret = request_irq(ts.irq_tc, stylus_irq, 0,
0354 "s3c2410_ts_pen", ts.input);
0355 if (ret) {
0356 dev_err(dev, "cannot get TC interrupt\n");
0357 goto err_inputdev;
0358 }
0359
0360 dev_info(dev, "driver attached, registering input device\n");
0361
0362
0363 ret = input_register_device(ts.input);
0364 if (ret < 0) {
0365 dev_err(dev, "failed to register input device\n");
0366 ret = -EIO;
0367 goto err_tcirq;
0368 }
0369
0370 return 0;
0371
0372 err_tcirq:
0373 free_irq(ts.irq_tc, ts.input);
0374 err_inputdev:
0375 input_free_device(ts.input);
0376 err_iomap:
0377 iounmap(ts.io);
0378 err_clk:
0379 clk_disable_unprepare(ts.clock);
0380 del_timer_sync(&touch_timer);
0381 err_clk_get:
0382 clk_put(ts.clock);
0383 return ret;
0384 }
0385
0386
0387
0388
0389
0390
0391
0392 static int s3c2410ts_remove(struct platform_device *pdev)
0393 {
0394 free_irq(ts.irq_tc, ts.input);
0395 del_timer_sync(&touch_timer);
0396
0397 clk_disable_unprepare(ts.clock);
0398 clk_put(ts.clock);
0399
0400 input_unregister_device(ts.input);
0401 iounmap(ts.io);
0402
0403 return 0;
0404 }
0405
0406 #ifdef CONFIG_PM
0407 static int s3c2410ts_suspend(struct device *dev)
0408 {
0409 writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC);
0410 disable_irq(ts.irq_tc);
0411 clk_disable(ts.clock);
0412
0413 return 0;
0414 }
0415
0416 static int s3c2410ts_resume(struct device *dev)
0417 {
0418 struct platform_device *pdev = to_platform_device(dev);
0419 struct s3c2410_ts_mach_info *info = dev_get_platdata(&pdev->dev);
0420
0421 clk_enable(ts.clock);
0422 enable_irq(ts.irq_tc);
0423
0424
0425 if ((info->delay & 0xffff) > 0)
0426 writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
0427
0428 writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
0429
0430 return 0;
0431 }
0432
0433 static const struct dev_pm_ops s3c_ts_pmops = {
0434 .suspend = s3c2410ts_suspend,
0435 .resume = s3c2410ts_resume,
0436 };
0437 #endif
0438
0439 static const struct platform_device_id s3cts_driver_ids[] = {
0440 { "s3c2410-ts", 0 },
0441 { "s3c2440-ts", 0 },
0442 { "s3c64xx-ts", FEAT_PEN_IRQ },
0443 { }
0444 };
0445 MODULE_DEVICE_TABLE(platform, s3cts_driver_ids);
0446
0447 static struct platform_driver s3c_ts_driver = {
0448 .driver = {
0449 .name = "samsung-ts",
0450 #ifdef CONFIG_PM
0451 .pm = &s3c_ts_pmops,
0452 #endif
0453 },
0454 .id_table = s3cts_driver_ids,
0455 .probe = s3c2410ts_probe,
0456 .remove = s3c2410ts_remove,
0457 };
0458 module_platform_driver(s3c_ts_driver);
0459
0460 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
0461 "Ben Dooks <ben@simtec.co.uk>, "
0462 "Simtec Electronics <linux@simtec.co.uk>");
0463 MODULE_DESCRIPTION("S3C24XX Touchscreen driver");
0464 MODULE_LICENSE("GPL v2");