xref: /linux/drivers/input/touchscreen/lpc32xx_ts.c (revision 5a94296bc02ac616336da7b5332b86d2ca8827f0)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23045a5f5SKevin Wells /*
33045a5f5SKevin Wells  * LPC32xx built-in touchscreen driver
43045a5f5SKevin Wells  *
53045a5f5SKevin Wells  * Copyright (C) 2010 NXP Semiconductors
63045a5f5SKevin Wells  */
73045a5f5SKevin Wells 
83045a5f5SKevin Wells #include <linux/platform_device.h>
93045a5f5SKevin Wells #include <linux/input.h>
103045a5f5SKevin Wells #include <linux/interrupt.h>
113045a5f5SKevin Wells #include <linux/module.h>
123045a5f5SKevin Wells #include <linux/clk.h>
133045a5f5SKevin Wells #include <linux/io.h>
143045a5f5SKevin Wells #include <linux/slab.h>
155cb727a8SRoland Stigge #include <linux/of.h>
163045a5f5SKevin Wells 
173045a5f5SKevin Wells /*
183045a5f5SKevin Wells  * Touchscreen controller register offsets
193045a5f5SKevin Wells  */
203045a5f5SKevin Wells #define LPC32XX_TSC_STAT			0x00
213045a5f5SKevin Wells #define LPC32XX_TSC_SEL				0x04
223045a5f5SKevin Wells #define LPC32XX_TSC_CON				0x08
233045a5f5SKevin Wells #define LPC32XX_TSC_FIFO			0x0C
243045a5f5SKevin Wells #define LPC32XX_TSC_DTR				0x10
253045a5f5SKevin Wells #define LPC32XX_TSC_RTR				0x14
263045a5f5SKevin Wells #define LPC32XX_TSC_UTR				0x18
273045a5f5SKevin Wells #define LPC32XX_TSC_TTR				0x1C
283045a5f5SKevin Wells #define LPC32XX_TSC_DXP				0x20
293045a5f5SKevin Wells #define LPC32XX_TSC_MIN_X			0x24
303045a5f5SKevin Wells #define LPC32XX_TSC_MAX_X			0x28
313045a5f5SKevin Wells #define LPC32XX_TSC_MIN_Y			0x2C
323045a5f5SKevin Wells #define LPC32XX_TSC_MAX_Y			0x30
333045a5f5SKevin Wells #define LPC32XX_TSC_AUX_UTR			0x34
343045a5f5SKevin Wells #define LPC32XX_TSC_AUX_MIN			0x38
353045a5f5SKevin Wells #define LPC32XX_TSC_AUX_MAX			0x3C
363045a5f5SKevin Wells 
37*4895bfe9Sedison.jiang #define LPC32XX_TSC_STAT_FIFO_OVRRN		BIT(8)
38*4895bfe9Sedison.jiang #define LPC32XX_TSC_STAT_FIFO_EMPTY		BIT(7)
393045a5f5SKevin Wells 
403045a5f5SKevin Wells #define LPC32XX_TSC_SEL_DEFVAL			0x0284
413045a5f5SKevin Wells 
423045a5f5SKevin Wells #define LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4	(0x1 << 11)
433045a5f5SKevin Wells #define LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(s)	((10 - (s)) << 7)
443045a5f5SKevin Wells #define LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(s)	((10 - (s)) << 4)
45*4895bfe9Sedison.jiang #define LPC32XX_TSC_ADCCON_POWER_UP		BIT(2)
46*4895bfe9Sedison.jiang #define LPC32XX_TSC_ADCCON_AUTO_EN		BIT(0)
473045a5f5SKevin Wells 
48*4895bfe9Sedison.jiang #define LPC32XX_TSC_FIFO_TS_P_LEVEL		BIT(31)
493045a5f5SKevin Wells #define LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(x)	(((x) & 0x03FF0000) >> 16)
503045a5f5SKevin Wells #define LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(y)	((y) & 0x000003FF)
513045a5f5SKevin Wells 
523045a5f5SKevin Wells #define LPC32XX_TSC_ADCDAT_VALUE_MASK		0x000003FF
533045a5f5SKevin Wells 
543045a5f5SKevin Wells #define LPC32XX_TSC_MIN_XY_VAL			0x0
553045a5f5SKevin Wells #define LPC32XX_TSC_MAX_XY_VAL			0x3FF
563045a5f5SKevin Wells 
573045a5f5SKevin Wells #define MOD_NAME "ts-lpc32xx"
583045a5f5SKevin Wells 
593045a5f5SKevin Wells #define tsc_readl(dev, reg) \
603045a5f5SKevin Wells 	__raw_readl((dev)->tsc_base + (reg))
613045a5f5SKevin Wells #define tsc_writel(dev, reg, val) \
623045a5f5SKevin Wells 	__raw_writel((val), (dev)->tsc_base + (reg))
633045a5f5SKevin Wells 
643045a5f5SKevin Wells struct lpc32xx_tsc {
653045a5f5SKevin Wells 	struct input_dev *dev;
663045a5f5SKevin Wells 	void __iomem *tsc_base;
673045a5f5SKevin Wells 	int irq;
683045a5f5SKevin Wells 	struct clk *clk;
693045a5f5SKevin Wells };
703045a5f5SKevin Wells 
713045a5f5SKevin Wells static void lpc32xx_fifo_clear(struct lpc32xx_tsc *tsc)
723045a5f5SKevin Wells {
733045a5f5SKevin Wells 	while (!(tsc_readl(tsc, LPC32XX_TSC_STAT) &
743045a5f5SKevin Wells 			LPC32XX_TSC_STAT_FIFO_EMPTY))
753045a5f5SKevin Wells 		tsc_readl(tsc, LPC32XX_TSC_FIFO);
763045a5f5SKevin Wells }
773045a5f5SKevin Wells 
783045a5f5SKevin Wells static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id)
793045a5f5SKevin Wells {
803045a5f5SKevin Wells 	u32 tmp, rv[4], xs[4], ys[4];
813045a5f5SKevin Wells 	int idx;
823045a5f5SKevin Wells 	struct lpc32xx_tsc *tsc = dev_id;
833045a5f5SKevin Wells 	struct input_dev *input = tsc->dev;
843045a5f5SKevin Wells 
853045a5f5SKevin Wells 	tmp = tsc_readl(tsc, LPC32XX_TSC_STAT);
863045a5f5SKevin Wells 
873045a5f5SKevin Wells 	if (tmp & LPC32XX_TSC_STAT_FIFO_OVRRN) {
883045a5f5SKevin Wells 		/* FIFO overflow - throw away samples */
893045a5f5SKevin Wells 		lpc32xx_fifo_clear(tsc);
903045a5f5SKevin Wells 		return IRQ_HANDLED;
913045a5f5SKevin Wells 	}
923045a5f5SKevin Wells 
933045a5f5SKevin Wells 	/*
943045a5f5SKevin Wells 	 * Gather and normalize 4 samples. Pen-up events may have less
953045a5f5SKevin Wells 	 * than 4 samples, but its ok to pop 4 and let the last sample
963045a5f5SKevin Wells 	 * pen status check drop the samples.
973045a5f5SKevin Wells 	 */
983045a5f5SKevin Wells 	idx = 0;
993045a5f5SKevin Wells 	while (idx < 4 &&
1003045a5f5SKevin Wells 	       !(tsc_readl(tsc, LPC32XX_TSC_STAT) &
1013045a5f5SKevin Wells 			LPC32XX_TSC_STAT_FIFO_EMPTY)) {
1023045a5f5SKevin Wells 		tmp = tsc_readl(tsc, LPC32XX_TSC_FIFO);
1033045a5f5SKevin Wells 		xs[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
1043045a5f5SKevin Wells 			LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(tmp);
1053045a5f5SKevin Wells 		ys[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -
1063045a5f5SKevin Wells 			LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(tmp);
1073045a5f5SKevin Wells 		rv[idx] = tmp;
1083045a5f5SKevin Wells 		idx++;
1093045a5f5SKevin Wells 	}
1103045a5f5SKevin Wells 
1113045a5f5SKevin Wells 	/* Data is only valid if pen is still down in last sample */
1123045a5f5SKevin Wells 	if (!(rv[3] & LPC32XX_TSC_FIFO_TS_P_LEVEL) && idx == 4) {
1133045a5f5SKevin Wells 		/* Use average of 2nd and 3rd sample for position */
1143045a5f5SKevin Wells 		input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2);
1153045a5f5SKevin Wells 		input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2);
1163045a5f5SKevin Wells 		input_report_key(input, BTN_TOUCH, 1);
1173045a5f5SKevin Wells 	} else {
1183045a5f5SKevin Wells 		input_report_key(input, BTN_TOUCH, 0);
1193045a5f5SKevin Wells 	}
1203045a5f5SKevin Wells 
1213045a5f5SKevin Wells 	input_sync(input);
1223045a5f5SKevin Wells 
1233045a5f5SKevin Wells 	return IRQ_HANDLED;
1243045a5f5SKevin Wells }
1253045a5f5SKevin Wells 
1263045a5f5SKevin Wells static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)
1273045a5f5SKevin Wells {
1283045a5f5SKevin Wells 	/* Disable auto mode */
1293045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_CON,
1303045a5f5SKevin Wells 		   tsc_readl(tsc, LPC32XX_TSC_CON) &
1313045a5f5SKevin Wells 			     ~LPC32XX_TSC_ADCCON_AUTO_EN);
1323045a5f5SKevin Wells 
13332470060SVladimir Zapolskiy 	clk_disable_unprepare(tsc->clk);
1343045a5f5SKevin Wells }
1353045a5f5SKevin Wells 
13671f9f081SFabio Estevam static int lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)
1373045a5f5SKevin Wells {
1383045a5f5SKevin Wells 	u32 tmp;
13971f9f081SFabio Estevam 	int err;
1403045a5f5SKevin Wells 
14171f9f081SFabio Estevam 	err = clk_prepare_enable(tsc->clk);
14271f9f081SFabio Estevam 	if (err)
14371f9f081SFabio Estevam 		return err;
1443045a5f5SKevin Wells 
1453045a5f5SKevin Wells 	tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;
1463045a5f5SKevin Wells 
1473045a5f5SKevin Wells 	/* Set the TSC FIFO depth to 4 samples @ 10-bits per sample (max) */
1483045a5f5SKevin Wells 	tmp = LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 |
1493045a5f5SKevin Wells 	      LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(10) |
1503045a5f5SKevin Wells 	      LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(10);
1513045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_CON, tmp);
1523045a5f5SKevin Wells 
1533045a5f5SKevin Wells 	/* These values are all preset */
1543045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_SEL, LPC32XX_TSC_SEL_DEFVAL);
1553045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_MIN_X, LPC32XX_TSC_MIN_XY_VAL);
1563045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_MAX_X, LPC32XX_TSC_MAX_XY_VAL);
1573045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_MIN_Y, LPC32XX_TSC_MIN_XY_VAL);
1583045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_MAX_Y, LPC32XX_TSC_MAX_XY_VAL);
1593045a5f5SKevin Wells 
1603045a5f5SKevin Wells 	/* Aux support is not used */
1613045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_AUX_UTR, 0);
1623045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_AUX_MIN, 0);
1633045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_AUX_MAX, 0);
1643045a5f5SKevin Wells 
1653045a5f5SKevin Wells 	/*
1663045a5f5SKevin Wells 	 * Set sample rate to about 240Hz per X/Y pair. A single measurement
1673045a5f5SKevin Wells 	 * consists of 4 pairs which gives about a 60Hz sample rate based on
1683045a5f5SKevin Wells 	 * a stable 32768Hz clock source. Values are in clocks.
1693045a5f5SKevin Wells 	 * Rate is (32768 / (RTR + XCONV + RTR + YCONV + DXP + TTR + UTR) / 4
1703045a5f5SKevin Wells 	 */
1713045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_RTR, 0x2);
1723045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_DTR, 0x2);
1733045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_TTR, 0x10);
1743045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_DXP, 0x4);
1753045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_UTR, 88);
1763045a5f5SKevin Wells 
1773045a5f5SKevin Wells 	lpc32xx_fifo_clear(tsc);
1783045a5f5SKevin Wells 
1793045a5f5SKevin Wells 	/* Enable automatic ts event capture */
1803045a5f5SKevin Wells 	tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN);
18171f9f081SFabio Estevam 
18271f9f081SFabio Estevam 	return 0;
1833045a5f5SKevin Wells }
1843045a5f5SKevin Wells 
1853045a5f5SKevin Wells static int lpc32xx_ts_open(struct input_dev *dev)
1863045a5f5SKevin Wells {
1873045a5f5SKevin Wells 	struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
1883045a5f5SKevin Wells 
18971f9f081SFabio Estevam 	return lpc32xx_setup_tsc(tsc);
1903045a5f5SKevin Wells }
1913045a5f5SKevin Wells 
1923045a5f5SKevin Wells static void lpc32xx_ts_close(struct input_dev *dev)
1933045a5f5SKevin Wells {
1943045a5f5SKevin Wells 	struct lpc32xx_tsc *tsc = input_get_drvdata(dev);
1953045a5f5SKevin Wells 
1963045a5f5SKevin Wells 	lpc32xx_stop_tsc(tsc);
1973045a5f5SKevin Wells }
1983045a5f5SKevin Wells 
1995298cc4cSBill Pemberton static int lpc32xx_ts_probe(struct platform_device *pdev)
2003045a5f5SKevin Wells {
2013045a5f5SKevin Wells 	struct lpc32xx_tsc *tsc;
2023045a5f5SKevin Wells 	struct input_dev *input;
2033045a5f5SKevin Wells 	struct resource *res;
2043045a5f5SKevin Wells 	resource_size_t size;
2053045a5f5SKevin Wells 	int irq;
2063045a5f5SKevin Wells 	int error;
2073045a5f5SKevin Wells 
2083045a5f5SKevin Wells 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2093045a5f5SKevin Wells 	if (!res) {
2103045a5f5SKevin Wells 		dev_err(&pdev->dev, "Can't get memory resource\n");
2113045a5f5SKevin Wells 		return -ENOENT;
2123045a5f5SKevin Wells 	}
2133045a5f5SKevin Wells 
2143045a5f5SKevin Wells 	irq = platform_get_irq(pdev, 0);
2150bec8b7eSStephen Boyd 	if (irq < 0)
2163045a5f5SKevin Wells 		return irq;
2173045a5f5SKevin Wells 
2183045a5f5SKevin Wells 	tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
2193045a5f5SKevin Wells 	input = input_allocate_device();
2203045a5f5SKevin Wells 	if (!tsc || !input) {
2213045a5f5SKevin Wells 		dev_err(&pdev->dev, "failed allocating memory\n");
2223045a5f5SKevin Wells 		error = -ENOMEM;
2233045a5f5SKevin Wells 		goto err_free_mem;
2243045a5f5SKevin Wells 	}
2253045a5f5SKevin Wells 
2263045a5f5SKevin Wells 	tsc->dev = input;
2273045a5f5SKevin Wells 	tsc->irq = irq;
2283045a5f5SKevin Wells 
2293045a5f5SKevin Wells 	size = resource_size(res);
2303045a5f5SKevin Wells 
2313045a5f5SKevin Wells 	if (!request_mem_region(res->start, size, pdev->name)) {
2323045a5f5SKevin Wells 		dev_err(&pdev->dev, "TSC registers are not free\n");
2333045a5f5SKevin Wells 		error = -EBUSY;
2343045a5f5SKevin Wells 		goto err_free_mem;
2353045a5f5SKevin Wells 	}
2363045a5f5SKevin Wells 
2373045a5f5SKevin Wells 	tsc->tsc_base = ioremap(res->start, size);
2383045a5f5SKevin Wells 	if (!tsc->tsc_base) {
2393045a5f5SKevin Wells 		dev_err(&pdev->dev, "Can't map memory\n");
2403045a5f5SKevin Wells 		error = -ENOMEM;
2413045a5f5SKevin Wells 		goto err_release_mem;
2423045a5f5SKevin Wells 	}
2433045a5f5SKevin Wells 
2443045a5f5SKevin Wells 	tsc->clk = clk_get(&pdev->dev, NULL);
2453045a5f5SKevin Wells 	if (IS_ERR(tsc->clk)) {
2463045a5f5SKevin Wells 		dev_err(&pdev->dev, "failed getting clock\n");
2473045a5f5SKevin Wells 		error = PTR_ERR(tsc->clk);
2483045a5f5SKevin Wells 		goto err_unmap;
2493045a5f5SKevin Wells 	}
2503045a5f5SKevin Wells 
2513045a5f5SKevin Wells 	input->name = MOD_NAME;
2523045a5f5SKevin Wells 	input->phys = "lpc32xx/input0";
2533045a5f5SKevin Wells 	input->id.bustype = BUS_HOST;
2543045a5f5SKevin Wells 	input->id.vendor = 0x0001;
2553045a5f5SKevin Wells 	input->id.product = 0x0002;
2563045a5f5SKevin Wells 	input->id.version = 0x0100;
2573045a5f5SKevin Wells 	input->dev.parent = &pdev->dev;
2583045a5f5SKevin Wells 	input->open = lpc32xx_ts_open;
2593045a5f5SKevin Wells 	input->close = lpc32xx_ts_close;
2603045a5f5SKevin Wells 
2613045a5f5SKevin Wells 	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
2623045a5f5SKevin Wells 	input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
2633045a5f5SKevin Wells 	input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,
2643045a5f5SKevin Wells 			     LPC32XX_TSC_MAX_XY_VAL, 0, 0);
2653045a5f5SKevin Wells 	input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,
2663045a5f5SKevin Wells 			     LPC32XX_TSC_MAX_XY_VAL, 0, 0);
2673045a5f5SKevin Wells 
2683045a5f5SKevin Wells 	input_set_drvdata(input, tsc);
2693045a5f5SKevin Wells 
2703045a5f5SKevin Wells 	error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
271ec4665c4SYong Zhang 			    0, pdev->name, tsc);
2723045a5f5SKevin Wells 	if (error) {
2733045a5f5SKevin Wells 		dev_err(&pdev->dev, "failed requesting interrupt\n");
2743045a5f5SKevin Wells 		goto err_put_clock;
2753045a5f5SKevin Wells 	}
2763045a5f5SKevin Wells 
2773045a5f5SKevin Wells 	error = input_register_device(input);
2783045a5f5SKevin Wells 	if (error) {
2793045a5f5SKevin Wells 		dev_err(&pdev->dev, "failed registering input device\n");
2803045a5f5SKevin Wells 		goto err_free_irq;
2813045a5f5SKevin Wells 	}
2823045a5f5SKevin Wells 
2833045a5f5SKevin Wells 	platform_set_drvdata(pdev, tsc);
2843045a5f5SKevin Wells 	device_init_wakeup(&pdev->dev, 1);
2853045a5f5SKevin Wells 
2863045a5f5SKevin Wells 	return 0;
2873045a5f5SKevin Wells 
2883045a5f5SKevin Wells err_free_irq:
2893045a5f5SKevin Wells 	free_irq(tsc->irq, tsc);
2903045a5f5SKevin Wells err_put_clock:
2913045a5f5SKevin Wells 	clk_put(tsc->clk);
2923045a5f5SKevin Wells err_unmap:
2933045a5f5SKevin Wells 	iounmap(tsc->tsc_base);
2943045a5f5SKevin Wells err_release_mem:
2953045a5f5SKevin Wells 	release_mem_region(res->start, size);
2963045a5f5SKevin Wells err_free_mem:
2973045a5f5SKevin Wells 	input_free_device(input);
2983045a5f5SKevin Wells 	kfree(tsc);
2993045a5f5SKevin Wells 
3003045a5f5SKevin Wells 	return error;
3013045a5f5SKevin Wells }
3023045a5f5SKevin Wells 
303e2619cf7SBill Pemberton static int lpc32xx_ts_remove(struct platform_device *pdev)
3043045a5f5SKevin Wells {
3053045a5f5SKevin Wells 	struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
3063045a5f5SKevin Wells 	struct resource *res;
3073045a5f5SKevin Wells 
3083045a5f5SKevin Wells 	free_irq(tsc->irq, tsc);
3093045a5f5SKevin Wells 
3103045a5f5SKevin Wells 	input_unregister_device(tsc->dev);
3113045a5f5SKevin Wells 
3123045a5f5SKevin Wells 	clk_put(tsc->clk);
3133045a5f5SKevin Wells 
3143045a5f5SKevin Wells 	iounmap(tsc->tsc_base);
3153045a5f5SKevin Wells 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3163045a5f5SKevin Wells 	release_mem_region(res->start, resource_size(res));
3173045a5f5SKevin Wells 
3183045a5f5SKevin Wells 	kfree(tsc);
3193045a5f5SKevin Wells 
3203045a5f5SKevin Wells 	return 0;
3213045a5f5SKevin Wells }
3223045a5f5SKevin Wells 
3233045a5f5SKevin Wells #ifdef CONFIG_PM
3243045a5f5SKevin Wells static int lpc32xx_ts_suspend(struct device *dev)
3253045a5f5SKevin Wells {
3263045a5f5SKevin Wells 	struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
3273045a5f5SKevin Wells 	struct input_dev *input = tsc->dev;
3283045a5f5SKevin Wells 
3293045a5f5SKevin Wells 	/*
3303045a5f5SKevin Wells 	 * Suspend and resume can be called when the device hasn't been
3313045a5f5SKevin Wells 	 * enabled. If there are no users that have the device open, then
3323045a5f5SKevin Wells 	 * avoid calling the TSC stop and start functions as the TSC
3333045a5f5SKevin Wells 	 * isn't yet clocked.
3343045a5f5SKevin Wells 	 */
3353045a5f5SKevin Wells 	mutex_lock(&input->mutex);
3363045a5f5SKevin Wells 
337d69f0a43SAndrzej Pietrasiewicz 	if (input_device_enabled(input)) {
3383045a5f5SKevin Wells 		if (device_may_wakeup(dev))
3393045a5f5SKevin Wells 			enable_irq_wake(tsc->irq);
3403045a5f5SKevin Wells 		else
3413045a5f5SKevin Wells 			lpc32xx_stop_tsc(tsc);
3423045a5f5SKevin Wells 	}
3433045a5f5SKevin Wells 
3443045a5f5SKevin Wells 	mutex_unlock(&input->mutex);
3453045a5f5SKevin Wells 
3463045a5f5SKevin Wells 	return 0;
3473045a5f5SKevin Wells }
3483045a5f5SKevin Wells 
3493045a5f5SKevin Wells static int lpc32xx_ts_resume(struct device *dev)
3503045a5f5SKevin Wells {
3513045a5f5SKevin Wells 	struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
3523045a5f5SKevin Wells 	struct input_dev *input = tsc->dev;
3533045a5f5SKevin Wells 
3543045a5f5SKevin Wells 	mutex_lock(&input->mutex);
3553045a5f5SKevin Wells 
356d69f0a43SAndrzej Pietrasiewicz 	if (input_device_enabled(input)) {
3573045a5f5SKevin Wells 		if (device_may_wakeup(dev))
3583045a5f5SKevin Wells 			disable_irq_wake(tsc->irq);
3593045a5f5SKevin Wells 		else
3603045a5f5SKevin Wells 			lpc32xx_setup_tsc(tsc);
3613045a5f5SKevin Wells 	}
3623045a5f5SKevin Wells 
3633045a5f5SKevin Wells 	mutex_unlock(&input->mutex);
3643045a5f5SKevin Wells 
3653045a5f5SKevin Wells 	return 0;
3663045a5f5SKevin Wells }
3673045a5f5SKevin Wells 
3683045a5f5SKevin Wells static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
3693045a5f5SKevin Wells 	.suspend	= lpc32xx_ts_suspend,
3703045a5f5SKevin Wells 	.resume		= lpc32xx_ts_resume,
3713045a5f5SKevin Wells };
3723045a5f5SKevin Wells #define LPC32XX_TS_PM_OPS (&lpc32xx_ts_pm_ops)
3733045a5f5SKevin Wells #else
3743045a5f5SKevin Wells #define LPC32XX_TS_PM_OPS NULL
3753045a5f5SKevin Wells #endif
3763045a5f5SKevin Wells 
3775cb727a8SRoland Stigge #ifdef CONFIG_OF
378f23e0abdSJingoo Han static const struct of_device_id lpc32xx_tsc_of_match[] = {
37934604086SRoland Stigge 	{ .compatible = "nxp,lpc3220-tsc", },
3805cb727a8SRoland Stigge 	{ },
3815cb727a8SRoland Stigge };
3825cb727a8SRoland Stigge MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
3835cb727a8SRoland Stigge #endif
3845cb727a8SRoland Stigge 
3853045a5f5SKevin Wells static struct platform_driver lpc32xx_ts_driver = {
3863045a5f5SKevin Wells 	.probe		= lpc32xx_ts_probe,
3871cb0aa88SBill Pemberton 	.remove		= lpc32xx_ts_remove,
3883045a5f5SKevin Wells 	.driver		= {
3893045a5f5SKevin Wells 		.name	= MOD_NAME,
3903045a5f5SKevin Wells 		.pm	= LPC32XX_TS_PM_OPS,
3915cb727a8SRoland Stigge 		.of_match_table = of_match_ptr(lpc32xx_tsc_of_match),
3923045a5f5SKevin Wells 	},
3933045a5f5SKevin Wells };
394cdcc96e2SJJ Ding module_platform_driver(lpc32xx_ts_driver);
3953045a5f5SKevin Wells 
3963045a5f5SKevin Wells MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com");
3973045a5f5SKevin Wells MODULE_DESCRIPTION("LPC32XX TSC Driver");
3983045a5f5SKevin Wells MODULE_LICENSE("GPL");
3993045a5f5SKevin Wells MODULE_ALIAS("platform:lpc32xx_ts");
400