Skip to content

Commit

Permalink
Input: edt-ft5x06 - add DT support
Browse files Browse the repository at this point in the history
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
Lothar Waßmann authored and Dmitry Torokhov committed Mar 28, 2014
1 parent 1730d81 commit dac90dc
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 31 deletions.
55 changes: 55 additions & 0 deletions Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
FocalTech EDT-FT5x06 Polytouch driver
=====================================

There are 3 variants of the chip for various touch panel sizes
FT5206GE1 2.8" .. 3.8"
FT5306DE4 4.3" .. 7"
FT5406EE8 7" .. 8.9"

The software interface is identical for all those chips, so that
currently there is no need for the driver to distinguish between the
different chips. Nevertheless distinct compatible strings are used so
that a distinction can be added if necessary without changing the DT
bindings.


Required properties:
- compatible: "edt,edt-ft5206"
or: "edt,edt-ft5306"
or: "edt,edt-ft5406"

- reg: I2C slave address of the chip (0x38)
- interrupt-parent: a phandle pointing to the interrupt controller
serving the interrupt for this chip
- interrupts: interrupt specification for the touchdetect
interrupt

Optional properties:
- reset-gpios: GPIO specification for the RESET input
- wake-gpios: GPIO specification for the WAKE input

- pinctrl-names: should be "default"
- pinctrl-0: a phandle pointing to the pin settings for the
control gpios

- threshold: allows setting the "click"-threshold in the range
from 20 to 80.

- gain: allows setting the sensitivity in the range from 0 to
31. Note that lower values indicate higher
sensitivity.

- offset: allows setting the edge compensation in the range from
0 to 31.

Example:
polytouch: edt-ft5x06@38 {
compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
reg = <0x38>;
pinctrl-names = "default";
pinctrl-0 = <&edt_ft5x06_pins>;
interrupt-parent = <&gpio2>;
interrupts = <5 0>;
reset-gpios = <&gpio2 6 1>;
wake-gpios = <&gpio4 9 0>;
};
145 changes: 114 additions & 31 deletions drivers/input/touchscreen/edt-ft5x06.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
* Lothar Waßmann <LW@KARO-electronics.de> (DT support)
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
Expand Down Expand Up @@ -33,6 +34,7 @@
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/input/mt.h>
#include <linux/input/edt-ft5x06.h>

Expand Down Expand Up @@ -65,6 +67,10 @@ struct edt_ft5x06_ts_data {
u16 num_x;
u16 num_y;

int reset_pin;
int irq_pin;
int wake_pin;

#if defined(CONFIG_DEBUG_FS)
struct dentry *debug_dir;
u8 *raw_buffer;
Expand Down Expand Up @@ -614,24 +620,38 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
#endif /* CONFIG_DEBUGFS */

static int edt_ft5x06_ts_reset(struct i2c_client *client,
int reset_pin)
struct edt_ft5x06_ts_data *tsdata)
{
int error;

if (gpio_is_valid(reset_pin)) {
if (gpio_is_valid(tsdata->wake_pin)) {
error = devm_gpio_request_one(&client->dev,
tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
"edt-ft5x06 wake");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d as wake pin, error %d\n",
tsdata->wake_pin, error);
return error;
}

mdelay(5);
gpio_set_value(tsdata->wake_pin, 1);
}
if (gpio_is_valid(tsdata->reset_pin)) {
/* this pulls reset down, enabling the low active reset */
error = devm_gpio_request_one(&client->dev, reset_pin,
GPIOF_OUT_INIT_LOW,
"edt-ft5x06 reset");
error = devm_gpio_request_one(&client->dev,
tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
"edt-ft5x06 reset");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d as reset pin, error %d\n",
reset_pin, error);
tsdata->reset_pin, error);
return error;
}

mdelay(50);
gpio_set_value(reset_pin, 1);
gpio_set_value(tsdata->reset_pin, 1);
mdelay(100);
}

Expand Down Expand Up @@ -672,6 +692,20 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
pdata->name <= edt_ft5x06_attr_##name.limit_high) \
edt_ft5x06_register_write(tsdata, reg, pdata->name)

