linux/drivers/hid/i2c-hid/i2c-hid-of-goodix.c
<<
>>
Prefs
   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
  20struct goodix_i2c_hid_timing_data {
  21        unsigned int post_gpio_reset_delay_ms;
  22        unsigned int post_power_delay_ms;
  23};
  24
  25struct i2c_hid_of_goodix {
  26        struct i2chid_ops ops;
  27
  28        struct regulator *vdd;
  29        struct notifier_block nb;
  30        struct mutex regulator_mutex;
  31        struct gpio_desc *reset_gpio;
  32        const struct goodix_i2c_hid_timing_data *timings;
  33};
  34
  35static void goodix_i2c_hid_deassert_reset(struct i2c_hid_of_goodix *ihid_goodix,
  36                                          bool regulator_just_turned_on)
  37{
  38        if (regulator_just_turned_on && ihid_goodix->timings->post_power_delay_ms)
  39                msleep(ihid_goodix->timings->post_power_delay_ms);
  40
  41        gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 0);
  42        if (ihid_goodix->timings->post_gpio_reset_delay_ms)
  43                msleep(ihid_goodix->timings->post_gpio_reset_delay_ms);
  44}
  45
  46static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
  47{
  48        struct i2c_hid_of_goodix *ihid_goodix =
  49                container_of(ops, struct i2c_hid_of_goodix, ops);
  50
  51        return regulator_enable(ihid_goodix->vdd);
  52}
  53
  54static void goodix_i2c_hid_power_down(struct i2chid_ops *ops)
  55{
  56        struct i2c_hid_of_goodix *ihid_goodix =
  57                container_of(ops, struct i2c_hid_of_goodix, ops);
  58
  59        regulator_disable(ihid_goodix->vdd);
  60}
  61
  62static int ihid_goodix_vdd_notify(struct notifier_block *nb,
  63                                    unsigned long event,
  64                                    void *ignored)
  65{
  66        struct i2c_hid_of_goodix *ihid_goodix =
  67                container_of(nb, struct i2c_hid_of_goodix, nb);
  68        int ret = NOTIFY_OK;
  69
  70        mutex_lock(&ihid_goodix->regulator_mutex);
  71
  72        switch (event) {
  73        case REGULATOR_EVENT_PRE_DISABLE:
  74                gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
  75                break;
  76
  77        case REGULATOR_EVENT_ENABLE:
  78                goodix_i2c_hid_deassert_reset(ihid_goodix, true);
  79                break;
  80
  81        case REGULATOR_EVENT_ABORT_DISABLE:
  82                goodix_i2c_hid_deassert_reset(ihid_goodix, false);
  83                break;
  84
  85        default:
  86                ret = NOTIFY_DONE;
  87                break;
  88        }
  89
  90        mutex_unlock(&ihid_goodix->regulator_mutex);
  91
  92        return ret;
  93}
  94
  95static int i2c_hid_of_goodix_probe(struct i2c_client *client,
  96                                   const struct i2c_device_id *id)
  97{
  98        struct i2c_hid_of_goodix *ihid_goodix;
  99        int ret;
 100        ihid_goodix = devm_kzalloc(&client->dev, sizeof(*ihid_goodix),
 101                                   GFP_KERNEL);
 102        if (!ihid_goodix)
 103                return -ENOMEM;
 104
 105        mutex_init(&ihid_goodix->regulator_mutex);
 106
 107        ihid_goodix->ops.power_up = goodix_i2c_hid_power_up;
 108        ihid_goodix->ops.power_down = goodix_i2c_hid_power_down;
 109
 110        /* Start out with reset asserted */
 111        ihid_goodix->reset_gpio =
 112                devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH);
 113        if (IS_ERR(ihid_goodix->reset_gpio))
 114                return PTR_ERR(ihid_goodix->reset_gpio);
 115
 116        ihid_goodix->vdd = devm_regulator_get(&client->dev, "vdd");
 117        if (IS_ERR(ihid_goodix->vdd))
 118                return PTR_ERR(ihid_goodix->vdd);
 119
 120        ihid_goodix->timings = device_get_match_data(&client->dev);
 121
 122        /*
 123         * We need to control the "reset" line in lockstep with the regulator
 124         * actually turning on an off instead of just when we make the request.
 125         * This matters if the regulator is shared with another consumer.
 126         * - If the regulator is off then we must assert reset. The reset
 127         *   line is active low and on some boards it could cause a current
 128         *   leak if left high.
 129         * - If the regulator is on then we don't want reset asserted for very
 130         *   long. Holding the controller in reset apparently draws extra
 131         *   power.
 132         */
 133        mutex_lock(&ihid_goodix->regulator_mutex);
 134        ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify;
 135        ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb);
 136        if (ret) {
 137                mutex_unlock(&ihid_goodix->regulator_mutex);
 138                return dev_err_probe(&client->dev, ret,
 139                        "regulator notifier request failed\n");
 140        }
 141
 142        /*
 143         * If someone else is holding the regulator on (or the regulator is
 144         * an always-on one) we might never be told to deassert reset. Do it
 145         * now. Here we'll assume that someone else might have _just
 146         * barely_ turned the regulator on so we'll do the full
 147         * "post_power_delay" just in case.
 148         */
 149        if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd))
 150                goodix_i2c_hid_deassert_reset(ihid_goodix, true);
 151        mutex_unlock(&ihid_goodix->regulator_mutex);
 152
 153        return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001);
 154}
 155
 156static const struct goodix_i2c_hid_timing_data goodix_gt7375p_timing_data = {
 157        .post_power_delay_ms = 10,
 158        .post_gpio_reset_delay_ms = 180,
 159};
 160
 161static const struct of_device_id goodix_i2c_hid_of_match[] = {
 162        { .compatible = "goodix,gt7375p", .data = &goodix_gt7375p_timing_data },
 163        { }
 164};
 165MODULE_DEVICE_TABLE(of, goodix_i2c_hid_of_match);
 166
 167static struct i2c_driver goodix_i2c_hid_ts_driver = {
 168        .driver = {
 169                .name   = "i2c_hid_of_goodix",
 170                .pm     = &i2c_hid_core_pm,
 171                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
 172                .of_match_table = of_match_ptr(goodix_i2c_hid_of_match),
 173        },
 174        .probe          = i2c_hid_of_goodix_probe,
 175        .remove         = i2c_hid_core_remove,
 176        .shutdown       = i2c_hid_core_shutdown,
 177};
 178module_i2c_driver(goodix_i2c_hid_ts_driver);
 179
 180MODULE_AUTHOR("Douglas Anderson <dianders@chromium.org>");
 181MODULE_DESCRIPTION("Goodix i2c-hid touchscreen driver");
 182MODULE_LICENSE("GPL v2");
 183