* [PATCH V2] input: add support for TI Touchscreen controller.
@ 2011-07-14 5:02 Patil, Rachna
2011-07-20 13:12 ` Patil, Rachna
0 siblings, 1 reply; 10+ messages in thread
From: Patil, Rachna @ 2011-07-14 5:02 UTC (permalink / raw)
To: linux-input; +Cc: Dmitry Torokhov, Dmitry Torokhov, Patil, Rachna
This patch adds support for TI's touchscreen
controller for a 4/5/8 wire resistive panel
that is directly fed to the ADC.
This touchscreen controller will be part of
an upcoming TI SoC and has been tested on
an emulation platform.
ChangeLog:
v2: fixed comments from Dmitry
Signed-off-by: Patil, Rachna <rachna@ti.com>
---
drivers/input/touchscreen/Kconfig | 11 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/ti_tscadc.c | 431 +++++++++++++++++++++++++++++++++
include/linux/input/ti_tscadc.h | 10 +
4 files changed, 453 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/touchscreen/ti_tscadc.c
create mode 100644 include/linux/input/ti_tscadc.h
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 44589f5..7d976d7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -395,6 +395,17 @@ config TOUCHSCREEN_TOUCHWIN
To compile this driver as a module, choose M here: the
module will be called touchwin.
+config TOUCHSCREEN_TI_TSCADC
+ tristate "TI Touchscreen Interface"
+ help
+ Say Y here if you have 4/5/8 wire touchscreen controller
+ to be connected to the ADC controller on your TI SoC.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ti_tscadc.
+
config TOUCHSCREEN_ATMEL_TSADCC
tristate "Atmel Touchscreen Interface"
depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 51b08b0..86b7ab6 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c
new file mode 100644
index 0000000..86264fc
--- /dev/null
+++ b/drivers/input/touchscreen/ti_tscadc.c
@@ -0,0 +1,431 @@
+/*
+ * TI Touch Screen driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/input/ti_tscadc.h>
+
+#define TSCADC_REG_IRQEOI 0x020
+#define TSCADC_REG_IRQSTATUS 0x028
+#define TSCADC_REG_IRQENABLE 0x02C
+#define TSCADC_REG_IRQWAKEUP 0x034
+#define TSCADC_REG_CTRL 0x040
+#define TSCADC_REG_ADCFSM 0x044
+#define TSCADC_REG_CLKDIV 0x04C
+#define TSCADC_REG_SE 0x054
+#define TSCADC_REG_IDLECONFIG 0x058
+#define TSCADC_REG_CHARGECONFIG 0x05C
+#define TSCADC_REG_STEPCONFIG1 0x064
+#define TSCADC_REG_STEPDELAY1 0x068
+#define TSCADC_REG_STEPCONFIG2 0x06C
+#define TSCADC_REG_STEPDELAY2 0x070
+#define TSCADC_REG_FIFO0 0x100
+
+/* Register Bitfields */
+#define TSCADC_IRQWKUP_ENB BIT(0)
+#define TSCADC_STPENB_STEPENB (7 << 0)
+#define TSCADC_IRQENB_IRQHWPEN BIT(10)
+#define TSCADC_IRQENB_IRQEOS BIT(1)
+#define TSCADC_IRQENB_FIFO_OVERFLOW BIT(3)
+#define TSCADC_IRQENB_PENUP BIT(9)
+#define TSCADC_STEPCONFIG_MODE_HWSYNC 0x3
+#define TSCADC_STEPCONFIG_2SAMPLES_AVG BIT(2)
+#define TSCADC_STEPCONFIG_XPP BIT(5)
+#define TSCADC_STEPCONFIG_XNN BIT(6)
+#define TSCADC_STEPCONFIG_YPP BIT(7)
+#define TSCADC_STEPCONFIG_YNN BIT(8)
+#define TSCADC_STEPCONFIG_XNP BIT(9)
+#define TSCADC_STEPCONFIG_YPN BIT(10)
+#define TSCADC_STEPCONFIG_RFP_X (1 << 12)
+#define TSCADC_STEPCONFIG_RFP_4_Y (1 << 13)
+#define TSCADC_STEPCONFIG_RFP_5_Y (1 << 12)
+#define TSCADC_STEPCONFIG_RFP_8_Y (1 << 13)
+#define TSCADC_STEPCONFIG_INM (1 << 18)
+#define TSCADC_STEPCONFIG_INP_4 (1 << 20)
+#define TSCADC_STEPCONFIG_INP_5 (1 << 21)
+#define TSCADC_STEPCONFIG_INP_8_X (3 << 20)
+#define TSCADC_STEPCONFIG_INP_8_Y (1 << 21)
+#define TSCADC_STEPCONFIG_RFM_4_X (1 << 23)
+#define TSCADC_STEPCONFIG_RFM_5_X (1 << 24)
+#define TSCADC_STEPCONFIG_RFM_8_X (1 << 23)
+#define TSCADC_STEPCONFIG_RFM_Y (1 << 24)
+#define TSCADC_STEPCONFIG_OPENDLY (0xf << 0)
+#define TSCADC_STEPCONFIG_SAMPLEDLY BIT(25)
+#define TSCADC_STEPCHARGE_INM BIT(18)
+#define TSCADC_STEPCHARGE_RFM (3 << 23)
+#define TSCADC_CNTRLREG_TSCSSENB BIT(0)
+#define TSCADC_CNTRLREG_STEPID BIT(1)
+#define TSCADC_CNTRLREG_STEPCONFIGWRT BIT(2)
+#define TSCADC_CNTRLREG_TSCENB BIT(7)
+#define TSCADC_CNTRLREG_4WIRE (0x1 << 5)
+#define TSCADC_CNTRLREG_5WIRE (0x1 << 6)
+#define TSCADC_CNTRLREG_8WIRE (0x3 << 5)
+#define TSCADC_ADCFSM_STEPID 0x10
+#define TSCADC_ADCFSM_FSM BIT(5)
+
+#define ADC_CLK 3000000
+
+#define MAX_12BIT ((1 << 12) - 1)
+
+struct tscadc {
+ struct input_dev *input;
+ int wires;
+ struct clk *clk;
+ int irq;
+ void __iomem *tsc_base;
+};
+
+static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
+{
+ return readl(ts->tsc_base + reg);
+}
+
+static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
+ unsigned int val)
+{
+ writel(val, tsc->tsc_base + reg);
+}
+
+static void tsc_step_config(struct tscadc *ts_dev)
+{
+ int stepconfig1, stepconfig2, delay;
+
+ /* Configure the Step registers */
+ stepconfig1 = TSCADC_STEPCONFIG_MODE_HWSYNC |
+ TSCADC_STEPCONFIG_2SAMPLES_AVG | TSCADC_STEPCONFIG_XPP |
+ TSCADC_STEPCONFIG_XNN | TSCADC_STEPCONFIG_INM |
+ TSCADC_STEPCONFIG_RFP_X;
+
+ stepconfig2 = TSCADC_STEPCONFIG_MODE_HWSYNC |
+ TSCADC_STEPCONFIG_2SAMPLES_AVG | TSCADC_STEPCONFIG_YNN |
+ TSCADC_STEPCONFIG_INM | TSCADC_STEPCONFIG_RFM_Y;
+ switch (ts_dev->wires) {
+ case 4:
+ stepconfig1 |= TSCADC_STEPCONFIG_INP_4 |
+ TSCADC_STEPCONFIG_RFM_4_X;
+
+ stepconfig2 |= TSCADC_STEPCONFIG_YPP |
+ TSCADC_STEPCONFIG_RFP_4_Y;
+ break;
+ case 5:
+ stepconfig1 |= TSCADC_STEPCONFIG_YPP |
+ TSCADC_STEPCONFIG_YNN |
+ TSCADC_STEPCONFIG_INP_5 |
+ TSCADC_STEPCONFIG_RFM_5_X;
+
+ stepconfig2 |= TSCADC_STEPCONFIG_XPP |
+ TSCADC_STEPCONFIG_XNP |
+ TSCADC_STEPCONFIG_YPN |
+ TSCADC_STEPCONFIG_RFP_5_Y |
+ TSCADC_STEPCONFIG_INP_5;
+ break;
+ case 8:
+ stepconfig1 |= TSCADC_STEPCONFIG_INP_8_X |
+ TSCADC_STEPCONFIG_RFM_8_X;
+
+ stepconfig2 |= TSCADC_STEPCONFIG_YPP |
+ TSCADC_STEPCONFIG_RFP_8_Y |
+ TSCADC_STEPCONFIG_INP_8_Y;
+ break;
+ }
+ delay = TSCADC_STEPCONFIG_OPENDLY | TSCADC_STEPCONFIG_SAMPLEDLY;
+
+ tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG1, stepconfig1);
+ tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY1, delay);
+ tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG2, stepconfig2);
+ tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY2, delay);
+
+ tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB);
+}
+
+static void tsc_idle_config(struct tscadc *ts_config)
+{
+ /* Idle mode touch screen config */
+ unsigned int idleconfig;
+
+ idleconfig = TSCADC_STEPCONFIG_YNN |
+ TSCADC_STEPCONFIG_RFP_X |
+ TSCADC_STEPCONFIG_INM ;
+
+ switch (ts_config->wires) {
+ case 4:
+ idleconfig |= TSCADC_STEPCONFIG_INP_4 |
+ TSCADC_STEPCONFIG_RFM_4_X;
+ break;
+ case 5:
+ idleconfig |= TSCADC_STEPCONFIG_INP_5 |
+ TSCADC_STEPCONFIG_RFM_5_X;
+ break;
+ case 8:
+ idleconfig |= TSCADC_STEPCONFIG_INP_4 |
+ TSCADC_STEPCONFIG_RFM_8_X;
+ break;
+ }
+ tscadc_writel(ts_config, TSCADC_REG_IDLECONFIG, idleconfig);
+}
+
+static irqreturn_t tscadc_interrupt(int irq, void *dev)
+{
+ struct tscadc *ts_dev = (struct tscadc *)dev;
+ struct input_dev *input_dev = ts_dev->input;
+ unsigned int status, store, cntrlreg, irqclr = 0;
+ int absx, absy;
+ int charge, fsm;
+
+ status = tscadc_readl(ts_dev, TSCADC_REG_IRQSTATUS);
+ tscadc_writel(ts_dev, TSCADC_REG_SE, 0x0);
+
+ /* Pen touch event */
+ if (status & TSCADC_IRQENB_IRQHWPEN)
+ irqclr = TSCADC_IRQENB_IRQHWPEN;
+
+ if (status & TSCADC_IRQENB_PENUP) {
+ /* Pen up event */
+ charge = TSCADC_STEPCHARGE_INM | TSCADC_STEPCHARGE_RFM;
+ tscadc_writel(ts_dev, TSCADC_REG_CHARGECONFIG, charge);
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_sync(input_dev);
+ tsc_idle_config(ts_dev);
+ irqclr |= TSCADC_IRQENB_PENUP;
+
+ }
+ if (status & TSCADC_IRQENB_IRQEOS) {
+ /* ADC is done with sampling, ready to read the data */
+ absx = tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
+ absy = tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
+
+ input_report_abs(input_dev, ABS_X, absx);
+ input_report_abs(input_dev, ABS_Y, absy);
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ input_sync(input_dev);
+
+ irqclr |= TSCADC_IRQENB_IRQEOS;
+
+ }
+ if (status & TSCADC_IRQENB_FIFO_OVERFLOW) {
+ /* FIFO overflow condition */
+ cntrlreg = tscadc_readl(ts_dev, TSCADC_REG_CTRL);
+ cntrlreg &= ~TSCADC_CNTRLREG_TSCSSENB;
+ tscadc_writel(ts_dev, TSCADC_REG_CTRL, cntrlreg);
+
+ irqclr |= TSCADC_IRQENB_FIFO_OVERFLOW;
+ }
+
+ tscadc_writel(ts_dev, TSCADC_REG_IRQSTATUS, irqclr);
+ fsm = tscadc_readl(ts_dev, TSCADC_REG_ADCFSM);
+ if ((fsm & TSCADC_ADCFSM_FSM) &&
+ (fsm & TSCADC_ADCFSM_STEPID)) {
+ store = tscadc_readl(ts_dev, TSCADC_REG_CTRL);
+ store |= TSCADC_CNTRLREG_TSCSSENB;
+ tscadc_writel(ts_dev, TSCADC_REG_CTRL, store);
+ }
+
+ /* check pending interrupts */
+ tscadc_writel(ts_dev, TSCADC_REG_IRQEOI, 0x0);
+
+ tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB);
+ return IRQ_HANDLED;
+}
+
+/*
+* The functions for inserting/removing driver as a module.
+*/
+
+static int __devinit tscadc_probe(struct platform_device *pdev)
+{
+ struct tscadc *ts_dev;
+ struct input_dev *input_dev;
+ int err;
+ int clk_value;
+ int clock_rate, irqenable, ctrl;
+ struct tsc_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no memory resource defined.\n");
+ return -EINVAL;
+ }
+
+ /* Allocate memory for device */
+ ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
+ if (!ts_dev) {
+ dev_err(&pdev->dev, "failed to allocate memory.\n");
+ return -ENOMEM;
+ }
+
+ ts_dev->irq = platform_get_irq(pdev, 0);
+ if (ts_dev->irq < 0) {
+ dev_err(&pdev->dev, "no irq ID is specified.\n");
+ return -ENODEV;
+ }
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ dev_err(&pdev->dev, "failed to allocate input device.\n");
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+ ts_dev->input = input_dev;
+
+ ts_dev->tsc_base = ioremap(res->start, resource_size(res));
+ if (!ts_dev->tsc_base) {
+ dev_err(&pdev->dev, "failed to map registers.\n");
+ err = -ENOMEM;
+ goto err_release_mem;
+ }
+
+ err = request_irq(ts_dev->irq, tscadc_interrupt, IRQF_DISABLED,
+ pdev->dev.driver->name, ts_dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to allocate irq.\n");
+ goto err_unmap_regs;
+ }
+
+ ts_dev->clk = clk_get(&pdev->dev, "tsc_clk");
+ if (IS_ERR(ts_dev->clk)) {
+ dev_err(&pdev->dev, "failed to get ts_clk\n");
+ err = PTR_ERR(ts_dev->clk);
+ goto err_free_irq;
+ }
+ clk_enable(ts_dev->clk);
+
+ clock_rate = clk_get_rate(ts_dev->clk);
+ clk_value = clock_rate / ADC_CLK;
+ if (clk_value < 7) {
+ dev_err(&pdev->dev, "clock input less than min clock requirement\n");
+ goto err_fail;
+ }
+ /* TSCADC_CLKDIV needs to be configured to the value minus 1 */
+ clk_value = clk_value - 1;
+ tscadc_writel(ts_dev, TSCADC_REG_CLKDIV, clk_value);
+
+ /* Enable wake-up of the SoC using touchscreen */
+ tscadc_writel(ts_dev, TSCADC_REG_IRQWAKEUP, TSCADC_IRQWKUP_ENB);
+
+ ts_dev->wires = pdata->wires;
+
+ /* Set the control register bits */
+ ctrl = TSCADC_CNTRLREG_STEPCONFIGWRT |
+ TSCADC_CNTRLREG_TSCENB |
+ TSCADC_CNTRLREG_STEPID;
+ switch (ts_dev->wires) {
+ case 4:
+ ctrl |= TSCADC_CNTRLREG_4WIRE;
+ break;
+ case 5:
+ ctrl |= TSCADC_CNTRLREG_5WIRE;
+ break;
+ case 8:
+ ctrl |= TSCADC_CNTRLREG_8WIRE;
+ break;
+ }
+ tscadc_writel(ts_dev, TSCADC_REG_CTRL, ctrl);
+
+ /* Set register bits for Idel Config Mode */
+ tsc_idle_config(ts_dev);
+
+ /* IRQ Enable */
+ irqenable = TSCADC_IRQENB_IRQHWPEN |
+ TSCADC_IRQENB_IRQEOS |
+ TSCADC_IRQENB_PENUP | TSCADC_IRQENB_FIFO_OVERFLOW;
+ tscadc_writel(ts_dev, TSCADC_REG_IRQENABLE, irqenable);
+
+ tsc_step_config(ts_dev);
+
+ ctrl |= TSCADC_CNTRLREG_TSCSSENB;
+ tscadc_writel(ts_dev, TSCADC_REG_CTRL, ctrl);
+
+ input_dev->name = "ti-tsc-adcc";
+ input_dev->dev.parent = &pdev->dev;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
+
+ /* register to the input system */
+ err = input_register_device(input_dev);
+ if (err)
+ goto err_fail;
+
+ return 0;
+
+err_fail:
+ clk_disable(ts_dev->clk);
+ clk_put(ts_dev->clk);
+err_free_irq:
+ free_irq(ts_dev->irq, ts_dev);
+err_unmap_regs:
+ iounmap(ts_dev->tsc_base);
+err_release_mem:
+ release_mem_region(res->start, resource_size(res));
+ input_free_device(ts_dev->input);
+err_free_mem:
+ kfree(ts_dev);
+ return err;
+}
+
+static int __devexit tscadc_remove(struct platform_device *pdev)
+{
+ struct tscadc *ts_dev = dev_get_drvdata(&pdev->dev);
+ struct resource *res;
+
+ free_irq(ts_dev->irq, ts_dev);
+
+ input_unregister_device(ts_dev->input);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(ts_dev->tsc_base);
+ release_mem_region(res->start, resource_size(res));
+
+ clk_disable(ts_dev->clk);
+ clk_put(ts_dev->clk);
+
+ kfree(ts_dev);
+
+ return 0;
+}
+
+static struct platform_driver ti_tsc_driver = {
+ .probe = tscadc_probe,
+ .remove = __devexit_p(tscadc_remove),
+ .driver = {
+ .name = "tsc",
+ },
+};
+
+static int __init ti_tsc_init(void)
+{
+ return platform_driver_register(&ti_tsc_driver);
+}
+
+static void __exit ti_tsc_exit(void)
+{
+ platform_driver_unregister(&ti_tsc_driver);
+}
+
+module_init(ti_tsc_init);
+module_exit(ti_tsc_exit);
diff --git a/include/linux/input/ti_tscadc.h b/include/linux/input/ti_tscadc.h
new file mode 100644
index 0000000..29f87db
--- /dev/null
+++ b/include/linux/input/ti_tscadc.h
@@ -0,0 +1,10 @@
+/**
+ * struct tsc_data Touchscreen wire configuration
+ * @wires: Wires refer to application modes
+ * i.e. 4/5/8 wire touchscreen support
+ * on the platform
+ */
+
+struct tsc_data {
+ int wires;
+};
--
1.6.2.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* RE: [PATCH V2] input: add support for TI Touchscreen controller.
2011-07-14 5:02 [PATCH V2] " Patil, Rachna
@ 2011-07-20 13:12 ` Patil, Rachna
2011-07-22 6:35 ` Dmitry Torokhov
0 siblings, 1 reply; 10+ messages in thread
From: Patil, Rachna @ 2011-07-20 13:12 UTC (permalink / raw)
To: linux-input@vger.kernel.org; +Cc: Dmitry Torokhov, Dmitry Torokhov
Hi Dmitry,
This is just a gentle reminder for the patch I had submitted viz. "[PATCH] input: add support for TI Touchscreen controller."
Can this patch be included in the 3.1 version?
I know this is a bit late but I presume that this patch just adds a new kind of driver and does not break anything existing.
Thanks & regards,
Rachna.
> -----Original Message-----
> From: Patil, Rachna
> Sent: Thursday, July 14, 2011 10:33 AM
> To: linux-input@vger.kernel.org
> Cc: Dmitry Torokhov; Dmitry Torokhov; Patil, Rachna
> Subject: [PATCH V2] input: add support for TI Touchscreen controller.
>
> This patch adds support for TI's touchscreen
> controller for a 4/5/8 wire resistive panel
> that is directly fed to the ADC.
>
> This touchscreen controller will be part of
> an upcoming TI SoC and has been tested on
> an emulation platform.
>
> ChangeLog:
> v2: fixed comments from Dmitry
>
> Signed-off-by: Patil, Rachna <rachna@ti.com>
> ---
> drivers/input/touchscreen/Kconfig | 11 +
> drivers/input/touchscreen/Makefile | 1 +
> drivers/input/touchscreen/ti_tscadc.c | 431
> +++++++++++++++++++++++++++++++++
> include/linux/input/ti_tscadc.h | 10 +
> 4 files changed, 453 insertions(+), 0 deletions(-)
> create mode 100644 drivers/input/touchscreen/ti_tscadc.c
> create mode 100644 include/linux/input/ti_tscadc.h
>
> diff --git a/drivers/input/touchscreen/Kconfig
> b/drivers/input/touchscreen/Kconfig
> index 44589f5..7d976d7 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -395,6 +395,17 @@ config TOUCHSCREEN_TOUCHWIN
> To compile this driver as a module, choose M here: the
> module will be called touchwin.
>
> +config TOUCHSCREEN_TI_TSCADC
> + tristate "TI Touchscreen Interface"
> + help
> + Say Y here if you have 4/5/8 wire touchscreen controller
> + to be connected to the ADC controller on your TI SoC.
> +
> + If unsure, say N.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called ti_tscadc.
> +
> config TOUCHSCREEN_ATMEL_TSADCC
> tristate "Atmel Touchscreen Interface"
> depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
> diff --git a/drivers/input/touchscreen/Makefile
> b/drivers/input/touchscreen/Makefile
> index 51b08b0..86b7ab6 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -41,6 +41,7 @@ obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o
> obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
> obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
> obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
> +obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o
> obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
> obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
> obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
> diff --git a/drivers/input/touchscreen/ti_tscadc.c
> b/drivers/input/touchscreen/ti_tscadc.c
> new file mode 100644
> index 0000000..86264fc
> --- /dev/null
> +++ b/drivers/input/touchscreen/ti_tscadc.c
> @@ -0,0 +1,431 @@
> +/*
> + * TI Touch Screen driver
> + *
> + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/module.h>
> +#include <linux/input.h>
> +#include <linux/slab.h>
> +#include <linux/interrupt.h>
> +#include <linux/clk.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/input/ti_tscadc.h>
> +
> +#define TSCADC_REG_IRQEOI 0x020
> +#define TSCADC_REG_IRQSTATUS 0x028
> +#define TSCADC_REG_IRQENABLE 0x02C
> +#define TSCADC_REG_IRQWAKEUP 0x034
> +#define TSCADC_REG_CTRL 0x040
> +#define TSCADC_REG_ADCFSM 0x044
> +#define TSCADC_REG_CLKDIV 0x04C
> +#define TSCADC_REG_SE 0x054
> +#define TSCADC_REG_IDLECONFIG 0x058
> +#define TSCADC_REG_CHARGECONFIG 0x05C
> +#define TSCADC_REG_STEPCONFIG1 0x064
> +#define TSCADC_REG_STEPDELAY1 0x068
> +#define TSCADC_REG_STEPCONFIG2 0x06C
> +#define TSCADC_REG_STEPDELAY2 0x070
> +#define TSCADC_REG_FIFO0 0x100
> +
> +/* Register Bitfields */
> +#define TSCADC_IRQWKUP_ENB BIT(0)
> +#define TSCADC_STPENB_STEPENB (7 << 0)
> +#define TSCADC_IRQENB_IRQHWPEN BIT(10)
> +#define TSCADC_IRQENB_IRQEOS BIT(1)
> +#define TSCADC_IRQENB_FIFO_OVERFLOW BIT(3)
> +#define TSCADC_IRQENB_PENUP BIT(9)
> +#define TSCADC_STEPCONFIG_MODE_HWSYNC 0x3
> +#define TSCADC_STEPCONFIG_2SAMPLES_AVG BIT(2)
> +#define TSCADC_STEPCONFIG_XPP BIT(5)
> +#define TSCADC_STEPCONFIG_XNN BIT(6)
> +#define TSCADC_STEPCONFIG_YPP BIT(7)
> +#define TSCADC_STEPCONFIG_YNN BIT(8)
> +#define TSCADC_STEPCONFIG_XNP BIT(9)
> +#define TSCADC_STEPCONFIG_YPN BIT(10)
> +#define TSCADC_STEPCONFIG_RFP_X (1 << 12)
> +#define TSCADC_STEPCONFIG_RFP_4_Y (1 << 13)
> +#define TSCADC_STEPCONFIG_RFP_5_Y (1 << 12)
> +#define TSCADC_STEPCONFIG_RFP_8_Y (1 << 13)
> +#define TSCADC_STEPCONFIG_INM (1 << 18)
> +#define TSCADC_STEPCONFIG_INP_4 (1 << 20)
> +#define TSCADC_STEPCONFIG_INP_5 (1 << 21)
> +#define TSCADC_STEPCONFIG_INP_8_X (3 << 20)
> +#define TSCADC_STEPCONFIG_INP_8_Y (1 << 21)
> +#define TSCADC_STEPCONFIG_RFM_4_X (1 << 23)
> +#define TSCADC_STEPCONFIG_RFM_5_X (1 << 24)
> +#define TSCADC_STEPCONFIG_RFM_8_X (1 << 23)
> +#define TSCADC_STEPCONFIG_RFM_Y (1 << 24)
> +#define TSCADC_STEPCONFIG_OPENDLY (0xf << 0)
> +#define TSCADC_STEPCONFIG_SAMPLEDLY BIT(25)
> +#define TSCADC_STEPCHARGE_INM BIT(18)
> +#define TSCADC_STEPCHARGE_RFM (3 << 23)
> +#define TSCADC_CNTRLREG_TSCSSENB BIT(0)
> +#define TSCADC_CNTRLREG_STEPID BIT(1)
> +#define TSCADC_CNTRLREG_STEPCONFIGWRT BIT(2)
> +#define TSCADC_CNTRLREG_TSCENB BIT(7)
> +#define TSCADC_CNTRLREG_4WIRE (0x1 << 5)
> +#define TSCADC_CNTRLREG_5WIRE (0x1 << 6)
> +#define TSCADC_CNTRLREG_8WIRE (0x3 << 5)
> +#define TSCADC_ADCFSM_STEPID 0x10
> +#define TSCADC_ADCFSM_FSM BIT(5)
> +
> +#define ADC_CLK 3000000
> +
> +#define MAX_12BIT ((1 << 12) - 1)
> +
> +struct tscadc {
> + struct input_dev *input;
> + int wires;
> + struct clk *clk;
> + int irq;
> + void __iomem *tsc_base;
> +};
> +
> +static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
> +{
> + return readl(ts->tsc_base + reg);
> +}
> +
> +static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
> + unsigned int val)
> +{
> + writel(val, tsc->tsc_base + reg);
> +}
> +
> +static void tsc_step_config(struct tscadc *ts_dev)
> +{
> + int stepconfig1, stepconfig2, delay;
> +
> + /* Configure the Step registers */
> + stepconfig1 = TSCADC_STEPCONFIG_MODE_HWSYNC |
> + TSCADC_STEPCONFIG_2SAMPLES_AVG | TSCADC_STEPCONFIG_XPP |
> + TSCADC_STEPCONFIG_XNN | TSCADC_STEPCONFIG_INM |
> + TSCADC_STEPCONFIG_RFP_X;
> +
> + stepconfig2 = TSCADC_STEPCONFIG_MODE_HWSYNC |
> + TSCADC_STEPCONFIG_2SAMPLES_AVG | TSCADC_STEPCONFIG_YNN |
> + TSCADC_STEPCONFIG_INM | TSCADC_STEPCONFIG_RFM_Y;
> + switch (ts_dev->wires) {
> + case 4:
> + stepconfig1 |= TSCADC_STEPCONFIG_INP_4 |
> + TSCADC_STEPCONFIG_RFM_4_X;
> +
> + stepconfig2 |= TSCADC_STEPCONFIG_YPP |
> + TSCADC_STEPCONFIG_RFP_4_Y;
> + break;
> + case 5:
> + stepconfig1 |= TSCADC_STEPCONFIG_YPP |
> + TSCADC_STEPCONFIG_YNN |
> + TSCADC_STEPCONFIG_INP_5 |
> + TSCADC_STEPCONFIG_RFM_5_X;
> +
> + stepconfig2 |= TSCADC_STEPCONFIG_XPP |
> + TSCADC_STEPCONFIG_XNP |
> + TSCADC_STEPCONFIG_YPN |
> + TSCADC_STEPCONFIG_RFP_5_Y |
> + TSCADC_STEPCONFIG_INP_5;
> + break;
> + case 8:
> + stepconfig1 |= TSCADC_STEPCONFIG_INP_8_X |
> + TSCADC_STEPCONFIG_RFM_8_X;
> +
> + stepconfig2 |= TSCADC_STEPCONFIG_YPP |
> + TSCADC_STEPCONFIG_RFP_8_Y |
> + TSCADC_STEPCONFIG_INP_8_Y;
> + break;
> + }
> + delay = TSCADC_STEPCONFIG_OPENDLY | TSCADC_STEPCONFIG_SAMPLEDLY;
> +
> + tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG1, stepconfig1);
> + tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY1, delay);
> + tscadc_writel(ts_dev, TSCADC_REG_STEPCONFIG2, stepconfig2);
> + tscadc_writel(ts_dev, TSCADC_REG_STEPDELAY2, delay);
> +
> + tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB);
> +}
> +
> +static void tsc_idle_config(struct tscadc *ts_config)
> +{
> + /* Idle mode touch screen config */
> + unsigned int idleconfig;
> +
> + idleconfig = TSCADC_STEPCONFIG_YNN |
> + TSCADC_STEPCONFIG_RFP_X |
> + TSCADC_STEPCONFIG_INM ;
> +
> + switch (ts_config->wires) {
> + case 4:
> + idleconfig |= TSCADC_STEPCONFIG_INP_4 |
> + TSCADC_STEPCONFIG_RFM_4_X;
> + break;
> + case 5:
> + idleconfig |= TSCADC_STEPCONFIG_INP_5 |
> + TSCADC_STEPCONFIG_RFM_5_X;
> + break;
> + case 8:
> + idleconfig |= TSCADC_STEPCONFIG_INP_4 |
> + TSCADC_STEPCONFIG_RFM_8_X;
> + break;
> + }
> + tscadc_writel(ts_config, TSCADC_REG_IDLECONFIG, idleconfig);
> +}
> +
> +static irqreturn_t tscadc_interrupt(int irq, void *dev)
> +{
> + struct tscadc *ts_dev = (struct tscadc *)dev;
> + struct input_dev *input_dev = ts_dev->input;
> + unsigned int status, store, cntrlreg, irqclr = 0;
> + int absx, absy;
> + int charge, fsm;
> +
> + status = tscadc_readl(ts_dev, TSCADC_REG_IRQSTATUS);
> + tscadc_writel(ts_dev, TSCADC_REG_SE, 0x0);
> +
> + /* Pen touch event */
> + if (status & TSCADC_IRQENB_IRQHWPEN)
> + irqclr = TSCADC_IRQENB_IRQHWPEN;
> +
> + if (status & TSCADC_IRQENB_PENUP) {
> + /* Pen up event */
> + charge = TSCADC_STEPCHARGE_INM | TSCADC_STEPCHARGE_RFM;
> + tscadc_writel(ts_dev, TSCADC_REG_CHARGECONFIG, charge);
> + input_report_key(input_dev, BTN_TOUCH, 0);
> + input_sync(input_dev);
> + tsc_idle_config(ts_dev);
> + irqclr |= TSCADC_IRQENB_PENUP;
> +
> + }
> + if (status & TSCADC_IRQENB_IRQEOS) {
> + /* ADC is done with sampling, ready to read the data */
> + absx = tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
> + absy = tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
> +
> + input_report_abs(input_dev, ABS_X, absx);
> + input_report_abs(input_dev, ABS_Y, absy);
> + input_report_key(input_dev, BTN_TOUCH, 1);
> + input_sync(input_dev);
> +
> + irqclr |= TSCADC_IRQENB_IRQEOS;
> +
> + }
> + if (status & TSCADC_IRQENB_FIFO_OVERFLOW) {
> + /* FIFO overflow condition */
> + cntrlreg = tscadc_readl(ts_dev, TSCADC_REG_CTRL);
> + cntrlreg &= ~TSCADC_CNTRLREG_TSCSSENB;
> + tscadc_writel(ts_dev, TSCADC_REG_CTRL, cntrlreg);
> +
> + irqclr |= TSCADC_IRQENB_FIFO_OVERFLOW;
> + }
> +
> + tscadc_writel(ts_dev, TSCADC_REG_IRQSTATUS, irqclr);
> + fsm = tscadc_readl(ts_dev, TSCADC_REG_ADCFSM);
> + if ((fsm & TSCADC_ADCFSM_FSM) &&
> + (fsm & TSCADC_ADCFSM_STEPID)) {
> + store = tscadc_readl(ts_dev, TSCADC_REG_CTRL);
> + store |= TSCADC_CNTRLREG_TSCSSENB;
> + tscadc_writel(ts_dev, TSCADC_REG_CTRL, store);
> + }
> +
> + /* check pending interrupts */
> + tscadc_writel(ts_dev, TSCADC_REG_IRQEOI, 0x0);
> +
> + tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB);
> + return IRQ_HANDLED;
> +}
> +
> +/*
> +* The functions for inserting/removing driver as a module.
> +*/
> +
> +static int __devinit tscadc_probe(struct platform_device *pdev)
> +{
> + struct tscadc *ts_dev;
> + struct input_dev *input_dev;
> + int err;
> + int clk_value;
> + int clock_rate, irqenable, ctrl;
> + struct tsc_data *pdata = pdev->dev.platform_data;
> + struct resource *res;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "no memory resource defined.\n");
> + return -EINVAL;
> + }
> +
> + /* Allocate memory for device */
> + ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
> + if (!ts_dev) {
> + dev_err(&pdev->dev, "failed to allocate memory.\n");
> + return -ENOMEM;
> + }
> +
> + ts_dev->irq = platform_get_irq(pdev, 0);
> + if (ts_dev->irq < 0) {
> + dev_err(&pdev->dev, "no irq ID is specified.\n");
> + return -ENODEV;
> + }
> +
> + input_dev = input_allocate_device();
> + if (!input_dev) {
> + dev_err(&pdev->dev, "failed to allocate input device.\n");
> + err = -ENOMEM;
> + goto err_free_mem;
> + }
> + ts_dev->input = input_dev;
> +
> + ts_dev->tsc_base = ioremap(res->start, resource_size(res));
> + if (!ts_dev->tsc_base) {
> + dev_err(&pdev->dev, "failed to map registers.\n");
> + err = -ENOMEM;
> + goto err_release_mem;
> + }
> +
> + err = request_irq(ts_dev->irq, tscadc_interrupt, IRQF_DISABLED,
> + pdev->dev.driver->name, ts_dev);
> + if (err) {
> + dev_err(&pdev->dev, "failed to allocate irq.\n");
> + goto err_unmap_regs;
> + }
> +
> + ts_dev->clk = clk_get(&pdev->dev, "tsc_clk");
> + if (IS_ERR(ts_dev->clk)) {
> + dev_err(&pdev->dev, "failed to get ts_clk\n");
> + err = PTR_ERR(ts_dev->clk);
> + goto err_free_irq;
> + }
> + clk_enable(ts_dev->clk);
> +
> + clock_rate = clk_get_rate(ts_dev->clk);
> + clk_value = clock_rate / ADC_CLK;
> + if (clk_value < 7) {
> + dev_err(&pdev->dev, "clock input less than min clock
> requirement\n");
> + goto err_fail;
> + }
> + /* TSCADC_CLKDIV needs to be configured to the value minus 1 */
> + clk_value = clk_value - 1;
> + tscadc_writel(ts_dev, TSCADC_REG_CLKDIV, clk_value);
> +
> + /* Enable wake-up of the SoC using touchscreen */
> + tscadc_writel(ts_dev, TSCADC_REG_IRQWAKEUP, TSCADC_IRQWKUP_ENB);
> +
> + ts_dev->wires = pdata->wires;
> +
> + /* Set the control register bits */
> + ctrl = TSCADC_CNTRLREG_STEPCONFIGWRT |
> + TSCADC_CNTRLREG_TSCENB |
> + TSCADC_CNTRLREG_STEPID;
> + switch (ts_dev->wires) {
> + case 4:
> + ctrl |= TSCADC_CNTRLREG_4WIRE;
> + break;
> + case 5:
> + ctrl |= TSCADC_CNTRLREG_5WIRE;
> + break;
> + case 8:
> + ctrl |= TSCADC_CNTRLREG_8WIRE;
> + break;
> + }
> + tscadc_writel(ts_dev, TSCADC_REG_CTRL, ctrl);
> +
> + /* Set register bits for Idel Config Mode */
> + tsc_idle_config(ts_dev);
> +
> + /* IRQ Enable */
> + irqenable = TSCADC_IRQENB_IRQHWPEN |
> + TSCADC_IRQENB_IRQEOS |
> + TSCADC_IRQENB_PENUP | TSCADC_IRQENB_FIFO_OVERFLOW;
> + tscadc_writel(ts_dev, TSCADC_REG_IRQENABLE, irqenable);
> +
> + tsc_step_config(ts_dev);
> +
> + ctrl |= TSCADC_CNTRLREG_TSCSSENB;
> + tscadc_writel(ts_dev, TSCADC_REG_CTRL, ctrl);
> +
> + input_dev->name = "ti-tsc-adcc";
> + input_dev->dev.parent = &pdev->dev;
> +
> + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
> + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
> +
> + input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
> + input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
> +
> + /* register to the input system */
> + err = input_register_device(input_dev);
> + if (err)
> + goto err_fail;
> +
> + return 0;
> +
> +err_fail:
> + clk_disable(ts_dev->clk);
> + clk_put(ts_dev->clk);
> +err_free_irq:
> + free_irq(ts_dev->irq, ts_dev);
> +err_unmap_regs:
> + iounmap(ts_dev->tsc_base);
> +err_release_mem:
> + release_mem_region(res->start, resource_size(res));
> + input_free_device(ts_dev->input);
> +err_free_mem:
> + kfree(ts_dev);
> + return err;
> +}
> +
> +static int __devexit tscadc_remove(struct platform_device *pdev)
> +{
> + struct tscadc *ts_dev = dev_get_drvdata(&pdev->dev);
> + struct resource *res;
> +
> + free_irq(ts_dev->irq, ts_dev);
> +
> + input_unregister_device(ts_dev->input);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + iounmap(ts_dev->tsc_base);
> + release_mem_region(res->start, resource_size(res));
> +
> + clk_disable(ts_dev->clk);
> + clk_put(ts_dev->clk);
> +
> + kfree(ts_dev);
> +
> + return 0;
> +}
> +
> +static struct platform_driver ti_tsc_driver = {
> + .probe = tscadc_probe,
> + .remove = __devexit_p(tscadc_remove),
> + .driver = {
> + .name = "tsc",
> + },
> +};
> +
> +static int __init ti_tsc_init(void)
> +{
> + return platform_driver_register(&ti_tsc_driver);
> +}
> +
> +static void __exit ti_tsc_exit(void)
> +{
> + platform_driver_unregister(&ti_tsc_driver);
> +}
> +
> +module_init(ti_tsc_init);
> +module_exit(ti_tsc_exit);
> diff --git a/include/linux/input/ti_tscadc.h
> b/include/linux/input/ti_tscadc.h
> new file mode 100644
> index 0000000..29f87db
> --- /dev/null
> +++ b/include/linux/input/ti_tscadc.h
> @@ -0,0 +1,10 @@
> +/**
> + * struct tsc_data Touchscreen wire configuration
> + * @wires: Wires refer to application modes
> + * i.e. 4/5/8 wire touchscreen support
> + * on the platform
> + */
> +
> +struct tsc_data {
> + int wires;
> +};
> --
> 1.6.2.4
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH V2] input: add support for TI Touchscreen controller.
2011-07-20 13:12 ` Patil, Rachna
@ 2011-07-22 6:35 ` Dmitry Torokhov
2011-07-22 9:12 ` Patil, Rachna
0 siblings, 1 reply; 10+ messages in thread
From: Dmitry Torokhov @ 2011-07-22 6:35 UTC (permalink / raw)
To: Patil, Rachna; +Cc: linux-input@vger.kernel.org
Hi Rachna,
On Wed, Jul 20, 2011 at 06:42:20PM +0530, Patil, Rachna wrote:
> Hi Dmitry,
>
> This is just a gentle reminder for the patch I had submitted viz. "[PATCH] input: add support for TI Touchscreen controller."
> Can this patch be included in the 3.1 version?
> I know this is a bit late but I presume that this patch just adds a new kind of driver and does not break anything existing.
>
I am getting the following while building the module:
ERROR: "clk_get_rate" [drivers/input/touchscreen/ti_tscadc.ko]
undefined!
ERROR: "clk_enable" [drivers/input/touchscreen/ti_tscadc.ko] undefined!
ERROR: "clk_get" [drivers/input/touchscreen/ti_tscadc.ko] undefined!
ERROR: "clk_put" [drivers/input/touchscreen/ti_tscadc.ko] undefined!
ERROR: "clk_disable" [drivers/input/touchscreen/ti_tscadc.ko] undefined!
make[1]: *** [__modpost] Error 1
Apparently we need to add some arch or platform dependency... Hmm, maybe
the driver should depend on CONFIG_HAVE_CLK?
Thanks.
--
Dmitry
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH V2] input: add support for TI Touchscreen controller.
2011-07-22 6:35 ` Dmitry Torokhov
@ 2011-07-22 9:12 ` Patil, Rachna
0 siblings, 0 replies; 10+ messages in thread
From: Patil, Rachna @ 2011-07-22 9:12 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input@vger.kernel.org
Hi Dmitry,
> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Friday, July 22, 2011 12:06 PM
> To: Patil, Rachna
> Cc: linux-input@vger.kernel.org
> Subject: Re: [PATCH V2] input: add support for TI Touchscreen controller.
>
> Hi Rachna,
>
> On Wed, Jul 20, 2011 at 06:42:20PM +0530, Patil, Rachna wrote:
> > Hi Dmitry,
> >
> > This is just a gentle reminder for the patch I had submitted viz.
> "[PATCH] input: add support for TI Touchscreen controller."
> > Can this patch be included in the 3.1 version?
> > I know this is a bit late but I presume that this patch just adds a new
> kind of driver and does not break anything existing.
> >
>
> I am getting the following while building the module:
>
> ERROR: "clk_get_rate" [drivers/input/touchscreen/ti_tscadc.ko]
> undefined!
> ERROR: "clk_enable" [drivers/input/touchscreen/ti_tscadc.ko] undefined!
> ERROR: "clk_get" [drivers/input/touchscreen/ti_tscadc.ko] undefined!
> ERROR: "clk_put" [drivers/input/touchscreen/ti_tscadc.ko] undefined!
> ERROR: "clk_disable" [drivers/input/touchscreen/ti_tscadc.ko] undefined!
> make[1]: *** [__modpost] Error 1
>
> Apparently we need to add some arch or platform dependency... Hmm, maybe
> the driver should depend on CONFIG_HAVE_CLK?
Yes, this is platform dependent. I will add CONFIG_HAVE_CLK against
the driver.
>
> Thanks.
>
> --
> Dmitry
Thanks & Regards,
Rachna.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2] input: add support for TI Touchscreen controller
@ 2011-12-09 11:29 Patil, Rachna
2011-12-30 3:55 ` Dmitry Torokhov
0 siblings, 1 reply; 10+ messages in thread
From: Patil, Rachna @ 2011-12-09 11:29 UTC (permalink / raw)
To: linux-input; +Cc: Dmitry Torokhov, Dmitry Torokhov, Rachna Patil
From: Rachna Patil <rachna@ti.com>
This patch adds support for TI's touchscreen
controller for a 4/5/8 wire resistive panel
that is directly fed to the ADC.
This touchscreen controller will be part of
AM335x TI SoC. The TRM can be found at:
http://www.ti.com/lit/ug/spruh73a/spruh73a.pdf
Signed-off-by: Patil, Rachna <rachna@ti.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---
v2: Fixed comments by Dmitry.
Have not included Fuzz, because it does not
solve the problem. I have also added a brief description
inside the interrupt handler to explain what is done.
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/ti_tscadc.c | 508 +++++++++++++++++++++++++++++++++
include/linux/input/ti_tscadc.h | 17 ++
4 files changed, 538 insertions(+), 0 deletions(-)
create mode 100644 drivers/input/touchscreen/ti_tscadc.c
create mode 100644 include/linux/input/ti_tscadc.h
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index cabd9e5..de4ee06 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -407,6 +407,18 @@ config TOUCHSCREEN_TOUCHWIN
To compile this driver as a module, choose M here: the
module will be called touchwin.
+config TOUCHSCREEN_TI_TSCADC
+ tristate "TI Touchscreen Interface"
+ depends on ARCH_OMAP2PLUS
+ help
+ Say Y here if you have 4/5/8 wire touchscreen controller
+ to be connected to the ADC controller on your TI AM335x SoC.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ti_tscadc.
+
config TOUCHSCREEN_ATMEL_TSADCC
tristate "Atmel Touchscreen Interface"
depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 282d6f7..e353bcb 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c
new file mode 100644
index 0000000..ed6f1eb
--- /dev/null
+++ b/drivers/input/touchscreen/ti_tscadc.c
@@ -0,0 +1,508 @@
+/*
+ * TI Touch Screen driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/input/ti_tscadc.h>
+#include <linux/delay.h>
+
+#define REG_IRQEOI 0x020
+#define REG_RAWIRQSTATUS 0x024
+#define REG_IRQSTATUS 0x028
+#define REG_IRQENABLE 0x02C
+#define REG_IRQWAKEUP 0x034
+#define REG_CTRL 0x040
+#define REG_ADCFSM 0x044
+#define REG_CLKDIV 0x04C
+#define REG_SE 0x054
+#define REG_IDLECONFIG 0x058
+#define REG_CHARGECONFIG 0x05C
+#define REG_CHARGEDELAY 0x060
+#define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8))
+#define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8))
+#define REG_STEPCONFIG13 0x0C4
+#define REG_STEPDELAY13 0x0C8
+#define REG_STEPCONFIG14 0x0CC
+#define REG_STEPDELAY14 0x0D0
+#define REG_FIFO0CNT 0xE4
+#define REG_FIFO1THR 0xF4
+#define REG_FIFO0 0x100
+#define REG_FIFO1 0x200
+
+/* Register Bitfields */
+#define IRQWKUP_ENB BIT(0)
+#define STPENB_STEPENB 0x7FFF
+#define IRQENB_FIFO1THRES BIT(5)
+#define IRQENB_PENUP BIT(9)
+#define STEPCONFIG_MODE_HWSYNC 0x2
+#define STEPCONFIG_SAMPLES_AVG (1 << 4)
+#define STEPCONFIG_XPP (1 << 5)
+#define STEPCONFIG_XNN (1 << 6)
+#define STEPCONFIG_YPP (1 << 7)
+#define STEPCONFIG_YNN (1 << 8)
+#define STEPCONFIG_XNP (1 << 9)
+#define STEPCONFIG_YPN (1 << 10)
+#define STEPCONFIG_INM (1 << 18)
+#define STEPCONFIG_INP (1 << 20)
+#define STEPCONFIG_INP_5 (1 << 21)
+#define STEPCONFIG_FIFO1 (1 << 26)
+#define STEPCONFIG_OPENDLY 0xff
+#define STEPCONFIG_Z1 (3 << 19)
+#define STEPIDLE_INP (1 << 22)
+#define STEPCHARGE_RFP (1 << 12)
+#define STEPCHARGE_INM (1 << 15)
+#define STEPCHARGE_INP (1 << 19)
+#define STEPCHARGE_RFM (1 << 23)
+#define STEPCHARGE_DELAY 0x1
+#define CNTRLREG_TSCSSENB (1 << 0)
+#define CNTRLREG_STEPID (1 << 1)
+#define CNTRLREG_STEPCONFIGWRT (1 << 2)
+#define CNTRLREG_4WIRE (1 << 5)
+#define CNTRLREG_5WIRE (1 << 6)
+#define CNTRLREG_8WIRE (3 << 5)
+#define CNTRLREG_TSCENB (1 << 7)
+#define ADCFSM_STEPID 0x10
+
+#define SEQ_SETTLE 275
+#define ADC_CLK 3000000
+#define MAX_12BIT ((1 << 12) - 1)
+
+struct tscadc {
+ struct input_dev *input;
+ struct clk *tsc_ick;
+ int irq;
+ int pen;
+ int wires;
+ int x_plate_resistance;
+ unsigned int bckup_x;
+ unsigned int bckup_y;
+ void __iomem *tsc_base;
+};
+
+static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
+{
+ return readl(ts->tsc_base + reg);
+}
+
+static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
+ unsigned int val)
+{
+ writel(val, tsc->tsc_base + reg);
+}
+
+static void tsc_step_config(struct tscadc *ts_dev)
+{
+ unsigned int config;
+ int i;
+
+ /* Configure the Step registers */
+
+ config = STEPCONFIG_MODE_HWSYNC |
+ STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP;
+ switch (ts_dev->wires) {
+ case 4:
+ config |= STEPCONFIG_INP |
+ STEPCONFIG_XNN;
+ break;
+ case 5:
+ config |= STEPCONFIG_YNN |
+ STEPCONFIG_INP_5 | STEPCONFIG_XNN |
+ STEPCONFIG_YPP;
+ break;
+ case 8:
+ config |= STEPCONFIG_INP |
+ STEPCONFIG_XNN;
+ break;
+ }
+ for (i = 1; i < 7; i++) {
+ tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
+ tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
+ }
+
+ config = 0;
+ config = STEPCONFIG_MODE_HWSYNC |
+ STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN |
+ STEPCONFIG_INM | STEPCONFIG_FIFO1;
+ switch (ts_dev->wires) {
+ case 4:
+ config |= STEPCONFIG_YPP;
+ break;
+ case 5:
+ config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 |
+ STEPCONFIG_XNP | STEPCONFIG_YPN;
+ break;
+ case 8:
+ config |= STEPCONFIG_YPP;
+ break;
+ }
+ for (i = 7; i < 13; i++) {
+ tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
+ tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
+ }
+
+ config = 0;
+ /* Charge step configuration */
+ config = STEPCONFIG_XPP | STEPCONFIG_YNN |
+ STEPCHARGE_RFP | STEPCHARGE_RFM |
+ STEPCHARGE_INM | STEPCHARGE_INP;
+
+ tscadc_writel(ts_dev, REG_CHARGECONFIG, config);
+ tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY);
+
+ config = 0;
+ /* Configure to calculate pressure */
+ config = STEPCONFIG_MODE_HWSYNC |
+ STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP |
+ STEPCONFIG_XNN | STEPCONFIG_INM;
+ tscadc_writel(ts_dev, REG_STEPCONFIG13, config);
+ tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY);
+
+ config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1;
+ tscadc_writel(ts_dev, REG_STEPCONFIG14, config);
+ tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY);
+
+ tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
+}
+
+static void tsc_idle_config(struct tscadc *ts_config)
+{
+ unsigned int idleconfig;
+
+ idleconfig = STEPCONFIG_YNN |
+ STEPCONFIG_INM |
+ STEPCONFIG_YPN | STEPIDLE_INP;
+ tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig);
+}
+
+static irqreturn_t interrupt(int irq, void *dev)
+{
+ struct tscadc *ts_dev = (struct tscadc *)dev;
+ struct input_dev *input_dev = ts_dev->input;
+ unsigned int status, irqclr = 0;
+ unsigned int read, diff;
+ unsigned int prev_val_x = ~0, prev_val_y = ~0;
+ unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
+ unsigned int val_x = 0, val_y = 0, diffx = 0, diffy = 0;
+ unsigned int z1 = 0, z2 = 0, z = 0;
+ int i, fsm, fifocount;
+
+ status = tscadc_readl(ts_dev, REG_IRQSTATUS);
+ if (status & IRQENB_FIFO1THRES) {
+ fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT);
+
+ /* Delta filter is used to remove large variations
+ * in sampled values from ADC. The filter tries to
+ * predict where the next coordinate could be.
+ * This is done by taking a previous coordinate and
+ * subtracting it form current one. Further the
+ * algorithm compares the difference with that of
+ * a present value, if true the value is reported
+ * to the sub system.
+ */
+ for (i = 0; i < (fifocount-1); i++) {
+ read = ((tscadc_readl(ts_dev, REG_FIFO0)) & 0xfff);
+ diff = abs(read - prev_val_x);
+ if (diff < prev_diff_x) {
+ prev_diff_x = diff;
+ val_x = read;
+ }
+ prev_val_x = read;
+
+ read = 0;
+ diff = 0;
+ read = ((tscadc_readl(ts_dev, REG_FIFO1)) & 0xfff);
+ diff = abs(read - prev_val_y);
+ if (diff < prev_diff_y) {
+ prev_diff_y = diff;
+ val_y = read;
+ }
+ prev_val_y = read;
+ }
+
+ diffx = abs(val_x - (ts_dev->bckup_x));
+ diffy = abs(val_y - (ts_dev->bckup_y));
+ ts_dev->bckup_x = val_x;
+ ts_dev->bckup_y = val_y;
+
+ z1 = ((tscadc_readl(ts_dev, REG_FIFO0)) & 0xfff);
+ z2 = ((tscadc_readl(ts_dev, REG_FIFO1)) & 0xfff);
+
+ if (ts_dev->pen == 0) {
+ if ((z1 != 0) && (z2 != 0)) {
+ /* cal pressure using formula
+ * Resistance(touch) = x plate resistance *
+ * x postion/4096 * ((z2 / z1) - 1)
+ */
+ z = z2 - z1;
+ z *= val_x;
+ z *= ts_dev->x_plate_resistance;
+ z /= z1;
+ z = (z + 2047) >> 12;
+
+ if ((diffx < 15) && (diffy < 15)
+ && (z <= MAX_12BIT)) {
+ input_report_abs(input_dev,
+ ABS_X, val_x);
+ input_report_abs(input_dev,
+ ABS_Y, val_y);
+ input_report_abs(input_dev,
+ ABS_PRESSURE, z);
+ input_report_key(input_dev,
+ BTN_TOUCH, 1);
+ input_sync(input_dev);
+ }
+ }
+ }
+ irqclr |= IRQENB_FIFO1THRES;
+ }
+
+ /*
+ * Time for sequencer to settle, to read
+ * correct state of the sequencer.
+ */
+ udelay(SEQ_SETTLE);
+
+ status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS);
+ if (status & IRQENB_PENUP) {
+ /* Pen up event */
+ fsm = tscadc_readl(ts_dev, REG_ADCFSM);
+ if (fsm == ADCFSM_STEPID) {
+ ts_dev->pen = 1;
+ ts_dev->bckup_x = 0;
+ ts_dev->bckup_y = 0;
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_report_abs(input_dev, ABS_PRESSURE, 0);
+ input_sync(input_dev);
+ } else {
+ ts_dev->pen = 0;
+ }
+ irqclr |= IRQENB_PENUP;
+ }
+
+ tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+ /* check pending interrupts */
+ tscadc_writel(ts_dev, REG_IRQEOI, 0x0);
+
+ tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
+ return IRQ_HANDLED;
+}
+
+/*
+* The functions for inserting/removing driver as a module.
+*/
+
+static int __devinit tscadc_probe(struct platform_device *pdev)
+{
+ const struct tsc_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ struct tscadc *ts_dev;
+ struct input_dev *input_dev;
+ struct clk *clk;
+ int err;
+ int clk_value, ctrl;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "missing platform data.\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no memory resource defined.\n");
+ return -EINVAL;
+ }
+
+ /* Allocate memory for device */
+ ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!ts_dev || !input_dev) {
+ dev_err(&pdev->dev, "failed to allocate memory.\n");
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ ts_dev->irq = platform_get_irq(pdev, 0);
+ if (ts_dev->irq < 0) {
+ dev_err(&pdev->dev, "no irq ID is specified.\n");
+ err = -ENODEV;
+ goto err_free_mem;
+ }
+
+ ts_dev->input = input_dev;
+ ts_dev->wires = pdata->wires;
+ ts_dev->x_plate_resistance = pdata->x_plate_resistance;
+ ts_dev->pen = 1;
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to reserve registers.\n");
+ err = -EBUSY;
+ goto err_free_mem;
+ }
+
+ ts_dev->tsc_base = ioremap(res->start, resource_size(res));
+ if (!ts_dev->tsc_base) {
+ dev_err(&pdev->dev, "failed to map registers.\n");
+ err = -ENOMEM;
+ goto err_release_mem_region;
+ }
+
+ err = request_irq(ts_dev->irq, interrupt, IRQF_DISABLED,
+ pdev->dev.driver->name, ts_dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to allocate irq.\n");
+ goto err_unmap_regs;
+ }
+
+ ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick");
+ if (IS_ERR(ts_dev->tsc_ick)) {
+ dev_err(&pdev->dev, "failed to get TSC ick\n");
+ goto err_free_irq;
+ }
+ clk_enable(ts_dev->tsc_ick);
+
+ clk = clk_get(&pdev->dev, "adc_tsc_fck");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "failed to get TSC fck\n");
+ err = PTR_ERR(clk);
+ goto err_disable_clk;
+ }
+
+ clk_value = clk_get_rate(clk) / ADC_CLK;
+ if (clk_value < 7) {
+ dev_err(&pdev->dev, "clock input less than min clock requirement\n");
+ goto err_disable_clk;
+ }
+ /* CLKDIV needs to be configured to the value minus 1 */
+ clk_value = clk_value - 1;
+ tscadc_writel(ts_dev, REG_CLKDIV, clk_value);
+
+ /* Enable wake-up of the SoC using touchscreen */
+ tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB);
+
+
+ ctrl = CNTRLREG_STEPCONFIGWRT |
+ CNTRLREG_TSCENB |
+ CNTRLREG_STEPID;
+ switch (ts_dev->wires) {
+ case 4:
+ ctrl |= CNTRLREG_4WIRE;
+ break;
+ case 5:
+ ctrl |= CNTRLREG_5WIRE;
+ break;
+ case 8:
+ ctrl |= CNTRLREG_8WIRE;
+ break;
+ }
+ tscadc_writel(ts_dev, REG_CTRL, ctrl);
+
+ tsc_idle_config(ts_dev);
+ tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES);
+ tsc_step_config(ts_dev);
+ tscadc_writel(ts_dev, REG_FIFO1THR, 6);
+
+ ctrl |= CNTRLREG_TSCSSENB;
+ tscadc_writel(ts_dev, REG_CTRL, ctrl);
+
+ input_dev->name = "ti-tsc-adc";
+ input_dev->dev.parent = &pdev->dev;
+
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
+
+ /* register to the input system */
+ err = input_register_device(input_dev);
+ if (err)
+ goto err_disable_clk;
+
+ platform_set_drvdata(pdev, ts_dev);
+ return 0;
+
+err_disable_clk:
+ clk_disable(ts_dev->tsc_ick);
+ clk_put(ts_dev->tsc_ick);
+err_free_irq:
+ free_irq(ts_dev->irq, ts_dev);
+err_unmap_regs:
+ iounmap(ts_dev->tsc_base);
+err_release_mem_region:
+ release_mem_region(res->start, resource_size(res));
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(ts_dev);
+ return err;
+}
+
+static int __devexit tscadc_remove(struct platform_device *pdev)
+{
+ struct tscadc *ts_dev = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ free_irq(ts_dev->irq, ts_dev);
+
+ input_unregister_device(ts_dev->input);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iounmap(ts_dev->tsc_base);
+ release_mem_region(res->start, resource_size(res));
+
+ clk_disable(ts_dev->tsc_ick);
+ clk_put(ts_dev->tsc_ick);
+
+ kfree(ts_dev);
+
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver ti_tsc_driver = {
+ .probe = tscadc_probe,
+ .remove = __devexit_p(tscadc_remove),
+ .driver = {
+ .name = "tsc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ti_tsc_init(void)
+{
+ return platform_driver_register(&ti_tsc_driver);
+}
+module_init(ti_tsc_init);
+
+static void __exit ti_tsc_exit(void)
+{
+ platform_driver_unregister(&ti_tsc_driver);
+}
+module_exit(ti_tsc_exit);
+
+MODULE_DESCRIPTION("TI touchscreen controller driver");
+MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/include/linux/input/ti_tscadc.h b/include/linux/input/ti_tscadc.h
new file mode 100644
index 0000000..b10a527
--- /dev/null
+++ b/include/linux/input/ti_tscadc.h
@@ -0,0 +1,17 @@
+#ifndef __LINUX_TI_TSCADC_H
+#define __LINUX_TI_TSCADC_H
+
+/**
+ * struct tsc_data Touchscreen wire configuration
+ * @wires: Wires refer to application modes
+ * i.e. 4/5/8 wire touchscreen support
+ * on the platform.
+ * @x_plate_resistance: X plate resistance.
+ */
+
+struct tsc_data {
+ int wires;
+ int x_plate_resistance;
+};
+
+#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2] input: add support for TI Touchscreen controller
2011-12-09 11:29 [PATCH v2] input: add support for TI Touchscreen controller Patil, Rachna
@ 2011-12-30 3:55 ` Dmitry Torokhov
2012-01-02 12:21 ` Patil, Rachna
0 siblings, 1 reply; 10+ messages in thread
From: Dmitry Torokhov @ 2011-12-30 3:55 UTC (permalink / raw)
To: Patil, Rachna; +Cc: linux-input
Hi Rachna,
On Fri, Dec 09, 2011 at 04:59:42PM +0530, Patil, Rachna wrote:
> From: Rachna Patil <rachna@ti.com>
>
> This patch adds support for TI's touchscreen
> controller for a 4/5/8 wire resistive panel
> that is directly fed to the ADC.
>
> This touchscreen controller will be part of
> AM335x TI SoC. The TRM can be found at:
> http://www.ti.com/lit/ug/spruh73a/spruh73a.pdf
>
This looks mostly good, could you also try the patch below (on top of
yours) and let me know if the driver still works?
Thanks!
--
Dmitry
Input: ti_tscadc - misc changes
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
- rely on input core to implement defuzzing (filtering out smaller
variations in coordinates);
- release the 2nd clock after getting its rate;
- IRQF_DISABLE is obsolete;
- split filtering of measurements into a separate function;
- misc formatting changes;
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---
drivers/input/touchscreen/ti_tscadc.c | 244 ++++++++++++++++-----------------
1 files changed, 115 insertions(+), 129 deletions(-)
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c
index ed6f1eb..8d23f5f 100644
--- a/drivers/input/touchscreen/ti_tscadc.c
+++ b/drivers/input/touchscreen/ti_tscadc.c
@@ -87,17 +87,17 @@
#define SEQ_SETTLE 275
#define ADC_CLK 3000000
#define MAX_12BIT ((1 << 12) - 1)
+#define TSCADC_FUZZ_X 15
+#define TSCADC_FUZZ_Y 15
struct tscadc {
struct input_dev *input;
struct clk *tsc_ick;
- int irq;
- int pen;
- int wires;
- int x_plate_resistance;
- unsigned int bckup_x;
- unsigned int bckup_y;
void __iomem *tsc_base;
+ unsigned int irq;
+ unsigned int wires;
+ unsigned int x_plate_resistance;
+ bool pen_down;
};
static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
@@ -111,7 +111,7 @@ static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
writel(val, tsc->tsc_base + reg);
}
-static void tsc_step_config(struct tscadc *ts_dev)
+static void tscadc_step_config(struct tscadc *ts_dev)
{
unsigned int config;
int i;
@@ -122,8 +122,7 @@ static void tsc_step_config(struct tscadc *ts_dev)
STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP;
switch (ts_dev->wires) {
case 4:
- config |= STEPCONFIG_INP |
- STEPCONFIG_XNN;
+ config |= STEPCONFIG_INP | STEPCONFIG_XNN;
break;
case 5:
config |= STEPCONFIG_YNN |
@@ -131,10 +130,10 @@ static void tsc_step_config(struct tscadc *ts_dev)
STEPCONFIG_YPP;
break;
case 8:
- config |= STEPCONFIG_INP |
- STEPCONFIG_XNN;
+ config |= STEPCONFIG_INP | STEPCONFIG_XNN;
break;
}
+
for (i = 1; i < 7; i++) {
tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
@@ -156,6 +155,7 @@ static void tsc_step_config(struct tscadc *ts_dev)
config |= STEPCONFIG_YPP;
break;
}
+
for (i = 7; i < 13; i++) {
tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
@@ -185,9 +185,9 @@ static void tsc_step_config(struct tscadc *ts_dev)
tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
}
-static void tsc_idle_config(struct tscadc *ts_config)
+static void tscadc_idle_config(struct tscadc *ts_config)
{
- unsigned int idleconfig;
+ unsigned int idleconfig;
idleconfig = STEPCONFIG_YNN |
STEPCONFIG_INM |
@@ -195,83 +195,78 @@ static void tsc_idle_config(struct tscadc *ts_config)
tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig);
}
-static irqreturn_t interrupt(int irq, void *dev)
+static void tscadc_read_coordinates(struct tscadc *ts_dev,
+ unsigned int *x, unsigned int *y)
{
- struct tscadc *ts_dev = (struct tscadc *)dev;
- struct input_dev *input_dev = ts_dev->input;
- unsigned int status, irqclr = 0;
- unsigned int read, diff;
- unsigned int prev_val_x = ~0, prev_val_y = ~0;
- unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
- unsigned int val_x = 0, val_y = 0, diffx = 0, diffy = 0;
- unsigned int z1 = 0, z2 = 0, z = 0;
- int i, fsm, fifocount;
+ unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT);
+ unsigned int prev_val_x = ~0, prev_val_y = ~0;
+ unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
+ unsigned int read, diff;
+ unsigned int i;
- status = tscadc_readl(ts_dev, REG_IRQSTATUS);
- if (status & IRQENB_FIFO1THRES) {
- fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT);
-
- /* Delta filter is used to remove large variations
- * in sampled values from ADC. The filter tries to
- * predict where the next coordinate could be.
- * This is done by taking a previous coordinate and
- * subtracting it form current one. Further the
- * algorithm compares the difference with that of
- * a present value, if true the value is reported
- * to the sub system.
- */
- for (i = 0; i < (fifocount-1); i++) {
- read = ((tscadc_readl(ts_dev, REG_FIFO0)) & 0xfff);
- diff = abs(read - prev_val_x);
- if (diff < prev_diff_x) {
- prev_diff_x = diff;
- val_x = read;
- }
- prev_val_x = read;
-
- read = 0;
- diff = 0;
- read = ((tscadc_readl(ts_dev, REG_FIFO1)) & 0xfff);
- diff = abs(read - prev_val_y);
- if (diff < prev_diff_y) {
- prev_diff_y = diff;
- val_y = read;
- }
- prev_val_y = read;
+ /*
+ * Delta filter is used to remove large variations
+ * in sampled values from ADC. The filter tries to
+ * predict where the next coordinate could be.
+ * This is done by taking a previous coordinate and
+ * subtracting it form current one. Further the
+ * algorithm compares the difference with that of
+ * a present value, if true the value is reported
+ * to the sub system.
+ */
+ for (i = 0; i < fifocount - 1; i++) {
+ read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
+ diff = abs(read - prev_val_x);
+ if (diff < prev_diff_x) {
+ prev_diff_x = diff;
+ *x = read;
}
+ prev_val_x = read;
- diffx = abs(val_x - (ts_dev->bckup_x));
- diffy = abs(val_y - (ts_dev->bckup_y));
- ts_dev->bckup_x = val_x;
- ts_dev->bckup_y = val_y;
-
- z1 = ((tscadc_readl(ts_dev, REG_FIFO0)) & 0xfff);
- z2 = ((tscadc_readl(ts_dev, REG_FIFO1)) & 0xfff);
-
- if (ts_dev->pen == 0) {
- if ((z1 != 0) && (z2 != 0)) {
- /* cal pressure using formula
- * Resistance(touch) = x plate resistance *
- * x postion/4096 * ((z2 / z1) - 1)
- */
- z = z2 - z1;
- z *= val_x;
- z *= ts_dev->x_plate_resistance;
- z /= z1;
- z = (z + 2047) >> 12;
-
- if ((diffx < 15) && (diffy < 15)
- && (z <= MAX_12BIT)) {
- input_report_abs(input_dev,
- ABS_X, val_x);
- input_report_abs(input_dev,
- ABS_Y, val_y);
- input_report_abs(input_dev,
- ABS_PRESSURE, z);
- input_report_key(input_dev,
- BTN_TOUCH, 1);
- input_sync(input_dev);
- }
+ read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
+ diff = abs(read - prev_val_y);
+ if (diff < prev_diff_y) {
+ prev_diff_y = diff;
+ *y = read;
+ }
+ prev_val_y = read;
+ }
+}
+
+static irqreturn_t tscadc_irq(int irq, void *dev)
+{
+ struct tscadc *ts_dev = dev;
+ struct input_dev *input_dev = ts_dev->input;
+ unsigned int status, irqclr = 0;
+ unsigned int x = 0, y = 0;
+ unsigned int z1, z2, z;
+ unsigned int fsm;
+
+ status = tscadc_readl(ts_dev, REG_IRQSTATUS);
+ if (status & IRQENB_FIFO1THRES) {
+ tscadc_read_coordinates(ts_dev, &x, &y);
+
+ z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
+ z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
+
+ if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
+ /*
+ * Calculate pressure using formula
+ * Resistance(touch) = x plate resistance *
+ * x postion/4096 * ((z2 / z1) - 1)
+ */
+ z = z2 - z1;
+ z *= x;
+ z *= ts_dev->x_plate_resistance;
+ z /= z1;
+ z = (z + 2047) >> 12;
+
+ if (z <= MAX_12BIT) {
+ input_report_abs(input_dev, ABS_X, x);
+ input_report_abs(input_dev, ABS_Y, y);
+ input_report_abs(input_dev, ABS_PRESSURE, z);
+ input_report_key(input_dev, BTN_TOUCH, 1);
+ input_sync(input_dev);
}
}
irqclr |= IRQENB_FIFO1THRES;
@@ -288,14 +283,12 @@ static irqreturn_t interrupt(int irq, void *dev)
/* Pen up event */
fsm = tscadc_readl(ts_dev, REG_ADCFSM);
if (fsm == ADCFSM_STEPID) {
- ts_dev->pen = 1;
- ts_dev->bckup_x = 0;
- ts_dev->bckup_y = 0;
+ ts_dev->pen_down = false;
input_report_key(input_dev, BTN_TOUCH, 0);
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_sync(input_dev);
} else {
- ts_dev->pen = 0;
+ ts_dev->pen_down = true;
}
irqclr |= IRQENB_PENUP;
}
@@ -309,18 +302,18 @@ static irqreturn_t interrupt(int irq, void *dev)
}
/*
-* The functions for inserting/removing driver as a module.
-*/
+ * The functions for inserting/removing driver as a module.
+ */
-static int __devinit tscadc_probe(struct platform_device *pdev)
+static int __devinit tscadc_probe(struct platform_device *pdev)
{
- const struct tsc_data *pdata = pdev->dev.platform_data;
- struct resource *res;
- struct tscadc *ts_dev;
- struct input_dev *input_dev;
- struct clk *clk;
- int err;
- int clk_value, ctrl;
+ const struct tsc_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ struct tscadc *ts_dev;
+ struct input_dev *input_dev;
+ struct clk *clk;
+ int err;
+ int clk_value, ctrl, irq;
if (!pdata) {
dev_err(&pdev->dev, "missing platform data.\n");
@@ -333,6 +326,12 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
return -EINVAL;
}
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no irq ID is specified.\n");
+ return -EINVAL;
+ }
+
/* Allocate memory for device */
ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
input_dev = input_allocate_device();
@@ -342,7 +341,6 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
goto err_free_mem;
}
- ts_dev->irq = platform_get_irq(pdev, 0);
if (ts_dev->irq < 0) {
dev_err(&pdev->dev, "no irq ID is specified.\n");
err = -ENODEV;
@@ -350,11 +348,11 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
}
ts_dev->input = input_dev;
+ ts_dev->irq = irq;
ts_dev->wires = pdata->wires;
ts_dev->x_plate_resistance = pdata->x_plate_resistance;
- ts_dev->pen = 1;
- res = request_mem_region(res->start, resource_size(res), pdev->name);
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) {
dev_err(&pdev->dev, "failed to reserve registers.\n");
err = -EBUSY;
@@ -368,8 +366,8 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
goto err_release_mem_region;
}
- err = request_irq(ts_dev->irq, interrupt, IRQF_DISABLED,
- pdev->dev.driver->name, ts_dev);
+ err = request_irq(ts_dev->irq, tscadc_irq,
+ 0, pdev->dev.driver->name, ts_dev);
if (err) {
dev_err(&pdev->dev, "failed to allocate irq.\n");
goto err_unmap_regs;
@@ -390,18 +388,18 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
}
clk_value = clk_get_rate(clk) / ADC_CLK;
+ clk_put(clk);
+
if (clk_value < 7) {
dev_err(&pdev->dev, "clock input less than min clock requirement\n");
goto err_disable_clk;
}
/* CLKDIV needs to be configured to the value minus 1 */
- clk_value = clk_value - 1;
- tscadc_writel(ts_dev, REG_CLKDIV, clk_value);
+ tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1);
/* Enable wake-up of the SoC using touchscreen */
tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB);
-
ctrl = CNTRLREG_STEPCONFIGWRT |
CNTRLREG_TSCENB |
CNTRLREG_STEPID;
@@ -418,9 +416,9 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
}
tscadc_writel(ts_dev, REG_CTRL, ctrl);
- tsc_idle_config(ts_dev);
+ tscadc_idle_config(ts_dev);
tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES);
- tsc_step_config(ts_dev);
+ tscadc_step_config(ts_dev);
tscadc_writel(ts_dev, REG_FIFO1THR, 6);
ctrl |= CNTRLREG_TSCSSENB;
@@ -432,8 +430,8 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
+ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, TSCADC_FUZZ_X, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, TSCADC_FUZZ_Y, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
/* register to the input system */
@@ -461,8 +459,8 @@ err_free_mem:
static int __devexit tscadc_remove(struct platform_device *pdev)
{
- struct tscadc *ts_dev = platform_get_drvdata(pdev);
- struct resource *res;
+ struct tscadc *ts_dev = platform_get_drvdata(pdev);
+ struct resource *res;
free_irq(ts_dev->irq, ts_dev);
@@ -485,24 +483,12 @@ static struct platform_driver ti_tsc_driver = {
.probe = tscadc_probe,
.remove = __devexit_p(tscadc_remove),
.driver = {
- .name = "tsc",
- .owner = THIS_MODULE,
+ .name = "tsc",
+ .owner = THIS_MODULE,
},
};
-
-static int __init ti_tsc_init(void)
-{
- return platform_driver_register(&ti_tsc_driver);
-}
-module_init(ti_tsc_init);
-
-static void __exit ti_tsc_exit(void)
-{
- platform_driver_unregister(&ti_tsc_driver);
-}
-module_exit(ti_tsc_exit);
+module_platform_driver(ti_tsc_driver);
MODULE_DESCRIPTION("TI touchscreen controller driver");
MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
MODULE_LICENSE("GPL");
-
^ permalink raw reply related [flat|nested] 10+ messages in thread
* RE: [PATCH v2] input: add support for TI Touchscreen controller
2011-12-30 3:55 ` Dmitry Torokhov
@ 2012-01-02 12:21 ` Patil, Rachna
2012-01-03 6:43 ` Patil, Rachna
2012-03-04 16:03 ` Dmitry Torokhov
0 siblings, 2 replies; 10+ messages in thread
From: Patil, Rachna @ 2012-01-02 12:21 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input@vger.kernel.org
Hi Dmitry,
Thanks for the patch.
Please find my comments inline.
On Fri, Dec 30, 2011 at 09:25:21, Dmitry Torokhov wrote:
> Hi Rachna,
>
>
> On Fri, Dec 09, 2011 at 04:59:42PM +0530, Patil, Rachna wrote:
> > From: Rachna Patil <rachna@ti.com>
> >
> > This patch adds support for TI's touchscreen controller for a 4/5/8
> > wire resistive panel that is directly fed to the ADC.
> >
> > This touchscreen controller will be part of AM335x TI SoC. The TRM can
> > be found at:
> > http://www.ti.com/lit/ug/spruh73a/spruh73a.pdf
> >
>
> This looks mostly good, could you also try the patch below (on top of
> yours) and let me know if the driver still works?
>
> Thanks!
>
> --
> Dmitry
>
>
> Input: ti_tscadc - misc changes
>
> From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>
> - rely on input core to implement defuzzing (filtering out smaller
> variations in coordinates);
> - release the 2nd clock after getting its rate;
> - IRQF_DISABLE is obsolete;
> - split filtering of measurements into a separate function;
> - misc formatting changes;
>
> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
> ---
>
> drivers/input/touchscreen/ti_tscadc.c | 244 ++++++++++++++++-----------------
> 1 files changed, 115 insertions(+), 129 deletions(-)
>
>
> diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c
> index ed6f1eb..8d23f5f 100644
> --- a/drivers/input/touchscreen/ti_tscadc.c
> +++ b/drivers/input/touchscreen/ti_tscadc.c
> @@ -87,17 +87,17 @@
> #define SEQ_SETTLE 275
> #define ADC_CLK 3000000
> #define MAX_12BIT ((1 << 12) - 1)
> +#define TSCADC_FUZZ_X 15
> +#define TSCADC_FUZZ_Y 15
>
> struct tscadc {
> struct input_dev *input;
> struct clk *tsc_ick;
> - int irq;
> - int pen;
> - int wires;
> - int x_plate_resistance;
> - unsigned int bckup_x;
> - unsigned int bckup_y;
> void __iomem *tsc_base;
> + unsigned int irq;
> + unsigned int wires;
> + unsigned int x_plate_resistance;
> + bool pen_down;
> };
>
> static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
> @@ -111,7 +111,7 @@ static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
> writel(val, tsc->tsc_base + reg);
> }
>
> -static void tsc_step_config(struct tscadc *ts_dev)
> +static void tscadc_step_config(struct tscadc *ts_dev)
> {
> unsigned int config;
> int i;
> @@ -122,8 +122,7 @@ static void tsc_step_config(struct tscadc *ts_dev)
> STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP;
> switch (ts_dev->wires) {
> case 4:
> - config |= STEPCONFIG_INP |
> - STEPCONFIG_XNN;
> + config |= STEPCONFIG_INP | STEPCONFIG_XNN;
> break;
> case 5:
> config |= STEPCONFIG_YNN |
> @@ -131,10 +130,10 @@ static void tsc_step_config(struct tscadc *ts_dev)
> STEPCONFIG_YPP;
> break;
> case 8:
> - config |= STEPCONFIG_INP |
> - STEPCONFIG_XNN;
> + config |= STEPCONFIG_INP | STEPCONFIG_XNN;
> break;
> }
> +
> for (i = 1; i < 7; i++) {
> tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
> tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
> @@ -156,6 +155,7 @@ static void tsc_step_config(struct tscadc *ts_dev)
> config |= STEPCONFIG_YPP;
> break;
> }
> +
> for (i = 7; i < 13; i++) {
> tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
> tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
> @@ -185,9 +185,9 @@ static void tsc_step_config(struct tscadc *ts_dev)
> tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
> }
>
> -static void tsc_idle_config(struct tscadc *ts_config)
> +static void tscadc_idle_config(struct tscadc *ts_config)
> {
> - unsigned int idleconfig;
> + unsigned int idleconfig;
>
> idleconfig = STEPCONFIG_YNN |
> STEPCONFIG_INM |
> @@ -195,83 +195,78 @@ static void tsc_idle_config(struct tscadc *ts_config)
> tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig);
> }
>
> -static irqreturn_t interrupt(int irq, void *dev)
> +static void tscadc_read_coordinates(struct tscadc *ts_dev,
> + unsigned int *x, unsigned int *y)
> {
> - struct tscadc *ts_dev = (struct tscadc *)dev;
> - struct input_dev *input_dev = ts_dev->input;
> - unsigned int status, irqclr = 0;
> - unsigned int read, diff;
> - unsigned int prev_val_x = ~0, prev_val_y = ~0;
> - unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
> - unsigned int val_x = 0, val_y = 0, diffx = 0, diffy = 0;
> - unsigned int z1 = 0, z2 = 0, z = 0;
> - int i, fsm, fifocount;
> + unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT);
> + unsigned int prev_val_x = ~0, prev_val_y = ~0;
> + unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
> + unsigned int read, diff;
> + unsigned int i;
>
> - status = tscadc_readl(ts_dev, REG_IRQSTATUS);
> - if (status & IRQENB_FIFO1THRES) {
> - fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT);
> -
> - /* Delta filter is used to remove large variations
> - * in sampled values from ADC. The filter tries to
> - * predict where the next coordinate could be.
> - * This is done by taking a previous coordinate and
> - * subtracting it form current one. Further the
> - * algorithm compares the difference with that of
> - * a present value, if true the value is reported
> - * to the sub system.
> - */
> - for (i = 0; i < (fifocount-1); i++) {
> - read = ((tscadc_readl(ts_dev, REG_FIFO0)) & 0xfff);
> - diff = abs(read - prev_val_x);
> - if (diff < prev_diff_x) {
> - prev_diff_x = diff;
> - val_x = read;
> - }
> - prev_val_x = read;
> -
> - read = 0;
> - diff = 0;
> - read = ((tscadc_readl(ts_dev, REG_FIFO1)) & 0xfff);
> - diff = abs(read - prev_val_y);
> - if (diff < prev_diff_y) {
> - prev_diff_y = diff;
> - val_y = read;
> - }
> - prev_val_y = read;
> + /*
> + * Delta filter is used to remove large variations
> + * in sampled values from ADC. The filter tries to
> + * predict where the next coordinate could be.
> + * This is done by taking a previous coordinate and
> + * subtracting it form current one. Further the
> + * algorithm compares the difference with that of
> + * a present value, if true the value is reported
> + * to the sub system.
> + */
> + for (i = 0; i < fifocount - 1; i++) {
> + read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
> + diff = abs(read - prev_val_x);
> + if (diff < prev_diff_x) {
> + prev_diff_x = diff;
> + *x = read;
> }
> + prev_val_x = read;
>
> - diffx = abs(val_x - (ts_dev->bckup_x));
> - diffy = abs(val_y - (ts_dev->bckup_y));
> - ts_dev->bckup_x = val_x;
> - ts_dev->bckup_y = val_y;
> -
> - z1 = ((tscadc_readl(ts_dev, REG_FIFO0)) & 0xfff);
> - z2 = ((tscadc_readl(ts_dev, REG_FIFO1)) & 0xfff);
> -
> - if (ts_dev->pen == 0) {
> - if ((z1 != 0) && (z2 != 0)) {
> - /* cal pressure using formula
> - * Resistance(touch) = x plate resistance *
> - * x postion/4096 * ((z2 / z1) - 1)
> - */
> - z = z2 - z1;
> - z *= val_x;
> - z *= ts_dev->x_plate_resistance;
> - z /= z1;
> - z = (z + 2047) >> 12;
> -
> - if ((diffx < 15) && (diffy < 15)
> - && (z <= MAX_12BIT)) {
Using defuzz alone does not solve the problem. I am trying to
filter out odd random values from the ADC that are incorrect
(Not only noise). Hence as explained I am using delta algorithm.
As a part of this algorithm I am checking for value being less than 15.
> - input_report_abs(input_dev,
> - ABS_X, val_x);
> - input_report_abs(input_dev,
> - ABS_Y, val_y);
> - input_report_abs(input_dev,
> - ABS_PRESSURE, z);
> - input_report_key(input_dev,
> - BTN_TOUCH, 1);
> - input_sync(input_dev);
> - }
> + read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
> + diff = abs(read - prev_val_y);
> + if (diff < prev_diff_y) {
> + prev_diff_y = diff;
> + *y = read;
> + }
> + prev_val_y = read;
> + }
> +}
> +
> +static irqreturn_t tscadc_irq(int irq, void *dev)
> +{
> + struct tscadc *ts_dev = dev;
> + struct input_dev *input_dev = ts_dev->input;
> + unsigned int status, irqclr = 0;
> + unsigned int x = 0, y = 0;
> + unsigned int z1, z2, z;
> + unsigned int fsm;
> +
> + status = tscadc_readl(ts_dev, REG_IRQSTATUS);
> + if (status & IRQENB_FIFO1THRES) {
> + tscadc_read_coordinates(ts_dev, &x, &y);
> +
> + z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
> + z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
> +
> + if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
> + /*
> + * Calculate pressure using formula
> + * Resistance(touch) = x plate resistance *
> + * x postion/4096 * ((z2 / z1) - 1)
> + */
> + z = z2 - z1;
> + z *= x;
> + z *= ts_dev->x_plate_resistance;
> + z /= z1;
> + z = (z + 2047) >> 12;
> +
> + if (z <= MAX_12BIT) {
> + input_report_abs(input_dev, ABS_X, x);
> + input_report_abs(input_dev, ABS_Y, y);
> + input_report_abs(input_dev, ABS_PRESSURE, z);
> + input_report_key(input_dev, BTN_TOUCH, 1);
> + input_sync(input_dev);
> }
> }
> irqclr |= IRQENB_FIFO1THRES;
> @@ -288,14 +283,12 @@ static irqreturn_t interrupt(int irq, void *dev)
> /* Pen up event */
> fsm = tscadc_readl(ts_dev, REG_ADCFSM);
> if (fsm == ADCFSM_STEPID) {
> - ts_dev->pen = 1;
> - ts_dev->bckup_x = 0;
> - ts_dev->bckup_y = 0;
> + ts_dev->pen_down = false;
> input_report_key(input_dev, BTN_TOUCH, 0);
> input_report_abs(input_dev, ABS_PRESSURE, 0);
> input_sync(input_dev);
> } else {
> - ts_dev->pen = 0;
> + ts_dev->pen_down = true;
> }
> irqclr |= IRQENB_PENUP;
> }
> @@ -309,18 +302,18 @@ static irqreturn_t interrupt(int irq, void *dev)
> }
>
> /*
> -* The functions for inserting/removing driver as a module.
> -*/
> + * The functions for inserting/removing driver as a module.
> + */
>
> -static int __devinit tscadc_probe(struct platform_device *pdev)
> +static int __devinit tscadc_probe(struct platform_device *pdev)
> {
> - const struct tsc_data *pdata = pdev->dev.platform_data;
> - struct resource *res;
> - struct tscadc *ts_dev;
> - struct input_dev *input_dev;
> - struct clk *clk;
> - int err;
> - int clk_value, ctrl;
> + const struct tsc_data *pdata = pdev->dev.platform_data;
> + struct resource *res;
> + struct tscadc *ts_dev;
> + struct input_dev *input_dev;
> + struct clk *clk;
> + int err;
> + int clk_value, ctrl, irq;
>
> if (!pdata) {
> dev_err(&pdev->dev, "missing platform data.\n");
> @@ -333,6 +326,12 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
> return -EINVAL;
> }
>
> + irq = platform_get_irq(pdev, 0);
> + if (irq < 0) {
> + dev_err(&pdev->dev, "no irq ID is specified.\n");
> + return -EINVAL;
> + }
> +
> /* Allocate memory for device */
> ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
> input_dev = input_allocate_device();
> @@ -342,7 +341,6 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
> goto err_free_mem;
> }
>
> - ts_dev->irq = platform_get_irq(pdev, 0);
> if (ts_dev->irq < 0) {
> dev_err(&pdev->dev, "no irq ID is specified.\n");
> err = -ENODEV;
> @@ -350,11 +348,11 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
> }
>
> ts_dev->input = input_dev;
> + ts_dev->irq = irq;
> ts_dev->wires = pdata->wires;
> ts_dev->x_plate_resistance = pdata->x_plate_resistance;
> - ts_dev->pen = 1;
>
> - res = request_mem_region(res->start, resource_size(res), pdev->name);
> + res = request_mem_region(res->start, resource_size(res), pdev->name);
> if (!res) {
> dev_err(&pdev->dev, "failed to reserve registers.\n");
> err = -EBUSY;
> @@ -368,8 +366,8 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
> goto err_release_mem_region;
> }
>
> - err = request_irq(ts_dev->irq, interrupt, IRQF_DISABLED,
> - pdev->dev.driver->name, ts_dev);
> + err = request_irq(ts_dev->irq, tscadc_irq,
> + 0, pdev->dev.driver->name, ts_dev);
> if (err) {
> dev_err(&pdev->dev, "failed to allocate irq.\n");
> goto err_unmap_regs;
> @@ -390,18 +388,18 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
> }
>
> clk_value = clk_get_rate(clk) / ADC_CLK;
> + clk_put(clk);
> +
> if (clk_value < 7) {
> dev_err(&pdev->dev, "clock input less than min clock requirement\n");
> goto err_disable_clk;
> }
> /* CLKDIV needs to be configured to the value minus 1 */
> - clk_value = clk_value - 1;
> - tscadc_writel(ts_dev, REG_CLKDIV, clk_value);
> + tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1);
>
> /* Enable wake-up of the SoC using touchscreen */
> tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB);
>
> -
> ctrl = CNTRLREG_STEPCONFIGWRT |
> CNTRLREG_TSCENB |
> CNTRLREG_STEPID;
> @@ -418,9 +416,9 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
> }
> tscadc_writel(ts_dev, REG_CTRL, ctrl);
>
> - tsc_idle_config(ts_dev);
> + tscadc_idle_config(ts_dev);
> tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES);
> - tsc_step_config(ts_dev);
> + tscadc_step_config(ts_dev);
> tscadc_writel(ts_dev, REG_FIFO1THR, 6);
>
> ctrl |= CNTRLREG_TSCSSENB;
> @@ -432,8 +430,8 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
> input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
> input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
>
> - input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
> - input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
> + input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, TSCADC_FUZZ_X, 0);
> + input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, TSCADC_FUZZ_Y, 0);
> input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
>
> /* register to the input system */
> @@ -461,8 +459,8 @@ err_free_mem:
>
> static int __devexit tscadc_remove(struct platform_device *pdev)
> {
> - struct tscadc *ts_dev = platform_get_drvdata(pdev);
> - struct resource *res;
> + struct tscadc *ts_dev = platform_get_drvdata(pdev);
> + struct resource *res;
>
> free_irq(ts_dev->irq, ts_dev);
>
> @@ -485,24 +483,12 @@ static struct platform_driver ti_tsc_driver = {
> .probe = tscadc_probe,
> .remove = __devexit_p(tscadc_remove),
> .driver = {
> - .name = "tsc",
> - .owner = THIS_MODULE,
> + .name = "tsc",
> + .owner = THIS_MODULE,
> },
> };
> -
> -static int __init ti_tsc_init(void)
> -{
> - return platform_driver_register(&ti_tsc_driver);
> -}
> -module_init(ti_tsc_init);
> -
> -static void __exit ti_tsc_exit(void)
> -{
> - platform_driver_unregister(&ti_tsc_driver);
> -}
> -module_exit(ti_tsc_exit);
> +module_platform_driver(ti_tsc_driver);
>
> MODULE_DESCRIPTION("TI touchscreen controller driver");
> MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
> MODULE_LICENSE("GPL");
> -
>
Regards,
Rachna.
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH v2] input: add support for TI Touchscreen controller
2012-01-02 12:21 ` Patil, Rachna
@ 2012-01-03 6:43 ` Patil, Rachna
2012-01-05 5:50 ` Patil, Rachna
2012-03-04 16:03 ` Dmitry Torokhov
1 sibling, 1 reply; 10+ messages in thread
From: Patil, Rachna @ 2012-01-03 6:43 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input@vger.kernel.org
Hi Dmitry,
On Mon, Jan 02, 2012 at 17:51:59, Patil, Rachna wrote:
> Hi Dmitry,
> Thanks for the patch.
> Please find my comments inline.
>
> On Fri, Dec 30, 2011 at 09:25:21, Dmitry Torokhov wrote:
> > Hi Rachna,
> >
> >
> > On Fri, Dec 09, 2011 at 04:59:42PM +0530, Patil, Rachna wrote:
> > > From: Rachna Patil <rachna@ti.com>
> > >
> > > This patch adds support for TI's touchscreen controller for a 4/5/8
> > > wire resistive panel that is directly fed to the ADC.
> > >
> > > This touchscreen controller will be part of AM335x TI SoC. The TRM
> > > can be found at:
> > > http://www.ti.com/lit/ug/spruh73a/spruh73a.pdf
> > >
> >
> > This looks mostly good, could you also try the patch below (on top of
> > yours) and let me know if the driver still works?
> >
> > Thanks!
> >
> > --
> > Dmitry
> >
> >
> > Input: ti_tscadc - misc changes
> >
> > From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> >
> > - rely on input core to implement defuzzing (filtering out smaller
> > variations in coordinates);
> > - release the 2nd clock after getting its rate;
> > - IRQF_DISABLE is obsolete;
> > - split filtering of measurements into a separate function;
> > - misc formatting changes;
> >
> > Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
> > ---
> >
> > drivers/input/touchscreen/ti_tscadc.c | 244
> > ++++++++++++++++-----------------
> > 1 files changed, 115 insertions(+), 129 deletions(-)
<SNIP>
> > + /*
> > + * Delta filter is used to remove large variations
> > + * in sampled values from ADC. The filter tries to
> > + * predict where the next coordinate could be.
> > + * This is done by taking a previous coordinate and
> > + * subtracting it form current one. Further the
> > + * algorithm compares the difference with that of
> > + * a present value, if true the value is reported
> > + * to the sub system.
> > + */
> > + for (i = 0; i < fifocount - 1; i++) {
> > + read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
> > + diff = abs(read - prev_val_x);
> > + if (diff < prev_diff_x) {
> > + prev_diff_x = diff;
> > + *x = read;
> > }
> > + prev_val_x = read;
> >
> > - diffx = abs(val_x - (ts_dev->bckup_x));
> > - diffy = abs(val_y - (ts_dev->bckup_y));
> > - ts_dev->bckup_x = val_x;
> > - ts_dev->bckup_y = val_y;
> > -
> > - z1 = ((tscadc_readl(ts_dev, REG_FIFO0)) & 0xfff);
> > - z2 = ((tscadc_readl(ts_dev, REG_FIFO1)) & 0xfff);
> > -
> > - if (ts_dev->pen == 0) {
> > - if ((z1 != 0) && (z2 != 0)) {
> > - /* cal pressure using formula
> > - * Resistance(touch) = x plate resistance *
> > - * x postion/4096 * ((z2 / z1) - 1)
> > - */
> > - z = z2 - z1;
> > - z *= val_x;
> > - z *= ts_dev->x_plate_resistance;
> > - z /= z1;
> > - z = (z + 2047) >> 12;
> > -
> > - if ((diffx < 15) && (diffy < 15)
> > - && (z <= MAX_12BIT)) {
>
> Using defuzz alone does not solve the problem. I am trying to filter out odd random values from the ADC that are incorrect (Not only noise). Hence as explained I am using delta algorithm.
> As a part of this algorithm I am checking for value being less than 15.
I will apply your patch on top of the driver and also submit an incremental patch
that will include changes for touchscreen to work as expected on my setup.
This way we can come to a conclusion on the driver.
>
> > - input_report_abs(input_dev,
> > - ABS_X, val_x);
> > - input_report_abs(input_dev,
> > - ABS_Y, val_y);
> > - input_report_abs(input_dev,
> > - ABS_PRESSURE, z);
> > - input_report_key(input_dev,
> > - BTN_TOUCH, 1);
> > - input_sync(input_dev);
> > - }
> > + read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
> > + diff = abs(read - prev_val_y);
> > + if (diff < prev_diff_y) {
> > + prev_diff_y = diff;
> > + *y = read;
> > + }
> > + prev_val_y = read;
> > + }
> > +}
> > +
<SNIP>
Regards,
Rachna.
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH v2] input: add support for TI Touchscreen controller
2012-01-03 6:43 ` Patil, Rachna
@ 2012-01-05 5:50 ` Patil, Rachna
0 siblings, 0 replies; 10+ messages in thread
From: Patil, Rachna @ 2012-01-05 5:50 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input@vger.kernel.org
Hi Dmitry,
<SNIP>
> > > -
> > > - if (ts_dev->pen == 0) {
> > > - if ((z1 != 0) && (z2 != 0)) {
> > > - /* cal pressure using formula
> > > - * Resistance(touch) = x plate resistance *
> > > - * x postion/4096 * ((z2 / z1) - 1)
> > > - */
> > > - z = z2 - z1;
> > > - z *= val_x;
> > > - z *= ts_dev->x_plate_resistance;
> > > - z /= z1;
> > > - z = (z + 2047) >> 12;
> > > -
> > > - if ((diffx < 15) && (diffy < 15)
> > > - && (z <= MAX_12BIT)) {
> >
> > Using defuzz alone does not solve the problem. I am trying to filter out odd random values from the ADC that are incorrect (Not only noise). Hence as explained I am using delta algorithm.
> > As a part of this algorithm I am checking for value being less than 15.
>
> I will apply your patch on top of the driver and also submit an incremental patch that will include changes for touchscreen to work as expected on my setup.
> This way we can come to a conclusion on the driver.
>
Can you try the patch below on top of your patch and
let me know if this is good?
From: Patil, Rachna <rachna@ti.com>
Subject: Input: ti_tscadc.c
Changes made to add delta difference to get touchscreen
working accordingly
Signed-off-by: Patil, Rachna <rachna@ti.com>---
drivers/input/touchscreen/ti_tscadc.c | 19 ++++++++++++++-----
1 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c
index 8d23f5f..8887c76 100644
--- a/drivers/input/touchscreen/ti_tscadc.c
+++ b/drivers/input/touchscreen/ti_tscadc.c
@@ -87,8 +87,8 @@
#define SEQ_SETTLE 275
#define ADC_CLK 3000000
#define MAX_12BIT ((1 << 12) - 1)
-#define TSCADC_FUZZ_X 15
-#define TSCADC_FUZZ_Y 15
+#define TSCADC_DELTA_X 15
+#define TSCADC_DELTA_Y 15
struct tscadc {
struct input_dev *input;
@@ -97,6 +97,8 @@ struct tscadc {
unsigned int irq;
unsigned int wires;
unsigned int x_plate_resistance;
+ unsigned int bckup_x;
+ unsigned int bckup_y;
bool pen_down;
};
@@ -239,6 +241,7 @@ static irqreturn_t tscadc_irq(int irq, void *dev)
struct input_dev *input_dev = ts_dev->input;
unsigned int status, irqclr = 0;
unsigned int x = 0, y = 0;
+ unsigned int diffx, diffy;
unsigned int z1, z2, z;
unsigned int fsm;
@@ -246,6 +249,11 @@ static irqreturn_t tscadc_irq(int irq, void *dev)
if (status & IRQENB_FIFO1THRES) {
tscadc_read_coordinates(ts_dev, &x, &y);
+ diffx = abs(x - (ts_dev->bckup_x));
+ diffy = abs(y - (ts_dev->bckup_y));
+ ts_dev->bckup_x = x;
+ ts_dev->bckup_y = y;
+
z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
@@ -261,7 +269,8 @@ static irqreturn_t tscadc_irq(int irq, void *dev)
z /= z1;
z = (z + 2047) >> 12;
- if (z <= MAX_12BIT) {
+ if ((z <= MAX_12BIT) && (diffx < TSCADC_DELTA_X) &&
+ (diffy < TSCADC_DELTA_Y)){
input_report_abs(input_dev, ABS_X, x);
input_report_abs(input_dev, ABS_Y, y);
input_report_abs(input_dev, ABS_PRESSURE, z);
@@ -430,8 +439,8 @@ static int __devinit tscadc_probe(struct platform_device *pdev)
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, TSCADC_FUZZ_X, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, TSCADC_FUZZ_Y, 0);
+ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
/* register to the input system */
--
1.7.1
Regards,
Rachna.
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2] input: add support for TI Touchscreen controller
2012-01-02 12:21 ` Patil, Rachna
2012-01-03 6:43 ` Patil, Rachna
@ 2012-03-04 16:03 ` Dmitry Torokhov
1 sibling, 0 replies; 10+ messages in thread
From: Dmitry Torokhov @ 2012-03-04 16:03 UTC (permalink / raw)
To: Patil, Rachna; +Cc: linux-input@vger.kernel.org
Hi Rachna,
Sorry for not replying earlier.
On Mon, Jan 02, 2012 at 12:21:59PM +0000, Patil, Rachna wrote:
> On Fri, Dec 30, 2011 at 09:25:21, Dmitry Torokhov wrote:
> > -
> > - if (ts_dev->pen == 0) {
> > - if ((z1 != 0) && (z2 != 0)) {
> > - /* cal pressure using formula
> > - * Resistance(touch) = x plate resistance *
> > - * x postion/4096 * ((z2 / z1) - 1)
> > - */
> > - z = z2 - z1;
> > - z *= val_x;
> > - z *= ts_dev->x_plate_resistance;
> > - z /= z1;
> > - z = (z + 2047) >> 12;
> > -
> > - if ((diffx < 15) && (diffy < 15)
> > - && (z <= MAX_12BIT)) {
>
> Using defuzz alone does not solve the problem. I am trying to
> filter out odd random values from the ADC that are incorrect
> (Not only noise). Hence as explained I am using delta algorithm.
> As a part of this algorithm I am checking for value being less than 15.
>
Ah, yes, I misread the original code. But would not that mean that quick
gestures across the screen (resulting in delta being greater than 15)
would be refused as invalid?
Anyway, tslib (the library that is normally used to interface with
touchscreens) has, among many other useful thngs, a 'variance' filter
that should implement what you are trying to do in kernel. What I am
going to do is apply the version of the driver that does not do the
variance filtering (but still has the delta filtering of data in FIFO
queue). We can revisit doing variance (in kernel or elsewhere) if tslib
is not working fot you at a later time.
Thanks.
--
Dmitry
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2012-03-04 22:09 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-09 11:29 [PATCH v2] input: add support for TI Touchscreen controller Patil, Rachna
2011-12-30 3:55 ` Dmitry Torokhov
2012-01-02 12:21 ` Patil, Rachna
2012-01-03 6:43 ` Patil, Rachna
2012-01-05 5:50 ` Patil, Rachna
2012-03-04 16:03 ` Dmitry Torokhov
-- strict thread matches above, loose matches on Subject: below --
2011-07-14 5:02 [PATCH V2] " Patil, Rachna
2011-07-20 13:12 ` Patil, Rachna
2011-07-22 6:35 ` Dmitry Torokhov
2011-07-22 9:12 ` Patil, Rachna
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).