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:
Родитель
1730d81460
Коммит
dac90dc232
|
@ -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>;
|
||||
};
|
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче