This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SPI Bus 2.0 - ads7846 spi2.0: no device detected, test read result was 0x00000000

Other Parts Discussed in Thread: ADS7846, DM3730, TSC2046, ADS7806

Hi


I am using an external touch controller with DM3730 which is TCS2046. Its is same as ADS7846. The issue I have is that I can not read nor write from this bus. I have followed the procedure as below with no joy and hope someone can point me in right Direction

static struct spi_board_info VAR_SOM_OM3X_spi_board_info[] = {

            [0] = {

                        .modalias                      = "ads7846",

                        .bus_num                      = 2,

                        .chip_select                  = 0,

                        .max_speed_hz             = 1500000,

                        .controller_data = &ads7846_mcspi_config,

                        .irq                               = OMAP_GPIO_IRQ(VAR_SOM_OM3X_TS_GPIO),

                        .platform_data              = &ads7846_config,

            },

};

 

In u-boot I have added MUX VAL as

 

            MUX_VAL(CP(ETK_D13_ES2),    (IEN  | PTD | DIS | M4)) /*GPIO_27 nTOUCH_IRQ*/\

 

            MUX_VAL(CP(MCSPI2_CLK),                (IEN  | PTD | DIS | M0)) /*McSPI2_CLK*/\

            MUX_VAL(CP(MCSPI2_SIMO),              (IEN  | PTD | DIS | M0)) /*McSPI2_SIMO  */\

            MUX_VAL(CP(MCSPI2_SOMI),              (IEN  | PTD | DIS | M0)) /*McSPI2_SOMI  */\

            MUX_VAL(CP(MCSPI2_CS0),                (IEN  | PTD | DIS | M0)) /*McSPI2_CS0*/\

            MUX_VAL(CP(MCSPI2_CS1),                (IDIS | PTD | DIS  | M4)) /*McSPI2_CS1*/

the log message i am getting is

The log message I am getting is

[    3.561218] ads7846 spi2.0: touchscreen, irq 187
[    3.575164] ads7846 spi2.0: no device detected, test read result was 0x00000000

