Loading Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt 0 → 100644 +55 −0 Original line number Diff line number Diff line 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>; }; drivers/input/touchscreen/edt-ft5x06.c +114 −31 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -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> Loading Loading @@ -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; Loading Loading @@ -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, 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); } Loading Loading @@ -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) Loading Loading @@ -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) { Loading @@ -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, 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"); Loading @@ -754,7 +820,11 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, return error; } 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, Loading Loading @@ -784,8 +854,8 @@ 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, error = devm_request_threaded_irq(&client->dev, client->irq, NULL, edt_ft5x06_ts_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, tsdata); if (error) { Loading @@ -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) Loading Loading @@ -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, Loading Loading
Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt 0 → 100644 +55 −0 Original line number Diff line number Diff line 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>; };
drivers/input/touchscreen/edt-ft5x06.c +114 −31 Original line number Diff line number Diff line /* * 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 Loading Loading @@ -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> Loading Loading @@ -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; Loading Loading @@ -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, 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); } Loading Loading @@ -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) Loading Loading @@ -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) { Loading @@ -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, 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"); Loading @@ -754,7 +820,11 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, return error; } 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, Loading Loading @@ -784,8 +854,8 @@ 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, error = devm_request_threaded_irq(&client->dev, client->irq, NULL, edt_ft5x06_ts_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, tsdata); if (error) { Loading @@ -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) Loading Loading @@ -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, Loading