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

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

 



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@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)) {

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@xxxxxx>");
>  MODULE_LICENSE("GPL");
> -
> 


Regards,
Rachna.

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