Re: [PATCH v2] input: add support for TI Touchscreen controller

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Rachna,


On Fri, Dec 09, 2011 at 04:59:42PM +0530, Patil, Rachna wrote:
> From: Rachna Patil <rachna@xxxxxx>
> 
> 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@xxxxxxxxx>

- 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@xxxxxxx>
---

 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@xxxxxx>");
 MODULE_LICENSE("GPL");
-
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux