cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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");