* [PATCH v2 1/5] phy: cpcap-usb: Prevent line glitches from triggering sysrq
2026-07-05 7:58 [PATCH v2 0/5] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
@ 2026-07-05 7:58 ` Ivaylo Dimitrov
2026-07-05 8:08 ` sashiko-bot
2026-07-05 7:58 ` [PATCH v2 2/5] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt Ivaylo Dimitrov
` (3 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-05 7:58 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,
Ivaylo Dimitrov
We can get random sysrq events on switching from USB to debug serial
port mode unless we temporarily disable sysrq on serial line for the mode
changes.
Suggested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
---
drivers/phy/motorola/phy-cpcap-usb.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
index 7cb020dd3423..d1c70c715346 100644
--- a/drivers/phy/motorola/phy-cpcap-usb.c
+++ b/drivers/phy/motorola/phy-cpcap-usb.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/sysrq.h>
#include <linux/gpio/consumer.h>
#include <linux/mfd/motorola-cpcap.h>
@@ -413,7 +414,12 @@ static int cpcap_usb_gpio_set_mode(struct cpcap_phy_ddata *ddata,
static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)
{
- int error;
+ int old_sysrq_mask, error;
+
+ /* Disable sysrq to prevent random sysrq events on line glitches */
+ old_sysrq_mask = sysrq_mask();
+ if (old_sysrq_mask & 1)
+ sysrq_toggle_support(old_sysrq_mask & ~1);
/* Disable lines to prevent glitches from waking up mdm6600 */
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
@@ -445,13 +451,13 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)
/* Enable UART mode */
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);
+ if (old_sysrq_mask & 1)
+ sysrq_toggle_support(old_sysrq_mask);
+
+ if (error)
+ dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
return error;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 1/5] phy: cpcap-usb: Prevent line glitches from triggering sysrq
2026-07-05 7:58 ` [PATCH v2 1/5] phy: cpcap-usb: Prevent line glitches from triggering sysrq Ivaylo Dimitrov
@ 2026-07-05 8:08 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-05 8:08 UTC (permalink / raw)
To: Ivaylo Dimitrov
Cc: robh, olteanv, linux-phy, conor+dt, vkoul, devicetree,
neil.armstrong
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Modifying system-wide SysRq state from a leaf PHY driver is a severe layer violation, and the implementation fails to disable SysRq in many configurations while also overwriting administrative changes.
- [High] Lockless manipulation of the global SysRq state introduces a data race that corrupts the input subsystem's handler list, leading to a kernel panic.
--
commit 1e47bb3741a2d7707b55cf24510e851f11fad240
Author: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
phy: cpcap-usb: Prevent line glitches from triggering sysrq
This commit temporarily disables sysrq support when switching between
USB and debug serial port modes to prevent line glitches from
triggering spurious sysrq events.
> diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
> index 7cb020dd3423c..d1c70c7153466 100644
> --- a/drivers/phy/motorola/phy-cpcap-usb.c
> +++ b/drivers/phy/motorola/phy-cpcap-usb.c
[ ... ]
> @@ -413,7 +414,12 @@ static int cpcap_usb_gpio_set_mode(struct cpcap_phy_ddata *ddata,
>
> static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)
> {
> - int error;
> + int old_sysrq_mask, error;
> +
> + /* Disable sysrq to prevent random sysrq events on line glitches */
> + old_sysrq_mask = sysrq_mask();
> + if (old_sysrq_mask & 1)
> + sysrq_toggle_support(old_sysrq_mask & ~1);
[Severity: High]
Is it safe to modify the global sysrq state from a leaf PHY driver?
Arbitrarily toggling global SysRq state affects all input devices (keyboard,
network, etc.) system-wide.
Also, checking (old_sysrq_mask & 1) assumes bit 0 is always set when sysrq
is enabled. If the system uses a custom mask without bit 0 (like 0x01b6),
would this fail to disable sysrq and leave the system vulnerable to the
glitch panic?
Additionally, calling sysrq_toggle_support() locklessly from this background
worker path can race with administrative sysctl changes or other drivers.
If this races with another thread calling sysrq_toggle_support(), couldn't
both threads observe that sysrq_on() is false and concurrently call
sysrq_register_handler()?
Since sysrq_register_handler() uses input_register_handler() on a single
statically allocated sysrq_handler, registering it twice would corrupt the
input_handler_list and lead to a crash.
> /* Disable lines to prevent glitches from waking up mdm6600 */
> error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
[ ... ]
> out_err:
> - dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
> + if (old_sysrq_mask & 1)
> + sysrq_toggle_support(old_sysrq_mask);
[Severity: High]
By unconditionally restoring the old mask here, could this accidentally
clobber concurrent administrative changes made via sysctl kernel.sysrq while
the mode switch was happening?
> +
> + if (error)
> + dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
>
> return error;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260705075809.1793784-1-ivo.g.dimitrov.75@gmail.com?part=1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 2/5] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt
2026-07-05 7:58 [PATCH v2 0/5] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
2026-07-05 7:58 ` [PATCH v2 1/5] phy: cpcap-usb: Prevent line glitches from triggering sysrq Ivaylo Dimitrov
@ 2026-07-05 7:58 ` Ivaylo Dimitrov
2026-07-05 8:07 ` sashiko-bot
2026-07-05 7:58 ` [PATCH v2 3/5] ARM: dts: ti: cpcap-mapphone: use charger detection interrupt for CPCAP USB PHY Ivaylo Dimitrov
` (2 subsequent siblings)
4 siblings, 1 reply; 11+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-05 7:58 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,
Ivaylo Dimitrov
The CPCAP USB PHY driver uses the CPCAP charger detection interrupt
for DCP detection.
Update the binding and example DTS to use 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 | 6 ++++--
1 file changed, 4 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..1a202cd29724 100644
--- a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
@@ -28,6 +28,7 @@ properties:
- description: sessvld interrupt
- description: sessend interrupt
- description: se1 interrupt
+ - description: charger detection interrupt
- description: dm interrupt
- description: dp interrupt
@@ -41,6 +42,7 @@ properties:
- const: sessvld
- const: sessend
- const: se1
+ - const: chrg_det
- const: dm
- const: dp
@@ -91,10 +93,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] 11+ messages in thread* Re: [PATCH v2 2/5] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt
2026-07-05 7:58 ` [PATCH v2 2/5] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt Ivaylo Dimitrov
@ 2026-07-05 8:07 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-05 8:07 UTC (permalink / raw)
To: Ivaylo Dimitrov
Cc: linux-phy, devicetree, neil.armstrong, robh, vkoul, conor+dt,
olteanv
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Low] DT Schema validation failure due to mismatched interrupt order in examples.
- [Low] DT Binding ABI Breakage by enforcing a backward-incompatible interrupt order.
--
commit 99e058efdaf5b3537435adf0f22c2c642d7b8007
Author: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt
The CPCAP USB PHY driver uses the CPCAP charger detection interrupt
for DCP detection. Update the binding and example DTS to use the
corresponding chrg_det interrupt name.
> diff --git a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
> index dd345cbd0a0b4..62121a8d8e76c 100644
> --- a/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
> +++ b/Documentation/devicetree/bindings/phy/motorola,cpcap-usb-phy.yaml
> @@ -28,6 +28,7 @@ properties:
> - description: sessvld interrupt
> - description: sessend interrupt
> - description: se1 interrupt
> + - description: charger detection interrupt
> - description: dm interrupt
> - description: dp interrupt
>
> @@ -41,6 +42,7 @@ properties:
> - const: sessvld
> - const: sessend
> - const: se1
> + - const: chrg_det
> - const: dm
> - const: dp
[Severity: Low]
Does adding this new interrupt in the middle of the items list break backward
compatibility for existing device trees?
By inserting it at index 7 (before dm and dp) without configuring minItems, the
schema now implicitly requires all 10 items in this strict order.
Existing device trees that only define 9 interrupts will fail validation because
their 7th item is dm instead of chrg_det.
[ ... ]
> @@ -91,10 +93,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";
[Severity: Low]
Will this example pass dt_binding_check validation?
The schema's properties block was updated above to expect chrg_det at index 7,
before dm and dp. However, the example appends chrg_det to the end of the list
at index 9.
YAML lists enforce positional matches, so validation might fail when it compares
the example's dm at index 7 against the newly expected chrg_det.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260705075809.1793784-1-ivo.g.dimitrov.75@gmail.com?part=2
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 3/5] ARM: dts: ti: cpcap-mapphone: use charger detection interrupt for CPCAP USB PHY
2026-07-05 7:58 [PATCH v2 0/5] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
2026-07-05 7:58 ` [PATCH v2 1/5] phy: cpcap-usb: Prevent line glitches from triggering sysrq Ivaylo Dimitrov
2026-07-05 7:58 ` [PATCH v2 2/5] dt-bindings: phy: motorola,cpcap-usb: add chrg_det interrupt Ivaylo Dimitrov
@ 2026-07-05 7:58 ` Ivaylo Dimitrov
2026-07-05 8:07 ` sashiko-bot
2026-07-05 7:58 ` [PATCH v2 4/5] phy: cpcap-usb: add DCP detection and make UART idle mode optional Ivaylo Dimitrov
2026-07-05 7:58 ` [PATCH v2 5/5] phy: cpcap-usb: add extcon support Ivaylo Dimitrov
4 siblings, 1 reply; 11+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-05 7:58 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,
Ivaylo Dimitrov
Update the CPCAP USB PHY interrupt mapping to use the charger
detection interrupt and corresponding "chrg_det" interrupt name.
This matches the driver and binding updates for DCP detection.
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] 11+ messages in thread* Re: [PATCH v2 3/5] ARM: dts: ti: cpcap-mapphone: use charger detection interrupt for CPCAP USB PHY
2026-07-05 7:58 ` [PATCH v2 3/5] ARM: dts: ti: cpcap-mapphone: use charger detection interrupt for CPCAP USB PHY Ivaylo Dimitrov
@ 2026-07-05 8:07 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-05 8:07 UTC (permalink / raw)
To: Ivaylo Dimitrov
Cc: conor+dt, neil.armstrong, robh, devicetree, vkoul, olteanv,
linux-phy
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The device tree patch appends the `chrg_det` interrupt to the end of the arrays, violating the strict positional ordering defined in the `motorola,cpcap-usb-phy.yaml` schema and breaking `make dtbs_check` validation.
--
commit cf71076312e1b822a677c10b23613d38d2cce1b0
Author: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
ARM: dts: ti: cpcap-mapphone: use charger detection interrupt for CPCAP USB PHY
Update the CPCAP USB PHY interrupt mapping to use the charger
detection interrupt and corresponding "chrg_det" interrupt name.
This matches the driver and binding updates for DCP detection.
> diff --git a/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi
> --- a/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi
> +++ b/arch/arm/boot/dts/ti/omap/motorola-cpcap-mapphone.dtsi
> @@ -106,11 +106,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";
[Severity: Medium]
Will this order of interrupt-names cause a failure during make dtbs_check?
The device tree binding schema motorola,cpcap-usb-phy.yaml expects chrg_det
to appear before dm and dp in the items list.
While the driver uses platform_get_irq_byname() so the runtime behavior works
regardless of order, appending chrg_det to the end of the array here violates
the positional ordering defined in the schema and breaks validation.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260705075809.1793784-1-ivo.g.dimitrov.75@gmail.com?part=3
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 4/5] phy: cpcap-usb: add DCP detection and make UART idle mode optional
2026-07-05 7:58 [PATCH v2 0/5] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
` (2 preceding siblings ...)
2026-07-05 7:58 ` [PATCH v2 3/5] ARM: dts: ti: cpcap-mapphone: use charger detection interrupt for CPCAP USB PHY Ivaylo Dimitrov
@ 2026-07-05 7:58 ` Ivaylo Dimitrov
2026-07-05 8:10 ` sashiko-bot
2026-07-05 7:58 ` [PATCH v2 5/5] phy: cpcap-usb: add extcon support Ivaylo Dimitrov
4 siblings, 1 reply; 11+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-05 7:58 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,
Ivaylo Dimitrov
Handle DCP separately from USB host connections based on CPCAP charger
detection status.
Make the existing idle UART mode optional via the "enable_uart" module
parameter. When disabled, the PHY remains in its USB/charger detection
configuration while idle. This reduces power usage in idle by 25mW.
Also initialize the PHY into the baseline configuration required for
reliable charger detection during probe.
Fix possible race where HW setup in cpcap_usb_phy_remove() can be run
in parallel with cpcap_usb_detect().
Note: Enabling UART idle mode increases idle power consumption.
Signed-off-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
---
drivers/phy/motorola/phy-cpcap-usb.c | 263 +++++++++++++++++++++------
1 file changed, 209 insertions(+), 54 deletions(-)
diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
index d1c70c715346..e776e54bbfd5 100644
--- a/drivers/phy/motorola/phy-cpcap-usb.c
+++ b/drivers/phy/motorola/phy-cpcap-usb.c
@@ -111,6 +111,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;
@@ -125,10 +134,13 @@ struct cpcap_phy_ddata {
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;
@@ -176,6 +188,7 @@ static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata,
s->id_ground = val & BIT(15);
s->id_float = val & BIT(14);
+ s->chrg_det = val & BIT(13);
s->vbusov = val & BIT(11);
error = regmap_read(ddata->reg, CPCAP_REG_INTS2, &val);
@@ -197,8 +210,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)
@@ -229,7 +243,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);
@@ -244,7 +258,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);
@@ -253,15 +267,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);
/*
@@ -275,17 +288,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,
@@ -293,38 +302,61 @@ 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 */
+ if (vbus && ddata->mode != CPCAP_USB_HOST) {
+ enum cpcap_mode new_mode;
+
+ if (!s.chrg_det || !s.sessvld || ddata->mode != CPCAP_IDLE)
+ return;
+
+ 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;
- /* 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;
@@ -374,7 +406,7 @@ static const char * const cpcap_phy_irqs[] = {
"id_ground", "id_float",
/* REG_INT1 */
- "se0conn", "vbusvld", "sessvld", "sessend", "se1",
+ "se0conn", "vbusvld", "sessvld", "sessend", "chrg_det",
/* REG_INT_3 */
"dm", "dp",
@@ -412,48 +444,78 @@ 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_idle_mode(struct cpcap_phy_ddata *ddata)
{
- int old_sysrq_mask, error;
+ int old_sysrq_mask = 0, error;
+ unsigned int val;
+ bool enable_uart = cpcap_enable_uart;
/* Disable sysrq to prevent random sysrq events on line glitches */
- old_sysrq_mask = sysrq_mask();
- if (old_sysrq_mask & 1)
- sysrq_toggle_support(old_sysrq_mask & ~1);
+ if (enable_uart) {
+ old_sysrq_mask = sysrq_mask();
+ if (old_sysrq_mask & 1)
+ sysrq_toggle_support(old_sysrq_mask & ~1);
+ }
/* Disable lines to prevent glitches from waking up mdm6600 */
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
if (error)
goto out_err;
- if (ddata->pins_uart) {
- error = pinctrl_select_state(ddata->pins, ddata->pins_uart);
+ if (enable_uart && ddata->pins_uart) {
+ error = pinctrl_select_state(ddata->pins, ddata->pins_uart);
+ if (error)
+ goto out_err;
+ } else if (!enable_uart && ddata->pins_ulpi) {
+ error = pinctrl_select_state(ddata->pins, ddata->pins_ulpi);
if (error)
goto out_err;
}
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;
+
+ dev_dbg(ddata->dev, "set %s mode\n", enable_uart ? "UART" : "IDLE");
out_err:
- if (old_sysrq_mask & 1)
+ if (enable_uart && (old_sysrq_mask & 1))
sysrq_toggle_support(old_sysrq_mask);
if (error)
@@ -514,6 +576,42 @@ 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 = 0;
+
+ /* Disable lines to prevent glitches from waking up mdm6600 */
+ error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
+ if (error)
+ return error;
+
+ if (ddata->pins_ulpi) {
+ error = pinctrl_select_state(ddata->pins, ddata->pins_ulpi);
+ if (error) {
+ dev_err(ddata->dev, "could not set usb mode: %i\n",
+ 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);
@@ -543,9 +641,6 @@ 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);
-
return 0;
}
@@ -598,6 +693,65 @@ 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_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
+ if (error)
+ return error;
+
+ if (ddata->pins_ulpi) {
+ error = pinctrl_select_state(ddata->pins, ddata->pins_ulpi);
+ 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[] = {
{
@@ -631,6 +785,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";
@@ -675,6 +830,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;
@@ -694,17 +853,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] 11+ messages in thread* Re: [PATCH v2 4/5] phy: cpcap-usb: add DCP detection and make UART idle mode optional
2026-07-05 7:58 ` [PATCH v2 4/5] phy: cpcap-usb: add DCP detection and make UART idle mode optional Ivaylo Dimitrov
@ 2026-07-05 8:10 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-05 8:10 UTC (permalink / raw)
To: Ivaylo Dimitrov
Cc: conor+dt, devicetree, linux-phy, vkoul, neil.armstrong, olteanv,
robh
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The USB PHY state machine gets permanently stuck in CPCAP_UNKNOWN if a USB host or charger is connected during boot.
Pre-existing issues:
- [High] A Time-Of-Check to Time-Of-Use (TOCTOU) race condition allows a delayed work timer to be queued just before the driver's data structure is freed.
--
commit c15ba246412946a134691c79cf0b6023882d635b
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 based on CPCAP charger
detection status. Make the existing idle UART mode optional and initialize
the PHY into the baseline configuration. Fix a race in removal.
> diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
> index d1c70c7153466..e776e54bbfd56 100644
> --- a/drivers/phy/motorola/phy-cpcap-usb.c
> +++ b/drivers/phy/motorola/phy-cpcap-usb.c
[ ... ]
> @@ -293,38 +302,61 @@ static void cpcap_usb_detect(struct work_struct *work)
[ ... ]
> 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 */
> + if (vbus && ddata->mode != CPCAP_USB_HOST) {
> + enum cpcap_mode new_mode;
> +
> + if (!s.chrg_det || !s.sessvld || ddata->mode != CPCAP_IDLE)
> + return;
[Severity: High]
Does this early return prevent the PHY from ever initializing if a cable
is connected during boot?
During cpcap_usb_phy_probe(), ddata->mode is initialized to CPCAP_UNKNOWN.
If a charger or host is already connected, vbus is true, and this block is
entered in cpcap_usb_detect(). Because ddata->mode is CPCAP_UNKNOWN, the
condition ddata->mode != CPCAP_IDLE is unconditionally true, which causes
an immediate return without transitioning the state.
[ ... ]
> @@ -694,17 +853,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);
[Severity: High]
This is a pre-existing issue, but does moving cancel_delayed_work_sync()
here still leave a window for a use-after-free if the IRQ thread is
preempted?
Looking at cpcap_phy_irq_thread():
if (!atomic_read(&ddata->active))
return IRQ_NONE;
schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1));
If the IRQ handler checks ddata->active and sees 1, but is then preempted
before scheduling the work, cpcap_usb_phy_remove() can run, set active to 0,
and cancel the currently empty workqueue.
When the IRQ handler resumes, it queues the work, which then fires after
devres has freed ddata.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260705075809.1793784-1-ivo.g.dimitrov.75@gmail.com?part=4
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 5/5] phy: cpcap-usb: add extcon support
2026-07-05 7:58 [PATCH v2 0/5] phy: cpcap-usb: improve charger detection and export cable state Ivaylo Dimitrov
` (3 preceding siblings ...)
2026-07-05 7:58 ` [PATCH v2 4/5] phy: cpcap-usb: add DCP detection and make UART idle mode optional Ivaylo Dimitrov
@ 2026-07-05 7:58 ` Ivaylo Dimitrov
2026-07-05 8:11 ` sashiko-bot
4 siblings, 1 reply; 11+ messages in thread
From: Ivaylo Dimitrov @ 2026-07-05 7:58 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,
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 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
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 5/5] phy: cpcap-usb: add extcon support
2026-07-05 7:58 ` [PATCH v2 5/5] phy: cpcap-usb: add extcon support Ivaylo Dimitrov
@ 2026-07-05 8:11 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-05 8:11 UTC (permalink / raw)
To: Ivaylo Dimitrov
Cc: neil.armstrong, devicetree, olteanv, vkoul, robh, linux-phy,
conor+dt
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Missing Kconfig dependency on CONFIG_EXTCON causes linker errors or breaks USB probe entirely if Extcon is disabled or built as a module.
Pre-existing issues:
- [High] Race condition between module removal and the threaded IRQ handler can lead to a use-after-free of `ddata`.
- [High] Booting with a USB cable or charger already attached prevents the driver from detecting the connection.
--
commit 85bc183819335614278666a8396810aa855aa0d7
Author: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
phy: cpcap-usb: add extcon support
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.
> diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
> index e776e54bbfd56..f1f2fe8183241 100644
> --- a/drivers/phy/motorola/phy-cpcap-usb.c
> +++ b/drivers/phy/motorola/phy-cpcap-usb.c
[ ... ]
> @@ -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;
> }
[Severity: High]
This is a pre-existing issue, but does the early return logic just above this
section prevent the driver from detecting a cable connected at boot time?
Looking earlier in cpcap_usb_detect():
if (vbus && ddata->mode != CPCAP_USB_HOST) {
enum cpcap_mode new_mode;
if (!s.chrg_det || !s.sessvld || ddata->mode != CPCAP_IDLE)
return;
At probe, ddata->mode is initialized to CPCAP_UNKNOWN. If a cable is already
attached when the device boots, vbus is valid. The condition checks if
ddata->mode != CPCAP_IDLE, which evaluates to true because the mode is set to
CPCAP_UNKNOWN.
This causes an early return without updating the mode or rescheduling the
work, which seems to leave the USB connection undetected.
[ ... ]
> @@ -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;
> +
[Severity: High]
Does PHY_CPCAP_USB need a Kconfig dependency on CONFIG_EXTCON?
If the driver is built-in but the extcon subsystem is configured as a
module, won't this cause a build failure due to undefined references to
devm_extcon_dev_allocate() and devm_extcon_dev_register()?
Additionally, if the extcon subsystem is completely disabled, the stub
function for devm_extcon_dev_allocate() returns ERR_PTR(-ENOSYS). This
would cause cpcap_usb_phy_probe() to unconditionally fail.
[ ... ]
[Severity: High]
This is a pre-existing issue, but is there a race condition during module
removal that could lead to a use-after-free of the ddata structure?
During driver removal, cpcap_usb_phy_remove() sets ddata->active to 0 and
cancels the delayed work:
atomic_set(&ddata->active, 0);
cancel_delayed_work_sync(&ddata->detect_work);
However, the IRQ is managed by devm_request_threaded_irq() and remains
active until after the remove function completes. If the threaded IRQ handler
cpcap_phy_irq_thread() reads ddata->active == 1 but is preempted before
calling schedule_delayed_work():
if (!atomic_read(&ddata->active))
return IRQ_NONE;
schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1));
The remove function could finish, causing devm to free the ddata structure.
When the IRQ thread resumes, it would schedule work using the freed ddata
pointer. Could this be resolved by explicitly disabling the IRQ before
canceling the work?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260705075809.1793784-1-ivo.g.dimitrov.75@gmail.com?part=5
^ permalink raw reply [flat|nested] 11+ messages in thread