All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/9] usb/dwc3 / phy/tusb1210: Add TUSB1211 charger detection
@ 2022-02-13 13:05 ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

Hi All,

Here is v2 of the patchs-series to add support for USB charger-type
(SDP/DCP) detection using a tusb1210 phy connected to a dwc3 controller.

Changes in v2:
[PATCH v2 9/9] phy: ti: tusb1210: Add charger detection:
- Add an online attribute to the registered power_supply class device,
  otherwise upower thinks it is an extra system battery
- Add tusb1210_remove_charger_detect() function to properly unregister
  the tusb->psy_nb notifier and to cancel tusb->chg_det_work

v1 cover-letter:

Some Android x86 tablets with a Bay Trail (BYT) SoC (with DWC3 UDC)
and a Crystal Cove PMIC, which does not support charger-detection,
rely on a TUSB1211 phy for charger-detection.

This series adds support for this, it starts with some dwc3 bug-fixes
for issues hit while developing this, as well as adding support to
the dwc3 code to set a special property checked by the tusb1210 driver
to signal that it needs to enable charger-detection.

The 2nd half of the series does some refactoring / fixes to the
tusb1210 driver and adds the charger-detection support.

Regards,

Hans


Hans de Goede (8):
  usb: dwc3: pci: Add "snps,dis_u2_susphy_quirk" for Intel Bay Trail
  usb: dwc3: pci: Fix Bay Trail phy GPIO mappings
  usb: dwc3: pci: Set the swnode from inside dwc3_pci_quirks()
  usb: dwc3: pci: Set "linux,phy_charger_detect" property on some Bay
    Trail boards
  usb: dwc3: pci: Also apply Bay Trail GPIO mappings to ulpi-device
  phy: ti: tusb1210: Improve ulpi_read()/_write() error checking
  phy: ti: tusb1210: Drop tusb->vendor_specific2 != 0 check from
    tusb1210_power_on()
  phy: ti: tusb1210: Add a delay between power-on and restoring the
    phy-parameters

Stephan Gerhold (1):
  phy: ti: tusb1210: Add charger detection

 drivers/phy/ti/phy-tusb1210.c | 439 ++++++++++++++++++++++++++++++++--
 drivers/usb/dwc3/dwc3-pci.c   |  60 ++++-
 2 files changed, 467 insertions(+), 32 deletions(-)

-- 
2.33.1


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 0/9] usb/dwc3 / phy/tusb1210: Add TUSB1211 charger detection
@ 2022-02-13 13:05 ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

Hi All,

Here is v2 of the patchs-series to add support for USB charger-type
(SDP/DCP) detection using a tusb1210 phy connected to a dwc3 controller.

Changes in v2:
[PATCH v2 9/9] phy: ti: tusb1210: Add charger detection:
- Add an online attribute to the registered power_supply class device,
  otherwise upower thinks it is an extra system battery
- Add tusb1210_remove_charger_detect() function to properly unregister
  the tusb->psy_nb notifier and to cancel tusb->chg_det_work

v1 cover-letter:

Some Android x86 tablets with a Bay Trail (BYT) SoC (with DWC3 UDC)
and a Crystal Cove PMIC, which does not support charger-detection,
rely on a TUSB1211 phy for charger-detection.

This series adds support for this, it starts with some dwc3 bug-fixes
for issues hit while developing this, as well as adding support to
the dwc3 code to set a special property checked by the tusb1210 driver
to signal that it needs to enable charger-detection.

The 2nd half of the series does some refactoring / fixes to the
tusb1210 driver and adds the charger-detection support.

Regards,

Hans


Hans de Goede (8):
  usb: dwc3: pci: Add "snps,dis_u2_susphy_quirk" for Intel Bay Trail
  usb: dwc3: pci: Fix Bay Trail phy GPIO mappings
  usb: dwc3: pci: Set the swnode from inside dwc3_pci_quirks()
  usb: dwc3: pci: Set "linux,phy_charger_detect" property on some Bay
    Trail boards
  usb: dwc3: pci: Also apply Bay Trail GPIO mappings to ulpi-device
  phy: ti: tusb1210: Improve ulpi_read()/_write() error checking
  phy: ti: tusb1210: Drop tusb->vendor_specific2 != 0 check from
    tusb1210_power_on()
  phy: ti: tusb1210: Add a delay between power-on and restoring the
    phy-parameters

Stephan Gerhold (1):
  phy: ti: tusb1210: Add charger detection

 drivers/phy/ti/phy-tusb1210.c | 439 ++++++++++++++++++++++++++++++++--
 drivers/usb/dwc3/dwc3-pci.c   |  60 ++++-
 2 files changed, 467 insertions(+), 32 deletions(-)

-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH v2 1/9] usb: dwc3: pci: Add "snps,dis_u2_susphy_quirk" for Intel Bay Trail
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-13 13:05   ` Hans de Goede
  -1 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy, Serge Semin

Commit e0082698b689 ("usb: dwc3: ulpi: conditionally resume ULPI PHY")
fixed an issue where ULPI transfers would timeout if any requests where
send to the phy sometime after init, giving it enough time to auto-suspend.

Commit e5f4ca3fce90 ("usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend
regression") changed the behavior to instead of clearing the
DWC3_GUSB2PHYCFG_SUSPHY bit, add an extra sleep when it is set.

But on Bay Trail devices, when phy_set_mode() gets called during init,
this leads to errors like these:
[   28.451522] tusb1210 dwc3.ulpi: error -110 writing val 0x01 to reg 0x0a
[   28.464089] tusb1210 dwc3.ulpi: error -110 writing val 0x01 to reg 0x0a

Add "snps,dis_u2_susphy_quirk" to the settings for Bay Trail devices to
fix this. This restores the old behavior for Bay Trail devices, since
previously the DWC3_GUSB2PHYCFG_SUSPHY bit would get cleared on the first
ulpi_read/_write() and then was never set again.

Fixes: e5f4ca3fce90 ("usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend regression")
Cc: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 7ff8fc8f79a9..022341aef400 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -119,6 +119,13 @@ static const struct property_entry dwc3_pci_intel_properties[] = {
 	{}
 };
 
+static const struct property_entry dwc3_pci_intel_byt_properties[] = {
+	PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
+	PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+	{}
+};
+
 static const struct property_entry dwc3_pci_mrfld_properties[] = {
 	PROPERTY_ENTRY_STRING("dr_mode", "otg"),
 	PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
@@ -161,6 +168,10 @@ static const struct software_node dwc3_pci_intel_swnode = {
 	.properties = dwc3_pci_intel_properties,
 };
 
+static const struct software_node dwc3_pci_intel_byt_swnode = {
+	.properties = dwc3_pci_intel_byt_properties,
+};
+
 static const struct software_node dwc3_pci_intel_mrfld_swnode = {
 	.properties = dwc3_pci_mrfld_properties,
 };
@@ -344,7 +355,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
 	  (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
-	  (kernel_ulong_t) &dwc3_pci_intel_swnode, },
+	  (kernel_ulong_t) &dwc3_pci_intel_byt_swnode, },
 
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
 	  (kernel_ulong_t) &dwc3_pci_intel_mrfld_swnode, },
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 1/9] usb: dwc3: pci: Add "snps, dis_u2_susphy_quirk" for Intel Bay Trail
@ 2022-02-13 13:05   ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy, Serge Semin

Commit e0082698b689 ("usb: dwc3: ulpi: conditionally resume ULPI PHY")
fixed an issue where ULPI transfers would timeout if any requests where
send to the phy sometime after init, giving it enough time to auto-suspend.

Commit e5f4ca3fce90 ("usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend
regression") changed the behavior to instead of clearing the
DWC3_GUSB2PHYCFG_SUSPHY bit, add an extra sleep when it is set.

But on Bay Trail devices, when phy_set_mode() gets called during init,
this leads to errors like these:
[   28.451522] tusb1210 dwc3.ulpi: error -110 writing val 0x01 to reg 0x0a
[   28.464089] tusb1210 dwc3.ulpi: error -110 writing val 0x01 to reg 0x0a

Add "snps,dis_u2_susphy_quirk" to the settings for Bay Trail devices to
fix this. This restores the old behavior for Bay Trail devices, since
previously the DWC3_GUSB2PHYCFG_SUSPHY bit would get cleared on the first
ulpi_read/_write() and then was never set again.

Fixes: e5f4ca3fce90 ("usb: dwc3: ulpi: Fix USB2.0 HS/FS/LS PHY suspend regression")
Cc: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 7ff8fc8f79a9..022341aef400 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -119,6 +119,13 @@ static const struct property_entry dwc3_pci_intel_properties[] = {
 	{}
 };
 
+static const struct property_entry dwc3_pci_intel_byt_properties[] = {
+	PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
+	PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+	{}
+};
+
 static const struct property_entry dwc3_pci_mrfld_properties[] = {
 	PROPERTY_ENTRY_STRING("dr_mode", "otg"),
 	PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
@@ -161,6 +168,10 @@ static const struct software_node dwc3_pci_intel_swnode = {
 	.properties = dwc3_pci_intel_properties,
 };
 
+static const struct software_node dwc3_pci_intel_byt_swnode = {
+	.properties = dwc3_pci_intel_byt_properties,
+};
+
 static const struct software_node dwc3_pci_intel_mrfld_swnode = {
 	.properties = dwc3_pci_mrfld_properties,
 };
@@ -344,7 +355,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
 	  (kernel_ulong_t) &dwc3_pci_intel_swnode, },
 
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
-	  (kernel_ulong_t) &dwc3_pci_intel_swnode, },
+	  (kernel_ulong_t) &dwc3_pci_intel_byt_swnode, },
 
 	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
 	  (kernel_ulong_t) &dwc3_pci_intel_mrfld_swnode, },
-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 2/9] usb: dwc3: pci: Fix Bay Trail phy GPIO mappings
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-13 13:05   ` Hans de Goede
  -1 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

When the Bay Trail phy GPIO mappings where added cs and reset were swapped,
this did not cause any issues sofar, because sofar they were always driven
high/low at the same time.

Note the new mapping has been verified both in /sys/kernel/debug/gpio
output on Android factory images on multiple devices, as well as in
the schematics for some devices.

