From 3adbaa30d973093a4f37927baf9596cca51b593d Mon Sep 17 00:00:00 2001 From: Alvin Šipraga Date: Wed, 15 Mar 2023 15:15:47 +0100 Subject: extcon: usbc-tusb320: Unregister typec port on driver removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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@vger.kernel.org Signed-off-by: Alvin Šipraga Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-usbc-tusb320.c | 42 +++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'drivers/extcon') 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, -- cgit v1.2.3 From 07c8eb325f29a4a967f939b9fe6cce09f35e25e9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 2 Jan 2023 22:29:19 +0200 Subject: extcon: axp288: Replace open coded acpi_dev_put() Instead of calling put_device(&adev->dev) where adev is a pointer to an ACPI device, use specific call, i.e. acpi_dev_put(). Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-axp288.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-axp288.c b/drivers/extcon/extcon-axp288.c index 180be768c215..a703a8315634 100644 --- a/drivers/extcon/extcon-axp288.c +++ b/drivers/extcon/extcon-axp288.c @@ -393,7 +393,7 @@ static int axp288_extcon_probe(struct platform_device *pdev) adev = acpi_dev_get_first_match_dev("INT3496", NULL, -1); if (adev) { info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev)); - put_device(&adev->dev); + acpi_dev_put(adev); if (IS_ERR(info->id_extcon)) return PTR_ERR(info->id_extcon); -- cgit v1.2.3 From fe551bc9dcc6a557831dfe1544c1653ab24347a6 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 28 Dec 2022 13:30:58 +0000 Subject: extcon: qcom-spmi: Switch to platform_get_irq_byname_optional Valid configurations for the extcon interrupt declarations are - usb_id - usb_vbus - (usb_id | usb_vbus) In the case of a standalone usb_id or usb_vbus failure to find one of the interrupts shouldn't generate a warning message. A warning is already in place if both IRQs are missing. Switch to using platform_get_irq_byname_optional() in order to facilitate this behaviour. Suggested-by: Marijn Suijten Signed-off-by: Bryan O'Donoghue Reviewed-by: Marijn Suijten Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-qcom-spmi-misc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c index eb02cb962b5e..f72e90ceca53 100644 --- a/drivers/extcon/extcon-qcom-spmi-misc.c +++ b/drivers/extcon/extcon-qcom-spmi-misc.c @@ -123,7 +123,7 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev) if (ret) return ret; - info->id_irq = platform_get_irq_byname(pdev, "usb_id"); + info->id_irq = platform_get_irq_byname_optional(pdev, "usb_id"); if (info->id_irq > 0) { ret = devm_request_threaded_irq(dev, info->id_irq, NULL, qcom_usb_irq_handler, @@ -136,7 +136,7 @@ static int qcom_usb_extcon_probe(struct platform_device *pdev) } } - info->vbus_irq = platform_get_irq_byname(pdev, "usb_vbus"); + info->vbus_irq = platform_get_irq_byname_optional(pdev, "usb_vbus"); if (info->vbus_irq > 0) { ret = devm_request_threaded_irq(dev, info->vbus_irq, NULL, qcom_usb_irq_handler, -- cgit v1.2.3 From c95fb88fb6e4bd92720a183014d9160e627e4c4b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 13 Mar 2023 19:41:48 +0900 Subject: extcon: palmas: Remove unused of_gpio.h of_gpio.h provides a single function, which is not used in this driver. Remove unused header. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-palmas.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index 32f8b541770b..d339b8680445 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 7f4c9bc29ba72c5e3d0f9eaa91cabac9cd3342c9 Mon Sep 17 00:00:00 2001 From: Bumwoo Lee Date: Thu, 2 Mar 2023 18:01:40 +0900 Subject: extcon: Remove redundant null checking for class create_extcon_class() is already Null checking. Signed-off-by: Bumwoo Lee Acked-by: MyungJoo Ham --- drivers/extcon/extcon.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index d43ba8e7260d..2fa033711a55 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1012,12 +1012,13 @@ ATTRIBUTE_GROUPS(extcon); static int create_extcon_class(void) { - if (!extcon_class) { - extcon_class = class_create("extcon"); - if (IS_ERR(extcon_class)) - return PTR_ERR(extcon_class); - extcon_class->dev_groups = extcon_groups; - } + if (extcon_class) + return 0; + + extcon_class = class_create("extcon"); + if (IS_ERR(extcon_class)) + return PTR_ERR(extcon_class); + extcon_class->dev_groups = extcon_groups; return 0; } @@ -1088,11 +1089,9 @@ int extcon_dev_register(struct extcon_dev *edev) int ret, index = 0; static atomic_t edev_no = ATOMIC_INIT(-1); - if (!extcon_class) { - ret = create_extcon_class(); - if (ret < 0) - return ret; - } + ret = create_extcon_class(); + if (ret < 0) + return ret; if (!edev || !edev->supported_cable) return -EINVAL; -- cgit v1.2.3 From 3d9138e5bdcf9f0277904441cbf4cb1407ed8603 Mon Sep 17 00:00:00 2001 From: Bumwoo Lee Date: Mon, 20 Mar 2023 12:19:37 +0900 Subject: extcon: Add extcon_alloc_cables to simplify extcon register function The cable allocation part is functionalized from extcon_dev_register. Signed-off-by: Bumwoo Lee Acked-by: MyungJoo Ham --- drivers/extcon/extcon.c | 111 ++++++++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 46 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 2fa033711a55..72591af2fec2 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1070,6 +1070,66 @@ void extcon_dev_free(struct extcon_dev *edev) } EXPORT_SYMBOL_GPL(extcon_dev_free); +/** + * extcon_alloc_cables() - alloc the cables for extcon device + * @edev: extcon device which has cables + * + * Returns 0 if success or error number if fail. + */ +static int extcon_alloc_cables(struct extcon_dev *edev) +{ + int index; + char *str; + struct extcon_cable *cable; + + if (!edev) + return -EINVAL; + + if (!edev->max_supported) + return 0; + + edev->cables = kcalloc(edev->max_supported, + sizeof(struct extcon_cable), + GFP_KERNEL); + if (!edev->cables) + return -ENOMEM; + + for (index = 0; index < edev->max_supported; index++) { + cable = &edev->cables[index]; + + str = kasprintf(GFP_KERNEL, "cable.%d", index); + if (!str) { + for (index--; index >= 0; index--) { + cable = &edev->cables[index]; + kfree(cable->attr_g.name); + } + + kfree(edev->cables); + return -ENOMEM; + } + + cable->edev = edev; + cable->cable_index = index; + cable->attrs[0] = &cable->attr_name.attr; + cable->attrs[1] = &cable->attr_state.attr; + cable->attrs[2] = NULL; + cable->attr_g.name = str; + cable->attr_g.attrs = cable->attrs; + + sysfs_attr_init(&cable->attr_name.attr); + cable->attr_name.attr.name = "name"; + cable->attr_name.attr.mode = 0444; + cable->attr_name.show = cable_name_show; + + sysfs_attr_init(&cable->attr_state.attr); + cable->attr_state.attr.name = "state"; + cable->attr_state.attr.mode = 0444; + cable->attr_state.show = cable_state_show; + } + + return 0; +} + /** * extcon_dev_register() - Register an new extcon device * @edev: the extcon device to be registered @@ -1117,50 +1177,9 @@ int extcon_dev_register(struct extcon_dev *edev) dev_set_name(&edev->dev, "extcon%lu", (unsigned long)atomic_inc_return(&edev_no)); - if (edev->max_supported) { - char *str; - struct extcon_cable *cable; - - edev->cables = kcalloc(edev->max_supported, - sizeof(struct extcon_cable), - GFP_KERNEL); - if (!edev->cables) { - ret = -ENOMEM; - goto err_sysfs_alloc; - } - for (index = 0; index < edev->max_supported; index++) { - cable = &edev->cables[index]; - - str = kasprintf(GFP_KERNEL, "cable.%d", index); - if (!str) { - for (index--; index >= 0; index--) { - cable = &edev->cables[index]; - kfree(cable->attr_g.name); - } - ret = -ENOMEM; - - goto err_alloc_cables; - } - - cable->edev = edev; - cable->cable_index = index; - cable->attrs[0] = &cable->attr_name.attr; - cable->attrs[1] = &cable->attr_state.attr; - cable->attrs[2] = NULL; - cable->attr_g.name = str; - cable->attr_g.attrs = cable->attrs; - - sysfs_attr_init(&cable->attr_name.attr); - cable->attr_name.attr.name = "name"; - cable->attr_name.attr.mode = 0444; - cable->attr_name.show = cable_name_show; - - sysfs_attr_init(&cable->attr_state.attr); - cable->attr_state.attr.name = "state"; - cable->attr_state.attr.mode = 0444; - cable->attr_state.show = cable_state_show; - } - } + ret = extcon_alloc_cables(edev); + if (ret < 0) + goto err_alloc_cables; if (edev->max_supported && edev->mutually_exclusive) { char *name; @@ -1279,10 +1298,10 @@ err_alloc_groups: err_muex: for (index = 0; index < edev->max_supported; index++) kfree(edev->cables[index].attr_g.name); -err_alloc_cables: if (edev->max_supported) kfree(edev->cables); -err_sysfs_alloc: +err_alloc_cables: + return ret; } EXPORT_SYMBOL_GPL(extcon_dev_register); -- cgit v1.2.3 From 3e70a014abcdf7e795ee7f446dde4160dfe354a4 Mon Sep 17 00:00:00 2001 From: Bumwoo Lee Date: Mon, 20 Mar 2023 12:19:38 +0900 Subject: extcon: Add extcon_alloc_muex to simplify extcon register function The mutual exclusive part is functionalized from extcon_dev_register. Signed-off-by: Bumwoo Lee Acked-by: MyungJoo Ham --- drivers/extcon/extcon.c | 109 +++++++++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 48 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 72591af2fec2..3188b0e8c6d9 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1130,6 +1130,63 @@ static int extcon_alloc_cables(struct extcon_dev *edev) return 0; } +/** + * extcon_alloc_muex() - alloc the mutual exclusive for extcon device + * @edev: extcon device + * + * Returns 0 if success or error number if fail. + */ +static int extcon_alloc_muex(struct extcon_dev *edev) +{ + char *name; + int index; + + if (!edev) + return -EINVAL; + + if (!(edev->max_supported && edev->mutually_exclusive)) + return 0; + + /* Count the size of mutually_exclusive array */ + for (index = 0; edev->mutually_exclusive[index]; index++) + ; + + edev->attrs_muex = kcalloc(index + 1, + sizeof(struct attribute *), + GFP_KERNEL); + if (!edev->attrs_muex) + return -ENOMEM; + + edev->d_attrs_muex = kcalloc(index, + sizeof(struct device_attribute), + GFP_KERNEL); + if (!edev->d_attrs_muex) { + kfree(edev->attrs_muex); + return -ENOMEM; + } + + for (index = 0; edev->mutually_exclusive[index]; index++) { + name = kasprintf(GFP_KERNEL, "0x%x", + edev->mutually_exclusive[index]); + if (!name) { + for (index--; index >= 0; index--) + kfree(edev->d_attrs_muex[index].attr.name); + + kfree(edev->d_attrs_muex); + kfree(edev->attrs_muex); + return -ENOMEM; + } + sysfs_attr_init(&edev->d_attrs_muex[index].attr); + edev->d_attrs_muex[index].attr.name = name; + edev->d_attrs_muex[index].attr.mode = 0000; + edev->attrs_muex[index] = &edev->d_attrs_muex[index].attr; + } + edev->attr_g_muex.name = muex_name; + edev->attr_g_muex.attrs = edev->attrs_muex; + + return 0; +} + /** * extcon_dev_register() - Register an new extcon device * @edev: the extcon device to be registered @@ -1181,53 +1238,9 @@ int extcon_dev_register(struct extcon_dev *edev) if (ret < 0) goto err_alloc_cables; - if (edev->max_supported && edev->mutually_exclusive) { - char *name; - - /* Count the size of mutually_exclusive array */ - for (index = 0; edev->mutually_exclusive[index]; index++) - ; - - edev->attrs_muex = kcalloc(index + 1, - sizeof(struct attribute *), - GFP_KERNEL); - if (!edev->attrs_muex) { - ret = -ENOMEM; - goto err_muex; - } - - edev->d_attrs_muex = kcalloc(index, - sizeof(struct device_attribute), - GFP_KERNEL); - if (!edev->d_attrs_muex) { - ret = -ENOMEM; - kfree(edev->attrs_muex); - goto err_muex; - } - - for (index = 0; edev->mutually_exclusive[index]; index++) { - name = kasprintf(GFP_KERNEL, "0x%x", - edev->mutually_exclusive[index]); - if (!name) { - for (index--; index >= 0; index--) { - kfree(edev->d_attrs_muex[index].attr. - name); - } - kfree(edev->d_attrs_muex); - kfree(edev->attrs_muex); - ret = -ENOMEM; - goto err_muex; - } - sysfs_attr_init(&edev->d_attrs_muex[index].attr); - edev->d_attrs_muex[index].attr.name = name; - edev->d_attrs_muex[index].attr.mode = 0000; - edev->attrs_muex[index] = &edev->d_attrs_muex[index] - .attr; - } - edev->attr_g_muex.name = muex_name; - edev->attr_g_muex.attrs = edev->attrs_muex; - - } + ret = extcon_alloc_muex(edev); + if (ret < 0) + goto err_alloc_muex; if (edev->max_supported) { edev->extcon_dev_type.groups = @@ -1295,7 +1308,7 @@ err_alloc_groups: kfree(edev->d_attrs_muex); kfree(edev->attrs_muex); } -err_muex: +err_alloc_muex: for (index = 0; index < edev->max_supported; index++) kfree(edev->cables[index].attr_g.name); if (edev->max_supported) -- cgit v1.2.3 From 04151575c507e7ea3aa6dee73ff9970d699641d3 Mon Sep 17 00:00:00 2001 From: Bumwoo Lee Date: Mon, 20 Mar 2023 12:19:39 +0900 Subject: extcon: Add extcon_alloc_groups to simplify extcon register function The alloc groups is functionalized from extcon_dev_register. Signed-off-by: Bumwoo Lee Acked-by: MyungJoo Ham --- drivers/extcon/extcon.c | 61 +++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 22 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 3188b0e8c6d9..3997b39680b7 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1187,6 +1187,42 @@ static int extcon_alloc_muex(struct extcon_dev *edev) return 0; } +/** + * extcon_alloc_groups() - alloc the groups for extcon device + * @edev: extcon device + * + * Returns 0 if success or error number if fail. + */ +static int extcon_alloc_groups(struct extcon_dev *edev) +{ + int index; + + if (!edev) + return -EINVAL; + + if (!edev->max_supported) + return 0; + + edev->extcon_dev_type.groups = kcalloc(edev->max_supported + 2, + sizeof(struct attribute_group *), + GFP_KERNEL); + if (!edev->extcon_dev_type.groups) + return -ENOMEM; + + edev->extcon_dev_type.name = dev_name(&edev->dev); + edev->extcon_dev_type.release = dummy_sysfs_dev_release; + + for (index = 0; index < edev->max_supported; index++) + edev->extcon_dev_type.groups[index] = &edev->cables[index].attr_g; + + if (edev->mutually_exclusive) + edev->extcon_dev_type.groups[index] = &edev->attr_g_muex; + + edev->dev.type = &edev->extcon_dev_type; + + return 0; +} + /** * extcon_dev_register() - Register an new extcon device * @edev: the extcon device to be registered @@ -1242,28 +1278,9 @@ int extcon_dev_register(struct extcon_dev *edev) if (ret < 0) goto err_alloc_muex; - if (edev->max_supported) { - edev->extcon_dev_type.groups = - kcalloc(edev->max_supported + 2, - sizeof(struct attribute_group *), - GFP_KERNEL); - if (!edev->extcon_dev_type.groups) { - ret = -ENOMEM; - goto err_alloc_groups; - } - - edev->extcon_dev_type.name = dev_name(&edev->dev); - edev->extcon_dev_type.release = dummy_sysfs_dev_release; - - for (index = 0; index < edev->max_supported; index++) - edev->extcon_dev_type.groups[index] = - &edev->cables[index].attr_g; - if (edev->mutually_exclusive) - edev->extcon_dev_type.groups[index] = - &edev->attr_g_muex; - - edev->dev.type = &edev->extcon_dev_type; - } + ret = extcon_alloc_groups(edev); + if (ret < 0) + goto err_alloc_groups; spin_lock_init(&edev->lock); if (edev->max_supported) { -- cgit v1.2.3 From 18eb81d804c41c98b7e831560ebb933375496529 Mon Sep 17 00:00:00 2001 From: Alvin Šipraga Date: Sat, 18 Mar 2023 16:05:53 +0100 Subject: extcon: usbc-tusb320: add accessory detection support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TUSB320 can detect the following types of accessory: - Audio Accessory - Audio Accessory with charge-thru - Debug Accessory (DFP) - Debug Accessory (UFP) Moreover, the typec subsystem can be informed of this through the typec_set_mode() function. The information will be propagated to any linked typec muxes. Add the necessary support to the driver. Note that for the Debug Accessory modes, an educated guess was made that for the USB data role, DFP implies HOST and UFP implies DEVICE. But this might want to be made configurable at a later date. Signed-off-by: Alvin Šipraga Acked-by: Heikki Krogerus Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-usbc-tusb320.c | 90 +++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 22 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-usbc-tusb320.c b/drivers/extcon/extcon-usbc-tusb320.c index 10dff1c512c4..882d1f48495e 100644 --- a/drivers/extcon/extcon-usbc-tusb320.c +++ b/drivers/extcon/extcon-usbc-tusb320.c @@ -15,6 +15,7 @@ #include #include #include +#include #define TUSB320_REG8 0x8 #define TUSB320_REG8_CURRENT_MODE_ADVERTISE GENMASK(7, 6) @@ -26,16 +27,16 @@ #define TUSB320_REG8_CURRENT_MODE_DETECT_MED 0x1 #define TUSB320_REG8_CURRENT_MODE_DETECT_ACC 0x2 #define TUSB320_REG8_CURRENT_MODE_DETECT_HI 0x3 -#define TUSB320_REG8_ACCESSORY_CONNECTED GENMASK(3, 2) +#define TUSB320_REG8_ACCESSORY_CONNECTED GENMASK(3, 1) #define TUSB320_REG8_ACCESSORY_CONNECTED_NONE 0x0 #define TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO 0x4 -#define TUSB320_REG8_ACCESSORY_CONNECTED_ACC 0x5 -#define TUSB320_REG8_ACCESSORY_CONNECTED_DEBUG 0x6 +#define TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG 0x5 +#define TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP 0x6 +#define TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP 0x7 #define TUSB320_REG8_ACTIVE_CABLE_DETECTION BIT(0) #define TUSB320_REG9 0x9 -#define TUSB320_REG9_ATTACHED_STATE_SHIFT 6 -#define TUSB320_REG9_ATTACHED_STATE_MASK 0x3 +#define TUSB320_REG9_ATTACHED_STATE GENMASK(7, 6) #define TUSB320_REG9_CABLE_DIRECTION BIT(5) #define TUSB320_REG9_INTERRUPT_STATUS BIT(4) @@ -250,8 +251,7 @@ static void tusb320_extcon_irq_handler(struct tusb320_priv *priv, u8 reg) { int state, polarity; - state = (reg >> TUSB320_REG9_ATTACHED_STATE_SHIFT) & - TUSB320_REG9_ATTACHED_STATE_MASK; + state = FIELD_GET(TUSB320_REG9_ATTACHED_STATE, reg); polarity = !!(reg & TUSB320_REG9_CABLE_DIRECTION); dev_dbg(priv->dev, "attached state: %s, polarity: %d\n", @@ -277,32 +277,78 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9) { struct typec_port *port = priv->port; struct device *dev = priv->dev; - u8 mode, role, state; + int typec_mode; + enum typec_role pwr_role; + enum typec_data_role data_role; + u8 state, mode, accessory; int ret, reg8; bool ori; + ret = regmap_read(priv->regmap, TUSB320_REG8, ®8); + if (ret) { + dev_err(dev, "error during reg8 i2c read, ret=%d!\n", ret); + return; + } + ori = reg9 & TUSB320_REG9_CABLE_DIRECTION; typec_set_orientation(port, ori ? TYPEC_ORIENTATION_REVERSE : TYPEC_ORIENTATION_NORMAL); - state = (reg9 >> TUSB320_REG9_ATTACHED_STATE_SHIFT) & - TUSB320_REG9_ATTACHED_STATE_MASK; - if (state == TUSB320_ATTACHED_STATE_DFP) - role = TYPEC_SOURCE; - else - role = TYPEC_SINK; + state = FIELD_GET(TUSB320_REG9_ATTACHED_STATE, reg9); + accessory = FIELD_GET(TUSB320_REG8_ACCESSORY_CONNECTED, reg8); + + switch (state) { + case TUSB320_ATTACHED_STATE_DFP: + typec_mode = TYPEC_MODE_USB2; + pwr_role = TYPEC_SOURCE; + data_role = TYPEC_HOST; + break; + case TUSB320_ATTACHED_STATE_UFP: + typec_mode = TYPEC_MODE_USB2; + pwr_role = TYPEC_SINK; + data_role = TYPEC_DEVICE; + break; + case TUSB320_ATTACHED_STATE_ACC: + /* + * Accessory detected. For debug accessories, just make some + * qualified guesses as to the role for lack of a better option. + */ + if (accessory == TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO || + accessory == TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG) { + typec_mode = TYPEC_MODE_AUDIO; + pwr_role = TYPEC_SINK; + data_role = TYPEC_DEVICE; + break; + } else if (accessory == + TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP) { + typec_mode = TYPEC_MODE_DEBUG; + pwr_role = TYPEC_SOURCE; + data_role = TYPEC_HOST; + break; + } else if (accessory == + TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP) { + typec_mode = TYPEC_MODE_DEBUG; + pwr_role = TYPEC_SINK; + data_role = TYPEC_DEVICE; + break; + } - typec_set_vconn_role(port, role); - typec_set_pwr_role(port, role); - typec_set_data_role(port, role == TYPEC_SOURCE ? - TYPEC_HOST : TYPEC_DEVICE); + dev_warn(priv->dev, "unexpected ACCESSORY_CONNECTED state %d\n", + accessory); - ret = regmap_read(priv->regmap, TUSB320_REG8, ®8); - if (ret) { - dev_err(dev, "error during reg8 i2c read, ret=%d!\n", ret); - return; + fallthrough; + default: + typec_mode = TYPEC_MODE_USB2; + pwr_role = TYPEC_SINK; + data_role = TYPEC_DEVICE; + break; } + typec_set_vconn_role(port, pwr_role); + typec_set_pwr_role(port, pwr_role); + typec_set_data_role(port, data_role); + typec_set_mode(port, typec_mode); + mode = FIELD_GET(TUSB320_REG8_CURRENT_MODE_DETECT, reg8); if (mode == TUSB320_REG8_CURRENT_MODE_DETECT_DEF) typec_set_pwr_opmode(port, TYPEC_PWR_MODE_USB); -- cgit v1.2.3 From df101446a402bb1bc164f3445d2f028a1dbec6ac Mon Sep 17 00:00:00 2001 From: Alvin Šipraga Date: Sat, 18 Mar 2023 16:05:54 +0100 Subject: extcon: usbc-tusb320: add usb_role_switch support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The connector child node of the TUSB320 device might be linked with a dual-role capable USB controller. Add driver support for detecting a usb_role_switch and setting its state in the typec interrupt handler. This follows similar practice in other drivers in the typec subsystem, which this extcon driver can opt-in to. Signed-off-by: Alvin Šipraga Acked-by: Heikki Krogerus Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-usbc-tusb320.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-usbc-tusb320.c b/drivers/extcon/extcon-usbc-tusb320.c index 882d1f48495e..cc2d0ac7c5f6 100644 --- a/drivers/extcon/extcon-usbc-tusb320.c +++ b/drivers/extcon/extcon-usbc-tusb320.c @@ -16,6 +16,7 @@ #include #include #include +#include #define TUSB320_REG8 0x8 #define TUSB320_REG8_CURRENT_MODE_ADVERTISE GENMASK(7, 6) @@ -80,6 +81,7 @@ struct tusb320_priv { enum typec_port_type port_type; enum typec_pwr_opmode pwr_opmode; struct fwnode_handle *connector_fwnode; + struct usb_role_switch *role_sw; }; static const char * const tusb_attached_states[] = { @@ -278,6 +280,7 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9) struct typec_port *port = priv->port; struct device *dev = priv->dev; int typec_mode; + enum usb_role usb_role; enum typec_role pwr_role; enum typec_data_role data_role; u8 state, mode, accessory; @@ -300,11 +303,13 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9) switch (state) { case TUSB320_ATTACHED_STATE_DFP: typec_mode = TYPEC_MODE_USB2; + usb_role = USB_ROLE_HOST; pwr_role = TYPEC_SOURCE; data_role = TYPEC_HOST; break; case TUSB320_ATTACHED_STATE_UFP: typec_mode = TYPEC_MODE_USB2; + usb_role = USB_ROLE_DEVICE; pwr_role = TYPEC_SINK; data_role = TYPEC_DEVICE; break; @@ -316,6 +321,7 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9) if (accessory == TUSB320_REG8_ACCESSORY_CONNECTED_AUDIO || accessory == TUSB320_REG8_ACCESSORY_CONNECTED_ACHRG) { typec_mode = TYPEC_MODE_AUDIO; + usb_role = USB_ROLE_NONE; pwr_role = TYPEC_SINK; data_role = TYPEC_DEVICE; break; @@ -323,12 +329,14 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9) TUSB320_REG8_ACCESSORY_CONNECTED_DBGDFP) { typec_mode = TYPEC_MODE_DEBUG; pwr_role = TYPEC_SOURCE; + usb_role = USB_ROLE_HOST; data_role = TYPEC_HOST; break; } else if (accessory == TUSB320_REG8_ACCESSORY_CONNECTED_DBGUFP) { typec_mode = TYPEC_MODE_DEBUG; pwr_role = TYPEC_SINK; + usb_role = USB_ROLE_DEVICE; data_role = TYPEC_DEVICE; break; } @@ -339,6 +347,7 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9) fallthrough; default: typec_mode = TYPEC_MODE_USB2; + usb_role = USB_ROLE_NONE; pwr_role = TYPEC_SINK; data_role = TYPEC_DEVICE; break; @@ -348,6 +357,7 @@ static void tusb320_typec_irq_handler(struct tusb320_priv *priv, u8 reg9) typec_set_pwr_role(port, pwr_role); typec_set_data_role(port, data_role); typec_set_mode(port, typec_mode); + usb_role_switch_set_role(priv->role_sw, usb_role); mode = FIELD_GET(TUSB320_REG8_CURRENT_MODE_DETECT, reg8); if (mode == TUSB320_REG8_CURRENT_MODE_DETECT_DEF) @@ -472,10 +482,20 @@ static int tusb320_typec_probe(struct i2c_client *client, goto err_put; } + /* Find any optional USB role switch that needs reporting to */ + priv->role_sw = fwnode_usb_role_switch_get(connector); + if (IS_ERR(priv->role_sw)) { + ret = PTR_ERR(priv->role_sw); + goto err_unreg; + } + priv->connector_fwnode = connector; return 0; +err_unreg: + typec_unregister_port(priv->port); + err_put: fwnode_handle_put(connector); @@ -484,6 +504,7 @@ err_put: static void tusb320_typec_remove(struct tusb320_priv *priv) { + usb_role_switch_put(priv->role_sw); typec_unregister_port(priv->port); fwnode_handle_put(priv->connector_fwnode); } -- cgit v1.2.3 From 65acf9c6539b1bf082bc593a9517ef718335d8aa Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 22 Mar 2023 12:16:51 +0100 Subject: extcon: usbc-tusb320: add USB_ROLE_SWITCH dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_USB_ROLE_SWITCH=m, tusb320 cannot be built-in: ld.lld: error: undefined symbol: fwnode_usb_role_switch_get >>> referenced by extcon-usbc-tusb320.c >>> drivers/extcon/extcon-usbc-tusb320.o:(tusb320_probe) in archive vmlinux.a ld.lld: error: undefined symbol: usb_role_switch_set_role >>> referenced by extcon-usbc-tusb320.c >>> drivers/extcon/extcon-usbc-tusb320.o:(tusb320_state_update_handler) in archive vmlinux.a Add the appropriate Kconfig dependency to prevent this configuration but still allow the driver to be built-in when USB_ROLE_SWITCH is disabled. Fixes: df101446a402 ("extcon: usbc-tusb320: add usb_role_switch support") Signed-off-by: Arnd Bergmann Reviewed-by: Alvin Šipraga Signed-off-by: Chanwoo Choi --- drivers/extcon/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/extcon') diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 290186e44e6b..0ef1971d22bb 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -185,6 +185,7 @@ config EXTCON_USBC_TUSB320 tristate "TI TUSB320 USB-C extcon support" depends on I2C && TYPEC select REGMAP_I2C + depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH help Say Y here to enable support for USB Type C cable detection extcon support using a TUSB320. -- cgit v1.2.3 From 7e77e0b7a9f4cdf91cb0950749b40c840ea63efc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Mar 2023 16:39:52 +0200 Subject: extcon: Fix kernel doc of property fields to avoid warnings Kernel documentation has to be synchronized with a code, otherwise the validator is not happy: Function parameter or member 'usb_propval' not described in 'extcon_cable' Function parameter or member 'chg_propval' not described in 'extcon_cable' Function parameter or member 'jack_propval' not described in 'extcon_cable' Function parameter or member 'disp_propval' not described in 'extcon_cable' Describe the fields added in the past. Fixes: 067c1652e7a7 ("extcon: Add the support for extcon property according to extcon type") Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 3997b39680b7..1bc2639704c2 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -206,6 +206,10 @@ static const struct __extcon_info { * @attr_name: "name" sysfs entry * @attr_state: "state" sysfs entry * @attrs: the array pointing to attr_name and attr_state for attr_g + * @usb_propval: the array of USB connector properties + * @chg_propval: the array of charger connector properties + * @jack_propval: the array of jack connector properties + * @disp_propval: the array of display connector properties */ struct extcon_cable { struct extcon_dev *edev; -- cgit v1.2.3 From 73346b9965ebda2feb7fef8629e9b28baee820e3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Mar 2023 16:39:53 +0200 Subject: extcon: Fix kernel doc of property capability fields to avoid warnings Kernel documentation has to be synchronized with a code, otherwise the validator is not happy: Function parameter or member 'usb_bits' not described in 'extcon_cable' Function parameter or member 'chg_bits' not described in 'extcon_cable' Function parameter or member 'jack_bits' not described in 'extcon_cable' Function parameter or member 'disp_bits' not described in 'extcon_cable' Describe the fields added in the past. Fixes: ceaa98f442cf ("extcon: Add the support for the capability of each property") Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 1bc2639704c2..79006ab5334b 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -210,6 +210,10 @@ static const struct __extcon_info { * @chg_propval: the array of charger connector properties * @jack_propval: the array of jack connector properties * @disp_propval: the array of display connector properties + * @usb_bits: the bit array of the USB connector property capabilities + * @chg_bits: the bit array of the charger connector property capabilities + * @jack_bits: the bit array of the jack connector property capabilities + * @disp_bits: the bit array of the display connector property capabilities */ struct extcon_cable { struct extcon_dev *edev; -- cgit v1.2.3 From 6e4e8670c03b4fcac54bca8b62e5465182caeb26 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Mar 2023 16:39:54 +0200 Subject: extcon: Use DECLARE_BITMAP() to declare bit arrays Bit arrays has a specific type helper for the declaration. Use it instead of homegronw equivalent. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 79006ab5334b..70e9755ba2bc 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -230,10 +230,10 @@ struct extcon_cable { union extcon_property_value jack_propval[EXTCON_PROP_JACK_CNT]; union extcon_property_value disp_propval[EXTCON_PROP_DISP_CNT]; - unsigned long usb_bits[BITS_TO_LONGS(EXTCON_PROP_USB_CNT)]; - unsigned long chg_bits[BITS_TO_LONGS(EXTCON_PROP_CHG_CNT)]; - unsigned long jack_bits[BITS_TO_LONGS(EXTCON_PROP_JACK_CNT)]; - unsigned long disp_bits[BITS_TO_LONGS(EXTCON_PROP_DISP_CNT)]; + DECLARE_BITMAP(usb_bits, EXTCON_PROP_USB_CNT); + DECLARE_BITMAP(chg_bits, EXTCON_PROP_CHG_CNT); + DECLARE_BITMAP(jack_bits, EXTCON_PROP_JACK_CNT); + DECLARE_BITMAP(disp_bits, EXTCON_PROP_DISP_CNT); }; static struct class *extcon_class; -- cgit v1.2.3 From 6ee0a22e8694074877550bf4284cc4085f86dd4f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Mar 2023 16:39:55 +0200 Subject: extcon: Use sysfs_emit() to instead of sprintf() Follow the advice of the Documentation/filesystems/sysfs.rst that show() should only use sysfs_emit() or sysfs_emit_at() when formatting the value to be returned to user space. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 70e9755ba2bc..ac84f4aafc69 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -370,12 +370,12 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, struct extcon_dev *edev = dev_get_drvdata(dev); if (edev->max_supported == 0) - return sprintf(buf, "%u\n", edev->state); + return sysfs_emit(buf, "%u\n", edev->state); for (i = 0; i < edev->max_supported; i++) { - count += sprintf(buf + count, "%s=%d\n", - extcon_info[edev->supported_cable[i]].name, - !!(edev->state & BIT(i))); + count += sysfs_emit_at(buf, count, "%s=%d\n", + extcon_info[edev->supported_cable[i]].name, + !!(edev->state & BIT(i))); } return count; @@ -387,7 +387,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, { struct extcon_dev *edev = dev_get_drvdata(dev); - return sprintf(buf, "%s\n", edev->name); + return sysfs_emit(buf, "%s\n", edev->name); } static DEVICE_ATTR_RO(name); @@ -398,8 +398,8 @@ static ssize_t cable_name_show(struct device *dev, attr_name); int i = cable->cable_index; - return sprintf(buf, "%s\n", - extcon_info[cable->edev->supported_cable[i]].name); + return sysfs_emit(buf, "%s\n", + extcon_info[cable->edev->supported_cable[i]].name); } static ssize_t cable_state_show(struct device *dev, @@ -410,8 +410,8 @@ static ssize_t cable_state_show(struct device *dev, int i = cable->cable_index; - return sprintf(buf, "%d\n", - extcon_get_state(cable->edev, cable->edev->supported_cable[i])); + return sysfs_emit(buf, "%d\n", + extcon_get_state(cable->edev, cable->edev->supported_cable[i])); } /** -- cgit v1.2.3 From 2b5e61f5069c29df7119af683ea1cf3c3f20a4bd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Mar 2023 16:39:56 +0200 Subject: extcon: Amend kernel documentation of struct extcon_dev First of all, the @lock description is missing. Add it. Second, correct the terminator value for the mutual exclusive cabling. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h index 93b5e0306966..15616446140d 100644 --- a/drivers/extcon/extcon.h +++ b/drivers/extcon/extcon.h @@ -13,8 +13,8 @@ * are disabled. * @mutually_exclusive: Array of mutually exclusive set of cables that cannot * be attached simultaneously. The array should be - * ending with NULL or be NULL (no mutually exclusive - * cables). For example, if it is { 0x7, 0x30, 0}, then, + * ending with 0 or be NULL (no mutually exclusive cables). + * For example, if it is {0x7, 0x30, 0}, then, * {0, 1}, {0, 1, 2}, {0, 2}, {1, 2}, or {4, 5} cannot * be attached simulataneously. {0x7, 0} is equivalent to * {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there @@ -27,7 +27,7 @@ * @nh: Notifier for the state change events from this extcon * @entry: To support list of extcon devices so that users can * search for extcon devices based on the extcon name. - * @lock: + * @lock: Protects device state and serialises device registration * @max_supported: Internal value to store the number of cables. * @extcon_dev_type: Device_type struct to provide attribute_groups * customized for each extcon device. -- cgit v1.2.3 From 0146f56b91a8ad287e7c94ea340b95a7040d29cf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Mar 2023 16:40:00 +0200 Subject: extcon: Use device_match_of_node() helper Instead of open coding, use device_match_of_node() helper. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index ac84f4aafc69..588c552b9525 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1405,7 +1405,7 @@ struct extcon_dev *extcon_find_edev_by_node(struct device_node *node) mutex_lock(&extcon_dev_list_lock); list_for_each_entry(edev, &extcon_dev_list, entry) - if (edev->dev.parent && edev->dev.parent->of_node == node) + if (edev->dev.parent && device_match_of_node(edev->dev.parent, node)) goto out; edev = ERR_PTR(-EPROBE_DEFER); out: -- cgit v1.2.3 From 9b4aea51cbcaefacaac655392f360bb3929ab63d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Mar 2023 16:40:01 +0200 Subject: extcon: Use dev_of_node(dev) instead of dev->of_node The dev_of_node function should be preferred. In the result we may drop unneeded NULL check of the pointer to the device object. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 588c552b9525..89b3946b3123 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1423,21 +1423,17 @@ out: */ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) { - struct device_node *node; + struct device_node *node, *np = dev_of_node(dev); struct extcon_dev *edev; - if (!dev) - return ERR_PTR(-EINVAL); - - if (!dev->of_node) { + if (!np) { dev_dbg(dev, "device does not have a device node entry\n"); return ERR_PTR(-EINVAL); } - node = of_parse_phandle(dev->of_node, "extcon", index); + node = of_parse_phandle(np, "extcon", index); if (!node) { - dev_dbg(dev, "failed to get phandle in %pOF node\n", - dev->of_node); + dev_dbg(dev, "failed to get phandle in %pOF node\n", np); return ERR_PTR(-ENODEV); } -- cgit v1.2.3 From 566825a31f65da111270abac35662502706e7c8a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Mar 2023 16:40:02 +0200 Subject: extcon: Remove dup device name in the message and unneeded error check The device name is already printed with dev_err(), no need to repeat. The device pointer itself is not supposed to be an error point, drop that check. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 89b3946b3123..47819c5144d5 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1362,9 +1362,8 @@ void extcon_dev_unregister(struct extcon_dev *edev) list_del(&edev->entry); mutex_unlock(&extcon_dev_list_lock); - if (IS_ERR_OR_NULL(get_device(&edev->dev))) { - dev_err(&edev->dev, "Failed to unregister extcon_dev (%s)\n", - dev_name(&edev->dev)); + if (!get_device(&edev->dev)) { + dev_err(&edev->dev, "Failed to unregister extcon_dev\n"); return; } -- cgit v1.2.3 From 7bba9e81a6fbf00daa4063c41da6b250d339f43b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 11 Apr 2023 14:48:22 +0300 Subject: extcon: Use unique number for the extcon device ID The use of atomic variable is still racy when we do not control which device has been unregistered and there is a (theoretical) possibility of the overflow that may cause a duplicate extcon device ID number to be allocated next time a device is registered. Replace above mentioned approach by using IDA framework. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 16 +++++++++++++--- drivers/extcon/extcon.h | 2 ++ 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 47819c5144d5..5da1cc60582a 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -238,6 +239,7 @@ struct extcon_cable { static struct class *extcon_class; +static DEFINE_IDA(extcon_dev_ids); static LIST_HEAD(extcon_dev_list); static DEFINE_MUTEX(extcon_dev_list_lock); @@ -1248,7 +1250,6 @@ static int extcon_alloc_groups(struct extcon_dev *edev) int extcon_dev_register(struct extcon_dev *edev) { int ret, index = 0; - static atomic_t edev_no = ATOMIC_INIT(-1); ret = create_extcon_class(); if (ret < 0) @@ -1275,8 +1276,14 @@ int extcon_dev_register(struct extcon_dev *edev) "extcon device name is null\n"); return -EINVAL; } - dev_set_name(&edev->dev, "extcon%lu", - (unsigned long)atomic_inc_return(&edev_no)); + + ret = ida_alloc(&extcon_dev_ids, GFP_KERNEL); + if (ret < 0) + return ret; + + edev->id = ret; + + dev_set_name(&edev->dev, "extcon%d", edev->id); ret = extcon_alloc_cables(edev); if (ret < 0) @@ -1339,6 +1346,7 @@ err_alloc_muex: if (edev->max_supported) kfree(edev->cables); err_alloc_cables: + ida_free(&extcon_dev_ids, edev->id); return ret; } @@ -1367,6 +1375,8 @@ void extcon_dev_unregister(struct extcon_dev *edev) return; } + ida_free(&extcon_dev_ids, edev->id); + device_unregister(&edev->dev); if (edev->mutually_exclusive && edev->max_supported) { diff --git a/drivers/extcon/extcon.h b/drivers/extcon/extcon.h index 15616446140d..946182687786 100644 --- a/drivers/extcon/extcon.h +++ b/drivers/extcon/extcon.h @@ -20,6 +20,7 @@ * {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there * can be no simultaneous connections. * @dev: Device of this extcon. + * @id: Unique device ID of this extcon. * @state: Attach/detach state of this extcon. Do not provide at * register-time. * @nh_all: Notifier for the state change events for all supported @@ -46,6 +47,7 @@ struct extcon_dev { /* Internal data. Please do not set. */ struct device dev; + unsigned int id; struct raw_notifier_head nh_all; struct raw_notifier_head *nh; struct list_head entry; -- cgit v1.2.3 From ef753fb4e86607afc6228d8632705122bc67f29a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 11 Apr 2023 14:48:23 +0300 Subject: extcon: Use sizeof(*pointer) instead of sizeof(type) It is preferred to use sizeof(*pointer) instead of sizeof(type). The type of the variable can change and one needs not change the former (unlike the latter). No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 5da1cc60582a..76dc41e8f250 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1098,8 +1098,7 @@ static int extcon_alloc_cables(struct extcon_dev *edev) if (!edev->max_supported) return 0; - edev->cables = kcalloc(edev->max_supported, - sizeof(struct extcon_cable), + edev->cables = kcalloc(edev->max_supported, sizeof(*edev->cables), GFP_KERNEL); if (!edev->cables) return -ENOMEM; @@ -1161,14 +1160,12 @@ static int extcon_alloc_muex(struct extcon_dev *edev) for (index = 0; edev->mutually_exclusive[index]; index++) ; - edev->attrs_muex = kcalloc(index + 1, - sizeof(struct attribute *), + edev->attrs_muex = kcalloc(index + 1, sizeof(*edev->attrs_muex), GFP_KERNEL); if (!edev->attrs_muex) return -ENOMEM; - edev->d_attrs_muex = kcalloc(index, - sizeof(struct device_attribute), + edev->d_attrs_muex = kcalloc(index, sizeof(*edev->d_attrs_muex), GFP_KERNEL); if (!edev->d_attrs_muex) { kfree(edev->attrs_muex); @@ -1214,8 +1211,8 @@ static int extcon_alloc_groups(struct extcon_dev *edev) return 0; edev->extcon_dev_type.groups = kcalloc(edev->max_supported + 2, - sizeof(struct attribute_group *), - GFP_KERNEL); + sizeof(*edev->extcon_dev_type.groups), + GFP_KERNEL); if (!edev->extcon_dev_type.groups) return -ENOMEM; -- cgit v1.2.3 From 93e60cd5e00e63f29e896453e10c7ede4cd8e882 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 11 Apr 2023 14:48:24 +0300 Subject: extcon: Drop unneeded assignments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In one case the assignment is duplicative, in the other, it's better to move it into the loop — the user of it. Signed-off-by: Andy Shevchenko Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 76dc41e8f250..6f7a60d2ed91 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -245,7 +245,7 @@ static DEFINE_MUTEX(extcon_dev_list_lock); static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state) { - int i = 0; + int i; if (!edev->mutually_exclusive) return 0; @@ -1246,7 +1246,7 @@ static int extcon_alloc_groups(struct extcon_dev *edev) */ int extcon_dev_register(struct extcon_dev *edev) { - int ret, index = 0; + int ret, index; ret = create_extcon_class(); if (ret < 0) @@ -1255,7 +1255,7 @@ int extcon_dev_register(struct extcon_dev *edev) if (!edev || !edev->supported_cable) return -EINVAL; - for (; edev->supported_cable[index] != EXTCON_NONE; index++); + for (index = 0; edev->supported_cable[index] != EXTCON_NONE; index++); edev->max_supported = index; if (index > SUPPORTED_CABLE_MAX) { -- cgit v1.2.3 From bcfa8e33064f1357e60a7c056a2e51cc5928d629 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 30 May 2023 07:17:26 +0200 Subject: extcon: Switch i2c drivers back to use .probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit b8a1a4cd5a98 ("i2c: Provide a temporary .probe_new() call-back type"), all drivers being converted to .probe_new() and then 03c835f498b5 ("i2c: Switch .probe() to not take an id parameter") convert back to (the new) .probe() to be able to eventually drop .probe_new() from struct i2c_driver. Signed-off-by: Uwe Kleine-König Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-fsa9480.c | 2 +- drivers/extcon/extcon-ptn5150.c | 2 +- drivers/extcon/extcon-rt8973a.c | 2 +- drivers/extcon/extcon-sm5502.c | 2 +- drivers/extcon/extcon-usbc-tusb320.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/extcon') diff --git a/drivers/extcon/extcon-fsa9480.c b/drivers/extcon/extcon-fsa9480.c index e8b2671eb29b..e458ce0c45ab 100644 --- a/drivers/extcon/extcon-fsa9480.c +++ b/drivers/extcon/extcon-fsa9480.c @@ -369,7 +369,7 @@ static struct i2c_driver fsa9480_i2c_driver = { .pm = &fsa9480_pm_ops, .of_match_table = fsa9480_of_match, }, - .probe_new = fsa9480_probe, + .probe = fsa9480_probe, .id_table = fsa9480_id, }; diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c index 017a07197f38..4616da7e5430 100644 --- a/drivers/extcon/extcon-ptn5150.c +++ b/drivers/extcon/extcon-ptn5150.c @@ -348,7 +348,7 @@ static struct i2c_driver ptn5150_i2c_driver = { .name = "ptn5150", .of_match_table = ptn5150_dt_match, }, - .probe_new = ptn5150_i2c_probe, + .probe = ptn5150_i2c_probe, .id_table = ptn5150_i2c_id, }; module_i2c_driver(ptn5150_i2c_driver); diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c index afc9b405d103..19bb49f13fb0 100644 --- a/drivers/extcon/extcon-rt8973a.c +++ b/drivers/extcon/extcon-rt8973a.c @@ -695,7 +695,7 @@ static struct i2c_driver rt8973a_muic_i2c_driver = { .pm = &rt8973a_muic_pm_ops, .of_match_table = rt8973a_dt_match, }, - .probe_new = rt8973a_muic_i2c_probe, + .probe = rt8973a_muic_i2c_probe, .remove = rt8973a_muic_i2c_remove, .id_table = rt8973a_i2c_id, }; diff --git a/drivers/extcon/extcon-sm5502.c b/drivers/extcon/extcon-sm5502.c index 8401e8b27788..c8c4b9ef72aa 100644 --- a/drivers/extcon/extcon-sm5502.c +++ b/drivers/extcon/extcon-sm5502.c @@ -840,7 +840,7 @@ static struct i2c_driver sm5502_muic_i2c_driver = { .pm = &sm5502_muic_pm_ops, .of_match_table = sm5502_dt_match, }, - .probe_new = sm5022_muic_i2c_probe, + .probe = sm5022_muic_i2c_probe, .id_table = sm5502_i2c_id, }; diff --git a/drivers/extcon/extcon-usbc-tusb320.c b/drivers/extcon/extcon-usbc-tusb320.c index cc2d0ac7c5f6..4d08c2123e59 100644 --- a/drivers/extcon/extcon-usbc-tusb320.c +++ b/drivers/extcon/extcon-usbc-tusb320.c @@ -593,7 +593,7 @@ static const struct of_device_id tusb320_extcon_dt_match[] = { MODULE_DEVICE_TABLE(of, tusb320_extcon_dt_match); static struct i2c_driver tusb320_extcon_driver = { - .probe_new = tusb320_probe, + .probe = tusb320_probe, .remove = tusb320_remove, .driver = { .name = "extcon-tusb320", -- cgit v1.2.3