All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [GIT PULL 00/28] PHY for 3.15
@ 2014-03-08  9:29 Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 01/28] usb: phy: twl4030-usb: Silence checkpatch warnings Kishon Vijay Abraham I
                   ` (29 more replies)
  0 siblings, 30 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

Hi Greg,

Here's the PULL REQUEST for 3.15 merge window.
More users are starting to use the generic PHY framework including USB and
SATA PHY in exynos, USB in sunxi and multi-purpose PHY (currently only SATA)
in APM. There is also a patch to adapt USB3 PHY driver (PIPE3) used in OMAP
to generic PHY framework and use the same driver for SATA.
It also includes few fixes and cleanups.

Please let me know if you want me to make any changes.

Cheers
Kishon

The following changes since commit cfbf8d4857c26a8a307fb7cd258074c9dcd8c691:

  Linux 3.14-rc4 (2014-02-23 17:40:03 -0800)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git tags/for_3.15

for you to fetch changes up to 303fd52cda953d14dc82ac82b570761599eb9ab2:

  PHY: add APM X-Gene SoC 15Gbps Multi-purpose PHY driver (2014-03-08 12:39:51 +0530)

----------------------------------------------------------------
Add new PHY drivers for SATA and USB in exynos, for USB in sunxi,
and a multi-purpose PHY in APM, all adapted to generic PHY framework.
Adapted USB3 PHY driver in OMAP to generic PHY driver and also used
the same driver for SATA in OMAP. It also includes miscellaneous cleanups
and fixes.

----------------------------------------------------------------
Austin Beam (1):
      phy: omap-usb2: Provide workaround for USB2PHY false disconnect

George Cherian (2):
      phy: omap-usb2: Adapt phy-omap-usb2 for AM437x
      phy: omap-usb2: Add different compatible for OMAP5

Hans de Goede (1):
      PHY: sunxi: Add driver for sunxi usb phy

Kamil Debski (4):
      phy: core: Add an exported of_phy_get function
      phy: core: Add devm_of_phy_get to phy-core
      phy: Add new Exynos USB 2.0 PHY driver
      phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver

Kishon Vijay Abraham I (4):
      drivers: phy: usb3/pipe3: Adapt pipe3 driver to Generic PHY Framework
      usb: phy: omap-usb2: remove *set_suspend* callback from omap-usb2
      phy: omap-usb2: move omap_usb.h from linux/usb/ to linux/phy/
      phy: rename struct omap_control_usb to struct omap_control_phy

Loc Ho (2):
      Documentation: Add APM X-Gene SoC 15Gbps Multi-purpose PHY driver binding documentation
      PHY: add APM X-Gene SoC 15Gbps Multi-purpose PHY driver

Roger Quadros (7):
      phy: omap-control: update dra7 and am437 usb2 bindings
      phy: ti-pipe3: cleanup clock handling
      phy: ti-pipe3: Add SATA DPLL support
      phy: ti-pipe3: Don't get 'wkupclk' and 'refclk' for SATA PHY
      phy: ti-pipe3: streamline PHY operations
      phy: ti-pipe3: Fix suspend/resume and module reload
      phy: omap: Depend on OMAP_OCP2SCP bus driver

Sachin Kamat (3):
      usb: phy: twl4030-usb: Silence checkpatch warnings
      usb: phy: twl4030-usb: Remove redundant semicolon
      usb: phy: bcm-kona-usb2: Use PTR_ERR_OR_ZERO

Sebastian Hesselbarth (1):
      phy: mvebu-sata: prepare new Dove DT Kconfig variable

Sylwester Nawrocki (2):
      phy: Select PHY_EXYNOS_MIPI_VIDEO by default for ARCH_EXYNOS
      phy: Select PHY_EXYNOS_DP_VIDEO by default for ARCH_EXYNOS

Yuvaraj Kumar C D (1):
      PHY: Exynos: Add Exynos5250 SATA PHY driver

 .../devicetree/bindings/phy/apm-xgene-phy.txt      |   79 +
 .../devicetree/bindings/phy/samsung-phy.txt        |   54 +
 .../devicetree/bindings/phy/sun4i-usb-phy.txt      |   26 +
 Documentation/devicetree/bindings/usb/usb-phy.txt  |    6 +-
 Documentation/phy/samsung-usb2.txt                 |  135 ++
 drivers/phy/Kconfig                                |  107 +-
 drivers/phy/Makefile                               |    9 +
 drivers/phy/phy-bcm-kona-usb2.c                    |    4 +-
 drivers/phy/phy-core.c                             |   76 +-
 drivers/phy/phy-exynos4210-usb2.c                  |  261 +++
 drivers/phy/phy-exynos4x12-usb2.c                  |  328 ++++
 drivers/phy/phy-exynos5250-sata.c                  |  251 +++
 drivers/phy/phy-exynos5250-usb2.c                  |  404 +++++
 drivers/{usb => }/phy/phy-omap-control.c           |  169 +-
 drivers/phy/phy-omap-usb2.c                        |  131 +-
 drivers/phy/phy-samsung-usb2.c                     |  228 +++
 drivers/phy/phy-samsung-usb2.h                     |   67 +
 drivers/phy/phy-sun4i-usb.c                        |  331 ++++
 drivers/phy/phy-ti-pipe3.c                         |  470 ++++++
 drivers/phy/phy-twl4030-usb.c                      |    6 +-
 drivers/phy/phy-xgene.c                            | 1750 ++++++++++++++++++++
 drivers/usb/musb/omap2430.c                        |    2 +-
 drivers/usb/phy/Kconfig                            |   21 -
 drivers/usb/phy/Makefile                           |    2 -
 drivers/usb/phy/phy-omap-usb3.c                    |  361 ----
 drivers/usb/phy/phy-twl6030-usb.c                  |    2 +-
 .../omap_control_usb.h => phy/omap_control_phy.h}  |   36 +-
 include/linux/{usb => phy}/omap_usb.h              |   14 +-
 include/linux/phy/phy.h                            |   15 +
 29 files changed, 4797 insertions(+), 548 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/phy/apm-xgene-phy.txt
 create mode 100644 Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
 create mode 100644 Documentation/phy/samsung-usb2.txt
 create mode 100644 drivers/phy/phy-exynos4210-usb2.c
 create mode 100644 drivers/phy/phy-exynos4x12-usb2.c
 create mode 100644 drivers/phy/phy-exynos5250-sata.c
 create mode 100644 drivers/phy/phy-exynos5250-usb2.c
 rename drivers/{usb => }/phy/phy-omap-control.c (53%)
 create mode 100644 drivers/phy/phy-samsung-usb2.c
 create mode 100644 drivers/phy/phy-samsung-usb2.h
 create mode 100644 drivers/phy/phy-sun4i-usb.c
 create mode 100644 drivers/phy/phy-ti-pipe3.c
 create mode 100644 drivers/phy/phy-xgene.c
 delete mode 100644 drivers/usb/phy/phy-omap-usb3.c
 rename include/linux/{usb/omap_control_usb.h => phy/omap_control_phy.h} (68%)
 rename include/linux/{usb => phy}/omap_usb.h (86%)
-- 
1.7.9.5


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

* [PATCH 01/28] usb: phy: twl4030-usb: Silence checkpatch warnings
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 02/28] usb: phy: twl4030-usb: Remove redundant semicolon Kishon Vijay Abraham I
                   ` (28 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Sachin Kamat <sachin.kamat@linaro.org>

Silences the following warnings:
WARNING: sizeof *twl should be sizeof(*twl)
WARNING: sizeof *otg should be sizeof(*otg)

Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-twl4030-usb.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index c3ace1d..6c7cec7 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -661,7 +661,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
 	struct phy_provider	*phy_provider;
 	struct phy_init_data	*init_data = NULL;
 
-	twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL);
+	twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
 	if (!twl)
 		return -ENOMEM;
 
@@ -676,7 +676,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
-	otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL);
+	otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
 	if (!otg)
 		return -ENOMEM;
 
-- 
1.7.9.5


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

* [PATCH 02/28] usb: phy: twl4030-usb: Remove redundant semicolon
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 01/28] usb: phy: twl4030-usb: Silence checkpatch warnings Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 03/28] usb: phy: bcm-kona-usb2: Use PTR_ERR_OR_ZERO Kishon Vijay Abraham I
                   ` (27 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Sachin Kamat <sachin.kamat@linaro.org>

Semicolon after switch statement is not needed.

Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-twl4030-usb.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index 6c7cec7..2e0e9b3 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -338,7 +338,7 @@ static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode)
 		dev_err(twl->dev, "unsupported T2 transceiver mode %d\n",
 				mode);
 		break;
-	};
+	}
 }
 
 static void twl4030_i2c_access(struct twl4030_usb *twl, int on)
-- 
1.7.9.5


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

* [PATCH 03/28] usb: phy: bcm-kona-usb2: Use PTR_ERR_OR_ZERO
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 01/28] usb: phy: twl4030-usb: Silence checkpatch warnings Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 02/28] usb: phy: twl4030-usb: Remove redundant semicolon Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 04/28] phy: Select PHY_EXYNOS_MIPI_VIDEO by default for ARCH_EXYNOS Kishon Vijay Abraham I
                   ` (26 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Sachin Kamat <sachin.kamat@linaro.org>

PTR_ERR_OR_ZERO simplifies the code.

Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Cc: Matt Porter <mporter@linaro.org>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-bcm-kona-usb2.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/phy-bcm-kona-usb2.c
index efc5c1a..e94f5a6 100644
--- a/drivers/phy/phy-bcm-kona-usb2.c
+++ b/drivers/phy/phy-bcm-kona-usb2.c
@@ -128,10 +128,8 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev)
 
 	phy_provider = devm_of_phy_provider_register(dev,
 			of_phy_simple_xlate);
-	if (IS_ERR(phy_provider))
-		return PTR_ERR(phy_provider);
 
-	return 0;
+	return PTR_ERR_OR_ZERO(phy_provider);
 }
 
 static const struct of_device_id bcm_kona_usb2_dt_ids[] = {
-- 
1.7.9.5


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

* [PATCH 04/28] phy: Select PHY_EXYNOS_MIPI_VIDEO by default for ARCH_EXYNOS
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (2 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 03/28] usb: phy: bcm-kona-usb2: Use PTR_ERR_OR_ZERO Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 05/28] phy: Select PHY_EXYNOS_DP_VIDEO " Kishon Vijay Abraham I
                   ` (25 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Sylwester Nawrocki <s.nawrocki@samsung.com>

Instead of requiring user to figure out when PHY_EXYNOS_MIPI_VIDEO needs
to be selected select it by default for Exynos SoCs. Also enable it when
COMPILE_TEST is selected. If required the MIPI CSIS/DPHY driver can be
then disabled or compiled in as module.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/Kconfig |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index c7a551c..f0fb429 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -16,8 +16,11 @@ config GENERIC_PHY
 	  framework should select this config.
 
 config PHY_EXYNOS_MIPI_VIDEO
-	depends on HAS_IOMEM
 	tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
+	depends on HAS_IOMEM
+	depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
+	select GENERIC_PHY
+	default y if ARCH_S5PV210 || ARCH_EXYNOS
 	help
 	  Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P
 	  and EXYNOS SoCs.
-- 
1.7.9.5


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

* [PATCH 05/28] phy: Select PHY_EXYNOS_DP_VIDEO by default for ARCH_EXYNOS
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (3 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 04/28] phy: Select PHY_EXYNOS_MIPI_VIDEO by default for ARCH_EXYNOS Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 06/28] PHY: Exynos: Add Exynos5250 SATA PHY driver Kishon Vijay Abraham I
                   ` (24 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Sylwester Nawrocki <s.nawrocki@samsung.com>

Instead of requiring user to figure out when PHY_EXYNOS_DP_VIDEO needs
to be selected select it by default for Exynos SoCs. Also enable it
when COMPILE_TEST is selected. If required the display port PHY driver
can be then disabled or compiled in as module.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/Kconfig |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index f0fb429..5bf9ed3 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -57,6 +57,8 @@ config TWL4030_USB
 config PHY_EXYNOS_DP_VIDEO
 	tristate "EXYNOS SoC series Display Port PHY driver"
 	depends on OF
+	depends on ARCH_EXYNOS || COMPILE_TEST
+	default ARCH_EXYNOS
 	select GENERIC_PHY
 	help
 	  Support for Display Port PHY found on Samsung EXYNOS SoCs.
-- 
1.7.9.5


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

* [PATCH 06/28] PHY: Exynos: Add Exynos5250 SATA PHY driver
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (4 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 05/28] phy: Select PHY_EXYNOS_DP_VIDEO " Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 07/28] PHY: sunxi: Add driver for sunxi usb phy Kishon Vijay Abraham I
                   ` (23 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Yuvaraj Kumar C D <yuvaraj.cd@gmail.com>

This patch adds the SATA PHY driver for Exynos5250.This driver uses the
generic PHY framework to deal with SATA PHY.Exynos5250 SATA PHY comprises
of CMU and TRSV blocks which are of I2C register Map.So this driver
configures the CMU and TRSV block of exynos5250 SATA PHY using i2c.

Signed-off-by: Yuvaraj Kumar C D <yuvaraj.cd@samsung.com>
Signed-off-by: Girish K S <ks.giri@samsung.com>
Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/Kconfig               |   15 +++
 drivers/phy/Makefile              |    1 +
 drivers/phy/phy-exynos5250-sata.c |  251 +++++++++++++++++++++++++++++++++++++
 3 files changed, 267 insertions(+)
 create mode 100644 drivers/phy/phy-exynos5250-sata.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 5bf9ed3..0431284 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -70,4 +70,19 @@ config BCM_KONA_USB2_PHY
 	help
 	  Enable this to support the Broadcom Kona USB 2.0 PHY.
 
+config PHY_EXYNOS5250_SATA
+	tristate "Exynos5250 Sata SerDes/PHY driver"
+	depends on SOC_EXYNOS5250
+	depends on HAS_IOMEM
+	depends on OF
+	select GENERIC_PHY
+	select I2C
+	select I2C_S3C2410
+	select MFD_SYSCON
+	help
+	  Enable this to support SATA SerDes/Phy found on Samsung's
+	  Exynos5250 based SoCs.This SerDes/Phy supports SATA 1.5 Gb/s,
+	  SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host
+	  port to accept one SATA device.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index b57c253..0d03822 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
 obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
+obj-$(CONFIG_PHY_EXYNOS5250_SATA)	+= phy-exynos5250-sata.o
diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/phy-exynos5250-sata.c
new file mode 100644
index 0000000..c9361b7
--- /dev/null
+++ b/drivers/phy/phy-exynos5250-sata.c
@@ -0,0 +1,251 @@
+/*
+ * Samsung SATA SerDes(PHY) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Authors: Girish K S <ks.giri@samsung.com>
+ *         Yuvaraj Kumar C D <yuvaraj.cd@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/i2c.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 <linux/mfd/syscon.h>
+
+#define SATAPHY_CONTROL_OFFSET		0x0724
+#define EXYNOS5_SATAPHY_PMU_ENABLE	BIT(0)
+#define EXYNOS5_SATA_RESET		0x4
+#define RESET_GLOBAL_RST_N		BIT(0)
+#define RESET_CMN_RST_N			BIT(1)
+#define RESET_CMN_BLOCK_RST_N		BIT(2)
+#define RESET_CMN_I2C_RST_N		BIT(3)
+#define RESET_TX_RX_PIPE_RST_N		BIT(4)
+#define RESET_TX_RX_BLOCK_RST_N		BIT(5)
+#define RESET_TX_RX_I2C_RST_N		(BIT(6) | BIT(7))
+#define LINK_RESET			0xf0000
+#define EXYNOS5_SATA_MODE0		0x10
+#define SATA_SPD_GEN3			BIT(1)
+#define EXYNOS5_SATA_CTRL0		0x14
+#define CTRL0_P0_PHY_CALIBRATED_SEL	BIT(9)
+#define CTRL0_P0_PHY_CALIBRATED		BIT(8)
+#define EXYNOS5_SATA_PHSATA_CTRLM	0xe0
+#define PHCTRLM_REF_RATE		BIT(1)
+#define PHCTRLM_HIGH_SPEED		BIT(0)
+#define EXYNOS5_SATA_PHSATA_STATM	0xf0
+#define PHSTATM_PLL_LOCKED		BIT(0)
+
+#define PHY_PLL_TIMEOUT (usecs_to_jiffies(1000))
+
+struct exynos_sata_phy {
+	struct phy *phy;
+	struct clk *phyclk;
+	void __iomem *regs;
+	struct regmap *pmureg;
+	struct i2c_client *client;
+};
+
+static int wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit,
+				u32 status)
+{
+	unsigned long timeout = jiffies + PHY_PLL_TIMEOUT;
+
+	while (time_before(jiffies, timeout)) {
+		if ((readl(base + reg) & checkbit) == status)
+			return 0;
+	}
+
+	return -EFAULT;
+}
+
+static int exynos_sata_phy_power_on(struct phy *phy)
+{
+	struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
+
+	return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
+			EXYNOS5_SATAPHY_PMU_ENABLE, true);
+
+}
+
+static int exynos_sata_phy_power_off(struct phy *phy)
+{
+	struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
+
+	return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
+			EXYNOS5_SATAPHY_PMU_ENABLE, false);
+
+}
+
+static int exynos_sata_phy_init(struct phy *phy)
+{
+	u32 val = 0;
+	int ret = 0;
+	u8 buf[] = { 0x3a, 0x0b };
+	struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
+
+	ret = regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
+			EXYNOS5_SATAPHY_PMU_ENABLE, true);
+	if (ret != 0)
+		dev_err(&sata_phy->phy->dev, "phy init failed\n");
+
+	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+	val |= RESET_GLOBAL_RST_N | RESET_CMN_RST_N | RESET_CMN_BLOCK_RST_N
+		| RESET_CMN_I2C_RST_N | RESET_TX_RX_PIPE_RST_N
+		| RESET_TX_RX_BLOCK_RST_N | RESET_TX_RX_I2C_RST_N;
+	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+	val |= LINK_RESET;
+	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+	val |= RESET_CMN_RST_N;
+	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+	val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+	val &= ~PHCTRLM_REF_RATE;
+	writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+
+	/* High speed enable for Gen3 */
+	val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+	val |= PHCTRLM_HIGH_SPEED;
+	writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
+
+	val = readl(sata_phy->regs + EXYNOS5_SATA_CTRL0);
+	val |= CTRL0_P0_PHY_CALIBRATED_SEL | CTRL0_P0_PHY_CALIBRATED;
+	writel(val, sata_phy->regs + EXYNOS5_SATA_CTRL0);
+
+	val = readl(sata_phy->regs + EXYNOS5_SATA_MODE0);
+	val |= SATA_SPD_GEN3;
+	writel(val, sata_phy->regs + EXYNOS5_SATA_MODE0);
+
+	ret = i2c_master_send(sata_phy->client, buf, sizeof(buf));
+	if (ret < 0)
+		return ret;
+
+	/* release cmu reset */
+	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+	val &= ~RESET_CMN_RST_N;
+	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+	val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
+	val |= RESET_CMN_RST_N;
+	writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
+
+	ret = wait_for_reg_status(sata_phy->regs,
+				EXYNOS5_SATA_PHSATA_STATM,
+				PHSTATM_PLL_LOCKED, 1);
+	if (ret < 0)
+		dev_err(&sata_phy->phy->dev,
+			"PHY PLL locking failed\n");
+	return ret;
+}
+
+static struct phy_ops exynos_sata_phy_ops = {
+	.init		= exynos_sata_phy_init,
+	.power_on	= exynos_sata_phy_power_on,
+	.power_off	= exynos_sata_phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static int exynos_sata_phy_probe(struct platform_device *pdev)
+{
+	struct exynos_sata_phy *sata_phy;
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct phy_provider *phy_provider;
+	struct device_node *node;
+	int ret = 0;
+
+	sata_phy = devm_kzalloc(dev, sizeof(*sata_phy), GFP_KERNEL);
+	if (!sata_phy)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	sata_phy->regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(sata_phy->regs))
+		return PTR_ERR(sata_phy->regs);
+
+	sata_phy->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
+					"samsung,syscon-phandle");
+	if (IS_ERR(sata_phy->pmureg)) {
+		dev_err(dev, "syscon regmap lookup failed.\n");
+		return PTR_ERR(sata_phy->pmureg);
+	}
+
+	node = of_parse_phandle(dev->of_node,
+			"samsung,exynos-sataphy-i2c-phandle", 0);
+	if (!node)
+		return -EINVAL;
+
+	sata_phy->client = of_find_i2c_device_by_node(node);
+	if (!sata_phy->client)
+		return -EPROBE_DEFER;
+
+	dev_set_drvdata(dev, sata_phy);
+
+	sata_phy->phyclk = devm_clk_get(dev, "sata_phyctrl");
+	if (IS_ERR(sata_phy->phyclk)) {
+		dev_err(dev, "failed to get clk for PHY\n");
+		return PTR_ERR(sata_phy->phyclk);
+	}
+
+	ret = clk_prepare_enable(sata_phy->phyclk);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable source clk\n");
+		return ret;
+	}
+
+	sata_phy->phy = devm_phy_create(dev, &exynos_sata_phy_ops, NULL);
+	if (IS_ERR(sata_phy->phy)) {
+		clk_disable_unprepare(sata_phy->phyclk);
+		dev_err(dev, "failed to create PHY\n");
+		return PTR_ERR(sata_phy->phy);
+	}
+
+	phy_set_drvdata(sata_phy->phy, sata_phy);
+
+	phy_provider = devm_of_phy_provider_register(dev,
+					of_phy_simple_xlate);
+	if (IS_ERR(phy_provider)) {
+		clk_disable_unprepare(sata_phy->phyclk);
+		return PTR_ERR(phy_provider);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id exynos_sata_phy_of_match[] = {
+	{ .compatible = "samsung,exynos5250-sata-phy" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, exynos_sata_phy_of_match);
+
+static struct platform_driver exynos_sata_phy_driver = {
+	.probe	= exynos_sata_phy_probe,
+	.driver = {
+		.of_match_table	= exynos_sata_phy_of_match,
+		.name  = "samsung,sata-phy",
+		.owner = THIS_MODULE,
+	}
+};
+module_platform_driver(exynos_sata_phy_driver);
+
+MODULE_DESCRIPTION("Samsung SerDes PHY driver");
+MODULE_LICENSE("GPL V2");
+MODULE_AUTHOR("Girish K S <ks.giri@samsung.com>");
+MODULE_AUTHOR("Yuvaraj C D <yuvaraj.cd@samsung.com>");
-- 
1.7.9.5


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

* [PATCH 07/28] PHY: sunxi: Add driver for sunxi usb phy
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (5 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 06/28] PHY: Exynos: Add Exynos5250 SATA PHY driver Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 08/28] phy: mvebu-sata: prepare new Dove DT Kconfig variable Kishon Vijay Abraham I
                   ` (22 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Hans de Goede <hdegoede@redhat.com>

The Allwinner A1x / A2x SoCs have 2 or 3 usb phys which are all accessed
through a single set of registers. Besides this there are also some other
phy related bits which need poking, which are per phy, but shared between the
ohci and ehci controllers, so these are also controlled from this new phy
driver.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../devicetree/bindings/phy/sun4i-usb-phy.txt      |   26 ++
 drivers/phy/Kconfig                                |   11 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-sun4i-usb.c                        |  331 ++++++++++++++++++++
 4 files changed, 369 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
 create mode 100644 drivers/phy/phy-sun4i-usb.c

diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
new file mode 100644
index 0000000..a82361b
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
@@ -0,0 +1,26 @@
+Allwinner sun4i USB PHY
+-----------------------
+
+Required properties:
+- compatible : should be one of "allwinner,sun4i-a10-usb-phy",
+  "allwinner,sun5i-a13-usb-phy" or "allwinner,sun7i-a20-usb-phy"
+- reg : a list of offset + length pairs
+- reg-names : "phy_ctrl", "pmu1" and for sun4i or sun7i "pmu2"
+- #phy-cells : from the generic phy bindings, must be 1
+- clocks : phandle + clock specifier for the phy clock
+- clock-names : "usb_phy"
+- resets : a list of phandle + reset specifier pairs
+- reset-names : "usb0_reset", "usb1_reset" and for sun4i or sun7i "usb2_reset"
+
+Example:
+	usbphy: phy@0x01c13400 {
+		#phy-cells = <1>;
+		compatible = "allwinner,sun4i-a10-usb-phy";
+		/* phy base regs, phy1 pmu reg, phy2 pmu reg */
+		reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
+		reg-names = "phy_ctrl", "pmu1", "pmu2";
+		clocks = <&usb_clk 8>;
+		clock-names = "usb_phy";
+		resets = <&usb_clk 1>, <&usb_clk 2>;
+		reset-names = "usb1_reset", "usb2_reset";
+	};
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 0431284..e677ee0 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -85,4 +85,15 @@ config PHY_EXYNOS5250_SATA
 	  SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host
 	  port to accept one SATA device.
 
+config PHY_SUN4I_USB
+	tristate "Allwinner sunxi SoC USB PHY driver"
+	depends on ARCH_SUNXI && HAS_IOMEM && OF
+	select GENERIC_PHY
+	help
+	  Enable this to support the transceiver that is part of Allwinner
+	  sunxi SoCs.
+
+	  This driver controls the entire USB PHY block, both the USB OTG
+	  parts, as well as the 2 regular USB 2 host PHYs.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 0d03822..5d0b59e 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
 obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
 obj-$(CONFIG_PHY_EXYNOS5250_SATA)	+= phy-exynos5250-sata.o
+obj-$(CONFIG_PHY_SUN4I_USB)		+= phy-sun4i-usb.o
diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
new file mode 100644
index 0000000..e6e6c4b
--- /dev/null
+++ b/drivers/phy/phy-sun4i-usb.c
@@ -0,0 +1,331 @@
+/*
+ * Allwinner sun4i USB phy driver
+ *
+ * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
+ *
+ * Modelled after: Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+
+#define REG_ISCR			0x00
+#define REG_PHYCTL			0x04
+#define REG_PHYBIST			0x08
+#define REG_PHYTUNE			0x0c
+
+#define PHYCTL_DATA			BIT(7)
+
+#define SUNXI_AHB_ICHR8_EN		BIT(10)
+#define SUNXI_AHB_INCR4_BURST_EN	BIT(9)
+#define SUNXI_AHB_INCRX_ALIGN_EN	BIT(8)
+#define SUNXI_ULPI_BYPASS_EN		BIT(0)
+
+/* Common Control Bits for Both PHYs */
+#define PHY_PLL_BW			0x03
+#define PHY_RES45_CAL_EN		0x0c
+
+/* Private Control Bits for Each PHY */
+#define PHY_TX_AMPLITUDE_TUNE		0x20
+#define PHY_TX_SLEWRATE_TUNE		0x22
+#define PHY_VBUSVALID_TH_SEL		0x25
+#define PHY_PULLUP_RES_SEL		0x27
+#define PHY_OTG_FUNC_EN			0x28
+#define PHY_VBUS_DET_EN			0x29
+#define PHY_DISCON_TH_SEL		0x2a
+
+#define MAX_PHYS			3
+
+struct sun4i_usb_phy_data {
+	struct clk *clk;
+	void __iomem *base;
+	struct mutex mutex;
+	int num_phys;
+	u32 disc_thresh;
+	struct sun4i_usb_phy {
+		struct phy *phy;
+		void __iomem *pmu;
+		struct regulator *vbus;
+		struct reset_control *reset;
+		int index;
+	} phys[MAX_PHYS];
+};
+
+#define to_sun4i_usb_phy_data(phy) \
+	container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
+
+static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
+				int len)
+{
+	struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
+	u32 temp, usbc_bit = BIT(phy->index * 2);
+	int i;
+
+	mutex_lock(&phy_data->mutex);
+
+	for (i = 0; i < len; i++) {
+		temp = readl(phy_data->base + REG_PHYCTL);
+
+		/* clear the address portion */
+		temp &= ~(0xff << 8);
+
+		/* set the address */
+		temp |= ((addr + i) << 8);
+		writel(temp, phy_data->base + REG_PHYCTL);
+
+		/* set the data bit and clear usbc bit*/
+		temp = readb(phy_data->base + REG_PHYCTL);
+		if (data & 0x1)
+			temp |= PHYCTL_DATA;
+		else
+			temp &= ~PHYCTL_DATA;
+		temp &= ~usbc_bit;
+		writeb(temp, phy_data->base + REG_PHYCTL);
+
+		/* pulse usbc_bit */
+		temp = readb(phy_data->base + REG_PHYCTL);
+		temp |= usbc_bit;
+		writeb(temp, phy_data->base + REG_PHYCTL);
+
+		temp = readb(phy_data->base + REG_PHYCTL);
+		temp &= ~usbc_bit;
+		writeb(temp, phy_data->base + REG_PHYCTL);
+
+		data >>= 1;
+	}
+	mutex_unlock(&phy_data->mutex);
+}
+
+static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable)
+{
+	u32 bits, reg_value;
+
+	if (!phy->pmu)
+		return;
+
+	bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
+		SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
+
+	reg_value = readl(phy->pmu);
+
+	if (enable)
+		reg_value |= bits;
+	else
+		reg_value &= ~bits;
+
+	writel(reg_value, phy->pmu);
+}
+
+static int sun4i_usb_phy_init(struct phy *_phy)
+{
+	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
+	int ret;
+
+	ret = clk_prepare_enable(data->clk);
+	if (ret)
+		return ret;
+
+	ret = reset_control_deassert(phy->reset);
+	if (ret) {
+		clk_disable_unprepare(data->clk);
+		return ret;
+	}
+
+	/* Adjust PHY's magnitude and rate */
+	sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
+
+	/* Disconnect threshold adjustment */
+	sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, data->disc_thresh, 2);
+
+	sun4i_usb_phy_passby(phy, 1);
+
+	return 0;
+}
+
+static int sun4i_usb_phy_exit(struct phy *_phy)
+{
+	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
+
+	sun4i_usb_phy_passby(phy, 0);
+	reset_control_assert(phy->reset);
+	clk_disable_unprepare(data->clk);
+
+	return 0;
+}
+
+static int sun4i_usb_phy_power_on(struct phy *_phy)
+{
+	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+	int ret = 0;
+
+	if (phy->vbus)
+		ret = regulator_enable(phy->vbus);
+
+	return ret;
+}
+
+static int sun4i_usb_phy_power_off(struct phy *_phy)
+{
+	struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
+
+	if (phy->vbus)
+		regulator_disable(phy->vbus);
+
+	return 0;
+}
+
+static struct phy_ops sun4i_usb_phy_ops = {
+	.init		= sun4i_usb_phy_init,
+	.exit		= sun4i_usb_phy_exit,
+	.power_on	= sun4i_usb_phy_power_on,
+	.power_off	= sun4i_usb_phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *sun4i_usb_phy_xlate(struct device *dev,
+					struct of_phandle_args *args)
+{
+	struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
+
+	if (WARN_ON(args->args[0] == 0 || args->args[0] >= data->num_phys))
+		return ERR_PTR(-ENODEV);
+
+	return data->phys[args->args[0]].phy;
+}
+
+static int sun4i_usb_phy_probe(struct platform_device *pdev)
+{
+	struct sun4i_usb_phy_data *data;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	void __iomem *pmu = NULL;
+	struct phy_provider *phy_provider;
+	struct reset_control *reset;
+	struct regulator *vbus;
+	struct resource *res;
+	struct phy *phy;
+	char name[16];
+	int i;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	mutex_init(&data->mutex);
+
+	if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy"))
+		data->num_phys = 2;
+	else
+		data->num_phys = 3;
+
+	if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy"))
+		data->disc_thresh = 3;
+	else
+		data->disc_thresh = 2;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
+	data->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(data->base))
+		return PTR_ERR(data->base);
+
+	data->clk = devm_clk_get(dev, "usb_phy");
+	if (IS_ERR(data->clk)) {
+		dev_err(dev, "could not get usb_phy clock\n");
+		return PTR_ERR(data->clk);
+	}
+
+	/* Skip 0, 0 is the phy for otg which is not yet supported. */
+	for (i = 1; i < data->num_phys; i++) {
+		snprintf(name, sizeof(name), "usb%d_vbus", i);
+		vbus = devm_regulator_get_optional(dev, name);
+		if (IS_ERR(vbus)) {
+			if (PTR_ERR(vbus) == -EPROBE_DEFER)
+				return -EPROBE_DEFER;
+			vbus = NULL;
+		}
+
+		snprintf(name, sizeof(name), "usb%d_reset", i);
+		reset = devm_reset_control_get(dev, name);
+		if (IS_ERR(reset)) {
+			dev_err(dev, "failed to get reset %s\n", name);
+			return PTR_ERR(reset);
+		}
+
+		if (i) { /* No pmu for usbc0 */
+			snprintf(name, sizeof(name), "pmu%d", i);
+			res = platform_get_resource_byname(pdev,
+							IORESOURCE_MEM, name);
+			pmu = devm_ioremap_resource(dev, res);
+			if (IS_ERR(pmu))
+				return PTR_ERR(pmu);
+		}
+
+		phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			dev_err(dev, "failed to create PHY %d\n", i);
+			return PTR_ERR(phy);
+		}
+
+		data->phys[i].phy = phy;
+		data->phys[i].pmu = pmu;
+		data->phys[i].vbus = vbus;
+		data->phys[i].reset = reset;
+		data->phys[i].index = i;
+		phy_set_drvdata(phy, &data->phys[i]);
+	}
+
+	dev_set_drvdata(dev, data);
+	phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate);
+	if (IS_ERR(phy_provider))
+		return PTR_ERR(phy_provider);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_usb_phy_of_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-usb-phy" },
+	{ .compatible = "allwinner,sun5i-a13-usb-phy" },
+	{ .compatible = "allwinner,sun7i-a20-usb-phy" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
+
+static struct platform_driver sun4i_usb_phy_driver = {
+	.probe	= sun4i_usb_phy_probe,
+	.driver = {
+		.of_match_table	= sun4i_usb_phy_of_match,
+		.name  = "sun4i-usb-phy",
+		.owner = THIS_MODULE,
+	}
+};
+module_platform_driver(sun4i_usb_phy_driver);
+
+MODULE_DESCRIPTION("Allwinner sun4i USB phy driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5


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

* [PATCH 08/28] phy: mvebu-sata: prepare new Dove DT Kconfig variable
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (6 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 07/28] PHY: sunxi: Add driver for sunxi usb phy Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 09/28] drivers: phy: usb3/pipe3: Adapt pipe3 driver to Generic PHY Framework Kishon Vijay Abraham I
                   ` (21 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>

DT-enabled Dove will move over from ARCH_DOVE in mach-dove to MACH_DOVE in
mach-mvebu. As non-DT ARCH_DOVE will stay to rot for a while, add a new
DT-only MACH_DOVE Kconfig.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Acked-by: Jason Cooper <jason@lakedaemon.net>
---
 drivers/phy/Kconfig |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index e677ee0..dc1756c 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -27,7 +27,7 @@ config PHY_EXYNOS_MIPI_VIDEO
 
 config PHY_MVEBU_SATA
 	def_bool y
-	depends on ARCH_KIRKWOOD || ARCH_DOVE
+	depends on ARCH_KIRKWOOD || ARCH_DOVE || MACH_DOVE
 	depends on OF
 	select GENERIC_PHY
 
-- 
1.7.9.5


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

* [PATCH 09/28] drivers: phy: usb3/pipe3: Adapt pipe3 driver to Generic PHY Framework
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (7 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 08/28] phy: mvebu-sata: prepare new Dove DT Kconfig variable Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 10/28] usb: phy: omap-usb2: remove *set_suspend* callback from omap-usb2 Kishon Vijay Abraham I
                   ` (20 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

Adapted omap-usb3 PHY driver to Generic PHY Framework and moved phy-omap-usb3
driver in drivers/usb/phy to drivers/phy and also renamed the file to
phy-ti-pipe3 since this same driver will be used for SATA PHY and
PCIE PHY.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/Kconfig                                |   11 +
 drivers/phy/Makefile                               |    1 +
 .../phy/phy-omap-usb3.c => phy/phy-ti-pipe3.c}     |  240 ++++++++++++--------
 drivers/usb/phy/Kconfig                            |   11 -
 drivers/usb/phy/Makefile                           |    1 -
 5 files changed, 158 insertions(+), 106 deletions(-)
 rename drivers/{usb/phy/phy-omap-usb3.c => phy/phy-ti-pipe3.c} (54%)

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index dc1756c..fde4192 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -43,6 +43,17 @@ config OMAP_USB2
 	  The USB OTG controller communicates with the comparator using this
 	  driver.
 
+config TI_PIPE3
+	tristate "TI PIPE3 PHY Driver"
+	depends on ARCH_OMAP2PLUS || COMPILE_TEST
+	select GENERIC_PHY
+	select OMAP_CONTROL_USB
+	help
+	  Enable this to support the PIPE3 PHY that is part of TI SOCs. This
+	  driver takes care of all the PHY functionality apart from comparator.
+	  This driver interacts with the "OMAP Control PHY Driver" to power
+	  on/off the PHY.
+
 config TWL4030_USB
 	tristate "TWL4030 USB Transceiver Driver"
 	depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 5d0b59e..977a50e 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
 obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
+obj-$(CONFIG_TI_PIPE3)			+= phy-ti-pipe3.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
 obj-$(CONFIG_PHY_EXYNOS5250_SATA)	+= phy-exynos5250-sata.o
 obj-$(CONFIG_PHY_SUN4I_USB)		+= phy-sun4i-usb.o
diff --git a/drivers/usb/phy/phy-omap-usb3.c b/drivers/phy/phy-ti-pipe3.c
similarity index 54%
rename from drivers/usb/phy/phy-omap-usb3.c
rename to drivers/phy/phy-ti-pipe3.c
index 0c6ba29..c8d1674 100644
--- a/drivers/usb/phy/phy-omap-usb3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -1,5 +1,5 @@
 /*
- * omap-usb3 - USB PHY, talking to dwc3 controller in OMAP.
+ * phy-ti-pipe3 - PIPE3 PHY driver.
  *
  * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
  * This program is free software; you can redistribute it and/or modify
@@ -19,10 +19,11 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
-#include <linux/usb/omap_usb.h>
+#include <linux/phy/phy.h>
 #include <linux/of.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/io.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
 #include <linux/usb/omap_control_usb.h>
@@ -52,17 +53,34 @@
 
 /*
  * This is an Empirical value that works, need to confirm the actual
- * value required for the USB3PHY_PLL_CONFIGURATION2.PLL_IDLE status
- * to be correctly reflected in the USB3PHY_PLL_STATUS register.
+ * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
+ * to be correctly reflected in the PIPE3PHY_PLL_STATUS register.
  */
 # define PLL_IDLE_TIME  100;
 
-struct usb_dpll_map {
+struct pipe3_dpll_params {
+	u16	m;
+	u8	n;
+	u8	freq:3;
+	u8	sd;
+	u32	mf;
+};
+
+struct ti_pipe3 {
+	void __iomem		*pll_ctrl_base;
+	struct device		*dev;
+	struct device		*control_dev;
+	struct clk		*wkupclk;
+	struct clk		*sys_clk;
+	struct clk		*optclk;
+};
+
+struct pipe3_dpll_map {
 	unsigned long rate;
-	struct usb_dpll_params params;
+	struct pipe3_dpll_params params;
 };
 
-static struct usb_dpll_map dpll_map[] = {
+static struct pipe3_dpll_map dpll_map[] = {
 	{12000000, {1250, 5, 4, 20, 0} },	/* 12 MHz */
 	{16800000, {3125, 20, 4, 20, 0} },	/* 16.8 MHz */
 	{19200000, {1172, 8, 4, 20, 65537} },	/* 19.2 MHz */
@@ -71,7 +89,18 @@ static struct usb_dpll_map dpll_map[] = {
 	{38400000, {3125, 47, 4, 20, 92843} },	/* 38.4 MHz */
 };
 
-static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate)
+static inline u32 ti_pipe3_readl(void __iomem *addr, unsigned offset)
+{
+	return __raw_readl(addr + offset);
+}
+
+static inline void ti_pipe3_writel(void __iomem *addr, unsigned offset,
+	u32 data)
+{
+	__raw_writel(data, addr + offset);
+}
+
+static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(unsigned long rate)
 {
 	int i;
 
@@ -83,110 +112,123 @@ static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate)
 	return NULL;
 }
 
-static int omap_usb3_suspend(struct usb_phy *x, int suspend)
+static int ti_pipe3_power_off(struct phy *x)
+{
+	struct ti_pipe3 *phy = phy_get_drvdata(x);
+	int val;
+	int timeout = PLL_IDLE_TIME;
+
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+	val |= PLL_IDLE;
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+	do {
+		val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+		if (val & PLL_TICOPWDN)
+			break;
+		udelay(5);
+	} while (--timeout);
+
+	if (!timeout) {
+		dev_err(phy->dev, "power off failed\n");
+		return -EBUSY;
+	}
+
+	omap_control_usb_phy_power(phy->control_dev, 0);
+
+	return 0;
+}
+
+static int ti_pipe3_power_on(struct phy *x)
 {
-	struct omap_usb *phy = phy_to_omapusb(x);
-	int	val;
+	struct ti_pipe3 *phy = phy_get_drvdata(x);
+	int val;
 	int timeout = PLL_IDLE_TIME;
 
-	if (suspend && !phy->is_suspended) {
-		val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
-		val |= PLL_IDLE;
-		omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
-
-		do {
-			val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS);
-			if (val & PLL_TICOPWDN)
-				break;
-			udelay(1);
-		} while (--timeout);
-
-		omap_control_usb_phy_power(phy->control_dev, 0);
-
-		phy->is_suspended	= 1;
-	} else if (!suspend && phy->is_suspended) {
-		phy->is_suspended	= 0;
-
-		val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
-		val &= ~PLL_IDLE;
-		omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
-
-		do {
-			val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS);
-			if (!(val & PLL_TICOPWDN))
-				break;
-			udelay(1);
-		} while (--timeout);
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+	val &= ~PLL_IDLE;
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+	do {
+		val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+		if (!(val & PLL_TICOPWDN))
+			break;
+		udelay(5);
+	} while (--timeout);
+
+	if (!timeout) {
+		dev_err(phy->dev, "power on failed\n");
+		return -EBUSY;
 	}
 
 	return 0;
 }
 
-static void omap_usb_dpll_relock(struct omap_usb *phy)
+static void ti_pipe3_dpll_relock(struct ti_pipe3 *phy)
 {
 	u32		val;
 	unsigned long	timeout;
 
-	omap_usb_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
 
 	timeout = jiffies + msecs_to_jiffies(20);
 	do {
-		val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS);
+		val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
 		if (val & PLL_LOCK)
 			break;
 	} while (!WARN_ON(time_after(jiffies, timeout)));
 }
 
