All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] USB PHY driver for Broadcom's Cygnus chipset
@ 2015-02-17 19:20 ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 19:20 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree
  Cc: Jonathan Richardson, Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau, 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

Arun Ramamurthy (2):
  phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  phy: usbphy: Add Broadcom Cygnus USB PHY driver

 .../bindings/phy/brcm,cygnus-usb-phy.txt           |  50 +++
 drivers/phy/Kconfig                                |  12 +
 drivers/phy/Makefile                               |   2 +
 drivers/phy/phy-bcm-cygnus-usb.c                   | 491 +++++++++++++++++++++
 4 files changed, 555 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
 create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c

-- 
2.3.0


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

* [PATCH 0/2] USB PHY driver for Broadcom's Cygnus chipset
@ 2015-02-17 19:20 ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 19:20 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: Jonathan Richardson, Scott Branden, Ray Jui,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dmitry Torokhov,
	Anatol Pomazau, 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

Arun Ramamurthy (2):
  phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  phy: usbphy: Add Broadcom Cygnus USB PHY driver

 .../bindings/phy/brcm,cygnus-usb-phy.txt           |  50 +++
 drivers/phy/Kconfig                                |  12 +
 drivers/phy/Makefile                               |   2 +
 drivers/phy/phy-bcm-cygnus-usb.c                   | 491 +++++++++++++++++++++
 4 files changed, 555 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
 create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c

-- 
2.3.0

--
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] 40+ messages in thread

* [PATCH 0/2] USB PHY driver for Broadcom's Cygnus chipset
@ 2015-02-17 19:20 ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 19:20 UTC (permalink / raw)
  To: linux-arm-kernel

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

Arun Ramamurthy (2):
  phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  phy: usbphy: Add Broadcom Cygnus USB PHY driver

 .../bindings/phy/brcm,cygnus-usb-phy.txt           |  50 +++
 drivers/phy/Kconfig                                |  12 +
 drivers/phy/Makefile                               |   2 +
 drivers/phy/phy-bcm-cygnus-usb.c                   | 491 +++++++++++++++++++++
 4 files changed, 555 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
 create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c

-- 
2.3.0

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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-17 19:20   ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 19:20 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree
  Cc: Jonathan Richardson, Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau, Arun Ramamurthy

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
---
 .../bindings/phy/brcm,cygnus-usb-phy.txt           | 50 ++++++++++++++++++++++
 1 file changed, 50 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..f218fae
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
@@ -0,0 +1,50 @@
+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
+	 - num_phys : Number of phys available
+	 - #phy-cells must be 2
+The node that uses the phy must provide two integers, the first indicates the
+port and the second indicates whether its host or device. The second integer
+is 0 for device and 1 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 {
+		#phy-cells = <2>;
+		num_phys = <3>;
+		compatible = "brcm,cygnus-usb-phy";
+		reg = <0x0301c000 0x2000>,
+		      <0x18115000 0x1000>,
+		      <0x18111000 0x1000>;
+		status = "okay";
+	};
+
+Example of node using the phy:
+
+	/* This nodes declares  port 0
+	and port 1 as host*/
+
+	ehci0: usb@0x18048000 {
+		compatible = "generic-ehci";
+		reg = <0x18048000 0x100>;
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0 0 1 &usbphy0 1>;
+		phy-names = "usbp0","usbp1";
+		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 0>;
+		phy-names = "usb";
+	};
-- 
2.3.0


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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-17 19:20   ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 19:20 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: Jonathan Richardson, Scott Branden, Ray Jui,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dmitry Torokhov,
	Anatol Pomazau, Arun Ramamurthy

Reviewed-by: Ray Jui <rjui-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Reviewed-by: Scott Branden <sbranden-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Arun Ramamurthy <arun.ramamurthy-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 .../bindings/phy/brcm,cygnus-usb-phy.txt           | 50 ++++++++++++++++++++++
 1 file changed, 50 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..f218fae
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
@@ -0,0 +1,50 @@
+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
+	 - num_phys : Number of phys available
+	 - #phy-cells must be 2
+The node that uses the phy must provide two integers, the first indicates the
+port and the second indicates whether its host or device. The second integer
+is 0 for device and 1 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 {
+		#phy-cells = <2>;
+		num_phys = <3>;
+		compatible = "brcm,cygnus-usb-phy";
+		reg = <0x0301c000 0x2000>,
+		      <0x18115000 0x1000>,
+		      <0x18111000 0x1000>;
+		status = "okay";
+	};
+
+Example of node using the phy:
+
+	/* This nodes declares  port 0
+	and port 1 as host*/
+
+	ehci0: usb@0x18048000 {
+		compatible = "generic-ehci";
+		reg = <0x18048000 0x100>;
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0 0 1 &usbphy0 1>;
+		phy-names = "usbp0","usbp1";
+		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 0>;
+		phy-names = "usb";
+	};
-- 
2.3.0

--
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] 40+ messages in thread

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-17 19:20   ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 19:20 UTC (permalink / raw)
  To: linux-arm-kernel

Reviewed-by: Ray Jui <rjui@broadcom.com>
Reviewed-by: Scott Branden <sbranden@broadcom.com>
Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
---
 .../bindings/phy/brcm,cygnus-usb-phy.txt           | 50 ++++++++++++++++++++++
 1 file changed, 50 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..f218fae
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/brcm,cygnus-usb-phy.txt
@@ -0,0 +1,50 @@
+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
+	 - num_phys : Number of phys available
+	 - #phy-cells must be 2
+The node that uses the phy must provide two integers, the first indicates the
+port and the second indicates whether its host or device. The second integer
+is 0 for device and 1 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 at 0x0301c000 {
+		#phy-cells = <2>;
+		num_phys = <3>;
+		compatible = "brcm,cygnus-usb-phy";
+		reg = <0x0301c000 0x2000>,
+		      <0x18115000 0x1000>,
+		      <0x18111000 0x1000>;
+		status = "okay";
+	};
+
+Example of node using the phy:
+
+	/* This nodes declares  port 0
+	and port 1 as host*/
+
+	ehci0: usb at 0x18048000 {
+		compatible = "generic-ehci";
+		reg = <0x18048000 0x100>;
+		interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0 0 1 &usbphy0 1>;
+		phy-names = "usbp0","usbp1";
+		status = "okay";
+	};
+
+	/* This node declares port 2 phy
+	and configures it for device */
+
+	usbd_udc_dwc1: usbd_udc_dwc at 0x1804c000 {
+		compatible = "iproc-udc";
+		reg = <0x1804c000 0x2000>;
+		interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+		phys = <&usbphy0 2 0>;
+		phy-names = "usb";
+	};
-- 
2.3.0

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

* [PATCH 2/2] phy: usbphy: Add Broadcom Cygnus USB PHY driver
  2015-02-17 19:20 ` Arun Ramamurthy
  (?)
@ 2015-02-17 19:20   ` Arun Ramamurthy
  -1 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 19:20 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree
  Cc: Jonathan Richardson, Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau, Arun Ramamurthy

This driver adds support for USB 2.0 host and device phy
for Broadcom's Cygnus chipset

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

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index ccad880..c934090 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -277,4 +277,16 @@ config PHY_STIH41X_USB
 	  Enable this to support the USB transceiver that is part of
 	  STMicroelectronics STiH41x SoC series.
 
+config PHY_BCM_CYGNUS_USB
+	tristate "Broadcom Cygnus USB PHY support"
+	depends on OF
+	depends on ARCH_BCM_CYGNUS
+	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 aa74f96..b235677 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,6 +7,7 @@ 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_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
+obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
@@ -34,3 +35,4 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
 obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
 obj-$(CONFIG_PHY_STIH407_USB)		+= phy-stih407-usb.o
 obj-$(CONFIG_PHY_STIH41X_USB)		+= phy-stih41x-usb.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..e5d3e50
--- /dev/null
+++ b/drivers/phy/phy-bcm-cygnus-usb.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2014 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>
+#include <linux/regulator/consumer.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_P2_STATUS_OFFSET			0x1200
+
+#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
+#define PHY2_DEV_HOST_CTRL_SEL_DEVICE			0
+#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
+#define CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG	1
+#define CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK		0
+#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_REGULATOR_NAME_LEN  25
+
+struct bcm_phy_instance;
+
+struct bcm_phy_driver {
+	void __iomem *usbphy_regs;
+	void __iomem *usb2h_idm_regs;
+	void __iomem *usb2d_idm_regs;
+	spinlock_t lock;
+	int num_phys, idm_host_enabled;
+	struct bcm_phy_instance *instances;
+};
+
+struct bcm_phy_instance {
+	struct bcm_phy_driver *driver;
+	struct phy *generic_phy;
+	int port;
+	int host_mode; /* 1 - Host , 0 - device */
+	int power; /* 1 -powered_on 0 -powered off */
+	struct regulator *vbus_supply;
+};
+
+static inline int cdru_usbphy_p2_status_wait(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 +
+				CDRU_USBPHY_P2_STATUS_OFFSET);
+	} while (--retry > 0 && (reg_val & (1 << reg_bit)) == 0);
+
+	if (retry == 0)
+		return -EBUSY;
+	else
+		return 0;
+}
+
+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);
+
+	if (!phy_driver)
+		return ERR_PTR(-EINVAL);
+
+	if (WARN_ON(args->args[0] >= phy_driver->num_phys))
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(args->args[1] < 0 || args->args[1] > 1))
+		return ERR_PTR(-EINVAL);
+
+	if (WARN_ON(args->args_count < 2))
+		return ERR_PTR(-EINVAL);
+
+	phy_driver->instances[args->args[0]].port = args->args[0];
+	phy_driver->instances[args->args[0]].host_mode = args->args[1];
+
+	return phy_driver->instances[args->args[0]].generic_phy;
+}
+
+static int bcm_phy_init(struct phy *generic_phy)
+{
+	u32 reg_val;
+	unsigned long flags;
+	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* Only PORT 2 is capabale of being device and host
+	 * Default setting is device, check if it is set to host */
+	if (instance_ptr->port == 2) {
+		if (instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_HOST)
+			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)
+{
+
+	u32 reg_val, powered_on_phy;
+	int i, power_off_flag = 1;
+	unsigned long flags;
+	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* power down the phy */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CRMU_USB_PHY_AON_CTRL_OFFSET);
+	if (instance_ptr->port == 0) {
+		reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
+		reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
+	} else if (instance_ptr->port == 1) {
+		reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
+		reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
+	} else if (instance_ptr->port == 2) {
+		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);
+
+	instance_ptr->power = 0;
+
+	/* if a port is configured to device and it is being shutdown,
+	 * turn off the clocks to the usb device controller */
+	if (instance_ptr->port == 2 &&
+		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
+		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 {
+
+		/* 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 == instance_ptr->port) {
+			for (i = 0; i < phy_driver->num_phys; i++) {
+				if (phy_driver->instances[i].power == 1 &&
+				phy_driver->instances[i].host_mode ==
+				PHY2_DEV_HOST_CTRL_SEL_HOST) {
+					power_off_flag = 0;
+					powered_on_phy = i;
+				}
+			}
+		}
+
+		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);
+
+	if (instance_ptr->vbus_supply)
+		regulator_disable(instance_ptr->vbus_supply);
+
+	return 0;
+}
+
+static int bcm_phy_poweron(struct phy *generic_phy)
+{
+	int ret, clock_reset_flag = 1;
+	unsigned long flags;
+	u32 reg_val;
+	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
+
+	if (instance_ptr->vbus_supply) {
+		ret = regulator_enable(instance_ptr->vbus_supply);
+		if (ret) {
+			dev_err(&generic_phy->dev,
+				"failed to enable regulator\n");
+			return ret;
+		}
+	}
+
+	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);
+
+	if (instance_ptr->port == 0)
+		reg_val |= (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
+	else if (instance_ptr->port == 1)
+		reg_val |= (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
+	else if (instance_ptr->port == 2)
+		reg_val |= (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
+	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
+
+	instance_ptr->power = 1;
+
+	/* Check if the port 2 is configured for device */
+	if (instance_ptr->port == 2 &&
+		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
+
+		ret = cdru_usbphy_p2_status_wait
+		       (CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG, phy_driver);
+		if (ret < 0) {
+			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_ILDO_ON_FLAG on CDRU_USBPHY_P2_STATUS");
+			goto err_shutdown;
+		}
+
+		ret = cdru_usbphy_p2_status_wait
+			(CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK, phy_driver);
+		if (ret < 0) {
+			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_PLL_LOCK on CDRU_USBPHY_P2_STATUS");
+			goto err_shutdown;
+		}
+
+
+	/* 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 < phy_driver->num_phys) {
+			if (phy_driver->instances[reg_val].power == 1)
+				clock_reset_flag = 0;
+		}
+
+		/* if not set the current phy */
+		if (clock_reset_flag) {
+			reg_val = instance_ptr->port;
+			writel(reg_val, phy_driver->usbphy_regs +
+			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+		}
+	}
+
+	if (phy_driver->idm_host_enabled != 1) {
+		/* 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 = 1;
+	}
+
+	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 resource res;
+	struct bcm_phy_driver *phy_driver;
+	struct phy_provider *phy_provider;
+	int ret, num_phys, i;
+	u32 reg_val;
+
+	/* get number of phy cells */
+	ret = of_property_read_u32(dev->of_node, "num-phys", &num_phys);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource num-phys\n");
+		return ret;
+	}
+
+	/* allocate memory for each phy instance */
+	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
+				  GFP_KERNEL);
+	if (!phy_driver)
+		return -ENOMEM;
+
+	phy_driver->instances = devm_kcalloc(dev, num_phys,
+					     sizeof(struct bcm_phy_instance),
+					     GFP_KERNEL);
+	phy_driver->num_phys = num_phys;
+	spin_lock_init(&phy_driver->lock);
+
+	ret = of_address_to_resource(dev->of_node, 0, &res);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource usbphy_regs\n");
+		return ret;
+	}
+	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;
+	}
+
+	ret = of_address_to_resource(dev->of_node, 1, &res);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource usb2h_idm_regs\n");
+		return ret;
+	}
+	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;
+	}
+
+	ret = of_address_to_resource(dev->of_node, 2, &res);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource usb2d_idm_regs\n");
+		return ret;
+	}
+	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 = 0;
+
+	/* Shutdown 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 (i = 0; i < phy_driver->num_phys; i++) {
+		char *vbus_name;
+		struct bcm_phy_instance *instance_ptr =
+					&phy_driver->instances[i];
+
+		vbus_name = devm_kzalloc(dev, MAX_REGULATOR_NAME_LEN,
+					 GFP_KERNEL);
+		if (!vbus_name)
+			return -ENOMEM;
+
+		/* regulator use is optional */
+		sprintf(vbus_name, "vbus-p%d", i);
+		instance_ptr->vbus_supply = devm_regulator_get(dev, vbus_name);
+		if (IS_ERR(instance_ptr->vbus_supply))
+			instance_ptr->vbus_supply = NULL;
+		devm_kfree(dev, vbus_name);
+
+		instance_ptr->generic_phy =
+				devm_phy_create(dev, NULL, &ops);
+
+		if (IS_ERR(instance_ptr->generic_phy)) {
+			dev_err(dev, "Failed to create usb phy %d", i);
+			return PTR_ERR(instance_ptr->generic_phy);
+		}
+		instance_ptr->driver = phy_driver;
+		phy_set_drvdata(instance_ptr->generic_phy, instance_ptr);
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev,
+					bcm_usb_phy_xlate);
+
+	if (IS_ERR(phy_provider)) {
+		dev_err(dev, "Failed to register as phy provider\n");
+		return PTR_ERR(phy_provider);
+	}
+
+	platform_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.0


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

* [PATCH 2/2] phy: usbphy: Add Broadcom Cygnus USB PHY driver
@ 2015-02-17 19:20   ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 19:20 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree
  Cc: Jonathan Richardson, Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau, Arun Ramamurthy