Fixes: 5741022cbdf3 ("usb: dwc3: pci: Add GPIO lookup table on platforms without ACPI GPIO resources")
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 022341aef400..1ecedbb1684c 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -85,8 +85,8 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
 static struct gpiod_lookup_table platform_bytcr_gpios = {
 	.dev_id		= "0000:00:16.0",
 	.table		= {
-		GPIO_LOOKUP("INT33FC:00", 54, "reset", GPIO_ACTIVE_HIGH),
-		GPIO_LOOKUP("INT33FC:02", 14, "cs", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("INT33FC:00", 54, "cs", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("INT33FC:02", 14, "reset", GPIO_ACTIVE_HIGH),
 		{}
 	},
 };
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 2/9] usb: dwc3: pci: Fix Bay Trail phy GPIO mappings
@ 2022-02-13 13:05   ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

When the Bay Trail phy GPIO mappings where added cs and reset were swapped,
this did not cause any issues sofar, because sofar they were always driven
high/low at the same time.

Note the new mapping has been verified both in /sys/kernel/debug/gpio
output on Android factory images on multiple devices, as well as in
the schematics for some devices.

Fixes: 5741022cbdf3 ("usb: dwc3: pci: Add GPIO lookup table on platforms without ACPI GPIO resources")
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 022341aef400..1ecedbb1684c 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -85,8 +85,8 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
 static struct gpiod_lookup_table platform_bytcr_gpios = {
 	.dev_id		= "0000:00:16.0",
 	.table		= {
-		GPIO_LOOKUP("INT33FC:00", 54, "reset", GPIO_ACTIVE_HIGH),
-		GPIO_LOOKUP("INT33FC:02", 14, "cs", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("INT33FC:00", 54, "cs", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("INT33FC:02", 14, "reset", GPIO_ACTIVE_HIGH),
 		{}
 	},
 };
-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 3/9] usb: dwc3: pci: Set the swnode from inside dwc3_pci_quirks()
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-13 13:05   ` Hans de Goede
  -1 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

The quirk handling may need to set some different properties
which means using a different swnode, move the setting of the swnode
to inside dwc3_pci_quirks() so that the quirk handling can choose
a different swnode.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 1ecedbb1684c..40a3a1b114e9 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -184,7 +184,8 @@ static const struct software_node dwc3_pci_amd_mr_swnode = {
 	.properties = dwc3_pci_mr_properties,
 };
 
-static int dwc3_pci_quirks(struct dwc3_pci *dwc)
+static int dwc3_pci_quirks(struct dwc3_pci *dwc,
+			   const struct software_node *swnode)
 {
 	struct pci_dev			*pdev = dwc->pci;
 
@@ -241,7 +242,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
 		}
 	}
 
-	return 0;
+	return device_add_software_node(&dwc->dwc3->dev, swnode);
 }
 
 #ifdef CONFIG_PM
@@ -306,11 +307,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
 	dwc->dwc3->dev.parent = dev;
 	ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
 
-	ret = device_add_software_node(&dwc->dwc3->dev, (void *)id->driver_data);
-	if (ret < 0)
-		goto err;
-
-	ret = dwc3_pci_quirks(dwc);
+	ret = dwc3_pci_quirks(dwc, (void *)id->driver_data);
 	if (ret)
 		goto err;
 
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 3/9] usb: dwc3: pci: Set the swnode from inside dwc3_pci_quirks()
@ 2022-02-13 13:05   ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

The quirk handling may need to set some different properties
which means using a different swnode, move the setting of the swnode
to inside dwc3_pci_quirks() so that the quirk handling can choose
a different swnode.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 1ecedbb1684c..40a3a1b114e9 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -184,7 +184,8 @@ static const struct software_node dwc3_pci_amd_mr_swnode = {
 	.properties = dwc3_pci_mr_properties,
 };
 
-static int dwc3_pci_quirks(struct dwc3_pci *dwc)
+static int dwc3_pci_quirks(struct dwc3_pci *dwc,
+			   const struct software_node *swnode)
 {
 	struct pci_dev			*pdev = dwc->pci;
 
@@ -241,7 +242,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
 		}
 	}
 
-	return 0;
+	return device_add_software_node(&dwc->dwc3->dev, swnode);
 }
 
 #ifdef CONFIG_PM
@@ -306,11 +307,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
 	dwc->dwc3->dev.parent = dev;
 	ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
 
-	ret = device_add_software_node(&dwc->dwc3->dev, (void *)id->driver_data);
-	if (ret < 0)
-		goto err;
-
-	ret = dwc3_pci_quirks(dwc);
+	ret = dwc3_pci_quirks(dwc, (void *)id->driver_data);
 	if (ret)
 		goto err;
 
-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 4/9] usb: dwc3: pci: Set "linux,phy_charger_detect" property on some Bay Trail boards
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-13 13:05   ` Hans de Goede
  -1 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

Some Android x86 tablets with a Bay Trail (BYT) SoC and a Crystal Cove
PMIC, which does not support charger-detection, rely on the TUSB1211 phy
for charger-detection.

Windows tablets with the same SoC + PMIC often use an extra chip for
charger-detection like the FSA831A. But since on Android tablets
the designers already need to add a TUSB1211 phy to support device/gadget
mode the phy is used to do charger-detection instead.

These Android x86 tablets can be identified by the unique combination of
a Bay Trail SoC (already checked for by PCI-ids) + a Crystal Cove PMIC +
not using the standard ACPI battery and ac drivers. Where as on Windows
tablets the standard ACPI battery and ac drivers will be used on BYT
boards with a Crystal Cove PMIC.

Set a special kernel-internal (so not part of the dt-bindings)
"linux,phy_charger_detect" property on these boards, which tells the
tusb1210 driver to enable charger-detection.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 40a3a1b114e9..8deccf0aa5e7 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -126,6 +126,14 @@ static const struct property_entry dwc3_pci_intel_byt_properties[] = {
 	{}
 };
 
+static const struct property_entry dwc3_pci_intel_phy_charger_detect_properties[] = {
+	PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
+	PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+	PROPERTY_ENTRY_BOOL("linux,phy_charger_detect"),
+	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+	{}
+};
+
 static const struct property_entry dwc3_pci_mrfld_properties[] = {
 	PROPERTY_ENTRY_STRING("dr_mode", "otg"),
 	PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
@@ -172,6 +180,10 @@ static const struct software_node dwc3_pci_intel_byt_swnode = {
 	.properties = dwc3_pci_intel_byt_properties,
 };
 
+static const struct software_node dwc3_pci_intel_phy_charger_detect_swnode = {
+	.properties = dwc3_pci_intel_phy_charger_detect_properties,
+};
+
 static const struct software_node dwc3_pci_intel_mrfld_swnode = {
 	.properties = dwc3_pci_mrfld_properties,
 };
@@ -239,6 +251,18 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc,
 				gpiod_put(gpio);
 				usleep_range(10000, 11000);
 			}
+
+			/*
+			 * Some Android tablets with a Crystal Cove PMIC
+			 * (INT33FD), rely on the TUSB1211 phy for charger
+			 * detection. These can be identified by them _not_
+			 * using the standard ACPI battery and ac drivers.
+			 */
+			if (acpi_dev_present("INT33FD", "1", 2) &&
+			    acpi_quirk_skip_acpi_ac_and_battery()) {
+				dev_info(&pdev->dev, "Using TUSB1211 phy for charger detection\n");
+				swnode = &dwc3_pci_intel_phy_charger_detect_swnode;
+			}
 		}
 	}
 
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 4/9] usb: dwc3: pci: Set "linux, phy_charger_detect" property on some Bay Trail boards
@ 2022-02-13 13:05   ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

Some Android x86 tablets with a Bay Trail (BYT) SoC and a Crystal Cove
PMIC, which does not support charger-detection, rely on the TUSB1211 phy
for charger-detection.

Windows tablets with the same SoC + PMIC often use an extra chip for
charger-detection like the FSA831A. But since on Android tablets
the designers already need to add a TUSB1211 phy to support device/gadget
mode the phy is used to do charger-detection instead.

These Android x86 tablets can be identified by the unique combination of
a Bay Trail SoC (already checked for by PCI-ids) + a Crystal Cove PMIC +
not using the standard ACPI battery and ac drivers. Where as on Windows
tablets the standard ACPI battery and ac drivers will be used on BYT
boards with a Crystal Cove PMIC.

Set a special kernel-internal (so not part of the dt-bindings)
"linux,phy_charger_detect" property on these boards, which tells the
tusb1210 driver to enable charger-detection.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 40a3a1b114e9..8deccf0aa5e7 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -126,6 +126,14 @@ static const struct property_entry dwc3_pci_intel_byt_properties[] = {
 	{}
 };
 
+static const struct property_entry dwc3_pci_intel_phy_charger_detect_properties[] = {
+	PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
+	PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+	PROPERTY_ENTRY_BOOL("linux,phy_charger_detect"),
+	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+	{}
+};
+
 static const struct property_entry dwc3_pci_mrfld_properties[] = {
 	PROPERTY_ENTRY_STRING("dr_mode", "otg"),
 	PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
@@ -172,6 +180,10 @@ static const struct software_node dwc3_pci_intel_byt_swnode = {
 	.properties = dwc3_pci_intel_byt_properties,
 };
 
+static const struct software_node dwc3_pci_intel_phy_charger_detect_swnode = {
+	.properties = dwc3_pci_intel_phy_charger_detect_properties,
+};
+
 static const struct software_node dwc3_pci_intel_mrfld_swnode = {
 	.properties = dwc3_pci_mrfld_properties,
 };
@@ -239,6 +251,18 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc,
 				gpiod_put(gpio);
 				usleep_range(10000, 11000);
 			}
+
+			/*
+			 * Some Android tablets with a Crystal Cove PMIC
+			 * (INT33FD), rely on the TUSB1211 phy for charger
+			 * detection. These can be identified by them _not_
+			 * using the standard ACPI battery and ac drivers.
+			 */
+			if (acpi_dev_present("INT33FD", "1", 2) &&
+			    acpi_quirk_skip_acpi_ac_and_battery()) {
+				dev_info(&pdev->dev, "Using TUSB1211 phy for charger detection\n");
+				swnode = &dwc3_pci_intel_phy_charger_detect_swnode;
+			}
 		}
 	}
 
