All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 0/4] Add a new Rockchip usb2 phy driver
@ 2016-07-22  7:00 ` Frank Wang
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Wang @ 2016-07-22  7:00 UTC (permalink / raw)
  To: heiko, dianders, linux, groeck, jwerner, kishon, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak
  Cc: linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu,
	kever.yang, huangtao, william.wu, daniel.meng, frank.wang

The newer SoCs (rk3366, rk3399) of Rock-chip take a different usb-phy
IP block than rk3288 and before, and most of phy-related registers are
also different from the past, so a new phy driver is required necessarily.

These series patch add phy-rockchip-inno-usb2.c and the corresponding
dt-bindings.

Changes in v9:
 - Move the usb gpio config from dtsi to dts.
 - Add vin-supply (vcc5v0_sys) for vcc5v0_host.
 - Change some properties' name.

Changes in v8:
 - Added support for rk3399 SoC.
 - Prepare input clock of phy at probe time.
 - Improved sm_work function to handle phy-port state more clearly.

Changes in v7:
 - Renamed functions *usb2phy_resume/*usb2phy_suspend to *usb2phy_power_on/usb2phy_power_off.

Changes in v6:
 - Changed '_' to '-' for otg-id and otg-bvalid property in devicetree bindings.
 - Fixed the output clock would be disabled more than once while phy-port was going to suspend.
 - Improved the driver to avoid the currently empty otg-port would cause null-pointer dereferences.

Changes in v5:
 - Added 'reg' property both in devicetree bindings and driver to match the different phy-blocks.

Changes in v4:
 - Used 'phy-supply' instead of 'vbus_*-supply'.

Changes in v3:
 - Supplemented some hardware-description into the devicetree bindings.
 - Resolved the mapping defect between fixed value in driver and the property
   in devicetree.
 - Code cleanup.

Changes in v2:
 - Specified more hardware-description into the devicetree bindings.
 - Optimized some process of driver.

Frank Wang (4):
  Documentation: bindings: add DT documentation for Rockchip USB2PHY
  phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy
  arm64: dts: rockchip: add usb2-phy support for rk3399
  arm64: dts: rockchip: configure usb2-phy support for rk3399-evb

 .../bindings/phy/phy-rockchip-inno-usb2.txt        |   64 ++
 arch/arm64/boot/dts/rockchip/rk3399-evb.dts        |   44 ++
 arch/arm64/boot/dts/rockchip/rk3399.dtsi           |   42 +-
 drivers/phy/Kconfig                                |    7 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-rockchip-inno-usb2.c               |  707 ++++++++++++++++++++
 6 files changed, 864 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
 create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c

-- 
1.7.9.5

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

* [PATCH v9 0/4] Add a new Rockchip usb2 phy driver
@ 2016-07-22  7:00 ` Frank Wang
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Wang @ 2016-07-22  7:00 UTC (permalink / raw)
  To: heiko-4mtYJXux2i+zQB+pC5nmwQ, dianders-F7+t8E8rja9g9hUCZPvPmw,
	linux-0h96xk9xTtrk1uMJSBkQmQ, groeck-F7+t8E8rja9g9hUCZPvPmw,
	jwerner-F7+t8E8rja9g9hUCZPvPmw, kishon-l0cyMroinI0,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	xzy.xu-TNX95d0MmH7DzftRWevZcw, kever.yang-TNX95d0MmH7DzftRWevZcw,
	huangtao-TNX95d0MmH7DzftRWevZcw,
	william.wu-TNX95d0MmH7DzftRWevZcw,
	daniel.meng-TNX95d0MmH7DzftRWevZcw,
	frank.wang-TNX95d0MmH7DzftRWevZcw

The newer SoCs (rk3366, rk3399) of Rock-chip take a different usb-phy
IP block than rk3288 and before, and most of phy-related registers are
also different from the past, so a new phy driver is required necessarily.

These series patch add phy-rockchip-inno-usb2.c and the corresponding
dt-bindings.

Changes in v9:
 - Move the usb gpio config from dtsi to dts.
 - Add vin-supply (vcc5v0_sys) for vcc5v0_host.
 - Change some properties' name.

Changes in v8:
 - Added support for rk3399 SoC.
 - Prepare input clock of phy at probe time.
 - Improved sm_work function to handle phy-port state more clearly.

