Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for Elan touchscreens that use the i2c-hid protocol.
0004  *
0005  * Copyright 2020 Google LLC
0006  */
0007 
0008 #include <linux/delay.h>
0009 #include <linux/device.h>
0010 #include <linux/gpio/consumer.h>
0011 #include <linux/i2c.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/of.h>
0015 #include <linux/pm.h>
0016 #include <linux/regulator/consumer.h>
0017 
0018 #include "i2c-hid.h"
0019 
0020 struct elan_i2c_hid_chip_data {
0021     unsigned int post_gpio_reset_delay_ms;
0022     unsigned int post_power_delay_ms;
0023     u16 hid_descriptor_address;
0024 };
0025 
0026 struct i2c_hid_of_elan {
0027     struct i2chid_ops ops;
0028 
0029     struct regulator *vcc33;
0030     struct regulator *vccio;
0031     struct gpio_desc *reset_gpio;
0032     const struct elan_i2c_hid_chip_data *chip_data;
0033 };
0034 
0035 static int elan_i2c_hid_power_up(struct i2chid_ops *ops)
0036 {
0037     struct i2c_hid_of_elan *ihid_elan =
0038         container_of(ops, struct i2c_hid_of_elan, ops);
0039     int ret;
0040 
0041     ret = regulator_enable(ihid_elan->vcc33);
0042     if (ret)
0043         return ret;
0044 
0045     ret = regulator_enable(ihid_elan->vccio);
0046     if (ret) {
0047         regulator_disable(ihid_elan->vcc33);
0048         return ret;
0049     }
0050 
0051     if (ihid_elan->chip_data->post_power_delay_ms)
0052         msleep(ihid_elan->chip_data->post_power_delay_ms);
0053 
0054     gpiod_set_value_cansleep(ihid_elan->reset_gpio, 0);
0055     if (ihid_elan->chip_data->post_gpio_reset_delay_ms)
0056         msleep(ihid_elan->chip_data->post_gpio_reset_delay_ms);
0057 
0058     return 0;
0059 }
0060 
0061 static void elan_i2c_hid_power_down(struct i2chid_ops *ops)
0062 {
0063     struct i2c_hid_of_elan *ihid_elan =
0064         container_of(ops, struct i2c_hid_of_elan, ops);
0065 
0066     gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1);
0067     regulator_disable(ihid_elan->vccio);
0068     regulator_disable(ihid_elan->vcc33);
0069 }
0070 
0071 static int i2c_hid_of_elan_probe(struct i2c_client *client,
0072                  const struct i2c_device_id *id)
0073 {
0074     struct i2c_hid_of_elan *ihid_elan;
0075 
0076     ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL);
0077     if (!ihid_elan)
0078         return -ENOMEM;
0079 
0080     ihid_elan->ops.power_up = elan_i2c_hid_power_up;
0081     ihid_elan->ops.power_down = elan_i2c_hid_power_down;
0082 
0083     /* Start out with reset asserted */
0084     ihid_elan->reset_gpio =
0085         devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH);
0086     if (IS_ERR(ihid_elan->reset_gpio))
0087         return PTR_ERR(ihid_elan->reset_gpio);
0088 
0089     ihid_elan->vccio = devm_regulator_get(&client->dev, "vccio");
0090     if (IS_ERR(ihid_elan->vccio))
0091         return PTR_ERR(ihid_elan->vccio);
0092 
0093     ihid_elan->vcc33 = devm_regulator_get(&client->dev, "vcc33");
0094     if (IS_ERR(ihid_elan->vcc33))
0095         return PTR_ERR(ihid_elan->vcc33);
0096 
0097     ihid_elan->chip_data = device_get_match_data(&client->dev);
0098 
0099     return i2c_hid_core_probe(client, &ihid_elan->ops,
0100                   ihid_elan->chip_data->hid_descriptor_address, 0);
0101 }
0102 
0103 static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = {
0104     .post_power_delay_ms = 1,
0105     .post_gpio_reset_delay_ms = 300,
0106     .hid_descriptor_address = 0x0001,
0107 };
0108 
0109 static const struct of_device_id elan_i2c_hid_of_match[] = {
0110     { .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data },
0111     { }
0112 };
0113 MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match);
0114 
0115 static struct i2c_driver elan_i2c_hid_ts_driver = {
0116     .driver = {
0117         .name   = "i2c_hid_of_elan",
0118         .pm = &i2c_hid_core_pm,
0119         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
0120         .of_match_table = of_match_ptr(elan_i2c_hid_of_match),
0121     },
0122     .probe      = i2c_hid_of_elan_probe,
0123     .remove     = i2c_hid_core_remove,
0124     .shutdown   = i2c_hid_core_shutdown,
0125 };
0126 module_i2c_driver(elan_i2c_hid_ts_driver);
0127 
0128 MODULE_AUTHOR("Douglas Anderson <dianders@chromium.org>");
0129 MODULE_DESCRIPTION("Elan i2c-hid touchscreen driver");
0130 MODULE_LICENSE("GPL");