diff options
author | Lothar Waßmann <LW@KARO-electronics.de> | 2014-03-28 09:23:02 -0700 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-03-28 09:33:03 -0700 |
commit | dac90dc23211996286c3b934057d0df77cfef0b4 (patch) | |
tree | ddf114d901f257d7f63c60163a529a94bbbf1967 /drivers | |
parent | 1730d81460b929b1f217cb7d9cb193a7b0e58dd9 (diff) | |
download | linux-dac90dc23211996286c3b934057d0df77cfef0b4.tar.bz2 |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/touchscreen/edt-ft5x06.c | 145 |
1 files changed, 114 insertions, 31 deletions
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 155ab3ba84ee..9d61f1e36b33 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -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"); + 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"); @@ -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, |