-static int omap_usb_dpll_lock(struct omap_usb *phy)
+static int ti_pipe3_dpll_lock(struct ti_pipe3 *phy)
 {
 	u32			val;
 	unsigned long		rate;
-	struct usb_dpll_params *dpll_params;
+	struct pipe3_dpll_params *dpll_params;
 
 	rate = clk_get_rate(phy->sys_clk);
-	dpll_params = omap_usb3_get_dpll_params(rate);
+	dpll_params = ti_pipe3_get_dpll_params(rate);
 	if (!dpll_params) {
 		dev_err(phy->dev,
 			  "No DPLL configuration for %lu Hz SYS CLK\n", rate);
 		return -EINVAL;
 	}
 
-	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
 	val &= ~PLL_REGN_MASK;
 	val |= dpll_params->n << PLL_REGN_SHIFT;
-	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
 
-	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
 	val &= ~PLL_SELFREQDCO_MASK;
 	val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
-	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
 
-	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
 	val &= ~PLL_REGM_MASK;
 	val |= dpll_params->m << PLL_REGM_SHIFT;
-	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
 
-	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
 	val &= ~PLL_REGM_F_MASK;
 	val |= dpll_params->mf << PLL_REGM_F_SHIFT;
-	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
 
-	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
 	val &= ~PLL_SD_MASK;
 	val |= dpll_params->sd << PLL_SD_SHIFT;
-	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
 
-	omap_usb_dpll_relock(phy);
+	ti_pipe3_dpll_relock(phy);
 
 	return 0;
 }
 
-static int omap_usb3_init(struct usb_phy *x)
+static int ti_pipe3_init(struct phy *x)
 {
-	struct omap_usb	*phy = phy_to_omapusb(x);
+	struct ti_pipe3 *phy = phy_get_drvdata(x);
 	int ret;
 
-	ret = omap_usb_dpll_lock(phy);
+	ret = ti_pipe3_dpll_lock(phy);
 	if (ret)
 		return ret;
 
@@ -195,9 +237,18 @@ static int omap_usb3_init(struct usb_phy *x)
 	return 0;
 }
 
