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

lpc32xx_ts.c (10016B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * LPC32xx built-in touchscreen driver
      4 *
      5 * Copyright (C) 2010 NXP Semiconductors
      6 */
      7
      8#include <linux/platform_device.h>
      9#include <linux/input.h>
     10#include <linux/interrupt.h>
     11#include <linux/module.h>
     12#include <linux/clk.h>
     13#include <linux/io.h>
     14#include <linux/slab.h>
     15#include <linux/of.h>
     16
     17/*
     18 * Touchscreen controller register offsets
     19 */
     20#define LPC32XX_TSC_STAT			0x00
     21#define LPC32XX_TSC_SEL				0x04
     22#define LPC32XX_TSC_CON				0x08
     23#define LPC32XX_TSC_FIFO			0x0C
     24#define LPC32XX_TSC_DTR				0x10
     25#define LPC32XX_TSC_RTR				0x14
     26#define LPC32XX_TSC_UTR				0x18
     27#define LPC32XX_TSC_TTR				0x1C
     28#define LPC32XX_TSC_DXP				0x20
     29#define LPC32XX_TSC_MIN_X			0x24
     30#define LPC32XX_TSC_MAX_X			0x28
     31#define LPC32XX_TSC_MIN_Y			0x2C
     32#define LPC32XX_TSC_MAX_Y			0x30
     33#define LPC32XX_TSC_AUX_UTR			0x34
     34#define LPC32XX_TSC_AUX_MIN			0x38
     35#define LPC32XX_TSC_AUX_MAX			0x3C
     36
     37#define LPC32XX_TSC_STAT_FIFO_OVRRN		BIT(8)
     38#define LPC32XX_TSC_STAT_FIFO_EMPTY		BIT(7)
     39
     40#define LPC32XX_TSC_SEL_DEFVAL			0x0284
     41
     42#define LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4	(0x1 << 11)
     43#define LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(s)	((10 - (s)) << 7)
     44#define LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(s)	((10 - (s)) << 4)
     45#define LPC32XX_TSC_ADCCON_POWER_UP		BIT(2)
     46#define LPC32XX_TSC_ADCCON_AUTO_EN		BIT(0)
     47
     48#define LPC32XX_TSC_FIFO_TS_P_LEVEL		BIT(31)
     49#define LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(x)	(((x) & 0x03FF0000) >> 16)
     50#define LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(y)	((y) & 0x000003FF)
     51
     52#define LPC32XX_TSC_ADCDAT_VALUE_MASK		0x000003FF
     53
     54#define LPC32XX_TSC_MIN_XY_VAL			0x0
     55#define LPC32XX_TSC_MAX_XY_VAL			0x3FF
     56
     57#define MOD_NAME "ts-lpc32xx"
     58
     59#define tsc_readl(dev, reg) \
     60	__raw_readl((dev)->tsc_base + (reg))
     61#define tsc_writel(dev, reg, val) \
     62	__raw_writel((val), (dev)->tsc_base + (reg))
     63
     64struct lpc32xx_tsc {
     65	struct input_dev *dev;
     66	void __iomem *tsc_base;
     67	int irq;
     68	struct clk *clk;
     69};
     70
     71static void lpc32xx_fifo_clear(struct lpc32xx_tsc *tsc)
     72{
     73	while (!(tsc_readl(tsc, LPC32XX_TSC_STAT) &
     74			LPC32XX_TSC_STAT_FIFO_EMPTY))
     75		tsc_readl(tsc, LPC32XX_TSC_FIFO);
     76}
     77
     78static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id)
     79{
     80	u32 tmp, rv[4], xs[4], ys[4];
     81	int idx;
     82	struct lpc32xx_tsc *tsc = dev_id;
     83	struct input_dev *input = tsc->dev;
     84
     85	tmp = tsc_readl(tsc, LPC32XX_TSC_STAT);
     86
     87	if (tmp & LPC32XX_TSC_STAT_FIFO_OVRRN) {
     88		/* FIFO overflow - throw away samples */
     89		lpc32xx_fifo_clear(tsc);
     90		return IRQ_HANDLED;
     91	}
     92
     93	/*
     94	 * Gather and normalize 4 samples. Pen-up events may have less
     95	 * than 4 samples, but its ok to pop 4 and let the last sample
     96	 * pen status check drop the samples.
     97	 */
     98	idx = 0;
     99	while (idx < 4 &&
    100	       !(tsc_readl(tsc, LPC32XX_TSC_STAT) &
    101			LPC32XX_TSC_STAT_FIFO_EMPTY)) {
    102		tmp = tsc_readl(tsc, LPC32XX_TSC_FIFO);
    103		xs[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
    104			LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(tmp);
    105		ys[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
    106			LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(tmp);
    107		rv[idx] = tmp;
    108		idx++;
    109	}
    110
    111	/* Data is only valid if pen is still down in last sample */
    112	if (!(rv[3] & LPC32XX_TSC_FIFO_TS_P_LEVEL) && idx == 4) {
    113		/* Use average of 2nd and 3rd sample for position */
    114		input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2);
    115		input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2);
    116		input_report_key(input, BTN_TOUCH, 1);
    117	} else {
    118		input_report_key(input, BTN_TOUCH, 0);
    119	}
    120
    121	input_sync(input);
    122
    123	return IRQ_HANDLED;
    124}
    125
    126static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)
    127{
    128	/* Disable auto mode */
    129	tsc_writel(tsc, LPC32XX_TSC_CON,
    130		   tsc_readl(tsc, LPC32XX_TSC_CON) &
    131			     ~LPC32XX_TSC_ADCCON_AUTO_EN);
    132
    133	clk_disable_unprepare(tsc->clk);
    134}
    135
    136static int lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
    137{
    138	u32 tmp;
    139	int err;
    140
    141	err = clk_prepare_enable(tsc->clk);
    142	if (err)
    143		return err;
    144
    145	tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;
    146
    147	/* Set the TSC FIFO depth to 4 samples @ 10-bits per sample (max) */
    148	tmp = LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 |
    149	      LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(10) |
    150	      LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(10);
    151	tsc_writel(tsc, LPC32XX_TSC_CON, tmp);
    152
    153	/* These values are all preset */
    154	tsc_writel(tsc, LPC32XX_TSC_SEL, LPC32XX_TSC_SEL_DEFVAL);
    155	tsc_writel(tsc, LPC32XX_TSC_MIN_X, LPC32XX_TSC_MIN_XY_VAL);
    156	tsc_writel(tsc, LPC32XX_TSC_MAX_X, LPC32XX_TSC_MAX_XY_VAL);
    157	tsc_writel(tsc, LPC32XX_TSC_MIN_Y, LPC32XX_TSC_MIN_XY_VAL);
    158	tsc_writel(tsc, LPC32XX_TSC_MAX_Y, LPC32XX_TSC_MAX_XY_VAL);
    159
    160	/* Aux support is not used */
    161	tsc_writel(tsc, LPC32XX_TSC_AUX_UTR, 0);
    162	tsc_writel(tsc, LPC32XX_TSC_AUX_MIN, 0);
    163	tsc_writel(tsc, LPC32XX_TSC_AUX_MAX, 0);
    164
    165	/*
    166	 * Set sample rate to about 240Hz per X/Y pair. A single measurement
    167	 * consists of 4 pairs which gives about a 60Hz sample rate based on
    168	 * a stable 32768Hz clock source. Values are in clocks.
    169	 * Rate is (32768 / (RTR + XCONV + RTR + YCONV + DXP + TTR + UTR) / 4
    170	 */
    171	tsc_writel(tsc, LPC32XX_TSC_RTR, 0x2);
    172	tsc_writel(tsc, LPC32XX_TSC_DTR, 0x2);
    173	tsc_writel(tsc, LPC32XX_TSC_TTR, 0x10);
    174	tsc_writel(tsc, LPC32XX_TSC_DXP, 0x4);
    175	tsc_writel(tsc, LPC32XX_TSC_UTR, 88);
    176
    177	lpc32xx_fifo_clear(tsc);
    178
    179	/* Enable automatic ts event capture */
    180	tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN);
    181
    182	return 0;
    183}
    184
    185static int lpc32xx_ts_open(struct input_dev *dev)
    186{
    187	struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
    188
    189	return lpc32xx_setup_tsc(tsc);
    190}
    191
    192static void lpc32xx_ts_close(struct input_dev *dev)
    193{
    194	struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
    195
    196	lpc32xx_stop_tsc(tsc);
    197}
    198
    199static int lpc32xx_ts_probe(struct platform_device *pdev)
    200{
    201	struct lpc32xx_tsc *tsc;
    202	struct input_dev *input;
    203	struct resource *res;
    204	resource_size_t size;
    205	int irq;
    206	int error;
    207
    208	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    209	if (!res) {
    210		dev_err(&pdev->dev, "Can't get memory resource\n");
    211		return -ENOENT;
    212	}
    213
    214	irq = platform_get_irq(pdev, 0);
    215	if (irq < 0)
    216		return irq;
    217
    218	tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
    219	input = input_allocate_device();
    220	if (!tsc || !input) {
    221		dev_err(&pdev->dev, "failed allocating memory\n");
    222		error = -ENOMEM;
    223		goto err_free_mem;
    224	}
    225
    226	tsc->dev = input;
    227	tsc->irq = irq;
    228
    229	size = resource_size(res);
    230
    231	if (!request_mem_region(res->start, size, pdev->name)) {
    232		dev_err(&pdev->dev, "TSC registers are not free\n");
    233		error = -EBUSY;
    234		goto err_free_mem;
    235	}
    236
    237	tsc->tsc_base = ioremap(res->start, size);
    238	if (!tsc->tsc_base) {
    239		dev_err(&pdev->dev, "Can't map memory\n");
    240		error = -ENOMEM;
    241		goto err_release_mem;
    242	}
    243
    244	tsc->clk = clk_get(&pdev->dev, NULL);
    245	if (IS_ERR(tsc->clk)) {
    246		dev_err(&pdev->dev, "failed getting clock\n");
    247		error = PTR_ERR(tsc->clk);
    248		goto err_unmap;
    249	}
    250
    251	input->name = MOD_NAME;
    252	input->phys = "lpc32xx/input0";
    253	input->id.bustype = BUS_HOST;
    254	input->id.vendor = 0x0001;
    255	input->id.product = 0x0002;
    256	input->id.version = 0x0100;
    257	input->dev.parent = &pdev->dev;
    258	input->open = lpc32xx_ts_open;
    259	input->close = lpc32xx_ts_close;
    260
    261	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    262	input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    263	input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,
    264			     LPC32XX_TSC_MAX_XY_VAL, 0, 0);
    265	input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,
    266			     LPC32XX_TSC_MAX_XY_VAL, 0, 0);
    267
    268	input_set_drvdata(input, tsc);
    269
    270	error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
    271			    0, pdev->name, tsc);
    272	if (error) {
    273		dev_err(&pdev->dev, "failed requesting interrupt\n");
    274		goto err_put_clock;
    275	}
    276
    277	error = input_register_device(input);
    278	if (error) {
    279		dev_err(&pdev->dev, "failed registering input device\n");
    280		goto err_free_irq;
    281	}
    282
    283	platform_set_drvdata(pdev, tsc);
    284	device_init_wakeup(&pdev->dev, 1);
    285
    286	return 0;
    287
    288err_free_irq:
    289	free_irq(tsc->irq, tsc);
    290err_put_clock:
    291	clk_put(tsc->clk);
    292err_unmap:
    293	iounmap(tsc->tsc_base);
    294err_release_mem:
    295	release_mem_region(res->start, size);
    296err_free_mem:
    297	input_free_device(input);
    298	kfree(tsc);
    299
    300	return error;
    301}
    302
    303static int lpc32xx_ts_remove(struct platform_device *pdev)
    304{
    305	struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
    306	struct resource *res;
    307
    308	free_irq(tsc->irq, tsc);
    309
    310	input_unregister_device(tsc->dev);
    311
    312	clk_put(tsc->clk);
    313
    314	iounmap(tsc->tsc_base);
    315	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    316	release_mem_region(res->start, resource_size(res));
    317
    318	kfree(tsc);
    319
    320	return 0;
    321}
    322
    323#ifdef CONFIG_PM
    324static int lpc32xx_ts_suspend(struct device *dev)
    325{
    326	struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
    327	struct input_dev *input = tsc->dev;
    328
    329	/*
    330	 * Suspend and resume can be called when the device hasn't been
    331	 * enabled. If there are no users that have the device open, then
    332	 * avoid calling the TSC stop and start functions as the TSC
    333	 * isn't yet clocked.
    334	 */
    335	mutex_lock(&input->mutex);
    336
    337	if (input_device_enabled(input)) {
    338		if (device_may_wakeup(dev))
    339			enable_irq_wake(tsc->irq);
    340		else
    341			lpc32xx_stop_tsc(tsc);
    342	}
    343
    344	mutex_unlock(&input->mutex);
    345
    346	return 0;
    347}
    348
    349static int lpc32xx_ts_resume(struct device *dev)
    350{
    351	struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
    352	struct input_dev *input = tsc->dev;
    353
    354	mutex_lock(&input->mutex);
    355
    356	if (input_device_enabled(input)) {
    357		if (device_may_wakeup(dev))
    358			disable_irq_wake(tsc->irq);
    359		else
    360			lpc32xx_setup_tsc(tsc);
    361	}
    362
    363	mutex_unlock(&input->mutex);
    364
    365	return 0;
    366}
    367
    368static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
    369	.suspend	= lpc32xx_ts_suspend,
    370	.resume		= lpc32xx_ts_resume,
    371};
    372#define LPC32XX_TS_PM_OPS (&lpc32xx_ts_pm_ops)
    373#else
    374#define LPC32XX_TS_PM_OPS NULL
    375#endif
    376
    377#ifdef CONFIG_OF
    378static const struct of_device_id lpc32xx_tsc_of_match[] = {
    379	{ .compatible = "nxp,lpc3220-tsc", },
    380	{ },
    381};
    382MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
    383#endif
    384
    385static struct platform_driver lpc32xx_ts_driver = {
    386	.probe		= lpc32xx_ts_probe,
    387	.remove		= lpc32xx_ts_remove,
    388	.driver		= {
    389		.name	= MOD_NAME,
    390		.pm	= LPC32XX_TS_PM_OPS,
    391		.of_match_table = of_match_ptr(lpc32xx_tsc_of_match),
    392	},
    393};
    394module_platform_driver(lpc32xx_ts_driver);
    395
    396MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com");
    397MODULE_DESCRIPTION("LPC32XX TSC Driver");
    398MODULE_LICENSE("GPL");
    399MODULE_ALIAS("platform:lpc32xx_ts");