Not sure where I have gone wrong. Any help would be great.

  • Hi,

    Please share your complete bootup log and your modified oard file.

  • Hi Titusra,

    Here is what I have. I am trying to get touch working using custom made board. On variscite SOM SPI1 is used but I have another touch controller I am using which is TSC2046. The 4 wire touch screen is connected to the controller and the controller to the SOM. The GPIO_27 is used as Touch IRQ. Hope this helps.

    7103.HAWKIII.txt

    6433.board-var-som-om3x.c

  • Hi,

    Which touch screen controller want to work ?

    Is this AD7846 or TSC2046 ?

    Your code seems to modified for ADs7846, If you have ADS7806 TS controller on board, definitely should work.

  • Hi,


    It is for TSC2046. It should work but I think I know the problem and not sure hoe to fix it. The TS+X, TS+Y, TS-X, TS-Y are not connected directly to SOM the SPI2 data needs to somehow get into touchdriver. Also looking at file ADS7846 it says in the top comments that "TSC2046 is just newer ads7846 silicon" which means it should read and write to the device but I am not sure what I have done wrong or what I am missing.

  • Hi,

    You have to use dedicated TSC2046 linux driver and board file configuration.

    Please try to apply this patch and update us.

    1)

    http://www.spinics.net/lists/linux-input/msg06312.html

    2)

    https://gitorious.org/omap3camera/mainline/source/78e73e07e27783951ba64da4a3012b84b43b7b90:drivers/input/touchscreen/tsc2046_ts.c

    ---
     arch/arm/mach-omap2/board-2430sdp.c    |   32 +
     drivers/input/touchscreen/Kconfig      |    6 
     drivers/input/touchscreen/Makefile     |    1 
     drivers/input/touchscreen/tsc2046_ts.c |  555 +++++++++++++++++++++++++++++++++
     include/linux/spi/tsc2046.h            |   60 +++
     5 files changed, 654 insertions(+)
    
    Index: dev/arch/arm/mach-omap2/board-2430sdp.c
    ===================================================================
    --- dev.orig/arch/arm/mach-omap2/board-2430sdp.c
    +++ dev/arch/arm/mach-omap2/board-2430sdp.c
    @@ -21,6 +21,8 @@
     #include <linux/delay.h>
     #include <linux/err.h>
     #include <linux/clk.h>
    +#include <linux/spi/spi.h>
    +#include <linux/spi/tsc2046.h>
     
     #include <asm/hardware.h>
     #include <asm/mach-types.h>
    @@ -33,6 +35,7 @@
     #include <asm/arch/board.h>
     #include <asm/arch/common.h>
     #include <asm/arch/gpmc.h>
    +#include <asm/arch/mcspi.h>
     #include "prcm-regs.h"
     
     #include <asm/io.h>
    @@ -40,6 +43,9 @@
     #define	SDP2430_FLASH_CS	0
     #define	SDP2430_SMC91X_CS	5
     
    +/* TSC2046 (touchscreen) */
    +#define TS_GPIO                 24
    +
     static struct mtd_partition sdp2430_partitions[] = {
     	/* bootloader (U-Boot, etc) in first sector */
     	{
    @@ -119,6 +125,29 @@ static struct platform_device *sdp2430_d
     	&sdp2430_flash_device,
     };
     
    +static struct tsc2046_platform_data tsc2046_config = {
    +	.dav_gpio       = TS_GPIO,
    +	.gpio_debounce  = 0xa,
    +};
    +
    +static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
    +	.turbo_mode	= 0,
    +	.single_channel = 0,  /* 0: slave, 1: master */
    +};
    +
    +static struct spi_board_info sdp2430_spi_board_info[] __initdata = {
    +	[0] = {
    +		/* TSC2046 operates at a max freqency of 2MHz, so
    +		 * operate slightly below at 1.5MHz */
    +		.modalias	= "tsc2046",
    +		.bus_num	= 1,
    +		.chip_select	= 0,
    +		.max_speed_hz   = 1500000,
    +		.controller_data= &tsc2046_mcspi_config,
    +		.platform_data  = &tsc2046_config,
    +	},
    +};
    +
     static inline void __init sdp2430_init_smc91x(void)
     {
     	int eth_cs;
    @@ -198,6 +227,9 @@ static void __init omap_2430sdp_init(voi
     	omap_board_config = sdp2430_config;
     	omap_board_config_size = ARRAY_SIZE(sdp2430_config);
     	omap_serial_init();
    +
    +	spi_register_board_info(sdp2430_spi_board_info,
    +				ARRAY_SIZE(sdp2430_spi_board_info));
     }
     
     static void __init omap_2430sdp_map_io(void)
    Index: dev/drivers/input/touchscreen/Kconfig
    ===================================================================
    --- dev.orig/drivers/input/touchscreen/Kconfig
    +++ dev/drivers/input/touchscreen/Kconfig
    @@ -165,4 +165,10 @@ config TOUCHSCREEN_TSC2301
     	help
     	  Say Y here for if you are using the touchscreen features of TSC2301.
     
    +config TOUCHSCREEN_TSC2046
    +	tristate "TSC2046 touchscreen support"
    +	default MACH_OMAP2430SDP
    +	  help
    +	  Say Y here for if you are using the touchscreen features of TSC2046
    +
     endif
    Index: dev/drivers/input/touchscreen/Makefile
    ===================================================================
    --- dev.orig/drivers/input/touchscreen/Makefile
    +++ dev/drivers/input/touchscreen/Makefile
    @@ -19,3 +19,4 @@ obj-$(CONFIG_TOUCHSCREEN_UCB1400)	+= ucb
     obj-$(CONFIG_TOUCHSCREEN_TSC2102)	+= tsc2102_ts.o
     obj-$(CONFIG_TOUCHSCREEN_OMAP)	+= omap/
     obj-$(CONFIG_TOUCHSCREEN_TSC2301)	+= tsc2301_ts.o
    +obj-$(CONFIG_TOUCHSCREEN_TSC2046)	+= tsc2046_ts.o
    Index: dev/drivers/input/touchscreen/tsc2046_ts.c
    ===================================================================
    --- /dev/null
    +++ dev/drivers/input/touchscreen/tsc2046_ts.c
    @@ -0,0 +1,555 @@
    +/*
    + * TSC2046 Touchscreen driver
    + *
    + * Author: Kevin Hilman, MontaVista Software, Inc. <source at mvista.com>
    + *
    + * Communication details from original TI driver
    + * Copyright (C) 2004-2005 Texas Instruments, Inc.
    + *
    + * Structure based heavily on TSC2301 driver
    + * Copyright (C) 2005-2006 Nokia Corporation
    + *
    + * 2007 (c) MontaVista Software, Inc. This file is licensed under
    + * the terms of the GNU General Public License version 2. This program
    + * is licensed "as is" without any warranty of any kind, whether express
    + * or implied.
    + *
    + */
    +
    +#include <linux/kernel.h>
    +#include <linux/module.h>
    +#include <linux/input.h>
    +#include <linux/interrupt.h>
    +#include <linux/delay.h>
    +#include <linux/spi/spi.h>
    +
    +#ifdef CONFIG_ARCH_OMAP
    +#include <asm/arch/gpio.h>
    +#endif
    +
    +#include <linux/spi/tsc2046.h>
    +
    +/* TSC2046 commands */
    +#define START_BYTE		0x8000
    +#define	X_CMDWD			0xd300
    +#define Y_CMDWD			0x9300
    +#define Z1_CMDWD		0xb300
    +#define Z2_CMDWD		0xc300
    +
    +#define TSC2046_TS_SCAN_TIME	1
    +#define MAX_12BIT		((1 << 12) - 1)
    +
    +struct tsc2046_ts {
    +	struct input_dev	*idev;
    +	char			phys[32];
    +	struct timer_list	timer;
    +	spinlock_t		lock;
    +
    +	struct spi_transfer	read_xfer[3];
    +	struct spi_message	read_msg;
    +	struct spi_message	enable_msg;
    +	u16                     data[5];
    +
    +	u16			x;
    +	u16			y;
    +	u16			p;
    +	int			sample_cnt;
    +
    +	int			ignore_last : 1;
    +	u16			x_plate_ohm;
    +	int			max_pressure;
    +	int			touch_pressure;
    +	int			pressure_limit;
    +
    +	u16			irq_enabled:1;
    +	u16			pen_down:1;
    +	u16			disabled:1;
    +	u16			pending:1;
    +
    +	s16			dav_gpio;
    +	int			irq;
    +};
    +
    +static const u16 tsc2046_ts_cmd_data[] = {
    +	START_BYTE, X_CMDWD, Y_CMDWD, Z1_CMDWD, Z2_CMDWD,
    +};
    +
    +static int device_suspended(struct device *dev)
    +{
    +	struct tsc2046 *tsc = dev_get_drvdata(dev);
    +	return dev->power.power_state.event != PM_EVENT_ON || tsc->ts->disabled;
    +}
    +
    +static void update_pen_state(struct tsc2046 *tsc, int x, int y, int pressure)
    +{
    +	struct tsc2046_ts *ts = tsc->ts;
    +	int sync = 0;
    +
    +	if (pressure) {
    +		input_report_abs(ts->idev, ABS_X, x);
    +		input_report_abs(ts->idev, ABS_Y, y);
    +		input_report_abs(ts->idev, ABS_PRESSURE, pressure);
    +		if (!ts->pen_down)
    +			input_report_key(ts->idev, BTN_TOUCH, 1);
    +		sync = 1;
    +	} else if (ts->pen_down) {
    +		input_report_abs(ts->idev, ABS_PRESSURE, 0);
    +		input_report_key(ts->idev, BTN_TOUCH, 0);
    +		sync = 1;
    +	}
    +
    +	if (sync)
    +		input_sync(ts->idev);
    +
    +	ts->pen_down = pressure ? 1 : 0;
    +
    +#ifdef VERBOSE
    +	dev_dbg(&tsc->spi->dev, "x %4d y %4d p %4d\n", x, y, pressure);
    +#endif
    +}
    +
    +#define CONV_DATA(d1, d2) \
    +  (((d1 & 0x7f) << 5) | ((d2 >> 11) & 0x1f))
    +
    +/*
    + * This procedure is called by the SPI framework after the coordinates
    + * have been read from TSC2046
    + */
    +static void tsc2046_ts_rx(void *arg)
    +{
    +	struct tsc2046 *tsc = arg;
    +	struct tsc2046_ts *ts = tsc->ts;
    +	unsigned int x, y, z1, z2, pressure;
    +
    +	x  = CONV_DATA(ts->data[2], ts->data[3]);
    +	y  = CONV_DATA(ts->data[1], ts->data[2]);
    +	z1 = CONV_DATA(ts->data[3], ts->data[4]);
    +	z2 = CONV_DATA(ts->data[4], 0);
    +
    +	if (z1) {
    +		pressure = ts->x_plate_ohm * x;
    +		pressure /= 4096;
    +		pressure *= z2 - z1;
    +		pressure /= z1;
    +	} else
    +		pressure = 0;
    +
    +	/* If pressure value is above a preset limit (pen is barely
    +	 * touching the screen) we can't trust the coordinate values.
    +	 */
    +	if (pressure < ts->pressure_limit && x < MAX_12BIT && y < MAX_12BIT) {
    +		ts->pressure_limit = ts->max_pressure;
    +		if (ts->ignore_last) {
    +			if (ts->sample_cnt)
    +				update_pen_state(tsc, ts->x, ts->y, ts->p);
    +			ts->x = x;
    +			ts->y = y;
    +			ts->p = pressure;
    +		} else
    +			update_pen_state(tsc, x, y, pressure);
    +		ts->sample_cnt++;
    +	}
    +
    +	mod_timer(&ts->timer,
    +		  jiffies + msecs_to_jiffies(TSC2046_TS_SCAN_TIME));
    +}
    +
    +static int is_pen_down(struct tsc2046_ts *ts)
    +{
    +	return ts->pen_down;
    +}
    +
    +/*
    + * Timer is called every TSC2046_TS_SCAN_TIME when the pen is down
    + */
    +static void tsc2046_ts_timer(unsigned long arg)
    +{
    +	struct tsc2046 *tsc = (void *) arg;
    +	struct tsc2046_ts *ts = tsc->ts;
    +	unsigned long flags;
    +	int ndav;
    +	int r;
    +
    +	spin_lock_irqsave(&ts->lock, flags);
    +	ndav = omap_get_gpio_datain(ts->dav_gpio);
    +	if (ndav || device_suspended(&tsc->spi->dev)) {
    +		/* Pen has been lifted */
    +		if (!device_suspended(&tsc->spi->dev) &&
    +		    !ts->irq_enabled) {
    +			ts->irq_enabled = 1;
    +			enable_irq(ts->irq);
    +		}
    +		update_pen_state(tsc, 0, 0, 0);
    +		ts->pending = 0;
    +		spin_unlock_irqrestore(&ts->lock, flags);
    +
    +	} else {
    +		ts->pen_down = 1;
    +		spin_unlock_irqrestore(&ts->lock, flags);
    +
    +		r = spi_async(tsc->spi, &ts->read_msg);
    +		if (r)
    +			dev_err(&tsc->spi->dev, "ts: spi_async() failed");
    +	}
    +}
    +
    +/*
    + * This interrupt is called when pen is down and first coordinates are
    + * available. That is indicated by a falling edge on DEV line.  IRQ is
    + * disabled here because while the pen is down the coordinates are
    + * read by a timer.
    + */
    +static irqreturn_t tsc2046_ts_irq_handler(int irq, void *dev_id)
    +{
    +	struct tsc2046 *tsc = dev_id;
    +	struct tsc2046_ts *ts = tsc->ts;
    +	unsigned long flags;
    +
    +	spin_lock_irqsave(&ts->lock, flags);
    +	if (ts->irq_enabled) {
    +		ts->irq_enabled = 0;
    +		disable_irq(ts->irq);
    +		ts->pending = 1;
    +		ts->pressure_limit = ts->touch_pressure;
    +		ts->sample_cnt = 0;
    +		mod_timer(&ts->timer,
    +			  jiffies + msecs_to_jiffies(TSC2046_TS_SCAN_TIME));
    +	}
    +	spin_unlock_irqrestore(&ts->lock, flags);
    +
    +	return IRQ_HANDLED;
    +}
    +
    +/* Must be called with ts->lock held */
    +static void tsc2046_ts_disable(struct tsc2046 *tsc)
    +{
    +	struct tsc2046_ts *ts = tsc->ts;
    +
    +	if (ts->disabled)
    +		return;
    +
    +	ts->disabled = 1;
    +	if (!ts->pending) {
    +		ts->irq_enabled = 0;
    +		disable_irq(ts->irq);
    +	} else {
    +		while (ts->pending) {
    +			spin_unlock_irq(&ts->lock);
    +			msleep(1);
    +			spin_lock_irq(&ts->lock);
    +		}
    +	}
    +}
    +
    +static void tsc2046_ts_enable(struct tsc2046 *tsc)
    +{
    +	struct tsc2046_ts *ts = tsc->ts;
    +
    +	if (!ts->disabled)
    +		return;
    +
    +	ts->disabled = 0;
    +	ts->irq_enabled = 1;
    +	enable_irq(ts->irq);
    +}
    +
    +#ifdef CONFIG_PM
    +int tsc2046_ts_suspend(struct tsc2046 *tsc)
    +{
    +	struct tsc2046_ts *ts = tsc->ts;
    +
    +	spin_lock_irq(&ts->lock);
    +	tsc2046_ts_disable(tsc);
    +	spin_unlock_irq(&ts->lock);
    +
    +	return 0;
    +}
    +
    +void tsc2046_ts_resume(struct tsc2046 *tsc)
    +{
    +	struct tsc2046_ts *ts = tsc->ts;
    +
    +	spin_lock_irq(&ts->lock);
    +	tsc2046_ts_enable(tsc);
    +	spin_unlock_irq(&ts->lock);
    +}
    +#endif
    +
    +static void tsc2046_ts_setup_spi_xfer(struct tsc2046 *tsc)
    +{
    +	struct tsc2046_ts *ts = tsc->ts;
    +	struct spi_message *m = &ts->read_msg;
    +	struct spi_transfer *x = &ts->read_xfer[1];
    +
    +	spi_message_init(m);
    +
    +	/* read and write data in one transaction */
    +	x->tx_buf = &tsc2046_ts_cmd_data;
    +	x->rx_buf = &ts->data;
    +	x->len    = 10;
    +	spi_message_add_tail(x, m);
    +
    +	/* send another START_BYTE to (re)enable pen interrupts */
    +	x++;
    +	x->tx_buf = &tsc2046_ts_cmd_data[0];
    +	x->len = 2;
    +	spi_message_add_tail(x, m);
    +
    +	m->complete = tsc2046_ts_rx;
    +	m->context = tsc;
    +}
    +
    +static ssize_t tsc2046_ts_pen_down_show(struct device *dev,
    +					struct device_attribute *attr,
    +					char *buf)
    +{
    +	struct tsc2046 *tsc = dev_get_drvdata(dev);
    +
    +	return sprintf(buf, "%u\n", is_pen_down(tsc->ts));
    +}
    +
    +static DEVICE_ATTR(pen_down, S_IRUGO, tsc2046_ts_pen_down_show, NULL);
    +
    +static ssize_t tsc2046_ts_disable_show(struct device *dev,
    +				       struct device_attribute *attr, char *buf)
    +{
    +	struct tsc2046		*tsc = dev_get_drvdata(dev);
    +	struct tsc2046_ts	*ts = tsc->ts;
    +
    +	return sprintf(buf, "%u\n", ts->disabled);
    +}
    +
    +static ssize_t tsc2046_ts_disable_store(struct device *dev,
    +					struct device_attribute *attr,
    +					const char *buf, size_t count)
    +{
    +	struct tsc2046		*tsc = dev_get_drvdata(dev);
    +	struct tsc2046_ts	*ts = tsc->ts;
    +	char *endp;
    +	int i;
    +
    +	i = simple_strtoul(buf, &endp, 10);
    +	spin_lock_irq(&ts->lock);
    +
    +	if (i)
    +		tsc2046_ts_disable(tsc);
    +	else
    +		tsc2046_ts_enable(tsc);
    +
    +	spin_unlock_irq(&ts->lock);
    +
    +	return count;
    +}
    +
    +static DEVICE_ATTR(disable_ts, 0664, tsc2046_ts_disable_show,
    +		   tsc2046_ts_disable_store);
    +
    +int __devinit tsc2046_ts_init(struct tsc2046 *tsc,
    +			      struct tsc2046_platform_data *pdata)
    +{
    +	struct tsc2046_ts *ts;
    +	struct input_dev *idev;
    +	int dav_gpio, r;
    +
    +	if (pdata->dav_gpio < 0) {
    +		dev_err(&tsc->spi->dev, "need DAV GPIO");
    +		return -EINVAL;
    +	}
    +	dav_gpio = pdata->dav_gpio;
    +
    +	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
    +	if (ts == NULL)
    +		return -ENOMEM;
    +	tsc->ts = ts;
    +
    +	ts->dav_gpio = dav_gpio;
    +#ifdef CONFIG_ARCH_OMAP
    +	r = omap_request_gpio(dav_gpio);
    +	if (r < 0) {
    +		dev_err(&tsc->spi->dev, "unable to get DAV GPIO");
    +		goto err1;
    +	}
    +	omap_set_gpio_direction(dav_gpio, 1);
    +	if (pdata->gpio_debounce) {
    +		omap_set_gpio_debounce(tsc->gpio, 1);
    +		omap_set_gpio_debounce_time(tsc->gpio, pdata->gpio_debounce);
    +	}
    +
    +	ts->irq = OMAP_GPIO_IRQ(dav_gpio);
    +#endif
    +	init_timer(&ts->timer);
    +	ts->timer.data = (unsigned long) tsc;
    +	ts->timer.function = tsc2046_ts_timer;
    +
    +	spin_lock_init(&ts->lock);
    +
    +	ts->x_plate_ohm	= pdata->ts_x_plate_ohm ? : 280;
    +	ts->max_pressure= pdata->ts_max_pressure ? : MAX_12BIT;
    +	ts->touch_pressure = pdata->ts_touch_pressure ? : ts->max_pressure;
    +	ts->ignore_last	= pdata->ts_ignore_last;
    +
    +	idev = input_allocate_device();
    +	if (idev == NULL) {
    +		r = -ENOMEM;
    +		goto err2;
    +	}
    +	idev->name = "TSC2046 touchscreen";
    +	snprintf(ts->phys, sizeof(ts->phys),
    +		 "%s/input-ts", tsc->spi->dev.bus_id);
    +	idev->phys = ts->phys;
    +
    +	idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
    +	idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
    +	ts->idev = idev;
    +
    +	tsc2046_ts_setup_spi_xfer(tsc);
    +
    +	/* These parameters should perhaps be configurable? */
    +	input_set_abs_params(idev, ABS_X, 0, 4096, 0, 0);
    +	input_set_abs_params(idev, ABS_Y, 0, 4096, 0, 0);
    +	input_set_abs_params(idev, ABS_PRESSURE, 0, 1024, 0, 0);
    +
    +	ts->irq_enabled = 1;
    +	r = request_irq(ts->irq, tsc2046_ts_irq_handler,
    +			SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
    +			"tsc2046-ts", tsc);
    +	if (r < 0) {
    +		dev_err(&tsc->spi->dev, "unable to get DAV IRQ");
    +		goto err3;
    +	}
    +	set_irq_wake(ts->irq, 1);
    +
    +	if (device_create_file(&tsc->spi->dev, &dev_attr_pen_down) < 0)
    +		goto err4;
    +	if (device_create_file(&tsc->spi->dev, &dev_attr_disable_ts) < 0)
    +		goto err5;
    +
    +	r = input_register_device(idev);
    +	if (r < 0) {
    +		dev_err(&tsc->spi->dev, "can't register touchscreen device\n");
    +		goto err6;
    +	}
    +
    +	/* kick off a transaction to enable pen interrupts */
    +	spi_async(tsc->spi, &ts->read_msg);
    +
    +	return 0;
    +err6:
    +	device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
    +err5:
    +	device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
    +err4:
    +	free_irq(ts->irq, tsc);
    +err3:
    +	input_free_device(idev);
    +err2:
    +#ifdef CONFIG_ARCH_OMAP
    +	omap_free_gpio(dav_gpio);
    +#endif
    + err1:
    +	kfree(ts);
    +	return r;
    +}
    +EXPORT_SYMBOL(tsc2046_ts_init);
    +
    +void __devexit tsc2046_ts_exit(struct tsc2046 *tsc)
    +{
    +	struct tsc2046_ts *ts = tsc->ts;
    +	unsigned long flags;
    +
    +	spin_lock_irqsave(&ts->lock, flags);
    +	tsc2046_ts_disable(tsc);
    +	spin_unlock_irqrestore(&ts->lock, flags);
    +
    +	device_remove_file(&tsc->spi->dev, &dev_attr_disable_ts);
    +	device_remove_file(&tsc->spi->dev, &dev_attr_pen_down);
    +
    +	free_irq(ts->irq, tsc);
    +	input_unregister_device(ts->idev);
    +
    +#ifdef CONFIG_ARCH_OMAP
    +	omap_free_gpio(ts->dav_gpio);
    +#endif
    +	kfree(ts);
    +}
    +EXPORT_SYMBOL(tsc2046_ts_exit);
    +
    +
    +static int __devinit tsc2046_probe(struct spi_device *spi)
    +{
    +	struct tsc2046			*tsc;
    +	struct tsc2046_platform_data	*pdata = spi->dev.platform_data;
    +	int r = -ENODEV;
    +
    +	dev_dbg(&spi->dev, "%s\n", __FUNCTION__);
    +
    +	if (!pdata) {
    +		dev_dbg(&spi->dev, "no platform data?\n");
    +		return -ENODEV;
    +	}
    +
    +	tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
    +	if (tsc == NULL)
    +		return -ENOMEM;
    +
    +	dev_set_drvdata(&spi->dev, tsc);
    +	tsc->spi = spi;
    +	spi->dev.power.power_state = PMSG_ON;
    +
    +	spi->mode = SPI_MODE_1;
    +	spi->bits_per_word = 16;
    +
    +	/* The max speed might've been defined by the board-specific
    +	 * struct */
    +	if (!spi->max_speed_hz)
    +		spi->max_speed_hz = TSC2046_HZ;
    +	spi_setup(spi);
    +
    +	r = tsc2046_ts_init(tsc, pdata);
    +	if (r)
    +		goto err1;
    +
    +	return 0;
    + err1:
    +	kfree(tsc);
    +	return r;
    +}
    +
    +static int __devexit tsc2046_remove(struct spi_device *spi)
    +{
    +	struct tsc2046 *tsc = dev_get_drvdata(&spi->dev);
    +
    +	dev_dbg(&tsc->spi->dev, "%s\n", __FUNCTION__);
    +
    +        tsc2046_ts_exit(tsc);
    +	kfree(tsc);
    +
    +	return 0;
    +}
    +
    +static struct spi_driver tsc2046_driver = {
    +	.driver = {
    +		   .name = "tsc2046",
    +		   .bus = &spi_bus_type,
    +		   .owner = THIS_MODULE,
    +	},
    +	.probe = tsc2046_probe,
    +	.remove = __devexit_p(tsc2046_remove),
    +};
    +
    +static int __init tsc2046_init(void)
    +{
    +	printk("TSC2046 driver initializing\n");
    +
    +	return spi_register_driver(&tsc2046_driver);
    +}
    +module_init(tsc2046_init);
    +
    +static void __exit tsc2046_exit(void)
    +{
    +	spi_unregister_driver(&tsc2046_driver);
    +}
    +module_exit(tsc2046_exit);
    +
    +MODULE_AUTHOR("Kevin Hilman <khilman at mvista.com>");
    +MODULE_LICENSE("GPL");
    Index: dev/include/linux/spi/tsc2046.h
    ===================================================================
    --- /dev/null
    +++ dev/include/linux/spi/tsc2046.h
    @@ -0,0 +1,60 @@
    +#ifndef _LINUX_SPI_TSC2046_H
    +#define _LINUX_SPI_TSC2046_H
    +
    +#include <linux/types.h>
    +#include <linux/timer.h>
    +
    +struct tsc2046_platform_data {
    +	s16	dav_gpio;
    +	s16	gpio_debounce;
    +	u16	ts_x_plate_ohm;
    +	u32	ts_max_pressure;  /* Samples with bigger pressure value will
    +				     be ignored, since the corresponding X, Y
    +				     values are unreliable */
    +	u32	ts_touch_pressure;/* Pressure limit until we report a
    +				     touch event. After that we switch
    +				     to ts_max_pressure. */
    +	unsigned ts_ignore_last : 1;
    +
    +};
    +
    +struct tsc2046_ts;
    +
    +struct tsc2046 {
    +	struct spi_device	*spi;
    +	int                     gpio;
    +
    +	struct tsc2046_ts	*ts;
    +};
    +
    +/* The TSC2046 operates at a maximum speed of 2MHz */
    +#define TSC2046_HZ	2000000
    +
    +#define TSC2046_DECL_MOD(module)					\
    +extern int  tsc2046_##module##_init(struct tsc2046 *tsc,		\
    +			   struct tsc2046_platform_data *pdata);	\
    +extern void tsc2046_##module##_exit(struct tsc2046 *tsc);		\
    +extern int  tsc2046_##module##_suspend(struct tsc2046 *tsc);		\
    +extern void tsc2046_##module##_resume(struct tsc2046 *tsc);
    +
    +#define TSC2046_DECL_EMPTY_MOD(module)					\
    +static inline int tsc2046_##module##_init(struct tsc2046 *tsc,		\
    +			   struct tsc2046_platform_data *pdata)		\
    +{									\
    +	return 0;							\
    +}									\
    +static inline void tsc2046_##module##_exit(struct tsc2046 *tsc) {}	\
    +static inline int  tsc2046_##module##_suspend(struct tsc2046 *tsc)	\
    +{									\
    +	return 0;							\
    +}									\
    +static inline void tsc2046_##module##_resume(struct tsc2046 *tsc) {}
    +
    +#if defined(CONFIG_TOUCHSCREEN_TSC2046) || \
    +    defined(CONFIG_TOUCHSCREEN_TSC2046_MODULE)
    +TSC2046_DECL_MOD(ts)
    +#else
    +TSC2046_DECL_EMPTY_MOD(ts)
    +#endif
    +
    +#endif
    

  • Hi,

    I am using Linux kernel 2.6.37 for gingerbread and it seems like this option to configure in kernel is not available for TSC2046. Can i just use this file TSC file and specify my modalias as tcs2046

    Regards


    Ali

  • Hi,


    I am not sure if I need that patch as board-3430sdp.c, board-igep0020.c and board-idp.c all use TSC2046 touch controller with ADS7846 driver. Also I am using this for gingerbread so not sure about the source yet. i'l have a dig at it and post an update.

  • Hi Titu S

    I am trying to apply the above patch but when compiling am getting erros. Can not find GPIO file. Is this obselete code I am using Linux Kernel 2.6.37

    drivers/input/touchscreen/tsc2046.c: In function 'tsc2046_ts_timer':
    drivers/input/touchscreen/tsc2046.c:176: error: implicit declaration of function 'omap_get_gpio_datain'
    drivers/input/touchscreen/tsc2046.c: In function 'tsc2046_ts_init':
    drivers/input/touchscreen/tsc2046.c:369: error: implicit declaration of function 'omap_request_gpio'
    drivers/input/touchscreen/tsc2046.c:374: error: implicit declaration of function 'omap_set_gpio_direction'
    drivers/input/touchscreen/tsc2046.c:400: error: 'struct device' has no member named 'bus_id'
    drivers/input/touchscreen/tsc2046.c:416: error: 'SA_SAMPLE_RANDOM' undeclared (first use in this function)
    drivers/input/touchscreen/tsc2046.c:416: error: (Each undeclared identifier is reported only once
    drivers/input/touchscreen/tsc2046.c:416: error: for each function it appears in.)
    drivers/input/touchscreen/tsc2046.c:416: error: 'SA_TRIGGER_FALLING' undeclared (first use in this function)
    drivers/input/touchscreen/tsc2046.c:449: error: implicit declaration of function 'omap_free_gpio'
    make[3]: *** [drivers/input/touchscreen/tsc2046.o] Error 1
    make[2]: *** [drivers/input/touchscreen] Error 2
    make[1]: *** [drivers/input] Error 2
    make: *** [drivers] Error 2

  • Hi,

    This driver is used in old kernel, so some function might deprecated.

    Try the below workarounds for successful build.

    1)

    drivers/input/touchscreen/tsc2046.c:176: error: implicit declaration of function 'omap_get_gpio_datain'

    Use "gpio_get_value" API

    Ex:

    ndav = gpio_get_value(ts->dav_gpio);

    2)

    drivers/input/touchscreen/tsc2046.c:369: error: implicit declaration of function 'omap_request_gpio'

    Use "gpio_request" API

    Ex:

    r = gpio_request(dav_gpio, "tsc2046");

    3)

    drivers/input/touchscreen/tsc2046.c:400: error: 'struct device' has no member named 'bus_id'

    Comment out the line.

    //snprintf(ts->phys, sizeof(ts->phys),

    //        "%s/input-ts", tsc->spi->dev.bus_id);
    4)
    drivers/input/touchscreen/tsc2046.c:416: error: 'SA_SAMPLE_RANDOM' undeclared (first use in this function)
    drivers/input/touchscreen/tsc2046.c:416: error: (Each undeclared identifier is reported only once
    drivers/input/touchscreen/tsc2046.c:416: error: for each function it appears in.)
    drivers/input/touchscreen/tsc2046.c:416: error: 'SA_TRIGGER_FALLING' undeclared (first use in this function)
    Use IRQ type '0' (pass NULL).
    r = request_irq(ts->irq, tsc2046_ts_irq_handler,0,"tsc2046-ts", tsc);
    5)
    drivers/input/touchscreen/tsc2046.c:449: error: implicit declaration of function 'omap_free_gpio'
    Use "gpio_free" API
    +   gpio_free(dav_gpio);
  • Hi Titus S,


    I managed to get the successful build by changing some of the code. I downloaded the file from the link

    https://gitorious.org/omap3camera/mainline/source/78e73e07e27783951ba64da4a3012b84b43b7b90:drivers/input/touchscreen/tsc2046_ts.c

    I hope I have got this right then. I can now generate the interrupt on GPIO 27 which is what I wanted. The problem I still have is that the x and y values from TSC2046 are not being read back. I am not sure whats going on here and was wondering if you could guide me in the right direction.

    When PENIRQ interrupt happens, it then disables the interrupt and starts the timer. The timer than checks if the pen is down then it performs spi_async and when not down it enables the interrupt. I cant understand where the commands are issued via SPI to do 12 bit ADC conversion on TSC2046 and read back the x and y values.


    Any help in this regard would be great.

    Thanks

    Ali

  • Just a little update on Touchscrren controller I am using.

    I used the TSC2046 Driver above to no avail. I was not able to get the Touch working. I have also tried the ADS7846 driver to no avail.

    The PENIRQ interrupts are working on both and SPI seems to be reading 0 for x,y and pressure. I want to get the dev_vdbg enabled to see what the driver is reading from SPI rather than putting the printk statements but struggling to find it. I hope you can advise on this.

  • Hi,

    The PENIRQ interrupts are working on both and SPI seems to be reading 0 for x,y and pressure. I want to get the dev_vdbg enabled to see what the driver is reading from SPI rather than putting the printk statements but struggling to find it. I hope you can advise on this.

    make menuconfig ARCH=arm CROSS_COMPILE=arm-arago-linux-gnueabi-

    Device Drivers  --->

     [*] SPI support  --->

    [*]   Debug support for SPI drivers

  • Thanks for that Titus,

    I am just building the kernel now, wanted to get some information about this touchscreen, to see if I can get it to work I am not sure how to get this across but I have TSC2046 Touchscreen controller which needs to read X and Y values via SPI bus and then use these X and Y values to get the touch. Now I believe ADS7846 Driver already does that but I cant see how. The routine

    static void __devinit ads7846_setup_spi_msg(struct ads7846 *ts,
                    const struct ads7846_platform_data *pdata)

    just about does it but its only called once in

    static int __devinit ads7846_probe(struct spi_device *spi)

    Now to constantly get the X and Y values should this not be called every time interrupt happens.

    Regards

    Ali

  • Hi Titus

    Right this is what I have got so far and pretty sure that I am not talking to SPI correctly as per datasheet of TSC2046.

    At the moment All I am looking for is to issue a command on SPI bus say 0xd300 and read the result back. Can you please help me in understanding how to get this


    I am following the Fig 13 on Page 18 of Datasheet.

    Regards

  • Thought I just put some update on.


    Pin Mux was getting over written hence was not able to read back the x and y values. Which after resolving seems to be ok. Now the problem is that even though I am reading these x and y values the touch does not seem to be working. I tested the Windows CE 6.0 image on the custom board and that is fine with touch being detected and working. Any suggestions would be great.

    Ali

  • Hi Ali,

    You can try "evtest" to test your input touchscreen device.

    Are you getting any /dev/touchscreen0" node something like that ?

  • Finally I have got the touch working. There were few things which had to be changed. MUX issue was one as mentioned above and second was the SPI bus. Our custom made board has a trani before the CS pin on TSC2046 which required the signal to be inverted. It now seems to be working.

    Another thing was that I had to use the main ADS7846 driver rather then the one mentioned in the thread. The driver is the main line driver with  below values

    #define OMAP3EVM_XMIN        93
    #define OMAP3EVM_XMAX        4000
    #define OMAP3EVM_YMIN        300
    #define OMAP3EVM_YMAX        3850

    One issue still remains that my touch screen is playing funny games it seems like its in portrait and not land scape can any one help me on this one to fix it.

    Regards

    Ali

  • Hi Titus S,

    I have manged to get the touchscrren working but it seems like its in portrait mode can you please help me resolve this I need it in Landscape mode. All the X_RES and Y_RES are correct 800x480.


    Regards

    Ali

  • Hi Ali,

    Sounds good.

    I'm glad that you able to work.

    Have you calibrate the touch screen ?

    Please refer the link to calibrate.

    http://e2e.ti.com/support/embedded/linux/f/354/t/354444.aspx

  • Hi Titus,

    Thanks,

    No I have not yet calibrated. I am not sure how I can read those values. By printing values from below line I get stupid values

            printk("%4d/%4d/%4d\n", x, y, Rt);
            dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);

    3634/65507/ 210

    These are the x/y/Rt values at top left not sure if they are correct.

  • Hi Titus,

    All seems to be working fine now. I have had to use calibration values using printk command top left and bottom right and swaping x,y values.

    The problem I now face is that my X values seems to be inverted. Can you help with that.

    Regards

  • Hello


    I thought I'll just update on the fix which I employed to get it to work on the touch screen I was using.

    I am using 4 wire resistive touch screen.

    Carefully configure spi_board_info

    Carefully set OMAP3_MUX to configure SPI I/O's

    Modified ads7846_platform_data to include .swap_xy (Swap x and y values. Optional Depending on screen)

    Use ADS7846 driver. TSC2046 did not work for me.

    My x values were inverted so had to use something like  (y = OMAP3EVM_YMAX - y;) to get right indicator for touch and not inverted.

    Build and Enjoy.

    By the way did configure kernel to give debug. Dont forget to take debug off.

  • Hi Ali,

    Sounds good.

    Thanks for the update and your steps & workarounds and it would help other community members too.