-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 5/9] usb: dwc3: pci: Also apply Bay Trail GPIO mappings to ulpi-device
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-13 13:05   ` Hans de Goede
  -1 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

In order for the phy driver to be able to actually get and control
the cs and reset GPIOs the dev_id member of the gpiod_lookup table must
be set to point to the dev_name() of the ulpi-device instantiated by
dwc3_ulpi_init().

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 8deccf0aa5e7..fdcf552a6365 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -252,6 +252,14 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc,
 				usleep_range(10000, 11000);
 			}
 
+			/*
+			 * Make the pdev name predictable (only 1 DWC3 on BYT)
+			 * and patch the phy dev-name into the lookup table so
+			 * that the phy-driver can get the GPIOs.
+			 */
+			dwc->dwc3->id = PLATFORM_DEVID_NONE;
+			platform_bytcr_gpios.dev_id = "dwc3.ulpi";
+
 			/*
 			 * Some Android tablets with a Crystal Cove PMIC
 			 * (INT33FD), rely on the TUSB1211 phy for charger
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 5/9] usb: dwc3: pci: Also apply Bay Trail GPIO mappings to ulpi-device
@ 2022-02-13 13:05   ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

In order for the phy driver to be able to actually get and control
the cs and reset GPIOs the dev_id member of the gpiod_lookup table must
be set to point to the dev_name() of the ulpi-device instantiated by
dwc3_ulpi_init().

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/usb/dwc3/dwc3-pci.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 8deccf0aa5e7..fdcf552a6365 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -252,6 +252,14 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc,
 				usleep_range(10000, 11000);
 			}
 
+			/*
+			 * Make the pdev name predictable (only 1 DWC3 on BYT)
+			 * and patch the phy dev-name into the lookup table so
+			 * that the phy-driver can get the GPIOs.
+			 */
+			dwc->dwc3->id = PLATFORM_DEVID_NONE;
+			platform_bytcr_gpios.dev_id = "dwc3.ulpi";
+
 			/*
 			 * Some Android tablets with a Crystal Cove PMIC
 			 * (INT33FD), rely on the TUSB1211 phy for charger
-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 6/9] phy: ti: tusb1210: Improve ulpi_read()/_write() error checking
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-13 13:05   ` Hans de Goede
  -1 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

ulpi_read() and ulpi_write() calls can fail. Add wrapper functions to log
errors when this happens and add error checking to the read + write of
the phy parameters from the TUSB1210_VENDOR_SPECIFIC2 register.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/phy/ti/phy-tusb1210.c | 62 +++++++++++++++++++++++++++--------
 1 file changed, 48 insertions(+), 14 deletions(-)

diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c
index 15c1c79e5c29..bf7793afdc84 100644
--- a/drivers/phy/ti/phy-tusb1210.c
+++ b/drivers/phy/ti/phy-tusb1210.c
@@ -26,6 +26,33 @@ struct tusb1210 {
 	u8 vendor_specific2;
 };
 
+static int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val)
+{
+	int ret;
+
+	ret = ulpi_write(tusb->ulpi, reg, val);
+	if (ret)
+		dev_err(&tusb->ulpi->dev, "error %d writing val 0x%02x to reg 0x%02x\n",
+			ret, val, reg);
+
+	return ret;
+}
+
+static int tusb1210_ulpi_read(struct tusb1210 *tusb, u8 reg, u8 *val)
+{
+	int ret;
+
+	ret = ulpi_read(tusb->ulpi, reg);
+	if (ret >= 0) {
+		*val = ret;
+		ret = 0;
+	} else {
+		dev_err(&tusb->ulpi->dev, "error %d reading reg 0x%02x\n", ret, reg);
+	}
+
+	return ret;
+}
+
 static int tusb1210_power_on(struct phy *phy)
 {
 	struct tusb1210 *tusb = phy_get_drvdata(phy);
@@ -35,8 +62,8 @@ static int tusb1210_power_on(struct phy *phy)
 
 	/* Restore the optional eye diagram optimization value */
 	if (tusb->vendor_specific2)
-		ulpi_write(tusb->ulpi, TUSB1210_VENDOR_SPECIFIC2,
-			   tusb->vendor_specific2);
+		return tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
+					   tusb->vendor_specific2);
 
 	return 0;
 }
@@ -55,33 +82,34 @@ static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 {
 	struct tusb1210 *tusb = phy_get_drvdata(phy);
 	int ret;
+	u8 reg;
 
-	ret = ulpi_read(tusb->ulpi, ULPI_OTG_CTRL);
+	ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &reg);
 	if (ret < 0)
 		return ret;
 
 	switch (mode) {
 	case PHY_MODE_USB_HOST:
-		ret |= (ULPI_OTG_CTRL_DRVVBUS_EXT
+		reg |= (ULPI_OTG_CTRL_DRVVBUS_EXT
 			| ULPI_OTG_CTRL_ID_PULLUP
 			| ULPI_OTG_CTRL_DP_PULLDOWN
 			| ULPI_OTG_CTRL_DM_PULLDOWN);
-		ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
-		ret |= ULPI_OTG_CTRL_DRVVBUS;
+		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
+		reg |= ULPI_OTG_CTRL_DRVVBUS;
 		break;
 	case PHY_MODE_USB_DEVICE:
-		ret &= ~(ULPI_OTG_CTRL_DRVVBUS
+		reg &= ~(ULPI_OTG_CTRL_DRVVBUS
 			 | ULPI_OTG_CTRL_DP_PULLDOWN
 			 | ULPI_OTG_CTRL_DM_PULLDOWN);
-		ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
-		ret &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
+		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
+		reg &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
 		break;
 	default:
 		/* nothing */
 		return 0;
 	}
 
-	return ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
+	return tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
 }
 
 static const struct phy_ops phy_ops = {
@@ -95,11 +123,14 @@ static int tusb1210_probe(struct ulpi *ulpi)
 {
 	struct tusb1210 *tusb;
 	u8 val, reg;
+	int ret;
 
 	tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
 	if (!tusb)
 		return -ENOMEM;
 
+	tusb->ulpi = ulpi;
+
 	tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset",
 						   GPIOD_OUT_LOW);
 	if (IS_ERR(tusb->gpio_reset))
@@ -119,7 +150,9 @@ static int tusb1210_probe(struct ulpi *ulpi)
 	 * diagram optimization and DP/DM swap.
 	 */
 
-	reg = ulpi_read(ulpi, TUSB1210_VENDOR_SPECIFIC2);
+	ret = tusb1210_ulpi_read(tusb, TUSB1210_VENDOR_SPECIFIC2, &reg);
+	if (ret)
+		return ret;
 
 	/* High speed output drive strength configuration */
 	if (!device_property_read_u8(&ulpi->dev, "ihstx", &val))
@@ -133,15 +166,16 @@ static int tusb1210_probe(struct ulpi *ulpi)
 	if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val))
 		u8p_replace_bits(&reg, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK);
 
-	ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
+	ret = tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, reg);
+	if (ret)
+		return ret;
+
 	tusb->vendor_specific2 = reg;
 
 	tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
 	if (IS_ERR(tusb->phy))
 		return PTR_ERR(tusb->phy);
 
-	tusb->ulpi = ulpi;
-
 	phy_set_drvdata(tusb->phy, tusb);
 	ulpi_set_drvdata(ulpi, tusb);
 	return 0;
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 6/9] phy: ti: tusb1210: Improve ulpi_read()/_write() error checking
@ 2022-02-13 13:05   ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

ulpi_read() and ulpi_write() calls can fail. Add wrapper functions to log
errors when this happens and add error checking to the read + write of
the phy parameters from the TUSB1210_VENDOR_SPECIFIC2 register.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/phy/ti/phy-tusb1210.c | 62 +++++++++++++++++++++++++++--------
 1 file changed, 48 insertions(+), 14 deletions(-)

diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c
index 15c1c79e5c29..bf7793afdc84 100644
--- a/drivers/phy/ti/phy-tusb1210.c
+++ b/drivers/phy/ti/phy-tusb1210.c
@@ -26,6 +26,33 @@ struct tusb1210 {
 	u8 vendor_specific2;
 };
 
+static int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val)
+{
+	int ret;
+
+	ret = ulpi_write(tusb->ulpi, reg, val);
+	if (ret)
+		dev_err(&tusb->ulpi->dev, "error %d writing val 0x%02x to reg 0x%02x\n",
+			ret, val, reg);
+
+	return ret;
+}
+
+static int tusb1210_ulpi_read(struct tusb1210 *tusb, u8 reg, u8 *val)
+{
+	int ret;
+
+	ret = ulpi_read(tusb->ulpi, reg);
+	if (ret >= 0) {
+		*val = ret;
+		ret = 0;
+	} else {
+		dev_err(&tusb->ulpi->dev, "error %d reading reg 0x%02x\n", ret, reg);
+	}
+
+	return ret;
+}
+
 static int tusb1210_power_on(struct phy *phy)
 {
 	struct tusb1210 *tusb = phy_get_drvdata(phy);
@@ -35,8 +62,8 @@ static int tusb1210_power_on(struct phy *phy)
 
 	/* Restore the optional eye diagram optimization value */
 	if (tusb->vendor_specific2)
-		ulpi_write(tusb->ulpi, TUSB1210_VENDOR_SPECIFIC2,
-			   tusb->vendor_specific2);
+		return tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
+					   tusb->vendor_specific2);
 
 	return 0;
 }
