[PATCH v2 5/5] phy: cpcap-usb: add extcon support
From: Ivaylo Dimitrov
Date: Sun Jul 05 2026 - 03:59:06 EST
Register an Extcon device and report the detected cable state.
The driver already determines the type of cable attached during USB cable
detection. Export the detected state through the Extcon framework so
other drivers can consume it using a standard kernel interface.
Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@xxxxxxxxx>
---
drivers/phy/motorola/phy-cpcap-usb.c | 69 ++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
index e776e54bbfd5..f1f2fe818324 100644
--- a/drivers/phy/motorola/phy-cpcap-usb.c
+++ b/drivers/phy/motorola/phy-cpcap-usb.c
@@ -12,6 +12,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/extcon-provider.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -124,6 +125,7 @@ struct cpcap_phy_ddata {
struct regmap *reg;
struct device *dev;
struct usb_phy phy;
+ struct extcon_dev *edev;
struct delayed_work detect_work;
struct pinctrl *pins;
struct pinctrl_state *pins_ulpi;
@@ -135,12 +137,23 @@ struct cpcap_phy_ddata {
struct regulator *vusb;
atomic_t active;
enum cpcap_mode mode;
+ int cable;
};
static bool cpcap_enable_uart;
module_param_named(enable_uart, cpcap_enable_uart, bool, 0644);
MODULE_PARM_DESC(enable_uart,
"Enable UART on the USB connector while idle (increases power consumption)");
+
+/* List of detectable cables */
+static const unsigned int cpcap_extcon_cables[] = {
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+ EXTCON_CHG_USB_SDP,
+ EXTCON_CHG_USB_DCP,
+ EXTCON_NONE,
+};
+
static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata)
{
int error, value = 0;
@@ -227,6 +240,46 @@ static void cpcap_usb_try_musb_mailbox(struct cpcap_phy_ddata *ddata,
__func__, error);
}
+static void cpcap_usb_set_extcon(struct cpcap_phy_ddata *ddata)
+{
+ int cable;
+
+ switch (ddata->mode) {
+ case CPCAP_CHARGER:
+ cable = EXTCON_CHG_USB_DCP;
+ break;
+ case CPCAP_USB:
+ cable = EXTCON_CHG_USB_SDP;
+ break;
+ case CPCAP_USB_HOST:
+ case CPCAP_DOCK:
+ cable = EXTCON_USB_HOST;
+ break;
+ case CPCAP_IDLE:
+ cable = EXTCON_NONE;
+ break;
+ case CPCAP_UNKNOWN:
+ dev_warn_once(ddata->dev, "called with unknown PHY mode\n");
+ return;
+ }
+
+ if (cable == ddata->cable)
+ return;
+
+ if (ddata->cable == EXTCON_CHG_USB_SDP)
+ extcon_set_state_sync(ddata->edev, EXTCON_USB, false);
+ else if (cable == EXTCON_CHG_USB_SDP)
+ extcon_set_state_sync(ddata->edev, EXTCON_USB, true);
+
+ if (ddata->cable != EXTCON_NONE)
+ extcon_set_state_sync(ddata->edev, ddata->cable, false);
+
+ if (cable != EXTCON_NONE)
+ extcon_set_state_sync(ddata->edev, cable, true);
+
+ ddata->cable = cable;
+}
+
static void cpcap_usb_detect(struct work_struct *work)
{
struct cpcap_phy_ddata *ddata;
@@ -276,6 +329,7 @@ static void cpcap_usb_detect(struct work_struct *work)
ddata->mode = CPCAP_DOCK;
cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
+ cpcap_usb_set_extcon(ddata);
/*
* Force check state again after musb has reoriented,
@@ -304,6 +358,7 @@ static void cpcap_usb_detect(struct work_struct *work)
ddata->mode = CPCAP_USB_HOST;
cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
+ cpcap_usb_set_extcon(ddata);
return;
}
@@ -345,6 +400,8 @@ static void cpcap_usb_detect(struct work_struct *work)
if (ddata->mode == CPCAP_USB)
cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_VALID);
+ cpcap_usb_set_extcon(ddata);
+
return;
}
@@ -357,6 +414,7 @@ static void cpcap_usb_detect(struct work_struct *work)
ddata->mode = CPCAP_IDLE;
cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);
+ cpcap_usb_set_extcon(ddata);
return;
@@ -785,7 +843,18 @@ static int cpcap_usb_phy_probe(struct platform_device *pdev)
if (!otg)
return -ENOMEM;
+ ddata->edev = devm_extcon_dev_allocate(&pdev->dev, cpcap_extcon_cables);
+ if (IS_ERR(ddata->edev)) {
+ return dev_err_probe(&pdev->dev, PTR_ERR(ddata->edev),
+ "failed to allocate extcon device\n");
+ }
+
+ error = devm_extcon_dev_register(&pdev->dev, ddata->edev);
+ if (error < 0)
+ return error;
+
ddata->mode = CPCAP_UNKNOWN;
+ ddata->cable = EXTCON_NONE;
ddata->dev = &pdev->dev;
ddata->phy.dev = ddata->dev;
ddata->phy.label = "cpcap_usb_phy";
--
2.39.5