From 4652fefcda3c604c83d1ae28ede94544e2142f06 Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Sat, 15 Nov 2025 10:59:05 +0800 Subject: [PATCH 1/7] extcon: ptn5150: handle pending IRQ events during system resume When the system is suspended and ptn5150 wakeup interrupt is disabled, any changes on ptn5150 will only be record in interrupt status registers and won't fire an IRQ since its trigger type is falling edge. So the HW interrupt line will keep at low state and any further changes won't trigger IRQ anymore. To fix it, this will schedule a work to check whether any IRQ are pending and handle it accordingly. Fixes: 4ed754de2d66 ("extcon: Add support for ptn5150 extcon driver") Cc: stable@vger.kernel.org Reviewed-by: Krzysztof Kozlowski Acked-by: MyungJoo Ham Signed-off-by: Xu Yang Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20251115025905.1395347-1-xu.yang_2@nxp.com/ --- drivers/extcon/extcon-ptn5150.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c index 78ad86c4a3be..31970fb34fcb 100644 --- a/drivers/extcon/extcon-ptn5150.c +++ b/drivers/extcon/extcon-ptn5150.c @@ -331,6 +331,19 @@ static int ptn5150_i2c_probe(struct i2c_client *i2c) return 0; } +static int ptn5150_resume(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + struct ptn5150_info *info = i2c_get_clientdata(i2c); + + /* Need to check possible pending interrupt events */ + schedule_work(&info->irq_work); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ptn5150_pm_ops, NULL, ptn5150_resume); + static const struct of_device_id ptn5150_dt_match[] = { { .compatible = "nxp,ptn5150" }, { }, @@ -346,6 +359,7 @@ MODULE_DEVICE_TABLE(i2c, ptn5150_i2c_id); static struct i2c_driver ptn5150_i2c_driver = { .driver = { .name = "ptn5150", + .pm = pm_sleep_ptr(&ptn5150_pm_ops), .of_match_table = ptn5150_dt_match, }, .probe = ptn5150_i2c_probe, From 6a4d20fecc650d0aeeb668cd1be6aa704220e227 Mon Sep 17 00:00:00 2001 From: Marco Crivellari Date: Tue, 4 Nov 2025 12:01:05 +0100 Subject: [PATCH 2/7] extcon: int3496: replace use of system_wq with system_percpu_wq Currently if a user enqueue a work item using schedule_delayed_work() the used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to schedule_work() that is using system_wq and queue_work(), that makes use again of WORK_CPU_UNBOUND. This lack of consistentcy cannot be addressed without refactoring the API. This patch continues the effort to refactor worqueue APIs, which has begun with the change introducing new workqueues and a new alloc_workqueue flag: commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq") commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag") system_wq should be the per-cpu workqueue, yet in this name nothing makes that clear, so replace system_wq with system_percpu_wq. The old wq (system_wq) will be kept for a few release cycles. Suggested-by: Tejun Heo Signed-off-by: Marco Crivellari Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20251104110105.116858-1-marco.crivellari@suse.com/ --- drivers/extcon/extcon-intel-int3496.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon-intel-int3496.c b/drivers/extcon/extcon-intel-int3496.c index ded1a85a5549..7d16d5b7d58f 100644 --- a/drivers/extcon/extcon-intel-int3496.c +++ b/drivers/extcon/extcon-intel-int3496.c @@ -106,7 +106,7 @@ static irqreturn_t int3496_thread_isr(int irq, void *priv) struct int3496_data *data = priv; /* Let the pin settle before processing it */ - mod_delayed_work(system_wq, &data->work, DEBOUNCE_TIME); + mod_delayed_work(system_percpu_wq, &data->work, DEBOUNCE_TIME); return IRQ_HANDLED; } @@ -181,7 +181,7 @@ static int int3496_probe(struct platform_device *pdev) } /* process id-pin so that we start with the right status */ - queue_delayed_work(system_wq, &data->work, 0); + queue_delayed_work(system_percpu_wq, &data->work, 0); flush_delayed_work(&data->work); platform_set_drvdata(pdev, data); From 8857f2495a2a37609ac925ab2fcd72104b190499 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Fri, 24 Oct 2025 10:49:46 +0800 Subject: [PATCH 3/7] extcon: Fixed sysfs duplicate filename issue With current extcon_dev_unregister() timing, ida_free is before device_unregister(), that may cause current id re-alloc to another device in extcon_dev_register() context but sysfs filename path not removal completed yet. The right timing shows below: on extcon_dev_register: ida_alloc() -> device_register() on extcon_dev_unregister: device_unregister() -> ida_free() stack information when an error occurs: sysfs: cannot create duplicate filename '/class/extcon/extcon1' Call trace: sysfs_warn_dup+0x68/0x88 sysfs_do_create_link_sd+0x94/0xdc sysfs_create_link+0x30/0x48 device_add_class_symlinks+0xb4/0x12c device_add+0x1e0/0x48c device_register+0x20/0x34 extcon_dev_register+0x3b8/0x5c4 Fixes: 7bba9e81a6fb ("extcon: Use unique number for the extcon device ID") Acked-by: MyungJoo Ham Reviewed-by: Andy Shevchenko Signed-off-by: Michael Wu Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20251024024946.16618-1-michael@allwinnertech.com/ --- drivers/extcon/extcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index d9e9815a5f96..98d85cc114a7 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1366,10 +1366,10 @@ void extcon_dev_unregister(struct extcon_dev *edev) return; } - ida_free(&extcon_dev_ids, edev->id); - device_unregister(&edev->dev); + ida_free(&extcon_dev_ids, edev->id); + if (edev->mutually_exclusive && edev->max_supported) { for (index = 0; edev->mutually_exclusive[index]; index++) From 086d7f1e063b3f7bbc6c54bbbabf1fa842be289f Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Fri, 26 Sep 2025 10:53:07 +0800 Subject: [PATCH 4/7] dt-bindings: extcon: ptn5150: Allow "connector" node to present PTN5150 is usually used with a Type-C connector, so allow a "connector" node to be defined under it. Acked-by: Chanwoo Choi Acked-by: Rob Herring (Arm) Signed-off-by: Xu Yang Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20250926025309.24267-1-xu.yang_2@nxp.com/ --- Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml b/Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml index 072b3c0c5fd0..79f88b5f4e5c 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml +++ b/Documentation/devicetree/bindings/extcon/extcon-ptn5150.yaml @@ -42,6 +42,9 @@ properties: description: A port node to link the usb controller for the dual role switch. + connector: + $ref: /schemas/connector/usb-connector.yaml# + required: - compatible - interrupts From 842546c56345eebc2396927df5b4e933d90de43a Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Fri, 26 Sep 2025 10:53:08 +0800 Subject: [PATCH 5/7] extcon: ptn5150: Add Type-C orientation switch support PTN5150 is able to detect CC polarity. The field[1:0] of CC status register (04H) will keep the result. 00: Cable Not Attached 01: CC1 is connected (normal orientation) 10: CC2 is connected (reversed orientation) 11: Reserved Add orientation switch support to correctly set orientation of multiplexer according to CC status. Acked-by: Chanwoo Choi Reviewed-by: Frank Li Signed-off-by: Xu Yang Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20250926025309.24267-2-xu.yang_2@nxp.com/ --- drivers/extcon/Kconfig | 1 + drivers/extcon/extcon-ptn5150.c | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index aec46bf03302..68d9df7d2dae 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -158,6 +158,7 @@ config EXTCON_PTN5150 tristate "NXP PTN5150 CC LOGIC USB EXTCON support" depends on I2C && (GPIOLIB || COMPILE_TEST) depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH + depends on TYPEC || !TYPEC select REGMAP_I2C help Say Y here to enable support for USB peripheral and USB host diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c index 31970fb34fcb..de753d00c4c2 100644 --- a/drivers/extcon/extcon-ptn5150.c +++ b/drivers/extcon/extcon-ptn5150.c @@ -18,6 +18,7 @@ #include #include #include +#include /* PTN5150 registers */ #define PTN5150_REG_DEVICE_ID 0x01 @@ -38,7 +39,11 @@ #define PTN5150_REG_DEVICE_ID_VERSION GENMASK(7, 3) #define PTN5150_REG_DEVICE_ID_VENDOR GENMASK(2, 0) +#define PTN5150_POLARITY_CC1 0x1 +#define PTN5150_POLARITY_CC2 0x2 + #define PTN5150_REG_CC_PORT_ATTACHMENT GENMASK(4, 2) +#define PTN5150_REG_CC_POLARITY GENMASK(1, 0) #define PTN5150_REG_CC_VBUS_DETECTION BIT(7) #define PTN5150_REG_INT_CABLE_ATTACH_MASK BIT(0) #define PTN5150_REG_INT_CABLE_DETACH_MASK BIT(1) @@ -53,6 +58,7 @@ struct ptn5150_info { int irq; struct work_struct irq_work; struct mutex mutex; + struct typec_switch *orient_sw; struct usb_role_switch *role_sw; }; @@ -71,6 +77,7 @@ static const struct regmap_config ptn5150_regmap_config = { static void ptn5150_check_state(struct ptn5150_info *info) { + enum typec_orientation orient = TYPEC_ORIENTATION_NONE; unsigned int port_status, reg_data, vbus; enum usb_role usb_role = USB_ROLE_NONE; int ret; @@ -81,6 +88,23 @@ static void ptn5150_check_state(struct ptn5150_info *info) return; } + orient = FIELD_GET(PTN5150_REG_CC_POLARITY, reg_data); + switch (orient) { + case PTN5150_POLARITY_CC1: + orient = TYPEC_ORIENTATION_NORMAL; + break; + case PTN5150_POLARITY_CC2: + orient = TYPEC_ORIENTATION_REVERSE; + break; + default: + orient = TYPEC_ORIENTATION_NONE; + break; + } + + ret = typec_switch_set(info->orient_sw, orient); + if (ret) + dev_err(info->dev, "failed to set orientation: %d\n", ret); + port_status = FIELD_GET(PTN5150_REG_CC_PORT_ATTACHMENT, reg_data); switch (port_status) { @@ -152,6 +176,12 @@ static void ptn5150_irq_work(struct work_struct *work) dev_err(info->dev, "failed to set none role: %d\n", ret); + + ret = typec_switch_set(info->orient_sw, + TYPEC_ORIENTATION_NONE); + if (ret) + dev_err(info->dev, + "failed to set orientation: %d\n", ret); } } @@ -219,12 +249,14 @@ static void ptn5150_work_sync_and_put(void *data) cancel_work_sync(&info->irq_work); usb_role_switch_put(info->role_sw); + typec_switch_put(info->orient_sw); } static int ptn5150_i2c_probe(struct i2c_client *i2c) { struct device *dev = &i2c->dev; struct device_node *np = i2c->dev.of_node; + struct fwnode_handle *connector; struct ptn5150_info *info; int ret; @@ -311,6 +343,14 @@ static int ptn5150_i2c_probe(struct i2c_client *i2c) if (ret) return -EINVAL; + connector = device_get_named_child_node(dev, "connector"); + if (connector) { + info->orient_sw = fwnode_typec_switch_get(connector); + if (IS_ERR(info->orient_sw)) + return dev_err_probe(info->dev, PTR_ERR(info->orient_sw), + "failed to get orientation switch\n"); + } + info->role_sw = usb_role_switch_get(info->dev); if (IS_ERR(info->role_sw)) return dev_err_probe(info->dev, PTR_ERR(info->role_sw), From 9c98fdec70ec15c46610464366d414df1d6a0bee Mon Sep 17 00:00:00 2001 From: Xu Yang Date: Fri, 26 Sep 2025 10:53:09 +0800 Subject: [PATCH 6/7] extcon: ptn5150: Support USB role switch via connector fwnode Since the PTN5150 is a Type-C chip, it's common to describe related properties under the connector node. To align with this, the port node will be located under the connector node in the future. To support this layout, retrieve the USB role switch using the connector's fwnode. For compatibility with existing device trees, keep the usb_role_switch_get() function. Acked-by: Chanwoo Choi Reviewed-by: Frank Li Signed-off-by: Xu Yang Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/20250926025309.24267-3-xu.yang_2@nxp.com/ --- drivers/extcon/extcon-ptn5150.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/extcon/extcon-ptn5150.c b/drivers/extcon/extcon-ptn5150.c index de753d00c4c2..eca1b140aeb0 100644 --- a/drivers/extcon/extcon-ptn5150.c +++ b/drivers/extcon/extcon-ptn5150.c @@ -352,6 +352,8 @@ static int ptn5150_i2c_probe(struct i2c_client *i2c) } info->role_sw = usb_role_switch_get(info->dev); + if (!info->role_sw && connector) + info->role_sw = fwnode_usb_role_switch_get(connector); if (IS_ERR(info->role_sw)) return dev_err_probe(info->dev, PTR_ERR(info->role_sw), "failed to get role switch\n"); From 1bf0ba46d9d2c784120fd9cb235c08add3a6e7be Mon Sep 17 00:00:00 2001 From: Yannis Bolliger Date: Fri, 17 Oct 2025 19:30:01 +0000 Subject: [PATCH 7/7] extcon: usbc-tusb320: Make typec-power-opmode optional The driver returned an error in the probe function when a usb c connector is configured in the DT without a "typec-power-opmode" property. This property is used to initialize the CURRENT_MODE_ADVERTISE register of the TUSB320, which is unused when operating as a UFP. Requiring this property causes unnecessary configuration overhead and inconsistency with the USB connector DT bindings, which do not specify it as required. This change makes typec-power-opmode optional. When the property is not present, the driver will skip programming the CURRENT_MODE_ADVERTISE register and rely on the hardware default. Signed-off-by: Yannis Bolliger Signed-off-by: Chanwoo Choi Link: https://lore.kernel.org/lkml/aPKZJ6WTZlhSOyST@yaene-desktop/ --- drivers/extcon/extcon-usbc-tusb320.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/extcon/extcon-usbc-tusb320.c b/drivers/extcon/extcon-usbc-tusb320.c index 2eab341de6b7..920b03421850 100644 --- a/drivers/extcon/extcon-usbc-tusb320.c +++ b/drivers/extcon/extcon-usbc-tusb320.c @@ -454,20 +454,18 @@ static int tusb320_typec_probe(struct i2c_client *client, 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) - goto err_put; + if (!fwnode_property_read_string(connector, "typec-power-opmode", + &cap_str)) { + ret = typec_find_pwr_opmode(cap_str); + if (ret < 0) + goto err_put; + priv->pwr_opmode = ret; - ret = typec_find_pwr_opmode(cap_str); - if (ret < 0) - goto err_put; - - priv->pwr_opmode = ret; - - /* Initialize the hardware with the devicetree settings. */ - ret = tusb320_set_adv_pwr_mode(priv); - if (ret) - goto err_put; + /* Initialize the hardware with the devicetree settings. */ + ret = tusb320_set_adv_pwr_mode(priv); + if (ret) + goto err_put; + } priv->cap.revision = USB_TYPEC_REV_1_1; priv->cap.accessory[0] = TYPEC_ACCESSORY_AUDIO;