]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
extcon: ptn5150: Add Type-C orientation switch support
authorXu Yang <xu.yang_2@nxp.com>
Fri, 26 Sep 2025 02:53:08 +0000 (10:53 +0800)
committerChanwoo Choi <cw00.choi@samsung.com>
Fri, 20 Mar 2026 02:20:43 +0000 (11:20 +0900)
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 <cw00.choi@samsung.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Link: https://lore.kernel.org/lkml/20250926025309.24267-2-xu.yang_2@nxp.com/
drivers/extcon/Kconfig
drivers/extcon/extcon-ptn5150.c

index aec46bf03302c9ef6e18c3d574c78e1365d898d8..68d9df7d2dae0d406f15ab87fd32c9cbad7ffbc6 100644 (file)
@@ -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
index 31970fb34fcb2e7f516afd1d8a94e4c680c00958..de753d00c4c2bfba897d7d5f66b025d4b2919716 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/extcon-provider.h>
 #include <linux/gpio/consumer.h>
 #include <linux/usb/role.h>
+#include <linux/usb/typec_mux.h>
 
 /* PTN5150 registers */
 #define PTN5150_REG_DEVICE_ID                  0x01
 #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),