All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] USB PHY driver for Broadcom's Cygnus chipset
@ 2015-04-22 23:14 ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Arun Ramamurthy

This patchset adds the USB phy driver and documentation 
for Broadom's Cygnus chipset. The phy is configurable from device tree
and is capable of both device and host functions. It also provides
a clock and reset to the host controller

History:
v1:
    - Included Dmitry Torokhov's patch that addresed Kishon Vijay Abraham's 
    comments on multiple phy model
    - Inlucded Dmitry Torokhov's patch to use phy regulator
    - Addressed Arnd Bergmann's comments on usage of this phy driver by
    ehci-platform and ohci-platform driver in a separate patchset. 
v2:
    - Addressed Kishon's comments on documentation and function names
    - Dmitry Addressed Kishon's comments on per port phy regulators
v3:
    - Addressed Kishon's comments on error code in phy driver and multi level
    if else statements
    - Corrected documentation to use defines for constants
    - Corrected commit log for phy regulator patch

Arun Ramamurthy (3):
  phy: phy-core: allow specifying supply at port level
  Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
  phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver

 .../bindings/phy/brcm,cygnus-usb-phy.txt           |  69 +++
 drivers/phy/Kconfig                                |  12 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-bcm-cygnus-usb.c                   | 504 +++++++++++++++++++++
 drivers/phy/phy-core.c                             |  23 +-
 include/dt-bindings/phy/phy.h                      |   2 +
 6 files changed, 598 insertions(+), 13 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
 create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c

-- 
2.3.4


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

* [PATCH v3 0/3] USB PHY driver for Broadcom's Cygnus chipset
@ 2015-04-22 23:14 ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Arun Ramamurthy

This patchset adds the USB phy driver and documentation 
for Broadom's Cygnus chipset. The phy is configurable from device tree
and is capable of both device and host functions. It also provides
a clock and reset to the host controller

History:
v1:
    - Included Dmitry Torokhov's patch that addresed Kishon Vijay Abraham's 
    comments on multiple phy model
    - Inlucded Dmitry Torokhov's patch to use phy regulator
    - Addressed Arnd Bergmann's comments on usage of this phy driver by
    ehci-platform and ohci-platform driver in a separate patchset. 
v2:
    - Addressed Kishon's comments on documentation and function names
    - Dmitry Addressed Kishon's comments on per port phy regulators
v3:
    - Addressed Kishon's comments on error code in phy driver and multi level
    if else statements
    - Corrected documentation to use defines for constants
    - Corrected commit log for phy regulator patch

Arun Ramamurthy (3):
  phy: phy-core: allow specifying supply at port level
  Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
  phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver

 .../bindings/phy/brcm,cygnus-usb-phy.txt           |  69 +++
 drivers/phy/Kconfig                                |  12 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-bcm-cygnus-usb.c                   | 504 +++++++++++++++++++++
 drivers/phy/phy-core.c                             |  23 +-
 include/dt-bindings/phy/phy.h                      |   2 +
 6 files changed, 598 insertions(+), 13 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
 create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c

-- 
2.3.4

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

* [PATCH v3 0/3] USB PHY driver for Broadcom's Cygnus chipset
@ 2015-04-22 23:14 ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Arun Ramamurthy

This patchset adds the USB phy driver and documentation 
for Broadom's Cygnus chipset. The phy is configurable from device tree
and is capable of both device and host functions. It also provides
a clock and reset to the host controller

History:
v1:
    - Included Dmitry Torokhov's patch that addresed Kishon Vijay Abraham's 
    comments on multiple phy model
    - Inlucded Dmitry Torokhov's patch to use phy regulator
    - Addressed Arnd Bergmann's comments on usage of this phy driver by
    ehci-platform and ohci-platform driver in a separate patchset. 
v2:
    - Addressed Kishon's comments on documentation and function names
    - Dmitry Addressed Kishon's comments on per port phy regulators
v3:
    - Addressed Kishon's comments on error code in phy driver and multi level
    if else statements
    - Corrected documentation to use defines for constants
    - Corrected commit log for phy regulator patch

Arun Ramamurthy (3):
  phy: phy-core: allow specifying supply at port level
  Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
  phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver

 .../bindings/phy/brcm,cygnus-usb-phy.txt           |  69 +++
 drivers/phy/Kconfig                                |  12 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-bcm-cygnus-usb.c                   | 504 +++++++++++++++++++++
 drivers/phy/phy-core.c                             |  23 +-
 include/dt-bindings/phy/phy.h                      |   2 +
 6 files changed, 598 insertions(+), 13 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
 create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c

-- 
2.3.4


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

* [PATCH v3 1/3] phy: phy-core: allow specifying supply at port level
  2015-04-22 23:14 ` Arun Ramamurthy
  (?)
@ 2015-04-22 23:14   ` Arun Ramamurthy
  -1 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Dmitry Torokhov, Arun Ramamurthy

From: Dmitry Torokhov <dtor@chromium.org>

Multi-port phys may have per port power supplies. Let's change phy
core to look for supply at the port level when multiple ports are
specified. To keep compatibility with the existing device tree board
descriptions for single-port phys we will continue looking up the
power supply at the parent node level

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 drivers/phy/phy-core.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 3791838..c7aa297 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -651,16 +651,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
 		goto free_phy;
 	}
 
-	/* phy-supply */
-	phy->pwr = regulator_get_optional(dev, "phy");
-	if (IS_ERR(phy->pwr)) {
-		if (PTR_ERR(phy->pwr) == -EPROBE_DEFER) {
-			ret = -EPROBE_DEFER;
-			goto free_ida;
-		}
-		phy->pwr = NULL;
-	}
-
 	device_initialize(&phy->dev);
 	mutex_init(&phy->mutex);
 
@@ -674,6 +664,16 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
 	if (ret)
 		goto put_dev;
 
+	/* phy-supply */
+	phy->pwr = regulator_get_optional(&phy->dev, "phy");
+	if (IS_ERR(phy->pwr)) {
+		ret = PTR_ERR(phy->pwr);
+		if (ret == -EPROBE_DEFER)
+			goto put_dev;
+
+		phy->pwr = NULL;
+	}
+
 	ret = device_add(&phy->dev);
 	if (ret)
 		goto put_dev;
@@ -689,9 +689,6 @@ put_dev:
 	put_device(&phy->dev);  /* calls phy_release() which frees resources */
 	return ERR_PTR(ret);
 
-free_ida:
-	ida_simple_remove(&phy_ida, phy->id);
-
 free_phy:
 	kfree(phy);
 	return ERR_PTR(ret);
-- 
2.3.4


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

* [PATCH v3 1/3] phy: phy-core: allow specifying supply at port level
@ 2015-04-22 23:14   ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Dmitry Torokhov, Arun Ramamurthy

From: Dmitry Torokhov <dtor@chromium.org>

Multi-port phys may have per port power supplies. Let's change phy
core to look for supply at the port level when multiple ports are
specified. To keep compatibility with the existing device tree board
descriptions for single-port phys we will continue looking up the
power supply at the parent node level

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 drivers/phy/phy-core.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 3791838..c7aa297 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -651,16 +651,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
 		goto free_phy;
 	}
 
-	/* phy-supply */
-	phy->pwr = regulator_get_optional(dev, "phy");
-	if (IS_ERR(phy->pwr)) {
-		if (PTR_ERR(phy->pwr) == -EPROBE_DEFER) {
-			ret = -EPROBE_DEFER;
-			goto free_ida;
-		}
-		phy->pwr = NULL;
-	}
-
 	device_initialize(&phy->dev);
 	mutex_init(&phy->mutex);
 
@@ -674,6 +664,16 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
 	if (ret)
 		goto put_dev;
 
+	/* phy-supply */
+	phy->pwr = regulator_get_optional(&phy->dev, "phy");
+	if (IS_ERR(phy->pwr)) {
+		ret = PTR_ERR(phy->pwr);
+		if (ret == -EPROBE_DEFER)
+			goto put_dev;
+
+		phy->pwr = NULL;
+	}
+
 	ret = device_add(&phy->dev);
 	if (ret)
 		goto put_dev;
@@ -689,9 +689,6 @@ put_dev:
 	put_device(&phy->dev);  /* calls phy_release() which frees resources */
 	return ERR_PTR(ret);
 
-free_ida:
-	ida_simple_remove(&phy_ida, phy->id);
-
 free_phy:
 	kfree(phy);
 	return ERR_PTR(ret);
-- 
2.3.4

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

* [PATCH v3 1/3] phy: phy-core: allow specifying supply at port level
@ 2015-04-22 23:14   ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Dmitry Torokhov, Arun Ramamurthy

From: Dmitry Torokhov <dtor@chromium.org>

Multi-port phys may have per port power supplies. Let's change phy
core to look for supply at the port level when multiple ports are
specified. To keep compatibility with the existing device tree board
descriptions for single-port phys we will continue looking up the
power supply at the parent node level

Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 drivers/phy/phy-core.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 3791838..c7aa297 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -651,16 +651,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
 		goto free_phy;
 	}
 
-	/* phy-supply */
-	phy->pwr = regulator_get_optional(dev, "phy");
-	if (IS_ERR(phy->pwr)) {
-		if (PTR_ERR(phy->pwr) = -EPROBE_DEFER) {
-			ret = -EPROBE_DEFER;
-			goto free_ida;
-		}
-		phy->pwr = NULL;
-	}
-
 	device_initialize(&phy->dev);
 	mutex_init(&phy->mutex);
 
@@ -674,6 +664,16 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
 	if (ret)
 		goto put_dev;
 
+	/* phy-supply */
+	phy->pwr = regulator_get_optional(&phy->dev, "phy");
+	if (IS_ERR(phy->pwr)) {
+		ret = PTR_ERR(phy->pwr);
+		if (ret = -EPROBE_DEFER)
+			goto put_dev;
+
+		phy->pwr = NULL;
+	}
+
 	ret = device_add(&phy->dev);
 	if (ret)
 		goto put_dev;
@@ -689,9 +689,6 @@ put_dev:
 	put_device(&phy->dev);  /* calls phy_release() which frees resources */
 	return ERR_PTR(ret);
 
-free_ida:
-	ida_simple_remove(&phy_ida, phy->id);
-
 free_phy:
 	kfree(phy);
 	return ERR_PTR(ret);
-- 
2.3.4


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

* [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-04-22 23:14   ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Arun Ramamurthy

Broadcom's Cygnus chip has a USB 2.0 host controller connected to
three separate phys. One of the phs (port 2) is also connectd to
a usb 2.0 device controller

Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69 ++++++++++++++++++++++
 include/dt-bindings/phy/phy.h                      |  2 +
 2 files changed, 71 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt

diff --git a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
new file mode 100644
index 0000000..ec62044
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
@@ -0,0 +1,69 @@
+BROADCOM CYGNUS USB PHY
+
+Required Properties:
+	- compatible:  brcm,cygnus-usb-phy
+	- reg : usbphy_regs - Base address of phy registers
+			usb2h_idm_regs - Base address of host idm registers
+			usb2d_idm_regs - Base address of device idm registers
+	- phy-cells - must be 1 for each port declared. The node
+		      that uses the phy must provide either PHY_CONFIG_DEVICE for device
+		      or PHY_CONFIG_HOST for host
+
+NOTE: port 0 and port 1 are host only and port 2 can be configured for host or
+device.
+
+Example of phy :
+	usbphy0: usbphy@0x0301c000 {
+		compatible = "brcm,cygnus-usb-phy";
+		reg = <0x0301c000 0x2000>,
+		      <0x18115000 0x1000>,
+		      <0x18111000 0x1000>;
+		status = "okay";
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+		usbphy0_0: usbphy0@0 {
+			#phy-cells = <1>;
+			reg = <0>;
+			status = "okay";
+			phy-supply = <&vbus_p0>;
+		};
+
+		usbphy0_1: usbphy0@1 {
+			#phy-cells = <1>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		usbphy0_2: usbphy0@2 {
+			#phy-cells = <1>;
+			reg = <2>;
+			status = "okay";
+			phy-supply = <&vbus_p2>;
+		};
+	};
+
+Example of node using the phy:
+
+	/* This nodes declares all three ports as host */
+
+	ehci0: usb@0x18048000 {
+		compatible = "generic-ehci";
+		reg = <0x18048000 0x100>;
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST &usbphy0_2 PHY_CONFIG_HOST>;
+		status = "okay";
+	};
+
+	/*
+	 * This node declares port 2 phy
+	 * and configures it for device
+	 */
+
+	usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
+		compatible = "iproc-udc";
+		reg = <0x1804c000 0x2000>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
+		phy-names = "usb";
+	};
diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
index 6c90193..3f6b1ac 100644
--- a/include/dt-bindings/phy/phy.h
+++ b/include/dt-bindings/phy/phy.h
@@ -15,5 +15,7 @@
 #define PHY_TYPE_PCIE		2
 #define PHY_TYPE_USB2		3
 #define PHY_TYPE_USB3		4
+#define PHY_CONFIG_HOST		1
+#define PHY_CONFIG_DEVICE	0
 
 #endif /* _DT_BINDINGS_PHY */
-- 
2.3.4


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

* [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-04-22 23:14   ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Arun Ramamurthy

Broadcom's Cygnus chip has a USB 2.0 host controller connected to
three separate phys. One of the phs (port 2) is also connectd to
a usb 2.0 device controller

Signed-off-by: Arun Ramamurthy <arun.ramamurthy-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Reviewed-by: Ray Jui <rjui-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Reviewed-by: Scott Branden <sbranden-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69 ++++++++++++++++++++++
 include/dt-bindings/phy/phy.h                      |  2 +
 2 files changed, 71 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt

diff --git a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
new file mode 100644
index 0000000..ec62044
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
@@ -0,0 +1,69 @@
+BROADCOM CYGNUS USB PHY
+
+Required Properties:
+	- compatible:  brcm,cygnus-usb-phy
+	- reg : usbphy_regs - Base address of phy registers
+			usb2h_idm_regs - Base address of host idm registers
+			usb2d_idm_regs - Base address of device idm registers
+	- phy-cells - must be 1 for each port declared. The node
+		      that uses the phy must provide either PHY_CONFIG_DEVICE for device
+		      or PHY_CONFIG_HOST for host
+
+NOTE: port 0 and port 1 are host only and port 2 can be configured for host or
+device.
+
+Example of phy :
+	usbphy0: usbphy@0x0301c000 {
+		compatible = "brcm,cygnus-usb-phy";
+		reg = <0x0301c000 0x2000>,
+		      <0x18115000 0x1000>,
+		      <0x18111000 0x1000>;
+		status = "okay";
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+		usbphy0_0: usbphy0@0 {
+			#phy-cells = <1>;
+			reg = <0>;
+			status = "okay";
+			phy-supply = <&vbus_p0>;
+		};
+
+		usbphy0_1: usbphy0@1 {
+			#phy-cells = <1>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		usbphy0_2: usbphy0@2 {
+			#phy-cells = <1>;
+			reg = <2>;
+			status = "okay";
+			phy-supply = <&vbus_p2>;
+		};
+	};
+
+Example of node using the phy:
+
+	/* This nodes declares all three ports as host */
+
+	ehci0: usb@0x18048000 {
+		compatible = "generic-ehci";
+		reg = <0x18048000 0x100>;
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST &usbphy0_2 PHY_CONFIG_HOST>;
+		status = "okay";
+	};
+
+	/*
+	 * This node declares port 2 phy
+	 * and configures it for device
+	 */
+
+	usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
+		compatible = "iproc-udc";
+		reg = <0x1804c000 0x2000>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
+		phy-names = "usb";
+	};
diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
index 6c90193..3f6b1ac 100644
--- a/include/dt-bindings/phy/phy.h
+++ b/include/dt-bindings/phy/phy.h
@@ -15,5 +15,7 @@
 #define PHY_TYPE_PCIE		2
 #define PHY_TYPE_USB2		3
 #define PHY_TYPE_USB3		4
+#define PHY_CONFIG_HOST		1
+#define PHY_CONFIG_DEVICE	0
 
 #endif /* _DT_BINDINGS_PHY */
-- 
2.3.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-04-22 23:14   ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Arun Ramamurthy

Broadcom's Cygnus chip has a USB 2.0 host controller connected to
three separate phys. One of the phs (port 2) is also connectd to
a usb 2.0 device controller

Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69 ++++++++++++++++++++++
 include/dt-bindings/phy/phy.h                      |  2 +
 2 files changed, 71 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt

diff --git a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
new file mode 100644
index 0000000..ec62044
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
@@ -0,0 +1,69 @@
+BROADCOM CYGNUS USB PHY
+
+Required Properties:
+	- compatible:  brcm,cygnus-usb-phy
+	- reg : usbphy_regs - Base address of phy registers
+			usb2h_idm_regs - Base address of host idm registers
+			usb2d_idm_regs - Base address of device idm registers
+	- phy-cells - must be 1 for each port declared. The node
+		      that uses the phy must provide either PHY_CONFIG_DEVICE for device
+		      or PHY_CONFIG_HOST for host
+
+NOTE: port 0 and port 1 are host only and port 2 can be configured for host or
+device.
+
+Example of phy :
+	usbphy0: usbphy@0x0301c000 {
+		compatible = "brcm,cygnus-usb-phy";
+		reg = <0x0301c000 0x2000>,
+		      <0x18115000 0x1000>,
+		      <0x18111000 0x1000>;
+		status = "okay";
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+		usbphy0_0: usbphy0@0 {
+			#phy-cells = <1>;
+			reg = <0>;
+			status = "okay";
+			phy-supply = <&vbus_p0>;
+		};
+
+		usbphy0_1: usbphy0@1 {
+			#phy-cells = <1>;
+			reg = <1>;
+			status = "okay";
+		};
+
+		usbphy0_2: usbphy0@2 {
+			#phy-cells = <1>;
+			reg = <2>;
+			status = "okay";
+			phy-supply = <&vbus_p2>;
+		};
+	};
+
+Example of node using the phy:
+
+	/* This nodes declares all three ports as host */
+
+	ehci0: usb@0x18048000 {
+		compatible = "generic-ehci";
+		reg = <0x18048000 0x100>;
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST &usbphy0_2 PHY_CONFIG_HOST>;
+		status = "okay";
+	};
+
+	/*
+	 * This node declares port 2 phy
+	 * and configures it for device
+	 */
+
+	usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
+		compatible = "iproc-udc";
+		reg = <0x1804c000 0x2000>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
+		phy-names = "usb";
+	};
diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
index 6c90193..3f6b1ac 100644
--- a/include/dt-bindings/phy/phy.h
+++ b/include/dt-bindings/phy/phy.h
@@ -15,5 +15,7 @@
 #define PHY_TYPE_PCIE		2
 #define PHY_TYPE_USB2		3
 #define PHY_TYPE_USB3		4
+#define PHY_CONFIG_HOST		1
+#define PHY_CONFIG_DEVICE	0
 
 #endif /* _DT_BINDINGS_PHY */
-- 
2.3.4


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

* [PATCH v3 3/3] phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver
  2015-04-22 23:14 ` Arun Ramamurthy
  (?)
@ 2015-04-22 23:14   ` Arun Ramamurthy
  -1 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Arun Ramamurthy, Dmitry Torokhov

