Skip to content

Commit

Permalink
Input: tsc2005 - add DT support
Browse files Browse the repository at this point in the history
This adds DT support to the tsc2005 touchscreen driver. It also adds
regulator support to the driver if booted via DT.

Reviewed-by: Pavel Machek <pavel@ucw.cz>
Acked-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
Sebastian Reichel authored and Dmitry Torokhov committed May 29, 2014
1 parent b98abe5 commit a38cfeb
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 20 deletions.
42 changes: 42 additions & 0 deletions Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
* Texas Instruments tsc2005 touchscreen controller

Required properties:
- compatible : "ti,tsc2005"
- reg : SPI device address
- spi-max-frequency : Maximal SPI speed
- interrupts : IRQ specifier
- reset-gpios : GPIO specifier
- vio-supply : Regulator specifier

Optional properties:
- ti,x-plate-ohms : integer, resistance of the touchscreen's X plates
in ohm (defaults to 280)
- ti,esd-recovery-timeout-ms : integer, if the touchscreen does not respond after
the configured time (in milli seconds), the driver
will reset it. This is disabled by default.
- properties defined in touchscreen.txt

Example:

&mcspi1 {
tsc2005@0 {
compatible = "ti,tsc2005";
spi-max-frequency = <6000000>;
reg = <0>;

vio-supply = <&vio>;

reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; /* 104 */
interrupts-extended = <&gpio4 4 IRQ_TYPE_EDGE_RISING>; /* 100 */

touchscreen-fuzz-x = <4>;
touchscreen-fuzz-y = <7>;
touchscreen-fuzz-pressure = <2>;
touchscreen-max-x = <4096>;
touchscreen-max-y = <4096>;
touchscreen-max-pressure = <2048>;

ti,x-plate-ohms = <280>;
ti,esd-recovery-timeout-ms = <8000>;
};
}
124 changes: 104 additions & 20 deletions drivers/input/touchscreen/tsc2005.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -143,6 +152,9 @@ struct tsc2005 {

bool pen_down;

struct regulator *vio;

int reset_gpio;
void (*set_reset)(bool enable);
};

Expand Down Expand Up @@ -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)
{
Expand All @@ -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(
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -572,29 +592,47 @@ static void tsc2005_setup_spi_xfer(struct tsc2005 *ts)
static int tsc2005_probe(struct spi_device *spi)
{
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) {
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_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)
Expand All @@ -615,9 +653,37 @@ static int tsc2005_probe(struct spi_device *spi)
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);

Expand All @@ -642,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;

Expand All @@ -659,12 +728,19 @@ static int tsc2005_probe(struct spi_device *spi)
return error;
}

/* enable regulator for DT */
if (ts->vio) {
error = regulator_enable(ts->vio);
if (error)
return error;
}

spi_set_drvdata(spi, ts);
error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group);
if (error) {
dev_err(&spi->dev,
"Failed to create sysfs attributes, err: %d\n", error);
return error;
goto disable_regulator;
}

error = input_register_device(ts->idev);
Expand All @@ -679,13 +755,21 @@ static int tsc2005_probe(struct spi_device *spi)

err_remove_sysfs:
sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
disable_regulator:
if (ts->vio)
regulator_disable(ts->vio);
return error;
}

static int tsc2005_remove(struct spi_device *spi)
{
struct tsc2005 *ts = spi_get_drvdata(spi);

sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);

if (ts->vio)
regulator_disable(ts->vio);

return 0;
}

Expand Down

0 comments on commit a38cfeb

Please sign in to comment.