From 13e2a1ff811cf5a4dc00efbc6affdba6203674a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= <megi@xff.cz>
Date: Fri, 4 Feb 2022 02:25:34 +0100
Subject: [PATCH 343/463] phy: rockchip-inno-usb2: More robust charger
 detection extcon updates

Make sure we always clear the charger detection results. Allow to
disable updates of EXTCON_USB state via extcon,ignore-usb DT property.
The previous method was smart, but assumed !vbus_branch would
always be called.

Signed-off-by: Ondrej Jirman <megi@xff.cz>
---
 drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 39 +++++++++++--------
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index df05812434b50..543e839867e36 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -640,21 +640,27 @@ static const struct phy_ops rockchip_usb2phy_ops = {
 	.owner		= THIS_MODULE,
 };
 
+const int rockchip_usb2phy_cable_types[] = {
+	EXTCON_CHG_USB_SDP,
+	EXTCON_CHG_USB_DCP,
+	EXTCON_CHG_USB_CDP,
+	EXTCON_CHG_USB_ACA,
+};
+
 static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
 {
 	struct rockchip_usb2phy_port *rport =
 		container_of(work, struct rockchip_usb2phy_port,
 			     otg_sm_work.work);
 	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
-	static unsigned int cable;
+	unsigned int cable = 0, i;
 	unsigned long delay;
-	bool vbus_attach, sch_work, notify_charger;
+	bool vbus_attach, sch_work;
 
 	vbus_attach = property_enabled(rphy->grf,
 				       &rport->port_cfg->utmi_bvalid);
 
 	sch_work = false;
-	notify_charger = false;
 	delay = OTG_SCHEDULE_DELAY;
 	dev_dbg(&rport->phy->dev, "%s otg sm work\n",
 		usb_otg_state_string(rport->state));
@@ -683,14 +689,12 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
 					dev_dbg(&rport->phy->dev, "sdp cable is connected\n");
 					rockchip_usb2phy_power_on(rport->phy);
 					rport->state = OTG_STATE_B_PERIPHERAL;
-					notify_charger = true;
 					sch_work = true;
 					cable = EXTCON_CHG_USB_SDP;
 					break;
 				case POWER_SUPPLY_TYPE_USB_DCP:
 					dev_dbg(&rport->phy->dev, "dcp cable is connected\n");
 					rockchip_usb2phy_power_off(rport->phy);
-					notify_charger = true;
 					sch_work = true;
 					cable = EXTCON_CHG_USB_DCP;
 					break;
@@ -698,7 +702,6 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
 					dev_dbg(&rport->phy->dev, "cdp cable is connected\n");
 					rockchip_usb2phy_power_on(rport->phy);
 					rport->state = OTG_STATE_B_PERIPHERAL;
-					notify_charger = true;
 					sch_work = true;
 					cable = EXTCON_CHG_USB_CDP;
 					break;
@@ -710,22 +713,26 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
 				break;
 			}
 		} else {
-			notify_charger = true;
 			rphy->chg_state = USB_CHG_STATE_UNDEFINED;
 			rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
 		}
 
-		if (rport->vbus_attached != vbus_attach) {
-			rport->vbus_attached = vbus_attach;
+		if (rphy->edev && extcon_get_state(rphy->edev, cable) != vbus_attach) {
+			for (i = 0; i < ARRAY_SIZE(rockchip_usb2phy_cable_types); i++) {
+				int type = rockchip_usb2phy_cable_types[i];
 
-			if (notify_charger && rphy->edev) {
-				extcon_set_state_sync(rphy->edev,
-							cable, vbus_attach);
-				if (cable == EXTCON_CHG_USB_SDP)
-					extcon_set_state_sync(rphy->edev,
-							      EXTCON_USB,
-							      vbus_attach);
+				if (extcon_get_state(rphy->edev, type))
+					extcon_set_state_sync(rphy->edev, type, 0);
 			}
+
+			if (vbus_attach)
+				extcon_set_state_sync(rphy->edev, cable, vbus_attach);
+
+			if ((cable == EXTCON_CHG_USB_SDP || cable == POWER_SUPPLY_TYPE_USB_CDP)
+				&& extcon_get_state(rphy->edev, EXTCON_USB) != vbus_attach
+				&& !of_property_read_bool(rphy->dev->of_node, "extcon,ignore-usb"))
+				extcon_set_state_sync(rphy->edev,
+						      EXTCON_USB, vbus_attach);
 		}
 		break;
 	case OTG_STATE_B_PERIPHERAL:
-- 
2.46.0

