[PATCH 2/2] usb: typec: hd3ss3220: Add support for supply regulators
Alexey Charkov <[email protected]>
| Newsgroups | org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel,org.kernel.vger.linux-usb |
|---|---|
| Message-ID | <[email protected]> |
HD3SS3220 requires VDD5 input to be present 2ms before VCC33 is applied, or else it gets backpowered via the 3.3V rail in a non-functional state and wedges the I2C bus, bringing down all devices on it. Enable both regulators in the datasheet prescribed sequence if provided. Signed-off-by: Alexey Charkov <[email protected]> --- drivers/usb/typec/hd3ss3220.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/usb/typec/hd3ss3220.c b/drivers/usb/typec/hd3ss3220.c index d0de5a2488f9..b53455abc048 100644 --- a/drivers/usb/typec/hd3ss3220.c +++ b/drivers/usb/typec/hd3ss3220.c @@ -49,6 +49,9 @@ #define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_UFP BIT(4) #define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DRP (BIT(5) | BIT(4)) +/* Minimum time VDD5 has to be stable before VCC33 starts ramping up */ +#define HD3SS3220_TVDD5V_PG_US 2000 + struct hd3ss3220 { struct device *dev; struct regmap *regmap; @@ -358,6 +361,31 @@ static irqreturn_t hd3ss3220_id_isr(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * Bring both supplies up in the order the datasheet asks for. Powering VCC33 + * first can back-power the device in a non-functioning state, which grounds + * the I2C bus and takes both this device and any others on the same bus down + */ +static int hd3ss3220_power_up(struct device *dev) +{ + int ret; + + ret = devm_regulator_get_enable(dev, "vdd5"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable VDD5\n"); + + /* Nothing to stagger against unless the board describes both rails */ + if (device_property_present(dev, "vdd5-supply") && + device_property_present(dev, "vcc33-supply")) + fsleep(HD3SS3220_TVDD5V_PG_US); + + ret = devm_regulator_get_enable(dev, "vcc33"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable VCC33\n"); + + return 0; +} + static int hd3ss3220_probe(struct i2c_client *client) { struct typec_capability typec_cap = { }; @@ -379,6 +407,10 @@ static int hd3ss3220_probe(struct i2c_client *client) if (IS_ERR(hd3ss3220->regmap)) return PTR_ERR(hd3ss3220->regmap); + ret = hd3ss3220_power_up(hd3ss3220->dev); + if (ret) + return ret; + /* For backward compatibility check the connector child node first */ connector = device_get_named_child_node(hd3ss3220->dev, "connector"); if (connector) { -- 2.54.0