This driver adds support for USB 2.0 host and device phy
for Broadcom's Cygnus chipset

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

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index ccad880..c934090 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -277,4 +277,16 @@ config PHY_STIH41X_USB
 	  Enable this to support the USB transceiver that is part of
 	  STMicroelectronics STiH41x SoC series.
 
+config PHY_BCM_CYGNUS_USB
+	tristate "Broadcom Cygnus USB PHY support"
+	depends on OF
+	depends on ARCH_BCM_CYGNUS
+	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 aa74f96..b235677 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,6 +7,7 @@ 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_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
+obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
@@ -34,3 +35,4 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
 obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
 obj-$(CONFIG_PHY_STIH407_USB)		+= phy-stih407-usb.o
 obj-$(CONFIG_PHY_STIH41X_USB)		+= phy-stih41x-usb.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..e5d3e50
--- /dev/null
+++ b/drivers/phy/phy-bcm-cygnus-usb.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2014 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>
+#include <linux/regulator/consumer.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_P2_STATUS_OFFSET			0x1200
+
+#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
+#define PHY2_DEV_HOST_CTRL_SEL_DEVICE			0
+#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
+#define CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG	1
+#define CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK		0
+#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_REGULATOR_NAME_LEN  25
+
+struct bcm_phy_instance;
+
+struct bcm_phy_driver {
+	void __iomem *usbphy_regs;
+	void __iomem *usb2h_idm_regs;
+	void __iomem *usb2d_idm_regs;
+	spinlock_t lock;
+	int num_phys, idm_host_enabled;
+	struct bcm_phy_instance *instances;
+};
+
+struct bcm_phy_instance {
+	struct bcm_phy_driver *driver;
+	struct phy *generic_phy;
+	int port;
+	int host_mode; /* 1 - Host , 0 - device */
+	int power; /* 1 -powered_on 0 -powered off */
+	struct regulator *vbus_supply;
+};
+
+static inline int cdru_usbphy_p2_status_wait(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 +
+				CDRU_USBPHY_P2_STATUS_OFFSET);
+	} while (--retry > 0 && (reg_val & (1 << reg_bit)) == 0);
+
+	if (retry == 0)
+		return -EBUSY;
+	else
+		return 0;
+}
+
+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);
+
+	if (!phy_driver)
+		return ERR_PTR(-EINVAL);
+
+	if (WARN_ON(args->args[0] >= phy_driver->num_phys))
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(args->args[1] < 0 || args->args[1] > 1))
+		return ERR_PTR(-EINVAL);
+
+	if (WARN_ON(args->args_count < 2))
+		return ERR_PTR(-EINVAL);
+
+	phy_driver->instances[args->args[0]].port = args->args[0];
+	phy_driver->instances[args->args[0]].host_mode = args->args[1];
+
+	return phy_driver->instances[args->args[0]].generic_phy;
+}
+
+static int bcm_phy_init(struct phy *generic_phy)
+{
+	u32 reg_val;
+	unsigned long flags;
+	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* Only PORT 2 is capabale of being device and host
+	 * Default setting is device, check if it is set to host */
+	if (instance_ptr->port == 2) {
+		if (instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_HOST)
+			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)
+{
+
+	u32 reg_val, powered_on_phy;
+	int i, power_off_flag = 1;
+	unsigned long flags;
+	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* power down the phy */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CRMU_USB_PHY_AON_CTRL_OFFSET);
+	if (instance_ptr->port == 0) {
+		reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
+		reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
+	} else if (instance_ptr->port == 1) {
+		reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
+		reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
+	} else if (instance_ptr->port == 2) {
+		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);
+
+	instance_ptr->power = 0;
+
+	/* if a port is configured to device and it is being shutdown,
+	 * turn off the clocks to the usb device controller */
+	if (instance_ptr->port == 2 &&
+		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
+		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 {
+
+		/* 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 == instance_ptr->port) {
+			for (i = 0; i < phy_driver->num_phys; i++) {
+				if (phy_driver->instances[i].power == 1 &&
+				phy_driver->instances[i].host_mode ==
+				PHY2_DEV_HOST_CTRL_SEL_HOST) {
+					power_off_flag = 0;
+					powered_on_phy = i;
+				}
+			}
+		}
+
+		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);
+
+	if (instance_ptr->vbus_supply)
+		regulator_disable(instance_ptr->vbus_supply);
+
+	return 0;
+}
+
+static int bcm_phy_poweron(struct phy *generic_phy)
+{
+	int ret, clock_reset_flag = 1;
+	unsigned long flags;
+	u32 reg_val;
+	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
+
+	if (instance_ptr->vbus_supply) {
+		ret = regulator_enable(instance_ptr->vbus_supply);
+		if (ret) {
+			dev_err(&generic_phy->dev,
+				"failed to enable regulator\n");
+			return ret;
+		}
+	}
+
+	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);
+
+	if (instance_ptr->port == 0)
+		reg_val |= (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
+	else if (instance_ptr->port == 1)
+		reg_val |= (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
+	else if (instance_ptr->port == 2)
+		reg_val |= (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
+	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
+
+	instance_ptr->power = 1;
+
+	/* Check if the port 2 is configured for device */
+	if (instance_ptr->port == 2 &&
+		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
+
+		ret = cdru_usbphy_p2_status_wait
+		       (CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG, phy_driver);
+		if (ret < 0) {
+			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_ILDO_ON_FLAG on CDRU_USBPHY_P2_STATUS");
+			goto err_shutdown;
+		}
+
+		ret = cdru_usbphy_p2_status_wait
+			(CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK, phy_driver);
+		if (ret < 0) {
+			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_PLL_LOCK on CDRU_USBPHY_P2_STATUS");
+			goto err_shutdown;
+		}
+
+
+	/* 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 < phy_driver->num_phys) {
+			if (phy_driver->instances[reg_val].power == 1)
+				clock_reset_flag = 0;
+		}
+
+		/* if not set the current phy */
+		if (clock_reset_flag) {
+			reg_val = instance_ptr->port;
+			writel(reg_val, phy_driver->usbphy_regs +
+			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+		}
+	}
+
+	if (phy_driver->idm_host_enabled != 1) {
+		/* 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 = 1;
+	}
+
+	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 resource res;
+	struct bcm_phy_driver *phy_driver;
+	struct phy_provider *phy_provider;
+	int ret, num_phys, i;
+	u32 reg_val;
+
+	/* get number of phy cells */
+	ret = of_property_read_u32(dev->of_node, "num-phys", &num_phys);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource num-phys\n");
+		return ret;
+	}
+
+	/* allocate memory for each phy instance */
+	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
+				  GFP_KERNEL);
+	if (!phy_driver)
+		return -ENOMEM;
+
+	phy_driver->instances = devm_kcalloc(dev, num_phys,
+					     sizeof(struct bcm_phy_instance),
+					     GFP_KERNEL);
+	phy_driver->num_phys = num_phys;
+	spin_lock_init(&phy_driver->lock);
+
+	ret = of_address_to_resource(dev->of_node, 0, &res);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource usbphy_regs\n");
+		return ret;
+	}
+	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;
+	}
+
+	ret = of_address_to_resource(dev->of_node, 1, &res);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource usb2h_idm_regs\n");
+		return ret;
+	}
+	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;
+	}
+
+	ret = of_address_to_resource(dev->of_node, 2, &res);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource usb2d_idm_regs\n");
+		return ret;
+	}
+	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 = 0;
+
+	/* Shutdown 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 (i = 0; i < phy_driver->num_phys; i++) {
+		char *vbus_name;
+		struct bcm_phy_instance *instance_ptr =
+					&phy_driver->instances[i];
+
+		vbus_name = devm_kzalloc(dev, MAX_REGULATOR_NAME_LEN,
+					 GFP_KERNEL);
+		if (!vbus_name)
+			return -ENOMEM;
+
+		/* regulator use is optional */
+		sprintf(vbus_name, "vbus-p%d", i);
+		instance_ptr->vbus_supply = devm_regulator_get(dev, vbus_name);
+		if (IS_ERR(instance_ptr->vbus_supply))
+			instance_ptr->vbus_supply = NULL;
+		devm_kfree(dev, vbus_name);
+
+		instance_ptr->generic_phy =
+				devm_phy_create(dev, NULL, &ops);
+
+		if (IS_ERR(instance_ptr->generic_phy)) {
+			dev_err(dev, "Failed to create usb phy %d", i);
+			return PTR_ERR(instance_ptr->generic_phy);
+		}
+		instance_ptr->driver = phy_driver;
+		phy_set_drvdata(instance_ptr->generic_phy, instance_ptr);
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev,
+					bcm_usb_phy_xlate);
+
+	if (IS_ERR(phy_provider)) {
+		dev_err(dev, "Failed to register as phy provider\n");
+		return PTR_ERR(phy_provider);
+	}
+
+	platform_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.0

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

* [PATCH 2/2] phy: usbphy: Add Broadcom Cygnus USB PHY driver
@ 2015-02-17 19:20   ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 19:20 UTC (permalink / raw)
  To: linux-arm-kernel

This driver adds support for USB 2.0 host and device phy
for Broadcom's Cygnus chipset

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

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index ccad880..c934090 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -277,4 +277,16 @@ config PHY_STIH41X_USB
 	  Enable this to support the USB transceiver that is part of
 	  STMicroelectronics STiH41x SoC series.
 
+config PHY_BCM_CYGNUS_USB
+	tristate "Broadcom Cygnus USB PHY support"
+	depends on OF
+	depends on ARCH_BCM_CYGNUS
+	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 aa74f96..b235677 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,6 +7,7 @@ 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_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
+obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
@@ -34,3 +35,4 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
 obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
 obj-$(CONFIG_PHY_STIH407_USB)		+= phy-stih407-usb.o
 obj-$(CONFIG_PHY_STIH41X_USB)		+= phy-stih41x-usb.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..e5d3e50
--- /dev/null
+++ b/drivers/phy/phy-bcm-cygnus-usb.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2014 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>
+#include <linux/regulator/consumer.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_P2_STATUS_OFFSET			0x1200
+
+#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
+#define PHY2_DEV_HOST_CTRL_SEL_DEVICE			0
+#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
+#define CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG	1
+#define CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK		0
+#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_REGULATOR_NAME_LEN  25
+
+struct bcm_phy_instance;
+
+struct bcm_phy_driver {
+	void __iomem *usbphy_regs;
+	void __iomem *usb2h_idm_regs;
+	void __iomem *usb2d_idm_regs;
+	spinlock_t lock;
+	int num_phys, idm_host_enabled;
+	struct bcm_phy_instance *instances;
+};
+
+struct bcm_phy_instance {
+	struct bcm_phy_driver *driver;
+	struct phy *generic_phy;
+	int port;
+	int host_mode; /* 1 - Host , 0 - device */
+	int power; /* 1 -powered_on 0 -powered off */
+	struct regulator *vbus_supply;
+};
+
+static inline int cdru_usbphy_p2_status_wait(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 +
+				CDRU_USBPHY_P2_STATUS_OFFSET);
+	} while (--retry > 0 && (reg_val & (1 << reg_bit)) == 0);
+
+	if (retry == 0)
+		return -EBUSY;
+	else
+		return 0;
+}
+
+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);
+
+	if (!phy_driver)
+		return ERR_PTR(-EINVAL);
+
+	if (WARN_ON(args->args[0] >= phy_driver->num_phys))
+		return ERR_PTR(-ENODEV);
+
+	if (WARN_ON(args->args[1] < 0 || args->args[1] > 1))
+		return ERR_PTR(-EINVAL);
+
+	if (WARN_ON(args->args_count < 2))
+		return ERR_PTR(-EINVAL);
+
+	phy_driver->instances[args->args[0]].port = args->args[0];
+	phy_driver->instances[args->args[0]].host_mode = args->args[1];
+
+	return phy_driver->instances[args->args[0]].generic_phy;
+}
+
+static int bcm_phy_init(struct phy *generic_phy)
+{
+	u32 reg_val;
+	unsigned long flags;
+	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* Only PORT 2 is capabale of being device and host
+	 * Default setting is device, check if it is set to host */
+	if (instance_ptr->port == 2) {
+		if (instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_HOST)
+			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)
+{
+
+	u32 reg_val, powered_on_phy;
+	int i, power_off_flag = 1;
+	unsigned long flags;
+	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
+
+	spin_lock_irqsave(&phy_driver->lock, flags);
+
+	/* power down the phy */
+	reg_val = readl(phy_driver->usbphy_regs +
+			CRMU_USB_PHY_AON_CTRL_OFFSET);
+	if (instance_ptr->port == 0) {
+		reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
+		reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
+	} else if (instance_ptr->port == 1) {
+		reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
+		reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
+	} else if (instance_ptr->port == 2) {
+		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);
+
+	instance_ptr->power = 0;
+
+	/* if a port is configured to device and it is being shutdown,
+	 * turn off the clocks to the usb device controller */
+	if (instance_ptr->port == 2 &&
+		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
+		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 {
+
+		/* 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 == instance_ptr->port) {
+			for (i = 0; i < phy_driver->num_phys; i++) {
+				if (phy_driver->instances[i].power == 1 &&
+				phy_driver->instances[i].host_mode ==
+				PHY2_DEV_HOST_CTRL_SEL_HOST) {
+					power_off_flag = 0;
+					powered_on_phy = i;
+				}
+			}
+		}
+
+		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);
+
+	if (instance_ptr->vbus_supply)
+		regulator_disable(instance_ptr->vbus_supply);
+
+	return 0;
+}
+
+static int bcm_phy_poweron(struct phy *generic_phy)
+{
+	int ret, clock_reset_flag = 1;
+	unsigned long flags;
+	u32 reg_val;
+	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
+	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
+
+	if (instance_ptr->vbus_supply) {
+		ret = regulator_enable(instance_ptr->vbus_supply);
+		if (ret) {
+			dev_err(&generic_phy->dev,
+				"failed to enable regulator\n");
+			return ret;
+		}
+	}
+
+	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);
+
+	if (instance_ptr->port == 0)
+		reg_val |= (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
+	else if (instance_ptr->port == 1)
+		reg_val |= (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
+	else if (instance_ptr->port == 2)
+		reg_val |= (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
+	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
+
+	instance_ptr->power = 1;
+
+	/* Check if the port 2 is configured for device */
+	if (instance_ptr->port == 2 &&
+		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
+
+		ret = cdru_usbphy_p2_status_wait
+		       (CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG, phy_driver);
+		if (ret < 0) {
+			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_ILDO_ON_FLAG on CDRU_USBPHY_P2_STATUS");
+			goto err_shutdown;
+		}
+
+		ret = cdru_usbphy_p2_status_wait
+			(CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK, phy_driver);
+		if (ret < 0) {
+			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_PLL_LOCK on CDRU_USBPHY_P2_STATUS");
+			goto err_shutdown;
+		}
+
+
+	/* 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 < phy_driver->num_phys) {
+			if (phy_driver->instances[reg_val].power == 1)
+				clock_reset_flag = 0;
+		}
+
+		/* if not set the current phy */
+		if (clock_reset_flag) {
+			reg_val = instance_ptr->port;
+			writel(reg_val, phy_driver->usbphy_regs +
+			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
+		}
+	}
+
+	if (phy_driver->idm_host_enabled != 1) {
+		/* 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 = 1;
+	}
+
+	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 resource res;
+	struct bcm_phy_driver *phy_driver;
+	struct phy_provider *phy_provider;
+	int ret, num_phys, i;
+	u32 reg_val;
+
+	/* get number of phy cells */
+	ret = of_property_read_u32(dev->of_node, "num-phys", &num_phys);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource num-phys\n");
+		return ret;
+	}
+
+	/* allocate memory for each phy instance */
+	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
+				  GFP_KERNEL);
+	if (!phy_driver)
+		return -ENOMEM;
+
+	phy_driver->instances = devm_kcalloc(dev, num_phys,
+					     sizeof(struct bcm_phy_instance),
+					     GFP_KERNEL);
+	phy_driver->num_phys = num_phys;
+	spin_lock_init(&phy_driver->lock);
+
+	ret = of_address_to_resource(dev->of_node, 0, &res);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource usbphy_regs\n");
+		return ret;
+	}
+	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;
+	}
+
+	ret = of_address_to_resource(dev->of_node, 1, &res);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource usb2h_idm_regs\n");
+		return ret;
+	}
+	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;
+	}
+
+	ret = of_address_to_resource(dev->of_node, 2, &res);
+	if (ret) {
+		dev_err(dev, "Failed to obtain device tree resource usb2d_idm_regs\n");
+		return ret;
+	}
+	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 = 0;
+
+	/* Shutdown 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 (i = 0; i < phy_driver->num_phys; i++) {
+		char *vbus_name;
+		struct bcm_phy_instance *instance_ptr =
+					&phy_driver->instances[i];
+
+		vbus_name = devm_kzalloc(dev, MAX_REGULATOR_NAME_LEN,
+					 GFP_KERNEL);
+		if (!vbus_name)
+			return -ENOMEM;
+
+		/* regulator use is optional */
+		sprintf(vbus_name, "vbus-p%d", i);
+		instance_ptr->vbus_supply = devm_regulator_get(dev, vbus_name);
+		if (IS_ERR(instance_ptr->vbus_supply))
+			instance_ptr->vbus_supply = NULL;
+		devm_kfree(dev, vbus_name);
+
+		instance_ptr->generic_phy =
+				devm_phy_create(dev, NULL, &ops);
+
+		if (IS_ERR(instance_ptr->generic_phy)) {
+			dev_err(dev, "Failed to create usb phy %d", i);
+			return PTR_ERR(instance_ptr->generic_phy);
+		}
+		instance_ptr->driver = phy_driver;
+		phy_set_drvdata(instance_ptr->generic_phy, instance_ptr);
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev,
+					bcm_usb_phy_xlate);
+
+	if (IS_ERR(phy_provider)) {
+		dev_err(dev, "Failed to register as phy provider\n");
+		return PTR_ERR(phy_provider);
+	}
+
+	platform_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.0

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  2015-02-17 19:20   ` Arun Ramamurthy
@ 2015-02-17 19:41     ` Arnd Bergmann
  -1 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-02-17 19:41 UTC (permalink / raw)
  To: Arun Ramamurthy
  Cc: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Jonathan Richardson,
	Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau

