From: Lothar Waßmann Date: Thu, 24 Oct 2013 06:59:32 +0000 (+0200) Subject: Input: edt-ft5x06 - add DT support X-Git-Tag: KARO-TX6-2013-11-08 X-Git-Url: https://git.karo-electronics.de/?p=karo-tx-linux.git;a=commitdiff_plain;h=8f8a611bc320c3e99f3ba9c42860ead3c62e47c6 Input: edt-ft5x06 - add DT support Signed-off-by: Lothar Waßmann --- diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt new file mode 100644 index 000000000000..7028b54c18da --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt @@ -0,0 +1,30 @@ +* EDT FT5x06 Multiple Touch Controller + +Required properties: +- compatible: must be "edt,edt-ft5x06" +- reg: i2c slave address +- interrupt-parent: the phandle for the interrupt controller +- interrupts: touch controller interrupt + +Optional properties: +- reset-gpios: the gpio pin to be used for resetting the controller +- wakeup-gpios: the gpio pin to be used for waking up the controller + + The following properties provide default values for the + corresponding parameters configurable via sysfs + (see Documentation/input/edt-ft5x06.txt) +- threshold: allows setting the "click"-threshold in the range from 20 to 80. +- gain: sensitivity (0..31) (lower value -> higher sensitivity) +- offset: edge compensation (0..31) +- report_rate: report rate (3..14) + +Example: + + edt-ft5x06@38 { + compatible = "edt,edt-ft5x06"; + reg = <0x38>; + interrupt-parent = <&gpio2>; + interrupts = <5 0>; + reset-gpios = <&gpio2 6 GPIO_ACTIVE_LOW>; + wakeup-gpios = <&gpio4 9 GPIO_ACTIVE_HIGH>; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 04eab45dd148..b100a432514e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -23,6 +23,7 @@ cortina Cortina Systems, Inc. dallas Maxim Integrated Products (formerly Dallas Semiconductor) davicom DAVICOM Semiconductor, Inc. denx Denx Software Engineering +edt Emerging Display Technologies emmicro EM Microelectronic epson Seiko Epson Corp. est ESTeem Wireless Modems diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 83fa1b15a97f..edab79093fe1 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,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; @@ -617,24 +622,37 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) 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 = gpio_request_one(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 = gpio_request_one(reset_pin, GPIOF_OUT_INIT_LOW, + error = gpio_request_one(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); - mdelay(100); + mdelay(5); + gpio_set_value(tsdata->reset_pin, 1); + mdelay(300); } return 0; @@ -674,6 +692,21 @@ 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) { \ + const u32 *prop = of_get_property(np, #name, NULL); \ + if (prop) \ + edt_ft5x06_register_write(tsdata, reg, be32_to_cpu(*prop)); \ +} + +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); + EDT_GET_PROP(report_rate, WORK_REGISTER_REPORT_RATE); +} + static void edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata, const struct edt_ft5x06_platform_data *pdata) @@ -701,6 +734,39 @@ 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) +{ + int ret; + struct device_node *np = dev->of_node; + enum of_gpio_flags gpio_flags; + + if (!np) + return -ENODEV; + + /* + * irq_pin is not needed for DT setup. + * irq is associated via 'interrupts' property in DT + */ + tsdata->irq_pin = -EINVAL; + + ret = of_get_named_gpio_flags(np, "reset-gpios", 0, &gpio_flags); + tsdata->reset_pin = ret; + + ret = of_get_named_gpio_flags(np, "wake-gpios", 0, &gpio_flags); + tsdata->wake_pin = ret; + + return 0; +} +#else +static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev, + struct edt_ft5x06_i2c_ts_data *tsdata) +{ + return -ENODEV; +} +#endif + static int edt_ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -713,30 +779,43 @@ 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 = gpio_request_one(pdata->irq_pin, + if (gpio_is_valid(tsdata->irq_pin)) { + error = gpio_request_one(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 = kzalloc(sizeof(*tsdata), GFP_KERNEL); input = input_allocate_device(); - if (!tsdata || !input) { - dev_err(&client->dev, "failed to allocate driver data.\n"); + if (!input) { + dev_err(&client->dev, "failed to allocate input device.\n"); error = -ENOMEM; goto err_free_mem; } @@ -752,7 +831,11 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, goto err_free_mem; } - 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, @@ -802,8 +885,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, 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; @@ -813,18 +896,18 @@ err_free_irq: free_irq(client->irq, tsdata); err_free_mem: input_free_device(input); - kfree(tsdata); - - if (gpio_is_valid(pdata->irq_pin)) - gpio_free(pdata->irq_pin); + if (gpio_is_valid(tsdata->irq_pin)) + gpio_free(tsdata->irq_pin); + if (gpio_is_valid(tsdata->reset_pin)) + gpio_free(tsdata->reset_pin); + if (gpio_is_valid(tsdata->wake_pin)) + gpio_free(tsdata->wake_pin); return error; } static int edt_ft5x06_ts_remove(struct i2c_client *client) { - const struct edt_ft5x06_platform_data *pdata = - dev_get_platdata(&client->dev); struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); edt_ft5x06_ts_teardown_debugfs(tsdata); @@ -833,12 +916,12 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client) free_irq(client->irq, tsdata); input_unregister_device(tsdata->input); - if (gpio_is_valid(pdata->irq_pin)) - gpio_free(pdata->irq_pin); - if (gpio_is_valid(pdata->reset_pin)) - gpio_free(pdata->reset_pin); - - kfree(tsdata); + if (gpio_is_valid(tsdata->irq_pin)) + gpio_free(tsdata->irq_pin); + if (gpio_is_valid(tsdata->reset_pin)) + gpio_free(tsdata->reset_pin); + if (gpio_is_valid(tsdata->wake_pin)) + gpio_free(tsdata->wake_pin); return 0; } @@ -869,15 +952,22 @@ static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); static const struct i2c_device_id edt_ft5x06_ts_id[] = { - { "edt-ft5x06", 0 }, - { } + { "edt-ft5x06", 0, }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); +static const struct of_device_id edt_ft5x06_of_match[] = { + { .compatible = "edt,edt-ft5x06", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); + static struct i2c_driver edt_ft5x06_ts_driver = { .driver = { .owner = THIS_MODULE, .name = "edt_ft5x06", + .of_match_table = edt_ft5x06_of_match, .pm = &edt_ft5x06_ts_pm_ops, }, .id_table = edt_ft5x06_ts_id, @@ -890,3 +980,4 @@ module_i2c_driver(edt_ft5x06_ts_driver); MODULE_AUTHOR("Simon Budig "); MODULE_DESCRIPTION("EDT FT5x06 I2C Touchscreen Driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:edt-ft5x06");