* [PATCH v4 1/6] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt
2026-07-11 16:47 [PATCH v4 0/6] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
@ 2026-07-11 16:47 ` Ivaylo Dimitrov
2026-07-11 16:47 ` [PATCH v4 2/6] dt-bindings: phy: motorola,cpcap-usb-phy: add optional safe pinctrl state Ivaylo Dimitrov
` (4 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-11 16:47 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
Roger Quadros, Tony Lindgren, Linus Walleij, Bartosz Golaszewski,
--cc=linux-phy, devicetree, linux-kernel, linux-omap, linux-gpio
Cc: Ivaylo Dimitrov
Document the optional CPCAP charger detection interrupt in the USB PHY
binding.
Update the example DTS to include the corresponding "chrg_det" interrupt
name.
Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
---
.../devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
index 0febd04a61f4..d6d52d21280c 100644
--- a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
@@ -20,6 +20,7 @@ properties:
interrupts:
description: CPCAP PMIC interrupts used by the USB PHY
+ minItems: 9
items:
- description: id_ground interrupt
- description: id_float interrupt
@@ -30,9 +31,11 @@ properties:
- description: se1 interrupt
- description: dm interrupt
- description: dp interrupt
+ - description: charger detection interrupt
interrupt-names:
description: Interrupt names
+ minItems: 9
items:
- const: id_ground
- const: id_float
@@ -43,6 +46,7 @@ properties:
- const: se1
- const: dm
- const: dp
+ - const: chrg_det
io-channels:
description: IIO ADC channels used by the USB PHY
@@ -91,10 +95,10 @@ examples:
interrupts-extended = <
&cpcap 15 0 &cpcap 14 0 &cpcap 28 0 &cpcap 19 0
&cpcap 18 0 &cpcap 17 0 &cpcap 16 0 &cpcap 49 0
- &cpcap 48 1
+ &cpcap 48 1 &cpcap 13 0
>;
interrupt-names = "id_ground", "id_float", "se0conn", "vbusvld",
- "sessvld", "sessend", "se1", "dm", "dp";
+ "sessvld", "sessend", "se1", "dm", "dp", "chrg_det";
io-channels = <&cpcap_adc 2>, <&cpcap_adc 7>;
io-channel-names = "vbus", "id";
vusb-supply = <&vusb>;
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v4 2/6] dt-bindings: phy: motorola,cpcap-usb-phy: add optional safe pinctrl state
2026-07-11 16:47 [PATCH v4 0/6] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
2026-07-11 16:47 ` [PATCH v4 1/6] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt Ivaylo Dimitrov
@ 2026-07-11 16:47 ` Ivaylo Dimitrov
2026-07-11 17:00 ` sashiko-bot
2026-07-11 16:47 ` [PATCH v4 3/6] phy: cpcap-usb: add DCP detection and make UART idle mode optional Ivaylo Dimitrov
` (3 subsequent siblings)
5 siblings, 1 reply; 10+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-11 16:47 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
Roger Quadros, Tony Lindgren, Linus Walleij, Bartosz Golaszewski,
--cc=linux-phy, devicetree, linux-kernel, linux-omap, linux-gpio
Cc: Ivaylo Dimitrov
Document the optional "safe" pinctrl state used by the CPCAP USB PHY
driver.
Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
---
.../devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
index d6d52d21280c..25c36138bf66 100644
--- a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
@@ -62,11 +62,13 @@ properties:
vusb-supply: true
pinctrl-names:
+ minItems: 4
items:
- const: default
- const: ulpi
- const: utmi
- const: uart
+ - const: safe
mode-gpios:
description: Optional GPIOs for configuring alternate modes
@@ -106,6 +108,7 @@ examples:
pinctrl-1 = <&usb_ulpi_pins>;
pinctrl-2 = <&usb_utmi_pins>;
pinctrl-3 = <&uart3_pins>;
- pinctrl-names = "default", "ulpi", "utmi", "uart";
+ pinctrl-4 = <&usb_safe_pins>;
+ pinctrl-names = "default", "ulpi", "utmi", "uart", "safe";
mode-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>, <&gpio1 0 GPIO_ACTIVE_HIGH>;
};
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v4 2/6] dt-bindings: phy: motorola,cpcap-usb-phy: add optional safe pinctrl state
2026-07-11 16:47 ` [PATCH v4 2/6] dt-bindings: phy: motorola,cpcap-usb-phy: add optional safe pinctrl state Ivaylo Dimitrov
@ 2026-07-11 17:00 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-07-11 17:00 UTC (permalink / raw)
To: Ivaylo Dimitrov
Cc: conor+dt, linux-phy, vkoul, robh, devicetree, olteanv,
neil.armstrong
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The commit message claims to document the 'safe' pinctrl state used by the CPCAP USB PHY driver, but the driver itself never references or uses this state.
--
--- Patch [2]: [PATCH v4 2/6] dt-bindings: phy: motorola,cpcap-usb-phy: add optional safe pinctrl state ---
commit a9d2c62cbbf0fb6ec2341d2c0459bff90670c671
Author: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
dt-bindings: phy: motorola,cpcap-usb-phy: add optional safe pinctrl state
This commit adds a new safe pinctrl state to the CPCAP USB PHY device tree
bindings.
> Document the optional "safe" pinctrl state used by the CPCAP USB PHY
> driver.
[Severity: Medium]
Is this commit message accurate regarding the driver actually using this state?
Looking at the driver implementation in
drivers/phy/motorola/phy-cpcap-usb.c:cpcap_usb_init_optional_pins(), it
appears to only request the ulpi, utmi, and uart states:
ddata->pins_ulpi = pinctrl_lookup_state(ddata->pins, "ulpi");
if (IS_ERR(ddata->pins_ulpi))
...
ddata->pins_utmi = pinctrl_lookup_state(ddata->pins, "utmi");
...
ddata->pins_uart = pinctrl_lookup_state(ddata->pins, "uart");
The safe state does not appear to be requested or used anywhere in the driver
code.
Does the driver still need to be updated to support this new state, or could
the commit message be clarified to reflect that this is laying the groundwork
for future driver support?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260711164754.185565-1-ivo.g.dimitrov.75@gmail.com?part=2
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 3/6] phy: cpcap-usb: add DCP detection and make UART idle mode optional
2026-07-11 16:47 [PATCH v4 0/6] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
2026-07-11 16:47 ` [PATCH v4 1/6] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt Ivaylo Dimitrov
2026-07-11 16:47 ` [PATCH v4 2/6] dt-bindings: phy: motorola,cpcap-usb-phy: add optional safe pinctrl state Ivaylo Dimitrov
@ 2026-07-11 16:47 ` Ivaylo Dimitrov
2026-07-11 17:06 ` sashiko-bot
2026-07-11 16:47 ` [PATCH v4 4/6] phy: cpcap-usb: add extcon support Ivaylo Dimitrov
` (2 subsequent siblings)
5 siblings, 1 reply; 10+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-11 16:47 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
Roger Quadros, Tony Lindgren, Linus Walleij, Bartosz Golaszewski,
--cc=linux-phy, devicetree, linux-kernel, linux-omap, linux-gpio
Cc: Ivaylo Dimitrov
Handle DCP separately from USB host connections using CPCAP charger
detection status.
Make the existing idle UART mode optional via the "enable_uart" module
parameter. When disabled (default), the PHY remains in its USB/charger
detection configuration while idle.
Also initialize the PHY into the baseline configuration required for
reliable charger detection during probe.
Use the optional "safe" pinctrl state before switching between modes to
avoid glitches on USB or UART lines.
Fix a possible race between idle mode setup in cpcap_usb_phy_remove() and
cpcap_usb_detect().
Note: Enabling UART idle mode increases idle power consumption (by 25mW
on droid4).
Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
---
drivers/phy/motorola/phy-cpcap-usb.c | 281 +++++++++++++++++++++------
1 file changed, 219 insertions(+), 62 deletions(-)
diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
index 7cb020dd3423..d4eb8086b600 100644
--- a/drivers/phy/motorola/phy-cpcap-usb.c
+++ b/drivers/phy/motorola/phy-cpcap-usb.c
@@ -110,6 +110,15 @@ enum cpcap_gpio_mode {
CPCAP_OTG_DM_DP,
};
+enum cpcap_mode {
+ CPCAP_UNKNOWN,
+ CPCAP_IDLE,
+ CPCAP_CHARGER,
+ CPCAP_USB,
+ CPCAP_USB_HOST,
+ CPCAP_DOCK,
+};
+
struct cpcap_phy_ddata {
struct regmap *reg;
struct device *dev;
@@ -119,15 +128,19 @@ struct cpcap_phy_ddata {
struct pinctrl_state *pins_ulpi;
struct pinctrl_state *pins_utmi;
struct pinctrl_state *pins_uart;
+ struct pinctrl_state *pins_safe;
struct gpio_desc *gpio[2];
struct iio_channel *vbus;
struct iio_channel *id;
struct regulator *vusb;
atomic_t active;
- unsigned int vbus_provider:1;
- unsigned int docked:1;
+ enum cpcap_mode mode;
};
+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)");
static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata)
{
int error, value = 0;
@@ -196,8 +209,9 @@ static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata,
return 0;
}
-static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata);
+static int cpcap_usb_set_idle_mode(struct cpcap_phy_ddata *ddata);
static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata);
+static int cpcap_usb_set_dcp_mode(struct cpcap_phy_ddata *ddata);
static void cpcap_usb_try_musb_mailbox(struct cpcap_phy_ddata *ddata,
enum musb_vbus_id_status status)
@@ -228,7 +242,7 @@ static void cpcap_usb_detect(struct work_struct *work)
vbus = cpcap_usb_vbus_valid(ddata);
/* We need to kick the VBUS as USB A-host */
- if (s.id_ground && ddata->vbus_provider) {
+ if (s.id_ground && ddata->mode == CPCAP_USB_HOST) {
dev_dbg(ddata->dev, "still in USB A-host mode, kicking VBUS\n");
cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
@@ -243,7 +257,7 @@ static void cpcap_usb_detect(struct work_struct *work)
return;
}
- if (vbus && s.id_ground && ddata->docked) {
+ if (vbus && s.id_ground && ddata->mode == CPCAP_DOCK) {
dev_dbg(ddata->dev, "still docked as A-host, signal ID down\n");
cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
@@ -252,15 +266,14 @@ static void cpcap_usb_detect(struct work_struct *work)
}
/* No VBUS needed with docks */
- if (vbus && s.id_ground && !ddata->vbus_provider) {
+ if (vbus && s.id_ground && ddata->mode != CPCAP_USB_HOST) {
dev_dbg(ddata->dev, "connected to a dock\n");
- ddata->docked = true;
-
error = cpcap_usb_set_usb_mode(ddata);
if (error)
goto out_err;
+ ddata->mode = CPCAP_DOCK;
cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
/*
@@ -274,17 +287,13 @@ static void cpcap_usb_detect(struct work_struct *work)
return;
}
- if (s.id_ground && !ddata->docked) {
+ if (s.id_ground && ddata->mode != CPCAP_DOCK) {
dev_dbg(ddata->dev, "id ground, USB host mode\n");
- ddata->vbus_provider = true;
-
error = cpcap_usb_set_usb_mode(ddata);
if (error)
goto out_err;
- cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
-
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
CPCAP_BIT_VBUSSTBY_EN |
CPCAP_BIT_VBUSEN_SPI,
@@ -292,38 +301,64 @@ static void cpcap_usb_detect(struct work_struct *work)
if (error)
goto out_err;
+ ddata->mode = CPCAP_USB_HOST;
+ cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
+
return;
}
- error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
- CPCAP_BIT_VBUSSTBY_EN |
- CPCAP_BIT_VBUSEN_SPI, 0);
- if (error)
- goto out_err;
-
vbus = cpcap_usb_vbus_valid(ddata);
- /* Otherwise assume we're connected to a USB host */
- if (vbus) {
- dev_dbg(ddata->dev, "connected to USB host\n");
- error = cpcap_usb_set_usb_mode(ddata);
+ /* Check if we're connected to a USB host or charger */
+ if (vbus && ddata->mode != CPCAP_USB_HOST) {
+ enum cpcap_mode new_mode;
+
+ if (s.se1)
+ new_mode = CPCAP_CHARGER;
+ else if (!s.dm && !s.dp)
+ new_mode = CPCAP_USB;
+ else
+ return;
+
+ dev_dbg(ddata->dev, "connected to %s\n",
+ s.se1 ? "DCP" : "USB host");
+
+ error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
+ CPCAP_BIT_VBUSSTBY_EN |
+ CPCAP_BIT_VBUSEN_SPI, 0);
if (error)
goto out_err;
- cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_VALID);
+
+ if (new_mode == CPCAP_CHARGER)
+ error = cpcap_usb_set_dcp_mode(ddata);
+ else
+ error = cpcap_usb_set_usb_mode(ddata);
+
+ if (error)
+ goto out_err;
+
+ ddata->mode = new_mode;
+ if (ddata->mode == CPCAP_USB)
+ cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_VALID);
return;
}
- ddata->vbus_provider = false;
- ddata->docked = false;
- cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);
+ if (ddata->mode == CPCAP_IDLE)
+ return;
+
+ error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
+ CPCAP_BIT_VBUSSTBY_EN |
+ CPCAP_BIT_VBUSEN_SPI, 0);
+ if (error)
+ goto out_err;
- /* Default to debug UART mode */
- error = cpcap_usb_set_uart_mode(ddata);
+ error = cpcap_usb_set_idle_mode(ddata);
if (error)
goto out_err;
- dev_dbg(ddata->dev, "set UART mode\n");
+ ddata->mode = CPCAP_IDLE;
+ cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);
return;
@@ -411,43 +446,84 @@ static int cpcap_usb_gpio_set_mode(struct cpcap_phy_ddata *ddata,
return 0;
}
-static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)
+static int cpcap_usb_set_safe_mode(struct cpcap_phy_ddata *ddata)
{
int error;
/* Disable lines to prevent glitches from waking up mdm6600 */
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
if (error)
- goto out_err;
+ return error;
- if (ddata->pins_uart) {
- error = pinctrl_select_state(ddata->pins, ddata->pins_uart);
- if (error)
- goto out_err;
+ if (ddata->pins_safe) {
+ error = pinctrl_select_state(ddata->pins, ddata->pins_safe);
+ if (error) {
+ dev_err(ddata->dev, "could not set safe mode: %i\n",
+ error);
+ }
}
+ return error;
+}
+
+static int cpcap_usb_set_idle_mode(struct cpcap_phy_ddata *ddata)
+{
+ int error;
+ unsigned int val;
+ bool enable_uart = cpcap_enable_uart;
+
+ error = cpcap_usb_set_safe_mode(ddata);
+ if (error)
+ return error;
+
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1,
+ CPCAP_BIT_DP150KPU |
+ CPCAP_BIT_DP1K5PU |
+ CPCAP_BIT_DM1K5PU |
+ CPCAP_BIT_DPPD |
+ CPCAP_BIT_DMPD |
CPCAP_BIT_VBUSPD,
+ CPCAP_BIT_DP150KPU |
CPCAP_BIT_VBUSPD);
if (error)
goto out_err;
- error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2,
- 0xffff, CPCAP_BIT_UARTMUX0 |
- CPCAP_BIT_EMUMODE0);
+ val = CPCAP_BIT_USBSUSPEND;
+
+ if (enable_uart)
+ val |= (CPCAP_BIT_UARTMUX0 | CPCAP_BIT_EMUMODE0);
+
+ error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2, 0xffff, val);
if (error)
goto out_err;
- error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, 0x7fff,
- CPCAP_BIT_IDPU_SPI);
+ val = CPCAP_BIT_VBUSSTBY_EN |
+ CPCAP_BIT_VBUSPD_SPI |
+ CPCAP_BIT_DMPD_SPI |
+ CPCAP_BIT_DPPD_SPI |
+ CPCAP_BIT_PU_SPI |
+ CPCAP_BIT_IDPU_SPI |
+ CPCAP_BIT_ULPI_SPI_SEL;
+
+ if (!enable_uart)
+ val |= CPCAP_BIT_SUSPEND_SPI;
+
+ error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, 0x7fff, val);
if (error)
goto out_err;
- /* Enable UART mode */
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP);
if (error)
goto out_err;
+ if (enable_uart && ddata->pins_uart) {
+ error = pinctrl_select_state(ddata->pins, ddata->pins_uart);
+ if (error)
+ goto out_err;
+ }
+
+ dev_dbg(ddata->dev, "set %s mode\n", enable_uart ? "UART" : "IDLE");
+
return 0;
out_err:
@@ -460,21 +536,10 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
{
int error;
- /* Disable lines to prevent glitches from waking up mdm6600 */
- error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
+ error = cpcap_usb_set_safe_mode(ddata);
if (error)
return error;
- if (ddata->pins_utmi) {
- error = pinctrl_select_state(ddata->pins, ddata->pins_utmi);
- if (error) {
- dev_err(ddata->dev, "could not set usb mode: %i\n",
- error);
-
- return error;
- }
- }
-
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1,
CPCAP_BIT_VBUSPD, 0);
if (error)
@@ -495,6 +560,16 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
if (error)
goto out_err;
+ if (ddata->pins_utmi) {
+ error = pinctrl_select_state(ddata->pins, ddata->pins_utmi);
+ if (error) {
+ dev_err(ddata->dev, "could not set usb mode: %i\n",
+ error);
+
+ return error;
+ }
+ }
+
/* Enable USB mode */
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP);
if (error)
@@ -508,6 +583,31 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
return error;
}
+static int cpcap_usb_set_dcp_mode(struct cpcap_phy_ddata *ddata)
+{
+ int error;
+
+ error = cpcap_usb_set_safe_mode(ddata);
+ if (error)
+ return error;
+
+ error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
+ CPCAP_BIT_SUSPEND_SPI, 0);
+ if (error)
+ goto out_err;
+
+ error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP);
+ if (error)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
+
+ return error;
+}
+
static int cpcap_usb_init_optional_pins(struct cpcap_phy_ddata *ddata)
{
ddata->pins = devm_pinctrl_get(ddata->dev);
@@ -537,8 +637,11 @@ static int cpcap_usb_init_optional_pins(struct cpcap_phy_ddata *ddata)
ddata->pins_uart = NULL;
}
- if (ddata->pins_uart)
- return pinctrl_select_state(ddata->pins, ddata->pins_uart);
+ ddata->pins_safe = pinctrl_lookup_state(ddata->pins, "safe");
+ if (IS_ERR(ddata->pins_safe)) {
+ dev_info(ddata->dev, "safe pins not configured\n");
+ ddata->pins_safe = NULL;
+ }
return 0;
}
@@ -592,6 +695,59 @@ static int cpcap_usb_init_iio(struct cpcap_phy_ddata *ddata)
return error;
}
+static int cpcap_usb_init_usb(struct cpcap_phy_ddata *ddata)
+{
+ struct cpcap_usb_ints_state s;
+ int error;
+ int mask;
+
+ error = cpcap_phy_get_ints_state(ddata, &s);
+ if (error)
+ return error;
+
+ error = cpcap_usb_set_safe_mode(ddata);
+ if (error)
+ return error;
+
+ /*
+ * Do not touch DM/DP PD as this will break charger detection if charger
+ * is connected before we detect it.
+ */
+ if (s.se1) {
+ mask = CPCAP_BIT_VBUSEN_SPI | CPCAP_BIT_VBUSPU_SPI |
+ CPCAP_BIT_SUSPEND_SPI | CPCAP_BIT_ULPI_SPI_SEL;
+ } else {
+ mask = CPCAP_BIT_VBUSEN_SPI | CPCAP_BIT_VBUSPU_SPI |
+ CPCAP_BIT_DMPD_SPI | CPCAP_BIT_DPPD_SPI |
+ CPCAP_BIT_SUSPEND_SPI | CPCAP_BIT_PU_SPI |
+ CPCAP_BIT_ULPI_SPI_SEL;
+ }
+
+ error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, mask,
+ CPCAP_BIT_ULPI_SPI_SEL);
+ if (error)
+ return error;
+
+ /*
+ * Configure safe DP/DM termination state.
+ *
+ * Vendor kernel uses:
+ * DP150KPU = enabled
+ * all USB pullups/pulldowns = disabled
+ */
+ error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1,
+ CPCAP_BIT_DP150KPU |
+ CPCAP_BIT_DP1K5PU |
+ CPCAP_BIT_DM1K5PU |
+ CPCAP_BIT_DPPD |
+ CPCAP_BIT_DMPD,
+ CPCAP_BIT_DP150KPU);
+ if (error)
+ return error;
+
+ return cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP);
+}
+
#ifdef CONFIG_OF
static const struct of_device_id cpcap_usb_phy_id_table[] = {
{
@@ -625,6 +781,7 @@ static int cpcap_usb_phy_probe(struct platform_device *pdev)
if (!otg)
return -ENOMEM;
+ ddata->mode = CPCAP_UNKNOWN;
ddata->dev = &pdev->dev;
ddata->phy.dev = ddata->dev;
ddata->phy.label = "cpcap_usb_phy";
@@ -669,6 +826,10 @@ static int cpcap_usb_phy_probe(struct platform_device *pdev)
if (error)
goto out_reg_disable;
+ error = cpcap_usb_init_usb(ddata);
+ if (error)
+ goto out_reg_disable;
+
error = cpcap_usb_init_interrupts(pdev, ddata);
if (error)
goto out_reg_disable;
@@ -688,17 +849,13 @@ static int cpcap_usb_phy_probe(struct platform_device *pdev)
static void cpcap_usb_phy_remove(struct platform_device *pdev)
{
struct cpcap_phy_ddata *ddata = platform_get_drvdata(pdev);
- int error;
atomic_set(&ddata->active, 0);
- error = cpcap_usb_set_uart_mode(ddata);
- if (error)
- dev_err(ddata->dev, "could not set UART mode\n");
-
+ cancel_delayed_work_sync(&ddata->detect_work);
+ cpcap_usb_set_idle_mode(ddata);
cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);
usb_remove_phy(&ddata->phy);
- cancel_delayed_work_sync(&ddata->detect_work);
regulator_disable(ddata->vusb);
}
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v4 3/6] phy: cpcap-usb: add DCP detection and make UART idle mode optional
2026-07-11 16:47 ` [PATCH v4 3/6] phy: cpcap-usb: add DCP detection and make UART idle mode optional Ivaylo Dimitrov
@ 2026-07-11 17:06 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-07-11 17:06 UTC (permalink / raw)
To: Ivaylo Dimitrov
Cc: robh, conor+dt, devicetree, vkoul, olteanv, neil.armstrong,
linux-phy
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] `cpcap_usb_set_idle_mode()` unconditionally sets `CPCAP_BIT_DMPD_SPI` and `CPCAP_BIT_DPPD_SPI`, overriding hardware pulldowns and breaking subsequent charger detection.
- [Medium] The `cpcap_usb_set_dcp_mode` function fails to fully configure the PHY registers, leaving them in a non-deterministic state.
Pre-existing issues:
- [High] A TOCTOU race condition exists between the IRQ handler thread and `cpcap_usb_phy_remove`, leading to a use-after-free of the `ddata` structure.
--
--- Patch [3]: [PATCH v4 3/6] phy: cpcap-usb: add DCP detection and make UART idle mode optional ---
commit ccdf9470fbb5fbd414c5546a329d78f69ecf50b7
Author: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
phy: cpcap-usb: add DCP detection and make UART idle mode optional
Handle DCP separately from USB host connections using CPCAP charger
detection status. Make the existing idle UART mode optional via the
enable_uart module parameter. Also initialize the PHY into the baseline
configuration required for reliable charger detection during probe.
> diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
> index 7cb020dd3423c..d4eb8086b6000 100644
> --- a/drivers/phy/motorola/phy-cpcap-usb.c
> +++ b/drivers/phy/motorola/phy-cpcap-usb.c
[ ... ]
> @@ -411,43 +446,84 @@ static int cpcap_usb_gpio_set_mode(struct cpcap_phy_ddata *ddata,
[ ... ]
> +static int cpcap_usb_set_idle_mode(struct cpcap_phy_ddata *ddata)
> +{
> + int error;
> + unsigned int val;
> + bool enable_uart = cpcap_enable_uart;
> +
> + error = cpcap_usb_set_safe_mode(ddata);
> + if (error)
> + return error;
> +
> error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1,
> + CPCAP_BIT_DP150KPU |
> + CPCAP_BIT_DP1K5PU |
> + CPCAP_BIT_DM1K5PU |
> + CPCAP_BIT_DPPD |
> + CPCAP_BIT_DMPD |
> CPCAP_BIT_VBUSPD,
> + CPCAP_BIT_DP150KPU |
> CPCAP_BIT_VBUSPD);
> if (error)
> goto out_err;
>
> - error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2,
> - 0xffff, CPCAP_BIT_UARTMUX0 |
> - CPCAP_BIT_EMUMODE0);
> + val = CPCAP_BIT_USBSUSPEND;
> +
> + if (enable_uart)
> + val |= (CPCAP_BIT_UARTMUX0 | CPCAP_BIT_EMUMODE0);
> +
> + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2, 0xffff, val);
> if (error)
> goto out_err;
>
> - error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, 0x7fff,
> - CPCAP_BIT_IDPU_SPI);
> + val = CPCAP_BIT_VBUSSTBY_EN |
> + CPCAP_BIT_VBUSPD_SPI |
> + CPCAP_BIT_DMPD_SPI |
> + CPCAP_BIT_DPPD_SPI |
> + CPCAP_BIT_PU_SPI |
> + CPCAP_BIT_IDPU_SPI |
> + CPCAP_BIT_ULPI_SPI_SEL;
> +
> + if (!enable_uart)
> + val |= CPCAP_BIT_SUSPEND_SPI;
> +
> + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, 0x7fff, val);
[Severity: High]
Does setting CPCAP_BIT_DMPD_SPI and CPCAP_BIT_DPPD_SPI here break charger
detection?
Writing this value to USBC3 unconditionally sets both DMPD_SPI and DPPD_SPI to
1. This overrides the hardware pulldowns and forces them off. The original
code correctly cleared these bits, and as noted in cpcap_usb_init_usb(),
disabling these pulldowns can break subsequent charger detection when the
cable is disconnected.
> if (error)
> goto out_err;
>
[ ... ]
> @@ -508,6 +583,31 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
> return error;
> }
>
> +static int cpcap_usb_set_dcp_mode(struct cpcap_phy_ddata *ddata)
> +{
> + int error;
> +
> + error = cpcap_usb_set_safe_mode(ddata);
> + if (error)
> + return error;
> +
> + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
> + CPCAP_BIT_SUSPEND_SPI, 0);
> + if (error)
> + goto out_err;
[Severity: Medium]
Does cpcap_usb_set_dcp_mode() need to configure USBC1 and USBC2 as well?
Because this only updates USBC3, it seems to inherit whatever state was left
by the previous mode. For example, if transitioning from USB mode, USBXCVREN
in USBC2 might remain set. If transitioning from IDLE mode with
enable_uart=1, UARTMUX0 might remain set, leaving the UART connected to the
data lines during charging.
> +
> + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP);
> + if (error)
> + goto out_err;
> +
> + return 0;
> +
> +out_err:
> + dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
> +
> + return error;
> +}
> +
[ ... ]
> @@ -688,17 +849,13 @@ static int cpcap_usb_phy_probe(struct platform_device *pdev)
> static void cpcap_usb_phy_remove(struct platform_device *pdev)
> {
> struct cpcap_phy_ddata *ddata = platform_get_drvdata(pdev);
> - int error;
>
> atomic_set(&ddata->active, 0);
> - error = cpcap_usb_set_uart_mode(ddata);
> - if (error)
> - dev_err(ddata->dev, "could not set UART mode\n");
> -
> + cancel_delayed_work_sync(&ddata->detect_work);
> + cpcap_usb_set_idle_mode(ddata);
> cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);
>
> usb_remove_phy(&ddata->phy);
> - cancel_delayed_work_sync(&ddata->detect_work);
> regulator_disable(ddata->vusb);
> }
[Severity: High]
This is a pre-existing issue, but is there a TOCTOU race condition between
cpcap_phy_irq_thread() and cpcap_usb_phy_remove() that can result in a
use-after-free?
If the IRQ thread reads ddata->active as 1 in cpcap_phy_irq_thread() and gets
preempted:
cpcap_phy_irq_thread() {
if (!atomic_read(&ddata->active))
return IRQ_NONE;
/* preempted here */
And cpcap_usb_phy_remove() completes, setting ddata->active = 0, canceling the
work, and allowing devres to free ddata:
cpcap_usb_phy_remove() {
atomic_set(&ddata->active, 0);
cancel_delayed_work_sync(&ddata->detect_work);
...
}
/* devres frees ddata */
Could the IRQ thread then resume and call schedule_delayed_work() on the freed
ddata?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260711164754.185565-1-ivo.g.dimitrov.75@gmail.com?part=3
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 4/6] phy: cpcap-usb: add extcon support
2026-07-11 16:47 [PATCH v4 0/6] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
` (2 preceding siblings ...)
2026-07-11 16:47 ` [PATCH v4 3/6] phy: cpcap-usb: add DCP detection and make UART idle mode optional Ivaylo Dimitrov
@ 2026-07-11 16:47 ` Ivaylo Dimitrov
2026-07-11 17:14 ` sashiko-bot
2026-07-11 16:47 ` [PATCH v4 5/6] ARM: dts: ti: cpcap-mapphone: add charger detection interrupt for CPCAP USB PHY Ivaylo Dimitrov
2026-07-11 16:47 ` [PATCH v4 6/6] ARM: dts: ti: cpcap-mapphone: add USB safe pinctrl state Ivaylo Dimitrov
5 siblings, 1 reply; 10+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-11 16:47 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
Roger Quadros, Tony Lindgren, Linus Walleij, Bartosz Golaszewski,
--cc=linux-phy, devicetree, linux-kernel, linux-omap, linux-gpio
Cc: Ivaylo Dimitrov
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@gmail.com>
---
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 d4eb8086b600..8f9bea1d8a21 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>
@@ -123,6 +124,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;
@@ -226,6 +239,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;
@@ -275,6 +328,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,
@@ -303,6 +357,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;
}
@@ -341,6 +396,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;
}
@@ -359,6 +416,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;
@@ -781,7 +839,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
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v4 4/6] phy: cpcap-usb: add extcon support
2026-07-11 16:47 ` [PATCH v4 4/6] phy: cpcap-usb: add extcon support Ivaylo Dimitrov
@ 2026-07-11 17:14 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-07-11 17:14 UTC (permalink / raw)
To: Ivaylo Dimitrov
Cc: olteanv, linux-phy, conor+dt, vkoul, robh, devicetree,
neil.armstrong
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Medium] The ordering of extcon state updates exposes invalid intermediate cable states to userspace.
Pre-existing issues:
- [High] Pre-existing UAF: Delayed work can be re-armed after cancel_delayed_work_sync() during driver removal due to an IRQ thread race.
--
--- Patch [4]: [PATCH v4 4/6] phy: cpcap-usb: add extcon support ---
commit 5fa6aab542d92a2c79fbe5195a861859976507b6
Author: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
phy: cpcap-usb: add extcon support
This commit registers an Extcon device and reports the detected USB cable
state. It exports this state through the Extcon framework so other drivers
can consume it using standard kernel interfaces.
> diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
> index d4eb8086b6000..8f9bea1d8a212 100644
> --- a/drivers/phy/motorola/phy-cpcap-usb.c
> +++ b/drivers/phy/motorola/phy-cpcap-usb.c
[ ... ]
> @@ -226,6 +239,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) {
[ ... ]
> + 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);
[Severity: Medium]
Could this ordering expose invalid intermediate cable states to userspace?
When transitioning to a new cable state (specifically EXTCON_CHG_USB_SDP),
the new state's associated EXTCON_USB state is enabled before the old
ddata->cable state is cleared.
Because extcon_set_state_sync() immediately notifies consumers and emits a
uevent, consumers might briefly observe overlapping, mutually exclusive
states (such as both DCP and SDP active simultaneously).
Would it be safer to completely clear the old states before asserting any
new states?
> +
> + if (cable != EXTCON_NONE)
> + extcon_set_state_sync(ddata->edev, cable, true);
> +
> + ddata->cable = cable;
> +}
[ ... ]
[Severity: High]
This is a pre-existing issue, but I noticed a potential use-after-free race
involving the delayed work during driver unbind. Does this execution sequence
leave the work queued after removal?
If the IRQ thread checks ddata->active and gets preempted before calling
schedule_delayed_work():
cpcap_phy_irq_thread() {
...
if (atomic_read(&ddata->active))
... <preempted here> ...
cpcap_usb_phy_remove() can concurrently set active to 0 and call
cancel_delayed_work_sync(). Since the work isn't queued yet, the
cancellation completes immediately:
cpcap_usb_phy_remove() {
...
atomic_set(&ddata->active, 0);
cancel_delayed_work_sync(&ddata->detect_work);
...
During devres cleanup, free_irq() waits for the IRQ thread to finish.
The thread then resumes, unconditionally calls schedule_delayed_work(),
and exits:
schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1));
}
After free_irq() completes, devres frees ddata. The delayed work will
subsequently execute and access the freed memory.
Could this be prevented by disabling IRQs prior to cancelling the work?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260711164754.185565-1-ivo.g.dimitrov.75@gmail.com?part=4
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 5/6] ARM: dts: ti: cpcap-mapphone: add charger detection interrupt for CPCAP USB PHY
2026-07-11 16:47 [PATCH v4 0/6] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
` (3 preceding siblings ...)
2026-07-11 16:47 ` [PATCH v4 4/6] phy: cpcap-usb: add extcon support Ivaylo Dimitrov
@ 2026-07-11 16:47 ` Ivaylo Dimitrov
2026-07-11 16:47 ` [PATCH v4 6/6] ARM: dts: ti: cpcap-mapphone: add USB safe pinctrl state Ivaylo Dimitrov
5 siblings, 0 replies; 10+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-11 16:47 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
Roger Quadros, Tony Lindgren, Linus Walleij, Bartosz Golaszewski,
--cc=linux-phy, devicetree, linux-kernel, linux-omap, linux-gpio
Cc: Ivaylo Dimitrov
Update the CPCAP USB PHY interrupt mapping to use the charger
detection interrupt and corresponding "chrg_det" interrupt name.
Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
---
arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi
index 6b1195c2a768..51a858021541 100644
--- a/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi
+++ b/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi
@@ -125,11 +125,13 @@ cpcap_usb2_phy: phy {
interrupts-extended =
<&cpcap 15 0>, <&cpcap 14 0>, <&cpcap 28 0>,
<&cpcap 19 0>, <&cpcap 18 0>, <&cpcap 17 0>,
- <&cpcap 16 0>, <&cpcap 49 0>, <&cpcap 48 0>;
+ <&cpcap 16 0>, <&cpcap 49 0>, <&cpcap 48 0>,
+ <&cpcap 13 0>;
interrupt-names =
"id_ground", "id_float", "se0conn",
"vbusvld", "sessvld", "sessend",
- "se1", "dm", "dp";
+ "se1", "dm", "dp",
+ "chrg_det";
mode-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,
<&gpio1 0 GPIO_ACTIVE_HIGH>;
io-channels = <&cpcap_adc 2>, <&cpcap_adc 7>;
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v4 6/6] ARM: dts: ti: cpcap-mapphone: add USB safe pinctrl state
2026-07-11 16:47 [PATCH v4 0/6] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
` (4 preceding siblings ...)
2026-07-11 16:47 ` [PATCH v4 5/6] ARM: dts: ti: cpcap-mapphone: add charger detection interrupt for CPCAP USB PHY Ivaylo Dimitrov
@ 2026-07-11 16:47 ` Ivaylo Dimitrov
5 siblings, 0 replies; 10+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-11 16:47 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Aaro Koskinen, Andreas Kemnade, Kevin Hilman,
Roger Quadros, Tony Lindgren, Linus Walleij, Bartosz Golaszewski,
--cc=linux-phy, devicetree, linux-kernel, linux-omap, linux-gpio
Cc: Ivaylo Dimitrov
Add a pinctrl state that configures the USB interface pins into a safe
GPIO configuration. This allows the CPCAP USB PHY driver to place the
pins into a defined state whenever the USB interface is not active.
Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
---
.../dts/ti/omap/motorola-cpcap-mapphone.dtsi | 3 ++-
.../dts/ti/omap/motorola-mapphone-common.dtsi | 19 +++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi
index 51a858021541..368cb539997f 100644
--- a/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi
+++ b/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi
@@ -120,7 +120,8 @@ cpcap_usb2_phy: phy {
pinctrl-1 = <&usb_ulpi_pins>;
pinctrl-2 = <&usb_utmi_pins>;
pinctrl-3 = <&uart3_pins>;
- pinctrl-names = "default", "ulpi", "utmi", "uart";
+ pinctrl-4 = <&usb_safe_pins>;
+ pinctrl-names = "default", "ulpi", "utmi", "uart", "safe";
#phy-cells = <0>;
interrupts-extended =
<&cpcap 15 0>, <&cpcap 14 0>, <&cpcap 28 0>,
diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi
index acac3c243c7a..475ffe678e76 100644
--- a/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi
+++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi
@@ -352,6 +352,25 @@ OMAP4_IOPAD(0x1c8, PIN_INPUT_PULLUP | MUX_MODE7)
>;
};
+ usb_safe_pins: usb-safe-pins {
+ pinctrl-single,pins = <
+ OMAP4_IOPAD(0x196, MUX_MODE7)
+ OMAP4_IOPAD(0x198, MUX_MODE7)
+ OMAP4_IOPAD(0x1b2, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1b4, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1b6, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1b8, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1ba, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1bc, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1be, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1c0, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1c2, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1c4, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1c6, PIN_INPUT_PULLUP | MUX_MODE7)
+ OMAP4_IOPAD(0x1c8, PIN_INPUT_PULLUP | MUX_MODE7)
+ >;
+ };
+
/*
* Note that the v3.0.8 stock userspace dynamically remuxes uart1
* rts pin probably for PM purposes to PIN_INPUT_PULLUP | MUX_MODE7
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread