Input: edt-ft5x06 - add DT support

Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
Lothar Waßmann 2014-03-28 09:23:02 -07:00 committed by Dmitry Torokhov
parent 1730d81460
commit dac90dc232
2 changed files with 176 additions and 38 deletions

View File

@ -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>;
};

View File

@ -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
@ -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>
@ -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;
@ -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);
}
@ -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)
@ -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)
{
@ -711,32 +769,40 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
if (!pdata) {
dev_err(&client->dev, "no platform data?\n");
return -EINVAL;
}
error = edt_ft5x06_ts_reset(client, pdata->reset_pin);
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 (error) {
dev_err(&client->dev,
"Failed to request GPIO %d, error %d\n",
pdata->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;
}
if (!pdata) {
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, tsdata);
if (error)
return error;
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",
tsdata->irq_pin, error);
return error;
}
}
input = devm_input_allocate_device(&client->dev);
if (!input) {
dev_err(&client->dev, "failed to allocate input device.\n");
@ -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,
@ -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;
@ -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)
@ -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,