Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Samsung S3C24XX touchscreen driver
0004  *
0005  * Copyright 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
0006  * Copyright 2008 Ben Dooks <ben-linux@fluff.org>
0007  * Copyright 2009 Simtec Electronics <linux@simtec.co.uk>
0008  *
0009  * Additional work by Herbert Pƶtzl <herbert@13thfloor.at> and
0010  * Harald Welte <laforge@openmoko.org>
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 /* ADCTSC Register Bits */
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 /* ADCDAT0 Bits */
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 /* ADCDAT1 Bits */
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)    /* HAS ADCCLRINTPNDNUP */
0077 
0078 /* Per-touchscreen data. */
0079 
0080 /**
0081  * struct s3c2410ts - driver touchscreen state.
0082  * @client: The ADC client we registered with the core driver.
0083  * @dev: The device we are bound to.
0084  * @input: The input device we registered with the input subsystem.
0085  * @clock: The clock for the adc.
0086  * @io: Pointer to the IO base.
0087  * @xp: The accumulated X position data.
0088  * @yp: The accumulated Y position data.
0089  * @irq_tc: The interrupt number for pen up/down interrupt
0090  * @count: The number of samples collected.
0091  * @shift: The log2 of the maximum count to read in one go.
0092  * @features: The features supported by the TSADC MOdule.
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  * get_down - return the down state of the pen
0112  * @data0: The data read from ADCDAT0 register.
0113  * @data1: The data read from ADCDAT1 register.
0114  *
0115  * Return non-zero if both readings show that the pen is down.
0116  */
0117 static inline bool get_down(unsigned long data0, unsigned long data1)
0118 {
0119     /* returns true if both data values show stylus down */
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  * stylus_irq - touchscreen stylus event interrupt
0171  * @irq: The interrupt number
0172  * @dev_id: The device ID.
0173  *
0174  * Called when the IRQ_TC is fired for a pen up or down event.
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     /* TODO we should never get an interrupt with down set while
0188      * the timer is running, but maybe we ought to verify that the
0189      * timer isn't running anyways. */
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         /* Clear pen down/up interrupt */
0198         writel(0x0, ts.io + S3C64XX_ADCCLRINTPNDNUP);
0199     }
0200 
0201     return IRQ_HANDLED;
0202 }
0203 
0204 /**
0205  * s3c24xx_ts_conversion - ADC conversion callback
0206  * @client: The client that was registered with the ADC core.
0207  * @data0: The reading from ADCDAT0.
0208  * @data1: The reading from ADCDAT1.
0209  * @left: The number of samples left.
0210  *
0211  * Called when a conversion has finished.
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     /* From tests, it seems that it is unlikely to get a pen-up
0225      * event during the conversion process which means we can
0226      * ignore any pen-up events with less than the requisite
0227      * count done.
0228      *
0229      * In several thousand conversions, no pen-ups where detected
0230      * before count completed.
0231      */
0232 }
0233 
0234 /**
0235  * s3c24xx_ts_select - ADC selection callback.
0236  * @client: The client that was registered with the ADC core.
0237  * @select: The reason for select.
0238  *
0239  * Called when the ADC core selects (or deslects) us as a client.
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  * s3c2410ts_probe - device core probe entry point
0254  * @pdev: The device we are being bound to.
0255  *
0256  * Initialise, find and allocate any resources we need to run and then
0257  * register with the ADC and input systems.
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     /* Initialise input stuff */
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     /* inititalise the gpio */
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     /* Initialise registers */
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     /* All went ok, so register to the input system */
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  * s3c2410ts_remove - device core removal entry point
0388  * @pdev: The device we are being removed from.
0389  *
0390  * Free up our state ready to be removed.
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     /* Initialise registers */
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");