On Tuesday 17 February 2015 11:20:20 Arun Ramamurthy wrote:
> +       /* This nodes declares  port 0
> +       and port 1 as host*/
> +
> +       ehci0: usb@0x18048000 {
> +               compatible = "generic-ehci";
> +               reg = <0x18048000 0x100>;
> +               interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
> +               phys = <&usbphy0 0 1 &usbphy0 1>;

The second reference in the example is missing the last cell,
as you have #phy-cells = <2>.

> +               phy-names = "usbp0","usbp1";
> +               status = "okay";
> +       };

Further, the binding for "generic-ehci" requires the name to be "usb",
not "usbp0". You should probably update that binding if you can have
multiple references to mention that.

Can you make both names "usb"? If not, we should document a common
naming scheme that the driver can use.

	Arnd

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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-17 19:41     ` Arnd Bergmann
  0 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-02-17 19:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 17 February 2015 11:20:20 Arun Ramamurthy wrote:
> +       /* This nodes declares  port 0
> +       and port 1 as host*/
> +
> +       ehci0: usb at 0x18048000 {
> +               compatible = "generic-ehci";
> +               reg = <0x18048000 0x100>;
> +               interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
> +               phys = <&usbphy0 0 1 &usbphy0 1>;

The second reference in the example is missing the last cell,
as you have #phy-cells = <2>.

> +               phy-names = "usbp0","usbp1";
> +               status = "okay";
> +       };

Further, the binding for "generic-ehci" requires the name to be "usb",
not "usbp0". You should probably update that binding if you can have
multiple references to mention that.

Can you make both names "usb"? If not, we should document a common
naming scheme that the driver can use.

	Arnd

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  2015-02-17 19:41     ` Arnd Bergmann
  (?)
@ 2015-02-17 20:00       ` Arun Ramamurthy
  -1 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 20:00 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Jonathan Richardson,
	Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau

Thank you for the review Arnd.
On 15-02-17 11:41 AM, Arnd Bergmann wrote:
> On Tuesday 17 February 2015 11:20:20 Arun Ramamurthy wrote:
>> +       /* This nodes declares  port 0
>> +       and port 1 as host*/
>> +
>> +       ehci0: usb@0x18048000 {
>> +               compatible = "generic-ehci";
>> +               reg = <0x18048000 0x100>;
>> +               interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
>> +               phys = <&usbphy0 0 1 &usbphy0 1>;
>
> The second reference in the example is missing the last cell,
> as you have #phy-cells = <2>.
>
I am missing a 1 for the port number, will update in next patchset, 
thank you
>> +               phy-names = "usbp0","usbp1";
>> +               status = "okay";
>> +       };
>
> Further, the binding for "generic-ehci" requires the name to be "usb",
> not "usbp0". You should probably update that binding if you can have
> multiple references to mention that.
>
> Can you make both names "usb"? If not, we should document a common
> naming scheme that the driver can use.
>
Arnd, I patched the ehci and ohci driver to accept multiple phys so they 
require different names and cannot both be "usb". That patch was 
accepted by Alen Stern but I did not update the bindings documentation.
I will send out another patch for that. Could we go with the naming 
scheme of "usb" + "p" + port number or do you have other suggestions?


> 	Arnd
>

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-17 20:00       ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 20:00 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Jonathan Richardson,
	Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau

Thank you for the review Arnd.
On 15-02-17 11:41 AM, Arnd Bergmann wrote:
> On Tuesday 17 February 2015 11:20:20 Arun Ramamurthy wrote:
>> +       /* This nodes declares  port 0
>> +       and port 1 as host*/
>> +
>> +       ehci0: usb@0x18048000 {
>> +               compatible = "generic-ehci";
>> +               reg = <0x18048000 0x100>;
>> +               interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
>> +               phys = <&usbphy0 0 1 &usbphy0 1>;
>
> The second reference in the example is missing the last cell,
> as you have #phy-cells = <2>.
>
I am missing a 1 for the port number, will update in next patchset, 
thank you
>> +               phy-names = "usbp0","usbp1";
>> +               status = "okay";
>> +       };
>
> Further, the binding for "generic-ehci" requires the name to be "usb",
> not "usbp0". You should probably update that binding if you can have
> multiple references to mention that.
>
> Can you make both names "usb"? If not, we should document a common
> naming scheme that the driver can use.
>
Arnd, I patched the ehci and ohci driver to accept multiple phys so they 
require different names and cannot both be "usb". That patch was 
accepted by Alen Stern but I did not update the bindings documentation.
I will send out another patch for that. Could we go with the naming 
scheme of "usb" + "p" + port number or do you have other suggestions?


> 	Arnd
>

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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-17 20:00       ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 20:00 UTC (permalink / raw)
  To: linux-arm-kernel

Thank you for the review Arnd.
On 15-02-17 11:41 AM, Arnd Bergmann wrote:
> On Tuesday 17 February 2015 11:20:20 Arun Ramamurthy wrote:
>> +       /* This nodes declares  port 0
>> +       and port 1 as host*/
>> +
>> +       ehci0: usb at 0x18048000 {
>> +               compatible = "generic-ehci";
>> +               reg = <0x18048000 0x100>;
>> +               interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
>> +               phys = <&usbphy0 0 1 &usbphy0 1>;
>
> The second reference in the example is missing the last cell,
> as you have #phy-cells = <2>.
>
I am missing a 1 for the port number, will update in next patchset, 
thank you
>> +               phy-names = "usbp0","usbp1";
>> +               status = "okay";
>> +       };
>
> Further, the binding for "generic-ehci" requires the name to be "usb",
> not "usbp0". You should probably update that binding if you can have
> multiple references to mention that.
>
> Can you make both names "usb"? If not, we should document a common
> naming scheme that the driver can use.
>
Arnd, I patched the ehci and ohci driver to accept multiple phys so they 
require different names and cannot both be "usb". That patch was 
accepted by Alen Stern but I did not update the bindings documentation.
I will send out another patch for that. Could we go with the naming 
scheme of "usb" + "p" + port number or do you have other suggestions?


> 	Arnd
>

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  2015-02-17 20:00       ` Arun Ramamurthy
@ 2015-02-17 20:53         ` Arnd Bergmann
  -1 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-02-17 20:53 UTC (permalink / raw)
  To: Arun Ramamurthy
  Cc: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Jonathan Richardson,
	Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau

On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
> Arnd, I patched the ehci and ohci driver to accept multiple phys so they 
> require different names and cannot both be "usb". That patch was 
> accepted by Alen Stern but I did not update the bindings documentation.
> I will send out another patch for that. Could we go with the naming 
> scheme of "usb" + "p" + port number or do you have other suggestions?

I don't have a good idea, but I think it would be best if the first
phy could remain named "usb" for compatibility with the existing binding.

What is the reason for having two phys in your case? Are these
identical phy devices connected to a single controller or do they
server different purposes?

	Arnd

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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-17 20:53         ` Arnd Bergmann
  0 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-02-17 20:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
> Arnd, I patched the ehci and ohci driver to accept multiple phys so they 
> require different names and cannot both be "usb". That patch was 
> accepted by Alen Stern but I did not update the bindings documentation.
> I will send out another patch for that. Could we go with the naming 
> scheme of "usb" + "p" + port number or do you have other suggestions?

I don't have a good idea, but I think it would be best if the first
phy could remain named "usb" for compatibility with the existing binding.

What is the reason for having two phys in your case? Are these
identical phy devices connected to a single controller or do they
server different purposes?

	Arnd

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  2015-02-17 20:53         ` Arnd Bergmann
  (?)
@ 2015-02-17 21:05           ` Arun Ramamurthy
  -1 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 21:05 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Jonathan Richardson,
	Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau



On 15-02-17 12:53 PM, Arnd Bergmann wrote:
> On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
>> Arnd, I patched the ehci and ohci driver to accept multiple phys so they
>> require different names and cannot both be "usb". That patch was
>> accepted by Alen Stern but I did not update the bindings documentation.
>> I will send out another patch for that. Could we go with the naming
>> scheme of "usb" + "p" + port number or do you have other suggestions?
>
> I don't have a good idea, but I think it would be best if the first
> phy could remain named "usb" for compatibility with the existing binding.
>
The patch was written in a way that all the existing and new drivers can
continue to use "usb" if they are using only one phy so that we remain 
compatible. The names need to be different only if more than one phy is 
specified. In such cases i don't think the first phy should be "usb" as 
it would be confusing to have
	phy-names = "usb","usbp1"
Should I run this by Alan Stern?
> What is the reason for having two phys in your case? Are these
> identical phy devices connected to a single controller or do they
> server different purposes?
>
Yes, we have three identical phys connected to a single host controller 
and one of the phys is also connected to the device controller
> 	Arnd
>

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-17 21:05           ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 21:05 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Jonathan Richardson, Scott Branden, Ray Jui,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dmitry Torokhov,
	Anatol Pomazau



On 15-02-17 12:53 PM, Arnd Bergmann wrote:
> On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
>> Arnd, I patched the ehci and ohci driver to accept multiple phys so they
>> require different names and cannot both be "usb". That patch was
>> accepted by Alen Stern but I did not update the bindings documentation.
>> I will send out another patch for that. Could we go with the naming
>> scheme of "usb" + "p" + port number or do you have other suggestions?
>
> I don't have a good idea, but I think it would be best if the first
> phy could remain named "usb" for compatibility with the existing binding.
>
The patch was written in a way that all the existing and new drivers can
continue to use "usb" if they are using only one phy so that we remain 
compatible. The names need to be different only if more than one phy is 
specified. In such cases i don't think the first phy should be "usb" as 
it would be confusing to have
	phy-names = "usb","usbp1"
Should I run this by Alan Stern?
> What is the reason for having two phys in your case? Are these
> identical phy devices connected to a single controller or do they
> server different purposes?
>
Yes, we have three identical phys connected to a single host controller 
and one of the phys is also connected to the device controller
> 	Arnd
>
--
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] 40+ messages in thread

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-17 21:05           ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-17 21:05 UTC (permalink / raw)
  To: linux-arm-kernel



On 15-02-17 12:53 PM, Arnd Bergmann wrote:
> On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
>> Arnd, I patched the ehci and ohci driver to accept multiple phys so they
>> require different names and cannot both be "usb". That patch was
>> accepted by Alen Stern but I did not update the bindings documentation.
>> I will send out another patch for that. Could we go with the naming
>> scheme of "usb" + "p" + port number or do you have other suggestions?
>
> I don't have a good idea, but I think it would be best if the first
> phy could remain named "usb" for compatibility with the existing binding.
>
The patch was written in a way that all the existing and new drivers can
continue to use "usb" if they are using only one phy so that we remain 
compatible. The names need to be different only if more than one phy is 
specified. In such cases i don't think the first phy should be "usb" as 
it would be confusing to have
	phy-names = "usb","usbp1"
Should I run this by Alan Stern?
> What is the reason for having two phys in your case? Are these
> identical phy devices connected to a single controller or do they
> server different purposes?
>
Yes, we have three identical phys connected to a single host controller 
and one of the phys is also connected to the device controller
> 	Arnd
>

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

