diff options
Diffstat (limited to 'drivers/input/touchscreen/tsc2005.c')
| -rw-r--r-- | drivers/input/touchscreen/tsc2005.c | 161 | 
1 files changed, 117 insertions, 44 deletions
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 7213e8b07e7..52380b68ebd 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -25,11 +25,15 @@  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/input.h> +#include <linux/input/touchscreen.h>  #include <linux/interrupt.h>  #include <linux/delay.h>  #include <linux/pm.h> +#include <linux/of.h> +#include <linux/of_gpio.h>  #include <linux/spi/spi.h>  #include <linux/spi/tsc2005.h> +#include <linux/regulator/consumer.h>  /*   * The touchscreen interface operates as follows: @@ -100,6 +104,11 @@  					 TSC2005_CFR2_AVG_7)  #define MAX_12BIT			0xfff +#define TSC2005_DEF_X_FUZZ		4 +#define TSC2005_DEF_Y_FUZZ		8 +#define TSC2005_DEF_P_FUZZ		2 +#define TSC2005_DEF_RESISTOR		280 +  #define TSC2005_SPI_MAX_SPEED_HZ	10000000  #define TSC2005_PENUP_TIME_MS		40 @@ -143,6 +152,9 @@ struct tsc2005 {  	bool			pen_down; +	struct regulator	*vio; + +	int			reset_gpio;  	void			(*set_reset)(bool enable);  }; @@ -337,6 +349,14 @@ static void tsc2005_stop_scan(struct tsc2005 *ts)  	tsc2005_cmd(ts, TSC2005_CMD_STOP);  } +static void tsc2005_set_reset(struct tsc2005 *ts, bool enable) +{ +	if (ts->reset_gpio >= 0) +		gpio_set_value(ts->reset_gpio, enable); +	else if (ts->set_reset) +		ts->set_reset(enable); +} +  /* must be called with ts->mutex held */  static void __tsc2005_disable(struct tsc2005 *ts)  { @@ -355,7 +375,7 @@ static void __tsc2005_enable(struct tsc2005 *ts)  {  	tsc2005_start_scan(ts); -	if (ts->esd_timeout && ts->set_reset) { +	if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) {  		ts->last_valid_interrupt = jiffies;  		schedule_delayed_work(&ts->esd_work,  				round_jiffies_relative( @@ -414,9 +434,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev,  	}  	/* hardware reset */ -	ts->set_reset(false); +	tsc2005_set_reset(ts, false);  	usleep_range(100, 500); /* only 10us required */ -	ts->set_reset(true); +	tsc2005_set_reset(ts, true);  	if (!success)  		goto out; @@ -459,7 +479,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj,  	umode_t mode = attr->mode;  	if (attr == &dev_attr_selftest.attr) { -		if (!ts->set_reset) +		if (!ts->set_reset && !ts->reset_gpio)  			mode = 0;  	} @@ -509,9 +529,9 @@ static void tsc2005_esd_work(struct work_struct *work)  	tsc2005_update_pen_state(ts, 0, 0, 0); -	ts->set_reset(false); +	tsc2005_set_reset(ts, false);  	usleep_range(100, 500); /* only 10us required */ -	ts->set_reset(true); +	tsc2005_set_reset(ts, true);  	enable_irq(ts->spi->irq);  	tsc2005_start_scan(ts); @@ -571,30 +591,48 @@ static void tsc2005_setup_spi_xfer(struct tsc2005 *ts)  static int tsc2005_probe(struct spi_device *spi)  { -	const struct tsc2005_platform_data *pdata = spi->dev.platform_data; +	const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev); +	struct device_node *np = spi->dev.of_node; +  	struct tsc2005 *ts;  	struct input_dev *input_dev; -	unsigned int max_x, max_y, max_p; -	unsigned int fudge_x, fudge_y, fudge_p; +	unsigned int max_x = MAX_12BIT; +	unsigned int max_y = MAX_12BIT; +	unsigned int max_p = MAX_12BIT; +	unsigned int fudge_x = TSC2005_DEF_X_FUZZ; +	unsigned int fudge_y = TSC2005_DEF_Y_FUZZ; +	unsigned int fudge_p = TSC2005_DEF_P_FUZZ; +	unsigned int x_plate_ohm = TSC2005_DEF_RESISTOR; +	unsigned int esd_timeout;  	int error; -	if (!pdata) { -		dev_dbg(&spi->dev, "no platform data\n"); +	if (!np && !pdata) { +		dev_err(&spi->dev, "no platform data\n");  		return -ENODEV;  	} -	fudge_x	= pdata->ts_x_fudge	   ? : 4; -	fudge_y	= pdata->ts_y_fudge	   ? : 8; -	fudge_p	= pdata->ts_pressure_fudge ? : 2; -	max_x	= pdata->ts_x_max	   ? : MAX_12BIT; -	max_y	= pdata->ts_y_max	   ? : MAX_12BIT; -	max_p	= pdata->ts_pressure_max   ? : MAX_12BIT; -  	if (spi->irq <= 0) { -		dev_dbg(&spi->dev, "no irq\n"); +		dev_err(&spi->dev, "no irq\n");  		return -ENODEV;  	} +	if (pdata) { +		fudge_x	= pdata->ts_x_fudge; +		fudge_y	= pdata->ts_y_fudge; +		fudge_p	= pdata->ts_pressure_fudge; +		max_x	= pdata->ts_x_max; +		max_y	= pdata->ts_y_max; +		max_p	= pdata->ts_pressure_max; +		x_plate_ohm = pdata->ts_x_plate_ohm; +		esd_timeout = pdata->esd_timeout_ms; +	} else { +		x_plate_ohm = TSC2005_DEF_RESISTOR; +		of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm); +		esd_timeout = 0; +		of_property_read_u32(np, "ti,esd-recovery-timeout-ms", +								&esd_timeout); +	} +  	spi->mode = SPI_MODE_0;  	spi->bits_per_word = 8;  	if (!spi->max_speed_hz) @@ -604,19 +642,48 @@ static int tsc2005_probe(struct spi_device *spi)  	if (error)  		return error; -	ts = kzalloc(sizeof(*ts), GFP_KERNEL); -	input_dev = input_allocate_device(); -	if (!ts || !input_dev) { -		error = -ENOMEM; -		goto err_free_mem; -	} +	ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL); +	if (!ts) +		return -ENOMEM; + +	input_dev = devm_input_allocate_device(&spi->dev); +	if (!input_dev) +		return -ENOMEM;  	ts->spi = spi;  	ts->idev = input_dev; -	ts->x_plate_ohm	= pdata->ts_x_plate_ohm	? : 280; -	ts->esd_timeout	= pdata->esd_timeout_ms; -	ts->set_reset	= pdata->set_reset; +	ts->x_plate_ohm = x_plate_ohm; +	ts->esd_timeout = esd_timeout; + +	if (np) { +		ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); +		if (ts->reset_gpio == -EPROBE_DEFER) +			return ts->reset_gpio; +		if (ts->reset_gpio < 0) { +			dev_err(&spi->dev, "error acquiring reset gpio: %d\n", +				ts->reset_gpio); +			return ts->reset_gpio; +		} + +		error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0, +					      "reset-gpios"); +		if (error) { +			dev_err(&spi->dev, "error requesting reset gpio: %d\n", +				error); +			return error; +		} + +		ts->vio = devm_regulator_get(&spi->dev, "vio"); +		if (IS_ERR(ts->vio)) { +			error = PTR_ERR(ts->vio); +			dev_err(&spi->dev, "vio regulator missing (%d)", error); +			return error; +		} +	} else { +		ts->reset_gpio = -1; +		ts->set_reset = pdata->set_reset; +	}  	mutex_init(&ts->mutex); @@ -641,6 +708,9 @@ static int tsc2005_probe(struct spi_device *spi)  	input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);  	input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); +	if (np) +		touchscreen_parse_of_params(input_dev); +  	input_dev->open = tsc2005_open;  	input_dev->close = tsc2005_close; @@ -649,12 +719,20 @@ static int tsc2005_probe(struct spi_device *spi)  	/* Ensure the touchscreen is off */  	tsc2005_stop_scan(ts); -	error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, -				     IRQF_TRIGGER_RISING | IRQF_ONESHOT, -				     "tsc2005", ts); +	error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, +					  tsc2005_irq_thread, +					  IRQF_TRIGGER_RISING | IRQF_ONESHOT, +					  "tsc2005", ts);  	if (error) {  		dev_err(&spi->dev, "Failed to request irq, err: %d\n", error); -		goto err_free_mem; +		return error; +	} + +	/* enable regulator for DT */ +	if (ts->vio) { +		error = regulator_enable(ts->vio); +		if (error) +			return error;  	}  	spi_set_drvdata(spi, ts); @@ -662,7 +740,7 @@ static int tsc2005_probe(struct spi_device *spi)  	if (error) {  		dev_err(&spi->dev,  			"Failed to create sysfs attributes, err: %d\n", error); -		goto err_clear_drvdata; +		goto disable_regulator;  	}  	error = input_register_device(ts->idev); @@ -677,12 +755,9 @@ static int tsc2005_probe(struct spi_device *spi)  err_remove_sysfs:  	sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); -err_clear_drvdata: -	spi_set_drvdata(spi, NULL); -	free_irq(spi->irq, ts); -err_free_mem: -	input_free_device(input_dev); -	kfree(ts); +disable_regulator: +	if (ts->vio) +		regulator_disable(ts->vio);  	return error;  } @@ -690,13 +765,11 @@ static int tsc2005_remove(struct spi_device *spi)  {  	struct tsc2005 *ts = spi_get_drvdata(spi); -	sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); +	sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); -	free_irq(ts->spi->irq, ts); -	input_unregister_device(ts->idev); -	kfree(ts); +	if (ts->vio) +		regulator_disable(ts->vio); -	spi_set_drvdata(spi, NULL);  	return 0;  }  | 
