Path: blob/master/drivers/input/touchscreen/lpc32xx_ts.c
15112 views
/*1* LPC32xx built-in touchscreen driver2*3* Copyright (C) 2010 NXP Semiconductors4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*/1516#include <linux/platform_device.h>17#include <linux/init.h>18#include <linux/input.h>19#include <linux/interrupt.h>20#include <linux/module.h>21#include <linux/clk.h>22#include <linux/io.h>23#include <linux/slab.h>2425/*26* Touchscreen controller register offsets27*/28#define LPC32XX_TSC_STAT 0x0029#define LPC32XX_TSC_SEL 0x0430#define LPC32XX_TSC_CON 0x0831#define LPC32XX_TSC_FIFO 0x0C32#define LPC32XX_TSC_DTR 0x1033#define LPC32XX_TSC_RTR 0x1434#define LPC32XX_TSC_UTR 0x1835#define LPC32XX_TSC_TTR 0x1C36#define LPC32XX_TSC_DXP 0x2037#define LPC32XX_TSC_MIN_X 0x2438#define LPC32XX_TSC_MAX_X 0x2839#define LPC32XX_TSC_MIN_Y 0x2C40#define LPC32XX_TSC_MAX_Y 0x3041#define LPC32XX_TSC_AUX_UTR 0x3442#define LPC32XX_TSC_AUX_MIN 0x3843#define LPC32XX_TSC_AUX_MAX 0x3C4445#define LPC32XX_TSC_STAT_FIFO_OVRRN (1 << 8)46#define LPC32XX_TSC_STAT_FIFO_EMPTY (1 << 7)4748#define LPC32XX_TSC_SEL_DEFVAL 0x02844950#define LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 (0x1 << 11)51#define LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(s) ((10 - (s)) << 7)52#define LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(s) ((10 - (s)) << 4)53#define LPC32XX_TSC_ADCCON_POWER_UP (1 << 2)54#define LPC32XX_TSC_ADCCON_AUTO_EN (1 << 0)5556#define LPC32XX_TSC_FIFO_TS_P_LEVEL (1 << 31)57#define LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(x) (((x) & 0x03FF0000) >> 16)58#define LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(y) ((y) & 0x000003FF)5960#define LPC32XX_TSC_ADCDAT_VALUE_MASK 0x000003FF6162#define LPC32XX_TSC_MIN_XY_VAL 0x063#define LPC32XX_TSC_MAX_XY_VAL 0x3FF6465#define MOD_NAME "ts-lpc32xx"6667#define tsc_readl(dev, reg) \68__raw_readl((dev)->tsc_base + (reg))69#define tsc_writel(dev, reg, val) \70__raw_writel((val), (dev)->tsc_base + (reg))7172struct lpc32xx_tsc {73struct input_dev *dev;74void __iomem *tsc_base;75int irq;76struct clk *clk;77};7879static void lpc32xx_fifo_clear(struct lpc32xx_tsc *tsc)80{81while (!(tsc_readl(tsc, LPC32XX_TSC_STAT) &82LPC32XX_TSC_STAT_FIFO_EMPTY))83tsc_readl(tsc, LPC32XX_TSC_FIFO);84}8586static irqreturn_t lpc32xx_ts_interrupt(int irq, void *dev_id)87{88u32 tmp, rv[4], xs[4], ys[4];89int idx;90struct lpc32xx_tsc *tsc = dev_id;91struct input_dev *input = tsc->dev;9293tmp = tsc_readl(tsc, LPC32XX_TSC_STAT);9495if (tmp & LPC32XX_TSC_STAT_FIFO_OVRRN) {96/* FIFO overflow - throw away samples */97lpc32xx_fifo_clear(tsc);98return IRQ_HANDLED;99}100101/*102* Gather and normalize 4 samples. Pen-up events may have less103* than 4 samples, but its ok to pop 4 and let the last sample104* pen status check drop the samples.105*/106idx = 0;107while (idx < 4 &&108!(tsc_readl(tsc, LPC32XX_TSC_STAT) &109LPC32XX_TSC_STAT_FIFO_EMPTY)) {110tmp = tsc_readl(tsc, LPC32XX_TSC_FIFO);111xs[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -112LPC32XX_TSC_FIFO_NORMALIZE_X_VAL(tmp);113ys[idx] = LPC32XX_TSC_ADCDAT_VALUE_MASK -114LPC32XX_TSC_FIFO_NORMALIZE_Y_VAL(tmp);115rv[idx] = tmp;116idx++;117}118119/* Data is only valid if pen is still down in last sample */120if (!(rv[3] & LPC32XX_TSC_FIFO_TS_P_LEVEL) && idx == 4) {121/* Use average of 2nd and 3rd sample for position */122input_report_abs(input, ABS_X, (xs[1] + xs[2]) / 2);123input_report_abs(input, ABS_Y, (ys[1] + ys[2]) / 2);124input_report_key(input, BTN_TOUCH, 1);125} else {126input_report_key(input, BTN_TOUCH, 0);127}128129input_sync(input);130131return IRQ_HANDLED;132}133134static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc)135{136/* Disable auto mode */137tsc_writel(tsc, LPC32XX_TSC_CON,138tsc_readl(tsc, LPC32XX_TSC_CON) &139~LPC32XX_TSC_ADCCON_AUTO_EN);140141clk_disable(tsc->clk);142}143144static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc)145{146u32 tmp;147148clk_enable(tsc->clk);149150tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP;151152/* Set the TSC FIFO depth to 4 samples @ 10-bits per sample (max) */153tmp = LPC32XX_TSC_ADCCON_IRQ_TO_FIFO_4 |154LPC32XX_TSC_ADCCON_X_SAMPLE_SIZE(10) |155LPC32XX_TSC_ADCCON_Y_SAMPLE_SIZE(10);156tsc_writel(tsc, LPC32XX_TSC_CON, tmp);157158/* These values are all preset */159tsc_writel(tsc, LPC32XX_TSC_SEL, LPC32XX_TSC_SEL_DEFVAL);160tsc_writel(tsc, LPC32XX_TSC_MIN_X, LPC32XX_TSC_MIN_XY_VAL);161tsc_writel(tsc, LPC32XX_TSC_MAX_X, LPC32XX_TSC_MAX_XY_VAL);162tsc_writel(tsc, LPC32XX_TSC_MIN_Y, LPC32XX_TSC_MIN_XY_VAL);163tsc_writel(tsc, LPC32XX_TSC_MAX_Y, LPC32XX_TSC_MAX_XY_VAL);164165/* Aux support is not used */166tsc_writel(tsc, LPC32XX_TSC_AUX_UTR, 0);167tsc_writel(tsc, LPC32XX_TSC_AUX_MIN, 0);168tsc_writel(tsc, LPC32XX_TSC_AUX_MAX, 0);169170/*171* Set sample rate to about 240Hz per X/Y pair. A single measurement172* consists of 4 pairs which gives about a 60Hz sample rate based on173* a stable 32768Hz clock source. Values are in clocks.174* Rate is (32768 / (RTR + XCONV + RTR + YCONV + DXP + TTR + UTR) / 4175*/176tsc_writel(tsc, LPC32XX_TSC_RTR, 0x2);177tsc_writel(tsc, LPC32XX_TSC_DTR, 0x2);178tsc_writel(tsc, LPC32XX_TSC_TTR, 0x10);179tsc_writel(tsc, LPC32XX_TSC_DXP, 0x4);180tsc_writel(tsc, LPC32XX_TSC_UTR, 88);181182lpc32xx_fifo_clear(tsc);183184/* Enable automatic ts event capture */185tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN);186}187188static int lpc32xx_ts_open(struct input_dev *dev)189{190struct lpc32xx_tsc *tsc = input_get_drvdata(dev);191192lpc32xx_setup_tsc(tsc);193194return 0;195}196197static void lpc32xx_ts_close(struct input_dev *dev)198{199struct lpc32xx_tsc *tsc = input_get_drvdata(dev);200201lpc32xx_stop_tsc(tsc);202}203204static int __devinit lpc32xx_ts_probe(struct platform_device *pdev)205{206struct lpc32xx_tsc *tsc;207struct input_dev *input;208struct resource *res;209resource_size_t size;210int irq;211int error;212213res = platform_get_resource(pdev, IORESOURCE_MEM, 0);214if (!res) {215dev_err(&pdev->dev, "Can't get memory resource\n");216return -ENOENT;217}218219irq = platform_get_irq(pdev, 0);220if (irq < 0) {221dev_err(&pdev->dev, "Can't get interrupt resource\n");222return irq;223}224225tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);226input = input_allocate_device();227if (!tsc || !input) {228dev_err(&pdev->dev, "failed allocating memory\n");229error = -ENOMEM;230goto err_free_mem;231}232233tsc->dev = input;234tsc->irq = irq;235236size = resource_size(res);237238if (!request_mem_region(res->start, size, pdev->name)) {239dev_err(&pdev->dev, "TSC registers are not free\n");240error = -EBUSY;241goto err_free_mem;242}243244tsc->tsc_base = ioremap(res->start, size);245if (!tsc->tsc_base) {246dev_err(&pdev->dev, "Can't map memory\n");247error = -ENOMEM;248goto err_release_mem;249}250251tsc->clk = clk_get(&pdev->dev, NULL);252if (IS_ERR(tsc->clk)) {253dev_err(&pdev->dev, "failed getting clock\n");254error = PTR_ERR(tsc->clk);255goto err_unmap;256}257258input->name = MOD_NAME;259input->phys = "lpc32xx/input0";260input->id.bustype = BUS_HOST;261input->id.vendor = 0x0001;262input->id.product = 0x0002;263input->id.version = 0x0100;264input->dev.parent = &pdev->dev;265input->open = lpc32xx_ts_open;266input->close = lpc32xx_ts_close;267268input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);269input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);270input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,271LPC32XX_TSC_MAX_XY_VAL, 0, 0);272input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,273LPC32XX_TSC_MAX_XY_VAL, 0, 0);274275input_set_drvdata(input, tsc);276277error = request_irq(tsc->irq, lpc32xx_ts_interrupt,278IRQF_DISABLED, pdev->name, tsc);279if (error) {280dev_err(&pdev->dev, "failed requesting interrupt\n");281goto err_put_clock;282}283284error = input_register_device(input);285if (error) {286dev_err(&pdev->dev, "failed registering input device\n");287goto err_free_irq;288}289290platform_set_drvdata(pdev, tsc);291device_init_wakeup(&pdev->dev, 1);292293return 0;294295err_free_irq:296free_irq(tsc->irq, tsc);297err_put_clock:298clk_put(tsc->clk);299err_unmap:300iounmap(tsc->tsc_base);301err_release_mem:302release_mem_region(res->start, size);303err_free_mem:304input_free_device(input);305kfree(tsc);306307return error;308}309310static int __devexit lpc32xx_ts_remove(struct platform_device *pdev)311{312struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);313struct resource *res;314315device_init_wakeup(&pdev->dev, 0);316free_irq(tsc->irq, tsc);317318input_unregister_device(tsc->dev);319320clk_put(tsc->clk);321322iounmap(tsc->tsc_base);323res = platform_get_resource(pdev, IORESOURCE_MEM, 0);324release_mem_region(res->start, resource_size(res));325326kfree(tsc);327328return 0;329}330331#ifdef CONFIG_PM332static int lpc32xx_ts_suspend(struct device *dev)333{334struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);335struct input_dev *input = tsc->dev;336337/*338* Suspend and resume can be called when the device hasn't been339* enabled. If there are no users that have the device open, then340* avoid calling the TSC stop and start functions as the TSC341* isn't yet clocked.342*/343mutex_lock(&input->mutex);344345if (input->users) {346if (device_may_wakeup(dev))347enable_irq_wake(tsc->irq);348else349lpc32xx_stop_tsc(tsc);350}351352mutex_unlock(&input->mutex);353354return 0;355}356357static int lpc32xx_ts_resume(struct device *dev)358{359struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);360struct input_dev *input = tsc->dev;361362mutex_lock(&input->mutex);363364if (input->users) {365if (device_may_wakeup(dev))366disable_irq_wake(tsc->irq);367else368lpc32xx_setup_tsc(tsc);369}370371mutex_unlock(&input->mutex);372373return 0;374}375376static const struct dev_pm_ops lpc32xx_ts_pm_ops = {377.suspend = lpc32xx_ts_suspend,378.resume = lpc32xx_ts_resume,379};380#define LPC32XX_TS_PM_OPS (&lpc32xx_ts_pm_ops)381#else382#define LPC32XX_TS_PM_OPS NULL383#endif384385static struct platform_driver lpc32xx_ts_driver = {386.probe = lpc32xx_ts_probe,387.remove = __devexit_p(lpc32xx_ts_remove),388.driver = {389.name = MOD_NAME,390.owner = THIS_MODULE,391.pm = LPC32XX_TS_PM_OPS,392},393};394395static int __init lpc32xx_ts_init(void)396{397return platform_driver_register(&lpc32xx_ts_driver);398}399module_init(lpc32xx_ts_init);400401static void __exit lpc32xx_ts_exit(void)402{403platform_driver_unregister(&lpc32xx_ts_driver);404}405module_exit(lpc32xx_ts_exit);406407MODULE_AUTHOR("Kevin Wells <[email protected]");408MODULE_DESCRIPTION("LPC32XX TSC Driver");409MODULE_LICENSE("GPL");410MODULE_ALIAS("platform:lpc32xx_ts");411412413