On 23. 3. 15. 23:15, Alvin Šipraga wrote: > From: Alvin Šipraga <alsi@xxxxxxxxxxxxxxx> > > The driver can register a typec port if suitable firmware properties are > present. But if the driver is removed through sysfs unbind, rmmod or > similar, then it does not clean up after itself and the typec port > device remains registered. This can be seen in sysfs, where stale typec > ports get left over in /sys/class/typec. > > In order to fix this we have to add an i2c_driver remove function and > call typec_unregister_port(), which is a no-op in the case where no > typec port is created and the pointer remains NULL. > > In the process we should also put the fwnode_handle when the typec port > isn't registered anymore, including if an error occurs during probe. The > typec subsystem does not increase or decrease the reference counter for > us, so we track it in the driver's private data. > > Note that the conditional check on TYPEC_PWR_MODE_PD was removed in the > probe path because a call to tusb320_set_adv_pwr_mode() will perform an > even more robust validation immediately after, hence there is no > functional change here. > > Fixes: bf7571c00dca ("extcon: usbc-tusb320: Add USB TYPE-C support") > Cc: stable@xxxxxxxxxxxxxxx > Signed-off-by: Alvin Šipraga <alsi@xxxxxxxxxxxxxxx> > --- > v2: properly assign priv->connector_fwnode = connector; > --- > drivers/extcon/extcon-usbc-tusb320.c | 42 ++++++++++++++++++++++------ > 1 file changed, 34 insertions(+), 8 deletions(-) > > diff --git a/drivers/extcon/extcon-usbc-tusb320.c b/drivers/extcon/extcon-usbc-tusb320.c > index b408ce989c22..10dff1c512c4 100644 > --- a/drivers/extcon/extcon-usbc-tusb320.c > +++ b/drivers/extcon/extcon-usbc-tusb320.c > @@ -78,6 +78,7 @@ struct tusb320_priv { > struct typec_capability cap; > enum typec_port_type port_type; > enum typec_pwr_opmode pwr_opmode; > + struct fwnode_handle *connector_fwnode; > }; > > static const char * const tusb_attached_states[] = { > @@ -391,27 +392,25 @@ static int tusb320_typec_probe(struct i2c_client *client, > /* Type-C connector found. */ > ret = typec_get_fw_cap(&priv->cap, connector); > if (ret) > - return ret; > + goto err_put; > > priv->port_type = priv->cap.type; > > /* This goes into register 0x8 field CURRENT_MODE_ADVERTISE */ > ret = fwnode_property_read_string(connector, "typec-power-opmode", &cap_str); > if (ret) > - return ret; > + goto err_put; > > ret = typec_find_pwr_opmode(cap_str); > if (ret < 0) > - return ret; > - if (ret == TYPEC_PWR_MODE_PD) > - return -EINVAL; > + goto err_put; > > priv->pwr_opmode = ret; > > /* Initialize the hardware with the devicetree settings. */ > ret = tusb320_set_adv_pwr_mode(priv); > if (ret) > - return ret; > + goto err_put; > > priv->cap.revision = USB_TYPEC_REV_1_1; > priv->cap.accessory[0] = TYPEC_ACCESSORY_AUDIO; > @@ -422,10 +421,25 @@ static int tusb320_typec_probe(struct i2c_client *client, > priv->cap.fwnode = connector; > > priv->port = typec_register_port(&client->dev, &priv->cap); > - if (IS_ERR(priv->port)) > - return PTR_ERR(priv->port); > + if (IS_ERR(priv->port)) { > + ret = PTR_ERR(priv->port); > + goto err_put; > + } > + > + priv->connector_fwnode = connector; > > return 0; > + > +err_put: > + fwnode_handle_put(connector); > + > + return ret; > +} > + > +static void tusb320_typec_remove(struct tusb320_priv *priv) > +{ > + typec_unregister_port(priv->port); > + fwnode_handle_put(priv->connector_fwnode); > } > > static int tusb320_probe(struct i2c_client *client) > @@ -438,7 +452,9 @@ static int tusb320_probe(struct i2c_client *client) > priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); > if (!priv) > return -ENOMEM; > + > priv->dev = &client->dev; > + i2c_set_clientdata(client, priv); > > priv->regmap = devm_regmap_init_i2c(client, &tusb320_regmap_config); > if (IS_ERR(priv->regmap)) > @@ -489,10 +505,19 @@ static int tusb320_probe(struct i2c_client *client) > tusb320_irq_handler, > IRQF_TRIGGER_FALLING | IRQF_ONESHOT, > client->name, priv); > + if (ret) > + tusb320_typec_remove(priv); > > return ret; > } > > +static void tusb320_remove(struct i2c_client *client) > +{ > + struct tusb320_priv *priv = i2c_get_clientdata(client); > + > + tusb320_typec_remove(priv); > +} > + > static const struct of_device_id tusb320_extcon_dt_match[] = { > { .compatible = "ti,tusb320", .data = &tusb320_ops, }, > { .compatible = "ti,tusb320l", .data = &tusb320l_ops, }, > @@ -502,6 +527,7 @@ MODULE_DEVICE_TABLE(of, tusb320_extcon_dt_match); > > static struct i2c_driver tusb320_extcon_driver = { > .probe_new = tusb320_probe, > + .remove = tusb320_remove, > .driver = { > .name = "extcon-tusb320", > .of_match_table = tusb320_extcon_dt_match, Applied it. Thanks. -- Best Regards, Samsung Electronics Chanwoo Choi