* Re: [PATCH 2/2] phy: usbphy: Add Broadcom Cygnus USB PHY driver
  2015-02-17 19:20   ` Arun Ramamurthy
  (?)
@ 2015-02-18  6:10     ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 40+ messages in thread
From: Kishon Vijay Abraham I @ 2015-02-18  6:10 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree
  Cc: Jonathan Richardson, Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau

Hi,

On Wednesday 18 February 2015 12:50 AM, Arun Ramamurthy wrote:
> This driver adds support for USB 2.0 host and device phy
> for Broadcom's Cygnus chipset
>
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> ---
>   drivers/phy/Kconfig              |  12 +
>   drivers/phy/Makefile             |   2 +
>   drivers/phy/phy-bcm-cygnus-usb.c | 491 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 505 insertions(+)
>   create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index ccad880..c934090 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -277,4 +277,16 @@ config PHY_STIH41X_USB
>   	  Enable this to support the USB transceiver that is part of
>   	  STMicroelectronics STiH41x SoC series.
>
> +config PHY_BCM_CYGNUS_USB
> +	tristate "Broadcom Cygnus USB PHY support"
> +	depends on OF
> +	depends on ARCH_BCM_CYGNUS
> +	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 aa74f96..b235677 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -7,6 +7,7 @@ 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_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
> +obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
>   obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>   obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>   obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
> @@ -34,3 +35,4 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
>   obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
>   obj-$(CONFIG_PHY_STIH407_USB)		+= phy-stih407-usb.o
>   obj-$(CONFIG_PHY_STIH41X_USB)		+= phy-stih41x-usb.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..e5d3e50
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-cygnus-usb.c
> @@ -0,0 +1,491 @@
> +/*
> + * Copyright (C) 2014 Broadcom Corporation

2015 already :-)
> + *
> + * 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>
> +#include <linux/regulator/consumer.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_P2_STATUS_OFFSET			0x1200
> +
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
> +#define PHY2_DEV_HOST_CTRL_SEL_DEVICE			0
> +#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
> +#define CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG	1
> +#define CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK		0
> +#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_REGULATOR_NAME_LEN  25
> +
> +struct bcm_phy_instance;
> +
> +struct bcm_phy_driver {
> +	void __iomem *usbphy_regs;
> +	void __iomem *usb2h_idm_regs;
> +	void __iomem *usb2d_idm_regs;
> +	spinlock_t lock;
> +	int num_phys, idm_host_enabled;
> +	struct bcm_phy_instance *instances;
> +};
> +
> +struct bcm_phy_instance {
> +	struct bcm_phy_driver *driver;
> +	struct phy *generic_phy;
> +	int port;
> +	int host_mode; /* 1 - Host , 0 - device */
> +	int power; /* 1 -powered_on 0 -powered off */
> +	struct regulator *vbus_supply;
> +};
> +
> +static inline int cdru_usbphy_p2_status_wait(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 +
> +				CDRU_USBPHY_P2_STATUS_OFFSET);
> +	} while (--retry > 0 && (reg_val & (1 << reg_bit)) == 0);

you can move the check on reg_val inside the do block. No strong feelings 
except that it improves readability.
> +
> +	if (retry == 0)
> +		return -EBUSY;
> +	else
> +		return 0;
> +}
> +
> +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);
> +
> +	if (!phy_driver)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args[0] >= phy_driver->num_phys))
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args[1] < 0 || args->args[1] > 1))
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args_count < 2))
> +		return ERR_PTR(-EINVAL);
> +
> +	phy_driver->instances[args->args[0]].port = args->args[0];
> +	phy_driver->instances[args->args[0]].host_mode = args->args[1];
> +
> +	return phy_driver->instances[args->args[0]].generic_phy;
> +}
> +
> +static int bcm_phy_init(struct phy *generic_phy)
> +{
> +	u32 reg_val;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* Only PORT 2 is capabale of being device and host
> +	 * Default setting is device, check if it is set to host */
> +	if (instance_ptr->port == 2) {
> +		if (instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_HOST)
> +			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)
> +{
> +
> +	u32 reg_val, powered_on_phy;
> +	int i, power_off_flag = 1;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* power down the phy */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	if (instance_ptr->port == 0) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
> +	} else if (instance_ptr->port == 1) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
> +	} else if (instance_ptr->port == 2) {
> +		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);
> +
> +	instance_ptr->power = 0;
> +
> +	/* if a port is configured to device and it is being shutdown,
> +	 * turn off the clocks to the usb device controller */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
> +		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 {
> +
> +		/* 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 == instance_ptr->port) {
> +			for (i = 0; i < phy_driver->num_phys; i++) {
> +				if (phy_driver->instances[i].power == 1 &&
> +				phy_driver->instances[i].host_mode ==
> +				PHY2_DEV_HOST_CTRL_SEL_HOST) {
> +					power_off_flag = 0;
> +					powered_on_phy = i;
> +				}
> +			}
> +		}
> +
> +		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);
> +
> +	if (instance_ptr->vbus_supply)
> +		regulator_disable(instance_ptr->vbus_supply);
> +
> +	return 0;
> +}
> +
> +static int bcm_phy_poweron(struct phy *generic_phy)
> +{
> +	int ret, clock_reset_flag = 1;
> +	unsigned long flags;
> +	u32 reg_val;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	if (instance_ptr->vbus_supply) {
> +		ret = regulator_enable(instance_ptr->vbus_supply);
> +		if (ret) {
> +			dev_err(&generic_phy->dev,
> +				"failed to enable regulator\n");
> +			return ret;
> +		}
> +	}
> +
> +	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);
> +
> +	if (instance_ptr->port == 0)
> +		reg_val |= (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 1)
> +		reg_val |= (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 2)
> +		reg_val |= (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
> +	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	instance_ptr->power = 1;
> +
> +	/* Check if the port 2 is configured for device */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
> +
> +		ret = cdru_usbphy_p2_status_wait
> +		       (CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_ILDO_ON_FLAG on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +		ret = cdru_usbphy_p2_status_wait
> +			(CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_PLL_LOCK on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +
> +	/* 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 < phy_driver->num_phys) {
> +			if (phy_driver->instances[reg_val].power == 1)
> +				clock_reset_flag = 0;
> +		}
> +
> +		/* if not set the current phy */
> +		if (clock_reset_flag) {
> +			reg_val = instance_ptr->port;
> +			writel(reg_val, phy_driver->usbphy_regs +
> +			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		}
> +	}
> +
> +	if (phy_driver->idm_host_enabled != 1) {
> +		/* 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 = 1;
> +	}
> +
> +	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 resource res;
> +	struct bcm_phy_driver *phy_driver;
> +	struct phy_provider *phy_provider;
> +	int ret, num_phys, i;
> +	u32 reg_val;
> +
> +	/* get number of phy cells */
> +	ret = of_property_read_u32(dev->of_node, "num-phys", &num_phys);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource num-phys\n");
> +		return ret;
> +	}
> +
> +	/* allocate memory for each phy instance */
> +	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
> +				  GFP_KERNEL);
> +	if (!phy_driver)
> +		return -ENOMEM;
> +
> +	phy_driver->instances = devm_kcalloc(dev, num_phys,
> +					     sizeof(struct bcm_phy_instance),
> +					     GFP_KERNEL);
> +	phy_driver->num_phys = num_phys;
> +	spin_lock_init(&phy_driver->lock);
> +
> +	ret = of_address_to_resource(dev->of_node, 0, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usbphy_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 1, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2h_idm_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 2, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2d_idm_regs\n");
> +		return ret;
> +	}
> +	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 = 0;
> +
> +	/* Shutdown 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 (i = 0; i < phy_driver->num_phys; i++) {

for multi phy PHY providers each PHY should be modeled as a sub node of the PHY 
provider. See phy-miphy365x.c for reference.

Thanks
Kishon

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

* Re: [PATCH 2/2] phy: usbphy: Add Broadcom Cygnus USB PHY driver
@ 2015-02-18  6:10     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 40+ messages in thread
From: Kishon Vijay Abraham I @ 2015-02-18  6:10 UTC (permalink / raw)
  To: Arun Ramamurthy, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree
  Cc: Jonathan Richardson, Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Dmitry Torokhov,
	Anatol Pomazau

Hi,

On Wednesday 18 February 2015 12:50 AM, Arun Ramamurthy wrote:
> This driver adds support for USB 2.0 host and device phy
> for Broadcom's Cygnus chipset
>
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> ---
>   drivers/phy/Kconfig              |  12 +
>   drivers/phy/Makefile             |   2 +
>   drivers/phy/phy-bcm-cygnus-usb.c | 491 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 505 insertions(+)
>   create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index ccad880..c934090 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -277,4 +277,16 @@ config PHY_STIH41X_USB
>   	  Enable this to support the USB transceiver that is part of
>   	  STMicroelectronics STiH41x SoC series.
>
> +config PHY_BCM_CYGNUS_USB
> +	tristate "Broadcom Cygnus USB PHY support"
> +	depends on OF
> +	depends on ARCH_BCM_CYGNUS
> +	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 aa74f96..b235677 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -7,6 +7,7 @@ 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_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
> +obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
>   obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>   obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>   obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
> @@ -34,3 +35,4 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
>   obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
>   obj-$(CONFIG_PHY_STIH407_USB)		+= phy-stih407-usb.o
>   obj-$(CONFIG_PHY_STIH41X_USB)		+= phy-stih41x-usb.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..e5d3e50
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-cygnus-usb.c
> @@ -0,0 +1,491 @@
> +/*
> + * Copyright (C) 2014 Broadcom Corporation

2015 already :-)
> + *
> + * 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>
> +#include <linux/regulator/consumer.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_P2_STATUS_OFFSET			0x1200
> +
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
> +#define PHY2_DEV_HOST_CTRL_SEL_DEVICE			0
> +#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
> +#define CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG	1
> +#define CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK		0
> +#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_REGULATOR_NAME_LEN  25
> +
> +struct bcm_phy_instance;
> +
> +struct bcm_phy_driver {
> +	void __iomem *usbphy_regs;
> +	void __iomem *usb2h_idm_regs;
> +	void __iomem *usb2d_idm_regs;
> +	spinlock_t lock;
> +	int num_phys, idm_host_enabled;
> +	struct bcm_phy_instance *instances;
> +};
> +
> +struct bcm_phy_instance {
> +	struct bcm_phy_driver *driver;
> +	struct phy *generic_phy;
> +	int port;
> +	int host_mode; /* 1 - Host , 0 - device */
> +	int power; /* 1 -powered_on 0 -powered off */
> +	struct regulator *vbus_supply;
> +};
> +
> +static inline int cdru_usbphy_p2_status_wait(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 +
> +				CDRU_USBPHY_P2_STATUS_OFFSET);
> +	} while (--retry > 0 && (reg_val & (1 << reg_bit)) == 0);

you can move the check on reg_val inside the do block. No strong feelings 
except that it improves readability.
> +
> +	if (retry == 0)
> +		return -EBUSY;
> +	else
> +		return 0;
> +}
> +
> +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);
> +
> +	if (!phy_driver)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args[0] >= phy_driver->num_phys))
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args[1] < 0 || args->args[1] > 1))
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args_count < 2))
> +		return ERR_PTR(-EINVAL);
> +
> +	phy_driver->instances[args->args[0]].port = args->args[0];
> +	phy_driver->instances[args->args[0]].host_mode = args->args[1];
> +
> +	return phy_driver->instances[args->args[0]].generic_phy;
> +}
> +
> +static int bcm_phy_init(struct phy *generic_phy)
> +{
> +	u32 reg_val;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* Only PORT 2 is capabale of being device and host
> +	 * Default setting is device, check if it is set to host */
> +	if (instance_ptr->port == 2) {
> +		if (instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_HOST)
> +			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)
> +{
> +
> +	u32 reg_val, powered_on_phy;
> +	int i, power_off_flag = 1;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* power down the phy */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	if (instance_ptr->port == 0) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
> +	} else if (instance_ptr->port == 1) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
> +	} else if (instance_ptr->port == 2) {
> +		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);
> +
> +	instance_ptr->power = 0;
> +
> +	/* if a port is configured to device and it is being shutdown,
> +	 * turn off the clocks to the usb device controller */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
> +		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 {
> +
> +		/* 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 == instance_ptr->port) {
> +			for (i = 0; i < phy_driver->num_phys; i++) {
> +				if (phy_driver->instances[i].power == 1 &&
> +				phy_driver->instances[i].host_mode ==
> +				PHY2_DEV_HOST_CTRL_SEL_HOST) {
> +					power_off_flag = 0;
> +					powered_on_phy = i;
> +				}
> +			}
> +		}
> +
> +		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);
> +
> +	if (instance_ptr->vbus_supply)
> +		regulator_disable(instance_ptr->vbus_supply);
> +
> +	return 0;
> +}
> +
> +static int bcm_phy_poweron(struct phy *generic_phy)
> +{
> +	int ret, clock_reset_flag = 1;
> +	unsigned long flags;
> +	u32 reg_val;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	if (instance_ptr->vbus_supply) {
> +		ret = regulator_enable(instance_ptr->vbus_supply);
> +		if (ret) {
> +			dev_err(&generic_phy->dev,
> +				"failed to enable regulator\n");
> +			return ret;
> +		}
> +	}
> +
> +	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);
> +
> +	if (instance_ptr->port == 0)
> +		reg_val |= (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 1)
> +		reg_val |= (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 2)
> +		reg_val |= (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
> +	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	instance_ptr->power = 1;
> +
> +	/* Check if the port 2 is configured for device */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
> +
> +		ret = cdru_usbphy_p2_status_wait
> +		       (CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_ILDO_ON_FLAG on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +		ret = cdru_usbphy_p2_status_wait
> +			(CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_PLL_LOCK on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +
> +	/* 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 < phy_driver->num_phys) {
> +			if (phy_driver->instances[reg_val].power == 1)
> +				clock_reset_flag = 0;
> +		}
> +
> +		/* if not set the current phy */
> +		if (clock_reset_flag) {
> +			reg_val = instance_ptr->port;
> +			writel(reg_val, phy_driver->usbphy_regs +
> +			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		}
> +	}
> +
> +	if (phy_driver->idm_host_enabled != 1) {
> +		/* 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 = 1;
> +	}
> +
> +	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 resource res;
> +	struct bcm_phy_driver *phy_driver;
> +	struct phy_provider *phy_provider;
> +	int ret, num_phys, i;
> +	u32 reg_val;
> +
> +	/* get number of phy cells */
> +	ret = of_property_read_u32(dev->of_node, "num-phys", &num_phys);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource num-phys\n");
> +		return ret;
> +	}
> +
> +	/* allocate memory for each phy instance */
> +	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
> +				  GFP_KERNEL);
> +	if (!phy_driver)
> +		return -ENOMEM;
> +
> +	phy_driver->instances = devm_kcalloc(dev, num_phys,
> +					     sizeof(struct bcm_phy_instance),
> +					     GFP_KERNEL);
> +	phy_driver->num_phys = num_phys;
> +	spin_lock_init(&phy_driver->lock);
> +
> +	ret = of_address_to_resource(dev->of_node, 0, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usbphy_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 1, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2h_idm_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 2, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2d_idm_regs\n");
> +		return ret;
> +	}
> +	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 = 0;
> +
> +	/* Shutdown 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 (i = 0; i < phy_driver->num_phys; i++) {

for multi phy PHY providers each PHY should be modeled as a sub node of the PHY 
provider. See phy-miphy365x.c for reference.

Thanks
Kishon

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

* [PATCH 2/2] phy: usbphy: Add Broadcom Cygnus USB PHY driver
@ 2015-02-18  6:10     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 40+ messages in thread
From: Kishon Vijay Abraham I @ 2015-02-18  6:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Wednesday 18 February 2015 12:50 AM, Arun Ramamurthy wrote:
> This driver adds support for USB 2.0 host and device phy
> for Broadcom's Cygnus chipset
>
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> ---
>   drivers/phy/Kconfig              |  12 +
>   drivers/phy/Makefile             |   2 +
>   drivers/phy/phy-bcm-cygnus-usb.c | 491 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 505 insertions(+)
>   create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index ccad880..c934090 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -277,4 +277,16 @@ config PHY_STIH41X_USB
>   	  Enable this to support the USB transceiver that is part of
>   	  STMicroelectronics STiH41x SoC series.
>
> +config PHY_BCM_CYGNUS_USB
> +	tristate "Broadcom Cygnus USB PHY support"
> +	depends on OF
> +	depends on ARCH_BCM_CYGNUS
> +	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 aa74f96..b235677 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -7,6 +7,7 @@ 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_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
> +obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
>   obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>   obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>   obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
> @@ -34,3 +35,4 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
>   obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
>   obj-$(CONFIG_PHY_STIH407_USB)		+= phy-stih407-usb.o
>   obj-$(CONFIG_PHY_STIH41X_USB)		+= phy-stih41x-usb.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..e5d3e50
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-cygnus-usb.c
> @@ -0,0 +1,491 @@
> +/*
> + * Copyright (C) 2014 Broadcom Corporation

2015 already :-)
> + *
> + * 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>
> +#include <linux/regulator/consumer.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_P2_STATUS_OFFSET			0x1200
> +
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
> +#define PHY2_DEV_HOST_CTRL_SEL_DEVICE			0
> +#define PHY2_DEV_HOST_CTRL_SEL_HOST			1
> +#define CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG	1
> +#define CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK		0
> +#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_REGULATOR_NAME_LEN  25
> +
> +struct bcm_phy_instance;
> +
> +struct bcm_phy_driver {
> +	void __iomem *usbphy_regs;
> +	void __iomem *usb2h_idm_regs;
> +	void __iomem *usb2d_idm_regs;
> +	spinlock_t lock;
> +	int num_phys, idm_host_enabled;
> +	struct bcm_phy_instance *instances;
> +};
> +
> +struct bcm_phy_instance {
> +	struct bcm_phy_driver *driver;
> +	struct phy *generic_phy;
> +	int port;
> +	int host_mode; /* 1 - Host , 0 - device */
> +	int power; /* 1 -powered_on 0 -powered off */
> +	struct regulator *vbus_supply;
> +};
> +
> +static inline int cdru_usbphy_p2_status_wait(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 +
> +				CDRU_USBPHY_P2_STATUS_OFFSET);
> +	} while (--retry > 0 && (reg_val & (1 << reg_bit)) == 0);

you can move the check on reg_val inside the do block. No strong feelings 
except that it improves readability.
> +
> +	if (retry == 0)
> +		return -EBUSY;
> +	else
> +		return 0;
> +}
> +
> +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);
> +
> +	if (!phy_driver)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args[0] >= phy_driver->num_phys))
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args[1] < 0 || args->args[1] > 1))
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args_count < 2))
> +		return ERR_PTR(-EINVAL);
> +
> +	phy_driver->instances[args->args[0]].port = args->args[0];
> +	phy_driver->instances[args->args[0]].host_mode = args->args[1];
> +
> +	return phy_driver->instances[args->args[0]].generic_phy;
> +}
> +
> +static int bcm_phy_init(struct phy *generic_phy)
> +{
> +	u32 reg_val;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* Only PORT 2 is capabale of being device and host
> +	 * Default setting is device, check if it is set to host */
> +	if (instance_ptr->port == 2) {
> +		if (instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_HOST)
> +			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)
> +{
> +
> +	u32 reg_val, powered_on_phy;
> +	int i, power_off_flag = 1;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* power down the phy */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	if (instance_ptr->port == 0) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
> +	} else if (instance_ptr->port == 1) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
> +	} else if (instance_ptr->port == 2) {
> +		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);
> +
> +	instance_ptr->power = 0;
> +
> +	/* if a port is configured to device and it is being shutdown,
> +	 * turn off the clocks to the usb device controller */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
> +		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 {
> +
> +		/* 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 == instance_ptr->port) {
> +			for (i = 0; i < phy_driver->num_phys; i++) {
> +				if (phy_driver->instances[i].power == 1 &&
> +				phy_driver->instances[i].host_mode ==
> +				PHY2_DEV_HOST_CTRL_SEL_HOST) {
> +					power_off_flag = 0;
> +					powered_on_phy = i;
> +				}
> +			}
> +		}
> +
> +		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);
> +
> +	if (instance_ptr->vbus_supply)
> +		regulator_disable(instance_ptr->vbus_supply);
> +
> +	return 0;
> +}
> +
> +static int bcm_phy_poweron(struct phy *generic_phy)
> +{
> +	int ret, clock_reset_flag = 1;
> +	unsigned long flags;
> +	u32 reg_val;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	if (instance_ptr->vbus_supply) {
> +		ret = regulator_enable(instance_ptr->vbus_supply);
> +		if (ret) {
> +			dev_err(&generic_phy->dev,
> +				"failed to enable regulator\n");
> +			return ret;
> +		}
> +	}
> +
> +	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);
> +
> +	if (instance_ptr->port == 0)
> +		reg_val |= (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 1)
> +		reg_val |= (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 2)
> +		reg_val |= (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);
> +	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	instance_ptr->power = 1;
> +
> +	/* Check if the port 2 is configured for device */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {
> +
> +		ret = cdru_usbphy_p2_status_wait
> +		       (CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_ILDO_ON_FLAG on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +		ret = cdru_usbphy_p2_status_wait
> +			(CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_PLL_LOCK on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +
> +	/* 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 < phy_driver->num_phys) {
> +			if (phy_driver->instances[reg_val].power == 1)
> +				clock_reset_flag = 0;
> +		}
> +
> +		/* if not set the current phy */
> +		if (clock_reset_flag) {
> +			reg_val = instance_ptr->port;
> +			writel(reg_val, phy_driver->usbphy_regs +
> +			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		}
> +	}
> +
> +	if (phy_driver->idm_host_enabled != 1) {
> +		/* 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 = 1;
> +	}
> +
> +	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 resource res;
> +	struct bcm_phy_driver *phy_driver;
> +	struct phy_provider *phy_provider;
> +	int ret, num_phys, i;
> +	u32 reg_val;
> +
> +	/* get number of phy cells */
> +	ret = of_property_read_u32(dev->of_node, "num-phys", &num_phys);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource num-phys\n");
> +		return ret;
> +	}
> +
> +	/* allocate memory for each phy instance */
> +	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
> +				  GFP_KERNEL);
> +	if (!phy_driver)
> +		return -ENOMEM;
> +
> +	phy_driver->instances = devm_kcalloc(dev, num_phys,
> +					     sizeof(struct bcm_phy_instance),
> +					     GFP_KERNEL);
> +	phy_driver->num_phys = num_phys;
> +	spin_lock_init(&phy_driver->lock);
> +
> +	ret = of_address_to_resource(dev->of_node, 0, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usbphy_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 1, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2h_idm_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 2, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2d_idm_regs\n");
> +		return ret;
> +	}
> +	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 = 0;
> +
> +	/* Shutdown 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 (i = 0; i < phy_driver->num_phys; i++) {

for multi phy PHY providers each PHY should be modeled as a sub node of the PHY 
provider. See phy-miphy365x.c for reference.

Thanks
Kishon

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  2015-02-17 21:05           ` Arun Ramamurthy
@ 2015-02-18 15:15             ` Arnd Bergmann
  -1 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-02-18 15:15 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Arun Ramamurthy, Mark Rutland, devicetree, Scott Branden,
	Pawel Moll, Ian Campbell, Ray Jui, linux-kernel,
	Kishon Vijay Abraham I, Jonathan Richardson, Rob Herring,
	bcm-kernel-feedback-list, Dmitry Torokhov, Kumar Gala,
	Anatol Pomazau, stern

On Tuesday 17 February 2015 13:05:50 Arun Ramamurthy wrote:
> On 15-02-17 12:53 PM, Arnd Bergmann wrote:
> > On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
> >> Arnd, I patched the ehci and ohci driver to accept multiple phys so they
> >> require different names and cannot both be "usb". That patch was
> >> accepted by Alen Stern but I did not update the bindings documentation.
> >> I will send out another patch for that. Could we go with the naming
> >> scheme of "usb" + "p" + port number or do you have other suggestions?
> >
> > I don't have a good idea, but I think it would be best if the first
> > phy could remain named "usb" for compatibility with the existing binding.
> >
> The patch was written in a way that all the existing and new drivers can
> continue to use "usb" if they are using only one phy so that we remain 
> compatible. The names need to be different only if more than one phy is 
> specified. In such cases i don't think the first phy should be "usb" as 
> it would be confusing to have
>         phy-names = "usb","usbp1"

I see your patch now, as 7e7a0e67f2c ("usb: ehci-platform: add support for
multiple phys per controller"), and I'm not too happy about the way you
did this.

We already concluded that there should have been a binding change
to go along with this, and that would have caught the fact that you
circumvent the API here by reading the phy names manually. That
part should never have made it into the kernel.

I think we can do this either by defining specific names for the
phy, or by changing the generic PHY binding to allow anonymous
phy references (leaving out "phy-names" entirely), and adding a
proper API for that.

> Should I run this by Alan Stern?

I've added him to Cc here. He clearly didn't know the background about
the DT binding change, and should not need to, but he may have an opinion
on what names we should use.

> > What is the reason for having two phys in your case? Are these
> > identical phy devices connected to a single controller or do they
> > server different purposes?
> >
> Yes, we have three identical phys connected to a single host controller 
> and one of the phys is also connected to the device controller

Ok, no problem with that, let's just make sure we come up with a
good binding for it.

	Arnd

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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-18 15:15             ` Arnd Bergmann
  0 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-02-18 15:15 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 17 February 2015 13:05:50 Arun Ramamurthy wrote:
