1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for Goodix touchscreens that use the i2c-hid protocol. 4 * 5 * Copyright 2020 Google LLC 6 */ 7 8 #include <linux/delay.h> 9 #include <linux/device.h> 10 #include <linux/gpio/consumer.h> 11 #include <linux/i2c.h> 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/pm.h> 16 #include <linux/regulator/consumer.h> 17 18 #include "i2c-hid.h" 19 20 struct goodix_i2c_hid_timing_data { 21 unsigned int post_gpio_reset_delay_ms; 22 unsigned int post_power_delay_ms; 23 }; 24 25 struct i2c_hid_of_goodix { 26 struct i2chid_ops ops; 27 28 struct regulator *vdd; 29 struct regulator *vddio; 30 struct gpio_desc *reset_gpio; 31 const struct goodix_i2c_hid_timing_data *timings; 32 }; 33 34 static int goodix_i2c_hid_power_up(struct i2chid_ops *ops) 35 { 36 struct i2c_hid_of_goodix *ihid_goodix = 37 container_of(ops, struct i2c_hid_of_goodix, ops); 38 int ret; 39 40 ret = regulator_enable(ihid_goodix->vdd); 41 if (ret) 42 return ret; 43 44 ret = regulator_enable(ihid_goodix->vddio); 45 if (ret) 46 return ret; 47 48 if (ihid_goodix->timings->post_power_delay_ms) 49 msleep(ihid_goodix->timings->post_power_delay_ms); 50 51 gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 0); 52 if (ihid_goodix->timings->post_gpio_reset_delay_ms) 53 msleep(ihid_goodix->timings->post_gpio_reset_delay_ms); 54 55 return 0; 56 } 57 58 static void goodix_i2c_hid_power_down(struct i2chid_ops *ops) 59 { 60 struct i2c_hid_of_goodix *ihid_goodix = 61 container_of(ops, struct i2c_hid_of_goodix, ops); 62 63 gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1); 64 regulator_disable(ihid_goodix->vddio); 65 regulator_disable(ihid_goodix->vdd); 66 } 67 68 static int i2c_hid_of_goodix_probe(struct i2c_client *client) 69 { 70 struct i2c_hid_of_goodix *ihid_goodix; 71 72 ihid_goodix = devm_kzalloc(&client->dev, sizeof(*ihid_goodix), 73 GFP_KERNEL); 74 if (!ihid_goodix) 75 return -ENOMEM; 76 77 ihid_goodix->ops.power_up = goodix_i2c_hid_power_up; 78 ihid_goodix->ops.power_down = goodix_i2c_hid_power_down; 79 80 /* Start out with reset asserted */ 81 ihid_goodix->reset_gpio = 82 devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); 83 if (IS_ERR(ihid_goodix->reset_gpio)) 84 return PTR_ERR(ihid_goodix->reset_gpio); 85 86 ihid_goodix->vdd = devm_regulator_get(&client->dev, "vdd"); 87 if (IS_ERR(ihid_goodix->vdd)) 88 return PTR_ERR(ihid_goodix->vdd); 89 90 ihid_goodix->vddio = devm_regulator_get(&client->dev, "mainboard-vddio"); 91 if (IS_ERR(ihid_goodix->vddio)) 92 return PTR_ERR(ihid_goodix->vddio); 93 94 ihid_goodix->timings = device_get_match_data(&client->dev); 95 96 return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0); 97 } 98 99 static const struct goodix_i2c_hid_timing_data goodix_gt7375p_timing_data = { 100 .post_power_delay_ms = 10, 101 .post_gpio_reset_delay_ms = 180, 102 }; 103 104 static const struct of_device_id goodix_i2c_hid_of_match[] = { 105 { .compatible = "goodix,gt7375p", .data = &goodix_gt7375p_timing_data }, 106 { } 107 }; 108 MODULE_DEVICE_TABLE(of, goodix_i2c_hid_of_match); 109 110 static struct i2c_driver goodix_i2c_hid_ts_driver = { 111 .driver = { 112 .name = "i2c_hid_of_goodix", 113 .pm = &i2c_hid_core_pm, 114 .probe_type = PROBE_PREFER_ASYNCHRONOUS, 115 .of_match_table = of_match_ptr(goodix_i2c_hid_of_match), 116 }, 117 .probe_new = i2c_hid_of_goodix_probe, 118 .remove = i2c_hid_core_remove, 119 .shutdown = i2c_hid_core_shutdown, 120 }; 121 module_i2c_driver(goodix_i2c_hid_ts_driver); 122 123 MODULE_AUTHOR("Douglas Anderson <dianders@chromium.org>"); 124 MODULE_DESCRIPTION("Goodix i2c-hid touchscreen driver"); 125 MODULE_LICENSE("GPL v2"); 126