Skip to content

Commit f8d2bf7

Browse files
Kriskura176767gregkh
authored andcommitted
usb: typec: hd3ss3220: Enable VBUS based on ID pin state
There is a ID pin present on HD3SS3220 controller that can be routed to SoC. As per the datasheet: "Upon detecting a UFP device, HD3SS3220 will keep ID pin high if VBUS is not at VSafe0V. Once VBUS is at VSafe0V, the HD3SS3220 will assert ID pin low. This is done to enforce Type-C requirement that VBUS must be at VSafe0V before re-enabling VBUS" Add support to read the ID pin state and enable VBUS accordingly. Signed-off-by: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://patch.msgid.link/20251111072025.2199142-3-krishna.kurapati@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d53bdaa commit f8d2bf7

1 file changed

Lines changed: 73 additions & 2 deletions

File tree

drivers/usb/typec/hd3ss3220.c

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
#include <linux/usb/typec.h>
1616
#include <linux/delay.h>
1717
#include <linux/workqueue.h>
18+
#include <linux/gpio/consumer.h>
19+
#include <linux/regulator/consumer.h>
20+
#include <linux/of_graph.h>
1821

1922
#define HD3SS3220_REG_CN_STAT 0x08
2023
#define HD3SS3220_REG_CN_STAT_CTRL 0x09
@@ -54,6 +57,11 @@ struct hd3ss3220 {
5457
struct delayed_work output_poll_work;
5558
enum usb_role role_state;
5659
bool poll;
60+
61+
struct gpio_desc *id_gpiod;
62+
int id_irq;
63+
64+
struct regulator *vbus;
5765
};
5866

5967
static int hd3ss3220_set_power_opmode(struct hd3ss3220 *hd3ss3220, int power_opmode)
@@ -319,13 +327,33 @@ static const struct regmap_config config = {
319327
.max_register = 0x0A,
320328
};
321329

330+
static irqreturn_t hd3ss3220_id_isr(int irq, void *dev_id)
331+
{
332+
struct hd3ss3220 *hd3ss3220 = dev_id;
333+
int ret;
334+
int id;
335+
336+
id = gpiod_get_value_cansleep(hd3ss3220->id_gpiod);
337+
if (!id)
338+
ret = regulator_enable(hd3ss3220->vbus);
339+
else
340+
ret = regulator_disable(hd3ss3220->vbus);
341+
342+
if (ret)
343+
dev_err(hd3ss3220->dev,
344+
"vbus regulator %s failed: %d\n", id ? "disable" : "enable", ret);
345+
346+
return IRQ_HANDLED;
347+
}
348+
322349
static int hd3ss3220_probe(struct i2c_client *client)
323350
{
324351
struct typec_capability typec_cap = { };
325-
struct hd3ss3220 *hd3ss3220;
326352
struct fwnode_handle *connector, *ep;
327-
int ret;
353+
struct hd3ss3220 *hd3ss3220;
354+
struct regulator *vbus;
328355
unsigned int data;
356+
int ret;
329357

330358
hd3ss3220 = devm_kzalloc(&client->dev, sizeof(struct hd3ss3220),
331359
GFP_KERNEL);
@@ -359,6 +387,49 @@ static int hd3ss3220_probe(struct i2c_client *client)
359387
goto err_put_fwnode;
360388
}
361389

390+
vbus = devm_of_regulator_get_optional(hd3ss3220->dev,
391+
to_of_node(connector),
392+
"vbus");
393+
if (IS_ERR(vbus) && vbus != ERR_PTR(-ENODEV)) {
394+
ret = PTR_ERR(vbus);
395+
dev_err(hd3ss3220->dev, "failed to get vbus: %d", ret);
396+
goto err_put_fwnode;
397+
}
398+
399+
hd3ss3220->vbus = (vbus == ERR_PTR(-ENODEV) ? NULL : vbus);
400+
401+
if (hd3ss3220->vbus) {
402+
hd3ss3220->id_gpiod = devm_gpiod_get_optional(hd3ss3220->dev,
403+
"id",
404+
GPIOD_IN);
405+
if (IS_ERR(hd3ss3220->id_gpiod)) {
406+
ret = PTR_ERR(hd3ss3220->id_gpiod);
407+
goto err_put_fwnode;
408+
}
409+
}
410+
411+
if (hd3ss3220->id_gpiod) {
412+
hd3ss3220->id_irq = gpiod_to_irq(hd3ss3220->id_gpiod);
413+
if (hd3ss3220->id_irq < 0) {
414+
ret = hd3ss3220->id_irq;
415+
dev_err(hd3ss3220->dev,
416+
"failed to get ID gpio: %d\n",
417+
hd3ss3220->id_irq);
418+
goto err_put_fwnode;
419+
}
420+
421+
ret = devm_request_threaded_irq(hd3ss3220->dev,
422+
hd3ss3220->id_irq, NULL,
423+
hd3ss3220_id_isr,
424+
IRQF_TRIGGER_RISING |
425+
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
426+
dev_name(hd3ss3220->dev), hd3ss3220);
427+
if (ret < 0) {
428+
dev_err(hd3ss3220->dev, "failed to get ID irq: %d\n", ret);
429+
goto err_put_fwnode;
430+
}
431+
}
432+
362433
typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
363434
typec_cap.driver_data = hd3ss3220;
364435
typec_cap.type = TYPEC_PORT_DRP;

0 commit comments

Comments
 (0)