> On 15-02-17 12:53 PM, Arnd Bergmann wrote:
> > On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
> >> Arnd, I patched the ehci and ohci driver to accept multiple phys so they
> >> require different names and cannot both be "usb". That patch was
> >> accepted by Alen Stern but I did not update the bindings documentation.
> >> I will send out another patch for that. Could we go with the naming
> >> scheme of "usb" + "p" + port number or do you have other suggestions?
> >
> > I don't have a good idea, but I think it would be best if the first
> > phy could remain named "usb" for compatibility with the existing binding.
> >
> The patch was written in a way that all the existing and new drivers can
> continue to use "usb" if they are using only one phy so that we remain 
> compatible. The names need to be different only if more than one phy is 
> specified. In such cases i don't think the first phy should be "usb" as 
> it would be confusing to have
>         phy-names = "usb","usbp1"

I see your patch now, as 7e7a0e67f2c ("usb: ehci-platform: add support for
multiple phys per controller"), and I'm not too happy about the way you
did this.

We already concluded that there should have been a binding change
to go along with this, and that would have caught the fact that you
circumvent the API here by reading the phy names manually. That
part should never have made it into the kernel.

I think we can do this either by defining specific names for the
phy, or by changing the generic PHY binding to allow anonymous
phy references (leaving out "phy-names" entirely), and adding a
proper API for that.

> Should I run this by Alan Stern?

I've added him to Cc here. He clearly didn't know the background about
the DT binding change, and should not need to, but he may have an opinion
on what names we should use.

> > What is the reason for having two phys in your case? Are these
> > identical phy devices connected to a single controller or do they
> > server different purposes?
> >
> Yes, we have three identical phys connected to a single host controller 
> and one of the phys is also connected to the device controller

Ok, no problem with that, let's just make sure we come up with a
good binding for it.

	Arnd

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  2015-02-18 15:15             ` Arnd Bergmann
  (?)
@ 2015-02-19  0:46               ` Arun Ramamurthy
  -1 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-19  0:46 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel
  Cc: Mark Rutland, devicetree, Scott Branden, Pawel Moll,
	Ian Campbell, Ray Jui, linux-kernel, Kishon Vijay Abraham I,
	Jonathan Richardson, Rob Herring, bcm-kernel-feedback-list,
	Dmitry Torokhov, Kumar Gala, Anatol Pomazau, stern



On 15-02-18 07:15 AM, Arnd Bergmann wrote:
> On Tuesday 17 February 2015 13:05:50 Arun Ramamurthy wrote:
>> On 15-02-17 12:53 PM, Arnd Bergmann wrote:
>>> On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
>>>> Arnd, I patched the ehci and ohci driver to accept multiple phys so they
>>>> require different names and cannot both be "usb". That patch was
>>>> accepted by Alen Stern but I did not update the bindings documentation.
>>>> I will send out another patch for that. Could we go with the naming
>>>> scheme of "usb" + "p" + port number or do you have other suggestions?
>>>
>>> I don't have a good idea, but I think it would be best if the first
>>> phy could remain named "usb" for compatibility with the existing binding.
>>>
>> The patch was written in a way that all the existing and new drivers can
>> continue to use "usb" if they are using only one phy so that we remain
>> compatible. The names need to be different only if more than one phy is
>> specified. In such cases i don't think the first phy should be "usb" as
>> it would be confusing to have
>>          phy-names = "usb","usbp1"
>
> I see your patch now, as 7e7a0e67f2c ("usb: ehci-platform: add support for
> multiple phys per controller"), and I'm not too happy about the way you
> did this.

> We already concluded that there should have been a binding change
> to go along with this, and that would have caught the fact that you
> circumvent the API here by reading the phy names manually. That
> part should never have made it into the kernel.
>
> I think we can do this either by defining specific names for the
> phy, or by changing the generic PHY binding to allow anonymous
> phy references (leaving out "phy-names" entirely), and adding a
> proper API for that.
>
Thanks Arnd, I will wait for Alan's comments before proceeding. I am 
happy to patch the ehci-platform driver to use a new api instead of 
devm_phy_get if that is the best option.

>> Should I run this by Alan Stern?
>
> I've added him to Cc here. He clearly didn't know the background about
> the DT binding change, and should not need to, but he may have an opinion
> on what names we should use.
>

>>> What is the reason for having two phys in your case? Are these
>>> identical phy devices connected to a single controller or do they
>>> server different purposes?
>>>
>> Yes, we have three identical phys connected to a single host controller
>> and one of the phys is also connected to the device controller
>
> Ok, no problem with that, let's just make sure we come up with a
> good binding for it.
>
> 	Arnd
>

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-19  0:46               ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-19  0:46 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel
  Cc: Mark Rutland, devicetree, Scott Branden, Pawel Moll,
	Ian Campbell, Ray Jui, linux-kernel, Kishon Vijay Abraham I,
	Jonathan Richardson, Rob Herring, bcm-kernel-feedback-list,
	Dmitry Torokhov, Kumar Gala, Anatol Pomazau, stern



On 15-02-18 07:15 AM, Arnd Bergmann wrote:
> On Tuesday 17 February 2015 13:05:50 Arun Ramamurthy wrote:
>> On 15-02-17 12:53 PM, Arnd Bergmann wrote:
>>> On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
>>>> Arnd, I patched the ehci and ohci driver to accept multiple phys so they
>>>> require different names and cannot both be "usb". That patch was
>>>> accepted by Alen Stern but I did not update the bindings documentation.
>>>> I will send out another patch for that. Could we go with the naming
>>>> scheme of "usb" + "p" + port number or do you have other suggestions?
>>>
>>> I don't have a good idea, but I think it would be best if the first
>>> phy could remain named "usb" for compatibility with the existing binding.
>>>
>> The patch was written in a way that all the existing and new drivers can
>> continue to use "usb" if they are using only one phy so that we remain
>> compatible. The names need to be different only if more than one phy is
>> specified. In such cases i don't think the first phy should be "usb" as
>> it would be confusing to have
>>          phy-names = "usb","usbp1"
>
> I see your patch now, as 7e7a0e67f2c ("usb: ehci-platform: add support for
> multiple phys per controller"), and I'm not too happy about the way you
> did this.

> We already concluded that there should have been a binding change
> to go along with this, and that would have caught the fact that you
> circumvent the API here by reading the phy names manually. That
> part should never have made it into the kernel.
>
> I think we can do this either by defining specific names for the
> phy, or by changing the generic PHY binding to allow anonymous
> phy references (leaving out "phy-names" entirely), and adding a
> proper API for that.
>
Thanks Arnd, I will wait for Alan's comments before proceeding. I am 
happy to patch the ehci-platform driver to use a new api instead of 
devm_phy_get if that is the best option.

>> Should I run this by Alan Stern?
>
> I've added him to Cc here. He clearly didn't know the background about
> the DT binding change, and should not need to, but he may have an opinion
> on what names we should use.
>

>>> What is the reason for having two phys in your case? Are these
>>> identical phy devices connected to a single controller or do they
>>> server different purposes?
>>>
>> Yes, we have three identical phys connected to a single host controller
>> and one of the phys is also connected to the device controller
>
> Ok, no problem with that, let's just make sure we come up with a
> good binding for it.
>
> 	Arnd
>

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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-19  0:46               ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-19  0:46 UTC (permalink / raw)
  To: linux-arm-kernel



On 15-02-18 07:15 AM, Arnd Bergmann wrote:
> On Tuesday 17 February 2015 13:05:50 Arun Ramamurthy wrote:
>> On 15-02-17 12:53 PM, Arnd Bergmann wrote:
>>> On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
>>>> Arnd, I patched the ehci and ohci driver to accept multiple phys so they
>>>> require different names and cannot both be "usb". That patch was
>>>> accepted by Alen Stern but I did not update the bindings documentation.
>>>> I will send out another patch for that. Could we go with the naming
>>>> scheme of "usb" + "p" + port number or do you have other suggestions?
>>>
>>> I don't have a good idea, but I think it would be best if the first
>>> phy could remain named "usb" for compatibility with the existing binding.
>>>
>> The patch was written in a way that all the existing and new drivers can
>> continue to use "usb" if they are using only one phy so that we remain
>> compatible. The names need to be different only if more than one phy is
>> specified. In such cases i don't think the first phy should be "usb" as
>> it would be confusing to have
>>          phy-names = "usb","usbp1"
>
> I see your patch now, as 7e7a0e67f2c ("usb: ehci-platform: add support for
> multiple phys per controller"), and I'm not too happy about the way you
> did this.

> We already concluded that there should have been a binding change
> to go along with this, and that would have caught the fact that you
> circumvent the API here by reading the phy names manually. That
> part should never have made it into the kernel.
>
> I think we can do this either by defining specific names for the
> phy, or by changing the generic PHY binding to allow anonymous
> phy references (leaving out "phy-names" entirely), and adding a
> proper API for that.
>
Thanks Arnd, I will wait for Alan's comments before proceeding. I am 
happy to patch the ehci-platform driver to use a new api instead of 
devm_phy_get if that is the best option.

>> Should I run this by Alan Stern?
>
> I've added him to Cc here. He clearly didn't know the background about
> the DT binding change, and should not need to, but he may have an opinion
> on what names we should use.
>

>>> What is the reason for having two phys in your case? Are these
>>> identical phy devices connected to a single controller or do they
>>> server different purposes?
>>>
>> Yes, we have three identical phys connected to a single host controller
>> and one of the phys is also connected to the device controller
>
> Ok, no problem with that, let's just make sure we come up with a
> good binding for it.
>
> 	Arnd
>

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  2015-02-19  0:46               ` Arun Ramamurthy
  (?)
@ 2015-02-26  0:24                 ` Arun Ramamurthy
  -1 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-26  0:24 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel, Alan Stern
  Cc: Mark Rutland, devicetree, Scott Branden, Pawel Moll,
	Ian Campbell, Ray Jui, linux-kernel, Kishon Vijay Abraham I,
	Jonathan Richardson, Rob Herring, bcm-kernel-feedback-list,
	Dmitry Torokhov, Kumar Gala, Anatol Pomazau

Hello Alan and Arnd

I wanted to follow up on this patch and ascertain what I would have to 
change. Please see below for my questions

On 15-02-18 04:46 PM, Arun Ramamurthy wrote:
>
>
> On 15-02-18 07:15 AM, Arnd Bergmann wrote:
>> On Tuesday 17 February 2015 13:05:50 Arun Ramamurthy wrote:
>>> On 15-02-17 12:53 PM, Arnd Bergmann wrote:
>>>> On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
>>>>> Arnd, I patched the ehci and ohci driver to accept multiple phys so
>>>>> they
>>>>> require different names and cannot both be "usb". That patch was
>>>>> accepted by Alen Stern but I did not update the bindings
>>>>> documentation.
>>>>> I will send out another patch for that. Could we go with the naming
>>>>> scheme of "usb" + "p" + port number or do you have other suggestions?
>>>>
>>>> I don't have a good idea, but I think it would be best if the first
>>>> phy could remain named "usb" for compatibility with the existing
>>>> binding.
>>>>
>>> The patch was written in a way that all the existing and new drivers can
>>> continue to use "usb" if they are using only one phy so that we remain
>>> compatible. The names need to be different only if more than one phy is
>>> specified. In such cases i don't think the first phy should be "usb" as
>>> it would be confusing to have
>>>          phy-names = "usb","usbp1"
>>
>> I see your patch now, as 7e7a0e67f2c ("usb: ehci-platform: add support
>> for
>> multiple phys per controller"), and I'm not too happy about the way you
>> did this.
>
>> We already concluded that there should have been a binding change
>> to go along with this, and that would have caught the fact that you
>> circumvent the API here by reading the phy names manually. That
>> part should never have made it into the kernel.
>>
>> I think we can do this either by defining specific names for the
>> phy, or by changing the generic PHY binding to allow anonymous
>> phy references (leaving out "phy-names" entirely), and adding a
>> proper API for that.
>>
> Thanks Arnd, I will wait for Alan's comments before proceeding. I am
> happy to patch the ehci-platform driver to use a new api instead of
> devm_phy_get if that is the best option.
>
>>> Should I run this by Alan Stern?
>>
>> I've added him to Cc here. He clearly didn't know the background about
>> the DT binding change, and should not need to, but he may have an opinion
>> on what names we should use.
>>
>
Arnd, should I re patch the ehci-platform driver to avoid phy-names 
entirely? Alan, if not do you have an opinion on what the usb phy names 
should be? The current patch uses "usbp" + port number such as "usbp0" , 
"usbp1" etc

>>>> What is the reason for having two phys in your case? Are these
>>>> identical phy devices connected to a single controller or do they
>>>> server different purposes?
>>>>
>>> Yes, we have three identical phys connected to a single host controller
>>> and one of the phys is also connected to the device controller
>>
>> Ok, no problem with that, let's just make sure we come up with a
>> good binding for it.
>>
Arnd do you have any other comments on the phy driver itself? Thank you
>>     Arnd
>>

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-26  0:24                 ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-26  0:24 UTC (permalink / raw)
  To: Arnd Bergmann, linux-arm-kernel, Alan Stern
  Cc: Mark Rutland, devicetree, Scott Branden, Pawel Moll,
	Ian Campbell, Ray Jui, linux-kernel, Kishon Vijay Abraham I,
	Jonathan Richardson, Rob Herring, bcm-kernel-feedback-list,
	Dmitry Torokhov, Kumar Gala, Anatol Pomazau

Hello Alan and Arnd

I wanted to follow up on this patch and ascertain what I would have to 
change. Please see below for my questions

On 15-02-18 04:46 PM, Arun Ramamurthy wrote:
>
>
> On 15-02-18 07:15 AM, Arnd Bergmann wrote:
>> On Tuesday 17 February 2015 13:05:50 Arun Ramamurthy wrote:
>>> On 15-02-17 12:53 PM, Arnd Bergmann wrote:
>>>> On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
>>>>> Arnd, I patched the ehci and ohci driver to accept multiple phys so
>>>>> they
>>>>> require different names and cannot both be "usb". That patch was
>>>>> accepted by Alen Stern but I did not update the bindings
>>>>> documentation.
>>>>> I will send out another patch for that. Could we go with the naming
>>>>> scheme of "usb" + "p" + port number or do you have other suggestions?
>>>>
>>>> I don't have a good idea, but I think it would be best if the first
>>>> phy could remain named "usb" for compatibility with the existing
>>>> binding.
>>>>
>>> The patch was written in a way that all the existing and new drivers can
>>> continue to use "usb" if they are using only one phy so that we remain
>>> compatible. The names need to be different only if more than one phy is
>>> specified. In such cases i don't think the first phy should be "usb" as
>>> it would be confusing to have
>>>          phy-names = "usb","usbp1"
>>
>> I see your patch now, as 7e7a0e67f2c ("usb: ehci-platform: add support
>> for
>> multiple phys per controller"), and I'm not too happy about the way you
>> did this.
>
>> We already concluded that there should have been a binding change
>> to go along with this, and that would have caught the fact that you
>> circumvent the API here by reading the phy names manually. That
>> part should never have made it into the kernel.
>>
>> I think we can do this either by defining specific names for the
>> phy, or by changing the generic PHY binding to allow anonymous
>> phy references (leaving out "phy-names" entirely), and adding a
>> proper API for that.
>>
> Thanks Arnd, I will wait for Alan's comments before proceeding. I am
> happy to patch the ehci-platform driver to use a new api instead of
> devm_phy_get if that is the best option.
>
>>> Should I run this by Alan Stern?
>>
>> I've added him to Cc here. He clearly didn't know the background about
>> the DT binding change, and should not need to, but he may have an opinion
>> on what names we should use.
>>
>
Arnd, should I re patch the ehci-platform driver to avoid phy-names 
entirely? Alan, if not do you have an opinion on what the usb phy names 
should be? The current patch uses "usbp" + port number such as "usbp0" , 
"usbp1" etc

>>>> What is the reason for having two phys in your case? Are these
>>>> identical phy devices connected to a single controller or do they
>>>> server different purposes?
>>>>
>>> Yes, we have three identical phys connected to a single host controller
>>> and one of the phys is also connected to the device controller
>>
>> Ok, no problem with that, let's just make sure we come up with a
>> good binding for it.
>>
Arnd do you have any other comments on the phy driver itself? Thank you
>>     Arnd
>>

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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-02-26  0:24                 ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-02-26  0:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Alan and Arnd

I wanted to follow up on this patch and ascertain what I would have to 
change. Please see below for my questions

On 15-02-18 04:46 PM, Arun Ramamurthy wrote:
>
>
> On 15-02-18 07:15 AM, Arnd Bergmann wrote:
>> On Tuesday 17 February 2015 13:05:50 Arun Ramamurthy wrote:
>>> On 15-02-17 12:53 PM, Arnd Bergmann wrote:
>>>> On Tuesday 17 February 2015 12:00:49 Arun Ramamurthy wrote:
>>>>> Arnd, I patched the ehci and ohci driver to accept multiple phys so
>>>>> they
>>>>> require different names and cannot both be "usb". That patch was
>>>>> accepted by Alen Stern but I did not update the bindings
>>>>> documentation.
>>>>> I will send out another patch for that. Could we go with the naming
>>>>> scheme of "usb" + "p" + port number or do you have other suggestions?
>>>>
>>>> I don't have a good idea, but I think it would be best if the first
>>>> phy could remain named "usb" for compatibility with the existing
>>>> binding.
>>>>
>>> The patch was written in a way that all the existing and new drivers can
>>> continue to use "usb" if they are using only one phy so that we remain
>>> compatible. The names need to be different only if more than one phy is
>>> specified. In such cases i don't think the first phy should be "usb" as
>>> it would be confusing to have
>>>          phy-names = "usb","usbp1"
>>
>> I see your patch now, as 7e7a0e67f2c ("usb: ehci-platform: add support
>> for
>> multiple phys per controller"), and I'm not too happy about the way you
>> did this.
>
>> We already concluded that there should have been a binding change
>> to go along with this, and that would have caught the fact that you
>> circumvent the API here by reading the phy names manually. That
>> part should never have made it into the kernel.
>>
>> I think we can do this either by defining specific names for the
>> phy, or by changing the generic PHY binding to allow anonymous
>> phy references (leaving out "phy-names" entirely), and adding a
>> proper API for that.
>>
> Thanks Arnd, I will wait for Alan's comments before proceeding. I am
> happy to patch the ehci-platform driver to use a new api instead of
> devm_phy_get if that is the best option.
>
>>> Should I run this by Alan Stern?
>>
>> I've added him to Cc here. He clearly didn't know the background about
>> the DT binding change, and should not need to, but he may have an opinion
>> on what names we should use.
>>
>
Arnd, should I re patch the ehci-platform driver to avoid phy-names 
entirely? Alan, if not do you have an opinion on what the usb phy names 
should be? The current patch uses "usbp" + port number such as "usbp0" , 
"usbp1" etc

>>>> What is the reason for having two phys in your case? Are these
>>>> identical phy devices connected to a single controller or do they
>>>> server different purposes?
>>>>
>>> Yes, we have three identical phys connected to a single host controller
>>> and one of the phys is also connected to the device controller
>>
>> Ok, no problem with that, let's just make sure we come up with a
>> good binding for it.
>>
Arnd do you have any other comments on the phy driver itself? Thank you
>>     Arnd
>>

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

* Re: [PATCH 2/2] phy: usbphy: Add Broadcom Cygnus USB PHY driver
  2015-02-17 19:20   ` Arun Ramamurthy
@ 2015-03-05 22:33     ` Dmitry Torokhov
  -1 siblings, 0 replies; 40+ messages in thread
From: Dmitry Torokhov @ 2015-03-05 22:33 UTC (permalink / raw)
  To: Arun Ramamurthy
  Cc: Kishon Vijay Abraham I, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Jonathan Richardson,
	Scott Branden, Ray Jui, linux-arm-kernel,
	bcm-kernel-feedback-list, linux-kernel, Anatol Pomazau

Hi Arun,

On Tue, Feb 17, 2015 at 11:20:21AM -0800, Arun Ramamurthy wrote:
> This driver adds support for USB 2.0 host and device phy
> for Broadcom's Cygnus chipset

Mostly nitpicks...

> 
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> ---
>  drivers/phy/Kconfig              |  12 +
>  drivers/phy/Makefile             |   2 +
>  drivers/phy/phy-bcm-cygnus-usb.c | 491 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 505 insertions(+)
>  create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c
> 
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index ccad880..c934090 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -277,4 +277,16 @@ config PHY_STIH41X_USB
>  	  Enable this to support the USB transceiver that is part of
>  	  STMicroelectronics STiH41x SoC series.
>  
> +config PHY_BCM_CYGNUS_USB
> +	tristate "Broadcom Cygnus USB PHY support"
> +	depends on OF
> +	depends on ARCH_BCM_CYGNUS
> +	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 aa74f96..b235677 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -7,6 +7,7 @@ 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_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
> +obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
>  obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>  obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>  obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
> @@ -34,3 +35,4 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
>  obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
>  obj-$(CONFIG_PHY_STIH407_USB)		+= phy-stih407-usb.o
>  obj-$(CONFIG_PHY_STIH41X_USB)		+= phy-stih41x-usb.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..e5d3e50
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-cygnus-usb.c
> @@ -0,0 +1,491 @@
> +/*
> + * Copyright (C) 2014 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>
> +#include <linux/regulator/consumer.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_P2_STATUS_OFFSET			0x1200
> +
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
> +#define PHY2_DEV_HOST_CTRL_SEL_DEVICE			0
> +#define PHY2_DEV_HOST_CTRL_SEL_HOST			1

Do we need these 2? Seems like a boolean for host mode to me.

> +#define CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG	1
> +#define CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK		0
> +#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_REGULATOR_NAME_LEN  25
> +
> +struct bcm_phy_instance;
> +
> +struct bcm_phy_driver {
> +	void __iomem *usbphy_regs;
> +	void __iomem *usb2h_idm_regs;
> +	void __iomem *usb2d_idm_regs;
> +	spinlock_t lock;
> +	int num_phys, idm_host_enabled;

Make idm_host_enabled a boolean?

> +	struct bcm_phy_instance *instances;
> +};
> +
> +struct bcm_phy_instance {
> +	struct bcm_phy_driver *driver;
> +	struct phy *generic_phy;
> +	int port;
> +	int host_mode; /* 1 - Host , 0 - device */

bool?

> +	int power; /* 1 -powered_on 0 -powered off */

bool?

> +	struct regulator *vbus_supply;
> +};
> +
> +static inline int cdru_usbphy_p2_status_wait(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 +
> +				CDRU_USBPHY_P2_STATUS_OFFSET);
> +	} while (--retry > 0 && (reg_val & (1 << reg_bit)) == 0);
> +
> +	if (retry == 0)
> +		return -EBUSY;
> +	else
> +		return 0;

Hmm, on the last iteration you'll return -EBUSY even if operation
succeeds. How about:

	do {
		udelay(1);
		reg_val = readl(phy_driver->usbphy_regs +
				CDRU_USBPHY_P2_STATUS_OFFSET);
		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);
> +
> +	if (!phy_driver)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args[0] >= phy_driver->num_phys))
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args[1] < 0 || args->args[1] > 1))
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args_count < 2))
> +		return ERR_PTR(-EINVAL);
> +
> +	phy_driver->instances[args->args[0]].port = args->args[0];
> +	phy_driver->instances[args->args[0]].host_mode = args->args[1];
> +
> +	return phy_driver->instances[args->args[0]].generic_phy;
> +}
> +
> +static int bcm_phy_init(struct phy *generic_phy)
> +{
> +	u32 reg_val;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* Only PORT 2 is capabale of being device and host
> +	 * Default setting is device, check if it is set to host */
> +	if (instance_ptr->port == 2) {
> +		if (instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_HOST)
> +			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)
> +{
> +
> +	u32 reg_val, powered_on_phy;
> +	int i, power_off_flag = 1;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* power down the phy */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	if (instance_ptr->port == 0) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
> +	} else if (instance_ptr->port == 1) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
> +	} else if (instance_ptr->port == 2) {
> +		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);
> +
> +	instance_ptr->power = 0;
> +
> +	/* if a port is configured to device and it is being shutdown,
> +	 * turn off the clocks to the usb device controller */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {

	if (instance_ptr->port == 2 && !instance_ptr->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);
> +	} else {
> +
> +		/* 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
> +		 */

Here and elsewhere: preferred multi-line comment formatting is:

		/*
		 * Multi
		 * line
		 * comment
		 */


> +		reg_val = readl(phy_driver->usbphy_regs +
> +				CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		powered_on_phy = reg_val;
> +		if (reg_val == instance_ptr->port) {
> +			for (i = 0; i < phy_driver->num_phys; i++) {
> +				if (phy_driver->instances[i].power == 1 &&
> +				phy_driver->instances[i].host_mode ==
> +				PHY2_DEV_HOST_CTRL_SEL_HOST) {
> +					power_off_flag = 0;
> +					powered_on_phy = i;
> +				}
> +			}
> +		}
> +
> +		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);

if one branch has curly braces all of them shoudl have them:

		} else {
			writel(...);
		}