@@ -55,33 +82,34 @@ static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 {
 	struct tusb1210 *tusb = phy_get_drvdata(phy);
 	int ret;
+	u8 reg;
 
-	ret = ulpi_read(tusb->ulpi, ULPI_OTG_CTRL);
+	ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &reg);
 	if (ret < 0)
 		return ret;
 
 	switch (mode) {
 	case PHY_MODE_USB_HOST:
-		ret |= (ULPI_OTG_CTRL_DRVVBUS_EXT
+		reg |= (ULPI_OTG_CTRL_DRVVBUS_EXT
 			| ULPI_OTG_CTRL_ID_PULLUP
 			| ULPI_OTG_CTRL_DP_PULLDOWN
 			| ULPI_OTG_CTRL_DM_PULLDOWN);
-		ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
-		ret |= ULPI_OTG_CTRL_DRVVBUS;
+		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
+		reg |= ULPI_OTG_CTRL_DRVVBUS;
 		break;
 	case PHY_MODE_USB_DEVICE:
-		ret &= ~(ULPI_OTG_CTRL_DRVVBUS
+		reg &= ~(ULPI_OTG_CTRL_DRVVBUS
 			 | ULPI_OTG_CTRL_DP_PULLDOWN
 			 | ULPI_OTG_CTRL_DM_PULLDOWN);
-		ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
-		ret &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
+		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
+		reg &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
 		break;
 	default:
 		/* nothing */
 		return 0;
 	}
 
-	return ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
+	return tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
 }
 
 static const struct phy_ops phy_ops = {
@@ -95,11 +123,14 @@ static int tusb1210_probe(struct ulpi *ulpi)
 {
 	struct tusb1210 *tusb;
 	u8 val, reg;
+	int ret;
 
 	tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
 	if (!tusb)
 		return -ENOMEM;
 
+	tusb->ulpi = ulpi;
+
 	tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset",
 						   GPIOD_OUT_LOW);
 	if (IS_ERR(tusb->gpio_reset))
@@ -119,7 +150,9 @@ static int tusb1210_probe(struct ulpi *ulpi)
 	 * diagram optimization and DP/DM swap.
 	 */
 
-	reg = ulpi_read(ulpi, TUSB1210_VENDOR_SPECIFIC2);
+	ret = tusb1210_ulpi_read(tusb, TUSB1210_VENDOR_SPECIFIC2, &reg);
+	if (ret)
+		return ret;
 
 	/* High speed output drive strength configuration */
 	if (!device_property_read_u8(&ulpi->dev, "ihstx", &val))
@@ -133,15 +166,16 @@ static int tusb1210_probe(struct ulpi *ulpi)
 	if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val))
 		u8p_replace_bits(&reg, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK);
 
-	ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
+	ret = tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, reg);
+	if (ret)
+		return ret;
+
 	tusb->vendor_specific2 = reg;
 
 	tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
 	if (IS_ERR(tusb->phy))
 		return PTR_ERR(tusb->phy);
 
-	tusb->ulpi = ulpi;
-
 	phy_set_drvdata(tusb->phy, tusb);
 	ulpi_set_drvdata(ulpi, tusb);
 	return 0;
-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 7/9] phy: ti: tusb1210: Drop tusb->vendor_specific2 != 0 check from tusb1210_power_on()
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-13 13:05   ` Hans de Goede
  -1 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

Since commit eb445a15fa69 ("phy: tusb1210: use bitmasks to set
VENDOR_SPECIFIC2") tusb->vendor_specific2 always contains a valid value
so there no need to check that it is set.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/phy/ti/phy-tusb1210.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c
index bf7793afdc84..04baed24469f 100644
--- a/drivers/phy/ti/phy-tusb1210.c
+++ b/drivers/phy/ti/phy-tusb1210.c
@@ -61,11 +61,8 @@ static int tusb1210_power_on(struct phy *phy)
 	gpiod_set_value_cansleep(tusb->gpio_cs, 1);
 
 	/* Restore the optional eye diagram optimization value */
-	if (tusb->vendor_specific2)
-		return tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
-					   tusb->vendor_specific2);
-
-	return 0;
+	return tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
+				   tusb->vendor_specific2);
 }
 
 static int tusb1210_power_off(struct phy *phy)
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 7/9] phy: ti: tusb1210: Drop tusb->vendor_specific2 != 0 check from tusb1210_power_on()
@ 2022-02-13 13:05   ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

Since commit eb445a15fa69 ("phy: tusb1210: use bitmasks to set
VENDOR_SPECIFIC2") tusb->vendor_specific2 always contains a valid value
so there no need to check that it is set.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/phy/ti/phy-tusb1210.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c
index bf7793afdc84..04baed24469f 100644
--- a/drivers/phy/ti/phy-tusb1210.c
+++ b/drivers/phy/ti/phy-tusb1210.c
@@ -61,11 +61,8 @@ static int tusb1210_power_on(struct phy *phy)
 	gpiod_set_value_cansleep(tusb->gpio_cs, 1);
 
 	/* Restore the optional eye diagram optimization value */
-	if (tusb->vendor_specific2)
-		return tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
-					   tusb->vendor_specific2);
-
-	return 0;
+	return tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
+				   tusb->vendor_specific2);
 }
 
 static int tusb1210_power_off(struct phy *phy)
-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 8/9] phy: ti: tusb1210: Add a delay between power-on and restoring the phy-parameters
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-13 13:05   ` Hans de Goede
  -1 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

Now that we actually log errors on ulpi_write failures it becomes clear
that the ulpi_write() restoring the phy-parameters on power-on is failing
after a suspend/resume add a short delay after driving the cs line high
to fix this.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/phy/ti/phy-tusb1210.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c
index 04baed24469f..9ef4c5f79b75 100644
--- a/drivers/phy/ti/phy-tusb1210.c
+++ b/drivers/phy/ti/phy-tusb1210.c
@@ -8,6 +8,7 @@
  */
 #include <linux/module.h>
 #include <linux/bitfield.h>
+#include <linux/delay.h>
 #include <linux/ulpi/driver.h>
 #include <linux/ulpi/regs.h>
 #include <linux/gpio/consumer.h>
@@ -18,6 +19,8 @@
 #define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK	GENMASK(5, 4)
 #define TUSB1210_VENDOR_SPECIFIC2_DP_MASK	BIT(6)
 
+#define TUSB1210_RESET_TIME_MS				30
+
 struct tusb1210 {
 	struct ulpi *ulpi;
 	struct phy *phy;
@@ -60,6 +63,8 @@ static int tusb1210_power_on(struct phy *phy)
 	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
 	gpiod_set_value_cansleep(tusb->gpio_cs, 1);
 
+	msleep(TUSB1210_RESET_TIME_MS);
+
 	/* Restore the optional eye diagram optimization value */
 	return tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
 				   tusb->vendor_specific2);
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 8/9] phy: ti: tusb1210: Add a delay between power-on and restoring the phy-parameters
@ 2022-02-13 13:05   ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

Now that we actually log errors on ulpi_write failures it becomes clear
that the ulpi_write() restoring the phy-parameters on power-on is failing
after a suspend/resume add a short delay after driving the cs line high
to fix this.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/phy/ti/phy-tusb1210.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c
index 04baed24469f..9ef4c5f79b75 100644
--- a/drivers/phy/ti/phy-tusb1210.c
+++ b/drivers/phy/ti/phy-tusb1210.c
@@ -8,6 +8,7 @@
  */
 #include <linux/module.h>
 #include <linux/bitfield.h>
+#include <linux/delay.h>
 #include <linux/ulpi/driver.h>
 #include <linux/ulpi/regs.h>
 #include <linux/gpio/consumer.h>
@@ -18,6 +19,8 @@
 #define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK	GENMASK(5, 4)
 #define TUSB1210_VENDOR_SPECIFIC2_DP_MASK	BIT(6)
 
+#define TUSB1210_RESET_TIME_MS				30
+
 struct tusb1210 {
 	struct ulpi *ulpi;
 	struct phy *phy;
@@ -60,6 +63,8 @@ static int tusb1210_power_on(struct phy *phy)
 	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
 	gpiod_set_value_cansleep(tusb->gpio_cs, 1);
 
+	msleep(TUSB1210_RESET_TIME_MS);
+
 	/* Restore the optional eye diagram optimization value */
 	return tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
 				   tusb->vendor_specific2);