#define EDT_GET_PROP(name, reg) { \
u32 val; \
if (of_property_read_u32(np, #name, &val) == 0) \
edt_ft5x06_register_write(tsdata, reg, val); \
}

static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np,
struct edt_ft5x06_ts_data *tsdata)
{
EDT_GET_PROP(threshold, WORK_REGISTER_THRESHOLD);
EDT_GET_PROP(gain, WORK_REGISTER_GAIN);
EDT_GET_PROP(offset, WORK_REGISTER_OFFSET);
}

static void
edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
const struct edt_ft5x06_platform_data *pdata)
Expand Down Expand Up @@ -699,6 +733,30 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y);
}

#ifdef CONFIG_OF
static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
struct edt_ft5x06_ts_data *tsdata)
{
struct device_node *np = dev->of_node;

/*
* irq_pin is not needed for DT setup.
* irq is associated via 'interrupts' property in DT
*/
tsdata->irq_pin = -EINVAL;
tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0);

return 0;
}
#else
static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
struct edt_ft5x06_ts_data *tsdata)
{
return -ENODEV;
}
#endif

static int edt_ft5x06_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
Expand All @@ -711,32 +769,40 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,

dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");

tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
if (!tsdata) {
dev_err(&client->dev, "failed to allocate driver data.\n");
return -ENOMEM;
}

if (!pdata) {
dev_err(&client->dev, "no platform data?\n");
return -EINVAL;
error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata);
if (error) {
dev_err(&client->dev,
"DT probe failed and no platform data present\n");
return error;
}
} else {
tsdata->reset_pin = pdata->reset_pin;
tsdata->irq_pin = pdata->irq_pin;
tsdata->wake_pin = -EINVAL;
}

error = edt_ft5x06_ts_reset(client, pdata->reset_pin);
error = edt_ft5x06_ts_reset(client, tsdata);
if (error)
return error;

if (gpio_is_valid(pdata->irq_pin)) {
error = devm_gpio_request_one(&client->dev, pdata->irq_pin,
GPIOF_IN, "edt-ft5x06 irq");
if (gpio_is_valid(tsdata->irq_pin)) {
error = devm_gpio_request_one(&client->dev, tsdata->irq_pin,
GPIOF_IN, "edt-ft5x06 irq");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d, error %d\n",
pdata->irq_pin, error);
tsdata->irq_pin, error);
return error;
}
}

tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
if (!tsdata) {
dev_err(&client->dev, "failed to allocate driver data.\n");
return -ENOMEM;
}

input = devm_input_allocate_device(&client->dev);
if (!input) {
dev_err(&client->dev, "failed to allocate input device.\n");
Expand All @@ -754,7 +820,11 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error;
}

edt_ft5x06_ts_get_defaults(tsdata, pdata);
if (!pdata)
edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata);
else
edt_ft5x06_ts_get_defaults(tsdata, pdata);

edt_ft5x06_ts_get_parameters(tsdata);

dev_dbg(&client->dev,
Expand Down Expand Up @@ -784,10 +854,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
input_set_drvdata(input, tsdata);
i2c_set_clientdata(client, tsdata);

error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, edt_ft5x06_ts_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata);
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
edt_ft5x06_ts_isr,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
return error;
Expand All @@ -798,19 +868,21 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error;

error = input_register_device(input);
if (error) {
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
return error;
}
if (error)
goto err_remove_attrs;

edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
device_init_wakeup(&client->dev, 1);

dev_dbg(&client->dev,
"EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n",
pdata->irq_pin, pdata->reset_pin);
"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
client->irq, tsdata->wake_pin, tsdata->reset_pin);

return 0;

err_remove_attrs:
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
return error;
}

static int edt_ft5x06_ts_remove(struct i2c_client *client)
Expand Down Expand Up @@ -854,10 +926,21 @@ static const struct i2c_device_id edt_ft5x06_ts_id[] = {
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);

#ifdef CONFIG_OF
static const struct of_device_id edt_ft5x06_of_match[] = {
{ .compatible = "edt,edt-ft5206", },
{ .compatible = "edt,edt-ft5306", },
{ .compatible = "edt,edt-ft5406", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
#endif

static struct i2c_driver edt_ft5x06_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "edt_ft5x06",
.of_match_table = of_match_ptr(edt_ft5x06_of_match),
.pm = &edt_ft5x06_ts_pm_ops,
},
.id_table = edt_ft5x06_ts_id,
Expand Down

0 comments on commit dac90dc

Please sign in to comment.