> +	}
> +
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +
> +	if (instance_ptr->vbus_supply)
> +		regulator_disable(instance_ptr->vbus_supply);
> +
> +	return 0;
> +}
> +
> +static int bcm_phy_poweron(struct phy *generic_phy)
> +{
> +	int ret, clock_reset_flag = 1;

	bool clock_reset_flag = true;

> +	unsigned long flags;
> +	u32 reg_val;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	if (instance_ptr->vbus_supply) {
> +		ret = regulator_enable(instance_ptr->vbus_supply);
> +		if (ret) {
> +			dev_err(&generic_phy->dev,
> +				"failed to enable regulator\n");
> +			return ret;
> +		}
> +	}
> +
> +	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);
> +
> +	if (instance_ptr->port == 0)
> +		reg_val |= (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 1)
> +		reg_val |= (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 2)
> +		reg_val |= (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);

	switch (instance_ptr->port) {
	case 0:
		...
	}

or maybe have a table for instance and corresponding control bits?

> +	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	instance_ptr->power = 1;

	instance_ptr->power = true;

> +
> +	/* Check if the port 2 is configured for device */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {

	if (instance_ptr->port == 2 && !instance_ptr->host_mode) {

> +
> +		ret = cdru_usbphy_p2_status_wait
> +		       (CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_ILDO_ON_FLAG on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +		ret = cdru_usbphy_p2_status_wait
> +			(CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_PLL_LOCK on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +

Extra blank line.

> +	/* Enable clock to USB device and get the USB device out of reset */

Indentation.

> +		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 < phy_driver->num_phys) {
> +			if (phy_driver->instances[reg_val].power == 1)
> +				clock_reset_flag = 0;
> +		}
> +
> +		/* if not set the current phy */
> +		if (clock_reset_flag) {
> +			reg_val = instance_ptr->port;
> +			writel(reg_val, phy_driver->usbphy_regs +
> +			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		}
> +	}
> +
> +	if (phy_driver->idm_host_enabled != 1) {

	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 = 1;

		= 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 resource res;
> +	struct bcm_phy_driver *phy_driver;
> +	struct phy_provider *phy_provider;
> +	int ret, num_phys, i;
> +	u32 reg_val;
> +
> +	/* get number of phy cells */
> +	ret = of_property_read_u32(dev->of_node, "num-phys", &num_phys);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource num-phys\n");
> +		return ret;
> +	}
> +
> +	/* allocate memory for each phy instance */
> +	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
> +				  GFP_KERNEL);
> +	if (!phy_driver)
> +		return -ENOMEM;
> +
> +	phy_driver->instances = devm_kcalloc(dev, num_phys,
> +					     sizeof(struct bcm_phy_instance),
> +					     GFP_KERNEL);
> +	phy_driver->num_phys = num_phys;
> +	spin_lock_init(&phy_driver->lock);
> +
> +	ret = of_address_to_resource(dev->of_node, 0, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usbphy_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 1, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2h_idm_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 2, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2d_idm_regs\n");
> +		return ret;
> +	}
> +	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 = 0;

	= false;

> +
> +	/* Shutdown 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 (i = 0; i < phy_driver->num_phys; i++) {
> +		char *vbus_name;
> +		struct bcm_phy_instance *instance_ptr =
> +					&phy_driver->instances[i];
> +
> +		vbus_name = devm_kzalloc(dev, MAX_REGULATOR_NAME_LEN,
> +					 GFP_KERNEL);

Why is this devm if it is freed immediately? MAX_REGULATOR_NAME_LEN is
only 25 bytes, just have on-stack array for this.

> +		if (!vbus_name)
> +			return -ENOMEM;
> +
> +		/* regulator use is optional */
> +		sprintf(vbus_name, "vbus-p%d", i);
> +		instance_ptr->vbus_supply = devm_regulator_get(dev, vbus_name);
> +		if (IS_ERR(instance_ptr->vbus_supply))
> +			instance_ptr->vbus_supply = NULL;
> +		devm_kfree(dev, vbus_name);
> +
> +		instance_ptr->generic_phy =
> +				devm_phy_create(dev, NULL, &ops);
> +
> +		if (IS_ERR(instance_ptr->generic_phy)) {
> +			dev_err(dev, "Failed to create usb phy %d", i);
> +			return PTR_ERR(instance_ptr->generic_phy);
> +		}
> +		instance_ptr->driver = phy_driver;
> +		phy_set_drvdata(instance_ptr->generic_phy, instance_ptr);
> +	}
> +
> +	phy_provider = devm_of_phy_provider_register(dev,
> +					bcm_usb_phy_xlate);
> +
> +	if (IS_ERR(phy_provider)) {
> +		dev_err(dev, "Failed to register as phy provider\n");
> +		return PTR_ERR(phy_provider);
> +	}
> +
> +	platform_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.0
> 

Thanks.

-- 
Dmitry

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

* [PATCH 2/2] phy: usbphy: Add Broadcom Cygnus USB PHY driver
@ 2015-03-05 22:33     ` Dmitry Torokhov
  0 siblings, 0 replies; 40+ messages in thread
From: Dmitry Torokhov @ 2015-03-05 22:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Arun,

On Tue, Feb 17, 2015 at 11:20:21AM -0800, Arun Ramamurthy wrote:
> This driver adds support for USB 2.0 host and device phy
> for Broadcom's Cygnus chipset

Mostly nitpicks...

> 
> Reviewed-by: Ray Jui <rjui@broadcom.com>
> Reviewed-by: Scott Branden <sbranden@broadcom.com>
> Signed-off-by: Arun Ramamurthy <arun.ramamurthy@broadcom.com>
> ---
>  drivers/phy/Kconfig              |  12 +
>  drivers/phy/Makefile             |   2 +
>  drivers/phy/phy-bcm-cygnus-usb.c | 491 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 505 insertions(+)
>  create mode 100644 drivers/phy/phy-bcm-cygnus-usb.c
> 
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index ccad880..c934090 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -277,4 +277,16 @@ config PHY_STIH41X_USB
>  	  Enable this to support the USB transceiver that is part of
>  	  STMicroelectronics STiH41x SoC series.
>  
> +config PHY_BCM_CYGNUS_USB
> +	tristate "Broadcom Cygnus USB PHY support"
> +	depends on OF
> +	depends on ARCH_BCM_CYGNUS
> +	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 aa74f96..b235677 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -7,6 +7,7 @@ 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_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
> +obj-$(CONFIG_PHY_BCM_CYGNUS_USB)	+= phy-bcm-cygnus-usb.o
>  obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>  obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>  obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
> @@ -34,3 +35,4 @@ obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
>  obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
>  obj-$(CONFIG_PHY_STIH407_USB)		+= phy-stih407-usb.o
>  obj-$(CONFIG_PHY_STIH41X_USB)		+= phy-stih41x-usb.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..e5d3e50
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-cygnus-usb.c
> @@ -0,0 +1,491 @@
> +/*
> + * Copyright (C) 2014 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>
> +#include <linux/regulator/consumer.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_P2_STATUS_OFFSET			0x1200
> +
> +#define CDRU_USB_DEV_SUSPEND_RESUME_CTRL_DISABLE	0
> +#define PHY2_DEV_HOST_CTRL_SEL_DEVICE			0
> +#define PHY2_DEV_HOST_CTRL_SEL_HOST			1

Do we need these 2? Seems like a boolean for host mode to me.

> +#define CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG	1
> +#define CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK		0
> +#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_REGULATOR_NAME_LEN  25
> +
> +struct bcm_phy_instance;
> +
> +struct bcm_phy_driver {
> +	void __iomem *usbphy_regs;
> +	void __iomem *usb2h_idm_regs;
> +	void __iomem *usb2d_idm_regs;
> +	spinlock_t lock;
> +	int num_phys, idm_host_enabled;

Make idm_host_enabled a boolean?

> +	struct bcm_phy_instance *instances;
> +};
> +
> +struct bcm_phy_instance {
> +	struct bcm_phy_driver *driver;
> +	struct phy *generic_phy;
> +	int port;
> +	int host_mode; /* 1 - Host , 0 - device */

bool?

> +	int power; /* 1 -powered_on 0 -powered off */

bool?

> +	struct regulator *vbus_supply;
> +};
> +
> +static inline int cdru_usbphy_p2_status_wait(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 +
> +				CDRU_USBPHY_P2_STATUS_OFFSET);
> +	} while (--retry > 0 && (reg_val & (1 << reg_bit)) == 0);
> +
> +	if (retry == 0)
> +		return -EBUSY;
> +	else
> +		return 0;

Hmm, on the last iteration you'll return -EBUSY even if operation
succeeds. How about:

	do {
		udelay(1);
		reg_val = readl(phy_driver->usbphy_regs +
				CDRU_USBPHY_P2_STATUS_OFFSET);
		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);
> +
> +	if (!phy_driver)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args[0] >= phy_driver->num_phys))
> +		return ERR_PTR(-ENODEV);
> +
> +	if (WARN_ON(args->args[1] < 0 || args->args[1] > 1))
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args_count < 2))
> +		return ERR_PTR(-EINVAL);
> +
> +	phy_driver->instances[args->args[0]].port = args->args[0];
> +	phy_driver->instances[args->args[0]].host_mode = args->args[1];
> +
> +	return phy_driver->instances[args->args[0]].generic_phy;
> +}
> +
> +static int bcm_phy_init(struct phy *generic_phy)
> +{
> +	u32 reg_val;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* Only PORT 2 is capabale of being device and host
> +	 * Default setting is device, check if it is set to host */
> +	if (instance_ptr->port == 2) {
> +		if (instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_HOST)
> +			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)
> +{
> +
> +	u32 reg_val, powered_on_phy;
> +	int i, power_off_flag = 1;
> +	unsigned long flags;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	spin_lock_irqsave(&phy_driver->lock, flags);
> +
> +	/* power down the phy */
> +	reg_val = readl(phy_driver->usbphy_regs +
> +			CRMU_USB_PHY_AON_CTRL_OFFSET);
> +	if (instance_ptr->port == 0) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P0_RESETB);
> +	} else if (instance_ptr->port == 1) {
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +		reg_val &= ~(1 << CRMU_USBPHY_P1_RESETB);
> +	} else if (instance_ptr->port == 2) {
> +		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);
> +
> +	instance_ptr->power = 0;
> +
> +	/* if a port is configured to device and it is being shutdown,
> +	 * turn off the clocks to the usb device controller */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {

	if (instance_ptr->port == 2 && !instance_ptr->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);
> +	} else {
> +
> +		/* 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
> +		 */

Here and elsewhere: preferred multi-line comment formatting is:

		/*
		 * Multi
		 * line
		 * comment
		 */


> +		reg_val = readl(phy_driver->usbphy_regs +
> +				CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		powered_on_phy = reg_val;
> +		if (reg_val == instance_ptr->port) {
> +			for (i = 0; i < phy_driver->num_phys; i++) {
> +				if (phy_driver->instances[i].power == 1 &&
> +				phy_driver->instances[i].host_mode ==
> +				PHY2_DEV_HOST_CTRL_SEL_HOST) {
> +					power_off_flag = 0;
> +					powered_on_phy = i;
> +				}
> +			}
> +		}
> +
> +		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);

if one branch has curly braces all of them shoudl have them:

		} else {
			writel(...);
		}

> +	}
> +
> +	spin_unlock_irqrestore(&phy_driver->lock, flags);
> +
> +	if (instance_ptr->vbus_supply)
> +		regulator_disable(instance_ptr->vbus_supply);
> +
> +	return 0;
> +}
> +
> +static int bcm_phy_poweron(struct phy *generic_phy)
> +{
> +	int ret, clock_reset_flag = 1;

	bool clock_reset_flag = true;

> +	unsigned long flags;
> +	u32 reg_val;
> +	struct bcm_phy_instance *instance_ptr = phy_get_drvdata(generic_phy);
> +	struct bcm_phy_driver *phy_driver = instance_ptr->driver;
> +
> +	if (instance_ptr->vbus_supply) {
> +		ret = regulator_enable(instance_ptr->vbus_supply);
> +		if (ret) {
> +			dev_err(&generic_phy->dev,
> +				"failed to enable regulator\n");
> +			return ret;
> +		}
> +	}
> +
> +	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);
> +
> +	if (instance_ptr->port == 0)
> +		reg_val |= (1 << CRMU_USBPHY_P0_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 1)
> +		reg_val |= (1 << CRMU_USBPHY_P1_AFE_CORERDY_VDDC);
> +	else if (instance_ptr->port == 2)
> +		reg_val |= (1 << CRMU_USBPHY_P2_AFE_CORERDY_VDDC);

	switch (instance_ptr->port) {
	case 0:
		...
	}

or maybe have a table for instance and corresponding control bits?

> +	writel(reg_val, phy_driver->usbphy_regs + CRMU_USB_PHY_AON_CTRL_OFFSET);
> +
> +	instance_ptr->power = 1;

	instance_ptr->power = true;

> +
> +	/* Check if the port 2 is configured for device */
> +	if (instance_ptr->port == 2 &&
> +		instance_ptr->host_mode == PHY2_DEV_HOST_CTRL_SEL_DEVICE) {

	if (instance_ptr->port == 2 && !instance_ptr->host_mode) {

> +
> +		ret = cdru_usbphy_p2_status_wait
> +		       (CDRU_USBPHY_P2_STATUS__USBPHY_ILDO_ON_FLAG, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_ILDO_ON_FLAG on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +		ret = cdru_usbphy_p2_status_wait
> +			(CDRU_USBPHY_P2_STATUS__USBPHY_PLL_LOCK, phy_driver);
> +		if (ret < 0) {
> +			dev_err(&generic_phy->dev, "Timed out waiting for USBPHY_PLL_LOCK on CDRU_USBPHY_P2_STATUS");
> +			goto err_shutdown;
> +		}
> +
> +

Extra blank line.

> +	/* Enable clock to USB device and get the USB device out of reset */

Indentation.

> +		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 < phy_driver->num_phys) {
> +			if (phy_driver->instances[reg_val].power == 1)
> +				clock_reset_flag = 0;
> +		}
> +
> +		/* if not set the current phy */
> +		if (clock_reset_flag) {
> +			reg_val = instance_ptr->port;
> +			writel(reg_val, phy_driver->usbphy_regs +
> +			       CDRU_USBPHY_CLK_RST_SEL_OFFSET);
> +		}
> +	}
> +
> +	if (phy_driver->idm_host_enabled != 1) {

	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 = 1;

		= 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 resource res;
> +	struct bcm_phy_driver *phy_driver;
> +	struct phy_provider *phy_provider;
> +	int ret, num_phys, i;
> +	u32 reg_val;
> +
> +	/* get number of phy cells */
> +	ret = of_property_read_u32(dev->of_node, "num-phys", &num_phys);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource num-phys\n");
> +		return ret;
> +	}
> +
> +	/* allocate memory for each phy instance */
> +	phy_driver = devm_kzalloc(dev, sizeof(struct bcm_phy_driver),
> +				  GFP_KERNEL);
> +	if (!phy_driver)
> +		return -ENOMEM;
> +
> +	phy_driver->instances = devm_kcalloc(dev, num_phys,
> +					     sizeof(struct bcm_phy_instance),
> +					     GFP_KERNEL);
> +	phy_driver->num_phys = num_phys;
> +	spin_lock_init(&phy_driver->lock);
> +
> +	ret = of_address_to_resource(dev->of_node, 0, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usbphy_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 1, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2h_idm_regs\n");
> +		return ret;
> +	}
> +	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;
> +	}
> +
> +	ret = of_address_to_resource(dev->of_node, 2, &res);
> +	if (ret) {
> +		dev_err(dev, "Failed to obtain device tree resource usb2d_idm_regs\n");
> +		return ret;
> +	}
> +	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 = 0;

	= false;

> +
> +	/* Shutdown 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 (i = 0; i < phy_driver->num_phys; i++) {
> +		char *vbus_name;
> +		struct bcm_phy_instance *instance_ptr =
> +					&phy_driver->instances[i];
> +
> +		vbus_name = devm_kzalloc(dev, MAX_REGULATOR_NAME_LEN,
> +					 GFP_KERNEL);

Why is this devm if it is freed immediately? MAX_REGULATOR_NAME_LEN is
only 25 bytes, just have on-stack array for this.

> +		if (!vbus_name)
> +			return -ENOMEM;
> +
> +		/* regulator use is optional */
> +		sprintf(vbus_name, "vbus-p%d", i);
> +		instance_ptr->vbus_supply = devm_regulator_get(dev, vbus_name);
> +		if (IS_ERR(instance_ptr->vbus_supply))
> +			instance_ptr->vbus_supply = NULL;
> +		devm_kfree(dev, vbus_name);
> +
> +		instance_ptr->generic_phy =
> +				devm_phy_create(dev, NULL, &ops);
> +
> +		if (IS_ERR(instance_ptr->generic_phy)) {
> +			dev_err(dev, "Failed to create usb phy %d", i);
> +			return PTR_ERR(instance_ptr->generic_phy);
> +		}
> +		instance_ptr->driver = phy_driver;
> +		phy_set_drvdata(instance_ptr->generic_phy, instance_ptr);
> +	}
> +
> +	phy_provider = devm_of_phy_provider_register(dev,
> +					bcm_usb_phy_xlate);
> +
> +	if (IS_ERR(phy_provider)) {
> +		dev_err(dev, "Failed to register as phy provider\n");
> +		return PTR_ERR(phy_provider);
> +	}
> +
> +	platform_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.0
> 

Thanks.

-- 
Dmitry

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  2015-02-26  0:24                 ` Arun Ramamurthy
@ 2015-03-10 20:27                   ` Arnd Bergmann
  -1 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-03-10 20:27 UTC (permalink / raw)
  To: Arun Ramamurthy
  Cc: linux-arm-kernel, Alan Stern, Mark Rutland, devicetree,
	Scott Branden, Pawel Moll, Ian Campbell, Ray Jui, linux-kernel,
	Kishon Vijay Abraham I, Jonathan Richardson, Rob Herring,
	bcm-kernel-feedback-list, Dmitry Torokhov, Kumar Gala,
	Anatol Pomazau

On Wednesday 25 February 2015 16:24:06 Arun Ramamurthy wrote:
> >>> Should I run this by Alan Stern?
> >>
> >> I've added him to Cc here. He clearly didn't know the background about
> >> the DT binding change, and should not need to, but he may have an opinion
> >> on what names we should use.
> >>
> >
> Arnd, should I re patch the ehci-platform driver to avoid phy-names 
> entirely? Alan, if not do you have an opinion on what the usb phy names 
> should be? The current patch uses "usbp" + port number such as "usbp0" , 
> "usbp1" etc

I think avoiding the phy names would be best here, but it requires a
kernel API change first, because we do not have a way to get a phy
by index as we do for other subsystems (e.g. clocks or gpios).

	Arnd

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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-03-10 20:27                   ` Arnd Bergmann
  0 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-03-10 20:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 25 February 2015 16:24:06 Arun Ramamurthy wrote:
> >>> Should I run this by Alan Stern?
> >>
> >> I've added him to Cc here. He clearly didn't know the background about
> >> the DT binding change, and should not need to, but he may have an opinion
> >> on what names we should use.
> >>
> >
> Arnd, should I re patch the ehci-platform driver to avoid phy-names 
> entirely? Alan, if not do you have an opinion on what the usb phy names 
> should be? The current patch uses "usbp" + port number such as "usbp0" , 
> "usbp1" etc

I think avoiding the phy names would be best here, but it requires a
kernel API change first, because we do not have a way to get a phy
by index as we do for other subsystems (e.g. clocks or gpios).

	Arnd

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
  2015-03-10 20:27                   ` Arnd Bergmann
  (?)
@ 2015-03-11 21:37                     ` Arun Ramamurthy
  -1 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-03-11 21:37 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Alan Stern, Mark Rutland, devicetree,
	Scott Branden, Pawel Moll, Ian Campbell, Ray Jui, linux-kernel,
	Kishon Vijay Abraham I, Jonathan Richardson, Rob Herring,
	bcm-kernel-feedback-list, Dmitry Torokhov, Kumar Gala,
	Anatol Pomazau



On 15-03-10 01:27 PM, Arnd Bergmann wrote:
> On Wednesday 25 February 2015 16:24:06 Arun Ramamurthy wrote:
>>>>> Should I run this by Alan Stern?
>>>>
>>>> I've added him to Cc here. He clearly didn't know the background about
>>>> the DT binding change, and should not need to, but he may have an opinion
>>>> on what names we should use.
>>>>
>>>
>> Arnd, should I re patch the ehci-platform driver to avoid phy-names
>> entirely? Alan, if not do you have an opinion on what the usb phy names
>> should be? The current patch uses "usbp" + port number such as "usbp0" ,
>> "usbp1" etc
>
> I think avoiding the phy names would be best here, but it requires a
> kernel API change first, because we do not have a way to get a phy
> by index as we do for other subsystems (e.g. clocks or gpios).
>
Arnd , there is an existing api _of_phy_get that gets a phy by index. 
However it is not exported and is called from of_phy_get which is in 
turn called from devm_of_phy_get.

My plan is to create a new function maybe devm_of_phy_get_by_index that 
calls _of_phy_get directly? What are your thoughts?

> 	Arnd
>

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-03-11 21:37                     ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-03-11 21:37 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, Alan Stern, Mark Rutland, devicetree,
	Scott Branden, Pawel Moll, Ian Campbell, Ray Jui, linux-kernel,
	Kishon Vijay Abraham I, Jonathan Richardson, Rob Herring,
	bcm-kernel-feedback-list, Dmitry Torokhov, Kumar Gala,
	Anatol Pomazau



On 15-03-10 01:27 PM, Arnd Bergmann wrote:
> On Wednesday 25 February 2015 16:24:06 Arun Ramamurthy wrote:
>>>>> Should I run this by Alan Stern?
>>>>
>>>> I've added him to Cc here. He clearly didn't know the background about
>>>> the DT binding change, and should not need to, but he may have an opinion
>>>> on what names we should use.
>>>>
>>>
>> Arnd, should I re patch the ehci-platform driver to avoid phy-names
>> entirely? Alan, if not do you have an opinion on what the usb phy names
>> should be? The current patch uses "usbp" + port number such as "usbp0" ,
>> "usbp1" etc
>
> I think avoiding the phy names would be best here, but it requires a
> kernel API change first, because we do not have a way to get a phy
> by index as we do for other subsystems (e.g. clocks or gpios).
>
Arnd , there is an existing api _of_phy_get that gets a phy by index. 
However it is not exported and is called from of_phy_get which is in 
turn called from devm_of_phy_get.

My plan is to create a new function maybe devm_of_phy_get_by_index that 
calls _of_phy_get directly? What are your thoughts?

> 	Arnd
>

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

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-03-11 21:37                     ` Arun Ramamurthy
  0 siblings, 0 replies; 40+ messages in thread
From: Arun Ramamurthy @ 2015-03-11 21:37 UTC (permalink / raw)
  To: linux-arm-kernel



On 15-03-10 01:27 PM, Arnd Bergmann wrote:
> On Wednesday 25 February 2015 16:24:06 Arun Ramamurthy wrote:
>>>>> Should I run this by Alan Stern?
>>>>
>>>> I've added him to Cc here. He clearly didn't know the background about
>>>> the DT binding change, and should not need to, but he may have an opinion
>>>> on what names we should use.
>>>>
>>>
>> Arnd, should I re patch the ehci-platform driver to avoid phy-names
>> entirely? Alan, if not do you have an opinion on what the usb phy names
>> should be? The current patch uses "usbp" + port number such as "usbp0" ,
>> "usbp1" etc
>
> I think avoiding the phy names would be best here, but it requires a
> kernel API change first, because we do not have a way to get a phy
> by index as we do for other subsystems (e.g. clocks or gpios).
>
Arnd , there is an existing api _of_phy_get that gets a phy by index. 
However it is not exported and is called from of_phy_get which is in 
turn called from devm_of_phy_get.

My plan is to create a new function maybe devm_of_phy_get_by_index that 
calls _of_phy_get directly? What are your thoughts?

> 	Arnd
>

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-03-11 21:47                       ` Arnd Bergmann
  0 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-03-11 21:47 UTC (permalink / raw)
  To: Arun Ramamurthy
  Cc: linux-arm-kernel, Alan Stern, Mark Rutland, devicetree,
	Scott Branden, Pawel Moll, Ian Campbell, Ray Jui, linux-kernel,
	Kishon Vijay Abraham I, Jonathan Richardson, Rob Herring,
	bcm-kernel-feedback-list, Dmitry Torokhov, Kumar Gala,
	Anatol Pomazau

On Wednesday 11 March 2015 14:37:58 Arun Ramamurthy wrote:
> On 15-03-10 01:27 PM, Arnd Bergmann wrote:
> > On Wednesday 25 February 2015 16:24:06 Arun Ramamurthy wrote:
> >>>>> Should I run this by Alan Stern?
> >>>>
> >>>> I've added him to Cc here. He clearly didn't know the background about
> >>>> the DT binding change, and should not need to, but he may have an opinion
> >>>> on what names we should use.
> >>>>
> >>>
> >> Arnd, should I re patch the ehci-platform driver to avoid phy-names
> >> entirely? Alan, if not do you have an opinion on what the usb phy names
> >> should be? The current patch uses "usbp" + port number such as "usbp0" ,
> >> "usbp1" etc
> >
> > I think avoiding the phy names would be best here, but it requires a
> > kernel API change first, because we do not have a way to get a phy
> > by index as we do for other subsystems (e.g. clocks or gpios).
> >
> Arnd , there is an existing api _of_phy_get that gets a phy by index. 
> However it is not exported and is called from of_phy_get which is in 
> turn called from devm_of_phy_get.
> 
> My plan is to create a new function maybe devm_of_phy_get_by_index that 
> calls _of_phy_get directly? What are your thoughts?

Sounds good to me.

	Arnd

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

* Re: [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-03-11 21:47                       ` Arnd Bergmann
  0 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-03-11 21:47 UTC (permalink / raw)
  To: Arun Ramamurthy
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Alan Stern,
	Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA, Scott Branden,
	Pawel Moll, Ian Campbell, Ray Jui,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Kishon Vijay Abraham I,
	Jonathan Richardson, Rob Herring,
	bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Dmitry Torokhov,
	Kumar Gala, Anatol Pomazau

On Wednesday 11 March 2015 14:37:58 Arun Ramamurthy wrote:
> On 15-03-10 01:27 PM, Arnd Bergmann wrote:
> > On Wednesday 25 February 2015 16:24:06 Arun Ramamurthy wrote:
> >>>>> Should I run this by Alan Stern?
> >>>>
> >>>> I've added him to Cc here. He clearly didn't know the background about
> >>>> the DT binding change, and should not need to, but he may have an opinion
> >>>> on what names we should use.
> >>>>
> >>>
> >> Arnd, should I re patch the ehci-platform driver to avoid phy-names
> >> entirely? Alan, if not do you have an opinion on what the usb phy names
> >> should be? The current patch uses "usbp" + port number such as "usbp0" ,
> >> "usbp1" etc
> >
> > I think avoiding the phy names would be best here, but it requires a
> > kernel API change first, because we do not have a way to get a phy
> > by index as we do for other subsystems (e.g. clocks or gpios).
> >
> Arnd , there is an existing api _of_phy_get that gets a phy by index. 
> However it is not exported and is called from of_phy_get which is in 
> turn called from devm_of_phy_get.
> 
> My plan is to create a new function maybe devm_of_phy_get_by_index that 
> calls _of_phy_get directly? What are your thoughts?

Sounds good to me.

	Arnd
--
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] 40+ messages in thread

* [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver
@ 2015-03-11 21:47                       ` Arnd Bergmann
  0 siblings, 0 replies; 40+ messages in thread
From: Arnd Bergmann @ 2015-03-11 21:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 11 March 2015 14:37:58 Arun Ramamurthy wrote:
> On 15-03-10 01:27 PM, Arnd Bergmann wrote:
> > On Wednesday 25 February 2015 16:24:06 Arun Ramamurthy wrote:
> >>>>> Should I run this by Alan Stern?
> >>>>
> >>>> I've added him to Cc here. He clearly didn't know the background about
> >>>> the DT binding change, and should not need to, but he may have an opinion
> >>>> on what names we should use.
> >>>>
> >>>
> >> Arnd, should I re patch the ehci-platform driver to avoid phy-names
> >> entirely? Alan, if not do you have an opinion on what the usb phy names
> >> should be? The current patch uses "usbp" + port number such as "usbp0" ,
> >> "usbp1" etc
> >
> > I think avoiding the phy names would be best here, but it requires a
> > kernel API change first, because we do not have a way to get a phy
> > by index as we do for other subsystems (e.g. clocks or gpios).
> >
> Arnd , there is an existing api _of_phy_get that gets a phy by index. 
> However it is not exported and is called from of_phy_get which is in 
> turn called from devm_of_phy_get.
> 
> My plan is to create a new function maybe devm_of_phy_get_by_index that 
> calls _of_phy_get directly? What are your thoughts?

Sounds good to me.

	Arnd

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

end of thread, other threads:[~2015-03-11 21:48 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-17 19:20 [PATCH 0/2] USB PHY driver for Broadcom's Cygnus chipset Arun Ramamurthy
2015-02-17 19:20 ` Arun Ramamurthy
2015-02-17 19:20 ` Arun Ramamurthy
2015-02-17 19:20 ` [PATCH 1/2] phy: usbphy: Add dt documentation for Broadcom Cygnus USB PHY driver Arun Ramamurthy
2015-02-17 19:20   ` Arun Ramamurthy
2015-02-17 19:20   ` Arun Ramamurthy
2015-02-17 19:41   ` Arnd Bergmann
2015-02-17 19:41     ` Arnd Bergmann
2015-02-17 20:00     ` Arun Ramamurthy
2015-02-17 20:00       ` Arun Ramamurthy
2015-02-17 20:00       ` Arun Ramamurthy
2015-02-17 20:53       ` Arnd Bergmann
2015-02-17 20:53         ` Arnd Bergmann
2015-02-17 21:05         ` Arun Ramamurthy
2015-02-17 21:05           ` Arun Ramamurthy
2015-02-17 21:05           ` Arun Ramamurthy
2015-02-18 15:15           ` Arnd Bergmann
2015-02-18 15:15             ` Arnd Bergmann
2015-02-19  0:46             ` Arun Ramamurthy
2015-02-19  0:46               ` Arun Ramamurthy
2015-02-19  0:46               ` Arun Ramamurthy
2015-02-26  0:24               ` Arun Ramamurthy
2015-02-26  0:24                 ` Arun Ramamurthy
2015-02-26  0:24                 ` Arun Ramamurthy
2015-03-10 20:27                 ` Arnd Bergmann
2015-03-10 20:27                   ` Arnd Bergmann
2015-03-11 21:37                   ` Arun Ramamurthy
2015-03-11 21:37                     ` Arun Ramamurthy
2015-03-11 21:37                     ` Arun Ramamurthy
2015-03-11 21:47                     ` Arnd Bergmann
2015-03-11 21:47                       ` Arnd Bergmann
2015-03-11 21:47                       ` Arnd Bergmann
2015-02-17 19:20 ` [PATCH 2/2] phy: usbphy: Add " Arun Ramamurthy
2015-02-17 19:20   ` Arun Ramamurthy
2015-02-17 19:20   ` Arun Ramamurthy
2015-02-18  6:10   ` Kishon Vijay Abraham I
2015-02-18  6:10     ` Kishon Vijay Abraham I
2015-02-18  6:10     ` Kishon Vijay Abraham I
2015-03-05 22:33   ` Dmitry Torokhov
2015-03-05 22:33     ` Dmitry Torokhov

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.