-static int omap_usb3_probe(struct platform_device *pdev)
+static struct phy_ops ops = {
+	.init		= ti_pipe3_init,
+	.power_on	= ti_pipe3_power_on,
+	.power_off	= ti_pipe3_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static int ti_pipe3_probe(struct platform_device *pdev)
 {
-	struct omap_usb *phy;
+	struct ti_pipe3 *phy;
+	struct phy *generic_phy;
+	struct phy_provider *phy_provider;
 	struct resource *res;
 	struct device_node *node = pdev->dev.of_node;
 	struct device_node *control_node;
@@ -208,7 +259,7 @@ static int omap_usb3_probe(struct platform_device *pdev)
 
 	phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
 	if (!phy) {
-		dev_err(&pdev->dev, "unable to alloc mem for OMAP USB3 PHY\n");
+		dev_err(&pdev->dev, "unable to alloc mem for TI PIPE3 PHY\n");
 		return -ENOMEM;
 	}
 
@@ -219,13 +270,6 @@ static int omap_usb3_probe(struct platform_device *pdev)
 
 	phy->dev		= &pdev->dev;
 
-	phy->phy.dev		= phy->dev;
-	phy->phy.label		= "omap-usb3";
-	phy->phy.init		= omap_usb3_init;
-	phy->phy.set_suspend	= omap_usb3_suspend;
-	phy->phy.type		= USB_PHY_TYPE_USB3;
-
-	phy->is_suspended	= 1;
 	phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
 	if (IS_ERR(phy->wkupclk)) {
 		dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
@@ -251,6 +295,7 @@ static int omap_usb3_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev, "Failed to get control device phandle\n");
 		return -EINVAL;
 	}
+
 	control_pdev = of_find_device_by_node(control_node);
 	if (!control_pdev) {
 		dev_err(&pdev->dev, "Failed to get control device\n");
@@ -260,23 +305,31 @@ static int omap_usb3_probe(struct platform_device *pdev)
 	phy->control_dev = &control_pdev->dev;
 
 	omap_control_usb_phy_power(phy->control_dev, 0);
-	usb_add_phy_dev(&phy->phy);
 
 	platform_set_drvdata(pdev, phy);
-
 	pm_runtime_enable(phy->dev);
+
+	generic_phy = devm_phy_create(phy->dev, &ops, NULL);
+	if (IS_ERR(generic_phy))
+		return PTR_ERR(generic_phy);
+
+	phy_set_drvdata(generic_phy, phy);
+	phy_provider = devm_of_phy_provider_register(phy->dev,
+			of_phy_simple_xlate);
+	if (IS_ERR(phy_provider))
+		return PTR_ERR(phy_provider);
+
 	pm_runtime_get(&pdev->dev);
 
 	return 0;
 }
 
-static int omap_usb3_remove(struct platform_device *pdev)
+static int ti_pipe3_remove(struct platform_device *pdev)
 {
-	struct omap_usb *phy = platform_get_drvdata(pdev);
+	struct ti_pipe3 *phy = platform_get_drvdata(pdev);
 
 	clk_unprepare(phy->wkupclk);
 	clk_unprepare(phy->optclk);
-	usb_remove_phy(&phy->phy);
 	if (!pm_runtime_suspended(&pdev->dev))
 		pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -286,10 +339,9 @@ static int omap_usb3_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_PM_RUNTIME
 
-static int omap_usb3_runtime_suspend(struct device *dev)
+static int ti_pipe3_runtime_suspend(struct device *dev)
 {
-	struct platform_device	*pdev = to_platform_device(dev);
-	struct omap_usb	*phy = platform_get_drvdata(pdev);
+	struct ti_pipe3	*phy = dev_get_drvdata(dev);
 
 	clk_disable(phy->wkupclk);
 	clk_disable(phy->optclk);
@@ -297,11 +349,10 @@ static int omap_usb3_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static int omap_usb3_runtime_resume(struct device *dev)
+static int ti_pipe3_runtime_resume(struct device *dev)
 {
 	u32 ret = 0;
-	struct platform_device	*pdev = to_platform_device(dev);
-	struct omap_usb	*phy = platform_get_drvdata(pdev);
+	struct ti_pipe3	*phy = dev_get_drvdata(dev);
 
 	ret = clk_enable(phy->optclk);
 	if (ret) {
@@ -324,38 +375,39 @@ err1:
 	return ret;
 }
 
-static const struct dev_pm_ops omap_usb3_pm_ops = {
-	SET_RUNTIME_PM_OPS(omap_usb3_runtime_suspend, omap_usb3_runtime_resume,
-		NULL)
+static const struct dev_pm_ops ti_pipe3_pm_ops = {
+	SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
+			   ti_pipe3_runtime_resume, NULL)
 };
 
-#define DEV_PM_OPS     (&omap_usb3_pm_ops)
+#define DEV_PM_OPS     (&ti_pipe3_pm_ops)
 #else
 #define DEV_PM_OPS     NULL
 #endif
 
 #ifdef CONFIG_OF
-static const struct of_device_id omap_usb3_id_table[] = {
+static const struct of_device_id ti_pipe3_id_table[] = {
+	{ .compatible = "ti,phy-usb3" },
 	{ .compatible = "ti,omap-usb3" },
 	{}
 };
-MODULE_DEVICE_TABLE(of, omap_usb3_id_table);
+MODULE_DEVICE_TABLE(of, ti_pipe3_id_table);
 #endif
 
-static struct platform_driver omap_usb3_driver = {
-	.probe		= omap_usb3_probe,
-	.remove		= omap_usb3_remove,
+static struct platform_driver ti_pipe3_driver = {
+	.probe		= ti_pipe3_probe,
+	.remove		= ti_pipe3_remove,
 	.driver		= {
-		.name	= "omap-usb3",
+		.name	= "ti-pipe3",
 		.owner	= THIS_MODULE,
 		.pm	= DEV_PM_OPS,
-		.of_match_table = of_match_ptr(omap_usb3_id_table),
+		.of_match_table = of_match_ptr(ti_pipe3_id_table),
 	},
 };
 
-module_platform_driver(omap_usb3_driver);
+module_platform_driver(ti_pipe3_driver);
 
-MODULE_ALIAS("platform: omap_usb3");
+MODULE_ALIAS("platform: ti_pipe3");
 MODULE_AUTHOR("Texas Instruments Inc.");
-MODULE_DESCRIPTION("OMAP USB3 phy driver");
+MODULE_DESCRIPTION("TI PIPE3 phy driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 7d1451d..c337ba2 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -85,17 +85,6 @@ config OMAP_CONTROL_USB
 	  power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
 	  additional register to power on USB3 PHY.
 
-config OMAP_USB3
-	tristate "OMAP USB3 PHY Driver"
-	depends on ARCH_OMAP2PLUS || COMPILE_TEST
-	select OMAP_CONTROL_USB
-	select USB_PHY
-	help
-	  Enable this to support the USB3 PHY that is part of SOC. This
-	  driver takes care of all the PHY functionality apart from comparator.
-	  This driver interacts with the "OMAP Control USB Driver" to power
-	  on/off the PHY.
-
 config AM335X_CONTROL_USB
 	tristate
 
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index be58ada..15f1878 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -17,7 +17,6 @@ obj-$(CONFIG_OMAP_CONTROL_USB)		+= phy-omap-control.o
 obj-$(CONFIG_AM335X_CONTROL_USB)	+= phy-am335x-control.o
 obj-$(CONFIG_AM335X_PHY_USB)		+= phy-am335x.o
 obj-$(CONFIG_OMAP_OTG)			+= phy-omap-otg.o
-obj-$(CONFIG_OMAP_USB3)			+= phy-omap-usb3.o
 obj-$(CONFIG_SAMSUNG_USBPHY)		+= phy-samsung-usb.o
 obj-$(CONFIG_SAMSUNG_USB2PHY)		+= phy-samsung-usb2.o
 obj-$(CONFIG_SAMSUNG_USB3PHY)		+= phy-samsung-usb3.o
-- 
1.7.9.5


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

* [PATCH 10/28] usb: phy: omap-usb2: remove *set_suspend* callback from omap-usb2
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (8 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 09/28] drivers: phy: usb3/pipe3: Adapt pipe3 driver to Generic PHY Framework Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 11/28] phy: omap-usb2: move omap_usb.h from linux/usb/ to linux/phy/ Kishon Vijay Abraham I
                   ` (19 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

Now that omap-usb2 is adapted to the new generic PHY framework,
*set_suspend* ops can be removed from omap-usb2 driver.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Acked-by: Felipe Balbi <balbi@ti.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 drivers/phy/phy-omap-usb2.c |   25 -------------------------
 1 file changed, 25 deletions(-)

diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 7699752..705af5a 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -98,28 +98,6 @@ static int omap_usb_set_peripheral(struct usb_otg *otg,
 	return 0;
 }
 
-static int omap_usb2_suspend(struct usb_phy *x, int suspend)
-{
-	struct omap_usb *phy = phy_to_omapusb(x);
-	int ret;
-
-	if (suspend && !phy->is_suspended) {
-		omap_control_usb_phy_power(phy->control_dev, 0);
-		pm_runtime_put_sync(phy->dev);
-		phy->is_suspended = 1;
-	} else if (!suspend && phy->is_suspended) {
-		ret = pm_runtime_get_sync(phy->dev);
-		if (ret < 0) {
-			dev_err(phy->dev, "get_sync failed with err %d\n", ret);
-			return ret;
-		}
-		omap_control_usb_phy_power(phy->control_dev, 1);
-		phy->is_suspended = 0;
-	}
-
-	return 0;
-}
-
 static int omap_usb_power_off(struct phy *x)
 {
 	struct omap_usb *phy = phy_get_drvdata(x);
@@ -173,7 +151,6 @@ static int omap_usb2_probe(struct platform_device *pdev)
 
 	phy->phy.dev		= phy->dev;
 	phy->phy.label		= "omap-usb2";
-	phy->phy.set_suspend	= omap_usb2_suspend;
 	phy->phy.otg		= otg;
 	phy->phy.type		= USB_PHY_TYPE_USB2;
 
@@ -190,8 +167,6 @@ static int omap_usb2_probe(struct platform_device *pdev)
 	}
 
 	phy->control_dev = &control_pdev->dev;
-
-	phy->is_suspended	= 1;
 	omap_control_usb_phy_power(phy->control_dev, 0);
 
 	otg->set_host		= omap_usb_set_host;
-- 
1.7.9.5


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

* [PATCH 11/28] phy: omap-usb2: move omap_usb.h from linux/usb/ to linux/phy/
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (9 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 10/28] usb: phy: omap-usb2: remove *set_suspend* callback from omap-usb2 Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 12/28] phy: core: Add an exported of_phy_get function Kishon Vijay Abraham I
                   ` (18 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

No functional change. Moved omap_usb.h from linux/usb/ to linux/phy/.
Also removed the unused members of struct omap_usb (after phy-omap-pipe3
started using it's own header file)

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-omap-usb2.c           |    2 +-
 drivers/usb/phy/phy-twl6030-usb.c     |    2 +-
 include/linux/{usb => phy}/omap_usb.h |    3 ---
 3 files changed, 2 insertions(+), 5 deletions(-)
 rename include/linux/{usb => phy}/omap_usb.h (95%)

diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 705af5a..9c3f056 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -21,7 +21,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/io.h>
-#include <linux/usb/omap_usb.h>
+#include <linux/phy/omap_usb.h>
 #include <linux/usb/phy_companion.h>
 #include <linux/clk.h>
 #include <linux/err.h>
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index 214172b..04778cf 100644
--- a/drivers/usb/phy/phy-twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -27,7 +27,7 @@
 #include <linux/io.h>
 #include <linux/usb/musb-omap.h>
 #include <linux/usb/phy_companion.h>
-#include <linux/usb/omap_usb.h>
+#include <linux/phy/omap_usb.h>
 #include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
diff --git a/include/linux/usb/omap_usb.h b/include/linux/phy/omap_usb.h
similarity index 95%
rename from include/linux/usb/omap_usb.h
rename to include/linux/phy/omap_usb.h
index 6ae2936..19d343c3 100644
--- a/include/linux/usb/omap_usb.h
+++ b/include/linux/phy/omap_usb.h
@@ -33,13 +33,10 @@ struct usb_dpll_params {
 struct omap_usb {
 	struct usb_phy		phy;
 	struct phy_companion	*comparator;
-	void __iomem		*pll_ctrl_base;
 	struct device		*dev;
 	struct device		*control_dev;
 	struct clk		*wkupclk;
-	struct clk		*sys_clk;
 	struct clk		*optclk;
-	u8			is_suspended:1;
 };
 
 #define	phy_to_omapusb(x)	container_of((x), struct omap_usb, phy)
-- 
1.7.9.5


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

* [PATCH 12/28] phy: core: Add an exported of_phy_get function
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (10 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 11/28] phy: omap-usb2: move omap_usb.h from linux/usb/ to linux/phy/ Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 13/28] phy: core: Add devm_of_phy_get to phy-core Kishon Vijay Abraham I
                   ` (17 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Kamil Debski <k.debski@samsung.com>

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. The old function was renamed to _of_phy_get
and was left for internal use. of_phy_get function was added
and it was exported. The function enables to get a phy for
a given device tree node.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-core.c  |   45 ++++++++++++++++++++++++++++++++++++---------
 include/linux/phy/phy.h |    6 ++++++
 2 files changed, 42 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 6c73837..7c1b0e1 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -274,8 +274,8 @@ int phy_power_off(struct phy *phy)
 EXPORT_SYMBOL_GPL(phy_power_off);
 
 /**
- * of_phy_get() - lookup and obtain a reference to a phy by phandle
- * @dev: device that requests this phy
+ * _of_phy_get() - lookup and obtain a reference to a phy by phandle
+ * @np: device_node for which to get the phy
  * @index: the index of the phy
  *
  * Returns the phy associated with the given phandle value,
@@ -284,20 +284,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)
+static 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);
@@ -317,6 +314,36 @@ err0:
 }
 
 /**
+ * of_phy_get() - lookup and obtain a reference to a phy using a device_node.
+ * @np: device_node for which to get the phy
+ * @con_id: name of the phy from device's point of view
+ *
+ * Returns the phy driver, after getting a refcount to it; or
+ * -ENODEV if there is no such phy. The caller is responsible for
+ * calling phy_put() to release that count.
+ */
+struct phy *of_phy_get(struct device_node *np, const char *con_id)
+{
+	struct phy *phy = NULL;
+	int index = 0;
+
+	if (con_id)
+		index = of_property_match_string(np, "phy-names", con_id);
+
+	phy = _of_phy_get(np, index);
+	if (IS_ERR(phy))
+		return phy;
+
+	if (!try_module_get(phy->ops->owner))
+		return ERR_PTR(-EPROBE_DEFER);
+
+	get_device(&phy->dev);
+
+	return phy;
+}
+EXPORT_SYMBOL_GPL(of_phy_get);
+
+/**
  * phy_put() - release the PHY
  * @phy: the phy returned by phy_get()
  *
@@ -407,7 +434,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);
 	} else {
 		phy = phy_lookup(dev, string);
 	}
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 3f83459..50c7629 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -151,6 +151,7 @@ struct phy *devm_phy_get(struct device *dev, const char *string);
 struct phy *devm_phy_optional_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, const char *con_id);
 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,
@@ -259,6 +260,11 @@ static inline void devm_phy_put(struct device *dev, struct phy *phy)
 {
 }
 
+static inline struct phy *of_phy_get(struct device_node *np, const char *con_id)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
 static inline struct phy *of_phy_simple_xlate(struct device *dev,
 	struct of_phandle_args *args)
 {
-- 
1.7.9.5


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

* [PATCH 13/28] phy: core: Add devm_of_phy_get to phy-core
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (11 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 12/28] phy: core: Add an exported of_phy_get function Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 14/28] phy: Add new Exynos USB 2.0 PHY driver Kishon Vijay Abraham I
                   ` (16 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Kamil Debski <k.debski@samsung.com>

Adding devm_of_phy_get will allow to get phys by supplying a
pointer to the struct device_node instead of struct device.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-core.c  |   31 +++++++++++++++++++++++++++++++
 include/linux/phy/phy.h |    9 +++++++++
 2 files changed, 40 insertions(+)

diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 7c1b0e1..623b71c 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -526,6 +526,37 @@ struct phy *devm_phy_optional_get(struct device *dev, const char *string)
 EXPORT_SYMBOL_GPL(devm_phy_optional_get);
 
 /**
+ * devm_of_phy_get() - lookup and obtain a reference to a phy.
+ * @dev: device that requests this phy
+ * @np: node containing the phy
+ * @con_id: name of the phy from device's point of view
+ *
+ * Gets the phy using of_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,
+			    const char *con_id)
+{
+	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, con_id);
+	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 50c7629..e2f5ca9 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -149,6 +149,8 @@ struct phy *phy_get(struct device *dev, const char *string);
 struct phy *phy_optional_get(struct device *dev, const char *string);
 struct phy *devm_phy_get(struct device *dev, const char *string);
 struct phy *devm_phy_optional_get(struct device *dev, const char *string);
+struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
+			    const char *con_id);
 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, const char *con_id);
@@ -252,6 +254,13 @@ static inline struct phy *devm_phy_optional_get(struct device *dev,
 	return ERR_PTR(-ENOSYS);
 }
 
+static inline struct phy *devm_of_phy_get(struct device *dev,
+					  struct device_node *np,
+					  const char *con_id)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
 static inline void phy_put(struct phy *phy)
 {
 }
-- 
1.7.9.5


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

* [PATCH 14/28] phy: Add new Exynos USB 2.0 PHY driver
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (12 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 13/28] phy: core: Add devm_of_phy_get to phy-core Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 15/28] phy: Add Exynos 5250 support to the " Kishon Vijay Abraham I
                   ` (15 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Kamil Debski <k.debski@samsung.com>

Add a new driver for the Exynos USB 2.0 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>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../devicetree/bindings/phy/samsung-phy.txt        |   53 ++++
 Documentation/phy/samsung-usb2.txt                 |  135 ++++++++
 drivers/phy/Kconfig                                |   29 ++
 drivers/phy/Makefile                               |    3 +
 drivers/phy/phy-exynos4210-usb2.c                  |  261 ++++++++++++++++
 drivers/phy/phy-exynos4x12-usb2.c                  |  328 ++++++++++++++++++++
 drivers/phy/phy-samsung-usb2.c                     |  222 +++++++++++++
 drivers/phy/phy-samsung-usb2.h                     |   66 ++++
 8 files changed, 1097 insertions(+)
 create mode 100644 Documentation/phy/samsung-usb2.txt
 create mode 100644 drivers/phy/phy-exynos4210-usb2.c
 create mode 100644 drivers/phy/phy-exynos4x12-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-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt
index c0fccaa..bf955ab 100644
--- a/Documentation/devicetree/bindings/phy/samsung-phy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt
@@ -20,3 +20,56 @@ Required properties:
 - compatible : should be "samsung,exynos5250-dp-video-phy";
 - reg : offset and length of the Display Port PHY register set;
 - #phy-cells : from the generic PHY bindings, must be 0;
+
+Samsung S5P/EXYNOS SoC series USB PHY
+-------------------------------------------------
+
+Required properties:
+- compatible : should be one of the listed compatibles:
+	- "samsung,exynos4210-usb2-phy"
+	- "samsung,exynos4x12-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" clock is required by the phy module, used as a gate
+	- the "ref" clock is used to get the rate of the clock provided to the
+	  PHY module
+
+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,exynos4x12-usb2-phy";
+	reg = <0x125b0000 0x100>;
+	clocks = <&clock 305>, <&clock 2>;
+	clock-names = "phy", "ref";
+	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/Documentation/phy/samsung-usb2.txt b/Documentation/phy/samsung-usb2.txt
new file mode 100644
index 0000000..ed12d43
--- /dev/null
+++ b/Documentation/phy/samsung-usb2.txt
@@ -0,0 +1,135 @@
+.------------------------------------------------------------------------------+
+|			Samsung USB 2.0 PHY adaptation layer		       |
++-----------------------------------------------------------------------------+'
+
+| 1. Description
++----------------
+
+The architecture of the USB 2.0 PHY module in Samsung SoCs is similar
+among many SoCs. In spite of the similarities it proved difficult to
+create a one driver that would fit all these PHY controllers. Often
+the differences were minor and were found in particular bits of the
+registers of the PHY. In some rare cases the order of register writes or
+the PHY powering up process had to be altered. This adaptation layer is
+a compromise between having separate drivers and having a single driver
+with added support for many special cases.
+
+| 2. Files description
++----------------------
+
+- phy-samsung-usb2.c
+   This is the main file of the adaptation layer. This file contains
+   the probe function and provides two callbacks to the Generic PHY
+   Framework. This two callbacks are used to power on and power off the
+   phy. They carry out the common work that has to be done on all version
+   of the PHY module. Depending on which SoC was chosen they execute SoC
+   specific callbacks. The specific SoC version is selected by choosing
+   the appropriate compatible string. In addition, this file contains
+   struct of_device_id definitions for particular SoCs.
+
+- phy-samsung-usb2.h
+   This is the include file. It declares the structures used by this
+   driver. In addition it should contain extern declarations for
+   structures that describe particular SoCs.
+
+| 3. Supporting SoCs
++--------------------
+
+To support a new SoC a new file should be added to the drivers/phy
+directory. Each SoC's configuration is stored in an instance of the
+struct samsung_usb2_phy_config.
+
+struct samsung_usb2_phy_config {
+	const struct samsung_usb2_common_phy *phys;
+	int (*rate_to_clk)(unsigned long, u32 *);
+	unsigned int num_phys;
+	bool has_mode_switch;
+};
+
+The num_phys is the number of phys handled by the driver. *phys is an
+array that contains the configuration for each phy. The has_mode_switch
+property is a boolean flag that determines whether the SoC has USB host
+and device on a single pair of pins. If so, a special register has to
+be modified to change the internal routing of these pins between a USB
+device or host module.
+
+For example the configuration for Exynos 4210 is following:
+
+const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
+	.has_mode_switch        = 0,
+	.num_phys		= EXYNOS4210_NUM_PHYS,
+	.phys			= exynos4210_phys,
+	.rate_to_clk		= exynos4210_rate_to_clk,
+}
+
+- int (*rate_to_clk)(unsigned long, u32 *)
+	The rate_to_clk callback is to convert the rate of the clock
+	used as the reference clock for the PHY module to the value
+	that should be written in the hardware register.
+
+The exynos4210_phys configuration array is as follows:
+
+static const struct samsung_usb2_common_phy exynos4210_phys[] = {
+	{
+		.label		= "device",
+		.id		= EXYNOS4210_DEVICE,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS4210_HOST,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS4210_HSIC0,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS4210_HSIC1,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{},
+};
+
+- int (*power_on)(struct samsung_usb2_phy_instance *);
+- int (*power_off)(struct samsung_usb2_phy_instance *);
+	These two callbacks are used to power on and power off the phy
+	by modifying appropriate registers.
+
+Final change to the driver is adding appropriate compatible value to the
+phy-samsung-usb2.c file. In case of Exynos 4210 the following lines were
+added to the struct of_device_id samsung_usb2_phy_of_match[] array:
+
+#ifdef CONFIG_PHY_EXYNOS4210_USB2
+	{
+		.compatible = "samsung,exynos4210-usb2-phy",
+		.data = &exynos4210_usb2_phy_config,
+	},
+#endif
+
+To add further flexibility to the driver the Kconfig file enables to
+include support for selected SoCs in the compiled driver. The Kconfig
+entry for Exynos 4210 is following:
+
+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. This option requires that
+	  Samsung USB 2.0 PHY driver is enabled and means that support for this
+	  particular SoC is compiled in the driver. In case of Exynos 4210 four
+	  phys are available - device, host, HSCI0 and HSCI1.
+
+The newly created file that supports the new SoC has to be also added to the
+Makefile. In case of Exynos 4210 the added line is following:
+
+obj-$(CONFIG_PHY_EXYNOS4210_USB2)       += phy-exynos4210-usb2.o
+
+After completing these steps the support for the new SoC should be ready.
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index fde4192..3374836 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -107,4 +107,33 @@ config PHY_SUN4I_USB
 	  This driver controls the entire USB PHY block, both the USB OTG
 	  parts, as well as the 2 regular USB 2 host PHYs.
 
+config PHY_SAMSUNG_USB2
+	tristate "Samsung USB 2.0 PHY driver"
+	select GENERIC_PHY
+	select MFD_SYSCON
+	help
+	  Enable this to support the Samsung USB 2.0 PHY driver for Samsung
+	  SoCs. This driver provides the interface for USB 2.0 PHY. Support for
+	  particular SoCs has to be enabled in addition to this driver. Number
+	  and type of supported phys depends on the SoC.
+
+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. This option requires that
+	  Samsung USB 2.0 PHY driver is enabled and means that support for this
+	  particular SoC is compiled in the driver. In case of Exynos 4210 four
+	  phys are available - device, host, HSIC0 and HSIC1.
+
+config PHY_EXYNOS4X12_USB2
+	bool "Support for Exynos 4x12"
+	depends on PHY_SAMSUNG_USB2
+	depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
+	help
+	  Enable USB PHY support for Exynos 4x12. This option requires that
+	  Samsung USB 2.0 PHY driver is enabled and means that support for this
+	  particular SoC is compiled in the driver. In case of Exynos 4x12 four
+	  phys are available - device, host, HSIC0 and HSIC1.
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 977a50e..c4ddd23 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -12,3 +12,6 @@ obj-$(CONFIG_TI_PIPE3)			+= phy-ti-pipe3.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
 obj-$(CONFIG_PHY_EXYNOS5250_SATA)	+= phy-exynos5250-sata.o
 obj-$(CONFIG_PHY_SUN4I_USB)		+= phy-sun4i-usb.o
+obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
+obj-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/phy-exynos4210-usb2.c
new file mode 100644
index 0000000..236a52a
--- /dev/null
+++ b/drivers/phy/phy-exynos4210-usb2.c
@@ -0,0 +1,261 @@
+/*
+ * 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/delay.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4210_UPHYPWR			0x0
+
+#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	BIT(0)
+#define EXYNOS_4210_UPHYPWR_PHY0_PWR		BIT(3)
+#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	BIT(4)
+#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		BIT(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	BIT(6)
+#define EXYNOS_4210_UPHYPWR_PHY1_PWR		BIT(7)
+#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		BIT(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_HSIC0_SUSPEND	BIT(9)
+#define EXYNOS_4210_UPHYPWR_HSIC0_SLEEP		BIT(10)
+#define EXYNOS_4210_UPHYPWR_HSIC0 ( \
+	EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_HSIC0_SLEEP)
+
+#define EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND	BIT(11)
+#define EXYNOS_4210_UPHYPWR_HSIC1_SLEEP		BIT(12)
+#define EXYNOS_4210_UPHYPWR_HSIC1 ( \
+	EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND | \
+	EXYNOS_4210_UPHYPWR_HSIC1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4210_UPHYCLK			0x4
+
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
+#define EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET	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	BIT(2)
+#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	BIT(4)
+#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	BIT(7)
+
+/* PHY reset control */
+#define EXYNOS_4210_UPHYRST			0x8
+
+#define EXYNOS_4210_URSTCON_PHY0		BIT(0)
+#define EXYNOS_4210_URSTCON_OTG_HLINK		BIT(1)
+#define EXYNOS_4210_URSTCON_OTG_PHYLINK		BIT(2)
+#define EXYNOS_4210_URSTCON_PHY1_ALL		BIT(3)
+#define EXYNOS_4210_URSTCON_PHY1_P0		BIT(4)
+#define EXYNOS_4210_URSTCON_PHY1_P1P2		BIT(5)
+#define EXYNOS_4210_URSTCON_HOST_LINK_ALL	BIT(6)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P0	BIT(7)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P1	BIT(8)
+#define EXYNOS_4210_URSTCON_HOST_LINK_P2	BIT(9)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
+#define EXYNOS_4210_USB_ISOL_DEVICE		BIT(0)
+#define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
+#define EXYNOS_4210_USB_ISOL_HOST		BIT(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;
+	u32 clk;
+
+	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_HSIC0;
+		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
+				EXYNOS_4210_URSTCON_HOST_LINK_P1;
+		break;
+	case EXYNOS4210_HSIC1:
+		phypwr =	EXYNOS_4210_UPHYPWR_HSIC1;
+		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
+				EXYNOS_4210_URSTCON_HOST_LINK_P2;
+		break;
+	};
+
+	if (on) {
+		clk = readl(drv->reg_phy + EXYNOS_4210_UPHYCLK);
+		clk &= ~EXYNOS_4210_UPHYCLK_PHYFSEL_MASK;
+		clk |= drv->ref_reg_val << EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET;
+		writel(clk, 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);
+		/* The following delay is necessary for the reset sequence to be
+		 * completed */
+		udelay(80);
+	} 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,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS4210_HOST,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS4210_HSIC0,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS4210_HSIC1,
+		.power_on	= exynos4210_power_on,
+		.power_off	= exynos4210_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
+	.has_mode_switch	= 0,
+	.num_phys		= EXYNOS4210_NUM_PHYS,
+	.phys			= exynos4210_phys,
+	.rate_to_clk		= exynos4210_rate_to_clk,
+};
diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/phy-exynos4x12-usb2.c
new file mode 100644
index 0000000..d92a7cc
--- /dev/null
+++ b/drivers/phy/phy-exynos4x12-usb2.c
@@ -0,0 +1,328 @@
+/*
+ * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4x12 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/delay.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include "phy-samsung-usb2.h"
+
+/* Exynos USB PHY registers */
+
+/* PHY power control */
+#define EXYNOS_4x12_UPHYPWR			0x0
+
+#define EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND	BIT(0)
+#define EXYNOS_4x12_UPHYPWR_PHY0_PWR		BIT(3)
+#define EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR	BIT(4)
+#define EXYNOS_4x12_UPHYPWR_PHY0_SLEEP		BIT(5)
+#define EXYNOS_4x12_UPHYPWR_PHY0 ( \
+	EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND | \
+	EXYNOS_4x12_UPHYPWR_PHY0_PWR | \
+	EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR | \
+	EXYNOS_4x12_UPHYPWR_PHY0_SLEEP)
+
+#define EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND	BIT(6)
+#define EXYNOS_4x12_UPHYPWR_PHY1_PWR		BIT(7)
+#define EXYNOS_4x12_UPHYPWR_PHY1_SLEEP		BIT(8)
+#define EXYNOS_4x12_UPHYPWR_PHY1 ( \
+	EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND | \
+	EXYNOS_4x12_UPHYPWR_PHY1_PWR | \
+	EXYNOS_4x12_UPHYPWR_PHY1_SLEEP)
+
+#define EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND	BIT(9)
+#define EXYNOS_4x12_UPHYPWR_HSIC0_PWR		BIT(10)
+#define EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP		BIT(11)
+#define EXYNOS_4x12_UPHYPWR_HSIC0 ( \
+	EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND | \
+	EXYNOS_4x12_UPHYPWR_HSIC0_PWR | \
+	EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP)
+
+#define EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND	BIT(12)
+#define EXYNOS_4x12_UPHYPWR_HSIC1_PWR		BIT(13)
+#define EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP		BIT(14)
+#define EXYNOS_4x12_UPHYPWR_HSIC1 ( \
+	EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND | \
+	EXYNOS_4x12_UPHYPWR_HSIC1_PWR | \
+	EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP)
+
+/* PHY clock control */
+#define EXYNOS_4x12_UPHYCLK			0x4
+
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK	(0x7 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET	0
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6	(0x0 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ	(0x1 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2	(0x3 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ	(0x4 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ	(0x5 << 0)
+#define EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ	(0x7 << 0)
+
+#define EXYNOS_4x12_UPHYCLK_PHY0_ID_PULLUP	BIT(3)
+#define EXYNOS_4x12_UPHYCLK_PHY0_COMMON_ON	BIT(4)
+#define EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON	BIT(7)
+
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_MASK	(0x7f << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_OFFSET  10
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_12MHZ	(0x24 << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_15MHZ	(0x1c << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_16MHZ	(0x1a << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_19MHZ2	(0x15 << 10)
+#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_20MHZ	(0x14 << 10)
+
+/* PHY reset control */
+#define EXYNOS_4x12_UPHYRST			0x8
+
+#define EXYNOS_4x12_URSTCON_PHY0		BIT(0)
+#define EXYNOS_4x12_URSTCON_OTG_HLINK		BIT(1)
+#define EXYNOS_4x12_URSTCON_OTG_PHYLINK		BIT(2)
+#define EXYNOS_4x12_URSTCON_HOST_PHY		BIT(3)
+#define EXYNOS_4x12_URSTCON_PHY1		BIT(4)
+#define EXYNOS_4x12_URSTCON_HSIC0		BIT(5)
+#define EXYNOS_4x12_URSTCON_HSIC1		BIT(6)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_ALL	BIT(7)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_P0	BIT(8)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_P1	BIT(9)
+#define EXYNOS_4x12_URSTCON_HOST_LINK_P2	BIT(10)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_4x12_USB_ISOL_OFFSET		0x704
+#define EXYNOS_4x12_USB_ISOL_OTG		BIT(0)
+#define EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET	0x708
+#define EXYNOS_4x12_USB_ISOL_HSIC0		BIT(0)
+#define EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET	0x70c
+#define EXYNOS_4x12_USB_ISOL_HSIC1		BIT(0)
+
+/* Mode switching SUB Device <-> Host */
+#define EXYNOS_4x12_MODE_SWITCH_OFFSET		0x21c
+#define EXYNOS_4x12_MODE_SWITCH_MASK		1
+#define EXYNOS_4x12_MODE_SWITCH_DEVICE		0
+#define EXYNOS_4x12_MODE_SWITCH_HOST		1
+
+enum exynos4x12_phy_id {
+	EXYNOS4x12_DEVICE,
+	EXYNOS4x12_HOST,
+	EXYNOS4x12_HSIC0,
+	EXYNOS4x12_HSIC1,
+	EXYNOS4x12_NUM_PHYS,
+};
+
+/*
+ * exynos4x12_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static int exynos4x12_rate_to_clk(unsigned long rate, u32 *reg)
+{
+	/* EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK */
+
+	switch (rate) {
+	case 9600 * KHZ:
+		*reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6;
+		break;
+	case 10 * MHZ:
+		*reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ;
+		break;
+	case 12 * MHZ:
+		*reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ;
+		break;
+	case 19200 * KHZ:
+		*reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2;
+		break;
+	case 20 * MHZ:
+		*reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ;
+		break;
+	case 24 * MHZ:
+		*reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ;
+		break;
+	case 50 * MHZ:
+		*reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void exynos4x12_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 EXYNOS4x12_DEVICE:
+	case EXYNOS4x12_HOST:
+		offset = EXYNOS_4x12_USB_ISOL_OFFSET;
+		mask = EXYNOS_4x12_USB_ISOL_OTG;
+		break;
+	case EXYNOS4x12_HSIC0:
+		offset = EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET;
+		mask = EXYNOS_4x12_USB_ISOL_HSIC0;
+		break;
+	case EXYNOS4x12_HSIC1:
+		offset = EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET;
+		mask = EXYNOS_4x12_USB_ISOL_HSIC1;
+		break;
+	default:
+		return;
+	};
+
+	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
+}
+
+static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 clk;
+
+	clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK);
+	clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK;
+	clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET;
+	writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK);
+}
+
+static void exynos4x12_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;
+	u32 mode = 0;
+	u32 switch_mode = 0;
+
+	switch (inst->cfg->id) {
+	case EXYNOS4x12_DEVICE:
+		phypwr =	EXYNOS_4x12_UPHYPWR_PHY0;
+		rstbits =	EXYNOS_4x12_URSTCON_PHY0;
+		mode =		EXYNOS_4x12_MODE_SWITCH_DEVICE;
+		switch_mode =	1;
+		break;
+	case EXYNOS4x12_HOST:
+		phypwr =	EXYNOS_4x12_UPHYPWR_PHY1;
+		rstbits =	EXYNOS_4x12_URSTCON_HOST_PHY;
+		mode =		EXYNOS_4x12_MODE_SWITCH_HOST;
+		switch_mode =	1;
+		break;
+	case EXYNOS4x12_HSIC0:
+		phypwr =	EXYNOS_4x12_UPHYPWR_HSIC0;
+		rstbits =	EXYNOS_4x12_URSTCON_HSIC1 |
+				EXYNOS_4x12_URSTCON_HOST_LINK_P0 |
+				EXYNOS_4x12_URSTCON_HOST_PHY;
+		break;
+	case EXYNOS4x12_HSIC1:
+		phypwr =	EXYNOS_4x12_UPHYPWR_HSIC1;
+		rstbits =	EXYNOS_4x12_URSTCON_HSIC1 |
+				EXYNOS_4x12_URSTCON_HOST_LINK_P1;
+		break;
+	};
+
+	if (on) {
+		if (switch_mode)
+			regmap_update_bits(drv->reg_sys,
+					   EXYNOS_4x12_MODE_SWITCH_OFFSET,
+					   EXYNOS_4x12_MODE_SWITCH_MASK, mode);
+
+		pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+		pwr &= ~phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+
+		rst = readl(drv->reg_phy + EXYNOS_4x12_UPHYRST);
+		rst |= rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4x12_UPHYRST);
+		udelay(10);
+		rst &= ~rstbits;
+		writel(rst, drv->reg_phy + EXYNOS_4x12_UPHYRST);
+		/* The following delay is necessary for the reset sequence to be
+		 * completed */
+		udelay(80);
+	} else {
+		pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+		pwr |= phypwr;
+		writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR);
+	}
+}
+
+static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+
+	inst->enabled = 1;
+	exynos4x12_setup_clk(inst);
+	exynos4x12_phy_pwr(inst, 1);
+	exynos4x12_isol(inst, 0);
+
+	/* Power on the device, as it is necessary for HSIC to work */
+	if (inst->cfg->id == EXYNOS4x12_HSIC0) {
+		struct samsung_usb2_phy_instance *device =
+					&drv->instances[EXYNOS4x12_DEVICE];
+		exynos4x12_phy_pwr(device, 1);
+		exynos4x12_isol(device, 0);
+	}
+
+	return 0;
+}
+
+static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	struct samsung_usb2_phy_instance *device =
+					&drv->instances[EXYNOS4x12_DEVICE];
+
+	inst->enabled = 0;
+	exynos4x12_isol(inst, 1);
+	exynos4x12_phy_pwr(inst, 0);
+
+	if (inst->cfg->id == EXYNOS4x12_HSIC0 && !device->enabled) {
+		exynos4x12_isol(device, 1);
+		exynos4x12_phy_pwr(device, 0);
+	}
+
+	return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos4x12_phys[] = {
+	{
+		.label		= "device",
+		.id		= EXYNOS4x12_DEVICE,
+		.power_on	= exynos4x12_power_on,
+		.power_off	= exynos4x12_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS4x12_HOST,
+		.power_on	= exynos4x12_power_on,
+		.power_off	= exynos4x12_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS4x12_HSIC0,
+		.power_on	= exynos4x12_power_on,
+		.power_off	= exynos4x12_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS4x12_HSIC1,
+		.power_on	= exynos4x12_power_on,
+		.power_off	= exynos4x12_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config = {
+	.has_mode_switch	= 1,
+	.num_phys		= EXYNOS4x12_NUM_PHYS,
+	.phys			= exynos4x12_phys,
+	.rate_to_clk		= exynos4x12_rate_to_clk,
+};
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
new file mode 100644
index 0000000..c3b7719
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -0,0 +1,222 @@
+/*
+ * 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/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(drv->ref_clk);
+	if (ret)
+		goto err_instance_clk;
+	if (inst->cfg->power_on) {
+		spin_lock(&drv->lock);
+		ret = inst->cfg->power_on(inst);
+		spin_unlock(&drv->lock);
+	}
+
+	return 0;
+
+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(drv->ref_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_EXYNOS4X12_USB2
+	{
+		.compatible = "samsung,exynos4x12-usb2-phy",
+		.data = &exynos4x12_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 device *dev = &pdev->dev;
+	struct phy_provider *phy_provider;
+	struct resource *mem;
+	struct samsung_usb2_phy_driver *drv;
+	int i, ret;
+
+	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);
+	}
+
+	drv->ref_clk = devm_clk_get(dev, "ref");
+	if (IS_ERR(drv->ref_clk)) {
+		dev_err(dev, "Failed to get reference clock for the phy controller\n");
+		return PTR_ERR(drv->ref_clk);
+	}
+
+	drv->ref_rate = clk_get_rate(drv->ref_clk);
+	if (drv->cfg->rate_to_clk) {
+		ret = drv->cfg->rate_to_clk(drv->ref_rate, &drv->ref_reg_val);
+		if (ret)
+			return ret;
+	}
+
+	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_bus_width(p->phy, 8);
+		phy_set_drvdata(p->phy, p);
+	}
+
+	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..51a1601
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -0,0 +1,66 @@
+/*
+ * 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/phy/phy.h>
+#include <linux/device.h>
+#include <linux/regmap.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 {
+	const struct samsung_usb2_common_phy *cfg;
+	struct phy *phy;
+	struct samsung_usb2_phy_driver *drv;
+	bool enabled;
+};
+
+struct samsung_usb2_phy_driver {
+	const struct samsung_usb2_phy_config *cfg;
+	struct clk *clk;
+	struct clk *ref_clk;
+	unsigned long ref_rate;
+	u32 ref_reg_val;
+	struct device *dev;
+	void __iomem *reg_phy;
+	struct regmap *reg_pmu;
+	struct regmap *reg_sys;
+	spinlock_t lock;
+	struct samsung_usb2_phy_instance instances[0];
+};
+
+struct samsung_usb2_common_phy {
+	int (*power_on)(struct samsung_usb2_phy_instance *);
+	int (*power_off)(struct samsung_usb2_phy_instance *);
+	unsigned int id;
+	char *label;
+};
+
+
+struct samsung_usb2_phy_config {
+	const struct samsung_usb2_common_phy *phys;
+	int (*rate_to_clk)(unsigned long, u32 *);
+	unsigned int num_phys;
+	bool has_mode_switch;
+};
+
+extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
+extern const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config;
+#endif
-- 
1.7.9.5


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

* [PATCH 15/28] phy: Add Exynos 5250 support to the Exynos USB 2.0 PHY driver
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (13 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 14/28] phy: Add new Exynos USB 2.0 PHY driver Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 16/28] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x Kishon Vijay Abraham I
                   ` (14 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Kamil Debski <k.debski@samsung.com>

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: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../devicetree/bindings/phy/samsung-phy.txt        |    1 +
 drivers/phy/Kconfig                                |   11 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-exynos5250-usb2.c                  |  404 ++++++++++++++++++++
 drivers/phy/phy-samsung-usb2.c                     |    6 +
 drivers/phy/phy-samsung-usb2.h                     |    1 +
 6 files changed, 424 insertions(+)
 create mode 100644 drivers/phy/phy-exynos5250-usb2.c

diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt
index bf955ab..28f9edb 100644
--- a/Documentation/devicetree/bindings/phy/samsung-phy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt
@@ -28,6 +28,7 @@ Required properties:
 - compatible : should be one of the listed compatibles:
 	- "samsung,exynos4210-usb2-phy"
 	- "samsung,exynos4x12-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 3374836..1b607d7 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -136,4 +136,15 @@ config PHY_EXYNOS4X12_USB2
 	  Samsung USB 2.0 PHY driver is enabled and means that support for this
 	  particular SoC is compiled in the driver. In case of Exynos 4x12 four
 	  phys are available - device, host, HSIC0 and HSIC1.
+
+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. This option requires that
+	  Samsung USB 2.0 PHY driver is enabled and means that support for this
+	  particular SoC is compiled in the driver. In case of Exynos 5250 four
+	  phys are available - device, host, HSIC0 and HSIC.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index c4ddd23..ecf0d3f 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_PHY_SUN4I_USB)		+= phy-sun4i-usb.o
 obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-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..94179af
--- /dev/null
+++ b/drivers/phy/phy-exynos5250-usb2.c
@@ -0,0 +1,404 @@
+/*
+ * 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/delay.h>
+#include <linux/io.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.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		BIT(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		BIT(11)
+#define EXYNOS_5250_HOSTPHYCTRL0_RETENABLE		BIT(10)
+#define EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N		BIT(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			BIT(6)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP		BIT(5)
+#define EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND		BIT(4)
+#define EXYNOS_5250_HOSTPHYCTRL0_WORDINTERFACE		BIT(3)
+#define EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST		BIT(2)
+#define EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST		BIT(1)
+#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST		BIT(0)
+
+/* HSIC0 & HSIC1 */
+#define EXYNOS_5250_HSICPHYCTRL1			0x10
+#define EXYNOS_5250_HSICPHYCTRL2			0x20
+
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_MASK		(0x3 << 23)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT	(0x2 << 23)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_MASK		(0x7f << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12		(0x24 << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_15		(0x1c << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_16		(0x1a << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_19_2		(0x15 << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_20		(0x14 << 16)
+#define EXYNOS_5250_HSICPHYCTRLX_SIDDQ			BIT(6)
+#define EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP		BIT(5)
+#define EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND		BIT(4)
+#define EXYNOS_5250_HSICPHYCTRLX_WORDINTERFACE		BIT(3)
+#define EXYNOS_5250_HSICPHYCTRLX_UTMISWRST		BIT(2)
+#define EXYNOS_5250_HSICPHYCTRLX_PHYSWRST		BIT(0)
+
+/* EHCI control */
+#define EXYNOS_5250_HOSTEHCICTRL			0x30
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN		BIT(29)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR4		BIT(28)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR8		BIT(27)
+#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR16		BIT(26)
+#define EXYNOS_5250_HOSTEHCICTRL_AUTOPPDONOVRCUREN	BIT(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		BIT(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		BIT(0)
+
+/* USBOTG */
+#define EXYNOS_5250_USBOTGSYS				0x38
+#define EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET		BIT(14)
+#define EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG		BIT(13)
+#define EXYNOS_5250_USBOTGSYS_PHY_SW_RST		BIT(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			BIT(8)
+#define EXYNOS_5250_USBOTGSYS_COMMON_ON			BIT(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		BIT(3)
+#define EXYNOS_5250_USBOTGSYS_OTGDISABLE		BIT(2)
+#define EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG		BIT(1)
+#define EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND		BIT(0)
+
+/* Isolation, configured in the power management unit */
+#define EXYNOS_5250_USB_ISOL_OTG_OFFSET		0x704
+#define EXYNOS_5250_USB_ISOL_OTG		BIT(0)
+#define EXYNOS_5250_USB_ISOL_HOST_OFFSET	0x708
+#define EXYNOS_5250_USB_ISOL_HOST		BIT(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 int exynos5250_power_on(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 ctrl0;
+	u32 otg;
+	u32 ehci;
+	u32 ohci;
+	u32 hsic;
+
+	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 |= drv->ref_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:
+	case EXYNOS5250_HSIC0:
+	case EXYNOS5250_HSIC1:
+		/* Host registers configuration */
+		ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+		/* The clock */
+		ctrl0 &= ~EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK;
+		ctrl0 |= drv->ref_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 |= drv->ref_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);
+
+		/* HSIC phy configuration */
+		hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 |
+				EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT |
+				EXYNOS_5250_HSICPHYCTRLX_PHYSWRST);
+		writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
+		writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
+		udelay(10);
+		hsic &= ~EXYNOS_5250_HSICPHYCTRLX_PHYSWRST;
+		writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
+		writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
+		/* The following delay is necessary for the reset sequence to be
+		 * completed */
+		udelay(80);
+
+		/* 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;
+	}
+	inst->enabled = 1;
+	exynos5250_isol(inst, 0);
+
+	return 0;
+}
+
+static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst)
+{
+	struct samsung_usb2_phy_driver *drv = inst->drv;
+	u32 ctrl0;
+	u32 otg;
+	u32 hsic;
+
+	inst->enabled = 0;
+	exynos5250_isol(inst, 1);
+
+	switch (inst->cfg->id) {
+	case EXYNOS5250_DEVICE:
+		otg = readl(drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		otg |= (EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
+			EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG |
+			EXYNOS_5250_USBOTGSYS_FORCE_SLEEP);
+		writel(otg, drv->reg_phy + EXYNOS_5250_USBOTGSYS);
+		break;
+	case EXYNOS5250_HOST:
+		ctrl0 = readl(drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+		ctrl0 |= (EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
+				EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
+				EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP |
+				EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
+				EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL);
+		writel(ctrl0, drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
+		break;
+	case EXYNOS5250_HSIC0:
+	case EXYNOS5250_HSIC1:
+		hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 |
+				EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT |
+				EXYNOS_5250_HSICPHYCTRLX_SIDDQ |
+				EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP |
+				EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND
+				);
+		writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
+		writel(hsic, drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
+		break;
+	}
+
+	return 0;
+}
+
+
+static const struct samsung_usb2_common_phy exynos5250_phys[] = {
+	{
+		.label		= "device",
+		.id		= EXYNOS5250_DEVICE,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{
+		.label		= "host",
+		.id		= EXYNOS5250_HOST,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{
+		.label		= "hsic0",
+		.id		= EXYNOS5250_HSIC0,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{
+		.label		= "hsic1",
+		.id		= EXYNOS5250_HSIC1,
+		.power_on	= exynos5250_power_on,
+		.power_off	= exynos5250_power_off,
+	},
+	{},
+};
+
+const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
+	.has_mode_switch	= 1,
+	.num_phys		= EXYNOS5250_NUM_PHYS,
+	.phys			= exynos5250_phys,
+	.rate_to_clk		= exynos5250_rate_to_clk,
+};
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
index c3b7719..8a8c6bc 100644
--- a/drivers/phy/phy-samsung-usb2.c
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -99,6 +99,12 @@ static const struct of_device_id samsung_usb2_phy_of_match[] = {
 		.data = &exynos4x12_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 51a1601..45b3170 100644
--- a/drivers/phy/phy-samsung-usb2.h
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -63,4 +63,5 @@ struct samsung_usb2_phy_config {
 
 extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
 extern const struct samsung_usb2_phy_config exynos4x12_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] 35+ messages in thread

* [PATCH 16/28] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (14 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 15/28] phy: Add Exynos 5250 support to the " Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 17/28] phy: omap-usb2: Provide workaround for USB2PHY false disconnect Kishon Vijay Abraham I
                   ` (13 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: George Cherian <george.cherian@ti.com>

Adapt phy-omap-usb2 driver for AM437x.
	- Add new comaptible "ti,am437x-usb2" for AM437x
	- Pass proper data to differentiate AM437x and others.
	- AM437x doesnot support  set_vbus and start_srp.
	- Also update the Documentation to add new compatible.

Signed-off-by: George Cherian <george.cherian@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 Documentation/devicetree/bindings/usb/usb-phy.txt |    4 +-
 drivers/phy/phy-omap-usb2.c                       |   49 ++++++++++++++++-----
 include/linux/phy/omap_usb.h                      |    9 ++++
 3 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
index c0245c8..b3fa409 100644
--- a/Documentation/devicetree/bindings/usb/usb-phy.txt
+++ b/Documentation/devicetree/bindings/usb/usb-phy.txt
@@ -3,7 +3,9 @@ USB PHY
 OMAP USB2 PHY
 
 Required properties:
- - compatible: Should be "ti,omap-usb2"
+ - compatible: Should be either of
+	* "ti,omap-usb2" for OMAP4, OMAP5, DRA7
+	* "ti,am437x-usb2" for AM437x
  - reg : Address and length of the register set for the device.
  - #phy-cells: determine the number of cells that should be given in the
    phandle while referencing this phy.
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 9c3f056..0c78f54 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -122,6 +122,31 @@ static struct phy_ops ops = {
 	.owner		= THIS_MODULE,
 };
 
+#ifdef CONFIG_OF
+static const struct usb_phy_data omap_usb2_data = {
+	.label = "omap_usb2",
+	.flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
+};
+
+static const struct usb_phy_data am437x_usb2_data = {
+	.label = "am437x_usb2",
+	.flags =  0,
+};
+
+static const struct of_device_id omap_usb2_id_table[] = {
+	{
+		.compatible = "ti,omap-usb2",
+		.data = &omap_usb2_data,
+	},
+	{
+		.compatible = "ti,am437x-usb2",
+		.data = &am437x_usb2_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
+#endif
+
 static int omap_usb2_probe(struct platform_device *pdev)
 {
 	struct omap_usb	*phy;
@@ -131,10 +156,16 @@ static int omap_usb2_probe(struct platform_device *pdev)
 	struct device_node *node = pdev->dev.of_node;
 	struct device_node *control_node;
 	struct platform_device *control_pdev;
+	const struct of_device_id *of_id;
+	struct usb_phy_data *phy_data;
+
+	of_id = of_match_device(of_match_ptr(omap_usb2_id_table), &pdev->dev);
 
-	if (!node)
+	if (!of_id)
 		return -EINVAL;
 
+	phy_data = (struct usb_phy_data *)of_id->data;
+
 	phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
 	if (!phy) {
 		dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
@@ -150,7 +181,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
 	phy->dev		= &pdev->dev;
 
 	phy->phy.dev		= phy->dev;
-	phy->phy.label		= "omap-usb2";
+	phy->phy.label		= phy_data->label;
 	phy->phy.otg		= otg;
 	phy->phy.type		= USB_PHY_TYPE_USB2;
 
@@ -171,8 +202,10 @@ static int omap_usb2_probe(struct platform_device *pdev)
 
 	otg->set_host		= omap_usb_set_host;
 	otg->set_peripheral	= omap_usb_set_peripheral;
-	otg->set_vbus		= omap_usb_set_vbus;
-	otg->start_srp		= omap_usb_start_srp;
+	if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS)
+		otg->set_vbus		= omap_usb_set_vbus;
+	if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
+		otg->start_srp		= omap_usb_start_srp;
 	otg->phy		= &phy->phy;
 
 	platform_set_drvdata(pdev, phy);
@@ -272,14 +305,6 @@ static const struct dev_pm_ops omap_usb2_pm_ops = {
 #define DEV_PM_OPS     NULL
 #endif
 
-#ifdef CONFIG_OF
-static const struct of_device_id omap_usb2_id_table[] = {
-	{ .compatible = "ti,omap-usb2" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
-#endif
-
 static struct platform_driver omap_usb2_driver = {
 	.probe		= omap_usb2_probe,
 	.remove		= omap_usb2_remove,
diff --git a/include/linux/phy/omap_usb.h b/include/linux/phy/omap_usb.h
index 19d343c3..35989a8 100644
--- a/include/linux/phy/omap_usb.h
+++ b/include/linux/phy/omap_usb.h
@@ -39,6 +39,15 @@ struct omap_usb {
 	struct clk		*optclk;
 };
 
+struct usb_phy_data {
+	const char *label;
+	u8 flags;
+};
+
+/* Driver Flags */
+#define OMAP_USB2_HAS_START_SRP (1 << 0)
+#define OMAP_USB2_HAS_SET_VBUS (1 << 1)
+
 #define	phy_to_omapusb(x)	container_of((x), struct omap_usb, phy)
 
 #if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
-- 
1.7.9.5


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

* [PATCH 17/28] phy: omap-usb2: Provide workaround for USB2PHY false disconnect
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (15 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 16/28] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 18/28] phy: omap-usb2: Add different compatible for OMAP5 Kishon Vijay Abraham I
                   ` (12 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Austin Beam <austinbeam@ti.com>

Enable the dra7x errata workaround for false disconnect problem
with USB2PHY. False disconnects were detected with some of the devices.
Reduce the sensitivity of the disconnect logic within the USB2PHY subsystem
to enusre these false disconnects are not registered.

[george.cherian@ti.com]
While at that, pass proper flags for each SoC's. This is a common driver
used across OMAP4,OMAP5,DRA7xx and AM437x USB2PHY.

False disconnect workaround is currently applicable for only DRA7x.

Update the Documentation also to add new comaptible.

Signed-off-by: Austin Beam <austinbeam@ti.com>
Signed-off-by: George Cherian <george.cherian@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 Documentation/devicetree/bindings/usb/usb-phy.txt |    3 +-
 drivers/phy/phy-omap-usb2.c                       |   44 +++++++++++++++++++++
 include/linux/phy/omap_usb.h                      |    4 ++
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
index b3fa409..03de61a5 100644
--- a/Documentation/devicetree/bindings/usb/usb-phy.txt
+++ b/Documentation/devicetree/bindings/usb/usb-phy.txt
@@ -4,7 +4,8 @@ OMAP USB2 PHY
 
 Required properties:
  - compatible: Should be either of
-	* "ti,omap-usb2" for OMAP4, OMAP5, DRA7
+	* "ti,omap-usb2" for OMAP4 and OMAP5
+	* "ti,dra7x-usb2" for DRA7
 	* "ti,am437x-usb2" for AM437x
  - reg : Address and length of the register set for the device.
  - #phy-cells: determine the number of cells that should be given in the
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 0c78f54..b220202 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -31,6 +31,9 @@
 #include <linux/phy/phy.h>
 #include <linux/of_platform.h>
 
+#define USB2PHY_DISCON_BYP_LATCH (1 << 31)
+#define USB2PHY_ANA_CONFIG1 0x4c
+
 /**
  * omap_usb2_set_comparator - links the comparator present in the sytem with
  *	this phy
@@ -116,7 +119,30 @@ static int omap_usb_power_on(struct phy *x)
 	return 0;
 }
 
+static int omap_usb_init(struct phy *x)
+{
+	struct omap_usb *phy = phy_get_drvdata(x);
+	u32 val;
+
+	if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
+		/*
+		 *
+		 * Reduce the sensitivity of internal PHY by enabling the
+		 * DISCON_BYP_LATCH of the USB2PHY_ANA_CONFIG1 register. This
+		 * resolves issues with certain devices which can otherwise
+		 * be prone to false disconnects.
+		 *
+		 */
+		val = omap_usb_readl(phy->phy_base, USB2PHY_ANA_CONFIG1);
+		val |= USB2PHY_DISCON_BYP_LATCH;
+		omap_usb_writel(phy->phy_base, USB2PHY_ANA_CONFIG1, val);
+	}
+
+	return 0;
+}
+
 static struct phy_ops ops = {
+	.init		= omap_usb_init,
 	.power_on	= omap_usb_power_on,
 	.power_off	= omap_usb_power_off,
 	.owner		= THIS_MODULE,
@@ -128,6 +154,11 @@ static const struct usb_phy_data omap_usb2_data = {
 	.flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
 };
 
+static const struct usb_phy_data dra7x_usb2_data = {
+	.label = "dra7x_usb2",
+	.flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
+};
+
 static const struct usb_phy_data am437x_usb2_data = {
 	.label = "am437x_usb2",
 	.flags =  0,
@@ -139,6 +170,10 @@ static const struct of_device_id omap_usb2_id_table[] = {
 		.data = &omap_usb2_data,
 	},
 	{
+		.compatible = "ti,dra7x-usb2",
+		.data = &dra7x_usb2_data,
+	},
+	{
 		.compatible = "ti,am437x-usb2",
 		.data = &am437x_usb2_data,
 	},
@@ -151,6 +186,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
 {
 	struct omap_usb	*phy;
 	struct phy *generic_phy;
+	struct resource *res;
 	struct phy_provider *phy_provider;
 	struct usb_otg *otg;
 	struct device_node *node = pdev->dev.of_node;
@@ -185,6 +221,14 @@ static int omap_usb2_probe(struct platform_device *pdev)
 	phy->phy.otg		= otg;
 	phy->phy.type		= USB_PHY_TYPE_USB2;
 
+	if (phy_data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		phy->phy_base = devm_ioremap_resource(&pdev->dev, res);
+		if (!phy->phy_base)
+			return -ENOMEM;
+		phy->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT;
+	}
+
 	control_node = of_parse_phandle(node, "ctrl-module", 0);
 	if (!control_node) {
 		dev_err(&pdev->dev, "Failed to get control device phandle\n");
diff --git a/include/linux/phy/omap_usb.h b/include/linux/phy/omap_usb.h
index 35989a8..dc2c541 100644
--- a/include/linux/phy/omap_usb.h
+++ b/include/linux/phy/omap_usb.h
@@ -33,10 +33,13 @@ struct usb_dpll_params {
 struct omap_usb {
 	struct usb_phy		phy;
 	struct phy_companion	*comparator;
+	void __iomem		*pll_ctrl_base;
+	void __iomem		*phy_base;
 	struct device		*dev;
 	struct device		*control_dev;
 	struct clk		*wkupclk;
 	struct clk		*optclk;
+	u8			flags;
 };
 
 struct usb_phy_data {
@@ -47,6 +50,7 @@ struct usb_phy_data {
 /* Driver Flags */
 #define OMAP_USB2_HAS_START_SRP (1 << 0)
 #define OMAP_USB2_HAS_SET_VBUS (1 << 1)
+#define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT (1 << 2)
 
 #define	phy_to_omapusb(x)	container_of((x), struct omap_usb, phy)
 
-- 
1.7.9.5


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

* [PATCH 18/28] phy: omap-usb2: Add different compatible for OMAP5
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (16 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 17/28] phy: omap-usb2: Provide workaround for USB2PHY false disconnect Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 19/28] phy: rename struct omap_control_usb to struct omap_control_phy Kishon Vijay Abraham I
                   ` (11 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: George Cherian <george.cherian@ti.com>

Add a new compatible for OMAP5 since it does not use any of the
OTG operations as of now.
HAS_SRP and SET_VBUS functionalities are used only for OMAP4.

Update the Documentation also to add new comaptible.

Signed-off-by: George Cherian <george.cherian@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 Documentation/devicetree/bindings/usb/usb-phy.txt |    3 ++-
 drivers/phy/phy-omap-usb2.c                       |    9 +++++++++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
index 03de61a5..ec199a5 100644
--- a/Documentation/devicetree/bindings/usb/usb-phy.txt
+++ b/Documentation/devicetree/bindings/usb/usb-phy.txt
@@ -4,7 +4,8 @@ OMAP USB2 PHY
 
 Required properties:
  - compatible: Should be either of
-	* "ti,omap-usb2" for OMAP4 and OMAP5
+	* "ti,omap-usb2" for OMAP4
+	* "ti,omap5-usb2" for OMAP5
 	* "ti,dra7x-usb2" for DRA7
 	* "ti,am437x-usb2" for AM437x
  - reg : Address and length of the register set for the device.
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index b220202..3cc4aba 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -154,6 +154,11 @@ static const struct usb_phy_data omap_usb2_data = {
 	.flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
 };
 
+static const struct usb_phy_data omap5_usb2_data = {
+	.label = "omap5_usb2",
+	.flags = 0,
+};
+
 static const struct usb_phy_data dra7x_usb2_data = {
 	.label = "dra7x_usb2",
 	.flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
@@ -170,6 +175,10 @@ static const struct of_device_id omap_usb2_id_table[] = {
 		.data = &omap_usb2_data,
 	},
 	{
+		.compatible = "ti,omap5-usb2",
+		.data = &omap5_usb2_data,
+	},
+	{
 		.compatible = "ti,dra7x-usb2",
 		.data = &dra7x_usb2_data,
 	},
-- 
1.7.9.5


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

* [PATCH 19/28] phy: rename struct omap_control_usb to struct omap_control_phy
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (17 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 18/28] phy: omap-usb2: Add different compatible for OMAP5 Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 20/28] phy: omap-control: update dra7 and am437 usb2 bindings Kishon Vijay Abraham I
                   ` (10 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

Rename struct omap_control_usb to struct omap_control_phy since it can
be used to control PHY of USB, SATA and PCIE. Also move the driver and
include files under *phy* and made the corresponding changes in the users
of phy-omap-control.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Felipe Balbi <balbi@ti.com>
---
 drivers/phy/Kconfig                                |   14 +-
 drivers/phy/Makefile                               |    1 +
 drivers/{usb => }/phy/phy-omap-control.c           |  165 ++++++++++----------
 drivers/phy/phy-omap-usb2.c                        |    8 +-
 drivers/phy/phy-ti-pipe3.c                         |    8 +-
 drivers/usb/musb/omap2430.c                        |    2 +-
 drivers/usb/phy/Kconfig                            |   10 --
 drivers/usb/phy/Makefile                           |    1 -
 .../omap_control_usb.h => phy/omap_control_phy.h}  |   36 ++---
 9 files changed, 123 insertions(+), 122 deletions(-)
 rename drivers/{usb => }/phy/phy-omap-control.c (55%)
 rename include/linux/{usb/omap_control_usb.h => phy/omap_control_phy.h} (68%)

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 1b607d7..fe8c009 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -31,12 +31,22 @@ config PHY_MVEBU_SATA
 	depends on OF
 	select GENERIC_PHY
 
+config OMAP_CONTROL_PHY
+	tristate "OMAP CONTROL PHY Driver"
+	help
+	  Enable this to add support for the PHY part present in the control
+	  module. This driver has API to power on the USB2 PHY and to write to
+	  the mailbox. The mailbox is present only in omap4 and the register to
+	  power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
+	  additional register to power on USB3 PHY/SATA PHY/PCIE PHY
+	  (PIPE3 PHY).
+
 config OMAP_USB2
 	tristate "OMAP USB2 PHY Driver"
 	depends on ARCH_OMAP2PLUS
 	depends on USB_PHY
 	select GENERIC_PHY
-	select OMAP_CONTROL_USB
+	select OMAP_CONTROL_PHY
 	help
 	  Enable this to support the transceiver that is part of SOC. This
 	  driver takes care of all the PHY functionality apart from comparator.
@@ -47,7 +57,7 @@ config TI_PIPE3
 	tristate "TI PIPE3 PHY Driver"
 	depends on ARCH_OMAP2PLUS || COMPILE_TEST
 	select GENERIC_PHY
-	select OMAP_CONTROL_USB
+	select OMAP_CONTROL_PHY
 	help
 	  Enable this to support the PIPE3 PHY that is part of TI SOCs. This
 	  driver takes care of all the PHY functionality apart from comparator.
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index ecf0d3f..8da05a8 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_BCM_KONA_USB2_PHY)		+= phy-bcm-kona-usb2.o
 obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO)	+= phy-exynos-dp-video.o
 obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)	+= phy-exynos-mipi-video.o
 obj-$(CONFIG_PHY_MVEBU_SATA)		+= phy-mvebu-sata.o
+obj-$(CONFIG_OMAP_CONTROL_PHY)		+= phy-omap-control.o
 obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_TI_PIPE3)			+= phy-ti-pipe3.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/phy/phy-omap-control.c
similarity index 55%
rename from drivers/usb/phy/phy-omap-control.c
rename to drivers/phy/phy-omap-control.c
index e725318..17fc200 100644
--- a/drivers/usb/phy/phy-omap-control.c
+++ b/drivers/phy/phy-omap-control.c
@@ -1,5 +1,5 @@
 /*
- * omap-control-usb.c - The USB part of control module.
+ * omap-control-phy.c - The PHY part of control module.
  *
  * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
  * This program is free software; you can redistribute it and/or modify
@@ -24,36 +24,36 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/clk.h>
-#include <linux/usb/omap_control_usb.h>
+#include <linux/phy/omap_control_phy.h>
 
 /**
- * omap_control_usb_phy_power - power on/off the phy using control module reg
+ * omap_control_phy_power - power on/off the phy using control module reg
  * @dev: the control module device
  * @on: 0 or 1, based on powering on or off the PHY
  */
-void omap_control_usb_phy_power(struct device *dev, int on)
+void omap_control_phy_power(struct device *dev, int on)
 {
 	u32 val;
 	unsigned long rate;
-	struct omap_control_usb	*control_usb;
+	struct omap_control_phy	*control_phy;
 
 	if (IS_ERR(dev) || !dev) {
 		pr_err("%s: invalid device\n", __func__);
 		return;
 	}
 
-	control_usb = dev_get_drvdata(dev);
-	if (!control_usb) {
-		dev_err(dev, "%s: invalid control usb device\n", __func__);
+	control_phy = dev_get_drvdata(dev);
+	if (!control_phy) {
+		dev_err(dev, "%s: invalid control phy device\n", __func__);
 		return;
 	}
 
-	if (control_usb->type == OMAP_CTRL_TYPE_OTGHS)
+	if (control_phy->type == OMAP_CTRL_TYPE_OTGHS)
 		return;
 
-	val = readl(control_usb->power);
+	val = readl(control_phy->power);
 
-	switch (control_usb->type) {
+	switch (control_phy->type) {
 	case OMAP_CTRL_TYPE_USB2:
 		if (on)
 			val &= ~OMAP_CTRL_DEV_PHY_PD;
@@ -62,19 +62,20 @@ void omap_control_usb_phy_power(struct device *dev, int on)
 		break;
 
 	case OMAP_CTRL_TYPE_PIPE3:
-		rate = clk_get_rate(control_usb->sys_clk);
+		rate = clk_get_rate(control_phy->sys_clk);
 		rate = rate/1000000;
 
 		if (on) {
-			val &= ~(OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK |
-					OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK);
-			val |= OMAP_CTRL_USB3_PHY_TX_RX_POWERON <<
-				OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT;
-			val |= rate << OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT;
+			val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
+				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
+			val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
+				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
+			val |= rate <<
+				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
 		} else {
-			val &= ~OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK;
-			val |= OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF <<
-				OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT;
+			val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
+			val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
+				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
 		}
 		break;
 
@@ -100,66 +101,66 @@ void omap_control_usb_phy_power(struct device *dev, int on)
 		break;
 	default:
 		dev_err(dev, "%s: type %d not recognized\n",
-					__func__, control_usb->type);
+			__func__, control_phy->type);
 		break;
 	}
 
-	writel(val, control_usb->power);
+	writel(val, control_phy->power);
 }
-EXPORT_SYMBOL_GPL(omap_control_usb_phy_power);
+EXPORT_SYMBOL_GPL(omap_control_phy_power);
 
 /**
  * omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded
- * @ctrl_usb: struct omap_control_usb *
+ * @ctrl_phy: struct omap_control_phy *
  *
  * Writes to the mailbox register to notify the usb core that a usb
  * device has been connected.
  */
-static void omap_control_usb_host_mode(struct omap_control_usb *ctrl_usb)
+static void omap_control_usb_host_mode(struct omap_control_phy *ctrl_phy)
 {
 	u32 val;
 
-	val = readl(ctrl_usb->otghs_control);
+	val = readl(ctrl_phy->otghs_control);
 	val &= ~(OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND);
 	val |= OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID;
-	writel(val, ctrl_usb->otghs_control);
+	writel(val, ctrl_phy->otghs_control);
 }
 
 /**
  * omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high
  * impedance
- * @ctrl_usb: struct omap_control_usb *
+ * @ctrl_phy: struct omap_control_phy *
  *
  * Writes to the mailbox register to notify the usb core that it has been
  * connected to a usb host.
  */
-static void omap_control_usb_device_mode(struct omap_control_usb *ctrl_usb)
+static void omap_control_usb_device_mode(struct omap_control_phy *ctrl_phy)
 {
 	u32 val;
 
-	val = readl(ctrl_usb->otghs_control);
+	val = readl(ctrl_phy->otghs_control);
 	val &= ~OMAP_CTRL_DEV_SESSEND;
 	val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_AVALID |
 		OMAP_CTRL_DEV_VBUSVALID;
-	writel(val, ctrl_usb->otghs_control);
+	writel(val, ctrl_phy->otghs_control);
 }
 
 /**
  * omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high
  * impedance
- * @ctrl_usb: struct omap_control_usb *
+ * @ctrl_phy: struct omap_control_phy *
  *
  * Writes to the mailbox register to notify the usb core it's now in
  * disconnected state.
  */
-static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb)
+static void omap_control_usb_set_sessionend(struct omap_control_phy *ctrl_phy)
 {
 	u32 val;
 
-	val = readl(ctrl_usb->otghs_control);
+	val = readl(ctrl_phy->otghs_control);
 	val &= ~(OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID);
 	val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND;
-	writel(val, ctrl_usb->otghs_control);
+	writel(val, ctrl_phy->otghs_control);
 }
 
 /**
@@ -174,30 +175,30 @@ static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb)
 void omap_control_usb_set_mode(struct device *dev,
 	enum omap_control_usb_mode mode)
 {
-	struct omap_control_usb	*ctrl_usb;
+	struct omap_control_phy	*ctrl_phy;
 
 	if (IS_ERR(dev) || !dev)
 		return;
 
-	ctrl_usb = dev_get_drvdata(dev);
+	ctrl_phy = dev_get_drvdata(dev);
 
-	if (!ctrl_usb) {
-		dev_err(dev, "Invalid control usb device\n");
+	if (!ctrl_phy) {
+		dev_err(dev, "Invalid control phy device\n");
 		return;
 	}
 
-	if (ctrl_usb->type != OMAP_CTRL_TYPE_OTGHS)
+	if (ctrl_phy->type != OMAP_CTRL_TYPE_OTGHS)
 		return;
 
 	switch (mode) {
 	case USB_MODE_HOST:
-		omap_control_usb_host_mode(ctrl_usb);
+		omap_control_usb_host_mode(ctrl_phy);
 		break;
 	case USB_MODE_DEVICE:
-		omap_control_usb_device_mode(ctrl_usb);
+		omap_control_usb_device_mode(ctrl_phy);
 		break;
 	case USB_MODE_DISCONNECT:
-		omap_control_usb_set_sessionend(ctrl_usb);
+		omap_control_usb_set_sessionend(ctrl_phy);
 		break;
 	default:
 		dev_vdbg(dev, "invalid omap control usb mode\n");
@@ -207,13 +208,13 @@ EXPORT_SYMBOL_GPL(omap_control_usb_set_mode);
 
 #ifdef CONFIG_OF
 
-static const enum omap_control_usb_type otghs_data = OMAP_CTRL_TYPE_OTGHS;
-static const enum omap_control_usb_type usb2_data = OMAP_CTRL_TYPE_USB2;
-static const enum omap_control_usb_type pipe3_data = OMAP_CTRL_TYPE_PIPE3;
-static const enum omap_control_usb_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2;
-static const enum omap_control_usb_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2;
+static const enum omap_control_phy_type otghs_data = OMAP_CTRL_TYPE_OTGHS;
+static const enum omap_control_phy_type usb2_data = OMAP_CTRL_TYPE_USB2;
+static const enum omap_control_phy_type pipe3_data = OMAP_CTRL_TYPE_PIPE3;
+static const enum omap_control_phy_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2;
+static const enum omap_control_phy_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2;
 
-static const struct of_device_id omap_control_usb_id_table[] = {
+static const struct of_device_id omap_control_phy_id_table[] = {
 	{
 		.compatible = "ti,control-phy-otghs",
 		.data = &otghs_data,
@@ -236,84 +237,84 @@ static const struct of_device_id omap_control_usb_id_table[] = {
 	},
 	{},
 };
-MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
+MODULE_DEVICE_TABLE(of, omap_control_phy_id_table);
 #endif
 
 
-static int omap_control_usb_probe(struct platform_device *pdev)
+static int omap_control_phy_probe(struct platform_device *pdev)
 {
 	struct resource	*res;
 	const struct of_device_id *of_id;
-	struct omap_control_usb *control_usb;
+	struct omap_control_phy *control_phy;
 
-	of_id = of_match_device(of_match_ptr(omap_control_usb_id_table),
-								&pdev->dev);
+	of_id = of_match_device(of_match_ptr(omap_control_phy_id_table),
+				&pdev->dev);
 	if (!of_id)
 		return -EINVAL;
 
-	control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),
+	control_phy = devm_kzalloc(&pdev->dev, sizeof(*control_phy),
 		GFP_KERNEL);
-	if (!control_usb) {
-		dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+	if (!control_phy) {
+		dev_err(&pdev->dev, "unable to alloc memory for control phy\n");
 		return -ENOMEM;
 	}
 
-	control_usb->dev = &pdev->dev;
-	control_usb->type = *(enum omap_control_usb_type *)of_id->data;
+	control_phy->dev = &pdev->dev;
+	control_phy->type = *(enum omap_control_phy_type *)of_id->data;
 
-	if (control_usb->type == OMAP_CTRL_TYPE_OTGHS) {
+	if (control_phy->type == OMAP_CTRL_TYPE_OTGHS) {
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 			"otghs_control");
-		control_usb->otghs_control = devm_ioremap_resource(
+		control_phy->otghs_control = devm_ioremap_resource(
 			&pdev->dev, res);
-		if (IS_ERR(control_usb->otghs_control))
-			return PTR_ERR(control_usb->otghs_control);
+		if (IS_ERR(control_phy->otghs_control))
+			return PTR_ERR(control_phy->otghs_control);
 	} else {
 		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 				"power");
-		control_usb->power = devm_ioremap_resource(&pdev->dev, res);
-		if (IS_ERR(control_usb->power)) {
+		control_phy->power = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(control_phy->power)) {
 			dev_err(&pdev->dev, "Couldn't get power register\n");
-			return PTR_ERR(control_usb->power);
+			return PTR_ERR(control_phy->power);
 		}
 	}
 
-	if (control_usb->type == OMAP_CTRL_TYPE_PIPE3) {
-		control_usb->sys_clk = devm_clk_get(control_usb->dev,
+	if (control_phy->type == OMAP_CTRL_TYPE_PIPE3) {
+		control_phy->sys_clk = devm_clk_get(control_phy->dev,
 			"sys_clkin");
-		if (IS_ERR(control_usb->sys_clk)) {
+		if (IS_ERR(control_phy->sys_clk)) {
 			pr_err("%s: unable to get sys_clkin\n", __func__);
 			return -EINVAL;
 		}
 	}
 
-	dev_set_drvdata(control_usb->dev, control_usb);
+	dev_set_drvdata(control_phy->dev, control_phy);
 
 	return 0;
 }
 
-static struct platform_driver omap_control_usb_driver = {
-	.probe		= omap_control_usb_probe,
+static struct platform_driver omap_control_phy_driver = {
+	.probe		= omap_control_phy_probe,
 	.driver		= {
-		.name	= "omap-control-usb",
+		.name	= "omap-control-phy",
 		.owner	= THIS_MODULE,
-		.of_match_table = of_match_ptr(omap_control_usb_id_table),
+		.of_match_table = of_match_ptr(omap_control_phy_id_table),
 	},
 };
 
-static int __init omap_control_usb_init(void)
+static int __init omap_control_phy_init(void)
 {
-	return platform_driver_register(&omap_control_usb_driver);
+	return platform_driver_register(&omap_control_phy_driver);
 }
-subsys_initcall(omap_control_usb_init);
+subsys_initcall(omap_control_phy_init);
 
-static void __exit omap_control_usb_exit(void)
+static void __exit omap_control_phy_exit(void)
 {
-	platform_driver_unregister(&omap_control_usb_driver);
+	platform_driver_unregister(&omap_control_phy_driver);
 }
-module_exit(omap_control_usb_exit);
+module_exit(omap_control_phy_exit);
 
-MODULE_ALIAS("platform: omap_control_usb");
+MODULE_ALIAS("platform: omap_control_phy");
 MODULE_AUTHOR("Texas Instruments Inc.");
-MODULE_DESCRIPTION("OMAP Control Module USB Driver");
+MODULE_DESCRIPTION("OMAP Control Module PHY Driver");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 3cc4aba..a2205a8 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -27,7 +27,7 @@
 #include <linux/err.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
-#include <linux/usb/omap_control_usb.h>
+#include <linux/phy/omap_control_phy.h>
 #include <linux/phy/phy.h>
 #include <linux/of_platform.h>
 
@@ -105,7 +105,7 @@ static int omap_usb_power_off(struct phy *x)
 {
 	struct omap_usb *phy = phy_get_drvdata(x);
 
-	omap_control_usb_phy_power(phy->control_dev, 0);
+	omap_control_phy_power(phy->control_dev, 0);
 
 	return 0;
 }
@@ -114,7 +114,7 @@ static int omap_usb_power_on(struct phy *x)
 {
 	struct omap_usb *phy = phy_get_drvdata(x);
 
-	omap_control_usb_phy_power(phy->control_dev, 1);
+	omap_control_phy_power(phy->control_dev, 1);
 
 	return 0;
 }
@@ -251,7 +251,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
 	}
 
 	phy->control_dev = &control_pdev->dev;
-	omap_control_usb_phy_power(phy->control_dev, 0);
+	omap_control_phy_power(phy->control_dev, 0);
 
 	otg->set_host		= omap_usb_set_host;
 	otg->set_peripheral	= omap_usb_set_peripheral;
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index c8d1674..fd029b1 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -26,7 +26,7 @@
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
-#include <linux/usb/omap_control_usb.h>
+#include <linux/phy/omap_control_phy.h>
 #include <linux/of_platform.h>
 
 #define	PLL_STATUS		0x00000004
@@ -134,7 +134,7 @@ static int ti_pipe3_power_off(struct phy *x)
 		return -EBUSY;
 	}
 
-	omap_control_usb_phy_power(phy->control_dev, 0);
+	omap_control_phy_power(phy->control_dev, 0);
 
 	return 0;
 }
@@ -232,7 +232,7 @@ static int ti_pipe3_init(struct phy *x)
 	if (ret)
 		return ret;
 
-	omap_control_usb_phy_power(phy->control_dev, 1);
+	omap_control_phy_power(phy->control_dev, 1);
 
 	return 0;
 }
@@ -304,7 +304,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 
 	phy->control_dev = &control_pdev->dev;
 
-	omap_control_usb_phy_power(phy->control_dev, 0);
+	omap_control_phy_power(phy->control_dev, 0);
 
 	platform_set_drvdata(pdev, phy);
 	pm_runtime_enable(phy->dev);
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 8aa59a2..d341c14 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -37,7 +37,7 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/usb/musb-omap.h>
-#include <linux/usb/omap_control_usb.h>
+#include <linux/phy/omap_control_phy.h>
 #include <linux/of_platform.h>
 
 #include "musb_core.h"
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index c337ba2..416e0c8 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -75,16 +75,6 @@ config NOP_USB_XCEIV
 	  built-in with usb ip or which are autonomous and doesn't require any
 	  phy programming such as ISP1x04 etc.
 
-config OMAP_CONTROL_USB
-	tristate "OMAP CONTROL USB Driver"
-	depends on ARCH_OMAP2PLUS || COMPILE_TEST
-	help
-	  Enable this to add support for the USB part present in the control
-	  module. This driver has API to power on the USB2 PHY and to write to
-	  the mailbox. The mailbox is present only in omap4 and the register to
-	  power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an
-	  additional register to power on USB3 PHY.
-
 config AM335X_CONTROL_USB
 	tristate
 
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 15f1878..f8fa719 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_ISP1301_OMAP)		+= phy-isp1301-omap.o
 obj-$(CONFIG_MV_U3D_PHY)		+= phy-mv-u3d-usb.o
 obj-$(CONFIG_NOP_USB_XCEIV)		+= phy-generic.o
 obj-$(CONFIG_TAHVO_USB)			+= phy-tahvo.o
-obj-$(CONFIG_OMAP_CONTROL_USB)		+= phy-omap-control.o
 obj-$(CONFIG_AM335X_CONTROL_USB)	+= phy-am335x-control.o
 obj-$(CONFIG_AM335X_PHY_USB)		+= phy-am335x.o
 obj-$(CONFIG_OMAP_OTG)			+= phy-omap-otg.o
diff --git a/include/linux/usb/omap_control_usb.h b/include/linux/phy/omap_control_phy.h
similarity index 68%
rename from include/linux/usb/omap_control_usb.h
rename to include/linux/phy/omap_control_phy.h
index 69ae383..5450403 100644
--- a/include/linux/usb/omap_control_usb.h
+++ b/include/linux/phy/omap_control_phy.h
@@ -1,5 +1,5 @@
 /*
- * omap_control_usb.h - Header file for the USB part of control module.
+ * omap_control_phy.h - Header file for the PHY part of control module.
  *
  * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
  * This program is free software; you can redistribute it and/or modify
@@ -16,10 +16,10 @@
  *
  */
 
-#ifndef __OMAP_CONTROL_USB_H__
-#define __OMAP_CONTROL_USB_H__
+#ifndef __OMAP_CONTROL_PHY_H__
+#define __OMAP_CONTROL_PHY_H__
 
-enum omap_control_usb_type {
+enum omap_control_phy_type {
 	OMAP_CTRL_TYPE_OTGHS = 1,	/* Mailbox OTGHS_CONTROL */
 	OMAP_CTRL_TYPE_USB2,	/* USB2_PHY, power down in CONTROL_DEV_CONF */
 	OMAP_CTRL_TYPE_PIPE3,	/* PIPE3 PHY, DPLL & seperate Rx/Tx power */
@@ -27,7 +27,7 @@ enum omap_control_usb_type {
 	OMAP_CTRL_TYPE_AM437USB2, /* USB2 PHY, power e.g. AM437x */
 };
 
-struct omap_control_usb {
+struct omap_control_phy {
 	struct device *dev;
 
 	u32 __iomem *otghs_control;
@@ -36,7 +36,7 @@ struct omap_control_usb {
 
 	struct clk *sys_clk;
 
-	enum omap_control_usb_type type;
+	enum omap_control_phy_type type;
 };
 
 enum omap_control_usb_mode {
@@ -54,14 +54,14 @@ enum omap_control_usb_mode {
 #define	OMAP_CTRL_DEV_SESSEND		BIT(3)
 #define	OMAP_CTRL_DEV_IDDIG		BIT(4)
 
-#define	OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK	0x003FC000
-#define	OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT	0xE
+#define	OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK		0x003FC000
+#define	OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT	0xE
 
-#define	OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK	0xFFC00000
-#define	OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT	0x16
+#define	OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK	0xFFC00000
+#define	OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT	0x16
 
-#define	OMAP_CTRL_USB3_PHY_TX_RX_POWERON	0x3
-#define	OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF	0x0
+#define	OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON	0x3
+#define	OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF	0x0
 
 #define OMAP_CTRL_USB2_PHY_PD		BIT(28)
 
@@ -70,13 +70,13 @@ enum omap_control_usb_mode {
 #define AM437X_CTRL_USB2_OTGVDET_EN	BIT(19)
 #define AM437X_CTRL_USB2_OTGSESSEND_EN	BIT(20)
 
-#if IS_ENABLED(CONFIG_OMAP_CONTROL_USB)
-extern void omap_control_usb_phy_power(struct device *dev, int on);
-extern void omap_control_usb_set_mode(struct device *dev,
-	enum omap_control_usb_mode mode);
+#if IS_ENABLED(CONFIG_OMAP_CONTROL_PHY)
+void omap_control_phy_power(struct device *dev, int on);
+void omap_control_usb_set_mode(struct device *dev,
+			       enum omap_control_usb_mode mode);
 #else
 
-static inline void omap_control_usb_phy_power(struct device *dev, int on)
+static inline void omap_control_phy_power(struct device *dev, int on)
 {
 }
 
@@ -86,4 +86,4 @@ static inline void omap_control_usb_set_mode(struct device *dev,
 }
 #endif
 
-#endif	/* __OMAP_CONTROL_USB_H__ */
+#endif	/* __OMAP_CONTROL_PHY_H__ */
-- 
1.7.9.5


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

* [PATCH 20/28] phy: omap-control: update dra7 and am437 usb2 bindings
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (18 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 19/28] phy: rename struct omap_control_usb to struct omap_control_phy Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 21/28] phy: ti-pipe3: cleanup clock handling Kishon Vijay Abraham I
                   ` (9 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Roger Quadros <rogerq@ti.com>

The dra7-usb2 and am437-usb2 bindings have not yet been used.
Change them to be more elegant.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-omap-control.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/phy/phy-omap-control.c b/drivers/phy/phy-omap-control.c
index 17fc200..311b4f9 100644
--- a/drivers/phy/phy-omap-control.c
+++ b/drivers/phy/phy-omap-control.c
@@ -228,11 +228,11 @@ static const struct of_device_id omap_control_phy_id_table[] = {
 		.data = &pipe3_data,
 	},
 	{
-		.compatible = "ti,control-phy-dra7usb2",
+		.compatible = "ti,control-phy-usb2-dra7",
 		.data = &dra7usb2_data,
 	},
 	{
-		.compatible = "ti,control-phy-am437usb2",
+		.compatible = "ti,control-phy-usb2-am437",
 		.data = &am437usb2_data,
 	},
 	{},
-- 
1.7.9.5


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

* [PATCH 21/28] phy: ti-pipe3: cleanup clock handling
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (19 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 20/28] phy: omap-control: update dra7 and am437 usb2 bindings Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 22/28] phy: ti-pipe3: Add SATA DPLL support Kishon Vijay Abraham I
                   ` (8 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Roger Quadros <rogerq@ti.com>

As this driver is no longer USB specific, use generic clock names.
- Fix PLL_SD_SHIFT from 9 to 10
- Don't separate prepare/unprepare clock from enable/disable. This
  ensures optimal power savings.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-ti-pipe3.c |   55 ++++++++++++++++++++++----------------------
 1 file changed, 28 insertions(+), 27 deletions(-)

diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index fd029b1..211703c 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -45,7 +45,7 @@
 #define	PLL_SELFREQDCO_MASK	0x0000000E
 #define	PLL_SELFREQDCO_SHIFT	0x1
 #define	PLL_SD_MASK		0x0003FC00
-#define	PLL_SD_SHIFT		0x9
+#define	PLL_SD_SHIFT		10
 #define	SET_PLL_GO		0x1
 #define	PLL_TICOPWDN		0x10000
 #define	PLL_LOCK		0x2
@@ -72,7 +72,7 @@ struct ti_pipe3 {
 	struct device		*control_dev;
 	struct clk		*wkupclk;
 	struct clk		*sys_clk;
-	struct clk		*optclk;
+	struct clk		*refclk;
 };
 
 struct pipe3_dpll_map {
@@ -270,23 +270,21 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 
 	phy->dev		= &pdev->dev;
 
-	phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
+	phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
 	if (IS_ERR(phy->wkupclk)) {
-		dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
+		dev_err(&pdev->dev, "unable to get wkupclk\n");
 		return PTR_ERR(phy->wkupclk);
 	}
-	clk_prepare(phy->wkupclk);
 
-	phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m");
-	if (IS_ERR(phy->optclk)) {
-		dev_err(&pdev->dev, "unable to get usb_otg_ss_refclk960m\n");
-		return PTR_ERR(phy->optclk);
+	phy->refclk = devm_clk_get(phy->dev, "refclk");
+	if (IS_ERR(phy->refclk)) {
+		dev_err(&pdev->dev, "unable to get refclk\n");
+		return PTR_ERR(phy->refclk);
 	}
-	clk_prepare(phy->optclk);
 
-	phy->sys_clk = devm_clk_get(phy->dev, "sys_clkin");
+	phy->sys_clk = devm_clk_get(phy->dev, "sysclk");
 	if (IS_ERR(phy->sys_clk)) {
-		pr_err("%s: unable to get sys_clkin\n", __func__);
+		dev_err(&pdev->dev, "unable to get sysclk\n");
 		return -EINVAL;
 	}
 
@@ -326,10 +324,6 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 
 static int ti_pipe3_remove(struct platform_device *pdev)
 {
-	struct ti_pipe3 *phy = platform_get_drvdata(pdev);
-
-	clk_unprepare(phy->wkupclk);
-	clk_unprepare(phy->optclk);
 	if (!pm_runtime_suspended(&pdev->dev))
 		pm_runtime_put(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
@@ -343,8 +337,10 @@ static int ti_pipe3_runtime_suspend(struct device *dev)
 {
 	struct ti_pipe3	*phy = dev_get_drvdata(dev);
 
-	clk_disable(phy->wkupclk);
-	clk_disable(phy->optclk);
+	if (!IS_ERR(phy->wkupclk))
+		clk_disable_unprepare(phy->wkupclk);
+	if (!IS_ERR(phy->refclk))
+		clk_disable_unprepare(phy->refclk);
 
 	return 0;
 }
@@ -354,22 +350,27 @@ static int ti_pipe3_runtime_resume(struct device *dev)
 	u32 ret = 0;
 	struct ti_pipe3	*phy = dev_get_drvdata(dev);
 
-	ret = clk_enable(phy->optclk);
-	if (ret) {
-		dev_err(phy->dev, "Failed to enable optclk %d\n", ret);
-		goto err1;
+	if (!IS_ERR(phy->refclk)) {
+		ret = clk_prepare_enable(phy->refclk);
+		if (ret) {
+			dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
+			goto err1;
+		}
 	}
 
-	ret = clk_enable(phy->wkupclk);
-	if (ret) {
-		dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
-		goto err2;
+	if (!IS_ERR(phy->wkupclk)) {
+		ret = clk_prepare_enable(phy->wkupclk);
+		if (ret) {
+			dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
+			goto err2;
+		}
 	}
 
 	return 0;
 
 err2:
-	clk_disable(phy->optclk);
+	if (!IS_ERR(phy->refclk))
+		clk_disable_unprepare(phy->refclk);
 
 err1:
 	return ret;
-- 
1.7.9.5


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

* [PATCH 22/28] phy: ti-pipe3: Add SATA DPLL support
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (20 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 21/28] phy: ti-pipe3: cleanup clock handling Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 23/28] phy: ti-pipe3: Don't get 'wkupclk' and 'refclk' for SATA PHY Kishon Vijay Abraham I
                   ` (7 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Roger Quadros <rogerq@ti.com>

USB and SATA DPLLs need different settings. Provide
the SATA DPLL settings and use the proper DPLL settings
based on device tree node's compatible_id.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-ti-pipe3.c |   76 ++++++++++++++++++++++++++++++++------------
 1 file changed, 55 insertions(+), 21 deletions(-)

diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index 211703c..f141237 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -66,6 +66,11 @@ struct pipe3_dpll_params {
 	u32	mf;
 };
 
+struct pipe3_dpll_map {
+	unsigned long rate;
+	struct pipe3_dpll_params params;
+};
+
 struct ti_pipe3 {
 	void __iomem		*pll_ctrl_base;
 	struct device		*dev;
@@ -73,20 +78,27 @@ struct ti_pipe3 {
 	struct clk		*wkupclk;
 	struct clk		*sys_clk;
 	struct clk		*refclk;
+	struct pipe3_dpll_map	*dpll_map;
 };
 
-struct pipe3_dpll_map {
-	unsigned long rate;
-	struct pipe3_dpll_params params;
-};
-
-static struct pipe3_dpll_map dpll_map[] = {
+static struct pipe3_dpll_map dpll_map_usb[] = {
 	{12000000, {1250, 5, 4, 20, 0} },	/* 12 MHz */
 	{16800000, {3125, 20, 4, 20, 0} },	/* 16.8 MHz */
 	{19200000, {1172, 8, 4, 20, 65537} },	/* 19.2 MHz */
 	{20000000, {1000, 7, 4, 10, 0} },	/* 20 MHz */
 	{26000000, {1250, 12, 4, 20, 0} },	/* 26 MHz */
 	{38400000, {3125, 47, 4, 20, 92843} },	/* 38.4 MHz */
+	{ },					/* Terminator */
+};
+
+static struct pipe3_dpll_map dpll_map_sata[] = {
+	{12000000, {1000, 7, 4, 6, 0} },	/* 12 MHz */
+	{16800000, {714, 7, 4, 6, 0} },		/* 16.8 MHz */
+	{19200000, {625, 7, 4, 6, 0} },		/* 19.2 MHz */
+	{20000000, {600, 7, 4, 6, 0} },		/* 20 MHz */
+	{26000000, {461, 7, 4, 6, 0} },		/* 26 MHz */
+	{38400000, {312, 7, 4, 6, 0} },		/* 38.4 MHz */
+	{ },					/* Terminator */
 };
 
 static inline u32 ti_pipe3_readl(void __iomem *addr, unsigned offset)
@@ -100,15 +112,20 @@ static inline void ti_pipe3_writel(void __iomem *addr, unsigned offset,
 	__raw_writel(data, addr + offset);
 }
 
-static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(unsigned long rate)
+static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy)
 {
-	int i;
+	unsigned long rate;
+	struct pipe3_dpll_map *dpll_map = phy->dpll_map;
 
-	for (i = 0; i < ARRAY_SIZE(dpll_map); i++) {
-		if (rate == dpll_map[i].rate)
-			return &dpll_map[i].params;
+	rate = clk_get_rate(phy->sys_clk);
+
+	for (; dpll_map->rate; dpll_map++) {
+		if (rate == dpll_map->rate)
+			return &dpll_map->params;
 	}
 
+	dev_err(phy->dev, "No DPLL configuration for %lu Hz SYS CLK\n", rate);
+
 	return NULL;
 }
 
@@ -182,16 +199,11 @@ static void ti_pipe3_dpll_relock(struct ti_pipe3 *phy)
 static int ti_pipe3_dpll_lock(struct ti_pipe3 *phy)
 {
 	u32			val;
-	unsigned long		rate;
 	struct pipe3_dpll_params *dpll_params;
 
-	rate = clk_get_rate(phy->sys_clk);
-	dpll_params = ti_pipe3_get_dpll_params(rate);
-	if (!dpll_params) {
-		dev_err(phy->dev,
-			  "No DPLL configuration for %lu Hz SYS CLK\n", rate);
+	dpll_params = ti_pipe3_get_dpll_params(phy);
+	if (!dpll_params)
 		return -EINVAL;
-	}
 
 	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
 	val &= ~PLL_REGN_MASK;
@@ -244,6 +256,10 @@ static struct phy_ops ops = {
 	.owner		= THIS_MODULE,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id ti_pipe3_id_table[];
+#endif
+
 static int ti_pipe3_probe(struct platform_device *pdev)
 {
 	struct ti_pipe3 *phy;
@@ -253,8 +269,10 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 	struct device_node *node = pdev->dev.of_node;
 	struct device_node *control_node;
 	struct platform_device *control_pdev;
+	const struct of_device_id *match;
 
-	if (!node)
+	match = of_match_device(of_match_ptr(ti_pipe3_id_table), &pdev->dev);
+	if (!match)
 		return -EINVAL;
 
 	phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
@@ -263,6 +281,12 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	phy->dpll_map = (struct pipe3_dpll_map *)match->data;
+	if (!phy->dpll_map) {
+		dev_err(&pdev->dev, "no DPLL data\n");
+		return -EINVAL;
+	}
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl");
 	phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(phy->pll_ctrl_base))
@@ -388,8 +412,18 @@ static const struct dev_pm_ops ti_pipe3_pm_ops = {
 
 #ifdef CONFIG_OF
 static const struct of_device_id ti_pipe3_id_table[] = {
-	{ .compatible = "ti,phy-usb3" },
-	{ .compatible = "ti,omap-usb3" },
+	{
+		.compatible = "ti,phy-usb3",
+		.data = dpll_map_usb,
+	},
+	{
+		.compatible = "ti,omap-usb3",
+		.data = dpll_map_usb,
+	},
+	{
+		.compatible = "ti,phy-pipe3-sata",
+		.data = dpll_map_sata,
+	},
 	{}
 };
 MODULE_DEVICE_TABLE(of, ti_pipe3_id_table);
-- 
1.7.9.5


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

* [PATCH 23/28] phy: ti-pipe3: Don't get 'wkupclk' and 'refclk' for SATA PHY
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (21 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 22/28] phy: ti-pipe3: Add SATA DPLL support Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 24/28] phy: ti-pipe3: streamline PHY operations Kishon Vijay Abraham I
                   ` (6 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Roger Quadros <rogerq@ti.com>

SATA PHY doesn't need 'wkupclk; and 'refclk' so don't
try to get them for SATA PHY.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-ti-pipe3.c |   24 +++++++++++++++---------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index f141237..baa3f78d 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -294,16 +294,22 @@ static int ti_pipe3_probe(struct platform_device *pdev)
 
 	phy->dev		= &pdev->dev;
 
-	phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
-	if (IS_ERR(phy->wkupclk)) {
-		dev_err(&pdev->dev, "unable to get wkupclk\n");
-		return PTR_ERR(phy->wkupclk);
-	}
+	if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
+
+		phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
+		if (IS_ERR(phy->wkupclk)) {
+			dev_err(&pdev->dev, "unable to get wkupclk\n");
+			return PTR_ERR(phy->wkupclk);
+		}
 
-	phy->refclk = devm_clk_get(phy->dev, "refclk");
-	if (IS_ERR(phy->refclk)) {
-		dev_err(&pdev->dev, "unable to get refclk\n");
-		return PTR_ERR(phy->refclk);
+		phy->refclk = devm_clk_get(phy->dev, "refclk");
+		if (IS_ERR(phy->refclk)) {
+			dev_err(&pdev->dev, "unable to get refclk\n");
+			return PTR_ERR(phy->refclk);
+		}
+	} else {
+		phy->wkupclk = ERR_PTR(-ENODEV);
+		phy->refclk = ERR_PTR(-ENODEV);
 	}
 
 	phy->sys_clk = devm_clk_get(phy->dev, "sysclk");
-- 
1.7.9.5


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

* [PATCH 24/28] phy: ti-pipe3: streamline PHY operations
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (22 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 23/28] phy: ti-pipe3: Don't get 'wkupclk' and 'refclk' for SATA PHY Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 25/28] phy: ti-pipe3: Fix suspend/resume and module reload Kishon Vijay Abraham I
                   ` (5 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Roger Quadros <rogerq@ti.com>

Limit .power_on() and .power_off() to just control the
PHY power and not the DPLL. The DPLL will be enabled
in .init() and idled in .exit().

Don't reprogram the DPLL if it has been already locked
by the bootloader. This fixes a problem with SATA, where
it fails if SATA was used by the bootloader.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-ti-pipe3.c |  114 ++++++++++++++++++++++++--------------------
 1 file changed, 63 insertions(+), 51 deletions(-)

diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index baa3f78d..12cc900 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -47,7 +47,8 @@
 #define	PLL_SD_MASK		0x0003FC00
 #define	PLL_SD_SHIFT		10
 #define	SET_PLL_GO		0x1
-#define	PLL_TICOPWDN		0x10000
+#define PLL_LDOPWDN		BIT(15)
+#define PLL_TICOPWDN		BIT(16)
 #define	PLL_LOCK		0x2
 #define	PLL_IDLE		0x1
 
@@ -56,7 +57,8 @@
  * value required for the PIPE3PHY_PLL_CONFIGURATION2.PLL_IDLE status
  * to be correctly reflected in the PIPE3PHY_PLL_STATUS register.
  */
-# define PLL_IDLE_TIME  100;
+#define PLL_IDLE_TIME	100	/* in milliseconds */
+#define PLL_LOCK_TIME	100	/* in milliseconds */
 
 struct pipe3_dpll_params {
 	u16	m;
@@ -132,24 +134,6 @@ static struct pipe3_dpll_params *ti_pipe3_get_dpll_params(struct ti_pipe3 *phy)
 static int ti_pipe3_power_off(struct phy *x)
 {
 	struct ti_pipe3 *phy = phy_get_drvdata(x);
-	int val;
-	int timeout = PLL_IDLE_TIME;
-
-	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
-	val |= PLL_IDLE;
-	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
-
-	do {
-		val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
-		if (val & PLL_TICOPWDN)
-			break;
-		udelay(5);
-	} while (--timeout);
-
-	if (!timeout) {
-		dev_err(phy->dev, "power off failed\n");
-		return -EBUSY;
-	}
 
 	omap_control_phy_power(phy->control_dev, 0);
 
@@ -159,44 +143,34 @@ static int ti_pipe3_power_off(struct phy *x)
 static int ti_pipe3_power_on(struct phy *x)
 {
 	struct ti_pipe3 *phy = phy_get_drvdata(x);
-	int val;
-	int timeout = PLL_IDLE_TIME;
-
-	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
-	val &= ~PLL_IDLE;
-	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
 
-	do {
-		val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
-		if (!(val & PLL_TICOPWDN))
-			break;
-		udelay(5);
-	} while (--timeout);
-
-	if (!timeout) {
-		dev_err(phy->dev, "power on failed\n");
-		return -EBUSY;
-	}
+	omap_control_phy_power(phy->control_dev, 1);
 
 	return 0;
 }
 
-static void ti_pipe3_dpll_relock(struct ti_pipe3 *phy)
+static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy)
 {
 	u32		val;
 	unsigned long	timeout;
 
-	ti_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
-
-	timeout = jiffies + msecs_to_jiffies(20);
+	timeout = jiffies + msecs_to_jiffies(PLL_LOCK_TIME);
 	do {
+		cpu_relax();
 		val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
 		if (val & PLL_LOCK)
 			break;
-	} while (!WARN_ON(time_after(jiffies, timeout)));
+	} while (!time_after(jiffies, timeout));
+
+	if (!(val & PLL_LOCK)) {
+		dev_err(phy->dev, "DPLL failed to lock\n");
+		return -EBUSY;
+	}
+
+	return 0;
 }
 
-static int ti_pipe3_dpll_lock(struct ti_pipe3 *phy)
+static int ti_pipe3_dpll_program(struct ti_pipe3 *phy)
 {
 	u32			val;
 	struct pipe3_dpll_params *dpll_params;
@@ -230,27 +204,65 @@ static int ti_pipe3_dpll_lock(struct ti_pipe3 *phy)
 	val |= dpll_params->sd << PLL_SD_SHIFT;
 	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
 
-	ti_pipe3_dpll_relock(phy);
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
 
-	return 0;
+	return ti_pipe3_dpll_wait_lock(phy);
 }
 
 static int ti_pipe3_init(struct phy *x)
 {
 	struct ti_pipe3 *phy = phy_get_drvdata(x);
-	int ret;
+	u32 val;
+	int ret = 0;
 
-	ret = ti_pipe3_dpll_lock(phy);
-	if (ret)
-		return ret;
+	/* Bring it out of IDLE if it is IDLE */
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+	if (val & PLL_IDLE) {
+		val &= ~PLL_IDLE;
+		ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+		ret = ti_pipe3_dpll_wait_lock(phy);
+	}
 
-	omap_control_phy_power(phy->control_dev, 1);
+	/* Program the DPLL only if not locked */
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+	if (!(val & PLL_LOCK))
+		if (ti_pipe3_dpll_program(phy))
+			return -EINVAL;
 
-	return 0;
+	return ret;
 }
 
+static int ti_pipe3_exit(struct phy *x)
+{
+	struct ti_pipe3 *phy = phy_get_drvdata(x);
+	u32 val;
+	unsigned long timeout;
+
+	/* Put DPLL in IDLE mode */
+	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
+	val |= PLL_IDLE;
+	ti_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+	/* wait for LDO and Oscillator to power down */
+	timeout = jiffies + msecs_to_jiffies(PLL_IDLE_TIME);
+	do {
+		cpu_relax();
+		val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
+		if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
+			break;
+	} while (!time_after(jiffies, timeout));
+
+	if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
+		dev_err(phy->dev, "Failed to power down: PLL_STATUS 0x%x\n",
+			val);
+		return -EBUSY;
+	}
+
+	return 0;
+}
 static struct phy_ops ops = {
 	.init		= ti_pipe3_init,
+	.exit		= ti_pipe3_exit,
 	.power_on	= ti_pipe3_power_on,
 	.power_off	= ti_pipe3_power_off,
 	.owner		= THIS_MODULE,
-- 
1.7.9.5


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

* [PATCH 25/28] phy: ti-pipe3: Fix suspend/resume and module reload
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (23 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 24/28] phy: ti-pipe3: streamline PHY operations Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 26/28] phy: omap: Depend on OMAP_OCP2SCP bus driver Kishon Vijay Abraham I
                   ` (4 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Roger Quadros <rogerq@ti.com>

Due to Errata i783, SATA breaks if its DPLL is idled. The recommeded
workaround to issue a softreset to the SATA controller doesn't seem to
work. Here we just prevent SATA DPLL from Idling and hence avoid
the issue altogether.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/phy-ti-pipe3.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index 12cc900..5913676 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -238,6 +238,10 @@ static int ti_pipe3_exit(struct phy *x)
 	u32 val;
 	unsigned long timeout;
 
+	/* SATA DPLL can't be powered down due to Errata i783 */
+	if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
+		return 0;
+
 	/* Put DPLL in IDLE mode */
 	val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
 	val |= PLL_IDLE;
-- 
1.7.9.5


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

* [PATCH 26/28] phy: omap: Depend on OMAP_OCP2SCP bus driver
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (24 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 25/28] phy: ti-pipe3: Fix suspend/resume and module reload Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 27/28] Documentation: Add APM X-Gene SoC 15Gbps Multi-purpose PHY driver binding documentation Kishon Vijay Abraham I
                   ` (3 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Roger Quadros <rogerq@ti.com>

The OMAP_USB2 and OMAP_PIPE3 PHY devices will not be
detected if the OMAP_OCP2SCP bus driver is not present.
Make them depend on it.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/Kconfig |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index fe8c009..2aead8b 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -47,6 +47,7 @@ config OMAP_USB2
 	depends on USB_PHY
 	select GENERIC_PHY
 	select OMAP_CONTROL_PHY
+	depends on OMAP_OCP2SCP
 	help
 	  Enable this to support the transceiver that is part of SOC. This
 	  driver takes care of all the PHY functionality apart from comparator.
@@ -58,6 +59,7 @@ config TI_PIPE3
 	depends on ARCH_OMAP2PLUS || COMPILE_TEST
 	select GENERIC_PHY
 	select OMAP_CONTROL_PHY
+	depends on OMAP_OCP2SCP
 	help
 	  Enable this to support the PIPE3 PHY that is part of TI SOCs. This
 	  driver takes care of all the PHY functionality apart from comparator.
-- 
1.7.9.5


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

* [PATCH 27/28] Documentation: Add APM X-Gene SoC 15Gbps Multi-purpose PHY driver binding documentation
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (25 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 26/28] phy: omap: Depend on OMAP_OCP2SCP bus driver Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08  9:29 ` [PATCH 28/28] PHY: add APM X-Gene SoC 15Gbps Multi-purpose PHY driver Kishon Vijay Abraham I
                   ` (2 subsequent siblings)
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Loc Ho <lho@apm.com>

This patch adds the APM X-Gene SoC 15Gbps Multi-purpose PHY driver binding
documentation.

Signed-off-by: Loc Ho <lho@apm.com>
Signed-off-by: Tuan Phan <tphan@apm.com>
Signed-off-by: Suman Tripathi <stripathi@apm.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 .../devicetree/bindings/phy/apm-xgene-phy.txt      |   79 ++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/apm-xgene-phy.txt

diff --git a/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt b/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt
new file mode 100644
index 0000000..5f3a65a
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/apm-xgene-phy.txt
@@ -0,0 +1,79 @@
+* APM X-Gene 15Gbps Multi-purpose PHY nodes
+
+PHY nodes are defined to describe on-chip 15Gbps Multi-purpose PHY. Each
+PHY (pair of lanes) has its own node.
+
+Required properties:
+- compatible		: Shall be "apm,xgene-phy".
+- reg			: PHY memory resource is the SDS PHY access resource.
+- #phy-cells		: Shall be 1 as it expects one argument for setting
+			  the mode of the PHY. Possible values are 0 (SATA),
+			  1 (SGMII), 2 (PCIe), 3 (USB), and 4 (XFI).
+
+Optional properties:
+- status		: Shall be "ok" if enabled or "disabled" if disabled.
+			  Default is "ok".
+- clocks		: Reference to the clock entry.
+- apm,tx-eye-tuning	: Manual control to fine tune the capture of the serial
+			  bit lines from the automatic calibrated position.
+			  Two set of 3-tuple setting for each (up to 3)
+			  supported link speed on the host. Range from 0 to
+			  127 in unit of one bit period. Default is 10.
+- apm,tx-eye-direction	: Eye tuning manual control direction. 0 means sample
+			  data earlier than the nominal sampling point. 1 means
+			  sample data later than the nominal sampling point.
+			  Two set of 3-tuple setting for each (up to 3)
+			  supported link speed on the host. Default is 0.
+- apm,tx-boost-gain	: Frequency boost AC (LSB 3-bit) and DC (2-bit)
+			  gain control. Two set of 3-tuple setting for each
+			  (up to 3) supported link speed on the host. Range is
+			  between 0 to 31 in unit of dB. Default is 3.
+- apm,tx-amplitude	: Amplitude control. Two set of 3-tuple setting for
+			  each (up to 3) supported link speed on the host.
+			  Range is between 0 to 199500 in unit of uV.
+			  Default is 199500 uV.
+- apm,tx-pre-cursor1	: 1st pre-cursor emphasis taps control. Two set of
+			  3-tuple setting for each (up to 3) supported link
+			  speed on the host. Range is 0 to 273000 in unit of
+			  uV. Default is 0.
+- apm,tx-pre-cursor2	: 2st pre-cursor emphasis taps control. Two set of
+			  3-tuple setting for each (up to 3) supported link
+			  speed on the host. Range is 0 to 127400 in unit uV.
+			  Default is 0x0.
+- apm,tx-post-cursor	: Post-cursor emphasis taps control. Two set of
+			  3-tuple setting for Gen1, Gen2, and Gen3. Range is
+			  between 0 to 0x1f in unit of 18.2mV. Default is 0xf.
+- apm,tx-speed		: Tx operating speed. One set of 3-tuple for each
+			  supported link speed on the host.
+			   0 = 1-2Gbps
+			   1 = 2-4Gbps (1st tuple default)
+			   2 = 4-8Gbps
+			   3 = 8-15Gbps (2nd tuple default)
+			   4 = 2.5-4Gbps
+			   5 = 4-5Gbps
+			   6 = 5-6Gbps
+			   7 = 6-16Gbps (3rd tuple default)
+
+NOTE: PHY override parameters are board specific setting.
+
+Example:
+		phy1: phy@1f21a000 {
+			compatible = "apm,xgene-phy";
+			reg = <0x0 0x1f21a000 0x0 0x100>;
+			#phy-cells = <1>;
+			status = "disabled";
+		};
+
+		phy2: phy@1f22a000 {
+			compatible = "apm,xgene-phy";
+			reg = <0x0 0x1f22a000 0x0 0x100>;
+			#phy-cells = <1>;
+			status = "ok";
+		};
+
+		phy3: phy@1f23a000 {
+			compatible = "apm,xgene-phy";
+			reg = <0x0 0x1f23a000 0x0 0x100>;
+			#phy-cells = <1>;
+			status = "ok";
+		};
-- 
1.7.9.5


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

* [PATCH 28/28] PHY: add APM X-Gene SoC 15Gbps Multi-purpose PHY driver
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (26 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 27/28] Documentation: Add APM X-Gene SoC 15Gbps Multi-purpose PHY driver binding documentation Kishon Vijay Abraham I
@ 2014-03-08  9:29 ` Kishon Vijay Abraham I
  2014-03-08 16:42 ` [GIT PULL 00/28] PHY for 3.15 Greg KH
  2014-03-09  7:27 ` [PATCH 16/28 v2] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x Kishon Vijay Abraham I
  29 siblings, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-08  9:29 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Loc Ho <lho@apm.com>

This patch adds support for the APM X-Gene SoC 15Gbps Multi-purpose PHY.
This is the physical layer interface for the corresponding host
controller. Currently, only external clock and Gen3 SATA mode
are supported.

Signed-off-by: Loc Ho <lho@apm.com>
Signed-off-by: Tuan Phan <tphan@apm.com>
Signed-off-by: Suman Tripathi <stripathi@apm.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 drivers/phy/Kconfig     |    7 +
 drivers/phy/Makefile    |    1 +
 drivers/phy/phy-xgene.c | 1750 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1758 insertions(+)
 create mode 100644 drivers/phy/phy-xgene.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 2aead8b..8d3c49c 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -159,4 +159,11 @@ config PHY_EXYNOS5250_USB2
 	  particular SoC is compiled in the driver. In case of Exynos 5250 four
 	  phys are available - device, host, HSIC0 and HSIC.
 
+config PHY_XGENE
+	tristate "APM X-Gene 15Gbps PHY support"
+	depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST)
+	select GENERIC_PHY
+	help
+	  This option enables support for APM X-Gene SoC multi-purpose PHY.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 8da05a8..2faf78e 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
 obj-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
+obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c
new file mode 100644
index 0000000..4aa1ccd
--- /dev/null
+++ b/drivers/phy/phy-xgene.c
@@ -0,0 +1,1750 @@
+/*
+ * AppliedMicro X-Gene Multi-purpose PHY driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Loc Ho <lho@apm.com>
+ *         Tuan Phan <tphan@apm.com>
+ *         Suman Tripathi <stripathi@apm.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The APM X-Gene PHY consists of two PLL clock macro's (CMU) and lanes.
+ * The first PLL clock macro is used for internal reference clock. The second
+ * PLL clock macro is used to generate the clock for the PHY. This driver
+ * configures the first PLL CMU, the second PLL CMU, and programs the PHY to
+ * operate according to the mode of operation. The first PLL CMU is only
+ * required if internal clock is enabled.
+ *
+ * Logical Layer Out Of HW module units:
+ *
+ * -----------------
+ * | Internal      |    |------|
+ * | Ref PLL CMU   |----|      |     -------------    ---------
+ * ------------ ----    | MUX  |-----|PHY PLL CMU|----| Serdes|
+ *                      |      |     |           |    ---------
+ * External Clock ------|      |     -------------
+ *                      |------|
+ *
+ * The Ref PLL CMU CSR (Configuration System Registers) is accessed
+ * indirectly from the SDS offset at 0x2000. It is only required for
+ * internal reference clock.
+ * The PHY PLL CMU CSR is accessed indirectly from the SDS offset at 0x0000.
+ * The Serdes CSR is accessed indirectly from the SDS offset at 0x0400.
+ *
+ * The Ref PLL CMU can be located within the same PHY IP or outside the PHY IP
+ * due to shared Ref PLL CMU. For PHY with Ref PLL CMU shared with another IP,
+ * it is located outside the PHY IP. This is the case for the PHY located
+ * at 0x1f23a000 (SATA Port 4/5). For such PHY, another resource is required
+ * to located the SDS/Ref PLL CMU module and its clock for that IP enabled.
+ *
+ * Currently, this driver only supports Gen3 SATA mode with external clock.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/phy/phy.h>
+#include <linux/clk.h>
+
+/* Max 2 lanes per a PHY unit */
+#define MAX_LANE			2
+
+/* Register offset inside the PHY */
+#define SERDES_PLL_INDIRECT_OFFSET	0x0000
+#define SERDES_PLL_REF_INDIRECT_OFFSET	0x2000
+#define SERDES_INDIRECT_OFFSET		0x0400
+#define SERDES_LANE_STRIDE		0x0200
+
+/* Some default Serdes parameters */
+#define DEFAULT_SATA_TXBOOST_GAIN	{ 0x1e, 0x1e, 0x1e }
+#define DEFAULT_SATA_TXEYEDIRECTION	{ 0x0, 0x0, 0x0 }
+#define DEFAULT_SATA_TXEYETUNING	{ 0xa, 0xa, 0xa }
+#define DEFAULT_SATA_SPD_SEL		{ 0x1, 0x3, 0x7 }
+#define DEFAULT_SATA_TXAMP		{ 0x8, 0x8, 0x8 }
+#define DEFAULT_SATA_TXCN1		{ 0x2, 0x2, 0x2 }
+#define DEFAULT_SATA_TXCN2		{ 0x0, 0x0, 0x0 }
+#define DEFAULT_SATA_TXCP1		{ 0xa, 0xa, 0xa }
+
+#define SATA_SPD_SEL_GEN3		0x7
+#define SATA_SPD_SEL_GEN2		0x3
+#define SATA_SPD_SEL_GEN1		0x1
+
+#define SSC_DISABLE			0
+#define SSC_ENABLE			1
+
+#define FBDIV_VAL_50M			0x77
+#define REFDIV_VAL_50M			0x1
+#define FBDIV_VAL_100M			0x3B
+#define REFDIV_VAL_100M			0x0
+
+/* SATA Clock/Reset CSR */
+#define SATACLKENREG			0x00000000
+#define  SATA0_CORE_CLKEN		0x00000002
+#define  SATA1_CORE_CLKEN		0x00000004
+#define SATASRESETREG			0x00000004
+#define  SATA_MEM_RESET_MASK		0x00000020
+#define  SATA_MEM_RESET_RD(src)		(((src) & 0x00000020) >> 5)
+#define  SATA_SDS_RESET_MASK		0x00000004
+#define  SATA_CSR_RESET_MASK		0x00000001
+#define  SATA_CORE_RESET_MASK		0x00000002
+#define  SATA_PMCLK_RESET_MASK		0x00000010
+#define  SATA_PCLK_RESET_MASK		0x00000008
+
+/* SDS CSR used for PHY Indirect access */
+#define SATA_ENET_SDS_PCS_CTL0		0x00000000
+#define  REGSPEC_CFG_I_TX_WORDMODE0_SET(dst, src) \
+		(((dst) & ~0x00070000) | (((u32) (src) << 16) & 0x00070000))
+#define  REGSPEC_CFG_I_RX_WORDMODE0_SET(dst, src) \
+		(((dst) & ~0x00e00000) | (((u32) (src) << 21) & 0x00e00000))
+#define SATA_ENET_SDS_CTL0		0x0000000c
+#define  REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(dst, src) \
+		(((dst) & ~0x00007fff) | (((u32) (src)) & 0x00007fff))
+#define SATA_ENET_SDS_CTL1		0x00000010
+#define  CFG_I_SPD_SEL_CDR_OVR1_SET(dst, src) \
+		(((dst) & ~0x0000000f) | (((u32) (src)) & 0x0000000f))
+#define SATA_ENET_SDS_RST_CTL		0x00000024
+#define SATA_ENET_SDS_IND_CMD_REG	0x0000003c
+#define  CFG_IND_WR_CMD_MASK		0x00000001
+#define  CFG_IND_RD_CMD_MASK		0x00000002
+#define  CFG_IND_CMD_DONE_MASK		0x00000004
+#define  CFG_IND_ADDR_SET(dst, src) \
+		(((dst) & ~0x003ffff0) | (((u32) (src) << 4) & 0x003ffff0))
+#define SATA_ENET_SDS_IND_RDATA_REG	0x00000040
+#define SATA_ENET_SDS_IND_WDATA_REG	0x00000044
+#define SATA_ENET_CLK_MACRO_REG		0x0000004c
+#define  I_RESET_B_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32) (src)) & 0x00000001))
+#define  I_PLL_FBDIV_SET(dst, src) \
+		(((dst) & ~0x001ff000) | (((u32) (src) << 12) & 0x001ff000))
+#define  I_CUSTOMEROV_SET(dst, src) \
+		(((dst) & ~0x00000f80) | (((u32) (src) << 7) & 0x00000f80))
+#define  O_PLL_LOCK_RD(src)		(((src) & 0x40000000) >> 30)
+#define  O_PLL_READY_RD(src)		(((src) & 0x80000000) >> 31)
+
+/* PLL Clock Macro Unit (CMU) CSR accessing from SDS indirectly */
+#define CMU_REG0			0x00000
+#define  CMU_REG0_PLL_REF_SEL_MASK	0x00002000
+#define  CMU_REG0_PLL_REF_SEL_SET(dst, src)	\
+		(((dst) & ~0x00002000) | (((u32) (src) << 13) & 0x00002000))
+#define  CMU_REG0_PDOWN_MASK		0x00004000
+#define  CMU_REG0_CAL_COUNT_RESOL_SET(dst, src) \
+		(((dst) & ~0x000000e0) | (((u32) (src) << 5) & 0x000000e0))
+#define CMU_REG1			0x00002
+#define  CMU_REG1_PLL_CP_SET(dst, src) \
+		(((dst) & ~0x00003c00) | (((u32) (src) << 10) & 0x00003c00))
+#define  CMU_REG1_PLL_MANUALCAL_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define  CMU_REG1_PLL_CP_SEL_SET(dst, src) \
+		(((dst) & ~0x000003e0) | (((u32) (src) << 5) & 0x000003e0))
+#define  CMU_REG1_REFCLK_CMOS_SEL_MASK	0x00000001
+#define  CMU_REG1_REFCLK_CMOS_SEL_SET(dst, src)	\
+		(((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define CMU_REG2			0x00004
+#define  CMU_REG2_PLL_REFDIV_SET(dst, src) \
+		(((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define  CMU_REG2_PLL_LFRES_SET(dst, src) \
+		(((dst) & ~0x0000001e) | (((u32) (src) << 1) & 0x0000001e))
+#define  CMU_REG2_PLL_FBDIV_SET(dst, src) \
+		(((dst) & ~0x00003fe0) | (((u32) (src) << 5) & 0x00003fe0))
+#define CMU_REG3			0x00006
+#define  CMU_REG3_VCOVARSEL_SET(dst, src) \
+		(((dst) & ~0x0000000f) | (((u32) (src) << 0) & 0x0000000f))
+#define  CMU_REG3_VCO_MOMSEL_INIT_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define  CMU_REG3_VCO_MANMOMSEL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define CMU_REG4			0x00008
+#define CMU_REG5			0x0000a
+#define  CMU_REG5_PLL_LFSMCAP_SET(dst, src) \
+		(((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define  CMU_REG5_PLL_LOCK_RESOLUTION_SET(dst, src) \
+		(((dst) & ~0x0000000e) | (((u32) (src) << 1) & 0x0000000e))
+#define  CMU_REG5_PLL_LFCAP_SET(dst, src) \
+		(((dst) & ~0x00003000) | (((u32) (src) << 12) & 0x00003000))
+#define  CMU_REG5_PLL_RESETB_MASK	0x00000001
+#define CMU_REG6			0x0000c
+#define  CMU_REG6_PLL_VREGTRIM_SET(dst, src) \
+		(((dst) & ~0x00000600) | (((u32) (src) << 9) & 0x00000600))
+#define  CMU_REG6_MAN_PVT_CAL_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define CMU_REG7			0x0000e
+#define  CMU_REG7_PLL_CALIB_DONE_RD(src) ((0x00004000 & (u32) (src)) >> 14)
+#define  CMU_REG7_VCO_CAL_FAIL_RD(src)	((0x00000c00 & (u32) (src)) >> 10)
+#define CMU_REG8			0x00010
+#define CMU_REG9			0x00012
+#define  CMU_REG9_WORD_LEN_8BIT		0x000
+#define  CMU_REG9_WORD_LEN_10BIT	0x001
+#define  CMU_REG9_WORD_LEN_16BIT	0x002
+#define  CMU_REG9_WORD_LEN_20BIT	0x003
+#define  CMU_REG9_WORD_LEN_32BIT	0x004
+#define  CMU_REG9_WORD_LEN_40BIT	0x005
+#define  CMU_REG9_WORD_LEN_64BIT	0x006
+#define  CMU_REG9_WORD_LEN_66BIT	0x007
+#define  CMU_REG9_TX_WORD_MODE_CH1_SET(dst, src) \
+		(((dst) & ~0x00000380) | (((u32) (src) << 7) & 0x00000380))
+#define  CMU_REG9_TX_WORD_MODE_CH0_SET(dst, src) \
+		(((dst) & ~0x00000070) | (((u32) (src) << 4) & 0x00000070))
+#define  CMU_REG9_PLL_POST_DIVBY2_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define  CMU_REG9_VBG_BYPASSB_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define  CMU_REG9_IGEN_BYPASS_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define CMU_REG10			0x00014
+#define  CMU_REG10_VREG_REFSEL_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define CMU_REG11			0x00016
+#define CMU_REG12			0x00018
+#define  CMU_REG12_STATE_DELAY9_SET(dst, src) \
+		(((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0))
+#define CMU_REG13			0x0001a
+#define CMU_REG14			0x0001c
+#define CMU_REG15			0x0001e
+#define CMU_REG16			0x00020
+#define  CMU_REG16_PVT_DN_MAN_ENA_MASK	0x00000001
+#define  CMU_REG16_PVT_UP_MAN_ENA_MASK	0x00000002
+#define  CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(dst, src) \
+		(((dst) & ~0x0000001c) | (((u32) (src) << 2) & 0x0000001c))
+#define  CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(dst, src) \
+		(((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define  CMU_REG16_BYPASS_PLL_LOCK_SET(dst, src) \
+		(((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020))
+#define CMU_REG17			0x00022
+#define  CMU_REG17_PVT_CODE_R2A_SET(dst, src) \
+		(((dst) & ~0x00007f00) | (((u32) (src) << 8) & 0x00007f00))
+#define  CMU_REG17_RESERVED_7_SET(dst, src) \
+		(((dst) & ~0x000000e0) | (((u32) (src) << 5) & 0x000000e0))
+#define  CMU_REG17_PVT_TERM_MAN_ENA_MASK	0x00008000
+#define CMU_REG18			0x00024
+#define CMU_REG19			0x00026
+#define CMU_REG20			0x00028
+#define CMU_REG21			0x0002a
+#define CMU_REG22			0x0002c
+#define CMU_REG23			0x0002e
+#define CMU_REG24			0x00030
+#define CMU_REG25			0x00032
+#define CMU_REG26			0x00034
+#define  CMU_REG26_FORCE_PLL_LOCK_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define CMU_REG27			0x00036
+#define CMU_REG28			0x00038
+#define CMU_REG29			0x0003a
+#define CMU_REG30			0x0003c
+#define  CMU_REG30_LOCK_COUNT_SET(dst, src) \
+		(((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006))
+#define  CMU_REG30_PCIE_MODE_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define CMU_REG31			0x0003e
+#define CMU_REG32			0x00040
+#define  CMU_REG32_FORCE_VCOCAL_START_MASK	0x00004000
+#define  CMU_REG32_PVT_CAL_WAIT_SEL_SET(dst, src) \
+		(((dst) & ~0x00000006) | (((u32) (src) << 1) & 0x00000006))
+#define  CMU_REG32_IREF_ADJ_SET(dst, src) \
+		(((dst) & ~0x00000180) | (((u32) (src) << 7) & 0x00000180))
+#define CMU_REG33			0x00042
+#define CMU_REG34			0x00044
+#define  CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(dst, src) \
+		(((dst) & ~0x0000000f) | (((u32) (src) << 0) & 0x0000000f))
+#define  CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(dst, src) \
+		(((dst) & ~0x00000f00) | (((u32) (src) << 8) & 0x00000f00))
+#define  CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(dst, src) \
+		(((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0))
+#define  CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(dst, src) \
+		(((dst) & ~0x0000f000) | (((u32) (src) << 12) & 0x0000f000))
+#define CMU_REG35			0x00046
+#define  CMU_REG35_PLL_SSC_MOD_SET(dst, src) \
+		(((dst) & ~0x0000fe00) | (((u32) (src) << 9) & 0x0000fe00))
+#define CMU_REG36				0x00048
+#define  CMU_REG36_PLL_SSC_EN_SET(dst, src) \
+		(((dst) & ~0x00000010) | (((u32) (src) << 4) & 0x00000010))
+#define  CMU_REG36_PLL_SSC_VSTEP_SET(dst, src) \
+		(((dst) & ~0x0000ffc0) | (((u32) (src) << 6) & 0x0000ffc0))
+#define  CMU_REG36_PLL_SSC_DSMSEL_SET(dst, src) \
+		(((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020))
+#define CMU_REG37			0x0004a
+#define CMU_REG38			0x0004c
+#define CMU_REG39			0x0004e
+
+/* PHY lane CSR accessing from SDS indirectly */
+#define RXTX_REG0			0x000
+#define  RXTX_REG0_CTLE_EQ_HR_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define  RXTX_REG0_CTLE_EQ_QR_SET(dst, src) \
+		(((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define  RXTX_REG0_CTLE_EQ_FR_SET(dst, src) \
+		(((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG1			0x002
+#define  RXTX_REG1_RXACVCM_SET(dst, src) \
+		(((dst) & ~0x0000f000) | (((u32) (src) << 12) & 0x0000f000))
+#define  RXTX_REG1_CTLE_EQ_SET(dst, src) \
+		(((dst) & ~0x00000f80) | (((u32) (src) << 7) & 0x00000f80))
+#define  RXTX_REG1_RXVREG1_SET(dst, src) \
+		(((dst) & ~0x00000060) | (((u32) (src) << 5) & 0x00000060))
+#define  RXTX_REG1_RXIREF_ADJ_SET(dst, src) \
+		(((dst) & ~0x00000006) | (((u32) (src) << 1) &  0x00000006))
+#define RXTX_REG2			0x004
+#define  RXTX_REG2_VTT_ENA_SET(dst, src) \
+		(((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define  RXTX_REG2_TX_FIFO_ENA_SET(dst, src) \
+		(((dst) & ~0x00000020) | (((u32) (src) << 5) & 0x00000020))
+#define  RXTX_REG2_VTT_SEL_SET(dst, src) \
+		(((dst) & ~0x000000c0) | (((u32) (src) << 6) & 0x000000c0))
+#define RXTX_REG4			0x008
+#define  RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK	0x00000040
+#define  RXTX_REG4_TX_DATA_RATE_SET(dst, src) \
+		(((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define  RXTX_REG4_TX_WORD_MODE_SET(dst, src) \
+		(((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG5			0x00a
+#define  RXTX_REG5_TX_CN1_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define  RXTX_REG5_TX_CP1_SET(dst, src) \
+		(((dst) & ~0x000007e0) | (((u32) (src) << 5) & 0x000007e0))
+#define  RXTX_REG5_TX_CN2_SET(dst, src) \
+		(((dst) & ~0x0000001f) | (((u32) (src) << 0) & 0x0000001f))
+#define RXTX_REG6			0x00c
+#define  RXTX_REG6_TXAMP_CNTL_SET(dst, src) \
+		(((dst) & ~0x00000780) | (((u32) (src) << 7) & 0x00000780))
+#define  RXTX_REG6_TXAMP_ENA_SET(dst, src) \
+		(((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define  RXTX_REG6_RX_BIST_ERRCNT_RD_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define  RXTX_REG6_TX_IDLE_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define  RXTX_REG6_RX_BIST_RESYNC_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG7			0x00e
+#define  RXTX_REG7_RESETB_RXD_MASK	0x00000100
+#define  RXTX_REG7_RESETB_RXA_MASK	0x00000080
+#define  RXTX_REG7_BIST_ENA_RX_SET(dst, src) \
+		(((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define  RXTX_REG7_RX_WORD_MODE_SET(dst, src) \
+		(((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG8			0x010
+#define  RXTX_REG8_CDR_LOOP_ENA_SET(dst, src) \
+		(((dst) & ~0x00004000) | (((u32) (src) << 14) & 0x00004000))
+#define  RXTX_REG8_CDR_BYPASS_RXLOS_SET(dst, src) \
+		(((dst) & ~0x00000800) | (((u32) (src) << 11) & 0x00000800))
+#define  RXTX_REG8_SSC_ENABLE_SET(dst, src) \
+		(((dst) & ~0x00000200) | (((u32) (src) << 9) & 0x00000200))
+#define  RXTX_REG8_SD_VREF_SET(dst, src) \
+		(((dst) & ~0x000000f0) | (((u32) (src) << 4) & 0x000000f0))
+#define  RXTX_REG8_SD_DISABLE_SET(dst, src) \
+		(((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define RXTX_REG7			0x00e
+#define  RXTX_REG7_RESETB_RXD_SET(dst, src) \
+		(((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define  RXTX_REG7_RESETB_RXA_SET(dst, src) \
+		(((dst) & ~0x00000080) | (((u32) (src) << 7) & 0x00000080))
+#define  RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK	0x00004000
+#define  RXTX_REG7_LOOP_BACK_ENA_CTLE_SET(dst, src) \
+		(((dst) & ~0x00004000) | (((u32) (src) << 14) & 0x00004000))
+#define RXTX_REG11			0x016
+#define  RXTX_REG11_PHASE_ADJUST_LIMIT_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define RXTX_REG12			0x018
+#define  RXTX_REG12_LATCH_OFF_ENA_SET(dst, src) \
+		(((dst) & ~0x00002000) | (((u32) (src) << 13) & 0x00002000))
+#define  RXTX_REG12_SUMOS_ENABLE_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define  RXTX_REG12_RX_DET_TERM_ENABLE_MASK	0x00000002
+#define  RXTX_REG12_RX_DET_TERM_ENABLE_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG13			0x01a
+#define RXTX_REG14			0x01c
+#define  RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(dst, src) \
+		(((dst) & ~0x0000003f) | (((u32) (src) << 0) & 0x0000003f))
+#define  RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(dst, src) \
+		(((dst) & ~0x00000040) | (((u32) (src) << 6) & 0x00000040))
+#define RXTX_REG26			0x034
+#define  RXTX_REG26_PERIOD_ERROR_LATCH_SET(dst, src) \
+		(((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define  RXTX_REG26_BLWC_ENA_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define RXTX_REG21			0x02a
+#define  RXTX_REG21_DO_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define  RXTX_REG21_XO_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define  RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(src)	((0x0000000f & (u32)(src)))
+#define RXTX_REG22			0x02c
+#define  RXTX_REG22_SO_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define  RXTX_REG22_EO_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define  RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(src)	((0x0000000f & (u32)(src)))
+#define RXTX_REG23			0x02e
+#define  RXTX_REG23_DE_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define  RXTX_REG23_XE_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG24			0x030
+#define  RXTX_REG24_EE_LATCH_CALOUT_RD(src) ((0x0000fc00 & (u32) (src)) >> 10)
+#define  RXTX_REG24_SE_LATCH_CALOUT_RD(src) ((0x000003f0 & (u32) (src)) >> 4)
+#define RXTX_REG27			0x036
+#define RXTX_REG28			0x038
+#define RXTX_REG31			0x03e
+#define RXTX_REG38			0x04c
+#define  RXTX_REG38_CUSTOMER_PINMODE_INV_SET(dst, src) \
+		(((dst) & 0x0000fffe) | (((u32) (src) << 1) & 0x0000fffe))
+#define RXTX_REG39			0x04e
+#define RXTX_REG40			0x050
+#define RXTX_REG41			0x052
+#define RXTX_REG42			0x054
+#define RXTX_REG43			0x056
+#define RXTX_REG44			0x058
+#define RXTX_REG45			0x05a
+#define RXTX_REG46			0x05c
+#define RXTX_REG47			0x05e
+#define RXTX_REG48			0x060
+#define RXTX_REG49			0x062
+#define RXTX_REG50			0x064
+#define RXTX_REG51			0x066
+#define RXTX_REG52			0x068
+#define RXTX_REG53			0x06a
+#define RXTX_REG54			0x06c
+#define RXTX_REG55			0x06e
+#define RXTX_REG61			0x07a
+#define  RXTX_REG61_ISCAN_INBERT_SET(dst, src) \
+		(((dst) & ~0x00000010) | (((u32) (src) << 4) & 0x00000010))
+#define  RXTX_REG61_LOADFREQ_SHIFT_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define  RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(dst, src) \
+		(((dst) & ~0x000000c0) | (((u32) (src) << 6) & 0x000000c0))
+#define  RXTX_REG61_SPD_SEL_CDR_SET(dst, src) \
+		(((dst) & ~0x00003c00) | (((u32) (src) << 10) & 0x00003c00))
+#define RXTX_REG62			0x07c
+#define  RXTX_REG62_PERIOD_H1_QLATCH_SET(dst, src) \
+		(((dst) & ~0x00003800) | (((u32) (src) << 11) & 0x00003800))
+#define RXTX_REG81			0x0a2
+#define  RXTX_REG89_MU_TH7_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define  RXTX_REG89_MU_TH8_SET(dst, src) \
+		(((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define  RXTX_REG89_MU_TH9_SET(dst, src) \
+		(((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG96			0x0c0
+#define  RXTX_REG96_MU_FREQ1_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define  RXTX_REG96_MU_FREQ2_SET(dst, src) \
+		(((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define  RXTX_REG96_MU_FREQ3_SET(dst, src) \
+		(((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG99			0x0c6
+#define  RXTX_REG99_MU_PHASE1_SET(dst, src) \
+		(((dst) & ~0x0000f800) | (((u32) (src) << 11) & 0x0000f800))
+#define  RXTX_REG99_MU_PHASE2_SET(dst, src) \
+		(((dst) & ~0x000007c0) | (((u32) (src) << 6) & 0x000007c0))
+#define  RXTX_REG99_MU_PHASE3_SET(dst, src) \
+		(((dst) & ~0x0000003e) | (((u32) (src) << 1) & 0x0000003e))
+#define RXTX_REG102			0x0cc
+#define  RXTX_REG102_FREQLOOP_LIMIT_SET(dst, src) \
+		(((dst) & ~0x00000060) | (((u32) (src) << 5) & 0x00000060))
+#define RXTX_REG114			0x0e4
+#define RXTX_REG121			0x0f2
+#define  RXTX_REG121_SUMOS_CAL_CODE_RD(src) ((0x0000003e & (u32)(src)) >> 0x1)
+#define RXTX_REG125			0x0fa
+#define  RXTX_REG125_PQ_REG_SET(dst, src) \
+		(((dst) & ~0x0000fe00) | (((u32) (src) << 9) & 0x0000fe00))
+#define  RXTX_REG125_SIGN_PQ_SET(dst, src) \
+		(((dst) & ~0x00000100) | (((u32) (src) << 8) & 0x00000100))
+#define  RXTX_REG125_SIGN_PQ_2C_SET(dst, src) \
+		(((dst) & ~0x00000080) | (((u32) (src) << 7) & 0x00000080))
+#define  RXTX_REG125_PHZ_MANUALCODE_SET(dst, src) \
+		(((dst) & ~0x0000007c) | (((u32) (src) << 2) & 0x0000007c))
+#define  RXTX_REG125_PHZ_MANUAL_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define RXTX_REG127			0x0fe
+#define  RXTX_REG127_FORCE_SUM_CAL_START_MASK	0x00000002
+#define  RXTX_REG127_FORCE_LAT_CAL_START_MASK	0x00000004
+#define  RXTX_REG127_FORCE_SUM_CAL_START_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define  RXTX_REG127_FORCE_LAT_CAL_START_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define  RXTX_REG127_LATCH_MAN_CAL_ENA_SET(dst, src) \
+		(((dst) & ~0x00000008) | (((u32) (src) << 3) & 0x00000008))
+#define  RXTX_REG127_DO_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define  RXTX_REG127_XO_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG128			0x100
+#define  RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(dst, src) \
+		(((dst) & ~0x0000000c) | (((u32) (src) << 2) & 0x0000000c))
+#define  RXTX_REG128_EO_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define  RXTX_REG128_SO_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG129			0x102
+#define  RXTX_REG129_DE_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define  RXTX_REG129_XE_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG130			0x104
+#define  RXTX_REG130_EE_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x0000fc00) | (((u32) (src) << 10) & 0x0000fc00))
+#define  RXTX_REG130_SE_LATCH_MANCAL_SET(dst, src) \
+		(((dst) & ~0x000003f0) | (((u32) (src) << 4) & 0x000003f0))
+#define RXTX_REG145			0x122
+#define  RXTX_REG145_TX_IDLE_SATA_SET(dst, src) \
+		(((dst) & ~0x00000001) | (((u32) (src) << 0) & 0x00000001))
+#define  RXTX_REG145_RXES_ENA_SET(dst, src) \
+		(((dst) & ~0x00000002) | (((u32) (src) << 1) & 0x00000002))
+#define  RXTX_REG145_RXDFE_CONFIG_SET(dst, src) \
+		(((dst) & ~0x0000c000) | (((u32) (src) << 14) & 0x0000c000))
+#define  RXTX_REG145_RXVWES_LATENA_SET(dst, src) \
+		(((dst) & ~0x00000004) | (((u32) (src) << 2) & 0x00000004))
+#define RXTX_REG147			0x126
+#define RXTX_REG148			0x128
+
+/* Clock macro type */
+enum cmu_type_t {
+	REF_CMU = 0,	/* Clock macro is the internal reference clock */
+	PHY_CMU = 1,	/* Clock macro is the PLL for the Serdes */
+};
+
+enum mux_type_t {
+	MUX_SELECT_ATA = 0,	/* Switch the MUX to ATA */
+	MUX_SELECT_SGMMII = 0,	/* Switch the MUX to SGMII */
+};
+
+enum clk_type_t {
+	CLK_EXT_DIFF = 0,	/* External differential */
+	CLK_INT_DIFF = 1,	/* Internal differential */
+	CLK_INT_SING = 2,	/* Internal single ended */
+};
+
+enum phy_mode {
+	MODE_SATA	= 0,	/* List them for simple reference */
+	MODE_SGMII	= 1,
+	MODE_PCIE	= 2,
+	MODE_USB	= 3,
+	MODE_XFI	= 4,
+	MODE_MAX
+};
+
+struct xgene_sata_override_param {
+	u32 speed[MAX_LANE]; /* Index for override parameter per lane */
+	u32 txspeed[3];			/* Tx speed */
+	u32 txboostgain[MAX_LANE*3];	/* Tx freq boost and gain control */
+	u32 txeyetuning[MAX_LANE*3];	/* Tx eye tuning */
+	u32 txeyedirection[MAX_LANE*3]; /* Tx eye tuning direction */
+	u32 txamplitude[MAX_LANE*3];	/* Tx amplitude control */
+	u32 txprecursor_cn1[MAX_LANE*3]; /* Tx emphasis taps 1st pre-cursor */
+	u32 txprecursor_cn2[MAX_LANE*3]; /* Tx emphasis taps 2nd pre-cursor */
+	u32 txpostcursor_cp1[MAX_LANE*3]; /* Tx emphasis taps post-cursor */
+};
+
+struct xgene_phy_ctx {
+	struct device *dev;
+	struct phy *phy;
+	enum phy_mode mode;		/* Mode of operation */
+	enum clk_type_t clk_type;	/* Input clock selection */
+	void __iomem *sds_base;		/* PHY CSR base addr */
+	struct clk *clk;		/* Optional clock */
+
+	/* Override Serdes parameters */
+	struct xgene_sata_override_param sata_param;
+};
+
+/*
+ * For chip earlier than A3 version, enable this flag.
+ * To enable, pass boot argument phy_xgene.preA3Chip=1
+ */
+static int preA3Chip;
+MODULE_PARM_DESC(preA3Chip, "Enable pre-A3 chip support (1=enable 0=disable)");
+module_param_named(preA3Chip, preA3Chip, int, 0444);
+
+static void sds_wr(void __iomem *csr_base, u32 indirect_cmd_reg,
+		   u32 indirect_data_reg, u32 addr, u32 data)
+{
+	unsigned long deadline = jiffies + HZ;
+	u32 val;
+	u32 cmd;
+
+	cmd = CFG_IND_WR_CMD_MASK | CFG_IND_CMD_DONE_MASK;
+	cmd = CFG_IND_ADDR_SET(cmd, addr);
+	writel(data, csr_base + indirect_data_reg);
+	readl(csr_base + indirect_data_reg); /* Force a barrier */
+	writel(cmd, csr_base + indirect_cmd_reg);
+	readl(csr_base + indirect_cmd_reg); /* Force a barrier */
+	do {
+		val = readl(csr_base + indirect_cmd_reg);
+	} while (!(val & CFG_IND_CMD_DONE_MASK) &&
+		 time_before(jiffies, deadline));
+	if (!(val & CFG_IND_CMD_DONE_MASK))
+		pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n",
+		       csr_base + indirect_cmd_reg, addr, data);
+}
+
+static void sds_rd(void __iomem *csr_base, u32 indirect_cmd_reg,
+		   u32 indirect_data_reg, u32 addr, u32 *data)
+{
+	unsigned long deadline = jiffies + HZ;
+	u32 val;
+	u32 cmd;
+
+	cmd = CFG_IND_RD_CMD_MASK | CFG_IND_CMD_DONE_MASK;
+	cmd = CFG_IND_ADDR_SET(cmd, addr);
+	writel(cmd, csr_base + indirect_cmd_reg);
+	readl(csr_base + indirect_cmd_reg); /* Force a barrier */
+	do {
+		val = readl(csr_base + indirect_cmd_reg);
+	} while (!(val & CFG_IND_CMD_DONE_MASK) &&
+		 time_before(jiffies, deadline));
+	*data = readl(csr_base + indirect_data_reg);
+	if (!(val & CFG_IND_CMD_DONE_MASK))
+		pr_err("SDS WR timeout at 0x%p offset 0x%08X value 0x%08X\n",
+		       csr_base + indirect_cmd_reg, addr, *data);
+}
+
+static void cmu_wr(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+		   u32 reg, u32 data)
+{
+	void __iomem *sds_base = ctx->sds_base;
+	u32 val;
+
+	if (cmu_type == REF_CMU)
+		reg += SERDES_PLL_REF_INDIRECT_OFFSET;
+	else
+		reg += SERDES_PLL_INDIRECT_OFFSET;
+	sds_wr(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+		SATA_ENET_SDS_IND_WDATA_REG, reg, data);
+	sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+		SATA_ENET_SDS_IND_RDATA_REG, reg, &val);
+	pr_debug("CMU WR addr 0x%X value 0x%08X <-> 0x%08X\n", reg, data, val);
+}
+
+static void cmu_rd(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+		   u32 reg, u32 *data)
+{
+	void __iomem *sds_base = ctx->sds_base;
+
+	if (cmu_type == REF_CMU)
+		reg += SERDES_PLL_REF_INDIRECT_OFFSET;
+	else
+		reg += SERDES_PLL_INDIRECT_OFFSET;
+	sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+		SATA_ENET_SDS_IND_RDATA_REG, reg, data);
+	pr_debug("CMU RD addr 0x%X value 0x%08X\n", reg, *data);
+}
+
+static void cmu_toggle1to0(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+			   u32 reg, u32 bits)
+{
+	u32 val;
+
+	cmu_rd(ctx, cmu_type, reg, &val);
+	val |= bits;
+	cmu_wr(ctx, cmu_type, reg, val);
+	cmu_rd(ctx, cmu_type, reg, &val);
+	val &= ~bits;
+	cmu_wr(ctx, cmu_type, reg, val);
+}
+
+static void cmu_clrbits(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+			u32 reg, u32 bits)
+{
+	u32 val;
+
+	cmu_rd(ctx, cmu_type, reg, &val);
+	val &= ~bits;
+	cmu_wr(ctx, cmu_type, reg, val);
+}
+
+static void cmu_setbits(struct xgene_phy_ctx *ctx, enum cmu_type_t cmu_type,
+			u32 reg, u32 bits)
+{
+	u32 val;
+
+	cmu_rd(ctx, cmu_type, reg, &val);
+	val |= bits;
+	cmu_wr(ctx, cmu_type, reg, val);
+}
+
+static void serdes_wr(struct xgene_phy_ctx *ctx, int lane, u32 reg, u32 data)
+{
+	void __iomem *sds_base = ctx->sds_base;
+	u32 val;
+
+	reg += SERDES_INDIRECT_OFFSET;
+	reg += lane * SERDES_LANE_STRIDE;
+	sds_wr(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+	       SATA_ENET_SDS_IND_WDATA_REG, reg, data);
+	sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+	       SATA_ENET_SDS_IND_RDATA_REG, reg, &val);
+	pr_debug("SERDES WR addr 0x%X value 0x%08X <-> 0x%08X\n", reg, data,
+		 val);
+}
+
+static void serdes_rd(struct xgene_phy_ctx *ctx, int lane, u32 reg, u32 *data)
+{
+	void __iomem *sds_base = ctx->sds_base;
+
+	reg += SERDES_INDIRECT_OFFSET;
+	reg += lane * SERDES_LANE_STRIDE;
+	sds_rd(sds_base, SATA_ENET_SDS_IND_CMD_REG,
+	       SATA_ENET_SDS_IND_RDATA_REG, reg, data);
+	pr_debug("SERDES RD addr 0x%X value 0x%08X\n", reg, *data);
+}
+
+static void serdes_clrbits(struct xgene_phy_ctx *ctx, int lane, u32 reg,
+			   u32 bits)
+{
+	u32 val;
+
+	serdes_rd(ctx, lane, reg, &val);
+	val &= ~bits;
+	serdes_wr(ctx, lane, reg, val);
+}
+
+static void serdes_setbits(struct xgene_phy_ctx *ctx, int lane, u32 reg,
+			   u32 bits)
+{
+	u32 val;
+
+	serdes_rd(ctx, lane, reg, &val);
+	val |= bits;
+	serdes_wr(ctx, lane, reg, val);
+}
+
+static void xgene_phy_cfg_cmu_clk_type(struct xgene_phy_ctx *ctx,
+				       enum cmu_type_t cmu_type,
+				       enum clk_type_t clk_type)
+{
+	u32 val;
+
+	/* Set the reset sequence delay for TX ready assertion */
+	cmu_rd(ctx, cmu_type, CMU_REG12, &val);
+	val = CMU_REG12_STATE_DELAY9_SET(val, 0x1);
+	cmu_wr(ctx, cmu_type, CMU_REG12, val);
+	/* Set the programmable stage delays between various enable stages */
+	cmu_wr(ctx, cmu_type, CMU_REG13, 0x0222);
+	cmu_wr(ctx, cmu_type, CMU_REG14, 0x2225);
+
+	/* Configure clock type */
+	if (clk_type == CLK_EXT_DIFF) {
+		/* Select external clock mux */
+		cmu_rd(ctx, cmu_type, CMU_REG0, &val);
+		val = CMU_REG0_PLL_REF_SEL_SET(val, 0x0);
+		cmu_wr(ctx, cmu_type, CMU_REG0, val);
+		/* Select CMOS as reference clock  */
+		cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+		val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x0);
+		cmu_wr(ctx, cmu_type, CMU_REG1, val);
+		dev_dbg(ctx->dev, "Set external reference clock\n");
+	} else if (clk_type == CLK_INT_DIFF) {
+		/* Select internal clock mux */
+		cmu_rd(ctx, cmu_type, CMU_REG0, &val);
+		val = CMU_REG0_PLL_REF_SEL_SET(val, 0x1);
+		cmu_wr(ctx, cmu_type, CMU_REG0, val);
+		/* Select CMOS as reference clock  */
+		cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+		val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1);
+		cmu_wr(ctx, cmu_type, CMU_REG1, val);
+		dev_dbg(ctx->dev, "Set internal reference clock\n");
+	} else if (clk_type == CLK_INT_SING) {
+		/*
+		 * NOTE: This clock type is NOT support for controller
+		 *	 whose internal clock shared in the PCIe controller
+		 *
+		 * Select internal clock mux
+		 */
+		cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+		val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x1);
+		cmu_wr(ctx, cmu_type, CMU_REG1, val);
+		/* Select CML as reference clock */
+		cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+		val = CMU_REG1_REFCLK_CMOS_SEL_SET(val, 0x0);
+		cmu_wr(ctx, cmu_type, CMU_REG1, val);
+		dev_dbg(ctx->dev,
+			"Set internal single ended reference clock\n");
+	}
+}
+
+static void xgene_phy_sata_cfg_cmu_core(struct xgene_phy_ctx *ctx,
+					enum cmu_type_t cmu_type,
+					enum clk_type_t clk_type)
+{
+	u32 val;
+	int ref_100MHz;
+
+	if (cmu_type == REF_CMU) {
+		/* Set VCO calibration voltage threshold */
+		cmu_rd(ctx, cmu_type, CMU_REG34, &val);
+		val = CMU_REG34_VCO_CAL_VTH_LO_MAX_SET(val, 0x7);
+		val = CMU_REG34_VCO_CAL_VTH_HI_MAX_SET(val, 0xc);
+		val = CMU_REG34_VCO_CAL_VTH_LO_MIN_SET(val, 0x3);
+		val = CMU_REG34_VCO_CAL_VTH_HI_MIN_SET(val, 0x8);
+		cmu_wr(ctx, cmu_type, CMU_REG34, val);
+	}
+
+	/* Set the VCO calibration counter */
+	cmu_rd(ctx, cmu_type, CMU_REG0, &val);
+	if (cmu_type == REF_CMU || preA3Chip)
+		val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x4);
+	else
+		val = CMU_REG0_CAL_COUNT_RESOL_SET(val, 0x7);
+	cmu_wr(ctx, cmu_type, CMU_REG0, val);
+
+	/* Configure PLL for calibration */
+	cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+	val = CMU_REG1_PLL_CP_SET(val, 0x1);
+	if (cmu_type == REF_CMU || preA3Chip)
+		val = CMU_REG1_PLL_CP_SEL_SET(val, 0x5);
+	else
+		val = CMU_REG1_PLL_CP_SEL_SET(val, 0x3);
+	if (cmu_type == REF_CMU)
+		val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0);
+	else
+		val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x1);
+	cmu_wr(ctx, cmu_type, CMU_REG1, val);
+
+	if (cmu_type != REF_CMU)
+		cmu_clrbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+
+	/* Configure the PLL for either 100MHz or 50MHz */
+	cmu_rd(ctx, cmu_type, CMU_REG2, &val);
+	if (cmu_type == REF_CMU) {
+		val = CMU_REG2_PLL_LFRES_SET(val, 0xa);
+		ref_100MHz = 1;
+	} else {
+		val = CMU_REG2_PLL_LFRES_SET(val, 0x3);
+		if (clk_type == CLK_EXT_DIFF)
+			ref_100MHz = 0;
+		else
+			ref_100MHz = 1;
+	}
+	if (ref_100MHz) {
+		val = CMU_REG2_PLL_FBDIV_SET(val, FBDIV_VAL_100M);
+		val = CMU_REG2_PLL_REFDIV_SET(val, REFDIV_VAL_100M);
+	} else {
+		val = CMU_REG2_PLL_FBDIV_SET(val, FBDIV_VAL_50M);
+		val = CMU_REG2_PLL_REFDIV_SET(val, REFDIV_VAL_50M);
+	}
+	cmu_wr(ctx, cmu_type, CMU_REG2, val);
+
+	/* Configure the VCO */
+	cmu_rd(ctx, cmu_type, CMU_REG3, &val);
+	if (cmu_type == REF_CMU) {
+		val = CMU_REG3_VCOVARSEL_SET(val, 0x3);
+		val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x10);
+	} else {
+		val = CMU_REG3_VCOVARSEL_SET(val, 0xF);
+		if (preA3Chip)
+			val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x15);
+		else
+			val = CMU_REG3_VCO_MOMSEL_INIT_SET(val, 0x1a);
+		val = CMU_REG3_VCO_MANMOMSEL_SET(val, 0x15);
+	}
+	cmu_wr(ctx, cmu_type, CMU_REG3, val);
+
+	/* Disable force PLL lock */
+	cmu_rd(ctx, cmu_type, CMU_REG26, &val);
+	val = CMU_REG26_FORCE_PLL_LOCK_SET(val, 0x0);
+	cmu_wr(ctx, cmu_type, CMU_REG26, val);
+
+	/* Setup PLL loop filter */
+	cmu_rd(ctx, cmu_type, CMU_REG5, &val);
+	val = CMU_REG5_PLL_LFSMCAP_SET(val, 0x3);
+	val = CMU_REG5_PLL_LFCAP_SET(val, 0x3);
+	if (cmu_type == REF_CMU || !preA3Chip)
+		val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x7);
+	else
+		val = CMU_REG5_PLL_LOCK_RESOLUTION_SET(val, 0x4);
+	cmu_wr(ctx, cmu_type, CMU_REG5, val);
+
+	/* Enable or disable manual calibration */
+	cmu_rd(ctx, cmu_type, CMU_REG6, &val);
+	val = CMU_REG6_PLL_VREGTRIM_SET(val, preA3Chip ? 0x0 : 0x2);
+	val = CMU_REG6_MAN_PVT_CAL_SET(val, preA3Chip ? 0x1 : 0x0);
+	cmu_wr(ctx, cmu_type, CMU_REG6, val);
+
+	/* Configure lane for 20-bits */
+	if (cmu_type == PHY_CMU) {
+		cmu_rd(ctx, cmu_type, CMU_REG9, &val);
+		val = CMU_REG9_TX_WORD_MODE_CH1_SET(val,
+						    CMU_REG9_WORD_LEN_20BIT);
+		val = CMU_REG9_TX_WORD_MODE_CH0_SET(val,
+						    CMU_REG9_WORD_LEN_20BIT);
+		val = CMU_REG9_PLL_POST_DIVBY2_SET(val, 0x1);
+		if (!preA3Chip) {
+			val = CMU_REG9_VBG_BYPASSB_SET(val, 0x0);
+			val = CMU_REG9_IGEN_BYPASS_SET(val , 0x0);
+		}
+		cmu_wr(ctx, cmu_type, CMU_REG9, val);
+
+		if (!preA3Chip) {
+			cmu_rd(ctx, cmu_type, CMU_REG10, &val);
+			val = CMU_REG10_VREG_REFSEL_SET(val, 0x1);
+			cmu_wr(ctx, cmu_type, CMU_REG10, val);
+		}
+	}
+
+	cmu_rd(ctx, cmu_type, CMU_REG16, &val);
+	val = CMU_REG16_CALIBRATION_DONE_OVERRIDE_SET(val, 0x1);
+	val = CMU_REG16_BYPASS_PLL_LOCK_SET(val, 0x1);
+	if (cmu_type == REF_CMU || preA3Chip)
+		val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x4);
+	else
+		val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x7);
+	cmu_wr(ctx, cmu_type, CMU_REG16, val);
+
+	/* Configure for SATA */
+	cmu_rd(ctx, cmu_type, CMU_REG30, &val);
+	val = CMU_REG30_PCIE_MODE_SET(val, 0x0);
+	val = CMU_REG30_LOCK_COUNT_SET(val, 0x3);
+	cmu_wr(ctx, cmu_type, CMU_REG30, val);
+
+	/* Disable state machine bypass */
+	cmu_wr(ctx, cmu_type, CMU_REG31, 0xF);
+
+	cmu_rd(ctx, cmu_type, CMU_REG32, &val);
+	val = CMU_REG32_PVT_CAL_WAIT_SEL_SET(val, 0x3);
+	if (cmu_type == REF_CMU || preA3Chip)
+		val = CMU_REG32_IREF_ADJ_SET(val, 0x3);
+	else
+		val = CMU_REG32_IREF_ADJ_SET(val, 0x1);
+	cmu_wr(ctx, cmu_type, CMU_REG32, val);
+
+	/* Set VCO calibration threshold */
+	if (cmu_type != REF_CMU && preA3Chip)
+		cmu_wr(ctx, cmu_type, CMU_REG34, 0x8d27);
+	else
+		cmu_wr(ctx, cmu_type, CMU_REG34, 0x873c);
+
+	/* Set CTLE Override and override waiting from state machine */
+	cmu_wr(ctx, cmu_type, CMU_REG37, 0xF00F);
+}
+
+static void xgene_phy_ssc_enable(struct xgene_phy_ctx *ctx,
+				 enum cmu_type_t cmu_type)
+{
+	u32 val;
+
+	/* Set SSC modulation value */
+	cmu_rd(ctx, cmu_type, CMU_REG35, &val);
+	val = CMU_REG35_PLL_SSC_MOD_SET(val, 98);
+	cmu_wr(ctx, cmu_type, CMU_REG35, val);
+
+	/* Enable SSC, set vertical step and DSM value */
+	cmu_rd(ctx, cmu_type, CMU_REG36, &val);
+	val = CMU_REG36_PLL_SSC_VSTEP_SET(val, 30);
+	val = CMU_REG36_PLL_SSC_EN_SET(val, 1);
+	val = CMU_REG36_PLL_SSC_DSMSEL_SET(val, 1);
+	cmu_wr(ctx, cmu_type, CMU_REG36, val);
+
+	/* Reset the PLL */
+	cmu_clrbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+	cmu_setbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+
+	/* Force VCO calibration to restart */
+	cmu_toggle1to0(ctx, cmu_type, CMU_REG32,
+		       CMU_REG32_FORCE_VCOCAL_START_MASK);
+}
+
+static void xgene_phy_sata_cfg_lanes(struct xgene_phy_ctx *ctx)
+{
+	u32 val;
+	u32 reg;
+	int i;
+	int lane;
+
+	for (lane = 0; lane < MAX_LANE; lane++) {
+		serdes_wr(ctx, lane, RXTX_REG147, 0x6);
+
+		/* Set boost control for quarter, half, and full rate */
+		serdes_rd(ctx, lane, RXTX_REG0, &val);
+		val = RXTX_REG0_CTLE_EQ_HR_SET(val, 0x10);
+		val = RXTX_REG0_CTLE_EQ_QR_SET(val, 0x10);
+		val = RXTX_REG0_CTLE_EQ_FR_SET(val, 0x10);
+		serdes_wr(ctx, lane, RXTX_REG0, val);
+
+		/* Set boost control value */
+		serdes_rd(ctx, lane, RXTX_REG1, &val);
+		val = RXTX_REG1_RXACVCM_SET(val, 0x7);
+		val = RXTX_REG1_CTLE_EQ_SET(val,
+			ctx->sata_param.txboostgain[lane * 3 +
+			ctx->sata_param.speed[lane]]);
+		serdes_wr(ctx, lane, RXTX_REG1, val);
+
+		/* Latch VTT value based on the termination to ground and
+		   enable TX FIFO */
+		serdes_rd(ctx, lane, RXTX_REG2, &val);
+		val = RXTX_REG2_VTT_ENA_SET(val, 0x1);
+		val = RXTX_REG2_VTT_SEL_SET(val, 0x1);
+		val = RXTX_REG2_TX_FIFO_ENA_SET(val, 0x1);
+		serdes_wr(ctx, lane, RXTX_REG2, val);
+
+		/* Configure Tx for 20-bits */
+		serdes_rd(ctx, lane, RXTX_REG4, &val);
+		val = RXTX_REG4_TX_WORD_MODE_SET(val, CMU_REG9_WORD_LEN_20BIT);
+		serdes_wr(ctx, lane, RXTX_REG4, val);
+
+		if (!preA3Chip) {
+			serdes_rd(ctx, lane, RXTX_REG1, &val);
+			val = RXTX_REG1_RXVREG1_SET(val, 0x2);
+			val = RXTX_REG1_RXIREF_ADJ_SET(val, 0x2);
+			serdes_wr(ctx, lane, RXTX_REG1, val);
+		}
+
+		/* Set pre-emphasis first 1 and 2, and post-emphasis values */
+		serdes_rd(ctx, lane, RXTX_REG5, &val);
+		val = RXTX_REG5_TX_CN1_SET(val,
+			ctx->sata_param.txprecursor_cn1[lane * 3 +
+			ctx->sata_param.speed[lane]]);
+		val = RXTX_REG5_TX_CP1_SET(val,
+			ctx->sata_param.txpostcursor_cp1[lane * 3 +
+			ctx->sata_param.speed[lane]]);
+		val = RXTX_REG5_TX_CN2_SET(val,
+			ctx->sata_param.txprecursor_cn2[lane * 3 +
+			ctx->sata_param.speed[lane]]);
+		serdes_wr(ctx, lane, RXTX_REG5, val);
+
+		/* Set TX amplitude value */
+		serdes_rd(ctx, lane, RXTX_REG6, &val);
+		val = RXTX_REG6_TXAMP_CNTL_SET(val,
+			ctx->sata_param.txamplitude[lane * 3 +
+			ctx->sata_param.speed[lane]]);
+		val = RXTX_REG6_TXAMP_ENA_SET(val, 0x1);
+		val = RXTX_REG6_TX_IDLE_SET(val, 0x0);
+		val = RXTX_REG6_RX_BIST_RESYNC_SET(val, 0x0);
+		val = RXTX_REG6_RX_BIST_ERRCNT_RD_SET(val, 0x0);
+		serdes_wr(ctx, lane, RXTX_REG6, val);
+
+		/* Configure Rx for 20-bits */
+		serdes_rd(ctx, lane, RXTX_REG7, &val);
+		val = RXTX_REG7_BIST_ENA_RX_SET(val, 0x0);
+		val = RXTX_REG7_RX_WORD_MODE_SET(val, CMU_REG9_WORD_LEN_20BIT);
+		serdes_wr(ctx, lane, RXTX_REG7, val);
+
+		/* Set CDR and LOS values and enable Rx SSC */
+		serdes_rd(ctx, lane, RXTX_REG8, &val);
+		val = RXTX_REG8_CDR_LOOP_ENA_SET(val, 0x1);
+		val = RXTX_REG8_CDR_BYPASS_RXLOS_SET(val, 0x0);
+		val = RXTX_REG8_SSC_ENABLE_SET(val, 0x1);
+		val = RXTX_REG8_SD_DISABLE_SET(val, 0x0);
+		val = RXTX_REG8_SD_VREF_SET(val, 0x4);
+		serdes_wr(ctx, lane, RXTX_REG8, val);
+
+		/* Set phase adjust upper/lower limits */
+		serdes_rd(ctx, lane, RXTX_REG11, &val);
+		val = RXTX_REG11_PHASE_ADJUST_LIMIT_SET(val, 0x0);
+		serdes_wr(ctx, lane, RXTX_REG11, val);
+
+		/* Enable Latch Off; disable SUMOS and Tx termination */
+		serdes_rd(ctx, lane, RXTX_REG12, &val);
+		val = RXTX_REG12_LATCH_OFF_ENA_SET(val, 0x1);
+		val = RXTX_REG12_SUMOS_ENABLE_SET(val, 0x0);
+		val = RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0x0);
+		serdes_wr(ctx, lane, RXTX_REG12, val);
+
+		/* Set period error latch to 512T and enable BWL */
+		serdes_rd(ctx, lane, RXTX_REG26, &val);
+		val = RXTX_REG26_PERIOD_ERROR_LATCH_SET(val, 0x0);
+		val = RXTX_REG26_BLWC_ENA_SET(val, 0x1);
+		serdes_wr(ctx, lane, RXTX_REG26, val);
+
+		serdes_wr(ctx, lane, RXTX_REG28, 0x0);
+
+		/* Set DFE loop preset value */
+		serdes_wr(ctx, lane, RXTX_REG31, 0x0);
+
+		/* Set Eye Monitor counter width to 12-bit */
+		serdes_rd(ctx, lane, RXTX_REG61, &val);
+		val = RXTX_REG61_ISCAN_INBERT_SET(val, 0x1);
+		val = RXTX_REG61_LOADFREQ_SHIFT_SET(val, 0x0);
+		val = RXTX_REG61_EYE_COUNT_WIDTH_SEL_SET(val, 0x0);
+		serdes_wr(ctx, lane, RXTX_REG61, val);
+
+		serdes_rd(ctx, lane, RXTX_REG62, &val);
+		val = RXTX_REG62_PERIOD_H1_QLATCH_SET(val, 0x0);
+		serdes_wr(ctx, lane, RXTX_REG62, val);
+
+		/* Set BW select tap X for DFE loop */
+		for (i = 0; i < 9; i++) {
+			reg = RXTX_REG81 + i * 2;
+			serdes_rd(ctx, lane, reg, &val);
+			val = RXTX_REG89_MU_TH7_SET(val, 0xe);
+			val = RXTX_REG89_MU_TH8_SET(val, 0xe);
+			val = RXTX_REG89_MU_TH9_SET(val, 0xe);
+			serdes_wr(ctx, lane, reg, val);
+		}
+
+		/* Set BW select tap X for frequency adjust loop */
+		for (i = 0; i < 3; i++) {
+			reg = RXTX_REG96 + i * 2;
+			serdes_rd(ctx, lane, reg, &val);
+			val = RXTX_REG96_MU_FREQ1_SET(val, 0x10);
+			val = RXTX_REG96_MU_FREQ2_SET(val, 0x10);
+			val = RXTX_REG96_MU_FREQ3_SET(val, 0x10);
+			serdes_wr(ctx, lane, reg, val);
+		}
+
+		/* Set BW select tap X for phase adjust loop */
+		for (i = 0; i < 3; i++) {
+			reg = RXTX_REG99 + i * 2;
+			serdes_rd(ctx, lane, reg, &val);
+			val = RXTX_REG99_MU_PHASE1_SET(val, 0x7);
+			val = RXTX_REG99_MU_PHASE2_SET(val, 0x7);
+			val = RXTX_REG99_MU_PHASE3_SET(val, 0x7);
+			serdes_wr(ctx, lane, reg, val);
+		}
+
+		serdes_rd(ctx, lane, RXTX_REG102, &val);
+		val = RXTX_REG102_FREQLOOP_LIMIT_SET(val, 0x0);
+		serdes_wr(ctx, lane, RXTX_REG102, val);
+
+		serdes_wr(ctx, lane, RXTX_REG114, 0xffe0);
+
+		serdes_rd(ctx, lane, RXTX_REG125, &val);
+		val = RXTX_REG125_SIGN_PQ_SET(val,
+			ctx->sata_param.txeyedirection[lane * 3 +
+			ctx->sata_param.speed[lane]]);
+		val = RXTX_REG125_PQ_REG_SET(val,
+			ctx->sata_param.txeyetuning[lane * 3 +
+			ctx->sata_param.speed[lane]]);
+		val = RXTX_REG125_PHZ_MANUAL_SET(val, 0x1);
+		serdes_wr(ctx, lane, RXTX_REG125, val);
+
+		serdes_rd(ctx, lane, RXTX_REG127, &val);
+		val = RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x0);
+		serdes_wr(ctx, lane, RXTX_REG127, val);
+
+		serdes_rd(ctx, lane, RXTX_REG128, &val);
+		val = RXTX_REG128_LATCH_CAL_WAIT_SEL_SET(val, 0x3);
+		serdes_wr(ctx, lane, RXTX_REG128, val);
+
+		serdes_rd(ctx, lane, RXTX_REG145, &val);
+		val = RXTX_REG145_RXDFE_CONFIG_SET(val, 0x3);
+		val = RXTX_REG145_TX_IDLE_SATA_SET(val, 0x0);
+		if (preA3Chip) {
+			val = RXTX_REG145_RXES_ENA_SET(val, 0x1);
+			val = RXTX_REG145_RXVWES_LATENA_SET(val, 0x1);
+		} else {
+			val = RXTX_REG145_RXES_ENA_SET(val, 0x0);
+			val = RXTX_REG145_RXVWES_LATENA_SET(val, 0x0);
+		}
+		serdes_wr(ctx, lane, RXTX_REG145, val);
+
+		/*
+		 * Set Rx LOS filter clock rate, sample rate, and threshold
+		 * windows
+		 */
+		for (i = 0; i < 4; i++) {
+			reg = RXTX_REG148 + i * 2;
+			serdes_wr(ctx, lane, reg, 0xFFFF);
+		}
+	}
+}
+
+static int xgene_phy_cal_rdy_chk(struct xgene_phy_ctx *ctx,
+				 enum cmu_type_t cmu_type,
+				 enum clk_type_t clk_type)
+{
+	void __iomem *csr_serdes = ctx->sds_base;
+	int loop;
+	u32 val;
+
+	/* Release PHY main reset */
+	writel(0xdf, csr_serdes + SATA_ENET_SDS_RST_CTL);
+	readl(csr_serdes + SATA_ENET_SDS_RST_CTL); /* Force a barrier */
+
+	if (cmu_type != REF_CMU) {
+		cmu_setbits(ctx, cmu_type, CMU_REG5, CMU_REG5_PLL_RESETB_MASK);
+		/*
+		 * As per PHY design spec, the PLL reset requires a minimum
+		 * of 800us.
+		 */
+		usleep_range(800, 1000);
+
+		cmu_rd(ctx, cmu_type, CMU_REG1, &val);
+		val = CMU_REG1_PLL_MANUALCAL_SET(val, 0x0);
+		cmu_wr(ctx, cmu_type, CMU_REG1, val);
+		/*
+		 * As per PHY design spec, the PLL auto calibration requires
+		 * a minimum of 800us.
+		 */
+		usleep_range(800, 1000);
+
+		cmu_toggle1to0(ctx, cmu_type, CMU_REG32,
+			       CMU_REG32_FORCE_VCOCAL_START_MASK);
+		/*
+		 * As per PHY design spec, the PLL requires a minimum of
+		 * 800us to settle.
+		 */
+		usleep_range(800, 1000);
+	}
+
+	if (!preA3Chip)
+		goto skip_manual_cal;
+
+	/*
+	 * Configure the termination resister calibration
+	 * The serial receive pins, RXP/RXN, have TERMination resistor
+	 * that is required to be calibrated.
+	 */
+	cmu_rd(ctx, cmu_type, CMU_REG17, &val);
+	val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x12);
+	val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+	cmu_wr(ctx, cmu_type, CMU_REG17, val);
+	cmu_toggle1to0(ctx, cmu_type, CMU_REG17,
+		       CMU_REG17_PVT_TERM_MAN_ENA_MASK);
+	/*
+	 * The serial transmit pins, TXP/TXN, have Pull-UP and Pull-DOWN
+	 * resistors that are required to the calibrated.
+	 * Configure the pull DOWN calibration
+	 */
+	cmu_rd(ctx, cmu_type, CMU_REG17, &val);
+	val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x29);
+	val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+	cmu_wr(ctx, cmu_type, CMU_REG17, val);
+	cmu_toggle1to0(ctx, cmu_type, CMU_REG16,
+		       CMU_REG16_PVT_DN_MAN_ENA_MASK);
+	/* Configure the pull UP calibration */
+	cmu_rd(ctx, cmu_type, CMU_REG17, &val);
+	val = CMU_REG17_PVT_CODE_R2A_SET(val, 0x28);
+	val = CMU_REG17_RESERVED_7_SET(val, 0x0);
+	cmu_wr(ctx, cmu_type, CMU_REG17, val);
+	cmu_toggle1to0(ctx, cmu_type, CMU_REG16,
+		       CMU_REG16_PVT_UP_MAN_ENA_MASK);
+
+skip_manual_cal:
+	/* Poll the PLL calibration completion status for at least 1 ms */
+	loop = 100;
+	do {
+		cmu_rd(ctx, cmu_type, CMU_REG7, &val);
+		if (CMU_REG7_PLL_CALIB_DONE_RD(val))
+			break;
+		/*
+		 * As per PHY design spec, PLL calibration status requires
+		 * a minimum of 10us to be updated.
+		 */
+		usleep_range(10, 100);
+	} while (--loop > 0);
+
+	cmu_rd(ctx, cmu_type, CMU_REG7, &val);
+	dev_dbg(ctx->dev, "PLL calibration %s\n",
+		CMU_REG7_PLL_CALIB_DONE_RD(val) ? "done" : "failed");
+	if (CMU_REG7_VCO_CAL_FAIL_RD(val)) {
+		dev_err(ctx->dev,
+			"PLL calibration failed due to VCO failure\n");
+		return -1;
+	}
+	dev_dbg(ctx->dev, "PLL calibration successful\n");
+
+	cmu_rd(ctx, cmu_type, CMU_REG15, &val);
+	dev_dbg(ctx->dev, "PHY Tx is %sready\n", val & 0x300 ? "" : "not ");
+	return 0;
+}
+
+static void xgene_phy_pdwn_force_vco(struct xgene_phy_ctx *ctx,
+				     enum cmu_type_t cmu_type,
+				     enum clk_type_t clk_type)
+{
+	u32 val;
+
+	dev_dbg(ctx->dev, "Reset VCO and re-start again\n");
+	if (cmu_type == PHY_CMU) {
+		cmu_rd(ctx, cmu_type, CMU_REG16, &val);
+		val = CMU_REG16_VCOCAL_WAIT_BTW_CODE_SET(val, 0x7);
+		cmu_wr(ctx, cmu_type, CMU_REG16, val);
+	}
+
+	cmu_toggle1to0(ctx, cmu_type, CMU_REG0, CMU_REG0_PDOWN_MASK);
+	cmu_toggle1to0(ctx, cmu_type, CMU_REG32,
+		       CMU_REG32_FORCE_VCOCAL_START_MASK);
+}
+
+static int xgene_phy_hw_init_sata(struct xgene_phy_ctx *ctx,
+				  enum clk_type_t clk_type, int ssc_enable)
+{
+	void __iomem *sds_base = ctx->sds_base;
+	u32 val;
+	int i;
+
+	/* Configure the PHY for operation */
+	dev_dbg(ctx->dev, "Reset PHY\n");
+	/* Place PHY into reset */
+	writel(0x0, sds_base + SATA_ENET_SDS_RST_CTL);
+	val = readl(sds_base + SATA_ENET_SDS_RST_CTL);	/* Force a barrier */
+	/* Release PHY lane from reset (active high) */
+	writel(0x20, sds_base + SATA_ENET_SDS_RST_CTL);
+	readl(sds_base + SATA_ENET_SDS_RST_CTL);	/* Force a barrier */
+	/* Release all PHY module out of reset except PHY main reset */
+	writel(0xde, sds_base + SATA_ENET_SDS_RST_CTL);
+	readl(sds_base + SATA_ENET_SDS_RST_CTL);	/* Force a barrier */
+
+	/* Set the operation speed */
+	val = readl(sds_base + SATA_ENET_SDS_CTL1);
+	val = CFG_I_SPD_SEL_CDR_OVR1_SET(val,
+		ctx->sata_param.txspeed[ctx->sata_param.speed[0]]);
+	writel(val, sds_base + SATA_ENET_SDS_CTL1);
+
+	dev_dbg(ctx->dev, "Set the customer pin mode to SATA\n");
+	val = readl(sds_base + SATA_ENET_SDS_CTL0);
+	val = REGSPEC_CFG_I_CUSTOMER_PIN_MODE0_SET(val, 0x4421);
+	writel(val, sds_base + SATA_ENET_SDS_CTL0);
+
+	/* Configure the clock macro unit (CMU) clock type */
+	xgene_phy_cfg_cmu_clk_type(ctx, PHY_CMU, clk_type);
+
+	/* Configure the clock macro */
+	xgene_phy_sata_cfg_cmu_core(ctx, PHY_CMU, clk_type);
+
+	/* Enable SSC if enabled */
+	if (ssc_enable)
+		xgene_phy_ssc_enable(ctx, PHY_CMU);
+
+	/* Configure PHY lanes */
+	xgene_phy_sata_cfg_lanes(ctx);
+
+	/* Set Rx/Tx 20-bit */
+	val = readl(sds_base + SATA_ENET_SDS_PCS_CTL0);
+	val = REGSPEC_CFG_I_RX_WORDMODE0_SET(val, 0x3);
+	val = REGSPEC_CFG_I_TX_WORDMODE0_SET(val, 0x3);
+	writel(val, sds_base + SATA_ENET_SDS_PCS_CTL0);
+
+	/* Start PLL calibration and try for three times */
+	i = 10;
+	do {
+		if (!xgene_phy_cal_rdy_chk(ctx, PHY_CMU, clk_type))
+			break;
+		/* If failed, toggle the VCO power signal and start again */
+		xgene_phy_pdwn_force_vco(ctx, PHY_CMU, clk_type);
+	} while (--i > 0);
+	/* Even on failure, allow to continue any way */
+	if (i <= 0)
+		dev_err(ctx->dev, "PLL calibration failed\n");
+
+	return 0;
+}
+
+static int xgene_phy_hw_initialize(struct xgene_phy_ctx *ctx,
+				   enum clk_type_t clk_type,
+				   int ssc_enable)
+{
+	int rc;
+
+	dev_dbg(ctx->dev, "PHY init clk type %d\n", clk_type);
+
+	if (ctx->mode == MODE_SATA) {
+		rc = xgene_phy_hw_init_sata(ctx, clk_type, ssc_enable);
+		if (rc)
+			return rc;
+	} else {
+		dev_err(ctx->dev, "Un-supported customer pin mode %d\n",
+			ctx->mode);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/*
+ * Receiver Offset Calibration:
+ *
+ * Calibrate the receiver signal path offset in two steps - summar and
+ * latch calibrations
+ */
+static void xgene_phy_force_lat_summer_cal(struct xgene_phy_ctx *ctx, int lane)
+{
+	int i;
+	struct {
+		u32 reg;
+		u32 val;
+	} serdes_reg[] = {
+		{RXTX_REG38, 0x0},
+		{RXTX_REG39, 0xff00},
+		{RXTX_REG40, 0xffff},
+		{RXTX_REG41, 0xffff},
+		{RXTX_REG42, 0xffff},
+		{RXTX_REG43, 0xffff},
+		{RXTX_REG44, 0xffff},
+		{RXTX_REG45, 0xffff},
+		{RXTX_REG46, 0xffff},
+		{RXTX_REG47, 0xfffc},
+		{RXTX_REG48, 0x0},
+		{RXTX_REG49, 0x0},
+		{RXTX_REG50, 0x0},
+		{RXTX_REG51, 0x0},
+		{RXTX_REG52, 0x0},
+		{RXTX_REG53, 0x0},
+		{RXTX_REG54, 0x0},
+		{RXTX_REG55, 0x0},
+	};
+
+	/* Start SUMMER calibration */
+	serdes_setbits(ctx, lane, RXTX_REG127,
+		       RXTX_REG127_FORCE_SUM_CAL_START_MASK);
+	/*
+	 * As per PHY design spec, the Summer calibration requires a minimum
+	 * of 100us to complete.
+	 */
+	usleep_range(100, 500);
+	serdes_clrbits(ctx, lane, RXTX_REG127,
+			RXTX_REG127_FORCE_SUM_CAL_START_MASK);
+	/*
+	 * As per PHY design spec, the auto calibration requires a minimum
+	 * of 100us to complete.
+	 */
+	usleep_range(100, 500);
+
+	/* Start latch calibration */
+	serdes_setbits(ctx, lane, RXTX_REG127,
+		       RXTX_REG127_FORCE_LAT_CAL_START_MASK);
+	/*
+	 * As per PHY design spec, the latch calibration requires a minimum
+	 * of 100us to complete.
+	 */
+	usleep_range(100, 500);
+	serdes_clrbits(ctx, lane, RXTX_REG127,
+		       RXTX_REG127_FORCE_LAT_CAL_START_MASK);
+
+	/* Configure the PHY lane for calibration */
+	serdes_wr(ctx, lane, RXTX_REG28, 0x7);
+	serdes_wr(ctx, lane, RXTX_REG31, 0x7e00);
+	serdes_clrbits(ctx, lane, RXTX_REG4,
+		       RXTX_REG4_TX_LOOPBACK_BUF_EN_MASK);
+	serdes_clrbits(ctx, lane, RXTX_REG7,
+		       RXTX_REG7_LOOP_BACK_ENA_CTLE_MASK);
+	for (i = 0; i < ARRAY_SIZE(serdes_reg); i++)
+		serdes_wr(ctx, lane, serdes_reg[i].reg,
+			  serdes_reg[i].val);
+}
+
+static void xgene_phy_reset_rxd(struct xgene_phy_ctx *ctx, int lane)
+{
+	/* Reset digital Rx */
+	serdes_clrbits(ctx, lane, RXTX_REG7, RXTX_REG7_RESETB_RXD_MASK);
+	/* As per PHY design spec, the reset requires a minimum of 100us. */
+	usleep_range(100, 150);
+	serdes_setbits(ctx, lane, RXTX_REG7, RXTX_REG7_RESETB_RXD_MASK);
+}
+
+static int xgene_phy_get_avg(int accum, int samples)
+{
+	return (accum + (samples / 2)) / samples;
+}
+
+static void xgene_phy_gen_avg_val(struct xgene_phy_ctx *ctx, int lane)
+{
+	int max_loop = 10;
+	int avg_loop = 0;
+	int lat_do = 0, lat_xo = 0, lat_eo = 0, lat_so = 0;
+	int lat_de = 0, lat_xe = 0, lat_ee = 0, lat_se = 0;
+	int sum_cal = 0;
+	int lat_do_itr, lat_xo_itr, lat_eo_itr, lat_so_itr;
+	int lat_de_itr, lat_xe_itr, lat_ee_itr, lat_se_itr;
+	int sum_cal_itr;
+	int fail_even;
+	int fail_odd;
+	u32 val;
+
+	dev_dbg(ctx->dev, "Generating avg calibration value for lane %d\n",
+		lane);
+
+	/* Enable RX Hi-Z termination */
+	serdes_setbits(ctx, lane, RXTX_REG12,
+			RXTX_REG12_RX_DET_TERM_ENABLE_MASK);
+	/* Turn off DFE */
+	serdes_wr(ctx, lane, RXTX_REG28, 0x0000);
+	/* DFE Presets to zero */
+	serdes_wr(ctx, lane, RXTX_REG31, 0x0000);
+
+	/*
+	 * Receiver Offset Calibration:
+	 * Calibrate the receiver signal path offset in two steps - summar
+	 * and latch calibration.
+	 * Runs the "Receiver Offset Calibration multiple times to determine
+	 * the average value to use.
+	 */
+	while (avg_loop < max_loop) {
+		/* Start the calibration */
+		xgene_phy_force_lat_summer_cal(ctx, lane);
+
+		serdes_rd(ctx, lane, RXTX_REG21, &val);
+		lat_do_itr = RXTX_REG21_DO_LATCH_CALOUT_RD(val);
+		lat_xo_itr = RXTX_REG21_XO_LATCH_CALOUT_RD(val);
+		fail_odd = RXTX_REG21_LATCH_CAL_FAIL_ODD_RD(val);
+
+		serdes_rd(ctx, lane, RXTX_REG22, &val);
+		lat_eo_itr = RXTX_REG22_EO_LATCH_CALOUT_RD(val);
+		lat_so_itr = RXTX_REG22_SO_LATCH_CALOUT_RD(val);
+		fail_even = RXTX_REG22_LATCH_CAL_FAIL_EVEN_RD(val);
+
+		serdes_rd(ctx, lane, RXTX_REG23, &val);
+		lat_de_itr = RXTX_REG23_DE_LATCH_CALOUT_RD(val);
+		lat_xe_itr = RXTX_REG23_XE_LATCH_CALOUT_RD(val);
+
+		serdes_rd(ctx, lane, RXTX_REG24, &val);
+		lat_ee_itr = RXTX_REG24_EE_LATCH_CALOUT_RD(val);
+		lat_se_itr = RXTX_REG24_SE_LATCH_CALOUT_RD(val);
+
+		serdes_rd(ctx, lane, RXTX_REG121, &val);
+		sum_cal_itr = RXTX_REG121_SUMOS_CAL_CODE_RD(val);
+
+		/* Check for failure. If passed, sum them for averaging */
+		if ((fail_even == 0 || fail_even == 1) &&
+		    (fail_odd == 0 || fail_odd == 1)) {
+			lat_do += lat_do_itr;
+			lat_xo += lat_xo_itr;
+			lat_eo += lat_eo_itr;
+			lat_so += lat_so_itr;
+			lat_de += lat_de_itr;
+			lat_xe += lat_xe_itr;
+			lat_ee += lat_ee_itr;
+			lat_se += lat_se_itr;
+			sum_cal += sum_cal_itr;
+
+			dev_dbg(ctx->dev, "Iteration %d:\n", avg_loop);
+			dev_dbg(ctx->dev, "DO 0x%x XO 0x%x EO 0x%x SO 0x%x\n",
+				lat_do_itr, lat_xo_itr, lat_eo_itr,
+				lat_so_itr);
+			dev_dbg(ctx->dev, "DE 0x%x XE 0x%x EE 0x%x SE 0x%x\n",
+				lat_de_itr, lat_xe_itr, lat_ee_itr,
+				lat_se_itr);
+			dev_dbg(ctx->dev, "SUM 0x%x\n", sum_cal_itr);
+			++avg_loop;
+		} else {
+			dev_err(ctx->dev,
+				"Receiver calibration failed at %d loop\n",
+				avg_loop);
+		}
+		xgene_phy_reset_rxd(ctx, lane);
+	}
+
+	/* Update latch manual calibration with average value */
+	serdes_rd(ctx, lane, RXTX_REG127, &val);
+	val = RXTX_REG127_DO_LATCH_MANCAL_SET(val,
+		xgene_phy_get_avg(lat_do, max_loop));
+	val = RXTX_REG127_XO_LATCH_MANCAL_SET(val,
+		xgene_phy_get_avg(lat_xo, max_loop));
+	serdes_wr(ctx, lane, RXTX_REG127, val);
+
+	serdes_rd(ctx, lane, RXTX_REG128, &val);
+	val = RXTX_REG128_EO_LATCH_MANCAL_SET(val,
+		xgene_phy_get_avg(lat_eo, max_loop));
+	val = RXTX_REG128_SO_LATCH_MANCAL_SET(val,
+		xgene_phy_get_avg(lat_so, max_loop));
+	serdes_wr(ctx, lane, RXTX_REG128, val);
+
+	serdes_rd(ctx, lane, RXTX_REG129, &val);
+	val = RXTX_REG129_DE_LATCH_MANCAL_SET(val,
+		xgene_phy_get_avg(lat_de, max_loop));
+	val = RXTX_REG129_XE_LATCH_MANCAL_SET(val,
+		xgene_phy_get_avg(lat_xe, max_loop));
+	serdes_wr(ctx, lane, RXTX_REG129, val);
+
+	serdes_rd(ctx, lane, RXTX_REG130, &val);
+	val = RXTX_REG130_EE_LATCH_MANCAL_SET(val,
+		xgene_phy_get_avg(lat_ee, max_loop));
+	val = RXTX_REG130_SE_LATCH_MANCAL_SET(val,
+		xgene_phy_get_avg(lat_se, max_loop));
+	serdes_wr(ctx, lane, RXTX_REG130, val);
+
+	/* Update SUMMER calibration with average value */
+	serdes_rd(ctx, lane, RXTX_REG14, &val);
+	val = RXTX_REG14_CLTE_LATCAL_MAN_PROG_SET(val,
+		xgene_phy_get_avg(sum_cal, max_loop));
+	serdes_wr(ctx, lane, RXTX_REG14, val);
+
+	dev_dbg(ctx->dev, "Average Value:\n");
+	dev_dbg(ctx->dev, "DO 0x%x XO 0x%x EO 0x%x SO 0x%x\n",
+		 xgene_phy_get_avg(lat_do, max_loop),
+		 xgene_phy_get_avg(lat_xo, max_loop),
+		 xgene_phy_get_avg(lat_eo, max_loop),
+		 xgene_phy_get_avg(lat_so, max_loop));
+	dev_dbg(ctx->dev, "DE 0x%x XE 0x%x EE 0x%x SE 0x%x\n",
+		 xgene_phy_get_avg(lat_de, max_loop),
+		 xgene_phy_get_avg(lat_xe, max_loop),
+		 xgene_phy_get_avg(lat_ee, max_loop),
+		 xgene_phy_get_avg(lat_se, max_loop));
+	dev_dbg(ctx->dev, "SUM 0x%x\n",
+		xgene_phy_get_avg(sum_cal, max_loop));
+
+	serdes_rd(ctx, lane, RXTX_REG14, &val);
+	val = RXTX_REG14_CTLE_LATCAL_MAN_ENA_SET(val, 0x1);
+	serdes_wr(ctx, lane, RXTX_REG14, val);
+	dev_dbg(ctx->dev, "Enable Manual Summer calibration\n");
+
+	serdes_rd(ctx, lane, RXTX_REG127, &val);
+	val = RXTX_REG127_LATCH_MAN_CAL_ENA_SET(val, 0x1);
+	dev_dbg(ctx->dev, "Enable Manual Latch calibration\n");
+	serdes_wr(ctx, lane, RXTX_REG127, val);
+
+	/* Disable RX Hi-Z termination */
+	serdes_rd(ctx, lane, RXTX_REG12, &val);
+	val = RXTX_REG12_RX_DET_TERM_ENABLE_SET(val, 0);
+	serdes_wr(ctx, lane, RXTX_REG12, val);
+	/* Turn on DFE */
+	serdes_wr(ctx, lane, RXTX_REG28, 0x0007);
+	/* Set DFE preset */
+	serdes_wr(ctx, lane, RXTX_REG31, 0x7e00);
+}
+
+static int xgene_phy_hw_init(struct phy *phy)
+{
+	struct xgene_phy_ctx *ctx = phy_get_drvdata(phy);
+	int rc;
+	int i;
+
+	rc = xgene_phy_hw_initialize(ctx, CLK_EXT_DIFF, SSC_DISABLE);
+	if (rc) {
+		dev_err(ctx->dev, "PHY initialize failed %d\n", rc);
+		return rc;
+	}
+
+	/* Setup clock properly after PHY configuration */
+	if (!IS_ERR(ctx->clk)) {
+		/* HW requires an toggle of the clock */
+		clk_prepare_enable(ctx->clk);
+		clk_disable_unprepare(ctx->clk);
+		clk_prepare_enable(ctx->clk);
+	}
+
+	/* Compute average value */
+	for (i = 0; i < MAX_LANE; i++)
+		xgene_phy_gen_avg_val(ctx, i);
+
+	dev_dbg(ctx->dev, "PHY initialized\n");
+	return 0;
+}
+
+static const struct phy_ops xgene_phy_ops = {
+	.init		= xgene_phy_hw_init,
+	.owner		= THIS_MODULE,
+};
+
+static struct phy *xgene_phy_xlate(struct device *dev,
+				   struct of_phandle_args *args)
+{
+	struct xgene_phy_ctx *ctx = dev_get_drvdata(dev);
+
+	if (args->args_count <= 0)
+		return ERR_PTR(-EINVAL);
+	if (args->args[0] < MODE_SATA || args->args[0] >= MODE_MAX)
+		return ERR_PTR(-EINVAL);
+
+	ctx->mode = args->args[0];
+	return ctx->phy;
+}
+
+static void xgene_phy_get_param(struct platform_device *pdev,
+				const char *name, u32 *buffer,
+				int count, u32 *default_val,
+				u32 conv_factor)
+{
+	int i;
+
+	if (!of_property_read_u32_array(pdev->dev.of_node, name, buffer,
+					count)) {
+		for (i = 0; i < count; i++)
+			buffer[i] /= conv_factor;
+		return;
+	}
+	/* Does not exist, load default */
+	for (i = 0; i < count; i++)
+		buffer[i] = default_val[i % 3];
+}
+
+static int xgene_phy_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct xgene_phy_ctx *ctx;
+	struct resource *res;
+	int rc = 0;
+	u32 default_spd[] = DEFAULT_SATA_SPD_SEL;
+	u32 default_txboost_gain[] = DEFAULT_SATA_TXBOOST_GAIN;
+	u32 default_txeye_direction[] = DEFAULT_SATA_TXEYEDIRECTION;
+	u32 default_txeye_tuning[] = DEFAULT_SATA_TXEYETUNING;
+	u32 default_txamp[] = DEFAULT_SATA_TXAMP;
+	u32 default_txcn1[] = DEFAULT_SATA_TXCN1;
+	u32 default_txcn2[] = DEFAULT_SATA_TXCN2;
+	u32 default_txcp1[] = DEFAULT_SATA_TXCP1;
+	int i;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ctx->sds_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->sds_base)) {
+		rc = PTR_ERR(ctx->sds_base);
+		goto error;
+	}
+
+	/* Retrieve optional clock */
+	ctx->clk = clk_get(&pdev->dev, NULL);
+
+	/* Load override paramaters */
+	xgene_phy_get_param(pdev, "apm,tx-eye-tuning",
+		ctx->sata_param.txeyetuning, 6, default_txeye_tuning, 1);
+	xgene_phy_get_param(pdev, "apm,tx-eye-direction",
+		ctx->sata_param.txeyedirection, 6, default_txeye_direction, 1);
+	xgene_phy_get_param(pdev, "apm,tx-boost-gain",
+		ctx->sata_param.txboostgain, 6, default_txboost_gain, 1);
+	xgene_phy_get_param(pdev, "apm,tx-amplitude",
+		ctx->sata_param.txamplitude, 6, default_txamp, 13300);
+	xgene_phy_get_param(pdev, "apm,tx-pre-cursor1",
+		ctx->sata_param.txprecursor_cn1, 6, default_txcn1, 18200);
+	xgene_phy_get_param(pdev, "apm,tx-pre-cursor2",
+		ctx->sata_param.txprecursor_cn2, 6, default_txcn2, 18200);
+	xgene_phy_get_param(pdev, "apm,tx-post-cursor",
+		ctx->sata_param.txpostcursor_cp1, 6, default_txcp1, 18200);
+	xgene_phy_get_param(pdev, "apm,tx-speed",
+		ctx->sata_param.txspeed, 3, default_spd, 1);
+	for (i = 0; i < MAX_LANE; i++)
+		ctx->sata_param.speed[i] = 2; /* Default to Gen3 */
+
+	ctx->dev = &pdev->dev;
+	platform_set_drvdata(pdev, ctx);
+
+	ctx->phy = devm_phy_create(ctx->dev, &xgene_phy_ops, NULL);
+	if (IS_ERR(ctx->phy)) {
+		dev_dbg(&pdev->dev, "Failed to create PHY\n");
+		rc = PTR_ERR(ctx->phy);
+		goto error;
+	}
+	phy_set_drvdata(ctx->phy, ctx);
+
+	phy_provider = devm_of_phy_provider_register(ctx->dev,
+						     xgene_phy_xlate);
+	if (IS_ERR(phy_provider)) {
+		rc = PTR_ERR(phy_provider);
+		goto error;
+	}
+
+	return 0;
+
+error:
+	return rc;
+}
+
+static const struct of_device_id xgene_phy_of_match[] = {
+	{.compatible = "apm,xgene-phy",},
+	{},
+};
+MODULE_DEVICE_TABLE(of, xgene_phy_of_match);
+
+static struct platform_driver xgene_phy_driver = {
+	.probe = xgene_phy_probe,
+	.driver = {
+		   .name = "xgene-phy",
+		   .owner = THIS_MODULE,
+		   .of_match_table = xgene_phy_of_match,
+	},
+};
+module_platform_driver(xgene_phy_driver);
+
+MODULE_DESCRIPTION("APM X-Gene Multi-Purpose PHY driver");
+MODULE_AUTHOR("Loc Ho <lho@apm.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1");
-- 
1.7.9.5


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

* Re: [GIT PULL 00/28] PHY for 3.15
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (27 preceding siblings ...)
  2014-03-08  9:29 ` [PATCH 28/28] PHY: add APM X-Gene SoC 15Gbps Multi-purpose PHY driver Kishon Vijay Abraham I
@ 2014-03-08 16:42 ` Greg KH
  2014-03-09  7:35   ` Kishon Vijay Abraham I
  2014-03-09  7:27 ` [PATCH 16/28 v2] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x Kishon Vijay Abraham I
  29 siblings, 1 reply; 35+ messages in thread
From: Greg KH @ 2014-03-08 16:42 UTC (permalink / raw
  To: Kishon Vijay Abraham I; +Cc: linux-kernel, linux-usb, Felipe Balbi

On Sat, Mar 08, 2014 at 02:59:01PM +0530, Kishon Vijay Abraham I wrote:
> Hi Greg,
> 
> Here's the PULL REQUEST for 3.15 merge window.
> More users are starting to use the generic PHY framework including USB and
> SATA PHY in exynos, USB in sunxi and multi-purpose PHY (currently only SATA)
> in APM. There is also a patch to adapt USB3 PHY driver (PIPE3) used in OMAP
> to generic PHY framework and use the same driver for SATA.
> It also includes few fixes and cleanups.
> 
> Please let me know if you want me to make any changes.
> 
> Cheers
> Kishon
> 
> The following changes since commit cfbf8d4857c26a8a307fb7cd258074c9dcd8c691:
> 
>   Linux 3.14-rc4 (2014-02-23 17:40:03 -0800)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git tags/for_3.15
> 
> for you to fetch changes up to 303fd52cda953d14dc82ac82b570761599eb9ab2:
> 
>   PHY: add APM X-Gene SoC 15Gbps Multi-purpose PHY driver (2014-03-08 12:39:51 +0530)

When merging this with my usb-next tree, I get the following merge
issue, which I don't know how to resolve:
CONFLICT (modify/delete): Documentation/devicetree/bindings/usb/usb-phy.txt deleted in HEAD and modified in a0100026249158ec7aae606b553efae7cb37f616. Version a0100026249158ec7aae606b553efae7cb37f616 of Documentation/devicetree/bindings/usb/usb-phy.txt left in tree.

Any suggestions as to what I should do here?

thanks,

greg k-h


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

* [PATCH 16/28 v2] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x
  2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
                   ` (28 preceding siblings ...)
  2014-03-08 16:42 ` [GIT PULL 00/28] PHY for 3.15 Greg KH
@ 2014-03-09  7:27 ` Kishon Vijay Abraham I
  2014-03-09  7:27   ` [PATCH 17/28 v2] phy: omap-usb2: Provide workaround for USB2PHY false disconnect Kishon Vijay Abraham I
  2014-03-09  7:27   ` [PATCH 18/28 v2] phy: omap-usb2: Add different compatible for OMAP5 Kishon Vijay Abraham I
  29 siblings, 2 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-09  7:27 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: George Cherian <george.cherian@ti.com>

Adapt phy-omap-usb2 driver for AM437x.
	- Add new comaptible "ti,am437x-usb2" for AM437x
	- Pass proper data to differentiate AM437x and others.
	- AM437x doesnot support  set_vbus and start_srp.

Signed-off-by: George Cherian <george.cherian@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
Changes from v1:
removed the Documentation since the name of the file got modified in usb tree.

 drivers/phy/phy-omap-usb2.c  |   49 +++++++++++++++++++++++++++++++-----------
 include/linux/phy/omap_usb.h |    9 ++++++++
 2 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 9c3f056..0c78f54 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -122,6 +122,31 @@ static struct phy_ops ops = {
 	.owner		= THIS_MODULE,
 };
 
+#ifdef CONFIG_OF
+static const struct usb_phy_data omap_usb2_data = {
+	.label = "omap_usb2",
+	.flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
+};
+
+static const struct usb_phy_data am437x_usb2_data = {
+	.label = "am437x_usb2",
+	.flags =  0,
+};
+
+static const struct of_device_id omap_usb2_id_table[] = {
+	{
+		.compatible = "ti,omap-usb2",
+		.data = &omap_usb2_data,
+	},
+	{
+		.compatible = "ti,am437x-usb2",
+		.data = &am437x_usb2_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
+#endif
+
 static int omap_usb2_probe(struct platform_device *pdev)
 {
 	struct omap_usb	*phy;
@@ -131,10 +156,16 @@ static int omap_usb2_probe(struct platform_device *pdev)
 	struct device_node *node = pdev->dev.of_node;
 	struct device_node *control_node;
 	struct platform_device *control_pdev;
+	const struct of_device_id *of_id;
+	struct usb_phy_data *phy_data;
+
+	of_id = of_match_device(of_match_ptr(omap_usb2_id_table), &pdev->dev);
 
-	if (!node)
+	if (!of_id)
 		return -EINVAL;
 
+	phy_data = (struct usb_phy_data *)of_id->data;
+
 	phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
 	if (!phy) {
 		dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
@@ -150,7 +181,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
 	phy->dev		= &pdev->dev;
 
 	phy->phy.dev		= phy->dev;
-	phy->phy.label		= "omap-usb2";
+	phy->phy.label		= phy_data->label;
 	phy->phy.otg		= otg;
 	phy->phy.type		= USB_PHY_TYPE_USB2;
 
@@ -171,8 +202,10 @@ static int omap_usb2_probe(struct platform_device *pdev)
 
 	otg->set_host		= omap_usb_set_host;
 	otg->set_peripheral	= omap_usb_set_peripheral;
-	otg->set_vbus		= omap_usb_set_vbus;
-	otg->start_srp		= omap_usb_start_srp;
+	if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS)
+		otg->set_vbus		= omap_usb_set_vbus;
+	if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
+		otg->start_srp		= omap_usb_start_srp;
 	otg->phy		= &phy->phy;
 
 	platform_set_drvdata(pdev, phy);
@@ -272,14 +305,6 @@ static const struct dev_pm_ops omap_usb2_pm_ops = {
 #define DEV_PM_OPS     NULL
 #endif
 
-#ifdef CONFIG_OF
-static const struct of_device_id omap_usb2_id_table[] = {
-	{ .compatible = "ti,omap-usb2" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
-#endif
-
 static struct platform_driver omap_usb2_driver = {
 	.probe		= omap_usb2_probe,
 	.remove		= omap_usb2_remove,
diff --git a/include/linux/phy/omap_usb.h b/include/linux/phy/omap_usb.h
index 19d343c3..35989a8 100644
--- a/include/linux/phy/omap_usb.h
+++ b/include/linux/phy/omap_usb.h
@@ -39,6 +39,15 @@ struct omap_usb {
 	struct clk		*optclk;
 };
 
+struct usb_phy_data {
+	const char *label;
+	u8 flags;
+};
+
+/* Driver Flags */
+#define OMAP_USB2_HAS_START_SRP (1 << 0)
+#define OMAP_USB2_HAS_SET_VBUS (1 << 1)
+
 #define	phy_to_omapusb(x)	container_of((x), struct omap_usb, phy)
 
 #if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
-- 
1.7.9.5


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

* [PATCH 17/28 v2] phy: omap-usb2: Provide workaround for USB2PHY false disconnect
  2014-03-09  7:27 ` [PATCH 16/28 v2] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x Kishon Vijay Abraham I
@ 2014-03-09  7:27   ` Kishon Vijay Abraham I
  2014-03-09  7:27   ` [PATCH 18/28 v2] phy: omap-usb2: Add different compatible for OMAP5 Kishon Vijay Abraham I
  1 sibling, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-09  7:27 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: Austin Beam <austinbeam@ti.com>

Enable the dra7x errata workaround for false disconnect problem
with USB2PHY. False disconnects were detected with some of the devices.
Reduce the sensitivity of the disconnect logic within the USB2PHY subsystem
to enusre these false disconnects are not registered.

[george.cherian@ti.com]
While at that, pass proper flags for each SoC's. This is a common driver
used across OMAP4,OMAP5,DRA7xx and AM437x USB2PHY.

False disconnect workaround is currently applicable for only DRA7x.

Signed-off-by: Austin Beam <austinbeam@ti.com>
Signed-off-by: George Cherian <george.cherian@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
Changes from v1:
removed the Documentation since the name of the file got modified in usb tree.
 drivers/phy/phy-omap-usb2.c  |   44 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/phy/omap_usb.h |    4 ++++
 2 files changed, 48 insertions(+)

diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index 0c78f54..b220202 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -31,6 +31,9 @@
 #include <linux/phy/phy.h>
 #include <linux/of_platform.h>
 
+#define USB2PHY_DISCON_BYP_LATCH (1 << 31)
+#define USB2PHY_ANA_CONFIG1 0x4c
+
 /**
  * omap_usb2_set_comparator - links the comparator present in the sytem with
  *	this phy
@@ -116,7 +119,30 @@ static int omap_usb_power_on(struct phy *x)
 	return 0;
 }
 
+static int omap_usb_init(struct phy *x)
+{
+	struct omap_usb *phy = phy_get_drvdata(x);
+	u32 val;
+
+	if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
+		/*
+		 *
+		 * Reduce the sensitivity of internal PHY by enabling the
+		 * DISCON_BYP_LATCH of the USB2PHY_ANA_CONFIG1 register. This
+		 * resolves issues with certain devices which can otherwise
+		 * be prone to false disconnects.
+		 *
+		 */
+		val = omap_usb_readl(phy->phy_base, USB2PHY_ANA_CONFIG1);
+		val |= USB2PHY_DISCON_BYP_LATCH;
+		omap_usb_writel(phy->phy_base, USB2PHY_ANA_CONFIG1, val);
+	}
+
+	return 0;
+}
+
 static struct phy_ops ops = {
+	.init		= omap_usb_init,
 	.power_on	= omap_usb_power_on,
 	.power_off	= omap_usb_power_off,
 	.owner		= THIS_MODULE,
@@ -128,6 +154,11 @@ static const struct usb_phy_data omap_usb2_data = {
 	.flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
 };
 
+static const struct usb_phy_data dra7x_usb2_data = {
+	.label = "dra7x_usb2",
+	.flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
+};
+
 static const struct usb_phy_data am437x_usb2_data = {
 	.label = "am437x_usb2",
 	.flags =  0,
@@ -139,6 +170,10 @@ static const struct of_device_id omap_usb2_id_table[] = {
 		.data = &omap_usb2_data,
 	},
 	{
+		.compatible = "ti,dra7x-usb2",
+		.data = &dra7x_usb2_data,
+	},
+	{
 		.compatible = "ti,am437x-usb2",
 		.data = &am437x_usb2_data,
 	},
@@ -151,6 +186,7 @@ static int omap_usb2_probe(struct platform_device *pdev)
 {
 	struct omap_usb	*phy;
 	struct phy *generic_phy;
+	struct resource *res;
 	struct phy_provider *phy_provider;
 	struct usb_otg *otg;
 	struct device_node *node = pdev->dev.of_node;
@@ -185,6 +221,14 @@ static int omap_usb2_probe(struct platform_device *pdev)
 	phy->phy.otg		= otg;
 	phy->phy.type		= USB_PHY_TYPE_USB2;
 
+	if (phy_data->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		phy->phy_base = devm_ioremap_resource(&pdev->dev, res);
+		if (!phy->phy_base)
+			return -ENOMEM;
+		phy->flags |= OMAP_USB2_CALIBRATE_FALSE_DISCONNECT;
+	}
+
 	control_node = of_parse_phandle(node, "ctrl-module", 0);
 	if (!control_node) {
 		dev_err(&pdev->dev, "Failed to get control device phandle\n");
diff --git a/include/linux/phy/omap_usb.h b/include/linux/phy/omap_usb.h
index 35989a8..dc2c541 100644
--- a/include/linux/phy/omap_usb.h
+++ b/include/linux/phy/omap_usb.h
@@ -33,10 +33,13 @@ struct usb_dpll_params {
 struct omap_usb {
 	struct usb_phy		phy;
 	struct phy_companion	*comparator;
+	void __iomem		*pll_ctrl_base;
+	void __iomem		*phy_base;
 	struct device		*dev;
 	struct device		*control_dev;
 	struct clk		*wkupclk;
 	struct clk		*optclk;
+	u8			flags;
 };
 
 struct usb_phy_data {
@@ -47,6 +50,7 @@ struct usb_phy_data {
 /* Driver Flags */
 #define OMAP_USB2_HAS_START_SRP (1 << 0)
 #define OMAP_USB2_HAS_SET_VBUS (1 << 1)
+#define OMAP_USB2_CALIBRATE_FALSE_DISCONNECT (1 << 2)
 
 #define	phy_to_omapusb(x)	container_of((x), struct omap_usb, phy)
 
-- 
1.7.9.5


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

* [PATCH 18/28 v2] phy: omap-usb2: Add different compatible for OMAP5
  2014-03-09  7:27 ` [PATCH 16/28 v2] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x Kishon Vijay Abraham I
  2014-03-09  7:27   ` [PATCH 17/28 v2] phy: omap-usb2: Provide workaround for USB2PHY false disconnect Kishon Vijay Abraham I
@ 2014-03-09  7:27   ` Kishon Vijay Abraham I
  1 sibling, 0 replies; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-09  7:27 UTC (permalink / raw
  To: gregkh, kishon, linux-kernel

From: George Cherian <george.cherian@ti.com>

Add a new compatible for OMAP5 since it does not use any of the
OTG operations as of now.
HAS_SRP and SET_VBUS functionalities are used only for OMAP4.

Signed-off-by: George Cherian <george.cherian@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
Changes from v1:
removed the Documentation since the name of the file got modified in usb tree.
 drivers/phy/phy-omap-usb2.c |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c
index b220202..3cc4aba 100644
--- a/drivers/phy/phy-omap-usb2.c
+++ b/drivers/phy/phy-omap-usb2.c
@@ -154,6 +154,11 @@ static const struct usb_phy_data omap_usb2_data = {
 	.flags = OMAP_USB2_HAS_START_SRP | OMAP_USB2_HAS_SET_VBUS,
 };
 
+static const struct usb_phy_data omap5_usb2_data = {
+	.label = "omap5_usb2",
+	.flags = 0,
+};
+
 static const struct usb_phy_data dra7x_usb2_data = {
 	.label = "dra7x_usb2",
 	.flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
@@ -170,6 +175,10 @@ static const struct of_device_id omap_usb2_id_table[] = {
 		.data = &omap_usb2_data,
 	},
 	{
+		.compatible = "ti,omap5-usb2",
+		.data = &omap5_usb2_data,
+	},
+	{
 		.compatible = "ti,dra7x-usb2",
 		.data = &dra7x_usb2_data,
 	},
-- 
1.7.9.5


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

* Re: [GIT PULL 00/28] PHY for 3.15
  2014-03-08 16:42 ` [GIT PULL 00/28] PHY for 3.15 Greg KH
@ 2014-03-09  7:35   ` Kishon Vijay Abraham I
  2014-03-09 16:55     ` Greg KH
  0 siblings, 1 reply; 35+ messages in thread
From: Kishon Vijay Abraham I @ 2014-03-09  7:35 UTC (permalink / raw
  To: Greg KH; +Cc: linux-kernel, linux-usb, Felipe Balbi

Hi Greg,

On Saturday 08 March 2014 10:12 PM, Greg KH wrote:
> On Sat, Mar 08, 2014 at 02:59:01PM +0530, Kishon Vijay Abraham I wrote:
>> Hi Greg,
>>
>> Here's the PULL REQUEST for 3.15 merge window.
>> More users are starting to use the generic PHY framework including USB and
>> SATA PHY in exynos, USB in sunxi and multi-purpose PHY (currently only SATA)
>> in APM. There is also a patch to adapt USB3 PHY driver (PIPE3) used in OMAP
>> to generic PHY framework and use the same driver for SATA.
>> It also includes few fixes and cleanups.
>>
>> Please let me know if you want me to make any changes.
>>
>> Cheers
>> Kishon
>>
>> The following changes since commit cfbf8d4857c26a8a307fb7cd258074c9dcd8c691:
>>
>>    Linux 3.14-rc4 (2014-02-23 17:40:03 -0800)
>>
>> are available in the git repository at:
>>
>>    git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git tags/for_3.15
>>
>> for you to fetch changes up to 303fd52cda953d14dc82ac82b570761599eb9ab2:
>>
>>    PHY: add APM X-Gene SoC 15Gbps Multi-purpose PHY driver (2014-03-08 12:39:51 +0530)
>
> When merging this with my usb-next tree, I get the following merge
> issue, which I don't know how to resolve:
> CONFLICT (modify/delete): Documentation/devicetree/bindings/usb/usb-phy.txt deleted in HEAD and modified in a0100026249158ec7aae606b553efae7cb37f616. Version a0100026249158ec7aae606b553efae7cb37f616 of Documentation/devicetree/bindings/usb/usb-phy.txt left in tree.
>
> Any suggestions as to what I should do here?

There were 3 patches that modified usb-phy.txt but the file was moved to 
phy/ti-phy.txt in balbi's branch. I've resent the patches that modified 
this file and have also updated tags/for_3.15.

Let me know If I have to resend the PULL request.

Sorry for the hassle.

Thanks
Kishon

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

* Re: [GIT PULL 00/28] PHY for 3.15
  2014-03-09  7:35   ` Kishon Vijay Abraham I
@ 2014-03-09 16:55     ` Greg KH
  0 siblings, 0 replies; 35+ messages in thread
From: Greg KH @ 2014-03-09 16:55 UTC (permalink / raw
  To: Kishon Vijay Abraham I; +Cc: linux-kernel, linux-usb, Felipe Balbi

On Sun, Mar 09, 2014 at 01:05:36PM +0530, Kishon Vijay Abraham I wrote:
> Hi Greg,
> 
> On Saturday 08 March 2014 10:12 PM, Greg KH wrote:
> > On Sat, Mar 08, 2014 at 02:59:01PM +0530, Kishon Vijay Abraham I wrote:
> >> Hi Greg,
> >>
> >> Here's the PULL REQUEST for 3.15 merge window.
> >> More users are starting to use the generic PHY framework including USB and
> >> SATA PHY in exynos, USB in sunxi and multi-purpose PHY (currently only SATA)
> >> in APM. There is also a patch to adapt USB3 PHY driver (PIPE3) used in OMAP
> >> to generic PHY framework and use the same driver for SATA.
> >> It also includes few fixes and cleanups.
> >>
> >> Please let me know if you want me to make any changes.
> >>
> >> Cheers
> >> Kishon
> >>
> >> The following changes since commit cfbf8d4857c26a8a307fb7cd258074c9dcd8c691:
> >>
> >>    Linux 3.14-rc4 (2014-02-23 17:40:03 -0800)
> >>
> >> are available in the git repository at:
> >>
> >>    git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy.git tags/for_3.15
> >>
> >> for you to fetch changes up to 303fd52cda953d14dc82ac82b570761599eb9ab2:
> >>
> >>    PHY: add APM X-Gene SoC 15Gbps Multi-purpose PHY driver (2014-03-08 12:39:51 +0530)
> >
> > When merging this with my usb-next tree, I get the following merge
> > issue, which I don't know how to resolve:
> > CONFLICT (modify/delete): Documentation/devicetree/bindings/usb/usb-phy.txt deleted in HEAD and modified in a0100026249158ec7aae606b553efae7cb37f616. Version a0100026249158ec7aae606b553efae7cb37f616 of Documentation/devicetree/bindings/usb/usb-phy.txt left in tree.
> >
> > Any suggestions as to what I should do here?
> 
> There were 3 patches that modified usb-phy.txt but the file was moved to 
> phy/ti-phy.txt in balbi's branch. I've resent the patches that modified 
> this file and have also updated tags/for_3.15.
> 
> Let me know If I have to resend the PULL request.

Please do, because I want to see the updated diffstat that I am supposed
to be receiving.

thanks,

greg k-h

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

end of thread, other threads:[~2014-03-09 16:54 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-08  9:29 [GIT PULL 00/28] PHY for 3.15 Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 01/28] usb: phy: twl4030-usb: Silence checkpatch warnings Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 02/28] usb: phy: twl4030-usb: Remove redundant semicolon Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 03/28] usb: phy: bcm-kona-usb2: Use PTR_ERR_OR_ZERO Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 04/28] phy: Select PHY_EXYNOS_MIPI_VIDEO by default for ARCH_EXYNOS Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 05/28] phy: Select PHY_EXYNOS_DP_VIDEO " Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 06/28] PHY: Exynos: Add Exynos5250 SATA PHY driver Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 07/28] PHY: sunxi: Add driver for sunxi usb phy Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 08/28] phy: mvebu-sata: prepare new Dove DT Kconfig variable Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 09/28] drivers: phy: usb3/pipe3: Adapt pipe3 driver to Generic PHY Framework Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 10/28] usb: phy: omap-usb2: remove *set_suspend* callback from omap-usb2 Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 11/28] phy: omap-usb2: move omap_usb.h from linux/usb/ to linux/phy/ Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 12/28] phy: core: Add an exported of_phy_get function Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 13/28] phy: core: Add devm_of_phy_get to phy-core Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 14/28] phy: Add new Exynos USB 2.0 PHY driver Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 15/28] phy: Add Exynos 5250 support to the " Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 16/28] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 17/28] phy: omap-usb2: Provide workaround for USB2PHY false disconnect Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 18/28] phy: omap-usb2: Add different compatible for OMAP5 Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 19/28] phy: rename struct omap_control_usb to struct omap_control_phy Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 20/28] phy: omap-control: update dra7 and am437 usb2 bindings Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 21/28] phy: ti-pipe3: cleanup clock handling Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 22/28] phy: ti-pipe3: Add SATA DPLL support Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 23/28] phy: ti-pipe3: Don't get 'wkupclk' and 'refclk' for SATA PHY Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 24/28] phy: ti-pipe3: streamline PHY operations Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 25/28] phy: ti-pipe3: Fix suspend/resume and module reload Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 26/28] phy: omap: Depend on OMAP_OCP2SCP bus driver Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 27/28] Documentation: Add APM X-Gene SoC 15Gbps Multi-purpose PHY driver binding documentation Kishon Vijay Abraham I
2014-03-08  9:29 ` [PATCH 28/28] PHY: add APM X-Gene SoC 15Gbps Multi-purpose PHY driver Kishon Vijay Abraham I
2014-03-08 16:42 ` [GIT PULL 00/28] PHY for 3.15 Greg KH
2014-03-09  7:35   ` Kishon Vijay Abraham I
2014-03-09 16:55     ` Greg KH
2014-03-09  7:27 ` [PATCH 16/28 v2] phy: omap-usb2: Adapt phy-omap-usb2 for AM437x Kishon Vijay Abraham I
2014-03-09  7:27   ` [PATCH 17/28 v2] phy: omap-usb2: Provide workaround for USB2PHY false disconnect Kishon Vijay Abraham I
2014-03-09  7:27   ` [PATCH 18/28 v2] phy: omap-usb2: Add different compatible for OMAP5 Kishon Vijay Abraham I

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