This driver adds support for USB 2.0 host and device phy for
Broadcom's Cygnus chipset. The host controller is connected to
three separate phys and one of the phys (port 2) is connected to
the device controller

Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 drivers/phy/Kconfig              |  12 +
 drivers/phy/Makefile             |   1 +
 drivers/phy/phy-bcm-cygnus-usb.c | 504 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 517 insertions(+)
 create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 2962de2..0aa62dc 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -291,4 +291,16 @@ config PHY_QCOM_UFS
 	help
 	  Support for UFS PHY on QCOM chipsets.
 
+config PHY_BCM_CYGNUS_USB
+	tristate "Broadcom Cygnus USB PHY support"
+	depends on OF
+	depends on ARCH_BCM_CYGNUS || COMPILE_TEST
+	select GENERIC_PHY
+	default ARCH_BCM_CYGNUS
+	help
+	  Enable this to support the USB PHY in Broadcom's Cygnus chip.
+	  The phys are capable of supporting host mode for all ports
+	  and device mode for port 2. The host or device configuration is
+	  read from the device tree.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index f080e1b..47a37fa 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
 obj-$(CONFIG_PHY_BERLIN_USB)		+= phy-berlin-usb.o
 obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
 obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)	+= phy-armada375-usb2.o
+obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
 obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