-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 9/9] phy: ti: tusb1210: Add charger detection
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-13 13:05   ` Hans de Goede
  -1 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

From: Stephan Gerhold <stephan@gerhold.net>

Some Android x86 tablets with a Bay Trail (BYT) SoC and a Crystal Cove
PMIC, which does not support charger-detection, rely on a TUSB1211
phy for charger-detection.

Add support for charger detection on TUSB1211 phy-s and export
the information about the detected charger through the standard
power_supply class interface. power_supply class charger IC drivers
like the bq24190_charger.c driver will then pick this up and set
their input_current_limit based on this.

Note the "linux,phy_charger_detect" property used to enable this is
a special kernel-internal (so not part of the dt-bindings) property
used by dwc3 platform code to indicate that the phy needs to do
charger-detection.

Changes by Hans de Goede:
- Use "linux,phy_charger_detect" property to enable charger-detect
- Switch from a linear flow to a state-machine, with retries on
  ulpi communication errors
- Use SW_CONTROL bit to disable the FSM when detection is finished
- Do a phy-reset on disconnect to work around the phy often refusing
  ulpi_read()/_write() commands after a disconnect
- Use power_supply_reg_notifier() for Vbus monitoring
- Export the detection result through a power_supply class device

Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Co-developed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
- Add an online attribute to the registered power_supply class device,
  otherwise upower thinks it is an extra system battery
- Add tusb1210_remove_charger_detect() function to properly unregister
  the tusb->psy_nb notifier and to cancel tusb->chg_det_work
---
 drivers/phy/ti/phy-tusb1210.c | 377 +++++++++++++++++++++++++++++++++-
 1 file changed, 370 insertions(+), 7 deletions(-)

diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c
index 9ef4c5f79b75..a0cdbcadf09e 100644
--- a/drivers/phy/ti/phy-tusb1210.c
+++ b/drivers/phy/ti/phy-tusb1210.c
@@ -13,20 +13,59 @@
 #include <linux/ulpi/regs.h>
 #include <linux/gpio/consumer.h>
 #include <linux/phy/ulpi_phy.h>
-
-#define TUSB1210_VENDOR_SPECIFIC2		0x80
-#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK	GENMASK(3, 0)
-#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK	GENMASK(5, 4)
-#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK	BIT(6)
-
-#define TUSB1210_RESET_TIME_MS				30
+#include <linux/power_supply.h>
+#include <linux/workqueue.h>
+
+#define TUSB1211_POWER_CONTROL				0x3d
+#define TUSB1211_POWER_CONTROL_SET			0x3e
+#define TUSB1211_POWER_CONTROL_CLEAR			0x3f
+#define TUSB1211_POWER_CONTROL_SW_CONTROL		BIT(0)
+#define TUSB1211_POWER_CONTROL_DET_COMP			BIT(1)
+#define TUSB1211_POWER_CONTROL_DP_VSRC_EN		BIT(6)
+
+#define TUSB1210_VENDOR_SPECIFIC2			0x80
+#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK		GENMASK(3, 0)
+#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK		GENMASK(5, 4)
+#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK		BIT(6)
+
+#define TUSB1211_VENDOR_SPECIFIC3			0x85
+#define TUSB1211_VENDOR_SPECIFIC3_SET			0x86
+#define TUSB1211_VENDOR_SPECIFIC3_CLEAR			0x87
+#define TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET		BIT(4)
+#define TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN	BIT(6)
+
+#define TUSB1210_RESET_TIME_MS				50
+
+#define TUSB1210_CHG_DET_MAX_RETRIES			5
+
+/* TUSB1210 charger detection work states */
+enum tusb1210_chg_det_state {
+	TUSB1210_CHG_DET_CONNECTING,
+	TUSB1210_CHG_DET_START_DET,
+	TUSB1210_CHG_DET_READ_DET,
+	TUSB1210_CHG_DET_FINISH_DET,
+	TUSB1210_CHG_DET_CONNECTED,
+	TUSB1210_CHG_DET_DISCONNECTING,
+	TUSB1210_CHG_DET_DISCONNECTING_DONE,
+	TUSB1210_CHG_DET_DISCONNECTED,
+};
 
 struct tusb1210 {
 	struct ulpi *ulpi;
 	struct phy *phy;
 	struct gpio_desc *gpio_reset;
 	struct gpio_desc *gpio_cs;
+	u8 otg_ctrl;
 	u8 vendor_specific2;
+#ifdef CONFIG_POWER_SUPPLY
+	enum power_supply_usb_type chg_type;
+	enum tusb1210_chg_det_state chg_det_state;
+	int chg_det_retries;
+	struct delayed_work chg_det_work;
+	struct notifier_block psy_nb;
+	struct power_supply *psy;
+	struct power_supply *charger;
+#endif
 };
 
 static int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val)
@@ -111,9 +150,330 @@ static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 		return 0;
 	}
 
+	tusb->otg_ctrl = reg;
 	return tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
 }
 
+#ifdef CONFIG_POWER_SUPPLY
+const char * const tusb1210_chg_det_states[] = {
+	"CHG_DET_CONNECTING",
+	"CHG_DET_START_DET",
+	"CHG_DET_READ_DET",
+	"CHG_DET_FINISH_DET",
+	"CHG_DET_CONNECTED",
+	"CHG_DET_DISCONNECTING",
+	"CHG_DET_DISCONNECTING_DONE",
+	"CHG_DET_DISCONNECTED",
+};
+
+static void tusb1210_reset(struct tusb1210 *tusb)
+{
+	gpiod_set_value_cansleep(tusb->gpio_reset, 0);
+	usleep_range(200, 500);
+	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
+}
+
+static void tusb1210_chg_det_set_type(struct tusb1210 *tusb,
+				      enum power_supply_usb_type type)
+{
+	dev_dbg(&tusb->ulpi->dev, "charger type: %d\n", type);
+	tusb->chg_type = type;
+	tusb->chg_det_retries = 0;
+	power_supply_changed(tusb->psy);
+}
+
+static void tusb1210_chg_det_set_state(struct tusb1210 *tusb,
+				       enum tusb1210_chg_det_state new_state,
+				       int delay_ms)
+{
+	if (delay_ms)
+		dev_dbg(&tusb->ulpi->dev, "chg_det new state %s in %d ms\n",
+			tusb1210_chg_det_states[new_state], delay_ms);
+
+	tusb->chg_det_state = new_state;
+	mod_delayed_work(system_long_wq, &tusb->chg_det_work,
+			 msecs_to_jiffies(delay_ms));
+}
+
+static void tusb1210_chg_det_handle_ulpi_error(struct tusb1210 *tusb)
+{
+	tusb1210_reset(tusb);
+	if (tusb->chg_det_retries < TUSB1210_CHG_DET_MAX_RETRIES) {
+		tusb->chg_det_retries++;
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET,
+					   TUSB1210_RESET_TIME_MS);
+	} else {
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET,
+					   TUSB1210_RESET_TIME_MS);
+	}
+}
+
+/*
+ * Boards using a TUSB121x for charger-detection have 3 power_supply class devs:
+ *
+ * tusb1211-charger-detect(1) -> charger -> fuel-gauge
+ *
+ * To determine if an USB charger is connected to the board, the online prop of
+ * the charger psy needs to be read. Since the tusb1211-charger-detect psy is
+ * the start of the supplier -> supplied-to chain, power_supply_am_i_supplied()
+ * cannot be used here.
+ *
+ * Instead, below is a list of the power_supply names of known chargers for
+ * these boards and the charger psy is looked up by name from this list.
+ *
+ * (1) modelling the external USB charger
+ */
+static const char * const tusb1210_chargers[] = {
+	"bq24190-charger",
+};
+
+static bool tusb1210_get_online(struct tusb1210 *tusb)
+{
+	union power_supply_propval val;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !tusb->charger; i++)
+		tusb->charger = power_supply_get_by_name(tusb1210_chargers[i]);
+
+	if (!tusb->charger)
+		return false;
+
+	if (power_supply_get_property(tusb->charger, POWER_SUPPLY_PROP_ONLINE, &val))
+		return false;
+
+	return val.intval;
+}
+
+static void tusb1210_chg_det_work(struct work_struct *work)
+{
+	struct tusb1210 *tusb = container_of(work, struct tusb1210, chg_det_work.work);
+	bool vbus_present = tusb1210_get_online(tusb);
+	int ret;
+	u8 val;
+
+	dev_dbg(&tusb->ulpi->dev, "chg_det state %s vbus_present %d\n",
+		tusb1210_chg_det_states[tusb->chg_det_state], vbus_present);
+
+	switch (tusb->chg_det_state) {
+	case TUSB1210_CHG_DET_CONNECTING:
+		tusb->chg_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+		tusb->chg_det_retries = 0;
+		/* Power on USB controller for ulpi_read()/_write() */
+		ret = pm_runtime_resume_and_get(tusb->ulpi->dev.parent);
+		if (ret < 0) {
+			dev_err(&tusb->ulpi->dev, "error %d runtime-resuming\n", ret);
+			/* Should never happen, skip charger detection */
+			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
+			return;
+		}
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET, 0);
+		break;
+	case TUSB1210_CHG_DET_START_DET:
+		/*
+		 * Use the builtin charger detection FSM to keep things simple.
+		 * This only detects DCP / SDP. This is good enough for the few
+		 * boards which actually rely on the phy for charger detection.
+		 */
+		mutex_lock(&tusb->phy->mutex);
+		ret = tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_SET,
+					  TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET);
+		mutex_unlock(&tusb->phy->mutex);
+		if (ret) {
+			tusb1210_chg_det_handle_ulpi_error(tusb);
+			break;
+		}
+
+		/* Wait 400 ms for the charger detection FSM to finish */
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_READ_DET, 400);
+		break;
+	case TUSB1210_CHG_DET_READ_DET:
+		mutex_lock(&tusb->phy->mutex);
+		ret = tusb1210_ulpi_read(tusb, TUSB1211_POWER_CONTROL, &val);
+		mutex_unlock(&tusb->phy->mutex);
+		if (ret) {
+			tusb1210_chg_det_handle_ulpi_error(tusb);
+			break;
+		}
+
+		if (val & TUSB1211_POWER_CONTROL_DET_COMP)
+			tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_DCP);
+		else
+			tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_SDP);
+
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET, 0);
+		break;
+	case TUSB1210_CHG_DET_FINISH_DET:
+		mutex_lock(&tusb->phy->mutex);
+
+		/* Set SW_CONTROL to stop the charger-det FSM */
+		ret = tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_SET,
+					  TUSB1211_POWER_CONTROL_SW_CONTROL);
+
+		/* Clear DP_VSRC_EN which may have been enabled by the charger-det FSM */
+		ret |= tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_CLEAR,
+					   TUSB1211_POWER_CONTROL_DP_VSRC_EN);
+
+		/* Clear CHGD_IDP_SRC_EN (may have been enabled by the charger-det FSM) */
+		ret |= tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_CLEAR,
+					   TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN);
+
+		/* If any of the above fails reset the phy */
+		if (ret) {
+			tusb1210_reset(tusb);
+			msleep(TUSB1210_RESET_TIME_MS);
+		}
+
+		/* Restore phy-parameters and OTG_CTRL register */
+		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, tusb->otg_ctrl);
+		tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
+				    tusb->vendor_specific2);
+
+		mutex_unlock(&tusb->phy->mutex);
+
+		pm_runtime_put(tusb->ulpi->dev.parent);
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
+		break;
+	case TUSB1210_CHG_DET_CONNECTED:
+		if (!vbus_present)
+			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING, 0);
+		break;
+	case TUSB1210_CHG_DET_DISCONNECTING:
+		/*
+		 * The phy seems to take approx. 600ms longer then the charger
+		 * chip (which is used to get vbus_present) to determine Vbus
+		 * session end. Wait 800ms to ensure the phy has detected and
+		 * signalled Vbus session end.
+		 */
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING_DONE, 800);
+		break;
+	case TUSB1210_CHG_DET_DISCONNECTING_DONE:
+		/*
+		 * The phy often stops reacting to ulpi_read()/_write requests
+		 * after a Vbus-session end. Reset it to work around this.
+		 */
+		tusb1210_reset(tusb);
+		tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_UNKNOWN);
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTED, 0);
+		break;
+	case TUSB1210_CHG_DET_DISCONNECTED:
+		if (vbus_present)
+			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTING, 0);
+		break;
+	}
+}
+
+static int tusb1210_psy_notifier(struct notifier_block *nb,
+	unsigned long event, void *ptr)
+{
+	struct tusb1210 *tusb = container_of(nb, struct tusb1210, psy_nb);
+	struct power_supply *psy = ptr;
+
+	if (psy != tusb->psy && psy->desc->type == POWER_SUPPLY_TYPE_USB)
+		queue_delayed_work(system_long_wq, &tusb->chg_det_work, 0);
+
+	return NOTIFY_OK;
+}
+
+static int tusb1210_psy_get_prop(struct power_supply *psy,
+				 enum power_supply_property psp,
+				 union power_supply_propval *val)
+{
+	struct tusb1210 *tusb = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = tusb1210_get_online(tusb);
+		break;
+	case POWER_SUPPLY_PROP_USB_TYPE:
+		val->intval = tusb->chg_type;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		if (tusb->chg_type == POWER_SUPPLY_USB_TYPE_DCP)
+			val->intval = 2000000;
+		else
+			val->intval = 500000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const enum power_supply_usb_type tusb1210_psy_usb_types[] = {
+	POWER_SUPPLY_USB_TYPE_SDP,
+	POWER_SUPPLY_USB_TYPE_DCP,
+	POWER_SUPPLY_USB_TYPE_UNKNOWN,
+};
+
+static const enum power_supply_property tusb1210_psy_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_USB_TYPE,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static const struct power_supply_desc tusb1210_psy_desc = {
+	.name = "tusb1211-charger-detect",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.usb_types = tusb1210_psy_usb_types,
+	.num_usb_types = ARRAY_SIZE(tusb1210_psy_usb_types),
+	.properties = tusb1210_psy_props,
+	.num_properties = ARRAY_SIZE(tusb1210_psy_props),
+	.get_property = tusb1210_psy_get_prop,
+};
+
+/* Setup charger detection if requested, on errors continue without chg-det */
+static void tusb1210_probe_charger_detect(struct tusb1210 *tusb)
+{
+	struct power_supply_config psy_cfg = { .drv_data = tusb };
+	struct device *dev = &tusb->ulpi->dev;
+	int ret;
+
+	if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect"))
+		return;
+
+	if (tusb->ulpi->id.product != 0x1508) {
+		dev_err(dev, "error charger detection is only supported on the TUSB1211\n");
+		return;
+	}
+
+	ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &tusb->otg_ctrl);
+	if (ret)
+		return;
+
+	tusb->psy = power_supply_register(dev, &tusb1210_psy_desc, &psy_cfg);
+	if (IS_ERR(tusb->psy))
+		return;
+
+	/*
+	 * Delay initial run by 2 seconds to allow the charger driver,
+	 * which is used to determine vbus_present, to load.
+	 */
+	tusb->chg_det_state = TUSB1210_CHG_DET_DISCONNECTED;
+	INIT_DELAYED_WORK(&tusb->chg_det_work, tusb1210_chg_det_work);
+	queue_delayed_work(system_long_wq, &tusb->chg_det_work, 2 * HZ);
+
+	tusb->psy_nb.notifier_call = tusb1210_psy_notifier;
+	power_supply_reg_notifier(&tusb->psy_nb);
+}
+
+static void tusb1210_remove_charger_detect(struct tusb1210 *tusb)
+{
+
+	if (!IS_ERR_OR_NULL(tusb->psy)) {
+		power_supply_unreg_notifier(&tusb->psy_nb);
+		cancel_delayed_work_sync(&tusb->chg_det_work);
+		power_supply_unregister(tusb->psy);
+	}
+
+	if (tusb->charger)
+		power_supply_put(tusb->charger);
+}
+#else
+static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { }
+static void tusb1210_remove_charger_detect(struct tusb1210 *tusb) { }
+#endif
+
 static const struct phy_ops phy_ops = {
 	.power_on = tusb1210_power_on,
 	.power_off = tusb1210_power_off,
@@ -174,6 +534,8 @@ static int tusb1210_probe(struct ulpi *ulpi)
 
 	tusb->vendor_specific2 = reg;
 
+	tusb1210_probe_charger_detect(tusb);
+
 	tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
 	if (IS_ERR(tusb->phy))
 		return PTR_ERR(tusb->phy);
@@ -188,6 +550,7 @@ static void tusb1210_remove(struct ulpi *ulpi)
 	struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
 
 	ulpi_phy_destroy(ulpi, tusb->phy);
+	tusb1210_remove_charger_detect(tusb);
 }
 
 #define TI_VENDOR_ID 0x0451
-- 
2.33.1


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH v2 9/9] phy: ti: tusb1210: Add charger detection
@ 2022-02-13 13:05   ` Hans de Goede
  0 siblings, 0 replies; 24+ messages in thread
