All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver
@ 2013-12-05 12:29 Kamil Debski
  2013-12-05 12:29 ` [PATCH 1/9] phy: core: Change the way of_phy_get is called Kamil Debski
                   ` (9 more replies)
  0 siblings, 10 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-05 12:29 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, Kamil Debski

Hi,

This is the fourth version of the patchset adding the new Exynos USB 2.0 PHY
driver. The driver uses the Generic PHY Framework.

A month has passed since the last version. I have addressed numerous comments
that appeared on the mailing list in this patch. I would like to specially
thank Kishon, Tomasz, Matt and Vivek for their comments.

This patch contains two necessary patches to the phy core.
It is very useful to be able to get phy using a device tree node.

In addition this patch depends on:
[PATCH V11 1/3] ARM: dts: Add pmu sysreg node to exynos5250 and exynos5420 dtsi
files [1].

Best wishes,
Kamil Debski

[1] - http://www.spinics.net/lists/linux-samsung-soc/msg24528.html

----------------
Changes from v3:
- using PMU and system registers indirectly via syscon
- change labelling
- change Kconfig name
- fixed typos/stray whitespace
- move of_phy_provider_register() to the end of probe
- add a regular error return code to the rate_to_clk functions
- cleanup code and remove unused code
- change struct names to avoid collisions
- add mechanism to support multiple phys by the ehci driver

----------------
Changes from v2:
- rebase all patches to the usb-next branch
- fixes in the documentation file
  - remove wrong entries in the phy node (ranges, and #address- & #size-cells)
  - add clocks and clock-names as required properites
  - rephrase a few sentences
- fixes in the ehci-exynos.c file
  - move phy_name variable next to phy in exynos_ehci_hcd
  - remove otg from exynos_ehci_hcd as it was no longer used
  - move devm_phy_get after the Exynos5440 skip_phy check
- fixes in the s3c-hsotg.c file
  - cosmetic fixes (remove empty line that was wrongfully added)
- fixes in the main driver
  - remove cpu_type in favour for a boolean flag matched with the compatible
    value
  - rename files, structures, variables and Kconfig entires - change from simple
    "uphy" to "usb2_phy"
  - fix multiline comments style
  - simplify #ifdefs in of_device_id
  - fix Kconfig description
  - change dev_info to dev_dbg where reasonable
  - cosmetic changes (remove wrongful blank lines)
  - remove unnecessary reference counting

----------------
Changes from v1:
- the changes include minor fixes of the hardware initialization of the PHY
  module
- some other minor fixes were introduced

----------------------
Original cover letter:

Hi,

This patch adds a new drive for USB PHYs for Samsung SoCs. The driver is
using the Generic PHY Framework created by Kishon Vijay Abrahan I. It
can be found here https://lkml.org/lkml/2013/8/21/29. This patch adds
support to Exynos4 family of SoCs. Support for Exynos3 and Exynos5 is
planned to be added in the near future.

I welcome your comments.

----------------------

[1] https://lkml.org/lkml/2013/8/21/29


Kamil Debski (8):
  phy: core: Change the way of_phy_get is called
  phy: core: Add devm_of_phy_get to phy-core
  phy: Add new Exynos USB PHY driver
  usb: ehci-s5p: Change to use phy provided by the generic phy
    framework
  usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic
    phy framework
  phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver
  dts: Add usb2phy to Exynos 4
  dts: Add usb2phy to Exynos 5250

Mateusz Krawczuk (1):
  phy: Add support for S5PV210 to the Exynos USB PHY driver

 .../devicetree/bindings/arm/samsung/pmu.txt        |    2 +
 .../devicetree/bindings/phy/samsung-usbphy.txt     |   56 +++
 .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 +
 Documentation/devicetree/bindings/usb/usb-ehci.txt |   35 ++
 arch/arm/boot/dts/exynos4.dtsi                     |   31 ++
 arch/arm/boot/dts/exynos4210.dtsi                  |   17 +
 arch/arm/boot/dts/exynos4x12.dtsi                  |   17 +
 arch/arm/boot/dts/exynos5250.dtsi                  |   33 +-
 drivers/phy/Kconfig                                |   35 ++
 drivers/phy/Makefile                               |    5 +
 drivers/phy/phy-core.c                             |   43 ++-
 drivers/phy/phy-exynos4210-usb2.c                  |  264 ++++++++++++++
 drivers/phy/phy-exynos4212-usb2.c                  |  312 +++++++++++++++++
 drivers/phy/phy-exynos5250-usb2.c                  |  363 ++++++++++++++++++++
 drivers/phy/phy-s5pv210-usb2.c                     |  206 +++++++++++
 drivers/phy/phy-samsung-usb2.c                     |  240 +++++++++++++
 drivers/phy/phy-samsung-usb2.h                     |   74 ++++
 drivers/usb/gadget/s3c-hsotg.c                     |   11 +-
 drivers/usb/host/ehci-exynos.c                     |   95 +++--
 include/linux/phy/phy.h                            |    3 +
 20 files changed, 1789 insertions(+), 57 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/phy/samsung-usbphy.txt
 create mode 100644 drivers/phy/phy-exynos4210-usb2.c
 create mode 100644 drivers/phy/phy-exynos4212-usb2.c
 create mode 100644 drivers/phy/phy-exynos5250-usb2.c
 create mode 100644 drivers/phy/phy-s5pv210-usb2.c
 create mode 100644 drivers/phy/phy-samsung-usb2.c
 create mode 100644 drivers/phy/phy-samsung-usb2.h

-- 
1.7.9.5


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

* [PATCH 1/9] phy: core: Change the way of_phy_get is called
  2013-12-05 12:29 [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver Kamil Debski
@ 2013-12-05 12:29 ` Kamil Debski
  2013-12-06  5:30     ` Kishon Vijay Abraham I
  2013-12-05 12:29 ` [PATCH 2/9] phy: core: Add devm_of_phy_get to phy-core Kamil Debski
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 50+ messages in thread
From: Kamil Debski @ 2013-12-05 12:29 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, Kamil Debski

Previously the of_phy_get function took a struct device * and
was declared static. It was impossible to call it from
another driver and thus it was impossible to get phy defined
for a given node.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/phy/phy-core.c  |   12 +++++-------
 include/linux/phy/phy.h |    1 +
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 03cf8fb..7fb3474 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -250,20 +250,17 @@ EXPORT_SYMBOL_GPL(phy_power_off);
  * not yet loaded. This function uses of_xlate call back function provided
  * while registering the phy_provider to find the phy instance.
  */
-static struct phy *of_phy_get(struct device *dev, int index)
+struct phy *of_phy_get(struct device_node *np, int index)
 {
 	int ret;
 	struct phy_provider *phy_provider;
 	struct phy *phy = NULL;
 	struct of_phandle_args args;
 
-	ret = of_parse_phandle_with_args(dev->of_node, "phys", "#phy-cells",
+	ret = of_parse_phandle_with_args(np, "phys", "#phy-cells",
 		index, &args);
-	if (ret) {
-		dev_dbg(dev, "failed to get phy in %s node\n",
-			dev->of_node->full_name);
+	if (ret)
 		return ERR_PTR(-ENODEV);
-	}
 
 	mutex_lock(&phy_provider_mutex);
 	phy_provider = of_phy_provider_lookup(args.np);
@@ -281,6 +278,7 @@ err0:
 
 	return phy;
 }
+EXPORT_SYMBOL_GPL(of_phy_get);
 
 /**
  * phy_put() - release the PHY
@@ -370,7 +368,7 @@ struct phy *phy_get(struct device *dev, const char *string)
 	if (dev->of_node) {
 		index = of_property_match_string(dev->of_node, "phy-names",
 			string);
-		phy = of_phy_get(dev, index);
+		phy = of_phy_get(dev->of_node, index);
 		if (IS_ERR(phy)) {
 			dev_err(dev, "unable to find phy\n");
 			return phy;
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 6d72269..169f572 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -131,6 +131,7 @@ struct phy *phy_get(struct device *dev, const char *string);
 struct phy *devm_phy_get(struct device *dev, const char *string);
 void phy_put(struct phy *phy);
 void devm_phy_put(struct device *dev, struct phy *phy);
+struct phy *of_phy_get(struct device_node *np, int index);
 struct phy *of_phy_simple_xlate(struct device *dev,
 	struct of_phandle_args *args);
 struct phy *phy_create(struct device *dev, const struct phy_ops *ops,
-- 
1.7.9.5


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

* [PATCH 2/9] phy: core: Add devm_of_phy_get to phy-core
  2013-12-05 12:29 [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver Kamil Debski
  2013-12-05 12:29 ` [PATCH 1/9] phy: core: Change the way of_phy_get is called Kamil Debski
@ 2013-12-05 12:29 ` Kamil Debski
  2013-12-05 12:29   ` Kamil Debski
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-05 12:29 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, Kamil Debski

Adding devm_of_phy_get will allow to get phys by supplying the
device_node instead of by name.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/phy/phy-core.c  |   31 +++++++++++++++++++++++++++++++
 include/linux/phy/phy.h |    2 ++
 2 files changed, 33 insertions(+)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 7fb3474..b39b48c 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -421,6 +421,37 @@ struct phy *devm_phy_get(struct device *dev, const char *string)
 EXPORT_SYMBOL_GPL(devm_phy_get);
 
 /**
+ * devm_of_phy_get() - lookup and obtain a reference to a phy.
+ * @dev: device that requests this phy
+ * @np: node containing the phy
+ * @index: the index of the phy
+ *
+ * Gets the phy using phy_get(), and associates a device with it using
+ * devres. On driver detach, release function is invoked on the devres data,
+ * then, devres data is freed.
+ */
+struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, int
+									index)
+{
+	struct phy **ptr, *phy;
+
+	ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	phy = of_phy_get(np, index);
+	if (!IS_ERR(phy)) {
+		*ptr = phy;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return phy;
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_get);
+
+/**
  * phy_create() - create a new phy
  * @dev: device that is creating the new phy
  * @ops: function pointers for performing phy operations
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 169f572..f143ee8 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -129,6 +129,8 @@ int phy_power_on(struct phy *phy);
 int phy_power_off(struct phy *phy);
 struct phy *phy_get(struct device *dev, const char *string);
 struct phy *devm_phy_get(struct device *dev, const char *string);
+struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, int
+									index);
 void phy_put(struct phy *phy);
 void devm_phy_put(struct device *dev, struct phy *phy);
 struct phy *of_phy_get(struct device_node *np, int index);
-- 
1.7.9.5


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

* [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
@ 2013-12-05 12:29   ` Kamil Debski
  0 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-05 12:29 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, Kamil Debski

Add a new driver for the Exynos USB PHY. The new driver uses the generic
PHY framework. The driver includes support for the Exynos 4x10 and 4x12
SoC families.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 .../devicetree/bindings/phy/samsung-usbphy.txt     |   54 ++++
 drivers/phy/Kconfig                                |   20 ++
 drivers/phy/Makefile                               |    3 +
 drivers/phy/phy-exynos4210-usb2.c                  |  264 +++++++++++++++++
 drivers/phy/phy-exynos4212-usb2.c                  |  312 ++++++++++++++++++++
 drivers/phy/phy-samsung-usb2.c                     |  228 ++++++++++++++
 drivers/phy/phy-samsung-usb2.h                     |   72 +++++
 7 files changed, 953 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/samsung-usbphy.txt
 create mode 100644 drivers/phy/phy-exynos4210-usb2.c
 create mode 100644 drivers/phy/phy-exynos4212-usb2.c
 create mode 100644 drivers/phy/phy-samsung-usb2.c
 create mode 100644 drivers/phy/phy-samsung-usb2.h

diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
new file mode 100644
index 0000000..cadbf70
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
@@ -0,0 +1,54 @@
+Samsung S5P/EXYNOS SoC series USB PHY
+-------------------------------------------------
+
+Required properties:
+- compatible : should be one of the listed compatibles:
+	- "samsung,exynos4210-usb2-phy"
+	- "samsung,exynos4212-usb2-phy"
+- reg : a list of registers used by phy driver
+	- first and obligatory is the location of phy modules registers
+- samsung,sysreg-phandle - handle to syscon used to control the system registers
+- samsung,pmureg-phandle - handle to syscon used to control PMU registers
+- #phy-cells : from the generic phy bindings, must be 1;
+- clocks and clock-names:
+	- the "phy" clocks is required by the phy module
+	- next for each of the phys a clock has to be assidned, this clock
+	  will be used to determine clocking frequency for the phys
+	  (the labels are specified in the paragraph below)
+
+The first phandle argument in the PHY specifier identifies the PHY, its
+meaning is compatible dependent. For the currently supported SoCs (Exynos 4210
+and Exynos 4212) it is as follows:
+  0 - USB device ("device"),
+  1 - USB host ("host"),
+  2 - HSIC0 ("hsic0"),
+  3 - HSIC1 ("hsic1"),
+
+Exynos 4210 and Exynos 4212 use mode switching and require that mode switch
+register is supplied.
+
+Example:
+
+For Exynos 4412 (compatible with Exynos 4212):
+
+usbphy: phy@125B0000 {
+	compatible = "samsung,exynos4212-usb2-phy";
+	reg = <0x125B0000 0x100 0x10020704 0x0c 0x1001021c 0x4>;
+	clocks = <&clock 305>, <&clock 2>, <&clock 2>, <&clock 2>,
+							<&clock 2>;
+	clock-names = "phy", "device", "host", "hsic0", "hsic1";
+	status = "okay";
+	#phy-cells = <1>;
+	samsung,sysreg-phandle = <&sys_reg>;
+	samsung,pmureg-phandle = <&pmu_reg>;
+};
+
+Then the PHY can be used in other nodes such as:
+
+phy-consumer@12340000 {
+	phys = <&usbphy 2>;
+	phy-names = "phy";
+};
+
+Refer to DT bindings documentation of particular PHY consumer devices for more
+information about required PHYs and the way of specification.
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index a344f3d..b29018f 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -51,4 +51,24 @@ config PHY_EXYNOS_DP_VIDEO
 	help
 	  Support for Display Port PHY found on Samsung EXYNOS SoCs.
 
+config PHY_SAMSUNG_USB2
+	tristate "Samsung USB 2.0 PHY driver"
+	help
+	  Enable this to support Samsung USB phy helper driver for Samsung SoCs.
+	  This driver provides common interface to interact, for Samsung
+	  USB 2.0 PHY driver.
+
+config PHY_EXYNOS4210_USB2
+	bool "Support for Exynos 4210"
+	depends on PHY_SAMSUNG_USB2
+	depends on CPU_EXYNOS4210
+	help
+	  Enable USB PHY support for Exynos 4210
+
+config PHY_EXYNOS4212_USB2
+	bool "Support for Exynos 4212"
+	depends on PHY_SAMSUNG_USB2
+	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+	help
+	  Enable USB PHY support for Exynos 4212
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index d0caae9..9f4befd 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
+obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/phy-exynos4210-usb2.c
new file mode 100644
index 0000000..a02e5c2
--- /dev/null
+++ b/drivers/phy/phy-exynos4210-usb2.c
@@ -0,0 +1,264 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4210_UPHYPWR			0x0
+
+#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
+#define EXYNOS_4210_UPHYPWR_PHY0_PWR		(1 << 3)
+#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
+#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		(1 << 5)
+#define EXYNOS_4210_UPHYPWR_PHY0	( \
+	EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_PHY0_PWR | \
+	EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
+	EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND	(1 << 6)
+#define EXYNOS_4210_UPHYPWR_PHY1_PWR		(1 << 7)
+#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		(1 << 8)
+#define EXYNOS_4210_UPHYPWR_PHY1 ( \
+	EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_PHY1_PWR | \
+	EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
+#define EXYNOS_4210_UPHYPWR_HSCI0_SLEEP		(1 << 10)
+#define EXYNOS_4210_UPHYPWR_HSCI0 ( \
+	EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_HSCI0_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND	(1 << 11)
+#define EXYNOS_4210_UPHYPWR_HSCI1_SLEEP		(1 << 12)
+#define EXYNOS_4210_UPHYPWR_HSCI1 ( \
+	EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_HSCI1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4210_UPHYCLK			0x4
+
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
+
+#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
+#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
+#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
+
+/* PHY reset control */
+#define EXYNOS_4210_UPHYRST			0x8
+
+#define EXYNOS_4210_URSTCON_PHY0		(1 << 0)
+#define EXYNOS_4210_URSTCON_OTG_HLINK		(1 << 1)
+#define EXYNOS_4210_URSTCON_OTG_PHYLINK		(1 << 2)
+#define EXYNOS_4210_URSTCON_PHY1_ALL		(1 << 3)
+#define EXYNOS_4210_URSTCON_PHY1_P0		(1 << 4)
+#define EXYNOS_4210_URSTCON_PHY1_P1P2		(1 << 5)
+#define EXYNOS_4210_URSTCON_HOST_LINK_ALL	(1 << 6)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P0	(1 << 7)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P1	(1 << 8)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P2	(1 << 9)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
+#define EXYNOS_4210_USB_ISOL_DEVICE		(1 << 0)
+#define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
+#define EXYNOS_4210_USB_ISOL_HOST		(1 << 0)
+
+/* USBYPHY1 Floating prevention */
+#define EXYNOS_4210_UPHY1CON			0x34
+#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION	0x1
+
+/* Mode switching SUB Device <-> Host */
+#define EXYNOS_4210_MODE_SWITCH_OFFSET		0x21c
+#define EXYNOS_4210_MODE_SWITCH_MASK		1
+#define EXYNOS_4210_MODE_SWITCH_DEVICE		0
+#define EXYNOS_4210_MODE_SWITCH_HOST		1
+
+enum exynos4210_phy_id {
+	EXYNOS4210_DEVICE,
+	EXYNOS4210_HOST,
+	EXYNOS4210_HSIC0,
+	EXYNOS4210_HSIC1,
+	EXYNOS4210_NUM_PHYS,
+};
+
+/*
+ * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
+{
+	switch (rate) {
+	case 12 * MHZ:
+		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
+		break;
+	case 24 * MHZ:
+		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
+		break;
+	case 48 * MHZ:
+		reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 offset;
+	u32 mask;
+
+	switch (inst->cfg->id) {
+	case EXYNOS4210_DEVICE:
+		offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
+		mask = EXYNOS_4210_USB_ISOL_DEVICE;
+		break;
+	case EXYNOS4210_HOST:
+		offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
+		mask = EXYNOS_4210_USB_ISOL_HOST;
+		break;
+	default:
+		return;
+	};
+
+	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 rstbits = 0;
+	u32 phypwr = 0;
+	u32 rst;
+	u32 pwr;
+
+	switch (inst->cfg->id) {
+	case EXYNOS4210_DEVICE:
+		phypwr =	EXYNOS_4210_UPHYPWR_PHY0;
+		rstbits =	EXYNOS_4210_URSTCON_PHY0;
+		break;
+	case EXYNOS4210_HOST:
+		phypwr =	EXYNOS_4210_UPHYPWR_PHY1;
+		rstbits =	EXYNOS_4210_URSTCON_PHY1_ALL |
+				EXYNOS_4210_URSTCON_PHY1_P0 |
+				EXYNOS_4210_URSTCON_PHY1_P1P2 |
+				EXYNOS_4210_URSTCON_HOST_LINK_ALL |
+				EXYNOS_4210_URSTCON_HOST_LINK_P0;
+		writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
+		break;
+	case EXYNOS4210_HSIC0:
+		phypwr =	EXYNOS_4210_UPHYPWR_HSCI0;
+		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
+				EXYNOS_4210_URSTCON_HOST_LINK_P1;
+		break;
+	case EXYNOS4210_HSIC1:
+		phypwr =	EXYNOS_4210_UPHYPWR_HSCI1;
+		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
+				EXYNOS_4210_URSTCON_HOST_LINK_P2;
+		break;
+	};
+
+	if (on) {
+		writel(inst->clk_reg_val, drv->reg_phy + EXYNOS_4210_UPHYCLK);
+
+		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
+		pwr &= ~phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
+
+		rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
+		rst |= rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
+		udelay(10);
+		rst &= ~rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
+	} else {
+		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
+		pwr |= phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
+	}
+}
+
+static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
+{
+	/* Order of initialisation is important - first power then isolation */
+	exynos4210_phy_pwr(inst, 1);
+	exynos4210_isol(inst, 0);
+
+	return 0;
+}
+
+static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
+{
+	exynos4210_isol(inst, 1);
+	exynos4210_phy_pwr(inst, 0);
+
+	return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos4210_phys[] = {
+	{
+		.label		= "device",
+		.id		= EXYNOS4210_DEVICE,
+		.rate_to_clk	= exynos4210_rate_to_clk,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS4210_HOST,
+		.rate_to_clk	= exynos4210_rate_to_clk,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS4210_HSIC0,
+		.rate_to_clk	= exynos4210_rate_to_clk,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS4210_HSIC1,
+		.rate_to_clk	= exynos4210_rate_to_clk,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
+	.num_phys		= EXYNOS4210_NUM_PHYS,
+	.phys			= exynos4210_phys,
+	.has_mode_switch	= 1,
+};
+
diff --git a/drivers/phy/phy-exynos4212-usb2.c b/drivers/phy/phy-exynos4212-usb2.c
new file mode 100644
index 0000000..375ece0
--- /dev/null
+++ b/drivers/phy/phy-exynos4212-usb2.c
@@ -0,0 +1,312 @@
+/*
+ * Samsung S5P/EXYNOS SoC series USB PHY driver - Exynos 4212 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4212_UPHYPWR			0x0
+
+#define EXYNOS_4212_UPHYPWR_DEV_SUSPEND		(1 << 0)
+#define EXYNOS_4212_UPHYPWR_DEV_PWR		(1 << 3)
+#define EXYNOS_4212_UPHYPWR_DEV_OTG_PWR		(1 << 4)
+#define EXYNOS_4212_UPHYPWR_DEV_SLEEP		(1 << 5)
+#define EXYNOS_4212_UPHYPWR_DEV	( \
+	EXYNOS_4212_UPHYPWR_DEV_SUSPEND | \
+	EXYNOS_4212_UPHYPWR_DEV_PWR | \
+	EXYNOS_4212_UPHYPWR_DEV_OTG_PWR | \
+	EXYNOS_4212_UPHYPWR_DEV_SLEEP)
+
+#define EXYNOS_4212_UPHYPWR_HOST_SUSPEND	(1 << 6)
+#define EXYNOS_4212_UPHYPWR_HOST_PWR		(1 << 7)
+#define EXYNOS_4212_UPHYPWR_HOST_SLEEP		(1 << 8)
+#define EXYNOS_4212_UPHYPWR_HOST ( \
+	EXYNOS_4212_UPHYPWR_HOST_SUSPEND | \
+	EXYNOS_4212_UPHYPWR_HOST_PWR | \
+	EXYNOS_4212_UPHYPWR_HOST_SLEEP)
+
+#define EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
+#define EXYNOS_4212_UPHYPWR_HSCI0_PWR		(1 << 10)
+#define EXYNOS_4212_UPHYPWR_HSCI0_SLEEP		(1 << 11)
+#define EXYNOS_4212_UPHYPWR_HSCI0 ( \
+	EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND | \
+	EXYNOS_4212_UPHYPWR_HSCI0_PWR | \
+	EXYNOS_4212_UPHYPWR_HSCI0_SLEEP)
+
+#define EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND	(1 << 12)
+#define EXYNOS_4212_UPHYPWR_HSCI1_PWR		(1 << 13)
+#define EXYNOS_4212_UPHYPWR_HSCI1_SLEEP		(1 << 14)
+#define EXYNOS_4212_UPHYPWR_HSCI1 ( \
+	EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND | \
+	EXYNOS_4212_UPHYPWR_HSCI1_PWR | \
+	EXYNOS_4212_UPHYPWR_HSCI1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4212_UPHYCLK			0x4
+
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_MASK	(0x7 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6	(0x0 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ	(0x1 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2	(0x3 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ	(0x4 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ	(0x5 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ	(0x7 << 0)
+
+#define EXYNOS_4212_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 3)
+#define EXYNOS_4212_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
+#define EXYNOS_4212_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
+
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_MASK	(0x7f << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_12MHZ	(0x24 << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_15MHZ	(0x1c << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_16MHZ	(0x1a << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_19MHZ2	(0x15 << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_20MHZ	(0x14 << 10)
+
+/* PHY reset control */
+#define EXYNOS_4212_UPHYRST			0x8
+
+#define EXYNOS_4212_URSTCON_DEVICE		(1 << 0)
+#define EXYNOS_4212_URSTCON_OTG_HLINK		(1 << 1)
+#define EXYNOS_4212_URSTCON_OTG_PHYLINK		(1 << 2)
+#define EXYNOS_4212_URSTCON_HOST_PHY		(1 << 3)
+#define EXYNOS_4212_URSTCON_PHY1		(1 << 4)
+#define EXYNOS_4212_URSTCON_HSIC0		(1 << 5)
+#define EXYNOS_4212_URSTCON_HSIC1		(1 << 6)
+#define EXYNOS_4212_URSTCON_HOST_LINK_ALL	(1 << 7)
+#define EXYNOS_4212_URSTCON_HOST_LINK_P0	(1 << 8)
+#define EXYNOS_4212_URSTCON_HOST_LINK_P1	(1 << 9)
+#define EXYNOS_4212_URSTCON_HOST_LINK_P2	(1 << 10)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4212_USB_ISOL_OFFSET		0x704
+#define EXYNOS_4212_USB_ISOL_OTG		(1 << 0)
+#define EXYNOS_4212_USB_ISOL_HSIC0_OFFSET	0x708
+#define EXYNOS_4212_USB_ISOL_HSIC0		(1 << 0)
+#define EXYNOS_4212_USB_ISOL_HSIC1_OFFSET	0x70c
+#define EXYNOS_4212_USB_ISOL_HSIC1		(1 << 0)
+
+/* Mode switching SUB Device <-> Host */
+#define EXYNOS_4212_MODE_SWITCH_OFFSET		0x21c
+#define EXYNOS_4212_MODE_SWITCH_MASK		1
+#define EXYNOS_4212_MODE_SWITCH_DEVICE		0
+#define EXYNOS_4212_MODE_SWITCH_HOST		1
+
+enum exynos4x12_phy_id {
+	EXYNOS4212_DEVICE,
+	EXYNOS4212_HOST,
+	EXYNOS4212_HSIC0,
+	EXYNOS4212_HSIC1,
+	EXYNOS4212_NUM_PHYS,
+};
+
+/*
+ * exynos4212_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos4212_rate_to_clk(unsigned long rate, u32 *reg)
+{
+	/* EXYNOS_4212_UPHYCLK_PHYFSEL_MASK */
+
+	switch (rate) {
+	case 9600 * KHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6;
+		break;
+	case 10 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ;
+		break;
+	case 12 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ;
+		break;
+	case 19200 * KHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2;
+		break;
+	case 20 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ;
+		break;
+	case 24 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ;
+		break;
+	case 50 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void exynos4212_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 offset;
+	u32 mask;
+
+	switch (inst->cfg->id) {
+	case EXYNOS4212_DEVICE:
+	case EXYNOS4212_HOST:
+		offset = EXYNOS_4212_USB_ISOL_OFFSET;
+		mask = EXYNOS_4212_USB_ISOL_OTG;
+		break;
+	case EXYNOS4212_HSIC0:
+		offset = EXYNOS_4212_USB_ISOL_HSIC0_OFFSET;
+		mask = EXYNOS_4212_USB_ISOL_HSIC0;
+		break;
+	case EXYNOS4212_HSIC1:
+		offset = EXYNOS_4212_USB_ISOL_HSIC1_OFFSET;
+		mask = EXYNOS_4212_USB_ISOL_HSIC1;
+		break;
+	default:
+		return;
+	};
+
+	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos4212_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 rstbits = 0;
+	u32 phypwr = 0;
+	u32 rst;
+	u32 pwr;
+
+	switch (inst->cfg->id) {
+	case EXYNOS4212_DEVICE:
+		phypwr =	EXYNOS_4212_UPHYPWR_DEV;
+		rstbits =	EXYNOS_4212_URSTCON_DEVICE;
+		break;
+	case EXYNOS4212_HOST:
+		phypwr =	EXYNOS_4212_UPHYPWR_HOST;
+		rstbits =	EXYNOS_4212_URSTCON_HOST_PHY;
+		break;
+	case EXYNOS4212_HSIC0:
+		phypwr =	EXYNOS_4212_UPHYPWR_HSCI0;
+		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
+				EXYNOS_4212_URSTCON_HOST_LINK_P0 |
+				EXYNOS_4212_URSTCON_HOST_PHY;
+		break;
+	case EXYNOS4212_HSIC1:
+		phypwr =	EXYNOS_4212_UPHYPWR_HSCI1;
+		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
+				EXYNOS_4212_URSTCON_HOST_LINK_P1;
+		break;
+	};
+
+	if (on) {
+		writel(inst->clk_reg_val, drv->reg_phy + EXYNOS_4212_UPHYCLK);
+
+		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
+		pwr &= ~phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
+
+		rst = readl(drv->reg_phy + EXYNOS_4212_UPHYRST);
+		rst |= rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
+		udelay(10);
+		rst &= ~rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
+	} else {
+		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
+		pwr |= phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
+	}
+}
+
+static int exynos4212_power_on(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+
+	inst->enabled = 1;
+	exynos4212_phy_pwr(inst, 1);
+	exynos4212_isol(inst, 0);
+
+	/* Power on the device, as it is necessary for HSIC to work */
+	if (inst->cfg->id == EXYNOS4212_HSIC0) {
+		struct samsung_usb2_phy_instance *device =
+					&drv->instances[EXYNOS4212_DEVICE];
+		exynos4212_phy_pwr(device, 1);
+		exynos4212_isol(device, 0);
+	}
+
+	return 0;
+}
+
+static int exynos4212_power_off(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	struct samsung_usb2_phy_instance *device = &drv->instances[EXYNOS4212_DEVICE];
+
+	inst->enabled = 0;
+	exynos4212_isol(inst, 1);
+	exynos4212_phy_pwr(inst, 0);
+
+	if (inst->cfg->id == EXYNOS4212_HSIC0 && !device->enabled) {
+		exynos4212_isol(device, 1);
+		exynos4212_phy_pwr(device, 0);
+	}
+
+	return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos4212_phys[] = {
+	{
+		.label		= "device",
+		.id		= EXYNOS4212_DEVICE,
+		.rate_to_clk	= exynos4212_rate_to_clk,
+		.power_on	= exynos4212_power_on,
+		.power_off	= exynos4212_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS4212_HOST,
+		.rate_to_clk	= exynos4212_rate_to_clk,
+		.power_on	= exynos4212_power_on,
+		.power_off	= exynos4212_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS4212_HSIC0,
+		.rate_to_clk	= exynos4212_rate_to_clk,
+		.power_on	= exynos4212_power_on,
+		.power_off	= exynos4212_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS4212_HSIC1,
+		.rate_to_clk	= exynos4212_rate_to_clk,
+		.power_on	= exynos4212_power_on,
+		.power_off	= exynos4212_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config exynos4212_usb2_phy_config = {
+	.num_phys		= EXYNOS4212_NUM_PHYS,
+	.phys			= exynos4212_phys,
+	.has_mode_switch	= 1,
+};
+
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
new file mode 100644
index 0000000..804ec77
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -0,0 +1,228 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+static int samsung_usb2_phy_power_on(struct phy *phy)
+{
+	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	int ret;
+
+	dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
+							inst->cfg->label);
+	ret = clk_prepare_enable(drv->clk);
+	if (ret)
+		goto err_main_clk;
+	ret = clk_prepare_enable(inst->clk);
+	if (ret)
+		goto err_instance_clk;
+	inst->rate = clk_get_rate(inst->clk);
+	if (inst->cfg->rate_to_clk) {
+		ret = inst->cfg->rate_to_clk(inst->rate, &inst->clk_reg_val);
+		if (ret)
+			goto err_get_rate;
+	}
+	if (inst->cfg->power_on) {
+		spin_lock(&drv->lock);
+		ret = inst->cfg->power_on(inst);
+		spin_unlock(&drv->lock);
+	}
+
+	return 0;
+
+err_get_rate:
+	clk_disable_unprepare(inst->clk);
+err_instance_clk:
+	clk_disable_unprepare(drv->clk);
+err_main_clk:
+	return ret;
+}
+
+static int samsung_usb2_phy_power_off(struct phy *phy)
+{
+	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	int ret = 0;
+
+	dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
+							inst->cfg->label);
+	if (inst->cfg->power_off) {
+		spin_lock(&drv->lock);
+		ret = inst->cfg->power_off(inst);
+		spin_unlock(&drv->lock);
+	}
+	clk_disable_unprepare(inst->clk);
+	clk_disable_unprepare(drv->clk);
+	return ret;
+}
+
+static struct phy_ops samsung_usb2_phy_ops = {
+	.power_on	= samsung_usb2_phy_power_on,
+	.power_off	= samsung_usb2_phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *samsung_usb2_phy_xlate(struct device *dev,
+					struct of_phandle_args *args)
+{
+	struct samsung_usb2_phy_driver *drv;
+
+	drv = dev_get_drvdata(dev);
+	if (!drv)
+		return ERR_PTR(-EINVAL);
+
+	if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
+		return ERR_PTR(-ENODEV);
+
+	return drv->instances[args->args[0]].phy;
+}
+
+static const struct of_device_id samsung_usb2_phy_of_match[] = {
+#ifdef CONFIG_PHY_EXYNOS4210_USB2
+	{
+		.compatible = "samsung,exynos4210-usb2-phy",
+		.data = &exynos4210_usb2_phy_config,
+	},
+#endif
+#ifdef CONFIG_PHY_EXYNOS4212_USB2
+	{
+		.compatible = "samsung,exynos4212-usb2-phy",
+		.data = &exynos4212_usb2_phy_config,
+	},
+#endif
+	{ },
+};
+
+static int samsung_usb2_phy_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+	const struct samsung_usb2_phy_config *cfg;
+	struct clk *clk;
+	struct device *dev = &pdev->dev;
+	struct phy_provider *phy_provider;
+	struct resource *mem;
+	struct samsung_usb2_phy_driver *drv;
+	int i;
+
+	if (!pdev->dev.of_node) {
+		dev_err(dev, "This driver is required to be instantiated from device tree\n");
+		return -EINVAL;
+	}
+
+	match = of_match_node(samsung_usb2_phy_of_match, pdev->dev.of_node);
+	if (!match) {
+		dev_err(dev, "of_match_node() failed\n");
+		return -EINVAL;
+	}
+	cfg = match->data;
+
+	drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
+		cfg->num_phys * sizeof(struct samsung_usb2_phy_instance), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, drv);
+	spin_lock_init(&drv->lock);
+
+	drv->cfg = cfg;
+	drv->dev = dev;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drv->reg_phy = devm_ioremap_resource(dev, mem);
+	if (IS_ERR(drv->reg_phy)) {
+		dev_err(dev, "Failed to map register memory (phy)\n");
+		return PTR_ERR(drv->reg_phy);
+	}
+
+	drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+		"samsung,pmureg-phandle");
+	if (IS_ERR(drv->reg_pmu)) {
+		dev_err(dev, "Failed to map PMU registers (via syscon)\n");
+		return PTR_ERR(drv->reg_pmu);
+	}
+
+	if (drv->cfg->has_mode_switch) {
+		drv->reg_sys = syscon_regmap_lookup_by_phandle(
+				pdev->dev.of_node, "samsung,sysreg-phandle");
+		if (IS_ERR(drv->reg_sys)) {
+			dev_err(dev, "Failed to map system registers (via syscon)\n");
+			return PTR_ERR(drv->reg_sys);
+		}
+	}
+
+	drv->clk = devm_clk_get(dev, "phy");
+	if (IS_ERR(drv->clk)) {
+		dev_err(dev, "Failed to get clock of phy controller\n");
+		return PTR_ERR(drv->clk);
+	}
+
+	for (i = 0; i < drv->cfg->num_phys; i++) {
+		char *label = drv->cfg->phys[i].label;
+		struct samsung_usb2_phy_instance *p = &drv->instances[i];
+
+		dev_dbg(dev, "Creating phy \"%s\"\n", label);
+		p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
+		if (IS_ERR(p->phy)) {
+			dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
+						label);
+			return PTR_ERR(p->phy);
+		}
+
+		p->cfg = &drv->cfg->phys[i];
+		p->drv = drv;
+		phy_set_drvdata(p->phy, p);
+
+		clk = devm_clk_get(dev, p->cfg->label);
+		if (IS_ERR(clk)) {
+			dev_err(dev, "Failed to get clock of \"%s\" phy\n",
+								p->cfg->label);
+			return PTR_ERR(clk);
+		}
+		p->clk = clk;
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev,
+							samsung_usb2_phy_xlate);
+	if (IS_ERR(phy_provider)) {
+		dev_err(drv->dev, "Failed to register phy provider\n");
+		return PTR_ERR(phy_provider);
+	}
+
+	return 0;
+}
+
+static struct platform_driver samsung_usb2_phy_driver = {
+	.probe	= samsung_usb2_phy_probe,
+	.driver = {
+		.of_match_table	= samsung_usb2_phy_of_match,
+		.name		= "samsung-usb2-phy",
+		.owner		= THIS_MODULE,
+	}
+};
+
+module_platform_driver(samsung_usb2_phy_driver);
+MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:samsung-usb2-phy");
+
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
new file mode 100644
index 0000000..cd12477
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -0,0 +1,72 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PHY_EXYNOS_USB2_H
+#define _PHY_EXYNOS_USB2_H
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define KHZ 1000
+#define MHZ (KHZ * KHZ)
+
+struct samsung_usb2_phy_driver;
+struct samsung_usb2_phy_instance;
+struct samsung_usb2_phy_config;
+
+struct samsung_usb2_phy_instance {
+	struct samsung_usb2_phy_driver *drv;
+	struct phy *phy;
+	const struct samsung_usb2_common_phy *cfg;
+	char enabled;
+	struct clk *clk;
+	u32 clk_reg_val;
+	unsigned long rate;
+};
+
+struct samsung_usb2_phy_driver {
+	struct device *dev;
+	spinlock_t lock;
+	void __iomem *reg_phy;
+	struct regmap *reg_sys;
+	struct regmap *reg_pmu;
+	const struct samsung_usb2_phy_config *cfg;
+	struct clk *clk;
+	struct samsung_usb2_phy_instance instances[0];
+};
+
+struct samsung_usb2_common_phy {
+	char *label;
+	unsigned int id;
+	int (*rate_to_clk)(unsigned long, u32 *);
+	int (*power_on)(struct samsung_usb2_phy_instance *);
+	int (*power_off)(struct samsung_usb2_phy_instance *);
+};
+
+
+struct samsung_usb2_phy_config {
+	int num_phys;
+	const struct samsung_usb2_common_phy *phys;
+	char has_mode_switch;
+};
+
+extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
+extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
+#endif
+
-- 
1.7.9.5


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

* [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
@ 2013-12-05 12:29   ` Kamil Debski
  0 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-05 12:29 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, kishon-l0cyMroinI0,
	t.figa-Sze3O3UU22JBDgjK7y7TUQ, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ,
	mat.krawczuk-Re5JQEeQqe8AvxtiuMwx3w,
	yulgon.kim-Sze3O3UU22JBDgjK7y7TUQ,
	p.paneri-Sze3O3UU22JBDgjK7y7TUQ,
	av.tikhomirov-Sze3O3UU22JBDgjK7y7TUQ,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	matt.porter-QSEj5FYQhm4dnm+yROfE0A, Kamil Debski

Add a new driver for the Exynos USB PHY. The new driver uses the generic
PHY framework. The driver includes support for the Exynos 4x10 and 4x12
SoC families.

Signed-off-by: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 .../devicetree/bindings/phy/samsung-usbphy.txt     |   54 ++++
 drivers/phy/Kconfig                                |   20 ++
 drivers/phy/Makefile                               |    3 +
 drivers/phy/phy-exynos4210-usb2.c                  |  264 +++++++++++++++++
 drivers/phy/phy-exynos4212-usb2.c                  |  312 ++++++++++++++++++++
 drivers/phy/phy-samsung-usb2.c                     |  228 ++++++++++++++
 drivers/phy/phy-samsung-usb2.h                     |   72 +++++
 7 files changed, 953 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/samsung-usbphy.txt
 create mode 100644 drivers/phy/phy-exynos4210-usb2.c
 create mode 100644 drivers/phy/phy-exynos4212-usb2.c
 create mode 100644 drivers/phy/phy-samsung-usb2.c
 create mode 100644 drivers/phy/phy-samsung-usb2.h

diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
new file mode 100644
index 0000000..cadbf70
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
@@ -0,0 +1,54 @@
+Samsung S5P/EXYNOS SoC series USB PHY
+-------------------------------------------------
+
+Required properties:
+- compatible : should be one of the listed compatibles:
+	- "samsung,exynos4210-usb2-phy"
+	- "samsung,exynos4212-usb2-phy"
+- reg : a list of registers used by phy driver
+	- first and obligatory is the location of phy modules registers
+- samsung,sysreg-phandle - handle to syscon used to control the system registers
+- samsung,pmureg-phandle - handle to syscon used to control PMU registers
+- #phy-cells : from the generic phy bindings, must be 1;
+- clocks and clock-names:
+	- the "phy" clocks is required by the phy module
+	- next for each of the phys a clock has to be assidned, this clock
+	  will be used to determine clocking frequency for the phys
+	  (the labels are specified in the paragraph below)
+
+The first phandle argument in the PHY specifier identifies the PHY, its
+meaning is compatible dependent. For the currently supported SoCs (Exynos 4210
+and Exynos 4212) it is as follows:
+  0 - USB device ("device"),
+  1 - USB host ("host"),
+  2 - HSIC0 ("hsic0"),
+  3 - HSIC1 ("hsic1"),
+
+Exynos 4210 and Exynos 4212 use mode switching and require that mode switch
+register is supplied.
+
+Example:
+
+For Exynos 4412 (compatible with Exynos 4212):
+
+usbphy: phy@125B0000 {
+	compatible = "samsung,exynos4212-usb2-phy";
+	reg = <0x125B0000 0x100 0x10020704 0x0c 0x1001021c 0x4>;
+	clocks = <&clock 305>, <&clock 2>, <&clock 2>, <&clock 2>,
+							<&clock 2>;
+	clock-names = "phy", "device", "host", "hsic0", "hsic1";
+	status = "okay";
+	#phy-cells = <1>;
+	samsung,sysreg-phandle = <&sys_reg>;
+	samsung,pmureg-phandle = <&pmu_reg>;
+};
+
+Then the PHY can be used in other nodes such as:
+
+phy-consumer@12340000 {
+	phys = <&usbphy 2>;
+	phy-names = "phy";
+};
+
+Refer to DT bindings documentation of particular PHY consumer devices for more
+information about required PHYs and the way of specification.
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index a344f3d..b29018f 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -51,4 +51,24 @@ config PHY_EXYNOS_DP_VIDEO
 	help
 	  Support for Display Port PHY found on Samsung EXYNOS SoCs.
 
+config PHY_SAMSUNG_USB2
+	tristate "Samsung USB 2.0 PHY driver"
+	help
+	  Enable this to support Samsung USB phy helper driver for Samsung SoCs.
+	  This driver provides common interface to interact, for Samsung
+	  USB 2.0 PHY driver.
+
+config PHY_EXYNOS4210_USB2
+	bool "Support for Exynos 4210"
+	depends on PHY_SAMSUNG_USB2
+	depends on CPU_EXYNOS4210
+	help
+	  Enable USB PHY support for Exynos 4210
+
+config PHY_EXYNOS4212_USB2
+	bool "Support for Exynos 4212"
+	depends on PHY_SAMSUNG_USB2
+	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+	help
+	  Enable USB PHY support for Exynos 4212
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index d0caae9..9f4befd 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
+obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/phy-exynos4210-usb2.c
new file mode 100644
index 0000000..a02e5c2
--- /dev/null
+++ b/drivers/phy/phy-exynos4210-usb2.c
@@ -0,0 +1,264 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4210_UPHYPWR			0x0
+
+#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
+#define EXYNOS_4210_UPHYPWR_PHY0_PWR		(1 << 3)
+#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
+#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		(1 << 5)
+#define EXYNOS_4210_UPHYPWR_PHY0	( \
+	EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_PHY0_PWR | \
+	EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
+	EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND	(1 << 6)
+#define EXYNOS_4210_UPHYPWR_PHY1_PWR		(1 << 7)
+#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		(1 << 8)
+#define EXYNOS_4210_UPHYPWR_PHY1 ( \
+	EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_PHY1_PWR | \
+	EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
+#define EXYNOS_4210_UPHYPWR_HSCI0_SLEEP		(1 << 10)
+#define EXYNOS_4210_UPHYPWR_HSCI0 ( \
+	EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_HSCI0_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND	(1 << 11)
+#define EXYNOS_4210_UPHYPWR_HSCI1_SLEEP		(1 << 12)
+#define EXYNOS_4210_UPHYPWR_HSCI1 ( \
+	EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_HSCI1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4210_UPHYCLK			0x4
+
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
+
+#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
+#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
+#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
+
+/* PHY reset control */
+#define EXYNOS_4210_UPHYRST			0x8
+
+#define EXYNOS_4210_URSTCON_PHY0		(1 << 0)
+#define EXYNOS_4210_URSTCON_OTG_HLINK		(1 << 1)
+#define EXYNOS_4210_URSTCON_OTG_PHYLINK		(1 << 2)
+#define EXYNOS_4210_URSTCON_PHY1_ALL		(1 << 3)
+#define EXYNOS_4210_URSTCON_PHY1_P0		(1 << 4)
+#define EXYNOS_4210_URSTCON_PHY1_P1P2		(1 << 5)
+#define EXYNOS_4210_URSTCON_HOST_LINK_ALL	(1 << 6)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P0	(1 << 7)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P1	(1 << 8)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P2	(1 << 9)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
+#define EXYNOS_4210_USB_ISOL_DEVICE		(1 << 0)
+#define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
+#define EXYNOS_4210_USB_ISOL_HOST		(1 << 0)
+
+/* USBYPHY1 Floating prevention */
+#define EXYNOS_4210_UPHY1CON			0x34
+#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION	0x1
+
+/* Mode switching SUB Device <-> Host */
+#define EXYNOS_4210_MODE_SWITCH_OFFSET		0x21c
+#define EXYNOS_4210_MODE_SWITCH_MASK		1
+#define EXYNOS_4210_MODE_SWITCH_DEVICE		0
+#define EXYNOS_4210_MODE_SWITCH_HOST		1
+
+enum exynos4210_phy_id {
+	EXYNOS4210_DEVICE,
+	EXYNOS4210_HOST,
+	EXYNOS4210_HSIC0,
+	EXYNOS4210_HSIC1,
+	EXYNOS4210_NUM_PHYS,
+};
+
+/*
+ * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
+{
+	switch (rate) {
+	case 12 * MHZ:
+		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
+		break;
+	case 24 * MHZ:
+		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
+		break;
+	case 48 * MHZ:
+		reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 offset;
+	u32 mask;
+
+	switch (inst->cfg->id) {
+	case EXYNOS4210_DEVICE:
+		offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
+		mask = EXYNOS_4210_USB_ISOL_DEVICE;
+		break;
+	case EXYNOS4210_HOST:
+		offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
+		mask = EXYNOS_4210_USB_ISOL_HOST;
+		break;
+	default:
+		return;
+	};
+
+	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 rstbits = 0;
+	u32 phypwr = 0;
+	u32 rst;
+	u32 pwr;
+
+	switch (inst->cfg->id) {
+	case EXYNOS4210_DEVICE:
+		phypwr =	EXYNOS_4210_UPHYPWR_PHY0;
+		rstbits =	EXYNOS_4210_URSTCON_PHY0;
+		break;
+	case EXYNOS4210_HOST:
+		phypwr =	EXYNOS_4210_UPHYPWR_PHY1;
+		rstbits =	EXYNOS_4210_URSTCON_PHY1_ALL |
+				EXYNOS_4210_URSTCON_PHY1_P0 |
+				EXYNOS_4210_URSTCON_PHY1_P1P2 |
+				EXYNOS_4210_URSTCON_HOST_LINK_ALL |
+				EXYNOS_4210_URSTCON_HOST_LINK_P0;
+		writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
+		break;
+	case EXYNOS4210_HSIC0:
+		phypwr =	EXYNOS_4210_UPHYPWR_HSCI0;
+		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
+				EXYNOS_4210_URSTCON_HOST_LINK_P1;
+		break;
+	case EXYNOS4210_HSIC1:
+		phypwr =	EXYNOS_4210_UPHYPWR_HSCI1;
+		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
+				EXYNOS_4210_URSTCON_HOST_LINK_P2;
+		break;
+	};
+
+	if (on) {
+		writel(inst->clk_reg_val, drv->reg_phy + EXYNOS_4210_UPHYCLK);
+
+		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
+		pwr &= ~phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
+
+		rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
+		rst |= rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
+		udelay(10);
+		rst &= ~rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
+	} else {
+		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
+		pwr |= phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
+	}
+}
+
+static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
+{
+	/* Order of initialisation is important - first power then isolation */
+	exynos4210_phy_pwr(inst, 1);
+	exynos4210_isol(inst, 0);
+
+	return 0;
+}
+
+static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
+{
+	exynos4210_isol(inst, 1);
+	exynos4210_phy_pwr(inst, 0);
+
+	return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos4210_phys[] = {
+	{
+		.label		= "device",
+		.id		= EXYNOS4210_DEVICE,
+		.rate_to_clk	= exynos4210_rate_to_clk,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS4210_HOST,
+		.rate_to_clk	= exynos4210_rate_to_clk,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS4210_HSIC0,
+		.rate_to_clk	= exynos4210_rate_to_clk,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS4210_HSIC1,
+		.rate_to_clk	= exynos4210_rate_to_clk,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
+	.num_phys		= EXYNOS4210_NUM_PHYS,
+	.phys			= exynos4210_phys,
+	.has_mode_switch	= 1,
+};
+
diff --git a/drivers/phy/phy-exynos4212-usb2.c b/drivers/phy/phy-exynos4212-usb2.c
new file mode 100644
index 0000000..375ece0
--- /dev/null
+++ b/drivers/phy/phy-exynos4212-usb2.c
@@ -0,0 +1,312 @@
+/*
+ * Samsung S5P/EXYNOS SoC series USB PHY driver - Exynos 4212 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4212_UPHYPWR			0x0
+
+#define EXYNOS_4212_UPHYPWR_DEV_SUSPEND		(1 << 0)
+#define EXYNOS_4212_UPHYPWR_DEV_PWR		(1 << 3)
+#define EXYNOS_4212_UPHYPWR_DEV_OTG_PWR		(1 << 4)
+#define EXYNOS_4212_UPHYPWR_DEV_SLEEP		(1 << 5)
+#define EXYNOS_4212_UPHYPWR_DEV	( \
+	EXYNOS_4212_UPHYPWR_DEV_SUSPEND | \
+	EXYNOS_4212_UPHYPWR_DEV_PWR | \
+	EXYNOS_4212_UPHYPWR_DEV_OTG_PWR | \
+	EXYNOS_4212_UPHYPWR_DEV_SLEEP)
+
+#define EXYNOS_4212_UPHYPWR_HOST_SUSPEND	(1 << 6)
+#define EXYNOS_4212_UPHYPWR_HOST_PWR		(1 << 7)
+#define EXYNOS_4212_UPHYPWR_HOST_SLEEP		(1 << 8)
+#define EXYNOS_4212_UPHYPWR_HOST ( \
+	EXYNOS_4212_UPHYPWR_HOST_SUSPEND | \
+	EXYNOS_4212_UPHYPWR_HOST_PWR | \
+	EXYNOS_4212_UPHYPWR_HOST_SLEEP)
+
+#define EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
+#define EXYNOS_4212_UPHYPWR_HSCI0_PWR		(1 << 10)
+#define EXYNOS_4212_UPHYPWR_HSCI0_SLEEP		(1 << 11)
+#define EXYNOS_4212_UPHYPWR_HSCI0 ( \
+	EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND | \
+	EXYNOS_4212_UPHYPWR_HSCI0_PWR | \
+	EXYNOS_4212_UPHYPWR_HSCI0_SLEEP)
+
+#define EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND	(1 << 12)
+#define EXYNOS_4212_UPHYPWR_HSCI1_PWR		(1 << 13)
+#define EXYNOS_4212_UPHYPWR_HSCI1_SLEEP		(1 << 14)
+#define EXYNOS_4212_UPHYPWR_HSCI1 ( \
+	EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND | \
+	EXYNOS_4212_UPHYPWR_HSCI1_PWR | \
+	EXYNOS_4212_UPHYPWR_HSCI1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4212_UPHYCLK			0x4
+
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_MASK	(0x7 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6	(0x0 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ	(0x1 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2	(0x3 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ	(0x4 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ	(0x5 << 0)
+#define EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ	(0x7 << 0)
+
+#define EXYNOS_4212_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 3)
+#define EXYNOS_4212_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
+#define EXYNOS_4212_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
+
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_MASK	(0x7f << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_12MHZ	(0x24 << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_15MHZ	(0x1c << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_16MHZ	(0x1a << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_19MHZ2	(0x15 << 10)
+#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_20MHZ	(0x14 << 10)
+
+/* PHY reset control */
+#define EXYNOS_4212_UPHYRST			0x8
+
+#define EXYNOS_4212_URSTCON_DEVICE		(1 << 0)
+#define EXYNOS_4212_URSTCON_OTG_HLINK		(1 << 1)
+#define EXYNOS_4212_URSTCON_OTG_PHYLINK		(1 << 2)
+#define EXYNOS_4212_URSTCON_HOST_PHY		(1 << 3)
+#define EXYNOS_4212_URSTCON_PHY1		(1 << 4)
+#define EXYNOS_4212_URSTCON_HSIC0		(1 << 5)
+#define EXYNOS_4212_URSTCON_HSIC1		(1 << 6)
+#define EXYNOS_4212_URSTCON_HOST_LINK_ALL	(1 << 7)
+#define EXYNOS_4212_URSTCON_HOST_LINK_P0	(1 << 8)
+#define EXYNOS_4212_URSTCON_HOST_LINK_P1	(1 << 9)
+#define EXYNOS_4212_URSTCON_HOST_LINK_P2	(1 << 10)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4212_USB_ISOL_OFFSET		0x704
+#define EXYNOS_4212_USB_ISOL_OTG		(1 << 0)
+#define EXYNOS_4212_USB_ISOL_HSIC0_OFFSET	0x708
+#define EXYNOS_4212_USB_ISOL_HSIC0		(1 << 0)
+#define EXYNOS_4212_USB_ISOL_HSIC1_OFFSET	0x70c
+#define EXYNOS_4212_USB_ISOL_HSIC1		(1 << 0)
+
+/* Mode switching SUB Device <-> Host */
+#define EXYNOS_4212_MODE_SWITCH_OFFSET		0x21c
+#define EXYNOS_4212_MODE_SWITCH_MASK		1
+#define EXYNOS_4212_MODE_SWITCH_DEVICE		0
+#define EXYNOS_4212_MODE_SWITCH_HOST		1
+
+enum exynos4x12_phy_id {
+	EXYNOS4212_DEVICE,
+	EXYNOS4212_HOST,
+	EXYNOS4212_HSIC0,
+	EXYNOS4212_HSIC1,
+	EXYNOS4212_NUM_PHYS,
+};
+
+/*
+ * exynos4212_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos4212_rate_to_clk(unsigned long rate, u32 *reg)
+{
+	/* EXYNOS_4212_UPHYCLK_PHYFSEL_MASK */
+
+	switch (rate) {
+	case 9600 * KHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6;
+		break;
+	case 10 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ;
+		break;
+	case 12 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ;
+		break;
+	case 19200 * KHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2;
+		break;
+	case 20 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ;
+		break;
+	case 24 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ;
+		break;
+	case 50 * MHZ:
+		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void exynos4212_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 offset;
+	u32 mask;
+
+	switch (inst->cfg->id) {
+	case EXYNOS4212_DEVICE:
+	case EXYNOS4212_HOST:
+		offset = EXYNOS_4212_USB_ISOL_OFFSET;
+		mask = EXYNOS_4212_USB_ISOL_OTG;
+		break;
+	case EXYNOS4212_HSIC0:
+		offset = EXYNOS_4212_USB_ISOL_HSIC0_OFFSET;
+		mask = EXYNOS_4212_USB_ISOL_HSIC0;
+		break;
+	case EXYNOS4212_HSIC1:
+		offset = EXYNOS_4212_USB_ISOL_HSIC1_OFFSET;
+		mask = EXYNOS_4212_USB_ISOL_HSIC1;
+		break;
+	default:
+		return;
+	};
+
+	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos4212_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 rstbits = 0;
+	u32 phypwr = 0;
+	u32 rst;
+	u32 pwr;
+
+	switch (inst->cfg->id) {
+	case EXYNOS4212_DEVICE:
+		phypwr =	EXYNOS_4212_UPHYPWR_DEV;
+		rstbits =	EXYNOS_4212_URSTCON_DEVICE;
+		break;
+	case EXYNOS4212_HOST:
+		phypwr =	EXYNOS_4212_UPHYPWR_HOST;
+		rstbits =	EXYNOS_4212_URSTCON_HOST_PHY;
+		break;
+	case EXYNOS4212_HSIC0:
+		phypwr =	EXYNOS_4212_UPHYPWR_HSCI0;
+		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
+				EXYNOS_4212_URSTCON_HOST_LINK_P0 |
+				EXYNOS_4212_URSTCON_HOST_PHY;
+		break;
+	case EXYNOS4212_HSIC1:
+		phypwr =	EXYNOS_4212_UPHYPWR_HSCI1;
+		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
+				EXYNOS_4212_URSTCON_HOST_LINK_P1;
+		break;
+	};
+
+	if (on) {
+		writel(inst->clk_reg_val, drv->reg_phy + EXYNOS_4212_UPHYCLK);
+
+		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
+		pwr &= ~phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
+
+		rst = readl(drv->reg_phy + EXYNOS_4212_UPHYRST);
+		rst |= rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
+		udelay(10);
+		rst &= ~rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
+	} else {
+		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
+		pwr |= phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
+	}
+}
+
+static int exynos4212_power_on(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+
+	inst->enabled = 1;
+	exynos4212_phy_pwr(inst, 1);
+	exynos4212_isol(inst, 0);
+
+	/* Power on the device, as it is necessary for HSIC to work */
+	if (inst->cfg->id == EXYNOS4212_HSIC0) {
+		struct samsung_usb2_phy_instance *device =
+					&drv->instances[EXYNOS4212_DEVICE];
+		exynos4212_phy_pwr(device, 1);
+		exynos4212_isol(device, 0);
+	}
+
+	return 0;
+}
+
+static int exynos4212_power_off(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	struct samsung_usb2_phy_instance *device = &drv->instances[EXYNOS4212_DEVICE];
+
+	inst->enabled = 0;
+	exynos4212_isol(inst, 1);
+	exynos4212_phy_pwr(inst, 0);
+
+	if (inst->cfg->id == EXYNOS4212_HSIC0 && !device->enabled) {
+		exynos4212_isol(device, 1);
+		exynos4212_phy_pwr(device, 0);
+	}
+
+	return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos4212_phys[] = {
+	{
+		.label		= "device",
+		.id		= EXYNOS4212_DEVICE,
+		.rate_to_clk	= exynos4212_rate_to_clk,
+		.power_on	= exynos4212_power_on,
+		.power_off	= exynos4212_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS4212_HOST,
+		.rate_to_clk	= exynos4212_rate_to_clk,
+		.power_on	= exynos4212_power_on,
+		.power_off	= exynos4212_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS4212_HSIC0,
+		.rate_to_clk	= exynos4212_rate_to_clk,
+		.power_on	= exynos4212_power_on,
+		.power_off	= exynos4212_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS4212_HSIC1,
+		.rate_to_clk	= exynos4212_rate_to_clk,
+		.power_on	= exynos4212_power_on,
+		.power_off	= exynos4212_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config exynos4212_usb2_phy_config = {
+	.num_phys		= EXYNOS4212_NUM_PHYS,
+	.phys			= exynos4212_phys,
+	.has_mode_switch	= 1,
+};
+
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
new file mode 100644
index 0000000..804ec77
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -0,0 +1,228 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+static int samsung_usb2_phy_power_on(struct phy *phy)
+{
+	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	int ret;
+
+	dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
+							inst->cfg->label);
+	ret = clk_prepare_enable(drv->clk);
+	if (ret)
+		goto err_main_clk;
+	ret = clk_prepare_enable(inst->clk);
+	if (ret)
+		goto err_instance_clk;
+	inst->rate = clk_get_rate(inst->clk);
+	if (inst->cfg->rate_to_clk) {
+		ret = inst->cfg->rate_to_clk(inst->rate, &inst->clk_reg_val);
+		if (ret)
+			goto err_get_rate;
+	}
+	if (inst->cfg->power_on) {
+		spin_lock(&drv->lock);
+		ret = inst->cfg->power_on(inst);
+		spin_unlock(&drv->lock);
+	}
+
+	return 0;
+
+err_get_rate:
+	clk_disable_unprepare(inst->clk);
+err_instance_clk:
+	clk_disable_unprepare(drv->clk);
+err_main_clk:
+	return ret;
+}
+
+static int samsung_usb2_phy_power_off(struct phy *phy)
+{
+	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	int ret = 0;
+
+	dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
+							inst->cfg->label);
+	if (inst->cfg->power_off) {
+		spin_lock(&drv->lock);
+		ret = inst->cfg->power_off(inst);
+		spin_unlock(&drv->lock);
+	}
+	clk_disable_unprepare(inst->clk);
+	clk_disable_unprepare(drv->clk);
+	return ret;
+}
+
+static struct phy_ops samsung_usb2_phy_ops = {
+	.power_on	= samsung_usb2_phy_power_on,
+	.power_off	= samsung_usb2_phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *samsung_usb2_phy_xlate(struct device *dev,
+					struct of_phandle_args *args)
+{
+	struct samsung_usb2_phy_driver *drv;
+
+	drv = dev_get_drvdata(dev);
+	if (!drv)
+		return ERR_PTR(-EINVAL);
+
+	if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
+		return ERR_PTR(-ENODEV);
+
+	return drv->instances[args->args[0]].phy;
+}
+
+static const struct of_device_id samsung_usb2_phy_of_match[] = {
+#ifdef CONFIG_PHY_EXYNOS4210_USB2
+	{
+		.compatible = "samsung,exynos4210-usb2-phy",
+		.data = &exynos4210_usb2_phy_config,
+	},
+#endif
+#ifdef CONFIG_PHY_EXYNOS4212_USB2
+	{
+		.compatible = "samsung,exynos4212-usb2-phy",
+		.data = &exynos4212_usb2_phy_config,
+	},
+#endif
+	{ },
+};
+
+static int samsung_usb2_phy_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+	const struct samsung_usb2_phy_config *cfg;
+	struct clk *clk;
+	struct device *dev = &pdev->dev;
+	struct phy_provider *phy_provider;
+	struct resource *mem;
+	struct samsung_usb2_phy_driver *drv;
+	int i;
+
+	if (!pdev->dev.of_node) {
+		dev_err(dev, "This driver is required to be instantiated from device tree\n");
+		return -EINVAL;
+	}
+
+	match = of_match_node(samsung_usb2_phy_of_match, pdev->dev.of_node);
+	if (!match) {
+		dev_err(dev, "of_match_node() failed\n");
+		return -EINVAL;
+	}
+	cfg = match->data;
+
+	drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
+		cfg->num_phys * sizeof(struct samsung_usb2_phy_instance), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, drv);
+	spin_lock_init(&drv->lock);
+
+	drv->cfg = cfg;
+	drv->dev = dev;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	drv->reg_phy = devm_ioremap_resource(dev, mem);
+	if (IS_ERR(drv->reg_phy)) {
+		dev_err(dev, "Failed to map register memory (phy)\n");
+		return PTR_ERR(drv->reg_phy);
+	}
+
+	drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+		"samsung,pmureg-phandle");
+	if (IS_ERR(drv->reg_pmu)) {
+		dev_err(dev, "Failed to map PMU registers (via syscon)\n");
+		return PTR_ERR(drv->reg_pmu);
+	}
+
+	if (drv->cfg->has_mode_switch) {
+		drv->reg_sys = syscon_regmap_lookup_by_phandle(
+				pdev->dev.of_node, "samsung,sysreg-phandle");
+		if (IS_ERR(drv->reg_sys)) {
+			dev_err(dev, "Failed to map system registers (via syscon)\n");
+			return PTR_ERR(drv->reg_sys);
+		}
+	}
+
+	drv->clk = devm_clk_get(dev, "phy");
+	if (IS_ERR(drv->clk)) {
+		dev_err(dev, "Failed to get clock of phy controller\n");
+		return PTR_ERR(drv->clk);
+	}
+
+	for (i = 0; i < drv->cfg->num_phys; i++) {
+		char *label = drv->cfg->phys[i].label;
+		struct samsung_usb2_phy_instance *p = &drv->instances[i];
+
+		dev_dbg(dev, "Creating phy \"%s\"\n", label);
+		p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
+		if (IS_ERR(p->phy)) {
+			dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
+						label);
+			return PTR_ERR(p->phy);
+		}
+
+		p->cfg = &drv->cfg->phys[i];
+		p->drv = drv;
+		phy_set_drvdata(p->phy, p);
+
+		clk = devm_clk_get(dev, p->cfg->label);
+		if (IS_ERR(clk)) {
+			dev_err(dev, "Failed to get clock of \"%s\" phy\n",
+								p->cfg->label);
+			return PTR_ERR(clk);
+		}
+		p->clk = clk;
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev,
+							samsung_usb2_phy_xlate);
+	if (IS_ERR(phy_provider)) {
+		dev_err(drv->dev, "Failed to register phy provider\n");
+		return PTR_ERR(phy_provider);
+	}
+
+	return 0;
+}
+
+static struct platform_driver samsung_usb2_phy_driver = {
+	.probe	= samsung_usb2_phy_probe,
+	.driver = {
+		.of_match_table	= samsung_usb2_phy_of_match,
+		.name		= "samsung-usb2-phy",
+		.owner		= THIS_MODULE,
+	}
+};
+
+module_platform_driver(samsung_usb2_phy_driver);
+MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
+MODULE_AUTHOR("Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:samsung-usb2-phy");
+
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
new file mode 100644
index 0000000..cd12477
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -0,0 +1,72 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _PHY_EXYNOS_USB2_H
+#define _PHY_EXYNOS_USB2_H
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define KHZ 1000
+#define MHZ (KHZ * KHZ)
+
+struct samsung_usb2_phy_driver;
+struct samsung_usb2_phy_instance;
+struct samsung_usb2_phy_config;
+
+struct samsung_usb2_phy_instance {
+	struct samsung_usb2_phy_driver *drv;
+	struct phy *phy;
+	const struct samsung_usb2_common_phy *cfg;
+	char enabled;
+	struct clk *clk;
+	u32 clk_reg_val;
+	unsigned long rate;
+};
+
+struct samsung_usb2_phy_driver {
+	struct device *dev;
+	spinlock_t lock;
+	void __iomem *reg_phy;
+	struct regmap *reg_sys;
+	struct regmap *reg_pmu;
+	const struct samsung_usb2_phy_config *cfg;
+	struct clk *clk;
+	struct samsung_usb2_phy_instance instances[0];
+};
+
+struct samsung_usb2_common_phy {
+	char *label;
+	unsigned int id;
+	int (*rate_to_clk)(unsigned long, u32 *);
+	int (*power_on)(struct samsung_usb2_phy_instance *);
+	int (*power_off)(struct samsung_usb2_phy_instance *);
+};
+
+
+struct samsung_usb2_phy_config {
+	int num_phys;
+	const struct samsung_usb2_common_phy *phys;
+	char has_mode_switch;
+};
+
+extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
+extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
+#endif
+
-- 
1.7.9.5

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

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

* [PATCH v4 4/9] usb: ehci-s5p: Change to use phy provided by the generic phy framework
  2013-12-05 12:29 [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver Kamil Debski
                   ` (2 preceding siblings ...)
  2013-12-05 12:29   ` Kamil Debski
@ 2013-12-05 12:29 ` Kamil Debski
  2013-12-05 18:52     ` Alan Stern
  2013-12-05 12:29 ` [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with " Kamil Debski
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 50+ messages in thread
From: Kamil Debski @ 2013-12-05 12:29 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, Kamil Debski

Change the phy provider used from the old usb phy specific to a new one
using the generic phy framework.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 Documentation/devicetree/bindings/usb/usb-ehci.txt |   35 ++++++++
 drivers/usb/host/ehci-exynos.c                     |   95 +++++++++++++-------
 2 files changed, 97 insertions(+), 33 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
index fa18612..413f7cd 100644
--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
@@ -14,6 +14,10 @@ If controller implementation operates with big endian descriptors,
 If both big endian registers and descriptors are used by the controller
 implementation, "big-endian" property can be specified instead of having
 both "big-endian-regs" and "big-endian-desc".
+  - port: if in the SoC there are EHCI phys, they should be listed here.
+One phy per port. Each port should have its reg entry with a consecutive
+number. Also it should contain phys and phy-names entries specifying the
+phy used by the port.
 
 Example (Sequoia 440EPx):
     ehci@e0000300 {
@@ -23,3 +27,34 @@ Example (Sequoia 440EPx):
 	   reg = <0 e0000300 90 0 e0000390 70>;
 	   big-endian;
    };
+
+Example (Exynos 4212):
+    ehci@12580000 {
+        compatible = "samsung,exynos4210-ehci";
+        reg = <0x12580000 0x20000>;
+        interrupts = <0 70 0>;
+        clocks = <&clock 304>, <&clock 305>;
+        clock-names = "usbhost", "otg";
+        status = "disabled";
+        #address-cells = <1>;
+        #size-cells = <0>;
+        port@0 {
+            reg = <0>;
+            phys = <&usb2phy 1>;
+            phy-names = "host";
+            status = "disabled";
+        };
+        port@1 {
+            reg = <1>;
+            phys = <&usb2phy 2>;
+            phy-names = "hsic0";
+            status = "disabled";
+        };
+        port@2 {
+            reg = <2>;
+            phys = <&usb2phy 3>;
+            phy-names = "hsic1";
+            status = "disabled";
+        };
+    };
+
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index e97c198..bb81809 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -19,12 +19,12 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
+#include <linux/phy/phy.h>
 #include <linux/platform_device.h>
 #include <linux/usb/phy.h>
 #include <linux/usb/samsung_usb_phy.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
-#include <linux/usb/otg.h>
 
 #include "ehci.h"
 
@@ -42,10 +42,10 @@
 static const char hcd_name[] = "ehci-exynos";
 static struct hc_driver __read_mostly exynos_ehci_hc_driver;
 
+#define PHY_NUMBER 3
 struct exynos_ehci_hcd {
 	struct clk *clk;
-	struct usb_phy *phy;
-	struct usb_otg *otg;
+	struct phy *phy[PHY_NUMBER];
 };
 
 #define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv)
@@ -69,13 +69,43 @@ static void exynos_setup_vbus_gpio(struct platform_device *pdev)
 		dev_err(dev, "can't request ehci vbus gpio %d", gpio);
 }
 
+static int exynos_phys_on(struct phy *p[])
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; ret == 0 && i < PHY_NUMBER; i++)
+		if (p[i])
+			ret = phy_power_on(p[i]);
+	if (ret)
+		for (i--; i > 0; i--)
+			if (p[i])
+				phy_power_off(p[i]);
+
+	return ret;
+}
+
+static int exynos_phys_off(struct phy *p[])
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; ret == 0 && i < PHY_NUMBER; i++)
+		if (p[i])
+			ret = phy_power_off(p[i]);
+
+	return ret;
+}
+
 static int exynos_ehci_probe(struct platform_device *pdev)
 {
 	struct exynos_ehci_hcd *exynos_ehci;
 	struct usb_hcd *hcd;
 	struct ehci_hcd *ehci;
 	struct resource *res;
-	struct usb_phy *phy;
+	struct phy *phy;
+	struct device_node *child;
+	int phy_number;
 	int irq;
 	int err;
 
@@ -102,13 +132,24 @@ static int exynos_ehci_probe(struct platform_device *pdev)
 					"samsung,exynos5440-ehci"))
 		goto skip_phy;
 
-	phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
-	if (IS_ERR(phy)) {
-		usb_put_hcd(hcd);
-		dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
-		return -EPROBE_DEFER;
-	} else {
-		exynos_ehci->phy = phy;
+	for_each_available_child_of_node(pdev->dev.of_node, child) {
+		err = of_property_read_u32(child, "reg", &phy_number);
+		if (err) {
+			dev_err(&pdev->dev, "Failed to parse device tree\n");
+			return err;
+		}
+		if (phy_number >= PHY_NUMBER) {
+			dev_err(&pdev->dev, "Failed to parse device tree - number out of range\n");
+			return -EINVAL;
+		}
+		phy = devm_of_phy_get(&pdev->dev, child, 0);
+		of_node_put(child);
+		if (IS_ERR(phy)) {
+			dev_err(&pdev->dev, "Failed to get phy number %d",
+								phy_number);
+			return PTR_ERR(phy);
+		}
+		exynos_ehci->phy[phy_number] = phy;
 		exynos_ehci->otg = phy->otg;
 	}
 
@@ -149,11 +190,11 @@ skip_phy:
 		goto fail_io;
 	}
 
-	if (exynos_ehci->otg)
-		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
-
-	if (exynos_ehci->phy)
-		usb_phy_init(exynos_ehci->phy);
+	err = exynos_phys_on(exynos_ehci->phy);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to enabled phys\n");
+		goto fail_phys_on;
+	}
 
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = hcd->regs;
@@ -172,8 +213,8 @@ skip_phy:
 	return 0;
 
 fail_add_hcd:
-	if (exynos_ehci->phy)
-		usb_phy_shutdown(exynos_ehci->phy);
+	exynos_phys_off(exynos_ehci->phy);
+fail_phys_on:
 fail_io:
 	clk_disable_unprepare(exynos_ehci->clk);
 fail_clk:
@@ -188,11 +229,7 @@ static int exynos_ehci_remove(struct platform_device *pdev)
 
 	usb_remove_hcd(hcd);
 
-	if (exynos_ehci->otg)
-		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
-
-	if (exynos_ehci->phy)
-		usb_phy_shutdown(exynos_ehci->phy);
+	exynos_phys_off(exynos_ehci->phy);
 
 	clk_disable_unprepare(exynos_ehci->clk);
 
@@ -212,11 +249,7 @@ static int exynos_ehci_suspend(struct device *dev)
 
 	rc = ehci_suspend(hcd, do_wakeup);
 
-	if (exynos_ehci->otg)
-		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
-
-	if (exynos_ehci->phy)
-		usb_phy_shutdown(exynos_ehci->phy);
+	exynos_phys_off(exynos_ehci->phy);
 
 	clk_disable_unprepare(exynos_ehci->clk);
 
@@ -230,11 +263,7 @@ static int exynos_ehci_resume(struct device *dev)
 
 	clk_prepare_enable(exynos_ehci->clk);
 
-	if (exynos_ehci->otg)
-		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
-
-	if (exynos_ehci->phy)
-		usb_phy_init(exynos_ehci->phy);
+	exynos_phys_on(exynos_ehci->phy);
 
 	/* DMA burst Enable */
 	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
-- 
1.7.9.5


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

* [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
  2013-12-05 12:29 [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver Kamil Debski
                   ` (3 preceding siblings ...)
  2013-12-05 12:29 ` [PATCH v4 4/9] usb: ehci-s5p: Change to use phy provided by the generic phy framework Kamil Debski
@ 2013-12-05 12:29 ` Kamil Debski
  2013-12-06 11:11     ` Kishon Vijay Abraham I
                     ` (2 more replies)
  2013-12-05 15:07   ` Kishon Vijay Abraham I
                   ` (4 subsequent siblings)
  9 siblings, 3 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-05 12:29 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, Kamil Debski

Change the used phy driver to the new Exynos USB phy driver that uses the
generic phy framework.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
 drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++-----
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
index b83d428..9340d06 100644
--- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
+++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
@@ -24,6 +24,8 @@ Required properties:
     - first entry: must be "otg"
 - vusb_d-supply: phandle to voltage regulator of digital section,
 - vusb_a-supply: phandle to voltage regulator of analog section.
+- phys: from general PHY binding: phandle to the PHY device
+- phy-names: from general PHY binding: should be "usb2-phy"
 
 Example
 -----
@@ -36,5 +38,7 @@ Example
 		clock-names = "otg";
 		vusb_d-supply = <&vusb_reg>;
 		vusb_a-supply = <&vusbdac_reg>;
+		phys = <&usb2phy 0>;
+		phy-names = "device";
 	};
 
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index eccb147..db096fd 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -31,6 +31,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/phy/phy.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -162,7 +163,7 @@ struct s3c_hsotg_ep {
 struct s3c_hsotg {
 	struct device		 *dev;
 	struct usb_gadget_driver *driver;
-	struct usb_phy		*phy;
+	struct phy		 *phy;
 	struct s3c_hsotg_plat	 *plat;
 
 	spinlock_t              lock;
@@ -2905,7 +2906,7 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
 	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
 
 	if (hsotg->phy)
-		usb_phy_init(hsotg->phy);
+		phy_power_on(hsotg->phy);
 	else if (hsotg->plat->phy_init)
 		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
 }
@@ -2922,7 +2923,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
 	struct platform_device *pdev = to_platform_device(hsotg->dev);
 
 	if (hsotg->phy)
-		usb_phy_shutdown(hsotg->phy);
+		phy_power_off(hsotg->phy);
 	else if (hsotg->plat->phy_exit)
 		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
 }
@@ -3529,7 +3530,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
 static int s3c_hsotg_probe(struct platform_device *pdev)
 {
 	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
-	struct usb_phy *phy;
+	struct phy *phy;
 	struct device *dev = &pdev->dev;
 	struct s3c_hsotg_ep *eps;
 	struct s3c_hsotg *hsotg;
@@ -3544,7 +3545,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+	phy = devm_phy_get(&pdev->dev, "usb2-phy");
 	if (IS_ERR(phy)) {
 		/* Fallback for pdata */
 		plat = dev_get_platdata(&pdev->dev);
-- 
1.7.9.5


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

* Re: [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver
  2013-12-05 12:29 [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver Kamil Debski
@ 2013-12-05 15:07   ` Kishon Vijay Abraham I
  2013-12-05 12:29 ` [PATCH 2/9] phy: core: Add devm_of_phy_get to phy-core Kamil Debski
                     ` (8 subsequent siblings)
  9 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-05 15:07 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

Hi,

On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> Hi,
> 
> This is the fourth version of the patchset adding the new Exynos USB 2.0 PHY
> driver. The driver uses the Generic PHY Framework.
> 
> A month has passed since the last version. I have addressed numerous comments
> that appeared on the mailing list in this patch. I would like to specially
> thank Kishon, Tomasz, Matt and Vivek for their comments.
> 
> This patch contains two necessary patches to the phy core.
> It is very useful to be able to get phy using a device tree node.
> 
> In addition this patch depends on:
> [PATCH V11 1/3] ARM: dts: Add pmu sysreg node to exynos5250 and exynos5420 dtsi
> files [1].
> 
> Best wishes,
> Kamil Debski

The last four patches are missing [1]

[1] -> https://lkml.org/lkml/2013/12/5/166

Thanks
Kishon
> 
> [1] - http://www.spinics.net/lists/linux-samsung-soc/msg24528.html
> 
> ----------------
> Changes from v3:
> - using PMU and system registers indirectly via syscon
> - change labelling
> - change Kconfig name
> - fixed typos/stray whitespace
> - move of_phy_provider_register() to the end of probe
> - add a regular error return code to the rate_to_clk functions
> - cleanup code and remove unused code
> - change struct names to avoid collisions
> - add mechanism to support multiple phys by the ehci driver
> 
> ----------------
> Changes from v2:
> - rebase all patches to the usb-next branch
> - fixes in the documentation file
>   - remove wrong entries in the phy node (ranges, and #address- & #size-cells)
>   - add clocks and clock-names as required properites
>   - rephrase a few sentences
> - fixes in the ehci-exynos.c file
>   - move phy_name variable next to phy in exynos_ehci_hcd
>   - remove otg from exynos_ehci_hcd as it was no longer used
>   - move devm_phy_get after the Exynos5440 skip_phy check
> - fixes in the s3c-hsotg.c file
>   - cosmetic fixes (remove empty line that was wrongfully added)
> - fixes in the main driver
>   - remove cpu_type in favour for a boolean flag matched with the compatible
>     value
>   - rename files, structures, variables and Kconfig entires - change from simple
>     "uphy" to "usb2_phy"
>   - fix multiline comments style
>   - simplify #ifdefs in of_device_id
>   - fix Kconfig description
>   - change dev_info to dev_dbg where reasonable
>   - cosmetic changes (remove wrongful blank lines)
>   - remove unnecessary reference counting
> 
> ----------------
> Changes from v1:
> - the changes include minor fixes of the hardware initialization of the PHY
>   module
> - some other minor fixes were introduced
> 
> ----------------------
> Original cover letter:
> 
> Hi,
> 
> This patch adds a new drive for USB PHYs for Samsung SoCs. The driver is
> using the Generic PHY Framework created by Kishon Vijay Abrahan I. It
> can be found here https://lkml.org/lkml/2013/8/21/29. This patch adds
> support to Exynos4 family of SoCs. Support for Exynos3 and Exynos5 is
> planned to be added in the near future.
> 
> I welcome your comments.
> 
> ----------------------
> 
> [1] https://lkml.org/lkml/2013/8/21/29
> 
> 
> Kamil Debski (8):
>   phy: core: Change the way of_phy_get is called
>   phy: core: Add devm_of_phy_get to phy-core
>   phy: Add new Exynos USB PHY driver
>   usb: ehci-s5p: Change to use phy provided by the generic phy
>     framework
>   usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic
>     phy framework
>   phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver
>   dts: Add usb2phy to Exynos 4
>   dts: Add usb2phy to Exynos 5250
> 
> Mateusz Krawczuk (1):
>   phy: Add support for S5PV210 to the Exynos USB PHY driver
> 
>  .../devicetree/bindings/arm/samsung/pmu.txt        |    2 +
>  .../devicetree/bindings/phy/samsung-usbphy.txt     |   56 +++
>  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 +
>  Documentation/devicetree/bindings/usb/usb-ehci.txt |   35 ++
>  arch/arm/boot/dts/exynos4.dtsi                     |   31 ++
>  arch/arm/boot/dts/exynos4210.dtsi                  |   17 +
>  arch/arm/boot/dts/exynos4x12.dtsi                  |   17 +
>  arch/arm/boot/dts/exynos5250.dtsi                  |   33 +-
>  drivers/phy/Kconfig                                |   35 ++
>  drivers/phy/Makefile                               |    5 +
>  drivers/phy/phy-core.c                             |   43 ++-
>  drivers/phy/phy-exynos4210-usb2.c                  |  264 ++++++++++++++
>  drivers/phy/phy-exynos4212-usb2.c                  |  312 +++++++++++++++++
>  drivers/phy/phy-exynos5250-usb2.c                  |  363 ++++++++++++++++++++
>  drivers/phy/phy-s5pv210-usb2.c                     |  206 +++++++++++
>  drivers/phy/phy-samsung-usb2.c                     |  240 +++++++++++++
>  drivers/phy/phy-samsung-usb2.h                     |   74 ++++
>  drivers/usb/gadget/s3c-hsotg.c                     |   11 +-
>  drivers/usb/host/ehci-exynos.c                     |   95 +++--
>  include/linux/phy/phy.h                            |    3 +
>  20 files changed, 1789 insertions(+), 57 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/phy/samsung-usbphy.txt
>  create mode 100644 drivers/phy/phy-exynos4210-usb2.c
>  create mode 100644 drivers/phy/phy-exynos4212-usb2.c
>  create mode 100644 drivers/phy/phy-exynos5250-usb2.c
>  create mode 100644 drivers/phy/phy-s5pv210-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.h
> 


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

* Re: [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver
@ 2013-12-05 15:07   ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-05 15:07 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

Hi,

On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> Hi,
> 
> This is the fourth version of the patchset adding the new Exynos USB 2.0 PHY
> driver. The driver uses the Generic PHY Framework.
> 
> A month has passed since the last version. I have addressed numerous comments
> that appeared on the mailing list in this patch. I would like to specially
> thank Kishon, Tomasz, Matt and Vivek for their comments.
> 
> This patch contains two necessary patches to the phy core.
> It is very useful to be able to get phy using a device tree node.
> 
> In addition this patch depends on:
> [PATCH V11 1/3] ARM: dts: Add pmu sysreg node to exynos5250 and exynos5420 dtsi
> files [1].
> 
> Best wishes,
> Kamil Debski

The last four patches are missing [1]

[1] -> https://lkml.org/lkml/2013/12/5/166

Thanks
Kishon
> 
> [1] - http://www.spinics.net/lists/linux-samsung-soc/msg24528.html
> 
> ----------------
> Changes from v3:
> - using PMU and system registers indirectly via syscon
> - change labelling
> - change Kconfig name
> - fixed typos/stray whitespace
> - move of_phy_provider_register() to the end of probe
> - add a regular error return code to the rate_to_clk functions
> - cleanup code and remove unused code
> - change struct names to avoid collisions
> - add mechanism to support multiple phys by the ehci driver
> 
> ----------------
> Changes from v2:
> - rebase all patches to the usb-next branch
> - fixes in the documentation file
>   - remove wrong entries in the phy node (ranges, and #address- & #size-cells)
>   - add clocks and clock-names as required properites
>   - rephrase a few sentences
> - fixes in the ehci-exynos.c file
>   - move phy_name variable next to phy in exynos_ehci_hcd
>   - remove otg from exynos_ehci_hcd as it was no longer used
>   - move devm_phy_get after the Exynos5440 skip_phy check
> - fixes in the s3c-hsotg.c file
>   - cosmetic fixes (remove empty line that was wrongfully added)
> - fixes in the main driver
>   - remove cpu_type in favour for a boolean flag matched with the compatible
>     value
>   - rename files, structures, variables and Kconfig entires - change from simple
>     "uphy" to "usb2_phy"
>   - fix multiline comments style
>   - simplify #ifdefs in of_device_id
>   - fix Kconfig description
>   - change dev_info to dev_dbg where reasonable
>   - cosmetic changes (remove wrongful blank lines)
>   - remove unnecessary reference counting
> 
> ----------------
> Changes from v1:
> - the changes include minor fixes of the hardware initialization of the PHY
>   module
> - some other minor fixes were introduced
> 
> ----------------------
> Original cover letter:
> 
> Hi,
> 
> This patch adds a new drive for USB PHYs for Samsung SoCs. The driver is
> using the Generic PHY Framework created by Kishon Vijay Abrahan I. It
> can be found here https://lkml.org/lkml/2013/8/21/29. This patch adds
> support to Exynos4 family of SoCs. Support for Exynos3 and Exynos5 is
> planned to be added in the near future.
> 
> I welcome your comments.
> 
> ----------------------
> 
> [1] https://lkml.org/lkml/2013/8/21/29
> 
> 
> Kamil Debski (8):
>   phy: core: Change the way of_phy_get is called
>   phy: core: Add devm_of_phy_get to phy-core
>   phy: Add new Exynos USB PHY driver
>   usb: ehci-s5p: Change to use phy provided by the generic phy
>     framework
>   usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic
>     phy framework
>   phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver
>   dts: Add usb2phy to Exynos 4
>   dts: Add usb2phy to Exynos 5250
> 
> Mateusz Krawczuk (1):
>   phy: Add support for S5PV210 to the Exynos USB PHY driver
> 
>  .../devicetree/bindings/arm/samsung/pmu.txt        |    2 +
>  .../devicetree/bindings/phy/samsung-usbphy.txt     |   56 +++
>  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 +
>  Documentation/devicetree/bindings/usb/usb-ehci.txt |   35 ++
>  arch/arm/boot/dts/exynos4.dtsi                     |   31 ++
>  arch/arm/boot/dts/exynos4210.dtsi                  |   17 +
>  arch/arm/boot/dts/exynos4x12.dtsi                  |   17 +
>  arch/arm/boot/dts/exynos5250.dtsi                  |   33 +-
>  drivers/phy/Kconfig                                |   35 ++
>  drivers/phy/Makefile                               |    5 +
>  drivers/phy/phy-core.c                             |   43 ++-
>  drivers/phy/phy-exynos4210-usb2.c                  |  264 ++++++++++++++
>  drivers/phy/phy-exynos4212-usb2.c                  |  312 +++++++++++++++++
>  drivers/phy/phy-exynos5250-usb2.c                  |  363 ++++++++++++++++++++
>  drivers/phy/phy-s5pv210-usb2.c                     |  206 +++++++++++
>  drivers/phy/phy-samsung-usb2.c                     |  240 +++++++++++++
>  drivers/phy/phy-samsung-usb2.h                     |   74 ++++
>  drivers/usb/gadget/s3c-hsotg.c                     |   11 +-
>  drivers/usb/host/ehci-exynos.c                     |   95 +++--
>  include/linux/phy/phy.h                            |    3 +
>  20 files changed, 1789 insertions(+), 57 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/phy/samsung-usbphy.txt
>  create mode 100644 drivers/phy/phy-exynos4210-usb2.c
>  create mode 100644 drivers/phy/phy-exynos4212-usb2.c
>  create mode 100644 drivers/phy/phy-exynos5250-usb2.c
>  create mode 100644 drivers/phy/phy-s5pv210-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.h
> 

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

* Re: [PATCH v4 4/9] usb: ehci-s5p: Change to use phy provided by the generic phy framework
  2013-12-05 12:29 ` [PATCH v4 4/9] usb: ehci-s5p: Change to use phy provided by the generic phy framework Kamil Debski
@ 2013-12-05 18:52     ` Alan Stern
  0 siblings, 0 replies; 50+ messages in thread
From: Alan Stern @ 2013-12-05 18:52 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

On Thu, 5 Dec 2013, Kamil Debski wrote:

> Change the phy provider used from the old usb phy specific to a new one
> using the generic phy framework.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

> --- a/drivers/usb/host/ehci-exynos.c
> +++ b/drivers/usb/host/ehci-exynos.c

> @@ -42,10 +42,10 @@
>  static const char hcd_name[] = "ehci-exynos";
>  static struct hc_driver __read_mostly exynos_ehci_hc_driver;
>  
> +#define PHY_NUMBER 3
>  struct exynos_ehci_hcd {
>  	struct clk *clk;
> -	struct usb_phy *phy;
> -	struct usb_otg *otg;

Are you sure you want to remove that line?

> +	struct phy *phy[PHY_NUMBER];
>  };
>  
>  #define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv)

> @@ -102,13 +132,24 @@ static int exynos_ehci_probe(struct platform_device *pdev)
>  					"samsung,exynos5440-ehci"))
>  		goto skip_phy;
>  
> -	phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
> -	if (IS_ERR(phy)) {
> -		usb_put_hcd(hcd);
> -		dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
> -		return -EPROBE_DEFER;
> -	} else {
> -		exynos_ehci->phy = phy;
> +	for_each_available_child_of_node(pdev->dev.of_node, child) {
> +		err = of_property_read_u32(child, "reg", &phy_number);
> +		if (err) {
> +			dev_err(&pdev->dev, "Failed to parse device tree\n");
> +			return err;
> +		}
> +		if (phy_number >= PHY_NUMBER) {
> +			dev_err(&pdev->dev, "Failed to parse device tree - number out of range\n");
> +			return -EINVAL;

Do you need to call of_node_put(child) before each of these return 
statements?

> +		}
> +		phy = devm_of_phy_get(&pdev->dev, child, 0);
> +		of_node_put(child);
> +		if (IS_ERR(phy)) {
> +			dev_err(&pdev->dev, "Failed to get phy number %d",
> +								phy_number);
> +			return PTR_ERR(phy);
> +		}
> +		exynos_ehci->phy[phy_number] = phy;
>  		exynos_ehci->otg = phy->otg;

Did you intend to remove this line?  Above, you removed the
exynos_ehci->otg field.  I can't see how this patch would ever compile
without an error.

>  	}
>  
> @@ -149,11 +190,11 @@ skip_phy:
>  		goto fail_io;
>  	}
>  
> -	if (exynos_ehci->otg)
> -		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
> -
> -	if (exynos_ehci->phy)
> -		usb_phy_init(exynos_ehci->phy);
> +	err = exynos_phys_on(exynos_ehci->phy);
> +	if (err) {
> +		dev_err(&pdev->dev, "Failed to enabled phys\n");
> +		goto fail_phys_on;

Why add a new statement label?  Just goto fail_io.

> +	}
>  
>  	ehci = hcd_to_ehci(hcd);
>  	ehci->caps = hcd->regs;
> @@ -172,8 +213,8 @@ skip_phy:
>  	return 0;
>  
>  fail_add_hcd:
> -	if (exynos_ehci->phy)
> -		usb_phy_shutdown(exynos_ehci->phy);
> +	exynos_phys_off(exynos_ehci->phy);
> +fail_phys_on:
>  fail_io:
>  	clk_disable_unprepare(exynos_ehci->clk);
>  fail_clk:

Alan Stern


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

* Re: [PATCH v4 4/9] usb: ehci-s5p: Change to use phy provided by the generic phy framework
@ 2013-12-05 18:52     ` Alan Stern
  0 siblings, 0 replies; 50+ messages in thread
From: Alan Stern @ 2013-12-05 18:52 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

On Thu, 5 Dec 2013, Kamil Debski wrote:

> Change the phy provider used from the old usb phy specific to a new one
> using the generic phy framework.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>

> --- a/drivers/usb/host/ehci-exynos.c
> +++ b/drivers/usb/host/ehci-exynos.c

> @@ -42,10 +42,10 @@
>  static const char hcd_name[] = "ehci-exynos";
>  static struct hc_driver __read_mostly exynos_ehci_hc_driver;
>  
> +#define PHY_NUMBER 3
>  struct exynos_ehci_hcd {
>  	struct clk *clk;
> -	struct usb_phy *phy;
> -	struct usb_otg *otg;

Are you sure you want to remove that line?

> +	struct phy *phy[PHY_NUMBER];
>  };
>  
>  #define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv)

> @@ -102,13 +132,24 @@ static int exynos_ehci_probe(struct platform_device *pdev)
>  					"samsung,exynos5440-ehci"))
>  		goto skip_phy;
>  
> -	phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
> -	if (IS_ERR(phy)) {
> -		usb_put_hcd(hcd);
> -		dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
> -		return -EPROBE_DEFER;
> -	} else {
> -		exynos_ehci->phy = phy;
> +	for_each_available_child_of_node(pdev->dev.of_node, child) {
> +		err = of_property_read_u32(child, "reg", &phy_number);
> +		if (err) {
> +			dev_err(&pdev->dev, "Failed to parse device tree\n");
> +			return err;
> +		}
> +		if (phy_number >= PHY_NUMBER) {
> +			dev_err(&pdev->dev, "Failed to parse device tree - number out of range\n");
> +			return -EINVAL;

Do you need to call of_node_put(child) before each of these return 
statements?

> +		}
> +		phy = devm_of_phy_get(&pdev->dev, child, 0);
> +		of_node_put(child);
> +		if (IS_ERR(phy)) {
> +			dev_err(&pdev->dev, "Failed to get phy number %d",
> +								phy_number);
> +			return PTR_ERR(phy);
> +		}
> +		exynos_ehci->phy[phy_number] = phy;
>  		exynos_ehci->otg = phy->otg;

Did you intend to remove this line?  Above, you removed the
exynos_ehci->otg field.  I can't see how this patch would ever compile
without an error.

>  	}
>  
> @@ -149,11 +190,11 @@ skip_phy:
>  		goto fail_io;
>  	}
>  
> -	if (exynos_ehci->otg)
> -		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
> -
> -	if (exynos_ehci->phy)
> -		usb_phy_init(exynos_ehci->phy);
> +	err = exynos_phys_on(exynos_ehci->phy);
> +	if (err) {
> +		dev_err(&pdev->dev, "Failed to enabled phys\n");
> +		goto fail_phys_on;

Why add a new statement label?  Just goto fail_io.

> +	}
>  
>  	ehci = hcd_to_ehci(hcd);
>  	ehci->caps = hcd->regs;
> @@ -172,8 +213,8 @@ skip_phy:
>  	return 0;
>  
>  fail_add_hcd:
> -	if (exynos_ehci->phy)
> -		usb_phy_shutdown(exynos_ehci->phy);
> +	exynos_phys_off(exynos_ehci->phy);
> +fail_phys_on:
>  fail_io:
>  	clk_disable_unprepare(exynos_ehci->clk);
>  fail_clk:

Alan Stern

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

* Re: [PATCH 1/9] phy: core: Change the way of_phy_get is called
@ 2013-12-06  5:30     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06  5:30 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

Hi,

On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> Previously the of_phy_get function took a struct device * and
> was declared static. It was impossible to call it from
> another driver and thus it was impossible to get phy defined

It was never intended to be called from other drivers. What's up with the
wrapper of of_phy_get, phy_get()/devm_phy_get()? Why isn't that enough?

Thanks
Kishon
> for a given node.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  drivers/phy/phy-core.c  |   12 +++++-------
>  include/linux/phy/phy.h |    1 +
>  2 files changed, 6 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
> index 03cf8fb..7fb3474 100644
> --- a/drivers/phy/phy-core.c
> +++ b/drivers/phy/phy-core.c
> @@ -250,20 +250,17 @@ EXPORT_SYMBOL_GPL(phy_power_off);
>   * not yet loaded. This function uses of_xlate call back function provided
>   * while registering the phy_provider to find the phy instance.
>   */
> -static struct phy *of_phy_get(struct device *dev, int index)
> +struct phy *of_phy_get(struct device_node *np, int index)
>  {
>  	int ret;
>  	struct phy_provider *phy_provider;
>  	struct phy *phy = NULL;
>  	struct of_phandle_args args;
>  
> -	ret = of_parse_phandle_with_args(dev->of_node, "phys", "#phy-cells",
> +	ret = of_parse_phandle_with_args(np, "phys", "#phy-cells",
>  		index, &args);
> -	if (ret) {
> -		dev_dbg(dev, "failed to get phy in %s node\n",
> -			dev->of_node->full_name);
> +	if (ret)
>  		return ERR_PTR(-ENODEV);
> -	}
>  
>  	mutex_lock(&phy_provider_mutex);
>  	phy_provider = of_phy_provider_lookup(args.np);
> @@ -281,6 +278,7 @@ err0:
>  
>  	return phy;
>  }
> +EXPORT_SYMBOL_GPL(of_phy_get);
>  
>  /**
>   * phy_put() - release the PHY
> @@ -370,7 +368,7 @@ struct phy *phy_get(struct device *dev, const char *string)
>  	if (dev->of_node) {
>  		index = of_property_match_string(dev->of_node, "phy-names",
>  			string);
> -		phy = of_phy_get(dev, index);
> +		phy = of_phy_get(dev->of_node, index);
>  		if (IS_ERR(phy)) {
>  			dev_err(dev, "unable to find phy\n");
>  			return phy;
> diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
> index 6d72269..169f572 100644
> --- a/include/linux/phy/phy.h
> +++ b/include/linux/phy/phy.h
> @@ -131,6 +131,7 @@ struct phy *phy_get(struct device *dev, const char *string);
>  struct phy *devm_phy_get(struct device *dev, const char *string);
>  void phy_put(struct phy *phy);
>  void devm_phy_put(struct device *dev, struct phy *phy);
> +struct phy *of_phy_get(struct device_node *np, int index);
>  struct phy *of_phy_simple_xlate(struct device *dev,
>  	struct of_phandle_args *args);
>  struct phy *phy_create(struct device *dev, const struct phy_ops *ops,
> 


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

* Re: [PATCH 1/9] phy: core: Change the way of_phy_get is called
@ 2013-12-06  5:30     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06  5:30 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	t.figa-Sze3O3UU22JBDgjK7y7TUQ, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ,
	mat.krawczuk-Re5JQEeQqe8AvxtiuMwx3w,
	yulgon.kim-Sze3O3UU22JBDgjK7y7TUQ,
	p.paneri-Sze3O3UU22JBDgjK7y7TUQ,
	av.tikhomirov-Sze3O3UU22JBDgjK7y7TUQ,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	matt.porter-QSEj5FYQhm4dnm+yROfE0A

Hi,

On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> Previously the of_phy_get function took a struct device * and
> was declared static. It was impossible to call it from
> another driver and thus it was impossible to get phy defined

It was never intended to be called from other drivers. What's up with the
wrapper of of_phy_get, phy_get()/devm_phy_get()? Why isn't that enough?

Thanks
Kishon
> for a given node.
> 
> Signed-off-by: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/phy/phy-core.c  |   12 +++++-------
>  include/linux/phy/phy.h |    1 +
>  2 files changed, 6 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
> index 03cf8fb..7fb3474 100644
> --- a/drivers/phy/phy-core.c
> +++ b/drivers/phy/phy-core.c
> @@ -250,20 +250,17 @@ EXPORT_SYMBOL_GPL(phy_power_off);
>   * not yet loaded. This function uses of_xlate call back function provided
>   * while registering the phy_provider to find the phy instance.
>   */
> -static struct phy *of_phy_get(struct device *dev, int index)
> +struct phy *of_phy_get(struct device_node *np, int index)
>  {
>  	int ret;
>  	struct phy_provider *phy_provider;
>  	struct phy *phy = NULL;
>  	struct of_phandle_args args;
>  
> -	ret = of_parse_phandle_with_args(dev->of_node, "phys", "#phy-cells",
> +	ret = of_parse_phandle_with_args(np, "phys", "#phy-cells",
>  		index, &args);
> -	if (ret) {
> -		dev_dbg(dev, "failed to get phy in %s node\n",
> -			dev->of_node->full_name);
> +	if (ret)
>  		return ERR_PTR(-ENODEV);
> -	}
>  
>  	mutex_lock(&phy_provider_mutex);
>  	phy_provider = of_phy_provider_lookup(args.np);
> @@ -281,6 +278,7 @@ err0:
>  
>  	return phy;
>  }
> +EXPORT_SYMBOL_GPL(of_phy_get);
>  
>  /**
>   * phy_put() - release the PHY
> @@ -370,7 +368,7 @@ struct phy *phy_get(struct device *dev, const char *string)
>  	if (dev->of_node) {
>  		index = of_property_match_string(dev->of_node, "phy-names",
>  			string);
> -		phy = of_phy_get(dev, index);
> +		phy = of_phy_get(dev->of_node, index);
>  		if (IS_ERR(phy)) {
>  			dev_err(dev, "unable to find phy\n");
>  			return phy;
> diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
> index 6d72269..169f572 100644
> --- a/include/linux/phy/phy.h
> +++ b/include/linux/phy/phy.h
> @@ -131,6 +131,7 @@ struct phy *phy_get(struct device *dev, const char *string);
>  struct phy *devm_phy_get(struct device *dev, const char *string);
>  void phy_put(struct phy *phy);
>  void devm_phy_put(struct device *dev, struct phy *phy);
> +struct phy *of_phy_get(struct device_node *np, int index);
>  struct phy *of_phy_simple_xlate(struct device *dev,
>  	struct of_phandle_args *args);
>  struct phy *phy_create(struct device *dev, const struct phy_ops *ops,
> 

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

* [PATCH v4 6/9] phy: Add support for S5PV210 to the Exynos USB PHY driver
  2013-12-05 12:29 [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver Kamil Debski
                   ` (5 preceding siblings ...)
  2013-12-05 15:07   ` Kishon Vijay Abraham I
@ 2013-12-06 10:31 ` Kamil Debski
  2013-12-06 11:14     ` Kishon Vijay Abraham I
  2013-12-06 10:32   ` Kamil Debski
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 10:31 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, k.debski

From: Mateusz Krawczuk <mat.krawczuk@gmail.com>

Add support for the Samsung's S5PV210 SoC to the Exynos USB PHY driver.

Signed-off-by: Mateusz Krawczuk <m.krawczuk@partner.samsung.com>
[k.debski@samsung.com: cleanup and commit description]
[k.debski@samsung.com: make changes accordingly to the mailing list
comments]
Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 .../devicetree/bindings/phy/samsung-usbphy.txt     |    1 +
 drivers/phy/Kconfig                                |    7 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-s5pv210-usb2.c                     |  206 ++++++++++++++++++++
 drivers/phy/phy-samsung-usb2.c                     |    6 +
 drivers/phy/phy-samsung-usb2.h                     |    1 +
 6 files changed, 222 insertions(+)
 create mode 100644 drivers/phy/phy-s5pv210-usb2.c

diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
index cadbf70..77a8e9c 100644
--- a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
@@ -3,6 +3,7 @@ Samsung S5P/EXYNOS SoC series USB PHY
 
 Required properties:
 - compatible : should be one of the listed compatibles:
+	- "samsung,s5pv210-usb2-phy"
 	- "samsung,exynos4210-usb2-phy"
 	- "samsung,exynos4212-usb2-phy"
 - reg : a list of registers used by phy driver
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index b29018f..2e433cd 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -58,6 +58,13 @@ config PHY_SAMSUNG_USB2
 	  This driver provides common interface to interact, for Samsung
 	  USB 2.0 PHY driver.
 
+config PHY_S5PV210_USB2
+	bool "Support for S5PV210"
+	depends on PHY_SAMSUNG_USB2
+	depends on ARCH_S5PV210
+	help
+	  Enable USB PHY support for S5PV210
+
 config PHY_EXYNOS4210_USB2
 	bool "Support for Exynos 4210"
 	depends on PHY_SAMSUNG_USB2
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 9f4befd..fefc6c2 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -8,5 +8,6 @@ obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
 obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
+obj-$(CONFIG_PHY_S5PV210_USB2)		+= phy-s5pv210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
diff --git a/drivers/phy/phy-s5pv210-usb2.c b/drivers/phy/phy-s5pv210-usb2.c
new file mode 100644
index 0000000..528a114
--- /dev/null
+++ b/drivers/phy/phy-s5pv210-usb2.c
@@ -0,0 +1,206 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - S5PV210 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Authors: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define S5PV210_UPHYPWR			0x0
+
+#define S5PV210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
+#define S5PV210_UPHYPWR_PHY0_PWR		(1 << 3)
+#define S5PV210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
+#define S5PV210_UPHYPWR_PHY0	( \
+	S5PV210_UPHYPWR_PHY0_SUSPEND | \
+	S5PV210_UPHYPWR_PHY0_PWR | \
+	S5PV210_UPHYPWR_PHY0_OTG_PWR)
+
+#define S5PV210_UPHYPWR_PHY1_SUSPEND	(1 << 6)
+#define S5PV210_UPHYPWR_PHY1_PWR		(1 << 7)
+#define S5PV210_UPHYPWR_PHY1 ( \
+	S5PV210_UPHYPWR_PHY1_SUSPEND | \
+	S5PV210_UPHYPWR_PHY1_PWR)
+
+/* PHY clock control */
+#define S5PV210_UPHYCLK			0x4
+
+#define S5PV210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
+#define S5PV210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
+#define S5PV210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
+#define S5PV210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
+
+#define S5PV210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
+#define S5PV210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
+#define S5PV210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
+
+/* PHY reset control */
+#define S5PV210_UPHYRST			0x8
+
+#define S5PV210_URSTCON_PHY0		(1 << 0)
+#define S5PV210_URSTCON_OTG_HLINK		(1 << 1)
+#define S5PV210_URSTCON_OTG_PHYLINK		(1 << 2)
+#define S5PV210_URSTCON_PHY1_ALL		(1 << 3)
+#define S5PV210_URSTCON_HOST_LINK_ALL	(1 << 4)
+
+/* Isolation, configured in the power management unit */
+#define S5PV210_USB_ISOL_DEVICE_OFFSET	0x704
+#define S5PV210_USB_ISOL_DEVICE		(1 << 0)
+#define S5PV210_USB_ISOL_HOST_OFFSET	0x708
+#define S5PV210_USB_ISOL_HOST		(1 << 1)
+
+
+enum s5pv210_phy_id {
+	S5PV210_DEVICE,
+	S5PV210_HOST,
+	S5PV210_NUM_PHYS,
+};
+
+/*
+ * s5pv210_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int s5pv210_rate_to_clk(unsigned long rate, u32 *reg)
+{
+	pr_info("%lu\n", rate);
+	switch (rate) {
+	case 12 * MHZ:
+		*reg = S5PV210_UPHYCLK_PHYFSEL_12MHZ;
+		break;
+	case 24 * MHZ:
+		*reg = S5PV210_UPHYCLK_PHYFSEL_24MHZ;
+		break;
+	case 48 * MHZ:
+		*reg = S5PV210_UPHYCLK_PHYFSEL_48MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+}
+
+static void s5pv210_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 mask;
+	u32 tmp;
+
+	if (!drv->reg_isol)
+		return;
+
+	switch (inst->cfg->id) {
+	case S5PV210_DEVICE:
+		mask = S5PV210_USB_ISOL_DEVICE;
+		break;
+	case S5PV210_HOST:
+		mask = S5PV210_USB_ISOL_HOST;
+		break;
+	default:
+		return;
+	};
+
+	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 rstbits = 0;
+	u32 phypwr = 0;
+	u32 rst;
+	u32 pwr;
+
+	switch (inst->cfg->id) {
+	case S5PV210_DEVICE:
+		phypwr =	S5PV210_UPHYPWR_PHY0;
+		rstbits =	S5PV210_URSTCON_PHY0;
+		break;
+	case S5PV210_HOST:
+		phypwr =	S5PV210_UPHYPWR_PHY1;
+		rstbits =	S5PV210_URSTCON_PHY1_ALL |
+				S5PV210_URSTCON_HOST_LINK_ALL;
+		break;
+	};
+
+	if (on) {
+		writel(inst->clk, drv->reg_phy + S5PV210_UPHYCLK);
+
+		pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
+		pwr &= ~phypwr;
+		writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
+
+		rst = readl(drv->reg_phy + S5PV210_UPHYRST);
+		rst |= rstbits;
+		writel(rst, drv->reg_phy + S5PV210_UPHYRST);
+		udelay(10);
+		rst &= ~rstbits;
+		writel(rst, drv->reg_phy + S5PV210_UPHYRST);
+	} else {
+		pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
+		pwr |= phypwr;
+		writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
+	}
+}
+
+static int s5pv210_power_on(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+
+	s5pv210_isol(inst, 0);
+	s5pv210_phy_pwr(inst, 1);
+
+	return 0;
+}
+
+static int s5pv210_power_off(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+
+	s5pv210_phy_pwr(inst, 0);
+	s5pv210_isol(inst, 1);
+
+	return 0;
+}
+
+
+static const struct samsung_usb2_common_phy s5pv210_phys[] = {
+	{
+		.label		= "device",
+		.id		= S5PV210_DEVICE,
+		.rate_to_clk	= s5pv210_rate_to_clk,
+		.power_on	= s5pv210_power_on,
+		.power_off	= s5pv210_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= S5PV210_HOST,
+		.rate_to_clk	= s5pv210_rate_to_clk,
+		.power_on	= s5pv210_power_on,
+		.power_off	= s5pv210_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config s5pv210_usb2_phy_config = {
+	.cpu		= TYPE_S5PV210,
+	.num_phys	= S5PV210_NUM_PHYS,
+	.phys		= s5pv210_phys,
+};
+
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
index 804ec77..ef93fd3 100644
--- a/drivers/phy/phy-samsung-usb2.c
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -98,6 +98,12 @@ static struct phy *samsung_usb2_phy_xlate(struct device *dev,
 }
 
 static const struct of_device_id samsung_usb2_phy_of_match[] = {
+#ifdef CONFIG_PHY_S5PV210_USB2
+	{
+		.compatible = "samsung,s5pv210-usb2-phy",
+		.data = &s5pv210_usb2_phy_config,
+	},
+#endif
 #ifdef CONFIG_PHY_EXYNOS4210_USB2
 	{
 		.compatible = "samsung,exynos4210-usb2-phy",
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
index cd12477..0f51dbb 100644
--- a/drivers/phy/phy-samsung-usb2.h
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -66,6 +66,7 @@ struct samsung_usb2_phy_config {
 	char has_mode_switch;
 };
 
+extern const struct samsung_usb2_phy_config s5pv210_usb2_phy_config;
 extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
 extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
 #endif
-- 
1.7.9.5


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

* [PATCH v4 7/9] phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver
@ 2013-12-06 10:32   ` Kamil Debski
  0 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 10:32 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, k.debski

Add support for Exynos 5250. This driver is to replace the old
USB 2.0 PHY driver.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 .../devicetree/bindings/phy/samsung-usbphy.txt     |    1 +
 drivers/phy/Kconfig                                |    8 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-exynos5250-usb2.c                  |  363 ++++++++++++++++++++
 drivers/phy/phy-samsung-usb2.c                     |    6 +
 drivers/phy/phy-samsung-usb2.h                     |    1 +
 6 files changed, 380 insertions(+)
 create mode 100644 drivers/phy/phy-exynos5250-usb2.c

diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
index 77a8e9c..94096fc 100644
--- a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
@@ -6,6 +6,7 @@ Required properties:
 	- "samsung,s5pv210-usb2-phy"
 	- "samsung,exynos4210-usb2-phy"
 	- "samsung,exynos4212-usb2-phy"
+	- "samsung,exynos5250-usb2-phy"
 - reg : a list of registers used by phy driver
 	- first and obligatory is the location of phy modules registers
 - samsung,sysreg-phandle - handle to syscon used to control the system registers
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 2e433cd..74e9064 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -78,4 +78,12 @@ config PHY_EXYNOS4212_USB2
 	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
 	help
 	  Enable USB PHY support for Exynos 4212
+
+config PHY_EXYNOS5250_USB2
+	bool "Support for Exynos 5250"
+	depends on PHY_SAMSUNG_USB2
+	depends on SOC_EXYNOS5250
+	help
+	  Enable USB PHY support for Exynos 5250
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index fefc6c2..33c3ac1 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
 obj-$(CONFIG_PHY_S5PV210_USB2)		+= phy-s5pv210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
+obj-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/phy-exynos5250-usb2.c
new file mode 100644
index 0000000..7aeebc8
--- /dev/null
+++ b/drivers/phy/phy-exynos5250-usb2.c
@@ -0,0 +1,363 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+#define EXYNOS_5250_REFCLKSEL_CRYSTAL	0x0
+#define EXYNOS_5250_REFCLKSEL_XO	0x1
+#define EXYNOS_5250_REFCLKSEL_CLKCORE	0x2
+
+#define EXYNOS_5250_FSEL_9MHZ6		0x0
+#define EXYNOS_5250_FSEL_10MHZ		0x1
+#define EXYNOS_5250_FSEL_12MHZ		0x2
+#define EXYNOS_5250_FSEL_19MHZ2		0x3
+#define EXYNOS_5250_FSEL_20MHZ		0x4
+#define EXYNOS_5250_FSEL_24MHZ		0x5
+#define EXYNOS_5250_FSEL_50MHZ		0x7
+
+/* Normal host */
+#define EXYNOS_5250_HOSTPHYCTRL0			0x0
+
+#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL		(0x1 << 31)
+#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT	19
+#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_MASK	\
+		(0x3 << EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT)
+#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT		16
+#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK \
+		(0x7 << EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT)
+#define EXYNOS_5250_HOSTPHYCTRL0_TESTBURNIN		(0x1 << 11)
+#define EXYNOS_5250_HOSTPHYCTRL0_RETENABLE		(0x1 << 10)
+#define EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N		(0x1 << 9)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_MASK		(0x3 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_DUAL		(0x0 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ID0		(0x1 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ANALOGTEST	(0x2 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_SIDDQ			(0x1 << 6)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP		(0x1 << 5)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND		(0x1 << 4)
+#define EXYNOS_5250_HOSTPHYCTRL0_WORDINTERFACE		(0x1 << 3)
+#define EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST		(0x1 << 2)
+#define EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST		(0x1 << 1)
+#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST		(0x1 << 0)
+
+/* HSIC0 & HSCI1 */
+#define EXYNOS_5250_HOSTPHYCTRL1			0x10
+#define EXYNOS_5250_HOSTPHYCTRL2			0x20
+
+#define EXYNOS_5250_HOSTPHYCTRLX_REFCLKSEL_MASK		(0x3 << 23)
+#define EXYNOS_5250_HOSTPHYCTRLX_REFCLKDIV_MASK		(0x7f << 16)
+#define EXYNOS_5250_HOSTPHYCTRLX_SIDDQ			(0x1 << 6)
+#define EXYNOS_5250_HOSTPHYCTRLX_FORCESLEEP		(0x1 << 5)
+#define EXYNOS_5250_HOSTPHYCTRLX_FORCESUSPEND		(0x1 << 4)
+#define EXYNOS_5250_HOSTPHYCTRLX_WORDINTERFACE		(0x1 << 3)
+#define EXYNOS_5250_HOSTPHYCTRLX_UTMISWRST		(0x1 << 2)
+#define EXYNOS_5250_HOSTPHYCTRLX_PHYSWRST		(0x1 << 0)
+
+/* EHCI control */
+#define EXYNOS_5250_HOSTEHCICTRL			0x30
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN		(0x1 << 29)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR4		(0x1 << 28)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR8		(0x1 << 27)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR16		(0x1 << 26)
+#define EXYNOS_5250_HOSTEHCICTRL_AUTOPPDONOVRCUREN	(0x1 << 25)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT	19
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK	\
+		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT	13
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_MASK	\
+		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL2_SHIFT	7
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK	\
+		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT	1
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_MASK \
+		(0x1 << EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_SIMULATIONMODE		(0x1 << 0)
+
+/* OHCI control */
+#define EXYNOS_5250_HOSTOHCICTRL                        0x34
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT	1
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_MASK \
+		(0x3ff << EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT)
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVALEN		(0x1 << 0)
+
+/* USBOTG */
+#define EXYNOS_5250_USBOTGSYS				0x38
+#define EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET		(0x1 << 14)
+#define EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG		(0x1 << 13)
+#define EXYNOS_5250_USBOTGSYS_PHY_SW_RST		(0x1 << 12)
+#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT		9
+#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK \
+		(0x3 << EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT)
+#define EXYNOS_5250_USBOTGSYS_ID_PULLUP			(0x1 << 8)
+#define EXYNOS_5250_USBOTGSYS_COMMON_ON			(0x1 << 7)
+#define EXYNOS_5250_USBOTGSYS_FSEL_SHIFT		4
+#define EXYNOS_5250_USBOTGSYS_FSEL_MASK \
+		(0x3 << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT)
+#define EXYNOS_5250_USBOTGSYS_FORCE_SLEEP		(0x1 << 3)
+#define EXYNOS_5250_USBOTGSYS_OTGDISABLE		(0x1 << 2)
+#define EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG		(0x1 << 1)
+#define EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND		(0x1 << 0)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_5250_USB_ISOL_OTG_OFFSET		0x704
+#define EXYNOS_5250_USB_ISOL_OTG		(1 << 0)
+#define EXYNOS_5250_USB_ISOL_HOST_OFFSET	0x708
+#define EXYNOS_5250_USB_ISOL_HOST		(1 << 0)
+
+/* Mode swtich register */
+#define EXYNOS_5250_MODE_SWITCH_OFFSET		0x230
+#define EXYNOS_5250_MODE_SWITCH_MASK		1
+#define EXYNOS_5250_MODE_SWITCH_DEVICE		0
+#define EXYNOS_5250_MODE_SWITCH_HOST		1
+
+enum exynos4x12_phy_id {
+	EXYNOS5250_DEVICE,
+	EXYNOS5250_HOST,
+	EXYNOS5250_HSIC0,
+	EXYNOS5250_HSIC1,
+	EXYNOS5250_NUM_PHYS,
+};
+
+/*
+ * exynos5250_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos5250_rate_to_clk(unsigned long rate, u32 *reg)
+{
+	/* EXYNOS_5250_FSEL_MASK */
+
+	switch (rate) {
+	case 9600 * KHZ:
+		*reg = EXYNOS_5250_FSEL_9MHZ6;
+		break;
+	case 10 * MHZ:
+		*reg = EXYNOS_5250_FSEL_10MHZ;
+		break;
+	case 12 * MHZ:
+		*reg = EXYNOS_5250_FSEL_12MHZ;
+		break;
+	case 19200 * KHZ:
+		*reg = EXYNOS_5250_FSEL_19MHZ2;
+		break;
+	case 20 * MHZ:
+		*reg = EXYNOS_5250_FSEL_20MHZ;
+		break;
+	case 24 * MHZ:
+		*reg = EXYNOS_5250_FSEL_24MHZ;
+		break;
+	case 50 * MHZ:
+		*reg = EXYNOS_5250_FSEL_50MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 offset;
+	u32 mask;
+
+	switch (inst->cfg->id) {
+	case EXYNOS5250_DEVICE:
+		offset = EXYNOS_5250_USB_ISOL_OTG_OFFSET;
+		mask = EXYNOS_5250_USB_ISOL_OTG;
+		break;
+	case EXYNOS5250_HOST:
+		offset = EXYNOS_5250_USB_ISOL_HOST_OFFSET;
+		mask = EXYNOS_5250_USB_ISOL_HOST;
+		break;
+	default:
+		return;
+	};
+
+	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos5250_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 ctrl0;
+	u32 otg;
+	u32 ehci;
+	u32 ohci;
+
+	switch (inst->cfg->id) {
+	case EXYNOS5250_DEVICE:
+		regmap_update_bits(drv->reg_sys,
+			EXYNOS_5250_MODE_SWITCH_OFFSET,
+			EXYNOS_5250_MODE_SWITCH_MASK,
+			EXYNOS_5250_MODE_SWITCH_DEVICE);
+
+		/* OTG configuration */
+		otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		/* The clock */
+		otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
+		otg |= inst->clk_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
+		/* Reset */
+		otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+			EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
+			EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
+		otg |=	EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+			EXYNOS_5250_USBOTGSYS_OTGDISABLE;
+		/* Ref clock */
+		otg &=	~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
+		otg |=  EXYNOS_5250_REFCLKSEL_CLKCORE <<
+					EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
+		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		udelay(100);
+		otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+			EXYNOS_5250_USBOTGSYS_OTGDISABLE);
+		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+
+
+		break;
+	case EXYNOS5250_HOST:
+		/* Host registers configuration */
+		ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+		/* The clock */
+		ctrl0 &= ~EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK;
+		ctrl0 |= inst->clk_reg_val <<
+					EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT;
+
+		/* Reset */
+		ctrl0 &=	~(EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
+				EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL |
+				EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
+				EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
+				EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP);
+		ctrl0 |=	EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
+				EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST |
+				EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N;
+		writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+		udelay(10);
+		ctrl0 &=	~(EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
+				EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST);
+		writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+
+		/* OTG configuration */
+		otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		/* The clock */
+		otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
+		otg |= inst->clk_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
+		/* Reset */
+		otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+			EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
+			EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
+		otg |=	EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+			EXYNOS_5250_USBOTGSYS_OTGDISABLE;
+		/* Ref clock */
+		otg &=	~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
+		otg |=  EXYNOS_5250_REFCLKSEL_CLKCORE <<
+					EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
+		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		udelay(10);
+		otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET);
+
+		/* Enable EHCI DMA burst */
+		ehci = readl(drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
+		ehci |=	EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN |
+			EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 |
+			EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 |
+			EXYNOS_5250_HOSTEHCICTRL_ENAINCR16;
+		writel(ehci, drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
+
+		/* OHCI settings */
+		ohci = readl(drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
+		/* Following code is based on the old driver */
+		ohci |=	0x1 << 3;
+		writel(ohci, drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
+
+		break;
+	}
+}
+
+static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst)
+{
+	inst->enabled = 1;
+	exynos5250_phy_pwr(inst, 1);
+	exynos5250_isol(inst, 0);
+
+	return 0;
+}
+
+static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst)
+{
+	inst->enabled = 0;
+	exynos5250_isol(inst, 1);
+	exynos5250_phy_pwr(inst, 0);
+
+	return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos5250_phys[] = {
+	{
+		.label		= "device",
+		.id		= EXYNOS5250_DEVICE,
+		.rate_to_clk	= exynos5250_rate_to_clk,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS5250_HOST,
+		.rate_to_clk	= exynos5250_rate_to_clk,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS5250_HSIC0,
+		.rate_to_clk	= exynos5250_rate_to_clk,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS5250_HSIC1,
+		.rate_to_clk	= exynos5250_rate_to_clk,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
+	.num_phys		= EXYNOS5250_NUM_PHYS,
+	.phys			= exynos5250_phys,
+	.has_mode_switch	= 1,
+};
+
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
index ef93fd3..d62e847 100644
--- a/drivers/phy/phy-samsung-usb2.c
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -116,6 +116,12 @@ static const struct of_device_id samsung_usb2_phy_of_match[] = {
 		.data = &exynos4212_usb2_phy_config,
 	},
 #endif
+#ifdef CONFIG_PHY_EXYNOS5250_USB2
+	{
+		.compatible = "samsung,exynos5250-usb2-phy",
+		.data = &exynos5250_usb2_phy_config,
+	},
+#endif
 	{ },
 };
 
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
index 0f51dbb..0049e8a 100644
--- a/drivers/phy/phy-samsung-usb2.h
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -69,5 +69,6 @@ struct samsung_usb2_phy_config {
 extern const struct samsung_usb2_phy_config s5pv210_usb2_phy_config;
 extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
 extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
+extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config;
 #endif
 
-- 
1.7.9.5


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

* [PATCH v4 7/9] phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver
@ 2013-12-06 10:32   ` Kamil Debski
  0 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 10:32 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, kishon-l0cyMroinI0,
	t.figa-Sze3O3UU22JBDgjK7y7TUQ, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ,
	mat.krawczuk-Re5JQEeQqe8AvxtiuMwx3w,
	yulgon.kim-Sze3O3UU22JBDgjK7y7TUQ,
	p.paneri-Sze3O3UU22JBDgjK7y7TUQ,
	av.tikhomirov-Sze3O3UU22JBDgjK7y7TUQ,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	matt.porter-QSEj5FYQhm4dnm+yROfE0A,
	k.debski-Sze3O3UU22JBDgjK7y7TUQ

Add support for Exynos 5250. This driver is to replace the old
USB 2.0 PHY driver.

Signed-off-by: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 .../devicetree/bindings/phy/samsung-usbphy.txt     |    1 +
 drivers/phy/Kconfig                                |    8 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-exynos5250-usb2.c                  |  363 ++++++++++++++++++++
 drivers/phy/phy-samsung-usb2.c                     |    6 +
 drivers/phy/phy-samsung-usb2.h                     |    1 +
 6 files changed, 380 insertions(+)
 create mode 100644 drivers/phy/phy-exynos5250-usb2.c

diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
index 77a8e9c..94096fc 100644
--- a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
@@ -6,6 +6,7 @@ Required properties:
 	- "samsung,s5pv210-usb2-phy"
 	- "samsung,exynos4210-usb2-phy"
 	- "samsung,exynos4212-usb2-phy"
+	- "samsung,exynos5250-usb2-phy"
 - reg : a list of registers used by phy driver
 	- first and obligatory is the location of phy modules registers
 - samsung,sysreg-phandle - handle to syscon used to control the system registers
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 2e433cd..74e9064 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -78,4 +78,12 @@ config PHY_EXYNOS4212_USB2
 	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
 	help
 	  Enable USB PHY support for Exynos 4212
+
+config PHY_EXYNOS5250_USB2
+	bool "Support for Exynos 5250"
+	depends on PHY_SAMSUNG_USB2
+	depends on SOC_EXYNOS5250
+	help
+	  Enable USB PHY support for Exynos 5250
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index fefc6c2..33c3ac1 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
 obj-$(CONFIG_PHY_S5PV210_USB2)		+= phy-s5pv210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
+obj-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/phy-exynos5250-usb2.c
new file mode 100644
index 0000000..7aeebc8
--- /dev/null
+++ b/drivers/phy/phy-exynos5250-usb2.c
@@ -0,0 +1,363 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 support
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+#define EXYNOS_5250_REFCLKSEL_CRYSTAL	0x0
+#define EXYNOS_5250_REFCLKSEL_XO	0x1
+#define EXYNOS_5250_REFCLKSEL_CLKCORE	0x2
+
+#define EXYNOS_5250_FSEL_9MHZ6		0x0
+#define EXYNOS_5250_FSEL_10MHZ		0x1
+#define EXYNOS_5250_FSEL_12MHZ		0x2
+#define EXYNOS_5250_FSEL_19MHZ2		0x3
+#define EXYNOS_5250_FSEL_20MHZ		0x4
+#define EXYNOS_5250_FSEL_24MHZ		0x5
+#define EXYNOS_5250_FSEL_50MHZ		0x7
+
+/* Normal host */
+#define EXYNOS_5250_HOSTPHYCTRL0			0x0
+
+#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL		(0x1 << 31)
+#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT	19
+#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_MASK	\
+		(0x3 << EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT)
+#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT		16
+#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK \
+		(0x7 << EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT)
+#define EXYNOS_5250_HOSTPHYCTRL0_TESTBURNIN		(0x1 << 11)
+#define EXYNOS_5250_HOSTPHYCTRL0_RETENABLE		(0x1 << 10)
+#define EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N		(0x1 << 9)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_MASK		(0x3 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_DUAL		(0x0 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ID0		(0x1 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ANALOGTEST	(0x2 << 7)
+#define EXYNOS_5250_HOSTPHYCTRL0_SIDDQ			(0x1 << 6)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP		(0x1 << 5)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND		(0x1 << 4)
+#define EXYNOS_5250_HOSTPHYCTRL0_WORDINTERFACE		(0x1 << 3)
+#define EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST		(0x1 << 2)
+#define EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST		(0x1 << 1)
+#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST		(0x1 << 0)
+
+/* HSIC0 & HSCI1 */
+#define EXYNOS_5250_HOSTPHYCTRL1			0x10
+#define EXYNOS_5250_HOSTPHYCTRL2			0x20
+
+#define EXYNOS_5250_HOSTPHYCTRLX_REFCLKSEL_MASK		(0x3 << 23)
+#define EXYNOS_5250_HOSTPHYCTRLX_REFCLKDIV_MASK		(0x7f << 16)
+#define EXYNOS_5250_HOSTPHYCTRLX_SIDDQ			(0x1 << 6)
+#define EXYNOS_5250_HOSTPHYCTRLX_FORCESLEEP		(0x1 << 5)
+#define EXYNOS_5250_HOSTPHYCTRLX_FORCESUSPEND		(0x1 << 4)
+#define EXYNOS_5250_HOSTPHYCTRLX_WORDINTERFACE		(0x1 << 3)
+#define EXYNOS_5250_HOSTPHYCTRLX_UTMISWRST		(0x1 << 2)
+#define EXYNOS_5250_HOSTPHYCTRLX_PHYSWRST		(0x1 << 0)
+
+/* EHCI control */
+#define EXYNOS_5250_HOSTEHCICTRL			0x30
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN		(0x1 << 29)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR4		(0x1 << 28)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR8		(0x1 << 27)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR16		(0x1 << 26)
+#define EXYNOS_5250_HOSTEHCICTRL_AUTOPPDONOVRCUREN	(0x1 << 25)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT	19
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK	\
+		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT	13
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_MASK	\
+		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL2_SHIFT	7
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK	\
+		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT	1
+#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_MASK \
+		(0x1 << EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT)
+#define EXYNOS_5250_HOSTEHCICTRL_SIMULATIONMODE		(0x1 << 0)
+
+/* OHCI control */
+#define EXYNOS_5250_HOSTOHCICTRL                        0x34
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT	1
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_MASK \
+		(0x3ff << EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT)
+#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVALEN		(0x1 << 0)
+
+/* USBOTG */
+#define EXYNOS_5250_USBOTGSYS				0x38
+#define EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET		(0x1 << 14)
+#define EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG		(0x1 << 13)
+#define EXYNOS_5250_USBOTGSYS_PHY_SW_RST		(0x1 << 12)
+#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT		9
+#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK \
+		(0x3 << EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT)
+#define EXYNOS_5250_USBOTGSYS_ID_PULLUP			(0x1 << 8)
+#define EXYNOS_5250_USBOTGSYS_COMMON_ON			(0x1 << 7)
+#define EXYNOS_5250_USBOTGSYS_FSEL_SHIFT		4
+#define EXYNOS_5250_USBOTGSYS_FSEL_MASK \
+		(0x3 << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT)
+#define EXYNOS_5250_USBOTGSYS_FORCE_SLEEP		(0x1 << 3)
+#define EXYNOS_5250_USBOTGSYS_OTGDISABLE		(0x1 << 2)
+#define EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG		(0x1 << 1)
+#define EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND		(0x1 << 0)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_5250_USB_ISOL_OTG_OFFSET		0x704
+#define EXYNOS_5250_USB_ISOL_OTG		(1 << 0)
+#define EXYNOS_5250_USB_ISOL_HOST_OFFSET	0x708
+#define EXYNOS_5250_USB_ISOL_HOST		(1 << 0)
+
+/* Mode swtich register */
+#define EXYNOS_5250_MODE_SWITCH_OFFSET		0x230
+#define EXYNOS_5250_MODE_SWITCH_MASK		1
+#define EXYNOS_5250_MODE_SWITCH_DEVICE		0
+#define EXYNOS_5250_MODE_SWITCH_HOST		1
+
+enum exynos4x12_phy_id {
+	EXYNOS5250_DEVICE,
+	EXYNOS5250_HOST,
+	EXYNOS5250_HSIC0,
+	EXYNOS5250_HSIC1,
+	EXYNOS5250_NUM_PHYS,
+};
+
+/*
+ * exynos5250_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos5250_rate_to_clk(unsigned long rate, u32 *reg)
+{
+	/* EXYNOS_5250_FSEL_MASK */
+
+	switch (rate) {
+	case 9600 * KHZ:
+		*reg = EXYNOS_5250_FSEL_9MHZ6;
+		break;
+	case 10 * MHZ:
+		*reg = EXYNOS_5250_FSEL_10MHZ;
+		break;
+	case 12 * MHZ:
+		*reg = EXYNOS_5250_FSEL_12MHZ;
+		break;
+	case 19200 * KHZ:
+		*reg = EXYNOS_5250_FSEL_19MHZ2;
+		break;
+	case 20 * MHZ:
+		*reg = EXYNOS_5250_FSEL_20MHZ;
+		break;
+	case 24 * MHZ:
+		*reg = EXYNOS_5250_FSEL_24MHZ;
+		break;
+	case 50 * MHZ:
+		*reg = EXYNOS_5250_FSEL_50MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 offset;
+	u32 mask;
+
+	switch (inst->cfg->id) {
+	case EXYNOS5250_DEVICE:
+		offset = EXYNOS_5250_USB_ISOL_OTG_OFFSET;
+		mask = EXYNOS_5250_USB_ISOL_OTG;
+		break;
+	case EXYNOS5250_HOST:
+		offset = EXYNOS_5250_USB_ISOL_HOST_OFFSET;
+		mask = EXYNOS_5250_USB_ISOL_HOST;
+		break;
+	default:
+		return;
+	};
+
+	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos5250_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 ctrl0;
+	u32 otg;
+	u32 ehci;
+	u32 ohci;
+
+	switch (inst->cfg->id) {
+	case EXYNOS5250_DEVICE:
+		regmap_update_bits(drv->reg_sys,
+			EXYNOS_5250_MODE_SWITCH_OFFSET,
+			EXYNOS_5250_MODE_SWITCH_MASK,
+			EXYNOS_5250_MODE_SWITCH_DEVICE);
+
+		/* OTG configuration */
+		otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		/* The clock */
+		otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
+		otg |= inst->clk_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
+		/* Reset */
+		otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+			EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
+			EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
+		otg |=	EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+			EXYNOS_5250_USBOTGSYS_OTGDISABLE;
+		/* Ref clock */
+		otg &=	~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
+		otg |=  EXYNOS_5250_REFCLKSEL_CLKCORE <<
+					EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
+		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		udelay(100);
+		otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+			EXYNOS_5250_USBOTGSYS_OTGDISABLE);
+		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+
+
+		break;
+	case EXYNOS5250_HOST:
+		/* Host registers configuration */
+		ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+		/* The clock */
+		ctrl0 &= ~EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK;
+		ctrl0 |= inst->clk_reg_val <<
+					EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT;
+
+		/* Reset */
+		ctrl0 &=	~(EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
+				EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL |
+				EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
+				EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
+				EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP);
+		ctrl0 |=	EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
+				EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST |
+				EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N;
+		writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+		udelay(10);
+		ctrl0 &=	~(EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
+				EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST);
+		writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+
+		/* OTG configuration */
+		otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		/* The clock */
+		otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
+		otg |= inst->clk_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
+		/* Reset */
+		otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+			EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
+			EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
+		otg |=	EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
+			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+			EXYNOS_5250_USBOTGSYS_OTGDISABLE;
+		/* Ref clock */
+		otg &=	~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
+		otg |=  EXYNOS_5250_REFCLKSEL_CLKCORE <<
+					EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
+		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		udelay(10);
+		otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
+			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
+			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET);
+
+		/* Enable EHCI DMA burst */
+		ehci = readl(drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
+		ehci |=	EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN |
+			EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 |
+			EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 |
+			EXYNOS_5250_HOSTEHCICTRL_ENAINCR16;
+		writel(ehci, drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
+
+		/* OHCI settings */
+		ohci = readl(drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
+		/* Following code is based on the old driver */
+		ohci |=	0x1 << 3;
+		writel(ohci, drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
+
+		break;
+	}
+}
+
+static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst)
+{
+	inst->enabled = 1;
+	exynos5250_phy_pwr(inst, 1);
+	exynos5250_isol(inst, 0);
+
+	return 0;
+}
+
+static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst)
+{
+	inst->enabled = 0;
+	exynos5250_isol(inst, 1);
+	exynos5250_phy_pwr(inst, 0);
+
+	return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos5250_phys[] = {
+	{
+		.label		= "device",
+		.id		= EXYNOS5250_DEVICE,
+		.rate_to_clk	= exynos5250_rate_to_clk,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS5250_HOST,
+		.rate_to_clk	= exynos5250_rate_to_clk,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS5250_HSIC0,
+		.rate_to_clk	= exynos5250_rate_to_clk,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS5250_HSIC1,
+		.rate_to_clk	= exynos5250_rate_to_clk,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
+	.num_phys		= EXYNOS5250_NUM_PHYS,
+	.phys			= exynos5250_phys,
+	.has_mode_switch	= 1,
+};
+
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
index ef93fd3..d62e847 100644
--- a/drivers/phy/phy-samsung-usb2.c
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -116,6 +116,12 @@ static const struct of_device_id samsung_usb2_phy_of_match[] = {
 		.data = &exynos4212_usb2_phy_config,
 	},
 #endif
+#ifdef CONFIG_PHY_EXYNOS5250_USB2
+	{
+		.compatible = "samsung,exynos5250-usb2-phy",
+		.data = &exynos5250_usb2_phy_config,
+	},
+#endif
 	{ },
 };
 
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
index 0f51dbb..0049e8a 100644
--- a/drivers/phy/phy-samsung-usb2.h
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -69,5 +69,6 @@ struct samsung_usb2_phy_config {
 extern const struct samsung_usb2_phy_config s5pv210_usb2_phy_config;
 extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
 extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
+extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config;
 #endif
 
-- 
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] 50+ messages in thread

* [PATCH 8/9] dts: Add usb2phy to Exynos 4
  2013-12-05 12:29 [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver Kamil Debski
                   ` (7 preceding siblings ...)
  2013-12-06 10:32   ` Kamil Debski
@ 2013-12-06 10:33 ` Kamil Debski
  2013-12-06 10:34   ` Kamil Debski
  9 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 10:33 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, k.debski

Add support of new USB 2.0 phy driver to Exynos 4 SoC device tree.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 .../devicetree/bindings/arm/samsung/pmu.txt        |    2 ++
 arch/arm/boot/dts/exynos4.dtsi                     |   31 ++++++++++++++++++++
 arch/arm/boot/dts/exynos4210.dtsi                  |   17 +++++++++++
 arch/arm/boot/dts/exynos4x12.dtsi                  |   17 +++++++++++
 4 files changed, 67 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/samsung/pmu.txt b/Documentation/devicetree/bindings/arm/samsung/pmu.txt
index 307e727..bfccab0 100644
--- a/Documentation/devicetree/bindings/arm/samsung/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/pmu.txt
@@ -3,6 +3,8 @@ SAMSUNG Exynos SoC series PMU Registers
 Properties:
  - name : should be 'syscon';
  - compatible : should contain two values. First value must be one from following list:
+		   - "samsung,exynos4210-pmu" - for Exynos4210 SoC,
+		   - "samsung,exynos4212-pmu" - for Exynos4212 SoC,
 		   - "samsung,exynos5250-pmu" - for Exynos5250 SoC,
 		   - "samsung,exynos5420-pmu" - for Exynos5420 SoC.
 		second value must be always "syscon".
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index a73eeb5..031d07a 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -253,6 +253,17 @@
 		status = "disabled";
 	};
 
+	usbotg@12480000 {
+		compatible = "samsung,s3c6400-hsotg";
+		reg = <0x12480000 0x20000>;
+		interrupts = <0 71 0>;
+		clocks = <&clock 305>;
+		clock-names = "otg";
+		phys = <&usb2phy 0>;
+		phy-names = "usb2-phy";
+		status = "disabled";
+	};
+
 	ehci@12580000 {
 		compatible = "samsung,exynos4210-ehci";
 		reg = <0x12580000 0x100>;
@@ -260,6 +271,26 @@
 		clocks = <&clock 304>;
 		clock-names = "usbhost";
 		status = "disabled";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		port@0 {
+			phys = <&usb2phy 1>;
+			phy-names = "host";
+			reg = <0>;
+			status = "disabled";
+		};
+		port@1 {
+			phys = <&usb2phy 2>;
+			phy-names = "hsic0";
+			reg = <1>;
+			status = "disabled";
+		};
+		port@2 {
+			phys = <&usb2phy 3>;
+			phy-names = "hsic1";
+			reg = <2>;
+			status = "disabled";
+		};
 	};
 
 	ohci@12590000 {
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index 057d682..f9d06bb 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -155,4 +155,21 @@
 			samsung,lcd-wb;
 		};
 	};
+
+	pmu_reg: syscon@10020000 {
+		compatible = "samsung,exynos4210-pmu", "syscon";
+		reg = <0x10020000 0x4000>;
+	};
+
+	usb2phy: phy@125B0000 {
+		compatible = "samsung,exynos4210-usb2-phy";
+		reg = <0x125B0000 0x100>;
+		clocks = <&clock 305>, <&clock 2>, <&clock 2>, <&clock 2>,
+								<&clock 2>;
+		clock-names = "phy", "device", "host", "hsic0", "hsic1";
+		status = "disabled";
+		#phy-cells = <1>;
+		samsung,sysreg-phandle = <&sys_reg>;
+		samsung,pmureg-phandle = <&pmu_reg>;
+	};
 };
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index ad531fe..7121111 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -176,4 +176,21 @@
 			};
 		};
 	};
+
+	pmu_reg: syscon@10020000 {
+		compatible = "samsung,exynos4212-pmu", "syscon";
+		reg = <0x10020000 0x4000>;
+	};
+
+	usb2phy: phy@125B0000 {
+		compatible = "samsung,exynos4212-usb2-phy";
+		reg = <0x125B0000 0x100>;
+		clocks = <&clock 305>, <&clock 2>, <&clock 2>, <&clock 2>,
+								<&clock 2>;
+		clock-names = "phy", "device", "host", "hsic0", "hsic1";
+		status = "disabled";
+		#phy-cells = <1>;
+		samsung,sysreg-phandle = <&sys_reg>;
+		samsung,pmureg-phandle = <&pmu_reg>;
+	};
 };
-- 
1.7.9.5


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

* [PATCH 9/9] dts: Add usb2phy to Exynos 5250
@ 2013-12-06 10:34   ` Kamil Debski
  0 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 10:34 UTC (permalink / raw)
  To: linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter, k.debski

Add support of new USB 2.0 phy driver to the Exynos 5250 SoC device tree.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/boot/dts/exynos5250.dtsi |   33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 2f264ad..922e0ed 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -163,6 +163,11 @@
 		interrupts = <0 47 0>;
 	};
 
+	sys_syscon: syscon@10040000 {
+		compatible = "samsung,exynos5250-sys", "syscon";
+		reg = <0x10050000 0x5000>;
+	};
+
 	pmu_syscon: syscon@10040000 {
 		compatible = "samsung,exynos5250-pmu", "syscon";
 		reg = <0x10040000 0x5000>;
@@ -505,6 +510,14 @@
 
 		clocks = <&clock 285>;
 		clock-names = "usbhost";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		port@0 {
+			reg = <0>;
+			phys = <&usb2_phy 1>;
+			phy-names = "host";
+			status = "ok";
+		};
 	};
 
 	usb@12120000 {
@@ -516,19 +529,15 @@
 		clock-names = "usbhost";
 	};
 
-	usb2_phy: usbphy@12130000 {
-		compatible = "samsung,exynos5250-usb2phy";
+	usb2_phy: phy@12130000 {
+		compatible = "samsung,exynos5250-usb2-phy";
 		reg = <0x12130000 0x100>;
-		clocks = <&clock 1>, <&clock 285>;
-		clock-names = "ext_xtal", "usbhost";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-
-		usbphy-sys {
-			reg = <0x10040704 0x8>,
-			      <0x10050230 0x4>;
-		};
+		clocks = <&clock 285>, <&clock 1>, <&clock 1>, <&clock 1>,
+								<&clock 1>;
+		clock-names = "phy", "device", "host", "hsic0", "hsic1";
+		#phy-cells = <1>;
+		samsung,sysreg-phandle = <&sys_syscon>;
+		samsung,pmureg-phandle = <&pmu_syscon>;
 	};
 
 	amba {
-- 
1.7.9.5


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

* [PATCH 9/9] dts: Add usb2phy to Exynos 5250
@ 2013-12-06 10:34   ` Kamil Debski
  0 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 10:34 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, kishon-l0cyMroinI0,
	t.figa-Sze3O3UU22JBDgjK7y7TUQ, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ,
	mat.krawczuk-Re5JQEeQqe8AvxtiuMwx3w,
	yulgon.kim-Sze3O3UU22JBDgjK7y7TUQ,
	p.paneri-Sze3O3UU22JBDgjK7y7TUQ,
	av.tikhomirov-Sze3O3UU22JBDgjK7y7TUQ,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	matt.porter-QSEj5FYQhm4dnm+yROfE0A,
	k.debski-Sze3O3UU22JBDgjK7y7TUQ

Add support of new USB 2.0 phy driver to the Exynos 5250 SoC device tree.

Signed-off-by: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 arch/arm/boot/dts/exynos5250.dtsi |   33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 2f264ad..922e0ed 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -163,6 +163,11 @@
 		interrupts = <0 47 0>;
 	};
 
+	sys_syscon: syscon@10040000 {
+		compatible = "samsung,exynos5250-sys", "syscon";
+		reg = <0x10050000 0x5000>;
+	};
+
 	pmu_syscon: syscon@10040000 {
 		compatible = "samsung,exynos5250-pmu", "syscon";
 		reg = <0x10040000 0x5000>;
@@ -505,6 +510,14 @@
 
 		clocks = <&clock 285>;
 		clock-names = "usbhost";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		port@0 {
+			reg = <0>;
+			phys = <&usb2_phy 1>;
+			phy-names = "host";
+			status = "ok";
+		};
 	};
 
 	usb@12120000 {
@@ -516,19 +529,15 @@
 		clock-names = "usbhost";
 	};
 
-	usb2_phy: usbphy@12130000 {
-		compatible = "samsung,exynos5250-usb2phy";
+	usb2_phy: phy@12130000 {
+		compatible = "samsung,exynos5250-usb2-phy";
 		reg = <0x12130000 0x100>;
-		clocks = <&clock 1>, <&clock 285>;
-		clock-names = "ext_xtal", "usbhost";
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;

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

* RE: [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver
  2013-12-05 15:07   ` Kishon Vijay Abraham I
  (?)
@ 2013-12-06 10:51   ` Kamil Debski
  -1 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 10:51 UTC (permalink / raw)
  To: 'Kishon Vijay Abraham I',
	linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

Hi,

> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
> Sent: Thursday, December 05, 2013 4:07 PM
> 
> Hi,
> 
> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> > Hi,
> >
> > This is the fourth version of the patchset adding the new Exynos USB
> > 2.0 PHY driver. The driver uses the Generic PHY Framework.
> >
> > A month has passed since the last version. I have addressed numerous
> > comments that appeared on the mailing list in this patch. I would
> like
> > to specially thank Kishon, Tomasz, Matt and Vivek for their comments.
> >
> > This patch contains two necessary patches to the phy core.
> > It is very useful to be able to get phy using a device tree node.
> >
> > In addition this patch depends on:
> > [PATCH V11 1/3] ARM: dts: Add pmu sysreg node to exynos5250 and
> > exynos5420 dtsi files [1].
> >
> > Best wishes,
> > Kamil Debski
> 
> The last four patches are missing [1]

I am sorry, git send-email failed on the 6th patch thus that and the
Following patches were not sent. I guess it is the Murphy's law,
sending patches just before leaving office had high chances of such
a mishap.

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland
 
> [1] -> https://lkml.org/lkml/2013/12/5/166
> 
> Thanks
> Kishon
> >
> > [1] - http://www.spinics.net/lists/linux-samsung-soc/msg24528.html
> >
> > ----------------
> > Changes from v3:
> > - using PMU and system registers indirectly via syscon
> > - change labelling
> > - change Kconfig name
> > - fixed typos/stray whitespace
> > - move of_phy_provider_register() to the end of probe
> > - add a regular error return code to the rate_to_clk functions
> > - cleanup code and remove unused code
> > - change struct names to avoid collisions
> > - add mechanism to support multiple phys by the ehci driver
> >
> > ----------------
> > Changes from v2:
> > - rebase all patches to the usb-next branch
> > - fixes in the documentation file
> >   - remove wrong entries in the phy node (ranges, and #address- &
> #size-cells)
> >   - add clocks and clock-names as required properites
> >   - rephrase a few sentences
> > - fixes in the ehci-exynos.c file
> >   - move phy_name variable next to phy in exynos_ehci_hcd
> >   - remove otg from exynos_ehci_hcd as it was no longer used
> >   - move devm_phy_get after the Exynos5440 skip_phy check
> > - fixes in the s3c-hsotg.c file
> >   - cosmetic fixes (remove empty line that was wrongfully added)
> > - fixes in the main driver
> >   - remove cpu_type in favour for a boolean flag matched with the
> compatible
> >     value
> >   - rename files, structures, variables and Kconfig entires - change
> from simple
> >     "uphy" to "usb2_phy"
> >   - fix multiline comments style
> >   - simplify #ifdefs in of_device_id
> >   - fix Kconfig description
> >   - change dev_info to dev_dbg where reasonable
> >   - cosmetic changes (remove wrongful blank lines)
> >   - remove unnecessary reference counting
> >
> > ----------------
> > Changes from v1:
> > - the changes include minor fixes of the hardware initialization of
> the PHY
> >   module
> > - some other minor fixes were introduced
> >
> > ----------------------
> > Original cover letter:
> >
> > Hi,
> >
> > This patch adds a new drive for USB PHYs for Samsung SoCs. The driver
> > is using the Generic PHY Framework created by Kishon Vijay Abrahan I.
> > It can be found here https://lkml.org/lkml/2013/8/21/29. This patch
> > adds support to Exynos4 family of SoCs. Support for Exynos3 and
> > Exynos5 is planned to be added in the near future.
> >
> > I welcome your comments.
> >
> > ----------------------
> >
> > [1] https://lkml.org/lkml/2013/8/21/29
> >
> >
> > Kamil Debski (8):
> >   phy: core: Change the way of_phy_get is called
> >   phy: core: Add devm_of_phy_get to phy-core
> >   phy: Add new Exynos USB PHY driver
> >   usb: ehci-s5p: Change to use phy provided by the generic phy
> >     framework
> >   usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic
> >     phy framework
> >   phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver
> >   dts: Add usb2phy to Exynos 4
> >   dts: Add usb2phy to Exynos 5250
> >
> > Mateusz Krawczuk (1):
> >   phy: Add support for S5PV210 to the Exynos USB PHY driver
> >
> >  .../devicetree/bindings/arm/samsung/pmu.txt        |    2 +
> >  .../devicetree/bindings/phy/samsung-usbphy.txt     |   56 +++
> >  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 +
> >  Documentation/devicetree/bindings/usb/usb-ehci.txt |   35 ++
> >  arch/arm/boot/dts/exynos4.dtsi                     |   31 ++
> >  arch/arm/boot/dts/exynos4210.dtsi                  |   17 +
> >  arch/arm/boot/dts/exynos4x12.dtsi                  |   17 +
> >  arch/arm/boot/dts/exynos5250.dtsi                  |   33 +-
> >  drivers/phy/Kconfig                                |   35 ++
> >  drivers/phy/Makefile                               |    5 +
> >  drivers/phy/phy-core.c                             |   43 ++-
> >  drivers/phy/phy-exynos4210-usb2.c                  |  264
> ++++++++++++++
> >  drivers/phy/phy-exynos4212-usb2.c                  |  312
> +++++++++++++++++
> >  drivers/phy/phy-exynos5250-usb2.c                  |  363
> ++++++++++++++++++++
> >  drivers/phy/phy-s5pv210-usb2.c                     |  206
> +++++++++++
> >  drivers/phy/phy-samsung-usb2.c                     |  240
> +++++++++++++
> >  drivers/phy/phy-samsung-usb2.h                     |   74 ++++
> >  drivers/usb/gadget/s3c-hsotg.c                     |   11 +-
> >  drivers/usb/host/ehci-exynos.c                     |   95 +++--
> >  include/linux/phy/phy.h                            |    3 +
> >  20 files changed, 1789 insertions(+), 57 deletions(-)  create mode
> > 100644 Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> >  create mode 100644 drivers/phy/phy-exynos4210-usb2.c  create mode
> > 100644 drivers/phy/phy-exynos4212-usb2.c  create mode 100644
> > drivers/phy/phy-exynos5250-usb2.c  create mode 100644
> > drivers/phy/phy-s5pv210-usb2.c  create mode 100644
> > drivers/phy/phy-samsung-usb2.c  create mode 100644
> > drivers/phy/phy-samsung-usb2.h
> >


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

* RE: [PATCH 1/9] phy: core: Change the way of_phy_get is called
@ 2013-12-06 10:52       ` Kamil Debski
  0 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 10:52 UTC (permalink / raw)
  To: 'Kishon Vijay Abraham I',
	linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

Hi,

> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
> Sent: Friday, December 06, 2013 6:31 AM
> 
> Hi,
> 
> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> > Previously the of_phy_get function took a struct device * and was
> > declared static. It was impossible to call it from another driver and
> > thus it was impossible to get phy defined
> 
> It was never intended to be called from other drivers. What's up with
> the wrapper of of_phy_get, phy_get()/devm_phy_get()? Why isn't that
> enough?

Implementing support for multiple phys in the ehci driver is a bit tricky.
Especially when we want to do it right. Please have a look at this part of
the dts file:

+    ehci@12580000 {
+        compatible = "samsung,exynos4210-ehci";
+        reg = <0x12580000 0x20000>;
+        interrupts = <0 70 0>;
+        clocks = <&clock 304>, <&clock 305>;
+        clock-names = "usbhost", "otg";
+        status = "disabled";
+        #address-cells = <1>;
+        #size-cells = <0>;
+        port@0 {
+            reg = <0>;
+            phys = <&usb2phy 1>;
+            phy-names = "host";
+            status = "disabled";
+        };
+        port@1 {
+            reg = <1>;
+            phys = <&usb2phy 2>;
+            phy-names = "hsic0";
+            status = "disabled";
+        };
+        port@2 {
+            reg = <2>;
+            phys = <&usb2phy 3>;
+            phy-names = "hsic1";
+            status = "disabled";
+        };
+    };

With the above we have a clear specification of ports and their respective
phys. But to do this properly the ehci driver has to iterate over port
nodes. It is much easier to use devm_of_phy_get by giving the node as its
argument.

[snip]

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland



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

* RE: [PATCH 1/9] phy: core: Change the way of_phy_get is called
@ 2013-12-06 10:52       ` Kamil Debski
  0 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 10:52 UTC (permalink / raw)
  To: 'Kishon Vijay Abraham I',
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, Tomasz Figa,
	Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ,
	mat.krawczuk-Re5JQEeQqe8AvxtiuMwx3w,
	yulgon.kim-Sze3O3UU22JBDgjK7y7TUQ,
	p.paneri-Sze3O3UU22JBDgjK7y7TUQ,
	av.tikhomirov-Sze3O3UU22JBDgjK7y7TUQ,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	matt.porter-QSEj5FYQhm4dnm+yROfE0A

Hi,

> From: Kishon Vijay Abraham I [mailto:kishon-l0cyMroinI0@public.gmane.org]
> Sent: Friday, December 06, 2013 6:31 AM
> 
> Hi,
> 
> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> > Previously the of_phy_get function took a struct device * and was
> > declared static. It was impossible to call it from another driver and
> > thus it was impossible to get phy defined
> 
> It was never intended to be called from other drivers. What's up with
> the wrapper of of_phy_get, phy_get()/devm_phy_get()? Why isn't that
> enough?

Implementing support for multiple phys in the ehci driver is a bit tricky.
Especially when we want to do it right. Please have a look at this part of
the dts file:

+    ehci@12580000 {
+        compatible = "samsung,exynos4210-ehci";
+        reg = <0x12580000 0x20000>;
+        interrupts = <0 70 0>;
+        clocks = <&clock 304>, <&clock 305>;
+        clock-names = "usbhost", "otg";
+        status = "disabled";
+        #address-cells = <1>;
+        #size-cells = <0>;
+        port@0 {
+            reg = <0>;
+            phys = <&usb2phy 1>;
+            phy-names = "host";
+            status = "disabled";
+        };
+        port@1 {
+            reg = <1>;
+            phys = <&usb2phy 2>;
+            phy-names = "hsic0";
+            status = "disabled";
+        };
+        port@2 {
+            reg = <2>;
+            phys = <&usb2phy 3>;
+            phy-names = "hsic1";
+            status = "disabled";
+        };
+    };

With the above we have a clear specification of ports and their respective
phys. But to do this properly the ehci driver has to iterate over port
nodes. It is much easier to use devm_of_phy_get by giving the node as its
argument.

[snip]

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland


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

* Re: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
  2013-12-05 12:29   ` Kamil Debski
@ 2013-12-06 10:59     ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06 10:59 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb,
	devicetree, balbi, Greg Kroah-Hartman
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

Hi,

On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> Add a new driver for the Exynos USB PHY. The new driver uses the generic
> PHY framework. The driver includes support for the Exynos 4x10 and 4x12
> SoC families.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/phy/samsung-usbphy.txt     |   54 ++++
>  drivers/phy/Kconfig                                |   20 ++
>  drivers/phy/Makefile                               |    3 +
>  drivers/phy/phy-exynos4210-usb2.c                  |  264 +++++++++++++++++
>  drivers/phy/phy-exynos4212-usb2.c                  |  312 ++++++++++++++++++++
>  drivers/phy/phy-samsung-usb2.c                     |  228 ++++++++++++++
>  drivers/phy/phy-samsung-usb2.h                     |   72 +++++
>  7 files changed, 953 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/phy/samsung-usbphy.txt
>  create mode 100644 drivers/phy/phy-exynos4210-usb2.c
>  create mode 100644 drivers/phy/phy-exynos4212-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.h
> 
> diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> new file mode 100644
> index 0000000..cadbf70
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt

use the existing samsung-phy.txt.
> @@ -0,0 +1,54 @@
> +Samsung S5P/EXYNOS SoC series USB PHY
> +-------------------------------------------------
> +
> +Required properties:
> +- compatible : should be one of the listed compatibles:
> +	- "samsung,exynos4210-usb2-phy"
> +	- "samsung,exynos4212-usb2-phy"
> +- reg : a list of registers used by phy driver
> +	- first and obligatory is the location of phy modules registers
> +- samsung,sysreg-phandle - handle to syscon used to control the system registers
> +- samsung,pmureg-phandle - handle to syscon used to control PMU registers
> +- #phy-cells : from the generic phy bindings, must be 1;
> +- clocks and clock-names:
> +	- the "phy" clocks is required by the phy module
> +	- next for each of the phys a clock has to be assidned, this clock

%s/assidned/assigned/
> +	  will be used to determine clocking frequency for the phys
> +	  (the labels are specified in the paragraph below)
> +
> +The first phandle argument in the PHY specifier identifies the PHY, its
> +meaning is compatible dependent. For the currently supported SoCs (Exynos 4210
> +and Exynos 4212) it is as follows:
> +  0 - USB device ("device"),
> +  1 - USB host ("host"),
> +  2 - HSIC0 ("hsic0"),
> +  3 - HSIC1 ("hsic1"),
> +
> +Exynos 4210 and Exynos 4212 use mode switching and require that mode switch
> +register is supplied.
> +
> +Example:
> +
> +For Exynos 4412 (compatible with Exynos 4212):
> +
> +usbphy: phy@125B0000 {

use lower case for address here...
> +	compatible = "samsung,exynos4212-usb2-phy";
> +	reg = <0x125B0000 0x100 0x10020704 0x0c 0x1001021c 0x4>;
and here..
> +	clocks = <&clock 305>, <&clock 2>, <&clock 2>, <&clock 2>,
> +							<&clock 2>;
> +	clock-names = "phy", "device", "host", "hsic0", "hsic1";
> +	status = "okay";
> +	#phy-cells = <1>;
> +	samsung,sysreg-phandle = <&sys_reg>;
> +	samsung,pmureg-phandle = <&pmu_reg>;
> +};
> +
> +Then the PHY can be used in other nodes such as:
> +
> +phy-consumer@12340000 {
> +	phys = <&usbphy 2>;
> +	phy-names = "phy";
> +};
> +
> +Refer to DT bindings documentation of particular PHY consumer devices for more
> +information about required PHYs and the way of specification.
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index a344f3d..b29018f 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -51,4 +51,24 @@ config PHY_EXYNOS_DP_VIDEO
>  	help
>  	  Support for Display Port PHY found on Samsung EXYNOS SoCs.
>  
> +config PHY_SAMSUNG_USB2
> +	tristate "Samsung USB 2.0 PHY driver"
> +	help
> +	  Enable this to support Samsung USB phy helper driver for Samsung SoCs.
> +	  This driver provides common interface to interact, for Samsung
> +	  USB 2.0 PHY driver.
> +
> +config PHY_EXYNOS4210_USB2
> +	bool "Support for Exynos 4210"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on CPU_EXYNOS4210

select GENERIC_PHY here?
> +	help
> +	  Enable USB PHY support for Exynos 4210

Add more explanation here and make checkpatch happy.
> +
> +config PHY_EXYNOS4212_USB2
> +	bool "Support for Exynos 4212"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)

select GENERIC_PHY.
> +	help
> +	  Enable USB PHY support for Exynos 4212

more explanation here too..
>  endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index d0caae9..9f4befd 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>  obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>  obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
>  obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
> +obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
> +obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
> +obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/phy-exynos4210-usb2.c
> new file mode 100644
> index 0000000..a02e5c2
> --- /dev/null
> +++ b/drivers/phy/phy-exynos4210-usb2.c
> @@ -0,0 +1,264 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>

You've included most of the above header files in phy-samsung-usb2.h which you
are including below.
> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +
> +/* PHY power control */
> +#define EXYNOS_4210_UPHYPWR			0x0
> +
> +#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)

use BIT() here and everywhere below.
> +#define EXYNOS_4210_UPHYPWR_PHY0_PWR		(1 << 3)

replace PHY0 here with DEV so it looks similar to EXYNOS_4212.
> +#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
> +#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		(1 << 5)
> +#define EXYNOS_4210_UPHYPWR_PHY0	( \
> +	EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_PHY0_PWR | \
> +	EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
> +	EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
> +
> +#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND	(1 << 6)

replace PHY0 here with HOST so it looks similar to EXYNOS_4212.
> +#define EXYNOS_4210_UPHYPWR_PHY1_PWR		(1 << 7)
> +#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		(1 << 8)
> +#define EXYNOS_4210_UPHYPWR_PHY1 ( \
> +	EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_PHY1_PWR | \
> +	EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
> +
> +#define EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> +#define EXYNOS_4210_UPHYPWR_HSCI0_SLEEP		(1 << 10)
> +#define EXYNOS_4210_UPHYPWR_HSCI0 ( \
> +	EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_HSCI0_SLEEP)
> +
> +#define EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND	(1 << 11)
> +#define EXYNOS_4210_UPHYPWR_HSCI1_SLEEP		(1 << 12)
> +#define EXYNOS_4210_UPHYPWR_HSCI1 ( \
> +	EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_HSCI1_SLEEP)
> +
> +/* PHY clock control */
> +#define EXYNOS_4210_UPHYCLK			0x4
> +
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> +
> +#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
> +#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> +#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> +
> +/* PHY reset control */
> +#define EXYNOS_4210_UPHYRST			0x8
> +
> +#define EXYNOS_4210_URSTCON_PHY0		(1 << 0)
> +#define EXYNOS_4210_URSTCON_OTG_HLINK		(1 << 1)
> +#define EXYNOS_4210_URSTCON_OTG_PHYLINK		(1 << 2)
> +#define EXYNOS_4210_URSTCON_PHY1_ALL		(1 << 3)
> +#define EXYNOS_4210_URSTCON_PHY1_P0		(1 << 4)
> +#define EXYNOS_4210_URSTCON_PHY1_P1P2		(1 << 5)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_ALL	(1 << 6)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_P0	(1 << 7)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_P1	(1 << 8)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_P2	(1 << 9)
> +
> +/* Isolation, configured in the power management unit */
> +#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
> +#define EXYNOS_4210_USB_ISOL_DEVICE		(1 << 0)
> +#define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
> +#define EXYNOS_4210_USB_ISOL_HOST		(1 << 0)
> +
> +/* USBYPHY1 Floating prevention */
> +#define EXYNOS_4210_UPHY1CON			0x34
> +#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION	0x1
> +
> +/* Mode switching SUB Device <-> Host */
> +#define EXYNOS_4210_MODE_SWITCH_OFFSET		0x21c
> +#define EXYNOS_4210_MODE_SWITCH_MASK		1
> +#define EXYNOS_4210_MODE_SWITCH_DEVICE		0
> +#define EXYNOS_4210_MODE_SWITCH_HOST		1
> +
> +enum exynos4210_phy_id {
> +	EXYNOS4210_DEVICE,
> +	EXYNOS4210_HOST,
> +	EXYNOS4210_HSIC0,
> +	EXYNOS4210_HSIC1,
> +	EXYNOS4210_NUM_PHYS,
> +};
> +
> +/*
> + * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
> + * can be written to the phy register.
> + */
> +static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	switch (rate) {
> +	case 12 * MHZ:
> +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
> +		break;
> +	case 48 * MHZ:
> +		reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;

%s/reg/*reg
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 offset;
> +	u32 mask;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4210_DEVICE:
> +		offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
> +		mask = EXYNOS_4210_USB_ISOL_DEVICE;
> +		break;
> +	case EXYNOS4210_HOST:
> +		offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
> +		mask = EXYNOS_4210_USB_ISOL_HOST;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 rstbits = 0;
> +	u32 phypwr = 0;
> +	u32 rst;
> +	u32 pwr;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4210_DEVICE:
> +		phypwr =	EXYNOS_4210_UPHYPWR_PHY0;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY0;
> +		break;
> +	case EXYNOS4210_HOST:
> +		phypwr =	EXYNOS_4210_UPHYPWR_PHY1;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY1_ALL |
> +				EXYNOS_4210_URSTCON_PHY1_P0 |
> +				EXYNOS_4210_URSTCON_PHY1_P1P2 |
> +				EXYNOS_4210_URSTCON_HOST_LINK_ALL |
> +				EXYNOS_4210_URSTCON_HOST_LINK_P0;
> +		writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
> +		break;
> +	case EXYNOS4210_HSIC0:
> +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI0;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> +				EXYNOS_4210_URSTCON_HOST_LINK_P1;
> +		break;
> +	case EXYNOS4210_HSIC1:
> +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI1;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> +				EXYNOS_4210_URSTCON_HOST_LINK_P2;
> +		break;
> +	};
> +
> +	if (on) {
> +		writel(inst->clk_reg_val, drv->reg_phy + EXYNOS_4210_UPHYCLK);
> +
> +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +		pwr &= ~phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +
> +		rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
> +		rst |= rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
> +		udelay(10);
> +		rst &= ~rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);

Do you have to reset during every power on? IMO this reset should be done once
in phy_init.
> +	} else {
> +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +		pwr |= phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +	}
> +}
> +
> +static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	/* Order of initialisation is important - first power then isolation */
> +	exynos4210_phy_pwr(inst, 1);
> +	exynos4210_isol(inst, 0);
> +
> +	return 0;
> +}
> +
> +static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	exynos4210_isol(inst, 1);
> +	exynos4210_phy_pwr(inst, 0);
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy exynos4210_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= EXYNOS4210_DEVICE,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= EXYNOS4210_HOST,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{
> +		.label		= "hsic0",
> +		.id		= EXYNOS4210_HSIC0,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{
> +		.label		= "hsic1",
> +		.id		= EXYNOS4210_HSIC1,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
> +	.num_phys		= EXYNOS4210_NUM_PHYS,
> +	.phys			= exynos4210_phys,
> +	.has_mode_switch	= 1,
> +};
> +
> diff --git a/drivers/phy/phy-exynos4212-usb2.c b/drivers/phy/phy-exynos4212-usb2.c
> new file mode 100644
> index 0000000..375ece0
> --- /dev/null
> +++ b/drivers/phy/phy-exynos4212-usb2.c
> @@ -0,0 +1,312 @@
> +/*
> + * Samsung S5P/EXYNOS SoC series USB PHY driver - Exynos 4212 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>

You've included most of the above header files in phy-samsung-usb2.h which you
are including below.
> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +
> +/* PHY power control */
> +#define EXYNOS_4212_UPHYPWR			0x0
> +
> +#define EXYNOS_4212_UPHYPWR_DEV_SUSPEND		(1 << 0)

use BIT() here and below..
> +#define EXYNOS_4212_UPHYPWR_DEV_PWR		(1 << 3)
> +#define EXYNOS_4212_UPHYPWR_DEV_OTG_PWR		(1 << 4)
> +#define EXYNOS_4212_UPHYPWR_DEV_SLEEP		(1 << 5)
> +#define EXYNOS_4212_UPHYPWR_DEV	( \
> +	EXYNOS_4212_UPHYPWR_DEV_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_DEV_PWR | \
> +	EXYNOS_4212_UPHYPWR_DEV_OTG_PWR | \
> +	EXYNOS_4212_UPHYPWR_DEV_SLEEP)
> +
> +#define EXYNOS_4212_UPHYPWR_HOST_SUSPEND	(1 << 6)
> +#define EXYNOS_4212_UPHYPWR_HOST_PWR		(1 << 7)
> +#define EXYNOS_4212_UPHYPWR_HOST_SLEEP		(1 << 8)
> +#define EXYNOS_4212_UPHYPWR_HOST ( \
> +	EXYNOS_4212_UPHYPWR_HOST_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_HOST_PWR | \
> +	EXYNOS_4212_UPHYPWR_HOST_SLEEP)
> +
> +#define EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> +#define EXYNOS_4212_UPHYPWR_HSCI0_PWR		(1 << 10)
> +#define EXYNOS_4212_UPHYPWR_HSCI0_SLEEP		(1 << 11)
> +#define EXYNOS_4212_UPHYPWR_HSCI0 ( \
> +	EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_HSCI0_PWR | \
> +	EXYNOS_4212_UPHYPWR_HSCI0_SLEEP)
> +
> +#define EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND	(1 << 12)
> +#define EXYNOS_4212_UPHYPWR_HSCI1_PWR		(1 << 13)
> +#define EXYNOS_4212_UPHYPWR_HSCI1_SLEEP		(1 << 14)
> +#define EXYNOS_4212_UPHYPWR_HSCI1 ( \
> +	EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_HSCI1_PWR | \
> +	EXYNOS_4212_UPHYPWR_HSCI1_SLEEP)
> +
> +/* PHY clock control */
> +#define EXYNOS_4212_UPHYCLK			0x4
> +
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_MASK	(0x7 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6	(0x0 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ	(0x1 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2	(0x3 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ	(0x4 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ	(0x5 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ	(0x7 << 0)
> +
> +#define EXYNOS_4212_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 3)
> +#define EXYNOS_4212_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> +#define EXYNOS_4212_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> +
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_MASK	(0x7f << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_12MHZ	(0x24 << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_15MHZ	(0x1c << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_16MHZ	(0x1a << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_19MHZ2	(0x15 << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_20MHZ	(0x14 << 10)
> +
> +/* PHY reset control */
> +#define EXYNOS_4212_UPHYRST			0x8
> +
> +#define EXYNOS_4212_URSTCON_DEVICE		(1 << 0)
> +#define EXYNOS_4212_URSTCON_OTG_HLINK		(1 << 1)
> +#define EXYNOS_4212_URSTCON_OTG_PHYLINK		(1 << 2)
> +#define EXYNOS_4212_URSTCON_HOST_PHY		(1 << 3)
> +#define EXYNOS_4212_URSTCON_PHY1		(1 << 4)
> +#define EXYNOS_4212_URSTCON_HSIC0		(1 << 5)
> +#define EXYNOS_4212_URSTCON_HSIC1		(1 << 6)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_ALL	(1 << 7)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_P0	(1 << 8)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_P1	(1 << 9)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_P2	(1 << 10)
> +
> +/* Isolation, configured in the power management unit */
> +#define EXYNOS_4212_USB_ISOL_OFFSET		0x704
> +#define EXYNOS_4212_USB_ISOL_OTG		(1 << 0)
> +#define EXYNOS_4212_USB_ISOL_HSIC0_OFFSET	0x708
> +#define EXYNOS_4212_USB_ISOL_HSIC0		(1 << 0)
> +#define EXYNOS_4212_USB_ISOL_HSIC1_OFFSET	0x70c
> +#define EXYNOS_4212_USB_ISOL_HSIC1		(1 << 0)
> +
> +/* Mode switching SUB Device <-> Host */
> +#define EXYNOS_4212_MODE_SWITCH_OFFSET		0x21c
> +#define EXYNOS_4212_MODE_SWITCH_MASK		1
> +#define EXYNOS_4212_MODE_SWITCH_DEVICE		0
> +#define EXYNOS_4212_MODE_SWITCH_HOST		1
> +
> +enum exynos4x12_phy_id {
> +	EXYNOS4212_DEVICE,
> +	EXYNOS4212_HOST,
> +	EXYNOS4212_HSIC0,
> +	EXYNOS4212_HSIC1,
> +	EXYNOS4212_NUM_PHYS,
> +};
> +
> +/*
> + * exynos4212_rate_to_clk() converts the supplied clock rate to the value that
> + * can be written to the phy register.
> + */
> +static int exynos4212_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	/* EXYNOS_4212_UPHYCLK_PHYFSEL_MASK */
> +
> +	switch (rate) {
> +	case 9600 * KHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6;
> +		break;
> +	case 10 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ;
> +		break;
> +	case 12 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ;
> +		break;
> +	case 19200 * KHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2;
> +		break;
> +	case 20 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ;
> +		break;
> +	case 50 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void exynos4212_isol(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 offset;
> +	u32 mask;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4212_DEVICE:
> +	case EXYNOS4212_HOST:
> +		offset = EXYNOS_4212_USB_ISOL_OFFSET;
> +		mask = EXYNOS_4212_USB_ISOL_OTG;
> +		break;
> +	case EXYNOS4212_HSIC0:
> +		offset = EXYNOS_4212_USB_ISOL_HSIC0_OFFSET;
> +		mask = EXYNOS_4212_USB_ISOL_HSIC0;
> +		break;
> +	case EXYNOS4212_HSIC1:
> +		offset = EXYNOS_4212_USB_ISOL_HSIC1_OFFSET;
> +		mask = EXYNOS_4212_USB_ISOL_HSIC1;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void exynos4212_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 rstbits = 0;
> +	u32 phypwr = 0;
> +	u32 rst;
> +	u32 pwr;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4212_DEVICE:
> +		phypwr =	EXYNOS_4212_UPHYPWR_DEV;
> +		rstbits =	EXYNOS_4212_URSTCON_DEVICE;
> +		break;
> +	case EXYNOS4212_HOST:
> +		phypwr =	EXYNOS_4212_UPHYPWR_HOST;
> +		rstbits =	EXYNOS_4212_URSTCON_HOST_PHY;
> +		break;
> +	case EXYNOS4212_HSIC0:
> +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI0;
> +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> +				EXYNOS_4212_URSTCON_HOST_LINK_P0 |
> +				EXYNOS_4212_URSTCON_HOST_PHY;
> +		break;
> +	case EXYNOS4212_HSIC1:
> +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI1;
> +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> +				EXYNOS_4212_URSTCON_HOST_LINK_P1;
> +		break;
> +	};
> +
> +	if (on) {
> +		writel(inst->clk_reg_val, drv->reg_phy + EXYNOS_4212_UPHYCLK);
> +
> +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +		pwr &= ~phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +
> +		rst = readl(drv->reg_phy + EXYNOS_4212_UPHYRST);
> +		rst |= rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
> +		udelay(10);
> +		rst &= ~rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);

reset should be done once in init?
> +	} else {
> +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +		pwr |= phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +	}
> +}
> +
> +static int exynos4212_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +
> +	inst->enabled = 1;
> +	exynos4212_phy_pwr(inst, 1);
> +	exynos4212_isol(inst, 0);
> +
> +	/* Power on the device, as it is necessary for HSIC to work */

This looks weird. How powering on the 'device PHY' makes 'HSIC PHY' to work?
> +	if (inst->cfg->id == EXYNOS4212_HSIC0) {
> +		struct samsung_usb2_phy_instance *device =
> +					&drv->instances[EXYNOS4212_DEVICE];
> +		exynos4212_phy_pwr(device, 1);
> +		exynos4212_isol(device, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +static int exynos4212_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	struct samsung_usb2_phy_instance *device = &drv->instances[EXYNOS4212_DEVICE];
> +
> +	inst->enabled = 0;
> +	exynos4212_isol(inst, 1);
> +	exynos4212_phy_pwr(inst, 0);
> +
> +	if (inst->cfg->id == EXYNOS4212_HSIC0 && !device->enabled) {
> +		exynos4212_isol(device, 1);
> +		exynos4212_phy_pwr(device, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy exynos4212_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= EXYNOS4212_DEVICE,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= EXYNOS4212_HOST,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{
> +		.label		= "hsic0",
> +		.id		= EXYNOS4212_HSIC0,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{
> +		.label		= "hsic1",
> +		.id		= EXYNOS4212_HSIC1,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config exynos4212_usb2_phy_config = {
> +	.num_phys		= EXYNOS4212_NUM_PHYS,
> +	.phys			= exynos4212_phys,
> +	.has_mode_switch	= 1,
> +};
> +
> diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
> new file mode 100644
> index 0000000..804ec77
> --- /dev/null
> +++ b/drivers/phy/phy-samsung-usb2.c
> @@ -0,0 +1,228 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>

You've included most of the above header files in phy-samsung-usb2.h which you
are including below.
> +#include "phy-samsung-usb2.h"
> +
> +static int samsung_usb2_phy_power_on(struct phy *phy)
> +{
> +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	int ret;
> +
> +	dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
> +							inst->cfg->label);
> +	ret = clk_prepare_enable(drv->clk);
> +	if (ret)
> +		goto err_main_clk;
> +	ret = clk_prepare_enable(inst->clk);
> +	if (ret)
> +		goto err_instance_clk;
> +	inst->rate = clk_get_rate(inst->clk);
> +	if (inst->cfg->rate_to_clk) {
> +		ret = inst->cfg->rate_to_clk(inst->rate, &inst->clk_reg_val);
> +		if (ret)
> +			goto err_get_rate;
> +	}
> +	if (inst->cfg->power_on) {
> +		spin_lock(&drv->lock);
> +		ret = inst->cfg->power_on(inst);
> +		spin_unlock(&drv->lock);
> +	}
> +
> +	return 0;
> +
> +err_get_rate:
> +	clk_disable_unprepare(inst->clk);
> +err_instance_clk:
> +	clk_disable_unprepare(drv->clk);
> +err_main_clk:
> +	return ret;
> +}
> +
> +static int samsung_usb2_phy_power_off(struct phy *phy)
> +{
> +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	int ret = 0;
> +
> +	dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
> +							inst->cfg->label);
> +	if (inst->cfg->power_off) {
> +		spin_lock(&drv->lock);
> +		ret = inst->cfg->power_off(inst);
> +		spin_unlock(&drv->lock);
> +	}
> +	clk_disable_unprepare(inst->clk);
> +	clk_disable_unprepare(drv->clk);
> +	return ret;
> +}
> +
> +static struct phy_ops samsung_usb2_phy_ops = {
> +	.power_on	= samsung_usb2_phy_power_on,
> +	.power_off	= samsung_usb2_phy_power_off,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static struct phy *samsung_usb2_phy_xlate(struct device *dev,
> +					struct of_phandle_args *args)
> +{
> +	struct samsung_usb2_phy_driver *drv;
> +
> +	drv = dev_get_drvdata(dev);
> +	if (!drv)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
> +		return ERR_PTR(-ENODEV);
> +
> +	return drv->instances[args->args[0]].phy;
> +}
> +
> +static const struct of_device_id samsung_usb2_phy_of_match[] = {
> +#ifdef CONFIG_PHY_EXYNOS4210_USB2
> +	{
> +		.compatible = "samsung,exynos4210-usb2-phy",
> +		.data = &exynos4210_usb2_phy_config,
> +	},
> +#endif
> +#ifdef CONFIG_PHY_EXYNOS4212_USB2
> +	{
> +		.compatible = "samsung,exynos4212-usb2-phy",
> +		.data = &exynos4212_usb2_phy_config,
> +	},
> +#endif
> +	{ },
> +};

I think we've had enough discussion about this approach. Let's get the opinion
of others too. Felipe? Greg?

Summary:
We have two drivers PHY_EXYNOS4210_USB2 and PHY_EXYNOS4212_USB2 with almost
similar register map [1] and a samsung helper driver for these two drivers.
These two PHY drivers populate the function pointers in the helper driver. So
any phy_ops will first invoke the helper driver which will then invoke the
corresponding phy driver.

[1] -> http://www.diffchecker.com/7yno1uvk

Advantages:
* (more) clean and readable
* helper driver can be used with other PHY drivers which will be added soon

Disadvantages:
* code duplication

Maybe having a helper driver makes sense when we have other samsung PHY drivers
added but not sure if it's needed here for EXYNOS4210_USB2 and EXYNOS4212_USB2

Need your inputs on what you think about this.
> +
> +static int samsung_usb2_phy_probe(struct platform_device *pdev)
> +{
> +	const struct of_device_id *match;
> +	const struct samsung_usb2_phy_config *cfg;
> +	struct clk *clk;
> +	struct device *dev = &pdev->dev;
> +	struct phy_provider *phy_provider;
> +	struct resource *mem;
> +	struct samsung_usb2_phy_driver *drv;
> +	int i;
> +
> +	if (!pdev->dev.of_node) {
> +		dev_err(dev, "This driver is required to be instantiated from device tree\n");
> +		return -EINVAL;
> +	}
> +
> +	match = of_match_node(samsung_usb2_phy_of_match, pdev->dev.of_node);
> +	if (!match) {
> +		dev_err(dev, "of_match_node() failed\n");
> +		return -EINVAL;
> +	}
> +	cfg = match->data;
> +
> +	drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
> +		cfg->num_phys * sizeof(struct samsung_usb2_phy_instance), GFP_KERNEL);
> +	if (!drv)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(dev, drv);
> +	spin_lock_init(&drv->lock);
> +
> +	drv->cfg = cfg;
> +	drv->dev = dev;
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	drv->reg_phy = devm_ioremap_resource(dev, mem);
> +	if (IS_ERR(drv->reg_phy)) {
> +		dev_err(dev, "Failed to map register memory (phy)\n");
> +		return PTR_ERR(drv->reg_phy);
> +	}
> +
> +	drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> +		"samsung,pmureg-phandle");
> +	if (IS_ERR(drv->reg_pmu)) {
> +		dev_err(dev, "Failed to map PMU registers (via syscon)\n");
> +		return PTR_ERR(drv->reg_pmu);
> +	}
> +
> +	if (drv->cfg->has_mode_switch) {
> +		drv->reg_sys = syscon_regmap_lookup_by_phandle(
> +				pdev->dev.of_node, "samsung,sysreg-phandle");
> +		if (IS_ERR(drv->reg_sys)) {
> +			dev_err(dev, "Failed to map system registers (via syscon)\n");
> +			return PTR_ERR(drv->reg_sys);
> +		}
> +	}
> +
> +	drv->clk = devm_clk_get(dev, "phy");
> +	if (IS_ERR(drv->clk)) {
> +		dev_err(dev, "Failed to get clock of phy controller\n");
> +		return PTR_ERR(drv->clk);
> +	}
> +
> +	for (i = 0; i < drv->cfg->num_phys; i++) {
> +		char *label = drv->cfg->phys[i].label;
> +		struct samsung_usb2_phy_instance *p = &drv->instances[i];
> +
> +		dev_dbg(dev, "Creating phy \"%s\"\n", label);
> +		p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
> +		if (IS_ERR(p->phy)) {
> +			dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
> +						label);
> +			return PTR_ERR(p->phy);
> +		}
> +
> +		p->cfg = &drv->cfg->phys[i];
> +		p->drv = drv;
> +		phy_set_drvdata(p->phy, p);
> +
> +		clk = devm_clk_get(dev, p->cfg->label);
> +		if (IS_ERR(clk)) {
> +			dev_err(dev, "Failed to get clock of \"%s\" phy\n",
> +								p->cfg->label);
> +			return PTR_ERR(clk);
> +		}
> +		p->clk = clk;
> +	}
> +
> +	phy_provider = devm_of_phy_provider_register(dev,
> +							samsung_usb2_phy_xlate);
> +	if (IS_ERR(phy_provider)) {
> +		dev_err(drv->dev, "Failed to register phy provider\n");
> +		return PTR_ERR(phy_provider);
> +	}
> +
> +	return 0;
> +}
> +
> +static struct platform_driver samsung_usb2_phy_driver = {
> +	.probe	= samsung_usb2_phy_probe,
> +	.driver = {
> +		.of_match_table	= samsung_usb2_phy_of_match,
> +		.name		= "samsung-usb2-phy",
> +		.owner		= THIS_MODULE,
> +	}
> +};
> +
> +module_platform_driver(samsung_usb2_phy_driver);
> +MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
> +MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:samsung-usb2-phy");
> +
> diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
> new file mode 100644
> index 0000000..cd12477
> --- /dev/null
> +++ b/drivers/phy/phy-samsung-usb2.h
> @@ -0,0 +1,72 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef _PHY_EXYNOS_USB2_H
> +#define _PHY_EXYNOS_USB2_H
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +
> +#define KHZ 1000
> +#define MHZ (KHZ * KHZ)
> +
> +struct samsung_usb2_phy_driver;
> +struct samsung_usb2_phy_instance;
> +struct samsung_usb2_phy_config;
> +
> +struct samsung_usb2_phy_instance {
> +	struct samsung_usb2_phy_driver *drv;
> +	struct phy *phy;
> +	const struct samsung_usb2_common_phy *cfg;
> +	char enabled;
> +	struct clk *clk;
> +	u32 clk_reg_val;
> +	unsigned long rate;
> +};
> +
> +struct samsung_usb2_phy_driver {
> +	struct device *dev;
> +	spinlock_t lock;
> +	void __iomem *reg_phy;
> +	struct regmap *reg_sys;
> +	struct regmap *reg_pmu;
> +	const struct samsung_usb2_phy_config *cfg;
> +	struct clk *clk;
> +	struct samsung_usb2_phy_instance instances[0];
> +};
> +
> +struct samsung_usb2_common_phy {
> +	char *label;
> +	unsigned int id;
> +	int (*rate_to_clk)(unsigned long, u32 *);
> +	int (*power_on)(struct samsung_usb2_phy_instance *);
> +	int (*power_off)(struct samsung_usb2_phy_instance *);
> +};
> +
> +
> +struct samsung_usb2_phy_config {
> +	int num_phys;
> +	const struct samsung_usb2_common_phy *phys;
> +	char has_mode_switch;

u8 instead?

Thanks
Kishon

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

* Re: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
@ 2013-12-06 10:59     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06 10:59 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb,
	devicetree, balbi, Greg Kroah-Hartman
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

Hi,

On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> Add a new driver for the Exynos USB PHY. The new driver uses the generic
> PHY framework. The driver includes support for the Exynos 4x10 and 4x12
> SoC families.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/phy/samsung-usbphy.txt     |   54 ++++
>  drivers/phy/Kconfig                                |   20 ++
>  drivers/phy/Makefile                               |    3 +
>  drivers/phy/phy-exynos4210-usb2.c                  |  264 +++++++++++++++++
>  drivers/phy/phy-exynos4212-usb2.c                  |  312 ++++++++++++++++++++
>  drivers/phy/phy-samsung-usb2.c                     |  228 ++++++++++++++
>  drivers/phy/phy-samsung-usb2.h                     |   72 +++++
>  7 files changed, 953 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/phy/samsung-usbphy.txt
>  create mode 100644 drivers/phy/phy-exynos4210-usb2.c
>  create mode 100644 drivers/phy/phy-exynos4212-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.h
> 
> diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> new file mode 100644
> index 0000000..cadbf70
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt

use the existing samsung-phy.txt.
> @@ -0,0 +1,54 @@
> +Samsung S5P/EXYNOS SoC series USB PHY
> +-------------------------------------------------
> +
> +Required properties:
> +- compatible : should be one of the listed compatibles:
> +	- "samsung,exynos4210-usb2-phy"
> +	- "samsung,exynos4212-usb2-phy"
> +- reg : a list of registers used by phy driver
> +	- first and obligatory is the location of phy modules registers
> +- samsung,sysreg-phandle - handle to syscon used to control the system registers
> +- samsung,pmureg-phandle - handle to syscon used to control PMU registers
> +- #phy-cells : from the generic phy bindings, must be 1;
> +- clocks and clock-names:
> +	- the "phy" clocks is required by the phy module
> +	- next for each of the phys a clock has to be assidned, this clock

%s/assidned/assigned/
> +	  will be used to determine clocking frequency for the phys
> +	  (the labels are specified in the paragraph below)
> +
> +The first phandle argument in the PHY specifier identifies the PHY, its
> +meaning is compatible dependent. For the currently supported SoCs (Exynos 4210
> +and Exynos 4212) it is as follows:
> +  0 - USB device ("device"),
> +  1 - USB host ("host"),
> +  2 - HSIC0 ("hsic0"),
> +  3 - HSIC1 ("hsic1"),
> +
> +Exynos 4210 and Exynos 4212 use mode switching and require that mode switch
> +register is supplied.
> +
> +Example:
> +
> +For Exynos 4412 (compatible with Exynos 4212):
> +
> +usbphy: phy@125B0000 {

use lower case for address here...
> +	compatible = "samsung,exynos4212-usb2-phy";
> +	reg = <0x125B0000 0x100 0x10020704 0x0c 0x1001021c 0x4>;
and here..
> +	clocks = <&clock 305>, <&clock 2>, <&clock 2>, <&clock 2>,
> +							<&clock 2>;
> +	clock-names = "phy", "device", "host", "hsic0", "hsic1";
> +	status = "okay";
> +	#phy-cells = <1>;
> +	samsung,sysreg-phandle = <&sys_reg>;
> +	samsung,pmureg-phandle = <&pmu_reg>;
> +};
> +
> +Then the PHY can be used in other nodes such as:
> +
> +phy-consumer@12340000 {
> +	phys = <&usbphy 2>;
> +	phy-names = "phy";
> +};
> +
> +Refer to DT bindings documentation of particular PHY consumer devices for more
> +information about required PHYs and the way of specification.
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index a344f3d..b29018f 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -51,4 +51,24 @@ config PHY_EXYNOS_DP_VIDEO
>  	help
>  	  Support for Display Port PHY found on Samsung EXYNOS SoCs.
>  
> +config PHY_SAMSUNG_USB2
> +	tristate "Samsung USB 2.0 PHY driver"
> +	help
> +	  Enable this to support Samsung USB phy helper driver for Samsung SoCs.
> +	  This driver provides common interface to interact, for Samsung
> +	  USB 2.0 PHY driver.
> +
> +config PHY_EXYNOS4210_USB2
> +	bool "Support for Exynos 4210"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on CPU_EXYNOS4210

select GENERIC_PHY here?
> +	help
> +	  Enable USB PHY support for Exynos 4210

Add more explanation here and make checkpatch happy.
> +
> +config PHY_EXYNOS4212_USB2
> +	bool "Support for Exynos 4212"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)

select GENERIC_PHY.
> +	help
> +	  Enable USB PHY support for Exynos 4212

more explanation here too..
>  endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index d0caae9..9f4befd 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
>  obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>  obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
>  obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
> +obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
> +obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
> +obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/phy-exynos4210-usb2.c
> new file mode 100644
> index 0000000..a02e5c2
> --- /dev/null
> +++ b/drivers/phy/phy-exynos4210-usb2.c
> @@ -0,0 +1,264 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>

You've included most of the above header files in phy-samsung-usb2.h which you
are including below.
> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +
> +/* PHY power control */
> +#define EXYNOS_4210_UPHYPWR			0x0
> +
> +#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)

use BIT() here and everywhere below.
> +#define EXYNOS_4210_UPHYPWR_PHY0_PWR		(1 << 3)

replace PHY0 here with DEV so it looks similar to EXYNOS_4212.
> +#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
> +#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		(1 << 5)
> +#define EXYNOS_4210_UPHYPWR_PHY0	( \
> +	EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_PHY0_PWR | \
> +	EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
> +	EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
> +
> +#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND	(1 << 6)

replace PHY0 here with HOST so it looks similar to EXYNOS_4212.
> +#define EXYNOS_4210_UPHYPWR_PHY1_PWR		(1 << 7)
> +#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		(1 << 8)
> +#define EXYNOS_4210_UPHYPWR_PHY1 ( \
> +	EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_PHY1_PWR | \
> +	EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
> +
> +#define EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> +#define EXYNOS_4210_UPHYPWR_HSCI0_SLEEP		(1 << 10)
> +#define EXYNOS_4210_UPHYPWR_HSCI0 ( \
> +	EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_HSCI0_SLEEP)
> +
> +#define EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND	(1 << 11)
> +#define EXYNOS_4210_UPHYPWR_HSCI1_SLEEP		(1 << 12)
> +#define EXYNOS_4210_UPHYPWR_HSCI1 ( \
> +	EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_HSCI1_SLEEP)
> +
> +/* PHY clock control */
> +#define EXYNOS_4210_UPHYCLK			0x4
> +
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> +
> +#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
> +#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> +#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> +
> +/* PHY reset control */
> +#define EXYNOS_4210_UPHYRST			0x8
> +
> +#define EXYNOS_4210_URSTCON_PHY0		(1 << 0)
> +#define EXYNOS_4210_URSTCON_OTG_HLINK		(1 << 1)
> +#define EXYNOS_4210_URSTCON_OTG_PHYLINK		(1 << 2)
> +#define EXYNOS_4210_URSTCON_PHY1_ALL		(1 << 3)
> +#define EXYNOS_4210_URSTCON_PHY1_P0		(1 << 4)
> +#define EXYNOS_4210_URSTCON_PHY1_P1P2		(1 << 5)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_ALL	(1 << 6)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_P0	(1 << 7)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_P1	(1 << 8)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_P2	(1 << 9)
> +
> +/* Isolation, configured in the power management unit */
> +#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
> +#define EXYNOS_4210_USB_ISOL_DEVICE		(1 << 0)
> +#define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
> +#define EXYNOS_4210_USB_ISOL_HOST		(1 << 0)
> +
> +/* USBYPHY1 Floating prevention */
> +#define EXYNOS_4210_UPHY1CON			0x34
> +#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION	0x1
> +
> +/* Mode switching SUB Device <-> Host */
> +#define EXYNOS_4210_MODE_SWITCH_OFFSET		0x21c
> +#define EXYNOS_4210_MODE_SWITCH_MASK		1
> +#define EXYNOS_4210_MODE_SWITCH_DEVICE		0
> +#define EXYNOS_4210_MODE_SWITCH_HOST		1
> +
> +enum exynos4210_phy_id {
> +	EXYNOS4210_DEVICE,
> +	EXYNOS4210_HOST,
> +	EXYNOS4210_HSIC0,
> +	EXYNOS4210_HSIC1,
> +	EXYNOS4210_NUM_PHYS,
> +};
> +
> +/*
> + * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
> + * can be written to the phy register.
> + */
> +static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	switch (rate) {
> +	case 12 * MHZ:
> +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
> +		break;
> +	case 48 * MHZ:
> +		reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;

%s/reg/*reg
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 offset;
> +	u32 mask;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4210_DEVICE:
> +		offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
> +		mask = EXYNOS_4210_USB_ISOL_DEVICE;
> +		break;
> +	case EXYNOS4210_HOST:
> +		offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
> +		mask = EXYNOS_4210_USB_ISOL_HOST;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 rstbits = 0;
> +	u32 phypwr = 0;
> +	u32 rst;
> +	u32 pwr;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4210_DEVICE:
> +		phypwr =	EXYNOS_4210_UPHYPWR_PHY0;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY0;
> +		break;
> +	case EXYNOS4210_HOST:
> +		phypwr =	EXYNOS_4210_UPHYPWR_PHY1;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY1_ALL |
> +				EXYNOS_4210_URSTCON_PHY1_P0 |
> +				EXYNOS_4210_URSTCON_PHY1_P1P2 |
> +				EXYNOS_4210_URSTCON_HOST_LINK_ALL |
> +				EXYNOS_4210_URSTCON_HOST_LINK_P0;
> +		writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
> +		break;
> +	case EXYNOS4210_HSIC0:
> +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI0;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> +				EXYNOS_4210_URSTCON_HOST_LINK_P1;
> +		break;
> +	case EXYNOS4210_HSIC1:
> +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI1;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> +				EXYNOS_4210_URSTCON_HOST_LINK_P2;
> +		break;
> +	};
> +
> +	if (on) {
> +		writel(inst->clk_reg_val, drv->reg_phy + EXYNOS_4210_UPHYCLK);
> +
> +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +		pwr &= ~phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +
> +		rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
> +		rst |= rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
> +		udelay(10);
> +		rst &= ~rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);

Do you have to reset during every power on? IMO this reset should be done once
in phy_init.
> +	} else {
> +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +		pwr |= phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +	}
> +}
> +
> +static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	/* Order of initialisation is important - first power then isolation */
> +	exynos4210_phy_pwr(inst, 1);
> +	exynos4210_isol(inst, 0);
> +
> +	return 0;
> +}
> +
> +static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	exynos4210_isol(inst, 1);
> +	exynos4210_phy_pwr(inst, 0);
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy exynos4210_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= EXYNOS4210_DEVICE,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= EXYNOS4210_HOST,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{
> +		.label		= "hsic0",
> +		.id		= EXYNOS4210_HSIC0,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{
> +		.label		= "hsic1",
> +		.id		= EXYNOS4210_HSIC1,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
> +	.num_phys		= EXYNOS4210_NUM_PHYS,
> +	.phys			= exynos4210_phys,
> +	.has_mode_switch	= 1,
> +};
> +
> diff --git a/drivers/phy/phy-exynos4212-usb2.c b/drivers/phy/phy-exynos4212-usb2.c
> new file mode 100644
> index 0000000..375ece0
> --- /dev/null
> +++ b/drivers/phy/phy-exynos4212-usb2.c
> @@ -0,0 +1,312 @@
> +/*
> + * Samsung S5P/EXYNOS SoC series USB PHY driver - Exynos 4212 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>

You've included most of the above header files in phy-samsung-usb2.h which you
are including below.
> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +
> +/* PHY power control */
> +#define EXYNOS_4212_UPHYPWR			0x0
> +
> +#define EXYNOS_4212_UPHYPWR_DEV_SUSPEND		(1 << 0)

use BIT() here and below..
> +#define EXYNOS_4212_UPHYPWR_DEV_PWR		(1 << 3)
> +#define EXYNOS_4212_UPHYPWR_DEV_OTG_PWR		(1 << 4)
> +#define EXYNOS_4212_UPHYPWR_DEV_SLEEP		(1 << 5)
> +#define EXYNOS_4212_UPHYPWR_DEV	( \
> +	EXYNOS_4212_UPHYPWR_DEV_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_DEV_PWR | \
> +	EXYNOS_4212_UPHYPWR_DEV_OTG_PWR | \
> +	EXYNOS_4212_UPHYPWR_DEV_SLEEP)
> +
> +#define EXYNOS_4212_UPHYPWR_HOST_SUSPEND	(1 << 6)
> +#define EXYNOS_4212_UPHYPWR_HOST_PWR		(1 << 7)
> +#define EXYNOS_4212_UPHYPWR_HOST_SLEEP		(1 << 8)
> +#define EXYNOS_4212_UPHYPWR_HOST ( \
> +	EXYNOS_4212_UPHYPWR_HOST_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_HOST_PWR | \
> +	EXYNOS_4212_UPHYPWR_HOST_SLEEP)
> +
> +#define EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> +#define EXYNOS_4212_UPHYPWR_HSCI0_PWR		(1 << 10)
> +#define EXYNOS_4212_UPHYPWR_HSCI0_SLEEP		(1 << 11)
> +#define EXYNOS_4212_UPHYPWR_HSCI0 ( \
> +	EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_HSCI0_PWR | \
> +	EXYNOS_4212_UPHYPWR_HSCI0_SLEEP)
> +
> +#define EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND	(1 << 12)
> +#define EXYNOS_4212_UPHYPWR_HSCI1_PWR		(1 << 13)
> +#define EXYNOS_4212_UPHYPWR_HSCI1_SLEEP		(1 << 14)
> +#define EXYNOS_4212_UPHYPWR_HSCI1 ( \
> +	EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_HSCI1_PWR | \
> +	EXYNOS_4212_UPHYPWR_HSCI1_SLEEP)
> +
> +/* PHY clock control */
> +#define EXYNOS_4212_UPHYCLK			0x4
> +
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_MASK	(0x7 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6	(0x0 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ	(0x1 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2	(0x3 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ	(0x4 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ	(0x5 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ	(0x7 << 0)
> +
> +#define EXYNOS_4212_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 3)
> +#define EXYNOS_4212_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> +#define EXYNOS_4212_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> +
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_MASK	(0x7f << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_12MHZ	(0x24 << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_15MHZ	(0x1c << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_16MHZ	(0x1a << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_19MHZ2	(0x15 << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_20MHZ	(0x14 << 10)
> +
> +/* PHY reset control */
> +#define EXYNOS_4212_UPHYRST			0x8
> +
> +#define EXYNOS_4212_URSTCON_DEVICE		(1 << 0)
> +#define EXYNOS_4212_URSTCON_OTG_HLINK		(1 << 1)
> +#define EXYNOS_4212_URSTCON_OTG_PHYLINK		(1 << 2)
> +#define EXYNOS_4212_URSTCON_HOST_PHY		(1 << 3)
> +#define EXYNOS_4212_URSTCON_PHY1		(1 << 4)
> +#define EXYNOS_4212_URSTCON_HSIC0		(1 << 5)
> +#define EXYNOS_4212_URSTCON_HSIC1		(1 << 6)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_ALL	(1 << 7)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_P0	(1 << 8)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_P1	(1 << 9)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_P2	(1 << 10)
> +
> +/* Isolation, configured in the power management unit */
> +#define EXYNOS_4212_USB_ISOL_OFFSET		0x704
> +#define EXYNOS_4212_USB_ISOL_OTG		(1 << 0)
> +#define EXYNOS_4212_USB_ISOL_HSIC0_OFFSET	0x708
> +#define EXYNOS_4212_USB_ISOL_HSIC0		(1 << 0)
> +#define EXYNOS_4212_USB_ISOL_HSIC1_OFFSET	0x70c
> +#define EXYNOS_4212_USB_ISOL_HSIC1		(1 << 0)
> +
> +/* Mode switching SUB Device <-> Host */
> +#define EXYNOS_4212_MODE_SWITCH_OFFSET		0x21c
> +#define EXYNOS_4212_MODE_SWITCH_MASK		1
> +#define EXYNOS_4212_MODE_SWITCH_DEVICE		0
> +#define EXYNOS_4212_MODE_SWITCH_HOST		1
> +
> +enum exynos4x12_phy_id {
> +	EXYNOS4212_DEVICE,
> +	EXYNOS4212_HOST,
> +	EXYNOS4212_HSIC0,
> +	EXYNOS4212_HSIC1,
> +	EXYNOS4212_NUM_PHYS,
> +};
> +
> +/*
> + * exynos4212_rate_to_clk() converts the supplied clock rate to the value that
> + * can be written to the phy register.
> + */
> +static int exynos4212_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	/* EXYNOS_4212_UPHYCLK_PHYFSEL_MASK */
> +
> +	switch (rate) {
> +	case 9600 * KHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6;
> +		break;
> +	case 10 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ;
> +		break;
> +	case 12 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ;
> +		break;
> +	case 19200 * KHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2;
> +		break;
> +	case 20 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ;
> +		break;
> +	case 50 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void exynos4212_isol(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 offset;
> +	u32 mask;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4212_DEVICE:
> +	case EXYNOS4212_HOST:
> +		offset = EXYNOS_4212_USB_ISOL_OFFSET;
> +		mask = EXYNOS_4212_USB_ISOL_OTG;
> +		break;
> +	case EXYNOS4212_HSIC0:
> +		offset = EXYNOS_4212_USB_ISOL_HSIC0_OFFSET;
> +		mask = EXYNOS_4212_USB_ISOL_HSIC0;
> +		break;
> +	case EXYNOS4212_HSIC1:
> +		offset = EXYNOS_4212_USB_ISOL_HSIC1_OFFSET;
> +		mask = EXYNOS_4212_USB_ISOL_HSIC1;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void exynos4212_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 rstbits = 0;
> +	u32 phypwr = 0;
> +	u32 rst;
> +	u32 pwr;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4212_DEVICE:
> +		phypwr =	EXYNOS_4212_UPHYPWR_DEV;
> +		rstbits =	EXYNOS_4212_URSTCON_DEVICE;
> +		break;
> +	case EXYNOS4212_HOST:
> +		phypwr =	EXYNOS_4212_UPHYPWR_HOST;
> +		rstbits =	EXYNOS_4212_URSTCON_HOST_PHY;
> +		break;
> +	case EXYNOS4212_HSIC0:
> +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI0;
> +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> +				EXYNOS_4212_URSTCON_HOST_LINK_P0 |
> +				EXYNOS_4212_URSTCON_HOST_PHY;
> +		break;
> +	case EXYNOS4212_HSIC1:
> +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI1;
> +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> +				EXYNOS_4212_URSTCON_HOST_LINK_P1;
> +		break;
> +	};
> +
> +	if (on) {
> +		writel(inst->clk_reg_val, drv->reg_phy + EXYNOS_4212_UPHYCLK);
> +
> +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +		pwr &= ~phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +
> +		rst = readl(drv->reg_phy + EXYNOS_4212_UPHYRST);
> +		rst |= rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
> +		udelay(10);
> +		rst &= ~rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);

reset should be done once in init?
> +	} else {
> +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +		pwr |= phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +	}
> +}
> +
> +static int exynos4212_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +
> +	inst->enabled = 1;
> +	exynos4212_phy_pwr(inst, 1);
> +	exynos4212_isol(inst, 0);
> +
> +	/* Power on the device, as it is necessary for HSIC to work */

This looks weird. How powering on the 'device PHY' makes 'HSIC PHY' to work?
> +	if (inst->cfg->id == EXYNOS4212_HSIC0) {
> +		struct samsung_usb2_phy_instance *device =
> +					&drv->instances[EXYNOS4212_DEVICE];
> +		exynos4212_phy_pwr(device, 1);
> +		exynos4212_isol(device, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +static int exynos4212_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	struct samsung_usb2_phy_instance *device = &drv->instances[EXYNOS4212_DEVICE];
> +
> +	inst->enabled = 0;
> +	exynos4212_isol(inst, 1);
> +	exynos4212_phy_pwr(inst, 0);
> +
> +	if (inst->cfg->id == EXYNOS4212_HSIC0 && !device->enabled) {
> +		exynos4212_isol(device, 1);
> +		exynos4212_phy_pwr(device, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy exynos4212_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= EXYNOS4212_DEVICE,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= EXYNOS4212_HOST,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{
> +		.label		= "hsic0",
> +		.id		= EXYNOS4212_HSIC0,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{
> +		.label		= "hsic1",
> +		.id		= EXYNOS4212_HSIC1,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config exynos4212_usb2_phy_config = {
> +	.num_phys		= EXYNOS4212_NUM_PHYS,
> +	.phys			= exynos4212_phys,
> +	.has_mode_switch	= 1,
> +};
> +
> diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
> new file mode 100644
> index 0000000..804ec77
> --- /dev/null
> +++ b/drivers/phy/phy-samsung-usb2.c
> @@ -0,0 +1,228 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>

You've included most of the above header files in phy-samsung-usb2.h which you
are including below.
> +#include "phy-samsung-usb2.h"
> +
> +static int samsung_usb2_phy_power_on(struct phy *phy)
> +{
> +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	int ret;
> +
> +	dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
> +							inst->cfg->label);
> +	ret = clk_prepare_enable(drv->clk);
> +	if (ret)
> +		goto err_main_clk;
> +	ret = clk_prepare_enable(inst->clk);
> +	if (ret)
> +		goto err_instance_clk;
> +	inst->rate = clk_get_rate(inst->clk);
> +	if (inst->cfg->rate_to_clk) {
> +		ret = inst->cfg->rate_to_clk(inst->rate, &inst->clk_reg_val);
> +		if (ret)
> +			goto err_get_rate;
> +	}
> +	if (inst->cfg->power_on) {
> +		spin_lock(&drv->lock);
> +		ret = inst->cfg->power_on(inst);
> +		spin_unlock(&drv->lock);
> +	}
> +
> +	return 0;
> +
> +err_get_rate:
> +	clk_disable_unprepare(inst->clk);
> +err_instance_clk:
> +	clk_disable_unprepare(drv->clk);
> +err_main_clk:
> +	return ret;
> +}
> +
> +static int samsung_usb2_phy_power_off(struct phy *phy)
> +{
> +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	int ret = 0;
> +
> +	dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
> +							inst->cfg->label);
> +	if (inst->cfg->power_off) {
> +		spin_lock(&drv->lock);
> +		ret = inst->cfg->power_off(inst);
> +		spin_unlock(&drv->lock);
> +	}
> +	clk_disable_unprepare(inst->clk);
> +	clk_disable_unprepare(drv->clk);
> +	return ret;
> +}
> +
> +static struct phy_ops samsung_usb2_phy_ops = {
> +	.power_on	= samsung_usb2_phy_power_on,
> +	.power_off	= samsung_usb2_phy_power_off,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static struct phy *samsung_usb2_phy_xlate(struct device *dev,
> +					struct of_phandle_args *args)
> +{
> +	struct samsung_usb2_phy_driver *drv;
> +
> +	drv = dev_get_drvdata(dev);
> +	if (!drv)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
> +		return ERR_PTR(-ENODEV);
> +
> +	return drv->instances[args->args[0]].phy;
> +}
> +
> +static const struct of_device_id samsung_usb2_phy_of_match[] = {
> +#ifdef CONFIG_PHY_EXYNOS4210_USB2
> +	{
> +		.compatible = "samsung,exynos4210-usb2-phy",
> +		.data = &exynos4210_usb2_phy_config,
> +	},
> +#endif
> +#ifdef CONFIG_PHY_EXYNOS4212_USB2
> +	{
> +		.compatible = "samsung,exynos4212-usb2-phy",
> +		.data = &exynos4212_usb2_phy_config,
> +	},
> +#endif
> +	{ },
> +};

I think we've had enough discussion about this approach. Let's get the opinion
of others too. Felipe? Greg?

Summary:
We have two drivers PHY_EXYNOS4210_USB2 and PHY_EXYNOS4212_USB2 with almost
similar register map [1] and a samsung helper driver for these two drivers.
These two PHY drivers populate the function pointers in the helper driver. So
any phy_ops will first invoke the helper driver which will then invoke the
corresponding phy driver.

[1] -> http://www.diffchecker.com/7yno1uvk

Advantages:
* (more) clean and readable
* helper driver can be used with other PHY drivers which will be added soon

Disadvantages:
* code duplication

Maybe having a helper driver makes sense when we have other samsung PHY drivers
added but not sure if it's needed here for EXYNOS4210_USB2 and EXYNOS4212_USB2

Need your inputs on what you think about this.
> +
> +static int samsung_usb2_phy_probe(struct platform_device *pdev)
> +{
> +	const struct of_device_id *match;
> +	const struct samsung_usb2_phy_config *cfg;
> +	struct clk *clk;
> +	struct device *dev = &pdev->dev;
> +	struct phy_provider *phy_provider;
> +	struct resource *mem;
> +	struct samsung_usb2_phy_driver *drv;
> +	int i;
> +
> +	if (!pdev->dev.of_node) {
> +		dev_err(dev, "This driver is required to be instantiated from device tree\n");
> +		return -EINVAL;
> +	}
> +
> +	match = of_match_node(samsung_usb2_phy_of_match, pdev->dev.of_node);
> +	if (!match) {
> +		dev_err(dev, "of_match_node() failed\n");
> +		return -EINVAL;
> +	}
> +	cfg = match->data;
> +
> +	drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
> +		cfg->num_phys * sizeof(struct samsung_usb2_phy_instance), GFP_KERNEL);
> +	if (!drv)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(dev, drv);
> +	spin_lock_init(&drv->lock);
> +
> +	drv->cfg = cfg;
> +	drv->dev = dev;
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	drv->reg_phy = devm_ioremap_resource(dev, mem);
> +	if (IS_ERR(drv->reg_phy)) {
> +		dev_err(dev, "Failed to map register memory (phy)\n");
> +		return PTR_ERR(drv->reg_phy);
> +	}
> +
> +	drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> +		"samsung,pmureg-phandle");
> +	if (IS_ERR(drv->reg_pmu)) {
> +		dev_err(dev, "Failed to map PMU registers (via syscon)\n");
> +		return PTR_ERR(drv->reg_pmu);
> +	}
> +
> +	if (drv->cfg->has_mode_switch) {
> +		drv->reg_sys = syscon_regmap_lookup_by_phandle(
> +				pdev->dev.of_node, "samsung,sysreg-phandle");
> +		if (IS_ERR(drv->reg_sys)) {
> +			dev_err(dev, "Failed to map system registers (via syscon)\n");
> +			return PTR_ERR(drv->reg_sys);
> +		}
> +	}
> +
> +	drv->clk = devm_clk_get(dev, "phy");
> +	if (IS_ERR(drv->clk)) {
> +		dev_err(dev, "Failed to get clock of phy controller\n");
> +		return PTR_ERR(drv->clk);
> +	}
> +
> +	for (i = 0; i < drv->cfg->num_phys; i++) {
> +		char *label = drv->cfg->phys[i].label;
> +		struct samsung_usb2_phy_instance *p = &drv->instances[i];
> +
> +		dev_dbg(dev, "Creating phy \"%s\"\n", label);
> +		p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
> +		if (IS_ERR(p->phy)) {
> +			dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
> +						label);
> +			return PTR_ERR(p->phy);
> +		}
> +
> +		p->cfg = &drv->cfg->phys[i];
> +		p->drv = drv;
> +		phy_set_drvdata(p->phy, p);
> +
> +		clk = devm_clk_get(dev, p->cfg->label);
> +		if (IS_ERR(clk)) {
> +			dev_err(dev, "Failed to get clock of \"%s\" phy\n",
> +								p->cfg->label);
> +			return PTR_ERR(clk);
> +		}
> +		p->clk = clk;
> +	}
> +
> +	phy_provider = devm_of_phy_provider_register(dev,
> +							samsung_usb2_phy_xlate);
> +	if (IS_ERR(phy_provider)) {
> +		dev_err(drv->dev, "Failed to register phy provider\n");
> +		return PTR_ERR(phy_provider);
> +	}
> +
> +	return 0;
> +}
> +
> +static struct platform_driver samsung_usb2_phy_driver = {
> +	.probe	= samsung_usb2_phy_probe,
> +	.driver = {
> +		.of_match_table	= samsung_usb2_phy_of_match,
> +		.name		= "samsung-usb2-phy",
> +		.owner		= THIS_MODULE,
> +	}
> +};
> +
> +module_platform_driver(samsung_usb2_phy_driver);
> +MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
> +MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:samsung-usb2-phy");
> +
> diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
> new file mode 100644
> index 0000000..cd12477
> --- /dev/null
> +++ b/drivers/phy/phy-samsung-usb2.h
> @@ -0,0 +1,72 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef _PHY_EXYNOS_USB2_H
> +#define _PHY_EXYNOS_USB2_H
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +
> +#define KHZ 1000
> +#define MHZ (KHZ * KHZ)
> +
> +struct samsung_usb2_phy_driver;
> +struct samsung_usb2_phy_instance;
> +struct samsung_usb2_phy_config;
> +
> +struct samsung_usb2_phy_instance {
> +	struct samsung_usb2_phy_driver *drv;
> +	struct phy *phy;
> +	const struct samsung_usb2_common_phy *cfg;
> +	char enabled;
> +	struct clk *clk;
> +	u32 clk_reg_val;
> +	unsigned long rate;
> +};
> +
> +struct samsung_usb2_phy_driver {
> +	struct device *dev;
> +	spinlock_t lock;
> +	void __iomem *reg_phy;
> +	struct regmap *reg_sys;
> +	struct regmap *reg_pmu;
> +	const struct samsung_usb2_phy_config *cfg;
> +	struct clk *clk;
> +	struct samsung_usb2_phy_instance instances[0];
> +};
> +
> +struct samsung_usb2_common_phy {
> +	char *label;
> +	unsigned int id;
> +	int (*rate_to_clk)(unsigned long, u32 *);
> +	int (*power_on)(struct samsung_usb2_phy_instance *);
> +	int (*power_off)(struct samsung_usb2_phy_instance *);
> +};
> +
> +
> +struct samsung_usb2_phy_config {
> +	int num_phys;
> +	const struct samsung_usb2_common_phy *phys;
> +	char has_mode_switch;

u8 instead?

Thanks
Kishon

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

* Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
  2013-12-05 12:29 ` [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with " Kamil Debski
@ 2013-12-06 11:11     ` Kishon Vijay Abraham I
  2013-12-11 15:15   ` Matt Porter
  2013-12-16 21:40     ` Matt Porter
  2 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06 11:11 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

Hi,

On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> Change the used phy driver to the new Exynos USB phy driver that uses the
> generic phy framework.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
>  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++-----
>  2 files changed, 10 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> index b83d428..9340d06 100644
> --- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> @@ -24,6 +24,8 @@ Required properties:
>      - first entry: must be "otg"
>  - vusb_d-supply: phandle to voltage regulator of digital section,
>  - vusb_a-supply: phandle to voltage regulator of analog section.
> +- phys: from general PHY binding: phandle to the PHY device
> +- phy-names: from general PHY binding: should be "usb2-phy"

are you sure it's usb2-phy. The example below seems to have a different value.

Thanks
Kishon

>  
>  Example
>  -----
> @@ -36,5 +38,7 @@ Example
>  		clock-names = "otg";
>  		vusb_d-supply = <&vusb_reg>;
>  		vusb_a-supply = <&vusbdac_reg>;
> +		phys = <&usb2phy 0>;
> +		phy-names = "device";
>  	};
>  
> diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
> index eccb147..db096fd 100644
> --- a/drivers/usb/gadget/s3c-hsotg.c
> +++ b/drivers/usb/gadget/s3c-hsotg.c
> @@ -31,6 +31,7 @@
>  #include <linux/regulator/consumer.h>
>  #include <linux/of.h>
>  #include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
>  
>  #include <linux/usb/ch9.h>
>  #include <linux/usb/gadget.h>
> @@ -162,7 +163,7 @@ struct s3c_hsotg_ep {
>  struct s3c_hsotg {
>  	struct device		 *dev;
>  	struct usb_gadget_driver *driver;
> -	struct usb_phy		*phy;
> +	struct phy		 *phy;
>  	struct s3c_hsotg_plat	 *plat;
>  
>  	spinlock_t              lock;
> @@ -2905,7 +2906,7 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
>  	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
>  
>  	if (hsotg->phy)
> -		usb_phy_init(hsotg->phy);
> +		phy_power_on(hsotg->phy);
>  	else if (hsotg->plat->phy_init)
>  		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
>  }
> @@ -2922,7 +2923,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
>  	struct platform_device *pdev = to_platform_device(hsotg->dev);
>  
>  	if (hsotg->phy)
> -		usb_phy_shutdown(hsotg->phy);
> +		phy_power_off(hsotg->phy);
>  	else if (hsotg->plat->phy_exit)
>  		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
>  }
> @@ -3529,7 +3530,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
>  static int s3c_hsotg_probe(struct platform_device *pdev)
>  {
>  	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
> -	struct usb_phy *phy;
> +	struct phy *phy;
>  	struct device *dev = &pdev->dev;
>  	struct s3c_hsotg_ep *eps;
>  	struct s3c_hsotg *hsotg;
> @@ -3544,7 +3545,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  	}
>  
> -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
> +	phy = devm_phy_get(&pdev->dev, "usb2-phy");
>  	if (IS_ERR(phy)) {
>  		/* Fallback for pdata */
>  		plat = dev_get_platdata(&pdev->dev);
> 


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

* Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
@ 2013-12-06 11:11     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06 11:11 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

Hi,

On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> Change the used phy driver to the new Exynos USB phy driver that uses the
> generic phy framework.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
>  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++-----
>  2 files changed, 10 insertions(+), 5 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> index b83d428..9340d06 100644
> --- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> @@ -24,6 +24,8 @@ Required properties:
>      - first entry: must be "otg"
>  - vusb_d-supply: phandle to voltage regulator of digital section,
>  - vusb_a-supply: phandle to voltage regulator of analog section.
> +- phys: from general PHY binding: phandle to the PHY device
> +- phy-names: from general PHY binding: should be "usb2-phy"

are you sure it's usb2-phy. The example below seems to have a different value.

Thanks
Kishon

>  
>  Example
>  -----
> @@ -36,5 +38,7 @@ Example
>  		clock-names = "otg";
>  		vusb_d-supply = <&vusb_reg>;
>  		vusb_a-supply = <&vusbdac_reg>;
> +		phys = <&usb2phy 0>;
> +		phy-names = "device";
>  	};
>  
> diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
> index eccb147..db096fd 100644
> --- a/drivers/usb/gadget/s3c-hsotg.c
> +++ b/drivers/usb/gadget/s3c-hsotg.c
> @@ -31,6 +31,7 @@
>  #include <linux/regulator/consumer.h>
>  #include <linux/of.h>
>  #include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
>  
>  #include <linux/usb/ch9.h>
>  #include <linux/usb/gadget.h>
> @@ -162,7 +163,7 @@ struct s3c_hsotg_ep {
>  struct s3c_hsotg {
>  	struct device		 *dev;
>  	struct usb_gadget_driver *driver;
> -	struct usb_phy		*phy;
> +	struct phy		 *phy;
>  	struct s3c_hsotg_plat	 *plat;
>  
>  	spinlock_t              lock;
> @@ -2905,7 +2906,7 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
>  	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
>  
>  	if (hsotg->phy)
> -		usb_phy_init(hsotg->phy);
> +		phy_power_on(hsotg->phy);
>  	else if (hsotg->plat->phy_init)
>  		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
>  }
> @@ -2922,7 +2923,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
>  	struct platform_device *pdev = to_platform_device(hsotg->dev);
>  
>  	if (hsotg->phy)
> -		usb_phy_shutdown(hsotg->phy);
> +		phy_power_off(hsotg->phy);
>  	else if (hsotg->plat->phy_exit)
>  		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
>  }
> @@ -3529,7 +3530,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
>  static int s3c_hsotg_probe(struct platform_device *pdev)
>  {
>  	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
> -	struct usb_phy *phy;
> +	struct phy *phy;
>  	struct device *dev = &pdev->dev;
>  	struct s3c_hsotg_ep *eps;
>  	struct s3c_hsotg *hsotg;
> @@ -3544,7 +3545,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  	}
>  
> -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
> +	phy = devm_phy_get(&pdev->dev, "usb2-phy");
>  	if (IS_ERR(phy)) {
>  		/* Fallback for pdata */
>  		plat = dev_get_platdata(&pdev->dev);
> 

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

* Re: [PATCH v4 6/9] phy: Add support for S5PV210 to the Exynos USB PHY driver
  2013-12-06 10:31 ` [PATCH v4 6/9] phy: Add support for S5PV210 to the Exynos USB " Kamil Debski
@ 2013-12-06 11:14     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06 11:14 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

Hi,

On Friday 06 December 2013 04:01 PM, Kamil Debski wrote:
> From: Mateusz Krawczuk <mat.krawczuk@gmail.com>
> 
> Add support for the Samsung's S5PV210 SoC to the Exynos USB PHY driver.
> 
> Signed-off-by: Mateusz Krawczuk <m.krawczuk@partner.samsung.com>
> [k.debski@samsung.com: cleanup and commit description]
> [k.debski@samsung.com: make changes accordingly to the mailing list
> comments]
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/phy/samsung-usbphy.txt     |    1 +
>  drivers/phy/Kconfig                                |    7 +
>  drivers/phy/Makefile                               |    1 +
>  drivers/phy/phy-s5pv210-usb2.c                     |  206 ++++++++++++++++++++
>  drivers/phy/phy-samsung-usb2.c                     |    6 +
>  drivers/phy/phy-samsung-usb2.h                     |    1 +
>  6 files changed, 222 insertions(+)
>  create mode 100644 drivers/phy/phy-s5pv210-usb2.c
> 
> diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> index cadbf70..77a8e9c 100644
> --- a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> +++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> @@ -3,6 +3,7 @@ Samsung S5P/EXYNOS SoC series USB PHY
>  
>  Required properties:
>  - compatible : should be one of the listed compatibles:
> +	- "samsung,s5pv210-usb2-phy"
>  	- "samsung,exynos4210-usb2-phy"
>  	- "samsung,exynos4212-usb2-phy"
>  - reg : a list of registers used by phy driver
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index b29018f..2e433cd 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -58,6 +58,13 @@ config PHY_SAMSUNG_USB2
>  	  This driver provides common interface to interact, for Samsung
>  	  USB 2.0 PHY driver.
>  
> +config PHY_S5PV210_USB2
> +	bool "Support for S5PV210"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on ARCH_S5PV210
> +	help
> +	  Enable USB PHY support for S5PV210

more description here..
> +
>  config PHY_EXYNOS4210_USB2
>  	bool "Support for Exynos 4210"
>  	depends on PHY_SAMSUNG_USB2
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 9f4befd..fefc6c2 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -8,5 +8,6 @@ obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>  obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
>  obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
>  obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
> +obj-$(CONFIG_PHY_S5PV210_USB2)		+= phy-s5pv210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> diff --git a/drivers/phy/phy-s5pv210-usb2.c b/drivers/phy/phy-s5pv210-usb2.c
> new file mode 100644
> index 0000000..528a114
> --- /dev/null
> +++ b/drivers/phy/phy-s5pv210-usb2.c
> @@ -0,0 +1,206 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver - S5PV210 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Authors: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>

I think my comments for the previous patch with a similar driver
(phy-exynos4210-usb2.c) is applicable here also.

Thanks
Kishon

> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +
> +/* PHY power control */
> +#define S5PV210_UPHYPWR			0x0
> +
> +#define S5PV210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
> +#define S5PV210_UPHYPWR_PHY0_PWR		(1 << 3)
> +#define S5PV210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
> +#define S5PV210_UPHYPWR_PHY0	( \
> +	S5PV210_UPHYPWR_PHY0_SUSPEND | \
> +	S5PV210_UPHYPWR_PHY0_PWR | \
> +	S5PV210_UPHYPWR_PHY0_OTG_PWR)
> +
> +#define S5PV210_UPHYPWR_PHY1_SUSPEND	(1 << 6)
> +#define S5PV210_UPHYPWR_PHY1_PWR		(1 << 7)
> +#define S5PV210_UPHYPWR_PHY1 ( \
> +	S5PV210_UPHYPWR_PHY1_SUSPEND | \
> +	S5PV210_UPHYPWR_PHY1_PWR)
> +
> +/* PHY clock control */
> +#define S5PV210_UPHYCLK			0x4
> +
> +#define S5PV210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
> +#define S5PV210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
> +#define S5PV210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
> +#define S5PV210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> +
> +#define S5PV210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
> +#define S5PV210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> +#define S5PV210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> +
> +/* PHY reset control */
> +#define S5PV210_UPHYRST			0x8
> +
> +#define S5PV210_URSTCON_PHY0		(1 << 0)
> +#define S5PV210_URSTCON_OTG_HLINK		(1 << 1)
> +#define S5PV210_URSTCON_OTG_PHYLINK		(1 << 2)
> +#define S5PV210_URSTCON_PHY1_ALL		(1 << 3)
> +#define S5PV210_URSTCON_HOST_LINK_ALL	(1 << 4)
> +
> +/* Isolation, configured in the power management unit */
> +#define S5PV210_USB_ISOL_DEVICE_OFFSET	0x704
> +#define S5PV210_USB_ISOL_DEVICE		(1 << 0)
> +#define S5PV210_USB_ISOL_HOST_OFFSET	0x708
> +#define S5PV210_USB_ISOL_HOST		(1 << 1)
> +
> +
> +enum s5pv210_phy_id {
> +	S5PV210_DEVICE,
> +	S5PV210_HOST,
> +	S5PV210_NUM_PHYS,
> +};
> +
> +/*
> + * s5pv210_rate_to_clk() converts the supplied clock rate to the value that
> + * can be written to the phy register.
> + */
> +static int s5pv210_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	pr_info("%lu\n", rate);
> +	switch (rate) {
> +	case 12 * MHZ:
> +		*reg = S5PV210_UPHYCLK_PHYFSEL_12MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = S5PV210_UPHYCLK_PHYFSEL_24MHZ;
> +		break;
> +	case 48 * MHZ:
> +		*reg = S5PV210_UPHYCLK_PHYFSEL_48MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static void s5pv210_isol(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 mask;
> +	u32 tmp;
> +
> +	if (!drv->reg_isol)
> +		return;
> +
> +	switch (inst->cfg->id) {
> +	case S5PV210_DEVICE:
> +		mask = S5PV210_USB_ISOL_DEVICE;
> +		break;
> +	case S5PV210_HOST:
> +		mask = S5PV210_USB_ISOL_HOST;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 rstbits = 0;
> +	u32 phypwr = 0;
> +	u32 rst;
> +	u32 pwr;
> +
> +	switch (inst->cfg->id) {
> +	case S5PV210_DEVICE:
> +		phypwr =	S5PV210_UPHYPWR_PHY0;
> +		rstbits =	S5PV210_URSTCON_PHY0;
> +		break;
> +	case S5PV210_HOST:
> +		phypwr =	S5PV210_UPHYPWR_PHY1;
> +		rstbits =	S5PV210_URSTCON_PHY1_ALL |
> +				S5PV210_URSTCON_HOST_LINK_ALL;
> +		break;
> +	};
> +
> +	if (on) {
> +		writel(inst->clk, drv->reg_phy + S5PV210_UPHYCLK);
> +
> +		pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
> +		pwr &= ~phypwr;
> +		writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
> +
> +		rst = readl(drv->reg_phy + S5PV210_UPHYRST);
> +		rst |= rstbits;
> +		writel(rst, drv->reg_phy + S5PV210_UPHYRST);
> +		udelay(10);
> +		rst &= ~rstbits;
> +		writel(rst, drv->reg_phy + S5PV210_UPHYRST);
> +	} else {
> +		pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
> +		pwr |= phypwr;
> +		writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
> +	}
> +}
> +
> +static int s5pv210_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +
> +	s5pv210_isol(inst, 0);
> +	s5pv210_phy_pwr(inst, 1);
> +
> +	return 0;
> +}
> +
> +static int s5pv210_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +
> +	s5pv210_phy_pwr(inst, 0);
> +	s5pv210_isol(inst, 1);
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy s5pv210_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= S5PV210_DEVICE,
> +		.rate_to_clk	= s5pv210_rate_to_clk,
> +		.power_on	= s5pv210_power_on,
> +		.power_off	= s5pv210_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= S5PV210_HOST,
> +		.rate_to_clk	= s5pv210_rate_to_clk,
> +		.power_on	= s5pv210_power_on,
> +		.power_off	= s5pv210_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config s5pv210_usb2_phy_config = {
> +	.cpu		= TYPE_S5PV210,
> +	.num_phys	= S5PV210_NUM_PHYS,
> +	.phys		= s5pv210_phys,
> +};
> +
> diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
> index 804ec77..ef93fd3 100644
> --- a/drivers/phy/phy-samsung-usb2.c
> +++ b/drivers/phy/phy-samsung-usb2.c
> @@ -98,6 +98,12 @@ static struct phy *samsung_usb2_phy_xlate(struct device *dev,
>  }
>  
>  static const struct of_device_id samsung_usb2_phy_of_match[] = {
> +#ifdef CONFIG_PHY_S5PV210_USB2
> +	{
> +		.compatible = "samsung,s5pv210-usb2-phy",
> +		.data = &s5pv210_usb2_phy_config,
> +	},
> +#endif
>  #ifdef CONFIG_PHY_EXYNOS4210_USB2
>  	{
>  		.compatible = "samsung,exynos4210-usb2-phy",
> diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
> index cd12477..0f51dbb 100644
> --- a/drivers/phy/phy-samsung-usb2.h
> +++ b/drivers/phy/phy-samsung-usb2.h
> @@ -66,6 +66,7 @@ struct samsung_usb2_phy_config {
>  	char has_mode_switch;
>  };
>  
> +extern const struct samsung_usb2_phy_config s5pv210_usb2_phy_config;
>  extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
>  extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
>  #endif
> 


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

* Re: [PATCH v4 6/9] phy: Add support for S5PV210 to the Exynos USB PHY driver
@ 2013-12-06 11:14     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06 11:14 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

Hi,

On Friday 06 December 2013 04:01 PM, Kamil Debski wrote:
> From: Mateusz Krawczuk <mat.krawczuk@gmail.com>
> 
> Add support for the Samsung's S5PV210 SoC to the Exynos USB PHY driver.
> 
> Signed-off-by: Mateusz Krawczuk <m.krawczuk@partner.samsung.com>
> [k.debski@samsung.com: cleanup and commit description]
> [k.debski@samsung.com: make changes accordingly to the mailing list
> comments]
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/phy/samsung-usbphy.txt     |    1 +
>  drivers/phy/Kconfig                                |    7 +
>  drivers/phy/Makefile                               |    1 +
>  drivers/phy/phy-s5pv210-usb2.c                     |  206 ++++++++++++++++++++
>  drivers/phy/phy-samsung-usb2.c                     |    6 +
>  drivers/phy/phy-samsung-usb2.h                     |    1 +
>  6 files changed, 222 insertions(+)
>  create mode 100644 drivers/phy/phy-s5pv210-usb2.c
> 
> diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> index cadbf70..77a8e9c 100644
> --- a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> +++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> @@ -3,6 +3,7 @@ Samsung S5P/EXYNOS SoC series USB PHY
>  
>  Required properties:
>  - compatible : should be one of the listed compatibles:
> +	- "samsung,s5pv210-usb2-phy"
>  	- "samsung,exynos4210-usb2-phy"
>  	- "samsung,exynos4212-usb2-phy"
>  - reg : a list of registers used by phy driver
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index b29018f..2e433cd 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -58,6 +58,13 @@ config PHY_SAMSUNG_USB2
>  	  This driver provides common interface to interact, for Samsung
>  	  USB 2.0 PHY driver.
>  
> +config PHY_S5PV210_USB2
> +	bool "Support for S5PV210"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on ARCH_S5PV210
> +	help
> +	  Enable USB PHY support for S5PV210

more description here..
> +
>  config PHY_EXYNOS4210_USB2
>  	bool "Support for Exynos 4210"
>  	depends on PHY_SAMSUNG_USB2
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 9f4befd..fefc6c2 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -8,5 +8,6 @@ obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>  obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
>  obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
>  obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
> +obj-$(CONFIG_PHY_S5PV210_USB2)		+= phy-s5pv210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> diff --git a/drivers/phy/phy-s5pv210-usb2.c b/drivers/phy/phy-s5pv210-usb2.c
> new file mode 100644
> index 0000000..528a114
> --- /dev/null
> +++ b/drivers/phy/phy-s5pv210-usb2.c
> @@ -0,0 +1,206 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver - S5PV210 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Authors: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>

I think my comments for the previous patch with a similar driver
(phy-exynos4210-usb2.c) is applicable here also.

Thanks
Kishon

> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +
> +/* PHY power control */
> +#define S5PV210_UPHYPWR			0x0
> +
> +#define S5PV210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
> +#define S5PV210_UPHYPWR_PHY0_PWR		(1 << 3)
> +#define S5PV210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
> +#define S5PV210_UPHYPWR_PHY0	( \
> +	S5PV210_UPHYPWR_PHY0_SUSPEND | \
> +	S5PV210_UPHYPWR_PHY0_PWR | \
> +	S5PV210_UPHYPWR_PHY0_OTG_PWR)
> +
> +#define S5PV210_UPHYPWR_PHY1_SUSPEND	(1 << 6)
> +#define S5PV210_UPHYPWR_PHY1_PWR		(1 << 7)
> +#define S5PV210_UPHYPWR_PHY1 ( \
> +	S5PV210_UPHYPWR_PHY1_SUSPEND | \
> +	S5PV210_UPHYPWR_PHY1_PWR)
> +
> +/* PHY clock control */
> +#define S5PV210_UPHYCLK			0x4
> +
> +#define S5PV210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
> +#define S5PV210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
> +#define S5PV210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
> +#define S5PV210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> +
> +#define S5PV210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
> +#define S5PV210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> +#define S5PV210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> +
> +/* PHY reset control */
> +#define S5PV210_UPHYRST			0x8
> +
> +#define S5PV210_URSTCON_PHY0		(1 << 0)
> +#define S5PV210_URSTCON_OTG_HLINK		(1 << 1)
> +#define S5PV210_URSTCON_OTG_PHYLINK		(1 << 2)
> +#define S5PV210_URSTCON_PHY1_ALL		(1 << 3)
> +#define S5PV210_URSTCON_HOST_LINK_ALL	(1 << 4)
> +
> +/* Isolation, configured in the power management unit */
> +#define S5PV210_USB_ISOL_DEVICE_OFFSET	0x704
> +#define S5PV210_USB_ISOL_DEVICE		(1 << 0)
> +#define S5PV210_USB_ISOL_HOST_OFFSET	0x708
> +#define S5PV210_USB_ISOL_HOST		(1 << 1)
> +
> +
> +enum s5pv210_phy_id {
> +	S5PV210_DEVICE,
> +	S5PV210_HOST,
> +	S5PV210_NUM_PHYS,
> +};
> +
> +/*
> + * s5pv210_rate_to_clk() converts the supplied clock rate to the value that
> + * can be written to the phy register.
> + */
> +static int s5pv210_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	pr_info("%lu\n", rate);
> +	switch (rate) {
> +	case 12 * MHZ:
> +		*reg = S5PV210_UPHYCLK_PHYFSEL_12MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = S5PV210_UPHYCLK_PHYFSEL_24MHZ;
> +		break;
> +	case 48 * MHZ:
> +		*reg = S5PV210_UPHYCLK_PHYFSEL_48MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static void s5pv210_isol(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 mask;
> +	u32 tmp;
> +
> +	if (!drv->reg_isol)
> +		return;
> +
> +	switch (inst->cfg->id) {
> +	case S5PV210_DEVICE:
> +		mask = S5PV210_USB_ISOL_DEVICE;
> +		break;
> +	case S5PV210_HOST:
> +		mask = S5PV210_USB_ISOL_HOST;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 rstbits = 0;
> +	u32 phypwr = 0;
> +	u32 rst;
> +	u32 pwr;
> +
> +	switch (inst->cfg->id) {
> +	case S5PV210_DEVICE:
> +		phypwr =	S5PV210_UPHYPWR_PHY0;
> +		rstbits =	S5PV210_URSTCON_PHY0;
> +		break;
> +	case S5PV210_HOST:
> +		phypwr =	S5PV210_UPHYPWR_PHY1;
> +		rstbits =	S5PV210_URSTCON_PHY1_ALL |
> +				S5PV210_URSTCON_HOST_LINK_ALL;
> +		break;
> +	};
> +
> +	if (on) {
> +		writel(inst->clk, drv->reg_phy + S5PV210_UPHYCLK);
> +
> +		pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
> +		pwr &= ~phypwr;
> +		writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
> +
> +		rst = readl(drv->reg_phy + S5PV210_UPHYRST);
> +		rst |= rstbits;
> +		writel(rst, drv->reg_phy + S5PV210_UPHYRST);
> +		udelay(10);
> +		rst &= ~rstbits;
> +		writel(rst, drv->reg_phy + S5PV210_UPHYRST);
> +	} else {
> +		pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
> +		pwr |= phypwr;
> +		writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
> +	}
> +}
> +
> +static int s5pv210_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +
> +	s5pv210_isol(inst, 0);
> +	s5pv210_phy_pwr(inst, 1);
> +
> +	return 0;
> +}
> +
> +static int s5pv210_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +
> +	s5pv210_phy_pwr(inst, 0);
> +	s5pv210_isol(inst, 1);
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy s5pv210_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= S5PV210_DEVICE,
> +		.rate_to_clk	= s5pv210_rate_to_clk,
> +		.power_on	= s5pv210_power_on,
> +		.power_off	= s5pv210_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= S5PV210_HOST,
> +		.rate_to_clk	= s5pv210_rate_to_clk,
> +		.power_on	= s5pv210_power_on,
> +		.power_off	= s5pv210_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config s5pv210_usb2_phy_config = {
> +	.cpu		= TYPE_S5PV210,
> +	.num_phys	= S5PV210_NUM_PHYS,
> +	.phys		= s5pv210_phys,
> +};
> +
> diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
> index 804ec77..ef93fd3 100644
> --- a/drivers/phy/phy-samsung-usb2.c
> +++ b/drivers/phy/phy-samsung-usb2.c
> @@ -98,6 +98,12 @@ static struct phy *samsung_usb2_phy_xlate(struct device *dev,
>  }
>  
>  static const struct of_device_id samsung_usb2_phy_of_match[] = {
> +#ifdef CONFIG_PHY_S5PV210_USB2
> +	{
> +		.compatible = "samsung,s5pv210-usb2-phy",
> +		.data = &s5pv210_usb2_phy_config,
> +	},
> +#endif
>  #ifdef CONFIG_PHY_EXYNOS4210_USB2
>  	{
>  		.compatible = "samsung,exynos4210-usb2-phy",
> diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
> index cd12477..0f51dbb 100644
> --- a/drivers/phy/phy-samsung-usb2.h
> +++ b/drivers/phy/phy-samsung-usb2.h
> @@ -66,6 +66,7 @@ struct samsung_usb2_phy_config {
>  	char has_mode_switch;
>  };
>  
> +extern const struct samsung_usb2_phy_config s5pv210_usb2_phy_config;
>  extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
>  extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
>  #endif
> 

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

* Re: [PATCH v4 7/9] phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver
@ 2013-12-06 11:15     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06 11:15 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, t.figa, s.nawrocki, m.szyprowski, gautam.vivek,
	mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov, jg1.han,
	galak, matt.porter

On Friday 06 December 2013 04:02 PM, Kamil Debski wrote:
> Add support for Exynos 5250. This driver is to replace the old
> USB 2.0 PHY driver.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/phy/samsung-usbphy.txt     |    1 +
>  drivers/phy/Kconfig                                |    8 +
>  drivers/phy/Makefile                               |    1 +
>  drivers/phy/phy-exynos5250-usb2.c                  |  363 ++++++++++++++++++++
>  drivers/phy/phy-samsung-usb2.c                     |    6 +
>  drivers/phy/phy-samsung-usb2.h                     |    1 +
>  6 files changed, 380 insertions(+)
>  create mode 100644 drivers/phy/phy-exynos5250-usb2.c
> 
> diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> index 77a8e9c..94096fc 100644
> --- a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> +++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> @@ -6,6 +6,7 @@ Required properties:
>  	- "samsung,s5pv210-usb2-phy"
>  	- "samsung,exynos4210-usb2-phy"
>  	- "samsung,exynos4212-usb2-phy"
> +	- "samsung,exynos5250-usb2-phy"
>  - reg : a list of registers used by phy driver
>  	- first and obligatory is the location of phy modules registers
>  - samsung,sysreg-phandle - handle to syscon used to control the system registers
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 2e433cd..74e9064 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -78,4 +78,12 @@ config PHY_EXYNOS4212_USB2
>  	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
>  	help
>  	  Enable USB PHY support for Exynos 4212
> +
> +config PHY_EXYNOS5250_USB2
> +	bool "Support for Exynos 5250"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on SOC_EXYNOS5250
> +	help
> +	  Enable USB PHY support for Exynos 5250

My comments for the previous patch is applicable here too..

Thanks
Kishon

> +
>  endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index fefc6c2..33c3ac1 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
>  obj-$(CONFIG_PHY_S5PV210_USB2)		+= phy-s5pv210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> +obj-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
> diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/phy-exynos5250-usb2.c
> new file mode 100644
> index 0000000..7aeebc8
> --- /dev/null
> +++ b/drivers/phy/phy-exynos5250-usb2.c
> @@ -0,0 +1,363 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>
> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +#define EXYNOS_5250_REFCLKSEL_CRYSTAL	0x0
> +#define EXYNOS_5250_REFCLKSEL_XO	0x1
> +#define EXYNOS_5250_REFCLKSEL_CLKCORE	0x2
> +
> +#define EXYNOS_5250_FSEL_9MHZ6		0x0
> +#define EXYNOS_5250_FSEL_10MHZ		0x1
> +#define EXYNOS_5250_FSEL_12MHZ		0x2
> +#define EXYNOS_5250_FSEL_19MHZ2		0x3
> +#define EXYNOS_5250_FSEL_20MHZ		0x4
> +#define EXYNOS_5250_FSEL_24MHZ		0x5
> +#define EXYNOS_5250_FSEL_50MHZ		0x7
> +
> +/* Normal host */
> +#define EXYNOS_5250_HOSTPHYCTRL0			0x0
> +
> +#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL		(0x1 << 31)
> +#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT	19
> +#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_MASK	\
> +		(0x3 << EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT)
> +#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT		16
> +#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK \
> +		(0x7 << EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT)
> +#define EXYNOS_5250_HOSTPHYCTRL0_TESTBURNIN		(0x1 << 11)
> +#define EXYNOS_5250_HOSTPHYCTRL0_RETENABLE		(0x1 << 10)
> +#define EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N		(0x1 << 9)
> +#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_MASK		(0x3 << 7)
> +#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_DUAL		(0x0 << 7)
> +#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ID0		(0x1 << 7)
> +#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ANALOGTEST	(0x2 << 7)
> +#define EXYNOS_5250_HOSTPHYCTRL0_SIDDQ			(0x1 << 6)
> +#define EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP		(0x1 << 5)
> +#define EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND		(0x1 << 4)
> +#define EXYNOS_5250_HOSTPHYCTRL0_WORDINTERFACE		(0x1 << 3)
> +#define EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST		(0x1 << 2)
> +#define EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST		(0x1 << 1)
> +#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST		(0x1 << 0)
> +
> +/* HSIC0 & HSCI1 */
> +#define EXYNOS_5250_HOSTPHYCTRL1			0x10
> +#define EXYNOS_5250_HOSTPHYCTRL2			0x20
> +
> +#define EXYNOS_5250_HOSTPHYCTRLX_REFCLKSEL_MASK		(0x3 << 23)
> +#define EXYNOS_5250_HOSTPHYCTRLX_REFCLKDIV_MASK		(0x7f << 16)
> +#define EXYNOS_5250_HOSTPHYCTRLX_SIDDQ			(0x1 << 6)
> +#define EXYNOS_5250_HOSTPHYCTRLX_FORCESLEEP		(0x1 << 5)
> +#define EXYNOS_5250_HOSTPHYCTRLX_FORCESUSPEND		(0x1 << 4)
> +#define EXYNOS_5250_HOSTPHYCTRLX_WORDINTERFACE		(0x1 << 3)
> +#define EXYNOS_5250_HOSTPHYCTRLX_UTMISWRST		(0x1 << 2)
> +#define EXYNOS_5250_HOSTPHYCTRLX_PHYSWRST		(0x1 << 0)
> +
> +/* EHCI control */
> +#define EXYNOS_5250_HOSTEHCICTRL			0x30
> +#define EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN		(0x1 << 29)
> +#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR4		(0x1 << 28)
> +#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR8		(0x1 << 27)
> +#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR16		(0x1 << 26)
> +#define EXYNOS_5250_HOSTEHCICTRL_AUTOPPDONOVRCUREN	(0x1 << 25)
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT	19
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK	\
> +		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT	13
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_MASK	\
> +		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT)
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL2_SHIFT	7
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK	\
> +		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT	1
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_MASK \
> +		(0x1 << EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT)
> +#define EXYNOS_5250_HOSTEHCICTRL_SIMULATIONMODE		(0x1 << 0)
> +
> +/* OHCI control */
> +#define EXYNOS_5250_HOSTOHCICTRL                        0x34
> +#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT	1
> +#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_MASK \
> +		(0x3ff << EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT)
> +#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVALEN		(0x1 << 0)
> +
> +/* USBOTG */
> +#define EXYNOS_5250_USBOTGSYS				0x38
> +#define EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET		(0x1 << 14)
> +#define EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG		(0x1 << 13)
> +#define EXYNOS_5250_USBOTGSYS_PHY_SW_RST		(0x1 << 12)
> +#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT		9
> +#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK \
> +		(0x3 << EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT)
> +#define EXYNOS_5250_USBOTGSYS_ID_PULLUP			(0x1 << 8)
> +#define EXYNOS_5250_USBOTGSYS_COMMON_ON			(0x1 << 7)
> +#define EXYNOS_5250_USBOTGSYS_FSEL_SHIFT		4
> +#define EXYNOS_5250_USBOTGSYS_FSEL_MASK \
> +		(0x3 << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT)
> +#define EXYNOS_5250_USBOTGSYS_FORCE_SLEEP		(0x1 << 3)
> +#define EXYNOS_5250_USBOTGSYS_OTGDISABLE		(0x1 << 2)
> +#define EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG		(0x1 << 1)
> +#define EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND		(0x1 << 0)
> +
> +/* Isolation, configured in the power management unit */
> +#define EXYNOS_5250_USB_ISOL_OTG_OFFSET		0x704
> +#define EXYNOS_5250_USB_ISOL_OTG		(1 << 0)
> +#define EXYNOS_5250_USB_ISOL_HOST_OFFSET	0x708
> +#define EXYNOS_5250_USB_ISOL_HOST		(1 << 0)
> +
> +/* Mode swtich register */
> +#define EXYNOS_5250_MODE_SWITCH_OFFSET		0x230
> +#define EXYNOS_5250_MODE_SWITCH_MASK		1
> +#define EXYNOS_5250_MODE_SWITCH_DEVICE		0
> +#define EXYNOS_5250_MODE_SWITCH_HOST		1
> +
> +enum exynos4x12_phy_id {
> +	EXYNOS5250_DEVICE,
> +	EXYNOS5250_HOST,
> +	EXYNOS5250_HSIC0,
> +	EXYNOS5250_HSIC1,
> +	EXYNOS5250_NUM_PHYS,
> +};
> +
> +/*
> + * exynos5250_rate_to_clk() converts the supplied clock rate to the value that
> + * can be written to the phy register.
> + */
> +static int exynos5250_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	/* EXYNOS_5250_FSEL_MASK */
> +
> +	switch (rate) {
> +	case 9600 * KHZ:
> +		*reg = EXYNOS_5250_FSEL_9MHZ6;
> +		break;
> +	case 10 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_10MHZ;
> +		break;
> +	case 12 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_12MHZ;
> +		break;
> +	case 19200 * KHZ:
> +		*reg = EXYNOS_5250_FSEL_19MHZ2;
> +		break;
> +	case 20 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_20MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_24MHZ;
> +		break;
> +	case 50 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_50MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 offset;
> +	u32 mask;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS5250_DEVICE:
> +		offset = EXYNOS_5250_USB_ISOL_OTG_OFFSET;
> +		mask = EXYNOS_5250_USB_ISOL_OTG;
> +		break;
> +	case EXYNOS5250_HOST:
> +		offset = EXYNOS_5250_USB_ISOL_HOST_OFFSET;
> +		mask = EXYNOS_5250_USB_ISOL_HOST;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void exynos5250_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 ctrl0;
> +	u32 otg;
> +	u32 ehci;
> +	u32 ohci;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS5250_DEVICE:
> +		regmap_update_bits(drv->reg_sys,
> +			EXYNOS_5250_MODE_SWITCH_OFFSET,
> +			EXYNOS_5250_MODE_SWITCH_MASK,
> +			EXYNOS_5250_MODE_SWITCH_DEVICE);
> +
> +		/* OTG configuration */
> +		otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +		/* The clock */
> +		otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
> +		otg |= inst->clk_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
> +		/* Reset */
> +		otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
> +			EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
> +			EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
> +		otg |=	EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
> +			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
> +			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
> +			EXYNOS_5250_USBOTGSYS_OTGDISABLE;
> +		/* Ref clock */
> +		otg &=	~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
> +		otg |=  EXYNOS_5250_REFCLKSEL_CLKCORE <<
> +					EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
> +		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +		udelay(100);
> +		otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
> +			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
> +			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
> +			EXYNOS_5250_USBOTGSYS_OTGDISABLE);
> +		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +
> +
> +		break;
> +	case EXYNOS5250_HOST:
> +		/* Host registers configuration */
> +		ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
> +		/* The clock */
> +		ctrl0 &= ~EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK;
> +		ctrl0 |= inst->clk_reg_val <<
> +					EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT;
> +
> +		/* Reset */
> +		ctrl0 &=	~(EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
> +				EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL |
> +				EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
> +				EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
> +				EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP);
> +		ctrl0 |=	EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
> +				EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST |
> +				EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N;
> +		writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
> +		udelay(10);
> +		ctrl0 &=	~(EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
> +				EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST);
> +		writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
> +
> +		/* OTG configuration */
> +		otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +		/* The clock */
> +		otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
> +		otg |= inst->clk_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
> +		/* Reset */
> +		otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
> +			EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
> +			EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
> +		otg |=	EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
> +			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
> +			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
> +			EXYNOS_5250_USBOTGSYS_OTGDISABLE;
> +		/* Ref clock */
> +		otg &=	~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
> +		otg |=  EXYNOS_5250_REFCLKSEL_CLKCORE <<
> +					EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
> +		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +		udelay(10);
> +		otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
> +			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
> +			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET);
> +
> +		/* Enable EHCI DMA burst */
> +		ehci = readl(drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
> +		ehci |=	EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN |
> +			EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 |
> +			EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 |
> +			EXYNOS_5250_HOSTEHCICTRL_ENAINCR16;
> +		writel(ehci, drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
> +
> +		/* OHCI settings */
> +		ohci = readl(drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
> +		/* Following code is based on the old driver */
> +		ohci |=	0x1 << 3;
> +		writel(ohci, drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
> +
> +		break;
> +	}
> +}
> +
> +static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	inst->enabled = 1;
> +	exynos5250_phy_pwr(inst, 1);
> +	exynos5250_isol(inst, 0);
> +
> +	return 0;
> +}
> +
> +static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	inst->enabled = 0;
> +	exynos5250_isol(inst, 1);
> +	exynos5250_phy_pwr(inst, 0);
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy exynos5250_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= EXYNOS5250_DEVICE,
> +		.rate_to_clk	= exynos5250_rate_to_clk,
> +		.power_on	= exynos5250_power_on,
> +		.power_off	= exynos5250_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= EXYNOS5250_HOST,
> +		.rate_to_clk	= exynos5250_rate_to_clk,
> +		.power_on	= exynos5250_power_on,
> +		.power_off	= exynos5250_power_off,
> +	},
> +	{
> +		.label		= "hsic0",
> +		.id		= EXYNOS5250_HSIC0,
> +		.rate_to_clk	= exynos5250_rate_to_clk,
> +		.power_on	= exynos5250_power_on,
> +		.power_off	= exynos5250_power_off,
> +	},
> +	{
> +		.label		= "hsic1",
> +		.id		= EXYNOS5250_HSIC1,
> +		.rate_to_clk	= exynos5250_rate_to_clk,
> +		.power_on	= exynos5250_power_on,
> +		.power_off	= exynos5250_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
> +	.num_phys		= EXYNOS5250_NUM_PHYS,
> +	.phys			= exynos5250_phys,
> +	.has_mode_switch	= 1,
> +};
> +
> diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
> index ef93fd3..d62e847 100644
> --- a/drivers/phy/phy-samsung-usb2.c
> +++ b/drivers/phy/phy-samsung-usb2.c
> @@ -116,6 +116,12 @@ static const struct of_device_id samsung_usb2_phy_of_match[] = {
>  		.data = &exynos4212_usb2_phy_config,
>  	},
>  #endif
> +#ifdef CONFIG_PHY_EXYNOS5250_USB2
> +	{
> +		.compatible = "samsung,exynos5250-usb2-phy",
> +		.data = &exynos5250_usb2_phy_config,
> +	},
> +#endif
>  	{ },
>  };
>  
> diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
> index 0f51dbb..0049e8a 100644
> --- a/drivers/phy/phy-samsung-usb2.h
> +++ b/drivers/phy/phy-samsung-usb2.h
> @@ -69,5 +69,6 @@ struct samsung_usb2_phy_config {
>  extern const struct samsung_usb2_phy_config s5pv210_usb2_phy_config;
>  extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
>  extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
> +extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config;
>  #endif
>  
> 


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

* Re: [PATCH v4 7/9] phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver
@ 2013-12-06 11:15     ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-06 11:15 UTC (permalink / raw)
  To: Kamil Debski, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	t.figa-Sze3O3UU22JBDgjK7y7TUQ, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ,
	mat.krawczuk-Re5JQEeQqe8AvxtiuMwx3w,
	yulgon.kim-Sze3O3UU22JBDgjK7y7TUQ,
	p.paneri-Sze3O3UU22JBDgjK7y7TUQ,
	av.tikhomirov-Sze3O3UU22JBDgjK7y7TUQ,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	matt.porter-QSEj5FYQhm4dnm+yROfE0A

On Friday 06 December 2013 04:02 PM, Kamil Debski wrote:
> Add support for Exynos 5250. This driver is to replace the old
> USB 2.0 PHY driver.
> 
> Signed-off-by: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  .../devicetree/bindings/phy/samsung-usbphy.txt     |    1 +
>  drivers/phy/Kconfig                                |    8 +
>  drivers/phy/Makefile                               |    1 +
>  drivers/phy/phy-exynos5250-usb2.c                  |  363 ++++++++++++++++++++
>  drivers/phy/phy-samsung-usb2.c                     |    6 +
>  drivers/phy/phy-samsung-usb2.h                     |    1 +
>  6 files changed, 380 insertions(+)
>  create mode 100644 drivers/phy/phy-exynos5250-usb2.c
> 
> diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> index 77a8e9c..94096fc 100644
> --- a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> +++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> @@ -6,6 +6,7 @@ Required properties:
>  	- "samsung,s5pv210-usb2-phy"
>  	- "samsung,exynos4210-usb2-phy"
>  	- "samsung,exynos4212-usb2-phy"
> +	- "samsung,exynos5250-usb2-phy"
>  - reg : a list of registers used by phy driver
>  	- first and obligatory is the location of phy modules registers
>  - samsung,sysreg-phandle - handle to syscon used to control the system registers
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 2e433cd..74e9064 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -78,4 +78,12 @@ config PHY_EXYNOS4212_USB2
>  	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
>  	help
>  	  Enable USB PHY support for Exynos 4212
> +
> +config PHY_EXYNOS5250_USB2
> +	bool "Support for Exynos 5250"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on SOC_EXYNOS5250
> +	help
> +	  Enable USB PHY support for Exynos 5250

My comments for the previous patch is applicable here too..

Thanks
Kishon

> +
>  endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index fefc6c2..33c3ac1 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
>  obj-$(CONFIG_PHY_S5PV210_USB2)		+= phy-s5pv210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>  obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> +obj-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
> diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/phy-exynos5250-usb2.c
> new file mode 100644
> index 0000000..7aeebc8
> --- /dev/null
> +++ b/drivers/phy/phy-exynos5250-usb2.c
> @@ -0,0 +1,363 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>
> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +#define EXYNOS_5250_REFCLKSEL_CRYSTAL	0x0
> +#define EXYNOS_5250_REFCLKSEL_XO	0x1
> +#define EXYNOS_5250_REFCLKSEL_CLKCORE	0x2
> +
> +#define EXYNOS_5250_FSEL_9MHZ6		0x0
> +#define EXYNOS_5250_FSEL_10MHZ		0x1
> +#define EXYNOS_5250_FSEL_12MHZ		0x2
> +#define EXYNOS_5250_FSEL_19MHZ2		0x3
> +#define EXYNOS_5250_FSEL_20MHZ		0x4
> +#define EXYNOS_5250_FSEL_24MHZ		0x5
> +#define EXYNOS_5250_FSEL_50MHZ		0x7
> +
> +/* Normal host */
> +#define EXYNOS_5250_HOSTPHYCTRL0			0x0
> +
> +#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL		(0x1 << 31)
> +#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT	19
> +#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_MASK	\
> +		(0x3 << EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT)
> +#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT		16
> +#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK \
> +		(0x7 << EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT)
> +#define EXYNOS_5250_HOSTPHYCTRL0_TESTBURNIN		(0x1 << 11)
> +#define EXYNOS_5250_HOSTPHYCTRL0_RETENABLE		(0x1 << 10)
> +#define EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N		(0x1 << 9)
> +#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_MASK		(0x3 << 7)
> +#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_DUAL		(0x0 << 7)
> +#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ID0		(0x1 << 7)
> +#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ANALOGTEST	(0x2 << 7)
> +#define EXYNOS_5250_HOSTPHYCTRL0_SIDDQ			(0x1 << 6)
> +#define EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP		(0x1 << 5)
> +#define EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND		(0x1 << 4)
> +#define EXYNOS_5250_HOSTPHYCTRL0_WORDINTERFACE		(0x1 << 3)
> +#define EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST		(0x1 << 2)
> +#define EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST		(0x1 << 1)
> +#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST		(0x1 << 0)
> +
> +/* HSIC0 & HSCI1 */
> +#define EXYNOS_5250_HOSTPHYCTRL1			0x10
> +#define EXYNOS_5250_HOSTPHYCTRL2			0x20
> +
> +#define EXYNOS_5250_HOSTPHYCTRLX_REFCLKSEL_MASK		(0x3 << 23)
> +#define EXYNOS_5250_HOSTPHYCTRLX_REFCLKDIV_MASK		(0x7f << 16)
> +#define EXYNOS_5250_HOSTPHYCTRLX_SIDDQ			(0x1 << 6)
> +#define EXYNOS_5250_HOSTPHYCTRLX_FORCESLEEP		(0x1 << 5)
> +#define EXYNOS_5250_HOSTPHYCTRLX_FORCESUSPEND		(0x1 << 4)
> +#define EXYNOS_5250_HOSTPHYCTRLX_WORDINTERFACE		(0x1 << 3)
> +#define EXYNOS_5250_HOSTPHYCTRLX_UTMISWRST		(0x1 << 2)
> +#define EXYNOS_5250_HOSTPHYCTRLX_PHYSWRST		(0x1 << 0)
> +
> +/* EHCI control */
> +#define EXYNOS_5250_HOSTEHCICTRL			0x30
> +#define EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN		(0x1 << 29)
> +#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR4		(0x1 << 28)
> +#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR8		(0x1 << 27)
> +#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR16		(0x1 << 26)
> +#define EXYNOS_5250_HOSTEHCICTRL_AUTOPPDONOVRCUREN	(0x1 << 25)
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT	19
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK	\
> +		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT	13
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_MASK	\
> +		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT)
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL2_SHIFT	7
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK	\
> +		(0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT	1
> +#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_MASK \
> +		(0x1 << EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT)
> +#define EXYNOS_5250_HOSTEHCICTRL_SIMULATIONMODE		(0x1 << 0)
> +
> +/* OHCI control */
> +#define EXYNOS_5250_HOSTOHCICTRL                        0x34
> +#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT	1
> +#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_MASK \
> +		(0x3ff << EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT)
> +#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVALEN		(0x1 << 0)
> +
> +/* USBOTG */
> +#define EXYNOS_5250_USBOTGSYS				0x38
> +#define EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET		(0x1 << 14)
> +#define EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG		(0x1 << 13)
> +#define EXYNOS_5250_USBOTGSYS_PHY_SW_RST		(0x1 << 12)
> +#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT		9
> +#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK \
> +		(0x3 << EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT)
> +#define EXYNOS_5250_USBOTGSYS_ID_PULLUP			(0x1 << 8)
> +#define EXYNOS_5250_USBOTGSYS_COMMON_ON			(0x1 << 7)
> +#define EXYNOS_5250_USBOTGSYS_FSEL_SHIFT		4
> +#define EXYNOS_5250_USBOTGSYS_FSEL_MASK \
> +		(0x3 << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT)
> +#define EXYNOS_5250_USBOTGSYS_FORCE_SLEEP		(0x1 << 3)
> +#define EXYNOS_5250_USBOTGSYS_OTGDISABLE		(0x1 << 2)
> +#define EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG		(0x1 << 1)
> +#define EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND		(0x1 << 0)
> +
> +/* Isolation, configured in the power management unit */
> +#define EXYNOS_5250_USB_ISOL_OTG_OFFSET		0x704
> +#define EXYNOS_5250_USB_ISOL_OTG		(1 << 0)
> +#define EXYNOS_5250_USB_ISOL_HOST_OFFSET	0x708
> +#define EXYNOS_5250_USB_ISOL_HOST		(1 << 0)
> +
> +/* Mode swtich register */
> +#define EXYNOS_5250_MODE_SWITCH_OFFSET		0x230
> +#define EXYNOS_5250_MODE_SWITCH_MASK		1
> +#define EXYNOS_5250_MODE_SWITCH_DEVICE		0
> +#define EXYNOS_5250_MODE_SWITCH_HOST		1
> +
> +enum exynos4x12_phy_id {
> +	EXYNOS5250_DEVICE,
> +	EXYNOS5250_HOST,
> +	EXYNOS5250_HSIC0,
> +	EXYNOS5250_HSIC1,
> +	EXYNOS5250_NUM_PHYS,
> +};
> +
> +/*
> + * exynos5250_rate_to_clk() converts the supplied clock rate to the value that
> + * can be written to the phy register.
> + */
> +static int exynos5250_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	/* EXYNOS_5250_FSEL_MASK */
> +
> +	switch (rate) {
> +	case 9600 * KHZ:
> +		*reg = EXYNOS_5250_FSEL_9MHZ6;
> +		break;
> +	case 10 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_10MHZ;
> +		break;
> +	case 12 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_12MHZ;
> +		break;
> +	case 19200 * KHZ:
> +		*reg = EXYNOS_5250_FSEL_19MHZ2;
> +		break;
> +	case 20 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_20MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_24MHZ;
> +		break;
> +	case 50 * MHZ:
> +		*reg = EXYNOS_5250_FSEL_50MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 offset;
> +	u32 mask;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS5250_DEVICE:
> +		offset = EXYNOS_5250_USB_ISOL_OTG_OFFSET;
> +		mask = EXYNOS_5250_USB_ISOL_OTG;
> +		break;
> +	case EXYNOS5250_HOST:
> +		offset = EXYNOS_5250_USB_ISOL_HOST_OFFSET;
> +		mask = EXYNOS_5250_USB_ISOL_HOST;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void exynos5250_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 ctrl0;
> +	u32 otg;
> +	u32 ehci;
> +	u32 ohci;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS5250_DEVICE:
> +		regmap_update_bits(drv->reg_sys,
> +			EXYNOS_5250_MODE_SWITCH_OFFSET,
> +			EXYNOS_5250_MODE_SWITCH_MASK,
> +			EXYNOS_5250_MODE_SWITCH_DEVICE);
> +
> +		/* OTG configuration */
> +		otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +		/* The clock */
> +		otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
> +		otg |= inst->clk_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
> +		/* Reset */
> +		otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
> +			EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
> +			EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
> +		otg |=	EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
> +			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
> +			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
> +			EXYNOS_5250_USBOTGSYS_OTGDISABLE;
> +		/* Ref clock */
> +		otg &=	~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
> +		otg |=  EXYNOS_5250_REFCLKSEL_CLKCORE <<
> +					EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
> +		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +		udelay(100);
> +		otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
> +			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
> +			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
> +			EXYNOS_5250_USBOTGSYS_OTGDISABLE);
> +		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +
> +
> +		break;
> +	case EXYNOS5250_HOST:
> +		/* Host registers configuration */
> +		ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
> +		/* The clock */
> +		ctrl0 &= ~EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK;
> +		ctrl0 |= inst->clk_reg_val <<
> +					EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT;
> +
> +		/* Reset */
> +		ctrl0 &=	~(EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
> +				EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL |
> +				EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
> +				EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
> +				EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP);
> +		ctrl0 |=	EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
> +				EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST |
> +				EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N;
> +		writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
> +		udelay(10);
> +		ctrl0 &=	~(EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
> +				EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST);
> +		writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
> +
> +		/* OTG configuration */
> +		otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +		/* The clock */
> +		otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
> +		otg |= inst->clk_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
> +		/* Reset */
> +		otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
> +			EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
> +			EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
> +		otg |=	EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
> +			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
> +			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
> +			EXYNOS_5250_USBOTGSYS_OTGDISABLE;
> +		/* Ref clock */
> +		otg &=	~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
> +		otg |=  EXYNOS_5250_REFCLKSEL_CLKCORE <<
> +					EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
> +		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
> +		udelay(10);
> +		otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
> +			EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
> +			EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET);
> +
> +		/* Enable EHCI DMA burst */
> +		ehci = readl(drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
> +		ehci |=	EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN |
> +			EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 |
> +			EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 |
> +			EXYNOS_5250_HOSTEHCICTRL_ENAINCR16;
> +		writel(ehci, drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
> +
> +		/* OHCI settings */
> +		ohci = readl(drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
> +		/* Following code is based on the old driver */
> +		ohci |=	0x1 << 3;
> +		writel(ohci, drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
> +
> +		break;
> +	}
> +}
> +
> +static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	inst->enabled = 1;
> +	exynos5250_phy_pwr(inst, 1);
> +	exynos5250_isol(inst, 0);
> +
> +	return 0;
> +}
> +
> +static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	inst->enabled = 0;
> +	exynos5250_isol(inst, 1);
> +	exynos5250_phy_pwr(inst, 0);
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy exynos5250_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= EXYNOS5250_DEVICE,
> +		.rate_to_clk	= exynos5250_rate_to_clk,
> +		.power_on	= exynos5250_power_on,
> +		.power_off	= exynos5250_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= EXYNOS5250_HOST,
> +		.rate_to_clk	= exynos5250_rate_to_clk,
> +		.power_on	= exynos5250_power_on,
> +		.power_off	= exynos5250_power_off,
> +	},
> +	{
> +		.label		= "hsic0",
> +		.id		= EXYNOS5250_HSIC0,
> +		.rate_to_clk	= exynos5250_rate_to_clk,
> +		.power_on	= exynos5250_power_on,
> +		.power_off	= exynos5250_power_off,
> +	},
> +	{
> +		.label		= "hsic1",
> +		.id		= EXYNOS5250_HSIC1,
> +		.rate_to_clk	= exynos5250_rate_to_clk,
> +		.power_on	= exynos5250_power_on,
> +		.power_off	= exynos5250_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
> +	.num_phys		= EXYNOS5250_NUM_PHYS,
> +	.phys			= exynos5250_phys,
> +	.has_mode_switch	= 1,
> +};
> +
> diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
> index ef93fd3..d62e847 100644
> --- a/drivers/phy/phy-samsung-usb2.c
> +++ b/drivers/phy/phy-samsung-usb2.c
> @@ -116,6 +116,12 @@ static const struct of_device_id samsung_usb2_phy_of_match[] = {
>  		.data = &exynos4212_usb2_phy_config,
>  	},
>  #endif
> +#ifdef CONFIG_PHY_EXYNOS5250_USB2
> +	{
> +		.compatible = "samsung,exynos5250-usb2-phy",
> +		.data = &exynos5250_usb2_phy_config,
> +	},
> +#endif
>  	{ },
>  };
>  
> diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
> index 0f51dbb..0049e8a 100644
> --- a/drivers/phy/phy-samsung-usb2.h
> +++ b/drivers/phy/phy-samsung-usb2.h
> @@ -69,5 +69,6 @@ struct samsung_usb2_phy_config {
>  extern const struct samsung_usb2_phy_config s5pv210_usb2_phy_config;
>  extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
>  extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
> +extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config;
>  #endif
>  
> 

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

* RE: [PATCH v4 4/9] usb: ehci-s5p: Change to use phy provided by the generic phy framework
  2013-12-05 18:52     ` Alan Stern
  (?)
@ 2013-12-06 13:19     ` Kamil Debski
  -1 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 13:19 UTC (permalink / raw)
  To: 'Alan Stern'
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, kishon, Tomasz Figa, Sylwester Nawrocki,
	Marek Szyprowski, gautam.vivek, mat.krawczuk, yulgon.kim,
	p.paneri, av.tikhomirov, jg1.han, galak, matt.porter

Hi Alan,

Thank you for the review. Please find my replies inline.

> From: Alan Stern [mailto:stern@rowland.harvard.edu]
> Sent: Thursday, December 05, 2013 7:53 PM
> 
> On Thu, 5 Dec 2013, Kamil Debski wrote:
> 
> > Change the phy provider used from the old usb phy specific to a new
> > one using the generic phy framework.
> >
> > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> 
> > --- a/drivers/usb/host/ehci-exynos.c
> > +++ b/drivers/usb/host/ehci-exynos.c
> 
> > @@ -42,10 +42,10 @@
> >  static const char hcd_name[] = "ehci-exynos";  static struct
> > hc_driver __read_mostly exynos_ehci_hc_driver;
> >
> > +#define PHY_NUMBER 3
> >  struct exynos_ehci_hcd {
> >  	struct clk *clk;
> > -	struct usb_phy *phy;
> > -	struct usb_otg *otg;
> 
> Are you sure you want to remove that line?

Yes, I am. The new generic phy interface does not have the otg field in it.
 
> > +	struct phy *phy[PHY_NUMBER];
> >  };
> >
> >  #define to_exynos_ehci(hcd) (struct exynos_ehci_hcd
> > *)(hcd_to_ehci(hcd)->priv)
> 
> > @@ -102,13 +132,24 @@ static int exynos_ehci_probe(struct
> platform_device *pdev)
> >  					"samsung,exynos5440-ehci"))
> >  		goto skip_phy;
> >
> > -	phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
> > -	if (IS_ERR(phy)) {
> > -		usb_put_hcd(hcd);
> > -		dev_warn(&pdev->dev, "no platform data or transceiver
> defined\n");
> > -		return -EPROBE_DEFER;
> > -	} else {
> > -		exynos_ehci->phy = phy;
> > +	for_each_available_child_of_node(pdev->dev.of_node, child) {
> > +		err = of_property_read_u32(child, "reg", &phy_number);
> > +		if (err) {
> > +			dev_err(&pdev->dev, "Failed to parse device
tree\n");
> > +			return err;
> > +		}
> > +		if (phy_number >= PHY_NUMBER) {
> > +			dev_err(&pdev->dev, "Failed to parse device tree -
> number out of range\n");
> > +			return -EINVAL;
> 
> Do you need to call of_node_put(child) before each of these return
> statements?

You are right, thank you for spotting this.

> 
> > +		}
> > +		phy = devm_of_phy_get(&pdev->dev, child, 0);
> > +		of_node_put(child);
> > +		if (IS_ERR(phy)) {
> > +			dev_err(&pdev->dev, "Failed to get phy number %d",
> > +								phy_number);
> > +			return PTR_ERR(phy);
> > +		}
> > +		exynos_ehci->phy[phy_number] = phy;
> >  		exynos_ehci->otg = phy->otg;
> 
> Did you intend to remove this line?  Above, you removed the
> exynos_ehci->otg field.  I can't see how this patch would ever compile
> without an error.

Yes, I had this in a separate fix patch which I forgot to squash. Sorry for
this.

> >  	}
> >
> > @@ -149,11 +190,11 @@ skip_phy:
> >  		goto fail_io;
> >  	}
> >
> > -	if (exynos_ehci->otg)
> > -		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self);
> > -
> > -	if (exynos_ehci->phy)
> > -		usb_phy_init(exynos_ehci->phy);
> > +	err = exynos_phys_on(exynos_ehci->phy);
> > +	if (err) {
> > +		dev_err(&pdev->dev, "Failed to enabled phys\n");
> > +		goto fail_phys_on;
> 
> Why add a new statement label?  Just goto fail_io.

To me it seemed better to add a new label. I will drop it and use
goto fail_io, as you suggested.

> 
> > +	}
> >
> >  	ehci = hcd_to_ehci(hcd);
> >  	ehci->caps = hcd->regs;
> > @@ -172,8 +213,8 @@ skip_phy:
> >  	return 0;
> >
> >  fail_add_hcd:
> > -	if (exynos_ehci->phy)
> > -		usb_phy_shutdown(exynos_ehci->phy);
> > +	exynos_phys_off(exynos_ehci->phy);
> > +fail_phys_on:
> >  fail_io:
> >  	clk_disable_unprepare(exynos_ehci->clk);
> >  fail_clk:
> 
> Alan Stern

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland


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

* Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
@ 2013-12-06 15:01       ` Matt Porter
  0 siblings, 0 replies; 50+ messages in thread
From: Matt Porter @ 2013-12-06 15:01 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Kamil Debski, linux-kernel, linux-samsung-soc, linux-usb,
	devicetree, kyungmin.park, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak

On Fri, Dec 06, 2013 at 04:41:51PM +0530, Kishon Vijay Abraham I wrote:
> Hi,
> 
> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> > Change the used phy driver to the new Exynos USB phy driver that uses the
> > generic phy framework.
> > 
> > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > ---
> >  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
> >  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++-----
> >  2 files changed, 10 insertions(+), 5 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > index b83d428..9340d06 100644
> > --- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > @@ -24,6 +24,8 @@ Required properties:
> >      - first entry: must be "otg"
> >  - vusb_d-supply: phandle to voltage regulator of digital section,
> >  - vusb_a-supply: phandle to voltage regulator of analog section.
> > +- phys: from general PHY binding: phandle to the PHY device
> > +- phy-names: from general PHY binding: should be "usb2-phy"
> 
> are you sure it's usb2-phy. The example below seems to have a different value.

I requested this be changed to usb2-phy, looks like he just missed the
update to the example.

> 
> >  
> >  Example
> >  -----
> > @@ -36,5 +38,7 @@ Example
> >  		clock-names = "otg";
> >  		vusb_d-supply = <&vusb_reg>;
> >  		vusb_a-supply = <&vusbdac_reg>;
> > +		phys = <&usb2phy 0>;
> > +		phy-names = "device";
> >  	};
> >  
> > diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
> > index eccb147..db096fd 100644
> > --- a/drivers/usb/gadget/s3c-hsotg.c
> > +++ b/drivers/usb/gadget/s3c-hsotg.c
> > @@ -31,6 +31,7 @@
> >  #include <linux/regulator/consumer.h>
> >  #include <linux/of.h>
> >  #include <linux/of_platform.h>
> > +#include <linux/phy/phy.h>
> >  
> >  #include <linux/usb/ch9.h>
> >  #include <linux/usb/gadget.h>
> > @@ -162,7 +163,7 @@ struct s3c_hsotg_ep {
> >  struct s3c_hsotg {
> >  	struct device		 *dev;
> >  	struct usb_gadget_driver *driver;
> > -	struct usb_phy		*phy;
> > +	struct phy		 *phy;
> >  	struct s3c_hsotg_plat	 *plat;
> >  
> >  	spinlock_t              lock;
> > @@ -2905,7 +2906,7 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
> >  	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
> >  
> >  	if (hsotg->phy)
> > -		usb_phy_init(hsotg->phy);
> > +		phy_power_on(hsotg->phy);
> >  	else if (hsotg->plat->phy_init)
> >  		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
> >  }
> > @@ -2922,7 +2923,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
> >  	struct platform_device *pdev = to_platform_device(hsotg->dev);
> >  
> >  	if (hsotg->phy)
> > -		usb_phy_shutdown(hsotg->phy);
> > +		phy_power_off(hsotg->phy);
> >  	else if (hsotg->plat->phy_exit)
> >  		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
> >  }
> > @@ -3529,7 +3530,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
> >  static int s3c_hsotg_probe(struct platform_device *pdev)
> >  {
> >  	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
> > -	struct usb_phy *phy;
> > +	struct phy *phy;
> >  	struct device *dev = &pdev->dev;
> >  	struct s3c_hsotg_ep *eps;
> >  	struct s3c_hsotg *hsotg;
> > @@ -3544,7 +3545,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
> >  		return -ENOMEM;
> >  	}
> >  
> > -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
> > +	phy = devm_phy_get(&pdev->dev, "usb2-phy");
> >  	if (IS_ERR(phy)) {
> >  		/* Fallback for pdata */
> >  		plat = dev_get_platdata(&pdev->dev);
> > 
> 

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

* Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
@ 2013-12-06 15:01       ` Matt Porter
  0 siblings, 0 replies; 50+ messages in thread
From: Matt Porter @ 2013-12-06 15:01 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Kamil Debski, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ,
	t.figa-Sze3O3UU22JBDgjK7y7TUQ, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ,
	mat.krawczuk-Re5JQEeQqe8AvxtiuMwx3w,
	yulgon.kim-Sze3O3UU22JBDgjK7y7TUQ,
	p.paneri-Sze3O3UU22JBDgjK7y7TUQ,
	av.tikhomirov-Sze3O3UU22JBDgjK7y7TUQ,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, galak-sgV2jX0FEOL9JmXXK+q4OQ

On Fri, Dec 06, 2013 at 04:41:51PM +0530, Kishon Vijay Abraham I wrote:
> Hi,
> 
> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> > Change the used phy driver to the new Exynos USB phy driver that uses the
> > generic phy framework.
> > 
> > Signed-off-by: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> > Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> > ---
> >  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
> >  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++-----
> >  2 files changed, 10 insertions(+), 5 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > index b83d428..9340d06 100644
> > --- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > @@ -24,6 +24,8 @@ Required properties:
> >      - first entry: must be "otg"
> >  - vusb_d-supply: phandle to voltage regulator of digital section,
> >  - vusb_a-supply: phandle to voltage regulator of analog section.
> > +- phys: from general PHY binding: phandle to the PHY device
> > +- phy-names: from general PHY binding: should be "usb2-phy"
> 
> are you sure it's usb2-phy. The example below seems to have a different value.

I requested this be changed to usb2-phy, looks like he just missed the
update to the example.

> 
> >  
> >  Example
> >  -----
> > @@ -36,5 +38,7 @@ Example
> >  		clock-names = "otg";
> >  		vusb_d-supply = <&vusb_reg>;
> >  		vusb_a-supply = <&vusbdac_reg>;
> > +		phys = <&usb2phy 0>;
> > +		phy-names = "device";
> >  	};
> >  
> > diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
> > index eccb147..db096fd 100644
> > --- a/drivers/usb/gadget/s3c-hsotg.c
> > +++ b/drivers/usb/gadget/s3c-hsotg.c
> > @@ -31,6 +31,7 @@
> >  #include <linux/regulator/consumer.h>
> >  #include <linux/of.h>
> >  #include <linux/of_platform.h>
> > +#include <linux/phy/phy.h>
> >  
> >  #include <linux/usb/ch9.h>
> >  #include <linux/usb/gadget.h>
> > @@ -162,7 +163,7 @@ struct s3c_hsotg_ep {
> >  struct s3c_hsotg {
> >  	struct device		 *dev;
> >  	struct usb_gadget_driver *driver;
> > -	struct usb_phy		*phy;
> > +	struct phy		 *phy;
> >  	struct s3c_hsotg_plat	 *plat;
> >  
> >  	spinlock_t              lock;
> > @@ -2905,7 +2906,7 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
> >  	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
> >  
> >  	if (hsotg->phy)
> > -		usb_phy_init(hsotg->phy);
> > +		phy_power_on(hsotg->phy);
> >  	else if (hsotg->plat->phy_init)
> >  		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
> >  }
> > @@ -2922,7 +2923,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
> >  	struct platform_device *pdev = to_platform_device(hsotg->dev);
> >  
> >  	if (hsotg->phy)
> > -		usb_phy_shutdown(hsotg->phy);
> > +		phy_power_off(hsotg->phy);
> >  	else if (hsotg->plat->phy_exit)
> >  		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
> >  }
> > @@ -3529,7 +3530,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
> >  static int s3c_hsotg_probe(struct platform_device *pdev)
> >  {
> >  	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
> > -	struct usb_phy *phy;
> > +	struct phy *phy;
> >  	struct device *dev = &pdev->dev;
> >  	struct s3c_hsotg_ep *eps;
> >  	struct s3c_hsotg *hsotg;
> > @@ -3544,7 +3545,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
> >  		return -ENOMEM;
> >  	}
> >  
> > -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
> > +	phy = devm_phy_get(&pdev->dev, "usb2-phy");
> >  	if (IS_ERR(phy)) {
> >  		/* Fallback for pdata */
> >  		plat = dev_get_platdata(&pdev->dev);
> > 
> 
--
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] 50+ messages in thread

* RE: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
  2013-12-06 10:59     ` Kishon Vijay Abraham I
  (?)
@ 2013-12-06 16:28     ` Kamil Debski
  2013-12-09  7:56         ` Kishon Vijay Abraham I
  -1 siblings, 1 reply; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 16:28 UTC (permalink / raw)
  To: 'Kishon Vijay Abraham I',
	linux-kernel, linux-samsung-soc, linux-usb, devicetree, balbi,
	'Greg Kroah-Hartman'
  Cc: kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

Hi Kishon,

Thank you for the review.

> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
> Sent: Friday, December 06, 2013 11:59 AM
> 
> Hi,
> 
> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> > Add a new driver for the Exynos USB PHY. The new driver uses the
> > generic PHY framework. The driver includes support for the Exynos
> 4x10
> > and 4x12 SoC families.
> >
> > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > ---
> >  .../devicetree/bindings/phy/samsung-usbphy.txt     |   54 ++++
> >  drivers/phy/Kconfig                                |   20 ++
> >  drivers/phy/Makefile                               |    3 +
> >  drivers/phy/phy-exynos4210-usb2.c                  |  264
> +++++++++++++++++
> >  drivers/phy/phy-exynos4212-usb2.c                  |  312
> ++++++++++++++++++++
> >  drivers/phy/phy-samsung-usb2.c                     |  228
> ++++++++++++++
> >  drivers/phy/phy-samsung-usb2.h                     |   72 +++++
> >  7 files changed, 953 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> >  create mode 100644 drivers/phy/phy-exynos4210-usb2.c  create mode
> > 100644 drivers/phy/phy-exynos4212-usb2.c  create mode 100644
> > drivers/phy/phy-samsung-usb2.c  create mode 100644
> > drivers/phy/phy-samsung-usb2.h
> >
> > diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> > b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> > new file mode 100644
> > index 0000000..cadbf70
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> 
> use the existing samsung-phy.txt.

Ok.

> > @@ -0,0 +1,54 @@
> > +Samsung S5P/EXYNOS SoC series USB PHY
> > +-------------------------------------------------
> > +
> > +Required properties:
> > +- compatible : should be one of the listed compatibles:
> > +	- "samsung,exynos4210-usb2-phy"
> > +	- "samsung,exynos4212-usb2-phy"
> > +- reg : a list of registers used by phy driver
> > +	- first and obligatory is the location of phy modules registers
> > +- samsung,sysreg-phandle - handle to syscon used to control the
> > +system registers
> > +- samsung,pmureg-phandle - handle to syscon used to control PMU
> > +registers
> > +- #phy-cells : from the generic phy bindings, must be 1;
> > +- clocks and clock-names:
> > +	- the "phy" clocks is required by the phy module
> > +	- next for each of the phys a clock has to be assidned, this
> clock
> 
> %s/assidned/assigned/

Thank you for spotting this.

> > +	  will be used to determine clocking frequency for the phys
> > +	  (the labels are specified in the paragraph below)
> > +
> > +The first phandle argument in the PHY specifier identifies the PHY,
> > +its meaning is compatible dependent. For the currently supported
> SoCs
> > +(Exynos 4210 and Exynos 4212) it is as follows:
> > +  0 - USB device ("device"),
> > +  1 - USB host ("host"),
> > +  2 - HSIC0 ("hsic0"),
> > +  3 - HSIC1 ("hsic1"),
> > +
> > +Exynos 4210 and Exynos 4212 use mode switching and require that mode
> > +switch register is supplied.
> > +
> > +Example:
> > +
> > +For Exynos 4412 (compatible with Exynos 4212):
> > +
> > +usbphy: phy@125B0000 {
> 
> use lower case for address here...

Ok.

> > +	compatible = "samsung,exynos4212-usb2-phy";
> > +	reg = <0x125B0000 0x100 0x10020704 0x0c 0x1001021c 0x4>;
> and here..
> > +	clocks = <&clock 305>, <&clock 2>, <&clock 2>, <&clock 2>,
> > +							<&clock 2>;
> > +	clock-names = "phy", "device", "host", "hsic0", "hsic1";
> > +	status = "okay";
> > +	#phy-cells = <1>;
> > +	samsung,sysreg-phandle = <&sys_reg>;
> > +	samsung,pmureg-phandle = <&pmu_reg>; };
> > +
> > +Then the PHY can be used in other nodes such as:
> > +
> > +phy-consumer@12340000 {
> > +	phys = <&usbphy 2>;
> > +	phy-names = "phy";
> > +};
> > +
> > +Refer to DT bindings documentation of particular PHY consumer
> devices
> > +for more information about required PHYs and the way of
> specification.
> > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index
> > a344f3d..b29018f 100644
> > --- a/drivers/phy/Kconfig
> > +++ b/drivers/phy/Kconfig
> > @@ -51,4 +51,24 @@ config PHY_EXYNOS_DP_VIDEO
> >  	help
> >  	  Support for Display Port PHY found on Samsung EXYNOS SoCs.
> >
> > +config PHY_SAMSUNG_USB2
> > +	tristate "Samsung USB 2.0 PHY driver"
> > +	help
> > +	  Enable this to support Samsung USB phy helper driver for
> Samsung SoCs.
> > +	  This driver provides common interface to interact, for Samsung
> > +	  USB 2.0 PHY driver.
> > +
> > +config PHY_EXYNOS4210_USB2
> > +	bool "Support for Exynos 4210"
> > +	depends on PHY_SAMSUNG_USB2
> > +	depends on CPU_EXYNOS4210
> 
> select GENERIC_PHY here?

I think that depends on PHY_SAMSUNG_USB2 is better in this place.
However, I agree that I should add select GENERIC_PHY to PHY_SAMSUNG_USB2.

The reason why I am saying this is that I like how it looks in
menuconfig. Selecting PHY_SAMSUNG_USB2 expands more options and if
unselected the menu looks tidier.

> > +	help
> > +	  Enable USB PHY support for Exynos 4210
> 
> Add more explanation here and make checkpatch happy.

Here I think we should not treat checkpatch as an oracle. I also noticed
these warnings, but I think that writing a four line description for
SoC specific options in this menu is an overkill. In addition, checkpatch
also complains for the following entries in Kconfig file:
- PHY_EXYNOS_MIPI_VIDEO
- PHY_EXYNOS_DP_VIDEO
- PHY_SAMSUNG_USB2 (here expanding the description may be justified, but
  I think the current description is enough)

But thank you for directing my attention to the Kconfig file. I noticed
That SoC specific Kconfig entries should have "USB 2.0" instead of just
"USB".

> > +
> > +config PHY_EXYNOS4212_USB2
> > +	bool "Support for Exynos 4212"
> > +	depends on PHY_SAMSUNG_USB2
> > +	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
> 
> select GENERIC_PHY.

Please check my reply above.

> > +	help
> > +	  Enable USB PHY support for Exynos 4212
> 
> more explanation here too..

Please check my reply above.

> >  endmenu
> > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index
> > d0caae9..9f4befd 100644
> > --- a/drivers/phy/Makefile
> > +++ b/drivers/phy/Makefile
> > @@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-
> video.o
> >  obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
> >  obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
> >  obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
> > +obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
> > +obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
> > +obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> > diff --git a/drivers/phy/phy-exynos4210-usb2.c
> > b/drivers/phy/phy-exynos4210-usb2.c
> > new file mode 100644
> > index 0000000..a02e5c2
> > --- /dev/null
> > +++ b/drivers/phy/phy-exynos4210-usb2.c
> > @@ -0,0 +1,264 @@
> > +/*
> > + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
> > + *
> > + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> > + * Author: Kamil Debski <k.debski@samsung.com>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > +modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/spinlock.h>
> 
> You've included most of the above header files in phy-samsung-usb2.h
> which you are including below.

I agree that includes in phy-samsung-usb2.h could use a cleanup. On the
other
hand my opinion is that a .c file should include all .h files that are used
in
this .c file. Relaying on .h file to include another .h doesn't seem good to
me.

> > +#include "phy-samsung-usb2.h"
> > +
> > +/* Exynos USB PHY registers */
> > +
> > +/* PHY power control */
> > +#define EXYNOS_4210_UPHYPWR			0x0
> > +
> > +#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
> 
> use BIT() here and everywhere below.

All right.

> > +#define EXYNOS_4210_UPHYPWR_PHY0_PWR		(1 << 3)
> 
> replace PHY0 here with DEV so it looks similar to EXYNOS_4212.
> > +#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
> > +#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		(1 << 5)
> > +#define EXYNOS_4210_UPHYPWR_PHY0	( \
> > +	EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
> > +	EXYNOS_4210_UPHYPWR_PHY0_PWR | \
> > +	EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
> > +	EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
> > +
> > +#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND	(1 << 6)
> 
> replace PHY0 here with HOST so it looks similar to EXYNOS_4212.

Thank you for spotting this inconsistence. I will fix that. But I
rather incline to use PHY0/1 instead of DEVICE/HOST as it will be
then consistent with the date sheet.

> > +#define EXYNOS_4210_UPHYPWR_PHY1_PWR		(1 << 7)
> > +#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		(1 << 8)
> > +#define EXYNOS_4210_UPHYPWR_PHY1 ( \
> > +	EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
> > +	EXYNOS_4210_UPHYPWR_PHY1_PWR | \
> > +	EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
> > +
> > +#define EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> > +#define EXYNOS_4210_UPHYPWR_HSCI0_SLEEP		(1 << 10)
> > +#define EXYNOS_4210_UPHYPWR_HSCI0 ( \
> > +	EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND | \
> > +	EXYNOS_4210_UPHYPWR_HSCI0_SLEEP)
> > +
> > +#define EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND	(1 << 11)
> > +#define EXYNOS_4210_UPHYPWR_HSCI1_SLEEP		(1 << 12)
> > +#define EXYNOS_4210_UPHYPWR_HSCI1 ( \
> > +	EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND | \
> > +	EXYNOS_4210_UPHYPWR_HSCI1_SLEEP)
> > +
> > +/* PHY clock control */
> > +#define EXYNOS_4210_UPHYCLK			0x4
> > +
> > +#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
> > +#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
> > +#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
> > +#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> > +
> > +#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
> > +#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> > +#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> > +
> > +/* PHY reset control */
> > +#define EXYNOS_4210_UPHYRST			0x8
> > +
> > +#define EXYNOS_4210_URSTCON_PHY0		(1 << 0)
> > +#define EXYNOS_4210_URSTCON_OTG_HLINK		(1 << 1)
> > +#define EXYNOS_4210_URSTCON_OTG_PHYLINK		(1 << 2)
> > +#define EXYNOS_4210_URSTCON_PHY1_ALL		(1 << 3)
> > +#define EXYNOS_4210_URSTCON_PHY1_P0		(1 << 4)
> > +#define EXYNOS_4210_URSTCON_PHY1_P1P2		(1 << 5)
> > +#define EXYNOS_4210_URSTCON_HOST_LINK_ALL	(1 << 6)
> > +#define EXYNOS_4210_URSTCON_HOST_LINK_P0	(1 << 7)
> > +#define EXYNOS_4210_URSTCON_HOST_LINK_P1	(1 << 8)
> > +#define EXYNOS_4210_URSTCON_HOST_LINK_P2	(1 << 9)
> > +
> > +/* Isolation, configured in the power management unit */
> > +#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
> > +#define EXYNOS_4210_USB_ISOL_DEVICE		(1 << 0)
> > +#define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
> > +#define EXYNOS_4210_USB_ISOL_HOST		(1 << 0)
> > +
> > +/* USBYPHY1 Floating prevention */
> > +#define EXYNOS_4210_UPHY1CON			0x34
> > +#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION	0x1
> > +
> > +/* Mode switching SUB Device <-> Host */
> > +#define EXYNOS_4210_MODE_SWITCH_OFFSET		0x21c
> > +#define EXYNOS_4210_MODE_SWITCH_MASK		1
> > +#define EXYNOS_4210_MODE_SWITCH_DEVICE		0
> > +#define EXYNOS_4210_MODE_SWITCH_HOST		1
> > +
> > +enum exynos4210_phy_id {
> > +	EXYNOS4210_DEVICE,
> > +	EXYNOS4210_HOST,
> > +	EXYNOS4210_HSIC0,
> > +	EXYNOS4210_HSIC1,
> > +	EXYNOS4210_NUM_PHYS,
> > +};
> > +
> > +/*
> > + * exynos4210_rate_to_clk() converts the supplied clock rate to the
> > +value that
> > + * can be written to the phy register.
> > + */
> > +static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg) {
> > +	switch (rate) {
> > +	case 12 * MHZ:
> > +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
> > +		break;
> > +	case 24 * MHZ:
> > +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
> > +		break;
> > +	case 48 * MHZ:
> > +		reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
> 
> %s/reg/*Reg

Thank you.

> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void exynos4210_isol(struct samsung_usb2_phy_instance *inst,
> > +bool on) {
> > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > +	u32 offset;
> > +	u32 mask;
> > +
> > +	switch (inst->cfg->id) {
> > +	case EXYNOS4210_DEVICE:
> > +		offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
> > +		mask = EXYNOS_4210_USB_ISOL_DEVICE;
> > +		break;
> > +	case EXYNOS4210_HOST:
> > +		offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
> > +		mask = EXYNOS_4210_USB_ISOL_HOST;
> > +		break;
> > +	default:
> > +		return;
> > +	};
> > +
> > +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask); }
> > +
> > +static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance
> > +*inst, bool on) {
> > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > +	u32 rstbits = 0;
> > +	u32 phypwr = 0;
> > +	u32 rst;
> > +	u32 pwr;
> > +
> > +	switch (inst->cfg->id) {
> > +	case EXYNOS4210_DEVICE:
> > +		phypwr =	EXYNOS_4210_UPHYPWR_PHY0;
> > +		rstbits =	EXYNOS_4210_URSTCON_PHY0;
> > +		break;
> > +	case EXYNOS4210_HOST:
> > +		phypwr =	EXYNOS_4210_UPHYPWR_PHY1;
> > +		rstbits =	EXYNOS_4210_URSTCON_PHY1_ALL |
> > +				EXYNOS_4210_URSTCON_PHY1_P0 |
> > +				EXYNOS_4210_URSTCON_PHY1_P1P2 |
> > +				EXYNOS_4210_URSTCON_HOST_LINK_ALL |
> > +				EXYNOS_4210_URSTCON_HOST_LINK_P0;
> > +		writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
> > +		break;
> > +	case EXYNOS4210_HSIC0:
> > +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI0;
> > +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> > +				EXYNOS_4210_URSTCON_HOST_LINK_P1;
> > +		break;
> > +	case EXYNOS4210_HSIC1:
> > +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI1;
> > +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> > +				EXYNOS_4210_URSTCON_HOST_LINK_P2;
> > +		break;
> > +	};
> > +
> > +	if (on) {
> > +		writel(inst->clk_reg_val, drv->reg_phy +
> EXYNOS_4210_UPHYCLK);
> > +
> > +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> > +		pwr &= ~phypwr;
> > +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> > +
> > +		rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
> > +		rst |= rstbits;
> > +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
> > +		udelay(10);
> > +		rst &= ~rstbits;
> > +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
> 
> Do you have to reset during every power on? IMO this reset should be
> done once in phy_init.

It seems that this reset is neded by the hardware.

> > +	} else {
> > +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> > +		pwr |= phypwr;
> > +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> > +	}
> > +}
> > +
> > +static int exynos4210_power_on(struct samsung_usb2_phy_instance
> > +*inst) {
> > +	/* Order of initialisation is important - first power then
> isolation */
> > +	exynos4210_phy_pwr(inst, 1);
> > +	exynos4210_isol(inst, 0);
> > +
> > +	return 0;
> > +}
> > +
> > +static int exynos4210_power_off(struct samsung_usb2_phy_instance
> > +*inst) {
> > +	exynos4210_isol(inst, 1);
> > +	exynos4210_phy_pwr(inst, 0);
> > +
> > +	return 0;
> > +}
> > +
> > +
> > +static const struct samsung_usb2_common_phy exynos4210_phys[] = {
> > +	{
> > +		.label		= "device",
> > +		.id		= EXYNOS4210_DEVICE,
> > +		.rate_to_clk	= exynos4210_rate_to_clk,
> > +		.power_on	= exynos4210_power_on,
> > +		.power_off	= exynos4210_power_off,
> > +	},
> > +	{
> > +		.label		= "host",
> > +		.id		= EXYNOS4210_HOST,
> > +		.rate_to_clk	= exynos4210_rate_to_clk,
> > +		.power_on	= exynos4210_power_on,
> > +		.power_off	= exynos4210_power_off,
> > +	},
> > +	{
> > +		.label		= "hsic0",
> > +		.id		= EXYNOS4210_HSIC0,
> > +		.rate_to_clk	= exynos4210_rate_to_clk,
> > +		.power_on	= exynos4210_power_on,
> > +		.power_off	= exynos4210_power_off,
> > +	},
> > +	{
> > +		.label		= "hsic1",
> > +		.id		= EXYNOS4210_HSIC1,
> > +		.rate_to_clk	= exynos4210_rate_to_clk,
> > +		.power_on	= exynos4210_power_on,
> > +		.power_off	= exynos4210_power_off,
> > +	},
> > +	{},
> > +};
> > +
> > +const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
> > +	.num_phys		= EXYNOS4210_NUM_PHYS,
> > +	.phys			= exynos4210_phys,
> > +	.has_mode_switch	= 1,
> > +};
> > +
> > diff --git a/drivers/phy/phy-exynos4212-usb2.c
> > b/drivers/phy/phy-exynos4212-usb2.c
> > new file mode 100644
> > index 0000000..375ece0
> > --- /dev/null
> > +++ b/drivers/phy/phy-exynos4212-usb2.c
> > @@ -0,0 +1,312 @@
> > +/*
> > + * Samsung S5P/EXYNOS SoC series USB PHY driver - Exynos 4212
> support
> > + *
> > + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> > + * Author: Kamil Debski <k.debski@samsung.com>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > +modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/spinlock.h>
> 
> You've included most of the above header files in phy-samsung-usb2.h
> which you are including below.

Please see my reply above.

> > +#include "phy-samsung-usb2.h"
> > +
> > +/* Exynos USB PHY registers */
> > +
> > +/* PHY power control */
> > +#define EXYNOS_4212_UPHYPWR			0x0
> > +
> > +#define EXYNOS_4212_UPHYPWR_DEV_SUSPEND		(1 << 0)
> 
> use BIT() here and below..

All right.

> > +#define EXYNOS_4212_UPHYPWR_DEV_PWR		(1 << 3)
> > +#define EXYNOS_4212_UPHYPWR_DEV_OTG_PWR		(1 << 4)
> > +#define EXYNOS_4212_UPHYPWR_DEV_SLEEP		(1 << 5)
> > +#define EXYNOS_4212_UPHYPWR_DEV	( \
> > +	EXYNOS_4212_UPHYPWR_DEV_SUSPEND | \
> > +	EXYNOS_4212_UPHYPWR_DEV_PWR | \
> > +	EXYNOS_4212_UPHYPWR_DEV_OTG_PWR | \
> > +	EXYNOS_4212_UPHYPWR_DEV_SLEEP)
> > +
> > +#define EXYNOS_4212_UPHYPWR_HOST_SUSPEND	(1 << 6)
> > +#define EXYNOS_4212_UPHYPWR_HOST_PWR		(1 << 7)
> > +#define EXYNOS_4212_UPHYPWR_HOST_SLEEP		(1 << 8)
> > +#define EXYNOS_4212_UPHYPWR_HOST ( \
> > +	EXYNOS_4212_UPHYPWR_HOST_SUSPEND | \
> > +	EXYNOS_4212_UPHYPWR_HOST_PWR | \
> > +	EXYNOS_4212_UPHYPWR_HOST_SLEEP)
> > +
> > +#define EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> > +#define EXYNOS_4212_UPHYPWR_HSCI0_PWR		(1 << 10)
> > +#define EXYNOS_4212_UPHYPWR_HSCI0_SLEEP		(1 << 11)
> > +#define EXYNOS_4212_UPHYPWR_HSCI0 ( \
> > +	EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND | \
> > +	EXYNOS_4212_UPHYPWR_HSCI0_PWR | \
> > +	EXYNOS_4212_UPHYPWR_HSCI0_SLEEP)
> > +
> > +#define EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND	(1 << 12)
> > +#define EXYNOS_4212_UPHYPWR_HSCI1_PWR		(1 << 13)
> > +#define EXYNOS_4212_UPHYPWR_HSCI1_SLEEP		(1 << 14)
> > +#define EXYNOS_4212_UPHYPWR_HSCI1 ( \
> > +	EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND | \
> > +	EXYNOS_4212_UPHYPWR_HSCI1_PWR | \
> > +	EXYNOS_4212_UPHYPWR_HSCI1_SLEEP)
> > +
> > +/* PHY clock control */
> > +#define EXYNOS_4212_UPHYCLK			0x4
> > +
> > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_MASK	(0x7 << 0)
> > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6	(0x0 << 0)
> > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ	(0x1 << 0)
> > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2	(0x3 << 0)
> > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ	(0x4 << 0)
> > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ	(0x5 << 0)
> > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ	(0x7 << 0)
> > +
> > +#define EXYNOS_4212_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 3)
> > +#define EXYNOS_4212_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> > +#define EXYNOS_4212_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> > +
> > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_MASK	(0x7f << 10)
> > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_12MHZ	(0x24 << 10)
> > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_15MHZ	(0x1c << 10)
> > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_16MHZ	(0x1a << 10)
> > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_19MHZ2	(0x15 << 10)
> > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_20MHZ	(0x14 << 10)
> > +
> > +/* PHY reset control */
> > +#define EXYNOS_4212_UPHYRST			0x8
> > +
> > +#define EXYNOS_4212_URSTCON_DEVICE		(1 << 0)
> > +#define EXYNOS_4212_URSTCON_OTG_HLINK		(1 << 1)
> > +#define EXYNOS_4212_URSTCON_OTG_PHYLINK		(1 << 2)
> > +#define EXYNOS_4212_URSTCON_HOST_PHY		(1 << 3)
> > +#define EXYNOS_4212_URSTCON_PHY1		(1 << 4)
> > +#define EXYNOS_4212_URSTCON_HSIC0		(1 << 5)
> > +#define EXYNOS_4212_URSTCON_HSIC1		(1 << 6)
> > +#define EXYNOS_4212_URSTCON_HOST_LINK_ALL	(1 << 7)
> > +#define EXYNOS_4212_URSTCON_HOST_LINK_P0	(1 << 8)
> > +#define EXYNOS_4212_URSTCON_HOST_LINK_P1	(1 << 9)
> > +#define EXYNOS_4212_URSTCON_HOST_LINK_P2	(1 << 10)
> > +
> > +/* Isolation, configured in the power management unit */
> > +#define EXYNOS_4212_USB_ISOL_OFFSET		0x704
> > +#define EXYNOS_4212_USB_ISOL_OTG		(1 << 0)
> > +#define EXYNOS_4212_USB_ISOL_HSIC0_OFFSET	0x708
> > +#define EXYNOS_4212_USB_ISOL_HSIC0		(1 << 0)
> > +#define EXYNOS_4212_USB_ISOL_HSIC1_OFFSET	0x70c
> > +#define EXYNOS_4212_USB_ISOL_HSIC1		(1 << 0)
> > +
> > +/* Mode switching SUB Device <-> Host */
> > +#define EXYNOS_4212_MODE_SWITCH_OFFSET		0x21c
> > +#define EXYNOS_4212_MODE_SWITCH_MASK		1
> > +#define EXYNOS_4212_MODE_SWITCH_DEVICE		0
> > +#define EXYNOS_4212_MODE_SWITCH_HOST		1
> > +
> > +enum exynos4x12_phy_id {
> > +	EXYNOS4212_DEVICE,
> > +	EXYNOS4212_HOST,
> > +	EXYNOS4212_HSIC0,
> > +	EXYNOS4212_HSIC1,
> > +	EXYNOS4212_NUM_PHYS,
> > +};
> > +
> > +/*
> > + * exynos4212_rate_to_clk() converts the supplied clock rate to the
> > +value that
> > + * can be written to the phy register.
> > + */
> > +static int exynos4212_rate_to_clk(unsigned long rate, u32 *reg) {
> > +	/* EXYNOS_4212_UPHYCLK_PHYFSEL_MASK */
> > +
> > +	switch (rate) {
> > +	case 9600 * KHZ:
> > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6;
> > +		break;
> > +	case 10 * MHZ:
> > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ;
> > +		break;
> > +	case 12 * MHZ:
> > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ;
> > +		break;
> > +	case 19200 * KHZ:
> > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2;
> > +		break;
> > +	case 20 * MHZ:
> > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ;
> > +		break;
> > +	case 24 * MHZ:
> > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ;
> > +		break;
> > +	case 50 * MHZ:
> > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ;
> > +		break;
> > +	default:
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static void exynos4212_isol(struct samsung_usb2_phy_instance *inst,
> > +bool on) {
> > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > +	u32 offset;
> > +	u32 mask;
> > +
> > +	switch (inst->cfg->id) {
> > +	case EXYNOS4212_DEVICE:
> > +	case EXYNOS4212_HOST:
> > +		offset = EXYNOS_4212_USB_ISOL_OFFSET;
> > +		mask = EXYNOS_4212_USB_ISOL_OTG;
> > +		break;
> > +	case EXYNOS4212_HSIC0:
> > +		offset = EXYNOS_4212_USB_ISOL_HSIC0_OFFSET;
> > +		mask = EXYNOS_4212_USB_ISOL_HSIC0;
> > +		break;
> > +	case EXYNOS4212_HSIC1:
> > +		offset = EXYNOS_4212_USB_ISOL_HSIC1_OFFSET;
> > +		mask = EXYNOS_4212_USB_ISOL_HSIC1;
> > +		break;
> > +	default:
> > +		return;
> > +	};
> > +
> > +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask); }
> > +
> > +static void exynos4212_phy_pwr(struct samsung_usb2_phy_instance
> > +*inst, bool on) {
> > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > +	u32 rstbits = 0;
> > +	u32 phypwr = 0;
> > +	u32 rst;
> > +	u32 pwr;
> > +
> > +	switch (inst->cfg->id) {
> > +	case EXYNOS4212_DEVICE:
> > +		phypwr =	EXYNOS_4212_UPHYPWR_DEV;
> > +		rstbits =	EXYNOS_4212_URSTCON_DEVICE;
> > +		break;
> > +	case EXYNOS4212_HOST:
> > +		phypwr =	EXYNOS_4212_UPHYPWR_HOST;
> > +		rstbits =	EXYNOS_4212_URSTCON_HOST_PHY;
> > +		break;
> > +	case EXYNOS4212_HSIC0:
> > +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI0;
> > +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> > +				EXYNOS_4212_URSTCON_HOST_LINK_P0 |
> > +				EXYNOS_4212_URSTCON_HOST_PHY;
> > +		break;
> > +	case EXYNOS4212_HSIC1:
> > +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI1;
> > +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> > +				EXYNOS_4212_URSTCON_HOST_LINK_P1;
> > +		break;
> > +	};
> > +
> > +	if (on) {
> > +		writel(inst->clk_reg_val, drv->reg_phy +
> EXYNOS_4212_UPHYCLK);
> > +
> > +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> > +		pwr &= ~phypwr;
> > +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> > +
> > +		rst = readl(drv->reg_phy + EXYNOS_4212_UPHYRST);
> > +		rst |= rstbits;
> > +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
> > +		udelay(10);
> > +		rst &= ~rstbits;
> > +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
> 
> reset should be done once in init?

The hardware seems to need this reset.

> > +	} else {
> > +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> > +		pwr |= phypwr;
> > +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> > +	}
> > +}
> > +
> > +static int exynos4212_power_on(struct samsung_usb2_phy_instance
> > +*inst) {
> > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > +
> > +	inst->enabled = 1;
> > +	exynos4212_phy_pwr(inst, 1);
> > +	exynos4212_isol(inst, 0);
> > +
> > +	/* Power on the device, as it is necessary for HSIC to work */
> 
> This looks weird. How powering on the 'device PHY' makes 'HSIC PHY' to
> work?

I agree with you that it looks weird, but I found this necessary to be done.

> > +	if (inst->cfg->id == EXYNOS4212_HSIC0) {
> > +		struct samsung_usb2_phy_instance *device =
> > +					&drv->instances[EXYNOS4212_DEVICE];
> > +		exynos4212_phy_pwr(device, 1);
> > +		exynos4212_isol(device, 0);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int exynos4212_power_off(struct samsung_usb2_phy_instance
> > +*inst) {
> > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > +	struct samsung_usb2_phy_instance *device =
> > +&drv->instances[EXYNOS4212_DEVICE];
> > +
> > +	inst->enabled = 0;
> > +	exynos4212_isol(inst, 1);
> > +	exynos4212_phy_pwr(inst, 0);
> > +
> > +	if (inst->cfg->id == EXYNOS4212_HSIC0 && !device->enabled) {
> > +		exynos4212_isol(device, 1);
> > +		exynos4212_phy_pwr(device, 0);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +
> > +static const struct samsung_usb2_common_phy exynos4212_phys[] = {
> > +	{
> > +		.label		= "device",
> > +		.id		= EXYNOS4212_DEVICE,
> > +		.rate_to_clk	= exynos4212_rate_to_clk,
> > +		.power_on	= exynos4212_power_on,
> > +		.power_off	= exynos4212_power_off,
> > +	},
> > +	{
> > +		.label		= "host",
> > +		.id		= EXYNOS4212_HOST,
> > +		.rate_to_clk	= exynos4212_rate_to_clk,
> > +		.power_on	= exynos4212_power_on,
> > +		.power_off	= exynos4212_power_off,
> > +	},
> > +	{
> > +		.label		= "hsic0",
> > +		.id		= EXYNOS4212_HSIC0,
> > +		.rate_to_clk	= exynos4212_rate_to_clk,
> > +		.power_on	= exynos4212_power_on,
> > +		.power_off	= exynos4212_power_off,
> > +	},
> > +	{
> > +		.label		= "hsic1",
> > +		.id		= EXYNOS4212_HSIC1,
> > +		.rate_to_clk	= exynos4212_rate_to_clk,
> > +		.power_on	= exynos4212_power_on,
> > +		.power_off	= exynos4212_power_off,
> > +	},
> > +	{},
> > +};
> > +
> > +const struct samsung_usb2_phy_config exynos4212_usb2_phy_config = {
> > +	.num_phys		= EXYNOS4212_NUM_PHYS,
> > +	.phys			= exynos4212_phys,
> > +	.has_mode_switch	= 1,
> > +};
> > +
> > diff --git a/drivers/phy/phy-samsung-usb2.c
> > b/drivers/phy/phy-samsung-usb2.c new file mode 100644 index
> > 0000000..804ec77
> > --- /dev/null
> > +++ b/drivers/phy/phy-samsung-usb2.c
> > @@ -0,0 +1,228 @@
> > +/*
> > + * Samsung SoC USB 1.1/2.0 PHY driver
> > + *
> > + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> > + * Author: Kamil Debski <k.debski@samsung.com>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > +modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/spinlock.h>
> 
> You've included most of the above header files in phy-samsung-usb2.h
> which you are including below.

Please see my answer above.

> > +#include "phy-samsung-usb2.h"
> > +
> > +static int samsung_usb2_phy_power_on(struct phy *phy) {
> > +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > +	int ret;
> > +
> > +	dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
> > +							inst->cfg->label);
> > +	ret = clk_prepare_enable(drv->clk);
> > +	if (ret)
> > +		goto err_main_clk;
> > +	ret = clk_prepare_enable(inst->clk);
> > +	if (ret)
> > +		goto err_instance_clk;
> > +	inst->rate = clk_get_rate(inst->clk);
> > +	if (inst->cfg->rate_to_clk) {
> > +		ret = inst->cfg->rate_to_clk(inst->rate, &inst-
> >clk_reg_val);
> > +		if (ret)
> > +			goto err_get_rate;
> > +	}
> > +	if (inst->cfg->power_on) {
> > +		spin_lock(&drv->lock);
> > +		ret = inst->cfg->power_on(inst);
> > +		spin_unlock(&drv->lock);
> > +	}
> > +
> > +	return 0;
> > +
> > +err_get_rate:
> > +	clk_disable_unprepare(inst->clk);
> > +err_instance_clk:
> > +	clk_disable_unprepare(drv->clk);
> > +err_main_clk:
> > +	return ret;
> > +}
> > +
> > +static int samsung_usb2_phy_power_off(struct phy *phy) {
> > +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > +	int ret = 0;
> > +
> > +	dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
> > +							inst->cfg->label);
> > +	if (inst->cfg->power_off) {
> > +		spin_lock(&drv->lock);
> > +		ret = inst->cfg->power_off(inst);
> > +		spin_unlock(&drv->lock);
> > +	}
> > +	clk_disable_unprepare(inst->clk);
> > +	clk_disable_unprepare(drv->clk);
> > +	return ret;
> > +}
> > +
> > +static struct phy_ops samsung_usb2_phy_ops = {
> > +	.power_on	= samsung_usb2_phy_power_on,
> > +	.power_off	= samsung_usb2_phy_power_off,
> > +	.owner		= THIS_MODULE,
> > +};
> > +
> > +static struct phy *samsung_usb2_phy_xlate(struct device *dev,
> > +					struct of_phandle_args *args)
> > +{
> > +	struct samsung_usb2_phy_driver *drv;
> > +
> > +	drv = dev_get_drvdata(dev);
> > +	if (!drv)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
> > +		return ERR_PTR(-ENODEV);
> > +
> > +	return drv->instances[args->args[0]].phy;
> > +}
> > +
> > +static const struct of_device_id samsung_usb2_phy_of_match[] = {
> > +#ifdef CONFIG_PHY_EXYNOS4210_USB2
> > +	{
> > +		.compatible = "samsung,exynos4210-usb2-phy",
> > +		.data = &exynos4210_usb2_phy_config,
> > +	},
> > +#endif
> > +#ifdef CONFIG_PHY_EXYNOS4212_USB2
> > +	{
> > +		.compatible = "samsung,exynos4212-usb2-phy",
> > +		.data = &exynos4212_usb2_phy_config,
> > +	},
> > +#endif
> > +	{ },
> > +};
> 
> I think we've had enough discussion about this approach. Let's get the
> opinion of others too. Felipe? Greg?

Good idea.

> Summary:
> We have two drivers PHY_EXYNOS4210_USB2 and PHY_EXYNOS4212_USB2 with
> almost similar register map [1] and a samsung helper driver for these
> two drivers.

I would not call them separate drivers. It's a single USB 2.0 driver with
the option to include support for various SoCs. This patchset adds:
Exynos 4210, Exynos 4212, Exynos 5250 and S5PCV210. I know that another
person is working on supporting S3C6410.

> These two PHY drivers populate the function pointers in the helper
> driver. So any phy_ops will first invoke the helper driver which will
> then invoke the corresponding phy driver.
> 
> [1] -> http://www.diffchecker.com/7yno1uvk

Come on, this diff only includes the registers part of the file. 
The following functions are also different:
- exynos421*_rate_to_clk
- exynos421*_isol
- exynos421*_phy_pwr
- exynos421*_power_on
- exynos421*_power_on

It seems that the file is too large for the tool. But still this makes a
false impression that only registers are different.
 
> Advantages:
> * (more) clean and readable
> * helper driver can be used with other PHY drivers which will be added
> soon
> 
> Disadvantages:
> * code duplication

I would say that actually in this case less code is duplicated. Having
Separate drivers would mean that most of the phy-samsung-usb2.c file has
to be repeated. That is 240 times 4 (and surely more in the future, as
this patchset adds support for 4 SoCs). Which is almost 1000 lines more.

> 
> Maybe having a helper driver makes sense when we have other samsung PHY
> drivers added but not sure if it's needed here for EXYNOS4210_USB2 and
> EXYNOS4212_USB2
> 
> Need your inputs on what you think about this.

Yes, I would also welcome other people's opinions. 

> > +
> > +static int samsung_usb2_phy_probe(struct platform_device *pdev) {
> > +	const struct of_device_id *match;
> > +	const struct samsung_usb2_phy_config *cfg;
> > +	struct clk *clk;
> > +	struct device *dev = &pdev->dev;
> > +	struct phy_provider *phy_provider;
> > +	struct resource *mem;
> > +	struct samsung_usb2_phy_driver *drv;
> > +	int i;
> > +
> > +	if (!pdev->dev.of_node) {
> > +		dev_err(dev, "This driver is required to be instantiated
> from device tree\n");
> > +		return -EINVAL;
> > +	}
> > +
> > +	match = of_match_node(samsung_usb2_phy_of_match, pdev-
> >dev.of_node);
> > +	if (!match) {
> > +		dev_err(dev, "of_match_node() failed\n");
> > +		return -EINVAL;
> > +	}
> > +	cfg = match->data;
> > +
> > +	drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
> > +		cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),
> GFP_KERNEL);
> > +	if (!drv)
> > +		return -ENOMEM;
> > +
> > +	dev_set_drvdata(dev, drv);
> > +	spin_lock_init(&drv->lock);
> > +
> > +	drv->cfg = cfg;
> > +	drv->dev = dev;
> > +
> > +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +	drv->reg_phy = devm_ioremap_resource(dev, mem);
> > +	if (IS_ERR(drv->reg_phy)) {
> > +		dev_err(dev, "Failed to map register memory (phy)\n");
> > +		return PTR_ERR(drv->reg_phy);
> > +	}
> > +
> > +	drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> > +		"samsung,pmureg-phandle");
> > +	if (IS_ERR(drv->reg_pmu)) {
> > +		dev_err(dev, "Failed to map PMU registers (via syscon)\n");
> > +		return PTR_ERR(drv->reg_pmu);
> > +	}
> > +
> > +	if (drv->cfg->has_mode_switch) {
> > +		drv->reg_sys = syscon_regmap_lookup_by_phandle(
> > +				pdev->dev.of_node,
"samsung,sysreg-phandle");
> > +		if (IS_ERR(drv->reg_sys)) {
> > +			dev_err(dev, "Failed to map system registers (via
> syscon)\n");
> > +			return PTR_ERR(drv->reg_sys);
> > +		}
> > +	}
> > +
> > +	drv->clk = devm_clk_get(dev, "phy");
> > +	if (IS_ERR(drv->clk)) {
> > +		dev_err(dev, "Failed to get clock of phy controller\n");
> > +		return PTR_ERR(drv->clk);
> > +	}
> > +
> > +	for (i = 0; i < drv->cfg->num_phys; i++) {
> > +		char *label = drv->cfg->phys[i].label;
> > +		struct samsung_usb2_phy_instance *p = &drv->instances[i];
> > +
> > +		dev_dbg(dev, "Creating phy \"%s\"\n", label);
> > +		p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
> > +		if (IS_ERR(p->phy)) {
> > +			dev_err(drv->dev, "Failed to create usb2_phy
> \"%s\"\n",
> > +						label);
> > +			return PTR_ERR(p->phy);
> > +		}
> > +
> > +		p->cfg = &drv->cfg->phys[i];
> > +		p->drv = drv;
> > +		phy_set_drvdata(p->phy, p);
> > +
> > +		clk = devm_clk_get(dev, p->cfg->label);
> > +		if (IS_ERR(clk)) {
> > +			dev_err(dev, "Failed to get clock of \"%s\" phy\n",
> > +
p->cfg->label);
> > +			return PTR_ERR(clk);
> > +		}
> > +		p->clk = clk;
> > +	}
> > +
> > +	phy_provider = devm_of_phy_provider_register(dev,
> > +
samsung_usb2_phy_xlate);
> > +	if (IS_ERR(phy_provider)) {
> > +		dev_err(drv->dev, "Failed to register phy provider\n");
> > +		return PTR_ERR(phy_provider);
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static struct platform_driver samsung_usb2_phy_driver = {
> > +	.probe	= samsung_usb2_phy_probe,
> > +	.driver = {
> > +		.of_match_table	= samsung_usb2_phy_of_match,
> > +		.name		= "samsung-usb2-phy",
> > +		.owner		= THIS_MODULE,
> > +	}
> > +};
> > +
> > +module_platform_driver(samsung_usb2_phy_driver);
> > +MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
> > +MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
> > +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:samsung-usb2-phy");
> > +
> > diff --git a/drivers/phy/phy-samsung-usb2.h
> > b/drivers/phy/phy-samsung-usb2.h new file mode 100644 index
> > 0000000..cd12477
> > --- /dev/null
> > +++ b/drivers/phy/phy-samsung-usb2.h
> > @@ -0,0 +1,72 @@
> > +/*
> > + * Samsung SoC USB 1.1/2.0 PHY driver
> > + *
> > + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> > + * Author: Kamil Debski <k.debski@samsung.com>
> > + *
> > + * This program is free software; you can redistribute it and/or
> > +modify
> > + * it under the terms of the GNU General Public License version 2 as
> > + * published by the Free Software Foundation.
> > + */
> > +
> > +#ifndef _PHY_EXYNOS_USB2_H
> > +#define _PHY_EXYNOS_USB2_H
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/of_address.h>
> > +#include <linux/phy/phy.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/spinlock.h>
> > +
> > +#define KHZ 1000
> > +#define MHZ (KHZ * KHZ)
> > +
> > +struct samsung_usb2_phy_driver;
> > +struct samsung_usb2_phy_instance;
> > +struct samsung_usb2_phy_config;
> > +
> > +struct samsung_usb2_phy_instance {
> > +	struct samsung_usb2_phy_driver *drv;
> > +	struct phy *phy;
> > +	const struct samsung_usb2_common_phy *cfg;
> > +	char enabled;
> > +	struct clk *clk;
> > +	u32 clk_reg_val;
> > +	unsigned long rate;
> > +};
> > +
> > +struct samsung_usb2_phy_driver {
> > +	struct device *dev;
> > +	spinlock_t lock;
> > +	void __iomem *reg_phy;
> > +	struct regmap *reg_sys;
> > +	struct regmap *reg_pmu;
> > +	const struct samsung_usb2_phy_config *cfg;
> > +	struct clk *clk;
> > +	struct samsung_usb2_phy_instance instances[0]; };
> > +
> > +struct samsung_usb2_common_phy {
> > +	char *label;
> > +	unsigned int id;
> > +	int (*rate_to_clk)(unsigned long, u32 *);
> > +	int (*power_on)(struct samsung_usb2_phy_instance *);
> > +	int (*power_off)(struct samsung_usb2_phy_instance *); };
> > +
> > +
> > +struct samsung_usb2_phy_config {
> > +	int num_phys;
> > +	const struct samsung_usb2_common_phy *phys;
> > +	char has_mode_switch;
> 
> u8 instead?

Do we really need to specify that we need 8bits? Why do you think
char is wrong?

Please read this paragraph from LDD3:
"Sometimes kernel code requires data items of a specific size,
perhaps to match predefined binary structures,* to communicate with
user space, or to align data within structures by inserting
"padding" fields (but refer to the section "Data Alignment" for
information about alignment issues)."
Chapter 11, page 290 http://lwn.net/images/pdf/LDD3/ch11.pdf

has_mode_switch is only a flag 0 or 1. Never written anywhere in
hardware registers. Used in an if somewhere in code. Give me a good
reason why do you think it should be explicitly 8 bit long.

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland


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

* RE: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
  2013-12-06 15:01       ` Matt Porter
  (?)
@ 2013-12-06 16:29       ` Kamil Debski
  -1 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 16:29 UTC (permalink / raw)
  To: 'Matt Porter', 'Kishon Vijay Abraham I'
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak

Hi,

> From: Matt Porter [mailto:matt.porter@linaro.org]
> Sent: Friday, December 06, 2013 4:01 PM
> 
> On Fri, Dec 06, 2013 at 04:41:51PM +0530, Kishon Vijay Abraham I wrote:
> > Hi,
> >
> > On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> > > Change the used phy driver to the new Exynos USB phy driver that
> > > uses the generic phy framework.
> > >
> > > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > > ---
> > >  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
> > >  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++--
> ---
> > >  2 files changed, 10 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/usb/samsung-
> hsotg.txt
> > > b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > > index b83d428..9340d06 100644
> > > --- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > > +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > > @@ -24,6 +24,8 @@ Required properties:
> > >      - first entry: must be "otg"
> > >  - vusb_d-supply: phandle to voltage regulator of digital section,
> > >  - vusb_a-supply: phandle to voltage regulator of analog section.
> > > +- phys: from general PHY binding: phandle to the PHY device
> > > +- phy-names: from general PHY binding: should be "usb2-phy"
> >
> > are you sure it's usb2-phy. The example below seems to have a
> different value.
> 
> I requested this be changed to usb2-phy, looks like he just missed the
> update to the example.

This is true. I missed the change in the example part of the file.

> 
> >
> > >
> > >  Example
> > >  -----
> > > @@ -36,5 +38,7 @@ Example
> > >  		clock-names = "otg";
> > >  		vusb_d-supply = <&vusb_reg>;
> > >  		vusb_a-supply = <&vusbdac_reg>;
> > > +		phys = <&usb2phy 0>;
> > > +		phy-names = "device";
> > >  	};

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland


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

* RE: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
  2013-12-06 10:59     ` Kishon Vijay Abraham I
  (?)
  (?)
@ 2013-12-06 16:47     ` Kamil Debski
  -1 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-06 16:47 UTC (permalink / raw)
  To: 'Kamil Debski', 'Kishon Vijay Abraham I',
	linux-kernel, linux-samsung-soc, linux-usb, devicetree, balbi,
	'Greg Kroah-Hartman'
  Cc: kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

Hi,

> From: Kamil Debski [mailto:k.debski@samsung.com]
> Sent: Friday, December 06, 2013 5:28 PM
> 
> Hi Kishon,
> 
> Thank you for the review.
> 
> > From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
> > Sent: Friday, December 06, 2013 11:59 AM
> >
> > Hi,
> >
> > On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> > > Add a new driver for the Exynos USB PHY. The new driver uses the
> > > generic PHY framework. The driver includes support for the Exynos
> > 4x10
> > > and 4x12 SoC families.
> > >
> > > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > > ---
> > >  .../devicetree/bindings/phy/samsung-usbphy.txt     |   54 ++++
> > >  drivers/phy/Kconfig                                |   20 ++
> > >  drivers/phy/Makefile                               |    3 +
> > >  drivers/phy/phy-exynos4210-usb2.c                  |  264
> > +++++++++++++++++
> > >  drivers/phy/phy-exynos4212-usb2.c                  |  312
> > ++++++++++++++++++++
> > >  drivers/phy/phy-samsung-usb2.c                     |  228
> > ++++++++++++++
> > >  drivers/phy/phy-samsung-usb2.h                     |   72 +++++
> > >  7 files changed, 953 insertions(+)
> > >  create mode 100644
> > > Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> > >  create mode 100644 drivers/phy/phy-exynos4210-usb2.c  create mode
> > > 100644 drivers/phy/phy-exynos4212-usb2.c  create mode 100644
> > > drivers/phy/phy-samsung-usb2.c  create mode 100644
> > > drivers/phy/phy-samsung-usb2.h
> > >
> > > diff --git
> > > a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> > > b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> > > new file mode 100644
> > > index 0000000..cadbf70
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> >
> > use the existing samsung-phy.txt.
> 
> Ok.
> 
> > > @@ -0,0 +1,54 @@
> > > +Samsung S5P/EXYNOS SoC series USB PHY
> > > +-------------------------------------------------
> > > +
> > > +Required properties:
> > > +- compatible : should be one of the listed compatibles:
> > > +	- "samsung,exynos4210-usb2-phy"
> > > +	- "samsung,exynos4212-usb2-phy"
> > > +- reg : a list of registers used by phy driver
> > > +	- first and obligatory is the location of phy modules registers
> > > +- samsung,sysreg-phandle - handle to syscon used to control the
> > > +system registers
> > > +- samsung,pmureg-phandle - handle to syscon used to control PMU
> > > +registers
> > > +- #phy-cells : from the generic phy bindings, must be 1;
> > > +- clocks and clock-names:
> > > +	- the "phy" clocks is required by the phy module
> > > +	- next for each of the phys a clock has to be assidned, this
> > clock
> >
> > %s/assidned/assigned/
> 
> Thank you for spotting this.
> 
> > > +	  will be used to determine clocking frequency for the phys
> > > +	  (the labels are specified in the paragraph below)
> > > +
> > > +The first phandle argument in the PHY specifier identifies the PHY,
> > > +its meaning is compatible dependent. For the currently supported
> > SoCs
> > > +(Exynos 4210 and Exynos 4212) it is as follows:
> > > +  0 - USB device ("device"),
> > > +  1 - USB host ("host"),
> > > +  2 - HSIC0 ("hsic0"),
> > > +  3 - HSIC1 ("hsic1"),
> > > +
> > > +Exynos 4210 and Exynos 4212 use mode switching and require that
> > > +mode switch register is supplied.
> > > +
> > > +Example:
> > > +
> > > +For Exynos 4412 (compatible with Exynos 4212):
> > > +
> > > +usbphy: phy@125B0000 {
> >
> > use lower case for address here...
> 
> Ok.
> 
> > > +	compatible = "samsung,exynos4212-usb2-phy";
> > > +	reg = <0x125B0000 0x100 0x10020704 0x0c 0x1001021c 0x4>;
> > and here..
> > > +	clocks = <&clock 305>, <&clock 2>, <&clock 2>, <&clock 2>,
> > > +							<&clock 2>;
> > > +	clock-names = "phy", "device", "host", "hsic0", "hsic1";
> > > +	status = "okay";
> > > +	#phy-cells = <1>;
> > > +	samsung,sysreg-phandle = <&sys_reg>;
> > > +	samsung,pmureg-phandle = <&pmu_reg>; };
> > > +
> > > +Then the PHY can be used in other nodes such as:
> > > +
> > > +phy-consumer@12340000 {
> > > +	phys = <&usbphy 2>;
> > > +	phy-names = "phy";
> > > +};
> > > +
> > > +Refer to DT bindings documentation of particular PHY consumer
> > devices
> > > +for more information about required PHYs and the way of
> > specification.
> > > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index
> > > a344f3d..b29018f 100644
> > > --- a/drivers/phy/Kconfig
> > > +++ b/drivers/phy/Kconfig
> > > @@ -51,4 +51,24 @@ config PHY_EXYNOS_DP_VIDEO
> > >  	help
> > >  	  Support for Display Port PHY found on Samsung EXYNOS SoCs.
> > >
> > > +config PHY_SAMSUNG_USB2
> > > +	tristate "Samsung USB 2.0 PHY driver"
> > > +	help
> > > +	  Enable this to support Samsung USB phy helper driver for
> > Samsung SoCs.
> > > +	  This driver provides common interface to interact, for Samsung
> > > +	  USB 2.0 PHY driver.
> > > +
> > > +config PHY_EXYNOS4210_USB2
> > > +	bool "Support for Exynos 4210"
> > > +	depends on PHY_SAMSUNG_USB2
> > > +	depends on CPU_EXYNOS4210
> >
> > select GENERIC_PHY here?
> 
> I think that depends on PHY_SAMSUNG_USB2 is better in this place.
> However, I agree that I should add select GENERIC_PHY to
> PHY_SAMSUNG_USB2.
> 
> The reason why I am saying this is that I like how it looks in
> menuconfig. Selecting PHY_SAMSUNG_USB2 expands more options and if
> unselected the menu looks tidier.
> 
> > > +	help
> > > +	  Enable USB PHY support for Exynos 4210
> >
> > Add more explanation here and make checkpatch happy.
> 
> Here I think we should not treat checkpatch as an oracle. I also
> noticed these warnings, but I think that writing a four line
> description for SoC specific options in this menu is an overkill. In
> addition, checkpatch also complains for the following entries in
> Kconfig file:
> - PHY_EXYNOS_MIPI_VIDEO
> - PHY_EXYNOS_DP_VIDEO
> - PHY_SAMSUNG_USB2 (here expanding the description may be justified,
> but
>   I think the current description is enough)
> 
> But thank you for directing my attention to the Kconfig file. I noticed
> That SoC specific Kconfig entries should have "USB 2.0" instead of just
> "USB".
> 
> > > +
> > > +config PHY_EXYNOS4212_USB2
> > > +	bool "Support for Exynos 4212"
> > > +	depends on PHY_SAMSUNG_USB2
> > > +	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
> >
> > select GENERIC_PHY.
> 
> Please check my reply above.
> 
> > > +	help
> > > +	  Enable USB PHY support for Exynos 4212
> >
> > more explanation here too..
> 
> Please check my reply above.
> 
> > >  endmenu
> > > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index
> > > d0caae9..9f4befd 100644
> > > --- a/drivers/phy/Makefile
> > > +++ b/drivers/phy/Makefile
> > > @@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-
> exynos-dp-
> > video.o
> > >  obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
> > >  obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
> > >  obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
> > > +obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
> > > +obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
> > > +obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> > > diff --git a/drivers/phy/phy-exynos4210-usb2.c
> > > b/drivers/phy/phy-exynos4210-usb2.c
> > > new file mode 100644
> > > index 0000000..a02e5c2
> > > --- /dev/null
> > > +++ b/drivers/phy/phy-exynos4210-usb2.c
> > > @@ -0,0 +1,264 @@
> > > +/*
> > > + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
> > > + *
> > > + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> > > + * Author: Kamil Debski <k.debski@samsung.com>
> > > + *
> > > + * This program is free software; you can redistribute it and/or
> > > +modify
> > > + * it under the terms of the GNU General Public License version 2
> > > +as
> > > + * published by the Free Software Foundation.
> > > + */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/io.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_address.h>
> > > +#include <linux/phy/phy.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/regmap.h>
> > > +#include <linux/spinlock.h>
> >
> > You've included most of the above header files in phy-samsung-usb2.h
> > which you are including below.
> 
> I agree that includes in phy-samsung-usb2.h could use a cleanup. On the
> other hand my opinion is that a .c file should include all .h files
> that are used in this .c file. Relaying on .h file to include
> another .h doesn't seem good to me.
> 
> > > +#include "phy-samsung-usb2.h"
> > > +
> > > +/* Exynos USB PHY registers */
> > > +
> > > +/* PHY power control */
> > > +#define EXYNOS_4210_UPHYPWR			0x0
> > > +
> > > +#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
> >
> > use BIT() here and everywhere below.
> 
> All right.
> 
> > > +#define EXYNOS_4210_UPHYPWR_PHY0_PWR		(1 << 3)
> >
> > replace PHY0 here with DEV so it looks similar to EXYNOS_4212.
> > > +#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
> > > +#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		(1 << 5)
> > > +#define EXYNOS_4210_UPHYPWR_PHY0	( \
> > > +	EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
> > > +	EXYNOS_4210_UPHYPWR_PHY0_PWR | \
> > > +	EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
> > > +	EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
> > > +
> > > +#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND	(1 << 6)
> >
> > replace PHY0 here with HOST so it looks similar to EXYNOS_4212.
> 
> Thank you for spotting this inconsistence. I will fix that. But I
> rather incline to use PHY0/1 instead of DEVICE/HOST as it will be then
> consistent with the date sheet.
> 
> > > +#define EXYNOS_4210_UPHYPWR_PHY1_PWR		(1 << 7)
> > > +#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		(1 << 8)
> > > +#define EXYNOS_4210_UPHYPWR_PHY1 ( \
> > > +	EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
> > > +	EXYNOS_4210_UPHYPWR_PHY1_PWR | \
> > > +	EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
> > > +
> > > +#define EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> > > +#define EXYNOS_4210_UPHYPWR_HSCI0_SLEEP		(1 << 10)
> > > +#define EXYNOS_4210_UPHYPWR_HSCI0 ( \
> > > +	EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND | \
> > > +	EXYNOS_4210_UPHYPWR_HSCI0_SLEEP)
> > > +
> > > +#define EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND	(1 << 11)
> > > +#define EXYNOS_4210_UPHYPWR_HSCI1_SLEEP		(1 << 12)
> > > +#define EXYNOS_4210_UPHYPWR_HSCI1 ( \
> > > +	EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND | \
> > > +	EXYNOS_4210_UPHYPWR_HSCI1_SLEEP)
> > > +
> > > +/* PHY clock control */
> > > +#define EXYNOS_4210_UPHYCLK			0x4
> > > +
> > > +#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
> > > +#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
> > > +#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
> > > +#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> > > +
> > > +#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
> > > +#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> > > +#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> > > +
> > > +/* PHY reset control */
> > > +#define EXYNOS_4210_UPHYRST			0x8
> > > +
> > > +#define EXYNOS_4210_URSTCON_PHY0		(1 << 0)
> > > +#define EXYNOS_4210_URSTCON_OTG_HLINK		(1 << 1)
> > > +#define EXYNOS_4210_URSTCON_OTG_PHYLINK		(1 << 2)
> > > +#define EXYNOS_4210_URSTCON_PHY1_ALL		(1 << 3)
> > > +#define EXYNOS_4210_URSTCON_PHY1_P0		(1 << 4)
> > > +#define EXYNOS_4210_URSTCON_PHY1_P1P2		(1 << 5)
> > > +#define EXYNOS_4210_URSTCON_HOST_LINK_ALL	(1 << 6)
> > > +#define EXYNOS_4210_URSTCON_HOST_LINK_P0	(1 << 7)
> > > +#define EXYNOS_4210_URSTCON_HOST_LINK_P1	(1 << 8)
> > > +#define EXYNOS_4210_URSTCON_HOST_LINK_P2	(1 << 9)
> > > +
> > > +/* Isolation, configured in the power management unit */
> > > +#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
> > > +#define EXYNOS_4210_USB_ISOL_DEVICE		(1 << 0)
> > > +#define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
> > > +#define EXYNOS_4210_USB_ISOL_HOST		(1 << 0)
> > > +
> > > +/* USBYPHY1 Floating prevention */
> > > +#define EXYNOS_4210_UPHY1CON			0x34
> > > +#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION	0x1
> > > +
> > > +/* Mode switching SUB Device <-> Host */
> > > +#define EXYNOS_4210_MODE_SWITCH_OFFSET		0x21c
> > > +#define EXYNOS_4210_MODE_SWITCH_MASK		1
> > > +#define EXYNOS_4210_MODE_SWITCH_DEVICE		0
> > > +#define EXYNOS_4210_MODE_SWITCH_HOST		1
> > > +
> > > +enum exynos4210_phy_id {
> > > +	EXYNOS4210_DEVICE,
> > > +	EXYNOS4210_HOST,
> > > +	EXYNOS4210_HSIC0,
> > > +	EXYNOS4210_HSIC1,
> > > +	EXYNOS4210_NUM_PHYS,
> > > +};
> > > +
> > > +/*
> > > + * exynos4210_rate_to_clk() converts the supplied clock rate to
> the
> > > +value that
> > > + * can be written to the phy register.
> > > + */
> > > +static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg) {
> > > +	switch (rate) {
> > > +	case 12 * MHZ:
> > > +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
> > > +		break;
> > > +	case 24 * MHZ:
> > > +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
> > > +		break;
> > > +	case 48 * MHZ:
> > > +		reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
> >
> > %s/reg/*Reg
> 
> Thank you.
> 
> > > +		break;
> > > +	default:
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static void exynos4210_isol(struct samsung_usb2_phy_instance *inst,
> > > +bool on) {
> > > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > > +	u32 offset;
> > > +	u32 mask;
> > > +
> > > +	switch (inst->cfg->id) {
> > > +	case EXYNOS4210_DEVICE:
> > > +		offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
> > > +		mask = EXYNOS_4210_USB_ISOL_DEVICE;
> > > +		break;
> > > +	case EXYNOS4210_HOST:
> > > +		offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
> > > +		mask = EXYNOS_4210_USB_ISOL_HOST;
> > > +		break;
> > > +	default:
> > > +		return;
> > > +	};
> > > +
> > > +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask); }
> > > +
> > > +static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance
> > > +*inst, bool on) {
> > > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > > +	u32 rstbits = 0;
> > > +	u32 phypwr = 0;
> > > +	u32 rst;
> > > +	u32 pwr;
> > > +
> > > +	switch (inst->cfg->id) {
> > > +	case EXYNOS4210_DEVICE:
> > > +		phypwr =	EXYNOS_4210_UPHYPWR_PHY0;
> > > +		rstbits =	EXYNOS_4210_URSTCON_PHY0;
> > > +		break;
> > > +	case EXYNOS4210_HOST:
> > > +		phypwr =	EXYNOS_4210_UPHYPWR_PHY1;
> > > +		rstbits =	EXYNOS_4210_URSTCON_PHY1_ALL |
> > > +				EXYNOS_4210_URSTCON_PHY1_P0 |
> > > +				EXYNOS_4210_URSTCON_PHY1_P1P2 |
> > > +				EXYNOS_4210_URSTCON_HOST_LINK_ALL |
> > > +				EXYNOS_4210_URSTCON_HOST_LINK_P0;
> > > +		writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
> > > +		break;
> > > +	case EXYNOS4210_HSIC0:
> > > +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI0;
> > > +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> > > +				EXYNOS_4210_URSTCON_HOST_LINK_P1;
> > > +		break;
> > > +	case EXYNOS4210_HSIC1:
> > > +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI1;
> > > +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> > > +				EXYNOS_4210_URSTCON_HOST_LINK_P2;
> > > +		break;
> > > +	};
> > > +
> > > +	if (on) {
> > > +		writel(inst->clk_reg_val, drv->reg_phy +
> > EXYNOS_4210_UPHYCLK);
> > > +
> > > +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> > > +		pwr &= ~phypwr;
> > > +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> > > +
> > > +		rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
> > > +		rst |= rstbits;
> > > +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
> > > +		udelay(10);
> > > +		rst &= ~rstbits;
> > > +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
> >
> > Do you have to reset during every power on? IMO this reset should be
> > done once in phy_init.
> 
> It seems that this reset is neded by the hardware.
> 
> > > +	} else {
> > > +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> > > +		pwr |= phypwr;
> > > +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> > > +	}
> > > +}
> > > +
> > > +static int exynos4210_power_on(struct samsung_usb2_phy_instance
> > > +*inst) {
> > > +	/* Order of initialisation is important - first power then
> > isolation */
> > > +	exynos4210_phy_pwr(inst, 1);
> > > +	exynos4210_isol(inst, 0);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int exynos4210_power_off(struct samsung_usb2_phy_instance
> > > +*inst) {
> > > +	exynos4210_isol(inst, 1);
> > > +	exynos4210_phy_pwr(inst, 0);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +
> > > +static const struct samsung_usb2_common_phy exynos4210_phys[] = {
> > > +	{
> > > +		.label		= "device",
> > > +		.id		= EXYNOS4210_DEVICE,
> > > +		.rate_to_clk	= exynos4210_rate_to_clk,
> > > +		.power_on	= exynos4210_power_on,
> > > +		.power_off	= exynos4210_power_off,
> > > +	},
> > > +	{
> > > +		.label		= "host",
> > > +		.id		= EXYNOS4210_HOST,
> > > +		.rate_to_clk	= exynos4210_rate_to_clk,
> > > +		.power_on	= exynos4210_power_on,
> > > +		.power_off	= exynos4210_power_off,
> > > +	},
> > > +	{
> > > +		.label		= "hsic0",
> > > +		.id		= EXYNOS4210_HSIC0,
> > > +		.rate_to_clk	= exynos4210_rate_to_clk,
> > > +		.power_on	= exynos4210_power_on,
> > > +		.power_off	= exynos4210_power_off,
> > > +	},
> > > +	{
> > > +		.label		= "hsic1",
> > > +		.id		= EXYNOS4210_HSIC1,
> > > +		.rate_to_clk	= exynos4210_rate_to_clk,
> > > +		.power_on	= exynos4210_power_on,
> > > +		.power_off	= exynos4210_power_off,
> > > +	},
> > > +	{},
> > > +};
> > > +
> > > +const struct samsung_usb2_phy_config exynos4210_usb2_phy_config =
> {
> > > +	.num_phys		= EXYNOS4210_NUM_PHYS,
> > > +	.phys			= exynos4210_phys,
> > > +	.has_mode_switch	= 1,
> > > +};
> > > +
> > > diff --git a/drivers/phy/phy-exynos4212-usb2.c
> > > b/drivers/phy/phy-exynos4212-usb2.c
> > > new file mode 100644
> > > index 0000000..375ece0
> > > --- /dev/null
> > > +++ b/drivers/phy/phy-exynos4212-usb2.c
> > > @@ -0,0 +1,312 @@
> > > +/*
> > > + * Samsung S5P/EXYNOS SoC series USB PHY driver - Exynos 4212
> > support
> > > + *
> > > + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> > > + * Author: Kamil Debski <k.debski@samsung.com>
> > > + *
> > > + * This program is free software; you can redistribute it and/or
> > > +modify
> > > + * it under the terms of the GNU General Public License version 2
> > > +as
> > > + * published by the Free Software Foundation.
> > > + */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/io.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_address.h>
> > > +#include <linux/phy/phy.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/regmap.h>
> > > +#include <linux/spinlock.h>
> >
> > You've included most of the above header files in phy-samsung-usb2.h
> > which you are including below.
> 
> Please see my reply above.
> 
> > > +#include "phy-samsung-usb2.h"
> > > +
> > > +/* Exynos USB PHY registers */
> > > +
> > > +/* PHY power control */
> > > +#define EXYNOS_4212_UPHYPWR			0x0
> > > +
> > > +#define EXYNOS_4212_UPHYPWR_DEV_SUSPEND		(1 << 0)
> >
> > use BIT() here and below..
> 
> All right.
> 
> > > +#define EXYNOS_4212_UPHYPWR_DEV_PWR		(1 << 3)
> > > +#define EXYNOS_4212_UPHYPWR_DEV_OTG_PWR		(1 << 4)
> > > +#define EXYNOS_4212_UPHYPWR_DEV_SLEEP		(1 << 5)
> > > +#define EXYNOS_4212_UPHYPWR_DEV	( \
> > > +	EXYNOS_4212_UPHYPWR_DEV_SUSPEND | \
> > > +	EXYNOS_4212_UPHYPWR_DEV_PWR | \
> > > +	EXYNOS_4212_UPHYPWR_DEV_OTG_PWR | \
> > > +	EXYNOS_4212_UPHYPWR_DEV_SLEEP)
> > > +
> > > +#define EXYNOS_4212_UPHYPWR_HOST_SUSPEND	(1 << 6)
> > > +#define EXYNOS_4212_UPHYPWR_HOST_PWR		(1 << 7)
> > > +#define EXYNOS_4212_UPHYPWR_HOST_SLEEP		(1 << 8)
> > > +#define EXYNOS_4212_UPHYPWR_HOST ( \
> > > +	EXYNOS_4212_UPHYPWR_HOST_SUSPEND | \
> > > +	EXYNOS_4212_UPHYPWR_HOST_PWR | \
> > > +	EXYNOS_4212_UPHYPWR_HOST_SLEEP)
> > > +
> > > +#define EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> > > +#define EXYNOS_4212_UPHYPWR_HSCI0_PWR		(1 << 10)
> > > +#define EXYNOS_4212_UPHYPWR_HSCI0_SLEEP		(1 << 11)
> > > +#define EXYNOS_4212_UPHYPWR_HSCI0 ( \
> > > +	EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND | \
> > > +	EXYNOS_4212_UPHYPWR_HSCI0_PWR | \
> > > +	EXYNOS_4212_UPHYPWR_HSCI0_SLEEP)
> > > +
> > > +#define EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND	(1 << 12)
> > > +#define EXYNOS_4212_UPHYPWR_HSCI1_PWR		(1 << 13)
> > > +#define EXYNOS_4212_UPHYPWR_HSCI1_SLEEP		(1 << 14)
> > > +#define EXYNOS_4212_UPHYPWR_HSCI1 ( \
> > > +	EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND | \
> > > +	EXYNOS_4212_UPHYPWR_HSCI1_PWR | \
> > > +	EXYNOS_4212_UPHYPWR_HSCI1_SLEEP)
> > > +
> > > +/* PHY clock control */
> > > +#define EXYNOS_4212_UPHYCLK			0x4
> > > +
> > > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_MASK	(0x7 << 0)
> > > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6	(0x0 << 0)
> > > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ	(0x1 << 0)
> > > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> > > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2	(0x3 << 0)
> > > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ	(0x4 << 0)
> > > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ	(0x5 << 0)
> > > +#define EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ	(0x7 << 0)
> > > +
> > > +#define EXYNOS_4212_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 3)
> > > +#define EXYNOS_4212_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> > > +#define EXYNOS_4212_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> > > +
> > > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_MASK	(0x7f << 10)
> > > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_12MHZ	(0x24 << 10)
> > > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_15MHZ	(0x1c << 10)
> > > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_16MHZ	(0x1a << 10)
> > > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_19MHZ2	(0x15 << 10)
> > > +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_20MHZ	(0x14 << 10)
> > > +
> > > +/* PHY reset control */
> > > +#define EXYNOS_4212_UPHYRST			0x8
> > > +
> > > +#define EXYNOS_4212_URSTCON_DEVICE		(1 << 0)
> > > +#define EXYNOS_4212_URSTCON_OTG_HLINK		(1 << 1)
> > > +#define EXYNOS_4212_URSTCON_OTG_PHYLINK		(1 << 2)
> > > +#define EXYNOS_4212_URSTCON_HOST_PHY		(1 << 3)
> > > +#define EXYNOS_4212_URSTCON_PHY1		(1 << 4)
> > > +#define EXYNOS_4212_URSTCON_HSIC0		(1 << 5)
> > > +#define EXYNOS_4212_URSTCON_HSIC1		(1 << 6)
> > > +#define EXYNOS_4212_URSTCON_HOST_LINK_ALL	(1 << 7)
> > > +#define EXYNOS_4212_URSTCON_HOST_LINK_P0	(1 << 8)
> > > +#define EXYNOS_4212_URSTCON_HOST_LINK_P1	(1 << 9)
> > > +#define EXYNOS_4212_URSTCON_HOST_LINK_P2	(1 << 10)
> > > +
> > > +/* Isolation, configured in the power management unit */
> > > +#define EXYNOS_4212_USB_ISOL_OFFSET		0x704
> > > +#define EXYNOS_4212_USB_ISOL_OTG		(1 << 0)
> > > +#define EXYNOS_4212_USB_ISOL_HSIC0_OFFSET	0x708
> > > +#define EXYNOS_4212_USB_ISOL_HSIC0		(1 << 0)
> > > +#define EXYNOS_4212_USB_ISOL_HSIC1_OFFSET	0x70c
> > > +#define EXYNOS_4212_USB_ISOL_HSIC1		(1 << 0)
> > > +
> > > +/* Mode switching SUB Device <-> Host */
> > > +#define EXYNOS_4212_MODE_SWITCH_OFFSET		0x21c
> > > +#define EXYNOS_4212_MODE_SWITCH_MASK		1
> > > +#define EXYNOS_4212_MODE_SWITCH_DEVICE		0
> > > +#define EXYNOS_4212_MODE_SWITCH_HOST		1
> > > +
> > > +enum exynos4x12_phy_id {
> > > +	EXYNOS4212_DEVICE,
> > > +	EXYNOS4212_HOST,
> > > +	EXYNOS4212_HSIC0,
> > > +	EXYNOS4212_HSIC1,
> > > +	EXYNOS4212_NUM_PHYS,
> > > +};
> > > +
> > > +/*
> > > + * exynos4212_rate_to_clk() converts the supplied clock rate to
> the
> > > +value that
> > > + * can be written to the phy register.
> > > + */
> > > +static int exynos4212_rate_to_clk(unsigned long rate, u32 *reg) {
> > > +	/* EXYNOS_4212_UPHYCLK_PHYFSEL_MASK */
> > > +
> > > +	switch (rate) {
> > > +	case 9600 * KHZ:
> > > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6;
> > > +		break;
> > > +	case 10 * MHZ:
> > > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ;
> > > +		break;
> > > +	case 12 * MHZ:
> > > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ;
> > > +		break;
> > > +	case 19200 * KHZ:
> > > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2;
> > > +		break;
> > > +	case 20 * MHZ:
> > > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ;
> > > +		break;
> > > +	case 24 * MHZ:
> > > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ;
> > > +		break;
> > > +	case 50 * MHZ:
> > > +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ;
> > > +		break;
> > > +	default:
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static void exynos4212_isol(struct samsung_usb2_phy_instance *inst,
> > > +bool on) {
> > > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > > +	u32 offset;
> > > +	u32 mask;
> > > +
> > > +	switch (inst->cfg->id) {
> > > +	case EXYNOS4212_DEVICE:
> > > +	case EXYNOS4212_HOST:
> > > +		offset = EXYNOS_4212_USB_ISOL_OFFSET;
> > > +		mask = EXYNOS_4212_USB_ISOL_OTG;
> > > +		break;
> > > +	case EXYNOS4212_HSIC0:
> > > +		offset = EXYNOS_4212_USB_ISOL_HSIC0_OFFSET;
> > > +		mask = EXYNOS_4212_USB_ISOL_HSIC0;
> > > +		break;
> > > +	case EXYNOS4212_HSIC1:
> > > +		offset = EXYNOS_4212_USB_ISOL_HSIC1_OFFSET;
> > > +		mask = EXYNOS_4212_USB_ISOL_HSIC1;
> > > +		break;
> > > +	default:
> > > +		return;
> > > +	};
> > > +
> > > +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask); }
> > > +
> > > +static void exynos4212_phy_pwr(struct samsung_usb2_phy_instance
> > > +*inst, bool on) {
> > > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > > +	u32 rstbits = 0;
> > > +	u32 phypwr = 0;
> > > +	u32 rst;
> > > +	u32 pwr;
> > > +
> > > +	switch (inst->cfg->id) {
> > > +	case EXYNOS4212_DEVICE:
> > > +		phypwr =	EXYNOS_4212_UPHYPWR_DEV;
> > > +		rstbits =	EXYNOS_4212_URSTCON_DEVICE;
> > > +		break;
> > > +	case EXYNOS4212_HOST:
> > > +		phypwr =	EXYNOS_4212_UPHYPWR_HOST;
> > > +		rstbits =	EXYNOS_4212_URSTCON_HOST_PHY;
> > > +		break;
> > > +	case EXYNOS4212_HSIC0:
> > > +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI0;
> > > +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> > > +				EXYNOS_4212_URSTCON_HOST_LINK_P0 |
> > > +				EXYNOS_4212_URSTCON_HOST_PHY;
> > > +		break;
> > > +	case EXYNOS4212_HSIC1:
> > > +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI1;
> > > +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> > > +				EXYNOS_4212_URSTCON_HOST_LINK_P1;
> > > +		break;
> > > +	};
> > > +
> > > +	if (on) {
> > > +		writel(inst->clk_reg_val, drv->reg_phy +
> > EXYNOS_4212_UPHYCLK);
> > > +
> > > +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> > > +		pwr &= ~phypwr;
> > > +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> > > +
> > > +		rst = readl(drv->reg_phy + EXYNOS_4212_UPHYRST);
> > > +		rst |= rstbits;
> > > +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
> > > +		udelay(10);
> > > +		rst &= ~rstbits;
> > > +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
> >
> > reset should be done once in init?
> 
> The hardware seems to need this reset.
> 
> > > +	} else {
> > > +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> > > +		pwr |= phypwr;
> > > +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> > > +	}
> > > +}
> > > +
> > > +static int exynos4212_power_on(struct samsung_usb2_phy_instance
> > > +*inst) {
> > > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > > +
> > > +	inst->enabled = 1;
> > > +	exynos4212_phy_pwr(inst, 1);
> > > +	exynos4212_isol(inst, 0);
> > > +
> > > +	/* Power on the device, as it is necessary for HSIC to work */
> >
> > This looks weird. How powering on the 'device PHY' makes 'HSIC PHY'
> to
> > work?
> 
> I agree with you that it looks weird, but I found this necessary to be
> done.
> 
> > > +	if (inst->cfg->id == EXYNOS4212_HSIC0) {
> > > +		struct samsung_usb2_phy_instance *device =
> > > +					&drv->instances[EXYNOS4212_DEVICE];
> > > +		exynos4212_phy_pwr(device, 1);
> > > +		exynos4212_isol(device, 0);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int exynos4212_power_off(struct samsung_usb2_phy_instance
> > > +*inst) {
> > > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > > +	struct samsung_usb2_phy_instance *device =
> > > +&drv->instances[EXYNOS4212_DEVICE];
> > > +
> > > +	inst->enabled = 0;
> > > +	exynos4212_isol(inst, 1);
> > > +	exynos4212_phy_pwr(inst, 0);
> > > +
> > > +	if (inst->cfg->id == EXYNOS4212_HSIC0 && !device->enabled) {
> > > +		exynos4212_isol(device, 1);
> > > +		exynos4212_phy_pwr(device, 0);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +
> > > +static const struct samsung_usb2_common_phy exynos4212_phys[] = {
> > > +	{
> > > +		.label		= "device",
> > > +		.id		= EXYNOS4212_DEVICE,
> > > +		.rate_to_clk	= exynos4212_rate_to_clk,
> > > +		.power_on	= exynos4212_power_on,
> > > +		.power_off	= exynos4212_power_off,
> > > +	},
> > > +	{
> > > +		.label		= "host",
> > > +		.id		= EXYNOS4212_HOST,
> > > +		.rate_to_clk	= exynos4212_rate_to_clk,
> > > +		.power_on	= exynos4212_power_on,
> > > +		.power_off	= exynos4212_power_off,
> > > +	},
> > > +	{
> > > +		.label		= "hsic0",
> > > +		.id		= EXYNOS4212_HSIC0,
> > > +		.rate_to_clk	= exynos4212_rate_to_clk,
> > > +		.power_on	= exynos4212_power_on,
> > > +		.power_off	= exynos4212_power_off,
> > > +	},
> > > +	{
> > > +		.label		= "hsic1",
> > > +		.id		= EXYNOS4212_HSIC1,
> > > +		.rate_to_clk	= exynos4212_rate_to_clk,
> > > +		.power_on	= exynos4212_power_on,
> > > +		.power_off	= exynos4212_power_off,
> > > +	},
> > > +	{},
> > > +};
> > > +
> > > +const struct samsung_usb2_phy_config exynos4212_usb2_phy_config =
> {
> > > +	.num_phys		= EXYNOS4212_NUM_PHYS,
> > > +	.phys			= exynos4212_phys,
> > > +	.has_mode_switch	= 1,
> > > +};
> > > +
> > > diff --git a/drivers/phy/phy-samsung-usb2.c
> > > b/drivers/phy/phy-samsung-usb2.c new file mode 100644 index
> > > 0000000..804ec77
> > > --- /dev/null
> > > +++ b/drivers/phy/phy-samsung-usb2.c
> > > @@ -0,0 +1,228 @@
> > > +/*
> > > + * Samsung SoC USB 1.1/2.0 PHY driver
> > > + *
> > > + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> > > + * Author: Kamil Debski <k.debski@samsung.com>
> > > + *
> > > + * This program is free software; you can redistribute it and/or
> > > +modify
> > > + * it under the terms of the GNU General Public License version 2
> > > +as
> > > + * published by the Free Software Foundation.
> > > + */
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/io.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/mfd/syscon.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_address.h>
> > > +#include <linux/phy/phy.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/spinlock.h>
> >
> > You've included most of the above header files in phy-samsung-usb2.h
> > which you are including below.
> 
> Please see my answer above.
> 
> > > +#include "phy-samsung-usb2.h"
> > > +
> > > +static int samsung_usb2_phy_power_on(struct phy *phy) {
> > > +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> > > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > > +	int ret;
> > > +
> > > +	dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
> > > +							inst->cfg->label);
> > > +	ret = clk_prepare_enable(drv->clk);
> > > +	if (ret)
> > > +		goto err_main_clk;
> > > +	ret = clk_prepare_enable(inst->clk);
> > > +	if (ret)
> > > +		goto err_instance_clk;
> > > +	inst->rate = clk_get_rate(inst->clk);
> > > +	if (inst->cfg->rate_to_clk) {
> > > +		ret = inst->cfg->rate_to_clk(inst->rate, &inst-
> > >clk_reg_val);
> > > +		if (ret)
> > > +			goto err_get_rate;
> > > +	}
> > > +	if (inst->cfg->power_on) {
> > > +		spin_lock(&drv->lock);
> > > +		ret = inst->cfg->power_on(inst);
> > > +		spin_unlock(&drv->lock);
> > > +	}
> > > +
> > > +	return 0;
> > > +
> > > +err_get_rate:
> > > +	clk_disable_unprepare(inst->clk);
> > > +err_instance_clk:
> > > +	clk_disable_unprepare(drv->clk);
> > > +err_main_clk:
> > > +	return ret;
> > > +}
> > > +
> > > +static int samsung_usb2_phy_power_off(struct phy *phy) {
> > > +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> > > +	struct samsung_usb2_phy_driver *drv = inst->drv;
> > > +	int ret = 0;
> > > +
> > > +	dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
> > > +							inst->cfg->label);
> > > +	if (inst->cfg->power_off) {
> > > +		spin_lock(&drv->lock);
> > > +		ret = inst->cfg->power_off(inst);
> > > +		spin_unlock(&drv->lock);
> > > +	}
> > > +	clk_disable_unprepare(inst->clk);
> > > +	clk_disable_unprepare(drv->clk);
> > > +	return ret;
> > > +}
> > > +
> > > +static struct phy_ops samsung_usb2_phy_ops = {
> > > +	.power_on	= samsung_usb2_phy_power_on,
> > > +	.power_off	= samsung_usb2_phy_power_off,
> > > +	.owner		= THIS_MODULE,
> > > +};
> > > +
> > > +static struct phy *samsung_usb2_phy_xlate(struct device *dev,
> > > +					struct of_phandle_args *args)
> > > +{
> > > +	struct samsung_usb2_phy_driver *drv;
> > > +
> > > +	drv = dev_get_drvdata(dev);
> > > +	if (!drv)
> > > +		return ERR_PTR(-EINVAL);
> > > +
> > > +	if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
> > > +		return ERR_PTR(-ENODEV);
> > > +
> > > +	return drv->instances[args->args[0]].phy;
> > > +}
> > > +
> > > +static const struct of_device_id samsung_usb2_phy_of_match[] = {
> > > +#ifdef CONFIG_PHY_EXYNOS4210_USB2
> > > +	{
> > > +		.compatible = "samsung,exynos4210-usb2-phy",
> > > +		.data = &exynos4210_usb2_phy_config,
> > > +	},
> > > +#endif
> > > +#ifdef CONFIG_PHY_EXYNOS4212_USB2
> > > +	{
> > > +		.compatible = "samsung,exynos4212-usb2-phy",
> > > +		.data = &exynos4212_usb2_phy_config,
> > > +	},
> > > +#endif
> > > +	{ },
> > > +};
> >
> > I think we've had enough discussion about this approach. Let's get
> the
> > opinion of others too. Felipe? Greg?
> 
> Good idea.
> 
> > Summary:
> > We have two drivers PHY_EXYNOS4210_USB2 and PHY_EXYNOS4212_USB2 with
> > almost similar register map [1] and a samsung helper driver for these
> > two drivers.
> 
> I would not call them separate drivers. It's a single USB 2.0 driver
> with the option to include support for various SoCs. This patchset adds:
> Exynos 4210, Exynos 4212, Exynos 5250 and S5PCV210. I know that another
> person is working on supporting S3C6410.
> 
> > These two PHY drivers populate the function pointers in the helper
> > driver. So any phy_ops will first invoke the helper driver which will
> > then invoke the corresponding phy driver.
> >
> > [1] -> http://www.diffchecker.com/7yno1uvk
> 
> Come on, this diff only includes the registers part of the file.
> The following functions are also different:
> - exynos421*_rate_to_clk
> - exynos421*_isol
> - exynos421*_phy_pwr
> - exynos421*_power_on
> - exynos421*_power_on
> 
> It seems that the file is too large for the tool. But still this makes
> a false impression that only registers are different.
> 
> > Advantages:
> > * (more) clean and readable
> > * helper driver can be used with other PHY drivers which will be
> added
> > soon
> >
> > Disadvantages:
> > * code duplication
> 
> I would say that actually in this case less code is duplicated. Having
> Separate drivers would mean that most of the phy-samsung-usb2.c file
> has to be repeated. That is 240 times 4 (and surely more in the future,
> as this patchset adds support for 4 SoCs). Which is almost 1000 lines
> more.
> 
> >
> > Maybe having a helper driver makes sense when we have other samsung
> > PHY drivers added but not sure if it's needed here for
> EXYNOS4210_USB2
> > and
> > EXYNOS4212_USB2
> >
> > Need your inputs on what you think about this.
> 
> Yes, I would also welcome other people's opinions.
> 
> > > +
> > > +static int samsung_usb2_phy_probe(struct platform_device *pdev) {
> > > +	const struct of_device_id *match;
> > > +	const struct samsung_usb2_phy_config *cfg;
> > > +	struct clk *clk;
> > > +	struct device *dev = &pdev->dev;
> > > +	struct phy_provider *phy_provider;
> > > +	struct resource *mem;
> > > +	struct samsung_usb2_phy_driver *drv;
> > > +	int i;
> > > +
> > > +	if (!pdev->dev.of_node) {
> > > +		dev_err(dev, "This driver is required to be instantiated
> > from device tree\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	match = of_match_node(samsung_usb2_phy_of_match, pdev-
> > >dev.of_node);
> > > +	if (!match) {
> > > +		dev_err(dev, "of_match_node() failed\n");
> > > +		return -EINVAL;
> > > +	}
> > > +	cfg = match->data;
> > > +
> > > +	drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
> > > +		cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),
> > GFP_KERNEL);
> > > +	if (!drv)
> > > +		return -ENOMEM;
> > > +
> > > +	dev_set_drvdata(dev, drv);
> > > +	spin_lock_init(&drv->lock);
> > > +
> > > +	drv->cfg = cfg;
> > > +	drv->dev = dev;
> > > +
> > > +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > +	drv->reg_phy = devm_ioremap_resource(dev, mem);
> > > +	if (IS_ERR(drv->reg_phy)) {
> > > +		dev_err(dev, "Failed to map register memory (phy)\n");
> > > +		return PTR_ERR(drv->reg_phy);
> > > +	}
> > > +
> > > +	drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> > > +		"samsung,pmureg-phandle");
> > > +	if (IS_ERR(drv->reg_pmu)) {
> > > +		dev_err(dev, "Failed to map PMU registers (via syscon)\n");
> > > +		return PTR_ERR(drv->reg_pmu);
> > > +	}
> > > +
> > > +	if (drv->cfg->has_mode_switch) {
> > > +		drv->reg_sys = syscon_regmap_lookup_by_phandle(
> > > +				pdev->dev.of_node,
"samsung,sysreg-phandle");
> > > +		if (IS_ERR(drv->reg_sys)) {
> > > +			dev_err(dev, "Failed to map system registers (via
> > syscon)\n");
> > > +			return PTR_ERR(drv->reg_sys);
> > > +		}
> > > +	}
> > > +
> > > +	drv->clk = devm_clk_get(dev, "phy");
> > > +	if (IS_ERR(drv->clk)) {
> > > +		dev_err(dev, "Failed to get clock of phy controller\n");
> > > +		return PTR_ERR(drv->clk);
> > > +	}
> > > +
> > > +	for (i = 0; i < drv->cfg->num_phys; i++) {
> > > +		char *label = drv->cfg->phys[i].label;
> > > +		struct samsung_usb2_phy_instance *p = &drv->instances[i];
> > > +
> > > +		dev_dbg(dev, "Creating phy \"%s\"\n", label);
> > > +		p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
> > > +		if (IS_ERR(p->phy)) {
> > > +			dev_err(drv->dev, "Failed to create usb2_phy
> > \"%s\"\n",
> > > +						label);
> > > +			return PTR_ERR(p->phy);
> > > +		}
> > > +
> > > +		p->cfg = &drv->cfg->phys[i];
> > > +		p->drv = drv;
> > > +		phy_set_drvdata(p->phy, p);
> > > +
> > > +		clk = devm_clk_get(dev, p->cfg->label);
> > > +		if (IS_ERR(clk)) {
> > > +			dev_err(dev, "Failed to get clock of \"%s\" phy\n",
> > > +
p->cfg->label);
> > > +			return PTR_ERR(clk);
> > > +		}
> > > +		p->clk = clk;
> > > +	}
> > > +
> > > +	phy_provider = devm_of_phy_provider_register(dev,
> > > +
samsung_usb2_phy_xlate);
> > > +	if (IS_ERR(phy_provider)) {
> > > +		dev_err(drv->dev, "Failed to register phy provider\n");
> > > +		return PTR_ERR(phy_provider);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static struct platform_driver samsung_usb2_phy_driver = {
> > > +	.probe	= samsung_usb2_phy_probe,
> > > +	.driver = {
> > > +		.of_match_table	= samsung_usb2_phy_of_match,
> > > +		.name		= "samsung-usb2-phy",
> > > +		.owner		= THIS_MODULE,
> > > +	}
> > > +};
> > > +
> > > +module_platform_driver(samsung_usb2_phy_driver);
> > > +MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
> > > +MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
> > > +MODULE_LICENSE("GPL v2");
> > > +MODULE_ALIAS("platform:samsung-usb2-phy");
> > > +
> > > diff --git a/drivers/phy/phy-samsung-usb2.h
> > > b/drivers/phy/phy-samsung-usb2.h new file mode 100644 index
> > > 0000000..cd12477
> > > --- /dev/null
> > > +++ b/drivers/phy/phy-samsung-usb2.h
> > > @@ -0,0 +1,72 @@
> > > +/*
> > > + * Samsung SoC USB 1.1/2.0 PHY driver
> > > + *
> > > + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> > > + * Author: Kamil Debski <k.debski@samsung.com>
> > > + *
> > > + * This program is free software; you can redistribute it and/or
> > > +modify
> > > + * it under the terms of the GNU General Public License version 2
> > > +as
> > > + * published by the Free Software Foundation.
> > > + */
> > > +
> > > +#ifndef _PHY_EXYNOS_USB2_H
> > > +#define _PHY_EXYNOS_USB2_H
> > > +
> > > +#include <linux/clk.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/io.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/module.h>
> > > +#include <linux/of.h>
> > > +#include <linux/of_address.h>
> > > +#include <linux/phy/phy.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/spinlock.h>
> > > +
> > > +#define KHZ 1000
> > > +#define MHZ (KHZ * KHZ)
> > > +
> > > +struct samsung_usb2_phy_driver;
> > > +struct samsung_usb2_phy_instance;
> > > +struct samsung_usb2_phy_config;
> > > +
> > > +struct samsung_usb2_phy_instance {
> > > +	struct samsung_usb2_phy_driver *drv;
> > > +	struct phy *phy;
> > > +	const struct samsung_usb2_common_phy *cfg;
> > > +	char enabled;
> > > +	struct clk *clk;
> > > +	u32 clk_reg_val;
> > > +	unsigned long rate;
> > > +};
> > > +
> > > +struct samsung_usb2_phy_driver {
> > > +	struct device *dev;
> > > +	spinlock_t lock;
> > > +	void __iomem *reg_phy;
> > > +	struct regmap *reg_sys;
> > > +	struct regmap *reg_pmu;
> > > +	const struct samsung_usb2_phy_config *cfg;
> > > +	struct clk *clk;
> > > +	struct samsung_usb2_phy_instance instances[0]; };
> > > +
> > > +struct samsung_usb2_common_phy {
> > > +	char *label;
> > > +	unsigned int id;
> > > +	int (*rate_to_clk)(unsigned long, u32 *);
> > > +	int (*power_on)(struct samsung_usb2_phy_instance *);
> > > +	int (*power_off)(struct samsung_usb2_phy_instance *); };
> > > +
> > > +
> > > +struct samsung_usb2_phy_config {
> > > +	int num_phys;
> > > +	const struct samsung_usb2_common_phy *phys;
> > > +	char has_mode_switch;
> >
> > u8 instead?
> 
> Do we really need to specify that we need 8bits? Why do you think char
> is wrong?
> 
> Please read this paragraph from LDD3:
> "Sometimes kernel code requires data items of a specific size, perhaps
> to match predefined binary structures,* to communicate with user space,
> or to align data within structures by inserting "padding" fields (but
> refer to the section "Data Alignment" for information about alignment
> issues)."
> Chapter 11, page 290 http://lwn.net/images/pdf/LDD3/ch11.pdf
> 
> has_mode_switch is only a flag 0 or 1. Never written anywhere in
> hardware registers. Used in an if somewhere in code. Give me a good
> reason why do you think it should be explicitly 8 bit long.
> 

On the second thought, we both are wrong as bool would be the best choice
here. Have a good weekend.

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland



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

* Re: [PATCH 1/9] phy: core: Change the way of_phy_get is called
  2013-12-06 10:52       ` Kamil Debski
@ 2013-12-09  7:22         ` Kishon Vijay Abraham I
  -1 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-09  7:22 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

On Friday 06 December 2013 04:22 PM, Kamil Debski wrote:
> Hi,
>
>> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
>> Sent: Friday, December 06, 2013 6:31 AM
>>
>> Hi,
>>
>> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
>>> Previously the of_phy_get function took a struct device * and was
>>> declared static. It was impossible to call it from another driver and
>>> thus it was impossible to get phy defined
>>
>> It was never intended to be called from other drivers. What's up with
>> the wrapper of of_phy_get, phy_get()/devm_phy_get()? Why isn't that
>> enough?
>
> Implementing support for multiple phys in the ehci driver is a bit tricky.
> Especially when we want to do it right. Please have a look at this part of
> the dts file:
>
> +    ehci@12580000 {
> +        compatible = "samsung,exynos4210-ehci";
> +        reg = <0x12580000 0x20000>;
> +        interrupts = <0 70 0>;
> +        clocks = <&clock 304>, <&clock 305>;
> +        clock-names = "usbhost", "otg";
> +        status = "disabled";
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        port@0 {
> +            reg = <0>;
> +            phys = <&usb2phy 1>;
> +            phy-names = "host";
> +            status = "disabled";
> +        };
> +        port@1 {
> +            reg = <1>;
> +            phys = <&usb2phy 2>;
> +            phy-names = "hsic0";
> +            status = "disabled";
> +        };
> +        port@2 {
> +            reg = <2>;
> +            phys = <&usb2phy 3>;
> +            phy-names = "hsic1";
> +            status = "disabled";
> +        };
> +    };
>
> With the above we have a clear specification of ports and their respective
> phys. But to do this properly the ehci driver has to iterate over port
> nodes. It is much easier to use devm_of_phy_get by giving the node as its
> argument.

I see. There are a couple of more things we do in the wrapper that gets 
missed while exporting of_phy_get (get_device and try_module_get). You 
might want to re-work that one.

Thanks
Kishon

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

* Re: [PATCH 1/9] phy: core: Change the way of_phy_get is called
@ 2013-12-09  7:22         ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-09  7:22 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

On Friday 06 December 2013 04:22 PM, Kamil Debski wrote:
> Hi,
>
>> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
>> Sent: Friday, December 06, 2013 6:31 AM
>>
>> Hi,
>>
>> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
>>> Previously the of_phy_get function took a struct device * and was
>>> declared static. It was impossible to call it from another driver and
>>> thus it was impossible to get phy defined
>>
>> It was never intended to be called from other drivers. What's up with
>> the wrapper of of_phy_get, phy_get()/devm_phy_get()? Why isn't that
>> enough?
>
> Implementing support for multiple phys in the ehci driver is a bit tricky.
> Especially when we want to do it right. Please have a look at this part of
> the dts file:
>
> +    ehci@12580000 {
> +        compatible = "samsung,exynos4210-ehci";
> +        reg = <0x12580000 0x20000>;
> +        interrupts = <0 70 0>;
> +        clocks = <&clock 304>, <&clock 305>;
> +        clock-names = "usbhost", "otg";
> +        status = "disabled";
> +        #address-cells = <1>;
> +        #size-cells = <0>;
> +        port@0 {
> +            reg = <0>;
> +            phys = <&usb2phy 1>;
> +            phy-names = "host";
> +            status = "disabled";
> +        };
> +        port@1 {
> +            reg = <1>;
> +            phys = <&usb2phy 2>;
> +            phy-names = "hsic0";
> +            status = "disabled";
> +        };
> +        port@2 {
> +            reg = <2>;
> +            phys = <&usb2phy 3>;
> +            phy-names = "hsic1";
> +            status = "disabled";
> +        };
> +    };
>
> With the above we have a clear specification of ports and their respective
> phys. But to do this properly the ehci driver has to iterate over port
> nodes. It is much easier to use devm_of_phy_get by giving the node as its
> argument.

I see. There are a couple of more things we do in the wrapper that gets 
missed while exporting of_phy_get (get_device and try_module_get). You 
might want to re-work that one.

Thanks
Kishon

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

* Re: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
  2013-12-06 16:28     ` Kamil Debski
@ 2013-12-09  7:56         ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-09  7:56 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree, balbi,
	'Greg Kroah-Hartman',
	kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

Hi,

On Friday 06 December 2013 09:58 PM, Kamil Debski wrote:
> Hi Kishon,
>
> Thank you for the review.
>
>> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
>> Sent: Friday, December 06, 2013 11:59 AM
>>
>> Hi,
>>
>> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
>>> Add a new driver for the Exynos USB PHY. The new driver uses the
>>> generic PHY framework. The driver includes support for the Exynos
>> 4x10
>>> and 4x12 SoC families.
>>>
>>> Signed-off-by: Kamil Debski <k.debski@samsung.com>
>>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>>> ---


<snip>
.
.
>>> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index
>>> d0caae9..9f4befd 100644
>>> --- a/drivers/phy/Makefile
>>> +++ b/drivers/phy/Makefile
>>> @@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-
>> video.o
>>>   obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>>>   obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
>>>   obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
>>> +obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
>>> +obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>>> +obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
>>> diff --git a/drivers/phy/phy-exynos4210-usb2.c
>>> b/drivers/phy/phy-exynos4210-usb2.c
>>> new file mode 100644
>>> index 0000000..a02e5c2
>>> --- /dev/null
>>> +++ b/drivers/phy/phy-exynos4210-usb2.c
>>> @@ -0,0 +1,264 @@
>>> +/*
>>> + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
>>> + *
>>> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
>>> + * Author: Kamil Debski <k.debski@samsung.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> +modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>> +#include <linux/clk.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/io.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/phy/phy.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/regmap.h>
>>> +#include <linux/spinlock.h>
>>
>> You've included most of the above header files in phy-samsung-usb2.h
>> which you are including below.
>
> I agree that includes in phy-samsung-usb2.h could use a cleanup. On the
> other
> hand my opinion is that a .c file should include all .h files that are used
> in
> this .c file. Relaying on .h file to include another .h doesn't seem good to
> me.

then remove it in .h file.
>
>>> +#include "phy-samsung-usb2.h"
>>> +
>>> +/* Exynos USB PHY registers */
>>> +
>>> +/* PHY power control */
>>> +#define EXYNOS_4210_UPHYPWR			0x0
>>> +
>>> +#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
>>
>> use BIT() here and everywhere below.
>

<snip>
.
.

>>> +#ifdef CONFIG_PHY_EXYNOS4212_USB2
>>> +	{
>>> +		.compatible = "samsung,exynos4212-usb2-phy",
>>> +		.data = &exynos4212_usb2_phy_config,
>>> +	},
>>> +#endif
>>> +	{ },
>>> +};
>>
>> I think we've had enough discussion about this approach. Let's get the
>> opinion of others too. Felipe? Greg?
>
> Good idea.
>
>> Summary:
>> We have two drivers PHY_EXYNOS4210_USB2 and PHY_EXYNOS4212_USB2 with
>> almost similar register map [1] and a samsung helper driver for these
>> two drivers.
>
> I would not call them separate drivers. It's a single USB 2.0 driver with
> the option to include support for various SoCs. This patchset adds:
> Exynos 4210, Exynos 4212, Exynos 5250 and S5PCV210. I know that another
> person is working on supporting S3C6410.
>
>> These two PHY drivers populate the function pointers in the helper
>> driver. So any phy_ops will first invoke the helper driver which will
>> then invoke the corresponding phy driver.
>>
>> [1] -> http://www.diffchecker.com/7yno1uvk
>
> Come on, this diff only includes the registers part of the file.
> The following functions are also different:
> - exynos421*_rate_to_clk
> - exynos421*_isol
> - exynos421*_phy_pwr
> - exynos421*_power_on
> - exynos421*_power_on

But most of the differences is because your 4212 has additional features 
in HSIC and supports more clock rates.
>
> It seems that the file is too large for the tool. But still this makes a
> false impression that only registers are different.
>
>> Advantages:
>> * (more) clean and readable
>> * helper driver can be used with other PHY drivers which will be added
>> soon
>>
>> Disadvantages:
>> * code duplication
>
> I would say that actually in this case less code is duplicated. Having
> Separate drivers would mean that most of the phy-samsung-usb2.c file has

I actually meant a single driver for 4210 and 4212.

your current code has separate drivers for different versions of the 
same IP. If you have a single driver for the different versions, it will 
lead to a lot less code duplication (hint: I've given the exact 'same' 
comment at-least twice in this patch). There are quite a few examples in 
the kernel where the same driver is used for multiple versions of the IP.
> to be repeated. That is 240 times 4 (and surely more in the future, as
> this patchset adds support for 4 SoCs). Which is almost 1000 lines more.
>
>>
>> Maybe having a helper driver makes sense when we have other samsung PHY
>> drivers added but not sure if it's needed here for EXYNOS4210_USB2 and
>> EXYNOS4212_USB2
>>
>> Need your inputs on what you think about this.
>
> Yes, I would also welcome other people's opinions.
>
>>> +
>>> +static int samsung_usb2_phy_probe(struct platform_device *pdev) {
>>> +	const struct of_device_id *match;
>>> +	const struct samsung_usb2_phy_config *cfg;
>>> +	struct clk *clk;
>>> +	struct device *dev = &pdev->dev;
>>> +	struct phy_provider *phy_provider;
>>> +	struct resource *mem;
>>> +	struct samsung_usb2_phy_driver *drv;
>>> +	int i;
>>> +
>>> +	if (!pdev->dev.of_node) {
>>> +		dev_err(dev, "This driver is required to be instantiated
>> from device tree\n");
>>> +		return -EINVAL;
>>> +	}
>>> +

<snip>
.
.
>>> +	int (*power_on)(struct samsung_usb2_phy_instance *);
>>> +	int (*power_off)(struct samsung_usb2_phy_instance *); };
>>> +
>>> +
>>> +struct samsung_usb2_phy_config {
>>> +	int num_phys;
>>> +	const struct samsung_usb2_common_phy *phys;
>>> +	char has_mode_switch;
>>
>> u8 instead?
>
> Do we really need to specify that we need 8bits? Why do you think
> char is wrong?

Do you really assign a char? Having a char data type and assigning an 
integer is misleading.
>
> Please read this paragraph from LDD3:
> "Sometimes kernel code requires data items of a specific size,
> perhaps to match predefined binary structures,* to communicate with
> user space, or to align data within structures by inserting
> "padding" fields (but refer to the section "Data Alignment" for
> information about alignment issues)."
> Chapter 11, page 290 http://lwn.net/images/pdf/LDD3/ch11.pdf
>
> has_mode_switch is only a flag 0 or 1. Never written anywhere in
> hardware registers. Used in an if somewhere in code. Give me a good
> reason why do you think it should be explicitly 8 bit long.

I just thought you created a char type to assign an integer value is you 
wanted to some data type which is 8 bits long. If it is for any other 
reason you used a char data type, pls let us know.

Thanks
Kishon

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

* Re: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
@ 2013-12-09  7:56         ` Kishon Vijay Abraham I
  0 siblings, 0 replies; 50+ messages in thread
From: Kishon Vijay Abraham I @ 2013-12-09  7:56 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree, balbi,
	'Greg Kroah-Hartman',
	kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

Hi,

On Friday 06 December 2013 09:58 PM, Kamil Debski wrote:
> Hi Kishon,
>
> Thank you for the review.
>
>> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
>> Sent: Friday, December 06, 2013 11:59 AM
>>
>> Hi,
>>
>> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
>>> Add a new driver for the Exynos USB PHY. The new driver uses the
>>> generic PHY framework. The driver includes support for the Exynos
>> 4x10
>>> and 4x12 SoC families.
>>>
>>> Signed-off-by: Kamil Debski <k.debski@samsung.com>
>>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>>> ---


<snip>
.
.
>>> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index
>>> d0caae9..9f4befd 100644
>>> --- a/drivers/phy/Makefile
>>> +++ b/drivers/phy/Makefile
>>> @@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-
>> video.o
>>>   obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>>>   obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
>>>   obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
>>> +obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
>>> +obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
>>> +obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
>>> diff --git a/drivers/phy/phy-exynos4210-usb2.c
>>> b/drivers/phy/phy-exynos4210-usb2.c
>>> new file mode 100644
>>> index 0000000..a02e5c2
>>> --- /dev/null
>>> +++ b/drivers/phy/phy-exynos4210-usb2.c
>>> @@ -0,0 +1,264 @@
>>> +/*
>>> + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
>>> + *
>>> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
>>> + * Author: Kamil Debski <k.debski@samsung.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> +modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>> +#include <linux/clk.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/io.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/phy/phy.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/regmap.h>
>>> +#include <linux/spinlock.h>
>>
>> You've included most of the above header files in phy-samsung-usb2.h
>> which you are including below.
>
> I agree that includes in phy-samsung-usb2.h could use a cleanup. On the
> other
> hand my opinion is that a .c file should include all .h files that are used
> in
> this .c file. Relaying on .h file to include another .h doesn't seem good to
> me.

then remove it in .h file.
>
>>> +#include "phy-samsung-usb2.h"
>>> +
>>> +/* Exynos USB PHY registers */
>>> +
>>> +/* PHY power control */
>>> +#define EXYNOS_4210_UPHYPWR			0x0
>>> +
>>> +#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
>>
>> use BIT() here and everywhere below.
>

<snip>
.
.

>>> +#ifdef CONFIG_PHY_EXYNOS4212_USB2
>>> +	{
>>> +		.compatible = "samsung,exynos4212-usb2-phy",
>>> +		.data = &exynos4212_usb2_phy_config,
>>> +	},
>>> +#endif
>>> +	{ },
>>> +};
>>
>> I think we've had enough discussion about this approach. Let's get the
>> opinion of others too. Felipe? Greg?
>
> Good idea.
>
>> Summary:
>> We have two drivers PHY_EXYNOS4210_USB2 and PHY_EXYNOS4212_USB2 with
>> almost similar register map [1] and a samsung helper driver for these
>> two drivers.
>
> I would not call them separate drivers. It's a single USB 2.0 driver with
> the option to include support for various SoCs. This patchset adds:
> Exynos 4210, Exynos 4212, Exynos 5250 and S5PCV210. I know that another
> person is working on supporting S3C6410.
>
>> These two PHY drivers populate the function pointers in the helper
>> driver. So any phy_ops will first invoke the helper driver which will
>> then invoke the corresponding phy driver.
>>
>> [1] -> http://www.diffchecker.com/7yno1uvk
>
> Come on, this diff only includes the registers part of the file.
> The following functions are also different:
> - exynos421*_rate_to_clk
> - exynos421*_isol
> - exynos421*_phy_pwr
> - exynos421*_power_on
> - exynos421*_power_on

But most of the differences is because your 4212 has additional features 
in HSIC and supports more clock rates.
>
> It seems that the file is too large for the tool. But still this makes a
> false impression that only registers are different.
>
>> Advantages:
>> * (more) clean and readable
>> * helper driver can be used with other PHY drivers which will be added
>> soon
>>
>> Disadvantages:
>> * code duplication
>
> I would say that actually in this case less code is duplicated. Having
> Separate drivers would mean that most of the phy-samsung-usb2.c file has

I actually meant a single driver for 4210 and 4212.

your current code has separate drivers for different versions of the 
same IP. If you have a single driver for the different versions, it will 
lead to a lot less code duplication (hint: I've given the exact 'same' 
comment at-least twice in this patch). There are quite a few examples in 
the kernel where the same driver is used for multiple versions of the IP.
> to be repeated. That is 240 times 4 (and surely more in the future, as
> this patchset adds support for 4 SoCs). Which is almost 1000 lines more.
>
>>
>> Maybe having a helper driver makes sense when we have other samsung PHY
>> drivers added but not sure if it's needed here for EXYNOS4210_USB2 and
>> EXYNOS4212_USB2
>>
>> Need your inputs on what you think about this.
>
> Yes, I would also welcome other people's opinions.
>
>>> +
>>> +static int samsung_usb2_phy_probe(struct platform_device *pdev) {
>>> +	const struct of_device_id *match;
>>> +	const struct samsung_usb2_phy_config *cfg;
>>> +	struct clk *clk;
>>> +	struct device *dev = &pdev->dev;
>>> +	struct phy_provider *phy_provider;
>>> +	struct resource *mem;
>>> +	struct samsung_usb2_phy_driver *drv;
>>> +	int i;
>>> +
>>> +	if (!pdev->dev.of_node) {
>>> +		dev_err(dev, "This driver is required to be instantiated
>> from device tree\n");
>>> +		return -EINVAL;
>>> +	}
>>> +

<snip>
.
.
>>> +	int (*power_on)(struct samsung_usb2_phy_instance *);
>>> +	int (*power_off)(struct samsung_usb2_phy_instance *); };
>>> +
>>> +
>>> +struct samsung_usb2_phy_config {
>>> +	int num_phys;
>>> +	const struct samsung_usb2_common_phy *phys;
>>> +	char has_mode_switch;
>>
>> u8 instead?
>
> Do we really need to specify that we need 8bits? Why do you think
> char is wrong?

Do you really assign a char? Having a char data type and assigning an 
integer is misleading.
>
> Please read this paragraph from LDD3:
> "Sometimes kernel code requires data items of a specific size,
> perhaps to match predefined binary structures,* to communicate with
> user space, or to align data within structures by inserting
> "padding" fields (but refer to the section "Data Alignment" for
> information about alignment issues)."
> Chapter 11, page 290 http://lwn.net/images/pdf/LDD3/ch11.pdf
>
> has_mode_switch is only a flag 0 or 1. Never written anywhere in
> hardware registers. Used in an if somewhere in code. Give me a good
> reason why do you think it should be explicitly 8 bit long.

I just thought you created a char type to assign an integer value is you 
wanted to some data type which is 8 bits long. If it is for any other 
reason you used a char data type, pls let us know.

Thanks
Kishon

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

* RE: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
  2013-12-09  7:56         ` Kishon Vijay Abraham I
  (?)
@ 2013-12-09 13:35         ` Kamil Debski
  -1 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-09 13:35 UTC (permalink / raw)
  To: 'Kishon Vijay Abraham I'
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree, balbi,
	'Greg Kroah-Hartman',
	kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

Hi, 

> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
> Sent: Monday, December 09, 2013 8:56 AM
> 
> Hi,
> 
> On Friday 06 December 2013 09:58 PM, Kamil Debski wrote:
> > Hi Kishon,
> >
> > Thank you for the review.
> >
> >> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
> >> Sent: Friday, December 06, 2013 11:59 AM
> >>
> >> Hi,
> >>
> >> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> >>> Add a new driver for the Exynos USB PHY. The new driver uses the
> >>> generic PHY framework. The driver includes support for the Exynos
> >> 4x10
> >>> and 4x12 SoC families.
> >>>
> >>> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> >>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> >>> ---
> 
> 
> <snip>
> .
> .
> >>> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index
> >>> d0caae9..9f4befd 100644
> >>> --- a/drivers/phy/Makefile
> >>> +++ b/drivers/phy/Makefile
> >>> @@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-
> exynos-dp-
> >> video.o
> >>>   obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-
> video.o
> >>>   obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
> >>>   obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
> >>> +obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
> >>> +obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
> >>> +obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> >>> diff --git a/drivers/phy/phy-exynos4210-usb2.c
> >>> b/drivers/phy/phy-exynos4210-usb2.c
> >>> new file mode 100644
> >>> index 0000000..a02e5c2
> >>> --- /dev/null
> >>> +++ b/drivers/phy/phy-exynos4210-usb2.c
> >>> @@ -0,0 +1,264 @@
> >>> +/*
> >>> + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
> >>> + *
> >>> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> >>> + * Author: Kamil Debski <k.debski@samsung.com>
> >>> + *
> >>> + * This program is free software; you can redistribute it and/or
> >>> +modify
> >>> + * it under the terms of the GNU General Public License version 2
> >>> +as
> >>> + * published by the Free Software Foundation.
> >>> + */
> >>> +
> >>> +#include <linux/clk.h>
> >>> +#include <linux/delay.h>
> >>> +#include <linux/io.h>
> >>> +#include <linux/kernel.h>
> >>> +#include <linux/module.h>
> >>> +#include <linux/of.h>
> >>> +#include <linux/of_address.h>
> >>> +#include <linux/phy/phy.h>
> >>> +#include <linux/platform_device.h>
> >>> +#include <linux/regmap.h>
> >>> +#include <linux/spinlock.h>
> >>
> >> You've included most of the above header files in phy-samsung-usb2.h
> >> which you are including below.
> >
> > I agree that includes in phy-samsung-usb2.h could use a cleanup. On
> > the other hand my opinion is that a .c file should include all .h
> > files that are used in this .c file. Relaying on .h file to include
> > another .h doesn't seem good to me.
> 
> then remove it in .h file.
> >
> >>> +#include "phy-samsung-usb2.h"
> >>> +
> >>> +/* Exynos USB PHY registers */
> >>> +
> >>> +/* PHY power control */
> >>> +#define EXYNOS_4210_UPHYPWR			0x0
> >>> +
> >>> +#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
> >>
> >> use BIT() here and everywhere below.
> >
> 
> <snip>
> .
> .
> 
> >>> +#ifdef CONFIG_PHY_EXYNOS4212_USB2
> >>> +	{
> >>> +		.compatible = "samsung,exynos4212-usb2-phy",
> >>> +		.data = &exynos4212_usb2_phy_config,
> >>> +	},
> >>> +#endif
> >>> +	{ },
> >>> +};
> >>
> >> I think we've had enough discussion about this approach. Let's get
> >> the opinion of others too. Felipe? Greg?
> >
> > Good idea.
> >
> >> Summary:
> >> We have two drivers PHY_EXYNOS4210_USB2 and PHY_EXYNOS4212_USB2 with
> >> almost similar register map [1] and a samsung helper driver for
> these
> >> two drivers.
> >
> > I would not call them separate drivers. It's a single USB 2.0 driver
> > with the option to include support for various SoCs. This patchset
> adds:
> > Exynos 4210, Exynos 4212, Exynos 5250 and S5PCV210. I know that
> > another person is working on supporting S3C6410.
> >
> >> These two PHY drivers populate the function pointers in the helper
> >> driver. So any phy_ops will first invoke the helper driver which
> will
> >> then invoke the corresponding phy driver.
> >>
> >> [1] -> http://www.diffchecker.com/7yno1uvk
> >
> > Come on, this diff only includes the registers part of the file.
> > The following functions are also different:
> > - exynos421*_rate_to_clk
> > - exynos421*_isol
> > - exynos421*_phy_pwr
> > - exynos421*_power_on
> > - exynos421*_power_on
> 
> But most of the differences is because your 4212 has additional
> features in HSIC and supports more clock rates.
> >
> > It seems that the file is too large for the tool. But still this
> makes
> > a false impression that only registers are different.
> >
> >> Advantages:
> >> * (more) clean and readable
> >> * helper driver can be used with other PHY drivers which will be
> >> added soon
> >>
> >> Disadvantages:
> >> * code duplication
> >
> > I would say that actually in this case less code is duplicated.
> Having
> > Separate drivers would mean that most of the phy-samsung-usb2.c file
> > has
> 
> I actually meant a single driver for 4210 and 4212.
> 
> your current code has separate drivers for different versions of the
> same IP. If you have a single driver for the different versions, it
> will lead to a lot less code duplication (hint: I'v given the exact
> 'same'
> comment at-least twice in this patch).

You wrote more than twice, I know. I also replied quite a few times. 
I want to explain that this is not a driver for Exynos 4210 and 4212 only.
It is a driver for more SoCs with different IPs.
Like Exynos 5250, S5PV210 and I am sure many more are to follow.
The other two patches in this series add new functionality to this driver
and are not separate drivers.

It is a single driver with custom functions for separate SoC and separate
versions of the same IP. In my opinion it will lead to less code in the
kernel. But we have different opinion on that :) We agree that the code
is more clear and it is easier to manage and add support for new SoC.
Maybe we should focus more on having a clear and readable code?

Kishon, if we were talking about Exynos 4210 and 4212 only, then I could
agree with you. But this driver covers more SoCs.

> There are quite a few examples
> in the kernel where the same driver is used for multiple versions of
> the IP.
> > to be repeated. That is 240 times 4 (and surely more in the future,
> as
> > this patchset adds support for 4 SoCs). Which is almost 1000 lines
> more.
> >
> >>
> >> Maybe having a helper driver makes sense when we have other samsung
> >> PHY drivers added but not sure if it's needed here for
> >> EXYNOS4210_USB2 and
> >> EXYNOS4212_USB2
> >>
> >> Need your inputs on what you think about this.
> >
> > Yes, I would also welcome other people's opinions.
> >
> >>> +
> >>> +static int samsung_usb2_phy_probe(struct platform_device *pdev) {
> >>> +	const struct of_device_id *match;
> >>> +	const struct samsung_usb2_phy_config *cfg;
> >>> +	struct clk *clk;
> >>> +	struct device *dev = &pdev->dev;
> >>> +	struct phy_provider *phy_provider;
> >>> +	struct resource *mem;
> >>> +	struct samsung_usb2_phy_driver *drv;
> >>> +	int i;
> >>> +
> >>> +	if (!pdev->dev.of_node) {
> >>> +		dev_err(dev, "This driver is required to be instantiated
> >> from device tree\n");
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> 
> <snip>
> .
> .
> >>> +	int (*power_on)(struct samsung_usb2_phy_instance *);
> >>> +	int (*power_off)(struct samsung_usb2_phy_instance *); };
> >>> +
> >>> +
> >>> +struct samsung_usb2_phy_config {
> >>> +	int num_phys;
> >>> +	const struct samsung_usb2_common_phy *phys;
> >>> +	char has_mode_switch;
> >>
> >> u8 instead?
> >
> > Do we really need to specify that we need 8bits? Why do you think
> char
> > is wrong?
> 
> Do you really assign a char? Having a char data type and assigning an
> integer is misleading.
> >
> > Please read this paragraph from LDD3:
> > "Sometimes kernel code requires data items of a specific size,
> perhaps
> > to match predefined binary structures,* to communicate with user
> > space, or to align data within structures by inserting "padding"
> > fields (but refer to the section "Data Alignment" for information
> > about alignment issues)."
> > Chapter 11, page 290 http://lwn.net/images/pdf/LDD3/ch11.pdf
> >
> > has_mode_switch is only a flag 0 or 1. Never written anywhere in
> > hardware registers. Used in an if somewhere in code. Give me a good
> > reason why do you think it should be explicitly 8 bit long.
> 
> I just thought you created a char type to assign an integer value is
> you wanted to some data type which is 8 bits long. If it is for any
> other reason you used a char data type, pls let us know.
> 

You must have missed the message I sent soon after the one you replied
to - bool is the best candidate for has_mode_switch.

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland



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

* RE: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
  2013-12-05 12:29   ` Kamil Debski
  (?)
  (?)
@ 2013-12-10  2:42   ` Anton Tikhomirov
  2013-12-17 13:26     ` Kamil Debski
  -1 siblings, 1 reply; 50+ messages in thread
From: Anton Tikhomirov @ 2013-12-10  2:42 UTC (permalink / raw)
  To: 'Kamil Debski',
	linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, jg1.han, galak,
	matt.porter

Hi Kamil,

Same USB2.0 PHY may be used by several HCDs, for example EHCI and OHCI.
Consider the situation, when EHCI stops using the PHY and calls power_off,
then OHCI becomes non-operational. In other words, PHY power_on and
power_off calls must be balanced. 

Shall we handle it in your driver? (usage count?)

> Add a new driver for the Exynos USB PHY. The new driver uses the
> generic
> PHY framework. The driver includes support for the Exynos 4x10 and 4x12
> SoC families.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/phy/samsung-usbphy.txt     |   54 ++++
>  drivers/phy/Kconfig                                |   20 ++
>  drivers/phy/Makefile                               |    3 +
>  drivers/phy/phy-exynos4210-usb2.c                  |  264
> +++++++++++++++++
>  drivers/phy/phy-exynos4212-usb2.c                  |  312
> ++++++++++++++++++++
>  drivers/phy/phy-samsung-usb2.c                     |  228
> ++++++++++++++
>  drivers/phy/phy-samsung-usb2.h                     |   72 +++++
>  7 files changed, 953 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/phy/samsung-
> usbphy.txt
>  create mode 100644 drivers/phy/phy-exynos4210-usb2.c
>  create mode 100644 drivers/phy/phy-exynos4212-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.c
>  create mode 100644 drivers/phy/phy-samsung-usb2.h
> 
> diff --git a/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> new file mode 100644
> index 0000000..cadbf70
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/samsung-usbphy.txt
> @@ -0,0 +1,54 @@
> +Samsung S5P/EXYNOS SoC series USB PHY
> +-------------------------------------------------
> +
> +Required properties:
> +- compatible : should be one of the listed compatibles:
> +	- "samsung,exynos4210-usb2-phy"
> +	- "samsung,exynos4212-usb2-phy"
> +- reg : a list of registers used by phy driver
> +	- first and obligatory is the location of phy modules registers
> +- samsung,sysreg-phandle - handle to syscon used to control the system
> registers
> +- samsung,pmureg-phandle - handle to syscon used to control PMU
> registers
> +- #phy-cells : from the generic phy bindings, must be 1;
> +- clocks and clock-names:
> +	- the "phy" clocks is required by the phy module
> +	- next for each of the phys a clock has to be assidned, this
> clock
> +	  will be used to determine clocking frequency for the phys
> +	  (the labels are specified in the paragraph below)
> +
> +The first phandle argument in the PHY specifier identifies the PHY,
> its
> +meaning is compatible dependent. For the currently supported SoCs
> (Exynos 4210
> +and Exynos 4212) it is as follows:
> +  0 - USB device ("device"),
> +  1 - USB host ("host"),
> +  2 - HSIC0 ("hsic0"),
> +  3 - HSIC1 ("hsic1"),
> +
> +Exynos 4210 and Exynos 4212 use mode switching and require that mode
> switch
> +register is supplied.
> +
> +Example:
> +
> +For Exynos 4412 (compatible with Exynos 4212):
> +
> +usbphy: phy@125B0000 {
> +	compatible = "samsung,exynos4212-usb2-phy";
> +	reg = <0x125B0000 0x100 0x10020704 0x0c 0x1001021c 0x4>;
> +	clocks = <&clock 305>, <&clock 2>, <&clock 2>, <&clock 2>,
> +							<&clock 2>;
> +	clock-names = "phy", "device", "host", "hsic0", "hsic1";
> +	status = "okay";
> +	#phy-cells = <1>;
> +	samsung,sysreg-phandle = <&sys_reg>;
> +	samsung,pmureg-phandle = <&pmu_reg>;
> +};
> +
> +Then the PHY can be used in other nodes such as:
> +
> +phy-consumer@12340000 {
> +	phys = <&usbphy 2>;
> +	phy-names = "phy";
> +};
> +
> +Refer to DT bindings documentation of particular PHY consumer devices
> for more
> +information about required PHYs and the way of specification.
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index a344f3d..b29018f 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -51,4 +51,24 @@ config PHY_EXYNOS_DP_VIDEO
>  	help
>  	  Support for Display Port PHY found on Samsung EXYNOS SoCs.
> 
> +config PHY_SAMSUNG_USB2
> +	tristate "Samsung USB 2.0 PHY driver"
> +	help
> +	  Enable this to support Samsung USB phy helper driver for
> Samsung SoCs.
> +	  This driver provides common interface to interact, for Samsung
> +	  USB 2.0 PHY driver.
> +
> +config PHY_EXYNOS4210_USB2
> +	bool "Support for Exynos 4210"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on CPU_EXYNOS4210
> +	help
> +	  Enable USB PHY support for Exynos 4210
> +
> +config PHY_EXYNOS4212_USB2
> +	bool "Support for Exynos 4212"
> +	depends on PHY_SAMSUNG_USB2
> +	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
> +	help
> +	  Enable USB PHY support for Exynos 4212
>  endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index d0caae9..9f4befd 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -7,3 +7,6 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-
> video.o
>  obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
>  obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
>  obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
> +obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
> +obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
> +obj-$(CONFIG_PHY_EXYNOS4212_USB2)	+= phy-exynos4212-usb2.o
> diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/phy-
> exynos4210-usb2.c
> new file mode 100644
> index 0000000..a02e5c2
> --- /dev/null
> +++ b/drivers/phy/phy-exynos4210-usb2.c
> @@ -0,0 +1,264 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or
> modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>
> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +
> +/* PHY power control */
> +#define EXYNOS_4210_UPHYPWR			0x0
> +
> +#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	(1 << 0)
> +#define EXYNOS_4210_UPHYPWR_PHY0_PWR		(1 << 3)
> +#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	(1 << 4)
> +#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		(1 << 5)
> +#define EXYNOS_4210_UPHYPWR_PHY0	( \
> +	EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_PHY0_PWR | \
> +	EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
> +	EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
> +
> +#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND	(1 << 6)
> +#define EXYNOS_4210_UPHYPWR_PHY1_PWR		(1 << 7)
> +#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		(1 << 8)
> +#define EXYNOS_4210_UPHYPWR_PHY1 ( \
> +	EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_PHY1_PWR | \
> +	EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
> +
> +#define EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> +#define EXYNOS_4210_UPHYPWR_HSCI0_SLEEP		(1 << 10)
> +#define EXYNOS_4210_UPHYPWR_HSCI0 ( \
> +	EXYNOS_4210_UPHYPWR_HSCI0_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_HSCI0_SLEEP)
> +
> +#define EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND	(1 << 11)
> +#define EXYNOS_4210_UPHYPWR_HSCI1_SLEEP		(1 << 12)
> +#define EXYNOS_4210_UPHYPWR_HSCI1 ( \
> +	EXYNOS_4210_UPHYPWR_HSCI1_SUSPEND | \
> +	EXYNOS_4210_UPHYPWR_HSCI1_SLEEP)
> +
> +/* PHY clock control */
> +#define EXYNOS_4210_UPHYCLK			0x4
> +
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
> +#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> +
> +#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 2)
> +#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> +#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> +
> +/* PHY reset control */
> +#define EXYNOS_4210_UPHYRST			0x8
> +
> +#define EXYNOS_4210_URSTCON_PHY0		(1 << 0)
> +#define EXYNOS_4210_URSTCON_OTG_HLINK		(1 << 1)
> +#define EXYNOS_4210_URSTCON_OTG_PHYLINK		(1 << 2)
> +#define EXYNOS_4210_URSTCON_PHY1_ALL		(1 << 3)
> +#define EXYNOS_4210_URSTCON_PHY1_P0		(1 << 4)
> +#define EXYNOS_4210_URSTCON_PHY1_P1P2		(1 << 5)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_ALL	(1 << 6)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_P0	(1 << 7)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_P1	(1 << 8)
> +#define EXYNOS_4210_URSTCON_HOST_LINK_P2	(1 << 9)
> +
> +/* Isolation, configured in the power management unit */
> +#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
> +#define EXYNOS_4210_USB_ISOL_DEVICE		(1 << 0)
> +#define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
> +#define EXYNOS_4210_USB_ISOL_HOST		(1 << 0)
> +
> +/* USBYPHY1 Floating prevention */
> +#define EXYNOS_4210_UPHY1CON			0x34
> +#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION	0x1
> +
> +/* Mode switching SUB Device <-> Host */
> +#define EXYNOS_4210_MODE_SWITCH_OFFSET		0x21c
> +#define EXYNOS_4210_MODE_SWITCH_MASK		1
> +#define EXYNOS_4210_MODE_SWITCH_DEVICE		0
> +#define EXYNOS_4210_MODE_SWITCH_HOST		1
> +
> +enum exynos4210_phy_id {
> +	EXYNOS4210_DEVICE,
> +	EXYNOS4210_HOST,
> +	EXYNOS4210_HSIC0,
> +	EXYNOS4210_HSIC1,
> +	EXYNOS4210_NUM_PHYS,
> +};
> +
> +/*
> + * exynos4210_rate_to_clk() converts the supplied clock rate to the
> value that
> + * can be written to the phy register.
> + */
> +static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	switch (rate) {
> +	case 12 * MHZ:
> +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
> +		break;
> +	case 48 * MHZ:
> +		reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void exynos4210_isol(struct samsung_usb2_phy_instance *inst,
> bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 offset;
> +	u32 mask;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4210_DEVICE:
> +		offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
> +		mask = EXYNOS_4210_USB_ISOL_DEVICE;
> +		break;
> +	case EXYNOS4210_HOST:
> +		offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
> +		mask = EXYNOS_4210_USB_ISOL_HOST;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst,
> bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 rstbits = 0;
> +	u32 phypwr = 0;
> +	u32 rst;
> +	u32 pwr;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4210_DEVICE:
> +		phypwr =	EXYNOS_4210_UPHYPWR_PHY0;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY0;
> +		break;
> +	case EXYNOS4210_HOST:
> +		phypwr =	EXYNOS_4210_UPHYPWR_PHY1;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY1_ALL |
> +				EXYNOS_4210_URSTCON_PHY1_P0 |
> +				EXYNOS_4210_URSTCON_PHY1_P1P2 |
> +				EXYNOS_4210_URSTCON_HOST_LINK_ALL |
> +				EXYNOS_4210_URSTCON_HOST_LINK_P0;
> +		writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
> +		break;
> +	case EXYNOS4210_HSIC0:
> +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI0;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> +				EXYNOS_4210_URSTCON_HOST_LINK_P1;
> +		break;
> +	case EXYNOS4210_HSIC1:
> +		phypwr =	EXYNOS_4210_UPHYPWR_HSCI1;
> +		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
> +				EXYNOS_4210_URSTCON_HOST_LINK_P2;
> +		break;
> +	};
> +
> +	if (on) {
> +		writel(inst->clk_reg_val, drv->reg_phy +
> EXYNOS_4210_UPHYCLK);
> +
> +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +		pwr &= ~phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +
> +		rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
> +		rst |= rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
> +		udelay(10);
> +		rst &= ~rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
> +	} else {
> +		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +		pwr |= phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
> +	}
> +}
> +
> +static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	/* Order of initialisation is important - first power then
> isolation */
> +	exynos4210_phy_pwr(inst, 1);
> +	exynos4210_isol(inst, 0);
> +
> +	return 0;
> +}
> +
> +static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	exynos4210_isol(inst, 1);
> +	exynos4210_phy_pwr(inst, 0);
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy exynos4210_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= EXYNOS4210_DEVICE,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= EXYNOS4210_HOST,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{
> +		.label		= "hsic0",
> +		.id		= EXYNOS4210_HSIC0,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{
> +		.label		= "hsic1",
> +		.id		= EXYNOS4210_HSIC1,
> +		.rate_to_clk	= exynos4210_rate_to_clk,
> +		.power_on	= exynos4210_power_on,
> +		.power_off	= exynos4210_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
> +	.num_phys		= EXYNOS4210_NUM_PHYS,
> +	.phys			= exynos4210_phys,
> +	.has_mode_switch	= 1,
> +};
> +
> diff --git a/drivers/phy/phy-exynos4212-usb2.c b/drivers/phy/phy-
> exynos4212-usb2.c
> new file mode 100644
> index 0000000..375ece0
> --- /dev/null
> +++ b/drivers/phy/phy-exynos4212-usb2.c
> @@ -0,0 +1,312 @@
> +/*
> + * Samsung S5P/EXYNOS SoC series USB PHY driver - Exynos 4212 support
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or
> modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>
> +#include "phy-samsung-usb2.h"
> +
> +/* Exynos USB PHY registers */
> +
> +/* PHY power control */
> +#define EXYNOS_4212_UPHYPWR			0x0
> +
> +#define EXYNOS_4212_UPHYPWR_DEV_SUSPEND		(1 << 0)
> +#define EXYNOS_4212_UPHYPWR_DEV_PWR		(1 << 3)
> +#define EXYNOS_4212_UPHYPWR_DEV_OTG_PWR		(1 << 4)
> +#define EXYNOS_4212_UPHYPWR_DEV_SLEEP		(1 << 5)
> +#define EXYNOS_4212_UPHYPWR_DEV	( \
> +	EXYNOS_4212_UPHYPWR_DEV_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_DEV_PWR | \
> +	EXYNOS_4212_UPHYPWR_DEV_OTG_PWR | \
> +	EXYNOS_4212_UPHYPWR_DEV_SLEEP)
> +
> +#define EXYNOS_4212_UPHYPWR_HOST_SUSPEND	(1 << 6)
> +#define EXYNOS_4212_UPHYPWR_HOST_PWR		(1 << 7)
> +#define EXYNOS_4212_UPHYPWR_HOST_SLEEP		(1 << 8)
> +#define EXYNOS_4212_UPHYPWR_HOST ( \
> +	EXYNOS_4212_UPHYPWR_HOST_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_HOST_PWR | \
> +	EXYNOS_4212_UPHYPWR_HOST_SLEEP)
> +
> +#define EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND	(1 << 9)
> +#define EXYNOS_4212_UPHYPWR_HSCI0_PWR		(1 << 10)
> +#define EXYNOS_4212_UPHYPWR_HSCI0_SLEEP		(1 << 11)
> +#define EXYNOS_4212_UPHYPWR_HSCI0 ( \
> +	EXYNOS_4212_UPHYPWR_HSCI0_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_HSCI0_PWR | \
> +	EXYNOS_4212_UPHYPWR_HSCI0_SLEEP)
> +
> +#define EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND	(1 << 12)
> +#define EXYNOS_4212_UPHYPWR_HSCI1_PWR		(1 << 13)
> +#define EXYNOS_4212_UPHYPWR_HSCI1_SLEEP		(1 << 14)
> +#define EXYNOS_4212_UPHYPWR_HSCI1 ( \
> +	EXYNOS_4212_UPHYPWR_HSCI1_SUSPEND | \
> +	EXYNOS_4212_UPHYPWR_HSCI1_PWR | \
> +	EXYNOS_4212_UPHYPWR_HSCI1_SLEEP)
> +
> +/* PHY clock control */
> +#define EXYNOS_4212_UPHYCLK			0x4
> +
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_MASK	(0x7 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6	(0x0 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ	(0x1 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2	(0x3 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ	(0x4 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ	(0x5 << 0)
> +#define EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ	(0x7 << 0)
> +
> +#define EXYNOS_4212_UPHYCLK_PHY0_ID_PULLUP	(0x1 << 3)
> +#define EXYNOS_4212_UPHYCLK_PHY0_COMMON_ON	(0x1 << 4)
> +#define EXYNOS_4212_UPHYCLK_PHY1_COMMON_ON	(0x1 << 7)
> +
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_MASK	(0x7f << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_12MHZ	(0x24 << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_15MHZ	(0x1c << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_16MHZ	(0x1a << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_19MHZ2	(0x15 << 10)
> +#define EXYNOS_4212_UPHYCLK_HSIC_REFCLK_20MHZ	(0x14 << 10)
> +
> +/* PHY reset control */
> +#define EXYNOS_4212_UPHYRST			0x8
> +
> +#define EXYNOS_4212_URSTCON_DEVICE		(1 << 0)
> +#define EXYNOS_4212_URSTCON_OTG_HLINK		(1 << 1)
> +#define EXYNOS_4212_URSTCON_OTG_PHYLINK		(1 << 2)
> +#define EXYNOS_4212_URSTCON_HOST_PHY		(1 << 3)
> +#define EXYNOS_4212_URSTCON_PHY1		(1 << 4)
> +#define EXYNOS_4212_URSTCON_HSIC0		(1 << 5)
> +#define EXYNOS_4212_URSTCON_HSIC1		(1 << 6)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_ALL	(1 << 7)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_P0	(1 << 8)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_P1	(1 << 9)
> +#define EXYNOS_4212_URSTCON_HOST_LINK_P2	(1 << 10)
> +
> +/* Isolation, configured in the power management unit */
> +#define EXYNOS_4212_USB_ISOL_OFFSET		0x704
> +#define EXYNOS_4212_USB_ISOL_OTG		(1 << 0)
> +#define EXYNOS_4212_USB_ISOL_HSIC0_OFFSET	0x708
> +#define EXYNOS_4212_USB_ISOL_HSIC0		(1 << 0)
> +#define EXYNOS_4212_USB_ISOL_HSIC1_OFFSET	0x70c
> +#define EXYNOS_4212_USB_ISOL_HSIC1		(1 << 0)
> +
> +/* Mode switching SUB Device <-> Host */
> +#define EXYNOS_4212_MODE_SWITCH_OFFSET		0x21c
> +#define EXYNOS_4212_MODE_SWITCH_MASK		1
> +#define EXYNOS_4212_MODE_SWITCH_DEVICE		0
> +#define EXYNOS_4212_MODE_SWITCH_HOST		1
> +
> +enum exynos4x12_phy_id {
> +	EXYNOS4212_DEVICE,
> +	EXYNOS4212_HOST,
> +	EXYNOS4212_HSIC0,
> +	EXYNOS4212_HSIC1,
> +	EXYNOS4212_NUM_PHYS,
> +};
> +
> +/*
> + * exynos4212_rate_to_clk() converts the supplied clock rate to the
> value that
> + * can be written to the phy register.
> + */
> +static int exynos4212_rate_to_clk(unsigned long rate, u32 *reg)
> +{
> +	/* EXYNOS_4212_UPHYCLK_PHYFSEL_MASK */
> +
> +	switch (rate) {
> +	case 9600 * KHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_9MHZ6;
> +		break;
> +	case 10 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_10MHZ;
> +		break;
> +	case 12 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_12MHZ;
> +		break;
> +	case 19200 * KHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_19MHZ2;
> +		break;
> +	case 20 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_20MHZ;
> +		break;
> +	case 24 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_24MHZ;
> +		break;
> +	case 50 * MHZ:
> +		*reg = EXYNOS_4212_UPHYCLK_PHYFSEL_50MHZ;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static void exynos4212_isol(struct samsung_usb2_phy_instance *inst,
> bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 offset;
> +	u32 mask;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4212_DEVICE:
> +	case EXYNOS4212_HOST:
> +		offset = EXYNOS_4212_USB_ISOL_OFFSET;
> +		mask = EXYNOS_4212_USB_ISOL_OTG;
> +		break;
> +	case EXYNOS4212_HSIC0:
> +		offset = EXYNOS_4212_USB_ISOL_HSIC0_OFFSET;
> +		mask = EXYNOS_4212_USB_ISOL_HSIC0;
> +		break;
> +	case EXYNOS4212_HSIC1:
> +		offset = EXYNOS_4212_USB_ISOL_HSIC1_OFFSET;
> +		mask = EXYNOS_4212_USB_ISOL_HSIC1;
> +		break;
> +	default:
> +		return;
> +	};
> +
> +	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
> +}
> +
> +static void exynos4212_phy_pwr(struct samsung_usb2_phy_instance *inst,
> bool on)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	u32 rstbits = 0;
> +	u32 phypwr = 0;
> +	u32 rst;
> +	u32 pwr;
> +
> +	switch (inst->cfg->id) {
> +	case EXYNOS4212_DEVICE:
> +		phypwr =	EXYNOS_4212_UPHYPWR_DEV;
> +		rstbits =	EXYNOS_4212_URSTCON_DEVICE;
> +		break;
> +	case EXYNOS4212_HOST:
> +		phypwr =	EXYNOS_4212_UPHYPWR_HOST;
> +		rstbits =	EXYNOS_4212_URSTCON_HOST_PHY;
> +		break;
> +	case EXYNOS4212_HSIC0:
> +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI0;
> +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> +				EXYNOS_4212_URSTCON_HOST_LINK_P0 |
> +				EXYNOS_4212_URSTCON_HOST_PHY;
> +		break;
> +	case EXYNOS4212_HSIC1:
> +		phypwr =	EXYNOS_4212_UPHYPWR_HSCI1;
> +		rstbits =	EXYNOS_4212_URSTCON_HSIC1 |
> +				EXYNOS_4212_URSTCON_HOST_LINK_P1;
> +		break;
> +	};
> +
> +	if (on) {
> +		writel(inst->clk_reg_val, drv->reg_phy +
> EXYNOS_4212_UPHYCLK);
> +
> +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +		pwr &= ~phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +
> +		rst = readl(drv->reg_phy + EXYNOS_4212_UPHYRST);
> +		rst |= rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
> +		udelay(10);
> +		rst &= ~rstbits;
> +		writel(rst, drv->reg_phy + EXYNOS_4212_UPHYRST);
> +	} else {
> +		pwr = readl(drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +		pwr |= phypwr;
> +		writel(pwr, drv->reg_phy + EXYNOS_4212_UPHYPWR);
> +	}
> +}
> +
> +static int exynos4212_power_on(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +
> +	inst->enabled = 1;
> +	exynos4212_phy_pwr(inst, 1);
> +	exynos4212_isol(inst, 0);
> +
> +	/* Power on the device, as it is necessary for HSIC to work */
> +	if (inst->cfg->id == EXYNOS4212_HSIC0) {
> +		struct samsung_usb2_phy_instance *device =
> +					&drv->instances[EXYNOS4212_DEVICE];
> +		exynos4212_phy_pwr(device, 1);
> +		exynos4212_isol(device, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +static int exynos4212_power_off(struct samsung_usb2_phy_instance *inst)
> +{
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	struct samsung_usb2_phy_instance *device = &drv-
> >instances[EXYNOS4212_DEVICE];
> +
> +	inst->enabled = 0;
> +	exynos4212_isol(inst, 1);
> +	exynos4212_phy_pwr(inst, 0);
> +
> +	if (inst->cfg->id == EXYNOS4212_HSIC0 && !device->enabled) {
> +		exynos4212_isol(device, 1);
> +		exynos4212_phy_pwr(device, 0);
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static const struct samsung_usb2_common_phy exynos4212_phys[] = {
> +	{
> +		.label		= "device",
> +		.id		= EXYNOS4212_DEVICE,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{
> +		.label		= "host",
> +		.id		= EXYNOS4212_HOST,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{
> +		.label		= "hsic0",
> +		.id		= EXYNOS4212_HSIC0,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{
> +		.label		= "hsic1",
> +		.id		= EXYNOS4212_HSIC1,
> +		.rate_to_clk	= exynos4212_rate_to_clk,
> +		.power_on	= exynos4212_power_on,
> +		.power_off	= exynos4212_power_off,
> +	},
> +	{},
> +};
> +
> +const struct samsung_usb2_phy_config exynos4212_usb2_phy_config = {
> +	.num_phys		= EXYNOS4212_NUM_PHYS,
> +	.phys			= exynos4212_phys,
> +	.has_mode_switch	= 1,
> +};
> +
> diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-
> usb2.c
> new file mode 100644
> index 0000000..804ec77
> --- /dev/null
> +++ b/drivers/phy/phy-samsung-usb2.c
> @@ -0,0 +1,228 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or
> modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include "phy-samsung-usb2.h"
> +
> +static int samsung_usb2_phy_power_on(struct phy *phy)
> +{
> +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	int ret;
> +
> +	dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
> +							inst->cfg->label);
> +	ret = clk_prepare_enable(drv->clk);
> +	if (ret)
> +		goto err_main_clk;
> +	ret = clk_prepare_enable(inst->clk);
> +	if (ret)
> +		goto err_instance_clk;
> +	inst->rate = clk_get_rate(inst->clk);
> +	if (inst->cfg->rate_to_clk) {
> +		ret = inst->cfg->rate_to_clk(inst->rate, &inst-
> >clk_reg_val);
> +		if (ret)
> +			goto err_get_rate;
> +	}
> +	if (inst->cfg->power_on) {
> +		spin_lock(&drv->lock);
> +		ret = inst->cfg->power_on(inst);
> +		spin_unlock(&drv->lock);
> +	}
> +
> +	return 0;
> +
> +err_get_rate:
> +	clk_disable_unprepare(inst->clk);
> +err_instance_clk:
> +	clk_disable_unprepare(drv->clk);
> +err_main_clk:
> +	return ret;
> +}
> +
> +static int samsung_usb2_phy_power_off(struct phy *phy)
> +{
> +	struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
> +	struct samsung_usb2_phy_driver *drv = inst->drv;
> +	int ret = 0;
> +
> +	dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
> +							inst->cfg->label);
> +	if (inst->cfg->power_off) {
> +		spin_lock(&drv->lock);
> +		ret = inst->cfg->power_off(inst);
> +		spin_unlock(&drv->lock);
> +	}
> +	clk_disable_unprepare(inst->clk);
> +	clk_disable_unprepare(drv->clk);
> +	return ret;
> +}
> +
> +static struct phy_ops samsung_usb2_phy_ops = {
> +	.power_on	= samsung_usb2_phy_power_on,
> +	.power_off	= samsung_usb2_phy_power_off,
> +	.owner		= THIS_MODULE,
> +};
> +
> +static struct phy *samsung_usb2_phy_xlate(struct device *dev,
> +					struct of_phandle_args *args)
> +{
> +	struct samsung_usb2_phy_driver *drv;
> +
> +	drv = dev_get_drvdata(dev);
> +	if (!drv)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
> +		return ERR_PTR(-ENODEV);
> +
> +	return drv->instances[args->args[0]].phy;
> +}
> +
> +static const struct of_device_id samsung_usb2_phy_of_match[] = {
> +#ifdef CONFIG_PHY_EXYNOS4210_USB2
> +	{
> +		.compatible = "samsung,exynos4210-usb2-phy",
> +		.data = &exynos4210_usb2_phy_config,
> +	},
> +#endif
> +#ifdef CONFIG_PHY_EXYNOS4212_USB2
> +	{
> +		.compatible = "samsung,exynos4212-usb2-phy",
> +		.data = &exynos4212_usb2_phy_config,
> +	},
> +#endif
> +	{ },
> +};
> +
> +static int samsung_usb2_phy_probe(struct platform_device *pdev)
> +{
> +	const struct of_device_id *match;
> +	const struct samsung_usb2_phy_config *cfg;
> +	struct clk *clk;
> +	struct device *dev = &pdev->dev;
> +	struct phy_provider *phy_provider;
> +	struct resource *mem;
> +	struct samsung_usb2_phy_driver *drv;
> +	int i;
> +
> +	if (!pdev->dev.of_node) {
> +		dev_err(dev, "This driver is required to be instantiated
> from device tree\n");
> +		return -EINVAL;
> +	}
> +
> +	match = of_match_node(samsung_usb2_phy_of_match, pdev-
> >dev.of_node);
> +	if (!match) {
> +		dev_err(dev, "of_match_node() failed\n");
> +		return -EINVAL;
> +	}
> +	cfg = match->data;
> +
> +	drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
> +		cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),
> GFP_KERNEL);
> +	if (!drv)
> +		return -ENOMEM;
> +
> +	dev_set_drvdata(dev, drv);
> +	spin_lock_init(&drv->lock);
> +
> +	drv->cfg = cfg;
> +	drv->dev = dev;
> +
> +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	drv->reg_phy = devm_ioremap_resource(dev, mem);
> +	if (IS_ERR(drv->reg_phy)) {
> +		dev_err(dev, "Failed to map register memory (phy)\n");
> +		return PTR_ERR(drv->reg_phy);
> +	}
> +
> +	drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
> +		"samsung,pmureg-phandle");
> +	if (IS_ERR(drv->reg_pmu)) {
> +		dev_err(dev, "Failed to map PMU registers (via syscon)\n");
> +		return PTR_ERR(drv->reg_pmu);
> +	}
> +
> +	if (drv->cfg->has_mode_switch) {
> +		drv->reg_sys = syscon_regmap_lookup_by_phandle(
> +				pdev->dev.of_node,
"samsung,sysreg-phandle");
> +		if (IS_ERR(drv->reg_sys)) {
> +			dev_err(dev, "Failed to map system registers (via
> syscon)\n");
> +			return PTR_ERR(drv->reg_sys);
> +		}
> +	}
> +
> +	drv->clk = devm_clk_get(dev, "phy");
> +	if (IS_ERR(drv->clk)) {
> +		dev_err(dev, "Failed to get clock of phy controller\n");
> +		return PTR_ERR(drv->clk);
> +	}
> +
> +	for (i = 0; i < drv->cfg->num_phys; i++) {
> +		char *label = drv->cfg->phys[i].label;
> +		struct samsung_usb2_phy_instance *p = &drv->instances[i];
> +
> +		dev_dbg(dev, "Creating phy \"%s\"\n", label);
> +		p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
> +		if (IS_ERR(p->phy)) {
> +			dev_err(drv->dev, "Failed to create usb2_phy
> \"%s\"\n",
> +						label);
> +			return PTR_ERR(p->phy);
> +		}
> +
> +		p->cfg = &drv->cfg->phys[i];
> +		p->drv = drv;
> +		phy_set_drvdata(p->phy, p);
> +
> +		clk = devm_clk_get(dev, p->cfg->label);
> +		if (IS_ERR(clk)) {
> +			dev_err(dev, "Failed to get clock of \"%s\" phy\n",
> +
p->cfg->label);
> +			return PTR_ERR(clk);
> +		}
> +		p->clk = clk;
> +	}
> +
> +	phy_provider = devm_of_phy_provider_register(dev,
> +
samsung_usb2_phy_xlate);
> +	if (IS_ERR(phy_provider)) {
> +		dev_err(drv->dev, "Failed to register phy provider\n");
> +		return PTR_ERR(phy_provider);
> +	}
> +
> +	return 0;
> +}
> +
> +static struct platform_driver samsung_usb2_phy_driver = {
> +	.probe	= samsung_usb2_phy_probe,
> +	.driver = {
> +		.of_match_table	= samsung_usb2_phy_of_match,
> +		.name		= "samsung-usb2-phy",
> +		.owner		= THIS_MODULE,
> +	}
> +};
> +
> +module_platform_driver(samsung_usb2_phy_driver);
> +MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
> +MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:samsung-usb2-phy");
> +
> diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-
> usb2.h
> new file mode 100644
> index 0000000..cd12477
> --- /dev/null
> +++ b/drivers/phy/phy-samsung-usb2.h
> @@ -0,0 +1,72 @@
> +/*
> + * Samsung SoC USB 1.1/2.0 PHY driver
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Kamil Debski <k.debski@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or
> modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef _PHY_EXYNOS_USB2_H
> +#define _PHY_EXYNOS_USB2_H
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +
> +#define KHZ 1000
> +#define MHZ (KHZ * KHZ)
> +
> +struct samsung_usb2_phy_driver;
> +struct samsung_usb2_phy_instance;
> +struct samsung_usb2_phy_config;
> +
> +struct samsung_usb2_phy_instance {
> +	struct samsung_usb2_phy_driver *drv;
> +	struct phy *phy;
> +	const struct samsung_usb2_common_phy *cfg;
> +	char enabled;
> +	struct clk *clk;
> +	u32 clk_reg_val;
> +	unsigned long rate;
> +};
> +
> +struct samsung_usb2_phy_driver {
> +	struct device *dev;
> +	spinlock_t lock;
> +	void __iomem *reg_phy;
> +	struct regmap *reg_sys;
> +	struct regmap *reg_pmu;
> +	const struct samsung_usb2_phy_config *cfg;
> +	struct clk *clk;
> +	struct samsung_usb2_phy_instance instances[0];
> +};
> +
> +struct samsung_usb2_common_phy {
> +	char *label;
> +	unsigned int id;
> +	int (*rate_to_clk)(unsigned long, u32 *);
> +	int (*power_on)(struct samsung_usb2_phy_instance *);
> +	int (*power_off)(struct samsung_usb2_phy_instance *);
> +};
> +
> +
> +struct samsung_usb2_phy_config {
> +	int num_phys;
> +	const struct samsung_usb2_common_phy *phys;
> +	char has_mode_switch;
> +};
> +
> +extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
> +extern const struct samsung_usb2_phy_config exynos4212_usb2_phy_config;
> +#endif
> +
> --
> 1.7.9.5


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

* Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
  2013-12-05 12:29 ` [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with " Kamil Debski
  2013-12-06 11:11     ` Kishon Vijay Abraham I
@ 2013-12-11 15:15   ` Matt Porter
  2013-12-16 21:40     ` Matt Porter
  2 siblings, 0 replies; 50+ messages in thread
From: Matt Porter @ 2013-12-11 15:15 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak

On Thu, Dec 05, 2013 at 01:29:35PM +0100, Kamil Debski wrote:
> Change the used phy driver to the new Exynos USB phy driver that uses the
> generic phy framework.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
>  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++-----
>  2 files changed, 10 insertions(+), 5 deletions(-)

This is only applying with fuzz against -rc3, needs an update. It's
otherwise still working fine on my BCM Capri board.

-Matt

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

* RE: [PATCH 1/9] phy: core: Change the way of_phy_get is called
  2013-12-09  7:22         ` Kishon Vijay Abraham I
  (?)
@ 2013-12-13 14:20         ` Kamil Debski
  -1 siblings, 0 replies; 50+ messages in thread
From: Kamil Debski @ 2013-12-13 14:20 UTC (permalink / raw)
  To: 'Kishon Vijay Abraham I'
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, Tomasz Figa, Sylwester Nawrocki, Marek Szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, matt.porter

Hi, 

> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
> Sent: Monday, December 09, 2013 8:23 AM
> 
> On Friday 06 December 2013 04:22 PM, Kamil Debski wrote:
> > Hi,
> >
> >> From: Kishon Vijay Abraham I [mailto:kishon@ti.com]
> >> Sent: Friday, December 06, 2013 6:31 AM
> >>
> >> Hi,
> >>
> >> On Thursday 05 December 2013 05:59 PM, Kamil Debski wrote:
> >>> Previously the of_phy_get function took a struct device * and was
> >>> declared static. It was impossible to call it from another driver
> >>> and thus it was impossible to get phy defined
> >>
> >> It was never intended to be called from other drivers. What's up
> with
> >> the wrapper of of_phy_get, phy_get()/devm_phy_get()? Why isn't that
> >> enough?
> >
> > Implementing support for multiple phys in the ehci driver is a bit
> tricky.
> > Especially when we want to do it right. Please have a look at this
> > part of the dts file:
> >
> > +    ehci@12580000 {
> > +        compatible = "samsung,exynos4210-ehci";
> > +        reg = <0x12580000 0x20000>;
> > +        interrupts = <0 70 0>;
> > +        clocks = <&clock 304>, <&clock 305>;
> > +        clock-names = "usbhost", "otg";
> > +        status = "disabled";
> > +        #address-cells = <1>;
> > +        #size-cells = <0>;
> > +        port@0 {
> > +            reg = <0>;
> > +            phys = <&usb2phy 1>;
> > +            phy-names = "host";
> > +            status = "disabled";
> > +        };
> > +        port@1 {
> > +            reg = <1>;
> > +            phys = <&usb2phy 2>;
> > +            phy-names = "hsic0";
> > +            status = "disabled";
> > +        };
> > +        port@2 {
> > +            reg = <2>;
> > +            phys = <&usb2phy 3>;
> > +            phy-names = "hsic1";
> > +            status = "disabled";
> > +        };
> > +    };
> >
> > With the above we have a clear specification of ports and their
> > respective phys. But to do this properly the ehci driver has to
> > iterate over port nodes. It is much easier to use devm_of_phy_get by
> > giving the node as its argument.
> 
> I see. There are a couple of more things we do in the wrapper that gets
> missed while exporting of_phy_get (get_device and try_module_get). You
> might want to re-work that one.

Thank you for the review. I have just sent an updated version of the core
patches.

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland




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

* Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
@ 2013-12-16 21:40     ` Matt Porter
  0 siblings, 0 replies; 50+ messages in thread
From: Matt Porter @ 2013-12-16 21:40 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, kishon, t.figa, s.nawrocki, m.szyprowski,
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, av.tikhomirov,
	jg1.han, galak, Felipe Balbi

On Thu, Dec 05, 2013 at 01:29:35PM +0100, Kamil Debski wrote:
> Change the used phy driver to the new Exynos USB phy driver that uses the
> generic phy framework.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
>  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++-----
>  2 files changed, 10 insertions(+), 5 deletions(-)

Kamil,

Can we separate this patch out of this series? My bcm281xx series is
ready to go except for this dependency. Felipe has noted that there's
only a week until he locks his tree down for 3.14 [1]. I'm willing to
update this versus the comment Kishon made on fixing the example if
you don't have time before then. Let me know.

[1] https://lkml.org/lkml/2013/12/16/555

Thanks,
Matt

> diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> index b83d428..9340d06 100644
> --- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> @@ -24,6 +24,8 @@ Required properties:
>      - first entry: must be "otg"
>  - vusb_d-supply: phandle to voltage regulator of digital section,
>  - vusb_a-supply: phandle to voltage regulator of analog section.
> +- phys: from general PHY binding: phandle to the PHY device
> +- phy-names: from general PHY binding: should be "usb2-phy"
>  
>  Example
>  -----
> @@ -36,5 +38,7 @@ Example
>  		clock-names = "otg";
>  		vusb_d-supply = <&vusb_reg>;
>  		vusb_a-supply = <&vusbdac_reg>;
> +		phys = <&usb2phy 0>;
> +		phy-names = "device";
>  	};
>  
> diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
> index eccb147..db096fd 100644
> --- a/drivers/usb/gadget/s3c-hsotg.c
> +++ b/drivers/usb/gadget/s3c-hsotg.c
> @@ -31,6 +31,7 @@
>  #include <linux/regulator/consumer.h>
>  #include <linux/of.h>
>  #include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
>  
>  #include <linux/usb/ch9.h>
>  #include <linux/usb/gadget.h>
> @@ -162,7 +163,7 @@ struct s3c_hsotg_ep {
>  struct s3c_hsotg {
>  	struct device		 *dev;
>  	struct usb_gadget_driver *driver;
> -	struct usb_phy		*phy;
> +	struct phy		 *phy;
>  	struct s3c_hsotg_plat	 *plat;
>  
>  	spinlock_t              lock;
> @@ -2905,7 +2906,7 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
>  	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
>  
>  	if (hsotg->phy)
> -		usb_phy_init(hsotg->phy);
> +		phy_power_on(hsotg->phy);
>  	else if (hsotg->plat->phy_init)
>  		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
>  }
> @@ -2922,7 +2923,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
>  	struct platform_device *pdev = to_platform_device(hsotg->dev);
>  
>  	if (hsotg->phy)
> -		usb_phy_shutdown(hsotg->phy);
> +		phy_power_off(hsotg->phy);
>  	else if (hsotg->plat->phy_exit)
>  		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
>  }
> @@ -3529,7 +3530,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
>  static int s3c_hsotg_probe(struct platform_device *pdev)
>  {
>  	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
> -	struct usb_phy *phy;
> +	struct phy *phy;
>  	struct device *dev = &pdev->dev;
>  	struct s3c_hsotg_ep *eps;
>  	struct s3c_hsotg *hsotg;
> @@ -3544,7 +3545,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  	}
>  
> -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
> +	phy = devm_phy_get(&pdev->dev, "usb2-phy");
>  	if (IS_ERR(phy)) {
>  		/* Fallback for pdata */
>  		plat = dev_get_platdata(&pdev->dev);
> -- 
> 1.7.9.5
> 

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

* Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
@ 2013-12-16 21:40     ` Matt Porter
  0 siblings, 0 replies; 50+ messages in thread
From: Matt Porter @ 2013-12-16 21:40 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ, kishon-l0cyMroinI0,
	t.figa-Sze3O3UU22JBDgjK7y7TUQ, s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ,
	m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
	gautam.vivek-Sze3O3UU22JBDgjK7y7TUQ,
	mat.krawczuk-Re5JQEeQqe8AvxtiuMwx3w,
	yulgon.kim-Sze3O3UU22JBDgjK7y7TUQ,
	p.paneri-Sze3O3UU22JBDgjK7y7TUQ,
	av.tikhomirov-Sze3O3UU22JBDgjK7y7TUQ,
	jg1.han-Sze3O3UU22JBDgjK7y7TUQ, galak-sgV2jX0FEOL9JmXXK+q4OQ,
	Felipe Balbi

On Thu, Dec 05, 2013 at 01:29:35PM +0100, Kamil Debski wrote:
> Change the used phy driver to the new Exynos USB phy driver that uses the
> generic phy framework.
> 
> Signed-off-by: Kamil Debski <k.debski-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Kyungmin Park <kyungmin.park-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
>  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++-----
>  2 files changed, 10 insertions(+), 5 deletions(-)

Kamil,

Can we separate this patch out of this series? My bcm281xx series is
ready to go except for this dependency. Felipe has noted that there's
only a week until he locks his tree down for 3.14 [1]. I'm willing to
update this versus the comment Kishon made on fixing the example if
you don't have time before then. Let me know.

[1] https://lkml.org/lkml/2013/12/16/555

Thanks,
Matt

> diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> index b83d428..9340d06 100644
> --- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> @@ -24,6 +24,8 @@ Required properties:
>      - first entry: must be "otg"
>  - vusb_d-supply: phandle to voltage regulator of digital section,
>  - vusb_a-supply: phandle to voltage regulator of analog section.
> +- phys: from general PHY binding: phandle to the PHY device
> +- phy-names: from general PHY binding: should be "usb2-phy"
>  
>  Example
>  -----
> @@ -36,5 +38,7 @@ Example
>  		clock-names = "otg";
>  		vusb_d-supply = <&vusb_reg>;
>  		vusb_a-supply = <&vusbdac_reg>;
> +		phys = <&usb2phy 0>;
> +		phy-names = "device";
>  	};
>  
> diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
> index eccb147..db096fd 100644
> --- a/drivers/usb/gadget/s3c-hsotg.c
> +++ b/drivers/usb/gadget/s3c-hsotg.c
> @@ -31,6 +31,7 @@
>  #include <linux/regulator/consumer.h>
>  #include <linux/of.h>
>  #include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
>  
>  #include <linux/usb/ch9.h>
>  #include <linux/usb/gadget.h>
> @@ -162,7 +163,7 @@ struct s3c_hsotg_ep {
>  struct s3c_hsotg {
>  	struct device		 *dev;
>  	struct usb_gadget_driver *driver;
> -	struct usb_phy		*phy;
> +	struct phy		 *phy;
>  	struct s3c_hsotg_plat	 *plat;
>  
>  	spinlock_t              lock;
> @@ -2905,7 +2906,7 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
>  	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
>  
>  	if (hsotg->phy)
> -		usb_phy_init(hsotg->phy);
> +		phy_power_on(hsotg->phy);
>  	else if (hsotg->plat->phy_init)
>  		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
>  }
> @@ -2922,7 +2923,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
>  	struct platform_device *pdev = to_platform_device(hsotg->dev);
>  
>  	if (hsotg->phy)
> -		usb_phy_shutdown(hsotg->phy);
> +		phy_power_off(hsotg->phy);
>  	else if (hsotg->plat->phy_exit)
>  		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
>  }
> @@ -3529,7 +3530,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
>  static int s3c_hsotg_probe(struct platform_device *pdev)
>  {
>  	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
> -	struct usb_phy *phy;
> +	struct phy *phy;
>  	struct device *dev = &pdev->dev;
>  	struct s3c_hsotg_ep *eps;
>  	struct s3c_hsotg *hsotg;
> @@ -3544,7 +3545,7 @@ static int s3c_hsotg_probe(struct platform_device *pdev)
>  		return -ENOMEM;
>  	}
>  
> -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
> +	phy = devm_phy_get(&pdev->dev, "usb2-phy");
>  	if (IS_ERR(phy)) {
>  		/* Fallback for pdata */
>  		plat = dev_get_platdata(&pdev->dev);
> -- 
> 1.7.9.5
> 
--
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] 50+ messages in thread

* RE: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
  2013-12-16 21:40     ` Matt Porter
  (?)
@ 2013-12-17  9:41     ` Kamil Debski
  2013-12-17 13:13       ` 'Matt Porter'
  -1 siblings, 1 reply; 50+ messages in thread
From: Kamil Debski @ 2013-12-17  9:41 UTC (permalink / raw)
  To: 'Matt Porter'
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, kishon, Tomasz Figa, Sylwester Nawrocki,
	Marek Szyprowski, gautam.vivek, mat.krawczuk, yulgon.kim,
	p.paneri, av.tikhomirov, jg1.han, galak, 'Felipe Balbi'

Hi Matt,

I am afraid it is not possible. This patch cannot go in without the 
new  phy driver. It would break Exynos USB functionality. This
is because it changes s3c-hsotg to use the new phy driver.

I am working on an updated patch series addressing all the comments.
time permitting I want to post an alternative version - integrating
as much as possible in a single file. This way it would be possible
to have a hands-on comparison of the two approaches we were
discussing with Kishon. 

I estimate that I post it this week.

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland


> -----Original Message-----
> From: Matt Porter [mailto:mporter@linaro.org]
> Sent: Monday, December 16, 2013 10:40 PM
> To: Kamil Debski
> Cc: linux-kernel@vger.kernel.org; linux-samsung-soc@vger.kernel.org;
> linux-usb@vger.kernel.org; devicetree@vger.kernel.org;
> kyungmin.park@samsung.com; kishon@ti.com; t.figa@samsung.com;
> s.nawrocki@samsung.com; m.szyprowski@samsung.com;
> gautam.vivek@samsung.com; mat.krawczuk@gmail.com;
> yulgon.kim@samsung.com; p.paneri@samsung.com; av.tikhomirov@samsung.com;
> jg1.han@samsung.com; galak@codeaurora.org; Felipe Balbi
> Subject: Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy
> driver with the generic phy framework
> 
> On Thu, Dec 05, 2013 at 01:29:35PM +0100, Kamil Debski wrote:
> > Change the used phy driver to the new Exynos USB phy driver that uses
> > the generic phy framework.
> >
> > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > ---
> >  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
> >  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++----
> -
> >  2 files changed, 10 insertions(+), 5 deletions(-)
> 
> Kamil,
> 
> Can we separate this patch out of this series? My bcm281xx series is
> ready to go except for this dependency. Felipe has noted that there's
> only a week until he locks his tree down for 3.14 [1]. I'm willing to
> update this versus the comment Kishon made on fixing the example if you
> don't have time before then. Let me know.
> 
> [1] https://lkml.org/lkml/2013/12/16/555
> 
> Thanks,
> Matt
> 
> > diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > index b83d428..9340d06 100644
> > --- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > @@ -24,6 +24,8 @@ Required properties:
> >      - first entry: must be "otg"
> >  - vusb_d-supply: phandle to voltage regulator of digital section,
> >  - vusb_a-supply: phandle to voltage regulator of analog section.
> > +- phys: from general PHY binding: phandle to the PHY device
> > +- phy-names: from general PHY binding: should be "usb2-phy"
> >
> >  Example
> >  -----
> > @@ -36,5 +38,7 @@ Example
> >  		clock-names = "otg";
> >  		vusb_d-supply = <&vusb_reg>;
> >  		vusb_a-supply = <&vusbdac_reg>;
> > +		phys = <&usb2phy 0>;
> > +		phy-names = "device";
> >  	};
> >
> > diff --git a/drivers/usb/gadget/s3c-hsotg.c
> > b/drivers/usb/gadget/s3c-hsotg.c index eccb147..db096fd 100644
> > --- a/drivers/usb/gadget/s3c-hsotg.c
> > +++ b/drivers/usb/gadget/s3c-hsotg.c
> > @@ -31,6 +31,7 @@
> >  #include <linux/regulator/consumer.h>  #include <linux/of.h>
> > #include <linux/of_platform.h>
> > +#include <linux/phy/phy.h>
> >
> >  #include <linux/usb/ch9.h>
> >  #include <linux/usb/gadget.h>
> > @@ -162,7 +163,7 @@ struct s3c_hsotg_ep {  struct s3c_hsotg {
> >  	struct device		 *dev;
> >  	struct usb_gadget_driver *driver;
> > -	struct usb_phy		*phy;
> > +	struct phy		 *phy;
> >  	struct s3c_hsotg_plat	 *plat;
> >
> >  	spinlock_t              lock;
> > @@ -2905,7 +2906,7 @@ static void s3c_hsotg_phy_enable(struct
> s3c_hsotg *hsotg)
> >  	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
> >
> >  	if (hsotg->phy)
> > -		usb_phy_init(hsotg->phy);
> > +		phy_power_on(hsotg->phy);
> >  	else if (hsotg->plat->phy_init)
> >  		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);  } @@ -
> 2922,7
> > +2923,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
> >  	struct platform_device *pdev = to_platform_device(hsotg->dev);
> >
> >  	if (hsotg->phy)
> > -		usb_phy_shutdown(hsotg->phy);
> > +		phy_power_off(hsotg->phy);
> >  	else if (hsotg->plat->phy_exit)
> >  		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);  } @@ -
> 3529,7
> > +3530,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
> > static int s3c_hsotg_probe(struct platform_device *pdev)  {
> >  	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
> > -	struct usb_phy *phy;
> > +	struct phy *phy;
> >  	struct device *dev = &pdev->dev;
> >  	struct s3c_hsotg_ep *eps;
> >  	struct s3c_hsotg *hsotg;
> > @@ -3544,7 +3545,7 @@ static int s3c_hsotg_probe(struct
> platform_device *pdev)
> >  		return -ENOMEM;
> >  	}
> >
> > -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
> > +	phy = devm_phy_get(&pdev->dev, "usb2-phy");
> >  	if (IS_ERR(phy)) {
> >  		/* Fallback for pdata */
> >  		plat = dev_get_platdata(&pdev->dev);
> > --
> > 1.7.9.5
> >


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

* Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with the generic phy framework
  2013-12-17  9:41     ` Kamil Debski
@ 2013-12-17 13:13       ` 'Matt Porter'
  0 siblings, 0 replies; 50+ messages in thread
From: 'Matt Porter' @ 2013-12-17 13:13 UTC (permalink / raw)
  To: Kamil Debski
  Cc: linux-kernel, linux-samsung-soc, linux-usb, devicetree,
	kyungmin.park, kishon, Tomasz Figa, Sylwester Nawrocki,
	Marek Szyprowski, gautam.vivek, mat.krawczuk, yulgon.kim,
	p.paneri, av.tikhomirov, jg1.han, galak, 'Felipe Balbi'

On Tue, Dec 17, 2013 at 10:41:56AM +0100, Kamil Debski wrote:
> Hi Matt,
> 
> I am afraid it is not possible. This patch cannot go in without the 
> new  phy driver. It would break Exynos USB functionality. This
> is because it changes s3c-hsotg to use the new phy driver.

To clarify, I'm proposing that I would bring back the original patch
from my earlier postings on the bcm281xx series that preserves the old
style usb phy support as a fallback along with the pdata path.

> I am working on an updated patch series addressing all the comments.
> time permitting I want to post an alternative version - integrating
> as much as possible in a single file. This way it would be possible
> to have a hands-on comparison of the two approaches we were
> discussing with Kishon. 
> 
> I estimate that I post it this week.

Ok, thanks. In the meantime I'll update my original version of this
patch in case your work can't be taken in this window.

-Matt

> > -----Original Message-----
> > From: Matt Porter [mailto:mporter@linaro.org]
> > Sent: Monday, December 16, 2013 10:40 PM
> > To: Kamil Debski
> > Cc: linux-kernel@vger.kernel.org; linux-samsung-soc@vger.kernel.org;
> > linux-usb@vger.kernel.org; devicetree@vger.kernel.org;
> > kyungmin.park@samsung.com; kishon@ti.com; t.figa@samsung.com;
> > s.nawrocki@samsung.com; m.szyprowski@samsung.com;
> > gautam.vivek@samsung.com; mat.krawczuk@gmail.com;
> > yulgon.kim@samsung.com; p.paneri@samsung.com; av.tikhomirov@samsung.com;
> > jg1.han@samsung.com; galak@codeaurora.org; Felipe Balbi
> > Subject: Re: [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy
> > driver with the generic phy framework
> > 
> > On Thu, Dec 05, 2013 at 01:29:35PM +0100, Kamil Debski wrote:
> > > Change the used phy driver to the new Exynos USB phy driver that uses
> > > the generic phy framework.
> > >
> > > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > > ---
> > >  .../devicetree/bindings/usb/samsung-hsotg.txt      |    4 ++++
> > >  drivers/usb/gadget/s3c-hsotg.c                     |   11 ++++++----
> > -
> > >  2 files changed, 10 insertions(+), 5 deletions(-)
> > 
> > Kamil,
> > 
> > Can we separate this patch out of this series? My bcm281xx series is
> > ready to go except for this dependency. Felipe has noted that there's
> > only a week until he locks his tree down for 3.14 [1]. I'm willing to
> > update this versus the comment Kishon made on fixing the example if you
> > don't have time before then. Let me know.
> > 
> > [1] https://lkml.org/lkml/2013/12/16/555
> > 
> > Thanks,
> > Matt
> > 
> > > diff --git a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > > b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > > index b83d428..9340d06 100644
> > > --- a/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > > +++ b/Documentation/devicetree/bindings/usb/samsung-hsotg.txt
> > > @@ -24,6 +24,8 @@ Required properties:
> > >      - first entry: must be "otg"
> > >  - vusb_d-supply: phandle to voltage regulator of digital section,
> > >  - vusb_a-supply: phandle to voltage regulator of analog section.
> > > +- phys: from general PHY binding: phandle to the PHY device
> > > +- phy-names: from general PHY binding: should be "usb2-phy"
> > >
> > >  Example
> > >  -----
> > > @@ -36,5 +38,7 @@ Example
> > >  		clock-names = "otg";
> > >  		vusb_d-supply = <&vusb_reg>;
> > >  		vusb_a-supply = <&vusbdac_reg>;
> > > +		phys = <&usb2phy 0>;
> > > +		phy-names = "device";
> > >  	};
> > >
> > > diff --git a/drivers/usb/gadget/s3c-hsotg.c
> > > b/drivers/usb/gadget/s3c-hsotg.c index eccb147..db096fd 100644
> > > --- a/drivers/usb/gadget/s3c-hsotg.c
> > > +++ b/drivers/usb/gadget/s3c-hsotg.c
> > > @@ -31,6 +31,7 @@
> > >  #include <linux/regulator/consumer.h>  #include <linux/of.h>
> > > #include <linux/of_platform.h>
> > > +#include <linux/phy/phy.h>
> > >
> > >  #include <linux/usb/ch9.h>
> > >  #include <linux/usb/gadget.h>
> > > @@ -162,7 +163,7 @@ struct s3c_hsotg_ep {  struct s3c_hsotg {
> > >  	struct device		 *dev;
> > >  	struct usb_gadget_driver *driver;
> > > -	struct usb_phy		*phy;
> > > +	struct phy		 *phy;
> > >  	struct s3c_hsotg_plat	 *plat;
> > >
> > >  	spinlock_t              lock;
> > > @@ -2905,7 +2906,7 @@ static void s3c_hsotg_phy_enable(struct
> > s3c_hsotg *hsotg)
> > >  	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
> > >
> > >  	if (hsotg->phy)
> > > -		usb_phy_init(hsotg->phy);
> > > +		phy_power_on(hsotg->phy);
> > >  	else if (hsotg->plat->phy_init)
> > >  		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);  } @@ -
> > 2922,7
> > > +2923,7 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
> > >  	struct platform_device *pdev = to_platform_device(hsotg->dev);
> > >
> > >  	if (hsotg->phy)
> > > -		usb_phy_shutdown(hsotg->phy);
> > > +		phy_power_off(hsotg->phy);
> > >  	else if (hsotg->plat->phy_exit)
> > >  		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);  } @@ -
> > 3529,7
> > > +3530,7 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
> > > static int s3c_hsotg_probe(struct platform_device *pdev)  {
> > >  	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev);
> > > -	struct usb_phy *phy;
> > > +	struct phy *phy;
> > >  	struct device *dev = &pdev->dev;
> > >  	struct s3c_hsotg_ep *eps;
> > >  	struct s3c_hsotg *hsotg;
> > > @@ -3544,7 +3545,7 @@ static int s3c_hsotg_probe(struct
> > platform_device *pdev)
> > >  		return -ENOMEM;
> > >  	}
> > >
> > > -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
> > > +	phy = devm_phy_get(&pdev->dev, "usb2-phy");
> > >  	if (IS_ERR(phy)) {
> > >  		/* Fallback for pdata */
> > >  		plat = dev_get_platdata(&pdev->dev);
> > > --
> > > 1.7.9.5
> > >
> 

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

* RE: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
  2013-12-10  2:42   ` Anton Tikhomirov
@ 2013-12-17 13:26     ` Kamil Debski
  2013-12-18  0:54       ` Anton Tikhomirov
  0 siblings, 1 reply; 50+ messages in thread
From: Kamil Debski @ 2013-12-17 13:26 UTC (permalink / raw)
  To: 'Anton Tikhomirov',
	linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, Tomasz Figa, Sylwester Nawrocki,
	Marek Szyprowski, gautam.vivek, mat.krawczuk, yulgon.kim,
	p.paneri, jg1.han, galak, matt.porter

Hi Anton,

> From: Anton Tikhomirov [mailto:av.tikhomirov@samsung.com]
> Sent: Tuesday, December 10, 2013 3:43 AM
> 
> Hi Kamil,
> 
> Same USB2.0 PHY may be used by several HCDs, for example EHCI and OHCI.
> Consider the situation, when EHCI stops using the PHY and calls
> power_off, then OHCI becomes non-operational. In other words, PHY
> power_on and power_off calls must be balanced.
> 
> Shall we handle it in your driver? (usage count?)

Please look in the drivers/phy/phy-core.c file. Usage count is handled
there - see phy_power_on and phy_power_off functions. I understand that
after both EHCI and OHCI power on the phy, the usage count is 2. So
powering off one of them (EHCI for instance) the usage count is still
1, so the OHCI should still work properly.

[snip]

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland



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

* RE: [PATCH v4 3/9] phy: Add new Exynos USB PHY driver
  2013-12-17 13:26     ` Kamil Debski
@ 2013-12-18  0:54       ` Anton Tikhomirov
  0 siblings, 0 replies; 50+ messages in thread
From: Anton Tikhomirov @ 2013-12-18  0:54 UTC (permalink / raw)
  To: 'Kamil Debski',
	linux-kernel, linux-samsung-soc, linux-usb, devicetree
  Cc: kyungmin.park, kishon, 'Tomasz Figa',
	'Sylwester Nawrocki', 'Marek Szyprowski',
	gautam.vivek, mat.krawczuk, yulgon.kim, p.paneri, jg1.han, galak,
	matt.porter

Hi Kamil,

> Hi Anton,
> 
> > From: Anton Tikhomirov [mailto:av.tikhomirov@samsung.com]
> > Sent: Tuesday, December 10, 2013 3:43 AM
> >
> > Hi Kamil,
> >
> > Same USB2.0 PHY may be used by several HCDs, for example EHCI and
> OHCI.
> > Consider the situation, when EHCI stops using the PHY and calls
> > power_off, then OHCI becomes non-operational. In other words, PHY
> > power_on and power_off calls must be balanced.
> >
> > Shall we handle it in your driver? (usage count?)
> 
> Please look in the drivers/phy/phy-core.c file. Usage count is handled
> there - see phy_power_on and phy_power_off functions. I understand that
> after both EHCI and OHCI power on the phy, the usage count is 2. So
> powering off one of them (EHCI for instance) the usage count is still
> 1, so the OHCI should still work properly.

Oops, sorry, missed that.

> 
> [snip]
> 
> Best wishes,
> --
> Kamil Debski
> Samsung R&D Institute Poland


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

end of thread, other threads:[~2013-12-18  0:54 UTC | newest]

Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-05 12:29 [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver Kamil Debski
2013-12-05 12:29 ` [PATCH 1/9] phy: core: Change the way of_phy_get is called Kamil Debski
2013-12-06  5:30   ` Kishon Vijay Abraham I
2013-12-06  5:30     ` Kishon Vijay Abraham I
2013-12-06 10:52     ` Kamil Debski
2013-12-06 10:52       ` Kamil Debski
2013-12-09  7:22       ` Kishon Vijay Abraham I
2013-12-09  7:22         ` Kishon Vijay Abraham I
2013-12-13 14:20         ` Kamil Debski
2013-12-05 12:29 ` [PATCH 2/9] phy: core: Add devm_of_phy_get to phy-core Kamil Debski
2013-12-05 12:29 ` [PATCH v4 3/9] phy: Add new Exynos USB PHY driver Kamil Debski
2013-12-05 12:29   ` Kamil Debski
2013-12-06 10:59   ` Kishon Vijay Abraham I
2013-12-06 10:59     ` Kishon Vijay Abraham I
2013-12-06 16:28     ` Kamil Debski
2013-12-09  7:56       ` Kishon Vijay Abraham I
2013-12-09  7:56         ` Kishon Vijay Abraham I
2013-12-09 13:35         ` Kamil Debski
2013-12-06 16:47     ` Kamil Debski
2013-12-10  2:42   ` Anton Tikhomirov
2013-12-17 13:26     ` Kamil Debski
2013-12-18  0:54       ` Anton Tikhomirov
2013-12-05 12:29 ` [PATCH v4 4/9] usb: ehci-s5p: Change to use phy provided by the generic phy framework Kamil Debski
2013-12-05 18:52   ` Alan Stern
2013-12-05 18:52     ` Alan Stern
2013-12-06 13:19     ` Kamil Debski
2013-12-05 12:29 ` [PATCH v4 5/9] usb: s3c-hsotg: Use the new Exynos USB phy driver with " Kamil Debski
2013-12-06 11:11   ` Kishon Vijay Abraham I
2013-12-06 11:11     ` Kishon Vijay Abraham I
2013-12-06 15:01     ` Matt Porter
2013-12-06 15:01       ` Matt Porter
2013-12-06 16:29       ` Kamil Debski
2013-12-11 15:15   ` Matt Porter
2013-12-16 21:40   ` Matt Porter
2013-12-16 21:40     ` Matt Porter
2013-12-17  9:41     ` Kamil Debski
2013-12-17 13:13       ` 'Matt Porter'
2013-12-05 15:07 ` [PATCH v4 0/9] phy: Add new Exynos USB 2.0 PHY driver Kishon Vijay Abraham I
2013-12-05 15:07   ` Kishon Vijay Abraham I
2013-12-06 10:51   ` Kamil Debski
2013-12-06 10:31 ` [PATCH v4 6/9] phy: Add support for S5PV210 to the Exynos USB " Kamil Debski
2013-12-06 11:14   ` Kishon Vijay Abraham I
2013-12-06 11:14     ` Kishon Vijay Abraham I
2013-12-06 10:32 ` [PATCH v4 7/9] phy: Add Exynos 5250 support to the Exynos USB 2.0 " Kamil Debski
2013-12-06 10:32   ` Kamil Debski
2013-12-06 11:15   ` Kishon Vijay Abraham I
2013-12-06 11:15     ` Kishon Vijay Abraham I
2013-12-06 10:33 ` [PATCH 8/9] dts: Add usb2phy to Exynos 4 Kamil Debski
2013-12-06 10:34 ` [PATCH 9/9] dts: Add usb2phy to Exynos 5250 Kamil Debski
2013-12-06 10:34   ` Kamil Debski

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.