From: Kautuk Consul <kautuk_consul@xxxxxxxxxx> The upstream Atmel mXT driver implementation seems to handle the T19 GPIO/PWM object as a key pad. Keys can be defined in the device tree ("linux,gpio-keymap") and will be transported as key events to the Linux input device if GPIO state changes. With our hardware, the GPIO pins of the touch controller are connected to a PWM/backlight controller and used as supervision inputs. We like to read the status of the pins by a script or an application in the sysfs. Adding newer sysfs entries which shall be placed in the input class directory eg: /sys/class/input/input<n>/backlight_error1 Signed-off-by: Kautuk Consul <kautuk_consul@xxxxxxxxxx> Signed-off-by: Balasubramani Vivekanandan <balasubramani_vivekanandan@xxxxxxxxxx> Signed-off-by: George G. Davis <george_davis@xxxxxxxxxx> Signed-off-by: Jiada Wang <jiada_wang@xxxxxxxxxx> --- .../bindings/input/atmel,maxtouch.txt | 15 +++ drivers/input/touchscreen/atmel_mxt_ts.c | 120 ++++++++++++++++++ 2 files changed, 135 insertions(+) diff --git a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt index d7db16920083..7afe12a93202 100644 --- a/Documentation/devicetree/bindings/input/atmel,maxtouch.txt +++ b/Documentation/devicetree/bindings/input/atmel,maxtouch.txt @@ -42,6 +42,9 @@ Optional properties for main touchpad device: - atmel,input_name: Override name of input device from the default. +- atmel,gpios: Specify the GPIO input pins whose status will be read via the + /sys/class/input/input<n>/backlight_error<x> sysfs entries. + Example: touch@4b { @@ -49,4 +52,16 @@ Example: reg = <0x4b>; interrupt-parent = <&gpio>; interrupts = <TEGRA_GPIO(W, 3) IRQ_TYPE_LEVEL_LOW>; + + atmel,gpios { + backlight_error1 { + gpio = <3 GPIO_ACTIVE_HIGH>; /* connected to + * the GPIO3 pin of mXT input */ + }; + + backlight_error2 { + gpio = <5 GPIO_ACTIVE_HIGH>; /* connected to + * the GPIO5 pin of mXT input */ + }; + }; }; diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 9cdb7754599c..a8e2b927bb12 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -414,6 +414,15 @@ struct mxt_data { /* Indicates whether device is updating configuration */ bool updating_config; + + unsigned long gpio_input_pin_status; + struct attribute_group gpio_attrs; + unsigned long gpio_input_pin_status_default; +}; + +struct mxt_gpio_attr { + struct device_attribute attr; + int bit_index; }; struct mxt_vb2_buffer { @@ -1381,6 +1390,7 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message) } else if (report_id == data->T19_reportid) { mxt_input_button(data, message); data->update_input = true; + data->gpio_input_pin_status = message[1]; } else if (report_id >= data->T15_reportid_min && report_id <= data->T15_reportid_max) { mxt_proc_t15_messages(data, message); @@ -2747,6 +2757,16 @@ static int mxt_initialize_input_device(struct mxt_data *data) goto err_free_mem; } + if (data->gpio_attrs.attrs) { + error = sysfs_create_group(&input_dev->dev.kobj, + &data->gpio_attrs); + if (error) { + dev_err(dev, "Failure %d creating sysfs group\n", + error); + goto err_free_mem; + } + } + data->input_dev = input_dev; return 0; @@ -3995,10 +4015,26 @@ static void mxt_input_close(struct input_dev *dev) dev_err(&data->client->dev, "%s failed rc=%d\n", __func__, ret); } +static ssize_t mxt_gpio_input_pin_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct mxt_data *data = dev_get_drvdata(dev); + struct mxt_gpio_attr *attr_p = container_of(attr, struct mxt_gpio_attr, + attr); + int pin_status = test_bit(attr_p->bit_index, + &data->gpio_input_pin_status); + + return scnprintf(buf, PAGE_SIZE, "%d\n", pin_status); +} + static int mxt_parse_device_properties(struct mxt_data *data) { static const char keymap_property[] = "linux,gpio-keymap"; + static const char gpios_property[] = "atmel,gpios"; struct device *dev = &data->client->dev; + struct device_node *np = dev ? dev->of_node : NULL; + struct device_node *np_gpio; u32 *keymap; int n_keys; int error; @@ -4036,7 +4072,89 @@ static int mxt_parse_device_properties(struct mxt_data *data) device_property_read_u32(dev, "atmel,suspend-mode", &data->suspend_mode); + np_gpio = of_get_child_by_name(np, gpios_property); + if (np_gpio) { + int gpio_pin; + struct mxt_gpio_attr *attr_p; + char *sysfs_gpio_file_name; + u8 num_gpio_pins = 0; + + np_gpio = of_find_node_with_property(np_gpio, "gpio"); + if (!np_gpio) + return -EINVAL; + + data->gpio_attrs.attrs = + devm_kzalloc(dev, + 9 * sizeof(struct attribute *), + GFP_KERNEL); + if (!data->gpio_attrs.attrs) { + error = -ENOMEM; + goto err_gpios_property_put; + } + + do { + attr_p = devm_kmalloc(dev, + sizeof(struct mxt_gpio_attr), + GFP_KERNEL); + if (!attr_p) { + error = -ENOMEM; + goto err_gpios_property_put; + } + + error = of_property_read_u32_index(np_gpio, "gpio", 0, + &gpio_pin); + if (error) { + dev_warn(dev, + "Couldn't read gpio property for node : %s\n", + np_gpio->name); + error = -EINVAL; + goto err_gpios_property_put; + } + + if (gpio_pin > 7) { + dev_warn(dev, + "Incorrect GPIO pin index for node %s: %u\n", + np_gpio->name, gpio_pin); + error = -EINVAL; + goto err_gpios_property_put; + } + + sysfs_gpio_file_name = + devm_kmalloc(dev, + strlen(np_gpio->name) + 1, + GFP_KERNEL); + if (!sysfs_gpio_file_name) { + error = -ENOMEM; + goto err_gpios_property_put; + } + + strcpy(sysfs_gpio_file_name, np_gpio->name); + + sysfs_attr_init(&attr_p->attr.attr); + + attr_p->attr.attr.name = sysfs_gpio_file_name; + attr_p->attr.attr.mode = 0444; + attr_p->attr.show = mxt_gpio_input_pin_read; + attr_p->attr.store = NULL; + attr_p->bit_index = gpio_pin; + + data->gpio_input_pin_status_default |= BIT(gpio_pin); + + data->gpio_attrs.attrs[num_gpio_pins++] = + &attr_p->attr.attr; + } while ((np_gpio = + of_find_node_with_property(np_gpio, "gpio")) && + num_gpio_pins < 8); + + if (np_gpio) + of_node_put(np_gpio); + } + return 0; + +err_gpios_property_put: + of_node_put(np_gpio); + return error; } static const struct dmi_system_id chromebook_T9_suspend_dmi[] = { @@ -4106,6 +4224,8 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) if (error) return error; + data->gpio_input_pin_status = data->gpio_input_pin_status_default; + if (data->pcfg_name) mxt_update_file_name(&data->client->dev, &data->cfg_name, -- 2.19.2