From: Hans de Goede @ 2022-02-13 13:05 UTC (permalink / raw)
  To: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I, Vinod Koul
  Cc: Hans de Goede, Stephan Gerhold, linux-usb, linux-phy

From: Stephan Gerhold <stephan@gerhold.net>

Some Android x86 tablets with a Bay Trail (BYT) SoC and a Crystal Cove
PMIC, which does not support charger-detection, rely on a TUSB1211
phy for charger-detection.

Add support for charger detection on TUSB1211 phy-s and export
the information about the detected charger through the standard
power_supply class interface. power_supply class charger IC drivers
like the bq24190_charger.c driver will then pick this up and set
their input_current_limit based on this.

Note the "linux,phy_charger_detect" property used to enable this is
a special kernel-internal (so not part of the dt-bindings) property
used by dwc3 platform code to indicate that the phy needs to do
charger-detection.

Changes by Hans de Goede:
- Use "linux,phy_charger_detect" property to enable charger-detect
- Switch from a linear flow to a state-machine, with retries on
  ulpi communication errors
- Use SW_CONTROL bit to disable the FSM when detection is finished
- Do a phy-reset on disconnect to work around the phy often refusing
  ulpi_read()/_write() commands after a disconnect
- Use power_supply_reg_notifier() for Vbus monitoring
- Export the detection result through a power_supply class device

Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
Co-developed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
- Add an online attribute to the registered power_supply class device,
  otherwise upower thinks it is an extra system battery
- Add tusb1210_remove_charger_detect() function to properly unregister
  the tusb->psy_nb notifier and to cancel tusb->chg_det_work
---
 drivers/phy/ti/phy-tusb1210.c | 377 +++++++++++++++++++++++++++++++++-
 1 file changed, 370 insertions(+), 7 deletions(-)

diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c
index 9ef4c5f79b75..a0cdbcadf09e 100644
--- a/drivers/phy/ti/phy-tusb1210.c
+++ b/drivers/phy/ti/phy-tusb1210.c
@@ -13,20 +13,59 @@
 #include <linux/ulpi/regs.h>
 #include <linux/gpio/consumer.h>
 #include <linux/phy/ulpi_phy.h>
-
-#define TUSB1210_VENDOR_SPECIFIC2		0x80
-#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK	GENMASK(3, 0)
-#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK	GENMASK(5, 4)
-#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK	BIT(6)
-
-#define TUSB1210_RESET_TIME_MS				30
+#include <linux/power_supply.h>
+#include <linux/workqueue.h>
+
+#define TUSB1211_POWER_CONTROL				0x3d
+#define TUSB1211_POWER_CONTROL_SET			0x3e
+#define TUSB1211_POWER_CONTROL_CLEAR			0x3f
+#define TUSB1211_POWER_CONTROL_SW_CONTROL		BIT(0)
+#define TUSB1211_POWER_CONTROL_DET_COMP			BIT(1)
+#define TUSB1211_POWER_CONTROL_DP_VSRC_EN		BIT(6)
+
+#define TUSB1210_VENDOR_SPECIFIC2			0x80
+#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK		GENMASK(3, 0)
+#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK		GENMASK(5, 4)
+#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK		BIT(6)
+
+#define TUSB1211_VENDOR_SPECIFIC3			0x85
+#define TUSB1211_VENDOR_SPECIFIC3_SET			0x86
+#define TUSB1211_VENDOR_SPECIFIC3_CLEAR			0x87
+#define TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET		BIT(4)
+#define TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN	BIT(6)
+
+#define TUSB1210_RESET_TIME_MS				50
+
+#define TUSB1210_CHG_DET_MAX_RETRIES			5
+
+/* TUSB1210 charger detection work states */
+enum tusb1210_chg_det_state {
+	TUSB1210_CHG_DET_CONNECTING,
+	TUSB1210_CHG_DET_START_DET,
+	TUSB1210_CHG_DET_READ_DET,
+	TUSB1210_CHG_DET_FINISH_DET,
+	TUSB1210_CHG_DET_CONNECTED,
+	TUSB1210_CHG_DET_DISCONNECTING,
+	TUSB1210_CHG_DET_DISCONNECTING_DONE,
+	TUSB1210_CHG_DET_DISCONNECTED,
+};
 
 struct tusb1210 {
 	struct ulpi *ulpi;
 	struct phy *phy;
 	struct gpio_desc *gpio_reset;
 	struct gpio_desc *gpio_cs;
+	u8 otg_ctrl;
 	u8 vendor_specific2;
+#ifdef CONFIG_POWER_SUPPLY
+	enum power_supply_usb_type chg_type;
+	enum tusb1210_chg_det_state chg_det_state;
+	int chg_det_retries;
+	struct delayed_work chg_det_work;
+	struct notifier_block psy_nb;
+	struct power_supply *psy;
+	struct power_supply *charger;
+#endif
 };
 
 static int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val)
@@ -111,9 +150,330 @@ static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode, int submode)
 		return 0;
 	}
 
+	tusb->otg_ctrl = reg;
 	return tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
 }
 
