Thread (2 messages) flat view 2 messages, 2 authors, 13d ago

Re: [PATCH v5 4/7] phy: cpcap-usb: add DCP detection and make UART idle mode optional

From: Manivannan Sadhasivam <mani@kernel.org>
Date: 2026-09-09 16:08:08
Also in: linux-devicetree, linux-gpio, linux-omap, lkml

On Sat, Jul 11, 2026 at 11:42:07PM +0300, Ivaylo Dimitrov wrote:
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.
Looks like this change is doing multiple things at once. Please split the
changes logically to separate patches.
Note: Enabling UART idle mode increases idle power consumption (by 25mW
on droid4).

Signed-off-by: Ivaylo Dimitrov <redacted>

# Conflicts:
#	drivers/phy/motorola/phy-cpcap-usb.c
What is this conflict?
quoted hunk
---
 drivers/phy/motorola/phy-cpcap-usb.c | 301 +++++++++++++++++++++------
 1 file changed, 238 insertions(+), 63 deletions(-)
diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
index 741145c89e5b..2d770ff19e93 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)");
Use of module params is discouraged these days. Also, you are disabling it by
default, which could cause surprises to users who have boards wired up for debug
console. But considering that it consumes a lot of power, I think it is OK to
disable it this way. I can't think of another way to add this knob.
quoted hunk
 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;
 }
 
[...]
quoted hunk
@@ -473,21 +559,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)
@@ -503,11 +578,23 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
 		goto out_err;
 
 	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2,
-				   CPCAP_BIT_USBXCVREN,
+				   CPCAP_BIT_USBXCVREN |
+				   CPCAP_BIT_UARTMUX0 |
+				   CPCAP_BIT_EMUMODE0,
As Sashiko noted, you are not clearing CPCAP_BIT_USBSUSPEND bit set in
cpcap_usb_set_idle_mode().
quoted hunk
 				   CPCAP_BIT_USBXCVREN);
 	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)
@@ -521,6 +608,38 @@ 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_USBC2,
+				   CPCAP_BIT_USBXCVREN |
+				   CPCAP_BIT_UARTMUX0 |
+				   CPCAP_BIT_EMUMODE0, 0);
+	if (error)
+		goto out_err;
+
+	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);
Don't print function names in the error log.

- Mani

-- 
மணிவண்ணன் சதாசிவம்

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help