From 121db2e38e0f9bc735ba1d415d4cbff0c9524a7c Mon Sep 17 00:00:00 2001 From: Bin Yang Date: Wed, 4 Jan 2017 08:55:26 +0800 Subject: [PATCH] mfd: fusb302: add gpio control vbus discharge MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When type-c vbus output power down or disconnect charging input, the type-c vbus voltage discharge to 0V take a long time, during this time residual voltage would affect charge circuit in some platforms(e.g. rk3399-tve1205g board). So we need add fast discharge circuit, then use a gpio control it. Change-Id: I4c8eebc0cf10c6c38c7db9d9d5c71c4f6769e7fc Signed-off-by: Bin Yang --- drivers/mfd/fusb302.c | 35 +++++++++++++++++++++++++++++++++++ drivers/mfd/fusb302.h | 1 + 2 files changed, 36 insertions(+) diff --git a/drivers/mfd/fusb302.c b/drivers/mfd/fusb302.c index c7bc44266d54..6f07904718e4 100644 --- a/drivers/mfd/fusb302.c +++ b/drivers/mfd/fusb302.c @@ -300,6 +300,9 @@ static void fusb_timer_start(struct hrtimer *timer, int ms) static void platform_set_vbus_lvl_enable(struct fusb30x_chip *chip, int vbus_5v, int vbus_other) { + bool gpio_vbus_value = 0; + + gpio_vbus_value = gpiod_get_value(chip->gpio_vbus_5v); if (chip->gpio_vbus_5v) { gpiod_set_raw_value(chip->gpio_vbus_5v, vbus_5v); /* Only set state here, don't sync notifier to PMIC */ @@ -312,6 +315,12 @@ static void platform_set_vbus_lvl_enable(struct fusb30x_chip *chip, int vbus_5v, if (chip->gpio_vbus_other) gpiod_set_raw_value(chip->gpio_vbus_5v, vbus_other); + + if (chip->gpio_discharge && !vbus_5v && gpio_vbus_value) { + gpiod_set_value(chip->gpio_discharge, 1); + msleep(20); + gpiod_set_value(chip->gpio_discharge, 0); + } } static void set_state(struct fusb30x_chip *chip, enum connection_state state) @@ -786,7 +795,11 @@ static void set_state_unattached(struct fusb30x_chip *chip) memset(&chip->notify, 0, sizeof(struct notify_info)); platform_fusb_notify(chip); + if (chip->gpio_discharge) + gpiod_set_value(chip->gpio_discharge, 1); msleep(100); + if (chip->gpio_discharge) + gpiod_set_value(chip->gpio_discharge, 0); } static int tcpm_check_vbus(struct fusb30x_chip *chip) @@ -2278,6 +2291,14 @@ static int fusb_initialize_gpio(struct fusb30x_chip *chip) else gpiod_set_raw_value(chip->gpio_vbus_other, 0); + chip->gpio_discharge = devm_gpiod_get_optional(chip->dev, "discharge", + GPIOD_OUT_LOW); + if (IS_ERR(chip->gpio_discharge)) { + dev_warn(chip->dev, + "Could not get named GPIO for discharge!\n"); + chip->gpio_discharge = NULL; + } + return 0; } @@ -2503,6 +2524,19 @@ static int fusb30x_remove(struct i2c_client *client) return 0; } +static void fusb30x_shutdown(struct i2c_client *client) +{ + struct fusb30x_chip *chip = i2c_get_clientdata(client); + + if (chip->gpio_vbus_5v) + gpiod_set_value(chip->gpio_vbus_5v, 0); + if (chip->gpio_discharge) { + gpiod_set_value(chip->gpio_discharge, 1); + msleep(100); + gpiod_set_value(chip->gpio_discharge, 0); + } +} + static const struct of_device_id fusb30x_dt_match[] = { { .compatible = FUSB30X_I2C_DEVICETREE_NAME }, {}, @@ -2522,6 +2556,7 @@ static struct i2c_driver fusb30x_driver = { }, .probe = fusb30x_probe, .remove = fusb30x_remove, + .shutdown = fusb30x_shutdown, .id_table = fusb30x_i2c_device_id, }; diff --git a/drivers/mfd/fusb302.h b/drivers/mfd/fusb302.h index db564f4d0c2c..8d98e94120a9 100644 --- a/drivers/mfd/fusb302.h +++ b/drivers/mfd/fusb302.h @@ -378,6 +378,7 @@ struct fusb30x_chip { struct gpio_desc *gpio_vbus_5v; struct gpio_desc *gpio_vbus_other; struct gpio_desc *gpio_int; + struct gpio_desc *gpio_discharge; int timer_state; int timer_mux; int port_num; -- 2.34.1