+#ifdef CONFIG_POWER_SUPPLY
+const char * const tusb1210_chg_det_states[] = {
+	"CHG_DET_CONNECTING",
+	"CHG_DET_START_DET",
+	"CHG_DET_READ_DET",
+	"CHG_DET_FINISH_DET",
+	"CHG_DET_CONNECTED",
+	"CHG_DET_DISCONNECTING",
+	"CHG_DET_DISCONNECTING_DONE",
+	"CHG_DET_DISCONNECTED",
+};
+
+static void tusb1210_reset(struct tusb1210 *tusb)
+{
+	gpiod_set_value_cansleep(tusb->gpio_reset, 0);
+	usleep_range(200, 500);
+	gpiod_set_value_cansleep(tusb->gpio_reset, 1);
+}
+
+static void tusb1210_chg_det_set_type(struct tusb1210 *tusb,
+				      enum power_supply_usb_type type)
+{
+	dev_dbg(&tusb->ulpi->dev, "charger type: %d\n", type);
+	tusb->chg_type = type;
+	tusb->chg_det_retries = 0;
+	power_supply_changed(tusb->psy);
+}
+
+static void tusb1210_chg_det_set_state(struct tusb1210 *tusb,
+				       enum tusb1210_chg_det_state new_state,
+				       int delay_ms)
+{
+	if (delay_ms)
+		dev_dbg(&tusb->ulpi->dev, "chg_det new state %s in %d ms\n",
+			tusb1210_chg_det_states[new_state], delay_ms);
+
+	tusb->chg_det_state = new_state;
+	mod_delayed_work(system_long_wq, &tusb->chg_det_work,
+			 msecs_to_jiffies(delay_ms));
+}
+
+static void tusb1210_chg_det_handle_ulpi_error(struct tusb1210 *tusb)
+{
+	tusb1210_reset(tusb);
+	if (tusb->chg_det_retries < TUSB1210_CHG_DET_MAX_RETRIES) {
+		tusb->chg_det_retries++;
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET,
+					   TUSB1210_RESET_TIME_MS);
+	} else {
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET,
+					   TUSB1210_RESET_TIME_MS);
+	}
+}
+
+/*
+ * Boards using a TUSB121x for charger-detection have 3 power_supply class devs:
+ *
+ * tusb1211-charger-detect(1) -> charger -> fuel-gauge
+ *
+ * To determine if an USB charger is connected to the board, the online prop of
+ * the charger psy needs to be read. Since the tusb1211-charger-detect psy is
+ * the start of the supplier -> supplied-to chain, power_supply_am_i_supplied()
+ * cannot be used here.
+ *
+ * Instead, below is a list of the power_supply names of known chargers for
+ * these boards and the charger psy is looked up by name from this list.
+ *
+ * (1) modelling the external USB charger
+ */
+static const char * const tusb1210_chargers[] = {
+	"bq24190-charger",
+};
+
+static bool tusb1210_get_online(struct tusb1210 *tusb)
+{
+	union power_supply_propval val;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !tusb->charger; i++)
+		tusb->charger = power_supply_get_by_name(tusb1210_chargers[i]);
+
+	if (!tusb->charger)
+		return false;
+
+	if (power_supply_get_property(tusb->charger, POWER_SUPPLY_PROP_ONLINE, &val))
+		return false;
+
+	return val.intval;
+}
+
+static void tusb1210_chg_det_work(struct work_struct *work)
+{
+	struct tusb1210 *tusb = container_of(work, struct tusb1210, chg_det_work.work);
+	bool vbus_present = tusb1210_get_online(tusb);
+	int ret;
+	u8 val;
+
+	dev_dbg(&tusb->ulpi->dev, "chg_det state %s vbus_present %d\n",
+		tusb1210_chg_det_states[tusb->chg_det_state], vbus_present);
+
+	switch (tusb->chg_det_state) {
+	case TUSB1210_CHG_DET_CONNECTING:
+		tusb->chg_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+		tusb->chg_det_retries = 0;
+		/* Power on USB controller for ulpi_read()/_write() */
+		ret = pm_runtime_resume_and_get(tusb->ulpi->dev.parent);
+		if (ret < 0) {
+			dev_err(&tusb->ulpi->dev, "error %d runtime-resuming\n", ret);
+			/* Should never happen, skip charger detection */
+			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
+			return;
+		}
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET, 0);
+		break;
+	case TUSB1210_CHG_DET_START_DET:
+		/*
+		 * Use the builtin charger detection FSM to keep things simple.
+		 * This only detects DCP / SDP. This is good enough for the few
+		 * boards which actually rely on the phy for charger detection.
+		 */
+		mutex_lock(&tusb->phy->mutex);
+		ret = tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_SET,
+					  TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET);
+		mutex_unlock(&tusb->phy->mutex);
+		if (ret) {
+			tusb1210_chg_det_handle_ulpi_error(tusb);
+			break;
+		}
+
+		/* Wait 400 ms for the charger detection FSM to finish */
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_READ_DET, 400);
+		break;
+	case TUSB1210_CHG_DET_READ_DET:
+		mutex_lock(&tusb->phy->mutex);
+		ret = tusb1210_ulpi_read(tusb, TUSB1211_POWER_CONTROL, &val);
+		mutex_unlock(&tusb->phy->mutex);
+		if (ret) {
+			tusb1210_chg_det_handle_ulpi_error(tusb);
+			break;
+		}
+
+		if (val & TUSB1211_POWER_CONTROL_DET_COMP)
+			tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_DCP);
+		else
+			tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_SDP);
+
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET, 0);
+		break;
+	case TUSB1210_CHG_DET_FINISH_DET:
+		mutex_lock(&tusb->phy->mutex);
+
+		/* Set SW_CONTROL to stop the charger-det FSM */
+		ret = tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_SET,
+					  TUSB1211_POWER_CONTROL_SW_CONTROL);
+
+		/* Clear DP_VSRC_EN which may have been enabled by the charger-det FSM */
+		ret |= tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_CLEAR,
+					   TUSB1211_POWER_CONTROL_DP_VSRC_EN);
+
+		/* Clear CHGD_IDP_SRC_EN (may have been enabled by the charger-det FSM) */
+		ret |= tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_CLEAR,
+					   TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN);
+
+		/* If any of the above fails reset the phy */
+		if (ret) {
+			tusb1210_reset(tusb);
+			msleep(TUSB1210_RESET_TIME_MS);
+		}
+
+		/* Restore phy-parameters and OTG_CTRL register */
+		tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, tusb->otg_ctrl);
+		tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
+				    tusb->vendor_specific2);
+
+		mutex_unlock(&tusb->phy->mutex);
+
+		pm_runtime_put(tusb->ulpi->dev.parent);
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
+		break;
+	case TUSB1210_CHG_DET_CONNECTED:
+		if (!vbus_present)
+			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING, 0);
+		break;
+	case TUSB1210_CHG_DET_DISCONNECTING:
+		/*
+		 * The phy seems to take approx. 600ms longer then the charger
+		 * chip (which is used to get vbus_present) to determine Vbus
+		 * session end. Wait 800ms to ensure the phy has detected and
+		 * signalled Vbus session end.
+		 */
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING_DONE, 800);
+		break;
+	case TUSB1210_CHG_DET_DISCONNECTING_DONE:
+		/*
+		 * The phy often stops reacting to ulpi_read()/_write requests
+		 * after a Vbus-session end. Reset it to work around this.
+		 */
+		tusb1210_reset(tusb);
+		tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_UNKNOWN);
+		tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTED, 0);
+		break;
+	case TUSB1210_CHG_DET_DISCONNECTED:
+		if (vbus_present)
+			tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTING, 0);
+		break;
+	}
+}
+
+static int tusb1210_psy_notifier(struct notifier_block *nb,
+	unsigned long event, void *ptr)
+{
+	struct tusb1210 *tusb = container_of(nb, struct tusb1210, psy_nb);
+	struct power_supply *psy = ptr;
+
+	if (psy != tusb->psy && psy->desc->type == POWER_SUPPLY_TYPE_USB)
+		queue_delayed_work(system_long_wq, &tusb->chg_det_work, 0);
+
+	return NOTIFY_OK;
+}
+
+static int tusb1210_psy_get_prop(struct power_supply *psy,
+				 enum power_supply_property psp,
+				 union power_supply_propval *val)
+{
+	struct tusb1210 *tusb = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = tusb1210_get_online(tusb);
+		break;
+	case POWER_SUPPLY_PROP_USB_TYPE:
+		val->intval = tusb->chg_type;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		if (tusb->chg_type == POWER_SUPPLY_USB_TYPE_DCP)
+			val->intval = 2000000;
+		else
+			val->intval = 500000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const enum power_supply_usb_type tusb1210_psy_usb_types[] = {
+	POWER_SUPPLY_USB_TYPE_SDP,
+	POWER_SUPPLY_USB_TYPE_DCP,
+	POWER_SUPPLY_USB_TYPE_UNKNOWN,
+};
+
+static const enum power_supply_property tusb1210_psy_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_USB_TYPE,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+};
+
+static const struct power_supply_desc tusb1210_psy_desc = {
+	.name = "tusb1211-charger-detect",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.usb_types = tusb1210_psy_usb_types,
+	.num_usb_types = ARRAY_SIZE(tusb1210_psy_usb_types),
+	.properties = tusb1210_psy_props,
+	.num_properties = ARRAY_SIZE(tusb1210_psy_props),
+	.get_property = tusb1210_psy_get_prop,
+};
+
+/* Setup charger detection if requested, on errors continue without chg-det */
+static void tusb1210_probe_charger_detect(struct tusb1210 *tusb)
+{
+	struct power_supply_config psy_cfg = { .drv_data = tusb };
+	struct device *dev = &tusb->ulpi->dev;
+	int ret;
+
+	if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect"))
+		return;
+
+	if (tusb->ulpi->id.product != 0x1508) {
+		dev_err(dev, "error charger detection is only supported on the TUSB1211\n");
+		return;
+	}
+
+	ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &tusb->otg_ctrl);
+	if (ret)
+		return;
+
+	tusb->psy = power_supply_register(dev, &tusb1210_psy_desc, &psy_cfg);
+	if (IS_ERR(tusb->psy))
+		return;
+
+	/*
+	 * Delay initial run by 2 seconds to allow the charger driver,
+	 * which is used to determine vbus_present, to load.
+	 */
+	tusb->chg_det_state = TUSB1210_CHG_DET_DISCONNECTED;
+	INIT_DELAYED_WORK(&tusb->chg_det_work, tusb1210_chg_det_work);
+	queue_delayed_work(system_long_wq, &tusb->chg_det_work, 2 * HZ);
+
+	tusb->psy_nb.notifier_call = tusb1210_psy_notifier;
+	power_supply_reg_notifier(&tusb->psy_nb);
+}
+
+static void tusb1210_remove_charger_detect(struct tusb1210 *tusb)
+{
+
+	if (!IS_ERR_OR_NULL(tusb->psy)) {
+		power_supply_unreg_notifier(&tusb->psy_nb);
+		cancel_delayed_work_sync(&tusb->chg_det_work);
+		power_supply_unregister(tusb->psy);
+	}
+
+	if (tusb->charger)
+		power_supply_put(tusb->charger);
+}
+#else
+static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { }
+static void tusb1210_remove_charger_detect(struct tusb1210 *tusb) { }
+#endif
+
 static const struct phy_ops phy_ops = {
 	.power_on = tusb1210_power_on,
 	.power_off = tusb1210_power_off,
@@ -174,6 +534,8 @@ static int tusb1210_probe(struct ulpi *ulpi)
 
 	tusb->vendor_specific2 = reg;
 
+	tusb1210_probe_charger_detect(tusb);
+
 	tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
 	if (IS_ERR(tusb->phy))
 		return PTR_ERR(tusb->phy);
@@ -188,6 +550,7 @@ static void tusb1210_remove(struct ulpi *ulpi)
 	struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
 
 	ulpi_phy_destroy(ulpi, tusb->phy);
+	tusb1210_remove_charger_detect(tusb);
 }
 
 #define TI_VENDOR_ID 0x0451
