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