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.

Linux/TSC2007: Regarding Device tree configuration on Android.

Part Number: TSC2007
Other Parts Discussed in Thread: TSC200XSW-LINUX

Tool/software: Linux

Dear TI,

we are interfacing TSC2007 with msm8909 processor running with android OS, it recognize  tsc2007,  when i pressing the touch panel i get some data, we ensured by "cat /dev/input/event0"

command, but my application didn't response to the touch pressing or when i run getevent command it does not produce any value.

My Device tree following format,

tsc2007@48 {  
            compatible = "ti,tsc2007";
            reg=<0x48>;
            interrupt-parent = <&msm_gpio>;
            interrupts = <13 0x2008>;
            gpios = <&msm_gpio 13 0x2008>;
            ti,x-plate-ohms=<180>;    
        };

Qualcomm R&D engineer want to ensure that following node properties should present in device tree? or it is not mandatory?

Node properties attached as image,

    Thanks & Regards.....

  • Hello,

    Can you share a link to the Linux driver library you're referencing?
  • Dear Collin Wells,

    Thanks For your replay, i get the driver from following link,

    http://www.ti.com/tool/TSC200XSW-LINUX

    Here i attached those Qualcomm modified files, in this files did not produce the X and Y coordinates to input subsystem so touch screen did not response. please let me know if any correction is needed.

    /*
     * drivers/input/touchscreen/tsc2007.c
     *
     * Copyright (c) 2008 MtekVision Co., Ltd.
     *	Kwangwoo Lee <kwlee@mtekvision.com>
     *
     * Using code from:
     *  - ads7846.c
     *	Copyright (c) 2005 David Brownell
     *	Copyright (c) 2006 Nokia Corporation
     *  - corgi_ts.c
     *	Copyright (C) 2004-2005 Richard Purdie
     *  - omap_ts.[hc], ads7846.h, ts_osk.c
     *	Copyright (C) 2002 MontaVista Software
     *	Copyright (C) 2004 Texas Instruments
     *	Copyright (C) 2005 Dirk Behme
     *
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License version 2 as
     *  published by the Free Software Foundation.
     */
    
    #include <linux/module.h>
    #include <linux/slab.h>
    #include <linux/input.h>
    #include <linux/interrupt.h>
    #include <linux/i2c.h>
    #include <linux/i2c/tsc2007.h>
    #include <linux/pm.h>
    
    #if defined(CONFIG_HAS_EARLYSUSPEND)
    #include <linux/earlysuspend.h>
    #define TSC2007_SUSPEND_LEVEL 1
    #endif
    
    #define TSC2007_MEASURE_TEMP0		(0x0 << 4)
    #define TSC2007_MEASURE_AUX		(0x2 << 4)
    #define TSC2007_MEASURE_TEMP1		(0x4 << 4)
    #define TSC2007_ACTIVATE_XN		(0x8 << 4)
    #define TSC2007_ACTIVATE_YN		(0x9 << 4)
    #define TSC2007_ACTIVATE_YP_XN		(0xa << 4)
    #define TSC2007_SETUP			(0xb << 4)
    #define TSC2007_MEASURE_X		(0xc << 4)
    #define TSC2007_MEASURE_Y		(0xd << 4)
    #define TSC2007_MEASURE_Z1		(0xe << 4)
    #define TSC2007_MEASURE_Z2		(0xf << 4)
    
    #define TSC2007_POWER_OFF_IRQ_EN	(0x0 << 2)
    #define TSC2007_ADC_ON_IRQ_DIS0		(0x1 << 2)
    #define TSC2007_ADC_OFF_IRQ_EN		(0x2 << 2)
    #define TSC2007_ADC_ON_IRQ_DIS1		(0x3 << 2)
    
    #define TSC2007_12BIT			(0x0 << 1)
    #define TSC2007_8BIT			(0x1 << 1)
    
    #define	MAX_12BIT			((1 << 12) - 1)
    
    #define ADC_ON_12BIT	(TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)
    
    #define READ_Y		(ADC_ON_12BIT | TSC2007_MEASURE_Y)
    #define READ_Z1		(ADC_ON_12BIT | TSC2007_MEASURE_Z1)
    #define READ_Z2		(ADC_ON_12BIT | TSC2007_MEASURE_Z2)
    #define READ_X		(ADC_ON_12BIT | TSC2007_MEASURE_X)
    #define PWRDOWN		(TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)
    
    struct ts_event {
    	u16	x;
    	u16	y;
    	u16	z1, z2;
    };
    
    struct tsc2007 {
    	struct input_dev	*input;
    	char			phys[32];
    	struct delayed_work	work;
    
    	struct i2c_client	*client;
    
    	u16			model;
    	u16			x_plate_ohms;
    	u16			max_rt;
    	unsigned long		poll_delay;
    	unsigned long		poll_period;
    	u16			min_x;
    	u16			max_x;
    	u16			min_y;
    	u16			max_y;
    
    	bool			pendown;
    	int			irq;
    
    	bool			invert_x;
    	bool			invert_y;
    	bool			invert_z1;
    	bool			invert_z2;
    
    	int			(*get_pendown_state)(void);
    	void			(*clear_penirq)(void);
    	int			(*power_shutdown)(bool);
    #if defined(CONFIG_HAS_EARLYSUSPEND)
    	struct early_suspend	early_suspend;
    #endif
    };
    
    static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
    {
    	s32 data;
    	u16 val;
    
    	data = i2c_smbus_read_word_data(tsc->client, cmd);
    	if (data < 0) {
    		dev_err(&tsc->client->dev, "i2c io error: %d\n", data);
    		return data;
    	}
    
    	/* The protocol and raw data format from i2c interface:
    	 * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
    	 * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit].
    	 */
    	val = swab16(data) >> 4;
    
    	dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val);
    
    	return val;
    }
    
    static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
    {
    	/* y- still on; turn on only y+ (and ADC) */
    	tc->y = tsc2007_xfer(tsc, READ_Y);
    
    	/* turn y- off, x+ on, then leave in lowpower */
    	tc->x = tsc2007_xfer(tsc, READ_X);
    
    	/* turn y+ off, x- on; we'll use formula #1 */
    	tc->z1 = tsc2007_xfer(tsc, READ_Z1);
    	tc->z2 = tsc2007_xfer(tsc, READ_Z2);
    
    	if (tsc->invert_x == true)
    		tc->x = MAX_12BIT - tc->x;
    
    	if (tsc->invert_y == true)
    		tc->y = MAX_12BIT - tc->y;
    
    	if (tsc->invert_z1 == true)
    		tc->z1 = MAX_12BIT - tc->z1;
    
    	if (tsc->invert_z2 == true)
    		tc->z2 = MAX_12BIT - tc->z2;
    
    	/* Prepare for next touch reading - power down ADC, enable PENIRQ */
    	tsc2007_xfer(tsc, PWRDOWN);
    }
    
    static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
    {
    	u32 rt = 0;
    
    	/* range filtering */
    	if (tc->x == MAX_12BIT)
    		tc->x = 0;
    
    	if (likely(tc->x && tc->z1)) {
    		/* compute touch pressure resistance using equation #1 */
    		rt = tc->z2 - tc->z1;
    		rt *= tc->x;
    		rt *= tsc->x_plate_ohms;
    		rt /= tc->z1;
    		rt = (rt + 2047) >> 12;
    	}
    
    	return rt;
    }
    
    static void tsc2007_send_up_event(struct tsc2007 *tsc)
    {
    	struct input_dev *input = tsc->input;
    
    	dev_dbg(&tsc->client->dev, "UP\n");
    
    	input_report_key(input, BTN_TOUCH, 0);
    	input_report_abs(input, ABS_PRESSURE, 0);
    	input_sync(input);
    }
    
    static void tsc2007_work(struct work_struct *work)
    {
    	struct tsc2007 *ts =
    		container_of(to_delayed_work(work), struct tsc2007, work);
    	bool debounced = false;
    	struct ts_event tc;
    	u32 rt;
    
    	/*
    	 * NOTE: We can't rely on the pressure to determine the pen down
    	 * state, even though this controller has a pressure sensor.
    	 * The pressure value can fluctuate for quite a while after
    	 * lifting the pen and in some cases may not even settle at the
    	 * expected value.
    	 *
    	 * The only safe way to check for the pen up condition is in the
    	 * work function by reading the pen signal state (it's a GPIO
    	 * and IRQ). Unfortunately such callback is not always available,
    	 * in that case we have rely on the pressure anyway.
    	 */
    	if (ts->get_pendown_state) {
    		if (unlikely(!ts->get_pendown_state())) {
    			tsc2007_send_up_event(ts);
    			ts->pendown = false;
    			goto out;
    		}
    
    		dev_dbg(&ts->client->dev, "pen is still down\n");
    	}
    
    	tsc2007_read_values(ts, &tc);
    
    	rt = tsc2007_calculate_pressure(ts, &tc);
    	if (rt > ts->max_rt) {
    		/*
    		 * Sample found inconsistent by debouncing or pressure is
    		 * beyond the maximum. Don't report it to user space,
    		 * repeat at least once more the measurement.
    		 */
    		dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
    		debounced = true;
    		goto out;
    
    	}
    
    	if (rt) {
    		struct input_dev *input = ts->input;
    
    		if (!ts->pendown) {
    			dev_dbg(&ts->client->dev, "DOWN\n");
    
    			input_report_key(input, BTN_TOUCH, 1);
    			ts->pendown = true;
    		}
    
    		input_report_abs(input, ABS_X, tc.x);
    		input_report_abs(input, ABS_Y, tc.y);
    		input_report_abs(input, ABS_PRESSURE, rt);
    
    		input_sync(input);
    
    		dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
    			tc.x, tc.y, rt);
    
    	} else if (!ts->get_pendown_state && ts->pendown) {
    		/*
    		 * We don't have callback to check pendown state, so we
    		 * have to assume that since pressure reported is 0 the
    		 * pen was lifted up.
    		 */
    		tsc2007_send_up_event(ts);
    		ts->pendown = false;
    	}
    
     out:
    	if (ts->pendown || debounced)
    		schedule_delayed_work(&ts->work,
    				      msecs_to_jiffies(ts->poll_period));
    	else
    		enable_irq(ts->irq);
    }
    
    static irqreturn_t tsc2007_irq(int irq, void *handle)
    {
    	struct tsc2007 *ts = handle;
    
    	if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
    		disable_irq_nosync(ts->irq);
    		schedule_delayed_work(&ts->work,
    				      msecs_to_jiffies(ts->poll_delay));
    	}
    
    	if (ts->clear_penirq)
    		ts->clear_penirq();
    
    	return IRQ_HANDLED;
    }
    
    static void tsc2007_free_irq(struct tsc2007 *ts)
    {
    	free_irq(ts->irq, ts);
    	if (cancel_delayed_work_sync(&ts->work)) {
    		/*
    		 * Work was pending, therefore we need to enable
    		 * IRQ here to balance the disable_irq() done in the
    		 * interrupt handler.
    		 */
    		enable_irq(ts->irq);
    	}
    }
    
    #ifdef CONFIG_PM
    static int tsc2007_suspend(struct device *dev)
    {
    	int rc;
    	struct tsc2007	*ts = dev_get_drvdata(dev);
    
    	disable_irq(ts->irq);
    
    	if (cancel_delayed_work_sync(&ts->work))
    		enable_irq(ts->irq);
    
    	if (ts->power_shutdown) {
    		rc = ts->power_shutdown(true);
    		if (rc) {
    			pr_err("%s: Power off failed, suspend failed (%d)\n",
    							__func__, rc);
    			return rc;
    		}
    	}
    
    	return 0;
    }
    
    static int tsc2007_resume(struct device *dev)
    {
    	int rc;
    	struct tsc2007	*ts = dev_get_drvdata(dev);
    
    	if (ts->power_shutdown) {
    		rc = ts->power_shutdown(false);
    		if (rc) {
    			pr_err("%s: Power on failed, resume failed (%d)\n",
    							 __func__, rc);
    			return rc;
    		}
    	}
    
    	enable_irq(ts->irq);
    
    	return 0;
    }
    
    #ifdef CONFIG_HAS_EARLYSUSPEND
    static void tsc2007_early_suspend(struct early_suspend *h)
    {
    	struct tsc2007 *ts = container_of(h, struct tsc2007, early_suspend);
    
    	tsc2007_suspend(&ts->client->dev);
    }
    
    static void tsc2007_late_resume(struct early_suspend *h)
    {
    	struct tsc2007 *ts = container_of(h, struct tsc2007, early_suspend);
    
    	tsc2007_resume(&ts->client->dev);
    }
    #endif
    
    static const struct dev_pm_ops tsc2007_pm_ops = {
    #ifndef CONFIG_HAS_EARLYSUSPEND
    	.suspend	= tsc2007_suspend,
    	.resume		= tsc2007_resume,
    #endif
    };
    #endif
    
    static int tsc2007_probe(struct i2c_client *client,
    				   const struct i2c_device_id *id)
    {
    	struct tsc2007 *ts;
    	struct tsc2007_platform_data *pdata = client->dev.platform_data;
    	struct input_dev *input_dev;
    	int err;
    
    	if (!pdata) {
    		dev_err(&client->dev, "platform data is required!\n");
    		return -EINVAL;
    	}
    
    	if (!i2c_check_functionality(client->adapter,
    				     I2C_FUNC_SMBUS_READ_WORD_DATA))
    		return -EIO;
    
    	ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);
    	input_dev = input_allocate_device();
    	if (!ts || !input_dev) {
    		err = -ENOMEM;
    		goto err_free_mem;
    	}
    	//whitney add 20190220
    #if 0
    #ifdef GTP_CONFIG_OF	/* device tree support */
    	if (client->dev.of_node) {
    		ret = gt1x_parse_dt(&client->dev);
    		if (ret < 0) {
            	GTP_ERROR("GTP parse dts failed.");
            	return ret;
        	}
    	}
    #endif
    #endif
    //add  end  20190220
    	ts->client = client;
    	ts->irq = client->irq;
    	ts->input = input_dev;
    	INIT_DELAYED_WORK(&ts->work, tsc2007_work);
    
    	ts->model             = pdata->model;
    	ts->x_plate_ohms      = pdata->x_plate_ohms;
    	ts->max_rt            = pdata->max_rt ? : MAX_12BIT;
    	ts->poll_delay        = pdata->poll_delay ? : 1;
    	ts->poll_period       = pdata->poll_period ? : 1;
    	ts->get_pendown_state = pdata->get_pendown_state;
    	ts->clear_penirq      = pdata->clear_penirq;
    	ts->invert_x	      = pdata->invert_x;
    	ts->invert_y	      = pdata->invert_y;
    	ts->invert_z1	      = pdata->invert_z1;
    	ts->invert_z2	      = pdata->invert_z2;
    	ts->min_x	      = pdata->min_x ? pdata->min_x : 0;
    	ts->max_x	      = pdata->max_x ? pdata->max_x : MAX_12BIT;
    	ts->min_y	      = pdata->min_y ? pdata->min_y : 0;
    	ts->max_y	      = pdata->max_y ? pdata->max_y : MAX_12BIT;
    	ts->power_shutdown    = pdata->power_shutdown;
    
    	snprintf(ts->phys, sizeof(ts->phys),
    		 "%s/input0", dev_name(&client->dev));
    
    	input_dev->name = "TSC2007 Touchscreen";
    	input_dev->phys = ts->phys;
    	input_dev->id.bustype = BUS_I2C;
    
    	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
    	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    	__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
    
    	input_set_abs_params(input_dev, ABS_X, ts->min_x,
    				ts->max_x, pdata->fuzzx, 0);
    	input_set_abs_params(input_dev, ABS_Y, ts->min_y,
    				ts->max_y, pdata->fuzzy, 0);
    	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
    			pdata->fuzzz, 0);
    
    	if (pdata->init_platform_hw)
    		pdata->init_platform_hw();
    
    	err = request_irq(ts->irq, tsc2007_irq, pdata->irq_flags,
    			client->dev.driver->name, ts);
    	if (err < 0) {
    		dev_err(&client->dev, "irq %d busy?\n", ts->irq);
    		goto err_free_mem;
    	}
    
    	/* Prepare for touch readings - power down ADC and enable PENIRQ */
    	err = tsc2007_xfer(ts, PWRDOWN);
    	if (err < 0)
    		goto err_free_irq;
    
    	err = input_register_device(input_dev);
    	if (err)
    		goto err_free_irq;
    
    #ifdef CONFIG_HAS_EARLYSUSPEND
    	ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
    						TSC2007_SUSPEND_LEVEL;
    	ts->early_suspend.suspend = tsc2007_early_suspend;
    	ts->early_suspend.resume = tsc2007_late_resume;
    	register_early_suspend(&ts->early_suspend);
    #endif
    
    	i2c_set_clientdata(client, ts);
    
    	return 0;
    
     err_free_irq:
    	tsc2007_free_irq(ts);
    	if (pdata->exit_platform_hw)
    		pdata->exit_platform_hw();
     err_free_mem:
    	input_free_device(input_dev);
    	kfree(ts);
    	return err;
    }
    
    static int tsc2007_remove(struct i2c_client *client)
    {
    	struct tsc2007	*ts = i2c_get_clientdata(client);
    	struct tsc2007_platform_data *pdata = client->dev.platform_data;
    
    	tsc2007_free_irq(ts);
    
    	if (pdata->exit_platform_hw)
    		pdata->exit_platform_hw();
    
    #ifdef CONFIG_HAS_EARLYSUSPEND
    	unregister_early_suspend(&ts->early_suspend);
    #endif
    	input_unregister_device(ts->input);
    	kfree(ts);
    
    	return 0;
    }
    
    static const struct i2c_device_id tsc2007_idtable[] = {
    	{ "tsc2007", 0 },
    	{ }
    };
    
    MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);
    
    //whitney add 
    #if 0
    #ifdef CONFIG_PM
    		static struct of_device_id tsc2007_dt_match[] = {
    	{ .compatible = "tsc,tsc2007" },
    	{ }
    };
    #endif
    #endif
    //end
    
    static struct i2c_driver tsc2007_driver = {
    	.driver = {
    		.owner	= THIS_MODULE,
    		.name	= "tsc2007",
    #ifdef CONFIG_PM
    		.pm = &tsc2007_pm_ops,
    		//.of_match_table = of_match_ptr(tsc2007_dt_match),
    #endif
    	},
    	.id_table	= tsc2007_idtable,
    	.probe		= tsc2007_probe,
    	.remove		= tsc2007_remove,
    };
    
    module_i2c_driver(tsc2007_driver);
    
    MODULE_AUTHOR("Kwangwoo Lee <kwlee@mtekvision.com>");
    MODULE_DESCRIPTION("TSC2007 TouchScreen Driver");
    MODULE_LICENSE("GPL");
    
    tsc2007.h
    /*
     * drivers/input/touchscreen/tsc2007.c
     *
     * Copyright (c) 2008 MtekVision Co., Ltd.
     *	Kwangwoo Lee <kwlee@mtekvision.com>
     *
     * Using code from:
     *  - ads7846.c
     *	Copyright (c) 2005 David Brownell
     *	Copyright (c) 2006 Nokia Corporation
     *  - corgi_ts.c
     *	Copyright (C) 2004-2005 Richard Purdie
     *  - omap_ts.[hc], ads7846.h, ts_osk.c
     *	Copyright (C) 2002 MontaVista Software
     *	Copyright (C) 2004 Texas Instruments
     *	Copyright (C) 2005 Dirk Behme
     *
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License version 2 as
     *  published by the Free Software Foundation.
     */
    
    #include <linux/module.h>
    #include <linux/slab.h>
    #include <linux/input.h>
    #include <linux/interrupt.h>
    #include <linux/i2c.h>
    #include <linux/of_device.h>
    #include <linux/of_gpio.h>
    #include <linux/platform_data/tsc2007.h>
    #include "tsc2007.h"
    
    #undef dev_dbg
    #define dev_dbg dev_err
    
    int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
    {
    	s32 data;
    	u16 val;
    
    	data = i2c_smbus_read_word_data(tsc->client, cmd);
    	if (data < 0) {
    		dev_err(&tsc->client->dev, "i2c io error: %d\n", data);
    		return data;
    	}
    
    	/* The protocol and raw data format from i2c interface:
    	 * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
    	 * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit].
    	 */
    	val = swab16(data) >> 4;
    
    	dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val);
    
    	return val;
    }
    
    static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
    {
    	/* y- still on; turn on only y+ (and ADC) */
    	tc->y = tsc2007_xfer(tsc, READ_Y);
    
    	/* turn y- off, x+ on, then leave in lowpower */
    	tc->x = tsc2007_xfer(tsc, READ_X);
    
    	/* turn y+ off, x- on; we'll use formula #1 */
    	tc->z1 = tsc2007_xfer(tsc, READ_Z1);
    	tc->z2 = tsc2007_xfer(tsc, READ_Z2);
    
    	/* Prepare for next touch reading - power down ADC, enable PENIRQ */
    	tsc2007_xfer(tsc, PWRDOWN);
    }
    
    u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc)
    {
    	u32 rt = 0;
    
    	/* range filtering */
    	if (tc->x == MAX_12BIT)
    		tc->x = 0;
    
    	if (likely(tc->x && tc->z1)) {
    		/* compute touch resistance using equation #1 */
    		rt = tc->z2 - tc->z1;
    		rt *= tc->x;
    		rt *= tsc->x_plate_ohms;
    		rt /= tc->z1;
    		rt = (rt + 2047) >> 12;
    	}
    
    	return rt;
    }
    
    bool tsc2007_is_pen_down(struct tsc2007 *ts)
    {
    	/*
    	 * NOTE: We can't rely on the pressure to determine the pen down
    	 * state, even though this controller has a pressure sensor.
    	 * The pressure value can fluctuate for quite a while after
    	 * lifting the pen and in some cases may not even settle at the
    	 * expected value.
    	 *
    	 * The only safe way to check for the pen up condition is in the
    	 * work function by reading the pen signal state (it's a GPIO
    	 * and IRQ). Unfortunately such callback is not always available,
    	 * in that case we assume that the pen is down and expect caller
    	 * to fall back on the pressure reading.
    	 */
    
    	if (!ts->get_pendown_state)
    		return true;
    
    	return ts->get_pendown_state(&ts->client->dev);
    }
    
    static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
    {
    	struct tsc2007 *ts = handle;
    	struct input_dev *input = ts->input;
    	struct ts_event tc;
    	u32 rt;
    
    	while (!ts->stopped && tsc2007_is_pen_down(ts)) {
    
    		/* pen is down, continue with the measurement */
    
    		mutex_lock(&ts->mlock);
    		tsc2007_read_values(ts, &tc);
    		mutex_unlock(&ts->mlock);
    
    		rt = tsc2007_calculate_resistance(ts, &tc);
    
    		if (!rt && !ts->get_pendown_state) {
    			/*
    			 * If pressure reported is 0 and we don't have
    			 * callback to check pendown state, we have to
    			 * assume that pen was lifted up.
    			 */
    			break;
    		}
    
    		if (rt <= ts->max_rt) {
    			dev_dbg(&ts->client->dev,
    				"DOWN point(%4d,%4d), resistance (%4u)\n",
    				tc.x, tc.y, rt);
    
    			rt = ts->max_rt - rt;
    
    			input_report_key(input, BTN_TOUCH, 1);
    			input_report_abs(input, ABS_X, tc.x);
    			input_report_abs(input, ABS_Y, tc.y);
    			input_report_abs(input, ABS_PRESSURE, rt);
    
    			input_sync(input);
    
    		} else {
    			/*
    			 * Sample found inconsistent by debouncing or pressure is
    			 * beyond the maximum. Don't report it to user space,
    			 * repeat at least once more the measurement.
    			 */
    			dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
    		}
    
    		wait_event_timeout(ts->wait, ts->stopped, ts->poll_period);
    	}
    
    	dev_dbg(&ts->client->dev, "UP\n");
    
    	input_report_key(input, BTN_TOUCH, 0);
    	input_report_abs(input, ABS_PRESSURE, 0);
    	input_sync(input);
    
    	if (ts->clear_penirq)
    		ts->clear_penirq();
    
    	return IRQ_HANDLED;
    }
    
    static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
    {
    	struct tsc2007 *ts = handle;
    
    	if (tsc2007_is_pen_down(ts))
    		return IRQ_WAKE_THREAD;
    
    	if (ts->clear_penirq)
    		ts->clear_penirq();
    
    	return IRQ_HANDLED;
    }
    
    static void tsc2007_stop(struct tsc2007 *ts)
    {
    	ts->stopped = true;
    	mb();
    	wake_up(&ts->wait);
    
    	disable_irq(ts->irq);
    }
    
    static int tsc2007_open(struct input_dev *input_dev)
    {
    	struct tsc2007 *ts = input_get_drvdata(input_dev);
    	int err;
    
    	ts->stopped = false;
    	mb();
    
    	enable_irq(ts->irq);
    
    	/* Prepare for touch readings - power down ADC and enable PENIRQ */
    	err = tsc2007_xfer(ts, PWRDOWN);
    	if (err < 0) {
    		tsc2007_stop(ts);
    		return err;
    	}
    
    	return 0;
    }
    
    static void tsc2007_close(struct input_dev *input_dev)
    {
    	struct tsc2007 *ts = input_get_drvdata(input_dev);
    
    	tsc2007_stop(ts);
    }
    
    #ifdef CONFIG_OF
    static int tsc2007_get_pendown_state_gpio(struct device *dev)
    {
    	struct i2c_client *client = to_i2c_client(dev);
    	struct tsc2007 *ts = i2c_get_clientdata(client);
    
    	return !gpio_get_value(ts->gpio);
    }
    
    static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts)
    {
    	struct device_node *np = client->dev.of_node;
    	u32 val32;
    	u64 val64;
    
    	if (!np) {
    		dev_err(&client->dev, "missing device tree data\n");
    		return -EINVAL;
    	}
    
    	if (!of_property_read_u32(np, "ti,max-rt", &val32))
    		ts->max_rt = val32;
    	else
    		ts->max_rt = MAX_12BIT;
    
    	if (!of_property_read_u32(np, "ti,fuzzx", &val32))
    		ts->fuzzx = val32;
    
    	if (!of_property_read_u32(np, "ti,fuzzy", &val32))
    		ts->fuzzy = val32;
    
    	if (!of_property_read_u32(np, "ti,fuzzz", &val32))
    		ts->fuzzz = val32;
    
    	if (!of_property_read_u64(np, "ti,poll-period", &val64))
    		ts->poll_period = msecs_to_jiffies(val64);
    	else
    		ts->poll_period = msecs_to_jiffies(1);
    
    	if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) {
    		ts->x_plate_ohms = val32;
    	} else {
    		dev_err(&client->dev, "missing ti,x-plate-ohms devicetree property.");
    		return -EINVAL;
    	}
    
    	ts->gpio = of_get_gpio(np, 0);
    	if (gpio_is_valid(ts->gpio))
    		ts->get_pendown_state = tsc2007_get_pendown_state_gpio;
    	else
    		dev_warn(&client->dev,
    			 "GPIO not specified in DT (of_get_gpio returned %d)\n",
    			 ts->gpio);
    
    	return 0;
    }
    #else
    static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts)
    {
    	dev_err(&client->dev, "platform data is required!\n");
    	return -EINVAL;
    }
    #endif
    
    static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts,
    			      const struct tsc2007_platform_data *pdata,
    			      const struct i2c_device_id *id)
    {
    	ts->model             = pdata->model;
    	ts->x_plate_ohms      = pdata->x_plate_ohms;
    	ts->max_rt            = pdata->max_rt ? : MAX_12BIT;
    	ts->poll_period       = msecs_to_jiffies(pdata->poll_period ? : 1);
    	ts->get_pendown_state = pdata->get_pendown_state;
    	ts->clear_penirq      = pdata->clear_penirq;
    	ts->fuzzx             = pdata->fuzzx;
    	ts->fuzzy             = pdata->fuzzy;
    	ts->fuzzz             = pdata->fuzzz;
    
    	if (pdata->x_plate_ohms == 0) {
    		dev_err(&client->dev, "x_plate_ohms is not set up in platform data");
    		return -EINVAL;
    	}
    
    	return 0;
    }
    
    static void tsc2007_call_exit_platform_hw(void *data)
    {
    	struct device *dev = data;
    	const struct tsc2007_platform_data *pdata = dev_get_platdata(dev);
    
    	pdata->exit_platform_hw();
    }
    
    static int tsc2007_probe(struct i2c_client *client,
    			 const struct i2c_device_id *id)
    {
    	const struct tsc2007_platform_data *pdata =
    		dev_get_platdata(&client->dev);
    	struct tsc2007 *ts;
    	struct input_dev *input_dev;
    	int err;
    
    	if (!i2c_check_functionality(client->adapter,
    				     I2C_FUNC_SMBUS_READ_WORD_DATA))
    		return -EIO;
    
    	ts = devm_kzalloc(&client->dev, sizeof(struct tsc2007), GFP_KERNEL);
    	if (!ts)
    		return -ENOMEM;
    
    	if (pdata)
    		err = tsc2007_probe_pdev(client, ts, pdata, id);
    	else
    		err = tsc2007_probe_dt(client, ts);
    	if (err)
    		return err;
    
    	input_dev = devm_input_allocate_device(&client->dev);
    	if (!input_dev)
    		return -ENOMEM;
    
    	i2c_set_clientdata(client, ts);
    
    	ts->client = client;
    	ts->irq = client->irq;
    	ts->input = input_dev;
    
    	init_waitqueue_head(&ts->wait);
    	mutex_init(&ts->mlock);
    
    	snprintf(ts->phys, sizeof(ts->phys),
    		 "%s/input0", dev_name(&client->dev));
    
    	input_dev->name = "TSC2007 Touchscreen";
    	input_dev->phys = ts->phys;
    	input_dev->id.bustype = BUS_I2C;
    
    	input_dev->open = tsc2007_open;
    	input_dev->close = tsc2007_close;
    
    	input_set_drvdata(input_dev, ts);
    
    	input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
    
    	input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0);
    	input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);
    	input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
    			     ts->fuzzz, 0);
    
    	if (pdata) {
    		if (pdata->exit_platform_hw) {
    			err = devm_add_action(&client->dev,
    					      tsc2007_call_exit_platform_hw,
    					      &client->dev);
    			if (err) {
    				dev_err(&client->dev,
    					"Failed to register exit_platform_hw action, %d\n",
    					err);
    				return err;
    			}
    		}
    
    		if (pdata->init_platform_hw)
    			pdata->init_platform_hw();
    	}
    
    	err = devm_request_threaded_irq(&client->dev, ts->irq,
    					tsc2007_hard_irq, tsc2007_soft_irq,
    					IRQF_ONESHOT,
    					client->dev.driver->name, ts);
    	if (err) {
    		dev_err(&client->dev, "Failed to request irq %d: %d\n",
    			ts->irq, err);
    		return err;
    	}
    
    	tsc2007_stop(ts);
    
    	/* power down the chip (TSC2007_SETUP does not ACK on I2C) */
    	err = tsc2007_xfer(ts, PWRDOWN);
    	if (err < 0) {
    		dev_err(&client->dev,
    			"Failed to setup chip: %d\n", err);
    		return err;	/* chip does not respond */
    	}
    
    	err = input_register_device(input_dev);
    	if (err) {
    		dev_err(&client->dev,
    			"Failed to register input device: %d\n", err);
    		return err;
    	}
    
    	err =  tsc2007_iio_configure(ts);
    	if (err) {
    		dev_err(&client->dev,
    			"Failed to register with IIO: %d\n", err);
    		return err;
    	}
    
    	return 0;
    }
    
    static const struct i2c_device_id tsc2007_idtable[] = {
    	{ "tsc2007", 0 },
    	{ }
    };
    
    MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);
    
    #ifdef CONFIG_OF
    static const struct of_device_id tsc2007_of_match[] = {
    	{ .compatible = "ti,tsc2007" },
    	{ /* sentinel */ }
    };
    MODULE_DEVICE_TABLE(of, tsc2007_of_match);
    #endif
    
    static struct i2c_driver tsc2007_driver = {
    	.driver = {
    		.name	= "tsc2007",
    		.of_match_table = of_match_ptr(tsc2007_of_match),
    	},
    	.id_table	= tsc2007_idtable,
    	.probe		= tsc2007_probe,
    };
    
    module_i2c_driver(tsc2007_driver);
    
    MODULE_AUTHOR("Kwangwoo Lee <kwlee@mtekvision.com>");
    MODULE_DESCRIPTION("TSC2007 TouchScreen Driver");
    MODULE_LICENSE("GPL");
    
    /*
     * Copyright (c) 2016 Golden Delicious Comp. GmbH&Co. KG
     *	Nikolaus Schaller <hns@goldelico.com>
     *
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License version 2 as
     *  published by the Free Software Foundation.
     */
    
    #include <linux/i2c.h>
    #include <linux/iio/iio.h>
    #include "tsc2007.h"
    
    struct tsc2007_iio {
    	struct tsc2007 *ts;
    };
    
    #define TSC2007_CHAN_IIO(_chan, _name, _type, _chan_info) \
    { \
    	.datasheet_name = _name, \
    	.type = _type, \
    	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
    			BIT(_chan_info), \
    	.indexed = 1, \
    	.channel = _chan, \
    }
    
    static const struct iio_chan_spec tsc2007_iio_channel[] = {
    	TSC2007_CHAN_IIO(0, "x", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
    	TSC2007_CHAN_IIO(1, "y", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
    	TSC2007_CHAN_IIO(2, "z1", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
    	TSC2007_CHAN_IIO(3, "z2", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
    	TSC2007_CHAN_IIO(4, "adc", IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
    	TSC2007_CHAN_IIO(5, "rt", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), /* Ohms? */
    	TSC2007_CHAN_IIO(6, "pen", IIO_PRESSURE, IIO_CHAN_INFO_RAW),
    	TSC2007_CHAN_IIO(7, "temp0", IIO_TEMP, IIO_CHAN_INFO_RAW),
    	TSC2007_CHAN_IIO(8, "temp1", IIO_TEMP, IIO_CHAN_INFO_RAW),
    };
    
    static int tsc2007_read_raw(struct iio_dev *indio_dev,
    			    struct iio_chan_spec const *chan,
    			    int *val, int *val2, long mask)
    {
    	struct tsc2007_iio *iio = iio_priv(indio_dev);
    	struct tsc2007 *tsc = iio->ts;
    	int adc_chan = chan->channel;
    	int ret = 0;
    
    	if (adc_chan >= ARRAY_SIZE(tsc2007_iio_channel))
    		return -EINVAL;
    
    	if (mask != IIO_CHAN_INFO_RAW)
    		return -EINVAL;
    
    	mutex_lock(&tsc->mlock);
    
    	switch (chan->channel) {
    	case 0:
    		*val = tsc2007_xfer(tsc, READ_X);
    		break;
    	case 1:
    		*val = tsc2007_xfer(tsc, READ_Y);
    		break;
    	case 2:
    		*val = tsc2007_xfer(tsc, READ_Z1);
    		break;
    	case 3:
    		*val = tsc2007_xfer(tsc, READ_Z2);
    		break;
    	case 4:
    		*val = tsc2007_xfer(tsc, (ADC_ON_12BIT | TSC2007_MEASURE_AUX));
    		break;
    	case 5: {
    		struct ts_event tc;
    
    		tc.x = tsc2007_xfer(tsc, READ_X);
    		tc.z1 = tsc2007_xfer(tsc, READ_Z1);
    		tc.z2 = tsc2007_xfer(tsc, READ_Z2);
    		*val = tsc2007_calculate_resistance(tsc, &tc);
    		break;
    	}
    	case 6:
    		*val = tsc2007_is_pen_down(tsc);
    		break;
    	case 7:
    		*val = tsc2007_xfer(tsc,
    				    (ADC_ON_12BIT | TSC2007_MEASURE_TEMP0));
    		break;
    	case 8:
    		*val = tsc2007_xfer(tsc,
    				    (ADC_ON_12BIT | TSC2007_MEASURE_TEMP1));
    		break;
    	}
    
    	/* Prepare for next touch reading - power down ADC, enable PENIRQ */
    	tsc2007_xfer(tsc, PWRDOWN);
    
    	mutex_unlock(&tsc->mlock);
    
    	ret = IIO_VAL_INT;
    
    	return ret;
    }
    
    static const struct iio_info tsc2007_iio_info = {
    	.read_raw = tsc2007_read_raw,
    };
    
    int tsc2007_iio_configure(struct tsc2007 *ts)
    {
    	struct iio_dev *indio_dev;
    	struct tsc2007_iio *iio;
    	int error;
    
    	indio_dev = devm_iio_device_alloc(&ts->client->dev, sizeof(*iio));
    	if (!indio_dev) {
    		dev_err(&ts->client->dev, "iio_device_alloc failed\n");
    		return -ENOMEM;
    	}
    
    	iio = iio_priv(indio_dev);
    	iio->ts = ts;
    
    	indio_dev->name = "tsc2007";
    	indio_dev->dev.parent = &ts->client->dev;
    	indio_dev->info = &tsc2007_iio_info;
    	indio_dev->modes = INDIO_DIRECT_MODE;
    	indio_dev->channels = tsc2007_iio_channel;
    	indio_dev->num_channels = ARRAY_SIZE(tsc2007_iio_channel);
    
    	error = devm_iio_device_register(&ts->client->dev, indio_dev);
    	if (error) {
    		dev_err(&ts->client->dev,
    			"iio_device_register() failed: %d\n", error);
    		return error;
    	}
    
    	return 0;
    }
    

    Thanks & Regards

  • Hello,

    Please first understand that Linux driver support falls out of our direct area of expertise.  The link below is to a TSC2007 LINUX driver that we've referenced a few times recently and it seems to work for most people.

    1108.tsc2007.c


    If that driver doesn't solve the issues, please share a screen capture of the I2C communication and we'll try to figure out what's going on.

  • Dear Sir,
    Please provide header file related to 1108.tsc2007.c file, when i compile this code with i got error.

    Thanks and regards,
  • All we have is available in the link we previously provided. As mentioned LINUX driver support/debug is outside of our support structure. If you can share information about the I2C communication (scope shots) we can try to figure out what's going on.