-- 
2.33.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 0/9] usb/dwc3 / phy/tusb1210: Add TUSB1211 charger detection
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-17 15:31   ` Greg Kroah-Hartman
  -1 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2022-02-17 15:31 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Felipe Balbi, Kishon Vijay Abraham I, Vinod Koul,
	Stephan Gerhold, linux-usb, linux-phy

On Sun, Feb 13, 2022 at 02:05:15PM +0100, Hans de Goede wrote:
> Hi All,
> 
> Here is v2 of the patchs-series to add support for USB charger-type
> (SDP/DCP) detection using a tusb1210 phy connected to a dwc3 controller.
> 
> Changes in v2:
> [PATCH v2 9/9] phy: ti: tusb1210: Add charger detection:
> - Add an online attribute to the registered power_supply class device,
>   otherwise upower thinks it is an extra system battery
> - Add tusb1210_remove_charger_detect() function to properly unregister
>   the tusb->psy_nb notifier and to cancel tusb->chg_det_work
> 
> v1 cover-letter:
> 
> Some Android x86 tablets with a Bay Trail (BYT) SoC (with DWC3 UDC)
> and a Crystal Cove PMIC, which does not support charger-detection,
> rely on a TUSB1211 phy for charger-detection.
> 
> This series adds support for this, it starts with some dwc3 bug-fixes
> for issues hit while developing this, as well as adding support to
> the dwc3 code to set a special property checked by the tusb1210 driver
> to signal that it needs to enable charger-detection.
> 
> The 2nd half of the series does some refactoring / fixes to the
> tusb1210 driver and adds the charger-detection support.

The first 4 are all in my usb trees now, thanks.

greg k-h

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 0/9] usb/dwc3 / phy/tusb1210: Add TUSB1211 charger detection
@ 2022-02-17 15:31   ` Greg Kroah-Hartman
  0 siblings, 0 replies; 24+ messages in thread
From: Greg Kroah-Hartman @ 2022-02-17 15:31 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Felipe Balbi, Kishon Vijay Abraham I, Vinod Koul,
	Stephan Gerhold, linux-usb, linux-phy

On Sun, Feb 13, 2022 at 02:05:15PM +0100, Hans de Goede wrote:
> Hi All,
> 
> Here is v2 of the patchs-series to add support for USB charger-type
> (SDP/DCP) detection using a tusb1210 phy connected to a dwc3 controller.
> 
> Changes in v2:
> [PATCH v2 9/9] phy: ti: tusb1210: Add charger detection:
> - Add an online attribute to the registered power_supply class device,
>   otherwise upower thinks it is an extra system battery
> - Add tusb1210_remove_charger_detect() function to properly unregister
>   the tusb->psy_nb notifier and to cancel tusb->chg_det_work
> 
> v1 cover-letter:
> 
> Some Android x86 tablets with a Bay Trail (BYT) SoC (with DWC3 UDC)
> and a Crystal Cove PMIC, which does not support charger-detection,
> rely on a TUSB1211 phy for charger-detection.
> 
> This series adds support for this, it starts with some dwc3 bug-fixes
> for issues hit while developing this, as well as adding support to
> the dwc3 code to set a special property checked by the tusb1210 driver
> to signal that it needs to enable charger-detection.
> 
> The 2nd half of the series does some refactoring / fixes to the
> tusb1210 driver and adds the charger-detection support.

The first 4 are all in my usb trees now, thanks.

greg k-h

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 0/9] usb/dwc3 / phy/tusb1210: Add TUSB1211 charger detection
  2022-02-13 13:05 ` Hans de Goede
@ 2022-02-25  8:58   ` Vinod Koul
  -1 siblings, 0 replies; 24+ messages in thread
From: Vinod Koul @ 2022-02-25  8:58 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I,
	Stephan Gerhold, linux-usb, linux-phy

On 13-02-22, 14:05, Hans de Goede wrote:
> Hi All,
> 
> Here is v2 of the patchs-series to add support for USB charger-type
> (SDP/DCP) detection using a tusb1210 phy connected to a dwc3 controller.
> 
> Changes in v2:
> [PATCH v2 9/9] phy: ti: tusb1210: Add charger detection:
> - Add an online attribute to the registered power_supply class device,
>   otherwise upower thinks it is an extra system battery
> - Add tusb1210_remove_charger_detect() function to properly unregister
>   the tusb->psy_nb notifier and to cancel tusb->chg_det_work
> 
> v1 cover-letter:
> 
> Some Android x86 tablets with a Bay Trail (BYT) SoC (with DWC3 UDC)
> and a Crystal Cove PMIC, which does not support charger-detection,
> rely on a TUSB1211 phy for charger-detection.
> 
> This series adds support for this, it starts with some dwc3 bug-fixes
> for issues hit while developing this, as well as adding support to
> the dwc3 code to set a special property checked by the tusb1210 driver
> to signal that it needs to enable charger-detection.
> 
> The 2nd half of the series does some refactoring / fixes to the
> tusb1210 driver and adds the charger-detection support.

Applied phy patches to phy-next, thanks

-- 
~Vinod

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH v2 0/9] usb/dwc3 / phy/tusb1210: Add TUSB1211 charger detection
@ 2022-02-25  8:58   ` Vinod Koul
  0 siblings, 0 replies; 24+ messages in thread
From: Vinod Koul @ 2022-02-25  8:58 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Felipe Balbi, Greg Kroah-Hartman, Kishon Vijay Abraham I,
	Stephan Gerhold, linux-usb, linux-phy

On 13-02-22, 14:05, Hans de Goede wrote:
> Hi All,
> 
> Here is v2 of the patchs-series to add support for USB charger-type
> (SDP/DCP) detection using a tusb1210 phy connected to a dwc3 controller.
> 
> Changes in v2:
> [PATCH v2 9/9] phy: ti: tusb1210: Add charger detection:
> - Add an online attribute to the registered power_supply class device,
>   otherwise upower thinks it is an extra system battery
> - Add tusb1210_remove_charger_detect() function to properly unregister
>   the tusb->psy_nb notifier and to cancel tusb->chg_det_work
> 
> v1 cover-letter:
> 
> Some Android x86 tablets with a Bay Trail (BYT) SoC (with DWC3 UDC)
> and a Crystal Cove PMIC, which does not support charger-detection,
> rely on a TUSB1211 phy for charger-detection.
> 
> This series adds support for this, it starts with some dwc3 bug-fixes
> for issues hit while developing this, as well as adding support to
> the dwc3 code to set a special property checked by the tusb1210 driver
> to signal that it needs to enable charger-detection.
> 
> The 2nd half of the series does some refactoring / fixes to the
> tusb1210 driver and adds the charger-detection support.

Applied phy patches to phy-next, thanks

-- 
~Vinod

-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2022-02-25  8:58 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-13 13:05 [PATCH v2 0/9] usb/dwc3 / phy/tusb1210: Add TUSB1211 charger detection Hans de Goede
2022-02-13 13:05 ` Hans de Goede
2022-02-13 13:05 ` [PATCH v2 1/9] usb: dwc3: pci: Add "snps,dis_u2_susphy_quirk" for Intel Bay Trail Hans de Goede
2022-02-13 13:05   ` [PATCH v2 1/9] usb: dwc3: pci: Add "snps, dis_u2_susphy_quirk" " Hans de Goede
2022-02-13 13:05 ` [PATCH v2 2/9] usb: dwc3: pci: Fix Bay Trail phy GPIO mappings Hans de Goede
2022-02-13 13:05   ` Hans de Goede
2022-02-13 13:05 ` [PATCH v2 3/9] usb: dwc3: pci: Set the swnode from inside dwc3_pci_quirks() Hans de Goede
2022-02-13 13:05   ` Hans de Goede
2022-02-13 13:05 ` [PATCH v2 4/9] usb: dwc3: pci: Set "linux,phy_charger_detect" property on some Bay Trail boards Hans de Goede
2022-02-13 13:05   ` [PATCH v2 4/9] usb: dwc3: pci: Set "linux, phy_charger_detect" " Hans de Goede
2022-02-13 13:05 ` [PATCH v2 5/9] usb: dwc3: pci: Also apply Bay Trail GPIO mappings to ulpi-device Hans de Goede
2022-02-13 13:05   ` Hans de Goede
2022-02-13 13:05 ` [PATCH v2 6/9] phy: ti: tusb1210: Improve ulpi_read()/_write() error checking Hans de Goede
2022-02-13 13:05   ` Hans de Goede
2022-02-13 13:05 ` [PATCH v2 7/9] phy: ti: tusb1210: Drop tusb->vendor_specific2 != 0 check from tusb1210_power_on() Hans de Goede
2022-02-13 13:05   ` Hans de Goede
2022-02-13 13:05 ` [PATCH v2 8/9] phy: ti: tusb1210: Add a delay between power-on and restoring the phy-parameters Hans de Goede
2022-02-13 13:05   ` Hans de Goede
2022-02-13 13:05 ` [PATCH v2 9/9] phy: ti: tusb1210: Add charger detection Hans de Goede
2022-02-13 13:05   ` Hans de Goede
2022-02-17 15:31 ` [PATCH v2 0/9] usb/dwc3 / phy/tusb1210: Add TUSB1211 " Greg Kroah-Hartman
2022-02-17 15:31   ` Greg Kroah-Hartman
2022-02-25  8:58 ` Vinod Koul
2022-02-25  8:58   ` Vinod Koul

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.