Message ID | 20200914164639.1487650-3-angus@akkea.ca |
---|---|
State | New |
Headers | show |
Series | RFC: USB C extcon patchset for the tps6598x | expand |
Hi, On 9/15/20 1:46 AM, Angus Ainslie wrote: > The tps6598x type C chip can negotiate the VBUS sink/source status as > well as the VBUS voltage and current. Notify the extcon consumers of > these changes. > > Signed-off-by: Angus Ainslie <angus@akkea.ca> > --- > drivers/usb/typec/tps6598x.c | 138 +++++++++++++++++++++++++++++++++++ > 1 file changed, 138 insertions(+) > > diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c > index 3db33bb622c3..3b06d43c810d 100644 > --- a/drivers/usb/typec/tps6598x.c > +++ b/drivers/usb/typec/tps6598x.c > @@ -8,6 +8,8 @@ > > #include <linux/i2c.h> > #include <linux/acpi.h> > +#include <linux/extcon.h> > +#include <linux/extcon-provider.h> > #include <linux/module.h> > #include <linux/regmap.h> > #include <linux/interrupt.h> > @@ -95,7 +97,12 @@ struct tps6598x { > struct typec_port *port; > struct typec_partner *partner; > struct usb_pd_identity partner_identity; > + > struct usb_role_switch *role_sw; > + > +#ifdef CONFIG_EXTCON Is it necessary of 'ifdef CONFIG_EXTCON'? If you just add 'select EXTCON' for this driver, you don't need to check CONFIG_EXTCON. If any device driver need some framework, we can add the 'select EXTCON'. > + struct extcon_dev *edev; > +#endif > }; > > /* > @@ -209,6 +216,62 @@ static void tps6598x_set_data_role(struct tps6598x *tps, > typec_set_data_role(tps->port, role); > } > > +#ifdef CONFIG_EXTCON > +static void tps6589x_set_extcon_state(struct tps6598x *tps, > + u32 status, u16 pwr_status, bool state) > +{ > + union extcon_property_value val; > + int max_current; > + > + if (TPS_STATUS_DATAROLE(status)) { > + extcon_set_state(tps->edev, EXTCON_USB, false); > + extcon_set_state(tps->edev, EXTCON_USB_HOST, state); > + } else { > + extcon_set_state(tps->edev, EXTCON_USB, state); > + extcon_set_state(tps->edev, EXTCON_USB_HOST, false); > + } > + > + val.intval = TPS_STATUS_PORTROLE(status); > + extcon_set_property(tps->edev, EXTCON_USB_HOST, > + EXTCON_PROP_USB_VBUS_SRC, > + val); > + > + extcon_set_property(tps->edev, EXTCON_USB, > + EXTCON_PROP_USB_VBUS_SRC, > + val); > + > + switch (TPS_POWER_STATUS_PWROPMODE(pwr_status)) { > + case TYPEC_PWR_MODE_USB: > + max_current = 500; > + extcon_set_state(tps->edev, EXTCON_CHG_USB_SDP, state); > + extcon_set_state(tps->edev, EXTCON_CHG_USB_SLOW, state); > + break; > + case TYPEC_PWR_MODE_1_5A: > + max_current = 1500; > + break; > + case TYPEC_PWR_MODE_3_0A: > + max_current = 3000; > + break; > + case TYPEC_PWR_MODE_PD: > + max_current = 500; > + break; > + } > + > + val.intval = max_current; > + extcon_set_property(tps->edev, EXTCON_USB, > + EXTCON_PROP_USB_VBUS_CURRENT, > + val); > + extcon_set_property(tps->edev, EXTCON_USB_HOST, > + EXTCON_PROP_USB_VBUS_CURRENT, > + val); > + > + extcon_sync(tps->edev, EXTCON_USB); > + extcon_sync(tps->edev, EXTCON_USB_HOST); > + extcon_sync(tps->edev, EXTCON_CHG_USB_SDP); > + extcon_sync(tps->edev, EXTCON_CHG_USB_SLOW); > +} > +#endif > + > static int tps6598x_connect(struct tps6598x *tps, u32 status) > { > struct typec_partner_desc desc; > @@ -248,18 +311,41 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status) > if (desc.identity) > typec_partner_set_identity(tps->partner); > > +#ifdef CONFIG_EXTCON > + tps6598x_set_extcon_state(tps, status, pwr_status, true); > +#endif > + > return 0; > } > > static void tps6598x_disconnect(struct tps6598x *tps, u32 status) > { > + enum typec_pwr_opmode mode; > + u16 pwr_status; > + int ret; > + > if (!IS_ERR(tps->partner)) > typec_unregister_partner(tps->partner); > tps->partner = NULL; > typec_set_pwr_opmode(tps->port, TYPEC_PWR_MODE_USB); > typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status)); > typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status)); > + typec_set_data_role(tps->port, TPS_STATUS_DATAROLE(status)); > tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), false); > + > + ret = tps6598x_read16(tps, TPS_REG_POWER_STATUS, &pwr_status); > + if (ret < 0) > + return; > + > + mode = TPS_POWER_STATUS_PWROPMODE(pwr_status); > + > + dev_dbg(tps->dev, "%s: mode 0x%x pwr_role %d vconn_role %d data_role %d\n", > + __func__, mode, TPS_STATUS_PORTROLE(status), > + TPS_STATUS_VCONN(status), TPS_STATUS_DATAROLE(status)); > + > +#ifdef CONFIG_EXTCON > + tps6598x_set_extcon_state(tps, status, 0, false); > +#endif > } > > static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, > @@ -407,6 +493,9 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data) > goto err_unlock; > } > > + dev_dbg(tps->dev, "Received irq event: 0x%llx: 0x%x 0x%x", event1, > + (u32)((event1 & 0xFFFFFFFF00000000) >> 32), (u32)(event1 & 0xFFFFFFFF)); > + > ret = tps6598x_read32(tps, TPS_REG_STATUS, &status); > if (ret) { > dev_err(tps->dev, "%s: failed to read status\n", __func__); > @@ -467,6 +556,18 @@ static const struct regmap_config tps6598x_regmap_config = { > .max_register = 0x7F, > }; > > +#ifdef CONFIG_EXTCON > +/* List of detectable cables */ > +static const unsigned int tps6598x_extcon_cable[] = { > + EXTCON_USB, > + EXTCON_USB_HOST, > + EXTCON_CHG_USB_SDP, > + EXTCON_CHG_USB_SLOW, > + EXTCON_CHG_USB_FAST, > + EXTCON_NONE, > +}; > +#endif > + > static int tps6598x_probe(struct i2c_client *client) > { > struct typec_capability typec_cap = { }; > @@ -567,10 +668,47 @@ static int tps6598x_probe(struct i2c_client *client) > } > fwnode_handle_put(fwnode); > > +#ifdef CONFIG_EXTCON > + /* Allocate extcon device */ > + tps->edev = devm_extcon_dev_allocate(tps->dev, tps6598x_extcon_cable); > + if (IS_ERR(tps->edev)) { > + dev_err(tps->dev, "failed to allocate memory for extcon\n"); > + typec_unregister_port(tps->port); > + return -ENOMEM; > + } > + > + /* Register extcon device */ > + ret = devm_extcon_dev_register(tps->dev, tps->edev); > + if (ret) { > + dev_err(tps->dev, "failed to register extcon device\n"); > + typec_unregister_port(tps->port); > + return ret; > + } > + > + extcon_set_property_capability(tps->edev, EXTCON_USB, > + EXTCON_PROP_USB_VBUS); > + extcon_set_property_capability(tps->edev, EXTCON_USB, > + EXTCON_PROP_USB_VBUS_SRC); > + extcon_set_property_capability(tps->edev, EXTCON_USB, > + EXTCON_PROP_USB_VBUS_VOLTAGE); > + extcon_set_property_capability(tps->edev, EXTCON_USB, > + EXTCON_PROP_USB_VBUS_CURRENT); > + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, > + EXTCON_PROP_USB_VBUS); > + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, > + EXTCON_PROP_USB_VBUS_SRC); > + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, > + EXTCON_PROP_USB_VBUS_VOLTAGE); > + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, > + EXTCON_PROP_USB_VBUS_CURRENT); > +#endif > + > if (status & TPS_STATUS_PLUG_PRESENT) { > ret = tps6598x_connect(tps, status); > if (ret) > dev_err(&client->dev, "failed to register partner\n"); > + } else { > + tps6598x_disconnect(tps, status); > } > > ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, > -- Best Regards, Chanwoo Choi Samsung Electronics
Hi, On 2020-09-14 18:19, Chanwoo Choi wrote: > Hi, > > On 9/15/20 1:46 AM, Angus Ainslie wrote: >> The tps6598x type C chip can negotiate the VBUS sink/source status as >> well as the VBUS voltage and current. Notify the extcon consumers of >> these changes. >> >> Signed-off-by: Angus Ainslie <angus@akkea.ca> >> --- >> drivers/usb/typec/tps6598x.c | 138 >> +++++++++++++++++++++++++++++++++++ >> 1 file changed, 138 insertions(+) >> >> diff --git a/drivers/usb/typec/tps6598x.c >> b/drivers/usb/typec/tps6598x.c >> index 3db33bb622c3..3b06d43c810d 100644 >> --- a/drivers/usb/typec/tps6598x.c >> +++ b/drivers/usb/typec/tps6598x.c >> @@ -8,6 +8,8 @@ >> >> #include <linux/i2c.h> >> #include <linux/acpi.h> >> +#include <linux/extcon.h> >> +#include <linux/extcon-provider.h> >> #include <linux/module.h> >> #include <linux/regmap.h> >> #include <linux/interrupt.h> >> @@ -95,7 +97,12 @@ struct tps6598x { >> struct typec_port *port; >> struct typec_partner *partner; >> struct usb_pd_identity partner_identity; >> + >> struct usb_role_switch *role_sw; >> + >> +#ifdef CONFIG_EXTCON > > Is it necessary of 'ifdef CONFIG_EXTCON'? > If you just add 'select EXTCON' for this driver, > you don't need to check CONFIG_EXTCON. > > If any device driver need some framework, > we can add the 'select EXTCON'. > Sure I can change that for v2 Angus >> + struct extcon_dev *edev; >> +#endif >> }; >> >> /* >> @@ -209,6 +216,62 @@ static void tps6598x_set_data_role(struct >> tps6598x *tps, >> typec_set_data_role(tps->port, role); >> } >> >> +#ifdef CONFIG_EXTCON >> +static void tps6589x_set_extcon_state(struct tps6598x *tps, >> + u32 status, u16 pwr_status, bool state) >> +{ >> + union extcon_property_value val; >> + int max_current; >> + >> + if (TPS_STATUS_DATAROLE(status)) { >> + extcon_set_state(tps->edev, EXTCON_USB, false); >> + extcon_set_state(tps->edev, EXTCON_USB_HOST, state); >> + } else { >> + extcon_set_state(tps->edev, EXTCON_USB, state); >> + extcon_set_state(tps->edev, EXTCON_USB_HOST, false); >> + } >> + >> + val.intval = TPS_STATUS_PORTROLE(status); >> + extcon_set_property(tps->edev, EXTCON_USB_HOST, >> + EXTCON_PROP_USB_VBUS_SRC, >> + val); >> + >> + extcon_set_property(tps->edev, EXTCON_USB, >> + EXTCON_PROP_USB_VBUS_SRC, >> + val); >> + >> + switch (TPS_POWER_STATUS_PWROPMODE(pwr_status)) { >> + case TYPEC_PWR_MODE_USB: >> + max_current = 500; >> + extcon_set_state(tps->edev, EXTCON_CHG_USB_SDP, state); >> + extcon_set_state(tps->edev, EXTCON_CHG_USB_SLOW, state); >> + break; >> + case TYPEC_PWR_MODE_1_5A: >> + max_current = 1500; >> + break; >> + case TYPEC_PWR_MODE_3_0A: >> + max_current = 3000; >> + break; >> + case TYPEC_PWR_MODE_PD: >> + max_current = 500; >> + break; >> + } >> + >> + val.intval = max_current; >> + extcon_set_property(tps->edev, EXTCON_USB, >> + EXTCON_PROP_USB_VBUS_CURRENT, >> + val); >> + extcon_set_property(tps->edev, EXTCON_USB_HOST, >> + EXTCON_PROP_USB_VBUS_CURRENT, >> + val); >> + >> + extcon_sync(tps->edev, EXTCON_USB); >> + extcon_sync(tps->edev, EXTCON_USB_HOST); >> + extcon_sync(tps->edev, EXTCON_CHG_USB_SDP); >> + extcon_sync(tps->edev, EXTCON_CHG_USB_SLOW); >> +} >> +#endif >> + >> static int tps6598x_connect(struct tps6598x *tps, u32 status) >> { >> struct typec_partner_desc desc; >> @@ -248,18 +311,41 @@ static int tps6598x_connect(struct tps6598x >> *tps, u32 status) >> if (desc.identity) >> typec_partner_set_identity(tps->partner); >> >> +#ifdef CONFIG_EXTCON >> + tps6598x_set_extcon_state(tps, status, pwr_status, true); >> +#endif >> + >> return 0; >> } >> >> static void tps6598x_disconnect(struct tps6598x *tps, u32 status) >> { >> + enum typec_pwr_opmode mode; >> + u16 pwr_status; >> + int ret; >> + >> if (!IS_ERR(tps->partner)) >> typec_unregister_partner(tps->partner); >> tps->partner = NULL; >> typec_set_pwr_opmode(tps->port, TYPEC_PWR_MODE_USB); >> typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status)); >> typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status)); >> + typec_set_data_role(tps->port, TPS_STATUS_DATAROLE(status)); >> tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), false); >> + >> + ret = tps6598x_read16(tps, TPS_REG_POWER_STATUS, &pwr_status); >> + if (ret < 0) >> + return; >> + >> + mode = TPS_POWER_STATUS_PWROPMODE(pwr_status); >> + >> + dev_dbg(tps->dev, "%s: mode 0x%x pwr_role %d vconn_role %d data_role >> %d\n", >> + __func__, mode, TPS_STATUS_PORTROLE(status), >> + TPS_STATUS_VCONN(status), TPS_STATUS_DATAROLE(status)); >> + >> +#ifdef CONFIG_EXTCON >> + tps6598x_set_extcon_state(tps, status, 0, false); >> +#endif >> } >> >> static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, >> @@ -407,6 +493,9 @@ static irqreturn_t tps6598x_interrupt(int irq, >> void *data) >> goto err_unlock; >> } >> >> + dev_dbg(tps->dev, "Received irq event: 0x%llx: 0x%x 0x%x", event1, >> + (u32)((event1 & 0xFFFFFFFF00000000) >> 32), (u32)(event1 & >> 0xFFFFFFFF)); >> + >> ret = tps6598x_read32(tps, TPS_REG_STATUS, &status); >> if (ret) { >> dev_err(tps->dev, "%s: failed to read status\n", __func__); >> @@ -467,6 +556,18 @@ static const struct regmap_config >> tps6598x_regmap_config = { >> .max_register = 0x7F, >> }; >> >> +#ifdef CONFIG_EXTCON >> +/* List of detectable cables */ >> +static const unsigned int tps6598x_extcon_cable[] = { >> + EXTCON_USB, >> + EXTCON_USB_HOST, >> + EXTCON_CHG_USB_SDP, >> + EXTCON_CHG_USB_SLOW, >> + EXTCON_CHG_USB_FAST, >> + EXTCON_NONE, >> +}; >> +#endif >> + >> static int tps6598x_probe(struct i2c_client *client) >> { >> struct typec_capability typec_cap = { }; >> @@ -567,10 +668,47 @@ static int tps6598x_probe(struct i2c_client >> *client) >> } >> fwnode_handle_put(fwnode); >> >> +#ifdef CONFIG_EXTCON >> + /* Allocate extcon device */ >> + tps->edev = devm_extcon_dev_allocate(tps->dev, >> tps6598x_extcon_cable); >> + if (IS_ERR(tps->edev)) { >> + dev_err(tps->dev, "failed to allocate memory for extcon\n"); >> + typec_unregister_port(tps->port); >> + return -ENOMEM; >> + } >> + >> + /* Register extcon device */ >> + ret = devm_extcon_dev_register(tps->dev, tps->edev); >> + if (ret) { >> + dev_err(tps->dev, "failed to register extcon device\n"); >> + typec_unregister_port(tps->port); >> + return ret; >> + } >> + >> + extcon_set_property_capability(tps->edev, EXTCON_USB, >> + EXTCON_PROP_USB_VBUS); >> + extcon_set_property_capability(tps->edev, EXTCON_USB, >> + EXTCON_PROP_USB_VBUS_SRC); >> + extcon_set_property_capability(tps->edev, EXTCON_USB, >> + EXTCON_PROP_USB_VBUS_VOLTAGE); >> + extcon_set_property_capability(tps->edev, EXTCON_USB, >> + EXTCON_PROP_USB_VBUS_CURRENT); >> + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, >> + EXTCON_PROP_USB_VBUS); >> + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, >> + EXTCON_PROP_USB_VBUS_SRC); >> + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, >> + EXTCON_PROP_USB_VBUS_VOLTAGE); >> + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, >> + EXTCON_PROP_USB_VBUS_CURRENT); >> +#endif >> + >> if (status & TPS_STATUS_PLUG_PRESENT) { >> ret = tps6598x_connect(tps, status); >> if (ret) >> dev_err(&client->dev, "failed to register partner\n"); >> + } else { >> + tps6598x_disconnect(tps, status); >> } >> >> ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, >>
diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c index 3db33bb622c3..3b06d43c810d 100644 --- a/drivers/usb/typec/tps6598x.c +++ b/drivers/usb/typec/tps6598x.c @@ -8,6 +8,8 @@ #include <linux/i2c.h> #include <linux/acpi.h> +#include <linux/extcon.h> +#include <linux/extcon-provider.h> #include <linux/module.h> #include <linux/regmap.h> #include <linux/interrupt.h> @@ -95,7 +97,12 @@ struct tps6598x { struct typec_port *port; struct typec_partner *partner; struct usb_pd_identity partner_identity; + struct usb_role_switch *role_sw; + +#ifdef CONFIG_EXTCON + struct extcon_dev *edev; +#endif }; /* @@ -209,6 +216,62 @@ static void tps6598x_set_data_role(struct tps6598x *tps, typec_set_data_role(tps->port, role); } +#ifdef CONFIG_EXTCON +static void tps6589x_set_extcon_state(struct tps6598x *tps, + u32 status, u16 pwr_status, bool state) +{ + union extcon_property_value val; + int max_current; + + if (TPS_STATUS_DATAROLE(status)) { + extcon_set_state(tps->edev, EXTCON_USB, false); + extcon_set_state(tps->edev, EXTCON_USB_HOST, state); + } else { + extcon_set_state(tps->edev, EXTCON_USB, state); + extcon_set_state(tps->edev, EXTCON_USB_HOST, false); + } + + val.intval = TPS_STATUS_PORTROLE(status); + extcon_set_property(tps->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS_SRC, + val); + + extcon_set_property(tps->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS_SRC, + val); + + switch (TPS_POWER_STATUS_PWROPMODE(pwr_status)) { + case TYPEC_PWR_MODE_USB: + max_current = 500; + extcon_set_state(tps->edev, EXTCON_CHG_USB_SDP, state); + extcon_set_state(tps->edev, EXTCON_CHG_USB_SLOW, state); + break; + case TYPEC_PWR_MODE_1_5A: + max_current = 1500; + break; + case TYPEC_PWR_MODE_3_0A: + max_current = 3000; + break; + case TYPEC_PWR_MODE_PD: + max_current = 500; + break; + } + + val.intval = max_current; + extcon_set_property(tps->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS_CURRENT, + val); + extcon_set_property(tps->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS_CURRENT, + val); + + extcon_sync(tps->edev, EXTCON_USB); + extcon_sync(tps->edev, EXTCON_USB_HOST); + extcon_sync(tps->edev, EXTCON_CHG_USB_SDP); + extcon_sync(tps->edev, EXTCON_CHG_USB_SLOW); +} +#endif + static int tps6598x_connect(struct tps6598x *tps, u32 status) { struct typec_partner_desc desc; @@ -248,18 +311,41 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status) if (desc.identity) typec_partner_set_identity(tps->partner); +#ifdef CONFIG_EXTCON + tps6598x_set_extcon_state(tps, status, pwr_status, true); +#endif + return 0; } static void tps6598x_disconnect(struct tps6598x *tps, u32 status) { + enum typec_pwr_opmode mode; + u16 pwr_status; + int ret; + if (!IS_ERR(tps->partner)) typec_unregister_partner(tps->partner); tps->partner = NULL; typec_set_pwr_opmode(tps->port, TYPEC_PWR_MODE_USB); typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status)); typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status)); + typec_set_data_role(tps->port, TPS_STATUS_DATAROLE(status)); tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), false); + + ret = tps6598x_read16(tps, TPS_REG_POWER_STATUS, &pwr_status); + if (ret < 0) + return; + + mode = TPS_POWER_STATUS_PWROPMODE(pwr_status); + + dev_dbg(tps->dev, "%s: mode 0x%x pwr_role %d vconn_role %d data_role %d\n", + __func__, mode, TPS_STATUS_PORTROLE(status), + TPS_STATUS_VCONN(status), TPS_STATUS_DATAROLE(status)); + +#ifdef CONFIG_EXTCON + tps6598x_set_extcon_state(tps, status, 0, false); +#endif } static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, @@ -407,6 +493,9 @@ static irqreturn_t tps6598x_interrupt(int irq, void *data) goto err_unlock; } + dev_dbg(tps->dev, "Received irq event: 0x%llx: 0x%x 0x%x", event1, + (u32)((event1 & 0xFFFFFFFF00000000) >> 32), (u32)(event1 & 0xFFFFFFFF)); + ret = tps6598x_read32(tps, TPS_REG_STATUS, &status); if (ret) { dev_err(tps->dev, "%s: failed to read status\n", __func__); @@ -467,6 +556,18 @@ static const struct regmap_config tps6598x_regmap_config = { .max_register = 0x7F, }; +#ifdef CONFIG_EXTCON +/* List of detectable cables */ +static const unsigned int tps6598x_extcon_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_CHG_USB_SDP, + EXTCON_CHG_USB_SLOW, + EXTCON_CHG_USB_FAST, + EXTCON_NONE, +}; +#endif + static int tps6598x_probe(struct i2c_client *client) { struct typec_capability typec_cap = { }; @@ -567,10 +668,47 @@ static int tps6598x_probe(struct i2c_client *client) } fwnode_handle_put(fwnode); +#ifdef CONFIG_EXTCON + /* Allocate extcon device */ + tps->edev = devm_extcon_dev_allocate(tps->dev, tps6598x_extcon_cable); + if (IS_ERR(tps->edev)) { + dev_err(tps->dev, "failed to allocate memory for extcon\n"); + typec_unregister_port(tps->port); + return -ENOMEM; + } + + /* Register extcon device */ + ret = devm_extcon_dev_register(tps->dev, tps->edev); + if (ret) { + dev_err(tps->dev, "failed to register extcon device\n"); + typec_unregister_port(tps->port); + return ret; + } + + extcon_set_property_capability(tps->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS); + extcon_set_property_capability(tps->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS_SRC); + extcon_set_property_capability(tps->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS_VOLTAGE); + extcon_set_property_capability(tps->edev, EXTCON_USB, + EXTCON_PROP_USB_VBUS_CURRENT); + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS); + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS_SRC); + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS_VOLTAGE); + extcon_set_property_capability(tps->edev, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS_CURRENT); +#endif + if (status & TPS_STATUS_PLUG_PRESENT) { ret = tps6598x_connect(tps, status); if (ret) dev_err(&client->dev, "failed to register partner\n"); + } else { + tps6598x_disconnect(tps, status); } ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
The tps6598x type C chip can negotiate the VBUS sink/source status as well as the VBUS voltage and current. Notify the extcon consumers of these changes. Signed-off-by: Angus Ainslie <angus@akkea.ca> --- drivers/usb/typec/tps6598x.c | 138 +++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+)