diff --git a/drivers/phy/phy-bcm-cygnus-usb.c b/drivers/phy/phy-bcm-cygnus-usb.c
new file mode 100644
index 0000000..e718404
--- /dev/null
+++ b/drivers/phy/phy-bcm-cygnus-usb.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/delay.h>
+
+#define CDRU_USBPHY_CLK_RST_SEL_OFFSET			0x11b4
+#define CDRU_USBPHY2_HOST_DEV_SEL_OFFSET		0x11b8
+#define CDRU_SPARE_REG_0_OFFSET				0x1238
+#define CRMU_USB_PHY_AON_CTRL_OFFSET			0x00028
+#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET		0x1210
+#define CDRU_USBPHY_P0_STATUS_OFFSET			0x11D0
+#define CDRU_USBPHY_P1_STATUS_OFFSET			0x11E8
+#define CDRU_USBPHY_P2_STATUS_OFFSET			0x1200
+#define CDRU_USBPHY_USBPHY_ILDO_ON_FLAG			1
+#define CDRU_USBPHY_USBPHY_PLL_LOCK			0
+#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
+#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
+
+#define CRMU_USBPHY_P0_AFE_CORERDY_VDDC			1
+#define CRMU_USBPHY_P0_RESETB				2
+#define CRMU_USBPHY_P1_AFE_CORERDY_VDDC			9
+#define CRMU_USBPHY_P1_RESETB				10
+#define CRMU_USBPHY_P2_AFE_CORERDY_VDDC			17
+#define CRMU_USBPHY_P2_RESETB				18
+
+#define USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET		0x0408
+#define USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable	0
+#define USB2_IDM_IDM_RESET_CONTROL_OFFSET		0x0800
+#define USB2_IDM_IDM_RESET_CONTROL__RESET		0
+
+#define PLL_LOCK_RETRY_COUNT	1000
+#define MAX_PHY_PORTS		3
+
+static int power_bit[] = {CRMU_USBPHY_P0_AFE_CORERDY_VDDC,
+				CRMU_USBPHY_P1_AFE_CORERDY_VDDC,
+				CRMU_USBPHY_P2_AFE_CORERDY_VDDC};
+static int reset_bit[] = {CRMU_USBPHY_P0_RESETB,
+				CRMU_USBPHY_P1_RESETB,
+				CRMU_USBPHY_P2_RESETB};
+static int status_reg[] = {CDRU_USBPHY_P0_STATUS_OFFSET,
+				CDRU_USBPHY_P1_STATUS_OFFSET,
+				CDRU_USBPHY_P2_STATUS_OFFSET};
+
+struct bcm_phy_instance;
+
+struct bcm_phy_driver {
+	void __iomem *usbphy_regs;
+	void __iomem *usb2h_idm_regs;
+	void __iomem *usb2d_idm_regs;
+	struct bcm_phy_instance *ports[MAX_PHY_PORTS];
+	spinlock_t lock;
+	bool idm_host_enabled;
+};
+
+struct bcm_phy_instance {
+	struct bcm_phy_driver *driver;
+	struct phy *generic_phy;
+	int port_no;
+	bool host_mode; /* true - Host, false - device */
+	bool power;
+};
+
+static inline int bcm_phy_cdru_usbphy_status_wait(u32 usb_reg, int reg_bit,
+					  struct bcm_phy_driver *phy_driver)
+{
+	/* Wait for the PLL lock status */
+	int retry = PLL_LOCK_RETRY_COUNT;
+	u32 reg_val;
+
+	do {
+		udelay(1);
+		reg_val = readl(phy_driver->usbphy_regs +
+				usb_reg);
+		if (reg_val & (1 << reg_bit))
+			return 0;
+	} while (--retry > 0);
+
+	return -EBUSY;
+
+}
+
+static struct phy *bcm_usb_phy_xlate(struct device *dev,
+				     struct of_phandle_args *args)
+{
+	struct bcm_phy_driver *phy_driver = dev_get_drvdata(dev);
+	struct bcm_phy_instance *port = NULL;
+	int i;
+
+	if (!phy_driver)
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(args->args_count != 1))
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(args->args[0] < 0 || args->args[0] > 1))
+		return ERR_PTR(-ENODEV);
+
+	for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
+		struct bcm_phy_instance *p = phy_driver->ports[i];
+
+		if (p && p->generic_phy->dev.of_node == args->np) {
+			port = p;
+			break;
+		}
+	}
+
+	if (!port) {
+		dev_err(dev, "Failed to locate phy %s\n", args->np->name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	port->host_mode = args->args[0];
+
+	return port->generic_phy;
+}
+
+static int bcm_phy_init(struct phy *generic_phy)
+{
+	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = port->driver;
+	unsigned long flags;
+	u32 reg_val;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/*
+	 * Only PORT 2 is capable of being device and host
+	 * Default setting is device, check if it is set to host.
+	 */
+	if (port->port_no != 2) {
+		spin_unlock_irqrestore(&phy_driver->lock, flags);
+		return 0;
+	}
+
+	if (port->host_mode) {
+		writel(PHY2_DEV_HOST_CTRL_SEL_HOST,
+			phy_driver->usbphy_regs +
+			CDRU_USBPHY2_HOST_DEV_SEL_OFFSET);
+	} else {
+		/*
+		 * Disable suspend/resume signals to device controller
+		 * when a port is in device mode.
+		 */
+		reg_val = readl(phy_driver->usbphy_regs +
+			      CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
+		reg_val |=
+			1 << CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE;
+		writel(reg_val, phy_driver->usbphy_regs +
+		       CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
+	}
+
+
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+	return 0;
+}
+
+static int bcm_phy_shutdown(struct phy *generic_phy)
+{
+	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = port->driver;
+	unsigned long flags;
+	int i;
+	u32 reg_val, powered_on_phy;
+	bool power_off_flag = true;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* power down the phy */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CRMU_USB_PHY_AON_CTRL_OFFSET);
+	reg_val &= ~(1 << power_bit[port->port_no]);
+	reg_val &= ~(1 << reset_bit[port->port_no]);
+	writel(reg_val, phy_driver->usbphy_regs +
+		CRMU_USB_PHY_AON_CTRL_OFFSET);
+	port->power = false;
+
+	/*
+	 * If a port is configured to device and it is being shutdown,
+	 * turn off the clocks to the usb device controller.
+	 */
+	if (port->port_no == 2 && !port->host_mode) {
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val &= ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val |= 1 << USB2_IDM_IDM_RESET_CONTROL__RESET;
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+
+		spin_unlock_irqrestore(&phy_driver->lock, flags);
+		return 0;
+	}
+
+	/*
+	 * If the phy being shutdown provides clock and reset to
+	 * the host controller, change it do a different powered on phy
+	 * If all phys are powered off, shut of the host controller
+	 */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+	powered_on_phy = reg_val;
+	if (reg_val == port->port_no) {
+		for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
+			if (phy_driver->ports[i] &&
+			    phy_driver->ports[i]->power &&
+			    phy_driver->ports[i]->host_mode) {
+				power_off_flag = false;
+				powered_on_phy = i;
+				break;
+			}
+		}
+	}
+
+	if (power_off_flag) {
+		/*
+		 * Put the host controller into reset state and
+		 * disable clock.
+		 */
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+			USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val &=
+		  ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val |= (1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		phy_driver->idm_host_enabled = 0;
+	} else {
+		writel(powered_on_phy, phy_driver->usbphy_regs +
+			   CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+	}
+
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+
+	return 0;
+}
+
+static int bcm_phy_poweron(struct phy *generic_phy)
+{
+	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = port->driver;
+	unsigned long flags;
+	int ret;
+	u32 reg_val;
+	bool clock_reset_flag = true;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* Bring the AFE block out of reset to start powering up the PHY */
+	reg_val = readl(phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
+	reg_val |= 1 << power_bit[port->port_no];
+	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
+
+	/* Check for power on and PLL lock */
+	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
+		   CDRU_USBPHY_USBPHY_ILDO_ON_FLAG, phy_driver);
+	if (ret < 0) {
+		dev_err(&generic_phy->dev,
+			"Timed out waiting for USBPHY_ILDO_ON_FLAG on port %d",
+			port->port_no);
+		goto err_shutdown;
+	}
+	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
+		CDRU_USBPHY_USBPHY_PLL_LOCK, phy_driver);
+	if (ret < 0) {
+		dev_err(&generic_phy->dev,
+			"Timed out waiting for USBPHY_PLL_LOCK on port %d",
+			port->port_no);
+		goto err_shutdown;
+	}
+	port->power = true;
+
+	/* Check if the port 2 is configured for device */
+	if (port->port_no == 2 && !port->host_mode) {
+		/*
+		 * Enable clock to USB device and get the USB device
+		 * out of reset.
+		 */
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+
+	} else {
+		reg_val = readl(phy_driver->usbphy_regs +
+				CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+
+		/*
+		 * Check if the phy that is configured to provide clock
+		 * and reset is powered on.
+		 */
+		if (reg_val >= 0 && reg_val < ARRAY_SIZE(phy_driver->ports))
+			if (phy_driver->ports[reg_val])
+				if (phy_driver->ports[reg_val]->power)
+					clock_reset_flag = false;
+
+		/* if not set the current phy */
+		if (clock_reset_flag) {
+			reg_val = port->port_no;
+			writel(reg_val, phy_driver->usbphy_regs +
+			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+		}
+	}
+
+	if (!phy_driver->idm_host_enabled) {
+		/* Enable clock to USB and get the USB out of reset */
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		phy_driver->idm_host_enabled = true;
+	}
+
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+	return 0;
+
+err_shutdown:
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+	bcm_phy_shutdown(generic_phy);
+	return ret;
+}
+
+static struct phy_ops ops = {
+	.init		= bcm_phy_init,
+	.power_on	= bcm_phy_poweron,
+	.power_off	= bcm_phy_shutdown,
+};
+
+static const struct of_device_id bcm_phy_dt_ids[] = {
+	{ .compatible = "brcm,cygnus-usb-phy", },
+	{ }
+};
+
+static int bcm_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct bcm_phy_driver *phy_driver;
+	struct phy_provider *phy_provider;
+	struct device_node *child;
+	struct resource *res;
+	int error;
+	u32 reg_val;
+
+	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
+				  GFP_KERNEL);
+	if (!phy_driver)
+		return -ENOMEM;
+
+	spin_lock_init(&phy_driver->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory resource usbphy_regs\n");
+		return -EINVAL;
+	}
+	phy_driver->usbphy_regs = devm_ioremap_nocache(dev, res->start,
+						resource_size(res));
+	if (!phy_driver->usbphy_regs) {
+		dev_err(dev, "Failed to remap usbphy_regs\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory resource ubs2h_idm_regs\n");
+		return -EINVAL;
+	}
+	phy_driver->usb2h_idm_regs = devm_ioremap_nocache(dev, res->start,
+						  resource_size(res));
+	if (!phy_driver->usb2h_idm_regs) {
+		dev_err(dev, "Failed to remap usb2h_idm_regs\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory resource ubs2d_idm_regs\n");
+		return -EINVAL;
+	}
+	phy_driver->usb2d_idm_regs = devm_ioremap_nocache(dev, res->start,
+						   resource_size(res));
+	if (!phy_driver->usb2d_idm_regs) {
+		dev_err(dev, "Failed to remap usb2d_idm_regs\n");
+		return -ENOMEM;
+	}
+
+	dev_set_drvdata(dev, phy_driver);
+
+	phy_driver->idm_host_enabled = false;
+
+	/* Shut down all ports. They can be powered up as required */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CRMU_USB_PHY_AON_CTRL_OFFSET);
+	reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
+	reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
+	reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
+	reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
+	reg_val &= ~(1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
+	reg_val &= ~(1 << CRMU_USBPHY_P2_RESETB);
+	writel(reg_val, phy_driver->usbphy_regs +
+		CRMU_USB_PHY_AON_CTRL_OFFSET);
+
+	for_each_available_child_of_node(dev->of_node, child) {
+		struct bcm_phy_instance *port;
+		u32 port_no;
+
+		if (of_property_read_u32(child, "reg", &port_no)) {
+			dev_err(dev, "missing reg property in node %s\n",
+				child->name);
+			return -EINVAL;
+		}
+
+		if (port_no >= ARRAY_SIZE(phy_driver->ports)) {
+			dev_err(dev, "invalid reg in node %s: %u\n",
+				child->name, port_no);
+			return -EINVAL;
+		}
+
+		port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+		if (!port)
+			return -ENOMEM;
+
+		port->generic_phy = devm_phy_create(dev, child, &ops);
+		if (IS_ERR(port->generic_phy)) {
+			error = PTR_ERR(port->generic_phy);
+			dev_err(dev, "Failed to create phy %u: %d",
+				port_no, error);
+			return error;
+		}
+
+		port->port_no = port_no;
+		port->driver = phy_driver;
+		phy_set_drvdata(port->generic_phy, port);
+
+		phy_driver->ports[port_no] = port;
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate);
+	if (IS_ERR(phy_provider)) {
+		error = PTR_ERR(phy_provider);
+		dev_err(dev, "Failed to register as phy provider: %d\n",
+			error);
+		return error;
+	}
+
+	dev_set_drvdata(pdev, phy_driver);
+
+	return 0;
+
+}
+
+MODULE_DEVICE_TABLE(of, bcm_phy_dt_ids);
+
+static struct platform_driver bcm_phy_driver = {
+	.probe = bcm_phy_probe,
+	.driver = {
+		.name = "bcm-cygnus-usbphy",
+		.of_match_table = of_match_ptr(bcm_phy_dt_ids),
+	},
+};
+module_platform_driver(bcm_phy_driver);
+
+MODULE_ALIAS("platform:bcm-cygnus-usbphy");
+MODULE_AUTHOR("Broadcom");
+MODULE_DESCRIPTION("Broadcom Cygnus USB PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
2.3.4


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

* [PATCH v3 3/3] phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver
@ 2015-04-22 23:14   ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Arun Ramamurthy, Dmitry Torokhov

This driver adds support for USB 2.0 host and device phy for
Broadcom's Cygnus chipset. The host controller is connected to
three separate phys and one of the phys (port 2) is connected to
the device controller

Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 drivers/phy/Kconfig              |  12 +
 drivers/phy/Makefile             |   1 +
 drivers/phy/phy-bcm-cygnus-usb.c | 504 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 517 insertions(+)
 create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 2962de2..0aa62dc 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -291,4 +291,16 @@ config PHY_QCOM_UFS
 	help
 	  Support for UFS PHY on QCOM chipsets.
 
+config PHY_BCM_CYGNUS_USB
+	tristate "Broadcom Cygnus USB PHY support"
+	depends on OF
+	depends on ARCH_BCM_CYGNUS || COMPILE_TEST
+	select GENERIC_PHY
+	default ARCH_BCM_CYGNUS
+	help
+	  Enable this to support the USB PHY in Broadcom's Cygnus chip.
+	  The phys are capable of supporting host mode for all ports
+	  and device mode for port 2. The host or device configuration is
+	  read from the device tree.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index f080e1b..47a37fa 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
 obj-$(CONFIG_PHY_BERLIN_USB)		+= phy-berlin-usb.o
 obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
 obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)	+= phy-armada375-usb2.o
+obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
 obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
diff --git a/drivers/phy/phy-bcm-cygnus-usb.c b/drivers/phy/phy-bcm-cygnus-usb.c
new file mode 100644
index 0000000..e718404
--- /dev/null
+++ b/drivers/phy/phy-bcm-cygnus-usb.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/delay.h>
+
+#define CDRU_USBPHY_CLK_RST_SEL_OFFSET			0x11b4
+#define CDRU_USBPHY2_HOST_DEV_SEL_OFFSET		0x11b8
+#define CDRU_SPARE_REG_0_OFFSET				0x1238
+#define CRMU_USB_PHY_AON_CTRL_OFFSET			0x00028
+#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET		0x1210
+#define CDRU_USBPHY_P0_STATUS_OFFSET			0x11D0
+#define CDRU_USBPHY_P1_STATUS_OFFSET			0x11E8
+#define CDRU_USBPHY_P2_STATUS_OFFSET			0x1200
+#define CDRU_USBPHY_USBPHY_ILDO_ON_FLAG			1
+#define CDRU_USBPHY_USBPHY_PLL_LOCK			0
+#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
+#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
+
+#define CRMU_USBPHY_P0_AFE_CORERDY_VDDC			1
+#define CRMU_USBPHY_P0_RESETB				2
+#define CRMU_USBPHY_P1_AFE_CORERDY_VDDC			9
+#define CRMU_USBPHY_P1_RESETB				10
+#define CRMU_USBPHY_P2_AFE_CORERDY_VDDC			17
+#define CRMU_USBPHY_P2_RESETB				18
+
+#define USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET		0x0408
+#define USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable	0
+#define USB2_IDM_IDM_RESET_CONTROL_OFFSET		0x0800
+#define USB2_IDM_IDM_RESET_CONTROL__RESET		0
+
+#define PLL_LOCK_RETRY_COUNT	1000
+#define MAX_PHY_PORTS		3
+
+static int power_bit[] = {CRMU_USBPHY_P0_AFE_CORERDY_VDDC,
+				CRMU_USBPHY_P1_AFE_CORERDY_VDDC,
+				CRMU_USBPHY_P2_AFE_CORERDY_VDDC};
+static int reset_bit[] = {CRMU_USBPHY_P0_RESETB,
+				CRMU_USBPHY_P1_RESETB,
+				CRMU_USBPHY_P2_RESETB};
+static int status_reg[] = {CDRU_USBPHY_P0_STATUS_OFFSET,
+				CDRU_USBPHY_P1_STATUS_OFFSET,
+				CDRU_USBPHY_P2_STATUS_OFFSET};
+
+struct bcm_phy_instance;
+
+struct bcm_phy_driver {
+	void __iomem *usbphy_regs;
+	void __iomem *usb2h_idm_regs;
+	void __iomem *usb2d_idm_regs;
+	struct bcm_phy_instance *ports[MAX_PHY_PORTS];
+	spinlock_t lock;
+	bool idm_host_enabled;
+};
+
+struct bcm_phy_instance {
+	struct bcm_phy_driver *driver;
+	struct phy *generic_phy;
+	int port_no;
+	bool host_mode; /* true - Host, false - device */
+	bool power;
+};
+
+static inline int bcm_phy_cdru_usbphy_status_wait(u32 usb_reg, int reg_bit,
+					  struct bcm_phy_driver *phy_driver)
+{
+	/* Wait for the PLL lock status */
+	int retry = PLL_LOCK_RETRY_COUNT;
+	u32 reg_val;
+
+	do {
+		udelay(1);
+		reg_val = readl(phy_driver->usbphy_regs +
+				usb_reg);
+		if (reg_val & (1 << reg_bit))
+			return 0;
+	} while (--retry > 0);
+
+	return -EBUSY;
+
+}
+
+static struct phy *bcm_usb_phy_xlate(struct device *dev,
+				     struct of_phandle_args *args)
+{
+	struct bcm_phy_driver *phy_driver = dev_get_drvdata(dev);
+	struct bcm_phy_instance *port = NULL;
+	int i;
+
+	if (!phy_driver)
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(args->args_count != 1))
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(args->args[0] < 0 || args->args[0] > 1))
+		return ERR_PTR(-ENODEV);
+
+	for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
+		struct bcm_phy_instance *p = phy_driver->ports[i];
+
+		if (p && p->generic_phy->dev.of_node == args->np) {
+			port = p;
+			break;
+		}
+	}
+
+	if (!port) {
+		dev_err(dev, "Failed to locate phy %s\n", args->np->name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	port->host_mode = args->args[0];
+
+	return port->generic_phy;
+}
+
+static int bcm_phy_init(struct phy *generic_phy)
+{
+	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = port->driver;
+	unsigned long flags;
+	u32 reg_val;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/*
+	 * Only PORT 2 is capable of being device and host
+	 * Default setting is device, check if it is set to host.
+	 */
+	if (port->port_no != 2) {
+		spin_unlock_irqrestore(&phy_driver->lock, flags);
+		return 0;
+	}
+
+	if (port->host_mode) {
+		writel(PHY2_DEV_HOST_CTRL_SEL_HOST,
+			phy_driver->usbphy_regs +
+			CDRU_USBPHY2_HOST_DEV_SEL_OFFSET);
+	} else {
+		/*
+		 * Disable suspend/resume signals to device controller
+		 * when a port is in device mode.
+		 */
+		reg_val = readl(phy_driver->usbphy_regs +
+			      CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
+		reg_val |=
+			1 << CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE;
+		writel(reg_val, phy_driver->usbphy_regs +
+		       CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
+	}
+
+
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+	return 0;
+}
+
+static int bcm_phy_shutdown(struct phy *generic_phy)
+{
+	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = port->driver;
+	unsigned long flags;
+	int i;
+	u32 reg_val, powered_on_phy;
+	bool power_off_flag = true;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* power down the phy */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CRMU_USB_PHY_AON_CTRL_OFFSET);
+	reg_val &= ~(1 << power_bit[port->port_no]);
+	reg_val &= ~(1 << reset_bit[port->port_no]);
+	writel(reg_val, phy_driver->usbphy_regs +
+		CRMU_USB_PHY_AON_CTRL_OFFSET);
+	port->power = false;
+
+	/*
+	 * If a port is configured to device and it is being shutdown,
+	 * turn off the clocks to the usb device controller.
+	 */
+	if (port->port_no == 2 && !port->host_mode) {
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val &= ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val |= 1 << USB2_IDM_IDM_RESET_CONTROL__RESET;
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+
+		spin_unlock_irqrestore(&phy_driver->lock, flags);
+		return 0;
+	}
+
+	/*
+	 * If the phy being shutdown provides clock and reset to
+	 * the host controller, change it do a different powered on phy
+	 * If all phys are powered off, shut of the host controller
+	 */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+	powered_on_phy = reg_val;
+	if (reg_val == port->port_no) {
+		for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
+			if (phy_driver->ports[i] &&
+			    phy_driver->ports[i]->power &&
+			    phy_driver->ports[i]->host_mode) {
+				power_off_flag = false;
+				powered_on_phy = i;
+				break;
+			}
+		}
+	}
+
+	if (power_off_flag) {
+		/*
+		 * Put the host controller into reset state and
+		 * disable clock.
+		 */
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+			USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val &=
+		  ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val |= (1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		phy_driver->idm_host_enabled = 0;
+	} else {
+		writel(powered_on_phy, phy_driver->usbphy_regs +
+			   CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+	}
+
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+
+	return 0;
+}
+
+static int bcm_phy_poweron(struct phy *generic_phy)
+{
+	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = port->driver;
+	unsigned long flags;
+	int ret;
+	u32 reg_val;
+	bool clock_reset_flag = true;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* Bring the AFE block out of reset to start powering up the PHY */
+	reg_val = readl(phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
+	reg_val |= 1 << power_bit[port->port_no];
+	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
+
+	/* Check for power on and PLL lock */
+	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
+		   CDRU_USBPHY_USBPHY_ILDO_ON_FLAG, phy_driver);
+	if (ret < 0) {
+		dev_err(&generic_phy->dev,
+			"Timed out waiting for USBPHY_ILDO_ON_FLAG on port %d",
+			port->port_no);
+		goto err_shutdown;
+	}
+	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
+		CDRU_USBPHY_USBPHY_PLL_LOCK, phy_driver);
+	if (ret < 0) {
+		dev_err(&generic_phy->dev,
+			"Timed out waiting for USBPHY_PLL_LOCK on port %d",
+			port->port_no);
+		goto err_shutdown;
+	}
+	port->power = true;
+
+	/* Check if the port 2 is configured for device */
+	if (port->port_no == 2 && !port->host_mode) {
+		/*
+		 * Enable clock to USB device and get the USB device
+		 * out of reset.
+		 */
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+
+	} else {
+		reg_val = readl(phy_driver->usbphy_regs +
+				CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+
+		/*
+		 * Check if the phy that is configured to provide clock
+		 * and reset is powered on.
+		 */
+		if (reg_val >= 0 && reg_val < ARRAY_SIZE(phy_driver->ports))
+			if (phy_driver->ports[reg_val])
+				if (phy_driver->ports[reg_val]->power)
+					clock_reset_flag = false;
+
+		/* if not set the current phy */
+		if (clock_reset_flag) {
+			reg_val = port->port_no;
+			writel(reg_val, phy_driver->usbphy_regs +
+			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+		}
+	}
+
+	if (!phy_driver->idm_host_enabled) {
+		/* Enable clock to USB and get the USB out of reset */
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		phy_driver->idm_host_enabled = true;
+	}
+
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+	return 0;
+
+err_shutdown:
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+	bcm_phy_shutdown(generic_phy);
+	return ret;
+}
+
+static struct phy_ops ops = {
+	.init		= bcm_phy_init,
+	.power_on	= bcm_phy_poweron,
+	.power_off	= bcm_phy_shutdown,
+};
+
+static const struct of_device_id bcm_phy_dt_ids[] = {
+	{ .compatible = "brcm,cygnus-usb-phy", },
+	{ }
+};
+
+static int bcm_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct bcm_phy_driver *phy_driver;
+	struct phy_provider *phy_provider;
+	struct device_node *child;
+	struct resource *res;
+	int error;
+	u32 reg_val;
+
+	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
+				  GFP_KERNEL);
+	if (!phy_driver)
+		return -ENOMEM;
+
+	spin_lock_init(&phy_driver->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory resource usbphy_regs\n");
+		return -EINVAL;
+	}
+	phy_driver->usbphy_regs = devm_ioremap_nocache(dev, res->start,
+						resource_size(res));
+	if (!phy_driver->usbphy_regs) {
+		dev_err(dev, "Failed to remap usbphy_regs\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory resource ubs2h_idm_regs\n");
+		return -EINVAL;
+	}
+	phy_driver->usb2h_idm_regs = devm_ioremap_nocache(dev, res->start,
+						  resource_size(res));
+	if (!phy_driver->usb2h_idm_regs) {
+		dev_err(dev, "Failed to remap usb2h_idm_regs\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory resource ubs2d_idm_regs\n");
+		return -EINVAL;
+	}
+	phy_driver->usb2d_idm_regs = devm_ioremap_nocache(dev, res->start,
+						   resource_size(res));
+	if (!phy_driver->usb2d_idm_regs) {
+		dev_err(dev, "Failed to remap usb2d_idm_regs\n");
+		return -ENOMEM;
+	}
+
+	dev_set_drvdata(dev, phy_driver);
+
+	phy_driver->idm_host_enabled = false;
+
+	/* Shut down all ports. They can be powered up as required */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CRMU_USB_PHY_AON_CTRL_OFFSET);
+	reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
+	reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
+	reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
+	reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
+	reg_val &= ~(1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
+	reg_val &= ~(1 << CRMU_USBPHY_P2_RESETB);
+	writel(reg_val, phy_driver->usbphy_regs +
+		CRMU_USB_PHY_AON_CTRL_OFFSET);
+
+	for_each_available_child_of_node(dev->of_node, child) {
+		struct bcm_phy_instance *port;
+		u32 port_no;
+
+		if (of_property_read_u32(child, "reg", &port_no)) {
+			dev_err(dev, "missing reg property in node %s\n",
+				child->name);
+			return -EINVAL;
+		}
+
+		if (port_no >= ARRAY_SIZE(phy_driver->ports)) {
+			dev_err(dev, "invalid reg in node %s: %u\n",
+				child->name, port_no);
+			return -EINVAL;
+		}
+
+		port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+		if (!port)
+			return -ENOMEM;
+
+		port->generic_phy = devm_phy_create(dev, child, &ops);
+		if (IS_ERR(port->generic_phy)) {
+			error = PTR_ERR(port->generic_phy);
+			dev_err(dev, "Failed to create phy %u: %d",
+				port_no, error);
+			return error;
+		}
+
+		port->port_no = port_no;
+		port->driver = phy_driver;
+		phy_set_drvdata(port->generic_phy, port);
+
+		phy_driver->ports[port_no] = port;
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate);
+	if (IS_ERR(phy_provider)) {
+		error = PTR_ERR(phy_provider);
+		dev_err(dev, "Failed to register as phy provider: %d\n",
+			error);
+		return error;
+	}
+
+	dev_set_drvdata(pdev, phy_driver);
+
+	return 0;
+
+}
+
+MODULE_DEVICE_TABLE(of, bcm_phy_dt_ids);
+
+static struct platform_driver bcm_phy_driver = {
+	.probe = bcm_phy_probe,
+	.driver = {
+		.name = "bcm-cygnus-usbphy",
+		.of_match_table = of_match_ptr(bcm_phy_dt_ids),
+	},
+};
+module_platform_driver(bcm_phy_driver);
+
+MODULE_ALIAS("platform:bcm-cygnus-usbphy");
+MODULE_AUTHOR("Broadcom");
+MODULE_DESCRIPTION("Broadcom Cygnus USB PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
2.3.4

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

* [PATCH v3 3/3] phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver
@ 2015-04-22 23:14   ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-04-22 23:14 UTC (permalink / raw)
  To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Russell King, Kishon Vijay Abraham I, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Arun Ramamurthy, Dmitry Torokhov

This driver adds support for USB 2.0 host and device phy for
Broadcom's Cygnus chipset. The host controller is connected to
three separate phys and one of the phys (port 2) is connected to
the device controller

Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
---
 drivers/phy/Kconfig              |  12 +
 drivers/phy/Makefile             |   1 +
 drivers/phy/phy-bcm-cygnus-usb.c | 504 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 517 insertions(+)
 create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 2962de2..0aa62dc 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -291,4 +291,16 @@ config PHY_QCOM_UFS
 	help
 	  Support for UFS PHY on QCOM chipsets.
 
+config PHY_BCM_CYGNUS_USB
+	tristate "Broadcom Cygnus USB PHY support"
+	depends on OF
+	depends on ARCH_BCM_CYGNUS || COMPILE_TEST
+	select GENERIC_PHY
+	default ARCH_BCM_CYGNUS
+	help
+	  Enable this to support the USB PHY in Broadcom's Cygnus chip.
+	  The phys are capable of supporting host mode for all ports
+	  and device mode for port 2. The host or device configuration is
+	  read from the device tree.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index f080e1b..47a37fa 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
 obj-$(CONFIG_PHY_BERLIN_USB)		+= phy-berlin-usb.o
 obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
 obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)	+= phy-armada375-usb2.o
+obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
 obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
diff --git a/drivers/phy/phy-bcm-cygnus-usb.c b/drivers/phy/phy-bcm-cygnus-usb.c
new file mode 100644
index 0000000..e718404
--- /dev/null
+++ b/drivers/phy/phy-bcm-cygnus-usb.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/delay.h>
+
+#define CDRU_USBPHY_CLK_RST_SEL_OFFSET			0x11b4
+#define CDRU_USBPHY2_HOST_DEV_SEL_OFFSET		0x11b8
+#define CDRU_SPARE_REG_0_OFFSET				0x1238
+#define CRMU_USB_PHY_AON_CTRL_OFFSET			0x00028
+#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET		0x1210
+#define CDRU_USBPHY_P0_STATUS_OFFSET			0x11D0
+#define CDRU_USBPHY_P1_STATUS_OFFSET			0x11E8
+#define CDRU_USBPHY_P2_STATUS_OFFSET			0x1200
+#define CDRU_USBPHY_USBPHY_ILDO_ON_FLAG			1
+#define CDRU_USBPHY_USBPHY_PLL_LOCK			0
+#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
+#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
+
+#define CRMU_USBPHY_P0_AFE_CORERDY_VDDC			1
+#define CRMU_USBPHY_P0_RESETB				2
+#define CRMU_USBPHY_P1_AFE_CORERDY_VDDC			9
+#define CRMU_USBPHY_P1_RESETB				10
+#define CRMU_USBPHY_P2_AFE_CORERDY_VDDC			17
+#define CRMU_USBPHY_P2_RESETB				18
+
+#define USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET		0x0408
+#define USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable	0
+#define USB2_IDM_IDM_RESET_CONTROL_OFFSET		0x0800
+#define USB2_IDM_IDM_RESET_CONTROL__RESET		0
+
+#define PLL_LOCK_RETRY_COUNT	1000
+#define MAX_PHY_PORTS		3
+
+static int power_bit[] = {CRMU_USBPHY_P0_AFE_CORERDY_VDDC,
+				CRMU_USBPHY_P1_AFE_CORERDY_VDDC,
+				CRMU_USBPHY_P2_AFE_CORERDY_VDDC};
+static int reset_bit[] = {CRMU_USBPHY_P0_RESETB,
+				CRMU_USBPHY_P1_RESETB,
+				CRMU_USBPHY_P2_RESETB};
+static int status_reg[] = {CDRU_USBPHY_P0_STATUS_OFFSET,
+				CDRU_USBPHY_P1_STATUS_OFFSET,
+				CDRU_USBPHY_P2_STATUS_OFFSET};
+
+struct bcm_phy_instance;
+
+struct bcm_phy_driver {
+	void __iomem *usbphy_regs;
+	void __iomem *usb2h_idm_regs;
+	void __iomem *usb2d_idm_regs;
+	struct bcm_phy_instance *ports[MAX_PHY_PORTS];
+	spinlock_t lock;
+	bool idm_host_enabled;
+};
+
+struct bcm_phy_instance {
+	struct bcm_phy_driver *driver;
+	struct phy *generic_phy;
+	int port_no;
+	bool host_mode; /* true - Host, false - device */
+	bool power;
+};
+
+static inline int bcm_phy_cdru_usbphy_status_wait(u32 usb_reg, int reg_bit,
+					  struct bcm_phy_driver *phy_driver)
+{
+	/* Wait for the PLL lock status */
+	int retry = PLL_LOCK_RETRY_COUNT;
+	u32 reg_val;
+
+	do {
+		udelay(1);
+		reg_val = readl(phy_driver->usbphy_regs +
+				usb_reg);
+		if (reg_val & (1 << reg_bit))
+			return 0;
+	} while (--retry > 0);
+
+	return -EBUSY;
+
+}
+
+static struct phy *bcm_usb_phy_xlate(struct device *dev,
+				     struct of_phandle_args *args)
+{
+	struct bcm_phy_driver *phy_driver = dev_get_drvdata(dev);
+	struct bcm_phy_instance *port = NULL;
+	int i;
+
+	if (!phy_driver)
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(args->args_count != 1))
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(args->args[0] < 0 || args->args[0] > 1))
+		return ERR_PTR(-ENODEV);
+
+	for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
+		struct bcm_phy_instance *p = phy_driver->ports[i];
+
+		if (p && p->generic_phy->dev.of_node = args->np) {
+			port = p;
+			break;
+		}
+	}
+
+	if (!port) {
+		dev_err(dev, "Failed to locate phy %s\n", args->np->name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	port->host_mode = args->args[0];
+
+	return port->generic_phy;
+}
+
+static int bcm_phy_init(struct phy *generic_phy)
+{
+	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = port->driver;
+	unsigned long flags;
+	u32 reg_val;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/*
+	 * Only PORT 2 is capable of being device and host
+	 * Default setting is device, check if it is set to host.
+	 */
+	if (port->port_no != 2) {
+		spin_unlock_irqrestore(&phy_driver->lock, flags);
+		return 0;
+	}
+
+	if (port->host_mode) {
+		writel(PHY2_DEV_HOST_CTRL_SEL_HOST,
+			phy_driver->usbphy_regs +
+			CDRU_USBPHY2_HOST_DEV_SEL_OFFSET);
+	} else {
+		/*
+		 * Disable suspend/resume signals to device controller
+		 * when a port is in device mode.
+		 */
+		reg_val = readl(phy_driver->usbphy_regs +
+			      CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
+		reg_val |+			1 << CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE;
+		writel(reg_val, phy_driver->usbphy_regs +
+		       CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
+	}
+
+
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+	return 0;
+}
+
+static int bcm_phy_shutdown(struct phy *generic_phy)
+{
+	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = port->driver;
+	unsigned long flags;
+	int i;
+	u32 reg_val, powered_on_phy;
+	bool power_off_flag = true;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* power down the phy */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CRMU_USB_PHY_AON_CTRL_OFFSET);
+	reg_val &= ~(1 << power_bit[port->port_no]);
+	reg_val &= ~(1 << reset_bit[port->port_no]);
+	writel(reg_val, phy_driver->usbphy_regs +
+		CRMU_USB_PHY_AON_CTRL_OFFSET);
+	port->power = false;
+
+	/*
+	 * If a port is configured to device and it is being shutdown,
+	 * turn off the clocks to the usb device controller.
+	 */
+	if (port->port_no = 2 && !port->host_mode) {
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val &= ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val |= 1 << USB2_IDM_IDM_RESET_CONTROL__RESET;
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+
+		spin_unlock_irqrestore(&phy_driver->lock, flags);
+		return 0;
+	}
+
+	/*
+	 * If the phy being shutdown provides clock and reset to
+	 * the host controller, change it do a different powered on phy
+	 * If all phys are powered off, shut of the host controller
+	 */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+	powered_on_phy = reg_val;
+	if (reg_val = port->port_no) {
+		for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
+			if (phy_driver->ports[i] &&
+			    phy_driver->ports[i]->power &&
+			    phy_driver->ports[i]->host_mode) {
+				power_off_flag = false;
+				powered_on_phy = i;
+				break;
+			}
+		}
+	}
+
+	if (power_off_flag) {
+		/*
+		 * Put the host controller into reset state and
+		 * disable clock.
+		 */
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+			USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val &+		  ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val |= (1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		phy_driver->idm_host_enabled = 0;
+	} else {
+		writel(powered_on_phy, phy_driver->usbphy_regs +
+			   CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+	}
+
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+
+	return 0;
+}
+
+static int bcm_phy_poweron(struct phy *generic_phy)
+{
+	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = port->driver;
+	unsigned long flags;
+	int ret;
+	u32 reg_val;
+	bool clock_reset_flag = true;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* Bring the AFE block out of reset to start powering up the PHY */
+	reg_val = readl(phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
+	reg_val |= 1 << power_bit[port->port_no];
+	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
+
+	/* Check for power on and PLL lock */
+	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
+		   CDRU_USBPHY_USBPHY_ILDO_ON_FLAG, phy_driver);
+	if (ret < 0) {
+		dev_err(&generic_phy->dev,
+			"Timed out waiting for USBPHY_ILDO_ON_FLAG on port %d",
+			port->port_no);
+		goto err_shutdown;
+	}
+	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
+		CDRU_USBPHY_USBPHY_PLL_LOCK, phy_driver);
+	if (ret < 0) {
+		dev_err(&generic_phy->dev,
+			"Timed out waiting for USBPHY_PLL_LOCK on port %d",
+			port->port_no);
+		goto err_shutdown;
+	}
+	port->power = true;
+
+	/* Check if the port 2 is configured for device */
+	if (port->port_no = 2 && !port->host_mode) {
+		/*
+		 * Enable clock to USB device and get the USB device
+		 * out of reset.
+		 */
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
+		writel(reg_val, phy_driver->usb2d_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+
+	} else {
+		reg_val = readl(phy_driver->usbphy_regs +
+				CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+
+		/*
+		 * Check if the phy that is configured to provide clock
+		 * and reset is powered on.
+		 */
+		if (reg_val >= 0 && reg_val < ARRAY_SIZE(phy_driver->ports))
+			if (phy_driver->ports[reg_val])
+				if (phy_driver->ports[reg_val]->power)
+					clock_reset_flag = false;
+
+		/* if not set the current phy */
+		if (clock_reset_flag) {
+			reg_val = port->port_no;
+			writel(reg_val, phy_driver->usbphy_regs +
+			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+		}
+	}
+
+	if (!phy_driver->idm_host_enabled) {
+		/* Enable clock to USB and get the USB out of reset */
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
+
+		reg_val = readl(phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
+		writel(reg_val, phy_driver->usb2h_idm_regs +
+				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
+		phy_driver->idm_host_enabled = true;
+	}
+
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+	return 0;
+
+err_shutdown:
+	spin_unlock_irqrestore(&phy_driver->lock, flags);
+	bcm_phy_shutdown(generic_phy);
+	return ret;
+}
+
+static struct phy_ops ops = {
+	.init		= bcm_phy_init,
+	.power_on	= bcm_phy_poweron,
+	.power_off	= bcm_phy_shutdown,
+};
+
+static const struct of_device_id bcm_phy_dt_ids[] = {
+	{ .compatible = "brcm,cygnus-usb-phy", },
+	{ }
+};
+
+static int bcm_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct bcm_phy_driver *phy_driver;
+	struct phy_provider *phy_provider;
+	struct device_node *child;
+	struct resource *res;
+	int error;
+	u32 reg_val;
+
+	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
+				  GFP_KERNEL);
+	if (!phy_driver)
+		return -ENOMEM;
+
+	spin_lock_init(&phy_driver->lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory resource usbphy_regs\n");
+		return -EINVAL;
+	}
+	phy_driver->usbphy_regs = devm_ioremap_nocache(dev, res->start,
+						resource_size(res));
+	if (!phy_driver->usbphy_regs) {
+		dev_err(dev, "Failed to remap usbphy_regs\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory resource ubs2h_idm_regs\n");
+		return -EINVAL;
+	}
+	phy_driver->usb2h_idm_regs = devm_ioremap_nocache(dev, res->start,
+						  resource_size(res));
+	if (!phy_driver->usb2h_idm_regs) {
+		dev_err(dev, "Failed to remap usb2h_idm_regs\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory resource ubs2d_idm_regs\n");
+		return -EINVAL;
+	}
+	phy_driver->usb2d_idm_regs = devm_ioremap_nocache(dev, res->start,
+						   resource_size(res));
+	if (!phy_driver->usb2d_idm_regs) {
+		dev_err(dev, "Failed to remap usb2d_idm_regs\n");
+		return -ENOMEM;
+	}
+
+	dev_set_drvdata(dev, phy_driver);
+
+	phy_driver->idm_host_enabled = false;
+
+	/* Shut down all ports. They can be powered up as required */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CRMU_USB_PHY_AON_CTRL_OFFSET);
+	reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
+	reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
+	reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
+	reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
+	reg_val &= ~(1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
+	reg_val &= ~(1 << CRMU_USBPHY_P2_RESETB);
+	writel(reg_val, phy_driver->usbphy_regs +
+		CRMU_USB_PHY_AON_CTRL_OFFSET);
+
+	for_each_available_child_of_node(dev->of_node, child) {
+		struct bcm_phy_instance *port;
+		u32 port_no;
+
+		if (of_property_read_u32(child, "reg", &port_no)) {
+			dev_err(dev, "missing reg property in node %s\n",
+				child->name);
+			return -EINVAL;
+		}
+
+		if (port_no >= ARRAY_SIZE(phy_driver->ports)) {
+			dev_err(dev, "invalid reg in node %s: %u\n",
+				child->name, port_no);
+			return -EINVAL;
+		}
+
+		port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+		if (!port)
+			return -ENOMEM;
+
+		port->generic_phy = devm_phy_create(dev, child, &ops);
+		if (IS_ERR(port->generic_phy)) {
+			error = PTR_ERR(port->generic_phy);
+			dev_err(dev, "Failed to create phy %u: %d",
+				port_no, error);
+			return error;
+		}
+
+		port->port_no = port_no;
+		port->driver = phy_driver;
+		phy_set_drvdata(port->generic_phy, port);
+
+		phy_driver->ports[port_no] = port;
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate);
+	if (IS_ERR(phy_provider)) {
+		error = PTR_ERR(phy_provider);
+		dev_err(dev, "Failed to register as phy provider: %d\n",
+			error);
+		return error;
+	}
+
+	dev_set_drvdata(pdev, phy_driver);
+
+	return 0;
+
+}
+
+MODULE_DEVICE_TABLE(of, bcm_phy_dt_ids);
+
+static struct platform_driver bcm_phy_driver = {
+	.probe = bcm_phy_probe,
+	.driver = {
+		.name = "bcm-cygnus-usbphy",
+		.of_match_table = of_match_ptr(bcm_phy_dt_ids),
+	},
+};
+module_platform_driver(bcm_phy_driver);
+
+MODULE_ALIAS("platform:bcm-cygnus-usbphy");
+MODULE_AUTHOR("Broadcom");
+MODULE_DESCRIPTION("Broadcom Cygnus USB PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
2.3.4


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

* Re: [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
  2015-04-22 23:14   ` Arun Ramamurthy
  (?)
@ 2015-05-11 14:11     ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 24+ messages in thread
From: Kishon Vijay Abraham I @ 2015-05-11 14:11 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list

Hi,

On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
> Broadcom's Cygnus chip has a USB 2.0 host controller connected to
> three separate phys. One of the phs (port 2) is also connectd to
> a usb 2.0 device controller
>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> ---
>   .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69 ++++++++++++++++++++++
>   include/dt-bindings/phy/phy.h                      |  2 +
>   2 files changed, 71 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>
> diff --git a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
> new file mode 100644
> index 0000000..ec62044
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
> @@ -0,0 +1,69 @@
> +BROADCOM CYGNUS USB PHY
> +
> +Required Properties:
> +	- compatible:  brcm,cygnus-usb-phy
> +	- reg : usbphy_regs - Base address of phy registers
> +			usb2h_idm_regs - Base address of host idm registers
> +			usb2d_idm_regs - Base address of device idm registers
> +	- phy-cells - must be 1 for each port declared. The node
> +		      that uses the phy must provide either PHY_CONFIG_DEVICE for device
> +		      or PHY_CONFIG_HOST for host
> +
> +NOTE: port 0 and port 1 are host only and port 2 can be configured for host or
> +device.
> +
> +Example of phy :
> +	usbphy0: usbphy@0x0301c000 {
> +		compatible = "brcm,cygnus-usb-phy";
> +		reg = <0x0301c000 0x2000>,
> +		      <0x18115000 0x1000>,
> +		      <0x18111000 0x1000>;
> +		status = "okay";
> +
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		usbphy0_0: usbphy0@0 {
> +			#phy-cells = <1>;
> +			reg = <0>;
> +			status = "okay";
> +			phy-supply = <&vbus_p0>;
> +		};
> +
> +		usbphy0_1: usbphy0@1 {
> +			#phy-cells = <1>;
> +			reg = <1>;
> +			status = "okay";
> +		};
> +
> +		usbphy0_2: usbphy0@2 {
> +			#phy-cells = <1>;
> +			reg = <2>;
> +			status = "okay";
> +			phy-supply = <&vbus_p2>;
> +		};
> +	};
> +
> +Example of node using the phy:
> +
> +	/* This nodes declares all three ports as host */
> +
> +	ehci0: usb@0x18048000 {
> +		compatible = "generic-ehci";
> +		reg = <0x18048000 0x100>;
> +		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
> +		phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST &usbphy0_2 PHY_CONFIG_HOST>;
> +		status = "okay";
> +	};
> +
> +	/*
> +	 * This node declares port 2 phy
> +	 * and configures it for device
> +	 */
> +
> +	usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
> +		compatible = "iproc-udc";
> +		reg = <0x1804c000 0x2000>;
> +		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
> +		phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
> +		phy-names = "usb";
> +	};
> diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
> index 6c90193..3f6b1ac 100644
> --- a/include/dt-bindings/phy/phy.h
> +++ b/include/dt-bindings/phy/phy.h
> @@ -15,5 +15,7 @@
>   #define PHY_TYPE_PCIE		2
>   #define PHY_TYPE_USB2		3
>   #define PHY_TYPE_USB3		4
> +#define PHY_CONFIG_HOST		1
> +#define PHY_CONFIG_DEVICE	0

'0' and '1' are already defined for "PHY_NONE" and "PHY_TYPE_SATA". Is this for 
USB2 or for USB3?

Thanks
Kishon

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

* Re: [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-05-11 14:11     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 24+ messages in thread
From: Kishon Vijay Abraham I @ 2015-05-11 14:11 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list

Hi,

On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
> Broadcom's Cygnus chip has a USB 2.0 host controller connected to
> three separate phys. One of the phs (port 2) is also connectd to
> a usb 2.0 device controller
>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> ---
>   .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69 ++++++++++++++++++++++
>   include/dt-bindings/phy/phy.h                      |  2 +
>   2 files changed, 71 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>
> diff --git a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
> new file mode 100644
> index 0000000..ec62044
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
> @@ -0,0 +1,69 @@
> +BROADCOM CYGNUS USB PHY
> +
> +Required Properties:
> +	- compatible:  brcm,cygnus-usb-phy
> +	- reg : usbphy_regs - Base address of phy registers
> +			usb2h_idm_regs - Base address of host idm registers
> +			usb2d_idm_regs - Base address of device idm registers
> +	- phy-cells - must be 1 for each port declared. The node
> +		      that uses the phy must provide either PHY_CONFIG_DEVICE for device
> +		      or PHY_CONFIG_HOST for host
> +
> +NOTE: port 0 and port 1 are host only and port 2 can be configured for host or
> +device.
> +
> +Example of phy :
> +	usbphy0: usbphy@0x0301c000 {
> +		compatible = "brcm,cygnus-usb-phy";
> +		reg = <0x0301c000 0x2000>,
> +		      <0x18115000 0x1000>,
> +		      <0x18111000 0x1000>;
> +		status = "okay";
> +
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		usbphy0_0: usbphy0@0 {
> +			#phy-cells = <1>;
> +			reg = <0>;
> +			status = "okay";
> +			phy-supply = <&vbus_p0>;
> +		};
> +
> +		usbphy0_1: usbphy0@1 {
> +			#phy-cells = <1>;
> +			reg = <1>;
> +			status = "okay";
> +		};
> +
> +		usbphy0_2: usbphy0@2 {
> +			#phy-cells = <1>;
> +			reg = <2>;
> +			status = "okay";
> +			phy-supply = <&vbus_p2>;
> +		};
> +	};
> +
> +Example of node using the phy:
> +
> +	/* This nodes declares all three ports as host */
> +
> +	ehci0: usb@0x18048000 {
> +		compatible = "generic-ehci";
> +		reg = <0x18048000 0x100>;
> +		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
> +		phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST &usbphy0_2 PHY_CONFIG_HOST>;
> +		status = "okay";
> +	};
> +
> +	/*
> +	 * This node declares port 2 phy
> +	 * and configures it for device
> +	 */
> +
> +	usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
> +		compatible = "iproc-udc";
> +		reg = <0x1804c000 0x2000>;
> +		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
> +		phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
> +		phy-names = "usb";
> +	};
> diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
> index 6c90193..3f6b1ac 100644
> --- a/include/dt-bindings/phy/phy.h
> +++ b/include/dt-bindings/phy/phy.h
> @@ -15,5 +15,7 @@
>   #define PHY_TYPE_PCIE		2
>   #define PHY_TYPE_USB2		3
>   #define PHY_TYPE_USB3		4
> +#define PHY_CONFIG_HOST		1
> +#define PHY_CONFIG_DEVICE	0

'0' and '1' are already defined for "PHY_NONE" and "PHY_TYPE_SATA". Is this for 
USB2 or for USB3?

Thanks
Kishon

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

* Re: [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-05-11 14:11     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 24+ messages in thread
From: Kishon Vijay Abraham I @ 2015-05-11 14:23 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list

Hi,

On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
> Broadcom's Cygnus chip has a USB 2.0 host controller connected to
> three separate phys. One of the phs (port 2) is also connectd to
> a usb 2.0 device controller
>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> ---
>   .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69 ++++++++++++++++++++++
>   include/dt-bindings/phy/phy.h                      |  2 +
>   2 files changed, 71 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>
> diff --git a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
> new file mode 100644
> index 0000000..ec62044
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
> @@ -0,0 +1,69 @@
> +BROADCOM CYGNUS USB PHY
> +
> +Required Properties:
> +	- compatible:  brcm,cygnus-usb-phy
> +	- reg : usbphy_regs - Base address of phy registers
> +			usb2h_idm_regs - Base address of host idm registers
> +			usb2d_idm_regs - Base address of device idm registers
> +	- phy-cells - must be 1 for each port declared. The node
> +		      that uses the phy must provide either PHY_CONFIG_DEVICE for device
> +		      or PHY_CONFIG_HOST for host
> +
> +NOTE: port 0 and port 1 are host only and port 2 can be configured for host or
> +device.
> +
> +Example of phy :
> +	usbphy0: usbphy@0x0301c000 {
> +		compatible = "brcm,cygnus-usb-phy";
> +		reg = <0x0301c000 0x2000>,
> +		      <0x18115000 0x1000>,
> +		      <0x18111000 0x1000>;
> +		status = "okay";
> +
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		usbphy0_0: usbphy0@0 {
> +			#phy-cells = <1>;
> +			reg = <0>;
> +			status = "okay";
> +			phy-supply = <&vbus_p0>;
> +		};
> +
> +		usbphy0_1: usbphy0@1 {
> +			#phy-cells = <1>;
> +			reg = <1>;
> +			status = "okay";
> +		};
> +
> +		usbphy0_2: usbphy0@2 {
> +			#phy-cells = <1>;
> +			reg = <2>;
> +			status = "okay";
> +			phy-supply = <&vbus_p2>;
> +		};
> +	};
> +
> +Example of node using the phy:
> +
> +	/* This nodes declares all three ports as host */
> +
> +	ehci0: usb@0x18048000 {
> +		compatible = "generic-ehci";
> +		reg = <0x18048000 0x100>;
> +		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
> +		phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST &usbphy0_2 PHY_CONFIG_HOST>;
> +		status = "okay";
> +	};
> +
> +	/*
> +	 * This node declares port 2 phy
> +	 * and configures it for device
> +	 */
> +
> +	usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
> +		compatible = "iproc-udc";
> +		reg = <0x1804c000 0x2000>;
> +		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
> +		phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
> +		phy-names = "usb";
> +	};
> diff --git a/include/dt-bindings/phy/phy.h b/include/dt-bindings/phy/phy.h
> index 6c90193..3f6b1ac 100644
> --- a/include/dt-bindings/phy/phy.h
> +++ b/include/dt-bindings/phy/phy.h
> @@ -15,5 +15,7 @@
>   #define PHY_TYPE_PCIE		2
>   #define PHY_TYPE_USB2		3
>   #define PHY_TYPE_USB3		4
> +#define PHY_CONFIG_HOST		1
> +#define PHY_CONFIG_DEVICE	0

'0' and '1' are already defined for "PHY_NONE" and "PHY_TYPE_SATA". Is this for 
USB2 or for USB3?

Thanks
Kishon

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

* Re: [PATCH v3 3/3] phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver
  2015-04-22 23:14   ` Arun Ramamurthy
  (?)
@ 2015-05-11 14:37     ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 24+ messages in thread
From: Kishon Vijay Abraham I @ 2015-05-11 14:37 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Dmitry Torokhov

Hi,

On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
> This driver adds support for USB 2.0 host and device phy for
> Broadcom's Cygnus chipset. The host controller is connected to
> three separate phys and one of the phys (port 2) is connected to
> the device controller
>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> ---
>   drivers/phy/Kconfig              |  12 +
>   drivers/phy/Makefile             |   1 +
>   drivers/phy/phy-bcm-cygnus-usb.c | 504 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 517 insertions(+)
>   create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 2962de2..0aa62dc 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -291,4 +291,16 @@ config PHY_QCOM_UFS
>   	help
>   	  Support for UFS PHY on QCOM chipsets.
>
> +config PHY_BCM_CYGNUS_USB
> +	tristate "Broadcom Cygnus USB PHY support"
> +	depends on OF
> +	depends on ARCH_BCM_CYGNUS || COMPILE_TEST
> +	select GENERIC_PHY
> +	default ARCH_BCM_CYGNUS
> +	help
> +	  Enable this to support the USB PHY in Broadcom's Cygnus chip.
> +	  The phys are capable of supporting host mode for all ports
> +	  and device mode for port 2. The host or device configuration is
> +	  read from the device tree.
> +
>   endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index f080e1b..47a37fa 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
>   obj-$(CONFIG_PHY_BERLIN_USB)		+= phy-berlin-usb.o
>   obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
>   obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)	+= phy-armada375-usb2.o
> +obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
>   obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
>   obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>   obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
> diff --git a/drivers/phy/phy-bcm-cygnus-usb.c b/drivers/phy/phy-bcm-cygnus-usb.c
> new file mode 100644
> index 0000000..e718404
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-cygnus-usb.c
> @@ -0,0 +1,504 @@
> +/*
> + * Copyright (C) 2015 Broadcom Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/delay.h>
> +
> +#define CDRU_USBPHY_CLK_RST_SEL_OFFSET			0x11b4
> +#define CDRU_USBPHY2_HOST_DEV_SEL_OFFSET		0x11b8
> +#define CDRU_SPARE_REG_0_OFFSET				0x1238
> +#define CRMU_USB_PHY_AON_CTRL_OFFSET			0x00028
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET		0x1210
> +#define CDRU_USBPHY_P0_STATUS_OFFSET			0x11D0
> +#define CDRU_USBPHY_P1_STATUS_OFFSET			0x11E8
> +#define CDRU_USBPHY_P2_STATUS_OFFSET			0x1200
> +#define CDRU_USBPHY_USBPHY_ILDO_ON_FLAG			1
> +#define CDRU_USBPHY_USBPHY_PLL_LOCK			0
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
> +#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
> +
> +#define CRMU_USBPHY_P0_AFE_CORERDY_VDDC			1
> +#define CRMU_USBPHY_P0_RESETB				2
> +#define CRMU_USBPHY_P1_AFE_CORERDY_VDDC			9
> +#define CRMU_USBPHY_P1_RESETB				10
> +#define CRMU_USBPHY_P2_AFE_CORERDY_VDDC			17
> +#define CRMU_USBPHY_P2_RESETB				18
> +
> +#define USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET		0x0408
> +#define USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable	0
> +#define USB2_IDM_IDM_RESET_CONTROL_OFFSET		0x0800
> +#define USB2_IDM_IDM_RESET_CONTROL__RESET		0
> +
> +#define PLL_LOCK_RETRY_COUNT	1000
> +#define MAX_PHY_PORTS		3
> +
> +static int power_bit[] = {CRMU_USBPHY_P0_AFE_CORERDY_VDDC,
> +				CRMU_USBPHY_P1_AFE_CORERDY_VDDC,
> +				CRMU_USBPHY_P2_AFE_CORERDY_VDDC};
> +static int reset_bit[] = {CRMU_USBPHY_P0_RESETB,
> +				CRMU_USBPHY_P1_RESETB,
> +				CRMU_USBPHY_P2_RESETB};
> +static int status_reg[] = {CDRU_USBPHY_P0_STATUS_OFFSET,
> +				CDRU_USBPHY_P1_STATUS_OFFSET,
> +				CDRU_USBPHY_P2_STATUS_OFFSET};
> +
> +struct bcm_phy_instance;
> +
> +struct bcm_phy_driver {
> +	void __iomem *usbphy_regs;
> +	void __iomem *usb2h_idm_regs;
> +	void __iomem *usb2d_idm_regs;
> +	struct bcm_phy_instance *ports[MAX_PHY_PORTS];
> +	spinlock_t lock;
> +	bool idm_host_enabled;
> +};
> +
> +struct bcm_phy_instance {
> +	struct bcm_phy_driver *driver;
> +	struct phy *generic_phy;
> +	int port_no;
> +	bool host_mode; /* true - Host, false - device */
> +	bool power;
> +};
> +
> +static inline int bcm_phy_cdru_usbphy_status_wait(u32 usb_reg, int reg_bit,
> +					  struct bcm_phy_driver *phy_driver)
> +{
> +	/* Wait for the PLL lock status */
> +	int retry = PLL_LOCK_RETRY_COUNT;
> +	u32 reg_val;
> +
> +	do {
> +		udelay(1);
> +		reg_val = readl(phy_driver->usbphy_regs +
> +				usb_reg);
> +		if (reg_val & (1 << reg_bit))
> +			return 0;
> +	} while (--retry > 0);
> +
> +	return -EBUSY;
> +
> +}
> +
> +static struct phy *bcm_usb_phy_xlate(struct device *dev,
> +				     struct of_phandle_args *args)
> +{
> +	struct bcm_phy_driver *phy_driver = dev_get_drvdata(dev);
> +	struct bcm_phy_instance *port = NULL;
> +	int i;
> +
> +	if (!phy_driver)
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args_count != 1))
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args[0] < 0 || args->args[0] > 1))
> +		return ERR_PTR(-ENODEV);
> +
> +	for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
> +		struct bcm_phy_instance *p = phy_driver->ports[i];
> +
> +		if (p && p->generic_phy->dev.of_node == args->np) {
> +			port = p;
> +			break;
> +		}
> +	}
> +
> +	if (!port) {
> +		dev_err(dev, "Failed to locate phy %s\n", args->np->name);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	port->host_mode = args->args[0];
> +
> +	return port->generic_phy;
> +}
> +
> +static int bcm_phy_init(struct phy *generic_phy)
> +{
> +	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = port->driver;
> +	unsigned long flags;
> +	u32 reg_val;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/*
> +	 * Only PORT 2 is capable of being device and host
> +	 * Default setting is device, check if it is set to host.
> +	 */
> +	if (port->port_no != 2) {

can be a goto here with a label in the end.
> +		spin_unlock_irqrestore(&phy_driver->lock, flags);
> +		return 0;
> +	}
> +
> +	if (port->host_mode) {
> +		writel(PHY2_DEV_HOST_CTRL_SEL_HOST,
> +			phy_driver->usbphy_regs +
> +			CDRU_USBPHY2_HOST_DEV_SEL_OFFSET);
> +	} else {
> +		/*
> +		 * Disable suspend/resume signals to device controller
> +		 * when a port is in device mode.
> +		 */
> +		reg_val = readl(phy_driver->usbphy_regs +
> +			      CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
> +		reg_val |=
> +			1 << CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE;
> +		writel(reg_val, phy_driver->usbphy_regs +
> +		       CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
> +	}
> +
> +
^^spurious blank line.
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +	return 0;
> +}
> +
> +static int bcm_phy_shutdown(struct phy *generic_phy)
> +{
> +	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = port->driver;
> +	unsigned long flags;
> +	int i;
> +	u32 reg_val, powered_on_phy;
> +	bool power_off_flag = true;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* power down the phy */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	reg_val &= ~(1 << power_bit[port->port_no]);
> +	reg_val &= ~(1 << reset_bit[port->port_no]);
> +	writel(reg_val, phy_driver->usbphy_regs +
> +		CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	port->power = false;
> +
> +	/*
> +	 * If a port is configured to device and it is being shutdown,
> +	 * turn off the clocks to the usb device controller.
> +	 */
> +	if (port->port_no == 2 && !port->host_mode) {
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val &= ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);

please avoid using camel case..
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val |= 1 << USB2_IDM_IDM_RESET_CONTROL__RESET;
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +
> +		spin_unlock_irqrestore(&phy_driver->lock, flags);
> +		return 0;
> +	}
> +
> +	/*
> +	 * If the phy being shutdown provides clock and reset to
> +	 * the host controller, change it do a different powered on phy
> +	 * If all phys are powered off, shut of the host controller
> +	 */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +	powered_on_phy = reg_val;

The above statement is useless.
> +	if (reg_val == port->port_no) {
> +		for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
> +			if (phy_driver->ports[i] &&
> +			    phy_driver->ports[i]->power &&
> +			    phy_driver->ports[i]->host_mode) {
> +				power_off_flag = false;
> +				powered_on_phy = i;
> +				break;
> +			}
> +		}
> +	}
> +
> +	if (power_off_flag) {
> +		/*
> +		 * Put the host controller into reset state and
> +		 * disable clock.
> +		 */
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +			USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val &=
> +		  ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val |= (1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		phy_driver->idm_host_enabled = 0;
> +	} else {
> +		writel(powered_on_phy, phy_driver->usbphy_regs +
> +			   CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +	}
> +
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int bcm_phy_poweron(struct phy *generic_phy)
> +{
> +	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = port->driver;
> +	unsigned long flags;
> +	int ret;
> +	u32 reg_val;
> +	bool clock_reset_flag = true;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* Bring the AFE block out of reset to start powering up the PHY */
> +	reg_val = readl(phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	reg_val |= 1 << power_bit[port->port_no];
> +	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	/* Check for power on and PLL lock */
> +	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
> +		   CDRU_USBPHY_USBPHY_ILDO_ON_FLAG, phy_driver);
> +	if (ret < 0) {
> +		dev_err(&generic_phy->dev,
> +			"Timed out waiting for USBPHY_ILDO_ON_FLAG on port %d",
> +			port->port_no);
> +		goto err_shutdown;
> +	}
> +	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
> +		CDRU_USBPHY_USBPHY_PLL_LOCK, phy_driver);
> +	if (ret < 0) {
> +		dev_err(&generic_phy->dev,
> +			"Timed out waiting for USBPHY_PLL_LOCK on port %d",
> +			port->port_no);
> +		goto err_shutdown;
> +	}
> +	port->power = true;
> +
> +	/* Check if the port 2 is configured for device */
> +	if (port->port_no == 2 && !port->host_mode) {
> +		/*
> +		 * Enable clock to USB device and get the USB device
> +		 * out of reset.
> +		 */
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +
> +	} else {
> +		reg_val = readl(phy_driver->usbphy_regs +
> +				CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +
> +		/*
> +		 * Check if the phy that is configured to provide clock
> +		 * and reset is powered on.
> +		 */
> +		if (reg_val >= 0 && reg_val < ARRAY_SIZE(phy_driver->ports))
> +			if (phy_driver->ports[reg_val])
> +				if (phy_driver->ports[reg_val]->power)
> +					clock_reset_flag = false;
> +
> +		/* if not set the current phy */
> +		if (clock_reset_flag) {
> +			reg_val = port->port_no;
> +			writel(reg_val, phy_driver->usbphy_regs +
> +			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		}
> +	}
> +
> +	if (!phy_driver->idm_host_enabled) {
> +		/* Enable clock to USB and get the USB out of reset */
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		phy_driver->idm_host_enabled = true;
> +	}
> +
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +	return 0;
> +
> +err_shutdown:
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +	bcm_phy_shutdown(generic_phy);

Instead of calling the phy_shutdown, you can just power off the PHY.
> +	return ret;
> +}
> +
> +static struct phy_ops ops = {
> +	.init		= bcm_phy_init,
> +	.power_on	= bcm_phy_poweron,
> +	.power_off	= bcm_phy_shutdown,
> +};
> +
> +static const struct of_device_id bcm_phy_dt_ids[] = {
> +	{ .compatible = "brcm,cygnus-usb-phy", },
> +	{ }
> +};
> +
> +static int bcm_phy_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct bcm_phy_driver *phy_driver;
> +	struct phy_provider *phy_provider;
> +	struct device_node *child;
> +	struct resource *res;
> +	int error;
> +	u32 reg_val;
> +
> +	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
> +				  GFP_KERNEL);
> +	if (!phy_driver)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&phy_driver->lock);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "missing memory resource usbphy_regs\n");
> +		return -EINVAL;
> +	}
> +	phy_driver->usbphy_regs = devm_ioremap_nocache(dev, res->start,
> +						resource_size(res));
> +	if (!phy_driver->usbphy_regs) {
> +		dev_err(dev, "Failed to remap usbphy_regs\n");
> +		return -ENOMEM;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	if (!res) {
> +		dev_err(&pdev->dev, "missing memory resource ubs2h_idm_regs\n");
> +		return -EINVAL;
> +	}
> +	phy_driver->usb2h_idm_regs = devm_ioremap_nocache(dev, res->start,
> +						  resource_size(res));
> +	if (!phy_driver->usb2h_idm_regs) {
> +		dev_err(dev, "Failed to remap usb2h_idm_regs\n");
> +		return -ENOMEM;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	if (!res) {
> +		dev_err(&pdev->dev, "missing memory resource ubs2d_idm_regs\n");
> +		return -EINVAL;
> +	}
> +	phy_driver->usb2d_idm_regs = devm_ioremap_nocache(dev, res->start,
> +						   resource_size(res));
> +	if (!phy_driver->usb2d_idm_regs) {
> +		dev_err(dev, "Failed to remap usb2d_idm_regs\n");
> +		return -ENOMEM;
> +	}
> +
> +	dev_set_drvdata(dev, phy_driver);
> +
> +	phy_driver->idm_host_enabled = false;
> +
> +	/* Shut down all ports. They can be powered up as required */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +	reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
> +	reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +	reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
> +	reg_val &= ~(1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
> +	reg_val &= ~(1 << CRMU_USBPHY_P2_RESETB);
> +	writel(reg_val, phy_driver->usbphy_regs +
> +		CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	for_each_available_child_of_node(dev->of_node, child) {
> +		struct bcm_phy_instance *port;
> +		u32 port_no;
> +
> +		if (of_property_read_u32(child, "reg", &port_no)) {
> +			dev_err(dev, "missing reg property in node %s\n",
> +				child->name);
> +			return -EINVAL;
> +		}
> +
> +		if (port_no >= ARRAY_SIZE(phy_driver->ports)) {
> +			dev_err(dev, "invalid reg in node %s: %u\n",
> +				child->name, port_no);
> +			return -EINVAL;
> +		}
> +
> +		port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> +		if (!port)
> +			return -ENOMEM;
> +
> +		port->generic_phy = devm_phy_create(dev, child, &ops);
> +		if (IS_ERR(port->generic_phy)) {
> +			error = PTR_ERR(port->generic_phy);
> +			dev_err(dev, "Failed to create phy %u: %d",
> +				port_no, error);
> +			return error;
> +		}
> +
> +		port->port_no = port_no;
> +		port->driver = phy_driver;
> +		phy_set_drvdata(port->generic_phy, port);
> +
> +		phy_driver->ports[port_no] = port;
> +	}
> +
> +	phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate);
> +	if (IS_ERR(phy_provider)) {
> +		error = PTR_ERR(phy_provider);
> +		dev_err(dev, "Failed to register as phy provider: %d\n",
> +			error);
> +		return error;
> +	}
> +
> +	dev_set_drvdata(pdev, phy_driver);

dev_set_drvdata is being done multiple times.

Please also run checkpatch and fix all the errors and warnings before posting 
the next version.

Thanks
Kishon

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

* Re: [PATCH v3 3/3] phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver
@ 2015-05-11 14:37     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 24+ messages in thread
From: Kishon Vijay Abraham I @ 2015-05-11 14:37 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Dmitry Torokhov

Hi,

On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
> This driver adds support for USB 2.0 host and device phy for
> Broadcom's Cygnus chipset. The host controller is connected to
> three separate phys and one of the phys (port 2) is connected to
> the device controller
>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> ---
>   drivers/phy/Kconfig              |  12 +
>   drivers/phy/Makefile             |   1 +
>   drivers/phy/phy-bcm-cygnus-usb.c | 504 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 517 insertions(+)
>   create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 2962de2..0aa62dc 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -291,4 +291,16 @@ config PHY_QCOM_UFS
>   	help
>   	  Support for UFS PHY on QCOM chipsets.
>
> +config PHY_BCM_CYGNUS_USB
> +	tristate "Broadcom Cygnus USB PHY support"
> +	depends on OF
> +	depends on ARCH_BCM_CYGNUS || COMPILE_TEST
> +	select GENERIC_PHY
> +	default ARCH_BCM_CYGNUS
> +	help
> +	  Enable this to support the USB PHY in Broadcom's Cygnus chip.
> +	  The phys are capable of supporting host mode for all ports
> +	  and device mode for port 2. The host or device configuration is
> +	  read from the device tree.
> +
>   endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index f080e1b..47a37fa 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
>   obj-$(CONFIG_PHY_BERLIN_USB)		+= phy-berlin-usb.o
>   obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
>   obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)	+= phy-armada375-usb2.o
> +obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
>   obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
>   obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>   obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
> diff --git a/drivers/phy/phy-bcm-cygnus-usb.c b/drivers/phy/phy-bcm-cygnus-usb.c
> new file mode 100644
> index 0000000..e718404
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-cygnus-usb.c
> @@ -0,0 +1,504 @@
> +/*
> + * Copyright (C) 2015 Broadcom Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/delay.h>
> +
> +#define CDRU_USBPHY_CLK_RST_SEL_OFFSET			0x11b4
> +#define CDRU_USBPHY2_HOST_DEV_SEL_OFFSET		0x11b8
> +#define CDRU_SPARE_REG_0_OFFSET				0x1238
> +#define CRMU_USB_PHY_AON_CTRL_OFFSET			0x00028
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET		0x1210
> +#define CDRU_USBPHY_P0_STATUS_OFFSET			0x11D0
> +#define CDRU_USBPHY_P1_STATUS_OFFSET			0x11E8
> +#define CDRU_USBPHY_P2_STATUS_OFFSET			0x1200
> +#define CDRU_USBPHY_USBPHY_ILDO_ON_FLAG			1
> +#define CDRU_USBPHY_USBPHY_PLL_LOCK			0
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
> +#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
> +
> +#define CRMU_USBPHY_P0_AFE_CORERDY_VDDC			1
> +#define CRMU_USBPHY_P0_RESETB				2
> +#define CRMU_USBPHY_P1_AFE_CORERDY_VDDC			9
> +#define CRMU_USBPHY_P1_RESETB				10
> +#define CRMU_USBPHY_P2_AFE_CORERDY_VDDC			17
> +#define CRMU_USBPHY_P2_RESETB				18
> +
> +#define USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET		0x0408
> +#define USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable	0
> +#define USB2_IDM_IDM_RESET_CONTROL_OFFSET		0x0800
> +#define USB2_IDM_IDM_RESET_CONTROL__RESET		0
> +
> +#define PLL_LOCK_RETRY_COUNT	1000
> +#define MAX_PHY_PORTS		3
> +
> +static int power_bit[] = {CRMU_USBPHY_P0_AFE_CORERDY_VDDC,
> +				CRMU_USBPHY_P1_AFE_CORERDY_VDDC,
> +				CRMU_USBPHY_P2_AFE_CORERDY_VDDC};
> +static int reset_bit[] = {CRMU_USBPHY_P0_RESETB,
> +				CRMU_USBPHY_P1_RESETB,
> +				CRMU_USBPHY_P2_RESETB};
> +static int status_reg[] = {CDRU_USBPHY_P0_STATUS_OFFSET,
> +				CDRU_USBPHY_P1_STATUS_OFFSET,
> +				CDRU_USBPHY_P2_STATUS_OFFSET};
> +
> +struct bcm_phy_instance;
> +
> +struct bcm_phy_driver {
> +	void __iomem *usbphy_regs;
> +	void __iomem *usb2h_idm_regs;
> +	void __iomem *usb2d_idm_regs;
> +	struct bcm_phy_instance *ports[MAX_PHY_PORTS];
> +	spinlock_t lock;
> +	bool idm_host_enabled;
> +};
> +
> +struct bcm_phy_instance {
> +	struct bcm_phy_driver *driver;
> +	struct phy *generic_phy;
> +	int port_no;
> +	bool host_mode; /* true - Host, false - device */
> +	bool power;
> +};
> +
> +static inline int bcm_phy_cdru_usbphy_status_wait(u32 usb_reg, int reg_bit,
> +					  struct bcm_phy_driver *phy_driver)
> +{
> +	/* Wait for the PLL lock status */
> +	int retry = PLL_LOCK_RETRY_COUNT;
> +	u32 reg_val;
> +
> +	do {
> +		udelay(1);
> +		reg_val = readl(phy_driver->usbphy_regs +
> +				usb_reg);
> +		if (reg_val & (1 << reg_bit))
> +			return 0;
> +	} while (--retry > 0);
> +
> +	return -EBUSY;
> +
> +}
> +
> +static struct phy *bcm_usb_phy_xlate(struct device *dev,
> +				     struct of_phandle_args *args)
> +{
> +	struct bcm_phy_driver *phy_driver = dev_get_drvdata(dev);
> +	struct bcm_phy_instance *port = NULL;
> +	int i;
> +
> +	if (!phy_driver)
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args_count != 1))
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args[0] < 0 || args->args[0] > 1))
> +		return ERR_PTR(-ENODEV);
> +
> +	for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
> +		struct bcm_phy_instance *p = phy_driver->ports[i];
> +
> +		if (p && p->generic_phy->dev.of_node == args->np) {
> +			port = p;
> +			break;
> +		}
> +	}
> +
> +	if (!port) {
> +		dev_err(dev, "Failed to locate phy %s\n", args->np->name);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	port->host_mode = args->args[0];
> +
> +	return port->generic_phy;
> +}
> +
> +static int bcm_phy_init(struct phy *generic_phy)
> +{
> +	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = port->driver;
> +	unsigned long flags;
> +	u32 reg_val;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/*
> +	 * Only PORT 2 is capable of being device and host
> +	 * Default setting is device, check if it is set to host.
> +	 */
> +	if (port->port_no != 2) {

can be a goto here with a label in the end.
> +		spin_unlock_irqrestore(&phy_driver->lock, flags);
> +		return 0;
> +	}
> +
> +	if (port->host_mode) {
> +		writel(PHY2_DEV_HOST_CTRL_SEL_HOST,
> +			phy_driver->usbphy_regs +
> +			CDRU_USBPHY2_HOST_DEV_SEL_OFFSET);
> +	} else {
> +		/*
> +		 * Disable suspend/resume signals to device controller
> +		 * when a port is in device mode.
> +		 */
> +		reg_val = readl(phy_driver->usbphy_regs +
> +			      CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
> +		reg_val |=
> +			1 << CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE;
> +		writel(reg_val, phy_driver->usbphy_regs +
> +		       CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
> +	}
> +
> +
^^spurious blank line.
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +	return 0;
> +}
> +
> +static int bcm_phy_shutdown(struct phy *generic_phy)
> +{
> +	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = port->driver;
> +	unsigned long flags;
> +	int i;
> +	u32 reg_val, powered_on_phy;
> +	bool power_off_flag = true;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* power down the phy */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	reg_val &= ~(1 << power_bit[port->port_no]);
> +	reg_val &= ~(1 << reset_bit[port->port_no]);
> +	writel(reg_val, phy_driver->usbphy_regs +
> +		CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	port->power = false;
> +
> +	/*
> +	 * If a port is configured to device and it is being shutdown,
> +	 * turn off the clocks to the usb device controller.
> +	 */
> +	if (port->port_no == 2 && !port->host_mode) {
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val &= ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);

please avoid using camel case..
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val |= 1 << USB2_IDM_IDM_RESET_CONTROL__RESET;
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +
> +		spin_unlock_irqrestore(&phy_driver->lock, flags);
> +		return 0;
> +	}
> +
> +	/*
> +	 * If the phy being shutdown provides clock and reset to
> +	 * the host controller, change it do a different powered on phy
> +	 * If all phys are powered off, shut of the host controller
> +	 */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +	powered_on_phy = reg_val;

The above statement is useless.
> +	if (reg_val == port->port_no) {
> +		for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
> +			if (phy_driver->ports[i] &&
> +			    phy_driver->ports[i]->power &&
> +			    phy_driver->ports[i]->host_mode) {
> +				power_off_flag = false;
> +				powered_on_phy = i;
> +				break;
> +			}
> +		}
> +	}
> +
> +	if (power_off_flag) {
> +		/*
> +		 * Put the host controller into reset state and
> +		 * disable clock.
> +		 */
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +			USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val &=
> +		  ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val |= (1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		phy_driver->idm_host_enabled = 0;
> +	} else {
> +		writel(powered_on_phy, phy_driver->usbphy_regs +
> +			   CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +	}
> +
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int bcm_phy_poweron(struct phy *generic_phy)
> +{
> +	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = port->driver;
> +	unsigned long flags;
> +	int ret;
> +	u32 reg_val;
> +	bool clock_reset_flag = true;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* Bring the AFE block out of reset to start powering up the PHY */
> +	reg_val = readl(phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	reg_val |= 1 << power_bit[port->port_no];
> +	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	/* Check for power on and PLL lock */
> +	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
> +		   CDRU_USBPHY_USBPHY_ILDO_ON_FLAG, phy_driver);
> +	if (ret < 0) {
> +		dev_err(&generic_phy->dev,
> +			"Timed out waiting for USBPHY_ILDO_ON_FLAG on port %d",
> +			port->port_no);
> +		goto err_shutdown;
> +	}
> +	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
> +		CDRU_USBPHY_USBPHY_PLL_LOCK, phy_driver);
> +	if (ret < 0) {
> +		dev_err(&generic_phy->dev,
> +			"Timed out waiting for USBPHY_PLL_LOCK on port %d",
> +			port->port_no);
> +		goto err_shutdown;
> +	}
> +	port->power = true;
> +
> +	/* Check if the port 2 is configured for device */
> +	if (port->port_no == 2 && !port->host_mode) {
> +		/*
> +		 * Enable clock to USB device and get the USB device
> +		 * out of reset.
> +		 */
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +
> +	} else {
> +		reg_val = readl(phy_driver->usbphy_regs +
> +				CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +
> +		/*
> +		 * Check if the phy that is configured to provide clock
> +		 * and reset is powered on.
> +		 */
> +		if (reg_val >= 0 && reg_val < ARRAY_SIZE(phy_driver->ports))
> +			if (phy_driver->ports[reg_val])
> +				if (phy_driver->ports[reg_val]->power)
> +					clock_reset_flag = false;
> +
> +		/* if not set the current phy */
> +		if (clock_reset_flag) {
> +			reg_val = port->port_no;
> +			writel(reg_val, phy_driver->usbphy_regs +
> +			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		}
> +	}
> +
> +	if (!phy_driver->idm_host_enabled) {
> +		/* Enable clock to USB and get the USB out of reset */
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		phy_driver->idm_host_enabled = true;
> +	}
> +
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +	return 0;
> +
> +err_shutdown:
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +	bcm_phy_shutdown(generic_phy);

Instead of calling the phy_shutdown, you can just power off the PHY.
> +	return ret;
> +}
> +
> +static struct phy_ops ops = {
> +	.init		= bcm_phy_init,
> +	.power_on	= bcm_phy_poweron,
> +	.power_off	= bcm_phy_shutdown,
> +};
> +
> +static const struct of_device_id bcm_phy_dt_ids[] = {
> +	{ .compatible = "brcm,cygnus-usb-phy", },
> +	{ }
> +};
> +
> +static int bcm_phy_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct bcm_phy_driver *phy_driver;
> +	struct phy_provider *phy_provider;
> +	struct device_node *child;
> +	struct resource *res;
> +	int error;
> +	u32 reg_val;
> +
> +	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
> +				  GFP_KERNEL);
> +	if (!phy_driver)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&phy_driver->lock);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "missing memory resource usbphy_regs\n");
> +		return -EINVAL;
> +	}
> +	phy_driver->usbphy_regs = devm_ioremap_nocache(dev, res->start,
> +						resource_size(res));
> +	if (!phy_driver->usbphy_regs) {
> +		dev_err(dev, "Failed to remap usbphy_regs\n");
> +		return -ENOMEM;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	if (!res) {
> +		dev_err(&pdev->dev, "missing memory resource ubs2h_idm_regs\n");
> +		return -EINVAL;
> +	}
> +	phy_driver->usb2h_idm_regs = devm_ioremap_nocache(dev, res->start,
> +						  resource_size(res));
> +	if (!phy_driver->usb2h_idm_regs) {
> +		dev_err(dev, "Failed to remap usb2h_idm_regs\n");
> +		return -ENOMEM;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	if (!res) {
> +		dev_err(&pdev->dev, "missing memory resource ubs2d_idm_regs\n");
> +		return -EINVAL;
> +	}
> +	phy_driver->usb2d_idm_regs = devm_ioremap_nocache(dev, res->start,
> +						   resource_size(res));
> +	if (!phy_driver->usb2d_idm_regs) {
> +		dev_err(dev, "Failed to remap usb2d_idm_regs\n");
> +		return -ENOMEM;
> +	}
> +
> +	dev_set_drvdata(dev, phy_driver);
> +
> +	phy_driver->idm_host_enabled = false;
> +
> +	/* Shut down all ports. They can be powered up as required */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +	reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
> +	reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +	reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
> +	reg_val &= ~(1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
> +	reg_val &= ~(1 << CRMU_USBPHY_P2_RESETB);
> +	writel(reg_val, phy_driver->usbphy_regs +
> +		CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	for_each_available_child_of_node(dev->of_node, child) {
> +		struct bcm_phy_instance *port;
> +		u32 port_no;
> +
> +		if (of_property_read_u32(child, "reg", &port_no)) {
> +			dev_err(dev, "missing reg property in node %s\n",
> +				child->name);
> +			return -EINVAL;
> +		}
> +
> +		if (port_no >= ARRAY_SIZE(phy_driver->ports)) {
> +			dev_err(dev, "invalid reg in node %s: %u\n",
> +				child->name, port_no);
> +			return -EINVAL;
> +		}
> +
> +		port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> +		if (!port)
> +			return -ENOMEM;
> +
> +		port->generic_phy = devm_phy_create(dev, child, &ops);
> +		if (IS_ERR(port->generic_phy)) {
> +			error = PTR_ERR(port->generic_phy);
> +			dev_err(dev, "Failed to create phy %u: %d",
> +				port_no, error);
> +			return error;
> +		}
> +
> +		port->port_no = port_no;
> +		port->driver = phy_driver;
> +		phy_set_drvdata(port->generic_phy, port);
> +
> +		phy_driver->ports[port_no] = port;
> +	}
> +
> +	phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate);
> +	if (IS_ERR(phy_provider)) {
> +		error = PTR_ERR(phy_provider);
> +		dev_err(dev, "Failed to register as phy provider: %d\n",
> +			error);
> +		return error;
> +	}
> +
> +	dev_set_drvdata(pdev, phy_driver);

dev_set_drvdata is being done multiple times.

Please also run checkpatch and fix all the errors and warnings before posting 
the next version.

Thanks
Kishon

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

* Re: [PATCH v3 3/3] phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver
@ 2015-05-11 14:37     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 24+ messages in thread
From: Kishon Vijay Abraham I @ 2015-05-11 14:49 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list, Dmitry Torokhov

Hi,

On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
> This driver adds support for USB 2.0 host and device phy for
> Broadcom's Cygnus chipset. The host controller is connected to
> three separate phys and one of the phys (port 2) is connected to
> the device controller
>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> Signed-off-by: Dmitry Torokhov <dtor@chromium.org>
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> ---
>   drivers/phy/Kconfig              |  12 +
>   drivers/phy/Makefile             |   1 +
>   drivers/phy/phy-bcm-cygnus-usb.c | 504 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 517 insertions(+)
>   create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 2962de2..0aa62dc 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -291,4 +291,16 @@ config PHY_QCOM_UFS
>   	help
>   	  Support for UFS PHY on QCOM chipsets.
>
> +config PHY_BCM_CYGNUS_USB
> +	tristate "Broadcom Cygnus USB PHY support"
> +	depends on OF
> +	depends on ARCH_BCM_CYGNUS || COMPILE_TEST
> +	select GENERIC_PHY
> +	default ARCH_BCM_CYGNUS
> +	help
> +	  Enable this to support the USB PHY in Broadcom's Cygnus chip.
> +	  The phys are capable of supporting host mode for all ports
> +	  and device mode for port 2. The host or device configuration is
> +	  read from the device tree.
> +
>   endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index f080e1b..47a37fa 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -6,6 +6,7 @@ obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o
>   obj-$(CONFIG_PHY_BERLIN_USB)		+= phy-berlin-usb.o
>   obj-$(CONFIG_PHY_BERLIN_SATA)		+= phy-berlin-sata.o
>   obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY)	+= phy-armada375-usb2.o
> +obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
>   obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
>   obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>   obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
> diff --git a/drivers/phy/phy-bcm-cygnus-usb.c b/drivers/phy/phy-bcm-cygnus-usb.c
> new file mode 100644
> index 0000000..e718404
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-cygnus-usb.c
> @@ -0,0 +1,504 @@
> +/*
> + * Copyright (C) 2015 Broadcom Corporation
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/delay.h>
> +
> +#define CDRU_USBPHY_CLK_RST_SEL_OFFSET			0x11b4
> +#define CDRU_USBPHY2_HOST_DEV_SEL_OFFSET		0x11b8
> +#define CDRU_SPARE_REG_0_OFFSET				0x1238
> +#define CRMU_USB_PHY_AON_CTRL_OFFSET			0x00028
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET		0x1210
> +#define CDRU_USBPHY_P0_STATUS_OFFSET			0x11D0
> +#define CDRU_USBPHY_P1_STATUS_OFFSET			0x11E8
> +#define CDRU_USBPHY_P2_STATUS_OFFSET			0x1200
> +#define CDRU_USBPHY_USBPHY_ILDO_ON_FLAG			1
> +#define CDRU_USBPHY_USBPHY_PLL_LOCK			0
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
> +#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
> +
> +#define CRMU_USBPHY_P0_AFE_CORERDY_VDDC			1
> +#define CRMU_USBPHY_P0_RESETB				2
> +#define CRMU_USBPHY_P1_AFE_CORERDY_VDDC			9
> +#define CRMU_USBPHY_P1_RESETB				10
> +#define CRMU_USBPHY_P2_AFE_CORERDY_VDDC			17
> +#define CRMU_USBPHY_P2_RESETB				18
> +
> +#define USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET		0x0408
> +#define USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable	0
> +#define USB2_IDM_IDM_RESET_CONTROL_OFFSET		0x0800
> +#define USB2_IDM_IDM_RESET_CONTROL__RESET		0
> +
> +#define PLL_LOCK_RETRY_COUNT	1000
> +#define MAX_PHY_PORTS		3
> +
> +static int power_bit[] = {CRMU_USBPHY_P0_AFE_CORERDY_VDDC,
> +				CRMU_USBPHY_P1_AFE_CORERDY_VDDC,
> +				CRMU_USBPHY_P2_AFE_CORERDY_VDDC};
> +static int reset_bit[] = {CRMU_USBPHY_P0_RESETB,
> +				CRMU_USBPHY_P1_RESETB,
> +				CRMU_USBPHY_P2_RESETB};
> +static int status_reg[] = {CDRU_USBPHY_P0_STATUS_OFFSET,
> +				CDRU_USBPHY_P1_STATUS_OFFSET,
> +				CDRU_USBPHY_P2_STATUS_OFFSET};
> +
> +struct bcm_phy_instance;
> +
> +struct bcm_phy_driver {
> +	void __iomem *usbphy_regs;
> +	void __iomem *usb2h_idm_regs;
> +	void __iomem *usb2d_idm_regs;
> +	struct bcm_phy_instance *ports[MAX_PHY_PORTS];
> +	spinlock_t lock;
> +	bool idm_host_enabled;
> +};
> +
> +struct bcm_phy_instance {
> +	struct bcm_phy_driver *driver;
> +	struct phy *generic_phy;
> +	int port_no;
> +	bool host_mode; /* true - Host, false - device */
> +	bool power;
> +};
> +
> +static inline int bcm_phy_cdru_usbphy_status_wait(u32 usb_reg, int reg_bit,
> +					  struct bcm_phy_driver *phy_driver)
> +{
> +	/* Wait for the PLL lock status */
> +	int retry = PLL_LOCK_RETRY_COUNT;
> +	u32 reg_val;
> +
> +	do {
> +		udelay(1);
> +		reg_val = readl(phy_driver->usbphy_regs +
> +				usb_reg);
> +		if (reg_val & (1 << reg_bit))
> +			return 0;
> +	} while (--retry > 0);
> +
> +	return -EBUSY;
> +
> +}
> +
> +static struct phy *bcm_usb_phy_xlate(struct device *dev,
> +				     struct of_phandle_args *args)
> +{
> +	struct bcm_phy_driver *phy_driver = dev_get_drvdata(dev);
> +	struct bcm_phy_instance *port = NULL;
> +	int i;
> +
> +	if (!phy_driver)
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args_count != 1))
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args[0] < 0 || args->args[0] > 1))
> +		return ERR_PTR(-ENODEV);
> +
> +	for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
> +		struct bcm_phy_instance *p = phy_driver->ports[i];
> +
> +		if (p && p->generic_phy->dev.of_node = args->np) {
> +			port = p;
> +			break;
> +		}
> +	}
> +
> +	if (!port) {
> +		dev_err(dev, "Failed to locate phy %s\n", args->np->name);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	port->host_mode = args->args[0];
> +
> +	return port->generic_phy;
> +}
> +
> +static int bcm_phy_init(struct phy *generic_phy)
> +{
> +	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = port->driver;
> +	unsigned long flags;
> +	u32 reg_val;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/*
> +	 * Only PORT 2 is capable of being device and host
> +	 * Default setting is device, check if it is set to host.
> +	 */
> +	if (port->port_no != 2) {

can be a goto here with a label in the end.
> +		spin_unlock_irqrestore(&phy_driver->lock, flags);
> +		return 0;
> +	}
> +
> +	if (port->host_mode) {
> +		writel(PHY2_DEV_HOST_CTRL_SEL_HOST,
> +			phy_driver->usbphy_regs +
> +			CDRU_USBPHY2_HOST_DEV_SEL_OFFSET);
> +	} else {
> +		/*
> +		 * Disable suspend/resume signals to device controller
> +		 * when a port is in device mode.
> +		 */
> +		reg_val = readl(phy_driver->usbphy_regs +
> +			      CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
> +		reg_val |> +			1 << CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE;
> +		writel(reg_val, phy_driver->usbphy_regs +
> +		       CDRU_USB_DEV_SUSPEND_RESUME_CTRL_OFFSET);
> +	}
> +
> +
^^spurious blank line.
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +	return 0;
> +}
> +
> +static int bcm_phy_shutdown(struct phy *generic_phy)
> +{
> +	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = port->driver;
> +	unsigned long flags;
> +	int i;
> +	u32 reg_val, powered_on_phy;
> +	bool power_off_flag = true;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* power down the phy */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	reg_val &= ~(1 << power_bit[port->port_no]);
> +	reg_val &= ~(1 << reset_bit[port->port_no]);
> +	writel(reg_val, phy_driver->usbphy_regs +
> +		CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	port->power = false;
> +
> +	/*
> +	 * If a port is configured to device and it is being shutdown,
> +	 * turn off the clocks to the usb device controller.
> +	 */
> +	if (port->port_no = 2 && !port->host_mode) {
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val &= ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);

please avoid using camel case..
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val |= 1 << USB2_IDM_IDM_RESET_CONTROL__RESET;
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +
> +		spin_unlock_irqrestore(&phy_driver->lock, flags);
> +		return 0;
> +	}
> +
> +	/*
> +	 * If the phy being shutdown provides clock and reset to
> +	 * the host controller, change it do a different powered on phy
> +	 * If all phys are powered off, shut of the host controller
> +	 */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +	powered_on_phy = reg_val;

The above statement is useless.
> +	if (reg_val = port->port_no) {
> +		for (i = 0; i < ARRAY_SIZE(phy_driver->ports); i++) {
> +			if (phy_driver->ports[i] &&
> +			    phy_driver->ports[i]->power &&
> +			    phy_driver->ports[i]->host_mode) {
> +				power_off_flag = false;
> +				powered_on_phy = i;
> +				break;
> +			}
> +		}
> +	}
> +
> +	if (power_off_flag) {
> +		/*
> +		 * Put the host controller into reset state and
> +		 * disable clock.
> +		 */
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +			USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val &> +		  ~(1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable);
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +				 USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val |= (1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		phy_driver->idm_host_enabled = 0;
> +	} else {
> +		writel(powered_on_phy, phy_driver->usbphy_regs +
> +			   CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +	}
> +
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +
> +	return 0;
> +}
> +
> +static int bcm_phy_poweron(struct phy *generic_phy)
> +{
> +	struct bcm_phy_instance *port = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = port->driver;
> +	unsigned long flags;
> +	int ret;
> +	u32 reg_val;
> +	bool clock_reset_flag = true;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* Bring the AFE block out of reset to start powering up the PHY */
> +	reg_val = readl(phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	reg_val |= 1 << power_bit[port->port_no];
> +	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	/* Check for power on and PLL lock */
> +	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
> +		   CDRU_USBPHY_USBPHY_ILDO_ON_FLAG, phy_driver);
> +	if (ret < 0) {
> +		dev_err(&generic_phy->dev,
> +			"Timed out waiting for USBPHY_ILDO_ON_FLAG on port %d",
> +			port->port_no);
> +		goto err_shutdown;
> +	}
> +	ret = bcm_phy_cdru_usbphy_status_wait(status_reg[port->port_no],
> +		CDRU_USBPHY_USBPHY_PLL_LOCK, phy_driver);
> +	if (ret < 0) {
> +		dev_err(&generic_phy->dev,
> +			"Timed out waiting for USBPHY_PLL_LOCK on port %d",
> +			port->port_no);
> +		goto err_shutdown;
> +	}
> +	port->power = true;
> +
> +	/* Check if the port 2 is configured for device */
> +	if (port->port_no = 2 && !port->host_mode) {
> +		/*
> +		 * Enable clock to USB device and get the USB device
> +		 * out of reset.
> +		 */
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
> +		writel(reg_val, phy_driver->usb2d_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +
> +	} else {
> +		reg_val = readl(phy_driver->usbphy_regs +
> +				CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +
> +		/*
> +		 * Check if the phy that is configured to provide clock
> +		 * and reset is powered on.
> +		 */
> +		if (reg_val >= 0 && reg_val < ARRAY_SIZE(phy_driver->ports))
> +			if (phy_driver->ports[reg_val])
> +				if (phy_driver->ports[reg_val]->power)
> +					clock_reset_flag = false;
> +
> +		/* if not set the current phy */
> +		if (clock_reset_flag) {
> +			reg_val = port->port_no;
> +			writel(reg_val, phy_driver->usbphy_regs +
> +			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		}
> +	}
> +
> +	if (!phy_driver->idm_host_enabled) {
> +		/* Enable clock to USB and get the USB out of reset */
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +		reg_val |= 1 << USB2_IDM_IDM_IO_CONTROL_DIRECT__clk_enable;
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_IO_CONTROL_DIRECT_OFFSET);
> +
> +		reg_val = readl(phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		reg_val &= ~(1 << USB2_IDM_IDM_RESET_CONTROL__RESET);
> +		writel(reg_val, phy_driver->usb2h_idm_regs +
> +				USB2_IDM_IDM_RESET_CONTROL_OFFSET);
> +		phy_driver->idm_host_enabled = true;
> +	}
> +
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +	return 0;
> +
> +err_shutdown:
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +	bcm_phy_shutdown(generic_phy);

Instead of calling the phy_shutdown, you can just power off the PHY.
> +	return ret;
> +}
> +
> +static struct phy_ops ops = {
> +	.init		= bcm_phy_init,
> +	.power_on	= bcm_phy_poweron,
> +	.power_off	= bcm_phy_shutdown,
> +};
> +
> +static const struct of_device_id bcm_phy_dt_ids[] = {
> +	{ .compatible = "brcm,cygnus-usb-phy", },
> +	{ }
> +};
> +
> +static int bcm_phy_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct bcm_phy_driver *phy_driver;
> +	struct phy_provider *phy_provider;
> +	struct device_node *child;
> +	struct resource *res;
> +	int error;
> +	u32 reg_val;
> +
> +	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
> +				  GFP_KERNEL);
> +	if (!phy_driver)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&phy_driver->lock);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(&pdev->dev, "missing memory resource usbphy_regs\n");
> +		return -EINVAL;
> +	}
> +	phy_driver->usbphy_regs = devm_ioremap_nocache(dev, res->start,
> +						resource_size(res));
> +	if (!phy_driver->usbphy_regs) {
> +		dev_err(dev, "Failed to remap usbphy_regs\n");
> +		return -ENOMEM;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	if (!res) {
> +		dev_err(&pdev->dev, "missing memory resource ubs2h_idm_regs\n");
> +		return -EINVAL;
> +	}
> +	phy_driver->usb2h_idm_regs = devm_ioremap_nocache(dev, res->start,
> +						  resource_size(res));
> +	if (!phy_driver->usb2h_idm_regs) {
> +		dev_err(dev, "Failed to remap usb2h_idm_regs\n");
> +		return -ENOMEM;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +	if (!res) {
> +		dev_err(&pdev->dev, "missing memory resource ubs2d_idm_regs\n");
> +		return -EINVAL;
> +	}
> +	phy_driver->usb2d_idm_regs = devm_ioremap_nocache(dev, res->start,
> +						   resource_size(res));
> +	if (!phy_driver->usb2d_idm_regs) {
> +		dev_err(dev, "Failed to remap usb2d_idm_regs\n");
> +		return -ENOMEM;
> +	}
> +
> +	dev_set_drvdata(dev, phy_driver);
> +
> +	phy_driver->idm_host_enabled = false;
> +
> +	/* Shut down all ports. They can be powered up as required */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +	reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
> +	reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +	reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
> +	reg_val &= ~(1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
> +	reg_val &= ~(1 << CRMU_USBPHY_P2_RESETB);
> +	writel(reg_val, phy_driver->usbphy_regs +
> +		CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	for_each_available_child_of_node(dev->of_node, child) {
> +		struct bcm_phy_instance *port;
> +		u32 port_no;
> +
> +		if (of_property_read_u32(child, "reg", &port_no)) {
> +			dev_err(dev, "missing reg property in node %s\n",
> +				child->name);
> +			return -EINVAL;
> +		}
> +
> +		if (port_no >= ARRAY_SIZE(phy_driver->ports)) {
> +			dev_err(dev, "invalid reg in node %s: %u\n",
> +				child->name, port_no);
> +			return -EINVAL;
> +		}
> +
> +		port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> +		if (!port)
> +			return -ENOMEM;
> +
> +		port->generic_phy = devm_phy_create(dev, child, &ops);
> +		if (IS_ERR(port->generic_phy)) {
> +			error = PTR_ERR(port->generic_phy);
> +			dev_err(dev, "Failed to create phy %u: %d",
> +				port_no, error);
> +			return error;
> +		}
> +
> +		port->port_no = port_no;
> +		port->driver = phy_driver;
> +		phy_set_drvdata(port->generic_phy, port);
> +
> +		phy_driver->ports[port_no] = port;
> +	}
> +
> +	phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate);
> +	if (IS_ERR(phy_provider)) {
> +		error = PTR_ERR(phy_provider);
> +		dev_err(dev, "Failed to register as phy provider: %d\n",
> +			error);
> +		return error;
> +	}
> +
> +	dev_set_drvdata(pdev, phy_driver);

dev_set_drvdata is being done multiple times.

Please also run checkpatch and fix all the errors and warnings before posting 
the next version.

Thanks
Kishon

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

* Re: [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-05-12 22:05       ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-05-12 22:05 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list

Hi

On 15-05-11 07:11 AM, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
>> Broadcom's Cygnus chip has a USB 2.0 host controller connected to
>> three separate phys. One of the phs (port 2) is also connectd to
>> a usb 2.0 device controller
>>
>> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
>> Reviewed-by: Ray Jui <rjui@broadcom.com>
>> Reviewed-by: Scott Branden <sbranden@broadcom.com>
>> ---
>>   .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69
>> ++++++++++++++++++++++
>>   include/dt-bindings/phy/phy.h                      |  2 +
>>   2 files changed, 71 insertions(+)
>>   create mode 100644
>> Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>
>> diff --git
>> a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>> b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>> new file mode 100644
>> index 0000000..ec62044
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>> @@ -0,0 +1,69 @@
>> +BROADCOM CYGNUS USB PHY
>> +
>> +Required Properties:
>> +    - compatible:  brcm,cygnus-usb-phy
>> +    - reg : usbphy_regs - Base address of phy registers
>> +            usb2h_idm_regs - Base address of host idm registers
>> +            usb2d_idm_regs - Base address of device idm registers
>> +    - phy-cells - must be 1 for each port declared. The node
>> +              that uses the phy must provide either PHY_CONFIG_DEVICE
>> for device
>> +              or PHY_CONFIG_HOST for host
>> +
>> +NOTE: port 0 and port 1 are host only and port 2 can be configured
>> for host or
>> +device.
>> +
>> +Example of phy :
>> +    usbphy0: usbphy@0x0301c000 {
>> +        compatible = "brcm,cygnus-usb-phy";
>> +        reg = <0x0301c000 0x2000>,
>> +              <0x18115000 0x1000>,
>> +              <0x18111000 0x1000>;
>> +        status = "okay";
>> +
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +        usbphy0_0: usbphy0@0 {
>> +            #phy-cells = <1>;
>> +            reg = <0>;
>> +            status = "okay";
>> +            phy-supply = <&vbus_p0>;
>> +        };
>> +
>> +        usbphy0_1: usbphy0@1 {
>> +            #phy-cells = <1>;
>> +            reg = <1>;
>> +            status = "okay";
>> +        };
>> +
>> +        usbphy0_2: usbphy0@2 {
>> +            #phy-cells = <1>;
>> +            reg = <2>;
>> +            status = "okay";
>> +            phy-supply = <&vbus_p2>;
>> +        };
>> +    };
>> +
>> +Example of node using the phy:
>> +
>> +    /* This nodes declares all three ports as host */
>> +
>> +    ehci0: usb@0x18048000 {
>> +        compatible = "generic-ehci";
>> +        reg = <0x18048000 0x100>;
>> +        interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
>> +        phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST
>> &usbphy0_2 PHY_CONFIG_HOST>;
>> +        status = "okay";
>> +    };
>> +
>> +    /*
>> +     * This node declares port 2 phy
>> +     * and configures it for device
>> +     */
>> +
>> +    usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
>> +        compatible = "iproc-udc";
>> +        reg = <0x1804c000 0x2000>;
>> +        interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
>> +        phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
>> +        phy-names = "usb";
>> +    };
>> diff --git a/include/dt-bindings/phy/phy.h
>> b/include/dt-bindings/phy/phy.h
>> index 6c90193..3f6b1ac 100644
>> --- a/include/dt-bindings/phy/phy.h
>> +++ b/include/dt-bindings/phy/phy.h
>> @@ -15,5 +15,7 @@
>>   #define PHY_TYPE_PCIE        2
>>   #define PHY_TYPE_USB2        3
>>   #define PHY_TYPE_USB3        4
>> +#define PHY_CONFIG_HOST        1
>> +#define PHY_CONFIG_DEVICE    0
>
> '0' and '1' are already defined for "PHY_NONE" and "PHY_TYPE_SATA". Is
> this for USB2 or for USB3?
>
This is for USB2, do you want me to prefix the defines with USB2?
I think It would be misleading to use PHY_TYPE_SATA or PHY_NONE in this 
scenario
> Thanks
> Kishon

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

* Re: [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-05-12 22:05       ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-05-12 22:05 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w

Hi

On 15-05-11 07:11 AM, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
>> Broadcom's Cygnus chip has a USB 2.0 host controller connected to
>> three separate phys. One of the phs (port 2) is also connectd to
>> a usb 2.0 device controller
>>
>> Signed-off-by: Arun Ramamurthy <arun.ramamurthy-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
>> Reviewed-by: Ray Jui <rjui-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
>> Reviewed-by: Scott Branden <sbranden-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
>> ---
>>   .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69
>> ++++++++++++++++++++++
>>   include/dt-bindings/phy/phy.h                      |  2 +
>>   2 files changed, 71 insertions(+)
>>   create mode 100644
>> Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>
>> diff --git
>> a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>> b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>> new file mode 100644
>> index 0000000..ec62044
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>> @@ -0,0 +1,69 @@
>> +BROADCOM CYGNUS USB PHY
>> +
>> +Required Properties:
>> +    - compatible:  brcm,cygnus-usb-phy
>> +    - reg : usbphy_regs - Base address of phy registers
>> +            usb2h_idm_regs - Base address of host idm registers
>> +            usb2d_idm_regs - Base address of device idm registers
>> +    - phy-cells - must be 1 for each port declared. The node
>> +              that uses the phy must provide either PHY_CONFIG_DEVICE
>> for device
>> +              or PHY_CONFIG_HOST for host
>> +
>> +NOTE: port 0 and port 1 are host only and port 2 can be configured
>> for host or
>> +device.
>> +
>> +Example of phy :
>> +    usbphy0: usbphy@0x0301c000 {
>> +        compatible = "brcm,cygnus-usb-phy";
>> +        reg = <0x0301c000 0x2000>,
>> +              <0x18115000 0x1000>,
>> +              <0x18111000 0x1000>;
>> +        status = "okay";
>> +
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +        usbphy0_0: usbphy0@0 {
>> +            #phy-cells = <1>;
>> +            reg = <0>;
>> +            status = "okay";
>> +            phy-supply = <&vbus_p0>;
>> +        };
>> +
>> +        usbphy0_1: usbphy0@1 {
>> +            #phy-cells = <1>;
>> +            reg = <1>;
>> +            status = "okay";
>> +        };
>> +
>> +        usbphy0_2: usbphy0@2 {
>> +            #phy-cells = <1>;
>> +            reg = <2>;
>> +            status = "okay";
>> +            phy-supply = <&vbus_p2>;
>> +        };
>> +    };
>> +
>> +Example of node using the phy:
>> +
>> +    /* This nodes declares all three ports as host */
>> +
>> +    ehci0: usb@0x18048000 {
>> +        compatible = "generic-ehci";
>> +        reg = <0x18048000 0x100>;
>> +        interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
>> +        phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST
>> &usbphy0_2 PHY_CONFIG_HOST>;
>> +        status = "okay";
>> +    };
>> +
>> +    /*
>> +     * This node declares port 2 phy
>> +     * and configures it for device
>> +     */
>> +
>> +    usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
>> +        compatible = "iproc-udc";
>> +        reg = <0x1804c000 0x2000>;
>> +        interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
>> +        phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
>> +        phy-names = "usb";
>> +    };
>> diff --git a/include/dt-bindings/phy/phy.h
>> b/include/dt-bindings/phy/phy.h
>> index 6c90193..3f6b1ac 100644
>> --- a/include/dt-bindings/phy/phy.h
>> +++ b/include/dt-bindings/phy/phy.h
>> @@ -15,5 +15,7 @@
>>   #define PHY_TYPE_PCIE        2
>>   #define PHY_TYPE_USB2        3
>>   #define PHY_TYPE_USB3        4
>> +#define PHY_CONFIG_HOST        1
>> +#define PHY_CONFIG_DEVICE    0
>
> '0' and '1' are already defined for "PHY_NONE" and "PHY_TYPE_SATA". Is
> this for USB2 or for USB3?
>
This is for USB2, do you want me to prefix the defines with USB2?
I think It would be misleading to use PHY_TYPE_SATA or PHY_NONE in this 
scenario
> Thanks
> Kishon
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-05-12 22:05       ` Arun Ramamurthy
  0 siblings, 0 replies; 24+ messages in thread
From: Arun Ramamurthy @ 2015-05-12 22:05 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w

Hi

On 15-05-11 07:11 AM, Kishon Vijay Abraham I wrote:
> Hi,
>
> On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
>> Broadcom's Cygnus chip has a USB 2.0 host controller connected to
>> three separate phys. One of the phs (port 2) is also connectd to
>> a usb 2.0 device controller
>>
>> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
>> Reviewed-by: Ray Jui <rjui@broadcom.com>
>> Reviewed-by: Scott Branden <sbranden@broadcom.com>
>> ---
>>   .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69
>> ++++++++++++++++++++++
>>   include/dt-bindings/phy/phy.h                      |  2 +
>>   2 files changed, 71 insertions(+)
>>   create mode 100644
>> Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>
>> diff --git
>> a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>> b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>> new file mode 100644
>> index 0000000..ec62044
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>> @@ -0,0 +1,69 @@
>> +BROADCOM CYGNUS USB PHY
>> +
>> +Required Properties:
>> +    - compatible:  brcm,cygnus-usb-phy
>> +    - reg : usbphy_regs - Base address of phy registers
>> +            usb2h_idm_regs - Base address of host idm registers
>> +            usb2d_idm_regs - Base address of device idm registers
>> +    - phy-cells - must be 1 for each port declared. The node
>> +              that uses the phy must provide either PHY_CONFIG_DEVICE
>> for device
>> +              or PHY_CONFIG_HOST for host
>> +
>> +NOTE: port 0 and port 1 are host only and port 2 can be configured
>> for host or
>> +device.
>> +
>> +Example of phy :
>> +    usbphy0: usbphy@0x0301c000 {
>> +        compatible = "brcm,cygnus-usb-phy";
>> +        reg = <0x0301c000 0x2000>,
>> +              <0x18115000 0x1000>,
>> +              <0x18111000 0x1000>;
>> +        status = "okay";
>> +
>> +        #address-cells = <1>;
>> +        #size-cells = <0>;
>> +        usbphy0_0: usbphy0@0 {
>> +            #phy-cells = <1>;
>> +            reg = <0>;
>> +            status = "okay";
>> +            phy-supply = <&vbus_p0>;
>> +        };
>> +
>> +        usbphy0_1: usbphy0@1 {
>> +            #phy-cells = <1>;
>> +            reg = <1>;
>> +            status = "okay";
>> +        };
>> +
>> +        usbphy0_2: usbphy0@2 {
>> +            #phy-cells = <1>;
>> +            reg = <2>;
>> +            status = "okay";
>> +            phy-supply = <&vbus_p2>;
>> +        };
>> +    };
>> +
>> +Example of node using the phy:
>> +
>> +    /* This nodes declares all three ports as host */
>> +
>> +    ehci0: usb@0x18048000 {
>> +        compatible = "generic-ehci";
>> +        reg = <0x18048000 0x100>;
>> +        interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
>> +        phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST
>> &usbphy0_2 PHY_CONFIG_HOST>;
>> +        status = "okay";
>> +    };
>> +
>> +    /*
>> +     * This node declares port 2 phy
>> +     * and configures it for device
>> +     */
>> +
>> +    usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
>> +        compatible = "iproc-udc";
>> +        reg = <0x1804c000 0x2000>;
>> +        interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
>> +        phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
>> +        phy-names = "usb";
>> +    };
>> diff --git a/include/dt-bindings/phy/phy.h
>> b/include/dt-bindings/phy/phy.h
>> index 6c90193..3f6b1ac 100644
>> --- a/include/dt-bindings/phy/phy.h
>> +++ b/include/dt-bindings/phy/phy.h
>> @@ -15,5 +15,7 @@
>>   #define PHY_TYPE_PCIE        2
>>   #define PHY_TYPE_USB2        3
>>   #define PHY_TYPE_USB3        4
>> +#define PHY_CONFIG_HOST        1
>> +#define PHY_CONFIG_DEVICE    0
>
> '0' and '1' are already defined for "PHY_NONE" and "PHY_TYPE_SATA". Is
> this for USB2 or for USB3?
>
This is for USB2, do you want me to prefix the defines with USB2?
I think It would be misleading to use PHY_TYPE_SATA or PHY_NONE in this 
scenario
> Thanks
> Kishon

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

* Re: [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
  2015-05-12 22:05       ` Arun Ramamurthy
  (?)
@ 2015-05-13  6:02         ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 24+ messages in thread
From: Kishon Vijay Abraham I @ 2015-05-13  6:02 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list

Hi,

On Wednesday 13 May 2015 03:35 AM, Arun Ramamurthy wrote:
> Hi
>
> On 15-05-11 07:11 AM, Kishon Vijay Abraham I wrote:
>> Hi,
>>
>> On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
>>> Broadcom's Cygnus chip has a USB 2.0 host controller connected to
>>> three separate phys. One of the phs (port 2) is also connectd to
>>> a usb 2.0 device controller
>>>
>>> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
>>> Reviewed-by: Ray Jui <rjui@broadcom.com>
>>> Reviewed-by: Scott Branden <sbranden@broadcom.com>
>>> ---
>>>    .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69
>>> ++++++++++++++++++++++
>>>    include/dt-bindings/phy/phy.h                      |  2 +
>>>    2 files changed, 71 insertions(+)
>>>    create mode 100644
>>> Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>> b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>> new file mode 100644
>>> index 0000000..ec62044
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>> @@ -0,0 +1,69 @@
>>> +BROADCOM CYGNUS USB PHY
>>> +
>>> +Required Properties:
>>> +    - compatible:  brcm,cygnus-usb-phy
>>> +    - reg : usbphy_regs - Base address of phy registers
>>> +            usb2h_idm_regs - Base address of host idm registers
>>> +            usb2d_idm_regs - Base address of device idm registers
>>> +    - phy-cells - must be 1 for each port declared. The node
>>> +              that uses the phy must provide either PHY_CONFIG_DEVICE
>>> for device
>>> +              or PHY_CONFIG_HOST for host
>>> +
>>> +NOTE: port 0 and port 1 are host only and port 2 can be configured
>>> for host or
>>> +device.
>>> +
>>> +Example of phy :
>>> +    usbphy0: usbphy@0x0301c000 {
>>> +        compatible = "brcm,cygnus-usb-phy";
>>> +        reg = <0x0301c000 0x2000>,
>>> +              <0x18115000 0x1000>,
>>> +              <0x18111000 0x1000>;
>>> +        status = "okay";
>>> +
>>> +        #address-cells = <1>;
>>> +        #size-cells = <0>;
>>> +        usbphy0_0: usbphy0@0 {
>>> +            #phy-cells = <1>;
>>> +            reg = <0>;
>>> +            status = "okay";
>>> +            phy-supply = <&vbus_p0>;
>>> +        };
>>> +
>>> +        usbphy0_1: usbphy0@1 {
>>> +            #phy-cells = <1>;
>>> +            reg = <1>;
>>> +            status = "okay";
>>> +        };
>>> +
>>> +        usbphy0_2: usbphy0@2 {
>>> +            #phy-cells = <1>;
>>> +            reg = <2>;
>>> +            status = "okay";
>>> +            phy-supply = <&vbus_p2>;
>>> +        };
>>> +    };
>>> +
>>> +Example of node using the phy:
>>> +
>>> +    /* This nodes declares all three ports as host */
>>> +
>>> +    ehci0: usb@0x18048000 {
>>> +        compatible = "generic-ehci";
>>> +        reg = <0x18048000 0x100>;
>>> +        interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
>>> +        phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST
>>> &usbphy0_2 PHY_CONFIG_HOST>;
>>> +        status = "okay";
>>> +    };
>>> +
>>> +    /*
>>> +     * This node declares port 2 phy
>>> +     * and configures it for device
>>> +     */
>>> +
>>> +    usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
>>> +        compatible = "iproc-udc";
>>> +        reg = <0x1804c000 0x2000>;
>>> +        interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
>>> +        phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
>>> +        phy-names = "usb";
>>> +    };
>>> diff --git a/include/dt-bindings/phy/phy.h
>>> b/include/dt-bindings/phy/phy.h
>>> index 6c90193..3f6b1ac 100644
>>> --- a/include/dt-bindings/phy/phy.h
>>> +++ b/include/dt-bindings/phy/phy.h
>>> @@ -15,5 +15,7 @@
>>>    #define PHY_TYPE_PCIE        2
>>>    #define PHY_TYPE_USB2        3
>>>    #define PHY_TYPE_USB3        4
>>> +#define PHY_CONFIG_HOST        1
>>> +#define PHY_CONFIG_DEVICE    0
>>
>> '0' and '1' are already defined for "PHY_NONE" and "PHY_TYPE_SATA". Is
>> this for USB2 or for USB3?
>>
> This is for USB2, do you want me to prefix the defines with USB2?

yes. That will avoid confusion when someone tries to add USB3 HOST PHY or USB3 
DEVICE PHY.
> I think It would be misleading to use PHY_TYPE_SATA or PHY_NONE in this
> scenario

I meant to use the next available values like 5 and 6.

Thanks
Kishon

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

* Re: [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-05-13  6:02         ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 24+ messages in thread
From: Kishon Vijay Abraham I @ 2015-05-13  6:02 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list

Hi,

On Wednesday 13 May 2015 03:35 AM, Arun Ramamurthy wrote:
> Hi
>
> On 15-05-11 07:11 AM, Kishon Vijay Abraham I wrote:
>> Hi,
>>
>> On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
>>> Broadcom's Cygnus chip has a USB 2.0 host controller connected to
>>> three separate phys. One of the phs (port 2) is also connectd to
>>> a usb 2.0 device controller
>>>
>>> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
>>> Reviewed-by: Ray Jui <rjui@broadcom.com>
>>> Reviewed-by: Scott Branden <sbranden@broadcom.com>
>>> ---
>>>    .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69
>>> ++++++++++++++++++++++
>>>    include/dt-bindings/phy/phy.h                      |  2 +
>>>    2 files changed, 71 insertions(+)
>>>    create mode 100644
>>> Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>> b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>> new file mode 100644
>>> index 0000000..ec62044
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>> @@ -0,0 +1,69 @@
>>> +BROADCOM CYGNUS USB PHY
>>> +
>>> +Required Properties:
>>> +    - compatible:  brcm,cygnus-usb-phy
>>> +    - reg : usbphy_regs - Base address of phy registers
>>> +            usb2h_idm_regs - Base address of host idm registers
>>> +            usb2d_idm_regs - Base address of device idm registers
>>> +    - phy-cells - must be 1 for each port declared. The node
>>> +              that uses the phy must provide either PHY_CONFIG_DEVICE
>>> for device
>>> +              or PHY_CONFIG_HOST for host
>>> +
>>> +NOTE: port 0 and port 1 are host only and port 2 can be configured
>>> for host or
>>> +device.
>>> +
>>> +Example of phy :
>>> +    usbphy0: usbphy@0x0301c000 {
>>> +        compatible = "brcm,cygnus-usb-phy";
>>> +        reg = <0x0301c000 0x2000>,
>>> +              <0x18115000 0x1000>,
>>> +              <0x18111000 0x1000>;
>>> +        status = "okay";
>>> +
>>> +        #address-cells = <1>;
>>> +        #size-cells = <0>;
>>> +        usbphy0_0: usbphy0@0 {
>>> +            #phy-cells = <1>;
>>> +            reg = <0>;
>>> +            status = "okay";
>>> +            phy-supply = <&vbus_p0>;
>>> +        };
>>> +
>>> +        usbphy0_1: usbphy0@1 {
>>> +            #phy-cells = <1>;
>>> +            reg = <1>;
>>> +            status = "okay";
>>> +        };
>>> +
>>> +        usbphy0_2: usbphy0@2 {
>>> +            #phy-cells = <1>;
>>> +            reg = <2>;
>>> +            status = "okay";
>>> +            phy-supply = <&vbus_p2>;
>>> +        };
>>> +    };
>>> +
>>> +Example of node using the phy:
>>> +
>>> +    /* This nodes declares all three ports as host */
>>> +
>>> +    ehci0: usb@0x18048000 {
>>> +        compatible = "generic-ehci";
>>> +        reg = <0x18048000 0x100>;
>>> +        interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
>>> +        phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST
>>> &usbphy0_2 PHY_CONFIG_HOST>;
>>> +        status = "okay";
>>> +    };
>>> +
>>> +    /*
>>> +     * This node declares port 2 phy
>>> +     * and configures it for device
>>> +     */
>>> +
>>> +    usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
>>> +        compatible = "iproc-udc";
>>> +        reg = <0x1804c000 0x2000>;
>>> +        interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
>>> +        phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
>>> +        phy-names = "usb";
>>> +    };
>>> diff --git a/include/dt-bindings/phy/phy.h
>>> b/include/dt-bindings/phy/phy.h
>>> index 6c90193..3f6b1ac 100644
>>> --- a/include/dt-bindings/phy/phy.h
>>> +++ b/include/dt-bindings/phy/phy.h
>>> @@ -15,5 +15,7 @@
>>>    #define PHY_TYPE_PCIE        2
>>>    #define PHY_TYPE_USB2        3
>>>    #define PHY_TYPE_USB3        4
>>> +#define PHY_CONFIG_HOST        1
>>> +#define PHY_CONFIG_DEVICE    0
>>
>> '0' and '1' are already defined for "PHY_NONE" and "PHY_TYPE_SATA". Is
>> this for USB2 or for USB3?
>>
> This is for USB2, do you want me to prefix the defines with USB2?

yes. That will avoid confusion when someone tries to add USB3 HOST PHY or USB3 
DEVICE PHY.
> I think It would be misleading to use PHY_TYPE_SATA or PHY_NONE in this
> scenario

I meant to use the next available values like 5 and 6.

Thanks
Kishon

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

* Re: [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver
@ 2015-05-13  6:02         ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 24+ messages in thread
From: Kishon Vijay Abraham I @ 2015-05-13  6:14 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Russell King, Gregory CLEMENT,
	Gabriel FERNANDEZ, Jason Cooper, Thomas Petazzoni,
	Greg Kroah-Hartman, Arnd Bergmann
  Cc: devicetree, linux-kernel, linux-fbdev, Dmitry Torokhov,
	Anatol Pomazau, Jonathan Richardson, Scott Branden, Ray Jui,
	bcm-kernel-feedback-list

Hi,

On Wednesday 13 May 2015 03:35 AM, Arun Ramamurthy wrote:
> Hi
>
> On 15-05-11 07:11 AM, Kishon Vijay Abraham I wrote:
>> Hi,
>>
>> On Thursday 23 April 2015 04:44 AM, Arun Ramamurthy wrote:
>>> Broadcom's Cygnus chip has a USB 2.0 host controller connected to
>>> three separate phys. One of the phs (port 2) is also connectd to
>>> a usb 2.0 device controller
>>>
>>> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
>>> Reviewed-by: Ray Jui <rjui@broadcom.com>
>>> Reviewed-by: Scott Branden <sbranden@broadcom.com>
>>> ---
>>>    .../bindings/phy/brcm,cygnus-usb-phy.txt           | 69
>>> ++++++++++++++++++++++
>>>    include/dt-bindings/phy/phy.h                      |  2 +
>>>    2 files changed, 71 insertions(+)
>>>    create mode 100644
>>> Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>> b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>> new file mode 100644
>>> index 0000000..ec62044
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
>>> @@ -0,0 +1,69 @@
>>> +BROADCOM CYGNUS USB PHY
>>> +
>>> +Required Properties:
>>> +    - compatible:  brcm,cygnus-usb-phy
>>> +    - reg : usbphy_regs - Base address of phy registers
>>> +            usb2h_idm_regs - Base address of host idm registers
>>> +            usb2d_idm_regs - Base address of device idm registers
>>> +    - phy-cells - must be 1 for each port declared. The node
>>> +              that uses the phy must provide either PHY_CONFIG_DEVICE
>>> for device
>>> +              or PHY_CONFIG_HOST for host
>>> +
>>> +NOTE: port 0 and port 1 are host only and port 2 can be configured
>>> for host or
>>> +device.
>>> +
>>> +Example of phy :
>>> +    usbphy0: usbphy@0x0301c000 {
>>> +        compatible = "brcm,cygnus-usb-phy";
>>> +        reg = <0x0301c000 0x2000>,
>>> +              <0x18115000 0x1000>,
>>> +              <0x18111000 0x1000>;
>>> +        status = "okay";
>>> +
>>> +        #address-cells = <1>;
>>> +        #size-cells = <0>;
>>> +        usbphy0_0: usbphy0@0 {
>>> +            #phy-cells = <1>;
>>> +            reg = <0>;
>>> +            status = "okay";
>>> +            phy-supply = <&vbus_p0>;
>>> +        };
>>> +
>>> +        usbphy0_1: usbphy0@1 {
>>> +            #phy-cells = <1>;
>>> +            reg = <1>;
>>> +            status = "okay";
>>> +        };
>>> +
>>> +        usbphy0_2: usbphy0@2 {
>>> +            #phy-cells = <1>;
>>> +            reg = <2>;
>>> +            status = "okay";
>>> +            phy-supply = <&vbus_p2>;
>>> +        };
>>> +    };
>>> +
>>> +Example of node using the phy:
>>> +
>>> +    /* This nodes declares all three ports as host */
>>> +
>>> +    ehci0: usb@0x18048000 {
>>> +        compatible = "generic-ehci";
>>> +        reg = <0x18048000 0x100>;
>>> +        interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
>>> +        phys = <&usbphy0_0 PHY_CONFIG_HOST &usbphy0_1 PHY_CONFIG_HOST
>>> &usbphy0_2 PHY_CONFIG_HOST>;
>>> +        status = "okay";
>>> +    };
>>> +
>>> +    /*
>>> +     * This node declares port 2 phy
>>> +     * and configures it for device
>>> +     */
>>> +
>>> +    usbd_udc_dwc1: usbd_udc_dwc@0x1804c000 {
>>> +        compatible = "iproc-udc";
>>> +        reg = <0x1804c000 0x2000>;
>>> +        interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
>>> +        phys = <&usbphy0_2 PHY_CONFIG_DEVICE>;
>>> +        phy-names = "usb";
>>> +    };
>>> diff --git a/include/dt-bindings/phy/phy.h
>>> b/include/dt-bindings/phy/phy.h
>>> index 6c90193..3f6b1ac 100644
>>> --- a/include/dt-bindings/phy/phy.h
>>> +++ b/include/dt-bindings/phy/phy.h
>>> @@ -15,5 +15,7 @@
>>>    #define PHY_TYPE_PCIE        2
>>>    #define PHY_TYPE_USB2        3
>>>    #define PHY_TYPE_USB3        4
>>> +#define PHY_CONFIG_HOST        1
>>> +#define PHY_CONFIG_DEVICE    0
>>
>> '0' and '1' are already defined for "PHY_NONE" and "PHY_TYPE_SATA". Is
>> this for USB2 or for USB3?
>>
> This is for USB2, do you want me to prefix the defines with USB2?

yes. That will avoid confusion when someone tries to add USB3 HOST PHY or USB3 
DEVICE PHY.
> I think It would be misleading to use PHY_TYPE_SATA or PHY_NONE in this
> scenario

I meant to use the next available values like 5 and 6.

Thanks
Kishon

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

end of thread, other threads:[~2015-05-13  6:14 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-22 23:14 [PATCH v3 0/3] USB PHY driver for Broadcom's Cygnus chipset Arun Ramamurthy
2015-04-22 23:14 ` Arun Ramamurthy
2015-04-22 23:14 ` Arun Ramamurthy
2015-04-22 23:14 ` [PATCH v3 1/3] phy: phy-core: allow specifying supply at port level Arun Ramamurthy
2015-04-22 23:14   ` Arun Ramamurthy
2015-04-22 23:14   ` Arun Ramamurthy
2015-04-22 23:14 ` [PATCH v3 2/3] Phy: DT binding documentation for Broadcom Cygnus USB PHY driver Arun Ramamurthy
2015-04-22 23:14   ` Arun Ramamurthy
2015-04-22 23:14   ` Arun Ramamurthy
2015-05-11 14:11   ` Kishon Vijay Abraham I
2015-05-11 14:23     ` Kishon Vijay Abraham I
2015-05-11 14:11     ` Kishon Vijay Abraham I
2015-05-12 22:05     ` Arun Ramamurthy
2015-05-12 22:05       ` Arun Ramamurthy
2015-05-12 22:05       ` Arun Ramamurthy
2015-05-13  6:02       ` Kishon Vijay Abraham I
2015-05-13  6:14         ` Kishon Vijay Abraham I
2015-05-13  6:02         ` Kishon Vijay Abraham I
2015-04-22 23:14 ` [PATCH v3 3/3] phy: cygnus-usbphy: Add Broadcom Cygnus USB phy driver Arun Ramamurthy
2015-04-22 23:14   ` Arun Ramamurthy
2015-04-22 23:14   ` Arun Ramamurthy
2015-05-11 14:37   ` Kishon Vijay Abraham I
2015-05-11 14:49     ` Kishon Vijay Abraham I
2015-05-11 14:37     ` Kishon Vijay Abraham I

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.