Changes in v7:
 - Renamed functions *usb2phy_resume/*usb2phy_suspend to *usb2phy_power_on/usb2phy_power_off.

Changes in v6:
 - Changed '_' to '-' for otg-id and otg-bvalid property in devicetree bindings.
 - Fixed the output clock would be disabled more than once while phy-port was going to suspend.
 - Improved the driver to avoid the currently empty otg-port would cause null-pointer dereferences.

Changes in v5:
 - Added 'reg' property both in devicetree bindings and driver to match the different phy-blocks.

Changes in v4:
 - Used 'phy-supply' instead of 'vbus_*-supply'.

Changes in v3:
 - Supplemented some hardware-description into the devicetree bindings.
 - Resolved the mapping defect between fixed value in driver and the property
   in devicetree.
 - Code cleanup.

Changes in v2:
 - Specified more hardware-description into the devicetree bindings.
 - Optimized some process of driver.

Frank Wang (4):
  Documentation: bindings: add DT documentation for Rockchip USB2PHY
  phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy
  arm64: dts: rockchip: add usb2-phy support for rk3399
  arm64: dts: rockchip: configure usb2-phy support for rk3399-evb

 .../bindings/phy/phy-rockchip-inno-usb2.txt        |   64 ++
 arch/arm64/boot/dts/rockchip/rk3399-evb.dts        |   44 ++
 arch/arm64/boot/dts/rockchip/rk3399.dtsi           |   42 +-
 drivers/phy/Kconfig                                |    7 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-rockchip-inno-usb2.c               |  707 ++++++++++++++++++++
 6 files changed, 864 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
 create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c

-- 
1.7.9.5


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" 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] 15+ messages in thread

* [PATCH v9 1/4] Documentation: bindings: add DT documentation for Rockchip USB2PHY
@ 2016-07-22  7:00   ` Frank Wang
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Wang @ 2016-07-22  7:00 UTC (permalink / raw)
  To: heiko, dianders, linux, groeck, jwerner, kishon, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak
  Cc: linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu,
	kever.yang, huangtao, william.wu, daniel.meng, frank.wang

Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
---

Changes in v9: None

Changes in v8: None

Changes in v7: None

Changes in v6:
 - Changed '_' to '-' for otg-id and otg-bvalid property.

Changes in v5:
 - Added 'reg' property to identify the different phy-blocks.

Changes in v4:
 - Used 'phy-supply' instead of 'vbus_*-supply'.

Changes in v3:
 - Added 'clocks' and 'clock-names' optional properties.
 - Specified 'otg-port' and 'host-port' as the sub-node name.

Changes in v2:
 - Changed vbus_host optional property from gpio to regulator.
 - Specified vbus_otg-supply optional property.
 - Specified otg_id and otg_bvalid property.

 .../bindings/phy/phy-rockchip-inno-usb2.txt        |   64 ++++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt

diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
new file mode 100644
index 0000000..3c29c77
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
@@ -0,0 +1,64 @@
+ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK
+
+Required properties (phy (parent) node):
+ - compatible : should be one of the listed compatibles:
+	* "rockchip,rk3366-usb2phy"
+	* "rockchip,rk3399-usb2phy"
+ - reg : the address offset of grf for usb-phy configuration.
+ - #clock-cells : should be 0.
+ - clock-output-names : specify the 480m output clock name.
+
+Optional properties:
+ - clocks : phandle + phy specifier pair, for the input clock of phy.
+ - clock-names : input clock name of phy, must be "phyclk".
+
+Required nodes : a sub-node is required for each port the phy provides.
+		 The sub-node name is used to identify host or otg port,
+		 and shall be the following entries:
+	* "otg-port" : the name of otg port.
+	* "host-port" : the name of host port.
+
+Required properties (port (child) node):
+ - #phy-cells : must be 0. See ./phy-bindings.txt for details.
+ - interrupts : specify an interrupt for each entry in interrupt-names.
+ - interrupt-names : a list which shall be the following entries:
+	* "otg-id" : for the otg id interrupt.
+	* "otg-bvalid" : for the otg vbus interrupt.
+	* "linestate" : for the host/otg linestate interrupt.
+
+Optional properties:
+ - phy-supply : phandle to a regulator that provides power to VBUS.
+		See ./phy-bindings.txt for details.
+
+Example:
+
+grf: syscon@ff770000 {
+	compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+...
+
+	u2phy: usb2-phy@700 {
+		compatible = "rockchip,rk3366-usb2phy";
+		reg = <0x700 0x2c>;
+		#clock-cells = <0>;
+		clock-output-names = "sclk_otgphy0_480m";
+
+		u2phy_otg: otg-port {
+			#phy-cells = <0>;
+			interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "otg-id", "otg-bvalid", "linestate";
+			status = "okay";
+		};
+
+		u2phy_host: host-port {
+			#phy-cells = <0>;
+			interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "linestate";
+			status = "okay";
+		};
+	};
+};
-- 
1.7.9.5

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

* [PATCH v9 1/4] Documentation: bindings: add DT documentation for Rockchip USB2PHY
@ 2016-07-22  7:00   ` Frank Wang
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Wang @ 2016-07-22  7:00 UTC (permalink / raw)
  To: heiko-4mtYJXux2i+zQB+pC5nmwQ, dianders-F7+t8E8rja9g9hUCZPvPmw,
	linux-0h96xk9xTtrk1uMJSBkQmQ, groeck-F7+t8E8rja9g9hUCZPvPmw,
	jwerner-F7+t8E8rja9g9hUCZPvPmw, kishon-l0cyMroinI0,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	xzy.xu-TNX95d0MmH7DzftRWevZcw, kever.yang-TNX95d0MmH7DzftRWevZcw,
	huangtao-TNX95d0MmH7DzftRWevZcw,
	william.wu-TNX95d0MmH7DzftRWevZcw,
	daniel.meng-TNX95d0MmH7DzftRWevZcw,
	frank.wang-TNX95d0MmH7DzftRWevZcw

Signed-off-by: Frank Wang <frank.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Reviewed-by: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
---

Changes in v9: None

Changes in v8: None

Changes in v7: None

Changes in v6:
 - Changed '_' to '-' for otg-id and otg-bvalid property.

Changes in v5:
 - Added 'reg' property to identify the different phy-blocks.

Changes in v4:
 - Used 'phy-supply' instead of 'vbus_*-supply'.

Changes in v3:
 - Added 'clocks' and 'clock-names' optional properties.
 - Specified 'otg-port' and 'host-port' as the sub-node name.

Changes in v2:
 - Changed vbus_host optional property from gpio to regulator.
 - Specified vbus_otg-supply optional property.
 - Specified otg_id and otg_bvalid property.

 .../bindings/phy/phy-rockchip-inno-usb2.txt        |   64 ++++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt

diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
new file mode 100644
index 0000000..3c29c77
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
@@ -0,0 +1,64 @@
+ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK
+
+Required properties (phy (parent) node):
+ - compatible : should be one of the listed compatibles:
+	* "rockchip,rk3366-usb2phy"
+	* "rockchip,rk3399-usb2phy"
+ - reg : the address offset of grf for usb-phy configuration.
+ - #clock-cells : should be 0.
+ - clock-output-names : specify the 480m output clock name.
+
+Optional properties:
+ - clocks : phandle + phy specifier pair, for the input clock of phy.
+ - clock-names : input clock name of phy, must be "phyclk".
+
+Required nodes : a sub-node is required for each port the phy provides.
+		 The sub-node name is used to identify host or otg port,
+		 and shall be the following entries:
+	* "otg-port" : the name of otg port.
+	* "host-port" : the name of host port.
+
+Required properties (port (child) node):
+ - #phy-cells : must be 0. See ./phy-bindings.txt for details.
+ - interrupts : specify an interrupt for each entry in interrupt-names.
+ - interrupt-names : a list which shall be the following entries:
+	* "otg-id" : for the otg id interrupt.
+	* "otg-bvalid" : for the otg vbus interrupt.
+	* "linestate" : for the host/otg linestate interrupt.
+
+Optional properties:
+ - phy-supply : phandle to a regulator that provides power to VBUS.
+		See ./phy-bindings.txt for details.
+
+Example:
+
+grf: syscon@ff770000 {
+	compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+...
+
+	u2phy: usb2-phy@700 {
+		compatible = "rockchip,rk3366-usb2phy";
+		reg = <0x700 0x2c>;
+		#clock-cells = <0>;
+		clock-output-names = "sclk_otgphy0_480m";
+
+		u2phy_otg: otg-port {
+			#phy-cells = <0>;
+			interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "otg-id", "otg-bvalid", "linestate";
+			status = "okay";
+		};
+
+		u2phy_host: host-port {
+			#phy-cells = <0>;
+			interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "linestate";
+			status = "okay";
+		};
+	};
+};
-- 
1.7.9.5


--
To unsubscribe from this list: send the line "unsubscribe linux-usb" 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] 15+ messages in thread

* [PATCH v9 2/4] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy
  2016-07-22  7:00 ` Frank Wang
  (?)
  (?)
@ 2016-07-22  7:00 ` Frank Wang
  2016-08-12 10:09     ` Kishon Vijay Abraham I
  -1 siblings, 1 reply; 15+ messages in thread
From: Frank Wang @ 2016-07-22  7:00 UTC (permalink / raw)
  To: heiko, dianders, linux, groeck, jwerner, kishon, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak
  Cc: linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu,
	kever.yang, huangtao, william.wu, daniel.meng, frank.wang

The newer SoCs (rk3366, rk3399) take a different usb-phy IP block
than rk3288 and before, and most of phy-related registers are also
different from the past, so a new phy driver is required necessarily.

Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
Suggested-by: Heiko Stuebner <heiko@sntech.de>
Suggested-by: Guenter Roeck <linux@roeck-us.net>
Suggested-by: Doug Anderson <dianders@chromium.org>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
---

Changes in v9:
 - Add "Reviewed-by" info.

Changes in v8:
 - Added support for rk3399 SoC.
 - Prepare input clock of phy at probe time.
 - Improved sm_work function to handle phy-port state more clearly.

Changes in v7:
 - renamed functions *usb2phy_resume/*usb2phy_suspend to *usb2phy_power_on/usb2phy_power_off.

Changes in v6:
 - Fixed the output clock would be disabled more than once while phy-port was going to suspend.
 - Improved the driver to avoid the currently empty otg-port would cause null-pointer dereferences.

Changes in v5:
 - Added 'reg' in the data block to match the different phy-blocks in dt.

Changes in v4:
 - Removed some processes related to 'vbus_host-supply'.

Changes in v3:
 - Resolved the mapping defect between fixed value in driver and the property
   in devicetree.
 - Optimized 480m output clock register function.
 - Code cleanup.

Changes in v2:
 - Changed vbus_host operation from gpio to regulator in *_probe.
 - Improved the fault treatment relate to 480m clock register.
 - Cleaned up some meaningless codes in *_clk480m_disable.
 - made more clear the comment of *_sm_work.

 drivers/phy/Kconfig                  |    7 +
 drivers/phy/Makefile                 |    1 +
 drivers/phy/phy-rockchip-inno-usb2.c |  707 ++++++++++++++++++++++++++++++++++
 3 files changed, 715 insertions(+)
 create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index b869b98..29ef15c 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -347,6 +347,13 @@ config PHY_ROCKCHIP_USB
 	help
 	  Enable this to support the Rockchip USB 2.0 PHY.
 
+config PHY_ROCKCHIP_INNO_USB2
+	tristate "Rockchip INNO USB2PHY Driver"
+	depends on ARCH_ROCKCHIP && OF
+	select GENERIC_PHY
+	help
+	  Support for Rockchip USB2.0 PHY with Innosilicon IP block.
+
 config PHY_ROCKCHIP_EMMC
 	tristate "Rockchip EMMC PHY Driver"
 	depends on ARCH_ROCKCHIP && OF
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 9c3e73c..4963fbc 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -38,6 +38,7 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2)	+= phy-s5pv210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS5_USBDRD)	+= phy-exynos5-usbdrd.o
 obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
 obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
+obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2)	+= phy-rockchip-inno-usb2.o
 obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
 obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
new file mode 100644
index 0000000..ac20310
--- /dev/null
+++ b/drivers/phy/phy-rockchip-inno-usb2.c
@@ -0,0 +1,707 @@
+/*
+ * Rockchip USB2.0 PHY with Innosilicon IP block driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/gpio/consumer.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define BIT_WRITEABLE_SHIFT	16
+#define SCHEDULE_DELAY	(60 * HZ)
+
+enum rockchip_usb2phy_port_id {
+	USB2PHY_PORT_OTG,
+	USB2PHY_PORT_HOST,
+	USB2PHY_NUM_PORTS,
+};
+
+enum rockchip_usb2phy_host_state {
+	PHY_STATE_HS_ONLINE	= 0,
+	PHY_STATE_DISCONNECT	= 1,
+	PHY_STATE_CONNECT	= 2,
+	PHY_STATE_FS_LS_ONLINE	= 4,
+};
+
+struct usb2phy_reg {
+	unsigned int	offset;
+	unsigned int	bitend;
+	unsigned int	bitstart;
+	unsigned int	disable;
+	unsigned int	enable;
+};
+
+/**
+ * struct rockchip_usb2phy_port_cfg: usb-phy port configuration.
+ * @phy_sus: phy suspend register.
+ * @ls_det_en: linestate detection enable register.
+ * @ls_det_st: linestate detection state register.
+ * @ls_det_clr: linestate detection clear register.
+ * @utmi_ls: utmi linestate state register.
+ * @utmi_hstdet: utmi host disconnect register.
+ */
+struct rockchip_usb2phy_port_cfg {
+	struct usb2phy_reg	phy_sus;
+	struct usb2phy_reg	ls_det_en;
+	struct usb2phy_reg	ls_det_st;
+	struct usb2phy_reg	ls_det_clr;
+	struct usb2phy_reg	utmi_ls;
+	struct usb2phy_reg	utmi_hstdet;
+};
+
+/**
+ * struct rockchip_usb2phy_cfg: usb-phy configuration.
+ * @reg: the address offset of grf for usb-phy config.
+ * @num_ports: specify how many ports that the phy has.
+ * @clkout_ctl: keep on/turn off output clk of phy.
+ */
+struct rockchip_usb2phy_cfg {
+	unsigned int	reg;
+	unsigned int	num_ports;
+	struct usb2phy_reg	clkout_ctl;
+	const struct rockchip_usb2phy_port_cfg	port_cfgs[USB2PHY_NUM_PORTS];
+};
+
+/**
+ * struct rockchip_usb2phy_port: usb-phy port data.
+ * @port_id: flag for otg port or host port.
+ * @suspended: phy suspended flag.
+ * @ls_irq: IRQ number assigned for linestate detection.
+ * @mutex: for register updating in sm_work.
+ * @sm_work: OTG state machine work.
+ * @phy_cfg: port register configuration, assigned by driver data.
+ */
+struct rockchip_usb2phy_port {
+	struct phy	*phy;
+	unsigned int	port_id;
+	bool		suspended;
+	int		ls_irq;
+	struct mutex	mutex;
+	struct		delayed_work sm_work;
+	const struct	rockchip_usb2phy_port_cfg *port_cfg;
+};
+
+/**
+ * struct rockchip_usb2phy: usb2.0 phy driver data.
+ * @grf: General Register Files regmap.
+ * @clk: clock struct of phy input clk.
+ * @clk480m: clock struct of phy output clk.
+ * @clk_hw: clock struct of phy output clk management.
+ * @phy_cfg: phy register configuration, assigned by driver data.
+ * @ports: phy port instance.
+ */
+struct rockchip_usb2phy {
+	struct device	*dev;
+	struct regmap	*grf;
+	struct clk	*clk;
+	struct clk	*clk480m;
+	struct clk_hw	clk480m_hw;
+	const struct rockchip_usb2phy_cfg	*phy_cfg;
+	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];
+};
+
+static inline int property_enable(struct rockchip_usb2phy *rphy,
+				  const struct usb2phy_reg *reg, bool en)
+{
+	unsigned int val, mask, tmp;
+
+	tmp = en ? reg->enable : reg->disable;
+	mask = GENMASK(reg->bitend, reg->bitstart);
+	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
+
+	return regmap_write(rphy->grf, reg->offset, val);
+}
+
+static inline bool property_enabled(struct rockchip_usb2phy *rphy,
+				    const struct usb2phy_reg *reg)
+{
+	int ret;
+	unsigned int tmp, orig;
+	unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
+
+	ret = regmap_read(rphy->grf, reg->offset, &orig);
+	if (ret)
+		return false;
+
+	tmp = (orig & mask) >> reg->bitstart;
+	return tmp == reg->enable;
+}
+
+static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw)
+{
+	struct rockchip_usb2phy *rphy =
+		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
+	int ret;
+
+	/* turn on 480m clk output if it is off */
+	if (!property_enabled(rphy, &rphy->phy_cfg->clkout_ctl)) {
+		ret = property_enable(rphy, &rphy->phy_cfg->clkout_ctl, true);
+		if (ret)
+			return ret;
+
+		/* waitting for the clk become stable */
+		mdelay(1);
+	}
+
+	return 0;
+}
+
+static void rockchip_usb2phy_clk480m_disable(struct clk_hw *hw)
+{
+	struct rockchip_usb2phy *rphy =
+		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
+
+	/* turn off 480m clk output */
+	property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false);
+}
+
+static int rockchip_usb2phy_clk480m_enabled(struct clk_hw *hw)
+{
+	struct rockchip_usb2phy *rphy =
+		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
+
+	return property_enabled(rphy, &rphy->phy_cfg->clkout_ctl);
+}
+
+static unsigned long
+rockchip_usb2phy_clk480m_recalc_rate(struct clk_hw *hw,
+				     unsigned long parent_rate)
+{
+	return 480000000;
+}
+
+static const struct clk_ops rockchip_usb2phy_clkout_ops = {
+	.enable = rockchip_usb2phy_clk480m_enable,
+	.disable = rockchip_usb2phy_clk480m_disable,
+	.is_enabled = rockchip_usb2phy_clk480m_enabled,
+	.recalc_rate = rockchip_usb2phy_clk480m_recalc_rate,
+};
+
+static void rockchip_usb2phy_clk480m_unregister(void *data)
+{
+	struct rockchip_usb2phy *rphy = data;
+
+	of_clk_del_provider(rphy->dev->of_node);
+	clk_unregister(rphy->clk480m);
+}
+
+static int
+rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy)
+{
+	struct device_node *node = rphy->dev->of_node;
+	struct clk_init_data init;
+	const char *clk_name;
+	int ret;
+
+	init.flags = 0;
+	init.name = "clk_usbphy_480m";
+	init.ops = &rockchip_usb2phy_clkout_ops;
+
+	/* optional override of the clockname */
+	of_property_read_string(node, "clock-output-names", &init.name);
+
+	if (rphy->clk) {
+		clk_name = __clk_get_name(rphy->clk);
+		init.parent_names = &clk_name;
+		init.num_parents = 1;
+	} else {
+		init.parent_names = NULL;
+		init.num_parents = 0;
+	}
+
+	rphy->clk480m_hw.init = &init;
+
+	/* register the clock */
+	rphy->clk480m = clk_register(rphy->dev, &rphy->clk480m_hw);
+	if (IS_ERR(rphy->clk480m)) {
+		ret = PTR_ERR(rphy->clk480m);
+		goto err_ret;
+	}
+
+	ret = of_clk_add_provider(node, of_clk_src_simple_get, rphy->clk480m);
+	if (ret < 0)
+		goto err_clk_provider;
+
+	ret = devm_add_action(rphy->dev, rockchip_usb2phy_clk480m_unregister,
+			      rphy);
+	if (ret < 0)
+		goto err_unreg_action;
+
+	return 0;
+
+err_unreg_action:
+	of_clk_del_provider(node);
+err_clk_provider:
+	clk_unregister(rphy->clk480m);
+err_ret:
+	return ret;
+}
+
+static int rockchip_usb2phy_init(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
+	int ret;
+
+	if (rport->port_id == USB2PHY_PORT_HOST) {
+		/* clear linestate and enable linestate detect irq */
+		mutex_lock(&rport->mutex);
+
+		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+		if (ret) {
+			mutex_unlock(&rport->mutex);
+			return ret;
+		}
+
+		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
+		if (ret) {
+			mutex_unlock(&rport->mutex);
+			return ret;
+		}
+
+		mutex_unlock(&rport->mutex);
+		schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
+	}
+
+	return 0;
+}
+
+static int rockchip_usb2phy_power_on(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
+	int ret;
+
+	dev_dbg(&rport->phy->dev, "port power on\n");
+
+	if (!rport->suspended)
+		return 0;
+
+	ret = clk_prepare_enable(rphy->clk480m);
+	if (ret)
+		return ret;
+
+	ret = property_enable(rphy, &rport->port_cfg->phy_sus, false);
+	if (ret)
+		return ret;
+
+	rport->suspended = false;
+	return 0;
+}
+
+static int rockchip_usb2phy_power_off(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
+	int ret;
+
+	dev_dbg(&rport->phy->dev, "port power off\n");
+
+	if (rport->suspended)
+		return 0;
+
+	ret = property_enable(rphy, &rport->port_cfg->phy_sus, true);
+	if (ret)
+		return ret;
+
+	rport->suspended = true;
+	clk_disable_unprepare(rphy->clk480m);
+
+	return 0;
+}
+
+static int rockchip_usb2phy_exit(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+
+	if (rport->port_id == USB2PHY_PORT_HOST)
+		cancel_delayed_work_sync(&rport->sm_work);
+
+	return 0;
+}
+
+static const struct phy_ops rockchip_usb2phy_ops = {
+	.init		= rockchip_usb2phy_init,
+	.exit		= rockchip_usb2phy_exit,
+	.power_on	= rockchip_usb2phy_power_on,
+	.power_off	= rockchip_usb2phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+/*
+ * The function manage host-phy port state and suspend/resume phy port
+ * to save power.
+ *
+ * we rely on utmi_linestate and utmi_hostdisconnect to identify whether
+ * devices is disconnect or not. Besides, we do not need care it is FS/LS
+ * disconnected or HS disconnected, actually, we just only need get the
+ * device is disconnected at last through rearm the delayed work,
+ * to suspend the phy port in _PHY_STATE_DISCONNECT_ case.
+ *
+ * NOTE: It may invoke *phy_powr_off or *phy_power_on which will invoke
+ * some clk related APIs, so do not invoke it from interrupt context directly.
+ */
+static void rockchip_usb2phy_sm_work(struct work_struct *work)
+{
+	struct rockchip_usb2phy_port *rport =
+		container_of(work, struct rockchip_usb2phy_port, sm_work.work);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+	unsigned int sh = rport->port_cfg->utmi_hstdet.bitend -
+			  rport->port_cfg->utmi_hstdet.bitstart + 1;
+	unsigned int ul, uhd, state;
+	unsigned int ul_mask, uhd_mask;
+	int ret;
+
+	mutex_lock(&rport->mutex);
+
+	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_ls.offset, &ul);
+	if (ret < 0)
+		goto next_schedule;
+
+	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset,
+			  &uhd);
+	if (ret < 0)
+		goto next_schedule;
+
+	uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend,
+			   rport->port_cfg->utmi_hstdet.bitstart);
+	ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend,
+			  rport->port_cfg->utmi_ls.bitstart);
+
+	/* stitch on utmi_ls and utmi_hstdet as phy state */
+	state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) |
+		(((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh);
+
+	switch (state) {
+	case PHY_STATE_HS_ONLINE:
+		dev_dbg(&rport->phy->dev, "HS online\n");
+		break;
+	case PHY_STATE_FS_LS_ONLINE:
+		/*
+		 * For FS/LS device, the online state share with connect state
+		 * from utmi_ls and utmi_hstdet register, so we distinguish
+		 * them via suspended flag.
+		 *
+		 * Plus, there are two cases, one is D- Line pull-up, and D+
+		 * line pull-down, the state is 4; another is D+ line pull-up,
+		 * and D- line pull-down, the state is 2.
+		 */
+		if (!rport->suspended) {
+			/* D- line pull-up, D+ line pull-down */
+			dev_dbg(&rport->phy->dev, "FS/LS online\n");
+			break;
+		}
+		/* fall through */
+	case PHY_STATE_CONNECT:
+		if (rport->suspended) {
+			dev_dbg(&rport->phy->dev, "Connected\n");
+			rockchip_usb2phy_power_on(rport->phy);
+			rport->suspended = false;
+		} else {
+			/* D+ line pull-up, D- line pull-down */
+			dev_dbg(&rport->phy->dev, "FS/LS online\n");
+		}
+		break;
+	case PHY_STATE_DISCONNECT:
+		if (!rport->suspended) {
+			dev_dbg(&rport->phy->dev, "Disconnected\n");
+			rockchip_usb2phy_power_off(rport->phy);
+			rport->suspended = true;
+		}
+
+		/*
+		 * activate the linestate detection to get the next device
+		 * plug-in irq.
+		 */
+		property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+		property_enable(rphy, &rport->port_cfg->ls_det_en, true);
+
+		/*
+		 * we don't need to rearm the delayed work when the phy port
+		 * is suspended.
+		 */
+		mutex_unlock(&rport->mutex);
+		return;
+	default:
+		dev_dbg(&rport->phy->dev, "unknown phy state\n");
+		break;
+	}
+
+next_schedule:
+	mutex_unlock(&rport->mutex);
+	schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
+}
+
+static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data)
+{
+	struct rockchip_usb2phy_port *rport = data;
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+
+	if (!property_enabled(rphy, &rport->port_cfg->ls_det_st))
+		return IRQ_NONE;
+
+	mutex_lock(&rport->mutex);
+
+	/* disable linestate detect irq and clear its status */
+	property_enable(rphy, &rport->port_cfg->ls_det_en, false);
+	property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+
+	mutex_unlock(&rport->mutex);
+
+	/*
+	 * In this case for host phy port, a new device is plugged in,
+	 * meanwhile, if the phy port is suspended, we need rearm the work to
+	 * resume it and mange its states; otherwise, we do nothing about that.
+	 */
+	if (rport->suspended && rport->port_id == USB2PHY_PORT_HOST)
+		rockchip_usb2phy_sm_work(&rport->sm_work.work);
+
+	return IRQ_HANDLED;
+}
+
+static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
+					   struct rockchip_usb2phy_port *rport,
+					   struct device_node *child_np)
+{
+	int ret;
+
+	rport->port_id = USB2PHY_PORT_HOST;
+	rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST];
+	rport->suspended = true;
+
+	mutex_init(&rport->mutex);
+	INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);
+
+	rport->ls_irq = of_irq_get_byname(child_np, "linestate");
+	if (rport->ls_irq < 0) {
+		dev_err(rphy->dev, "no linestate irq provided\n");
+		return rport->ls_irq;
+	}
+
+	ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL,
+					rockchip_usb2phy_linestate_irq,
+					IRQF_ONESHOT,
+					"rockchip_usb2phy", rport);
+	if (ret) {
+		dev_err(rphy->dev, "failed to request irq handle\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_usb2phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *child_np;
+	struct phy_provider *provider;
+	struct rockchip_usb2phy *rphy;
+	const struct rockchip_usb2phy_cfg *phy_cfgs;
+	const struct of_device_id *match;
+	unsigned int reg;
+	int index, ret;
+
+	rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL);
+	if (!rphy)
+		return -ENOMEM;
+
+	match = of_match_device(dev->driver->of_match_table, dev);
+	if (!match || !match->data) {
+		dev_err(dev, "phy configs are not assigned!\n");
+		return -EINVAL;
+	}
+
+	if (!dev->parent || !dev->parent->of_node)
+		return -EINVAL;
+
+	rphy->grf = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(rphy->grf))
+		return PTR_ERR(rphy->grf);
+
+	if (of_property_read_u32(np, "reg", &reg)) {
+		dev_err(dev, "the reg property is not assigned in %s node\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	rphy->dev = dev;
+	phy_cfgs = match->data;
+	platform_set_drvdata(pdev, rphy);
+
+	/* find out a proper config which can be matched with dt. */
+	index = 0;
+	while (phy_cfgs[index].reg) {
+		if (phy_cfgs[index].reg == reg) {
+			rphy->phy_cfg = &phy_cfgs[index];
+			break;
+		}
+
+		++index;
+	}
+
+	if (!rphy->phy_cfg) {
+		dev_err(dev, "no phy-config can be matched with %s node\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	rphy->clk = of_clk_get_by_name(np, "phyclk");
+	if (!IS_ERR(rphy->clk)) {
+		clk_prepare_enable(rphy->clk);
+	} else {
+		dev_info(&pdev->dev, "no phyclk specified\n");
+		rphy->clk = NULL;
+	}
+
+	ret = rockchip_usb2phy_clk480m_register(rphy);
+	if (ret) {
+		dev_err(dev, "failed to register 480m output clock\n");
+		goto disable_clks;
+	}
+
+	index = 0;
+	for_each_available_child_of_node(np, child_np) {
+		struct rockchip_usb2phy_port *rport = &rphy->ports[index];
+		struct phy *phy;
+
+		/*
+		 * This driver aim to support both otg-port and host-port,
+		 * but unfortunately, the otg part is not ready in current,
+		 * so this comments and below codes are interim, which should
+		 * be changed after otg-port is supplied soon.
+		 */
+		if (of_node_cmp(child_np->name, "host-port"))
+			goto next_child;
+
+		phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops);
+		if (IS_ERR(phy)) {
+			dev_err(dev, "failed to create phy\n");
+			ret = PTR_ERR(phy);
+			goto put_child;
+		}
+
+		rport->phy = phy;
+		phy_set_drvdata(rport->phy, rport);
+
+		ret = rockchip_usb2phy_host_port_init(rphy, rport, child_np);
+		if (ret)
+			goto put_child;
+
+next_child:
+		/* to prevent out of boundary */
+		if (++index >= rphy->phy_cfg->num_ports)
+			break;
+	}
+
+	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+	return PTR_ERR_OR_ZERO(provider);
+
+put_child:
+	of_node_put(child_np);
+disable_clks:
+	if (rphy->clk) {
+		clk_disable_unprepare(rphy->clk);
+		clk_put(rphy->clk);
+	}
+	return ret;
+}
+
+static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
+	{
+		.reg = 0x700,
+		.num_ports	= 2,
+		.clkout_ctl	= { 0x0724, 15, 15, 1, 0 },
+		.port_cfgs	= {
+			[USB2PHY_PORT_HOST] = {
+				.phy_sus	= { 0x0728, 15, 0, 0, 0x1d1 },
+				.ls_det_en	= { 0x0680, 4, 4, 0, 1 },
+				.ls_det_st	= { 0x0690, 4, 4, 0, 1 },
+				.ls_det_clr	= { 0x06a0, 4, 4, 0, 1 },
+				.utmi_ls	= { 0x049c, 14, 13, 0, 1 },
+				.utmi_hstdet	= { 0x049c, 12, 12, 0, 1 }
+			}
+		},
+	},
+	{ /* sentinel */ }
+};
+
+static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
+	{
+		.reg = 0xe450,
+		.num_ports	= 2,
+		.clkout_ctl	= { 0xe450, 4, 4, 1, 0 },
+		.port_cfgs	= {
+			[USB2PHY_PORT_HOST] = {
+				.phy_sus	= { 0xe458, 1, 0, 0x2, 0x1 },
+				.ls_det_en	= { 0xe3c0, 6, 6, 0, 1 },
+				.ls_det_st	= { 0xe3e0, 6, 6, 0, 1 },
+				.ls_det_clr	= { 0xe3d0, 6, 6, 0, 1 },
+				.utmi_ls	= { 0xe2ac, 22, 21, 0, 1 },
+				.utmi_hstdet	= { 0xe2ac, 23, 23, 0, 1 }
+			}
+		},
+	},
+	{
+		.reg = 0xe460,
+		.num_ports	= 2,
+		.clkout_ctl	= { 0xe460, 4, 4, 1, 0 },
+		.port_cfgs	= {
+			[USB2PHY_PORT_HOST] = {
+				.phy_sus	= { 0xe468, 1, 0, 0x2, 0x1 },
+				.ls_det_en	= { 0xe3c0, 11, 11, 0, 1 },
+				.ls_det_st	= { 0xe3e0, 11, 11, 0, 1 },
+				.ls_det_clr	= { 0xe3d0, 11, 11, 0, 1 },
+				.utmi_ls	= { 0xe2ac, 26, 25, 0, 1 },
+				.utmi_hstdet	= { 0xe2ac, 27, 27, 0, 1 }
+			}
+		},
+	},
+	{ /* sentinel */ }
+};
+
+static const struct of_device_id rockchip_usb2phy_dt_match[] = {
+	{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
+	{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
+	{}
+};
+MODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match);
+
+static struct platform_driver rockchip_usb2phy_driver = {
+	.probe		= rockchip_usb2phy_probe,
+	.driver		= {
+		.name	= "rockchip-usb2phy",
+		.of_match_table = rockchip_usb2phy_dt_match,
+	},
+};
+module_platform_driver(rockchip_usb2phy_driver);
+
+MODULE_AUTHOR("Frank Wang <frank.wang@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip USB2.0 PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5

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

* [PATCH v9 3/4] arm64: dts: rockchip: add usb2-phy support for rk3399
  2016-07-22  7:00 ` Frank Wang
                   ` (2 preceding siblings ...)
  (?)
@ 2016-07-22  7:00 ` Frank Wang
  2016-08-03 19:34     ` Heiko Stübner
  2016-08-17  9:53   ` Heiko Stübner
  -1 siblings, 2 replies; 15+ messages in thread
From: Frank Wang @ 2016-07-22  7:00 UTC (permalink / raw)
  To: heiko, dianders, linux, groeck, jwerner, kishon, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak
  Cc: linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu,
	kever.yang, huangtao, william.wu, daniel.meng, frank.wang

Add usb2-phy nodes and specify phys phandle for ehci.

Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
---

Changes in v9:
 - Move the usb gpio config to rk3399-evb.dts
 - Fix ehci phy-names property.

 arch/arm64/boot/dts/rockchip/rk3399.dtsi |   42 +++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index d7f8e06..843d51c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -221,6 +221,8 @@
 		interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>;
 		clock-names = "hclk_host0", "hclk_host0_arb";
+		phys = <&u2phy0_host>;
+		phy-names = "usb";
 		status = "disabled";
 	};
 
@@ -239,6 +241,8 @@
 		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
 		clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>;
 		clock-names = "hclk_host1", "hclk_host1_arb";
+		phys = <&u2phy1_host>;
+		phy-names = "usb";
 		status = "disabled";
 	};
 
@@ -481,8 +485,44 @@
 	};
 
 	grf: syscon@ff770000 {
-		compatible = "rockchip,rk3399-grf", "syscon";
+		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
 		reg = <0x0 0xff770000 0x0 0x10000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		u2phy0: usb2-phy@e450 {
+			compatible = "rockchip,rk3399-usb2phy";
+			reg = <0xe450 0x10>;
+			clocks = <&cru SCLK_USB2PHY0_REF>;
+			clock-names = "phyclk";
+			#clock-cells = <0>;
+			clock-output-names = "clk_usbphy0_480m";
+			status = "disabled";
+
+			u2phy0_host: host-port {
+				#phy-cells = <0>;
+				interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "linestate";
+				status = "disabled";
+			};
+		};
+
+		u2phy1: usb2-phy@e460 {
+			compatible = "rockchip,rk3399-usb2phy";
+			reg = <0xe460 0x10>;
+			clocks = <&cru SCLK_USB2PHY1_REF>;
+			clock-names = "phyclk";
+			#clock-cells = <0>;
+			clock-output-names = "clk_usbphy1_480m";
+			status = "disabled";
+
+			u2phy1_host: host-port {
+				#phy-cells = <0>;
+				interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "linestate";
+				status = "disabled";
+			};
+		};
 	};
 
 	watchdog@ff840000 {
-- 
1.7.9.5

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

* [PATCH v9 4/4] arm64: dts: rockchip: configure usb2-phy support for rk3399-evb
  2016-07-22  7:00 ` Frank Wang
                   ` (3 preceding siblings ...)
  (?)
@ 2016-07-22  7:00 ` Frank Wang
  2016-08-17 10:02   ` Heiko Stübner
  -1 siblings, 1 reply; 15+ messages in thread
From: Frank Wang @ 2016-07-22  7:00 UTC (permalink / raw)
  To: heiko, dianders, linux, groeck, jwerner, kishon, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak
  Cc: linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu,
	kever.yang, huangtao, william.wu, daniel.meng, frank.wang

Add vcc5v0_host regulator for usb2-phy and enable host-port support.

Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399-evb.dts |   44 +++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
index 1a3eb14..56aeedb 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
@@ -69,6 +69,25 @@
 		regulator-max-microvolt = <3300000>;
 	};
 
+	vcc5v0_sys: vcc5v0-sys {
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v0_sys";
+		regulator-always-on;
+		regulator-boot-on;
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
+	vcc5v0_host: vcc5v0-host-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&host_vbus_drv>;
+		regulator-name = "vcc5v0_host";
+		vin-supply = <&vcc5v0_sys>;
+	};
+
 	vcc_phy: vcc-phy-regulator {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_phy";
@@ -89,6 +108,24 @@
 	status = "okay";
 };
 
+&u2phy0 {
+	status = "okay";
+
+	u2phy0_host: host-port {
+		phy-supply = <&vcc5v0_host>;
+		status = "okay";
+	};
+};
+
+&u2phy1 {
+	status = "okay";
+
+	u2phy1_host: host-port {
+		phy-supply = <&vcc5v0_host>;
+		status = "okay";
+	};
+};
+
 &uart2 {
 	status = "okay";
 };
@@ -121,4 +158,11 @@
 				<1 18 RK_FUNC_GPIO &pcfg_pull_down>;
 		};
 	};
+
+	usb2 {
+		host_vbus_drv: host-vbus-drv {
+			rockchip,pins =
+				<4 25 RK_FUNC_GPIO &pcfg_pull_none>;
+		};
+	};
 };
-- 
1.7.9.5

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

* Re: [PATCH v9 3/4] arm64: dts: rockchip: add usb2-phy support for rk3399
@ 2016-08-03 19:34     ` Heiko Stübner
  0 siblings, 0 replies; 15+ messages in thread
From: Heiko Stübner @ 2016-08-03 19:34 UTC (permalink / raw)
  To: Frank Wang
  Cc: dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll,
	mark.rutland, ijc+devicetree, galak, linux-kernel, devicetree,
	linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao,
	william.wu, daniel.meng

Am Freitag, 22. Juli 2016, 15:00:45 schrieb Frank Wang:
> Add usb2-phy nodes and specify phys phandle for ehci.
> 
> Signed-off-by: Frank Wang <frank.wang@rock-chips.com>

looks good to me. Of course we need Kishon to be happy with the driver itself 
first and the merge-window to end :-) .

I see that this won't apply cleanly, as the grf changed under your feet, but 
no need to resend for this alone, as I can fix that up myself.


Heiko

> ---
> 
> Changes in v9:
>  - Move the usb gpio config to rk3399-evb.dts
>  - Fix ehci phy-names property.
> 
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi |   42
> +++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1
> deletion(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index d7f8e06..843d51c 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -221,6 +221,8 @@
>  		interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
>  		clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>;
>  		clock-names = "hclk_host0", "hclk_host0_arb";
> +		phys = <&u2phy0_host>;
> +		phy-names = "usb";
>  		status = "disabled";
>  	};
> 
> @@ -239,6 +241,8 @@
>  		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
>  		clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>;
>  		clock-names = "hclk_host1", "hclk_host1_arb";
> +		phys = <&u2phy1_host>;
> +		phy-names = "usb";
>  		status = "disabled";
>  	};
> 
> @@ -481,8 +485,44 @@
>  	};
> 
>  	grf: syscon@ff770000 {
> -		compatible = "rockchip,rk3399-grf", "syscon";
> +		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
>  		reg = <0x0 0xff770000 0x0 0x10000>;
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +
> +		u2phy0: usb2-phy@e450 {
> +			compatible = "rockchip,rk3399-usb2phy";
> +			reg = <0xe450 0x10>;
> +			clocks = <&cru SCLK_USB2PHY0_REF>;
> +			clock-names = "phyclk";
> +			#clock-cells = <0>;
> +			clock-output-names = "clk_usbphy0_480m";
> +			status = "disabled";
> +
> +			u2phy0_host: host-port {
> +				#phy-cells = <0>;
> +				interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
> +				interrupt-names = "linestate";
> +				status = "disabled";
> +			};
> +		};
> +
> +		u2phy1: usb2-phy@e460 {
> +			compatible = "rockchip,rk3399-usb2phy";
> +			reg = <0xe460 0x10>;
> +			clocks = <&cru SCLK_USB2PHY1_REF>;
> +			clock-names = "phyclk";
> +			#clock-cells = <0>;
> +			clock-output-names = "clk_usbphy1_480m";
> +			status = "disabled";
> +
> +			u2phy1_host: host-port {
> +				#phy-cells = <0>;
> +				interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
> +				interrupt-names = "linestate";
> +				status = "disabled";
> +			};
> +		};
>  	};
> 
>  	watchdog@ff840000 {

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

* Re: [PATCH v9 3/4] arm64: dts: rockchip: add usb2-phy support for rk3399
@ 2016-08-03 19:34     ` Heiko Stübner
  0 siblings, 0 replies; 15+ messages in thread
From: Heiko Stübner @ 2016-08-03 19:34 UTC (permalink / raw)
  To: Frank Wang
  Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
	xzy.xu-TNX95d0MmH7DzftRWevZcw, huangtao-TNX95d0MmH7DzftRWevZcw,
	pawel.moll-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	dianders-F7+t8E8rja9g9hUCZPvPmw, kishon-l0cyMroinI0,
	kever.yang-TNX95d0MmH7DzftRWevZcw,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	groeck-F7+t8E8rja9g9hUCZPvPmw, jwerner-F7+t8E8rja9g9hUCZPvPmw,
	daniel.meng-TNX95d0MmH7DzftRWevZcw,
	william.wu-TNX95d0MmH7DzftRWevZcw, linux-0h96xk9xTtrk1uMJSBkQmQ

Am Freitag, 22. Juli 2016, 15:00:45 schrieb Frank Wang:
> Add usb2-phy nodes and specify phys phandle for ehci.
> 
> Signed-off-by: Frank Wang <frank.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>

looks good to me. Of course we need Kishon to be happy with the driver itself 
first and the merge-window to end :-) .

I see that this won't apply cleanly, as the grf changed under your feet, but 
no need to resend for this alone, as I can fix that up myself.


Heiko

> ---
> 
> Changes in v9:
>  - Move the usb gpio config to rk3399-evb.dts
>  - Fix ehci phy-names property.
> 
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi |   42
> +++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1
> deletion(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index d7f8e06..843d51c 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -221,6 +221,8 @@
>  		interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
>  		clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>;
>  		clock-names = "hclk_host0", "hclk_host0_arb";
> +		phys = <&u2phy0_host>;
> +		phy-names = "usb";
>  		status = "disabled";
>  	};
> 
> @@ -239,6 +241,8 @@
>  		interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
>  		clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>;
>  		clock-names = "hclk_host1", "hclk_host1_arb";
> +		phys = <&u2phy1_host>;
> +		phy-names = "usb";
>  		status = "disabled";
>  	};
> 
> @@ -481,8 +485,44 @@
>  	};
> 
>  	grf: syscon@ff770000 {
> -		compatible = "rockchip,rk3399-grf", "syscon";
> +		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
>  		reg = <0x0 0xff770000 0x0 0x10000>;
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +
> +		u2phy0: usb2-phy@e450 {
> +			compatible = "rockchip,rk3399-usb2phy";
> +			reg = <0xe450 0x10>;
> +			clocks = <&cru SCLK_USB2PHY0_REF>;
> +			clock-names = "phyclk";
> +			#clock-cells = <0>;
> +			clock-output-names = "clk_usbphy0_480m";
> +			status = "disabled";
> +
> +			u2phy0_host: host-port {
> +				#phy-cells = <0>;
> +				interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
> +				interrupt-names = "linestate";
> +				status = "disabled";
> +			};
> +		};
> +
> +		u2phy1: usb2-phy@e460 {
> +			compatible = "rockchip,rk3399-usb2phy";
> +			reg = <0xe460 0x10>;
> +			clocks = <&cru SCLK_USB2PHY1_REF>;
> +			clock-names = "phyclk";
> +			#clock-cells = <0>;
> +			clock-output-names = "clk_usbphy1_480m";
> +			status = "disabled";
> +
> +			u2phy1_host: host-port {
> +				#phy-cells = <0>;
> +				interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
> +				interrupt-names = "linestate";
> +				status = "disabled";
> +			};
> +		};
>  	};
> 
>  	watchdog@ff840000 {

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

* Re: [PATCH v9 2/4] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy
@ 2016-08-12 10:09     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 15+ messages in thread
From: Kishon Vijay Abraham I @ 2016-08-12 10:09 UTC (permalink / raw)
  To: Frank Wang, heiko, dianders, linux, groeck, jwerner, robh+dt,
	pawel.moll, mark.rutland, ijc+devicetree, galak
  Cc: linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu,
	kever.yang, huangtao, william.wu, daniel.meng

Hi,

On Friday 22 July 2016 12:30 PM, Frank Wang wrote:
> The newer SoCs (rk3366, rk3399) take a different usb-phy IP block
> than rk3288 and before, and most of phy-related registers are also
> different from the past, so a new phy driver is required necessarily.
> 
> Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
> Suggested-by: Heiko Stuebner <heiko@sntech.de>
> Suggested-by: Guenter Roeck <linux@roeck-us.net>
> Suggested-by: Doug Anderson <dianders@chromium.org>
> Reviewed-by: Heiko Stuebner <heiko@sntech.de>
> Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> ---
> 
> Changes in v9:
>  - Add "Reviewed-by" info.
> 
> Changes in v8:
>  - Added support for rk3399 SoC.
>  - Prepare input clock of phy at probe time.
>  - Improved sm_work function to handle phy-port state more clearly.
> 
> Changes in v7:
>  - renamed functions *usb2phy_resume/*usb2phy_suspend to *usb2phy_power_on/usb2phy_power_off.
> 
> Changes in v6:
>  - Fixed the output clock would be disabled more than once while phy-port was going to suspend.
>  - Improved the driver to avoid the currently empty otg-port would cause null-pointer dereferences.
> 
> Changes in v5:
>  - Added 'reg' in the data block to match the different phy-blocks in dt.
> 
> Changes in v4:
>  - Removed some processes related to 'vbus_host-supply'.
> 
> Changes in v3:
>  - Resolved the mapping defect between fixed value in driver and the property
>    in devicetree.
>  - Optimized 480m output clock register function.
>  - Code cleanup.
> 
> Changes in v2:
>  - Changed vbus_host operation from gpio to regulator in *_probe.
>  - Improved the fault treatment relate to 480m clock register.
>  - Cleaned up some meaningless codes in *_clk480m_disable.
>  - made more clear the comment of *_sm_work.
> 
>  drivers/phy/Kconfig                  |    7 +
>  drivers/phy/Makefile                 |    1 +
>  drivers/phy/phy-rockchip-inno-usb2.c |  707 ++++++++++++++++++++++++++++++++++
>  3 files changed, 715 insertions(+)
>  create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c
> 
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index b869b98..29ef15c 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -347,6 +347,13 @@ config PHY_ROCKCHIP_USB
>  	help
>  	  Enable this to support the Rockchip USB 2.0 PHY.
>  
> +config PHY_ROCKCHIP_INNO_USB2
> +	tristate "Rockchip INNO USB2PHY Driver"
> +	depends on ARCH_ROCKCHIP && OF

changed this to
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
and merged it.

Thanks
Kishon

> +	select GENERIC_PHY
> +	help
> +	  Support for Rockchip USB2.0 PHY with Innosilicon IP block.
> +
>  config PHY_ROCKCHIP_EMMC
>  	tristate "Rockchip EMMC PHY Driver"
>  	depends on ARCH_ROCKCHIP && OF
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 9c3e73c..4963fbc 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -38,6 +38,7 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2)	+= phy-s5pv210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS5_USBDRD)	+= phy-exynos5-usbdrd.o
>  obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
>  obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
> +obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2)	+= phy-rockchip-inno-usb2.o
>  obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
>  obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
>  obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
> diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
> new file mode 100644
> index 0000000..ac20310
> --- /dev/null
> +++ b/drivers/phy/phy-rockchip-inno-usb2.c
> @@ -0,0 +1,707 @@
> +/*
> + * Rockchip USB2.0 PHY with Innosilicon IP block driver
> + *
> + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
> + *
> + * 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; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/jiffies.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +
> +#define BIT_WRITEABLE_SHIFT	16
> +#define SCHEDULE_DELAY	(60 * HZ)
> +
> +enum rockchip_usb2phy_port_id {
> +	USB2PHY_PORT_OTG,
> +	USB2PHY_PORT_HOST,
> +	USB2PHY_NUM_PORTS,
> +};
> +
> +enum rockchip_usb2phy_host_state {
> +	PHY_STATE_HS_ONLINE	= 0,
> +	PHY_STATE_DISCONNECT	= 1,
> +	PHY_STATE_CONNECT	= 2,
> +	PHY_STATE_FS_LS_ONLINE	= 4,
> +};
> +
> +struct usb2phy_reg {
> +	unsigned int	offset;
> +	unsigned int	bitend;
> +	unsigned int	bitstart;
> +	unsigned int	disable;
> +	unsigned int	enable;
> +};
> +
> +/**
> + * struct rockchip_usb2phy_port_cfg: usb-phy port configuration.
> + * @phy_sus: phy suspend register.
> + * @ls_det_en: linestate detection enable register.
> + * @ls_det_st: linestate detection state register.
> + * @ls_det_clr: linestate detection clear register.
> + * @utmi_ls: utmi linestate state register.
> + * @utmi_hstdet: utmi host disconnect register.
> + */
> +struct rockchip_usb2phy_port_cfg {
> +	struct usb2phy_reg	phy_sus;
> +	struct usb2phy_reg	ls_det_en;
> +	struct usb2phy_reg	ls_det_st;
> +	struct usb2phy_reg	ls_det_clr;
> +	struct usb2phy_reg	utmi_ls;
> +	struct usb2phy_reg	utmi_hstdet;
> +};
> +
> +/**
> + * struct rockchip_usb2phy_cfg: usb-phy configuration.
> + * @reg: the address offset of grf for usb-phy config.
> + * @num_ports: specify how many ports that the phy has.
> + * @clkout_ctl: keep on/turn off output clk of phy.
> + */
> +struct rockchip_usb2phy_cfg {
> +	unsigned int	reg;
> +	unsigned int	num_ports;
> +	struct usb2phy_reg	clkout_ctl;
> +	const struct rockchip_usb2phy_port_cfg	port_cfgs[USB2PHY_NUM_PORTS];
> +};
> +
> +/**
> + * struct rockchip_usb2phy_port: usb-phy port data.
> + * @port_id: flag for otg port or host port.
> + * @suspended: phy suspended flag.
> + * @ls_irq: IRQ number assigned for linestate detection.
> + * @mutex: for register updating in sm_work.
> + * @sm_work: OTG state machine work.
> + * @phy_cfg: port register configuration, assigned by driver data.
> + */
> +struct rockchip_usb2phy_port {
> +	struct phy	*phy;
> +	unsigned int	port_id;
> +	bool		suspended;
> +	int		ls_irq;
> +	struct mutex	mutex;
> +	struct		delayed_work sm_work;
> +	const struct	rockchip_usb2phy_port_cfg *port_cfg;
> +};
> +
> +/**
> + * struct rockchip_usb2phy: usb2.0 phy driver data.
> + * @grf: General Register Files regmap.
> + * @clk: clock struct of phy input clk.
> + * @clk480m: clock struct of phy output clk.
> + * @clk_hw: clock struct of phy output clk management.
> + * @phy_cfg: phy register configuration, assigned by driver data.
> + * @ports: phy port instance.
> + */
> +struct rockchip_usb2phy {
> +	struct device	*dev;
> +	struct regmap	*grf;
> +	struct clk	*clk;
> +	struct clk	*clk480m;
> +	struct clk_hw	clk480m_hw;
> +	const struct rockchip_usb2phy_cfg	*phy_cfg;
> +	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];
> +};
> +
> +static inline int property_enable(struct rockchip_usb2phy *rphy,
> +				  const struct usb2phy_reg *reg, bool en)
> +{
> +	unsigned int val, mask, tmp;
> +
> +	tmp = en ? reg->enable : reg->disable;
> +	mask = GENMASK(reg->bitend, reg->bitstart);
> +	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
> +
> +	return regmap_write(rphy->grf, reg->offset, val);
> +}
> +
> +static inline bool property_enabled(struct rockchip_usb2phy *rphy,
> +				    const struct usb2phy_reg *reg)
> +{
> +	int ret;
> +	unsigned int tmp, orig;
> +	unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
> +
> +	ret = regmap_read(rphy->grf, reg->offset, &orig);
> +	if (ret)
> +		return false;
> +
> +	tmp = (orig & mask) >> reg->bitstart;
> +	return tmp == reg->enable;
> +}
> +
> +static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw)
> +{
> +	struct rockchip_usb2phy *rphy =
> +		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
> +	int ret;
> +
> +	/* turn on 480m clk output if it is off */
> +	if (!property_enabled(rphy, &rphy->phy_cfg->clkout_ctl)) {
> +		ret = property_enable(rphy, &rphy->phy_cfg->clkout_ctl, true);
> +		if (ret)
> +			return ret;
> +
> +		/* waitting for the clk become stable */
> +		mdelay(1);
> +	}
> +
> +	return 0;
> +}
> +
> +static void rockchip_usb2phy_clk480m_disable(struct clk_hw *hw)
> +{
> +	struct rockchip_usb2phy *rphy =
> +		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
> +
> +	/* turn off 480m clk output */
> +	property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false);
> +}
> +
> +static int rockchip_usb2phy_clk480m_enabled(struct clk_hw *hw)
> +{
> +	struct rockchip_usb2phy *rphy =
> +		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
> +
> +	return property_enabled(rphy, &rphy->phy_cfg->clkout_ctl);
> +}
> +
> +static unsigned long
> +rockchip_usb2phy_clk480m_recalc_rate(struct clk_hw *hw,
> +				     unsigned long parent_rate)
> +{
> +	return 480000000;
> +}
> +
> +static const struct clk_ops rockchip_usb2phy_clkout_ops = {
> +	.enable = rockchip_usb2phy_clk480m_enable,
> +	.disable = rockchip_usb2phy_clk480m_disable,
> +	.is_enabled = rockchip_usb2phy_clk480m_enabled,
> +	.recalc_rate = rockchip_usb2phy_clk480m_recalc_rate,
> +};
> +
> +static void rockchip_usb2phy_clk480m_unregister(void *data)
> +{
> +	struct rockchip_usb2phy *rphy = data;
> +
> +	of_clk_del_provider(rphy->dev->of_node);
> +	clk_unregister(rphy->clk480m);
> +}
> +
> +static int
> +rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy)
> +{
> +	struct device_node *node = rphy->dev->of_node;
> +	struct clk_init_data init;
> +	const char *clk_name;
> +	int ret;
> +
> +	init.flags = 0;
> +	init.name = "clk_usbphy_480m";
> +	init.ops = &rockchip_usb2phy_clkout_ops;
> +
> +	/* optional override of the clockname */
> +	of_property_read_string(node, "clock-output-names", &init.name);
> +
> +	if (rphy->clk) {
> +		clk_name = __clk_get_name(rphy->clk);
> +		init.parent_names = &clk_name;
> +		init.num_parents = 1;
> +	} else {
> +		init.parent_names = NULL;
> +		init.num_parents = 0;
> +	}
> +
> +	rphy->clk480m_hw.init = &init;
> +
> +	/* register the clock */
> +	rphy->clk480m = clk_register(rphy->dev, &rphy->clk480m_hw);
> +	if (IS_ERR(rphy->clk480m)) {
> +		ret = PTR_ERR(rphy->clk480m);
> +		goto err_ret;
> +	}
> +
> +	ret = of_clk_add_provider(node, of_clk_src_simple_get, rphy->clk480m);
> +	if (ret < 0)
> +		goto err_clk_provider;
> +
> +	ret = devm_add_action(rphy->dev, rockchip_usb2phy_clk480m_unregister,
> +			      rphy);
> +	if (ret < 0)
> +		goto err_unreg_action;
> +
> +	return 0;
> +
> +err_unreg_action:
> +	of_clk_del_provider(node);
> +err_clk_provider:
> +	clk_unregister(rphy->clk480m);
> +err_ret:
> +	return ret;
> +}
> +
> +static int rockchip_usb2phy_init(struct phy *phy)
> +{
> +	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
> +	int ret;
> +
> +	if (rport->port_id == USB2PHY_PORT_HOST) {
> +		/* clear linestate and enable linestate detect irq */
> +		mutex_lock(&rport->mutex);
> +
> +		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
> +		if (ret) {
> +			mutex_unlock(&rport->mutex);
> +			return ret;
> +		}
> +
> +		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
> +		if (ret) {
> +			mutex_unlock(&rport->mutex);
> +			return ret;
> +		}
> +
> +		mutex_unlock(&rport->mutex);
> +		schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_usb2phy_power_on(struct phy *phy)
> +{
> +	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
> +	int ret;
> +
> +	dev_dbg(&rport->phy->dev, "port power on\n");
> +
> +	if (!rport->suspended)
> +		return 0;
> +
> +	ret = clk_prepare_enable(rphy->clk480m);
> +	if (ret)
> +		return ret;
> +
> +	ret = property_enable(rphy, &rport->port_cfg->phy_sus, false);
> +	if (ret)
> +		return ret;
> +
> +	rport->suspended = false;
> +	return 0;
> +}
> +
> +static int rockchip_usb2phy_power_off(struct phy *phy)
> +{
> +	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
> +	int ret;
> +
> +	dev_dbg(&rport->phy->dev, "port power off\n");
> +
> +	if (rport->suspended)
> +		return 0;
> +
> +	ret = property_enable(rphy, &rport->port_cfg->phy_sus, true);
> +	if (ret)
> +		return ret;
> +
> +	rport->suspended = true;
> +	clk_disable_unprepare(rphy->clk480m);
> +
> +	return 0;
> +}
> +
> +static int rockchip_usb2phy_exit(struct phy *phy)
> +{
> +	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
> +
> +	if (rport->port_id == USB2PHY_PORT_HOST)
> +		cancel_delayed_work_sync(&rport->sm_work);
> +
> +	return 0;
> +}
> +
> +static const struct phy_ops rockchip_usb2phy_ops = {
> +	.init		= rockchip_usb2phy_init,
> +	.exit		= rockchip_usb2phy_exit,
> +	.power_on	= rockchip_usb2phy_power_on,
> +	.power_off	= rockchip_usb2phy_power_off,
> +	.owner		= THIS_MODULE,
> +};
> +
> +/*
> + * The function manage host-phy port state and suspend/resume phy port
> + * to save power.
> + *
> + * we rely on utmi_linestate and utmi_hostdisconnect to identify whether
> + * devices is disconnect or not. Besides, we do not need care it is FS/LS
> + * disconnected or HS disconnected, actually, we just only need get the
> + * device is disconnected at last through rearm the delayed work,
> + * to suspend the phy port in _PHY_STATE_DISCONNECT_ case.
> + *
> + * NOTE: It may invoke *phy_powr_off or *phy_power_on which will invoke
> + * some clk related APIs, so do not invoke it from interrupt context directly.
> + */
> +static void rockchip_usb2phy_sm_work(struct work_struct *work)
> +{
> +	struct rockchip_usb2phy_port *rport =
> +		container_of(work, struct rockchip_usb2phy_port, sm_work.work);
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
> +	unsigned int sh = rport->port_cfg->utmi_hstdet.bitend -
> +			  rport->port_cfg->utmi_hstdet.bitstart + 1;
> +	unsigned int ul, uhd, state;
> +	unsigned int ul_mask, uhd_mask;
> +	int ret;
> +
> +	mutex_lock(&rport->mutex);
> +
> +	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_ls.offset, &ul);
> +	if (ret < 0)
> +		goto next_schedule;
> +
> +	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset,
> +			  &uhd);
> +	if (ret < 0)
> +		goto next_schedule;
> +
> +	uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend,
> +			   rport->port_cfg->utmi_hstdet.bitstart);
> +	ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend,
> +			  rport->port_cfg->utmi_ls.bitstart);
> +
> +	/* stitch on utmi_ls and utmi_hstdet as phy state */
> +	state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) |
> +		(((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh);
> +
> +	switch (state) {
> +	case PHY_STATE_HS_ONLINE:
> +		dev_dbg(&rport->phy->dev, "HS online\n");
> +		break;
> +	case PHY_STATE_FS_LS_ONLINE:
> +		/*
> +		 * For FS/LS device, the online state share with connect state
> +		 * from utmi_ls and utmi_hstdet register, so we distinguish
> +		 * them via suspended flag.
> +		 *
> +		 * Plus, there are two cases, one is D- Line pull-up, and D+
> +		 * line pull-down, the state is 4; another is D+ line pull-up,
> +		 * and D- line pull-down, the state is 2.
> +		 */
> +		if (!rport->suspended) {
> +			/* D- line pull-up, D+ line pull-down */
> +			dev_dbg(&rport->phy->dev, "FS/LS online\n");
> +			break;
> +		}
> +		/* fall through */
> +	case PHY_STATE_CONNECT:
> +		if (rport->suspended) {
> +			dev_dbg(&rport->phy->dev, "Connected\n");
> +			rockchip_usb2phy_power_on(rport->phy);
> +			rport->suspended = false;
> +		} else {
> +			/* D+ line pull-up, D- line pull-down */
> +			dev_dbg(&rport->phy->dev, "FS/LS online\n");
> +		}
> +		break;
> +	case PHY_STATE_DISCONNECT:
> +		if (!rport->suspended) {
> +			dev_dbg(&rport->phy->dev, "Disconnected\n");
> +			rockchip_usb2phy_power_off(rport->phy);
> +			rport->suspended = true;
> +		}
> +
> +		/*
> +		 * activate the linestate detection to get the next device
> +		 * plug-in irq.
> +		 */
> +		property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
> +		property_enable(rphy, &rport->port_cfg->ls_det_en, true);
> +
> +		/*
> +		 * we don't need to rearm the delayed work when the phy port
> +		 * is suspended.
> +		 */
> +		mutex_unlock(&rport->mutex);
> +		return;
> +	default:
> +		dev_dbg(&rport->phy->dev, "unknown phy state\n");
> +		break;
> +	}
> +
> +next_schedule:
> +	mutex_unlock(&rport->mutex);
> +	schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
> +}
> +
> +static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data)
> +{
> +	struct rockchip_usb2phy_port *rport = data;
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
> +
> +	if (!property_enabled(rphy, &rport->port_cfg->ls_det_st))
> +		return IRQ_NONE;
> +
> +	mutex_lock(&rport->mutex);
> +
> +	/* disable linestate detect irq and clear its status */
> +	property_enable(rphy, &rport->port_cfg->ls_det_en, false);
> +	property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
> +
> +	mutex_unlock(&rport->mutex);
> +
> +	/*
> +	 * In this case for host phy port, a new device is plugged in,
> +	 * meanwhile, if the phy port is suspended, we need rearm the work to
> +	 * resume it and mange its states; otherwise, we do nothing about that.
> +	 */
> +	if (rport->suspended && rport->port_id == USB2PHY_PORT_HOST)
> +		rockchip_usb2phy_sm_work(&rport->sm_work.work);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
> +					   struct rockchip_usb2phy_port *rport,
> +					   struct device_node *child_np)
> +{
> +	int ret;
> +
> +	rport->port_id = USB2PHY_PORT_HOST;
> +	rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST];
> +	rport->suspended = true;
> +
> +	mutex_init(&rport->mutex);
> +	INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);
> +
> +	rport->ls_irq = of_irq_get_byname(child_np, "linestate");
> +	if (rport->ls_irq < 0) {
> +		dev_err(rphy->dev, "no linestate irq provided\n");
> +		return rport->ls_irq;
> +	}
> +
> +	ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL,
> +					rockchip_usb2phy_linestate_irq,
> +					IRQF_ONESHOT,
> +					"rockchip_usb2phy", rport);
> +	if (ret) {
> +		dev_err(rphy->dev, "failed to request irq handle\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_usb2phy_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct device_node *child_np;
> +	struct phy_provider *provider;
> +	struct rockchip_usb2phy *rphy;
> +	const struct rockchip_usb2phy_cfg *phy_cfgs;
> +	const struct of_device_id *match;
> +	unsigned int reg;
> +	int index, ret;
> +
> +	rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL);
> +	if (!rphy)
> +		return -ENOMEM;
> +
> +	match = of_match_device(dev->driver->of_match_table, dev);
> +	if (!match || !match->data) {
> +		dev_err(dev, "phy configs are not assigned!\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!dev->parent || !dev->parent->of_node)
> +		return -EINVAL;
> +
> +	rphy->grf = syscon_node_to_regmap(dev->parent->of_node);
> +	if (IS_ERR(rphy->grf))
> +		return PTR_ERR(rphy->grf);
> +
> +	if (of_property_read_u32(np, "reg", &reg)) {
> +		dev_err(dev, "the reg property is not assigned in %s node\n",
> +			np->name);
> +		return -EINVAL;
> +	}
> +
> +	rphy->dev = dev;
> +	phy_cfgs = match->data;
> +	platform_set_drvdata(pdev, rphy);
> +
> +	/* find out a proper config which can be matched with dt. */
> +	index = 0;
> +	while (phy_cfgs[index].reg) {
> +		if (phy_cfgs[index].reg == reg) {
> +			rphy->phy_cfg = &phy_cfgs[index];
> +			break;
> +		}
> +
> +		++index;
> +	}
> +
> +	if (!rphy->phy_cfg) {
> +		dev_err(dev, "no phy-config can be matched with %s node\n",
> +			np->name);
> +		return -EINVAL;
> +	}
> +
> +	rphy->clk = of_clk_get_by_name(np, "phyclk");
> +	if (!IS_ERR(rphy->clk)) {
> +		clk_prepare_enable(rphy->clk);
> +	} else {
> +		dev_info(&pdev->dev, "no phyclk specified\n");
> +		rphy->clk = NULL;
> +	}
> +
> +	ret = rockchip_usb2phy_clk480m_register(rphy);
> +	if (ret) {
> +		dev_err(dev, "failed to register 480m output clock\n");
> +		goto disable_clks;
> +	}
> +
> +	index = 0;
> +	for_each_available_child_of_node(np, child_np) {
> +		struct rockchip_usb2phy_port *rport = &rphy->ports[index];
> +		struct phy *phy;
> +
> +		/*
> +		 * This driver aim to support both otg-port and host-port,
> +		 * but unfortunately, the otg part is not ready in current,
> +		 * so this comments and below codes are interim, which should
> +		 * be changed after otg-port is supplied soon.
> +		 */
> +		if (of_node_cmp(child_np->name, "host-port"))
> +			goto next_child;
> +
> +		phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops);
> +		if (IS_ERR(phy)) {
> +			dev_err(dev, "failed to create phy\n");
> +			ret = PTR_ERR(phy);
> +			goto put_child;
> +		}
> +
> +		rport->phy = phy;
> +		phy_set_drvdata(rport->phy, rport);
> +
> +		ret = rockchip_usb2phy_host_port_init(rphy, rport, child_np);
> +		if (ret)
> +			goto put_child;
> +
> +next_child:
> +		/* to prevent out of boundary */
> +		if (++index >= rphy->phy_cfg->num_ports)
> +			break;
> +	}
> +
> +	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +	return PTR_ERR_OR_ZERO(provider);
> +
> +put_child:
> +	of_node_put(child_np);
> +disable_clks:
> +	if (rphy->clk) {
> +		clk_disable_unprepare(rphy->clk);
> +		clk_put(rphy->clk);
> +	}
> +	return ret;
> +}
> +
> +static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
> +	{
> +		.reg = 0x700,
> +		.num_ports	= 2,
> +		.clkout_ctl	= { 0x0724, 15, 15, 1, 0 },
> +		.port_cfgs	= {
> +			[USB2PHY_PORT_HOST] = {
> +				.phy_sus	= { 0x0728, 15, 0, 0, 0x1d1 },
> +				.ls_det_en	= { 0x0680, 4, 4, 0, 1 },
> +				.ls_det_st	= { 0x0690, 4, 4, 0, 1 },
> +				.ls_det_clr	= { 0x06a0, 4, 4, 0, 1 },
> +				.utmi_ls	= { 0x049c, 14, 13, 0, 1 },
> +				.utmi_hstdet	= { 0x049c, 12, 12, 0, 1 }
> +			}
> +		},
> +	},
> +	{ /* sentinel */ }
> +};
> +
> +static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
> +	{
> +		.reg = 0xe450,
> +		.num_ports	= 2,
> +		.clkout_ctl	= { 0xe450, 4, 4, 1, 0 },
> +		.port_cfgs	= {
> +			[USB2PHY_PORT_HOST] = {
> +				.phy_sus	= { 0xe458, 1, 0, 0x2, 0x1 },
> +				.ls_det_en	= { 0xe3c0, 6, 6, 0, 1 },
> +				.ls_det_st	= { 0xe3e0, 6, 6, 0, 1 },
> +				.ls_det_clr	= { 0xe3d0, 6, 6, 0, 1 },
> +				.utmi_ls	= { 0xe2ac, 22, 21, 0, 1 },
> +				.utmi_hstdet	= { 0xe2ac, 23, 23, 0, 1 }
> +			}
> +		},
> +	},
> +	{
> +		.reg = 0xe460,
> +		.num_ports	= 2,
> +		.clkout_ctl	= { 0xe460, 4, 4, 1, 0 },
> +		.port_cfgs	= {
> +			[USB2PHY_PORT_HOST] = {
> +				.phy_sus	= { 0xe468, 1, 0, 0x2, 0x1 },
> +				.ls_det_en	= { 0xe3c0, 11, 11, 0, 1 },
> +				.ls_det_st	= { 0xe3e0, 11, 11, 0, 1 },
> +				.ls_det_clr	= { 0xe3d0, 11, 11, 0, 1 },
> +				.utmi_ls	= { 0xe2ac, 26, 25, 0, 1 },
> +				.utmi_hstdet	= { 0xe2ac, 27, 27, 0, 1 }
> +			}
> +		},
> +	},
> +	{ /* sentinel */ }
> +};
> +
> +static const struct of_device_id rockchip_usb2phy_dt_match[] = {
> +	{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
> +	{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match);
> +
> +static struct platform_driver rockchip_usb2phy_driver = {
> +	.probe		= rockchip_usb2phy_probe,
> +	.driver		= {
> +		.name	= "rockchip-usb2phy",
> +		.of_match_table = rockchip_usb2phy_dt_match,
> +	},
> +};
> +module_platform_driver(rockchip_usb2phy_driver);
> +
> +MODULE_AUTHOR("Frank Wang <frank.wang@rock-chips.com>");
> +MODULE_DESCRIPTION("Rockchip USB2.0 PHY driver");
> +MODULE_LICENSE("GPL v2");
> 

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

* Re: [PATCH v9 2/4] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy
@ 2016-08-12 10:09     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 15+ messages in thread
From: Kishon Vijay Abraham I @ 2016-08-12 10:09 UTC (permalink / raw)
  To: Frank Wang, heiko-4mtYJXux2i+zQB+pC5nmwQ,
	dianders-F7+t8E8rja9g9hUCZPvPmw, linux-0h96xk9xTtrk1uMJSBkQmQ,
	groeck-F7+t8E8rja9g9hUCZPvPmw, jwerner-F7+t8E8rja9g9hUCZPvPmw,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ
  Cc: huangtao-TNX95d0MmH7DzftRWevZcw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, xzy.xu-TNX95d0MmH7DzftRWevZcw,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	kever.yang-TNX95d0MmH7DzftRWevZcw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	william.wu-TNX95d0MmH7DzftRWevZcw,
	daniel.meng-TNX95d0MmH7DzftRWevZcw

Hi,

On Friday 22 July 2016 12:30 PM, Frank Wang wrote:
> The newer SoCs (rk3366, rk3399) take a different usb-phy IP block
> than rk3288 and before, and most of phy-related registers are also
> different from the past, so a new phy driver is required necessarily.
> 
> Signed-off-by: Frank Wang <frank.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> Suggested-by: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
> Suggested-by: Guenter Roeck <linux-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
> Suggested-by: Doug Anderson <dianders-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Reviewed-by: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
> Reviewed-by: Guenter Roeck <linux-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
> ---
> 
> Changes in v9:
>  - Add "Reviewed-by" info.
> 
> Changes in v8:
>  - Added support for rk3399 SoC.
>  - Prepare input clock of phy at probe time.
>  - Improved sm_work function to handle phy-port state more clearly.
> 
> Changes in v7:
>  - renamed functions *usb2phy_resume/*usb2phy_suspend to *usb2phy_power_on/usb2phy_power_off.
> 
> Changes in v6:
>  - Fixed the output clock would be disabled more than once while phy-port was going to suspend.
>  - Improved the driver to avoid the currently empty otg-port would cause null-pointer dereferences.
> 
> Changes in v5:
>  - Added 'reg' in the data block to match the different phy-blocks in dt.
> 
> Changes in v4:
>  - Removed some processes related to 'vbus_host-supply'.
> 
> Changes in v3:
>  - Resolved the mapping defect between fixed value in driver and the property
>    in devicetree.
>  - Optimized 480m output clock register function.
>  - Code cleanup.
> 
> Changes in v2:
>  - Changed vbus_host operation from gpio to regulator in *_probe.
>  - Improved the fault treatment relate to 480m clock register.
>  - Cleaned up some meaningless codes in *_clk480m_disable.
>  - made more clear the comment of *_sm_work.
> 
>  drivers/phy/Kconfig                  |    7 +
>  drivers/phy/Makefile                 |    1 +
>  drivers/phy/phy-rockchip-inno-usb2.c |  707 ++++++++++++++++++++++++++++++++++
>  3 files changed, 715 insertions(+)
>  create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c
> 
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index b869b98..29ef15c 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -347,6 +347,13 @@ config PHY_ROCKCHIP_USB
>  	help
>  	  Enable this to support the Rockchip USB 2.0 PHY.
>  
> +config PHY_ROCKCHIP_INNO_USB2
> +	tristate "Rockchip INNO USB2PHY Driver"
> +	depends on ARCH_ROCKCHIP && OF

changed this to
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
and merged it.

Thanks
Kishon

> +	select GENERIC_PHY
> +	help
> +	  Support for Rockchip USB2.0 PHY with Innosilicon IP block.
> +
>  config PHY_ROCKCHIP_EMMC
>  	tristate "Rockchip EMMC PHY Driver"
>  	depends on ARCH_ROCKCHIP && OF
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 9c3e73c..4963fbc 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -38,6 +38,7 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2)	+= phy-s5pv210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS5_USBDRD)	+= phy-exynos5-usbdrd.o
>  obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
>  obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
> +obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2)	+= phy-rockchip-inno-usb2.o
>  obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
>  obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
>  obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
> diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
> new file mode 100644
> index 0000000..ac20310
> --- /dev/null
> +++ b/drivers/phy/phy-rockchip-inno-usb2.c
> @@ -0,0 +1,707 @@
> +/*
> + * Rockchip USB2.0 PHY with Innosilicon IP block driver
> + *
> + * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
> + *
> + * 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; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/jiffies.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +
> +#define BIT_WRITEABLE_SHIFT	16
> +#define SCHEDULE_DELAY	(60 * HZ)
> +
> +enum rockchip_usb2phy_port_id {
> +	USB2PHY_PORT_OTG,
> +	USB2PHY_PORT_HOST,
> +	USB2PHY_NUM_PORTS,
> +};
> +
> +enum rockchip_usb2phy_host_state {
> +	PHY_STATE_HS_ONLINE	= 0,
> +	PHY_STATE_DISCONNECT	= 1,
> +	PHY_STATE_CONNECT	= 2,
> +	PHY_STATE_FS_LS_ONLINE	= 4,
> +};
> +
> +struct usb2phy_reg {
> +	unsigned int	offset;
> +	unsigned int	bitend;
> +	unsigned int	bitstart;
> +	unsigned int	disable;
> +	unsigned int	enable;
> +};
> +
> +/**
> + * struct rockchip_usb2phy_port_cfg: usb-phy port configuration.
> + * @phy_sus: phy suspend register.
> + * @ls_det_en: linestate detection enable register.
> + * @ls_det_st: linestate detection state register.
> + * @ls_det_clr: linestate detection clear register.
> + * @utmi_ls: utmi linestate state register.
> + * @utmi_hstdet: utmi host disconnect register.
> + */
> +struct rockchip_usb2phy_port_cfg {
> +	struct usb2phy_reg	phy_sus;
> +	struct usb2phy_reg	ls_det_en;
> +	struct usb2phy_reg	ls_det_st;
> +	struct usb2phy_reg	ls_det_clr;
> +	struct usb2phy_reg	utmi_ls;
> +	struct usb2phy_reg	utmi_hstdet;
> +};
> +
> +/**
> + * struct rockchip_usb2phy_cfg: usb-phy configuration.
> + * @reg: the address offset of grf for usb-phy config.
> + * @num_ports: specify how many ports that the phy has.
> + * @clkout_ctl: keep on/turn off output clk of phy.
> + */
> +struct rockchip_usb2phy_cfg {
> +	unsigned int	reg;
> +	unsigned int	num_ports;
> +	struct usb2phy_reg	clkout_ctl;
> +	const struct rockchip_usb2phy_port_cfg	port_cfgs[USB2PHY_NUM_PORTS];
> +};
> +
> +/**
> + * struct rockchip_usb2phy_port: usb-phy port data.
> + * @port_id: flag for otg port or host port.
> + * @suspended: phy suspended flag.
> + * @ls_irq: IRQ number assigned for linestate detection.
> + * @mutex: for register updating in sm_work.
> + * @sm_work: OTG state machine work.
> + * @phy_cfg: port register configuration, assigned by driver data.
> + */
> +struct rockchip_usb2phy_port {
> +	struct phy	*phy;
> +	unsigned int	port_id;
> +	bool		suspended;
> +	int		ls_irq;
> +	struct mutex	mutex;
> +	struct		delayed_work sm_work;
> +	const struct	rockchip_usb2phy_port_cfg *port_cfg;
> +};
> +
> +/**
> + * struct rockchip_usb2phy: usb2.0 phy driver data.
> + * @grf: General Register Files regmap.
> + * @clk: clock struct of phy input clk.
> + * @clk480m: clock struct of phy output clk.
> + * @clk_hw: clock struct of phy output clk management.
> + * @phy_cfg: phy register configuration, assigned by driver data.
> + * @ports: phy port instance.
> + */
> +struct rockchip_usb2phy {
> +	struct device	*dev;
> +	struct regmap	*grf;
> +	struct clk	*clk;
> +	struct clk	*clk480m;
> +	struct clk_hw	clk480m_hw;
> +	const struct rockchip_usb2phy_cfg	*phy_cfg;
> +	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];
> +};
> +
> +static inline int property_enable(struct rockchip_usb2phy *rphy,
> +				  const struct usb2phy_reg *reg, bool en)
> +{
> +	unsigned int val, mask, tmp;
> +
> +	tmp = en ? reg->enable : reg->disable;
> +	mask = GENMASK(reg->bitend, reg->bitstart);
> +	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
> +
> +	return regmap_write(rphy->grf, reg->offset, val);
> +}
> +
> +static inline bool property_enabled(struct rockchip_usb2phy *rphy,
> +				    const struct usb2phy_reg *reg)
> +{
> +	int ret;
> +	unsigned int tmp, orig;
> +	unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
> +
> +	ret = regmap_read(rphy->grf, reg->offset, &orig);
> +	if (ret)
> +		return false;
> +
> +	tmp = (orig & mask) >> reg->bitstart;
> +	return tmp == reg->enable;
> +}
> +
> +static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw)
> +{
> +	struct rockchip_usb2phy *rphy =
> +		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
> +	int ret;
> +
> +	/* turn on 480m clk output if it is off */
> +	if (!property_enabled(rphy, &rphy->phy_cfg->clkout_ctl)) {
> +		ret = property_enable(rphy, &rphy->phy_cfg->clkout_ctl, true);
> +		if (ret)
> +			return ret;
> +
> +		/* waitting for the clk become stable */
> +		mdelay(1);
> +	}
> +
> +	return 0;
> +}
> +
> +static void rockchip_usb2phy_clk480m_disable(struct clk_hw *hw)
> +{
> +	struct rockchip_usb2phy *rphy =
> +		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
> +
> +	/* turn off 480m clk output */
> +	property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false);
> +}
> +
> +static int rockchip_usb2phy_clk480m_enabled(struct clk_hw *hw)
> +{
> +	struct rockchip_usb2phy *rphy =
> +		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
> +
> +	return property_enabled(rphy, &rphy->phy_cfg->clkout_ctl);
> +}
> +
> +static unsigned long
> +rockchip_usb2phy_clk480m_recalc_rate(struct clk_hw *hw,
> +				     unsigned long parent_rate)
> +{
> +	return 480000000;
> +}
> +
> +static const struct clk_ops rockchip_usb2phy_clkout_ops = {
> +	.enable = rockchip_usb2phy_clk480m_enable,
> +	.disable = rockchip_usb2phy_clk480m_disable,
> +	.is_enabled = rockchip_usb2phy_clk480m_enabled,
> +	.recalc_rate = rockchip_usb2phy_clk480m_recalc_rate,
> +};
> +
> +static void rockchip_usb2phy_clk480m_unregister(void *data)
> +{
> +	struct rockchip_usb2phy *rphy = data;
> +
> +	of_clk_del_provider(rphy->dev->of_node);
> +	clk_unregister(rphy->clk480m);
> +}
> +
> +static int
> +rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy)
> +{
> +	struct device_node *node = rphy->dev->of_node;
> +	struct clk_init_data init;
> +	const char *clk_name;
> +	int ret;
> +
> +	init.flags = 0;
> +	init.name = "clk_usbphy_480m";
> +	init.ops = &rockchip_usb2phy_clkout_ops;
> +
> +	/* optional override of the clockname */
> +	of_property_read_string(node, "clock-output-names", &init.name);
> +
> +	if (rphy->clk) {
> +		clk_name = __clk_get_name(rphy->clk);
> +		init.parent_names = &clk_name;
> +		init.num_parents = 1;
> +	} else {
> +		init.parent_names = NULL;
> +		init.num_parents = 0;
> +	}
> +
> +	rphy->clk480m_hw.init = &init;
> +
> +	/* register the clock */
> +	rphy->clk480m = clk_register(rphy->dev, &rphy->clk480m_hw);
> +	if (IS_ERR(rphy->clk480m)) {
> +		ret = PTR_ERR(rphy->clk480m);
> +		goto err_ret;
> +	}
> +
> +	ret = of_clk_add_provider(node, of_clk_src_simple_get, rphy->clk480m);
> +	if (ret < 0)
> +		goto err_clk_provider;
> +
> +	ret = devm_add_action(rphy->dev, rockchip_usb2phy_clk480m_unregister,
> +			      rphy);
> +	if (ret < 0)
> +		goto err_unreg_action;
> +
> +	return 0;
> +
> +err_unreg_action:
> +	of_clk_del_provider(node);
> +err_clk_provider:
> +	clk_unregister(rphy->clk480m);
> +err_ret:
> +	return ret;
> +}
> +
> +static int rockchip_usb2phy_init(struct phy *phy)
> +{
> +	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
> +	int ret;
> +
> +	if (rport->port_id == USB2PHY_PORT_HOST) {
> +		/* clear linestate and enable linestate detect irq */
> +		mutex_lock(&rport->mutex);
> +
> +		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
> +		if (ret) {
> +			mutex_unlock(&rport->mutex);
> +			return ret;
> +		}
> +
> +		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
> +		if (ret) {
> +			mutex_unlock(&rport->mutex);
> +			return ret;
> +		}
> +
> +		mutex_unlock(&rport->mutex);
> +		schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_usb2phy_power_on(struct phy *phy)
> +{
> +	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
> +	int ret;
> +
> +	dev_dbg(&rport->phy->dev, "port power on\n");
> +
> +	if (!rport->suspended)
> +		return 0;
> +
> +	ret = clk_prepare_enable(rphy->clk480m);
> +	if (ret)
> +		return ret;
> +
> +	ret = property_enable(rphy, &rport->port_cfg->phy_sus, false);
> +	if (ret)
> +		return ret;
> +
> +	rport->suspended = false;
> +	return 0;
> +}
> +
> +static int rockchip_usb2phy_power_off(struct phy *phy)
> +{
> +	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
> +	int ret;
> +
> +	dev_dbg(&rport->phy->dev, "port power off\n");
> +
> +	if (rport->suspended)
> +		return 0;
> +
> +	ret = property_enable(rphy, &rport->port_cfg->phy_sus, true);
> +	if (ret)
> +		return ret;
> +
> +	rport->suspended = true;
> +	clk_disable_unprepare(rphy->clk480m);
> +
> +	return 0;
> +}
> +
> +static int rockchip_usb2phy_exit(struct phy *phy)
> +{
> +	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
> +
> +	if (rport->port_id == USB2PHY_PORT_HOST)
> +		cancel_delayed_work_sync(&rport->sm_work);
> +
> +	return 0;
> +}
> +
> +static const struct phy_ops rockchip_usb2phy_ops = {
> +	.init		= rockchip_usb2phy_init,
> +	.exit		= rockchip_usb2phy_exit,
> +	.power_on	= rockchip_usb2phy_power_on,
> +	.power_off	= rockchip_usb2phy_power_off,
> +	.owner		= THIS_MODULE,
> +};
> +
> +/*
> + * The function manage host-phy port state and suspend/resume phy port
> + * to save power.
> + *
> + * we rely on utmi_linestate and utmi_hostdisconnect to identify whether
> + * devices is disconnect or not. Besides, we do not need care it is FS/LS
> + * disconnected or HS disconnected, actually, we just only need get the
> + * device is disconnected at last through rearm the delayed work,
> + * to suspend the phy port in _PHY_STATE_DISCONNECT_ case.
> + *
> + * NOTE: It may invoke *phy_powr_off or *phy_power_on which will invoke
> + * some clk related APIs, so do not invoke it from interrupt context directly.
> + */
> +static void rockchip_usb2phy_sm_work(struct work_struct *work)
> +{
> +	struct rockchip_usb2phy_port *rport =
> +		container_of(work, struct rockchip_usb2phy_port, sm_work.work);
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
> +	unsigned int sh = rport->port_cfg->utmi_hstdet.bitend -
> +			  rport->port_cfg->utmi_hstdet.bitstart + 1;
> +	unsigned int ul, uhd, state;
> +	unsigned int ul_mask, uhd_mask;
> +	int ret;
> +
> +	mutex_lock(&rport->mutex);
> +
> +	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_ls.offset, &ul);
> +	if (ret < 0)
> +		goto next_schedule;
> +
> +	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset,
> +			  &uhd);
> +	if (ret < 0)
> +		goto next_schedule;
> +
> +	uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend,
> +			   rport->port_cfg->utmi_hstdet.bitstart);
> +	ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend,
> +			  rport->port_cfg->utmi_ls.bitstart);
> +
> +	/* stitch on utmi_ls and utmi_hstdet as phy state */
> +	state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) |
> +		(((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh);
> +
> +	switch (state) {
> +	case PHY_STATE_HS_ONLINE:
> +		dev_dbg(&rport->phy->dev, "HS online\n");
> +		break;
> +	case PHY_STATE_FS_LS_ONLINE:
> +		/*
> +		 * For FS/LS device, the online state share with connect state
> +		 * from utmi_ls and utmi_hstdet register, so we distinguish
> +		 * them via suspended flag.
> +		 *
> +		 * Plus, there are two cases, one is D- Line pull-up, and D+
> +		 * line pull-down, the state is 4; another is D+ line pull-up,
> +		 * and D- line pull-down, the state is 2.
> +		 */
> +		if (!rport->suspended) {
> +			/* D- line pull-up, D+ line pull-down */
> +			dev_dbg(&rport->phy->dev, "FS/LS online\n");
> +			break;
> +		}
> +		/* fall through */
> +	case PHY_STATE_CONNECT:
> +		if (rport->suspended) {
> +			dev_dbg(&rport->phy->dev, "Connected\n");
> +			rockchip_usb2phy_power_on(rport->phy);
> +			rport->suspended = false;
> +		} else {
> +			/* D+ line pull-up, D- line pull-down */
> +			dev_dbg(&rport->phy->dev, "FS/LS online\n");
> +		}
> +		break;
> +	case PHY_STATE_DISCONNECT:
> +		if (!rport->suspended) {
> +			dev_dbg(&rport->phy->dev, "Disconnected\n");
> +			rockchip_usb2phy_power_off(rport->phy);
> +			rport->suspended = true;
> +		}
> +
> +		/*
> +		 * activate the linestate detection to get the next device
> +		 * plug-in irq.
> +		 */
> +		property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
> +		property_enable(rphy, &rport->port_cfg->ls_det_en, true);
> +
> +		/*
> +		 * we don't need to rearm the delayed work when the phy port
> +		 * is suspended.
> +		 */
> +		mutex_unlock(&rport->mutex);
> +		return;
> +	default:
> +		dev_dbg(&rport->phy->dev, "unknown phy state\n");
> +		break;
> +	}
> +
> +next_schedule:
> +	mutex_unlock(&rport->mutex);
> +	schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
> +}
> +
> +static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data)
> +{
> +	struct rockchip_usb2phy_port *rport = data;
> +	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
> +
> +	if (!property_enabled(rphy, &rport->port_cfg->ls_det_st))
> +		return IRQ_NONE;
> +
> +	mutex_lock(&rport->mutex);
> +
> +	/* disable linestate detect irq and clear its status */
> +	property_enable(rphy, &rport->port_cfg->ls_det_en, false);
> +	property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
> +
> +	mutex_unlock(&rport->mutex);
> +
> +	/*
> +	 * In this case for host phy port, a new device is plugged in,
> +	 * meanwhile, if the phy port is suspended, we need rearm the work to
> +	 * resume it and mange its states; otherwise, we do nothing about that.
> +	 */
> +	if (rport->suspended && rport->port_id == USB2PHY_PORT_HOST)
> +		rockchip_usb2phy_sm_work(&rport->sm_work.work);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
> +					   struct rockchip_usb2phy_port *rport,
> +					   struct device_node *child_np)
> +{
> +	int ret;
> +
> +	rport->port_id = USB2PHY_PORT_HOST;
> +	rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST];
> +	rport->suspended = true;
> +
> +	mutex_init(&rport->mutex);
> +	INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);
> +
> +	rport->ls_irq = of_irq_get_byname(child_np, "linestate");
> +	if (rport->ls_irq < 0) {
> +		dev_err(rphy->dev, "no linestate irq provided\n");
> +		return rport->ls_irq;
> +	}
> +
> +	ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL,
> +					rockchip_usb2phy_linestate_irq,
> +					IRQF_ONESHOT,
> +					"rockchip_usb2phy", rport);
> +	if (ret) {
> +		dev_err(rphy->dev, "failed to request irq handle\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_usb2phy_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct device_node *child_np;
> +	struct phy_provider *provider;
> +	struct rockchip_usb2phy *rphy;
> +	const struct rockchip_usb2phy_cfg *phy_cfgs;
> +	const struct of_device_id *match;
> +	unsigned int reg;
> +	int index, ret;
> +
> +	rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL);
> +	if (!rphy)
> +		return -ENOMEM;
> +
> +	match = of_match_device(dev->driver->of_match_table, dev);
> +	if (!match || !match->data) {
> +		dev_err(dev, "phy configs are not assigned!\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!dev->parent || !dev->parent->of_node)
> +		return -EINVAL;
> +
> +	rphy->grf = syscon_node_to_regmap(dev->parent->of_node);
> +	if (IS_ERR(rphy->grf))
> +		return PTR_ERR(rphy->grf);
> +
> +	if (of_property_read_u32(np, "reg", &reg)) {
> +		dev_err(dev, "the reg property is not assigned in %s node\n",
> +			np->name);
> +		return -EINVAL;
> +	}
> +
> +	rphy->dev = dev;
> +	phy_cfgs = match->data;
> +	platform_set_drvdata(pdev, rphy);
> +
> +	/* find out a proper config which can be matched with dt. */
> +	index = 0;
> +	while (phy_cfgs[index].reg) {
> +		if (phy_cfgs[index].reg == reg) {
> +			rphy->phy_cfg = &phy_cfgs[index];
> +			break;
> +		}
> +
> +		++index;
> +	}
> +
> +	if (!rphy->phy_cfg) {
> +		dev_err(dev, "no phy-config can be matched with %s node\n",
> +			np->name);
> +		return -EINVAL;
> +	}
> +
> +	rphy->clk = of_clk_get_by_name(np, "phyclk");
> +	if (!IS_ERR(rphy->clk)) {
> +		clk_prepare_enable(rphy->clk);
> +	} else {
> +		dev_info(&pdev->dev, "no phyclk specified\n");
> +		rphy->clk = NULL;
> +	}
> +
> +	ret = rockchip_usb2phy_clk480m_register(rphy);
> +	if (ret) {
> +		dev_err(dev, "failed to register 480m output clock\n");
> +		goto disable_clks;
> +	}
> +
> +	index = 0;
> +	for_each_available_child_of_node(np, child_np) {
> +		struct rockchip_usb2phy_port *rport = &rphy->ports[index];
> +		struct phy *phy;
> +
> +		/*
> +		 * This driver aim to support both otg-port and host-port,
> +		 * but unfortunately, the otg part is not ready in current,
> +		 * so this comments and below codes are interim, which should
> +		 * be changed after otg-port is supplied soon.
> +		 */
> +		if (of_node_cmp(child_np->name, "host-port"))
> +			goto next_child;
> +
> +		phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops);
> +		if (IS_ERR(phy)) {
> +			dev_err(dev, "failed to create phy\n");
> +			ret = PTR_ERR(phy);
> +			goto put_child;
> +		}
> +
> +		rport->phy = phy;
> +		phy_set_drvdata(rport->phy, rport);
> +
> +		ret = rockchip_usb2phy_host_port_init(rphy, rport, child_np);
> +		if (ret)
> +			goto put_child;
> +
> +next_child:
> +		/* to prevent out of boundary */
> +		if (++index >= rphy->phy_cfg->num_ports)
> +			break;
> +	}
> +
> +	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +	return PTR_ERR_OR_ZERO(provider);
> +
> +put_child:
> +	of_node_put(child_np);
> +disable_clks:
> +	if (rphy->clk) {
> +		clk_disable_unprepare(rphy->clk);
> +		clk_put(rphy->clk);
> +	}
> +	return ret;
> +}
> +
> +static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
> +	{
> +		.reg = 0x700,
> +		.num_ports	= 2,
> +		.clkout_ctl	= { 0x0724, 15, 15, 1, 0 },
> +		.port_cfgs	= {
> +			[USB2PHY_PORT_HOST] = {
> +				.phy_sus	= { 0x0728, 15, 0, 0, 0x1d1 },
> +				.ls_det_en	= { 0x0680, 4, 4, 0, 1 },
> +				.ls_det_st	= { 0x0690, 4, 4, 0, 1 },
> +				.ls_det_clr	= { 0x06a0, 4, 4, 0, 1 },
> +				.utmi_ls	= { 0x049c, 14, 13, 0, 1 },
> +				.utmi_hstdet	= { 0x049c, 12, 12, 0, 1 }
> +			}
> +		},
> +	},
> +	{ /* sentinel */ }
> +};
> +
> +static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
> +	{
> +		.reg = 0xe450,
> +		.num_ports	= 2,
> +		.clkout_ctl	= { 0xe450, 4, 4, 1, 0 },
> +		.port_cfgs	= {
> +			[USB2PHY_PORT_HOST] = {
> +				.phy_sus	= { 0xe458, 1, 0, 0x2, 0x1 },
> +				.ls_det_en	= { 0xe3c0, 6, 6, 0, 1 },
> +				.ls_det_st	= { 0xe3e0, 6, 6, 0, 1 },
> +				.ls_det_clr	= { 0xe3d0, 6, 6, 0, 1 },
> +				.utmi_ls	= { 0xe2ac, 22, 21, 0, 1 },
> +				.utmi_hstdet	= { 0xe2ac, 23, 23, 0, 1 }
> +			}
> +		},
> +	},
> +	{
> +		.reg = 0xe460,
> +		.num_ports	= 2,
> +		.clkout_ctl	= { 0xe460, 4, 4, 1, 0 },
> +		.port_cfgs	= {
> +			[USB2PHY_PORT_HOST] = {
> +				.phy_sus	= { 0xe468, 1, 0, 0x2, 0x1 },
> +				.ls_det_en	= { 0xe3c0, 11, 11, 0, 1 },
> +				.ls_det_st	= { 0xe3e0, 11, 11, 0, 1 },
> +				.ls_det_clr	= { 0xe3d0, 11, 11, 0, 1 },
> +				.utmi_ls	= { 0xe2ac, 26, 25, 0, 1 },
> +				.utmi_hstdet	= { 0xe2ac, 27, 27, 0, 1 }
> +			}
> +		},
> +	},
> +	{ /* sentinel */ }
> +};
> +
> +static const struct of_device_id rockchip_usb2phy_dt_match[] = {
> +	{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
> +	{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match);
> +
> +static struct platform_driver rockchip_usb2phy_driver = {
> +	.probe		= rockchip_usb2phy_probe,
> +	.driver		= {
> +		.name	= "rockchip-usb2phy",
> +		.of_match_table = rockchip_usb2phy_dt_match,
> +	},
> +};
> +module_platform_driver(rockchip_usb2phy_driver);
> +
> +MODULE_AUTHOR("Frank Wang <frank.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>");
> +MODULE_DESCRIPTION("Rockchip USB2.0 PHY driver");
> +MODULE_LICENSE("GPL v2");
> 

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

* Re: [PATCH v9 3/4] arm64: dts: rockchip: add usb2-phy support for rk3399
  2016-07-22  7:00 ` [PATCH v9 3/4] arm64: dts: rockchip: add usb2-phy support for rk3399 Frank Wang
  2016-08-03 19:34     ` Heiko Stübner
@ 2016-08-17  9:53   ` Heiko Stübner
  1 sibling, 0 replies; 15+ messages in thread
From: Heiko Stübner @ 2016-08-17  9:53 UTC (permalink / raw)
  To: Frank Wang
  Cc: dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll,
	mark.rutland, ijc+devicetree, galak, linux-kernel, devicetree,
	linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao,
	william.wu, daniel.meng

Am Freitag, 22. Juli 2016, 15:00:45 schrieb Frank Wang:
> Add usb2-phy nodes and specify phys phandle for ehci.
> 
> Signed-off-by: Frank Wang <frank.wang@rock-chips.com>

applied to my arm64 dts branch for 4.9

Thanks
Heiko

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

* Re: [PATCH v9 4/4] arm64: dts: rockchip: configure usb2-phy support for rk3399-evb
  2016-07-22  7:00 ` [PATCH v9 4/4] arm64: dts: rockchip: configure usb2-phy support for rk3399-evb Frank Wang
@ 2016-08-17 10:02   ` Heiko Stübner
  2016-08-18  2:53       ` Frank Wang
  0 siblings, 1 reply; 15+ messages in thread
From: Heiko Stübner @ 2016-08-17 10:02 UTC (permalink / raw)
  To: Frank Wang
  Cc: dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll,
	mark.rutland, ijc+devicetree, galak, linux-kernel, devicetree,
	linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao,
	william.wu, daniel.meng

Am Freitag, 22. Juli 2016, 15:00:46 schrieb Frank Wang:
> Add vcc5v0_host regulator for usb2-phy and enable host-port support.
> 
> Signed-off-by: Frank Wang <frank.wang@rock-chips.com>

applied to ny dts64 branch [0] with some changes:

- the pin is named vcc5v0_host_en not host_vbus_drv in the schematics
  please always try to use the names from the schematics
- separated the enablement of the subnodes


Heiko

[0] https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commit/?id=1d3bc1d6c9c4658d554bcf89a71b35a6783a5b4e


> ---
>  arch/arm64/boot/dts/rockchip/rk3399-evb.dts |   44
> +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts index 1a3eb14..56aeedb 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> @@ -69,6 +69,25 @@
>  		regulator-max-microvolt = <3300000>;
>  	};
> 
> +	vcc5v0_sys: vcc5v0-sys {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc5v0_sys";
> +		regulator-always-on;
> +		regulator-boot-on;
> +		regulator-min-microvolt = <5000000>;
> +		regulator-max-microvolt = <5000000>;
> +	};
> +
> +	vcc5v0_host: vcc5v0-host-regulator {
> +		compatible = "regulator-fixed";
> +		enable-active-high;
> +		gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&host_vbus_drv>;
> +		regulator-name = "vcc5v0_host";
> +		vin-supply = <&vcc5v0_sys>;
> +	};
> +
>  	vcc_phy: vcc-phy-regulator {
>  		compatible = "regulator-fixed";
>  		regulator-name = "vcc_phy";
> @@ -89,6 +108,24 @@
>  	status = "okay";
>  };
> 
> +&u2phy0 {
> +	status = "okay";
> +
> +	u2phy0_host: host-port {
> +		phy-supply = <&vcc5v0_host>;
> +		status = "okay";
> +	};
> +};
> +
> +&u2phy1 {
> +	status = "okay";
> +
> +	u2phy1_host: host-port {
> +		phy-supply = <&vcc5v0_host>;
> +		status = "okay";
> +	};
> +};
> +
>  &uart2 {
>  	status = "okay";
>  };
> @@ -121,4 +158,11 @@
>  				<1 18 RK_FUNC_GPIO &pcfg_pull_down>;
>  		};
>  	};
> +
> +	usb2 {
> +		host_vbus_drv: host-vbus-drv {
> +			rockchip,pins =
> +				<4 25 RK_FUNC_GPIO &pcfg_pull_none>;
> +		};
> +	};
>  };

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

* Re: [PATCH v9 4/4] arm64: dts: rockchip: configure usb2-phy support for rk3399-evb
  2016-08-17 10:02   ` Heiko Stübner
@ 2016-08-18  2:53       ` Frank Wang
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Wang @ 2016-08-18  2:53 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll,
	mark.rutland, ijc+devicetree, galak, linux-kernel, devicetree,
	linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao,
	william.wu, daniel.meng

On 2016/8/17 18:02, Heiko Stübner wrote:
> Am Freitag, 22. Juli 2016, 15:00:46 schrieb Frank Wang:
>> Add vcc5v0_host regulator for usb2-phy and enable host-port support.
>>
>> Signed-off-by: Frank Wang <frank.wang@rock-chips.com>
> applied to ny dts64 branch [0] with some changes:
>
> - the pin is named vcc5v0_host_en not host_vbus_drv in the schematics
>    please always try to use the names from the schematics
> - separated the enablement of the subnodes
>

Thanks for your valuable comments, I will try to improve the quality of 
my patches in future.

BR.
Frank

> Heiko
>
> [0] https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commit/?id=1d3bc1d6c9c4658d554bcf89a71b35a6783a5b4e
>
>
>> ---
>>   arch/arm64/boot/dts/rockchip/rk3399-evb.dts |   44
>> +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
>> b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts index 1a3eb14..56aeedb 100644
>> --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
>> +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
>> @@ -69,6 +69,25 @@
>>   		regulator-max-microvolt = <3300000>;
>>   	};
>>
>> +	vcc5v0_sys: vcc5v0-sys {
>> +		compatible = "regulator-fixed";
>> +		regulator-name = "vcc5v0_sys";
>> +		regulator-always-on;
>> +		regulator-boot-on;
>> +		regulator-min-microvolt = <5000000>;
>> +		regulator-max-microvolt = <5000000>;
>> +	};
>> +
>> +	vcc5v0_host: vcc5v0-host-regulator {
>> +		compatible = "regulator-fixed";
>> +		enable-active-high;
>> +		gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>;
>> +		pinctrl-names = "default";
>> +		pinctrl-0 = <&host_vbus_drv>;
>> +		regulator-name = "vcc5v0_host";
>> +		vin-supply = <&vcc5v0_sys>;
>> +	};
>> +
>>   	vcc_phy: vcc-phy-regulator {
>>   		compatible = "regulator-fixed";
>>   		regulator-name = "vcc_phy";
>> @@ -89,6 +108,24 @@
>>   	status = "okay";
>>   };
>>
>> +&u2phy0 {
>> +	status = "okay";
>> +
>> +	u2phy0_host: host-port {
>> +		phy-supply = <&vcc5v0_host>;
>> +		status = "okay";
>> +	};
>> +};
>> +
>> +&u2phy1 {
>> +	status = "okay";
>> +
>> +	u2phy1_host: host-port {
>> +		phy-supply = <&vcc5v0_host>;
>> +		status = "okay";
>> +	};
>> +};
>> +
>>   &uart2 {
>>   	status = "okay";
>>   };
>> @@ -121,4 +158,11 @@
>>   				<1 18 RK_FUNC_GPIO &pcfg_pull_down>;
>>   		};
>>   	};
>> +
>> +	usb2 {
>> +		host_vbus_drv: host-vbus-drv {
>> +			rockchip,pins =
>> +				<4 25 RK_FUNC_GPIO &pcfg_pull_none>;
>> +		};
>> +	};
>>   };

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

* Re: [PATCH v9 4/4] arm64: dts: rockchip: configure usb2-phy support for rk3399-evb
@ 2016-08-18  2:53       ` Frank Wang
  0 siblings, 0 replies; 15+ messages in thread
From: Frank Wang @ 2016-08-18  2:53 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: dianders-F7+t8E8rja9g9hUCZPvPmw, linux-0h96xk9xTtrk1uMJSBkQmQ,
	groeck-F7+t8E8rja9g9hUCZPvPmw, jwerner-F7+t8E8rja9g9hUCZPvPmw,
	kishon-l0cyMroinI0, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	xzy.xu-TNX95d0MmH7DzftRWevZcw, kever.yang-TNX95d0MmH7DzftRWevZcw,
	huangtao-TNX95d0MmH7DzftRWevZcw,
	william.wu-TNX95d0MmH7DzftRWevZcw,
	daniel.meng-TNX95d0MmH7DzftRWevZcw

On 2016/8/17 18:02, Heiko Stübner wrote:
> Am Freitag, 22. Juli 2016, 15:00:46 schrieb Frank Wang:
>> Add vcc5v0_host regulator for usb2-phy and enable host-port support.
>>
>> Signed-off-by: Frank Wang <frank.wang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> applied to ny dts64 branch [0] with some changes:
>
> - the pin is named vcc5v0_host_en not host_vbus_drv in the schematics
>    please always try to use the names from the schematics
> - separated the enablement of the subnodes
>

Thanks for your valuable comments, I will try to improve the quality of 
my patches in future.

BR.
Frank

> Heiko
>
> [0] https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commit/?id=1d3bc1d6c9c4658d554bcf89a71b35a6783a5b4e
>
>
>> ---
>>   arch/arm64/boot/dts/rockchip/rk3399-evb.dts |   44
>> +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
>> b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts index 1a3eb14..56aeedb 100644
>> --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
>> +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
>> @@ -69,6 +69,25 @@
>>   		regulator-max-microvolt = <3300000>;
>>   	};
>>
>> +	vcc5v0_sys: vcc5v0-sys {
>> +		compatible = "regulator-fixed";
>> +		regulator-name = "vcc5v0_sys";
>> +		regulator-always-on;
>> +		regulator-boot-on;
>> +		regulator-min-microvolt = <5000000>;
>> +		regulator-max-microvolt = <5000000>;
>> +	};
>> +
>> +	vcc5v0_host: vcc5v0-host-regulator {
>> +		compatible = "regulator-fixed";
>> +		enable-active-high;
>> +		gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>;
>> +		pinctrl-names = "default";
>> +		pinctrl-0 = <&host_vbus_drv>;
>> +		regulator-name = "vcc5v0_host";
>> +		vin-supply = <&vcc5v0_sys>;
>> +	};
>> +
>>   	vcc_phy: vcc-phy-regulator {
>>   		compatible = "regulator-fixed";
>>   		regulator-name = "vcc_phy";
>> @@ -89,6 +108,24 @@
>>   	status = "okay";
>>   };
>>
>> +&u2phy0 {
>> +	status = "okay";
>> +
>> +	u2phy0_host: host-port {
>> +		phy-supply = <&vcc5v0_host>;
>> +		status = "okay";
>> +	};
>> +};
>> +
>> +&u2phy1 {
>> +	status = "okay";
>> +
>> +	u2phy1_host: host-port {
>> +		phy-supply = <&vcc5v0_host>;
>> +		status = "okay";
>> +	};
>> +};
>> +
>>   &uart2 {
>>   	status = "okay";
>>   };
>> @@ -121,4 +158,11 @@
>>   				<1 18 RK_FUNC_GPIO &pcfg_pull_down>;
>>   		};
>>   	};
>> +
>> +	usb2 {
>> +		host_vbus_drv: host-vbus-drv {
>> +			rockchip,pins =
>> +				<4 25 RK_FUNC_GPIO &pcfg_pull_none>;
>> +		};
>> +	};
>>   };

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

end of thread, other threads:[~2016-08-18  2:53 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-22  7:00 [PATCH v9 0/4] Add a new Rockchip usb2 phy driver Frank Wang
2016-07-22  7:00 ` Frank Wang
2016-07-22  7:00 ` [PATCH v9 1/4] Documentation: bindings: add DT documentation for Rockchip USB2PHY Frank Wang
2016-07-22  7:00   ` Frank Wang
2016-07-22  7:00 ` [PATCH v9 2/4] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy Frank Wang
2016-08-12 10:09   ` Kishon Vijay Abraham I
2016-08-12 10:09     ` Kishon Vijay Abraham I
2016-07-22  7:00 ` [PATCH v9 3/4] arm64: dts: rockchip: add usb2-phy support for rk3399 Frank Wang
2016-08-03 19:34   ` Heiko Stübner
2016-08-03 19:34     ` Heiko Stübner
2016-08-17  9:53   ` Heiko Stübner
2016-07-22  7:00 ` [PATCH v9 4/4] arm64: dts: rockchip: configure usb2-phy support for rk3399-evb Frank Wang
2016-08-17 10:02   ` Heiko Stübner
2016-08-18  2:53     ` Frank Wang
2016-08-18  2:53       ` Frank Wang

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.