[9610] phy: usb: add PHY driver for USBDRD3
authorKisang Lee <kisang80.lee@samsung.com>
Thu, 17 May 2018 11:55:47 +0000 (20:55 +0900)
committerKisang Lee <kisang80.lee@samsung.com>
Thu, 17 May 2018 12:22:41 +0000 (21:22 +0900)
Change-Id: I7d79fa369409f6cb3c51e21a16ec9a385f97d7e7
Signed-off-by: Kisang Lee <kisang80.lee@samsung.com>
27 files changed:
drivers/phy/phy-core.c
drivers/phy/samsung/Kconfig
drivers/phy/samsung/Makefile
drivers/phy/samsung/phy-exynos-debug.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-debugfs.c [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-displayport.c [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-dp-debugfs.c [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-mipi.c [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usb3p1-reg.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usb3p1.c [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usb3p1.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdp-reg-cmn.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdp-reg-dp.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdp-reg-pcs.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdp-reg-trsv.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdp-reg.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdp.c [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdp.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdrd.c [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdrd.h [new file with mode: 0644]
drivers/phy/samsung/phy-exynos-usbdrd3.c [new file with mode: 0644]
drivers/phy/samsung/phy-samsung-usb-cal.h [new file with mode: 0644]
drivers/phy/samsung/phy-samsung-usb3-cal-combo.h [new file with mode: 0644]
drivers/phy/samsung/phy-samsung-usb3-cal.c [new file with mode: 0644]
drivers/phy/samsung/phy-samsung-usb3-cal.h [new file with mode: 0644]
drivers/usb/phy/Kconfig
include/linux/phy/phy.h

index 48a365e303e5a967bf7d65d7d7d87abe98de2b23..ce50fa87cd9969bf60019e878a9b00db39ca066c 100644 (file)
@@ -273,6 +273,83 @@ out:
 }
 EXPORT_SYMBOL_GPL(phy_exit);
 
+int phy_vendor_set(struct phy *phy, int is_enable, int is_cancel)
+{
+       int ret;
+
+       if (!phy || !phy->ops->vendor_set)
+               return 0;
+
+       ret = phy->ops->vendor_set(phy, is_enable, is_cancel);
+       if (ret < 0) {
+               dev_err(&phy->dev, "phy vendor setting failed --> %d\n", ret);
+       } else {
+               ret = 0; /* Override possible ret == -ENOTSUPP */
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(phy_vendor_set);
+
+int phy_ilbk(struct phy *phy)
+{
+       int ret;
+
+       if (!phy || !phy->ops->ilbk)
+               return 0;
+
+       ret = phy->ops->ilbk(phy);
+       if (ret < 0)
+               dev_err(&phy->dev, "phy ilbk failed --> %d\n", ret);
+       else
+               ret = 0; /* Override possible ret == -ENOTSUPP */
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(phy_ilbk);
+
+int phy_tune(struct phy *phy, int phy_state)
+{
+       int ret;
+
+       if (!phy || !phy->ops->tune)
+               return 0;
+
+       ret = phy->ops->tune(phy, phy_state);
+       if (ret < 0) {
+               dev_err(&phy->dev, "phy tune failed --> %d\n", ret);
+       } else {
+               ret = 0; /* Override possible ret == -ENOTSUPP */
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(phy_tune);
+
+void phy_conn(struct phy *phy, int option)
+{
+       if (!phy || !phy->ops->conn)
+               return;
+
+       phy->ops->conn(phy, option);
+
+       return;
+}
+EXPORT_SYMBOL_GPL(phy_conn);
+
+int phy_set(struct phy *phy, int option, void *info)
+{
+       int ret;
+
+       if (!phy || !phy->ops->set)
+               return 0;
+
+       ret = phy->ops->set(phy, option, info);
+       if (ret < 0)
+               dev_err(&phy->dev, "phy set failed --> %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(phy_set);
+
 int phy_power_on(struct phy *phy)
 {
        int ret = 0;
index b9651fc0308edb6601cdba9ce17bd1431c4337b3..b2af8eb12621bc0cb1c0e74eecbec478ac8920e0 100644 (file)
@@ -79,6 +79,62 @@ config PHY_EXYNOS5_USBDRD
          This driver provides PHY interface for USB 3.0 DRD controller
          present on Exynos5 SoC series.
 
+config PHY_EXYNOS_USBDRD
+       tristate "Exynos SoC series USB DRD PHY driver"
+       depends on ARCH_EXYNOS && OF
+       depends on HAS_IOMEM
+       depends on USB_DWC3_EXYNOS
+       select GENERIC_PHY
+       select MFD_SYSCON
+       default y
+       help
+         Enable USB DRD PHY support for Exynos SoC series.
+         This driver provides PHY interface for USB 3.0 DRD controller
+         present on Exynos SoC series.
+
+config PHY_EXYNOS_USBDRD3
+       tristate "Exynos SoC series USB DRD PHY3 & PHY2 driver"
+       depends on ARCH_EXYNOS && OF
+       depends on HAS_IOMEM
+       depends on USB_DWC3_EXYNOS
+       select GENERIC_PHY
+       select MFD_SYSCON
+       default y
+       help
+         Enable USB DRD PHY support for Exynos SoC series.
+         This driver provides PHY interface for USB 3.0 DRD controller
+         present on Exynos SoC series.
+
+config PHY_EXYNOS_DEBUGFS
+       tristate "Exynos SoC series USB DRD PHY DebugFS"
+       depends on DEBUG_FS
+       depends on PHY_EXYNOS_USBDRD || PHY_EXYNOS_USBDRD3
+       select GENERIC_PHY
+       default y
+       help
+         Enable USB DRD PHY DEBUGFS support for Exynos SoC series.
+         This driver provides PHY debugging interface for USBDRD PHY controller
+         present on Exynos SoC series.
+
+config PHY_EXYNOS_DP_DEBUGFS
+       tristate "Exynos SoC series USB DRD DP PHY DebugFS"
+       depends on DEBUG_FS
+       depends on PHY_EXYNOS_DEBUGFS
+       select GENERIC_PHY
+       default y
+       help
+         Enable USB DRD DP PHY DEBUGFS support for Exynos SoC series.
+         This driver provides PHY debugging interface for USBDRD DP PHY controller
+         present on Exynos SoC series.
+
+config PHY_SAMSUNG_USB_CAL
+       bool "Samsung USB PHY CAL"
+       depends on PHY_EXYNOS_USBDRD || PHY_EXYNOS_USBDRD3
+       default y
+       help
+         Enable this to support CAL (Chip Abstraction Layer)
+         for Samsung USB PHY controller.
+
 config PHY_EXYNOS5250_SATA
        tristate "Exynos5250 Sata SerDes/PHY driver"
        depends on SOC_EXYNOS5250
@@ -95,10 +151,19 @@ config PHY_EXYNOS5250_SATA
          port to accept one SATA device.
 
 config PHY_EXYNOS8895_MIPI
-       tristate "Samsung EXYNOS8895 SoC MIPI CSI/DSI PHY driver"
+       tristate "Samsung EXYNOS SoC MIPI CSI/DSI D/C-PHY driver"
        depends on HAS_IOMEM
        depends on ARCH_EXYNOS && OF || COMPILE_TEST
        select GENERIC_PHY
        help
          Support for MIPI CSI and MIPI DSI DPHY found on Samsung
          and EXYNOS SoCs.
+
+config PHY_EXYNOS_DISPLAYPORT
+       tristate "Samsung EXYNOS SoC DISPLAYPORT PHY driver"
+       depends on HAS_IOMEM
+       depends on ARCH_EXYNOS && OF || COMPILE_TEST
+       select GENERIC_PHY
+       help
+         Support for DISPLAYPORT PHY found on Samsung
+         and EXYNOS SoCs.
index 068a92999b4376a972bf27992dd445dc5606b346..75a7418d5b11adeff5a3978f4b4862dbaa0c8095 100644 (file)
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 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_EXYNOS8895_MIPI)      += phy-exynos8895-mipi.o
+obj-$(CONFIG_PHY_EXYNOS8895_MIPI)              += phy-exynos8895-mipi.o
+obj-$(CONFIG_PHY_EXYNOS_DISPLAYPORT)   += phy-exynos-displayport.o
 obj-$(CONFIG_PHY_EXYNOS_PCIE)          += phy-exynos-pcie.o
 obj-$(CONFIG_PHY_SAMSUNG_USB2)         += phy-exynos-usb2.o
 phy-exynos-usb2-y                      += phy-samsung-usb2.o
@@ -10,4 +11,10 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2)        += phy-exynos4x12-usb2.o
 phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2)  += phy-exynos5250-usb2.o
 phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2)     += phy-s5pv210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS5_USBDRD)       += phy-exynos5-usbdrd.o
+obj-$(CONFIG_PHY_EXYNOS_DEBUGFS)       += phy-exynos-debugfs.o
+obj-$(CONFIG_PHY_EXYNOS_DEBUGFS)       += phy-exynos-dp-debugfs.o
+obj-$(CONFIG_PHY_EXYNOS_USBDRD)                += phy-exynos-usbdrd.o
+obj-$(CONFIG_PHY_EXYNOS_USBDRD3)       += phy-exynos-usbdrd3.o
+obj-$(CONFIG_PHY_EXYNOS_DEBUGFS)       += phy-exynos-debugfs.o
+obj-$(CONFIG_PHY_SAMSUNG_USB_CAL)      += phy-exynos-usb3p1.o phy-exynos-usbdp.o
 obj-$(CONFIG_PHY_EXYNOS5250_SATA)      += phy-exynos5250-sata.o
diff --git a/drivers/phy/samsung/phy-exynos-debug.h b/drivers/phy/samsung/phy-exynos-debug.h
new file mode 100644 (file)
index 0000000..0a5a70f
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * phy-exynos-debug.h -  Samsung EXYNOS SoC series USB DRD PHY Debug Header
+ *
+ * Phy provider for USB 3.0 DRD controller on Exynos SoC series
+ *
+ * Copyright (C) 2016 Samsung Electronics Co., Ltd.
+ * Author: Kyounghye Yunm <k-hye.yun@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 "phy-exynos-usbdrd.h"
+#ifdef CONFIG_DEBUG_FS
+extern int exynos_usbdrd_debugfs_init(struct exynos_usbdrd_phy *phy_drd);
+extern int exynos_usbdrd_dp_debugfs_init(struct exynos_usbdrd_phy *phy_drd);
+extern void exynos_usbdrd_debugfs_exit(struct exynos_usbdrd_phy *phy_drd);
+#else
+static inline int exynos_usbdrd_debugfs_init(struct exynos_usbdrd_phy *)
+{  return 0;  }
+static inline void exynos_usbdrd_debugfs_exit(struct exynos_usbdrd_phy *)
+{  }
+#endif
+
+#define dump_register(nm)              \
+{                                      \
+       .name = __stringify(nm),        \
+       .offset = EXYNOS_USBCON_##nm,   \
+}
+#define dump_regmap_mask(nm, bit_nm, bit)      \
+{                                              \
+       .name = __stringify(nm),                \
+       .offset = EXYNOS_USBCON_##nm,           \
+       .bitname = #bit_nm,                     \
+       .bitmask = nm##_##bit_nm##_MASK,        \
+       .bitoffset = bit,                       \
+       .mask = true,                           \
+}
+#define dump_regmap(nm, bit_nm, bit)   \
+{                                      \
+       .name = __stringify(nm),        \
+       .offset = EXYNOS_USBCON_##nm,   \
+       .bitname = #bit_nm,             \
+       .bitmask = nm##_##bit_nm,       \
+       .bitoffset = bit,               \
+       .mask = false,                  \
+}
+
+#define dump_register_dp(rnm)          \
+{                                      \
+       .name = __stringify(rnm),       \
+       .offset = EXYNOS_USBDP_COM_##rnm,       \
+}
+#define dump_regmap_dp_mask(rnm, bit_rnm, bit_nm, bit) \
+{                                              \
+       .name = __stringify(rnm),               \
+       .offset = EXYNOS_USBDP_COM_##rnm,               \
+       .bitname = #bit_nm,                     \
+       .bitmask = bit_rnm##_##bit_nm##_MASK,   \
+       .bitoffset = bit,                       \
+       .mask = true,                           \
+}
+#define dump_regmap_dp(rnm, bit_rnm, bit_nm, bit)      \
+{                                      \
+       .name = __stringify(rnm),       \
+       .offset = EXYNOS_USBDP_COM_##rnm,       \
+       .bitname = #bit_nm,             \
+       .bitmask = bit_rnm##_##bit_nm,  \
+       .bitoffset = bit,               \
+       .mask = false,                  \
+}
+
+struct debugfs_regmap32 {
+       char *name;
+       char *bitname;
+       unsigned int offset;
+       unsigned int bitoffset;
+       unsigned int bitmask;
+       bool mask;
+};
+
+struct debugfs_regset_map {
+       const struct debugfs_regmap32 *regs;
+       int nregs;
+};
+
+struct exynos_debugfs_prvdata {
+       struct exynos_usbdrd_phy *phy_drd;
+       struct dentry   *root;
+       struct debugfs_regset32 *regset;
+       struct debugfs_regset_map *regmap;
+};
diff --git a/drivers/phy/samsung/phy-exynos-debugfs.c b/drivers/phy/samsung/phy-exynos-debugfs.c
new file mode 100644 (file)
index 0000000..985aecd
--- /dev/null
@@ -0,0 +1,816 @@
+/*
+ * Samsung EXYNOS SoC series USB DRD PHY DebugFS file
+ *
+ * Phy provider for USB 3.0 DRD controller on Exynos SoC series
+ *
+ * Copyright (C) 2016 Samsung Electronics Co., Ltd.
+ * Author: Kyounghye Yun <k-hye.yun@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/io.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+
+#include <linux/usb/ch9.h>
+#include "phy-exynos-usbdrd.h"
+#include "phy-samsung-usb3-cal.h"
+#include "phy-samsung-usb3-cal-combo.h"
+#include "phy-exynos-debug.h"
+
+struct exynos_debugfs_prvdata *prvdata;
+
+/* PHY Control register set of SOC which combo phy is applied in */
+static const struct debugfs_reg32 exynos_usb3drd_phycon_regs[] = {
+       dump_register(CTRLVER),
+       dump_register(LINKCTRL),
+       dump_register(PHYCON_LINKPORT),
+       dump_register(LINK_DEBUG_L),
+       dump_register(LINK_DEBUG_H),
+       dump_register(LTSTATE_HIS),
+       dump_register(CLKRSTCTRL),
+       dump_register(PWRCTL),
+       dump_register(SSPPLLCTL),
+       dump_register(SECPMACTL),
+       dump_register(UTMICTRL),
+       dump_register(HSPCTRL),
+       dump_register(HSPPARACON),
+       dump_register(HSPTEST),
+       dump_register(HSPPLLTUNE),
+       dump_register(REWA_CTRL),
+       dump_register(HSREWA_INTR),
+       dump_register(HSREWA_CTRL),
+       dump_register(HSREWA_REFTO),
+       dump_register(HSREWA_HSTK),
+       dump_register(HSREWA_CNT),
+       dump_register(HSREWA_INT1_EVNT),
+       dump_register(HSREWA_INT1_EVNT_MSK),
+};
+
+static const struct debugfs_reg32 exynos_usb3drd_regs[] = {
+       dump_register(LINKSYSTEM),
+       dump_register(PHYUTMI),
+       dump_register(PHYCLKRST),
+       dump_register(PHYREG0),
+       dump_register(PHYPARAM0),
+       dump_register(PHYPARAM1),
+       dump_register(PHYTEST),
+       dump_register(PHYRESUME),
+       dump_register(PHYPCSVAL),
+       dump_register(LINKPORT),
+       dump_register(PHYPARAM2),
+};
+
+static const struct debugfs_reg32 exynos_usb2drd_regs[] = {
+       dump_register(LINKSYSTEM),
+       dump_register(PHYUTMI),
+       dump_register(PHYCLKRST),
+       dump_register(PHYPARAM0),
+       dump_register(PHYPOWERDOWN),
+       dump_register(PHYRESUME),
+       dump_register(LINKPORT),
+       dump_register(HSPHYCTRL),
+       dump_register(HSPHYPLLTUNE),
+};
+
+/* PHY Control register set of SOC which combo phy is applied in */
+static const struct debugfs_regmap32 exynos_usb3drd_phycon_regmap[] = {
+       dump_regmap_mask(CTRLVER, CTRL_VER, 0),
+       dump_regmap(LINKCTRL, FORCE_RXELECIDLE, 18),
+       dump_regmap(LINKCTRL, FORCE_PHYSTATUS, 17),
+       dump_regmap(LINKCTRL, FORCE_PIPE_EN, 16),
+       dump_regmap(LINKCTRL, DIS_BUSPEND_QACT, 13),
+       dump_regmap(LINKCTRL, DIS_LINKGATE_QACT, 12),
+       dump_regmap(LINKCTRL, DIS_ID0_QACT, 11),
+       dump_regmap(LINKCTRL, DIS_VBUSVALID_QACT, 10),
+       dump_regmap(LINKCTRL, DIS_BVALID_QACT, 9),
+       dump_regmap(LINKCTRL, FORCE_QACT, 8),
+       dump_regmap_mask(LINKCTRL, BUS_FILTER_BYPASS, 4),
+       dump_regmap(LINKCTRL, HOST_SYSTEM_ERR, 2),
+       dump_regmap(LINKCTRL, LINK_PME, 1),
+       dump_regmap(LINKCTRL, PME_GENERATION, 0),
+       dump_regmap_mask(PHYCON_LINKPORT, HOST_NUM_U3, 16),
+       dump_regmap_mask(PHYCON_LINKPORT, HOST_NUM_U2, 12),
+       dump_regmap(PHYCON_LINKPORT, HOST_U3_PORT_DISABLE, 9),
+       dump_regmap(PHYCON_LINKPORT, HOST_U2_PORT_DISABLE, 8),
+       dump_regmap(PHYCON_LINKPORT, HOST_PORT_POWER_CON_PRESENT, 6),
+       dump_regmap(PHYCON_LINKPORT, HUB_PORT_OVERCURRENT_U3, 5),
+       dump_regmap(PHYCON_LINKPORT, HUB_PORT_OVERCURRENT_U2, 4),
+       dump_regmap(PHYCON_LINKPORT, HUB_PORT_OVERCURRENT_SET_U3, 3),
+       dump_regmap(PHYCON_LINKPORT, HUB_PORT_OVERCURRENT_SET_U2, 2),
+       dump_regmap(PHYCON_LINKPORT, HUB_PERM_ATTACH_U3, 1),
+       dump_regmap(PHYCON_LINKPORT, HUB_PERM_ATTACH_U2, 0),
+       dump_regmap_mask(LINK_DEBUG_L, DEBUG_L, 0),
+       dump_regmap_mask(LINK_DEBUG_H, DEBUG_H, 0),
+       dump_regmap(LTSTATE_HIS, LINKTRN_DONE, 31),
+       dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS4, 16),
+       dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS3, 12),
+       dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS2, 8),
+       dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS1, 4),
+       dump_regmap_mask(LTSTATE_HIS, LTSTATE_HIS0, 0),
+       dump_regmap(CLKRSTCTRL, USBAUDIO_CLK_GATE_EN, 9),
+       dump_regmap(CLKRSTCTRL, USBAUDIO_CLK_SEL, 8),
+       dump_regmap(CLKRSTCTRL, LINK_PCLK_SEL, 7),
+       dump_regmap(CLKRSTCTRL, REFCLKSEL, 4),
+       dump_regmap(CLKRSTCTRL, PHY_SW_RST, 3),
+       dump_regmap(CLKRSTCTRL, PHY_RESET_SEL, 2),
+       dump_regmap(CLKRSTCTRL, PORTRESET, 1),
+       dump_regmap(CLKRSTCTRL, LINK_SW_RST, 0),
+       dump_regmap(PWRCTL, FORCE_POWERDOWN, 2),
+       dump_regmap_mask(SSPPLLCTL, FSEL, 0),
+       dump_regmap_mask(SECPMACTL, PMA_PLL_REF_CLK_SEL, 10),
+       dump_regmap_mask(SECPMACTL, PMA_REF_FREQ_SEL, 8),
+       dump_regmap(SECPMACTL, PMA_LOW_PWR, 4),
+       dump_regmap(SECPMACTL, PMA_TRSV_SW_RST, 3),
+       dump_regmap(SECPMACTL, PMA_CMN_SW_RST, 2),
+       dump_regmap(SECPMACTL, PMA_INIT_SW_RST, 1),
+       dump_regmap(SECPMACTL, PMA_APB_SW_RST, 0),
+       dump_regmap(UTMICTRL, OPMODE_EN, 8),
+       dump_regmap_mask(UTMICTRL, FORCE_OPMODE, 6),
+       dump_regmap(UTMICTRL, FORCE_VBUSVALID, 5),
+       dump_regmap(UTMICTRL, FORCE_BVALID, 4),
+       dump_regmap(UTMICTRL, FORCE_DPPULLDOWN, 3),
+       dump_regmap(UTMICTRL, FORCE_DMPULLDOWN, 2),
+       dump_regmap(UTMICTRL, FORCE_SUSPEND, 1),
+       dump_regmap(UTMICTRL, FORCE_SLEEP, 0),
+       dump_regmap(HSPCTRL, AUTORSM_ENB, 29),
+       dump_regmap(HSPCTRL, RETENABLE_EN, 28),
+       dump_regmap(HSPCTRL, FSLS_SPEED_SEL, 25),
+       dump_regmap(HSPCTRL, FSV_OUT_EN, 24),
+       dump_regmap(HSPCTRL, HS_XCVR_EXT_CTL, 22),
+       dump_regmap(HSPCTRL, HS_RXDAT, 21),
+       dump_regmap(HSPCTRL, HS_SQUELCH, 20),
+       dump_regmap(HSPCTRL, FSVMINUS, 17),
+       dump_regmap(HSPCTRL, FSVPLUS, 16),
+       dump_regmap(HSPCTRL, VBUSVLDEXTSEL, 13),
+       dump_regmap(HSPCTRL, VBUSVLDEXT, 12),
+       dump_regmap(HSPCTRL, EN_UTMISUSPEND, 9),
+       dump_regmap(HSPCTRL, COMMONONN, 8),
+       dump_regmap(HSPCTRL, VATESTENB, 6),
+       dump_regmap(HSPCTRL, CHGDET, 5),
+       dump_regmap(HSPCTRL, VDATSRCENB, 4),
+       dump_regmap(HSPCTRL, VDATDETENB, 3),
+       dump_regmap(HSPCTRL, CHRGSEL, 2),
+       dump_regmap(HSPCTRL, ACAENB, 1),
+       dump_regmap(HSPCTRL, DEDENB, 0),
+       dump_regmap_mask(HSPPARACON, TXVREFTUNE, 28),
+       dump_regmap_mask(HSPPARACON, TXRISETUNE, 24),
+       dump_regmap_mask(HSPPARACON, TXRESTUNE, 21),
+       dump_regmap(HSPPARACON, TXPREEMPPULSETUNE, 20),
+       dump_regmap_mask(HSPPARACON, TXPREEMPAMPTUNE, 18),
+       dump_regmap_mask(HSPPARACON, TXHSXVTUNE, 16),
+       dump_regmap_mask(HSPPARACON, TXFSLSTUNE, 12),
+       dump_regmap_mask(HSPPARACON, SQRXTUNE, 8),
+       dump_regmap_mask(HSPPARACON, OTGTUNE, 4),
+       dump_regmap_mask(HSPPARACON, COMPDISTUNE, 0),
+       dump_regmap(HSPTEST, SIDDQ_PORT0, 24),
+       dump_regmap_mask(HSPTEST, LINESTATE_PORT0, 20),
+       dump_regmap_mask(HSPTEST, TESTDATAOUT_PORT0, 16),
+       dump_regmap(HSPTEST, TESTCLK_PORT0, 13),
+       dump_regmap(HSPTEST, TESTDATAOUTSEL_PORT0, 12),
+       dump_regmap_mask(HSPTEST, TESTADDR_PORT0, 8),
+       dump_regmap_mask(HSPTEST, TESTDATAIN_PORT0, 0),
+       dump_regmap(HSPPLLTUNE, PLLBTUNE, 8),
+       dump_regmap_mask(HSPPLLTUNE, PLLITUNE, 4),
+       dump_regmap_mask(HSPPLLTUNE, PLLPTUNE, 0),
+       dump_regmap(REWA_CTRL, HSREWA_EN, 0),
+       dump_regmap_mask(HSREWA_INTR, WAKEUP_MASK, 12),
+       dump_regmap_mask(HSREWA_INTR, TIMEOUT_INTR_MASK, 8),
+       dump_regmap_mask(HSREWA_INTR, EVENT_INT_MASK, 4),
+       dump_regmap_mask(HSREWA_INTR, WAKEUP_INTR_MASK, 0),
+       dump_regmap(HSREWA_CTRL, DIG_BYPASS_CON_EN, 28),
+       dump_regmap(HSREWA_CTRL, DPDM_MONITOR_SEL, 24),
+       dump_regmap(HSREWA_CTRL, HS_LINK_READY, 20),
+       dump_regmap(HSREWA_CTRL, HS_SYS_VALID, 16),
+       dump_regmap(HSREWA_CTRL, HS_REWA_ERROR, 4),
+       dump_regmap(HSREWA_CTRL, HS_REWA_DONE, 0),
+       dump_regmap_mask(HSREWA_REFTO, HOST_K_TIMEOUT, 0),
+       dump_regmap_mask(HSREWA_HSTK, HOST_K_DELAY, 0),
+       dump_regmap_mask(HSREWA_CNT, WAKEUP_CNT, 0),
+       dump_regmap(HSREWA_INT1_EVNT, ERR_SUS, 18),
+       dump_regmap(HSREWA_INT1_EVNT, ERR_DEV_K, 17),
+       dump_regmap(HSREWA_INT1_EVNT, DISCON, 16),
+       dump_regmap(HSREWA_INT1_EVNT, BYPASS_DIS, 2),
+       dump_regmap(HSREWA_INT1_EVNT, RET_DIS, 1),
+       dump_regmap(HSREWA_INT1_EVNT, RET_EN, 0),
+       dump_regmap(HSREWA_INT1_EVNT_MSK, ERR_SUS_MASK, 18),
+       dump_regmap(HSREWA_INT1_EVNT_MSK, ERR_DEV_K_MASK, 17),
+       dump_regmap(HSREWA_INT1_EVNT_MSK, DISCON_MASK, 16),
+       dump_regmap(HSREWA_INT1_EVNT_MSK, BYPASS_DIS_MASK, 2),
+       dump_regmap(HSREWA_INT1_EVNT_MSK, RET_DIS_MASK, 1),
+       dump_regmap(HSREWA_INT1_EVNT_MSK, RET_EN_MASK, 0),
+};
+
+static const struct debugfs_regmap32 exynos_usb2drd_regmap[] = {
+       dump_regmap(LINKSYSTEM, HOST_SYSTEM_ERR, 31),
+       dump_regmap(LINKSYSTEM, PHY_POWER_DOWN, 30),
+       dump_regmap(LINKSYSTEM, PHY_SW_RESET, 29),
+       dump_regmap(LINKSYSTEM, LINK_SW_RESET, 28),
+       dump_regmap(LINKSYSTEM, XHCI_VERSION_CONTROL, 27),
+       dump_regmap(LINKSYSTEM, FORCE_VBUSVALID, 8),
+       dump_regmap(LINKSYSTEM, FORCE_BVALID, 7),
+       dump_regmap_mask(LINKSYSTEM, FLADJ, 1),
+       dump_regmap(PHYUTMI, UTMI_SUSPEND_COM_N, 12),
+       dump_regmap(PHYUTMI, UTMI_L1_SUSPEND_COM_N, 11),
+       dump_regmap(PHYUTMI, VBUSVLDEXTSEL, 10),
+       dump_regmap(PHYUTMI, VBUSVLDEXT, 9),
+       dump_regmap(PHYUTMI, TXBITSTUFFENH, 8),
+       dump_regmap(PHYUTMI, TXBITSTUFFEN, 7),
+       dump_regmap(PHYUTMI, OTGDISABLE, 6),
+       dump_regmap(PHYUTMI, IDPULLUP, 5),
+       dump_regmap(PHYUTMI, DRVVBUS, 4),
+       dump_regmap(PHYUTMI, DPPULLDOWN, 3),
+       dump_regmap(PHYUTMI, DMPULLDOWN, 2),
+       dump_regmap(PHYUTMI, FORCESUSPEND, 1),
+       dump_regmap(PHYUTMI, FORCESLEEP, 0),
+       dump_regmap(PHYCLKRST, EN_UTMISUSPEND, 31),
+       dump_regmap_mask(PHYCLKRST, SSC_REFCLKSEL, 23),
+       dump_regmap_mask(PHYCLKRST, SSC_RANGE, 21),
+       dump_regmap(PHYCLKRST, SSC_EN, 20),
+       dump_regmap(PHYCLKRST, REF_SSP_EN, 19),
+       dump_regmap(PHYCLKRST, REF_CLKDIV2, 18),
+       dump_regmap_mask(PHYCLKRST, MPLL_MULTIPLIER, 11),
+       dump_regmap_mask(PHYCLKRST, FSEL, 5),
+       dump_regmap(PHYCLKRST, RETENABLEN, 4),
+       dump_regmap_mask(PHYCLKRST, REFCLKSEL, 2),
+       dump_regmap(PHYCLKRST, PORTRESET, 1),
+       dump_regmap(PHYCLKRST, COMMONONN, 0),
+       dump_regmap_mask(PHYPARAM0, TXVREFTUNE, 22),
+       dump_regmap_mask(PHYPARAM0, TXRISETUNE, 20),
+       dump_regmap_mask(PHYPARAM0, TXRESTUNE, 18),
+       dump_regmap(PHYPARAM0, TXPREEMPPULSETUNE, 17),
+       dump_regmap_mask(PHYPARAM0, TXPREEMPAMPTUNE, 15),
+       dump_regmap_mask(PHYPARAM0, TXHSXVTUNE, 13),
+       dump_regmap_mask(PHYPARAM0, TXFSLSTUNE, 9),
+       dump_regmap_mask(PHYPARAM0, SQRXTUNE, 6),
+       dump_regmap_mask(PHYPARAM0, OTGTUNE, 3),
+       dump_regmap_mask(PHYPARAM0, COMPDISTUNE, 0),
+       dump_regmap(PHYPOWERDOWN, VATESTENB, 6),
+       dump_regmap_mask(PHYPOWERDOWN, TEST_BURNIN, 4),
+       dump_regmap(PHYRESUME, BYPASS_SEL, 4),
+       dump_regmap(PHYRESUME, BYPASS_DM_EN, 3),
+       dump_regmap(PHYRESUME, BYPASS_DP_EN, 2),
+       dump_regmap(PHYRESUME, BYPASS_DM_DATA, 1),
+       dump_regmap(PHYRESUME, BYPASS_DP_DATA, 0),
+       dump_regmap_mask(LINKPORT, HOST_NUM_U2_PORT, 9),
+       dump_regmap(LINKPORT, HOST_U2_PORT_DISABLE, 7),
+       dump_regmap(LINKPORT, PORT_POWER_CONTROL, 6),
+       dump_regmap(LINKPORT, HOST_PORT_OVCR_U2, 4),
+       dump_regmap(LINKPORT, HOST_PORT_OVCR_U2_SEL, 2),
+       dump_regmap(LINKPORT, PERM_ATTACH_U2, 0),
+       dump_regmap(HSPHYCTRL, PHYSWRSTALL, 31),
+       dump_regmap(HSPHYCTRL, SIDDQ, 6),
+       dump_regmap(HSPHYCTRL, PHYSWRST, 0),
+       dump_regmap(HSPHYPLLTUNE, PLL_B_TUNE, 6),
+       dump_regmap_mask(HSPHYPLLTUNE, PLL_I_TUNE, 4),
+       dump_regmap_mask(HSPHYPLLTUNE, PLL_P_TUNE, 0),
+};
+
+static const struct debugfs_regmap32 exynos_usb3drd_regmap[] = {
+       dump_regmap(LINKSYSTEM, HOST_SYSTEM_ERR, 31),
+       dump_regmap(LINKSYSTEM, PHY_POWER_DOWN, 30),
+       dump_regmap(LINKSYSTEM, XHCI_VERSION_CONTROL, 27),
+       dump_regmap(LINKSYSTEM, FORCE_VBUSVALID, 8),
+       dump_regmap(LINKSYSTEM, FORCE_BVALID, 7),
+       dump_regmap_mask(LINKSYSTEM, FLADJ, 1),
+       dump_regmap(PHYUTMI, VBUSVLDEXTSEL, 10),
+       dump_regmap(PHYUTMI, VBUSVLDEXT, 9),
+       dump_regmap(PHYUTMI, TXBITSTUFFENH, 8),
+       dump_regmap(PHYUTMI, TXBITSTUFFEN, 7),
+       dump_regmap(PHYUTMI, OTGDISABLE, 6),
+       dump_regmap(PHYUTMI, IDPULLUP, 5),
+       dump_regmap(PHYUTMI, DRVVBUS, 4),
+       dump_regmap(PHYUTMI, DPPULLDOWN, 3),
+       dump_regmap(PHYUTMI, DMPULLDOWN, 2),
+       dump_regmap(PHYUTMI, FORCESUSPEND, 1),
+       dump_regmap(PHYUTMI, FORCESLEEP, 0),
+       dump_regmap(PHYPIPE, PHY_CLOCK_SEL, 4),
+       dump_regmap(PHYCLKRST, EN_UTMISUSPEND, 31),
+       dump_regmap(PHYCLKRST, SSC_EN, 20),
+       dump_regmap(PHYCLKRST, REF_SSP_EN, 19),
+       dump_regmap(PHYCLKRST, REF_CLKDIV2, 18),
+       dump_regmap_mask(PHYCLKRST, MPLL_MULTIPLIER, 11),
+       dump_regmap_mask(PHYCLKRST, FSEL, 5),
+       dump_regmap(PHYCLKRST, RETENABLEN, 4),
+       dump_regmap_mask(PHYCLKRST, REFCLKSEL, 2),
+       dump_regmap(PHYCLKRST, PORTRESET, 1),
+       dump_regmap(PHYCLKRST, COMMONONN, 0),
+       dump_regmap_mask(PHYREG0, SSC_REFCLKSEL, 23),
+       dump_regmap_mask(PHYREG0, SSC_RANGE, 20),
+       dump_regmap(PHYPARAM0, REF_USE_PAD, 31),
+       dump_regmap_mask(PHYPARAM0, REF_LOSLEVEL, 26),
+       dump_regmap_mask(PHYPARAM0, TXVREFTUNE, 22),
+       dump_regmap_mask(PHYPARAM0, TXRISETUNE, 20),
+       dump_regmap_mask(PHYPARAM0, TXRESTUNE, 18),
+       dump_regmap(PHYPARAM0, TXPREEMPPULSETUNE, 17),
+       dump_regmap_mask(PHYPARAM0, TXPREEMPAMPTUNE, 15),
+       dump_regmap_mask(PHYPARAM0, TXHSXVTUNE, 13),
+       dump_regmap_mask(PHYPARAM0, TXFSLSTUNE, 9),
+       dump_regmap_mask(PHYPARAM0, SQRXTUNE, 6),
+       dump_regmap_mask(PHYPARAM0, OTGTUNE, 3),
+       dump_regmap_mask(PHYPARAM0, COMPDISTUNE, 0),
+       dump_regmap_mask(PHYPARAM1, TX0_TERM_OFFSET, 26),
+       dump_regmap_mask(PHYPARAM1, PCS_TXSWING_FULL, 12),
+       dump_regmap_mask(PHYPARAM1, PCS_TXDEEMPH_3P5DB, 0),
+       dump_regmap(PHYTEST, POWERDOWN_SSP, 3),
+       dump_regmap(PHYTEST, POWERDOWN_HSP, 2),
+       dump_regmap(PHYRESUME, BYPASS_SEL, 4),
+       dump_regmap(PHYRESUME, BYPASS_DM_EN, 3),
+       dump_regmap(PHYRESUME, BYPASS_DP_EN, 2),
+       dump_regmap(PHYRESUME, BYPASS_DM_DATA, 1),
+       dump_regmap(PHYRESUME, BYPASS_DP_DATA, 0),
+       dump_regmap_mask(PHYPCSVAL, PCS_RX_LOS_MASK_VAL, 0),
+       dump_regmap_mask(LINKPORT, HOST_NUM_U3_PORT, 13),
+       dump_regmap_mask(LINKPORT, HOST_NUM_U2_PORT, 9),
+       dump_regmap(LINKPORT, HOST_U3_PORT_DISABLE, 8),
+       dump_regmap(LINKPORT, HOST_U2_PORT_DISABLE, 7),
+       dump_regmap(LINKPORT, PORT_POWER_CONTROL, 6),
+       dump_regmap(LINKPORT, HOST_PORT_OVCR_U3, 5),
+       dump_regmap(LINKPORT, HOST_PORT_OVCR_U2, 4),
+       dump_regmap(LINKPORT, HOST_PORT_OVCR_U3_SEL, 3),
+       dump_regmap(LINKPORT, HOST_PORT_OVCR_U2_SEL, 2),
+       dump_regmap(LINKPORT, PERM_ATTACH_U2, 0),
+       dump_regmap_mask(PHYPARAM2, TX_VBOOST_LVL, 3),
+       dump_regmap_mask(PHYPARAM2, LOS_BIAS, 0),
+};
+
+static int debugfs_phy_power_state(struct exynos_usbdrd_phy *phy_drd, int phy_index)
+{
+       struct regmap *reg_pmu;
+       u32 pmu_offset;
+       int phy_on;
+       int ret;
+
+       reg_pmu = phy_drd->phys[phy_index].reg_pmu;
+       pmu_offset = phy_drd->phys[phy_index].pmu_offset;
+       ret = regmap_read(reg_pmu, pmu_offset, &phy_on);
+       if (ret) {
+               dev_err(phy_drd->dev, "Can't read 0x%x\n", pmu_offset);
+               return ret;
+       }
+       phy_on &= phy_drd->phys[phy_index].pmu_mask;
+
+       return phy_on;
+}
+
+static int debugfs_print_regmap(struct seq_file *s, const struct debugfs_regmap32 *regs,
+                               int nregs, void __iomem *base,
+                               const struct debugfs_reg32 *parent)
+{
+       int i, j = 0;
+       int bit = 0;
+       unsigned int bitmask;
+       int max_string = 24;
+       int calc_tab;
+       u32 bit_value, reg_value;
+
+       reg_value = readl(base + parent->offset);
+       seq_printf(s, "%s (0x%04lx) : 0x%08x\n", parent->name,
+                                                       parent->offset, reg_value);
+       for (i = 0; i < nregs; i++, regs++) {
+               if (!strcmp(regs->name, parent->name)) {
+                       bit_value = (reg_value & regs->bitmask) >> regs->bitoffset;
+
+                       seq_printf(s, "\t%s", regs->bitname);
+                       calc_tab = max_string/8 - strlen(regs->bitname)/8;
+                       for (j = 0 ; j < calc_tab; j++)
+                               seq_printf(s, "\t");
+
+                       if (regs->mask) {
+                               bitmask = regs->bitmask;
+                               bitmask = bitmask >> regs->bitoffset;
+                               while (bitmask) {
+                                       bitmask = bitmask >> 1;
+                                       bit++;
+                               }
+                               seq_printf(s, "[%d:%d]\t: 0x%x\n", (int)regs->bitoffset,
+                                               ((int)regs->bitoffset + bit - 1), bit_value);
+                               bit = 0;
+                       } else {
+                               seq_printf(s, "[%d]\t: 0x%x\n", (int)regs->bitoffset,
+                                                                               bit_value);
+                       }
+               }
+       }
+       return 0;
+
+}
+
+static int debugfs_show_regmap(struct seq_file *s, void *data)
+{
+       struct exynos_debugfs_prvdata *prvdata = s->private;
+       struct debugfs_regset_map *regmap = prvdata->regmap;
+       struct debugfs_regset32 *regset = prvdata->regset;
+       const struct debugfs_reg32 *regs = regset->regs;
+       int phy_on, i = 0;
+
+       phy_on = debugfs_phy_power_state(prvdata->phy_drd, 0);
+       if (phy_on < 0) {
+               seq_printf(s, "can't read PHY register, error : %d\n", phy_on);
+               return -EIO;
+       }
+       if (!phy_on) {
+               seq_printf(s, "can't get PHY register, PHY: Power OFF\n");
+               return 0;
+       }
+       for (i = 0; i < regset->nregs; i++, regs++) {
+               debugfs_print_regmap(s, regmap->regs, regmap->nregs,
+                                               regset->base, regs);
+       }
+
+       return 0;
+}
+
+static int debugfs_open_regmap(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_show_regmap, inode->i_private);
+}
+
+static const struct file_operations fops_regmap = {
+       .open =         debugfs_open_regmap,
+       .read =         seq_read,
+       .llseek =       seq_lseek,
+       .release =      single_release,
+};
+
+int debugfs_print_regdump(struct seq_file *s, struct exynos_usbdrd_phy *phy_drd,
+                               const struct debugfs_reg32 *regs, int nregs,
+                               void __iomem *base)
+{
+       int phy_on;
+       int i;
+
+       for (i = 0; i < EXYNOS_DRDPHYS_NUM; i++) {
+               phy_on = debugfs_phy_power_state(phy_drd, i);
+               if (phy_on < 0) {
+                       seq_printf(s, "can't read PHY register, error : %d\n", phy_on);
+                       return phy_on;
+               }
+               if (!phy_on) {
+                       seq_printf(s, "can't get PHY register, PHY%d : Power OFF\n", i);
+                       continue;
+               }
+
+               for (i = 0; i < nregs; i++, regs++) {
+                       seq_printf(s, "%s", regs->name);
+                       if (strlen(regs->name) < 8)
+                               seq_printf(s, "\t\t");
+                       else
+                               seq_printf(s, "\t");
+
+                       seq_printf(s, "= 0x%08x\n", readl(base + regs->offset));
+               }
+       }
+
+       return 0;
+}
+static int debugfs_show_regdump(struct seq_file *s, void *data)
+{
+       struct exynos_debugfs_prvdata *prvdata = s->private;
+       struct debugfs_regset32 *regset = prvdata->regset;
+       int ret;
+
+       ret = debugfs_print_regdump(s, prvdata->phy_drd, regset->regs,
+                                       regset->nregs, regset->base);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int debugfs_open_regdump(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_show_regdump, inode->i_private);
+}
+
+static const struct file_operations fops_regdump = {
+       .open =         debugfs_open_regdump,
+       .read =         seq_read,
+       .llseek =       seq_lseek,
+       .release =      single_release,
+};
+static int debugfs_show_bitset(struct seq_file *s, void *data)
+{
+       char *b_name = s->private;
+       struct debugfs_regset_map *regmap = prvdata->regmap;
+       const struct debugfs_regmap32 *cmp = regmap->regs;
+       const struct debugfs_regmap32 *regs;
+       unsigned int bitmask;
+       int i, bit = 0;
+       u32 reg_value, bit_value;
+       u32 detect_regs = 0;
+
+       for (i = 0; i < regmap->nregs; i++, cmp++) {
+               if (!strcmp(cmp->bitname, b_name)) {
+                       regs = cmp;
+                       detect_regs = 1;
+                       break;
+               }
+       }
+
+       if (!detect_regs)
+               return -EINVAL;
+
+       reg_value = readl(prvdata->regset->base + regs->offset);
+       bit_value = (reg_value & regs->bitmask) >> regs->bitoffset;
+       if (regs->mask) {
+               bitmask = regs->bitmask;
+               bitmask = bitmask >> regs->bitoffset;
+               while (bitmask) {
+                       bitmask = bitmask >> 1;
+                       bit++;
+               }
+               seq_printf(s, "%s [%d:%d] = 0x%x\n", regs->name,
+                               (int)regs->bitoffset,
+                               ((int)regs->bitoffset + bit - 1), bit_value);
+       } else {
+               seq_printf(s, "%s [%d] = 0x%x\n", regs->name,
+                               (int)regs->bitoffset, bit_value);
+       }
+       return 0;
+}
+static ssize_t debugfs_write_regset(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       char *reg_name = s->private;
+       struct debugfs_regset32 *regset = prvdata->regset;
+       const struct debugfs_reg32 *regs = regset->regs;
+       unsigned long value;
+       char buf[8];
+       int i;
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       value = simple_strtol(buf, NULL, 16);
+
+       for (i = 0; i < regset->nregs; i++, regs++) {
+               if (!strcmp(regs->name, reg_name))
+                       break;
+       }
+
+       writel(value, regset->base + regs->offset);
+
+       return count;
+}
+static ssize_t debugfs_write_bitset(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       char *b_name = s->private;
+       struct debugfs_regset_map *regmap = prvdata->regmap;
+       const struct debugfs_regmap32 *regs = regmap->regs;
+       unsigned long value;
+       char buf[32];
+       int i;
+       u32 reg_value;
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
+               seq_printf(s, "%s, write error\n", __func__);
+               return -EFAULT;
+       }
+       value = simple_strtol(buf, NULL, 2);
+
+       for (i = 0; i < regmap->nregs; i++, regs++) {
+               if (!strcmp(regs->bitname, b_name))
+                       break;
+       }
+
+       value = value << regs->bitoffset;
+       reg_value = readl(prvdata->regset->base + regs->offset);
+       reg_value &= ~(regs->bitmask);
+       reg_value |= (u32)value;
+       writel(reg_value, prvdata->regset->base + regs->offset);
+
+       return count;
+}
+
+static int debugfs_open_bitset(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_show_bitset, inode->i_private);
+}
+
+static int debugfs_show_regset(struct seq_file *s, void *data)
+{
+       char *p_name = s->private;
+       struct debugfs_regset32 *regset = prvdata->regset;
+       struct debugfs_regset_map *regmap = prvdata->regmap;
+       const struct debugfs_reg32 *regs = regset->regs;
+       const struct debugfs_reg32 *parents;
+       u32 detect_regs = 0;
+
+
+       int i;
+
+       for (i = 0; i < regset->nregs; i++, regs++) {
+               if (!strcmp(regs->name, p_name)) {
+                       parents = regs;
+                       detect_regs = 1;
+                       break;
+               }
+       }
+       if (!detect_regs)
+               return -EINVAL;
+
+       debugfs_print_regmap(s, prvdata->regmap->regs, regmap->nregs,
+                                               regset->base, parents);
+
+       return 0;
+}
+
+static int debugfs_open_regset(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_show_regset, inode->i_private);
+}
+
+static const struct file_operations fops_regset = {
+       .open =         debugfs_open_regset,
+       .write =        debugfs_write_regset,
+       .read =         seq_read,
+       .llseek =       seq_lseek,
+       .release =      single_release,
+};
+
+static const struct file_operations fops_bitset = {
+       .open =         debugfs_open_bitset,
+       .write =        debugfs_write_bitset,
+       .read =         seq_read,
+       .llseek =       seq_lseek,
+       .release =      single_release,
+};
+
+static int debugfs_create_regfile(struct exynos_debugfs_prvdata *prvdata,
+                                       const struct debugfs_reg32 *parents,
+                                       struct dentry *root)
+{
+       struct debugfs_regset_map *regmap = prvdata->regmap;
+       const struct debugfs_regmap32 *regs = regmap->regs;
+       struct dentry *file;
+       int i, ret;
+
+       file = debugfs_create_file(parents->name, S_IRUGO | S_IWUGO, root,
+                                                       parents->name, &fops_regset);
+       if (!file) {
+               ret = -ENOMEM;
+               return ret;
+       }
+       for (i = 0; i < regmap->nregs; i++, regs++) {
+               if (!strcmp(regs->name, parents->name)) {
+                       file = debugfs_create_file(regs->bitname, S_IRUGO | S_IWUGO,
+                                       root, regs->bitname, &fops_bitset);
+                       if (!file) {
+                               ret = -ENOMEM;
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int debugfs_create_regdir(struct exynos_debugfs_prvdata *prvdata,
+                                               struct dentry *root)
+{
+       struct exynos_usbdrd_phy *phy_drd = prvdata->phy_drd;
+       struct debugfs_regset32 *regset = prvdata->regset;
+       const struct debugfs_reg32 *regs = regset->regs;
+       struct dentry   *dir;
+       int ret, i;
+
+       for (i = 0; i < regset->nregs; i++, regs++) {
+               dir = debugfs_create_dir(regs->name, root);
+               if (!dir) {
+                       dev_err(phy_drd->dev, "failed to create '%s' reg dir",
+                                                               regs->name);
+                       return -ENOMEM;
+               }
+               ret = debugfs_create_regfile(prvdata, regs, dir);
+               if (ret < 0) {
+                       dev_err(phy_drd->dev, "failed to create bitfile for %s, error : %d\n",
+                                               regs->name, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+int exynos_usbdrd_debugfs_init(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device   *dev = phy_drd->dev;
+       struct dentry   *root;
+       struct dentry   *dir;
+       struct dentry   *file;
+       u32 version = phy_drd->usbphy_info.version;
+       int             ret;
+
+
+       root = debugfs_create_dir(dev_name(dev), NULL);
+       if (!root) {
+               dev_err(dev, "failed to create root directory for USBPHY debugfs");
+               ret = -ENOMEM;
+               goto err0;
+       }
+
+       prvdata = devm_kmalloc(dev, sizeof(struct exynos_debugfs_prvdata), GFP_KERNEL);
+       if (!prvdata) {
+               dev_err(dev, "failed to alloc private data for debugfs");
+               ret = -ENOMEM;
+               goto err1;
+       }
+       prvdata->root = root;
+       prvdata->phy_drd = phy_drd;
+
+       prvdata->regset = devm_kmalloc(dev, sizeof(*prvdata->regset), GFP_KERNEL);
+       if (!prvdata->regset) {
+               dev_err(dev, "failed to alloc regmap");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       if ((version >= EXYNOS_USBCON_VER_02_0_0) &&
+                       (version <= EXYNOS_USBCON_VER_02_MAX)) {
+               /* for USB2PHY */
+               prvdata->regset->regs = exynos_usb2drd_regs;
+               prvdata->regset->nregs = ARRAY_SIZE(exynos_usb2drd_regs);
+       } else if ((version >= EXYNOS_USBCON_VER_03_0_0) &&
+                       (version <= EXYNOS_USBCON_VER_03_MAX)) {
+               /* for USB3PHY Lhotse */
+               prvdata->regset->regs = exynos_usb3drd_phycon_regs;
+               prvdata->regset->nregs = ARRAY_SIZE(exynos_usb3drd_phycon_regs);
+       } else {
+               /* for USB3PHY */
+               prvdata->regset->regs = exynos_usb3drd_regs;
+               prvdata->regset->nregs = ARRAY_SIZE(exynos_usb3drd_regs);
+       }
+       prvdata->regset->base = phy_drd->reg_phy;
+
+       prvdata->regmap = devm_kmalloc(dev, sizeof(*prvdata->regmap), GFP_KERNEL);
+       if (!prvdata->regmap) {
+               dev_err(dev, "failed to alloc regmap");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       if ((version >= EXYNOS_USBCON_VER_02_0_0) &&
+               /* for USB2PHY */
+               (version <= EXYNOS_USBCON_VER_02_MAX)) {
+               prvdata->regmap->regs = exynos_usb2drd_regmap;
+               prvdata->regmap->nregs = ARRAY_SIZE(exynos_usb2drd_regmap);
+       } else if ((version >= EXYNOS_USBCON_VER_03_0_0) &&
+                       (version <= EXYNOS_USBCON_VER_03_MAX)) {
+               /* for USB3PHY Lhotse */
+               prvdata->regmap->regs = exynos_usb3drd_phycon_regmap;
+               prvdata->regmap->nregs = ARRAY_SIZE(exynos_usb3drd_phycon_regmap);
+       } else {
+               /* for USB3PHY */
+               prvdata->regmap->regs = exynos_usb3drd_regmap;
+               prvdata->regmap->nregs = ARRAY_SIZE(exynos_usb3drd_regmap);
+       }
+
+       file = debugfs_create_file("regdump", S_IRUGO, root, prvdata, &fops_regdump);
+       if (!file) {
+               dev_err(dev, "failed to create file for register dump");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       file = debugfs_create_file("regmap", S_IRUGO, root, prvdata, &fops_regmap);
+       if (!file) {
+               dev_err(dev, "failed to create file for register dump");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       dir = debugfs_create_dir("regset", root);
+       if (!dir) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       ret = debugfs_create_regdir(prvdata, dir);
+       if (ret < 0) {
+               dev_err(dev, "failed to create regfile, error = %d\n", ret);
+               goto err1;
+       }
+
+
+       return 0;
+
+err1:
+       debugfs_remove_recursive(root);
+err0:
+       return ret;
+}
diff --git a/drivers/phy/samsung/phy-exynos-displayport.c b/drivers/phy/samsung/phy-exynos-displayport.c
new file mode 100644 (file)
index 0000000..57d9ef5
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Samsung EXYNOS SoC series MIPI DISPLAYPORT PHY driver
+ *
+ * Copyright (C) 2016 Samsung Electronics Co., Ltd.
+ * Author: Kwangje Kim <kj1.kim@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/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+
+#define EXYNOS_DISPLAYPORT_PHY_ISO_BYPASS  (1 << 0)
+
+struct exynos_displayport_phy {
+       struct device *dev;
+       spinlock_t slock;
+       void __iomem *regs;
+       struct regmap *reg_pmu;
+       struct displayport_phy_desc {
+               struct phy *phy;
+               unsigned int iso_offset;
+       } phys;
+};
+
+/* 1: Isolation bypass, 0: Isolation enable */
+static int __set_phy_isolation(struct regmap *reg_pmu,
+               unsigned int offset, unsigned int on)
+{
+       unsigned int val;
+       int ret;
+
+       val = on ? EXYNOS_DISPLAYPORT_PHY_ISO_BYPASS : 0;
+
+       ret = regmap_update_bits(reg_pmu, offset,
+                       EXYNOS_DISPLAYPORT_PHY_ISO_BYPASS, val);
+
+       pr_debug("%s off=0x%x, val=0x%x\n", __func__, offset, val);
+       return ret;
+}
+
+static const struct of_device_id exynos_displayport_phy_of_table[] = {
+       { .compatible = "samsung,displayport-phy" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, exynos_displayport_phy_of_table);
+
+#define to_displayport_phy(desc) \
+       container_of((desc), struct exynos_displayport_phy, phys)
+
+static int exynos_displayport_phy_power_on(struct phy *phy)
+{
+       struct displayport_phy_desc *phy_desc = phy_get_drvdata(phy);
+       struct exynos_displayport_phy *state = to_displayport_phy(phy_desc);
+
+       return __set_phy_isolation(state->reg_pmu, phy_desc->iso_offset, 1);
+}
+
+static int exynos_displayport_phy_power_off(struct phy *phy)
+{
+       struct displayport_phy_desc *phy_desc = phy_get_drvdata(phy);
+       struct exynos_displayport_phy *state = to_displayport_phy(phy_desc);
+
+       return __set_phy_isolation(state->reg_pmu, phy_desc->iso_offset, 0);
+}
+
+static struct phy *exynos_displayport_phy_of_xlate(struct device *dev,
+                                       struct of_phandle_args *args)
+{
+       struct exynos_displayport_phy *state = dev_get_drvdata(dev);
+
+       return state->phys.phy;
+}
+
+static struct phy_ops exynos_displayport_phy_ops = {
+       .power_on       = exynos_displayport_phy_power_on,
+       .power_off      = exynos_displayport_phy_power_off,
+       .owner          = THIS_MODULE,
+};
+
+static int exynos_displayport_phy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       struct exynos_displayport_phy *state;
+       struct phy_provider *phy_provider;
+       const struct of_device_id *of_id;
+       struct phy *generic_phy;
+       unsigned int iso[1];
+       unsigned int elements;
+       int ret = 0;
+
+       state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       state->dev = &pdev->dev;
+
+       of_id = of_match_device(of_match_ptr(exynos_displayport_phy_of_table), dev);
+       if (!of_id)
+               return -EINVAL;
+
+       dev_set_drvdata(dev, state);
+       spin_lock_init(&state->slock);
+
+       state->reg_pmu = syscon_regmap_lookup_by_phandle(node,
+                                               "samsung,pmu-syscon");
+       if (IS_ERR(state->reg_pmu)) {
+               dev_err(dev, "Failed to lookup PMU regmap\n");
+               return PTR_ERR(state->reg_pmu);
+       }
+
+       elements = of_property_count_u32_elems(node, "isolation");
+       ret = of_property_read_u32_array(node, "isolation", iso, elements);
+       if (ret) {
+               dev_err(dev, "cannot get displayport-phy isolation!!!\n");
+               return ret;
+       }
+
+       state->phys.iso_offset = iso[0];
+       dev_dbg(dev, "%s: iso 0x%x\n", __func__, state->phys.iso_offset);
+
+       generic_phy = devm_phy_create(dev, NULL,
+                               &exynos_displayport_phy_ops);
+       if (IS_ERR(generic_phy)) {
+               dev_err(dev, "failed to create PHY\n");
+               return PTR_ERR(generic_phy);
+       }
+
+       state->phys.phy = generic_phy;
+
+       phy_set_drvdata(generic_phy, &state->phys);
+
+       phy_provider = devm_of_phy_provider_register(dev,
+                       exynos_displayport_phy_of_xlate);
+
+       if (IS_ERR(phy_provider))
+               dev_err(dev, "failed to create exynos displayport-phy\n");
+       else
+               dev_err(dev, "Creating exynos-displayport-phy\n");
+
+       return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static int exynos_displayport_phy_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+
+       dev_info(dev, "%s, successfully removed\n", __func__);
+       return 0;
+}
+
+static struct platform_driver exynos_displayport_phy_driver = {
+       .probe  = exynos_displayport_phy_probe,
+       .remove = exynos_displayport_phy_remove,
+       .driver = {
+               .name  = "exynos-displayport-phy",
+               .of_match_table = of_match_ptr(exynos_displayport_phy_of_table),
+               .suppress_bind_attrs = true,
+       }
+};
+module_platform_driver(exynos_displayport_phy_driver);
+
+MODULE_DESCRIPTION("Samsung EXYNOS SoC DISPLAYPORT PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/samsung/phy-exynos-dp-debugfs.c b/drivers/phy/samsung/phy-exynos-dp-debugfs.c
new file mode 100644 (file)
index 0000000..78b66b5
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * Samsung EXYNOS SoC series USB DRD PHY DebugFS file
+ *
+ * Phy provider for USB 3.0 DRD controller on Exynos SoC series
+ *
+ * Copyright (C) 2016 Samsung Electronics Co., Ltd.
+ * Author: Kyounghye Yun <k-hye.yun@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/io.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+
+#include <linux/usb/ch9.h>
+#include "phy-exynos-usbdrd.h"
+#include "phy-exynos-usbdp-reg.h"
+#include "phy-exynos-debug.h"
+
+static struct exynos_debugfs_prvdata *prvdata_dp;
+
+/* PHY Combo DP register set */
+static const struct debugfs_reg32 exynos_usb3drd_dp_regs[] = {
+       dump_register_dp(TRSV_R01),
+       dump_register_dp(TRSV_R02),
+       dump_register_dp(TRSV_R03),
+       dump_register_dp(TRSV_R04),
+       dump_register_dp(TRSV_R0C),
+};
+
+/* PHY Combo DP register set */
+static const struct debugfs_regmap32 exynos_usb3drd_dp_regmap[] = {
+       dump_regmap_dp_mask(TRSV_R01, USBDP_TRSV01, RXAFE_LEQ_ISEL_GEN2, 6),
+       dump_regmap_dp_mask(TRSV_R01, USBDP_TRSV01, RXAFE_LEQ_ISEL_GEN1, 4),
+       dump_regmap_dp_mask(TRSV_R01, USBDP_TRSV01, RXAFE_CTLE_SEL, 2),
+       dump_regmap_dp_mask(TRSV_R01, USBDP_TRSV01, RXAFE_SCLBUF_EN, 0),
+       dump_regmap_dp_mask(TRSV_R02, USBDP_TRSV02, RXAFE_LEQ_CSEL_GEN2, 4),
+       dump_regmap_dp_mask(TRSV_R02, USBDP_TRSV02, RXAFE_LEQ_CSEL_GEN1, 0),
+       dump_regmap_dp_mask(TRSV_R03, USBDP_TRSV03, RXAFE_LEQ_RSEL_GEN2, 3),
+       dump_regmap_dp_mask(TRSV_R03, USBDP_TRSV03, RXAFE_LEQ_RSEL_GEN1, 0),
+       dump_regmap_dp_mask(TRSV_R04, USBDP_TRSV04, RXAFE_SQ_VFFSET_CTRL, 0),
+       dump_regmap_dp_mask(TRSV_R0C, USBDP_TRSV0C, MAN_TX_DE_EMP_LVL, 4),
+       dump_regmap_dp_mask(TRSV_R0C, USBDP_TRSV0C, MAN_TX_DRVR_LVL, 0),
+};
+
+static int debugfs_phy_power_state(struct exynos_usbdrd_phy *phy_drd, int phy_index)
+{
+       struct regmap *reg_pmu;
+       u32 pmu_offset;
+       int phy_on;
+       int ret;
+
+       reg_pmu = phy_drd->phys[phy_index].reg_pmu;
+       pmu_offset = phy_drd->phys[phy_index].pmu_offset;
+       ret = regmap_read(reg_pmu, pmu_offset, &phy_on);
+       if (ret) {
+               dev_err(phy_drd->dev, "Can't read 0x%x\n", pmu_offset);
+               return ret;
+       }
+       phy_on &= phy_drd->phys[phy_index].pmu_mask;
+
+       return phy_on;
+}
+
+static int debugfs_print_regmap(struct seq_file *s, const struct debugfs_regmap32 *regs,
+                               int nregs, void __iomem *base,
+                               const struct debugfs_reg32 *parent)
+{
+       int i, j = 0;
+       int bit = 0;
+       unsigned int bitmask;
+       int max_string = 24;
+       int calc_tab;
+       u32 bit_value, reg_value;
+
+       reg_value = readl(base + parent->offset);
+       seq_printf(s, "%s (0x%04lx) : 0x%08x\n", parent->name,
+                                                       parent->offset, reg_value);
+       for (i = 0; i < nregs; i++, regs++) {
+               if (!strcmp(regs->name, parent->name)) {
+                       bit_value = (reg_value & regs->bitmask) >> regs->bitoffset;
+
+                       seq_printf(s, "\t%s", regs->bitname);
+                       calc_tab = max_string/8 - strlen(regs->bitname)/8;
+                       for (j = 0 ; j < calc_tab; j++)
+                               seq_puts(s, "\t");
+
+                       if (regs->mask) {
+                               bitmask = regs->bitmask;
+                               bitmask = bitmask >> regs->bitoffset;
+                               while (bitmask) {
+                                       bitmask = bitmask >> 1;
+                                       bit++;
+                               }
+                               seq_printf(s, "[%d:%d]\t: 0x%x\n", (int)regs->bitoffset,
+                                               ((int)regs->bitoffset + bit - 1), bit_value);
+                               bit = 0;
+                       } else {
+                               seq_printf(s, "[%d]\t: 0x%x\n", (int)regs->bitoffset,
+                                                                               bit_value);
+                       }
+               }
+       }
+       return 0;
+
+}
+
+static int debugfs_show_regmap(struct seq_file *s, void *data)
+{
+       struct exynos_debugfs_prvdata *prvdata = s->private;
+       struct debugfs_regset_map *regmap = prvdata->regmap;
+       struct debugfs_regset32 *regset = prvdata->regset;
+       const struct debugfs_reg32 *regs = regset->regs;
+       int phy_on, i = 0;
+
+       phy_on = debugfs_phy_power_state(prvdata->phy_drd, 0);
+       if (phy_on < 0) {
+               seq_printf(s, "can't read PHY register, error : %d\n", phy_on);
+               return -EIO;
+       }
+       if (!phy_on) {
+               seq_puts(s, "can't get PHY register, PHY: Power OFF\n");
+               return 0;
+       }
+       for (i = 0; i < regset->nregs; i++, regs++) {
+               debugfs_print_regmap(s, regmap->regs, regmap->nregs,
+                                               regset->base, regs);
+       }
+
+       return 0;
+}
+
+static int debugfs_open_regmap(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_show_regmap, inode->i_private);
+}
+
+static const struct file_operations fops_regmap = {
+       .open =         debugfs_open_regmap,
+       .read =         seq_read,
+       .llseek =       seq_lseek,
+       .release =      single_release,
+};
+
+static int debugfs_print_regdump(struct seq_file *s, struct exynos_usbdrd_phy *phy_drd,
+                               const struct debugfs_reg32 *regs, int nregs,
+                               void __iomem *base)
+{
+       int phy_on;
+       int i;
+
+       for (i = 0; i < EXYNOS_DRDPHYS_NUM; i++) {
+               phy_on = debugfs_phy_power_state(phy_drd, i);
+               if (phy_on < 0) {
+                       seq_printf(s, "can't read PHY register, error : %d\n", phy_on);
+                       return phy_on;
+               }
+               if (!phy_on) {
+                       seq_printf(s, "can't get PHY register, PHY%d : Power OFF\n", i);
+                       continue;
+               }
+
+               for (i = 0; i < nregs; i++, regs++) {
+                       seq_printf(s, "%s", regs->name);
+                       if (strlen(regs->name) < 8)
+                               seq_puts(s, "\t\t");
+                       else
+                               seq_puts(s, "\t");
+
+                       seq_printf(s, "= 0x%08x\n", readl(base + regs->offset));
+               }
+       }
+
+       return 0;
+}
+static int debugfs_show_regdump(struct seq_file *s, void *data)
+{
+       struct exynos_debugfs_prvdata *prvdata = s->private;
+       struct debugfs_regset32 *regset = prvdata->regset;
+       int ret;
+
+       ret = debugfs_print_regdump(s, prvdata->phy_drd, regset->regs,
+                                       regset->nregs, regset->base);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int debugfs_open_regdump(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_show_regdump, inode->i_private);
+}
+
+static const struct file_operations fops_regdump = {
+       .open =         debugfs_open_regdump,
+       .read =         seq_read,
+       .llseek =       seq_lseek,
+       .release =      single_release,
+};
+static int debugfs_show_bitset(struct seq_file *s, void *data)
+{
+       char *b_name = s->private;
+       struct debugfs_regset_map *regmap = prvdata_dp->regmap;
+       const struct debugfs_regmap32 *cmp = regmap->regs;
+       const struct debugfs_regmap32 *regs;
+       unsigned int bitmask;
+       int i, bit = 0;
+       u32 reg_value, bit_value;
+       u32 detect_regs = 0;
+
+       for (i = 0; i < regmap->nregs; i++, cmp++) {
+               if (!strcmp(cmp->bitname, b_name)) {
+                       regs = cmp;
+                       detect_regs = 1;
+                       break;
+               }
+       }
+
+       if (!detect_regs)
+               return -EINVAL;
+
+       reg_value = readl(prvdata_dp->regset->base + regs->offset);
+       bit_value = (reg_value & regs->bitmask) >> regs->bitoffset;
+       if (regs->mask) {
+               bitmask = regs->bitmask;
+               bitmask = bitmask >> regs->bitoffset;
+               while (bitmask) {
+                       bitmask = bitmask >> 1;
+                       bit++;
+               }
+               seq_printf(s, "%s [%d:%d] = 0x%x\n", regs->name,
+                               (int)regs->bitoffset,
+                               ((int)regs->bitoffset + bit - 1), bit_value);
+       } else {
+               seq_printf(s, "%s [%d] = 0x%x\n", regs->name,
+                               (int)regs->bitoffset, bit_value);
+       }
+       return 0;
+}
+static ssize_t debugfs_write_regset(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       char *reg_name = s->private;
+       struct debugfs_regset32 *regset = prvdata_dp->regset;
+       const struct debugfs_reg32 *regs = regset->regs;
+       unsigned long value;
+       char buf[8];
+       int i;
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       value = simple_strtol(buf, NULL, 16);
+
+       for (i = 0; i < regset->nregs; i++, regs++) {
+               if (!strcmp(regs->name, reg_name))
+                       break;
+       }
+
+       writel(value, regset->base + regs->offset);
+
+       return count;
+}
+static ssize_t debugfs_write_bitset(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file *s = file->private_data;
+       char *b_name = s->private;
+       struct debugfs_regset_map *regmap = prvdata_dp->regmap;
+       const struct debugfs_regmap32 *regs = regmap->regs;
+       unsigned long value;
+       char buf[32];
+       int i;
+       u32 reg_value;
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
+               seq_printf(s, "%s, write error\n", __func__);
+               return -EFAULT;
+       }
+       value = simple_strtol(buf, NULL, 2);
+
+       for (i = 0; i < regmap->nregs; i++, regs++) {
+               if (!strcmp(regs->bitname, b_name))
+                       break;
+       }
+
+       value = value << regs->bitoffset;
+       reg_value = readl(prvdata_dp->regset->base + regs->offset);
+       reg_value &= ~(regs->bitmask);
+       reg_value |= (u32)value;
+       writel(reg_value, prvdata_dp->regset->base + regs->offset);
+
+       return count;
+}
+
+static int debugfs_open_bitset(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_show_bitset, inode->i_private);
+}
+
+static int debugfs_show_regset(struct seq_file *s, void *data)
+{
+       char *p_name = s->private;
+       struct debugfs_regset32 *regset = prvdata_dp->regset;
+       struct debugfs_regset_map *regmap = prvdata_dp->regmap;
+       const struct debugfs_reg32 *regs = regset->regs;
+       const struct debugfs_reg32 *parents;
+       u32 detect_regs = 0;
+
+
+       int i;
+
+       for (i = 0; i < regset->nregs; i++, regs++) {
+               if (!strcmp(regs->name, p_name)) {
+                       parents = regs;
+                       detect_regs = 1;
+                       break;
+               }
+       }
+       if (!detect_regs)
+               return -EINVAL;
+
+       debugfs_print_regmap(s, prvdata_dp->regmap->regs, regmap->nregs,
+                                               regset->base, parents);
+
+       return 0;
+}
+
+static int debugfs_open_regset(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_show_regset, inode->i_private);
+}
+
+static const struct file_operations fops_regset = {
+       .open =         debugfs_open_regset,
+       .write =        debugfs_write_regset,
+       .read =         seq_read,
+       .llseek =       seq_lseek,
+       .release =      single_release,
+};
+
+static const struct file_operations fops_bitset = {
+       .open =         debugfs_open_bitset,
+       .write =        debugfs_write_bitset,
+       .read =         seq_read,
+       .llseek =       seq_lseek,
+       .release =      single_release,
+};
+
+static int debugfs_create_regfile(struct exynos_debugfs_prvdata *prvdata,
+                                       const struct debugfs_reg32 *parents,
+                                       struct dentry *root)
+{
+       struct debugfs_regset_map *regmap = prvdata->regmap;
+       const struct debugfs_regmap32 *regs = regmap->regs;
+       struct dentry *file;
+       int i, ret;
+
+       file = debugfs_create_file(parents->name, 0644, root,
+                                                       parents->name, &fops_regset);
+       if (!file) {
+               ret = -ENOMEM;
+               return ret;
+       }
+       for (i = 0; i < regmap->nregs; i++, regs++) {
+               if (!strcmp(regs->name, parents->name)) {
+                       file = debugfs_create_file(regs->bitname, 0644,
+                                       root, regs->bitname, &fops_bitset);
+                       if (!file) {
+                               ret = -ENOMEM;
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int debugfs_create_regdir(struct exynos_debugfs_prvdata *prvdata,
+                                               struct dentry *root)
+{
+       struct exynos_usbdrd_phy *phy_drd = prvdata->phy_drd;
+       struct debugfs_regset32 *regset = prvdata->regset;
+       const struct debugfs_reg32 *regs = regset->regs;
+       struct dentry   *dir;
+       int ret, i;
+
+       for (i = 0; i < regset->nregs; i++, regs++) {
+               dir = debugfs_create_dir(regs->name, root);
+               if (!dir) {
+                       dev_err(phy_drd->dev, "failed to create '%s' reg dir",
+                                                               regs->name);
+                       return -ENOMEM;
+               }
+               ret = debugfs_create_regfile(prvdata, regs, dir);
+               if (ret < 0) {
+                       dev_err(phy_drd->dev, "failed to create bitfile for %s, error : %d\n",
+                                               regs->name, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+int exynos_usbdrd_dp_debugfs_init(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device   *dev = phy_drd->dev;
+       struct dentry   *root;
+       struct dentry   *dir;
+       struct dentry   *file;
+       u32 version = phy_drd->usbphy_sub_info.version;
+       int             ret;
+
+       root = debugfs_create_dir("110a0000.usbdp", NULL);
+       if (!root) {
+               dev_err(dev, "failed to create root directory for USBPHY debugfs");
+               ret = -ENOMEM;
+               goto err0;
+       }
+
+       prvdata_dp = devm_kmalloc(dev, sizeof(struct exynos_debugfs_prvdata), GFP_KERNEL);
+       if (!prvdata_dp) {
+               dev_err(dev, "failed to alloc private data for debugfs");
+               ret = -ENOMEM;
+               goto err1;
+       }
+       prvdata_dp->root = root;
+       prvdata_dp->phy_drd = phy_drd;
+
+       prvdata_dp->regset = devm_kmalloc(dev, sizeof(*prvdata_dp->regset), GFP_KERNEL);
+       if (!prvdata_dp->regset) {
+               dev_err(dev, "failed to alloc regmap");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       if (phy_drd->usbphy_sub_info.version == EXYNOS_USBCON_VER_04_0_0) {
+               /* for USB3PHY Lhotse */
+               prvdata_dp->regset->regs = exynos_usb3drd_dp_regs;
+               prvdata_dp->regset->nregs = ARRAY_SIZE(exynos_usb3drd_dp_regs);
+       }
+
+       prvdata_dp->regset->base = phy_drd->reg_phy2;
+
+       prvdata_dp->regmap = devm_kmalloc(dev, sizeof(*prvdata_dp->regmap), GFP_KERNEL);
+       if (!prvdata_dp->regmap) {
+               dev_err(dev, "failed to alloc regmap");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       if (version == EXYNOS_USBCON_VER_04_0_0) {
+               /* for USB3PHY Lhotse */
+               prvdata_dp->regmap->regs = exynos_usb3drd_dp_regmap;
+               prvdata_dp->regmap->nregs = ARRAY_SIZE(exynos_usb3drd_dp_regmap);
+       }
+
+       file = debugfs_create_file("regdump", 0444, root, prvdata_dp, &fops_regdump);
+       if (!file) {
+               dev_err(dev, "failed to create file for register dump");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       file = debugfs_create_file("regmap", 0444, root, prvdata_dp, &fops_regmap);
+       if (!file) {
+               dev_err(dev, "failed to create file for register dump");
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       dir = debugfs_create_dir("regset", root);
+       if (!dir) {
+               ret = -ENOMEM;
+               goto err1;
+       }
+
+       ret = debugfs_create_regdir(prvdata_dp, dir);
+       if (ret < 0) {
+               dev_err(dev, "failed to create regfile, error = %d\n", ret);
+               goto err1;
+       }
+
+
+       return 0;
+
+err1:
+       debugfs_remove_recursive(root);
+err0:
+       return ret;
+}
diff --git a/drivers/phy/samsung/phy-exynos-mipi.c b/drivers/phy/samsung/phy-exynos-mipi.c
new file mode 100644 (file)
index 0000000..0173ca2
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+ * Samsung EXYNOS SoC series MIPI CSI/DSI D/C-PHY driver
+ *
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
+ *             http://www.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/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <soc/samsung/exynos-pmu.h>
+
+/* the maximum number of PHY for each module */
+#define EXYNOS_MIPI_PHYS_NUM   4
+
+#define EXYNOS_MIPI_PHY_ISO_BYPASS  BIT(0)
+
+#define MIPI_PHY_MxSx_UNIQUE   (0 << 1)
+#define MIPI_PHY_MxSx_SHARED   (1 << 1)
+#define MIPI_PHY_MxSx_INIT_DONE        (2 << 1)
+
+enum exynos_mipi_phy_owner {
+       EXYNOS_MIPI_PHY_OWNER_DSIM = 0,
+       EXYNOS_MIPI_PHY_OWNER_CSIS = 1,
+};
+
+/* per MIPI-PHY module */
+struct exynos_mipi_phy_data {
+       u8 flags;
+       int active_count;
+       spinlock_t slock;
+};
+
+#define MKVER(ma, mi)  (((ma) << 16) | (mi))
+enum phy_infos {
+       VERSION,
+       TYPE,
+       LANES,
+       SPEED,
+       SETTLE,
+};
+
+struct exynos_mipi_phy_cfg {
+       u16 major;
+       u16 minor;
+       u32 type;
+       /* u32 max_speed */
+       int (*set)(void __iomem *regs, int option, u32 *info);
+};
+
+/* per DT MIPI-PHY node, can have multiple elements */
+struct exynos_mipi_phy {
+       struct device *dev;
+       spinlock_t slock;
+       struct regmap *reg_pmu;
+       struct regmap *reg_reset;
+       enum exynos_mipi_phy_owner owner;
+       struct mipi_phy_desc {
+               struct phy *phy;
+               struct exynos_mipi_phy_data *data;
+               unsigned int index;
+               unsigned int iso_offset;
+               unsigned int rst_bit;
+               void __iomem *regs;
+       } phys[EXYNOS_MIPI_PHYS_NUM];
+};
+
+/* 1: Isolation bypass, 0: Isolation enable */
+static int __set_phy_isolation(struct regmap *reg_pmu,
+               unsigned int offset, unsigned int on)
+{
+       unsigned int val;
+       int ret;
+
+       val = on ? EXYNOS_MIPI_PHY_ISO_BYPASS : 0;
+
+       if (reg_pmu)
+               ret = regmap_update_bits(reg_pmu, offset,
+                       EXYNOS_MIPI_PHY_ISO_BYPASS, val);
+       else
+               ret = exynos_pmu_update(offset,
+                       EXYNOS_MIPI_PHY_ISO_BYPASS, val);
+
+       if (ret)
+               pr_err("%s failed to %s PHY isolation 0x%x\n",
+                               __func__, on ? "set" : "clear", offset);
+
+       pr_debug("%s off=0x%x, val=0x%x\n", __func__, offset, val);
+
+       return ret;
+}
+
+/* 1: Enable reset -> release reset, 0: Enable reset */
+static int __set_phy_reset(struct regmap *reg_reset,
+               unsigned int bit, unsigned int on)
+{
+       unsigned int cfg;
+       int ret = 0;
+
+       if (!reg_reset)
+               return 0;
+
+       ret = regmap_update_bits(reg_reset, 0, BIT(bit), 0);
+       if (ret)
+               pr_err("%s failed to reset PHY(%d)\n", __func__, bit);
+
+       if (on) {
+               ret = regmap_update_bits(reg_reset, 0, BIT(bit), BIT(bit));
+               if (ret)
+                       pr_err("%s failed to release reset PHY(%d)\n",
+                                       __func__, bit);
+       }
+
+       regmap_read(reg_reset, 0, &cfg);
+       pr_debug("%s bit=%d, cfg=0x%x\n", __func__, bit, cfg);
+
+       return ret;
+}
+
+static int __set_phy_init(struct exynos_mipi_phy *state,
+               struct mipi_phy_desc *phy_desc, unsigned int on)
+{
+       unsigned int cfg;
+       int ret = 0;
+
+       if (state->reg_pmu)
+               ret = regmap_read(state->reg_pmu,
+                       phy_desc->iso_offset, &cfg);
+       else
+               ret = exynos_pmu_read(phy_desc->iso_offset, &cfg);
+
+       if (ret) {
+               dev_err(state->dev, "%s Can't read 0x%x\n",
+                               __func__, phy_desc->iso_offset);
+               ret = -EINVAL;
+               goto phy_exit;
+       }
+
+       /* Add INIT_DONE flag when ISO is already bypass(LCD_ON_UBOOT) */
+       if (cfg && EXYNOS_MIPI_PHY_ISO_BYPASS)
+               phy_desc->data->flags |= MIPI_PHY_MxSx_INIT_DONE;
+
+phy_exit:
+       return ret;
+}
+
+static int __set_phy_alone(struct exynos_mipi_phy *state,
+               struct mipi_phy_desc *phy_desc, unsigned int on)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&state->slock, flags);
+
+       if (on) {
+               ret = __set_phy_isolation(state->reg_pmu,
+                               phy_desc->iso_offset, on);
+               if (ret)
+                       goto phy_exit;
+
+               ret = __set_phy_reset(state->reg_reset,
+                               phy_desc->rst_bit, on);
+       } else {
+               ret = __set_phy_reset(state->reg_reset,
+                               phy_desc->rst_bit, on);
+               if (ret)
+                       goto phy_exit;
+
+               ret = __set_phy_isolation(state->reg_pmu,
+                               phy_desc->iso_offset, on);
+       }
+
+phy_exit:
+       pr_debug("%s: isolation 0x%x, reset 0x%x\n", __func__,
+                       phy_desc->iso_offset, phy_desc->rst_bit);
+
+       spin_unlock_irqrestore(&state->slock, flags);
+
+       return ret;
+}
+
+static int __set_phy_share(struct exynos_mipi_phy *state,
+               struct mipi_phy_desc *phy_desc, unsigned int on)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&phy_desc->data->slock, flags);
+
+       on ? ++(phy_desc->data->active_count) : --(phy_desc->data->active_count);
+
+       /* If phy is already initialization(power_on) */
+       if (state->owner == EXYNOS_MIPI_PHY_OWNER_DSIM &&
+                       phy_desc->data->flags & MIPI_PHY_MxSx_INIT_DONE) {
+               phy_desc->data->flags &= (~MIPI_PHY_MxSx_INIT_DONE);
+               spin_unlock_irqrestore(&phy_desc->data->slock, flags);
+               return ret;
+       }
+
+       if (on) {
+               /* Isolation bypass when reference count is 1 */
+               if (phy_desc->data->active_count) {
+                       ret = __set_phy_isolation(state->reg_pmu,
+                                       phy_desc->iso_offset, on);
+                       if (ret)
+                               goto phy_exit;
+               }
+
+               ret = __set_phy_reset(state->reg_reset,
+                               phy_desc->rst_bit, on);
+       } else {
+               ret = __set_phy_reset(state->reg_reset,
+                               phy_desc->rst_bit, on);
+               if (ret)
+                       goto phy_exit;
+
+               /* Isolation enabled when reference count is zero */
+               if (phy_desc->data->active_count == 0)
+                       ret = __set_phy_isolation(state->reg_pmu,
+                                       phy_desc->iso_offset, on);
+       }
+
+phy_exit:
+       pr_debug("%s: isolation 0x%x, reset 0x%x\n", __func__,
+                       phy_desc->iso_offset, phy_desc->rst_bit);
+
+       spin_unlock_irqrestore(&phy_desc->data->slock, flags);
+
+       return ret;
+}
+
+static int __set_phy_state(struct exynos_mipi_phy *state,
+               struct mipi_phy_desc *phy_desc, unsigned int on)
+{
+       int ret = 0;
+
+       if (phy_desc->data->flags & MIPI_PHY_MxSx_SHARED)
+               ret = __set_phy_share(state, phy_desc, on);
+       else
+               ret = __set_phy_alone(state, phy_desc, on);
+
+       return ret;
+}
+
+static void update_bits(void __iomem *addr, unsigned int start,
+                       unsigned int width, unsigned int val)
+{
+       unsigned int cfg;
+       unsigned int mask = (width >= 32) ? 0xffffffff : ((1U << width) - 1);
+
+       cfg = readl(addr);
+       cfg &= ~(mask << start);
+       cfg |= ((val & mask) << start);
+       writel(cfg, addr);
+}
+
+#define PHY_REF_SPEED  (1500)
+static int __set_phy_cfg_0501_0000_dphy(void __iomem *regs, int option, u32 *cfg)
+{
+
+       int i;
+       u32 skew_cal_en = 0;
+       u32 skew_delay_sel = 0;
+       u32 hs_mode_sel = 1;
+
+       if (cfg[SPEED] >= PHY_REF_SPEED) {
+               skew_cal_en = 1;
+
+               if (cfg[SPEED] >= 3000)
+                       skew_delay_sel = 1;
+               else if (cfg[SPEED] >= 2000)
+                       skew_delay_sel = 2;
+               else
+                       skew_delay_sel = 3;
+
+               hs_mode_sel = 0;
+       }
+
+       writel(0x2, regs + 0x0018);
+       update_bits(regs + 0x0084, 0, 8, 0x1);
+       for (i = 0; i <= cfg[LANES]; i++) {
+               update_bits(regs + 0x04e0 + (i * 0x400), 0, 1, skew_cal_en);
+               update_bits(regs + 0x043c + (i * 0x400), 5, 2, skew_delay_sel);
+               update_bits(regs + 0x04ac + (i * 0x400), 2, 1, hs_mode_sel);
+               update_bits(regs + 0x04b0 + (i * 0x400), 0, 8, cfg[SETTLE]);
+       }
+
+       return 0;
+}
+
+static int __set_phy_cfg_0502_0000_dphy(void __iomem *regs, int option, u32 *cfg)
+{
+
+       int i;
+       u32 settle_clk_sel = 1;
+       u32 skew_delay_sel = 0;
+
+       if (cfg[SPEED] >= PHY_REF_SPEED)
+               settle_clk_sel = 0;
+
+       if (cfg[SPEED] >= PHY_REF_SPEED && cfg[SPEED] < 4000) {
+               if (cfg[SPEED] >= 3000)
+                       skew_delay_sel = 1;
+               else if (cfg[SPEED] >= 2000)
+                       skew_delay_sel = 2;
+               else
+                       skew_delay_sel = 3;
+       }
+
+       writel(0x00000001, regs + 0x0000); /* SC_GNR_CON0 */
+       writel(0x00001450, regs + 0x0004); /* SC_GNR_CON1 */
+       writel(0x00000004, regs + 0x0008); /* SC_ANA_CON0 */
+       writel(0x00009000, regs + 0x000c); /* SC_ANA_CON1 */
+       writel(0x00000005, regs + 0x0010); /* SC_ANA_CON2 */
+       writel(0x00000600, regs + 0x0014); /* SC_ANA_CON3 */
+       writel(0x00000301, regs + 0x0030); /* SC_TIME_CON0 */
+
+       for (i = 0; i <= cfg[LANES]; i++) {
+               writel(0x00000001, regs + 0x0100 + (i * 0x100)); /* SD_GNR_CON0 */
+               writel(0x00001450, regs + 0x0104 + (i * 0x100)); /* SD_GNR_CON1 */
+               writel(0x00000004, regs + 0x0108 + (i * 0x100)); /* SD_ANA_CON0 */
+               writel(0x00009000, regs + 0x010c + (i * 0x100)); /* SD_ANA_CON1 */
+               writel(0x00000005, regs + 0x0110 + (i * 0x100)); /* SD_ANA_CON2 */
+               update_bits(regs + 0x0110 + (i * 0x100), 8, 2, skew_delay_sel); /* SD_ANA_CON2 */
+               writel(0x00000600, regs + 0x0114 + (i * 0x100)); /* SD_ANA_CON3 */
+               writel(0x00000040, regs + 0x0124 + (i * 0x100)); /* SD_ANA_CON7 */
+               update_bits(regs + 0x0130 + (i * 0x100), 0, 8, cfg[SETTLE]); /* SD_TIME_CON0 */
+               update_bits(regs + 0x0130 + (i * 0x100), 8, 1, settle_clk_sel); /* SD_TIME_CON0 */
+               writel(0x00000003, regs + 0x0134 + (i * 0x100)); /* SD_TIME_CON1 */
+               writel(0x0000081a, regs + 0x0150 + (i * 0x100)); /* SD_DESKEW_CON4 */
+       }
+
+       return 0;
+}
+
+static int __set_phy_cfg_0502_0001_dphy(void __iomem *regs, int option, u32 *cfg)
+{
+
+       int i;
+       u32 settle_clk_sel = 1;
+       u32 skew_delay_sel = 0;
+
+       if (cfg[SPEED] >= PHY_REF_SPEED)
+               settle_clk_sel = 0;
+
+       if (cfg[SPEED] >= PHY_REF_SPEED && cfg[SPEED] < 4000) {
+               if (cfg[SPEED] >= 3000)
+                       skew_delay_sel = 1;
+               else if (cfg[SPEED] >= 2000)
+                       skew_delay_sel = 2;
+               else
+                       skew_delay_sel = 3;
+       }
+
+       writel(0x00000001, regs + 0x0500); /* SC_GNR_CON0 */
+       writel(0x00001450, regs + 0x0504); /* SC_GNR_CON1 */
+       writel(0x00000004, regs + 0x0508); /* SC_ANA_CON0 */
+       writel(0x00009000, regs + 0x050c); /* SC_ANA_CON1 */
+       writel(0x00000005, regs + 0x0510); /* SC_ANA_CON2 */
+       writel(0x00000600, regs + 0x0514); /* SC_ANA_CON3 */
+       writel(0x00000301, regs + 0x0530); /* SC_TIME_CON0 */
+
+       for (i = 0; i <= cfg[LANES]; i++) {
+               writel(0x00000001, regs + 0x0000 + (i * 0x100)); /* SD_GNR_CON0 */
+               writel(0x00001450, regs + 0x0004 + (i * 0x100)); /* SD_GNR_CON1 */
+               writel(0x00000004, regs + 0x0008 + (i * 0x100)); /* SD_ANA_CON0 */
+               writel(0x00009000, regs + 0x000c + (i * 0x100)); /* SD_ANA_CON1 */
+               writel(0x00000005, regs + 0x0010 + (i * 0x100)); /* SD_ANA_CON2 */
+               update_bits(regs + 0x0010 + (i * 0x100), 8, 2, skew_delay_sel); /* SD_ANA_CON2 */
+               writel(0x00000600, regs + 0x0014 + (i * 0x100)); /* SD_ANA_CON3 */
+               writel(0x00000040, regs + 0x0024 + (i * 0x100)); /* SD_ANA_CON7 */
+               update_bits(regs + 0x0030 + (i * 0x100), 0, 8, cfg[SETTLE]); /* SD_TIME_CON0 */
+               update_bits(regs + 0x0030 + (i * 0x100), 8, 1, settle_clk_sel); /* SD_TIME_CON0 */
+               writel(0x00000003, regs + 0x0034 + (i * 0x100)); /* SD_TIME_CON1 */
+               writel(0x0000081a, regs + 0x0050 + (i * 0x100)); /* SD_DESKEW_CON4 */
+       }
+
+       return 0;
+}
+
+static const struct exynos_mipi_phy_cfg phy_cfg_table[] = {
+       {
+               .major = 0x0501,
+               .minor = 0x0000,
+               .type = 0xD,
+               .set = __set_phy_cfg_0501_0000_dphy,
+       },
+       {
+               .major = 0x0502,
+               .minor = 0x0000,
+               .type = 0xD,
+               .set = __set_phy_cfg_0502_0000_dphy,
+       },
+       {
+               .major = 0x0502,
+               .minor = 0x0001,
+               .type = 0xD,
+               .set = __set_phy_cfg_0502_0001_dphy,
+       },
+       { },
+};
+
+static int __set_phy_cfg(struct exynos_mipi_phy *state,
+               struct mipi_phy_desc *phy_desc, int option, void *info)
+{
+       u32 *cfg = (u32 *)info;
+       int i;
+       int ret = -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(phy_cfg_table); i++) {
+               if ((cfg[VERSION] == MKVER(phy_cfg_table[i].major,
+                                       phy_cfg_table[i].minor))
+                   && (cfg[TYPE] == phy_cfg_table[i].type)) {
+                       ret = phy_cfg_table[i].set(phy_desc->regs,
+                                       option, cfg);
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static struct exynos_mipi_phy_data mipi_phy_m4s4_top = {
+       .flags = MIPI_PHY_MxSx_SHARED,
+       .active_count = 0,
+       .slock = __SPIN_LOCK_UNLOCKED(mipi_phy_m4s4_top.slock),
+};
+
+static struct exynos_mipi_phy_data mipi_phy_m4s4_mod = {
+       .flags = MIPI_PHY_MxSx_SHARED,
+       .active_count = 0,
+       .slock = __SPIN_LOCK_UNLOCKED(mipi_phy_m4s4_mod.slock),
+};
+
+static struct exynos_mipi_phy_data mipi_phy_m4s4s4 = {
+       .flags = MIPI_PHY_MxSx_SHARED,
+       .active_count = 0,
+       .slock = __SPIN_LOCK_UNLOCKED(mipi_phy_m4s4s4.slock),
+};
+
+static struct exynos_mipi_phy_data mipi_phy_m4s0 = {
+       .flags = MIPI_PHY_MxSx_UNIQUE,
+       .active_count = 0,
+       .slock = __SPIN_LOCK_UNLOCKED(mipi_phy_m4s0.slock),
+};
+
+static struct exynos_mipi_phy_data mipi_phy_m2s4s4s2 = {
+       .flags = MIPI_PHY_MxSx_SHARED,
+       .active_count = 0,
+       .slock = __SPIN_LOCK_UNLOCKED(mipi_phy_m2s4s4s2.slock),
+};
+
+static struct exynos_mipi_phy_data mipi_phy_m1s2s2 = {
+       .flags = MIPI_PHY_MxSx_SHARED,
+       .active_count = 0,
+       .slock = __SPIN_LOCK_UNLOCKED(mipi_phy_m1s2s2.slock),
+};
+
+static struct exynos_mipi_phy_data mipi_phy_m0s4s4s4_mod = {
+       .flags = MIPI_PHY_MxSx_SHARED,
+       .active_count = 0,
+       .slock = __SPIN_LOCK_UNLOCKED(mipi_phy_m0s4s4s4.slock),
+};
+
+static const struct of_device_id exynos_mipi_phy_of_table[] = {
+       {
+               .compatible = "samsung,mipi-phy-m4s4-top",
+               .data = &mipi_phy_m4s4_top,
+       },
+       {
+               .compatible = "samsung,mipi-phy-m4s4-mod",
+               .data = &mipi_phy_m4s4_mod,
+       },
+       {
+               .compatible = "samsung,mipi-phy-m4s4s4",
+               .data = &mipi_phy_m4s4s4,
+       },
+       {
+               .compatible = "samsung,mipi-phy-m4s0",
+               .data = &mipi_phy_m4s0,
+       },
+       {
+               .compatible = "samsung,mipi-phy-m2s4s4s2",
+               .data = &mipi_phy_m2s4s4s2,
+       },
+       {
+               .compatible = "samsung,mipi-phy-m1s2s2",
+               .data = &mipi_phy_m1s2s2,
+       },
+       {
+               .compatible = "samsung,mipi-phy-m0s4s4s4-mod",
+               .data = &mipi_phy_m0s4s4s4_mod,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, exynos_mipi_phy_of_table);
+
+#define to_mipi_video_phy(desc) \
+       container_of((desc), struct exynos_mipi_phy, phys[(desc)->index])
+
+static int exynos_mipi_phy_init(struct phy *phy)
+{
+       struct mipi_phy_desc *phy_desc = phy_get_drvdata(phy);
+       struct exynos_mipi_phy *state = to_mipi_video_phy(phy_desc);
+
+       return __set_phy_init(state, phy_desc, 1);
+}
+
+static int exynos_mipi_phy_power_on(struct phy *phy)
+{
+       struct mipi_phy_desc *phy_desc = phy_get_drvdata(phy);
+       struct exynos_mipi_phy *state = to_mipi_video_phy(phy_desc);
+
+       return __set_phy_state(state, phy_desc, 1);
+}
+
+static int exynos_mipi_phy_power_off(struct phy *phy)
+{
+       struct mipi_phy_desc *phy_desc = phy_get_drvdata(phy);
+       struct exynos_mipi_phy *state = to_mipi_video_phy(phy_desc);
+
+       return __set_phy_state(state, phy_desc, 0);
+}
+
+static int exynos_mipi_phy_set(struct phy *phy, int option, void *info)
+{
+       struct mipi_phy_desc *phy_desc = phy_get_drvdata(phy);
+       struct exynos_mipi_phy *state = to_mipi_video_phy(phy_desc);
+
+       return __set_phy_cfg(state, phy_desc, option, info);
+}
+
+static struct phy *exynos_mipi_phy_of_xlate(struct device *dev,
+                                       struct of_phandle_args *args)
+{
+       struct exynos_mipi_phy *state = dev_get_drvdata(dev);
+
+       if (WARN_ON(args->args[0] >= EXYNOS_MIPI_PHYS_NUM))
+               return ERR_PTR(-ENODEV);
+
+       return state->phys[args->args[0]].phy;
+}
+
+static struct phy_ops exynos_mipi_phy_ops = {
+       .init           = exynos_mipi_phy_init,
+       .power_on       = exynos_mipi_phy_power_on,
+       .power_off      = exynos_mipi_phy_power_off,
+       .set            = exynos_mipi_phy_set,
+       .owner          = THIS_MODULE,
+};
+
+static int exynos_mipi_phy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       struct exynos_mipi_phy *state;
+       struct phy_provider *phy_provider;
+       struct exynos_mipi_phy_data *phy_data;
+       const struct of_device_id *of_id;
+       unsigned int iso[EXYNOS_MIPI_PHYS_NUM];
+       unsigned int rst[EXYNOS_MIPI_PHYS_NUM];
+       struct resource *res;
+       unsigned int i;
+       int ret = 0, elements = 0;
+
+       state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       state->dev  = &pdev->dev;
+
+       of_id = of_match_device(of_match_ptr(exynos_mipi_phy_of_table), dev);
+       if (!of_id)
+               return -EINVAL;
+
+       phy_data = (struct exynos_mipi_phy_data *)of_id->data;
+
+       dev_set_drvdata(dev, state);
+       spin_lock_init(&state->slock);
+
+       /* PMU isolation (optional) */
+       state->reg_pmu = syscon_regmap_lookup_by_phandle(node,
+                                                  "samsung,pmu-syscon");
+       if (IS_ERR(state->reg_pmu)) {
+               dev_err(dev, "failed to lookup PMU regmap, use PMU interface\n");
+               state->reg_pmu = NULL;
+       }
+
+       elements = of_property_count_u32_elems(node, "isolation");
+       if ((elements < 0) || (elements > EXYNOS_MIPI_PHYS_NUM))
+               return -EINVAL;
+
+       ret = of_property_read_u32_array(node, "isolation", iso,
+                                       elements);
+       if (ret) {
+               dev_err(dev, "cannot get PHY isolation offset\n");
+               return ret;
+       }
+
+       /* SYSREG reset (optional) */
+       state->reg_reset = syscon_regmap_lookup_by_phandle(node,
+                                               "samsung,reset-sysreg");
+       if (IS_ERR(state->reg_reset)) {
+               state->reg_reset = NULL;
+       } else {
+               ret = of_property_read_u32_array(node, "reset", rst, elements);
+               if (ret) {
+                       dev_err(dev, "cannot get PHY reset bit\n");
+                       return ret;
+               }
+       }
+
+       of_property_read_u32(node, "owner", &state->owner);
+
+       for (i = 0; i < elements; i++) {
+               state->phys[i].iso_offset = iso[i];
+               state->phys[i].rst_bit    = rst[i];
+               dev_info(dev, "%s: isolation 0x%x\n", __func__,
+                               state->phys[i].iso_offset);
+               if (state->reg_reset)
+                       dev_info(dev, "%s: reset %d\n", __func__,
+                               state->phys[i].rst_bit);
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               if (res) {
+                       state->phys[i].regs = devm_ioremap_resource(dev, res);
+                       if (IS_ERR(state->phys[i].regs))
+                               return PTR_ERR(state->phys[i].regs);
+               }
+       }
+
+       for (i = 0; i < elements; i++) {
+               struct phy *generic_phy = devm_phy_create(dev, NULL,
+                               &exynos_mipi_phy_ops);
+               if (IS_ERR(generic_phy)) {
+                       dev_err(dev, "failed to create PHY\n");
+                       return PTR_ERR(generic_phy);
+               }
+
+               state->phys[i].index    = i;
+               state->phys[i].phy      = generic_phy;
+               state->phys[i].data     = phy_data;
+               phy_set_drvdata(generic_phy, &state->phys[i]);
+       }
+
+       phy_provider = devm_of_phy_provider_register(dev,
+                       exynos_mipi_phy_of_xlate);
+
+       if (IS_ERR(phy_provider))
+               dev_err(dev, "failed to create exynos mipi-phy\n");
+       else
+               dev_err(dev, "creating exynos-mipi-phy\n");
+
+       return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static struct platform_driver exynos_mipi_phy_driver = {
+       .probe  = exynos_mipi_phy_probe,
+       .driver = {
+               .name  = "exynos-mipi-phy",
+               .of_match_table = of_match_ptr(exynos_mipi_phy_of_table),
+               .suppress_bind_attrs = true,
+       }
+};
+module_platform_driver(exynos_mipi_phy_driver);
+
+MODULE_DESCRIPTION("Samsung EXYNOS SoC MIPI CSI/DSI D/C-PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/samsung/phy-exynos-usb3p1-reg.h b/drivers/phy/samsung/phy-exynos-usb3p1-reg.h
new file mode 100644 (file)
index 0000000..f8374fd
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * phy-exynos-usb3p1-reg.h
+ *
+ *  Created on: Oct 27, 2016
+ *      Author: sung-hyun na
+ *             jee-woong oh
+ *             dae-man ko
+ */
+
+#ifndef DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USB3P1_REG_H_
+#define DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USB3P1_REG_H_
+
+#define EXYNOS_USBCON_CTRL_VER         (0x00)
+
+#define EXYNOS_USBCON_LINK_CTRL                (0x04)
+#define LINKCTRL_PIPE3_FORCE_RX_ELEC_IDLE      (0x1 << 18)
+#define LINKCTRL_PIPE3_FORCE_PHY_STATUS                (0x1 << 17)
+#define LINKCTRL_PIPE3_FORCE_EN                        (0x1 << 16)
+#define LINKCTRL_DIS_QACT_BUSPEND              (0x1 << 13)
+#define LINKCTRL_DIS_QACT_LINKGATE             (0x1 << 12)
+#define LINKCTRL_DIS_QACT_ID0                  (0x1 << 11)
+#define LINKCTRL_DIS_QACT_VBUS_VALID           (0x1 << 10)
+#define LINKCTRL_DIS_QACT_BVALID               (0x1 << 9)
+#define LINKCTRL_FORCE_QACT                    (0x1 << 8)
+#define LINKCTRL_BUS_FILTER_BYPASS(_x)         ((_x & 0xf) << 4)
+#define LINKCTRL_BUS_FILTER_BYPASS_MASK                (0xf << 4)
+#define LINKCTRL_HOST_SYSTEM_ERR               (0x1 << 2)
+#define LINKCTRL_LINK_PME                      (0x1 << 1)
+#define LINKCTRL_PME_GENERATION                        (0x1 << 0)
+
+#define EXYNOS_USBCON_LINK_PORT                (0x08)
+#define LINKPORT_HOST_NUM_U3(_x)               ((_x & 0xf) << 16)
+#define LINKPORT_HOST_NUM_U2(_x)               ((_x & 0xf) << 12)
+#define LINKPORT_HOST_U3_PORT_DISABLE          (0x1 << 9)
+#define LINKPORT_HOST_U2_PORT_DISABLE          (0x1 << 8)
+#define LINKPORT_HOST_PORT_POWER_CON_PRESENT   (0x1 << 6)
+#define LINKPORT_HUB_PORT_SET_OCD_U3           (0x1 << 5)
+#define LINKPORT_HUB_PORT_SET_OCD_U2           (0x1 << 4)
+#define LINKPORT_HUB_PORT_SEL_OCD_U3           (0x1 << 3)
+#define LINKPORT_HUB_PORT_SEL_OCD_U2           (0x1 << 2)
+#define LINKPORT_HUB_PERM_ATTACH_U3            (0x1 << 1)
+#define LINKPORT_HUB_PERM_ATTACH_U2            (0x1 << 0)
+
+#define EXYNOS_USBCON_LINK_DEBUG_L     (0x0C)
+#define EXYNOS_USBCON_LINK_DEBUG_H     (0x10)
+
+#define EXYNOS_USBCON_LTSTATE_HIS      (0x14)
+#define LTSTATE_LINKTRN_DONE                   (0x1 << 31)
+#define LTSTATE_HIS4(_x)                       ((_x & 0xf) << 16)
+#define LTSTATE_HIS3(_x)                       ((_x & 0xf) << 12)
+#define LTSTATE_HIS2(_x)                       ((_x & 0xf) << 8)
+#define LTSTATE_HIS1(_x)                       ((_x & 0xf) << 4)
+#define LTSTATE_HIS0(_x)                       ((_x & 0xf) << 0)
+
+#define EXYNOS_USBCON_CLKRST           (0x20)
+#define CLKRST_USBAUDIO_CLK_GATE_EN            (0x1 << 9)
+#define CLKRST_USBAUDIO_CLK_SEL                        (0x1 << 8)
+#define CLKRST_LINK_PCLK_SEL                   (0x1 << 7)
+#define CLKRST_PHYCLOCKSEL                     (0x1 << 6)
+#define CLKRST_PHY30_SW_RST                    (0x1 << 3)
+#define CLKRST_PHY30_RST_SEL                   (0x1 << 2)
+#define CLKRST_PHY20_SW_RST                    (0x1 << 13)
+#define CLKRST_PHY20_RST_SEL                   (0x1 << 12)
+#define CLKRST_PHY_SW_RST                      (0x1 << 3)
+#define CLKRST_PHY_RST_SEL                     (0x1 << 2)
+#define CLKRST_REFCLK_SEL                      (0x1 << 4)
+#define CLKRST_PORT_RST                                (0x1 << 1)
+#define CLKRST_LINK_SW_RST                     (0x1 << 0)
+
+#define EXYNOS_USBCON_PWR              (0x24)
+
+#define PWR_PIPE3_POWERDONW                    (0xf << 4)
+#define PWR_FORCE_POWERDOWN_EN                 (0x1 << 3)
+#define RSVD1                                  (0x7 << 0)
+#define PWR_FORCE_POWERDONW                    (0x1 << 2)
+#define PWR_TEST_POWERDOWN_SSP                 (0x1 << 1)
+#define PWR_TEST_POWERDOWN_HSP                 (0x1 << 0)
+
+#define EXYNOS_USBCON_DUALPHYSEL       (0x28)
+#define DUALPHYSEL_PHYSEL_CTRL                 (0x1 << 0)
+#define DUALPHYSEL_PHYSEL_SSPHY                        (0x1 << 1)
+#define DUALPHYSEL_PHYSEL_PIPECLK              (0x1 << 4)
+#define DUALPHYSEL_PHYSEL_PIPERST              (0x1 << 8)
+
+#define EXYNOS_USBCON_SSP_PLL          (0x30)
+#define SSP_PLL_MPLL_MULTIPLIER_MASK           (0x7F << 24)
+#define SSP_PLL_MPLL_MULTIPLIER(_x)            ((_x & 0x7f) << 24)
+#define SSP_PLL_SSC_REF_CLK_SEL_MASK           (0x1ff << 12)
+#define SSP_PLL_SSC_REF_CLK_SEL(_x)            ((_x & 0x1ff) << 12)
+#define SSP_PLL_SSC_EN                         (0x1 << 11)
+#define SSP_PLL_SSC_RANGE_MASK                 (0x7 << 8)
+#define SSP_PLL_SSC_RANGE(_x)                  ((_x & 0x7) << 8)
+#define SSP_PLL_REF_SSP_EN                     (0x1 << 7)
+#define SSP_PLL_REF_CLKDIV2                    (0x1 << 6)
+#define SSP_PLL_FSEL_MASK                      (0x3f << 0)
+#define SSP_PLL_FSEL(_x)                       ((_x & 0x3f) << 0)
+
+#define EXYNOS_USBCON_SSP_PARACON0     (0x34)
+#define SSP_PARACON0_TX0_TERM_OFFSET_MASK      (0x1f << 25)
+#define SSP_PARACON0_TX0_TERM_OFFSET(_x)       ((_x & 0x1f) << 25)
+#define SSP_PARACON0_PCS_TX_SWING_FULL_MASK    (0x7f << 16)
+#define SSP_PARACON0_PCS_TX_SWING_FULL(_x)     ((_x & 0x7f) << 16)
+#define SSP_PARACON0_PCS_TX_DEEMPH_6DB_MASK    (0x3f << 8)
+#define SSP_PARACON0_PCS_TX_DEEMPH_6DB(_x)     ((_x & 0x3f) << 8)
+#define SSP_PARACON0_PCS_TX_DEEMPH_3P5DB_MASK  (0x3f << 0)
+#define SSP_PARACON0_PCS_TX_DEEMPH_3P5DB(_x)   ((_x & 0x3f) << 0)
+
+#define EXYNOS_USBCON_SSP_PARACON1     (0x38)
+#define SSP_PARACON1_TX_VBOOST_LVL_SSTX_MASK   (0x7 << 28)
+#define SSP_PARACON1_TX_VBOOST_LVL_SSTX(_x)            ((_x & 0x7) << 28)
+#define SSP_PARACON1_TX_VBOOST_LVL_MASK                (0x7 << 24)
+#define SSP_PARACON1_TX_VBOOST_LVL(_x)         ((_x & 0x7) << 24)
+#define SSP_PARACON1_LOS_LEVEL_MASK            (0x1f << 16)
+#define SSP_PARACON1_LOS_LEVEL(_x)             ((_x & 0x1f) << 16)
+#define SSP_PARACON1_LOS_BIAS_MASK             (0x7 << 12)
+#define SSP_PARACON1_LOS_BIAS(_x)              ((_x & 0x7) << 12)
+#define SSP_PARACON1_PCS_RX_LOS_MASK_VAL_MASK  (0x3ff << 0)
+#define SSP_PARACON1_PCS_RX_LOS_MASK_VAL(_x)   ((_x & 0x3ff) << 0)
+
+#define EXYNOS_USBCON_SSP_TEST         (0x3C)
+#define SSP_TEST_TX_EYE_HEIGHT_CNTL_EN_MASK            (0x1 << 28)
+#define SSP_TEST_TX_EYE_HEIGHT_CNTL_EN(_x)             ((_x & 0x1) << 28)
+#define SSP_TEST_PIPE_TX_DEEMPH_UPDATE_DELAY_MASK      (0xf << 24)
+#define SSP_TEST_PIPE_TX_DEEMPH_UPDATE_DELAY(_x)       ((_x & 0xf) << 24)
+#define SSP_TEST_PCS_TX_SWING_FULL_SSTX_MASK   (0x7f << 16)
+#define SSP_TEST_PCS_TX_SWING_FULL_SSTX(_x)            ((_x & 0x7f) << 16)
+#define SSP_TEST_RTUNE_ACK                     (0x1 << 3)
+#define SSP_TEST_RTUNE_REQ                     (0x1 << 2)
+#define SSP_TEST_LANE0_TX2RX_LOOPBK            (0x1 << 1)
+#define SSP_TEST_LOOPBACKENB                   (0x1 << 0)
+
+#define EXYNOS_USBCON_SSP_CRCTL0       (0x40)
+#define SSP_CCTRL0_CR_DATA_IN_MASK             (0xffffU << 16)
+#define SSP_CCTRL0_CR_DATA_IN(_x)              ((_x & 0xffffU) << 16)
+#define SSP_CRCTRL0_CR_WRITE                   (0x1 << 3)
+#define SSP_CRCTRL0_CR_READ                    (0x1 << 2)
+#define SSP_CRCTRL0_CR_CAP_DATA                        (0x1 << 1)
+#define SSP_CRCTRL0_CR_CAP_ADDR                        (0x1 << 0)
+
+#define EXYNOS_USBCON_SSP_CRCTL1       (0x44)
+#define SSP_CRCTL1_CR_DATA_OUT_MASK            (0xffffU << 16)
+#define SSP_CRCTL1_CR_DATA_OUT(_x)             ((_x & 0xffffU) << 16)
+#define SSP_CRCTL1_CR_ACK                      (0x1 << 0)
+
+#define EXYNOS_USBCON_COMBO_PMA_CTRL   (0x48)
+/* S5E9820 added */
+#define PMA_REF_SOC_PLL_SSC                    (0x1 << 16)
+#define PMA_ROPLL_REF_REQ_MASK                 (0x3 << 12)
+#define PMA_ROPLL_REF_REQ_SET(_x)                      ((_x & 0x3) << 12)
+#define PMA_ROPLL_REF_REQ_GET(_x)                      ((_x & (0x3 << 12)) >> 12)
+/* S5E9820 added */
+#define PMA_PLL_REF_REQ_MASK                   (0x3 << 10)
+#define PMA_PLL_REF_REQ_SET(_x)                        ((_x & 0x3) << 10)
+#define PMA_PLL_REF_REQ_GET(_x)                        ((_x & (0x3 << 10)) >> 10)
+#define PMA_REF_FREQ_MASK                      (0x3 << 8)
+#define PMA_REF_FREQ_SET(_x)                   ((_x & 0x3) << 8)
+#define PMA_REF_FREQ_GET(_x)                   ((_x & (0x3 << 8)) >> 8)
+#define PMA_LOW_PWRN                           (0x1 << 4)
+#define PMA_TRSV_SW_RST                                (0x1 << 3)
+#define PMA_CMN_SW_RST                         (0x1 << 2)
+#define PMA_INIT_SW_RST                                (0x1 << 1)
+#define PMA_APB_SW_RST                         (0x1 << 0)
+
+
+#define EXYNOS_USBCON_UTMI             (0x50)
+#define UTMI_OPMODE_CTRL_EN                    (0x1 << 8)
+#define UTMI_FORCE_OPMODE_MASK                 (0x3 << 6)
+#define UTMI_FORCE_OPMODE_SET(_x)              ((_x & 0x3) << 6)
+#define UTMI_FORCE_VBUSVALID                   (0x1 << 5)
+#define UTMI_FORCE_BVALID                      (0x1 << 4)
+#define UTMI_DP_PULLDOWN                       (0x1 << 3)
+#define UTMI_DM_PULLDOWN                       (0x1 << 2)
+#define UTMI_FORCE_SUSPEND                     (0x1 << 1)
+#define UTMI_FORCE_SLEEP                       (0x1 << 0)
+
+#define EXYNOS_USBCON_HSP              (0x54)
+#define HSP_AUTORSM_ENB                                (0x1 << 29)
+#define HSP_RETENABLE_EN                       (0x1 << 28)
+#define HSP_FSLS_SPEED_SEL                     (0x1 << 25)
+#define HSP_FSV_OUT_EN                         (0x1 << 24)
+#define HSP_HS_XCVR_EXT_CTL                    (0x1 << 22)
+#define HSP_HS_RXDAT                           (0x1 << 21)
+#define HSP_HS_SQUELCH                         (0x1 << 20)
+#define HSP_FSVMINUS                           (0x1 << 17)
+#define HSP_FSVPLUS                            (0x1 << 16)
+#define HSP_FSVPLUS_GET(_x)            ((_x & (0x1 << 16)) >> 16)
+#define HSP_VBUSVLDEXTSEL                      (0x1 << 13)
+#define HSP_VBUSVLDEXT                         (0x1 << 12)
+#define HSP_EN_UTMISUSPEND                     (0x1 << 9)
+#define HSP_COMMONONN                          (0x1 << 8)
+#define HSP_VATESTENB                          (0x1 << 6)
+#define HSP_CHGDET                             (0x1 << 5)
+#define HSP_CHGDET_GET(_x)             ((_x & (0x1 << 5)) >> 5)
+#define HSP_VDATSRCENB                         (0x1 << 4)
+#define HSP_VDATDETENB                         (0x1 << 3)
+#define HSP_CHRGSEL                            (0x1 << 2)
+#define HSP_ACAENB                             (0x1 << 1)
+#define HSP_DCDENB                             (0x1 << 0)
+
+#define EXYNOS_USBCON_HSP_TUNE         (0x58)
+#define HSP_TUNE_TXVREF_MASK                   ((unsigned) 0xf << 28)
+#define HSP_TUNE_TXVREF_SET(_x)                        ((unsigned) (_x & 0xf) << 28)
+#define HSP_TUNE_TXVREF_GET(_x)                        ((_x & (0xfU << 28)) >> 28)
+#define HSP_TUNE_TXRISE_MASK                   (0x3 << 24)
+#define HSP_TUNE_TXRISE_SET(_x)                        ((_x & 0x3) << 24)
+#define HSP_TUNE_TXRISE_GET(_x)                        ((_x & (0x3 << 24)) >> 24)
+#define HSP_TUNE_TXRES_MASK                    (0x3 << 21)
+#define HSP_TUNE_TXRES_SET(_x)                 ((_x & 0x3) << 21)
+#define HSP_TUNE_TXRES_GET(_x)                 ((_x & (0x3 << 21)) >> 21)
+#define HSP_TUNE_TXPREEMPA_PLUS                        (0x1 << 20)
+#define HSP_TUNE_TXPREEMPA_PLUS_GET(_x)        ((_x & (0x1 << 20)) >> 20)
+#define HSP_TUNE_TXPREEMPA_MASK                        (0x3 << 18)
+#define HSP_TUNE_TXPREEMPA_SET(_x)             ((_x & 0x3) << 18)
+#define HSP_TUNE_TXPREEMPA_GET(_x)             ((_x & (0x3 << 18)) >> 18)
+#define HSP_TUNE_HSXV_MASK                     (0x3 << 16)
+#define HSP_TUNE_HSXV_SET(_x)                  ((_x & 0x3) << 16)
+#define HSP_TUNE_HSXV_GET(_x)                  ((_x & (0x3 << 16)) >> 16)
+#define HSP_TUNE_TXFSLS_MASK                   (0xf << 12)
+#define HSP_TUNE_TXFSLS_SET(_x)                        ((_x & 0xf) << 12)
+#define HSP_TUNE_TXFSLS_GET(_x)                        ((_x & (0xf << 12)) >> 12)
+#define HSP_TUNE_SQRX_MASK                     (0x7 << 8)
+#define HSP_TUNE_SQRX_SET(_x)                  ((_x & 0x7) << 8)
+#define HSP_TUNE_SQRX_GET(_x)                  ((_x & (0x7 << 8)) >> 8)
+#define HSP_TUNE_OTG_MASK                      (0x7 << 4)
+#define HSP_TUNE_OTG_SET(_x)                   ((_x & 0x7) << 4)
+#define HSP_TUNE_OTG_GET(_x)                   ((_x & (0x7 << 4)) >> 4)
+#define HSP_TUNE_COMPDIS_MASK                  (0x7 << 0)
+#define HSP_TUNE_COMPDIS_SET(_x)               ((_x & 0x7) << 0)
+#define HSP_TUNE_COMPDIS_GET(_x)               ((_x & (0x7 << 0)) >> 0)
+
+#define EXYNOS_USBCON_HSP_TEST         (0x5c)
+#define HSP_TEST_HS_RXDAT                      (0x1 << 26)
+#define HSP_TEST_HS_SQUELCH                    (0x1 << 25)
+#define HSP_TEST_SIDDQ                         (0x1 << 24)
+#define HSP_TEST_LINESTATE_MASK                        (0x3 << 20)
+#define HSP_TEST_LINESTATE_SET(_x)             ((_x & 0x3) << 20)
+#define HSP_TEST_LINESTATE_GET(_x)             ((_x & (0x3 << 20)) >> 20)
+#define HSP_TEST_DATA_OUT_MASK                 (0xf << 16)
+#define HSP_TEST_DATA_OUT_SET(_x)              ((_x & 0xf) << 16)
+#define HSP_TEST_DATA_OUT_GET(_x)              ((_x & (0xf << 16)) >> 16)
+#define HSP_TEST_CLK                           (0x1 << 13)
+#define HSP_TEST_DATA_OUT_SEL                  (0x1 << 12)
+#define HSP_TEST_DATA_ADDR_MASK                        (0xf << 8)
+#define HSP_TEST_DATA_ADDR_SET(_x)             ((_x & 0xf) << 8)
+#define HSP_TEST_DATA_ADDR_GET(_x)             ((_x & (0xf << 8)) >> 8)
+#define HSP_TEST_DATA_IN_MASK                  (0xff << 0)
+#define HSP_TEST_DATA_IN_SET(_x)               ((_x & 0xff) << 0)
+#define HSP_TEST_DATA_IN_GET(_x)               ((_x & (0xff << 0)) >> 0)
+
+#define EXYNOS_USBCON_HSP_PLL_TUNE     (0x60)
+#define HSP_PLL_BTUNE                          (0x1 << 8)
+#define HSP_PLL_ITUNE_MASK                     (0x3 << 4)
+#define HSP_PLL_ITUNE_IN_SET(_x)               ((_x & 0x3) << 4)
+#define HSP_PLL_ITUNE_IN_GET(_x)               ((_x & (0x3 << 4)) >> 4)
+#define HSP_PLL_PTUNE_MASK                     (0xf << 0)
+#define HSP_PLL_PTUNE_IN_SET(_x)               ((_x & 0xf) << 0)
+#define HSP_PLL_PTUNE_IN_GET(_x)               ((_x & (0xf << 0)) >> 0)
+
+/* Remote Wake-up Advisro (ReWA) */
+#define EXYNOS_USBCON_REWA_ENABLE      (0x100)
+#define REWA_ENABLE_SS_REWA_EN                 (0x1 << 8)
+#define REWA_ENABLE_HS_REWA_EN                 (0x1 << 0)
+
+#define EXYNOS_USBCON_HSREWA_INTR      (0x104)
+#define HSREWA_INTR_WAKEUP_REQ_MASK            (0x1 << 12)
+#define HSREWA_INTR_TIMEOUT_MASK               (0x1 << 8)
+#define HSREWA_INTR_EVT_MASK                   (0x1 << 4)
+#define HSREWA_INTR_WAKEUP_MASK                        (0x1 << 0)
+
+#define EXYNOS_USBCON_HSREWA_CTRL      (0x108)
+#define HSREWA_CTRL_DIG_BYPASS_CON_EN          (0x1 << 28)
+#define HSREWA_CTRL_DPDM_MON_SEL               (0x1 << 24)
+#define HSREWA_CTRL_HS_LINK_READY              (0x1 << 20)
+#define HSREWA_CTRL_HS_SYS_VALID               (0x1 << 16)
+#define HSREWA_CTRL_HS_REWA_ERR                        (0x1 << 4)
+#define HSREWA_CTRL_HS_REWA_DONE               (0x1 << 0)
+
+#define EXYNOS_USBCON_HSREWA_REFTO     (0x10C)
+
+#define EXYNOS_USBCON_HSREWA_HSTK      (0x110)
+
+#define EXYNOS_USBCON_HSREWA_CNT       (0x114)
+
+#define EXYNOS_USBCON_HSREWA_INT1_EVT  (0x118)
+#define HSREWA_CTRL_HS_EVT_ERR_SUS             (0x1 << 18)
+#define HSREWA_CTRL_HS_EVT_ERR_DEV_K           (0x1 << 17)
+#define HSREWA_CTRL_HS_EVT_DISCON              (0x1 << 16)
+#define HSREWA_CTRL_HS_EVT_BYPASS_DIS          (0x1 << 2)
+#define HSREWA_CTRL_HS_EVT_RET_DIS             (0x1 << 1)
+#define HSREWA_CTRL_HS_EVT_RET_EN              (0x1 << 0)
+
+#define EXYNOS_USBCON_HSREWA_INT1_MASK (0x11C)
+
+
+#endif /* DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USB3P1_REG_H_ */
diff --git a/drivers/phy/samsung/phy-exynos-usb3p1.c b/drivers/phy/samsung/phy-exynos-usb3p1.c
new file mode 100644 (file)
index 0000000..aff021b
--- /dev/null
@@ -0,0 +1,1682 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifdef __KERNEL__
+
+#ifndef __EXCITE__
+#include <linux/delay.h>
+#include <linux/io.h>
+#endif
+
+#include <linux/platform_device.h>
+
+#else
+
+#include "types.h"
+#ifndef __BOOT__
+#include "customfunctions.h"
+#include "mct.h"
+#else
+#include <string.h>
+#include <util.h>
+#include <pwm.h>
+#endif
+
+#endif
+
+#include "phy-samsung-usb-cal.h"
+
+#include "phy-exynos-usb3p1.h"
+#include "phy-exynos-usb3p1-reg.h"
+//#include "../../../../include/usb/usb_config.h"
+
+static int exynos_usb3p1_get_tune_param(struct exynos_usbphy_info *info,
+       char *param_name)
+{
+       int cnt, ret;
+       char *name;
+
+       if (!info->tune_param)
+               return -1;
+
+       for (cnt = 0, ret = -1;
+                       info->tune_param[cnt].value != EXYNOS_USB_TUNE_LAST;
+                       cnt++) {
+               name = info->tune_param[cnt].name;
+               if (strcmp(name, param_name))
+                       continue;
+               ret = info->tune_param[cnt].value;
+               break;
+       }
+
+       return ret;
+}
+
+#if !defined(CONFIG_BOARD_ZEBU)
+static void exynos_cal_usbphy_q_ch(void *regs_base, u8 enable)
+{
+       u32 phy_resume;
+
+       if (enable) {
+               /* WA for Q-channel: disable all q-act from usb */
+               phy_resume = readl(regs_base + EXYNOS_USBCON_LINK_CTRL);
+               phy_resume |= LINKCTRL_DIS_QACT_ID0;
+               phy_resume |= LINKCTRL_DIS_QACT_VBUS_VALID;
+               phy_resume |= LINKCTRL_DIS_QACT_BVALID;
+               phy_resume |= LINKCTRL_DIS_QACT_LINKGATE;
+               phy_resume &= ~LINKCTRL_FORCE_QACT;
+               udelay(500);
+               writel(phy_resume, regs_base + EXYNOS_USBCON_LINK_CTRL);
+               udelay(500);
+               phy_resume = readl(regs_base + EXYNOS_USBCON_LINK_CTRL);
+               phy_resume |= LINKCTRL_FORCE_QACT;
+               udelay(500);
+               writel(phy_resume, regs_base + EXYNOS_USBCON_LINK_CTRL);
+       } else {
+               phy_resume = readl(regs_base + EXYNOS_USBCON_LINK_CTRL);
+               phy_resume &= ~LINKCTRL_FORCE_QACT;
+               phy_resume |= LINKCTRL_DIS_QACT_ID0;
+               phy_resume |= LINKCTRL_DIS_QACT_VBUS_VALID;
+               phy_resume |= LINKCTRL_DIS_QACT_BVALID;
+               phy_resume |= LINKCTRL_DIS_QACT_LINKGATE;
+               writel(phy_resume, regs_base + EXYNOS_USBCON_LINK_CTRL);
+       }
+}
+#endif
+
+static void link_vbus_filter_en(struct exynos_usbphy_info *info,
+       u8 enable)
+{
+       u32 phy_resume;
+
+       phy_resume = readl(info->regs_base + EXYNOS_USBCON_LINK_CTRL);
+       if (enable)
+               phy_resume &= ~LINKCTRL_BUS_FILTER_BYPASS_MASK;
+       else
+               phy_resume |= LINKCTRL_BUS_FILTER_BYPASS(0xf);
+       writel(phy_resume, info->regs_base + EXYNOS_USBCON_LINK_CTRL);
+}
+
+static void phy_power_en(struct exynos_usbphy_info *info, u8 en)
+{
+       u32 reg;
+       int main_version;
+
+       main_version = info->version & EXYNOS_USBCON_VER_MAJOR_VER_MASK;
+       if (main_version == EXYNOS_USBCON_VER_05_0_0) {
+               void *__iomem reg_base;
+
+               if (info->used_phy_port == 1)
+                       reg_base = info->regs_base_2nd;
+               else
+                       reg_base = info->regs_base;
+
+               /* 3.0 PHY Power Down control */
+               reg = readl(reg_base + EXYNOS_USBCON_PWR);
+               if (en) {
+                       /* apply to KC asb vector */
+                       if (EXYNOS_USBCON_VER_MINOR(info->version) >= 0x1) {
+                               reg &= ~(PWR_PIPE3_POWERDONW);
+                               reg &= ~(PWR_FORCE_POWERDOWN_EN);
+                       } else {
+                               reg &= ~(PWR_TEST_POWERDOWN_HSP);
+                               reg &= ~(PWR_TEST_POWERDOWN_SSP);
+                               writel(reg, reg_base + EXYNOS_USBCON_PWR);
+                               udelay(1000);
+                               reg |= (PWR_TEST_POWERDOWN_HSP);
+                       }
+               } else {
+                       if (EXYNOS_USBCON_VER_MINOR(info->version) >= 0x1) {
+                               reg |= (PWR_PIPE3_POWERDONW);
+                               reg |= (PWR_FORCE_POWERDOWN_EN);
+                       } else {
+                               reg |= (PWR_TEST_POWERDOWN_SSP);
+                       }
+               }
+               writel(reg, reg_base + EXYNOS_USBCON_PWR);
+
+       } else if (main_version == EXYNOS_USBCON_VER_03_0_0) {
+               /* 2.0 PHY Power Down Control */
+               reg = readl(info->regs_base + EXYNOS_USBCON_HSP_TEST);
+               if (en)
+                       reg &= ~HSP_TEST_SIDDQ;
+               else
+                       reg |= HSP_TEST_SIDDQ;
+               writel(reg, info->regs_base + EXYNOS_USBCON_HSP_TEST);
+       }
+}
+
+static void phy_sw_rst_high(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       int main_version;
+       u32 clkrst;
+
+       main_version = info->version & EXYNOS_USBCON_VER_MAJOR_VER_MASK;
+       if ((main_version == EXYNOS_USBCON_VER_05_0_0) &&
+                       (info->used_phy_port == 1))
+               regs_base = info->regs_base_2nd;
+
+       clkrst = readl(regs_base + EXYNOS_USBCON_CLKRST);
+       if (EXYNOS_USBCON_VER_MINOR(info->version) >= 0x1) {
+               clkrst |= CLKRST_PHY20_SW_RST;
+               clkrst |= CLKRST_PHY20_RST_SEL;
+       } else {
+               clkrst |= CLKRST_PHY_SW_RST;
+               clkrst |= CLKRST_PHY_RST_SEL;
+               clkrst |= CLKRST_PORT_RST;
+       }
+       writel(clkrst, regs_base + EXYNOS_USBCON_CLKRST);
+}
+
+static void phy_sw_rst_low(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       int main_version;
+       u32 clkrst;
+
+       main_version = info->version & EXYNOS_USBCON_VER_MAJOR_VER_MASK;
+       if ((main_version == EXYNOS_USBCON_VER_05_0_0) &&
+                       (info->used_phy_port == 1))
+               regs_base = info->regs_base_2nd;
+
+       clkrst = readl(regs_base + EXYNOS_USBCON_CLKRST);
+       if (EXYNOS_USBCON_VER_MINOR(info->version) >= 0x1) {
+               clkrst |= CLKRST_PHY20_RST_SEL;
+               clkrst &= ~CLKRST_PHY20_SW_RST;
+               clkrst &= ~CLKRST_PORT_RST;
+
+       } else {
+               clkrst |= CLKRST_PHY_RST_SEL;
+               clkrst &= ~CLKRST_PHY_SW_RST;
+               clkrst &= ~CLKRST_PORT_RST;
+
+       }
+       writel(clkrst, regs_base + EXYNOS_USBCON_CLKRST);
+}
+
+void phy_exynos_usb_v3p1_pma_ready(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg;
+
+       reg = readl(regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       reg &= ~PMA_LOW_PWRN;
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+
+       udelay(1);
+
+       reg |= PMA_APB_SW_RST;
+       reg |= PMA_INIT_SW_RST;
+       reg |= PMA_CMN_SW_RST;
+       reg |= PMA_TRSV_SW_RST;
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+
+       udelay(1);
+
+       reg &= ~PMA_APB_SW_RST;
+       reg &= ~PMA_INIT_SW_RST;
+       reg &= ~PMA_PLL_REF_REQ_MASK;
+       reg &= ~PMA_REF_FREQ_MASK;
+       reg |= PMA_REF_FREQ_SET(0x1);
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+
+       reg = readl(regs_base + EXYNOS_USBCON_LINK_CTRL);
+       reg &= ~LINKCTRL_PIPE3_FORCE_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_LINK_CTRL);
+}
+/* S5E9820 - SS GEN2 PMA INIT */
+void phy_exynos_usb_v3p1_g2_pma_ready(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg;
+
+       /* Change pipe pclk to pipe3 */
+       reg = readl(regs_base + EXYNOS_USBCON_CLKRST);
+       reg |= CLKRST_LINK_PCLK_SEL;
+       writel(reg, regs_base + EXYNOS_USBCON_CLKRST);
+
+       reg = readl(regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       reg &= ~PMA_ROPLL_REF_REQ_MASK;
+       reg &= ~PMA_ROPLL_REF_REQ_MASK;
+       reg &= ~PMA_PLL_REF_REQ_MASK;
+       reg |= PMA_REF_FREQ_SET(1);
+       reg |= PMA_LOW_PWRN;
+       reg |= PMA_TRSV_SW_RST;
+       reg |= PMA_CMN_SW_RST;
+       reg |= PMA_INIT_SW_RST;
+       reg |= PMA_APB_SW_RST;
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       pr_info("clkrst = 0x%x\n", reg);
+
+       udelay(1);
+       reg = readl(regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       reg &= ~PMA_LOW_PWRN;
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       udelay(1);
+
+       // release overide
+       reg = readl(regs_base + EXYNOS_USBCON_LINK_CTRL);
+       reg &= ~LINKCTRL_PIPE3_FORCE_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_LINK_CTRL);
+
+       udelay(1);
+
+       reg = readl(regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       reg &= ~PMA_APB_SW_RST;
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+}
+
+
+void phy_exynos_usb_v3p1_pma_sw_rst_release(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg;
+
+       /* Reset Release for USB/DP PHY */
+       reg = readl(regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       reg &= ~PMA_CMN_SW_RST;
+       reg &= ~PMA_TRSV_SW_RST;
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+
+       udelay(1000);
+
+       /* Change pipe pclk to pipe3 */
+       reg = readl(regs_base + EXYNOS_USBCON_CLKRST);
+       reg |= CLKRST_LINK_PCLK_SEL;
+       writel(reg, regs_base + EXYNOS_USBCON_CLKRST);
+}
+
+void phy_exynos_usb_v3p1_g2_pma_sw_rst_release(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg;
+
+       /* Reset Release for USB/DP PHY */
+       reg = readl(regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       reg &= ~PMA_INIT_SW_RST;
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+
+       udelay(1); // Spec : wait for 200ns
+
+       /* run pll */
+       reg = readl(regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       reg &= ~PMA_TRSV_SW_RST;
+       reg &= ~PMA_CMN_SW_RST;
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+
+       udelay(1000);
+
+       /* Change pipe pclk to pipe3 */
+       /* add by LT case */
+       reg = readl(regs_base + EXYNOS_USBCON_CLKRST);
+       reg |= CLKRST_LINK_PCLK_SEL;
+       writel(reg, regs_base + EXYNOS_USBCON_CLKRST);
+
+}
+
+void phy_exynos_usb_v3p1_pipe_ready(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg;
+
+       reg = readl(regs_base + EXYNOS_USBCON_LINK_CTRL);
+       reg &= ~LINKCTRL_PIPE3_FORCE_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_LINK_CTRL);
+
+       reg = readl(regs_base + EXYNOS_USBCON_CLKRST);
+       reg &= ~CLKRST_LINK_PCLK_SEL;
+       writel(reg, regs_base + EXYNOS_USBCON_CLKRST);
+}
+
+void phy_exynos_usb_v3p1_pipe_ovrd(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg;
+
+       /* force pipe3 signal for link */
+       reg = readl(regs_base + EXYNOS_USBCON_LINK_CTRL);
+       reg |= LINKCTRL_PIPE3_FORCE_EN;
+       reg &= ~LINKCTRL_PIPE3_FORCE_PHY_STATUS;
+       reg |= LINKCTRL_PIPE3_FORCE_RX_ELEC_IDLE;
+       writel(reg, regs_base + EXYNOS_USBCON_LINK_CTRL);
+
+       /* PMA Disable */
+       reg = readl(regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+       reg |= PMA_LOW_PWRN;
+       writel(reg, regs_base + EXYNOS_USBCON_COMBO_PMA_CTRL);
+}
+
+void phy_exynos_usb3p1_rewa_ready(struct exynos_usbphy_info *info);
+void phy_exynos_usb_v3p1_late_enable(struct exynos_usbphy_info *info);
+
+void phy_exynos_usb_v3p1_enable(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg;
+       u32 reg_hsp;
+       bool ss_only_cap;
+       int main_version;
+
+       main_version = info->version & EXYNOS_USBCON_VER_MAJOR_VER_MASK;
+       ss_only_cap = (info->version & EXYNOS_USBCON_VER_SS_CAP) >> 4;
+
+       if (main_version == EXYNOS_USBCON_VER_03_0_0) {
+#if !defined(CONFIG_BOARD_ZEBU)
+               /* Set force q-channel */
+               exynos_cal_usbphy_q_ch(regs_base, 1);
+#endif
+
+#ifndef __BOOT__
+               /* Link Reset */
+               if (main_version == EXYNOS_USBCON_VER_03_0_0) {
+                       reg = readl(info->regs_base + EXYNOS_USBCON_CLKRST);
+                       reg |= CLKRST_LINK_SW_RST;
+                       writel(reg, regs_base + EXYNOS_USBCON_CLKRST);
+
+                       udelay(10);
+
+                       reg &= ~CLKRST_LINK_SW_RST;
+                       writel(reg, regs_base + EXYNOS_USBCON_CLKRST);
+               }
+#endif
+       }
+
+       /* Set PHY POR High */
+       phy_sw_rst_high(info);
+
+       if (!ss_only_cap) {
+               reg = readl(regs_base + EXYNOS_USBCON_UTMI);
+               reg &= ~UTMI_FORCE_SUSPEND;
+               reg &= ~UTMI_FORCE_SLEEP;
+               reg &= ~UTMI_DP_PULLDOWN;
+               reg &= ~UTMI_DM_PULLDOWN;
+               writel(reg, regs_base + EXYNOS_USBCON_UTMI);
+
+               /* set phy clock & control HS phy */
+               reg = readl(regs_base + EXYNOS_USBCON_HSP);
+
+               if (info->common_block_disable) {
+                       reg |= HSP_EN_UTMISUSPEND;
+                       reg |= HSP_COMMONONN;
+               } else
+                       reg &= ~HSP_COMMONONN;
+               writel(reg, regs_base + EXYNOS_USBCON_HSP);
+       } else {
+               void *ss_reg_base;
+
+               if (info->used_phy_port == 1)
+                       ss_reg_base = info->regs_base_2nd;
+               else
+                       ss_reg_base = info->regs_base;
+
+               /* Change pipe pclk to pipe3 */
+               reg = readl(ss_reg_base + EXYNOS_USBCON_CLKRST);
+               reg |= CLKRST_LINK_PCLK_SEL;
+               writel(reg, ss_reg_base + EXYNOS_USBCON_CLKRST);
+       }
+       udelay(100);
+
+       /* Follow setting sequence for USB Link */
+       /* 1. Set VBUS Valid and DP-Pull up control
+        * by VBUS pad usage */
+       link_vbus_filter_en(info, false);
+       reg = readl(regs_base + EXYNOS_USBCON_UTMI);
+       reg_hsp = readl(regs_base + EXYNOS_USBCON_HSP);
+       reg |= UTMI_FORCE_BVALID;
+       reg |= UTMI_FORCE_VBUSVALID;
+       reg_hsp |= HSP_VBUSVLDEXTSEL;
+       reg_hsp |= HSP_VBUSVLDEXT;
+
+       writel(reg, regs_base + EXYNOS_USBCON_UTMI);
+       writel(reg_hsp, regs_base + EXYNOS_USBCON_HSP);
+
+       /* Set PHY tune para */
+       phy_exynos_usb_v3p1_tune(info);
+
+       /* Enable PHY Power Mode */
+       phy_power_en(info, 1);
+
+       /* before POR low, 10us delay is needed. */
+       udelay(10);
+
+       /* Set PHY POR Low */
+       phy_sw_rst_low(info);
+
+       /* after POR low and delay 75us, PHYCLOCK is guaranteed. */
+       udelay(75);
+
+       if (ss_only_cap) {
+               phy_exynos_usb_v3p1_late_enable(info);
+               return;
+       }
+
+       /* Select PHY MUX */
+       if (info->dual_phy) {
+               u32 physel;
+
+               physel = readl(regs_base + EXYNOS_USBCON_DUALPHYSEL);
+               if (info->used_phy_port == 0) {
+                       physel &= ~DUALPHYSEL_PHYSEL_CTRL;
+                       physel &= ~DUALPHYSEL_PHYSEL_SSPHY;
+                       physel &= ~DUALPHYSEL_PHYSEL_PIPECLK;
+                       physel &= ~DUALPHYSEL_PHYSEL_PIPERST;
+               } else {
+                       physel |= DUALPHYSEL_PHYSEL_CTRL;
+                       physel |= DUALPHYSEL_PHYSEL_SSPHY;
+                       physel |= DUALPHYSEL_PHYSEL_PIPECLK;
+                       physel |= DUALPHYSEL_PHYSEL_PIPERST;
+               }
+               writel(physel, regs_base + EXYNOS_USBCON_DUALPHYSEL);
+       }
+
+       /* 2. OVC io usage */
+       reg = readl(regs_base + EXYNOS_USBCON_LINK_PORT);
+       if (info->use_io_for_ovc) {
+               reg &= ~LINKPORT_HUB_PORT_SEL_OCD_U3;
+               reg &= ~LINKPORT_HUB_PORT_SEL_OCD_U2;
+       } else {
+               reg |= LINKPORT_HUB_PORT_SEL_OCD_U3;
+               reg |= LINKPORT_HUB_PORT_SEL_OCD_U2;
+       }
+       writel(reg, regs_base + EXYNOS_USBCON_LINK_PORT);
+
+       /* Enable ReWA */
+       if (info->hs_rewa)
+               phy_exynos_usb3p1_rewa_ready(info);
+}
+
+enum exynos_usbcon_cr {
+       USBCON_CR_ADDR = 0,
+       USBCON_CR_DATA = 1,
+       USBCON_CR_READ = 18,
+       USBCON_CR_WRITE = 19,
+};
+
+static u16 phy_exynos_usb_v3p1_cr_access(struct exynos_usbphy_info *info,
+       enum exynos_usbcon_cr cr_bit, u16 data)
+{
+       void __iomem *base;
+
+       u32 ssp_crctl0 = 0;
+       u32 ssp_crctl1 = 0;
+       u32 loop;
+       u32 loop_cnt;
+
+       if (info->used_phy_port != -1) {
+               if (info->used_phy_port == 0)
+                       base = info->regs_base;
+               else
+                       base = info->regs_base_2nd;
+       } else
+               base = info->regs_base;
+
+       /*Clear CR port register*/
+       ssp_crctl0 = readl(base + EXYNOS_USBCON_SSP_CRCTL0);
+       ssp_crctl0 &= ~(0xf);
+       ssp_crctl0 &= ~(0xffffU << 16);
+       writel(ssp_crctl0, base + EXYNOS_USBCON_SSP_CRCTL0);
+
+       /*Set Data for cr port*/
+       ssp_crctl0 &= ~SSP_CCTRL0_CR_DATA_IN_MASK;
+       ssp_crctl0 |= SSP_CCTRL0_CR_DATA_IN(data);
+       writel(ssp_crctl0, base + EXYNOS_USBCON_SSP_CRCTL0);
+
+       if (cr_bit == USBCON_CR_ADDR)
+               loop = 1;
+       else
+               loop = 2;
+
+       for (loop_cnt = 0; loop_cnt < loop; loop_cnt++) {
+               u32 trigger_bit = 0;
+               u32 handshake_cnt = 2;
+               /* Trigger cr port */
+               if (cr_bit == USBCON_CR_ADDR)
+                       trigger_bit = SSP_CRCTRL0_CR_CAP_ADDR;
+               else {
+                       if (loop_cnt == 0)
+                               trigger_bit = SSP_CRCTRL0_CR_CAP_DATA;
+                       else {
+                               if (cr_bit == USBCON_CR_READ)
+                                       trigger_bit = SSP_CRCTRL0_CR_READ;
+                               else
+                                       trigger_bit = SSP_CRCTRL0_CR_WRITE;
+                       }
+               }
+               /* Handshake Procedure */
+               do {
+                       u32 usec = 100;
+                       if (handshake_cnt == 2)
+                               ssp_crctl0 |= trigger_bit;
+                       else
+                               ssp_crctl0 &= ~trigger_bit;
+                       writel(ssp_crctl0, base + EXYNOS_USBCON_SSP_CRCTL0);
+
+                       /* Handshake */
+                       do {
+                               ssp_crctl1 = readl(base + EXYNOS_USBCON_SSP_CRCTL1);
+                               if ((handshake_cnt == 2) && (ssp_crctl1 & SSP_CRCTL1_CR_ACK))
+                                       break;
+                               else if ((handshake_cnt == 1) && !(ssp_crctl1 & SSP_CRCTL1_CR_ACK))
+                                       break;
+
+                               udelay(1);
+                       } while (usec-- > 0);
+
+#ifndef __BOOT__
+                       if (!usec)
+                               pr_err("CRPORT handshake timeout1 (0x%08x)\n", ssp_crctl0);
+#endif
+
+                       udelay(5);
+                       handshake_cnt--;
+               } while (handshake_cnt != 0);
+               udelay(50);
+
+       }
+       return (u16) ((ssp_crctl1 & SSP_CRCTL1_CR_DATA_OUT_MASK) >> 16);
+}
+
+void phy_exynos_usb_v3p1_cal_cr_write(struct exynos_usbphy_info *info, u16 addr, u16 data)
+{
+       phy_exynos_usb_v3p1_cr_access(info, USBCON_CR_ADDR, addr);
+       phy_exynos_usb_v3p1_cr_access(info, USBCON_CR_WRITE, data);
+}
+
+u16 phy_exynos_usb_v3p1_cal_cr_read(struct exynos_usbphy_info *info, u16 addr)
+{
+       phy_exynos_usb_v3p1_cr_access(info, USBCON_CR_ADDR, addr);
+       return phy_exynos_usb_v3p1_cr_access(info, USBCON_CR_READ, 0);
+}
+
+void phy_exynos_usb_v3p1_cal_usb3phy_tune_fix_rxeq(struct exynos_usbphy_info *info)
+{
+       u16 reg;
+       int rxeq_val;
+
+       rxeq_val = exynos_usb3p1_get_tune_param(info, "rx_eq_fix_val");
+       if (rxeq_val == -1)
+               return;
+
+       reg = phy_exynos_usb_v3p1_cal_cr_read(info, 0x1006);
+       reg &= ~(1 << 6);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1006, reg);
+
+       udelay(10);
+
+       reg |= (1 << 7);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1006, reg);
+
+       udelay(10);
+
+       reg &= ~(0x7 << 0x8);
+       reg |= ((rxeq_val & 0x7) << 8);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1006, reg);
+
+       udelay(10);
+
+       reg |= (1 << 11);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1006, reg);
+#ifndef __BOOT__
+       pr_info("Reg RX_OVRD_IN_HI : 0x%x\n",
+               phy_exynos_usb_v3p1_cal_cr_read(info, 0x1006));
+       pr_info("Reg RX_CDR_CDR_FSM_DEBUG : 0x%x\n",
+               phy_exynos_usb_v3p1_cal_cr_read(info, 0x101c));
+#endif
+}
+
+static void set_ss_tx_impedance(struct exynos_usbphy_info *info)
+{
+       u16 rtune_debug, tx_ovrd_in_hi;
+       u8 tx_imp;
+
+       /* obtain calibration code for 45Ohm impedance */
+       rtune_debug = phy_exynos_usb_v3p1_cal_cr_read(info, 0x3);
+       /* set SUP.DIG.RTUNE_DEBUG.TYPE = 2 */
+       rtune_debug &= ~(0x3 << 3);
+       rtune_debug |= (0x2 << 3);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x3, rtune_debug);
+
+       /* read SUP.DIG.RTUNE_STAT (0x0004[9:0]) */
+       tx_imp = phy_exynos_usb_v3p1_cal_cr_read(info, 0x4);
+       /* current_tx_cal_code[9:0] = SUP.DIG.RTUNE_STAT (0x0004[9:0]) */
+       tx_imp += 8;
+       /* tx_cal_code[9:0] = current_tx_cal_code[9:0] + 8(decimal)
+        * NOTE, max value is 63;
+        * i.e. if tx_cal_code[9:0] > 63, tx_cal_code[9:0]==63; */
+       if (tx_imp > 63)
+               tx_imp = 63;
+
+       /* set LANEX_DIG_TX_OVRD_IN_HI.TX_RESET_OVRD = 1 */
+       tx_ovrd_in_hi = phy_exynos_usb_v3p1_cal_cr_read(info, 0x1001);
+       tx_ovrd_in_hi |= (1 << 7);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1001, tx_ovrd_in_hi);
+
+       /* SUP.DIG.RTUNE_DEBUG.MAN_TUNE = 0 */
+       rtune_debug &= ~(1 << 1);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x3, rtune_debug);
+
+       /* set SUP.DIG.RTUNE_DEBUG.VALUE = tx_cal_code[9:0] */
+       rtune_debug &= ~(0x1ff << 5);
+       rtune_debug |= (tx_imp << 5);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x3, rtune_debug);
+
+       /* set SUP.DIG.RTUNE_DEBUG.SET_VAL = 1 */
+       rtune_debug |= (1 << 2);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x3, rtune_debug);
+
+       /* set SUP.DIG.RTUNE_DEBUG.SET_VAL = 0 */
+       rtune_debug &= ~(1 << 2);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x3, rtune_debug);
+
+       /* set LANEX_DIG_TX_OVRD_IN_HI.TX_RESET = 1 */
+       tx_ovrd_in_hi |= (1 << 6);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1001, tx_ovrd_in_hi);
+
+       /* set LANEX_DIG_TX_OVRD_IN_HI.TX_RESET = 0 */
+       tx_ovrd_in_hi &= ~(1 << 6);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1001, tx_ovrd_in_hi);
+}
+
+void phy_exynos_usb_v3p1_cal_usb3phy_tune_adaptive_eq(
+       struct exynos_usbphy_info *info, u8 eq_fix)
+{
+       u16 reg;
+
+       reg = phy_exynos_usb_v3p1_cal_cr_read(info, 0x1006);
+       if (eq_fix) {
+               reg |= (1 << 6);
+               reg &= ~(1 << 7);
+       } else {
+               reg &= ~(1 << 6);
+               reg |= (1 << 7);
+       }
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1006, reg);
+}
+
+void phy_exynos_usb_v3p1_usb3phy_tune_chg_rxeq(
+       struct exynos_usbphy_info *info, u8 eq_val)
+{
+       u16 reg;
+
+       reg = phy_exynos_usb_v3p1_cal_cr_read(info, 0x1006);
+       reg &= ~(0x7 << 0x8);
+       reg |= ((eq_val & 0x7) << 8);
+       reg |= (1 << 11);
+       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1006, reg);
+}
+
+enum exynos_usbphy_tif {
+       USBCON_TIF_RD_STS,
+       USBCON_TIF_RD_OVRD,
+       USBCON_TIF_WR_OVRD,
+};
+
+static u8 phy_exynos_usb_v3p1_tif_access(struct exynos_usbphy_info *info,
+       enum exynos_usbphy_tif access_type, u8 addr, u8 data)
+{
+       void __iomem *base;
+       u32 hsp_test;
+
+       base = info->regs_base;
+       hsp_test = readl(base + EXYNOS_USBCON_HSP_TEST);
+       /* Set TEST DATA OUT SEL */
+       if (access_type == USBCON_TIF_RD_STS)
+               hsp_test &= ~HSP_TEST_DATA_OUT_SEL;
+       else
+               hsp_test |= HSP_TEST_DATA_OUT_SEL;
+       hsp_test &= ~HSP_TEST_DATA_IN_MASK;
+       hsp_test &= ~HSP_TEST_DATA_ADDR_MASK;
+       hsp_test |= HSP_TEST_DATA_ADDR_SET(addr);
+       writel(hsp_test, base + EXYNOS_USBCON_HSP_TEST);
+
+       udelay(10);
+
+       hsp_test = readl(base + EXYNOS_USBCON_HSP_TEST);
+       if (access_type != USBCON_TIF_WR_OVRD)
+               return HSP_TEST_DATA_OUT_GET(hsp_test);
+
+       hsp_test |= HSP_TEST_DATA_IN_SET((data | 0xf0));
+       hsp_test |= HSP_TEST_CLK;
+       writel(hsp_test, base + EXYNOS_USBCON_HSP_TEST);
+
+       udelay(10);
+
+       hsp_test = readl(base + EXYNOS_USBCON_HSP_TEST);
+       hsp_test &= ~HSP_TEST_CLK;
+       writel(hsp_test, base + EXYNOS_USBCON_HSP_TEST);
+
+       hsp_test = readl(base + EXYNOS_USBCON_HSP_TEST);
+       return HSP_TEST_DATA_OUT_GET(hsp_test);
+}
+
+u8 phy_exynos_usb_v3p1_tif_ov_rd(struct exynos_usbphy_info *info, u8 addr)
+{
+       return phy_exynos_usb_v3p1_tif_access(info, USBCON_TIF_RD_OVRD, addr, 0x0);
+}
+
+u8 phy_exynos_usb_v3p1_tif_ov_wr(struct exynos_usbphy_info *info, u8 addr, u8 data)
+{
+       return phy_exynos_usb_v3p1_tif_access(info, USBCON_TIF_WR_OVRD, addr, data);
+}
+
+u8 phy_exynos_usb_v3p1_tif_sts_rd(struct exynos_usbphy_info *info, u8 addr)
+{
+       return phy_exynos_usb_v3p1_tif_access(info, USBCON_TIF_RD_STS, addr, 0x0);
+}
+
+void phy_exynos_usb_v3p1_late_enable(struct exynos_usbphy_info *info)
+{
+       u32 version = info->version;
+
+
+       if (version > EXYNOS_USBCON_VER_05_0_0) {
+               int tune_val;
+               u16 cr_reg;
+
+               /*Set RXDET_MEAS_TIME[11:4] each reference clock*/
+               phy_exynos_usb_v3p1_cal_cr_write(info, 0x1010, 0x80);
+
+               tune_val = exynos_usb3p1_get_tune_param(info, "rx_decode_mode");
+               if (tune_val != -1)
+                       phy_exynos_usb_v3p1_cal_cr_write(info, 0x1026, 0x1);
+
+               tune_val = exynos_usb3p1_get_tune_param(info, "cr_lvl_ctrl_en");
+               if (tune_val != -1) {
+                       /* Enable override los_bias, los_level and
+                        * tx_vboost_lvl, Set los_bias to 0x5 and
+                        * los_level to 0x9 */
+                       phy_exynos_usb_v3p1_cal_cr_write(info, 0x15, 0xA409);
+                       /* Set TX_VBOOST_LEVLE to tune->tx_boost_level */
+                       tune_val = exynos_usb3p1_get_tune_param(info, "tx_vboost_lvl");
+                       if (tune_val != -1) {
+                               cr_reg = phy_exynos_usb_v3p1_cal_cr_read(info, 0x12);
+                               cr_reg &= ~(0x7 << 13);
+                               cr_reg |= ((tune_val & 0x7) << 13);
+                               phy_exynos_usb_v3p1_cal_cr_write(info, 0x12, cr_reg);
+                       }
+                       // Set swing_full to LANEN_DIG_TX_OVRD_DRV_LO
+                       cr_reg = 0x4000;
+                       tune_val = exynos_usb3p1_get_tune_param(info, "pcs_tx_deemph_3p5db");
+                       if (tune_val != -1) {
+                               cr_reg |= (tune_val << 7);
+                               tune_val = exynos_usb3p1_get_tune_param(info, "pcs_tx_swing_full");
+                               if (tune_val != -1)
+                                       cr_reg |= tune_val;
+                               else
+                                       cr_reg = 0;
+                       } else
+                               cr_reg = 0;
+                       if (cr_reg)
+                               phy_exynos_usb_v3p1_cal_cr_write(info, 0x1002, cr_reg);
+               }
+               /* to set the charge pump proportional current */
+               tune_val = exynos_usb3p1_get_tune_param(info, "mpll_charge_pump");
+               if (tune_val != -1)
+                       phy_exynos_usb_v3p1_cal_cr_write(info, 0x30, 0xC0);
+
+               tune_val = exynos_usb3p1_get_tune_param(info, "rx_eq_fix_val");
+               if (tune_val != -1)
+                       phy_exynos_usb_v3p1_cal_usb3phy_tune_fix_rxeq(info);
+
+               tune_val = exynos_usb3p1_get_tune_param(info, "decrese_ss_tx_imp");
+               if (tune_val != -1)
+                       set_ss_tx_impedance(info);
+       }
+}
+
+void phy_exynos_usb_v3p1_disable(struct exynos_usbphy_info *info)
+{
+       u32 reg;
+       void __iomem *regs_base = info->regs_base;
+
+       /* set phy clock & control HS phy */
+       reg = readl(regs_base + EXYNOS_USBCON_UTMI);
+       reg |= UTMI_FORCE_SUSPEND;
+       reg |= UTMI_FORCE_SLEEP;
+       writel(reg, regs_base + EXYNOS_USBCON_UTMI);
+
+       /* Disable PHY Power Mode */
+       phy_power_en(info, 0);
+
+#if !defined(CONFIG_BOARD_ZEBU)
+       /* clear force q-channel */
+       exynos_cal_usbphy_q_ch(regs_base, 0);
+#endif
+}
+
+u64 phy_exynos_usb3p1_get_logic_trace(struct exynos_usbphy_info *info)
+{
+       u64 ret;
+       void __iomem *regs_base = info->regs_base;
+
+       ret = readl(regs_base + EXYNOS_USBCON_LINK_DEBUG_L);
+       ret |= ((u64) readl(regs_base + EXYNOS_USBCON_LINK_DEBUG_H)) << 32;
+
+       return ret;
+}
+
+void phy_exynos_usb3p1_pcs_reset(struct exynos_usbphy_info *info)
+{
+       u32 clkrst;
+       void __iomem *regs_base = info->regs_base;
+
+       clkrst = readl(regs_base + EXYNOS_USBCON_CLKRST);
+       if (EXYNOS_USBCON_VER_MINOR(info->version) >= 0x1) {
+               /* TODO : How to pcs reset
+                * clkrst |= CLKRST_PHY30_RST_SEL;
+                * clkrst |= CLKRST_PHY30_SW_RST;
+                */
+       } else {
+               clkrst |= CLKRST_PHY_SW_RST;
+               clkrst |= CLKRST_PHY_RST_SEL;
+       }
+       writel(clkrst, regs_base + EXYNOS_USBCON_CLKRST);
+
+       udelay(1);
+
+       clkrst = readl(regs_base + EXYNOS_USBCON_CLKRST);
+       if (EXYNOS_USBCON_VER_MINOR(info->version) >= 0x1) {
+               clkrst |= CLKRST_PHY30_RST_SEL;
+               clkrst &= ~CLKRST_PHY30_SW_RST;
+       } else {
+               clkrst |= CLKRST_PHY_RST_SEL;
+               clkrst &= ~CLKRST_PHY_SW_RST;
+       }
+       writel(clkrst, regs_base + EXYNOS_USBCON_CLKRST);
+}
+
+void phy_exynos_usb_v3p1_enable_dp_pullup(struct exynos_usbphy_info *usbphy_info)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 phyutmi;
+
+       phyutmi = readl(regs_base + EXYNOS_USBCON_HSP);
+       phyutmi |= HSP_VBUSVLDEXT;
+       writel(phyutmi, regs_base + EXYNOS_USBCON_HSP);
+}
+
+void phy_exynos_usb_v3p1_disable_dp_pullup(struct exynos_usbphy_info *usbphy_info)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 phyutmi;
+
+       phyutmi = readl(regs_base + EXYNOS_USBCON_HSP);
+       phyutmi &= ~HSP_VBUSVLDEXT;
+       writel(phyutmi, regs_base + EXYNOS_USBCON_HSP);
+}
+
+void phy_exynos_usb_v3p1_config_host_mode(struct exynos_usbphy_info *info)
+{
+       u32 reg;
+       void __iomem *regs_base = info->regs_base;
+
+       /* DP/DM Pull Down Control */
+       reg = readl(regs_base + EXYNOS_USBCON_UTMI);
+       reg |= UTMI_DP_PULLDOWN;
+       reg |= UTMI_DM_PULLDOWN;
+       reg &= ~UTMI_FORCE_BVALID;
+       reg &= ~UTMI_FORCE_VBUSVALID;
+       writel(reg, regs_base + EXYNOS_USBCON_UTMI);
+
+       /* Disable Pull-up Register */
+       reg = readl(regs_base + EXYNOS_USBCON_HSP);
+       reg &= ~HSP_VBUSVLDEXTSEL;
+       reg &= ~HSP_VBUSVLDEXT;
+       writel(reg, regs_base + EXYNOS_USBCON_HSP);
+}
+
+void phy_exynos_usb_v3p1_tune(struct exynos_usbphy_info *info)
+{
+       u32 hsp_tune, ssp_tune0, ssp_tune1, ssp_tune2, cnt;
+
+       bool ss_only_cap;
+
+       ss_only_cap = (info->version & EXYNOS_USBCON_VER_SS_CAP) >> 4;
+
+       if (!info->tune_param)
+               return;
+
+       if (!ss_only_cap) {
+               /* hsphy tuning */
+               void __iomem *regs_base = info->regs_base;
+
+               hsp_tune = readl(regs_base + EXYNOS_USBCON_HSP_TUNE);
+
+               cnt = 0;
+               for (; info->tune_param[cnt].value != EXYNOS_USB_TUNE_LAST; cnt++) {
+                       char *para_name;
+                       int val;
+
+                       val = info->tune_param[cnt].value;
+                       if (val == -1)
+                               continue;
+                       para_name = info->tune_param[cnt].name;
+                       if (!strcmp(para_name, "compdis")) {
+                               hsp_tune &= ~HSP_TUNE_COMPDIS_MASK;
+                               hsp_tune |= HSP_TUNE_COMPDIS_SET(val);
+                       } else if (!strcmp(para_name, "otg")) {
+                               hsp_tune &= ~HSP_TUNE_OTG_MASK;
+                               hsp_tune |= HSP_TUNE_OTG_SET(val);
+                       } else if (!strcmp(para_name, "rx_sqrx")) {
+                               hsp_tune &= ~HSP_TUNE_SQRX_MASK;
+                               hsp_tune |= HSP_TUNE_SQRX_SET(val);
+                       } else if (!strcmp(para_name, "tx_fsls")) {
+                               hsp_tune &= ~HSP_TUNE_TXFSLS_MASK;
+                               hsp_tune |= HSP_TUNE_TXFSLS_SET(val);
+                       } else if (!strcmp(para_name, "tx_hsxv")) {
+                               hsp_tune &= ~HSP_TUNE_HSXV_MASK;
+                               hsp_tune |= HSP_TUNE_HSXV_SET(val);
+                       } else if (!strcmp(para_name, "tx_pre_emp")) {
+                               hsp_tune &= ~HSP_TUNE_TXPREEMPA_MASK;
+                               hsp_tune |= HSP_TUNE_TXPREEMPA_SET(val);
+                       } else if (!strcmp(para_name, "tx_pre_emp_plus")) {
+                               if (val)
+                                       hsp_tune |= HSP_TUNE_TXPREEMPA_PLUS;
+                               else
+                                       hsp_tune &= ~HSP_TUNE_TXPREEMPA_PLUS;
+                       } else if (!strcmp(para_name, "tx_res")) {
+                               hsp_tune &= ~HSP_TUNE_TXRES_MASK;
+                               hsp_tune |= HSP_TUNE_TXRES_SET(val);
+                       } else if (!strcmp(para_name, "tx_rise")) {
+                               hsp_tune &= ~HSP_TUNE_TXRISE_MASK;
+                               hsp_tune |= HSP_TUNE_TXRISE_SET(val);
+                       } else if (!strcmp(para_name, "tx_vref")) {
+                               hsp_tune &= ~HSP_TUNE_TXVREF_MASK;
+                               hsp_tune |= HSP_TUNE_TXVREF_SET(val);
+                       } else if (!strcmp(para_name, "tx_res_ovrd"))
+                               phy_exynos_usb_v3p1_tif_ov_wr(info, 0x6, val);
+               }
+               writel(hsp_tune, regs_base + EXYNOS_USBCON_HSP_TUNE);
+       } else {
+               /* ssphy tuning */
+               void __iomem *ss_reg_base;
+
+               if (info->used_phy_port == 1)
+                       ss_reg_base = info->regs_base_2nd;
+               else
+                       ss_reg_base = info->regs_base;
+
+               ssp_tune0 = readl(ss_reg_base + EXYNOS_USBCON_SSP_PARACON0);
+               ssp_tune1 = readl(ss_reg_base + EXYNOS_USBCON_SSP_PARACON1);
+               ssp_tune2 = readl(ss_reg_base + EXYNOS_USBCON_SSP_TEST);
+
+               cnt = 0;
+               for (; info->tune_param[cnt].value != EXYNOS_USB_TUNE_LAST; cnt++) {
+                       char *para_name;
+                       int val;
+
+                       val = info->tune_param[cnt].value;
+                       if (val == -1)
+                               continue;
+                       para_name = info->tune_param[cnt].name;
+                       if (!strcmp(para_name, "pcs_tx_swing_full")) {
+                               ssp_tune0 &= ~SSP_PARACON0_PCS_TX_SWING_FULL_MASK;
+                               ssp_tune0 |= SSP_PARACON0_PCS_TX_SWING_FULL(val);
+                       } else if (!strcmp(para_name, "pcs_tx_deemph_6db")) {
+                               ssp_tune0 &= ~SSP_PARACON0_PCS_TX_DEEMPH_6DB_MASK;
+                               ssp_tune0 |= SSP_PARACON0_PCS_TX_DEEMPH_6DB(val);
+                       } else if (!strcmp(para_name, "pcs_tx_deemph_3p5db")) {
+                               ssp_tune0 &= ~SSP_PARACON0_PCS_TX_DEEMPH_3P5DB_MASK;
+                               ssp_tune0 |= SSP_PARACON0_PCS_TX_DEEMPH_3P5DB(val);
+                       } else if (!strcmp(para_name, "tx_vboost_lvl_sstx")) {
+                               ssp_tune1 &= ~SSP_PARACON1_TX_VBOOST_LVL_SSTX_MASK;
+                               ssp_tune1 |= SSP_PARACON1_TX_VBOOST_LVL_SSTX(val);
+                       } else if (!strcmp(para_name, "tx_vboost_lvl")) {
+                               ssp_tune1 &= ~SSP_PARACON1_TX_VBOOST_LVL_MASK;
+                               ssp_tune1 |= SSP_PARACON1_TX_VBOOST_LVL(val);
+                       } else if (!strcmp(para_name, "los_level")) {
+                               ssp_tune1 &= ~SSP_PARACON1_LOS_LEVEL_MASK;
+                               ssp_tune1 |= SSP_PARACON1_LOS_LEVEL(val);
+                       } else if (!strcmp(para_name, "los_bias")) {
+                               ssp_tune1 &= ~SSP_PARACON1_LOS_BIAS_MASK;
+                               ssp_tune1 |= SSP_PARACON1_LOS_BIAS(val);
+                       } else if (!strcmp(para_name, "pcs_rx_los_mask_val")) {
+                               ssp_tune1 &= ~SSP_PARACON1_PCS_RX_LOS_MASK_VAL_MASK;
+                               ssp_tune1 |= SSP_PARACON1_PCS_RX_LOS_MASK_VAL(val);
+                               /* SSP TEST setting : 0x135e/f_0000 + 0x3c */
+                       } else if (!strcmp(para_name, "tx_eye_height_cntl_en")) {
+                               ssp_tune2 &= ~SSP_TEST_TX_EYE_HEIGHT_CNTL_EN_MASK;
+                               ssp_tune2 |= SSP_TEST_TX_EYE_HEIGHT_CNTL_EN(val);
+                       } else if (!strcmp(para_name, "pipe_tx_deemph_update_delay")) {
+                               ssp_tune2 &= ~SSP_TEST_PIPE_TX_DEEMPH_UPDATE_DELAY_MASK;
+                               ssp_tune2 |= SSP_TEST_PIPE_TX_DEEMPH_UPDATE_DELAY(val);
+                       } else if (!strcmp(para_name, "pcs_tx_swing_full_sstx")) {
+                               ssp_tune2 &= ~SSP_TEST_PCS_TX_SWING_FULL_SSTX_MASK;
+                               ssp_tune2 |= SSP_TEST_PCS_TX_SWING_FULL_SSTX(val);
+                       }
+
+               } /* for */
+               writel(ssp_tune0, ss_reg_base + EXYNOS_USBCON_SSP_PARACON0);
+               writel(ssp_tune1, ss_reg_base + EXYNOS_USBCON_SSP_PARACON1);
+               writel(ssp_tune2, ss_reg_base + EXYNOS_USBCON_SSP_TEST);
+       } /* else */
+}
+
+void phy_exynos_usb_v3p1_tune_each(struct exynos_usbphy_info *info,
+       char *para_name, int val)
+{
+#ifndef __BOOT__
+       u32 hsp_tune, ssp_tune0, ssp_tune1;
+
+       bool ss_only_cap;
+
+       ss_only_cap = (info->version & EXYNOS_USBCON_VER_SS_CAP) >> 4;
+
+       if (!info->tune_param)
+               return;
+
+       if (!ss_only_cap) {
+               void __iomem *regs_base = info->regs_base;
+
+               hsp_tune = readl(regs_base + EXYNOS_USBCON_HSP_TUNE);
+               if (!strcmp(para_name, "compdis")) {
+                       hsp_tune &= ~HSP_TUNE_COMPDIS_MASK;
+                       hsp_tune |= HSP_TUNE_COMPDIS_SET(val);
+               } else if (!strcmp(para_name, "otg")) {
+                       hsp_tune &= ~HSP_TUNE_OTG_MASK;
+                       hsp_tune |= HSP_TUNE_OTG_SET(val);
+               } else if (!strcmp(para_name, "rx_sqrx")) {
+                       hsp_tune &= ~HSP_TUNE_SQRX_MASK;
+                       hsp_tune |= HSP_TUNE_SQRX_SET(val);
+               } else if (!strcmp(para_name, "tx_fsls")) {
+                       hsp_tune &= ~HSP_TUNE_TXFSLS_MASK;
+                       hsp_tune |= HSP_TUNE_TXFSLS_SET(val);
+               } else if (!strcmp(para_name, "tx_hsxv")) {
+                       hsp_tune &= ~HSP_TUNE_HSXV_MASK;
+                       hsp_tune |= HSP_TUNE_HSXV_SET(val);
+               } else if (!strcmp(para_name, "tx_pre_emp")) {
+                       hsp_tune &= ~HSP_TUNE_TXPREEMPA_MASK;
+                       hsp_tune |= HSP_TUNE_TXPREEMPA_SET(val);
+               } else if (!strcmp(para_name, "tx_pre_emp_plus")) {
+                       if (val)
+                               hsp_tune |= HSP_TUNE_TXPREEMPA_PLUS;
+                       else
+                               hsp_tune &= ~HSP_TUNE_TXPREEMPA_PLUS;
+               } else if (!strcmp(para_name, "tx_res")) {
+                       hsp_tune &= ~HSP_TUNE_TXRES_MASK;
+                       hsp_tune |= HSP_TUNE_TXRES_SET(val);
+               } else if (!strcmp(para_name, "tx_rise")) {
+                       hsp_tune &= ~HSP_TUNE_TXRISE_MASK;
+                       hsp_tune |= HSP_TUNE_TXRISE_SET(val);
+               } else if (!strcmp(para_name, "tx_vref")) {
+                       hsp_tune &= ~HSP_TUNE_TXVREF_MASK;
+                       hsp_tune |= HSP_TUNE_TXVREF_SET(val);
+               } else if (!strcmp(para_name, "tx_res_ovrd"))
+                       phy_exynos_usb_v3p1_tif_ov_wr(info, 0x6, val);
+               writel(hsp_tune, regs_base + EXYNOS_USBCON_HSP_TUNE);
+       } else {
+               /* ssphy tuning */
+               void __iomem *ss_reg_base;
+
+               if (info->used_phy_port == 1)
+                       ss_reg_base = info->regs_base_2nd;
+               else
+                       ss_reg_base = info->regs_base;
+
+               ssp_tune0 = readl(ss_reg_base + EXYNOS_USBCON_SSP_PARACON0);
+               ssp_tune1 = readl(ss_reg_base + EXYNOS_USBCON_SSP_PARACON1);
+
+               if (!strcmp(para_name, "tx0_term_offset")) {
+                       ssp_tune0 &= ~SSP_PARACON0_TX0_TERM_OFFSET_MASK;
+                       ssp_tune0 |= SSP_PARACON0_TX0_TERM_OFFSET(val);
+               } else if (!strcmp(para_name, "pcs_tx_swing_full")) {
+                       ssp_tune0 &= ~SSP_PARACON0_PCS_TX_SWING_FULL_MASK;
+                       ssp_tune0 |= SSP_PARACON0_PCS_TX_SWING_FULL(val);
+               } else if (!strcmp(para_name, "pcs_tx_deemph_6db")) {
+                       ssp_tune0 &= ~SSP_PARACON0_PCS_TX_DEEMPH_6DB_MASK;
+                       ssp_tune0 |= SSP_PARACON0_PCS_TX_DEEMPH_6DB(val);
+               } else if (!strcmp(para_name, "pcs_tx_deemph_3p5db")) {
+                       ssp_tune0 &= ~SSP_PARACON0_PCS_TX_DEEMPH_3P5DB_MASK;
+                       ssp_tune0 |= SSP_PARACON0_PCS_TX_DEEMPH_3P5DB(val);
+               } else if (!strcmp(para_name, "tx_vboost_lvl")) {
+                       ssp_tune1 &= ~SSP_PARACON1_TX_VBOOST_LVL_MASK;
+                       ssp_tune1 |= SSP_PARACON1_TX_VBOOST_LVL(val);
+               } else if (!strcmp(para_name, "los_level")) {
+                       ssp_tune1 &= ~SSP_PARACON1_LOS_LEVEL_MASK;
+                       ssp_tune1 |= SSP_PARACON1_LOS_LEVEL(val);
+               } else if (!strcmp(para_name, "los_bias")) {
+                       ssp_tune1 &= ~SSP_PARACON1_LOS_BIAS_MASK;
+                       ssp_tune1 |= SSP_PARACON1_LOS_BIAS(val);
+               } else if (!strcmp(para_name, "pcs_rx_los_mask_val")) {
+                       ssp_tune1 &= ~SSP_PARACON1_PCS_RX_LOS_MASK_VAL_MASK;
+                       ssp_tune1 |= SSP_PARACON1_PCS_RX_LOS_MASK_VAL(val);
+               }
+               writel(ssp_tune0, ss_reg_base + EXYNOS_USBCON_SSP_PARACON0);
+               writel(ssp_tune1, ss_reg_base + EXYNOS_USBCON_SSP_PARACON1);
+       } /* else */
+#endif
+}
+
+void phy_exynos_usb_v3p1_rd_tune_each_from_reg(struct exynos_usbphy_info *info,
+       u32 tune, char *para_name, int *val)
+{
+       bool ss_only_cap;
+
+       ss_only_cap = (info->version & EXYNOS_USBCON_VER_SS_CAP) >> 4;
+
+       if (!info->tune_param)
+               return;
+
+       if (!ss_only_cap) { /* hsphy tuning */
+               if (!strcmp(para_name, "compdis"))
+                       *val = HSP_TUNE_COMPDIS_GET(tune);
+               else if (!strcmp(para_name, "otg"))
+                       *val = HSP_TUNE_OTG_GET(tune);
+               else if (!strcmp(para_name, "rx_sqrx"))
+                       *val = HSP_TUNE_SQRX_GET(tune);
+               else if (!strcmp(para_name, "tx_fsls"))
+                       *val = HSP_TUNE_TXFSLS_GET(tune);
+               else if (!strcmp(para_name, "tx_hsxv"))
+                       *val = HSP_TUNE_HSXV_GET(tune);
+               else if (!strcmp(para_name, "tx_pre_emp"))
+                       *val = HSP_TUNE_TXPREEMPA_GET(tune);
+               else if (!strcmp(para_name, "tx_pre_emp_plus"))
+                       *val = HSP_TUNE_TXPREEMPA_PLUS_GET(tune);
+               else if (!strcmp(para_name, "tx_res"))
+                       *val = HSP_TUNE_TXRES_GET(tune);
+               else if (!strcmp(para_name, "tx_rise"))
+                       *val = HSP_TUNE_TXRISE_GET(tune);
+               else if (!strcmp(para_name, "tx_vref"))
+                       *val = HSP_TUNE_TXVREF_GET(tune);
+               else
+                       *val = -1;
+       }
+}
+
+void phy_exynos_usb_v3p1_wr_tune_reg(struct exynos_usbphy_info *info, u32 val)
+{
+       void __iomem *regs_base = info->regs_base;
+
+       writel(val, regs_base + EXYNOS_USBCON_HSP_TUNE);
+}
+
+void phy_exynos_usb_v3p1_rd_tune_reg(struct exynos_usbphy_info *info, u32 *val)
+{
+       void __iomem *regs_base = info->regs_base;
+
+       if (!val)
+               return;
+
+       *val = readl(regs_base + EXYNOS_USBCON_HSP_TUNE);
+}
+
+void phy_exynos_usb3p1_rewa_ready(struct exynos_usbphy_info *info)
+{
+       u32 reg;
+       void __iomem *regs_base = info->regs_base;
+
+       /* Disable ReWA */
+       reg = readl(regs_base + EXYNOS_USBCON_REWA_ENABLE);
+       reg &= ~REWA_ENABLE_HS_REWA_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_REWA_ENABLE);
+
+       /* Config ReWA Operation */
+       reg = readl(regs_base + EXYNOS_USBCON_HSREWA_CTRL);
+       /* Select line state check circuit
+        * 0 : FSVPLUS/FSMINUS
+        * 1 : LINE STATE
+        * */
+       reg &= ~HSREWA_CTRL_DPDM_MON_SEL;
+       /* Select Drive K circuit
+        * 0 : Auto Resume in the PHY
+        * 1 : BYPASS mode by ReWA
+        * */
+       reg |= HSREWA_CTRL_DIG_BYPASS_CON_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_CTRL);
+
+       /* Set Driver K Time */
+       reg = 0x1;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_HSTK);
+
+       /* Set Timeout counter Driver K Time */
+       reg = 0xff00;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_REFTO);
+
+       /* Disable All events source for abnormal event generation */
+       reg = readl(regs_base + EXYNOS_USBCON_HSREWA_INT1_MASK);
+       reg |= HSREWA_CTRL_HS_EVT_ERR_SUS |
+                       HSREWA_CTRL_HS_EVT_ERR_DEV_K |
+                       HSREWA_CTRL_HS_EVT_DISCON |
+                       HSREWA_CTRL_HS_EVT_BYPASS_DIS |
+                       HSREWA_CTRL_HS_EVT_RET_DIS |
+                       HSREWA_CTRL_HS_EVT_RET_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_INT1_MASK);
+}
+
+int phy_exynos_usb3p1_rewa_enable(struct exynos_usbphy_info *info)
+{
+       int cnt;
+       u32 reg;
+       void __iomem *regs_base = info->regs_base;
+
+       /* Clear the system valid flag */
+       reg = readl(regs_base + EXYNOS_USBCON_HSREWA_CTRL);
+       reg &= ~HSREWA_CTRL_HS_SYS_VALID;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_CTRL);
+
+       /* Enable ReWA */
+       reg = readl(regs_base + EXYNOS_USBCON_REWA_ENABLE);
+       reg |= REWA_ENABLE_HS_REWA_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_REWA_ENABLE);
+
+       /* Check Status : Wait ReWA Status is retention enabled */
+       for (cnt = 10000; cnt != 0; cnt--) {
+
+               reg = readl(regs_base + EXYNOS_USBCON_HSREWA_INT1_EVT);
+
+               /* non suspend status*/
+               if (reg & HSREWA_CTRL_HS_EVT_ERR_SUS)
+                       return HS_REWA_EN_STS_NOT_SUSPEND;
+               /* Disconnect Status */
+               if (reg & HSREWA_CTRL_HS_EVT_DISCON)
+                       return HS_REWA_EN_STS_DISCONNECT;
+               /* Success ReWA Enable */
+               if (reg & HSREWA_CTRL_HS_EVT_RET_EN)
+                       break;
+#if !defined(CONFIG_BOARD_ZEBU)
+               udelay(30);
+#endif
+       }
+
+       if (!cnt)
+               return HS_REWA_EN_STS_NOT_SUSPEND;
+
+       /* Set the INT1 for detect K and Disconnect */
+       reg = readl(regs_base + EXYNOS_USBCON_HSREWA_INT1_MASK);
+       reg &= ~HSREWA_CTRL_HS_EVT_DISCON &
+                       ~HSREWA_CTRL_HS_EVT_ERR_DEV_K;
+       reg |= HSREWA_CTRL_HS_EVT_ERR_SUS |
+                       HSREWA_CTRL_HS_EVT_BYPASS_DIS |
+                       HSREWA_CTRL_HS_EVT_RET_DIS |
+                       HSREWA_CTRL_HS_EVT_RET_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_INT1_MASK);
+
+       /*  Enable All interrupt source and disnable Wake-up event */
+       reg = readl(regs_base + EXYNOS_USBCON_HSREWA_INTR);
+       reg &= ~HSREWA_INTR_WAKEUP_REQ_MASK &
+                       ~HSREWA_INTR_EVT_MASK &
+                       ~HSREWA_INTR_WAKEUP_MASK &
+                       ~HSREWA_INTR_TIMEOUT_MASK;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_INTR);
+
+       udelay(100);
+
+       return HS_REWA_EN_STS_ENALBED;
+}
+
+int phy_exynos_usb3p1_rewa_req_sys_valid(struct exynos_usbphy_info *info)
+{
+       int cnt;
+       u32 reg;
+       void __iomem *regs_base = info->regs_base;
+
+       /* Mask All Interrupt source for the INT1 */
+       reg = readl(regs_base + EXYNOS_USBCON_HSREWA_INT1_MASK);
+       reg &= ~HSREWA_CTRL_HS_EVT_DISCON &
+                       ~HSREWA_CTRL_HS_EVT_ERR_DEV_K &
+                       ~HSREWA_CTRL_HS_EVT_ERR_SUS &
+                       ~HSREWA_CTRL_HS_EVT_BYPASS_DIS &
+                       ~HSREWA_CTRL_HS_EVT_RET_DIS &
+                       ~HSREWA_CTRL_HS_EVT_RET_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_INT1_MASK);
+
+       /*  Enable All interrupt source and disnable Wake-up event */
+       reg = readl(regs_base + EXYNOS_USBCON_HSREWA_INTR);
+       reg |= HSREWA_INTR_WAKEUP_REQ_MASK;
+       reg |= HSREWA_INTR_TIMEOUT_MASK;
+       reg |= HSREWA_INTR_EVT_MASK;
+       reg |= HSREWA_INTR_WAKEUP_MASK;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_INTR);
+
+       /* Set the system valid flag */
+       reg = readl(regs_base + EXYNOS_USBCON_HSREWA_CTRL);
+       reg |= HSREWA_CTRL_HS_SYS_VALID;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_CTRL);
+
+       for (cnt = 10000; cnt != 0; cnt--) {
+
+               reg = readl(regs_base + EXYNOS_USBCON_HSREWA_INT1_EVT);
+
+               /* Disconnect Status */
+               if (reg & HSREWA_CTRL_HS_EVT_DISCON)
+                       return HS_REWA_EN_STS_DISCONNECT;
+               /* Success ReWA Enable */
+               if (reg & HSREWA_CTRL_HS_EVT_RET_EN)
+                       break;
+#if !defined(CONFIG_BOARD_ZEBU)
+               udelay(30);
+#endif
+       }
+
+       return HS_REWA_EN_STS_DISABLED;
+}
+
+int phy_exynos_usb3p1_rewa_disable(struct exynos_usbphy_info *info)
+{
+       int cnt;
+       u32 reg;
+       void __iomem *regs_base = info->regs_base;
+
+       /* Check ReWA Already diabled
+        * If ReWA was disabled states, disabled sequence is already done */
+       reg = readl(regs_base + EXYNOS_USBCON_REWA_ENABLE);
+       if (!(reg & REWA_ENABLE_HS_REWA_EN))
+               return 0;
+
+       /* Set Link ready to notify ReWA */
+       reg = readl(regs_base + EXYNOS_USBCON_HSREWA_CTRL);
+       reg |= HSREWA_CTRL_HS_LINK_READY;
+       writel(reg, regs_base + EXYNOS_USBCON_HSREWA_CTRL);
+       /* Wait Bypass Disable */
+       for (cnt = 10000; cnt != 0; cnt--) {
+               reg = readl(regs_base + EXYNOS_USBCON_HSREWA_INT1_EVT);
+               /* Success ReWA Enable */
+               if (reg & HSREWA_CTRL_HS_EVT_BYPASS_DIS)
+                       break;
+#if !defined(CONFIG_BOARD_ZEBU)
+               udelay(30);
+#endif
+       }
+       if (!cnt)
+               return -1;
+       /* Wait ReWA Done */
+       for (cnt = 1000; cnt != 0; cnt--) {
+               reg = readl(regs_base + EXYNOS_USBCON_HSREWA_CTRL);
+
+               /* Success ReWA Enable */
+               if (reg & HSREWA_CTRL_HS_REWA_DONE)
+                       break;
+#if !defined(CONFIG_BOARD_ZEBU)
+               udelay(30);
+#endif
+       }
+       if (!cnt)
+               return -1;
+       /*  Disable ReWA */
+       reg = readl(regs_base + EXYNOS_USBCON_REWA_ENABLE);
+       reg &= ~REWA_ENABLE_HS_REWA_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_REWA_ENABLE);
+
+       return 0;
+}
+
+int phy_exynos_usb3p1_rewa_cancel(struct exynos_usbphy_info *info)
+{
+       int ret;
+       u32 reg;
+       void __iomem *regs_base = info->regs_base;
+
+       /* Check ReWA Already diabled
+        * If ReWA was disabled states, disabled sequence is already done */
+       reg = readl(regs_base + EXYNOS_USBCON_REWA_ENABLE);
+       if (!(reg & REWA_ENABLE_HS_REWA_EN))
+               return 0;
+
+       ret = phy_exynos_usb3p1_rewa_req_sys_valid(info);
+
+       /*  Disable ReWA */
+       reg = readl(regs_base + EXYNOS_USBCON_REWA_ENABLE);
+       reg &= ~REWA_ENABLE_HS_REWA_EN;
+       writel(reg, regs_base + EXYNOS_USBCON_REWA_ENABLE);
+
+       udelay(100);
+
+       return ret;
+}
+
+void phy_exynos_usb3p1_usb3phy_dp_altmode_set_ss_disable(
+               struct exynos_usbphy_info *usbphy_info, int dp_phy_port)
+{
+       void __iomem *regs_base;
+       u32 reg;
+
+       if (dp_phy_port == 0)
+               regs_base = usbphy_info->regs_base;
+       else
+               regs_base = usbphy_info->regs_base_2nd;
+
+       /* Reset Mux Select */
+       /* Assert phy_reset */
+       reg = readl(regs_base + EXYNOS_USBCON_CLKRST);
+#if defined(CONFIG_USB_DP_COMBO_GEN2)
+       reg |= CLKRST_PHY20_SW_RST;
+       reg |= CLKRST_PHY20_RST_SEL;
+#else
+       reg |= CLKRST_PHY_SW_RST;
+       reg |= CLKRST_PHY_RST_SEL;
+#endif
+       writel(reg, regs_base + EXYNOS_USBCON_CLKRST);
+
+       udelay(100);
+
+       /* Deassert test_powerdown_ssp */
+       /* Deassert test_powerdown_hsp */
+       reg = readl(regs_base + EXYNOS_USBCON_PWR);
+
+#if !defined(CONFIG_USB_DP_COMBO_GEN2)
+       reg &= ~(PWR_TEST_POWERDOWN_HSP);
+       reg &= ~(PWR_TEST_POWERDOWN_SSP);
+#endif
+       writel(reg, regs_base + EXYNOS_USBCON_PWR);
+
+       udelay(100);
+}
+
+void phy_exynos_usb3p1_usb3phy_dp_altmode_clear_ss_disable(
+               struct exynos_usbphy_info *usbphy_info, int dp_phy_port)
+{
+       void __iomem *regs_base;
+       u32 reg;
+
+       if (dp_phy_port == 0)
+               regs_base = usbphy_info->regs_base;
+       else
+               regs_base = usbphy_info->regs_base_2nd;
+
+       /* Assert test_powerdown_ssp */
+       /* Assert test_powerdown_hsp */
+       reg = readl(regs_base + EXYNOS_USBCON_PWR);
+#if !defined(CONFIG_USB_DP_COMBO_GEN2)
+       reg |= (PWR_TEST_POWERDOWN_HSP);
+       reg |= (PWR_TEST_POWERDOWN_SSP);
+#endif
+       writel(reg, regs_base + EXYNOS_USBCON_PWR);
+
+       udelay(100);
+
+       reg = readl(regs_base + EXYNOS_USBCON_CLKRST);
+#if defined(CONFIG_USB_DP_COMBO_GEN2)
+       reg |= CLKRST_PHY20_RST_SEL;
+       reg &= ~CLKRST_PHY20_SW_RST;
+#else
+       reg |= CLKRST_PHY_RST_SEL;
+       reg &= ~CLKRST_PHY_SW_RST;
+#endif
+       writel(reg, regs_base + EXYNOS_USBCON_CLKRST);
+
+       udelay(100);
+}
+
+void phy_exynos_usb3p1_set_fs_vplus_vminus(
+               struct exynos_usbphy_info *usbphy_info, u32 fsls_speed_sel, u32 fsv_out_en)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 hsp_ctrl;
+
+       if (fsv_out_en) {
+               hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+               if (fsls_speed_sel)
+                       hsp_ctrl |= HSP_FSLS_SPEED_SEL;
+               else
+                       hsp_ctrl &= ~HSP_FSLS_SPEED_SEL;
+               hsp_ctrl |= HSP_FSV_OUT_EN;
+               writel(hsp_ctrl, regs_base + EXYNOS_USBCON_HSP);
+       } else {
+               hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+               hsp_ctrl &= ~HSP_FSLS_SPEED_SEL;
+               hsp_ctrl &= ~HSP_FSV_OUT_EN;
+               writel(hsp_ctrl, regs_base + EXYNOS_USBCON_HSP);
+       }
+
+}
+
+u8 phy_exynos_usb3p1_bc_data_contact_detect(struct exynos_usbphy_info *usbphy_info)
+{
+       bool ret = false;
+       u32 utmi_ctrl, hsp_ctrl;
+       u32 cnt;
+       u32 fsvplus;
+       void __iomem *regs_base = usbphy_info->regs_base;
+
+       // set UTMI_CTRL
+       utmi_ctrl = readl(regs_base + EXYNOS_USBCON_UTMI);
+       utmi_ctrl |= UTMI_OPMODE_CTRL_EN;
+       utmi_ctrl &= ~UTMI_FORCE_OPMODE_MASK;
+       utmi_ctrl |= UTMI_FORCE_OPMODE_SET(1);
+       utmi_ctrl &= ~UTMI_DP_PULLDOWN;
+       utmi_ctrl |= UTMI_DM_PULLDOWN;
+       utmi_ctrl |= UTMI_FORCE_SUSPEND;
+       writel(utmi_ctrl, regs_base + EXYNOS_USBCON_UTMI);
+
+       // Data contact Detection Enable
+       hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+       hsp_ctrl &= ~HSP_VDATSRCENB;
+       hsp_ctrl &= ~HSP_VDATDETENB;
+       hsp_ctrl |= HSP_DCDENB;
+       writel(hsp_ctrl, regs_base + EXYNOS_USBCON_HSP);
+
+       for (cnt = 8; cnt != 0; cnt--) {
+               // TDCD_TIMEOUT, 300ms~900ms
+               mdelay(40);
+
+               hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+               fsvplus = HSP_FSVPLUS_GET(hsp_ctrl);
+
+               if (!fsvplus)
+                       break;
+       }
+
+       if (fsvplus == 1 && cnt == 0)
+               ret = false;
+       else {
+               mdelay(10);     // TDCD_DBNC, 10ms
+
+               hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+               fsvplus = HSP_FSVPLUS_GET(hsp_ctrl);
+
+               if (!fsvplus)
+                       ret = true;
+               else
+                       ret = false;
+       }
+
+       hsp_ctrl &= ~HSP_DCDENB;
+       writel(hsp_ctrl, regs_base + EXYNOS_USBCON_HSP);
+
+       // restore UTMI_CTRL
+       utmi_ctrl = readl(regs_base + EXYNOS_USBCON_UTMI);
+       utmi_ctrl &= ~UTMI_OPMODE_CTRL_EN;
+       utmi_ctrl &= ~UTMI_FORCE_OPMODE_MASK;
+       utmi_ctrl &= ~UTMI_DM_PULLDOWN;
+       utmi_ctrl &= ~UTMI_FORCE_SUSPEND;
+       writel(utmi_ctrl, regs_base + EXYNOS_USBCON_UTMI);
+
+       return ret;
+}
+
+enum exynos_usb_bc phy_exynos_usb3p1_bc_battery_charger_detection(struct exynos_usbphy_info *usbphy_info)
+{
+       u32 utmi_ctrl, hsp_ctrl;
+       u32 chgdet;
+       enum exynos_usb_bc chg_port = BC_SDP;
+       void __iomem *regs_base = usbphy_info->regs_base;
+
+       /** Step 1. Primary Detection :: SDP / DCP or CDP
+        * voltage sourcing on the D+ line and sensing on the D- line
+        **/
+       // set UTMI_CTRL
+       utmi_ctrl = readl(regs_base + EXYNOS_USBCON_UTMI);
+       utmi_ctrl |= UTMI_OPMODE_CTRL_EN;
+       utmi_ctrl &= ~UTMI_FORCE_OPMODE_MASK;
+       utmi_ctrl |= UTMI_FORCE_OPMODE_SET(1);
+       utmi_ctrl &= ~UTMI_DP_PULLDOWN;
+       utmi_ctrl &= ~UTMI_DM_PULLDOWN;
+       utmi_ctrl |= UTMI_FORCE_SUSPEND;
+       writel(utmi_ctrl, regs_base + EXYNOS_USBCON_UTMI);
+
+       hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+       hsp_ctrl &= ~HSP_CHRGSEL;
+       hsp_ctrl |= HSP_VDATSRCENB;
+       hsp_ctrl |= HSP_VDATDETENB;
+       writel(hsp_ctrl, regs_base + EXYNOS_USBCON_HSP);
+
+       mdelay(40);     // TVDMSRC_ON, 40ms
+
+       hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+       chgdet = HSP_CHGDET_GET(hsp_ctrl);
+       if (!chgdet) {
+               /*
+                * IF CHGDET pin is not set,
+                * Standard Downstream Por
+                */
+               chg_port = BC_SDP;
+       } else {
+               hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+               hsp_ctrl &= ~HSP_VDATSRCENB;
+               hsp_ctrl &= ~HSP_VDATDETENB;
+               writel(hsp_ctrl, regs_base + EXYNOS_USBCON_HSP);
+
+               mdelay(20);
+
+               /* ELSE Maybe DCP or CDP but DCP is primary charger */
+
+               /*
+                * Step 2.1 Secondary Detection :: DCP or CDP
+                * voltage sourcing on the D- line and sensing on the D+ line
+                */
+               hsp_ctrl |= HSP_CHRGSEL;
+               hsp_ctrl |= HSP_VDATSRCENB;
+               hsp_ctrl |= HSP_VDATDETENB;
+               writel(hsp_ctrl, regs_base + EXYNOS_USBCON_HSP);
+
+               mdelay(40);     // TVDMSRC_ON, 40ms
+
+               hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+               chgdet = HSP_CHGDET_GET(hsp_ctrl);
+
+               if (!chgdet)
+                       chg_port = BC_CDP;
+               else
+                       chg_port = BC_DCP;
+       }
+
+       hsp_ctrl = readl(regs_base + EXYNOS_USBCON_HSP);
+       hsp_ctrl &= ~HSP_VDATSRCENB;
+       hsp_ctrl &= ~HSP_VDATDETENB;
+       writel(hsp_ctrl, regs_base + EXYNOS_USBCON_HSP);
+
+       // restore UTMI_CTRL
+       utmi_ctrl = readl(regs_base + EXYNOS_USBCON_UTMI);
+       utmi_ctrl &= ~UTMI_OPMODE_CTRL_EN;
+       utmi_ctrl &= ~UTMI_FORCE_OPMODE_MASK;
+       utmi_ctrl &= ~UTMI_FORCE_SUSPEND;
+       writel(utmi_ctrl, regs_base + EXYNOS_USBCON_UTMI);
+
+       return chg_port;
+}
diff --git a/drivers/phy/samsung/phy-exynos-usb3p1.h b/drivers/phy/samsung/phy-exynos-usb3p1.h
new file mode 100644 (file)
index 0000000..bb6c583
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USB3P1_H_
+#define DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USB3P1_H_
+
+#define HS_REWA_INTR_SRC_RET_EN                (1 << 0)
+#define HS_REWA_INTR_SRC_RET_DIS       (1 << 1)
+#define HS_REWA_INTR_SRC_BYPASS_DIS    (1 << 2)
+#define HS_REWA_INTR_SRC_DISCON                (1 << 16)
+#define HS_REWA_INTR_SRC_ERR_DEV_K     (1 << 17)
+#define HS_REWA_INTR_SRC_ERR_SUS       (1 << 18)
+
+#define HS_REWA_EN_STS_ENALBED         0
+#define HS_REWA_EN_STS_DISABLED                1
+#define HS_REWA_EN_STS_DISCONNECT      2
+#define HS_REWA_EN_STS_NOT_SUSPEND     -1
+
+
+/* initialted */
+extern void phy_exynos_usb_v3p1_enable(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_disable(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb3p1_pcs_reset(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb3p1_sw_rst(struct exynos_usbphy_info *info);
+extern u64 phy_exynos_usb3p1_get_logic_trace(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_enable_dp_pullup(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_disable_dp_pullup(struct exynos_usbphy_info *info);
+/* USB/DP PHY control */
+extern void phy_exynos_usb_v3p1_pma_ready(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_g2_pma_ready(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_pma_sw_rst_release(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_g2_pma_sw_rst_release(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_pipe_ovrd(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_pipe_ready(struct exynos_usbphy_info *info);
+/* Tune */
+extern void phy_exynos_usb_v3p1_config_host_mode(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_tune_host(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_tune_dev(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_tune(struct exynos_usbphy_info *info);
+extern void phy_exynos_usb_v3p1_tune_each(struct exynos_usbphy_info *info, char *para_name, int val);
+extern void phy_exynos_usb_v3p1_rd_tune_each_from_reg(struct exynos_usbphy_info *info, u32 tune, char *para_name, int *val);
+extern void phy_exynos_usb_v3p1_wr_tune_reg(struct exynos_usbphy_info *info, u32 val);
+extern void phy_exynos_usb_v3p1_rd_tune_reg(struct exynos_usbphy_info *info, u32 *val);
+/* High Speed Remote Wake-up Advisor(HS ReWA) */
+extern int phy_exynos_usb3p1_rewa_enable(struct exynos_usbphy_info *info);
+extern int phy_exynos_usb3p1_rewa_disable(struct exynos_usbphy_info *info);
+extern int phy_exynos_usb3p1_rewa_req_sys_valid(struct exynos_usbphy_info *info);
+extern int phy_exynos_usb3p1_rewa_cancel(struct exynos_usbphy_info *info);
+/* 3.0 PHY CR Port Access */
+extern void phy_exynos_usb_v3p1_cal_cr_write(struct exynos_usbphy_info *info, u16 addr, u16 data);
+extern u16 phy_exynos_usb_v3p1_cal_cr_read(struct exynos_usbphy_info *info, u16 addr);
+/* 2.0 PHY Test I/F Access */
+extern u8 phy_exynos_usb_v3p1_tif_ov_rd(struct exynos_usbphy_info *info, u8 addr);
+extern u8 phy_exynos_usb_v3p1_tif_ov_wr(struct exynos_usbphy_info *info, u8 addr, u8 data);
+extern u8 phy_exynos_usb_v3p1_tif_sts_rd(struct exynos_usbphy_info *info, u8 addr);
+/* FS_VPLUS/VMINUS interrupt */
+extern void phy_exynos_usb3p1_set_fs_vplus_vminus(struct exynos_usbphy_info *usbphy_info,
+                                                       u32 fsls_speed_sel, u32 fsv_out_en);
+/* BC 1.2 */
+extern u8 phy_exynos_usb3p1_bc_data_contact_detect(struct exynos_usbphy_info *usbphy_info);
+extern enum exynos_usb_bc phy_exynos_usb3p1_bc_battery_charger_detection(struct exynos_usbphy_info *usbphy_info);
+
+#endif /* DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USB3P1_H_ */
diff --git a/drivers/phy/samsung/phy-exynos-usbdp-reg-cmn.h b/drivers/phy/samsung/phy-exynos-usbdp-reg-cmn.h
new file mode 100644 (file)
index 0000000..1aa9dad
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _PHY_EXYNOS_USBDP_R_CMN_H_
+#define _PHY_EXYNOS_USBDP_R_CMN_H_
+
+#define EXYNOS_USBDP_COMBO_CMN_R00     (0x0000)
+#define USBDP_CMN00_SLAVE_ADDR_MASK            USBDP_COMBO_R_MSK(0, 8)
+#define USBDP_CMN00_SLAVE_ADDR_CLR             USBDP_COMBO_R_CLR(0, 8)
+#define USBDP_CMN00_SLAVE_ADDR_SET(_x)         USBDP_COMBO_R_SET(_x, 0, 8)
+#define USBDP_CMN00_SLAVE_ADDR_GET(_R)         USBDP_COMBO_R_GET(_R, 0, 8)
+
+#define EXYNOS_USBDP_COM_CMN_R01       (0x0004)
+#define USBDP_CMN01_BIAS_REXT_EN               USBDP_COMBO_R_MSK(7, 1)
+#define USBDP_CMN01_BIAS_CLK_SEL_MASK          USBDP_COMBO_R_MSK(5, 2)
+#define USBDP_CMN01_BIAS_CLK_SEL_SET(_x)       USBDP_COMBO_R_SET(_x, 5, 2)
+#define USBDP_CMN01_BIAS_CLK_SEL_GET(_r)       USBDP_COMBO_R_GET(_r, 5, 2)
+#define USBDP_CMN01_BIAS_LADDER_SEL_MASK       USBDP_COMBO_R_MSK(2, 3)
+#define USBDP_CMN01_BIAS_LADDER_SEL_SET(_x)    USBDP_COMBO_R_SET(_x, 2, 3)
+#define USBDP_CMN01_BIAS_LADDER_SEL_GET(_r)    USBDP_COMBO_R_GET(_x, 2, 3)
+#define USBDP_CMN01_BIAS_LADDER_EN             USBDP_COMBO_R_MSK(1, 1)
+#define USBDP_CMN01_BIAS_CLK_EN                        USBDP_COMBO_R_MSK(0, 1)
+
+#define EXYNOS_USBDP_COM_CMN_R02       (0x0008)
+#define USBDP_CMN02_MAN_BYPASS_LPF_EN          (1 << 7)
+#define USBDP_CMN02_DIV_SEL_MASK               (0x3 << 5)
+#define USBDP_CMN02_DIV_SEL_SET(_x)            ((_x & 0x3) << 5)
+#define USBDP_CMN02_DIV_SEL_GET(_r)            ((_r & 0x3) >> 5)
+#define USBDP_CMN02_BIAS_RES_CTRL_MASK         (0x7 << 2)
+#define USBDP_CMN02_BIAS_RES_CTRL_SET(_x)      ((_x & 0x7) << 2)
+#define USBDP_CMN02_BIAS_RES_CTRL_GET(_r)      ((_r & 0x7) >> 2)
+#define USBDP_CMN02_BIAS_VBG_SEL_MASK          (0x3 << 0)
+#define USBDP_CMN02_BIAS_VBG_SEL_SET(_x)       ((_x & 0x3) << 0)
+#define USBDP_CMN02_BIAS_VBG_SEL_GET(_r)       ((_r & 0x3) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R03       (0x000C)
+#define USBDP_CMN03_REFCLK_OUT_SOC_EN          (1 << 7)
+#define USBDP_CMN03_CD_SW_CLKQ_VDD             (1 << 6)
+#define USBDP_CMN03_CD_SW_CLKQ_PN              (1 << 5)
+#define USBDP_CMN03_CD_SW_CLKI_PN              (1 << 4)
+#define USBDP_CMN03_CD_SW_CLKI_CLKQ            (1 << 3)
+#define USBDP_CMN03_CD_EN_PWM_CLK              (1 << 2)
+#define USBDP_CMN03_CD_EN_CLKQ                 (1 << 1)
+#define USBDP_CMN03_MAN_BIAS_BYPASS_LPF                (1 << 0)
+
+#define EXYNOS_USBDP_COM_CMN_R04       (0x0010)
+#define USBDP_CMN04_CD_HSCLK_DIV1_PSTR_MASK    (0xf << 4)
+#define USBDP_CMN04_CD_HSCLK_DIV1_PSTR_SET(_x) ((_x & 0xf) << 4)
+#define USBDP_CMN04_CD_HSCLK_DIV1_PSTR_GET(_r) ((_r & 0xf) >> 4)
+#define USBDP_CMN04_CD_HSCLK_DIV1_NSTR_MASK    (0xf << 0)
+#define USBDP_CMN04_CD_HSCLK_DIV1_NSTR_SET(_x) ((_x & 0xf) << 0)
+#define USBDP_CMN04_CD_HSCLK_DIV1_NSTR_GET(_r) ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R05       (0x0014)
+#define USBDP_CMN05_CD_HSCLK_DIV5_PSTR_MASK    (0xf << 4)
+#define USBDP_CMN05_CD_HSCLK_DIV5_PSTR_SET(_x) ((_x & 0xf) << 4)
+#define USBDP_CMN05_CD_HSCLK_DIV5_PSTR_GET(_r) ((_r & 0xf) >> 4)
+#define USBDP_CMN05_CD_HSCLK_DIV5_NSTR_MASK    (0xf << 0)
+#define USBDP_CMN05_CD_HSCLK_DIV5_NSTR_SET(_x) ((_x & 0xf) << 0)
+#define USBDP_CMN05_CD_HSCLK_DIV5_NSTR_GET(_r) ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R06       (0x0018)
+#define USBDP_CMN06_CD_HSCLK_DIV10_PSTR_MASK   (0xf << 4)
+#define USBDP_CMN06_CD_HSCLK_DIV10_PSTR_SET(_x)        ((_x & 0xf) << 4)
+#define USBDP_CMN06_CD_HSCLK_DIV10_PSTR_GET(_r)        ((_r & 0xf) >> 4)
+#define USBDP_CMN06_CD_HSCLK_DIV10_NSTR_MASK   (0xf << 0)
+#define USBDP_CMN06_CD_HSCLK_DIV10_NSTR_SET(_x)        ((_x & 0xf) << 0)
+#define USBDP_CMN06_CD_HSCLK_DIV10_NSTR_GET(_r)        ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R07       (0x001C)
+#define USBDP_CMN07_REFCLK_HYS_100M_IN_MASK    (0x3 << 6)
+#define USBDP_CMN07_REFCLK_HYS_100M_IN_SET(_x) ((_x & 0x3) << 6)
+#define USBDP_CMN07_REFCLK_HYS_100M_IN_GET(_r) ((_r & 0x3) >> 6)
+#define USBDP_CMN07_MAN_PLL_REF_CLK_SEL_MASK   (0x3 << 4)
+#define USBDP_CMN07_MAN_PLL_REF_CLK_SEL_SET(_x)        ((_x & 0x3) << 4)
+#define USBDP_CMN07_MAN_PLL_REF_CLK_SEL_GET(_r)        ((_r & 0x3) >> 4)
+#define USBDP_CMN07_MAN_REFCLK_OUT_SOURCE      (1 << 3)
+#define USBDP_CMN07_MAN_REFCLK_OUT_EN          (1 << 2)
+#define USBDP_CMN07_MAN_REFCLK_IN_EN           (1 << 1)
+#define USBDP_CMN07_REFCLK_CTRL_EN             (1 << 0)
+
+#define EXYNOS_USBDP_COM_CMN_R08       (0x0020)
+#define USBDP_CMN08_REFCLK_OUT_STR_MASK                (0x7 << 5)
+#define USBDP_CMN08_REFCLK_OUT_STR_SET(_x)     ((_x & 0x7) << 5)
+#define USBDP_CMN08_REFCLK_OUT_STR_GET(_r)     ((_r & 0x7) >> 5)
+#define USBDP_CMN08_REFCLK_LOCKDONE_SEL                (1 << 4)
+#define USBDP_CMN08_MAN_PLL_REF_DIV_MASK       (0xf << 0)
+#define USBDP_CMN08_MAN_PLL_REF_DIV_SET(_x)    ((_x & 0xf) << 0)
+#define USBDP_CMN08_MAN_PLL_REF_DIV_GET(_r)    ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R09       (0x0024)
+#define USBDP_CMN09_REFCLK_TUNECODE_100M_IN_MASK       (0xf << 0)
+#define USBDP_CMN09_REFCLK_TUNECODE_100M_IN_SET(_x)    ((_x & 0xf) << 0)
+#define USBDP_CMN09_REFCLK_TUNECODE_100M_IN_GET(_r)    ((_r & 0xf) >> 0)
+#define USBDP_CMN09_REFCLK_VCM_PN_MASK         (0xf << 0)
+#define USBDP_CMN09_REFCLK_VCM_PN_SET(_x)      ((_x & 0xf) << 0)
+#define USBDP_CMN09_REFCLK_VCM_PN_GET(_r)      ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R0A       (0x0028)
+#define USBDP_CMN0A_PLL_AFC_FAST_LOCK_SETTLE_NO_MASK   (0x7 << 5)
+#define USBDP_CMN0A_PLL_AFC_FAST_LOCK_SETTLE_NO_SET(_x)        ((_x & 0x7) << 5)
+#define USBDP_CMN0A_PLL_AFC_FAST_LOCK_SETTLE_NO_GET(_r)        ((_r & 0x7) >> 5)
+#define USBDP_CMN0A_PLL_AFC_FAST_LOCK_BYPASS   (1 << 4)
+#define USBDP_CMN0A_PLL_AFC_BSEL               (1 << 3)
+#define USBDP_CMN0A_AFC_PRESET_VCO_CNT_MASK    (0x7 << 0)
+#define USBDP_CMN0A_AFC_PRESET_VCO_CNT_SET(_x) ((_x & 0x7) << 0)
+#define USBDP_CMN0A_AFC_PRESET_VCO_CNT_GET(_r) ((_r & 0x7) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R0B       (0x002C)
+#define USBDP_CMN0B_PLL_AFC_VFORCE                     (1 << 7)
+#define USBDP_CMN0B_PLL_SLOW_LOCK_BYPASS               (1 << 6)
+#define USBDP_CMN0B_PLL_AFC_LOCK_PPM_SET_MASK          (0x1f << 1)
+#define USBDP_CMN0B_PLL_AFC_LOCK_PPM_SET_SET(_x)       ((_x & 0x1f) << 1)
+#define USBDP_CMN0B_PLL_AFC_LOCK_PPM_SET_GET(_r)       ((_r & 0x1f) >> 1)
+#define USBDP_CMN0B_PLL_AFC_NON_CONTINUOUS_MODE                (1 << 0)
+
+#define EXYNOS_USBDP_COM_CMN_R0C       (0x0030)
+#define USBDP_CMN0C_PLL_AFC_TOL_MASK           (0xf << 4)
+#define USBDP_CMN0C_PLL_AFC_TOL_SET(_x)                ((_x & 0xf) << 4)
+#define USBDP_CMN0C_PLL_AFC_TOL_GET(_r)                ((_r & 0xf) >> 4)
+#define USBDP_CMN0C_PLL_AFC_STB_NUM_MASK       (0xf << 0)
+#define USBDP_CMN0C_PLL_AFC_STB_NUM_SET(_x)    ((_x & 0xf) << 0)
+#define USBDP_CMN0C_PLL_AFC_STB_NUM_GET(_r)    ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R0D       (0x0034)
+#define USBDP_CMN0D_PLL_AFC_VCO_CNT_WAIT_NO_MASK       (0xf << 0)
+#define USBDP_CMN0D_PLL_AFC_VCO_CNT_WAIT_NO_SET(_x)    ((_x & 0xf) << 0)
+#define USBDP_CMN0D_PLL_AFC_VCO_CNT_WAIT_NO_GET(_r)    ((_r & 0xf) >> 0)
+#define USBDP_CMN0D_LC_VCO_MODE                                (1 << 4)
+#define USBDP_CMN0D_PLL_AFC_MAN_BSEL_M_MASK            (0xf << 0)
+#define USBDP_CMN0D_PLL_AFC_MAN_BSEL_M_SET(_x)         ((_x & 0xf) << 0)
+#define USBDP_CMN0D_PLL_AFC_MAN_BSEL_M_GET(_r)         ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R0E       (0x0038)
+#define USBDP_CMN0E_PLL_AFC_ANA_CPI_CTRL_MASK          (0x7 << 5)
+#define USBDP_CMN0E_PLL_AFC_ANA_CPI_CTRL_SET(_x)       ((_x & 0x7) << 5)
+#define USBDP_CMN0E_PLL_AFC_ANA_CPI_CTRL_GET(_r)       ((_r & 0x7) >> 5)
+#define USBDP_CMN0E_PLL_AFC_VCO_CNT_RUN_NO_MASK                (0x1f << 0)
+#define USBDP_CMN0E_PLL_AFC_VCO_CNT_RUN_NO_SET(_x)     ((_x & 0x1f) << 0)
+#define USBDP_CMN0E_PLL_AFC_VCO_CNT_RUN_NO_GET(_r)     ((_r & 0x1f) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R0F       (0x003C)
+#define USBDP_CMN0F_PLL_ANA_EN_PI              (1 << 7)
+#define USBDP_CMN0F_PLL_ANA_DCC_EN_MASK                (0xf << 3)
+#define USBDP_CMN0F_PLL_ANA_DCC_EN_SET(_x)     ((_x & 0xf) << 3)
+#define USBDP_CMN0F_PLL_ANA_DCC_EN_GET(_r)     ((_r & 0xf) >> 3)
+#define USBDP_CMN0F_PLL_ANA_CPP_CTRL_MASK      (0x7 << 0)
+#define USBDP_CMN0F_PLL_ANA_CPP_CTRL_SET(_x)   ((_x & 0x7) << 0)
+#define USBDP_CMN0F_PLL_ANA_CPP_CTRL_GET(_r)   ((_r & 0x7) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R10       (0x0040)
+#define USBDP_CMN10_PLL_ANA_VCI_SEL_MASK       (0x7 << 5)
+#define USBDP_CMN10_PLL_ANA_VCI_SEL_SET(_x)    ((_x & 0x7) << 5)
+#define USBDP_CMN10_PLL_ANA_VCI_SEL_GET(_r)    ((_r & 0x7) >> 5)
+#define USBDP_CMN10_MAN_CMN_PLL_SET_EN         (1 << 4)
+#define USBDP_CMN10_PLL_ANA_LPF_RSEL_MASK      (0xf << 0)
+#define USBDP_CMN10_PLL_ANA_LPF_RSEL_SET(_x)   ((_x & 0xf) << 0)
+#define USBDP_CMN10_PLL_ANA_LPF_RSEL_GET(_r)   ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R11       (0x0044)
+#define USBDP_CMN11_PLL_ATB_SEL_MASK           (0x7 << 5)
+#define USBDP_CMN11_PLL_ATB_SEL_SET(_x)                ((_x & 0x7) << 5)
+#define USBDP_CMN11_PLL_ATB_SEL_GET(_r)                ((_r & 0x7) >> 5)
+#define USBDP_CMN11_PLL_ANA_TEST_EN            (1 << 4)
+#define USBDP_CMN11_PLL_ANA_PI_STR_MASK                (0xf << 0)
+#define USBDP_CMN11_PLL_ANA_PI_STR_SET(_x)     ((_x & 0xf) << 0)
+#define USBDP_CMN11_PLL_ANA_PI_STR_GET(_r)     ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R12       (0x0048)
+#define USBDP_CMN12_PLL_EN_100M                        (1 << 7)
+#define USBDP_CMN12_PLL_BYPASS_CLK_SEL_MASK    (0x3 << 5)
+#define USBDP_CMN12_PLL_BYPASS_CLK_SEL_SET(_x) ((_x & 0x3) << 5)
+#define USBDP_CMN12_PLL_BYPASS_CLK_SEL_GET(_r) ((_r & 0x3) >> 5)
+#define USBDP_CMN12_PLL_CKFB_MON_EN            (1 << 4)
+#define USBDP_CMN12_PLL_CK_MON_EN              (1 << 3)
+#define USBDP_CMN12_PLL_CHOPPER_CLK_EN         (1 << 2)
+#define USBDP_CMN12_PLL_ANA_VCO_PI_CTRL_MASK   (0xf << 0)
+#define USBDP_CMN12_PLL_ANA_VCO_PI_CTRL_SET(_x)        ((_x & 0xf) << 0)
+#define USBDP_CMN12_PLL_ANA_VCO_PI_CTRL_GET(_r)        ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R13       (0x004C)
+#define USBDP_CMN13_PLL_AFC_EN                 (1 << 7)
+#define USBDP_CMN13_PLL_DIV_NUM_MASK           (0x1f << 2)
+#define USBDP_CMN13_PLL_DIV_NUM_SET(_x)                ((_x & 0x1f) << 2)
+#define USBDP_CMN13_PLL_DIV_NUM_GET(_r)                ((_r & 0x1f) >> 2)
+#define USBDP_CMN13_PLL_EDGE_OPT_MASK          (0x3 << 0)
+#define USBDP_CMN13_PLL_EDGE_OPT_SET(_x)       ((_x & 0x3) << 0)
+#define USBDP_CMN13_PLL_EDGE_OPT_GET(_r)       ((_r & 0x3) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R14       (0x0050)
+#define USBDP_CMN14_PLL_FLD_RP_CODE_2_0_MASK   (0x7 << 5)
+#define USBDP_CMN14_PLL_FLD_RP_CODE_2_0_SET(_x)        ((_x & 0x7) << 5)
+#define USBDP_CMN14_PLL_FLD_RP_CODE_2_0_GET(_r)        ((_r & 0x7) >> 5)
+#define USBDP_CMN14_PLL_FLD_RP_CODE_MASK       (0x7 << 2)
+#define USBDP_CMN14_PLL_FLD_RP_CODE_SET(_x)    ((_x & 0x7) << 2)
+#define USBDP_CMN14_PLL_FLD_RP_CODE_GET(_r)    ((_r & 0x7) >> 2)
+#define USBDP_CMN14_PLL_FLD_CK_DIV_MASK                (0x3 << 0)
+#define USBDP_CMN14_PLL_FLD_CK_DIV_SET(_x)     ((_x & 0x3) << 0)
+#define USBDP_CMN14_PLL_FLD_CK_DIV_GET(_r)     ((_r & 0x3) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R15       (0x0054)
+#define USBDP_CMN15_PLL_PH_FIX                 (1 << 7)
+#define USBDP_CMN15_PLL_PCG_CLK_OUT_EN         (1 << 6)
+#define USBDP_CMN15_PLL_FLD_TG_CODE_8_3_MASK   (0x3f << 0)
+#define USBDP_CMN15_PLL_FLD_TG_CODE_8_3_SET(_x)        ((_x & 0x3f) << 0)
+#define USBDP_CMN15_PLL_FLD_TG_CODE_8_3_GET(_r)        ((_r & 0x3f) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R16       (0x0058)
+#define USBDP_CMN16_PLL_PH_SEL_MASK            (0xf << 4)
+#define USBDP_CMN16_PLL_PH_SEL_SET(_x)         ((_x & 0xf) << 4)
+#define USBDP_CMN16_PLL_PH_SEL_GET(_r)         ((_r & 0xf) >> 4)
+#define USBDP_CMN16_PLL_FLD_TOL_MASK           (0xf << 0)
+#define USBDP_CMN16_PLL_FLD_TOL_SET(_x)                ((_x & 0xf) << 0)
+#define USBDP_CMN16_PLL_FLD_TOL_GET(_r)                ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R17       (0x005C)
+#define USBDP_CMN17_PLL_RING_CLK_DIV2          (1 << 7)
+#define USBDP_CMN17_PLL_PH_SEL_3B              (1 << 6)
+#define USBDP_CMN17_PLL_MOD_CODE_MASK          (0x3f << 0)
+#define USBDP_CMN17_PLL_MOD_CODE_SET(_x)       ((_x & 0x3f) << 0)
+#define USBDP_CMN17_PLL_MOD_CODE_GET(_r)       ((_r & 0x3f) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R18       (0x0060)
+#define USBDP_CMN18_MAN_PLL_PMS_M_MASK         (0xff << 0)
+#define USBDP_CMN18_MAN_PLL_PMS_M_SET(_x)      ((_x & 0xff) << 0)
+#define USBDP_CMN18_MAN_PLL_PMS_M_GET(_r)      ((_r & 0xff) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R19       (0x0064)
+#define USBDP_CMN19_MAN_PLL_PMS_S_MASK         (0xf << 4)
+#define USBDP_CMN19_MAN_PLL_PMS_S_SET(_x)      ((_x & 0xf) << 4)
+#define USBDP_CMN19_MAN_PLL_PMS_S_GET(_r)      ((_r & 0xf) >> 4)
+#define USBDP_CMN19_MAN_PLL_PMS_P_MASK         (0xf << 0)
+#define USBDP_CMN19_MAN_PLL_PMS_P_SET(_x)      ((_x & 0xf) << 0)
+#define USBDP_CMN19_MAN_PLL_PMS_P_GET(_r)      ((_r & 0xf) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R1A       (0x0068)
+#define USBDP_CMN1A_MAN_PLL_SDC_LC_0           (1 << 7)
+#define USBDP_CMN1A_MAN_PLL_SDC_K_CODE_MASK    (0x3f << 1)
+#define USBDP_CMN1A_MAN_PLL_SDC_K_CODE_SET(_x) ((_x & 0x3f) << 1)
+#define USBDP_CMN1A_MAN_PLL_SDC_K_CODE_GET(_r) ((_r & 0x3f) >> 1)
+#define USBDP_CMN1A_MAN_PLL_SDC_N2             (1 << 0)
+
+#define EXYNOS_USBDP_COM_CMN_R1B       (0x006C)
+#define USBDP_CMN1B_MAN_PLL_SDC_N_MASK         (0x7 << 1)
+#define USBDP_CMN1B_MAN_PLL_SDC_N_SET(_x)      ((_x & 0x7) << 1)
+#define USBDP_CMN1B_MAN_PLL_SDC_N_GET(_r)      ((_r & 0x7) >> 1)
+#define USBDP_CMN1B_MAN_PLL_SDC_LC_5_1_MASK    (0x1f << 0)
+#define USBDP_CMN1B_MAN_PLL_SDC_LC_5_1_SET(_x) ((_x & 0x1f) << 0)
+#define USBDP_CMN1B_MAN_PLL_SDC_LC_5_1_GET(_r) ((_r & 0x1f) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R1C       (0x0070)
+#define USBDP_CMN1C_MAN_PLL_SDM_K_CODE_MASK    (0xff << 0)
+#define USBDP_CMN1C_MAN_PLL_SDM_K_CODE_SET(_x) ((_x & 0xff) << 0)
+#define USBDP_CMN1C_MAN_PLL_SDM_K_CODE_GET(_r) ((_r & 0xff) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R1D       (0x0074)
+#define USBDP_CMN1D_PLL_ANA_LPF_CISEL_MASK     (0xff << 0)
+#define USBDP_CMN1D_PLL_ANA_LPF_CISEL_SET(_x)  ((_x & 0xff) << 0)
+#define USBDP_CMN1D_PLL_ANA_LPF_CISEL_GET(_r)  ((_r & 0xff) >> 0)
+
+#define EXYNOS_USBDP_COM_CMN_R1E       (0x0078)
+#define USBDP_CMN1E_MAN_PLL_SDM_LC_CLR         USBDP_COMBO_REG_CLR(0, 8)
+#define USBDP_CMN1E_MAN_PLL_SDM_LC_MASK                USBDP_COMBO_REG_MSK(0, 8)
+#define USBDP_CMN1E_MAN_PLL_SDM_LC_SET(_x)     USBDP_COMBO_REG_SET(_x, 0, 8)
+#define USBDP_CMN1E_MAN_PLL_SDM_LC_GET(_R)     USBDP_COMBO_REG_GET(_R, 0, 8)
+
+#define EXYNOS_USBDP_COM_CMN_R1F       (0x007C)
+#define USBDP_CMN1F_MAN_HS_MODE                        USBDP_COMBO_REG_MSK(7, 1)
+#define USBDP_CMN1F_MAN_HS_MODE_EN             USBDP_COMBO_REG_MSK(6, 1)
+#define USBDP_CMN1F_CD_RSTN_DLY_CODE_MASK      USBDP_COMBO_REG_MSK(3, 3)
+#define USBDP_CMN1F_CD_RSTN_DLY_CODE_SET(_x)   USBDP_COMBO_REG_SET(_x, 3, 3)
+#define USBDP_CMN1F_CD_RSTN_DLY_CODE_GET(_R)   USBDP_COMBO_REG_GET(_R, 3, 3)
+#define USBDP_CMN1F_PLL_ANA_LPF_CSEL_MASK      USBDP_COMBO_REG_MSK(0, 3)
+#define USBDP_CMN1F_PLL_ANA_LPF_CSEL_SET(_x)   USBDP_COMBO_REG_SET(_x, 0, 3)
+#define USBDP_CMN1F_PLL_ANA_LPF_CSEL_GET(_R)   USBDP_COMBO_REG_GET(_R, 0, 3)
+
+#define EXYNOS_USBDP_COM_CMN_R20       (0x0080)
+#define USBDP_CMN1F_MAN_MDIV_RSTN              USBDP_COMBO_REG_MSK(7, 1)
+#define USBDP_CMN1F_MAN_PDIV_RSTN              USBDP_COMBO_REG_MSK(6, 1)
+#define USBDP_CMN1F_MAN_RSTN_CTRL              USBDP_COMBO_REG_MSK(5, 1)
+
+#define EXYNOS_USBDP_COM_CMN_R21       (0x0084)
+
+#define EXYNOS_USBDP_COM_CMN_R22       (0x0088)
+
+#define EXYNOS_USBDP_COM_CMN_R23       (0x008C)
+
+#define EXYNOS_USBDP_COM_CMN_R24       (0x0090)
+#define USBDP_CMN24_PLL_AGMC_MAN_GMSEL_MASK    USBDP_COMBO_REG_MSK(4, 4)
+#define USBDP_CMN24_PLL_AGMC_MAN_GMSEL_SET(_x) USBDP_COMBO_REG_SET(_x, 4, 4)
+#define USBDP_CMN24_PLL_AGMC_MAN_GMSEL_GET(_R) USBDP_COMBO_REG_GET(_R, 4, 4)
+#define USBDP_CMN24_PLL_AGMC_GMSEL_EN          USBDP_COMBO_REG_MSK(3, 1)
+#define USBDP_CMN24_PLL_DIG_CLK_SEL            USBDP_COMBO_REG_MSK(2, 1)
+#define USBDP_CMN24_NDIV_RSTN                  USBDP_COMBO_REG_MSK(1, 1)
+#define USBDP_CMN24_SSC_EN                     USBDP_COMBO_REG_MSK(0, 1)
+
+#define EXYNOS_USBDP_COM_CMN_R25       (0x0094)
+#define USBDP_CMN25_PLL_AGMC_TG_CODE_MASK      USBDP_COMBO_REG_MSK(0, 8)
+#define USBDP_CMN25_PLL_AGMC_TG_CODE_SET(_x)   USBDP_COMBO_REG_SET(_x, 0, 8)
+#define USBDP_CMN25_PLL_AGMC_TG_CODE_GET(_R)   USBDP_COMBO_REG_GET(_R, 0, 8)
+
+#define EXYNOS_USBDP_COM_CMN_R26       (0x0098)
+#define USBDP_CMN26_PLL_ANA_LC_GM_COMP_CTRL    USBDP_COMBO_REG_MSK(7, 1)
+#define USBDP_CMN26_PLL_AGMC_COMP_EN           USBDP_COMBO_REG_MSK(6, 1)
+#define USBDP_CMN26_PLL_AGMC_GM_ADD_MASK       USBDP_COMBO_REG_MSK(4, 2)
+#define USBDP_CMN26_PLL_AGMC_GM_ADD_SET(_x)    USBDP_COMBO_REG_SET(_x, 4, 2)
+#define USBDP_CMN26_PLL_AGMC_GM_ADD_GET(_R)    USBDP_COMBO_REG_GET(_R, 4, 2)
+#define USBDP_CMN26_PLL_AGMC_FROM_MAX_GM       USBDP_COMBO_REG_MSK(3, 1)
+#define USBDP_CMN26_PLL_AFC_FROM_PRE_CODE      USBDP_COMBO_REG_MSK(2, 1)
+#define USBDP_CMN26_PLL_AFC_MAN_BSEL_L_MASK    USBDP_COMBO_REG_MSK(0, 2)
+#define USBDP_CMN26_PLL_AFC_MAN_BSEL_L_SET(_x) USBDP_COMBO_REG_SET(_x, 0, 2)
+#define USBDP_CMN26_PLL_AFC_MAN_BSEL_L_GET(_R) USBDP_COMBO_REG_GET(_R, 0, 2)
+
+#define EXYNOS_USBDP_COM_CMN_R27       (0x009C)
+#define USBDP_CMN27_PLL_ANA_LC_VREF_BYPASS_EN                  USBDP_COMBO_REG_MSK(7, 1)
+#define USBDP_CMN27_PLL_ANA_LC_VCDO_CAP_OFFSET_SEL_MASK                USBDP_COMBO_REG_MSK(4, 3)
+#define USBDP_CMN27_PLL_ANA_LC_VCDO_CAP_OFFSET_SEL_SET(_x)     USBDP_COMBO_REG_SET(_x, 4, 3)
+#define USBDP_CMN27_PLL_ANA_LC_VCDO_CAP_OFFSET_SEL_GET(_R)     USBDP_COMBO_REG_GET(_R, 4, 3)
+#define USBDP_CMN27_PLL_ANA_LC_VCO_BUFF_EN             USBDP_COMBO_REG_MSK(3, 1)
+#define USBDP_CMN27_PLL_ANA_LC_GM_COMP_VCI_SEL_MASK    USBDP_COMBO_REG_MSK(0, 3)
+#define USBDP_CMN27_PLL_ANA_LC_GM_COMP_VCI_SEL_SET(_x) USBDP_COMBO_REG_SET(_x, 0, 3)
+#define USBDP_CMN27_PLL_ANA_LC_GM_COMP_VCI_SEL_GET(_R) USBDP_COMBO_REG_GET(_R, 0, 3)
+
+#define EXYNOS_USBDP_COM_CMN_R28       (0x00A0)
+
+#define EXYNOS_USBDP_COM_CMN_R29       (0x00A4)
+
+#define EXYNOS_USBDP_COM_CMN_R2A       (0x00A8)
+
+#define EXYNOS_USBDP_COM_CMN_R2B       (0x00AC)
+
+#define EXYNOS_USBDP_COM_CMN_R2C       (0x00B0)
+#define USBDP_CMN2C_NO_DELAY_PLL_LOCK_DONE_EN  USBDP_COMBO_REG_MSK(4, 1)
+#define USBDP_CMN2C_BGR_ATB_SEL                        USBDP_COMBO_REG_MSK(3, 1)
+#define USBDP_CMN2C_MAN_USBDP_MODE_MASK                USBDP_COMBO_REG_MSK(1, 2)
+#define USBDP_CMN2C_MAN_USBDP_MODE_SET(_x)     USBDP_COMBO_REG_SET(_x, 1, 2)
+#define USBDP_CMN2C_MAN_USBDP_MODE_GET(_x)     USBDP_COMBO_REG_GET(_x, 1, 2)
+#define USBDP_CMN2C_MAN_USBDP_MODE_EN          USBDP_COMBO_REG_MSK(0, 1)
+
+#define EXYNOS_USBDP_COM_CMN_R2D       (0x00B4)
+#define USBDP_CMN2D_USB_TX1_SEL                        USBDP_COMBO_REG_MSK(5, 1)
+#define USBDP_CMN2D_USB_TX3_SEL                        USBDP_COMBO_REG_MSK(4, 1)
+#define USBDP_CMN2D_LCPLL_SSCDIV_MASK          USBDP_COMBO_REG_MSK(0, 4)
+#define USBDP_CMN2D_LCPLL_SSCDIV_SET(_x)       USBDP_COMBO_REG_SET(_x, 0, 4)
+#define USBDP_CMN2D_LCPLL_SSCDIV_GET(_x)       USBDP_COMBO_REG_GET(_x, 0, 4)
+
+#define EXYNOS_USBDP_COM_CMN_R2E       (0x00B8)
+
+#define EXYNOS_USBDP_COM_CMN_R2F       (0x00BC)
+#define USBDP_CMN2F_PLL_MON_SEL_BAND_M_MASK    USBDP_COMBO_REG_MSK(4, 4)
+#define USBDP_CMN2F_PLL_MON_SEL_BAND_M_SET(_x) USBDP_COMBO_REG_SET(_x, 4, 4)
+#define USBDP_CMN2F_PLL_MON_SEL_BAND_M_GET(_x) USBDP_COMBO_REG_GET(_x, 4, 4)
+#define USBDP_CMN2F_PLL_MON_SEL_BAND_I_MASK    USBDP_COMBO_REG_MSK(2, 2)
+#define USBDP_CMN2F_PLL_MON_SEL_BAND_I_SET(_x) USBDP_COMBO_REG_SET(_x, 2, 2)
+#define USBDP_CMN2F_PLL_MON_SEL_BAND_I_GET(_x) USBDP_COMBO_REG_GET(_x, 2, 2)
+#define USBDP_CMN2F_PLL_AFC_DONE               USBDP_COMBO_REG_MSK(1, 1)
+#define USBDP_CMN2F_PLL_LOCK_DONE              USBDP_COMBO_REG_MSK(0, 1)
+
+#endif /* _PHY_EXYNOS_USBDP_R_CMN_H_ */
diff --git a/drivers/phy/samsung/phy-exynos-usbdp-reg-dp.h b/drivers/phy/samsung/phy-exynos-usbdp-reg-dp.h
new file mode 100644 (file)
index 0000000..6a43084
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USBDP_REG_DP_H_
+#define DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USBDP_REG_DP_H_
+
+#define EXYNOS_USBDP_COM_DP_RB3                (0x0ACC)
+#define USBDP_DPB3_CMN_DUMMY_CTRL_7            USBDP_COMBO_REG_MSK(7, 1)
+#define USBDP_DPB3_CMN_DUMMY_CTRL_6            USBDP_COMBO_REG_MSK(6, 1)
+#define USBDP_DPB3_CMN_DUMMY_CTRL_5            USBDP_COMBO_REG_MSK(5, 1)
+#define USBDP_DPB3_CMN_DUMMY_CTRL_4            USBDP_COMBO_REG_MSK(4, 1)
+#define USBDP_DPB3_CMN_DUMMY_CTRL_3            USBDP_COMBO_REG_MSK(3, 1)
+#define USBDP_DPB3_CMN_DUMMY_CTRL_2            USBDP_COMBO_REG_MSK(2, 1)
+#define USBDP_DPB3_CMN_DUMMY_CTRL_1            USBDP_COMBO_REG_MSK(1, 1)
+#define USBDP_DPB3_CMN_DUMMY_CTRL_0            USBDP_COMBO_REG_MSK(0, 1)
+
+
+#endif /* DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USBDP_REG_DP_H_ */
diff --git a/drivers/phy/samsung/phy-exynos-usbdp-reg-pcs.h b/drivers/phy/samsung/phy-exynos-usbdp-reg-pcs.h
new file mode 100644 (file)
index 0000000..550b93d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _CAL_PHY_EXYNOS_USBDP_REG_PCS_H_
+#define _CAL_PHY_EXYNOS_USBDP_REG_PCS_H_
+
+#define USBDP_PCSREG_FRONT_END_MODE_VEC                0x0200
+#define USBDP_PCSREG_RUN_LENGTH_TH                     USBDP_COMBO_REG_MSK(4, 1)
+#define USBDP_PCSREG_EN_DRAIN_AFTER_RX_VAL_FALL                USBDP_COMBO_REG_MSK(1, 1)
+#define USBDP_PCSREG_EN_REALIGN                                USBDP_COMBO_REG_MSK(0, 1)
+
+#define USBDP_PCSREG_DET_COMP_EN_SET           0x0300
+#define USBDP_PCSREG_COMP_EN_ASSERT_MASK               USBDP_COMBO_REG_MSK(0, 6)
+#define USBDP_PCSREG_COMP_EN_ASSERT_SET(_x)            USBDP_COMBO_REG_SET(_x, 0, 6)
+#define USBDP_PCSREG_COMP_EN_ASSERT_GET(_x)            USBDP_COMBO_REG_GET(_R, 0, 6)
+
+
+
+
+#endif /* _CAL_PHY_EXYNOS_USBDP_REG_PCS_H_ */
diff --git a/drivers/phy/samsung/phy-exynos-usbdp-reg-trsv.h b/drivers/phy/samsung/phy-exynos-usbdp-reg-trsv.h
new file mode 100644 (file)
index 0000000..72d4f60
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USBDP_REG_TRSV_H_
+#define DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USBDP_REG_TRSV_H_
+
+#define EXYNOS_USBDP_COM_TRSV_R01      (0x00c4)
+#define USBDP_TRSV01_RXAFE_LEQ_ISEL_GEN2_MASK          USBDP_COMBO_REG_MSK(6, 2)
+#define USBDP_TRSV01_RXAFE_LEQ_ISEL_GEN2_SET(_x)       USBDP_COMBO_REG_SET(_x, 6, 2)
+#define USBDP_TRSV01_RXAFE_LEQ_ISEL_GEN2_GET(_R)       USBDP_COMBO_REG_GET(_R, 6, 2)
+#define USBDP_TRSV01_RXAFE_LEQ_ISEL_GEN1_MASK          USBDP_COMBO_REG_MSK(4, 2)
+#define USBDP_TRSV01_RXAFE_LEQ_ISEL_GEN1_SET(_x)       USBDP_COMBO_REG_SET(_x, 4, 2)
+#define USBDP_TRSV01_RXAFE_LEQ_ISEL_GEN1_GET(_R)       USBDP_COMBO_REG_GET(_R, 4, 2)
+#define USBDP_TRSV01_RXAFE_CTLE_SEL_MASK       USBDP_COMBO_REG_MSK(2, 2)
+#define USBDP_TRSV01_RXAFE_CTLE_SEL_SET(_x)    USBDP_COMBO_REG_SET(_x, 2, 2)
+#define USBDP_TRSV01_RXAFE_CTLE_SEL_GET(_R)    USBDP_COMBO_REG_GET(_R, 2, 2)
+#define USBDP_TRSV01_RXAFE_SCLBUF_EN_MASK      USBDP_COMBO_REG_MSK(0, 2)
+#define USBDP_TRSV01_RXAFE_SCLBUF_EN_SET(_x)   USBDP_COMBO_REG_SET(_x, 0, 2)
+#define USBDP_TRSV01_RXAFE_SCLBUF_EN_GET(_R)   USBDP_COMBO_REG_GET(_R, 0, 2)
+
+#define EXYNOS_USBDP_COM_TRSV_R02      (0x00c8)
+#define USBDP_TRSV02_RXAFE_LEQ_CSEL_GEN2_MASK          USBDP_COMBO_REG_MSK(4, 4)
+#define USBDP_TRSV02_RXAFE_LEQ_CSEL_GEN2_SET(_x)       USBDP_COMBO_REG_SET(_x, 4, 4)
+#define USBDP_TRSV02_RXAFE_LEQ_CSEL_GEN2_GET(_R)       USBDP_COMBO_REG_GET(_R, 4, 4)
+#define USBDP_TRSV02_RXAFE_LEQ_CSEL_GEN1_MASK          USBDP_COMBO_REG_MSK(0, 4)
+#define USBDP_TRSV02_RXAFE_LEQ_CSEL_GEN1_SET(_x)       USBDP_COMBO_REG_SET(_x, 0, 4)
+#define USBDP_TRSV02_RXAFE_LEQ_CSEL_GEN1_GET(_R)       USBDP_COMBO_REG_GET(_R, 0, 4)
+
+#define EXYNOS_USBDP_COM_TRSV_R03      (0x00cc)
+#define USBDP_TRSV03_RXAFE_TERM_MODE                   USBDP_COMBO_REG_MSK(7, 1)
+#define USBDP_TRSV03_RXAFE_EQ_AMP3BUF_EN               USBDP_COMBO_REG_MSK(6, 1)
+#define USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN2_MASK          USBDP_COMBO_REG_MSK(3, 3)
+#define USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN2_SET(_x)       USBDP_COMBO_REG_SET(_x, 3, 3)
+#define USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN2_GET(_R)       USBDP_COMBO_REG_GET(_R, 3, 3)
+#define USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN1_MASK          USBDP_COMBO_REG_MSK(0, 3)
+#define USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN1_SET(_x)       USBDP_COMBO_REG_SET(_x, 0, 3)
+#define USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN1_GET(_R)       USBDP_COMBO_REG_GET(_R, 0, 3)
+
+#define EXYNOS_USBDP_COM_TRSV_R04      (0x00d0)
+#define USBDP_TRSV04_RXAFE_TUNE_MASK                   USBDP_COMBO_REG_MSK(4, 4)
+#define USBDP_TRSV04_RXAFE_TUNE_SET(_x)                        USBDP_COMBO_REG_SET(_x, 4, 4)
+#define USBDP_TRSV04_RXAFE_TUNE_GET(_R)                        USBDP_COMBO_REG_GET(_R, 4, 4)
+#define USBDP_TRSV04_RXAFE_SQ_VFFSET_CTRL_MASK         USBDP_COMBO_REG_MSK(0, 4)
+#define USBDP_TRSV04_RXAFE_SQ_VFFSET_CTRL_SET(_x)      USBDP_COMBO_REG_SET(_x, 0, 4)
+#define USBDP_TRSV04_RXAFE_SQ_VFFSET_CTRL_GET(_R)      USBDP_COMBO_REG_GET(_R, 0, 4)
+
+#define EXYNOS_USBDP_COM_TRSV_R0A      (0x00E8)
+#define USBDP_TRSV0A_APB_CAL_OFFSET_DIFP_MASK          USBDP_COMBO_REG_MSK(4, 4)
+#define USBDP_TRSV0A_APB_CAL_OFFSET_DIFP_SET(_x)       USBDP_COMBO_REG_SET(_x, 4, 4)
+#define USBDP_TRSV0A_APB_CAL_OFFSET_DIFP_GET(_R)       USBDP_COMBO_REG_GET(_R, 4, 4)
+
+#define EXYNOS_USBDP_COM_TRSV_R0B      (0x00EC)
+#define USBDP_TRSV0B_APB_CAL_OFFSET_DIFN_MASK          USBDP_COMBO_REG_MSK(0, 4)
+#define USBDP_TRSV0B_APB_CAL_OFFSET_DIFN_SET(_x)       USBDP_COMBO_REG_SET(_x, 0, 4)
+#define USBDP_TRSV0B_APB_CAL_OFFSET_DIFN_GET(_R)       USBDP_COMBO_REG_GET(_R, 0, 4)
+
+#define EXYNOS_USBDP_COM_TRSV_R0C      (0x00F0)
+#define USBDP_TRSV0C_MAN_TX_DE_EMP_LVL_MASK            USBDP_COMBO_REG_MSK(4, 4)
+#define USBDP_TRSV0C_MAN_TX_DE_EMP_LVL_SET(_x)         USBDP_COMBO_REG_SET(_x, 4, 4)
+#define USBDP_TRSV0C_MAN_TX_DE_EMP_LVL_GET(_R)         USBDP_COMBO_REG_GET(_R, 4, 4)
+#define USBDP_TRSV0C_MAN_TX_DRVR_LVL_MASK              USBDP_COMBO_REG_MSK(0, 4)
+#define USBDP_TRSV0C_MAN_TX_DRVR_LVL_SET(_x)           USBDP_COMBO_REG_SET(_x, 0, 4)
+#define USBDP_TRSV0C_MAN_TX_DRVR_LVL_GET(_R)           USBDP_COMBO_REG_GET(_R, 0, 4)
+
+#define EXYNOS_USBDP_COM_TRSV_R0D      (0x00F4)
+#define USBDP_TRSV0D_TX_RCV_COMB_CTRL_MASK             USBDP_COMBO_REG_MSK(6, 2)
+#define USBDP_TRSV0D_TX_RCV_COMB_CTRL_SET(_x)          USBDP_COMBO_REG_SET(_x, 6, 2)
+#define USBDP_TRSV0D_TX_RCV_COMB_CTRL_GET(_R)          USBDP_COMBO_REG_GET(_R, 6, 2)
+#define USBDP_TRSV0D_TX_LINE_LB_SEL                    USBDP_COMBO_REG_MSK(5, 1)
+#define USBDP_TRSV0D_TX_LINE_LB_EN                     USBDP_COMBO_REG_MSK(4, 1)
+#define USBDP_TRSV0D_TXHSCK_MON_EN                     USBDP_COMBO_REG_MSK(3, 1)
+#define USBDP_TRSV0D_EDP_MODE_SEL                      USBDP_COMBO_REG_MSK(2, 1)
+#define USBDP_TRSV0D_TX_DESKEW_BYPASS                  USBDP_COMBO_REG_MSK(1, 1)
+#define USBDP_TRSV0D_MAN_DRVR_DE_EMP_LVL_MAN_EN                USBDP_COMBO_REG_MSK(0, 1)
+
+#define EXYNOS_USBDP_COM_TRSV_R23      (0x014C)
+#define USBDP_TRSV23_DATA_CLEAR_BY_SIGVAL      USBDP_COMBO_REG_MSK(7, 1)
+#define USBDP_TRSV23_DESKEW_CHK_BYPASS         USBDP_COMBO_REG_MSK(6, 1)
+#define USBDP_TRSV23_TX_FIX_DB                 USBDP_COMBO_REG_MSK(5, 1)
+#define USBDP_TRSV23_TX_FIX_DA                 USBDP_COMBO_REG_MSK(4, 1)
+#define USBDP_TRSV23_FBB_H_BW_DIFF_MASK                USBDP_COMBO_REG_MSK(0, 4)
+#define USBDP_TRSV23_FBB_H_BW_DIFF_SET(_x)     USBDP_COMBO_REG_SET(_x, 0, 4)
+#define USBDP_TRSV23_FBB_H_BW_DIFF_GET(_R)     USBDP_COMBO_REG_GET(_R, 0, 4)
+
+#define EXYNOS_USBDP_COM_TRSV_R24      (0x0150)
+#define USBDP_TRSV24_MAN_TX_RCV_DET_EN                 USBDP_COMBO_REG_MSK(7, 1)
+
+#define EXYNOS_USBDP_COM_TRSV_R27      (0x015C)
+#define USBDP_TRSV27_MAN_EN_CTRL               USBDP_COMBO_REG_MSK(7, 1)
+#define USBDP_TRSV27_MAN_TX_SER_RSTN           USBDP_COMBO_REG_MSK(6, 1)
+#define USBDP_TRSV27_MAN_DESKEW_RSTN           USBDP_COMBO_REG_MSK(5, 1)
+#define USBDP_TRSV27_MAN_CDR_AFC_RSTN          USBDP_COMBO_REG_MSK(4, 1)
+#define USBDP_TRSV27_MAN_CDR_AFC_INIT_RSTN     USBDP_COMBO_REG_MSK(3, 1)
+#define USBDP_TRSV27_MAN_VALID_RSTN            USBDP_COMBO_REG_MSK(2, 1)
+#define USBDP_TRSV27_MAN_CDR_DES_RSTN          USBDP_COMBO_REG_MSK(1, 1)
+#define USBDP_TRSV27_MAN_RSTN_EN               USBDP_COMBO_REG_MSK(0, 1)
+
+#define EXYNOS_USBDP_COM_TRSV_R34      (0x0190)
+#define USBDP_TRSV34_SIGVAL_FILT_DLY_CODE_MASK         USBDP_COMBO_REG_MSK(2, 2)
+#define USBDP_TRSV34_SIGVAL_FILT_DLY_CODE_SET(_x)      USBDP_COMBO_REG_SET(_x, 2, 2)
+#define USBDP_TRSV34_SIGVAL_FILT_DLY_CODE_GET(_R)      USBDP_COMBO_REG_GET(_R, 2, 2)
+#define USBDP_TRSV34_OUT_SIGVAL_FILT_SEL               USBDP_COMBO_REG_MSK(1, 1)
+#define USBDP_TRSV34_INT_SIGVAL_FILT_SEL               USBDP_COMBO_REG_MSK(0, 1)
+
+#define EXYNOS_USBDP_COM_TRSV_R38      (0x01A0)
+#define USBDP_TRSV38_SFR_RX_LFPS_LPF_CTRL_MASK         USBDP_COMBO_REG_MSK(5, 2)
+#define USBDP_TRSV38_SFR_RX_LFPS_LPF_CTRL_SET(_x)      USBDP_COMBO_REG_SET(_x, 5, 2)
+#define USBDP_TRSV38_SFR_RX_LFPS_LPF_CTRL_GET(_R)      USBDP_COMBO_REG_GET(_R, 5, 2)
+#define USBDP_TRSV38_SFR_RX_LFPS_TH_CTRL_MASK          USBDP_COMBO_REG_MSK(2, 3)
+#define USBDP_TRSV38_SFR_RX_LFPS_TH_CTRL_SET(_x)       USBDP_COMBO_REG_SET(_x, 2, 3)
+#define USBDP_TRSV38_SFR_RX_LFPS_TH_CTRL_GET(_R)       USBDP_COMBO_REG_GET(_R, 2, 3)
+#define USBDP_TRSV38_SFR_RX_LFPS_COMP_I_CTRL   USBDP_COMBO_REG_MSK(1, 1)
+#define USBDP_TRSV38_RX_LFPS_DET_EN            USBDP_COMBO_REG_MSK(0, 1)
+
+#define EXYNOS_USBDP_COM_TRSV_R4B      (0x01EC)
+#define USBDP_TRSV4B_CDR_AFC_DONE              USBDP_COMBO_REG_MSK(5, 1)
+#define USBDP_TRSV4B_RX_CAL_DONE               USBDP_COMBO_REG_MSK(4, 1)
+#define USBDP_TRSV4B_CDR_FLD_PLL_MODE_DONE     USBDP_COMBO_REG_MSK(3, 1)
+#define USBDP_TRSV4B_BIST_COMP_TEST            USBDP_COMBO_REG_MSK(2, 1)
+#define USBDP_TRSV4B_BIST_ERR_INJ_TEST         USBDP_COMBO_REG_MSK(1, 1)
+#define USBDP_TRSV4B_BIST_COMP_START           USBDP_COMBO_REG_MSK(0, 1)
+
+#define EXYNOS_USBDP_COM_TRSV_R59      (0x0224)
+#define USBDP_TRSV59_TX_JEQ_EN                         USBDP_COMBO_REG_MSK(7, 1)
+#define USBDP_TRSV59_TX_DRV_PLL_REF_MON_EN             USBDP_COMBO_REG_MSK(6, 1)
+#define USBDP_TRSV59_TX_DRV_IDRV_IUP_CTRL_MASK         USBDP_COMBO_REG_MSK(3, 3)
+#define USBDP_TRSV59_TX_DRV_IDRV_IUP_CTRL_SET(_x)      USBDP_COMBO_REG_SET(_x, 3, 3)
+#define USBDP_TRSV59_TX_DRV_IDRV_IUP_CTRL_GET(_R)      USBDP_COMBO_REG_GET(_R, 3, 3)
+#define USBDP_TRSV59_TX_DRV_IDRV_EN                    USBDP_COMBO_REG_MSK(2, 1)
+#define USBDP_TRSV59_TX_DRV_ACCDRV_EN                  USBDP_COMBO_REG_MSK(1, 1)
+
+#define EXYNOS_USBDP_COM_TRSV_R5A      (0x0228)
+#define USBDP_TRSV5A_TX_DRV_ACCDRV_CTRL_MASK           USBDP_COMBO_REG_MSK(5, 3)
+#define USBDP_TRSV5A_TX_DRV_ACCDRV_CTRL_SET(_x)                USBDP_COMBO_REG_SET(_x, 5, 3)
+#define USBDP_TRSV5A_TX_DRV_ACCDRV_CTRL_GET(_R)                USBDP_COMBO_REG_GET(_R, 5, 3)
+
+#endif /* DRIVER_USB_USBPHY_CAL_PHY_EXYNOS_USBDP_REG_TRSV_H_ */
diff --git a/drivers/phy/samsung/phy-exynos-usbdp-reg.h b/drivers/phy/samsung/phy-exynos-usbdp-reg.h
new file mode 100644 (file)
index 0000000..e790da2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef _PHY_EXYNOS_USBDP_REG_H_
+#define _PHY_EXYNOS_USBDP_REG_H_
+
+#define USBDP_COMBO_BIT_MASK(_bw)              ((1 << _bw) - 1)
+
+#define USBDP_COMBO_REG_MSK(_pos, _B)          (USBDP_COMBO_BIT_MASK(_B) << _pos)
+#define USBDP_COMBO_REG_CLR(_pos, _B)          (~(USBDP_COMBO_BIT_MASK(_B) << _pos))
+#define USBDP_COMBO_REG_SET(_x, _pos, _B)      ((_x & USBDP_COMBO_BIT_MASK(_B)) << _pos)
+#define USBDP_COMBO_REG_GET(_x, _pos, _B)      ((_x & (USBDP_COMBO_BIT_MASK(_B) << _pos)) >> _pos)
+
+#include "phy-exynos-usbdp-reg-cmn.h"
+#include "phy-exynos-usbdp-reg-trsv.h"
+#include "phy-exynos-usbdp-reg-dp.h"
+#include "phy-exynos-usbdp-reg-pcs.h"
+
+#endif /* _PHY_EXYNOS_USBDP_REG_H_ */
diff --git a/drivers/phy/samsung/phy-exynos-usbdp.c b/drivers/phy/samsung/phy-exynos-usbdp.c
new file mode 100644 (file)
index 0000000..0d861d9
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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/delay.h>
+#include <linux/io.h>
+#include "phy-samsung-usb-cal.h"
+#include "phy-exynos-usbdp-reg.h"
+
+void phy_exynos_usbdp_tune_each(struct exynos_usbphy_info *info, char *name,
+       int val)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg;
+
+       if (!name)
+               return;
+
+       if (!strcmp(name, "sstx_deemph")) {
+               reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R0C);
+               reg &= ~USBDP_TRSV0C_MAN_TX_DE_EMP_LVL_MASK;
+               reg |= USBDP_TRSV0C_MAN_TX_DE_EMP_LVL_SET(val);
+               writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R0C);
+       } else if (!strcmp(name, "sstx_amp")) {
+               reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R0C);
+               reg &= ~USBDP_TRSV0C_MAN_TX_DRVR_LVL_MASK;
+               reg |= USBDP_TRSV0C_MAN_TX_DRVR_LVL_SET(val);
+               writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R0C);
+       } else if (!strcmp(name, "ssrx_los")) {
+               reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R0A);
+               reg &= ~USBDP_TRSV0A_APB_CAL_OFFSET_DIFP_MASK;
+               reg |= USBDP_TRSV0A_APB_CAL_OFFSET_DIFP_SET(val);
+               writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R0A);
+
+               reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R0B);
+               reg &= ~USBDP_TRSV0B_APB_CAL_OFFSET_DIFN_MASK;
+               reg |= USBDP_TRSV0B_APB_CAL_OFFSET_DIFN_SET(val);
+               writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R0B);
+       } else if (!strcmp(name, "ssrx_ctle")) {
+               reg = USBDP_TRSV02_RXAFE_LEQ_CSEL_GEN2_SET(0x2);
+               reg |= USBDP_TRSV02_RXAFE_LEQ_CSEL_GEN1_SET(0x7);
+               writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R02);
+
+               reg = USBDP_TRSV03_RXAFE_TERM_MODE;
+               reg &= ~USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN2_MASK;
+               reg |= USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN2_SET(0x7);
+               reg &= ~USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN1_MASK;
+               writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R03);
+
+               reg = USBDP_TRSV04_RXAFE_TUNE_SET(val);
+               reg |= USBDP_TRSV04_RXAFE_SQ_VFFSET_CTRL_SET(val);
+               writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R04);
+       }
+}
+
+void phy_exynos_usbdp_tune(struct exynos_usbphy_info *info)
+{
+       u32 cnt = 0;
+
+       for (; info->tune_param[cnt].value != EXYNOS_USB_TUNE_LAST; cnt++) {
+               char *para_name;
+               int val;
+
+               val = info->tune_param[cnt].value;
+               if (val == -1)
+                       continue;
+               para_name = info->tune_param[cnt].name;
+               if (!para_name)
+                       break;
+               phy_exynos_usbdp_tune_each(info, para_name, val);
+       }
+}
+
+void phy_exynos_usbdp_ilbk(struct exynos_usbphy_info *info)
+{
+
+}
+
+void phy_exynos_usbdp_enable(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg, reg_2c, reg_2d, reg_dp_b3;
+
+       /* Recevier Detection Off */
+       reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R24);
+       reg |= USBDP_TRSV24_MAN_TX_RCV_DET_EN;
+       writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R24);
+
+       /* Set Proper Value for PCS to avoid abnormal RX Detect */
+       reg = readl(info->regs_base_2nd + USBDP_PCSREG_FRONT_END_MODE_VEC);
+       reg |= USBDP_PCSREG_EN_REALIGN;
+       writel(reg, info->regs_base_2nd + USBDP_PCSREG_FRONT_END_MODE_VEC);
+
+       reg = USBDP_PCSREG_COMP_EN_ASSERT_SET(0x3f);
+       writel(reg, info->regs_base_2nd + USBDP_PCSREG_DET_COMP_EN_SET);
+
+       reg = 0;
+       reg |= USBDP_CMN0E_PLL_AFC_VCO_CNT_RUN_NO_SET(0x4);
+       reg |= USBDP_CMN0E_PLL_AFC_ANA_CPI_CTRL_SET(0x2);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_CMN_R0E);
+
+       reg = 0;
+       reg |= USBDP_CMN0F_PLL_ANA_EN_PI;
+       reg |= USBDP_CMN0F_PLL_ANA_DCC_EN_SET(0xf);
+       reg |= USBDP_CMN0F_PLL_ANA_CPP_CTRL_SET(0x7);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_CMN_R0F);
+
+       reg = 0;
+       reg |= USBDP_CMN10_PLL_ANA_VCI_SEL_SET(0x6);
+       reg |= USBDP_CMN10_PLL_ANA_LPF_RSEL_SET(0x8);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_CMN_R10);
+
+       reg = 0;
+       reg |= USBDP_CMN25_PLL_AGMC_TG_CODE_SET(0x30);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_CMN_R25);
+
+       reg = 0;
+       reg |= USBDP_CMN26_PLL_AGMC_COMP_EN;
+       reg |= USBDP_CMN26_PLL_AGMC_FROM_MAX_GM;
+       reg |= USBDP_CMN26_PLL_AFC_FROM_PRE_CODE;
+       reg |= USBDP_CMN26_PLL_AFC_MAN_BSEL_L_SET(0x3);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_CMN_R26);
+
+       reg = 0;
+       reg |= USBDP_CMN27_PLL_ANA_LC_VREF_BYPASS_EN;
+       reg |= USBDP_CMN27_PLL_ANA_LC_VCDO_CAP_OFFSET_SEL_SET(0x5);
+       reg |= USBDP_CMN27_PLL_ANA_LC_VCO_BUFF_EN;
+       reg |= USBDP_CMN27_PLL_ANA_LC_GM_COMP_VCI_SEL_SET(0x4);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_CMN_R27);
+
+       reg = 0;
+       reg |= USBDP_TRSV23_DATA_CLEAR_BY_SIGVAL;
+       reg |= USBDP_TRSV23_FBB_H_BW_DIFF_SET(0x5);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R23);
+
+       /* SSC Setting */
+       reg = readl(regs_base + EXYNOS_USBDP_COM_CMN_R24);
+       reg |= USBDP_CMN24_SSC_EN;
+       writel(reg, regs_base + EXYNOS_USBDP_COM_CMN_R24);
+
+       reg_2c = readl(regs_base + EXYNOS_USBDP_COM_CMN_R2C);
+       reg_2d = readl(regs_base + EXYNOS_USBDP_COM_CMN_R2D);
+       reg_dp_b3 = readl(regs_base + EXYNOS_USBDP_COM_DP_RB3);
+       if (info->used_phy_port == 0) {
+               reg_2c |= USBDP_CMN2C_MAN_USBDP_MODE_SET(0x3);
+               reg_2d |= USBDP_CMN2D_USB_TX1_SEL;
+               reg_2d &= ~USBDP_CMN2D_USB_TX3_SEL;
+               reg_dp_b3 &= ~USBDP_DPB3_CMN_DUMMY_CTRL_7;
+               reg_dp_b3 |= USBDP_DPB3_CMN_DUMMY_CTRL_6;
+               reg_dp_b3 |= USBDP_DPB3_CMN_DUMMY_CTRL_1;
+               reg_dp_b3 |= USBDP_DPB3_CMN_DUMMY_CTRL_0;
+       } else {
+               reg_2c &= ~USBDP_CMN2C_MAN_USBDP_MODE_MASK;
+               reg_2d &= ~USBDP_CMN2D_USB_TX1_SEL;
+               reg_2d |= USBDP_CMN2D_USB_TX3_SEL;
+               reg_dp_b3 |= USBDP_DPB3_CMN_DUMMY_CTRL_7;
+               reg_dp_b3 &= ~USBDP_DPB3_CMN_DUMMY_CTRL_6;
+               reg_dp_b3 &= ~USBDP_DPB3_CMN_DUMMY_CTRL_1;
+               reg_dp_b3 &= ~USBDP_DPB3_CMN_DUMMY_CTRL_0;
+       }
+       reg_2c |= USBDP_CMN2C_MAN_USBDP_MODE_EN;
+       reg_2d &= ~USBDP_CMN2D_LCPLL_SSCDIV_MASK;
+       reg_2d |= USBDP_CMN2D_LCPLL_SSCDIV_SET(0x1);
+       writel(reg_2c, regs_base + EXYNOS_USBDP_COM_CMN_R2C);
+       writel(reg_2d, regs_base + EXYNOS_USBDP_COM_CMN_R2D);
+       writel(reg_dp_b3,  regs_base + EXYNOS_USBDP_COM_DP_RB3);
+
+       reg = 0;
+       reg |= USBDP_TRSV38_SFR_RX_LFPS_LPF_CTRL_SET(0x2);
+       reg |= USBDP_TRSV38_SFR_RX_LFPS_TH_CTRL_SET(0x2);
+       reg |= USBDP_TRSV38_RX_LFPS_DET_EN;
+       writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R38);
+
+       /* RX EQ tuning */
+       reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R01);
+       reg &= ~USBDP_TRSV01_RXAFE_CTLE_SEL_MASK;
+       reg |= USBDP_TRSV01_RXAFE_CTLE_SEL_SET(0x3);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R01);
+
+       reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R03);
+       reg &= ~USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN1_MASK;
+       reg &= ~USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN2_MASK;
+       reg |= USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN1_SET(0x0);
+       reg |= USBDP_TRSV03_RXAFE_LEQ_RSEL_GEN2_SET(0x5);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R03);
+
+       reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R0D);
+       reg |= USBDP_TRSV0D_MAN_DRVR_DE_EMP_LVL_MAN_EN;
+       writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R0D);
+
+       /* Sys Valid Debouncd Digital Filter */
+       reg = 0;
+       reg |= USBDP_TRSV34_INT_SIGVAL_FILT_SEL;
+       reg |= USBDP_TRSV34_OUT_SIGVAL_FILT_SEL;
+       reg |= USBDP_TRSV34_SIGVAL_FILT_DLY_CODE_SET(0x3);
+       writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R34);
+
+       reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R27);
+       reg |= USBDP_TRSV27_MAN_RSTN_EN;
+       writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R27);
+
+       /* Recevier Detection On */
+       reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R24);
+       reg &= ~USBDP_TRSV24_MAN_TX_RCV_DET_EN;
+       writel(reg, regs_base + EXYNOS_USBDP_COM_TRSV_R24);
+
+       /* Set Tune Value */
+       phy_exynos_usbdp_tune(info);
+}
+
+int phy_exynos_usbdp_check_pll_lock(struct exynos_usbphy_info *info)
+{
+       void __iomem *regs_base = info->regs_base;
+       u32 reg;
+
+       reg = readl(regs_base + EXYNOS_USBDP_COM_CMN_R2F);
+       printk("CMN_2F(0x%p) : 0x%x\n",
+               regs_base + EXYNOS_USBDP_COM_CMN_R2F,
+               reg);
+       if (!(reg & USBDP_CMN2F_PLL_LOCK_DONE))
+               return -1;
+
+       reg = readl(regs_base + EXYNOS_USBDP_COM_TRSV_R4B);
+       printk("TRSV_4B(0x%p) : 0x%x\n",
+               regs_base + EXYNOS_USBDP_COM_TRSV_R4B,
+               reg);
+       if (!(reg & USBDP_TRSV4B_CDR_FLD_PLL_MODE_DONE))
+               return -1;
+
+       return 0;
+}
+
+void phy_exynos_usbdp_disable(struct exynos_usbphy_info *info)
+{
+
+}
diff --git a/drivers/phy/samsung/phy-exynos-usbdp.h b/drivers/phy/samsung/phy-exynos-usbdp.h
new file mode 100644 (file)
index 0000000..2cd394c
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef PHY_EXYNOS_USBDP_H_
+#define PHY_EXYNOS_USBDP_H_
+
+
+extern void phy_exynos_usbdp_enable(struct exynos_usbphy_info *);
+extern void phy_exynos_usbdp_ilbk(struct exynos_usbphy_info *info);
+extern int phy_exynos_usbdp_check_pll_lock(struct exynos_usbphy_info *info);
+extern void phy_exynos_usbdp_disable(struct exynos_usbphy_info *);
+extern void phy_exynos_usbdp_tune_each(struct exynos_usbphy_info *, char *, int);
+extern void phy_exynos_usbdp_tune(struct exynos_usbphy_info *info);
+extern void exynos_usbdrd_request_phy_isol(void);
+extern int exynos_usbdrd_inform_dp_use(int use, int lane_cnt);
+
+#endif /* PHY_EXYNOS_USBDP_H_ */
diff --git a/drivers/phy/samsung/phy-exynos-usbdrd.c b/drivers/phy/samsung/phy-exynos-usbdrd.c
new file mode 100644 (file)
index 0000000..8fa77e3
--- /dev/null
@@ -0,0 +1,1914 @@
+/*
+ * Samsung EXYNOS SoC series USB DRD PHY driver
+ *
+ * Phy provider for USB 3.0 DRD controller on Exynos SoC series
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd.
+ * Author: Vivek Gautam <gautam.vivek@samsung.com>
+ *        Minho Lee <minho55.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/exynos5-pmu.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/samsung_usb.h>
+#include <linux/usb/otg.h>
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+#include <linux/exynos_otp.h>
+#endif
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+
+#include "phy-exynos-usbdrd.h"
+#include "phy-exynos-debug.h"
+
+static void __iomem *usbdp_combo_phy_reg;
+static int phy_isol_delayed, dp_use_informed;
+static struct regmap *reg_pmu_delayed;
+static u32 pmu_offset_delayed, pmu_offset_dp_delayed;
+
+static int exynos_usbdrd_clk_prepare(struct exynos_usbdrd_phy *phy_drd)
+{
+       int i;
+       int ret;
+
+       for (i = 0; phy_drd->clocks[i] != NULL; i++) {
+               ret = clk_prepare(phy_drd->clocks[i]);
+               if (ret)
+                       goto err;
+       }
+
+       if (phy_drd->use_phy_umux) {
+               for (i = 0; phy_drd->phy_clocks[i] != NULL; i++) {
+                       ret = clk_prepare(phy_drd->phy_clocks[i]);
+                       if (ret)
+                               goto err1;
+               }
+       }
+       return 0;
+err:
+       for (i = i - 1; i >= 0; i--)
+               clk_unprepare(phy_drd->clocks[i]);
+       return ret;
+err1:
+       for (i = i - 1; i >= 0; i--)
+               clk_unprepare(phy_drd->phy_clocks[i]);
+       return ret;
+}
+
+static int exynos_usbdrd_clk_enable(struct exynos_usbdrd_phy *phy_drd,
+                                       bool umux)
+{
+       int i;
+       int ret;
+
+       if (!umux) {
+               for (i = 0; phy_drd->clocks[i] != NULL; i++) {
+                       ret = clk_enable(phy_drd->clocks[i]);
+                       if (ret)
+                               goto err;
+               }
+       } else {
+               for (i = 0; phy_drd->phy_clocks[i] != NULL; i++) {
+                               ret = clk_enable(phy_drd->phy_clocks[i]);
+                               if (ret)
+                                       goto err1;
+               }
+       }
+       return 0;
+err:
+       for (i = i - 1; i >= 0; i--)
+               clk_disable(phy_drd->clocks[i]);
+       return ret;
+err1:
+       for (i = i - 1; i >= 0; i--)
+               clk_disable(phy_drd->phy_clocks[i]);
+       return ret;
+}
+
+static void exynos_usbdrd_clk_unprepare(struct exynos_usbdrd_phy *phy_drd)
+{
+       int i;
+
+       for (i = 0; phy_drd->clocks[i] != NULL; i++)
+               clk_unprepare(phy_drd->clocks[i]);
+       for (i = 0; phy_drd->phy_clocks[i] != NULL; i++)
+               clk_unprepare(phy_drd->phy_clocks[i]);
+}
+
+static void exynos_usbdrd_clk_disable(struct exynos_usbdrd_phy *phy_drd, bool umux)
+{
+       int i;
+
+       if (!umux) {
+               for (i = 0; phy_drd->clocks[i] != NULL; i++)
+                       clk_disable(phy_drd->clocks[i]);
+       } else {
+               for (i = 0; phy_drd->phy_clocks[i] != NULL; i++)
+                       clk_disable(phy_drd->phy_clocks[i]);
+       }
+}
+static int exynos_usbdrd_phyclk_get(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       const char      **phyclk_ids;
+       const char      **clk_ids;
+       const char      *refclk_name;
+       struct clk      *clk;
+       int             phyclk_count;
+       int             clk_count;
+       bool            is_phyclk = false;
+       int             clk_index = 0;
+       int             i, j, ret;
+
+       phyclk_count = of_property_count_strings(dev->of_node, "phyclk_mux");
+       if (IS_ERR_VALUE((unsigned long)phyclk_count)) {
+               dev_err(dev, "invalid phyclk list in %s node\n",
+                                                       dev->of_node->name);
+               return -EINVAL;
+       }
+
+       phyclk_ids = (const char **)devm_kmalloc(dev,
+                                       (phyclk_count+1) * sizeof(const char *),
+                                       GFP_KERNEL);
+       for (i = 0; i < phyclk_count; i++) {
+               ret = of_property_read_string_index(dev->of_node,
+                                               "phyclk_mux", i, &phyclk_ids[i]);
+               if (ret) {
+                       dev_err(dev, "failed to read phyclk_mux name %d from %s node\n",
+                                       i, dev->of_node->name);
+                       return ret;
+               }
+       }
+       phyclk_ids[phyclk_count] = NULL;
+
+       if (!strcmp("none", phyclk_ids[0])) {
+               dev_info(dev, "don't need user Mux for phyclk\n");
+               phy_drd->use_phy_umux = false;
+               phyclk_count = 0;
+
+       } else {
+               phy_drd->use_phy_umux = true;
+
+               phy_drd->phy_clocks = (struct clk **) devm_kmalloc(dev,
+                               (phyclk_count+1) * sizeof(struct clk *),
+                               GFP_KERNEL);
+               if (!phy_drd->phy_clocks) {
+                       dev_err(dev, "failed to alloc : phy clocks\n");
+                       return -ENOMEM;
+               }
+
+               for (i = 0; phyclk_ids[i] != NULL; i++) {
+                       clk = devm_clk_get(dev, phyclk_ids[i]);
+                       if (IS_ERR_OR_NULL(clk)) {
+                               dev_err(dev, "couldn't get %s clock\n", phyclk_ids[i]);
+                               return -EINVAL;
+                       }
+                       phy_drd->phy_clocks[i] = clk;
+               }
+
+               phy_drd->phy_clocks[i] = NULL;
+       }
+
+       clk_count = of_property_count_strings(dev->of_node, "clock-names");
+       if (IS_ERR_VALUE((unsigned long)clk_count)) {
+               dev_err(dev, "invalid clk list in %s node", dev->of_node->name);
+               return -EINVAL;
+       }
+       clk_ids = (const char **)devm_kmalloc(dev,
+                               (clk_count + 1) * sizeof(const char *),
+                               GFP_KERNEL);
+       for (i = 0; i < clk_count; i++) {
+               ret = of_property_read_string_index(dev->of_node, "clock-names",
+                                                               i, &clk_ids[i]);
+               if (ret) {
+                       dev_err(dev, "failed to read clocks name %d from %s node\n",
+                                       i, dev->of_node->name);
+                       return ret;
+               }
+       }
+       clk_ids[clk_count] = NULL;
+
+       phy_drd->clocks = (struct clk **) devm_kmalloc(dev,
+                               (clk_count + 1) * sizeof(struct clk *), GFP_KERNEL);
+       if (!phy_drd->clocks) {
+               dev_err(dev, "failed to alloc for clocks\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; clk_ids[i] != NULL; i++) {
+               if (phyclk_count) {
+                       for (j = 0; phyclk_ids[j] != NULL; j++) {
+                               if (!strcmp(phyclk_ids[j], clk_ids[i])) {
+                                       is_phyclk = true;
+                                       phyclk_count--;
+                               }
+                       }
+               }
+               if (!is_phyclk) {
+                       clk = devm_clk_get(dev, clk_ids[i]);
+                       if (IS_ERR_OR_NULL(clk)) {
+                               dev_err(dev, "couldn't get %s clock\n", clk_ids[i]);
+                               return -EINVAL;
+                       }
+                       phy_drd->clocks[clk_index] = clk;
+                       clk_index++;
+               }
+               is_phyclk = false;
+       }
+       phy_drd->clocks[clk_index] = NULL;
+
+       ret = of_property_read_string_index(dev->of_node,
+                                               "phy_refclk", 0, &refclk_name);
+       if (ret) {
+               dev_err(dev, "failed to read ref_clocks name from %s node\n",
+                               dev->of_node->name);
+               return ret;
+       }
+
+       if (!strcmp("none", refclk_name)) {
+               dev_err(dev, "phy reference clock shouldn't be omitted");
+               return -EINVAL;
+       }
+
+       for (i = 0; clk_ids[i] != NULL; i++) {
+               if (!strcmp(clk_ids[i], refclk_name)) {
+                       phy_drd->ref_clk = devm_clk_get(dev, refclk_name);
+                       break;
+               }
+       }
+
+       if (IS_ERR_OR_NULL(phy_drd->ref_clk)) {
+               dev_err(dev, "%s couldn't get ref_clk", __func__);
+               return -EINVAL;
+       }
+
+       devm_kfree(dev, phyclk_ids);
+       devm_kfree(dev, clk_ids);
+
+       return 0;
+
+}
+
+static int exynos_usbdrd_clk_get(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       int             ret;
+
+       ret = exynos_usbdrd_phyclk_get(phy_drd);
+       if (ret < 0) {
+               dev_err(dev, "failed to get clock for DRD USBPHY");
+               return ret;
+       }
+
+       return 0;
+}
+
+static inline
+struct exynos_usbdrd_phy *to_usbdrd_phy(struct phy_usb_instance *inst)
+{
+       return container_of((inst), struct exynos_usbdrd_phy,
+                           phys[(inst)->index]);
+}
+
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+void exynos_usbdrd_phy_get_otp_info(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct tune_bits *data;
+       u16 magic;
+       u8 type;
+       u8 index_count;
+       u8 i, j;
+
+       phy_drd->otp_index[0] = phy_drd->otp_index[1] = 0;
+
+       for (i = 0; i < OTP_SUPPORT_USBPHY_NUMBER; i++) {
+               magic = i ? OTP_MAGIC_USB2: OTP_MAGIC_USB3;
+
+               if (otp_tune_bits_parsed(magic, &type, &index_count, &data)) {
+                       dev_err(phy_drd->dev, "%s failed to get usb%d otp\n",
+                               __func__, i ? 2 : 3);
+                       continue;
+               }
+               dev_info(phy_drd->dev, "usb[%d] otp index_count: %d\n",
+                                                               i, index_count);
+
+               if (!index_count) {
+                       phy_drd->otp_data[i] = NULL;
+                       continue;
+               }
+
+               phy_drd->otp_data[i] = devm_kzalloc(phy_drd->dev,
+                       sizeof(*data) * index_count, GFP_KERNEL);
+               if (!phy_drd->otp_data[i]) {
+                       dev_err(phy_drd->dev, "%s failed to alloc for usb%d\n",
+                               __func__, i ? 2 : 3);
+                       continue;
+               }
+
+               phy_drd->otp_index[i] = index_count;
+               phy_drd->otp_type[i] = type ? 4 : 1;
+               dev_info(phy_drd->dev, "usb[%d] otp type: %d\n", i, type);
+
+               for (j = 0; j < index_count; j++) {
+                       phy_drd->otp_data[i][j].index = data[j].index;
+                       phy_drd->otp_data[i][j].value = data[j].value;
+                       dev_dbg(phy_drd->dev,
+                               "usb[%d][%d] otp_data index:%d, value:0x%08x\n",
+                                       i, j, phy_drd->otp_data[i][j].index,
+                                       phy_drd->otp_data[i][j].value);
+               }
+       }
+}
+#endif
+
+/*
+ * exynos_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static unsigned int exynos_rate_to_clk(struct exynos_usbdrd_phy *phy_drd)
+{
+       int ret;
+
+       ret = clk_prepare_enable(phy_drd->ref_clk);
+       if (ret) {
+               dev_err(phy_drd->dev, "%s failed to enable ref_clk", __func__);
+               return 0;
+       }
+
+       /* EXYNOS_FSEL_MASK */
+       switch (clk_get_rate(phy_drd->ref_clk)) {
+       case 9600 * KHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_9MHZ6;
+               break;
+       case 10 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_10MHZ;
+               break;
+       case 12 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_12MHZ;
+               break;
+       case 19200 * KHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_19MHZ2;
+               break;
+       case 20 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_20MHZ;
+               break;
+       case 24 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_24MHZ;
+               break;
+       case 26 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_26MHZ;
+               break;
+       case 50 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_50MHZ;
+               break;
+       default:
+               phy_drd->extrefclk = 0;
+               clk_disable_unprepare(phy_drd->ref_clk);
+               return -EINVAL;
+       }
+
+       clk_disable_unprepare(phy_drd->ref_clk);
+
+       return 0;
+}
+
+static void exynos_usbdrd_pipe3_phy_isol(struct phy_usb_instance *inst,
+                                       unsigned int on, unsigned int mask)
+{
+       unsigned int val;
+
+       if (!inst->reg_pmu)
+               return;
+
+       val = on ? 0 : mask;
+
+       regmap_update_bits(inst->reg_pmu, inst->pmu_offset_dp,
+               mask, val);
+}
+
+static void exynos_usbdrd_utmi_phy_isol(struct phy_usb_instance *inst,
+                                       unsigned int on, unsigned int mask)
+{
+       unsigned int val;
+
+       if (!inst->reg_pmu)
+               return;
+
+       val = on ? 0 : mask;
+
+       regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
+               mask, val);
+}
+
+/*
+ * Sets the pipe3 phy's clk as EXTREFCLK (XXTI) which is internal clock
+ * from clock core. Further sets multiplier values and spread spectrum
+ * clock settings for SuperSpeed operations.
+ */
+static unsigned int
+exynos_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst)
+{
+       static u32 reg;
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       /* PHYCLKRST setting isn't required in Combo PHY */
+       if (phy_drd->usbphy_info.version >= EXYNOS_USBPHY_VER_02_0_0)
+               return -EINVAL;
+
+       /* restore any previous reference clock settings */
+       reg = readl(phy_drd->reg_phy + EXYNOS_DRD_PHYCLKRST);
+
+       /* Use EXTREFCLK as ref clock */
+       reg &= ~PHYCLKRST_REFCLKSEL_MASK;
+       reg |=  PHYCLKRST_REFCLKSEL_EXT_REFCLK;
+
+       /* FSEL settings corresponding to reference clock */
+       reg &= ~PHYCLKRST_FSEL_PIPE_MASK |
+               PHYCLKRST_MPLL_MULTIPLIER_MASK |
+               PHYCLKRST_SSC_REFCLKSEL_MASK;
+       switch (phy_drd->extrefclk) {
+       case EXYNOS_FSEL_50MHZ:
+               reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF |
+                       PHYCLKRST_SSC_REFCLKSEL(0x00));
+               break;
+       case EXYNOS_FSEL_24MHZ:
+               reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF |
+                       PHYCLKRST_SSC_REFCLKSEL(0x88));
+               break;
+       case EXYNOS_FSEL_20MHZ:
+               reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF |
+                       PHYCLKRST_SSC_REFCLKSEL(0x00));
+               break;
+       case EXYNOS_FSEL_19MHZ2:
+               reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF |
+                       PHYCLKRST_SSC_REFCLKSEL(0x88));
+               break;
+       default:
+               dev_dbg(phy_drd->dev, "unsupported ref clk\n");
+               break;
+       }
+
+       return reg;
+}
+
+/*
+ * Sets the utmi phy's clk as EXTREFCLK (XXTI) which is internal clock
+ * from clock core. Further sets the FSEL values for HighSpeed operations.
+ */
+static unsigned int
+exynos_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst)
+{
+       static u32 reg;
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       /* PHYCLKRST setting isn't required in Combo PHY */
+       if(phy_drd->usbphy_info.version >= EXYNOS_USBPHY_VER_02_0_0)
+               return EINVAL;
+
+       /* restore any previous reference clock settings */
+       reg = readl(phy_drd->reg_phy + EXYNOS_DRD_PHYCLKRST);
+
+       reg &= ~PHYCLKRST_REFCLKSEL_MASK;
+       reg |=  PHYCLKRST_REFCLKSEL_EXT_REFCLK;
+
+       reg &= ~PHYCLKRST_FSEL_UTMI_MASK |
+               PHYCLKRST_MPLL_MULTIPLIER_MASK |
+               PHYCLKRST_SSC_REFCLKSEL_MASK;
+       reg |= PHYCLKRST_FSEL(phy_drd->extrefclk);
+
+       return reg;
+}
+
+/*
+ * Sets the default PHY tuning values for high-speed connection.
+ */
+static int exynos_usbdrd_fill_hstune(struct exynos_usbdrd_phy *phy_drd,
+                               struct device_node *node)
+{
+       struct device *dev = phy_drd->dev;
+       struct exynos_usbphy_hs_tune *hs_tune = phy_drd->hs_value;
+       int ret;
+       u32 res[2];
+       u32 value;
+
+       ret = of_property_read_u32_array(node, "tx_vref", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_vref = res[0];
+               hs_tune[1].tx_vref = res[1];
+       } else {
+               dev_err(dev, "can't get tx_vref value, error = %d\n", ret);
+               return -EINVAL;
+               }
+
+       ret = of_property_read_u32_array(node, "tx_pre_emp", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_pre_emp = res[0];
+               hs_tune[1].tx_pre_emp = res[1];
+       } else {
+               dev_err(dev, "can't get tx_pre_emp value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_pre_emp_puls", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_pre_emp_puls = res[0];
+               hs_tune[1].tx_pre_emp_puls = res[1];
+       } else {
+               dev_err(dev, "can't get tx_pre_emp_puls value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_res", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_res = res[0];
+               hs_tune[1].tx_res = res[1];
+       } else {
+               dev_err(dev, "can't get tx_res value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_rise", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_rise = res[0];
+               hs_tune[1].tx_rise = res[1];
+       } else {
+               dev_err(dev, "can't get tx_rise value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_hsxv", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_hsxv = res[0];
+               hs_tune[1].tx_hsxv = res[1];
+       } else {
+               dev_err(dev, "can't get tx_hsxv value, error = %d\n", ret);
+               return -EINVAL;
+               }
+
+       ret = of_property_read_u32_array(node, "tx_fsls", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_fsls = res[0];
+               hs_tune[1].tx_fsls = res[1];
+       } else {
+               dev_err(dev, "can't get tx_fsls value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "rx_sqrx", res, 2);
+       if (ret == 0) {
+               hs_tune[0].rx_sqrx = res[0];
+               hs_tune[1].rx_sqrx = res[1];
+       } else {
+               dev_err(dev, "can't get tx_sqrx value, error = %d\n", ret);
+               return -EINVAL;
+}
+
+       ret = of_property_read_u32_array(node, "compdis", res, 2);
+       if (ret == 0) {
+               hs_tune[0].compdis = res[0];
+               hs_tune[1].compdis = res[1];
+       } else {
+               dev_err(dev, "can't get compdis value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "otg", res, 2);
+       if (ret == 0) {
+               hs_tune[0].otg = res[0];
+               hs_tune[1].otg = res[1];
+       } else {
+               dev_err(dev, "can't get otg_tune value, error = %d\n", ret);
+               return -EINVAL;
+                       }
+
+       ret = of_property_read_u32_array(node, "enable_user_imp", res, 2);
+       if (ret == 0) {
+               if (res[0]) {
+                       hs_tune[0].enable_user_imp = true;
+                       hs_tune[1].enable_user_imp = true;
+                       hs_tune[0].user_imp_value = res[1];
+                       hs_tune[1].user_imp_value = res[1];
+               } else {
+                       hs_tune[0].enable_user_imp = false;
+                       hs_tune[1].enable_user_imp = false;
+                       }
+       } else {
+               dev_err(dev, "can't get enable_user_imp value, error = %d\n", ret);
+               return -EINVAL;
+               }
+
+       ret = of_property_read_u32(node, "is_phyclock", &value);
+       if (ret == 0) {
+               if ( value == 1) {
+                       hs_tune[0].utmi_clk = USBPHY_UTMI_PHYCLOCK;
+                       hs_tune[1].utmi_clk = USBPHY_UTMI_PHYCLOCK;
+               } else {
+                       hs_tune[0].utmi_clk = USBPHY_UTMI_FREECLOCK;
+                       hs_tune[1].utmi_clk = USBPHY_UTMI_FREECLOCK;
+       }
+       } else {
+               dev_err(dev, "can't get is_phyclock value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Sets the default PHY tuning values for super-speed connection.
+ */
+static int exynos_usbdrd_fill_sstune(struct exynos_usbdrd_phy *phy_drd,
+                                                       struct device_node *node)
+{
+       struct device *dev = phy_drd->dev;
+       struct exynos_usbphy_ss_tune *ss_tune = phy_drd->ss_value;
+       u32 res[2];
+       int ret;
+
+       ret = of_property_read_u32_array(node, "tx_boost_level", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_boost_level = res[0];
+               ss_tune[1].tx_boost_level = res[1];
+       } else {
+               dev_err(dev, "can't get tx_boost_level value, error = %d\n", ret);
+               return -EINVAL;
+               }
+
+       ret = of_property_read_u32_array(node, "tx_swing_level", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_swing_level = res[0];
+               ss_tune[1].tx_swing_level = res[1];
+       } else {
+               dev_err(dev, "can't get tx_swing_level value, error = %d\n", ret);
+               return -EINVAL;
+               }
+
+       ret = of_property_read_u32_array(node, "tx_swing_full", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_swing_full = res[0];
+               ss_tune[1].tx_swing_full = res[1];
+       } else {
+               dev_err(dev, "can't get tx_swing_full value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_swing_low", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_swing_low = res[0];
+               ss_tune[1].tx_swing_low = res[1];
+       } else {
+               dev_err(dev, "can't get tx_swing_low value, error = %d\n", ret);
+               return -EINVAL;
+}
+
+       ret = of_property_read_u32_array(node, "tx_deemphasis_mode", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_deemphasis_mode = res[0];
+               ss_tune[1].tx_deemphasis_mode = res[1];
+       } else {
+               dev_err(dev, "can't get tx_deemphasis_mode value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_deemphasis_3p5db", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_deemphasis_3p5db = res[0];
+               ss_tune[1].tx_deemphasis_3p5db = res[1];
+       } else {
+               dev_err(dev, "can't get tx_deemphasis_3p5db value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_deemphasis_6db", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_deemphasis_6db = res[0];
+               ss_tune[1].tx_deemphasis_6db = res[1];
+       } else {
+               dev_err(dev, "can't get tx_deemphasis_6db value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "enable_ssc", res, 2);
+       if (ret == 0) {
+               ss_tune[0].enable_ssc = res[0];
+               ss_tune[1].enable_ssc = res[1];
+       } else {
+               dev_err(dev, "can't get enable_ssc value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "ssc_range", res, 2);
+       if (ret == 0) {
+               ss_tune[0].ssc_range = res[0];
+               ss_tune[1].ssc_range = res[1];
+       } else {
+               dev_err(dev, "can't get ssc_range value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "los_bias", res, 2);
+       if (ret == 0) {
+               ss_tune[0].los_bias = res[0];
+               ss_tune[1].los_bias = res[1];
+       } else {
+               dev_err(dev, "can't get los_bias value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "los_mask_val", res, 2);
+       if (ret == 0) {
+               ss_tune[0].los_mask_val = res[0];
+               ss_tune[1].los_mask_val = res[1];
+       } else {
+               dev_err(dev, "can't get los_mask_val value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "enable_fixed_rxeq_mode", res, 2);
+       if (ret == 0) {
+               ss_tune[0].enable_fixed_rxeq_mode = res[0];
+               ss_tune[1].enable_fixed_rxeq_mode = res[1];
+       } else {
+               dev_err(dev, "can't get enable_fixed_rxeq_mode value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "fix_rxeq_value", res, 2);
+       if (ret == 0) {
+               ss_tune[0].fix_rxeq_value = res[0];
+               ss_tune[1].fix_rxeq_value = res[1];
+       } else {
+               dev_err(dev, "can't get fix_rxeq_value value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "set_crport_level_en", res, 2);
+       if (ret == 0) {
+               ss_tune[0].set_crport_level_en = res[0];
+               ss_tune[1].set_crport_level_en = res[1];
+       } else {
+               dev_err(dev, "can't get set_crport_level_en value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "set_crport_mpll_charge_pump", res, 2);
+       if (ret == 0) {
+               ss_tune[0].set_crport_mpll_charge_pump = res[0];
+               ss_tune[1].set_crport_mpll_charge_pump = res[1];
+       } else {
+               dev_err(dev, "can't get set_crport_mpll_charge_pump value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int exynos_usbdrd_fill_hstune_param(struct exynos_usbdrd_phy *phy_drd,
+                               struct device_node *node)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *child = NULL;
+       struct exynos_usb_tune_param *hs_tune_param;
+       size_t size = sizeof(struct exynos_usb_tune_param);
+       int ret;
+       u32 res[2];
+       u32 param_index = 0;
+       const char *name;
+
+       ret = of_property_read_u32_array(node, "hs_tune_cnt", &res[0], 1);
+
+       dev_info(dev, "%s hs tune cnt = %d\n", __func__, res[0]);
+
+       hs_tune_param = devm_kzalloc(dev, size*res[0], GFP_KERNEL);
+       if (!hs_tune_param)
+               return -ENOMEM;
+       phy_drd->usbphy_info.tune_param = hs_tune_param;
+
+       for_each_child_of_node(node, child) {
+               ret = of_property_read_string(child, "tune_name", &name);
+               if (ret == 0) {
+                       memcpy(hs_tune_param[param_index].name, name, strlen(name));
+               } else {
+                       dev_err(dev, "failed to read hs tune name from %s node\n", child->name);
+                       return ret;
+               }
+
+               ret = of_property_read_u32_array(child, "tune_value", res, 2);
+               if (ret == 0) {
+                       phy_drd->hs_tune_param_value[param_index][0] = res[0];
+                       phy_drd->hs_tune_param_value[param_index][1] = res[1];
+               } else {
+                       dev_err(dev, "failed to read hs tune value from %s node\n", child->name);
+                       return -EINVAL;
+               }
+               param_index++;
+       }
+
+       hs_tune_param[param_index].value = EXYNOS_USB_TUNE_LAST;
+
+       return 0;
+}
+
+/*
+ * Sets the default PHY tuning values for super-speed connection.
+ */
+static int exynos_usbdrd_fill_sstune_param(struct exynos_usbdrd_phy *phy_drd,
+                                                       struct device_node *node)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *child = NULL;
+       struct exynos_usb_tune_param *ss_tune_param;
+       size_t size = sizeof(struct exynos_usb_tune_param);
+       int ret;
+       u32 res[2];
+       u32 param_index = 0;
+       const char *name;
+
+       ret = of_property_read_u32_array(node, "ss_tune_cnt", &res[0], 1);
+
+       dev_info(dev, "%s ss tune cnt = %d\n", __func__, res[0]);
+
+       ss_tune_param = devm_kzalloc(dev, size*res[0], GFP_KERNEL);
+       if (!ss_tune_param)
+               return -ENOMEM;
+       phy_drd->usbphy_sub_info.tune_param = ss_tune_param;
+
+       for_each_child_of_node(node, child) {
+               ret = of_property_read_string(child, "tune_name", &name);
+               if (ret == 0) {
+                       memcpy(ss_tune_param[param_index].name, name, strlen(name));
+               }
+               else {
+                       dev_err(dev, "failed to read ss tune name from %s node\n", child->name);
+                       return ret;
+               }
+
+               ret = of_property_read_u32_array(child, "tune_value", res, 2);
+               if (ret == 0) {
+                       phy_drd->ss_tune_param_value[param_index][0] = res[0];
+                       phy_drd->ss_tune_param_value[param_index][1] = res[1];
+               } else {
+                       dev_err(dev, "failed to read ss tune value from %s node\n", child->name);
+                       return -EINVAL;
+               }
+               param_index++;
+       }
+
+       ss_tune_param[param_index].value = EXYNOS_USB_TUNE_LAST;
+
+       return 0;
+}
+
+static int exynos_usbdrd_get_phy_refsel(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *node = dev->of_node;
+       int value, ret;
+       int check_flag = 0;
+
+       ret = of_property_read_u32(node, "phy_refsel_clockcore", &value);
+       if (ret == 0 && value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_CLKCORE;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_CLKCORE;
+       } else if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_clockcore, error = %d\n", ret);
+               return ret;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_ext_osc", &value);
+       if (ret == 0 && value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_EXT_OSC;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_EXT_OSC;
+       } else if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_ext_osc, error = %d\n", ret);
+               return ret;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_xtal", &value);
+       if (ret == 0 && value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_EXT_XTAL;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_EXT_XTAL;
+       } else if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_xtal, error = %d\n", ret);
+               return ret;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_diff_pad", &value);
+       if (ret == 0 && value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_DIFF_PAD;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_DIFF_PAD;
+       } else if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_diff_pad, error = %d\n", ret);
+               return ret;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_diff_internal", &value);
+       if (ret == 0 && value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_DIFF_INTERNAL;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_DIFF_INTERNAL;
+       } else if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_diff_internal, error = %d\n", ret);
+               return ret;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_diff_single", &value);
+       if (ret == 0 && value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_DIFF_SINGLE;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_DIFF_SINGLE;
+       } else if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_diff_single, error = %d\n", ret);
+               return ret;
+       } else {
+               check_flag++;
+       }
+
+       if (check_flag > 5) {
+               dev_err(dev, "USB refsel Must be choosed\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int exynos_usbdrd_get_sub_phyinfo(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *tune_node;
+       int ret;
+       int value;
+
+       if (!of_property_read_u32(dev->of_node, "sub_phy_version", &value)) {
+               phy_drd->usbphy_sub_info.version = value;
+       } else {
+               dev_err(dev, "can't get sub_phy_version\n");
+               return -EINVAL;
+       }
+       phy_drd->usbphy_sub_info.refclk = phy_drd->extrefclk;
+       phy_drd->usbphy_sub_info.regs_base = phy_drd->reg_phy2;
+       /* Temporary WA, CAL code modification is needed */
+       phy_drd->usbphy_info.regs_base_2nd = phy_drd->reg_phy2;
+       phy_drd->usbphy_sub_info.regs_base_2nd = phy_drd->reg_phy3;
+       usbdp_combo_phy_reg = phy_drd->usbphy_sub_info.regs_base;
+
+       tune_node = of_parse_phandle(dev->of_node, "ss_tune_param", 0);
+       if (tune_node != NULL) {
+               ret = exynos_usbdrd_fill_sstune_param(phy_drd, tune_node);
+               if (ret < 0) {
+                       dev_err(dev, "can't fill super speed tuning param\n");
+                       return -EINVAL;
+               }
+       } else
+               dev_info(dev, "don't need usbphy tuning param for high speed\n");
+
+       return 0;
+}
+
+static int exynos_usbdrd_get_phyinfo(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *tune_node;
+       int ret;
+       int value;
+
+       phy_drd->usbphy_info.hs_rewa = 1;
+
+       if (!of_property_read_u32(dev->of_node, "phy_version", &value)) {
+               phy_drd->usbphy_info.version = value;
+       } else {
+               dev_err(dev, "can't get phy_version\n");
+               return -EINVAL;
+       }
+
+       if (!of_property_read_u32(dev->of_node, "use_io_for_ovc", &value)) {
+               phy_drd->usbphy_info.use_io_for_ovc = value ? true : false;
+               } else {
+               dev_err(dev, "can't get io_for_ovc\n");
+               return -EINVAL;
+               }
+
+       if (!of_property_read_u32(dev->of_node, "common_block_disable", &value)) {
+               phy_drd->usbphy_info.common_block_disable = value ? true : false;
+       } else {
+               dev_err(dev, "can't get common_block_disable\n");
+               return -EINVAL;
+       }
+
+       phy_drd->usbphy_info.refclk = phy_drd->extrefclk;
+       phy_drd->usbphy_info.regs_base = phy_drd->reg_phy;
+
+       if (!of_property_read_u32(dev->of_node, "is_not_vbus_pad", &value)) {
+               phy_drd->usbphy_info.not_used_vbus_pad = value ? true : false;
+       } else {
+               dev_err(dev, "can't get vbus_pad\n");
+               return -EINVAL;
+       }
+
+       if (!of_property_read_u32(dev->of_node, "used_phy_port", &value)) {
+               phy_drd->usbphy_info.used_phy_port = value ? true : false;
+       } else {
+               dev_err(dev, "can't get used_phy_port\n");
+               return -EINVAL;
+       }
+
+       ret = exynos_usbdrd_get_phy_refsel(phy_drd);
+       if (ret < 0)
+               dev_err(dev, "can't get phy refsel\n");
+
+       tune_node = of_parse_phandle(dev->of_node, "ss_tune_info", 0);
+       if (tune_node == NULL)
+               dev_info(dev, "don't need usbphy tuning value for super speed\n");
+
+       if (of_device_is_available(tune_node)) {
+               ret = exynos_usbdrd_fill_sstune(phy_drd, tune_node);
+               if (ret < 0) {
+                       dev_err(dev, "can't fill super speed tuning value\n");
+                       return -EINVAL;
+               }
+       }
+
+       tune_node = of_parse_phandle(dev->of_node, "hs_tune_info", 0);
+       if (tune_node == NULL)
+               dev_info(dev, "don't need usbphy tuning value for high speed\n");
+
+       if (of_device_is_available(tune_node)) {
+               ret = exynos_usbdrd_fill_hstune(phy_drd, tune_node);
+               if (ret < 0) {
+                       dev_err(dev, "can't fill high speed tuning value\n");
+                       return -EINVAL;
+               }
+       }
+
+       tune_node = of_parse_phandle(dev->of_node, "hs_tune_param", 0);
+       if (tune_node != NULL) {
+               ret = exynos_usbdrd_fill_hstune_param(phy_drd, tune_node);
+               if (ret < 0) {
+                       dev_err(dev, "can't fill high speed tuning param\n");
+                       return -EINVAL;
+               }
+       } else
+               dev_info(dev, "don't need usbphy tuning param for high speed\n");
+
+       dev_info(phy_drd->dev, "usbphy info: version:0x%x, refclk:0x%x\n",
+               phy_drd->usbphy_info.version, phy_drd->usbphy_info.refclk);
+
+       return 0;
+}
+
+static int exynos_usbdrd_get_iptype(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       int ret, value;
+
+       ret = of_property_read_u32(dev->of_node, "ip_type", &value);
+       if (ret) {
+               dev_err(dev, "can't get ip type");
+               return ret;
+       }
+
+       switch (value) {
+       case TYPE_USB3DRD:
+               phy_drd->ip_type = TYPE_USB3DRD;
+               dev_info(dev, "It is TYPE USB3DRD");
+               break;
+       case TYPE_USB3HOST:
+               phy_drd->ip_type = TYPE_USB3HOST;
+               dev_info(dev, "It is TYPE USB3HOST");
+               break;
+       case TYPE_USB2DRD:
+               phy_drd->ip_type = TYPE_USB2DRD;
+               dev_info(dev, "It is TYPE USB2DRD");
+               break;
+       case TYPE_USB2HOST:
+               phy_drd->ip_type = TYPE_USB2HOST;
+               dev_info(dev, "It is TYPE USB2HOST");
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void exynos_usbdrd_pipe3_init(struct exynos_usbdrd_phy *phy_drd)
+{
+#if defined(USB_SS_ENABLED)
+       int value, ret;
+
+       if (gpio_is_valid(phy_drd->phy_port)) {
+               value = !gpio_get_value(phy_drd->phy_port);
+               phy_drd->usbphy_info.used_phy_port = phy_drd->usbphy_sub_info.used_phy_port = value;
+               dev_info(phy_drd->dev, "%s: phy port[%d]\n", __func__,
+                                               phy_drd->usbphy_info.used_phy_port);
+       } else {
+               dev_info(phy_drd->dev, "%s: phy port fail retry\n", __func__);
+               phy_drd->phy_port =  of_get_named_gpio(phy_drd->dev->of_node,
+                                               "phy,gpio_phy_port", 0);
+               if (gpio_is_valid(phy_drd->phy_port)) {
+                       dev_err(phy_drd->dev, "PHY CON Selection OK\n");
+
+                       ret = gpio_request(phy_drd->phy_port, "PHY_CON");
+                       if (ret)
+                               dev_err(phy_drd->dev, "fail to request gpio %s:%d\n", "PHY_CON", ret);
+                       else
+                               gpio_direction_input(phy_drd->phy_port);
+
+                       value = !gpio_get_value(phy_drd->phy_port);
+                       phy_drd->usbphy_info.used_phy_port = phy_drd->usbphy_sub_info.used_phy_port = value;
+                       dev_info(phy_drd->dev, "%s: phy port1[%d]\n", __func__,
+                                                       phy_drd->usbphy_info.used_phy_port);
+               } else {
+                       dev_err(phy_drd->dev, "non-DT: PHY CON Selection\n");
+               }
+       }
+
+       /* Fill USBDP Combo phy init */
+       phy_exynos_usb_v3p1_pma_ready(&phy_drd->usbphy_info);
+
+       phy_exynos_usbdp_enable(&phy_drd->usbphy_sub_info);
+
+       phy_exynos_usb_v3p1_pma_sw_rst_release(&phy_drd->usbphy_info);
+#endif
+}
+
+static void exynos_usbdrd_utmi_init(struct exynos_usbdrd_phy *phy_drd)
+{
+       int ret;
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+       struct tune_bits *otp_data;
+       u8 otp_type;
+       u8 otp_index;
+       u8 i;
+#endif
+       pr_info("%s: +++\n", __func__);
+
+       ret = exynos_usbdrd_clk_enable(phy_drd, false);
+       if (ret) {
+               dev_err(phy_drd->dev, "%s: Failed to enable clk\n", __func__);
+               return;
+       }
+
+       phy_exynos_usb_v3p1_enable(&phy_drd->usbphy_info);
+
+       phy_exynos_usb_v3p1_pipe_ovrd(&phy_drd->usbphy_info);
+
+       if (phy_drd->use_phy_umux) {
+               /* USB User MUX enable */
+               ret = exynos_usbdrd_clk_enable(phy_drd, true);
+               if (ret) {
+                       dev_err(phy_drd->dev, "%s: Failed to enable clk\n", __func__);
+                       return;
+               }
+       }
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+       if (phy_drd->ip_type < TYPE_USB2DRD) {
+               otp_type = phy_drd->otp_type[OTP_USB3PHY_INDEX];
+               otp_index = phy_drd->otp_index[OTP_USB3PHY_INDEX];
+               otp_data = phy_drd->otp_data[OTP_USB3PHY_INDEX];
+       } else {
+               otp_type = phy_drd->otp_type[OTP_USB2PHY_INDEX];
+               otp_index = phy_drd->otp_index[OTP_USB2PHY_INDEX];
+               otp_data = phy_drd->otp_data[OTP_USB2PHY_INDEX];
+       }
+
+       for (i = 0; i < otp_index; i++) {
+               samsung_exynos_cal_usb3phy_write_register(
+                       &phy_drd->usbphy_info,
+                       otp_data[i].index * otp_type,
+                       otp_data[i].value);
+       }
+#endif
+
+       pr_info("%s: ---\n", __func__);
+}
+
+static int exynos_usbdrd_phy_init(struct phy *phy)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       /* UTMI or PIPE3 specific init */
+       inst->phy_cfg->phy_init(phy_drd);
+
+       return 0;
+}
+
+static void __exynos_usbdrd_phy_shutdown(struct exynos_usbdrd_phy *phy_drd)
+{
+       phy_exynos_usb_v3p1_disable(&phy_drd->usbphy_info);
+       phy_exynos_usbdp_disable(&phy_drd->usbphy_sub_info);
+}
+
+static void exynos_usbdrd_pipe3_exit(struct exynos_usbdrd_phy *phy_drd)
+{
+       /* pipe3 phy diable is exucuted in utmi_exit.
+               Later divide the exit of main and sub phy if necessary */
+       return;
+}
+
+static void exynos_usbdrd_utmi_exit(struct exynos_usbdrd_phy *phy_drd)
+{
+       if (phy_drd->use_phy_umux) {
+               /*USB User MUX disable */
+               exynos_usbdrd_clk_disable(phy_drd, true);
+       }
+       phy_exynos_usb_v3p1_disable(&phy_drd->usbphy_info);
+       phy_exynos_usbdp_disable(&phy_drd->usbphy_sub_info);
+
+       exynos_usbdrd_clk_disable(phy_drd, false);
+}
+
+static int exynos_usbdrd_phy_exit(struct phy *phy)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       /* UTMI or PIPE3 specific exit */
+       inst->phy_cfg->phy_exit(phy_drd);
+
+       return 0;
+}
+
+static void exynos_usbdrd_utmi_ilbk(struct exynos_usbdrd_phy *phy_drd)
+{
+       dev_info(phy_drd->dev, "%s\n", __func__);
+}
+
+static void exynos_usbdrd_pipe3_ilbk(struct exynos_usbdrd_phy *phy_drd)
+{
+       dev_info(phy_drd->dev, "%s\n", __func__);
+
+       phy_exynos_usbdp_ilbk(&phy_drd->usbphy_sub_info);
+}
+
+static int exynos_usbdrd_pipe3_vendor_set(struct exynos_usbdrd_phy *phy_drd,
+                                                       int is_enable, int is_cancel)
+{
+       dev_info(phy_drd->dev, "%s \n",__func__);
+       return 0;
+}
+
+static int exynos_usbdrd_utmi_vendor_set(struct exynos_usbdrd_phy *phy_drd,
+                                                       int is_enable, int is_cancel)
+{
+       int ret = 0;
+
+       dev_info(phy_drd->dev, "rewa irq : %d, enable: %d, cancel: %d\n",
+                       phy_drd->is_irq_enabled, is_enable, is_cancel);
+       if (is_cancel) {
+               if (is_enable) {
+                       if (phy_drd->is_irq_enabled == 1) {
+                               dev_info(phy_drd->dev, "[%s] REWA CANCEL\n", __func__);
+                               phy_exynos_usb3p1_rewa_cancel(&phy_drd->usbphy_info);
+
+                               dev_info(phy_drd->dev, "REWA wakeup/conn IRQ disable\n");
+
+                               disable_irq_nosync(phy_drd->irq_wakeup);
+                               disable_irq_nosync(phy_drd->irq_conn);
+                               phy_drd->is_irq_enabled = 0;
+                       } else {
+                               dev_info(phy_drd->dev, "Vendor set by interrupt, Do not REWA cancel\n");
+                       }
+               }
+       } else {
+               if (is_enable) {
+                       ret = phy_exynos_usb3p1_rewa_enable(&phy_drd->usbphy_info);
+                       if (ret) {
+                               dev_err(phy_drd->dev, "REWA ENABLE FAIL, ret : %d \n", ret);
+                               return ret;
+                       }
+                       dev_info(phy_drd->dev, "REWA ENABLE Complete\n");
+
+                       if (phy_drd->is_irq_enabled == 0) {
+                               enable_irq(phy_drd->irq_wakeup);
+                               enable_irq(phy_drd->irq_conn);
+                               phy_drd->is_irq_enabled = 1;
+                       } else {
+                               dev_info(phy_drd->dev, "rewa irq already enabled\n");
+                       }
+               } else {
+                       dev_info(phy_drd->dev, "REWA Disconn & Wakeup IRQ DISABLE\n");
+                       ret = phy_exynos_usb3p1_rewa_disable(&phy_drd->usbphy_info);
+                       if (ret) {
+                               dev_err(phy_drd->dev, "REWA DISABLE FAIL, ret : %d \n", ret);
+                               return ret;
+                       }
+                       dev_info(phy_drd->dev, "REWA DISABLE Complete\n");
+               }
+       }
+       return ret;
+}
+
+static void exynos_usbdrd_pipe3_tune(struct exynos_usbdrd_phy *phy_drd,
+                                                       int phy_state)
+{
+       struct exynos_usb_tune_param *ss_tune_param = phy_drd->usbphy_sub_info.tune_param;
+       int i;
+
+       dev_info(phy_drd->dev, "%s\n", __func__);
+
+       if (phy_state >= OTG_STATE_A_IDLE) {
+               /* for host mode */
+               for (i = 0; ss_tune_param[i].value != EXYNOS_USB_TUNE_LAST; i++) {
+                       if (i == EXYNOS_DRD_MAX_TUNEPARAM_NUM)
+                               break;
+                       ss_tune_param[i].value = phy_drd->ss_tune_param_value[i][USBPHY_MODE_HOST];
+               }
+       } else {
+               /* for device mode */
+               for (i = 0; ss_tune_param[i].value != EXYNOS_USB_TUNE_LAST; i++) {
+                       if (i == EXYNOS_DRD_MAX_TUNEPARAM_NUM)
+                               break;
+                       ss_tune_param[i].value = phy_drd->ss_tune_param_value[i][USBPHY_MODE_DEV];
+               }
+       }
+       phy_exynos_usbdp_tune(&phy_drd->usbphy_sub_info);
+}
+
+static void exynos_usbdrd_utmi_tune(struct exynos_usbdrd_phy *phy_drd,
+                                                       int phy_state)
+{
+       struct exynos_usb_tune_param *hs_tune_param = phy_drd->usbphy_info.tune_param;
+       int i;
+
+       dev_info(phy_drd->dev, "%s\n", __func__);
+
+       if (phy_state >= OTG_STATE_A_IDLE) {
+               /* for host mode */
+               for (i = 0; hs_tune_param[i].value != EXYNOS_USB_TUNE_LAST; i++) {
+                       if (i == EXYNOS_DRD_MAX_TUNEPARAM_NUM)
+                               break;
+                       hs_tune_param[i].value = phy_drd->hs_tune_param_value[i][USBPHY_MODE_HOST];
+               }
+       } else {
+               /* for device mode */
+               for (i = 0; hs_tune_param[i].value != EXYNOS_USB_TUNE_LAST; i++)  {
+                       if (i == EXYNOS_DRD_MAX_TUNEPARAM_NUM)
+                               break;
+                       hs_tune_param[i].value = phy_drd->hs_tune_param_value[i][USBPHY_MODE_DEV];
+               }
+       }
+       phy_exynos_usb_v3p1_tune(&phy_drd->usbphy_info);
+}
+
+static int exynos_usbdrd_phy_tune(struct phy *phy, int phy_state)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       inst->phy_cfg->phy_tune(phy_drd, phy_state);
+
+       return 0;
+}
+
+static void exynos_usbdrd_phy_conn(struct phy *phy, int is_conn)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       if (is_conn) {
+               dev_info(phy_drd->dev, "USB PHY Conn Set\n");
+               phy_drd->is_conn = 1;
+       } else {
+               dev_info(phy_drd->dev, "USB PHY Conn Clear\n");
+               phy_drd->is_conn = 0;
+       }
+
+       return;
+}
+
+static int exynos_usbdrd_dp_ilbk(struct phy *phy)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       inst->phy_cfg->phy_ilbk(phy_drd);
+
+       return 0;
+}
+
+static int exynos_usbdrd_phy_vendor_set(struct phy *phy, int is_enable,
+                                               int is_cancel)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+       int ret;
+
+       ret = inst->phy_cfg->phy_vendor_set(phy_drd, is_enable, is_cancel);
+
+       return ret;
+}
+
+static void exynos_usbdrd_pipe3_set(struct exynos_usbdrd_phy *phy_drd,
+                                               int option, void *info)
+{
+       /* Fill USBDP Combo phy set */
+       return;
+}
+
+static void exynos_usbdrd_utmi_set(struct exynos_usbdrd_phy *phy_drd,
+                                               int option, void *info)
+{
+       switch (option) {
+       case SET_DPPULLUP_ENABLE:
+               phy_exynos_usb_v3p1_enable_dp_pullup(
+                                       &phy_drd->usbphy_info);
+               break;
+       case SET_DPPULLUP_DISABLE:
+                phy_exynos_usb_v3p1_disable_dp_pullup(
+                                       &phy_drd->usbphy_info);
+               break;
+       case SET_DPDM_PULLDOWN:
+               phy_exynos_usb_v3p1_config_host_mode(
+                                       &phy_drd->usbphy_info);
+       default:
+               break;
+       }
+}
+
+static int exynos_usbdrd_phy_set(struct phy *phy, int option, void *info)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       inst->phy_cfg->phy_set(phy_drd, option, info);
+
+       return 0;
+}
+
+static int exynos_usbdrd_phy_power_on(struct phy *phy)
+{
+       int ret;
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n");
+
+       /* Enable VBUS supply */
+       if (phy_drd->vbus) {
+               ret = regulator_enable(phy_drd->vbus);
+               if (ret) {
+                       dev_err(phy_drd->dev, "Failed to enable VBUS supply\n");
+                       return ret;
+               }
+       }
+
+       inst->phy_cfg->phy_isol(inst, 0, inst->pmu_mask);
+
+       phy_isol_delayed = 0;
+       dp_use_informed = 0;
+
+       return 0;
+}
+
+static int exynos_usbdrd_phy_power_off(struct phy *phy)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n");
+
+       if (!dp_use_informed)
+               inst->phy_cfg->phy_isol(inst, 1, inst->pmu_mask);
+       else
+               phy_isol_delayed = 1;
+
+       /* Disable VBUS supply */
+       if (phy_drd->vbus)
+               regulator_disable(phy_drd->vbus);
+
+       return 0;
+}
+
+void exynos_usbdrd_request_phy_isol(void)
+{
+       pr_info("[%s] phy_isol_delayed = %d\n", __func__, phy_isol_delayed);
+
+       if (!reg_pmu_delayed || !pmu_offset_dp_delayed)
+               return;
+
+       if (phy_isol_delayed == 1) {
+               regmap_update_bits(reg_pmu_delayed, pmu_offset_delayed, 1, 0);
+               regmap_update_bits(reg_pmu_delayed,
+                       pmu_offset_dp_delayed, 1, 0);
+               phy_isol_delayed = 0;
+               dp_use_informed = 0;
+       }
+}
+
+int exynos_usbdrd_inform_dp_use(int use, int lane_cnt)
+{
+       int ret = 0;
+
+       pr_info("[%s] dp use = %d, lane_cnt = %d\n", __func__, use, lane_cnt);
+
+       dp_use_informed = use;
+
+       if ((use == 1) && (lane_cnt == 4)) {
+               ret = xhci_portsc_set(0);
+               udelay(1);
+       }
+
+       return ret;
+}
+
+static struct phy *exynos_usbdrd_phy_xlate(struct device *dev,
+                                       struct of_phandle_args *args)
+{
+       struct exynos_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
+
+       if (WARN_ON(args->args[0] > EXYNOS_DRDPHYS_NUM))
+               return ERR_PTR(-ENODEV);
+
+       return phy_drd->phys[args->args[0]].phy;
+}
+
+#if defined(USB_L2_ENABLED)
+static irqreturn_t exynos_usbdrd_phy_wakeup_interrupt(int irq, void *_phydrd)
+{
+       struct exynos_usbdrd_phy *phy_drd = (struct exynos_usbdrd_phy *)_phydrd;
+       int ret;
+
+       ret = phy_exynos_usb3p1_rewa_req_sys_valid(&phy_drd->usbphy_info);
+       dev_info(phy_drd->dev, "[%s] rewa sys vaild set : %s \n",
+                       __func__, (ret == 1) ? "Disable" : "Disconnect");
+
+       if (phy_drd->is_irq_enabled == 1) {
+               disable_irq_nosync(phy_drd->irq_wakeup);
+               disable_irq_nosync(phy_drd->irq_conn);
+               phy_drd->is_irq_enabled = 0;
+       } else {
+               dev_info(phy_drd->dev, "rewa irq already disabled\n");
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t exynos_usbdrd_phy_conn_interrupt(int irq, void *_phydrd)
+{
+       struct exynos_usbdrd_phy *phy_drd = (struct exynos_usbdrd_phy *)_phydrd;
+       int ret;
+
+       ret = phy_exynos_usb3p1_rewa_req_sys_valid(&phy_drd->usbphy_info);
+       dev_info(phy_drd->dev, "[%s] rewa sys vaild set : %s \n",
+                       __func__, (ret == 1) ? "Disable" : "Disconnect");
+
+       if (phy_drd->is_irq_enabled == 1) {
+               disable_irq_nosync(phy_drd->irq_wakeup);
+               disable_irq_nosync(phy_drd->irq_conn);
+               phy_drd->is_irq_enabled = 0;
+       } else {
+               dev_info(phy_drd->dev, "rewa irq already disabled\n");
+       }
+
+       return IRQ_HANDLED;
+}
+#endif
+
+static struct phy_ops exynos_usbdrd_phy_ops = {
+       .init           = exynos_usbdrd_phy_init,
+       .exit           = exynos_usbdrd_phy_exit,
+       .tune           = exynos_usbdrd_phy_tune,
+       .set            = exynos_usbdrd_phy_set,
+       .vendor_set     = exynos_usbdrd_phy_vendor_set,
+       .conn           = exynos_usbdrd_phy_conn,
+       .ilbk           = exynos_usbdrd_dp_ilbk,
+       .power_on       = exynos_usbdrd_phy_power_on,
+       .power_off      = exynos_usbdrd_phy_power_off,
+       .owner          = THIS_MODULE,
+};
+
+static const struct exynos_usbdrd_phy_config phy_cfg_exynos[] = {
+       {
+               .id             = EXYNOS_DRDPHY_UTMI,
+               .phy_isol       = exynos_usbdrd_utmi_phy_isol,
+               .phy_init       = exynos_usbdrd_utmi_init,
+               .phy_exit       = exynos_usbdrd_utmi_exit,
+               .phy_tune       = exynos_usbdrd_utmi_tune,
+               .phy_vendor_set = exynos_usbdrd_utmi_vendor_set,
+               .phy_ilbk       = exynos_usbdrd_utmi_ilbk,
+               .phy_set        = exynos_usbdrd_utmi_set,
+               .set_refclk     = exynos_usbdrd_utmi_set_refclk,
+       },
+       {
+               .id             = EXYNOS_DRDPHY_PIPE3,
+               .phy_isol       = exynos_usbdrd_pipe3_phy_isol,
+               .phy_init       = exynos_usbdrd_pipe3_init,
+               .phy_exit       = exynos_usbdrd_pipe3_exit,
+               .phy_tune       = exynos_usbdrd_pipe3_tune,
+               .phy_vendor_set = exynos_usbdrd_pipe3_vendor_set,
+               .phy_ilbk       = exynos_usbdrd_pipe3_ilbk,
+               .phy_set        = exynos_usbdrd_pipe3_set,
+               .set_refclk     = exynos_usbdrd_pipe3_set_refclk,
+       },
+};
+
+static const struct exynos_usbdrd_phy_drvdata exynos_usbdrd_phy = {
+       .phy_cfg                = phy_cfg_exynos,
+};
+
+static const struct of_device_id exynos_usbdrd_phy_of_match[] = {
+       {
+               .compatible = "samsung,exynos-usbdrd-phy",
+               .data = &exynos_usbdrd_phy
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, exynos5_usbdrd_phy_of_match);
+
+void __iomem *phy_exynos_usbdp_get_address(void)
+{
+       return usbdp_combo_phy_reg;
+}
+
+static int exynos_usbdrd_phy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct exynos_usbdrd_phy *phy_drd;
+       struct phy_provider *phy_provider;
+       struct resource *res;
+       const struct of_device_id *match;
+       const struct exynos_usbdrd_phy_drvdata *drv_data;
+       struct regmap *reg_pmu;
+       u32 pmu_offset, pmu_offset_dp, pmu_mask;
+       int i, ret;
+
+       pr_info("%s: +++ %s %s\n", __func__, dev->init_name, pdev->name);
+       phy_drd = devm_kzalloc(dev, sizeof(*phy_drd), GFP_KERNEL);
+       if (!phy_drd)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, phy_drd);
+       phy_drd->dev = dev;
+
+       match = of_match_node(exynos_usbdrd_phy_of_match, pdev->dev.of_node);
+
+       drv_data = match->data;
+       phy_drd->drv_data = drv_data;
+
+#if defined(USB_L2_ENABLED)
+       phy_drd->irq_wakeup = platform_get_irq(pdev, 0);
+       irq_set_status_flags(phy_drd->irq_wakeup, IRQ_NOAUTOEN);
+       ret = devm_request_irq(dev, phy_drd->irq_wakeup, exynos_usbdrd_phy_wakeup_interrupt,
+                       IRQF_SHARED, "phydrd-wakeup", phy_drd);
+       if (ret) {
+               dev_err(dev, "failed to request irq #%d --> %d\n",
+                               phy_drd->irq_wakeup, ret);
+               return ret;
+       }
+       phy_drd->irq_conn = platform_get_irq(pdev, 1);
+       irq_set_status_flags(phy_drd->irq_conn, IRQ_NOAUTOEN);
+       ret = devm_request_irq(dev, phy_drd->irq_conn, exynos_usbdrd_phy_conn_interrupt,
+                                       IRQF_SHARED, "phydrd-conn", phy_drd);
+       if (ret) {
+               dev_err(dev, "failed to request irq #%d --> %d\n",
+                               phy_drd->irq_conn, ret);
+               return ret;
+       }
+#endif
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       phy_drd->reg_phy = devm_ioremap_resource(dev, res);
+       if (IS_ERR(phy_drd->reg_phy))
+               return PTR_ERR(phy_drd->reg_phy);
+
+       /* Both has_other_phy and has_combo_phy can't be enabled at the same time. It's alternative. */
+       if (!of_property_read_u32(dev->of_node, "has_other_phy", &ret)) {
+               if (ret) {
+                       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+                       phy_drd->reg_phy2 = devm_ioremap_resource(dev, res);
+                       if (IS_ERR(phy_drd->reg_phy2))
+                               return PTR_ERR(phy_drd->reg_phy2);
+               } else {
+                       dev_err(dev, "It has not the other phy\n");
+               }
+       }
+
+       ret = exynos_usbdrd_get_iptype(phy_drd);
+       if (ret) {
+               dev_err(dev, "%s: Failed to get ip_type\n", __func__);
+               return ret;
+       }
+
+       ret = exynos_usbdrd_clk_get(phy_drd);
+       if (ret) {
+               dev_err(dev, "%s: Failed to get clocks\n", __func__);
+               return ret;
+       }
+
+       ret = exynos_usbdrd_clk_prepare(phy_drd);
+       if (ret) {
+               dev_err(dev, "%s: Failed to prepare clocks\n", __func__);
+               return ret;
+       }
+
+       ret = exynos_rate_to_clk(phy_drd);
+       if (ret) {
+               dev_err(phy_drd->dev, "%s: Not supported ref clock\n",
+                               __func__);
+               goto err1;
+       }
+
+       reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
+                                                  "samsung,pmu-syscon");
+       if (IS_ERR(reg_pmu)) {
+               dev_err(dev, "Failed to lookup PMU regmap\n");
+               goto err1;
+       }
+
+       ret = of_property_read_u32(dev->of_node, "pmu_offset", &pmu_offset);
+       if (ret < 0) {
+               dev_err(dev, "couldn't read pmu_offset on %s node, error = %d\n",
+                                               dev->of_node->name, ret);
+               goto err1;
+       }
+       ret = of_property_read_u32(dev->of_node, "pmu_offset_dp", &pmu_offset_dp);
+       if (ret < 0) {
+               dev_err(dev, "couldn't read pmu_offset on %s node, error = %d\n",
+                                               dev->of_node->name, ret);
+               goto err1;
+       }
+       ret = of_property_read_u32(dev->of_node, "pmu_mask", &pmu_mask);
+       if (ret < 0) {
+               dev_err(dev, "couldn't read pmu_mask on %s node, error = %d\n",
+                                               dev->of_node->name, ret);
+               goto err1;
+       }
+       pmu_mask = (u32)BIT(pmu_mask);
+
+       dev_vdbg(dev, "Creating usbdrd_phy phy\n");
+       phy_drd->phy_port =  of_get_named_gpio(dev->of_node,
+                                       "phy,gpio_phy_port", 0);
+       if (gpio_is_valid(phy_drd->phy_port)) {
+               dev_err(dev, "PHY CON Selection OK\n");
+
+               ret = gpio_request(phy_drd->phy_port, "PHY_CON");
+               if (ret)
+                       dev_err(dev, "fail to request gpio %s:%d\n", "PHY_CON", ret);
+               else
+                       gpio_direction_input(phy_drd->phy_port);
+       }
+       else
+               dev_err(dev, "non-DT: PHY CON Selection\n");
+
+       ret = exynos_usbdrd_get_phyinfo(phy_drd);
+       if (ret)
+               goto err1;
+
+       if (!of_property_read_u32(dev->of_node, "has_combo_phy", &ret)) {
+               if (ret) {
+                       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+                       phy_drd->reg_phy2 = devm_ioremap_resource(dev, res);
+                       if (IS_ERR(phy_drd->reg_phy2))
+                               return PTR_ERR(phy_drd->reg_phy2);
+
+                       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+                       phy_drd->reg_phy3 = devm_ioremap_resource(dev, res);
+                       if (IS_ERR(phy_drd->reg_phy3))
+                               return PTR_ERR(phy_drd->reg_phy3);
+
+                       exynos_usbdrd_get_sub_phyinfo(phy_drd);
+               } else {
+                       dev_err(dev, "It has not combo phy\n");
+               }
+       }
+
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+       exynos_usbdrd_phy_get_otp_info(phy_drd);
+#endif
+
+       for (i = 0; i < EXYNOS_DRDPHYS_NUM; i++) {
+               struct phy *phy = devm_phy_create(dev, NULL,
+                                                 &exynos_usbdrd_phy_ops);
+               if (IS_ERR(phy)) {
+                       dev_err(dev, "Failed to create usbdrd_phy phy\n");
+                       goto err1;
+               }
+
+               phy_drd->phys[i].phy = phy;
+               phy_drd->phys[i].index = i;
+               phy_drd->phys[i].reg_pmu = reg_pmu_delayed = reg_pmu;
+               phy_drd->phys[i].pmu_offset = pmu_offset_delayed = pmu_offset;
+               phy_drd->phys[i].pmu_offset_dp =
+                       pmu_offset_dp_delayed = pmu_offset_dp;
+               phy_drd->phys[i].pmu_mask = pmu_mask;
+               phy_drd->phys[i].phy_cfg = &drv_data->phy_cfg[i];
+               phy_set_drvdata(phy, &phy_drd->phys[i]);
+       }
+#if IS_ENABLED(CONFIG_PHY_EXYNOS_DEBUGFS)
+       ret = exynos_usbdrd_debugfs_init(phy_drd);
+       if (ret) {
+               dev_err(dev, "Failed to initialize debugfs\n");
+               goto err1;
+       }
+#endif
+
+#if IS_ENABLED(CONFIG_PHY_EXYNOS_DP_DEBUGFS)
+       ret = exynos_usbdrd_dp_debugfs_init(phy_drd);
+       if (ret) {
+               dev_err(dev, "Failed to initialize dp debugfs\n");
+               goto err1;
+       }
+#endif
+
+       phy_provider = devm_of_phy_provider_register(dev,
+                                                    exynos_usbdrd_phy_xlate);
+       if (IS_ERR(phy_provider)) {
+               dev_err(phy_drd->dev, "Failed to register phy provider\n");
+               goto err1;
+       }
+
+       phy_drd->is_irq_enabled = 0;
+
+       pr_info("%s: ---\n", __func__);
+       return 0;
+err1:
+       exynos_usbdrd_clk_unprepare(phy_drd);
+
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static int exynos_usbdrd_phy_resume(struct device *dev)
+{
+       int ret;
+       struct exynos_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
+
+       /*
+        * There is issue, when USB3.0 PHY is in active state
+        * after resume. This leads to increased power consumption
+        * if no USB drivers use the PHY.
+        *
+        * The following code shutdowns the PHY, so it is in defined
+        * state (OFF) after resume. If any USB driver already got
+        * the PHY at this time, we do nothing and just exit.
+        */
+
+       dev_info(dev, "%s\n", __func__);
+
+       if (!phy_drd->is_conn) {
+               dev_info(dev, "USB wasn't connected\n");
+               ret = exynos_usbdrd_clk_enable(phy_drd, false);
+               if (ret) {
+                       dev_err(phy_drd->dev, "%s: Failed to enable clk\n", __func__);
+                       return ret;
+               }
+
+               __exynos_usbdrd_phy_shutdown(phy_drd);
+
+               exynos_usbdrd_clk_disable(phy_drd, false);
+       } else {
+               dev_info(dev, "USB was connected\n");
+       }
+
+       return 0;
+}
+
+static const struct dev_pm_ops exynos_usbdrd_phy_dev_pm_ops = {
+       .resume = exynos_usbdrd_phy_resume,
+};
+
+#define EXYNOS_USBDRD_PHY_PM_OPS       &(exynos_usbdrd_phy_dev_pm_ops)
+#else
+#define EXYNOS_USBDRD_PHY_PM_OPS       NULL
+#endif
+
+static struct platform_driver phy_exynos_usbdrd = {
+       .probe  = exynos_usbdrd_phy_probe,
+       .driver = {
+               .of_match_table = exynos_usbdrd_phy_of_match,
+               .name           = "phy_exynos_usbdrd",
+               .pm             = EXYNOS_USBDRD_PHY_PM_OPS,
+       }
+};
+
+module_platform_driver(phy_exynos_usbdrd);
+MODULE_DESCRIPTION("Samsung EXYNOS SoCs USB DRD controller PHY driver");
+MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:phy_exynos_usbdrd");
diff --git a/drivers/phy/samsung/phy-exynos-usbdrd.h b/drivers/phy/samsung/phy-exynos-usbdrd.h
new file mode 100644 (file)
index 0000000..bbe4ed3
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PHY_EXYNOS_USBDRD_H__
+#define __PHY_EXYNOS_USBDRD_H__
+
+#include "phy-samsung-usb-cal.h"
+#include "phy-exynos-usb3p1.h"
+#include "phy-exynos-usbdp.h"
+
+#define EXYNOS_USBPHY_VER_02_0_0       0x0200  /* Lhotse - USBDP Combo PHY */
+
+/* 9810 PMU register offset */
+#define EXYNOS_USBDP_PHY_CONTROL       (0x704)
+#define EXYNOS_USB2_PHY_CONTROL        (0x72C)
+/* PMU register offset for USB */
+#define EXYNOS_USBDEV_PHY_CONTROL      (0x704)
+#define EXYNOS_USBDRD_ENABLE           BIT(0)
+#define EXYNOS_USBHOST_ENABLE          BIT(1)
+/* enables TCXO_USB. 1:enable TCXO */
+#define ENABLE_TCXO_BUF_MASK           (0x10000)
+
+/* Exynos USB PHY registers */
+#define EXYNOS_FSEL_9MHZ6              0x0
+#define EXYNOS_FSEL_10MHZ              0x1
+#define EXYNOS_FSEL_12MHZ              0x2
+#define EXYNOS_FSEL_19MHZ2             0x3
+#define EXYNOS_FSEL_20MHZ              0x4
+#define EXYNOS_FSEL_24MHZ              0x5
+#define EXYNOS_FSEL_26MHZ              0x82
+#define EXYNOS_FSEL_50MHZ              0x7
+
+/* EXYNOS: USB DRD PHY registers */
+#define EXYNOS_DRD_LINKSYSTEM                  0x04
+
+#define LINKSYSTEM_FLADJ_MASK                  (0x3f << 1)
+#define LINKSYSTEM_FLADJ(_x)                   ((_x) << 1)
+
+#define EXYNOS_DRD_PHYUTMI                     0x08
+
+#define EXYNOS_DRD_PHYPIPE                     0x0c
+
+#define PHYPIPE_PHY_CLOCK_SEL                          (0x1 << 4)
+
+#define EXYNOS_DRD_PHYCLKRST                   0x10
+
+#define PHYCLKRST_SSC_REFCLKSEL_MASK           (0xff << 23)
+#define PHYCLKRST_SSC_REFCLKSEL(_x)            ((_x) << 23)
+
+#define PHYCLKRST_SSC_RANGE_MASK               (0x03 << 21)
+#define PHYCLKRST_SSC_RANGE(_x)                        ((_x) << 21)
+
+#define PHYCLKRST_MPLL_MULTIPLIER_MASK         (0x7f << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF   (0x19 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF      (0x32 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF    (0x68 << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF    (0x7d << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11)
+
+#define PHYCLKRST_FSEL_UTMI_MASK               (0x7 << 5)
+#define PHYCLKRST_FSEL_PIPE_MASK               (0x7 << 8)
+#define PHYCLKRST_FSEL(_x)                     ((_x) << 5)
+#define PHYCLKRST_FSEL_PAD_100MHZ              (0x27 << 5)
+#define PHYCLKRST_FSEL_PAD_24MHZ               (0x2a << 5)
+#define PHYCLKRST_FSEL_PAD_20MHZ               (0x31 << 5)
+#define PHYCLKRST_FSEL_PAD_19_2MHZ             (0x38 << 5)
+
+#define PHYCLKRST_REFCLKSEL_MASK               (0x03 << 2)
+#define PHYCLKRST_REFCLKSEL_PAD_REFCLK         (0x2 << 2)
+#define PHYCLKRST_REFCLKSEL_EXT_REFCLK         (0x3 << 2)
+
+#define EXYNOS_DRD_PHYREG0                     0x14
+#define EXYNOS_DRD_PHYREG1                     0x18
+
+#define EXYNOS_DRD_PHYPARAM0                   0x1c
+
+#define PHYPARAM0_REF_LOSLEVEL_MASK            (0x1f << 26)
+#define PHYPARAM0_REF_LOSLEVEL                 (0x9 << 26)
+
+#define EXYNOS_DRD_PHYPARAM1                   0x20
+
+#define PHYPARAM1_PCS_TXDEEMPH_MASK            (0x1f << 0)
+#define PHYPARAM1_PCS_TXDEEMPH                 (0x1c)
+
+#define EXYNOS_DRD_PHYTERM                     0x24
+
+#define EXYNOS_DRD_PHYTEST                     0x28
+
+#define EXYNOS_DRD_PHYADP                      0x2c
+
+#define EXYNOS_DRD_PHYUTMICLKSEL               0x30
+
+#define PHYUTMICLKSEL_UTMI_CLKSEL              BIT(2)
+
+#define EXYNOS_DRD_PHYRESUME                   0x34
+#define EXYNOS_DRD_LINKPORT                    0x44
+
+#define KHZ    1000
+#define MHZ    (KHZ * KHZ)
+
+#define EXYNOS_DRD_MAX_TUNEPARAM_NUM           32
+
+enum exynos_usbdrd_phy_id {
+       EXYNOS_DRDPHY_UTMI,
+       EXYNOS_DRDPHY_PIPE3,
+       EXYNOS_DRDPHYS_NUM,
+};
+
+struct phy_usb_instance;
+struct exynos_usbdrd_phy;
+
+struct exynos_usbdrd_phy_config {
+       u32 id;
+       void (*phy_isol)(struct phy_usb_instance *inst, u32 on, unsigned int);
+       void (*phy_init)(struct exynos_usbdrd_phy *phy_drd);
+       void (*phy_exit)(struct exynos_usbdrd_phy *phy_drd);
+       void (*phy_tune)(struct exynos_usbdrd_phy *phy_drd, int);
+       int (*phy_vendor_set)(struct exynos_usbdrd_phy *phy_drd, int, int);
+       void (*phy_ilbk)(struct exynos_usbdrd_phy *phy_drd);
+       void (*phy_set)(struct exynos_usbdrd_phy *phy_drd, int, void *);
+       unsigned int (*set_refclk)(struct phy_usb_instance *inst);
+};
+
+struct exynos_usbdrd_phy_drvdata {
+       const struct exynos_usbdrd_phy_config *phy_cfg;
+};
+
+/**
+ * struct exynos_usbdrd_phy - driver data for USB DRD PHY
+ * @dev: pointer to device instance of this platform device
+ * @reg_phy: usb phy controller register memory base
+ * @clk: phy clock for register access
+ * @drv_data: pointer to SoC level driver data structure
+ * @phys[]: array for 'EXYNOS_DRDPHYS_NUM' number of PHY
+ *         instances each with its 'phy' and 'phy_cfg'.
+ * @extrefclk: frequency select settings when using 'separate
+ *            reference clocks' for SS and HS operations
+ * @ref_clk: reference clock to PHY block from which PHY's
+ *          operational clocks are derived
+ * @usbphy_info; Phy main control info
+ * @usbphy_sub_info; USB3.0 phy control info
+ */
+struct exynos_usbdrd_phy {
+       struct device *dev;
+       void __iomem *reg_phy;
+       void __iomem *reg_phy2;
+       void __iomem *reg_phy3;
+       struct clk **clocks;
+       struct clk **phy_clocks;
+       const struct exynos_usbdrd_phy_drvdata *drv_data;
+       struct phy_usb_instance {
+               struct phy *phy;
+               u32 index;
+               struct regmap *reg_pmu;
+               u32 pmu_offset;
+               u32 pmu_offset_dp;
+               u32 pmu_mask;
+               const struct exynos_usbdrd_phy_config *phy_cfg;
+       } phys[EXYNOS_DRDPHYS_NUM];
+       u32 extrefclk;
+       bool use_phy_umux;
+       struct clk *ref_clk;
+       struct regulator *vbus;
+       struct exynos_usbphy_info usbphy_info;
+       struct exynos_usbphy_info usbphy_sub_info;
+       struct exynos_usbphy_ss_tune ss_value[2];
+       struct exynos_usbphy_hs_tune hs_value[2];
+       int hs_tune_param_value[EXYNOS_DRD_MAX_TUNEPARAM_NUM][2];
+       int ss_tune_param_value[EXYNOS_DRD_MAX_TUNEPARAM_NUM][2];
+
+       u32 ip_type;
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+#define OTP_SUPPORT_USBPHY_NUMBER      2
+#define OTP_USB3PHY_INDEX              0
+#define OTP_USB2PHY_INDEX              1
+       u8 otp_type[OTP_SUPPORT_USBPHY_NUMBER];
+       u8 otp_index[OTP_SUPPORT_USBPHY_NUMBER];
+       struct tune_bits *otp_data[OTP_SUPPORT_USBPHY_NUMBER];
+#endif
+       int irq_wakeup;
+       int irq_conn;
+       int is_conn;
+       int is_irq_enabled;
+       u32 phy_port;
+};
+
+void __iomem *phy_exynos_usbdp_get_address(void);
+extern int xhci_portsc_set(int on);
+
+#endif /* __PHY_EXYNOS_USBDRD_H__ */
diff --git a/drivers/phy/samsung/phy-exynos-usbdrd3.c b/drivers/phy/samsung/phy-exynos-usbdrd3.c
new file mode 100644 (file)
index 0000000..5ab61ef
--- /dev/null
@@ -0,0 +1,1644 @@
+/*
+ * Samsung EXYNOS SoC series USB DRD PHY driver
+ *
+ * Phy provider for USB 3.0 DRD controller on Exynos SoC series
+ *
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd.
+ * Author: Vivek Gautam <gautam.vivek@samsung.com>
+ *        Minho Lee <minho55.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/exynos5-pmu.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/samsung_usb.h>
+#include <linux/usb/otg.h>
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+#include <linux/exynos_otp.h>
+#endif
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+
+#include "phy-exynos-usbdrd.h"
+#include "phy-exynos-debug.h"
+/*
+extern int sm5713_get_usb_connect(void);
+*/
+
+static void exynos_usbdrd_check_connection(struct exynos_usbdrd_phy *phy_drd)
+{
+#if 0
+       int usb_side;
+
+       usb_side = sm5713_get_usb_connect();
+       dev_info(phy_drd->dev, "USB is plugged in %d side...\n", usb_side);
+
+       if (usb_side == 1) /* front */
+               phy_drd->usbphy_info.used_phy_port = 0;
+       else if (usb_side == 0)
+               phy_drd->usbphy_info.used_phy_port = 1;
+#endif
+}
+
+static int exynos_usbdrd_clk_prepare(struct exynos_usbdrd_phy *phy_drd)
+{
+       int i;
+       int ret;
+
+       for (i = 0; phy_drd->clocks[i] != NULL; i++) {
+               ret = clk_prepare(phy_drd->clocks[i]);
+               if (ret)
+                       goto err;
+       }
+
+       if (phy_drd->use_phy_umux) {
+               for (i = 0; phy_drd->phy_clocks[i] != NULL; i++) {
+                       ret = clk_prepare(phy_drd->phy_clocks[i]);
+                       if (ret)
+                               goto err1;
+               }
+       }
+       return 0;
+
+err1:
+       for (i = i - 1; i >= 0; i--)
+               clk_unprepare(phy_drd->phy_clocks[i]);
+err:
+       for (i = i - 1; i >= 0; i--)
+               clk_unprepare(phy_drd->clocks[i]);
+       return ret;
+}
+
+static int exynos_usbdrd_clk_enable(struct exynos_usbdrd_phy *phy_drd,
+                                       bool umux)
+{
+       int i;
+       int ret;
+
+#ifdef CONFIG_SOC_EXYNOS7885
+       clk_set_rate(phy_drd->ref_clk, 50 * 1000000);
+#endif
+
+       if (!phy_drd->use_phy_umux) {
+               for (i = 0; phy_drd->clocks[i] != NULL; i++) {
+                       ret = clk_enable(phy_drd->clocks[i]);
+                       if (ret)
+                               goto err;
+               }
+       } else {
+               for (i = 0; phy_drd->phy_clocks[i] != NULL; i++) {
+                       ret = clk_enable(phy_drd->phy_clocks[i]);
+                       if (ret)
+                               goto err1;
+                       }
+       }
+       return 0;
+
+err1:
+       for (i = i - 1; i >= 0; i--)
+               clk_disable(phy_drd->phy_clocks[i]);
+       return ret;
+err:
+       for (i = i - 1; i >= 0; i--)
+               clk_disable(phy_drd->clocks[i]);
+       return ret;
+}
+
+static void exynos_usbdrd_clk_unprepare(struct exynos_usbdrd_phy *phy_drd)
+{
+       int i;
+
+       for (i = 0; phy_drd->clocks[i] != NULL; i++)
+               clk_unprepare(phy_drd->clocks[i]);
+       for (i = 0; phy_drd->phy_clocks[i] != NULL; i++)
+               clk_unprepare(phy_drd->phy_clocks[i]);
+}
+
+static void exynos_usbdrd_clk_disable(struct exynos_usbdrd_phy *phy_drd, bool umux)
+{
+       int i;
+
+       if (!umux) {
+               for (i = 0; phy_drd->clocks[i] != NULL; i++)
+                       clk_disable(phy_drd->clocks[i]);
+       } else {
+               for (i = 0; phy_drd->phy_clocks[i] != NULL; i++)
+                       clk_disable(phy_drd->phy_clocks[i]);
+       }
+}
+static int exynos_usbdrd_phyclk_get(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       const char      **phyclk_ids;
+       const char      **clk_ids;
+       const char      *refclk_name;
+       struct clk      *clk;
+       int             phyclk_count;
+       int             clk_count;
+       bool            is_phyclk = false;
+       int             clk_index = 0;
+       int             i, j, ret;
+
+       phyclk_count = of_property_count_strings(dev->of_node, "phyclk_mux");
+       if (IS_ERR_VALUE((unsigned long)phyclk_count)) {
+               dev_err(dev, "invalid phyclk list in %s node\n",
+                                                       dev->of_node->name);
+               return -EINVAL;
+       }
+
+       phyclk_ids = (const char **)devm_kmalloc(dev,
+                                       (phyclk_count+1) * sizeof(const char *),
+                                       GFP_KERNEL);
+       for (i = 0; i < phyclk_count; i++) {
+               ret = of_property_read_string_index(dev->of_node,
+                                               "phyclk_mux", i, &phyclk_ids[i]);
+               if (ret) {
+                       dev_err(dev, "failed to read phyclk_mux name %d from %s node\n",
+                                       i, dev->of_node->name);
+                       return ret;
+               }
+       }
+       phyclk_ids[phyclk_count] = NULL;
+
+       if (!strcmp("none", phyclk_ids[0])) {
+               dev_info(dev, "don't need user Mux for phyclk\n");
+               phy_drd->use_phy_umux = false;
+               phyclk_count = 0;
+
+       } else {
+               phy_drd->use_phy_umux = true;
+
+               phy_drd->phy_clocks = (struct clk **) devm_kmalloc(dev,
+                               (phyclk_count+1) * sizeof(struct clk *),
+                               GFP_KERNEL);
+               if (!phy_drd->phy_clocks) {
+                       dev_err(dev, "failed to alloc : phy clocks\n");
+                       return -ENOMEM;
+               }
+
+               for (i = 0; phyclk_ids[i] != NULL; i++) {
+                       clk = devm_clk_get(dev, phyclk_ids[i]);
+                       if (IS_ERR_OR_NULL(clk)) {
+                               dev_err(dev, "couldn't get %s clock\n", phyclk_ids[i]);
+                               return -EINVAL;
+                       }
+                       phy_drd->phy_clocks[i] = clk;
+               }
+
+               phy_drd->phy_clocks[i] = NULL;
+       }
+
+       clk_count = of_property_count_strings(dev->of_node, "clock-names");
+       if (IS_ERR_VALUE((unsigned long)clk_count)) {
+               dev_err(dev, "invalid clk list in %s node", dev->of_node->name);
+               return -EINVAL;
+       }
+       clk_ids = (const char **)devm_kmalloc(dev,
+                               (clk_count + 1) * sizeof(const char *),
+                               GFP_KERNEL);
+       for (i = 0; i < clk_count; i++) {
+               ret = of_property_read_string_index(dev->of_node, "clock-names",
+                                                               i, &clk_ids[i]);
+               if (ret) {
+                       dev_err(dev, "failed to read clocks name %d from %s node\n",
+                                       i, dev->of_node->name);
+                       return ret;
+               }
+       }
+       clk_ids[clk_count] = NULL;
+
+       phy_drd->clocks = (struct clk **) devm_kmalloc(dev,
+                               (clk_count + 1) * sizeof(struct clk *), GFP_KERNEL);
+       if (!phy_drd->clocks) {
+               dev_err(dev, "failed to alloc for clocks\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; clk_ids[i] != NULL; i++) {
+               if (phyclk_count) {
+                       for (j = 0; phyclk_ids[j] != NULL; j++) {
+                               if (!strcmp(phyclk_ids[j], clk_ids[i])) {
+                                       is_phyclk = true;
+                                       phyclk_count--;
+                               }
+                       }
+               }
+               if (!is_phyclk) {
+                       clk = devm_clk_get(dev, clk_ids[i]);
+                       if (IS_ERR_OR_NULL(clk)) {
+                               dev_err(dev, "couldn't get %s clock\n", clk_ids[i]);
+                               return -EINVAL;
+                       }
+                       phy_drd->clocks[clk_index] = clk;
+                       clk_index++;
+               }
+               is_phyclk = false;
+       }
+       phy_drd->clocks[clk_index] = NULL;
+
+       ret = of_property_read_string_index(dev->of_node,
+                                               "phy_refclk", 0, &refclk_name);
+       if (ret) {
+               dev_err(dev, "failed to read ref_clocks name from %s node\n",
+                               dev->of_node->name);
+               return ret;
+       }
+
+       if (!strcmp("none", refclk_name)) {
+               dev_err(dev, "phy reference clock shouldn't be omitted");
+               return -EINVAL;
+       }
+
+       for (i = 0; clk_ids[i] != NULL; i++) {
+               if (!strcmp(clk_ids[i], refclk_name)) {
+                       phy_drd->ref_clk = devm_clk_get(dev, refclk_name);
+                       break;
+               }
+       }
+
+       if (IS_ERR_OR_NULL(phy_drd->ref_clk)) {
+               dev_err(dev, "%s couldn't get ref_clk", __func__);
+               return -EINVAL;
+       }
+
+       devm_kfree(dev, phyclk_ids);
+       devm_kfree(dev, clk_ids);
+
+       return 0;
+
+}
+
+static int exynos_usbdrd_clk_get(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       int             ret;
+
+       ret = exynos_usbdrd_phyclk_get(phy_drd);
+       if (ret < 0) {
+               dev_err(dev, "failed to get clock for DRD USBPHY");
+               return ret;
+       }
+
+       return 0;
+}
+
+static inline
+struct exynos_usbdrd_phy *to_usbdrd_phy(struct phy_usb_instance *inst)
+{
+       return container_of((inst), struct exynos_usbdrd_phy,
+                           phys[(inst)->index]);
+}
+
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+void exynos_usbdrd_phy_get_otp_info(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct tune_bits *data;
+       u16 magic;
+       u8 type;
+       u8 index_count;
+       u8 i, j;
+
+       phy_drd->otp_index[0] = phy_drd->otp_index[1] = 0;
+
+       for (i = 0; i < OTP_SUPPORT_USBPHY_NUMBER; i++) {
+               magic = i ? OTP_MAGIC_USB2 : OTP_MAGIC_USB3;
+
+               if (otp_tune_bits_parsed(magic, &type, &index_count, &data)) {
+                       dev_err(phy_drd->dev, "%s failed to get usb%d otp\n",
+                               __func__, i ? 2 : 3);
+                       continue;
+               }
+               dev_info(phy_drd->dev, "usb[%d] otp index_count: %d\n",
+                                                               i, index_count);
+
+               if (!index_count) {
+                       phy_drd->otp_data[i] = NULL;
+                       continue;
+               }
+
+               phy_drd->otp_data[i] = devm_kzalloc(phy_drd->dev,
+                       sizeof(*data) * index_count, GFP_KERNEL);
+               if (!phy_drd->otp_data[i])
+                       continue;
+
+               phy_drd->otp_index[i] = index_count;
+               phy_drd->otp_type[i] = type ? 4 : 1;
+               dev_info(phy_drd->dev, "usb[%d] otp type: %d\n", i, type);
+
+               for (j = 0; j < index_count; j++) {
+                       phy_drd->otp_data[i][j].index = data[j].index;
+                       phy_drd->otp_data[i][j].value = data[j].value;
+                       dev_dbg(phy_drd->dev,
+                               "usb[%d][%d] otp_data index:%d, value:0x%08x\n",
+                                       i, j, phy_drd->otp_data[i][j].index,
+                                       phy_drd->otp_data[i][j].value);
+               }
+       }
+}
+#endif
+
+/*
+ * exynos_rate_to_clk() converts the supplied clock rate to the value that
+ * can be written to the phy register.
+ */
+static unsigned int exynos_rate_to_clk(struct exynos_usbdrd_phy *phy_drd)
+{
+       int ret;
+
+#ifdef CONFIG_SOC_EXYNOS7885
+       clk_set_rate(phy_drd->ref_clk, 50 * 1000000);
+#endif
+
+       ret = clk_prepare_enable(phy_drd->ref_clk);
+       if (ret) {
+               dev_err(phy_drd->dev, "%s failed to enable ref_clk", __func__);
+               return 0;
+       }
+
+       /* EXYNOS_FSEL_MASK */
+       switch (clk_get_rate(phy_drd->ref_clk)) {
+       case 9600 * KHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_9MHZ6;
+               break;
+       case 10 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_10MHZ;
+               break;
+       case 12 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_12MHZ;
+               break;
+       case 19200 * KHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_19MHZ2;
+               break;
+       case 20 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_20MHZ;
+               break;
+       case 24 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_24MHZ;
+               break;
+       case 26 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_26MHZ;
+               break;
+       case 50 * MHZ:
+               phy_drd->extrefclk = EXYNOS_FSEL_50MHZ;
+               break;
+       default:
+               phy_drd->extrefclk = 0;
+               clk_disable_unprepare(phy_drd->ref_clk);
+               return -EINVAL;
+       }
+
+       clk_disable_unprepare(phy_drd->ref_clk);
+
+       return 0;
+}
+
+
+static void exynos_usbdrd_usb_txco_enable(struct phy_usb_instance *inst, int on)
+{
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+       void __iomem *base;
+       u32     reg;
+
+       base = ioremap(0x11860000, 0x100000);
+       reg = readl(base + EXYNOS_USBDEV_PHY_CONTROL);
+
+       dev_info(phy_drd->dev, "[%s] ++USB DEVCTRL reg 0x%x \n",
+                                                       __func__, reg);
+
+       if (!on) {
+               reg |= ENABLE_TCXO_BUF_MASK;
+       } else {
+               reg &= ~ENABLE_TCXO_BUF_MASK;
+       }
+       writel(reg, base + EXYNOS_USBDEV_PHY_CONTROL);
+
+       reg = readl(base + EXYNOS_USBDEV_PHY_CONTROL);
+       dev_info(phy_drd->dev, "[%s] --USB DEVCTRL reg 0x%x \n",
+                                                       __func__, reg);
+}
+
+static void exynos_usbdrd_pipe3_phy_isol(struct phy_usb_instance *inst,
+                                       unsigned int on, unsigned int mask)
+{
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+       unsigned int val;
+
+       if (!inst->reg_pmu)
+               return;
+
+       val = on ? 0 : mask;
+
+       dev_info(phy_drd->dev, "[%s] val : 0x%x / mask : 0x%x \n",
+                                                       __func__, val, mask);
+       regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
+                          mask, val);
+
+       /* Enable TCXO_USB */
+       val = on ? 0 : ENABLE_TCXO_BUF_MASK;
+       regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
+                          ENABLE_TCXO_BUF_MASK, val);
+
+       /* exynos_usbdrd_usb_txco_enable(inst, on); */
+}
+
+static void exynos_usbdrd_utmi_phy_isol(struct phy_usb_instance *inst,
+                                       unsigned int on, unsigned int mask)
+{
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+       unsigned int val;
+
+       if (!inst->reg_pmu)
+               return;
+
+       val = on ? 0 : mask;
+
+       dev_info(phy_drd->dev, "[%s] val : 0x%x / mask : 0x%x \n",
+                                               __func__, val, mask);
+       regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
+                          mask, val);
+
+       exynos_usbdrd_usb_txco_enable(inst, on);
+}
+
+/*
+ * Sets the pipe3 phy's clk as EXTREFCLK (XXTI) which is internal clock
+ * from clock core. Further sets multiplier values and spread spectrum
+ * clock settings for SuperSpeed operations.
+ */
+static unsigned int
+exynos_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst)
+{
+       return 0;
+}
+
+/*
+ * Sets the utmi phy's clk as EXTREFCLK (XXTI) which is internal clock
+ * from clock core. Further sets the FSEL values for HighSpeed operations.
+ */
+static unsigned int
+exynos_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst)
+{
+       static u32 reg;
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+       /* PHYCLKRST setting isn't required in Combo PHY */
+       if (phy_drd->usbphy_info.version >= EXYNOS_USBPHY_VER_02_0_0)
+               return -EINVAL;
+
+       /* restore any previous reference clock settings */
+       reg = readl(phy_drd->reg_phy + EXYNOS_DRD_PHYCLKRST);
+
+       reg &= ~PHYCLKRST_REFCLKSEL_MASK;
+       reg |=  PHYCLKRST_REFCLKSEL_EXT_REFCLK;
+
+       reg &= ~PHYCLKRST_FSEL_UTMI_MASK |
+               PHYCLKRST_MPLL_MULTIPLIER_MASK |
+               PHYCLKRST_SSC_REFCLKSEL_MASK;
+       reg |= PHYCLKRST_FSEL(phy_drd->extrefclk);
+
+       return reg;
+}
+
+#ifdef OLD_FASHIONED_PHY_TUNE
+/*
+ * Sets the default PHY tuning values for high-speed connection.
+ */
+static int exynos_usbdrd_fill_hstune(struct exynos_usbdrd_phy *phy_drd,
+                               struct device_node *node)
+{
+       struct device *dev = phy_drd->dev;
+       struct exynos_usbphy_hs_tune *hs_tune = phy_drd->hs_value;
+       int ret;
+       u32 res[2];
+       u32 value;
+
+       ret = of_property_read_u32_array(node, "tx_vref", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_vref = res[0];
+               hs_tune[1].tx_vref = res[1];
+       } else {
+               dev_err(dev, "can't get tx_vref value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_pre_emp", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_pre_emp = res[0];
+               hs_tune[1].tx_pre_emp = res[1];
+       } else {
+               dev_err(dev, "can't get tx_pre_emp value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_pre_emp_puls", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_pre_emp_puls = res[0];
+               hs_tune[1].tx_pre_emp_puls = res[1];
+       } else {
+               dev_err(dev, "can't get tx_pre_emp_puls value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_res", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_res = res[0];
+               hs_tune[1].tx_res = res[1];
+       } else {
+               dev_err(dev, "can't get tx_res value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_rise", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_rise = res[0];
+               hs_tune[1].tx_rise = res[1];
+       } else {
+               dev_err(dev, "can't get tx_rise value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_hsxv", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_hsxv = res[0];
+               hs_tune[1].tx_hsxv = res[1];
+       } else {
+               dev_err(dev, "can't get tx_hsxv value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_fsls", res, 2);
+       if (ret == 0) {
+               hs_tune[0].tx_fsls = res[0];
+               hs_tune[1].tx_fsls = res[1];
+       } else {
+               dev_err(dev, "can't get tx_fsls value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "rx_sqrx", res, 2);
+       if (ret == 0) {
+               hs_tune[0].rx_sqrx = res[0];
+               hs_tune[1].rx_sqrx = res[1];
+       } else {
+               dev_err(dev, "can't get tx_sqrx value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "compdis", res, 2);
+       if (ret == 0) {
+               hs_tune[0].compdis = res[0];
+               hs_tune[1].compdis = res[1];
+       } else {
+               dev_err(dev, "can't get compdis value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "otg", res, 2);
+       if (ret == 0) {
+               hs_tune[0].otg = res[0];
+               hs_tune[1].otg = res[1];
+       } else {
+               dev_err(dev, "can't get otg_tune value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "enable_user_imp", res, 2);
+       if (ret == 0) {
+               if (res[0]) {
+                       hs_tune[0].enable_user_imp = true;
+                       hs_tune[1].enable_user_imp = true;
+                       hs_tune[0].user_imp_value = res[1];
+                       hs_tune[1].user_imp_value = res[1];
+               } else {
+                       hs_tune[0].enable_user_imp = false;
+                       hs_tune[1].enable_user_imp = false;
+               }
+       } else {
+               dev_err(dev, "can't get enable_user_imp value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32(node, "is_phyclock", &value);
+       if (ret == 0) {
+               if (value == 1) {
+                       hs_tune[0].utmi_clk = USBPHY_UTMI_PHYCLOCK;
+                       hs_tune[1].utmi_clk = USBPHY_UTMI_PHYCLOCK;
+               } else {
+                       hs_tune[0].utmi_clk = USBPHY_UTMI_FREECLOCK;
+                       hs_tune[1].utmi_clk = USBPHY_UTMI_FREECLOCK;
+               }
+       } else {
+               dev_err(dev, "can't get is_phyclock value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Sets the default PHY tuning values for super-speed connection.
+ */
+static int exynos_usbdrd_fill_sstune(struct exynos_usbdrd_phy *phy_drd,
+                                                       struct device_node *node)
+{
+       struct device *dev = phy_drd->dev;
+       struct exynos_usbphy_ss_tune *ss_tune = phy_drd->ss_value;
+       u32 res[2];
+       int ret;
+
+       ret = of_property_read_u32_array(node, "tx_boost_level", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_boost_level = res[0];
+               ss_tune[1].tx_boost_level = res[1];
+       } else {
+               dev_err(dev, "can't get tx_boost_level value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_swing_level", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_swing_level = res[0];
+               ss_tune[1].tx_swing_level = res[1];
+       } else {
+               dev_err(dev, "can't get tx_swing_level value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_swing_full", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_swing_full = res[0];
+               ss_tune[1].tx_swing_full = res[1];
+       } else {
+               dev_err(dev, "can't get tx_swing_full value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_swing_low", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_swing_low = res[0];
+               ss_tune[1].tx_swing_low = res[1];
+       } else {
+               dev_err(dev, "can't get tx_swing_low value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_deemphasis_mode", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_deemphasis_mode = res[0];
+               ss_tune[1].tx_deemphasis_mode = res[1];
+       } else {
+               dev_err(dev, "can't get tx_deemphasis_mode value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_deemphasis_3p5db", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_deemphasis_3p5db = res[0];
+               ss_tune[1].tx_deemphasis_3p5db = res[1];
+       } else {
+               dev_err(dev, "can't get tx_deemphasis_3p5db value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "tx_deemphasis_6db", res, 2);
+       if (ret == 0) {
+               ss_tune[0].tx_deemphasis_6db = res[0];
+               ss_tune[1].tx_deemphasis_6db = res[1];
+       } else {
+               dev_err(dev, "can't get tx_deemphasis_6db value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "enable_ssc", res, 2);
+       if (ret == 0) {
+               ss_tune[0].enable_ssc = res[0];
+               ss_tune[1].enable_ssc = res[1];
+       } else {
+               dev_err(dev, "can't get enable_ssc value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "ssc_range", res, 2);
+       if (ret == 0) {
+               ss_tune[0].ssc_range = res[0];
+               ss_tune[1].ssc_range = res[1];
+       } else {
+               dev_err(dev, "can't get ssc_range value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "los_bias", res, 2);
+       if (ret == 0) {
+               ss_tune[0].los_bias = res[0];
+               ss_tune[1].los_bias = res[1];
+       } else {
+               dev_err(dev, "can't get los_bias value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "los_mask_val", res, 2);
+       if (ret == 0) {
+               ss_tune[0].los_mask_val = res[0];
+               ss_tune[1].los_mask_val = res[1];
+       } else {
+               dev_err(dev, "can't get los_mask_val value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "enable_fixed_rxeq_mode", res, 2);
+       if (ret == 0) {
+               ss_tune[0].enable_fixed_rxeq_mode = res[0];
+               ss_tune[1].enable_fixed_rxeq_mode = res[1];
+       } else {
+               dev_err(dev, "can't get enable_fixed_rxeq_mode value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "fix_rxeq_value", res, 2);
+       if (ret == 0) {
+               ss_tune[0].fix_rxeq_value = res[0];
+               ss_tune[1].fix_rxeq_value = res[1];
+       } else {
+               dev_err(dev, "can't get fix_rxeq_value value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "set_crport_level_en", res, 2);
+       if (ret == 0) {
+               ss_tune[0].set_crport_level_en = res[0];
+               ss_tune[1].set_crport_level_en = res[1];
+       } else {
+               dev_err(dev, "can't get set_crport_level_en value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(node, "set_crport_mpll_charge_pump", res, 2);
+       if (ret == 0) {
+               ss_tune[0].set_crport_mpll_charge_pump = res[0];
+               ss_tune[1].set_crport_mpll_charge_pump = res[1];
+       } else {
+               dev_err(dev, "can't get set_crport_mpll_charge_pump value, error = %d\n", ret);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+#endif
+
+static int exynos_usbdrd_fill_hstune_param(struct exynos_usbdrd_phy *phy_drd,
+                               struct device_node *node)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *child = NULL;
+       struct exynos_usb_tune_param *hs_tune_param;
+       size_t size = sizeof(struct exynos_usb_tune_param);
+       int ret;
+       u32 res[2];
+       u32 param_index = 0;
+       const char *name;
+
+       ret = of_property_read_u32_array(node, "hs_tune_cnt", &res[0], 1);
+
+       dev_info(dev, "%s hs tune cnt = %d\n", __func__, res[0]);
+
+       hs_tune_param = devm_kzalloc(dev, size*res[0], GFP_KERNEL);
+       phy_drd->usbphy_info.tune_param = hs_tune_param;
+
+       for_each_child_of_node(node, child) {
+               ret = of_property_read_string(child, "tune_name", &name);
+               if (ret == 0) {
+                       memcpy(hs_tune_param[param_index].name, name, strlen(name));
+               } else {
+                       dev_err(dev, "failed to read hs tune name from %s node\n", child->name);
+                       return ret;
+               }
+
+               ret = of_property_read_u32_array(child, "tune_value", res, 2);
+               if (ret == 0) {
+                       hs_tune_param[param_index].value = res[0];
+               } else {
+                       dev_err(dev, "failed to read hs tune value from %s node\n", child->name);
+                       return -EINVAL;
+               }
+               param_index++;
+       }
+
+       hs_tune_param[param_index].value = EXYNOS_USB_TUNE_LAST;
+
+       return 0;
+}
+
+/*
+ * Sets the default PHY tuning values for super-speed connection.
+ */
+static int exynos_usbdrd_fill_sstune_param(struct exynos_usbdrd_phy *phy_drd,
+                                                       struct device_node *node)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *child = NULL;
+       struct exynos_usb_tune_param *ss_tune_param;
+       size_t size = sizeof(struct exynos_usb_tune_param);
+       int ret;
+       u32 res[2];
+       u32 param_index = 0;
+       const char *name;
+
+       ret = of_property_read_u32_array(node, "ss_tune_cnt", &res[0], 1);
+
+       dev_info(dev, "%s ss tune cnt = %d\n", __func__, res[0]);
+
+       ss_tune_param = devm_kzalloc(dev, size*res[0], GFP_KERNEL);
+       phy_drd->usbphy_sub_info.tune_param = ss_tune_param;
+       for_each_child_of_node(node, child) {
+               ret = of_property_read_string(child, "tune_name", &name);
+               if (ret == 0)
+                       memcpy(ss_tune_param[param_index].name, name, strlen(name));
+               else {
+                       dev_err(dev, "failed to read ss tune name from %s node\n", child->name);
+                       return ret;
+               }
+
+               ret = of_property_read_u32_array(child, "tune_value", res, 2);
+               if (ret == 0) {
+                       ss_tune_param[param_index].value = res[0];
+               } else {
+                       dev_err(dev, "failed to read ss tune value from %s node\n", child->name);
+                       return -EINVAL;
+               }
+               param_index++;
+       }
+
+       ss_tune_param[param_index].value = EXYNOS_USB_TUNE_LAST;
+
+       return 0;
+}
+
+static int exynos_usbdrd_get_phy_refsel(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *node = dev->of_node;
+       int value, ret;
+       int check_flag = 0;
+
+       ret = of_property_read_u32(node, "phy_refsel_clockcore", &value);
+       if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_clockcore, error = %d\n", ret);
+               return ret;
+       }
+
+       if (value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_CLKCORE;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_CLKCORE;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_ext_osc", &value);
+       if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_ext_osc, error = %d\n", ret);
+               return ret;
+       }
+
+       if (value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_EXT_OSC;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_EXT_OSC;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_xtal", &value);
+       if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_xtal, error = %d\n", ret);
+               return ret;
+       }
+
+       if (value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_EXT_XTAL;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_EXT_XTAL;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_diff_pad", &value);
+       if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_diff_pad, error = %d\n", ret);
+               return ret;
+       }
+
+       if (value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_DIFF_PAD;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_DIFF_PAD;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_diff_internal", &value);
+       if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_diff_internal, error = %d\n", ret);
+               return ret;
+       }
+
+       if (value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_DIFF_INTERNAL;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_DIFF_INTERNAL;
+       } else {
+               check_flag++;
+       }
+
+       ret = of_property_read_u32(node, "phy_refsel_diff_single", &value);
+       if (ret < 0) {
+               dev_err(dev, "can't get phy_refsel_diff_single, error = %d\n", ret);
+               return ret;
+       }
+
+       if (value == 1) {
+               phy_drd->usbphy_info.refsel = USBPHY_REFSEL_DIFF_SINGLE;
+               phy_drd->usbphy_sub_info.refsel = USBPHY_REFSEL_DIFF_SINGLE;
+       } else {
+               check_flag++;
+       }
+
+       if (check_flag > 5) {
+               dev_err(dev, "USB refsel Must be choosed\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int exynos_usbdrd_get_sub_phyinfo(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *tune_node;
+       int ret;
+       int value;
+
+       if (!of_property_read_u32(dev->of_node, "sub_phy_version", &value)) {
+               phy_drd->usbphy_sub_info.version = value;
+       } else {
+               dev_err(dev, "can't get sub_phy_version\n");
+               return -EINVAL;
+       }
+       phy_drd->usbphy_sub_info.refclk = phy_drd->extrefclk;
+       phy_drd->usbphy_sub_info.regs_base = phy_drd->reg_phy2;
+       phy_drd->usbphy_sub_info.regs_base_2nd = phy_drd->reg_phy3;
+
+       /*
+        * use PHY of samsung
+        */
+       tune_node = of_parse_phandle(dev->of_node, "ss_tune_param", 0);
+       if (tune_node != NULL) {
+               ret = exynos_usbdrd_fill_sstune_param(phy_drd, tune_node);
+               if (ret < 0) {
+                       dev_err(dev, "can't fill super speed tuning param\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int exynos_usbdrd_get_phyinfo(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       struct device_node *tune_node;
+       int ret;
+       int value;
+
+       if (!of_property_read_u32(dev->of_node, "phy_version", &value)) {
+               phy_drd->usbphy_info.version = value;
+       } else {
+               dev_err(dev, "can't get phy_version\n");
+               return -EINVAL;
+       }
+
+       if (!of_property_read_u32(dev->of_node, "use_io_for_ovc", &value)) {
+               phy_drd->usbphy_info.use_io_for_ovc = value ? true : false;
+       } else {
+               dev_err(dev, "can't get io_for_ovc\n");
+               return -EINVAL;
+       }
+
+       if (!of_property_read_u32(dev->of_node, "common_block_disable", &value)) {
+               phy_drd->usbphy_info.common_block_disable = value ? true : false;
+       } else {
+               dev_err(dev, "can't get common_block_disable\n");
+               return -EINVAL;
+       }
+
+       phy_drd->usbphy_info.refclk = phy_drd->extrefclk;
+       phy_drd->usbphy_info.regs_base = phy_drd->reg_phy;
+
+       if (!of_property_read_u32(dev->of_node, "is_not_vbus_pad", &value)) {
+               phy_drd->usbphy_info.not_used_vbus_pad = value ? true : false;
+       } else {
+               dev_err(dev, "can't get vbus_pad\n");
+               return -EINVAL;
+       }
+       if (!of_property_read_u32(dev->of_node, "used_phy_port", &value)) {
+               phy_drd->usbphy_info.used_phy_port = value ? true : false;
+       } else {
+               dev_err(dev, "can't get used_phy_port\n");
+               return -EINVAL;
+       }
+
+       ret = exynos_usbdrd_get_phy_refsel(phy_drd);
+       if (ret < 0)
+               dev_err(dev, "can't get phy refsel\n");
+
+#ifdef OLD_FASHIONED_PHY_TUNE
+       /*
+        * use PHY of synopsys
+        */
+       tune_node = of_parse_phandle(dev->of_node, "ss_tune_info", 0);
+       if (tune_node == NULL)
+               dev_info(dev, "don't need usbphy tuning info for super speed\n");
+
+       if (of_device_is_available(tune_node)) {
+               ret = exynos_usbdrd_fill_sstune(phy_drd, tune_node);
+               if (ret < 0) {
+                       dev_err(dev, "can't fill super speed tuning info\n");
+                       return -EINVAL;
+               }
+       }
+
+       /*
+        * use PHY of synopsys
+        */
+       tune_node = of_parse_phandle(dev->of_node, "hs_tune_info", 0);
+       if (tune_node == NULL)
+               dev_info(dev, "don't need usbphy tuning info for high speed\n");
+
+       if (of_device_is_available(tune_node)) {
+               ret = exynos_usbdrd_fill_hstune(phy_drd, tune_node);
+               if (ret < 0) {
+                       dev_err(dev, "can't fill high speed tuning info\n");
+                       return -EINVAL;
+               }
+       }
+#endif
+
+       /*
+        * use PHY of synopsys
+        */
+       tune_node = of_parse_phandle(dev->of_node, "ss_tune_param", 0);
+       if (tune_node != NULL) {
+               ret = exynos_usbdrd_fill_sstune_param(phy_drd, tune_node);
+               if (ret < 0) {
+                       dev_err(dev, "can't fill super speed tuning param\n");
+                       return -EINVAL;
+               }
+       } else {
+               dev_info(dev, "don't need usbphy tuning param for super speed\n");
+       }
+
+       /*
+        * use PHY of samsung
+        */
+       tune_node = of_parse_phandle(dev->of_node, "hs_tune_param", 0);
+       if (tune_node != NULL) {
+               ret = exynos_usbdrd_fill_hstune_param(phy_drd, tune_node);
+               if (ret < 0) {
+                       dev_err(dev, "can't fill high speed tuning param\n");
+                       return -EINVAL;
+               }
+       } else {
+               dev_info(dev, "don't need usbphy tuning param for high speed\n");
+       }
+
+       dev_info(phy_drd->dev, "usbphy info: version:0x%x, refclk:0x%x\n",
+               phy_drd->usbphy_info.version, phy_drd->usbphy_info.refclk);
+
+       return 0;
+}
+
+static int exynos_usbdrd_get_iptype(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct device *dev = phy_drd->dev;
+       int ret, value;
+
+       ret = of_property_read_u32(dev->of_node, "ip_type", &value);
+       if (ret) {
+               dev_err(dev, "can't get ip type");
+               return ret;
+       }
+
+       switch (value) {
+       case TYPE_USB3DRD:
+               phy_drd->ip_type = TYPE_USB3DRD;
+               dev_info(dev, "It is TYPE USB3DRD");
+               break;
+       case TYPE_USB3HOST:
+               phy_drd->ip_type = TYPE_USB3HOST;
+               dev_info(dev, "It is TYPE USB3HOST");
+               break;
+       case TYPE_USB2DRD:
+               phy_drd->ip_type = TYPE_USB2DRD;
+               dev_info(dev, "It is TYPE USB2DRD");
+               break;
+       case TYPE_USB2HOST:
+               phy_drd->ip_type = TYPE_USB2HOST;
+               dev_info(dev, "It is TYPE USB2HOST");
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void exynos_usbdrd_pipe3_init(struct exynos_usbdrd_phy *phy_drd)
+{
+       exynos_usbdrd_check_connection(phy_drd);
+       phy_exynos_usb_v3p1_enable(&phy_drd->usbphy_info);
+}
+
+static void exynos_usbdrd_utmi_init(struct exynos_usbdrd_phy *phy_drd)
+{
+       int ret;
+       struct phy_usb_instance *inst = &phy_drd->phys[0];
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+       struct tune_bits *otp_data;
+       u8 otp_type;
+       u8 otp_index;
+       u8 i;
+#endif
+       pr_info("%s: +++\n", __func__);
+
+       if (gpio_is_valid(phy_drd->phy_port)) {
+               phy_drd->usbphy_info.used_phy_port = !gpio_get_value(phy_drd->phy_port);
+               dev_info(phy_drd->dev, "%s: phy port[%d]\n", __func__,
+                                               phy_drd->usbphy_info.used_phy_port);
+       }
+
+       inst->phy_cfg->phy_isol(inst, 0, inst->pmu_mask);
+
+       ret = exynos_usbdrd_clk_enable(phy_drd, false);
+       if (ret) {
+               dev_err(phy_drd->dev, "%s: Failed to enable clk\n", __func__);
+               return;
+       }
+
+       phy_exynos_usb_v3p1_enable(&phy_drd->usbphy_info);
+       /*
+        * The below function is used to block USB3.0 PHY. If you don't want to
+        * use USB3.0 PHY, add this function and comment phy_exynos_usbv3p1_pipe
+        * _ready().
+        *
+        * phy_exynos_usb_v3p1_pipe_ovrd(&phy_drd->usbphy_info);
+        */
+       phy_exynos_usb_v3p1_pipe_ready(&phy_drd->usbphy_info);
+       if (phy_drd->use_phy_umux) {
+               /* USB User MUX enable */
+               ret = exynos_usbdrd_clk_enable(phy_drd, true);
+               if (ret) {
+                       dev_err(phy_drd->dev, "%s: Failed to enable clk\n", __func__);
+                       return;
+               }
+       }
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+       if (phy_drd->ip_type < TYPE_USB2DRD) {
+               otp_type = phy_drd->otp_type[OTP_USB3PHY_INDEX];
+               otp_index = phy_drd->otp_index[OTP_USB3PHY_INDEX];
+               otp_data = phy_drd->otp_data[OTP_USB3PHY_INDEX];
+       } else {
+               otp_type = phy_drd->otp_type[OTP_USB2PHY_INDEX];
+               otp_index = phy_drd->otp_index[OTP_USB2PHY_INDEX];
+               otp_data = phy_drd->otp_data[OTP_USB2PHY_INDEX];
+       }
+
+       for (i = 0; i < otp_index; i++) {
+               samsung_exynos_cal_usb3phy_write_register(
+                       &phy_drd->usbphy_info,
+                       otp_data[i].index * otp_type,
+                       otp_data[i].value);
+       }
+#endif
+
+       pr_info("%s: ---\n", __func__);
+}
+
+static int exynos_usbdrd_phy_init(struct phy *phy)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       /* UTMI or PIPE3 specific init */
+       inst->phy_cfg->phy_init(phy_drd);
+
+       return 0;
+}
+
+static void exynos_usbdrd_pipe3_exit(struct exynos_usbdrd_phy *phy_drd)
+{
+       pr_info("%s : Do nothing...\n", __func__);
+}
+
+static void exynos_usbdrd_utmi_exit(struct exynos_usbdrd_phy *phy_drd)
+{
+       struct phy_usb_instance *inst = &phy_drd->phys[0];
+
+       if (phy_drd->use_phy_umux) {
+               /*USB User MUX disable */
+               exynos_usbdrd_clk_disable(phy_drd, true);
+       }
+       phy_exynos_usb_v3p1_disable(&phy_drd->usbphy_info);
+
+       exynos_usbdrd_clk_disable(phy_drd, false);
+
+       inst->phy_cfg->phy_isol(inst, 1, inst->pmu_mask);
+}
+
+static int exynos_usbdrd_phy_exit(struct phy *phy)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       /* UTMI or PIPE3 specific exit */
+       inst->phy_cfg->phy_exit(phy_drd);
+
+       return 0;
+}
+
+static void exynos_usbdrd_pipe3_tune(struct exynos_usbdrd_phy *phy_drd,
+                                                       int phy_state)
+{
+       struct exynos_usb_tune_param *ss_tune_param =
+                                       phy_drd->usbphy_info.ss_tune_param;
+       int i = 0;
+
+       exynos_usbdrd_check_connection(phy_drd);
+
+       dev_info(phy_drd->dev, "%s %s %d\n", __func__, ss_tune_param[0].name,
+               ss_tune_param[0].value);
+
+       for (i = 0; ss_tune_param[i].value != EXYNOS_USB_TUNE_LAST; i++)
+               phy_exynos_usb_v3p1_tune_each(&phy_drd->usbphy_info,
+                               ss_tune_param[i].name, ss_tune_param[i].value);
+}
+
+static void exynos_usbdrd_utmi_tune(struct exynos_usbdrd_phy *phy_drd,
+                                                       int phy_state)
+{
+       struct exynos_usb_tune_param *hs_tune_param = phy_drd->usbphy_info.tune_param;
+
+       dev_info(phy_drd->dev, "%s %s %d\n", __func__, hs_tune_param[0].name,
+               hs_tune_param[0].value);
+
+       phy_exynos_usb_v3p1_tune(&phy_drd->usbphy_info);
+
+       /* USB3P1 CAL code doesn't provide late_enable api */
+       /* samsung_exynos_cal_usb3phy_late_enable(&phy_drd->usbphy_info); */
+}
+
+static int exynos_usbdrd_phy_tune(struct phy *phy, int phy_state)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       inst->phy_cfg->phy_tune(phy_drd, phy_state);
+
+       return 0;
+}
+
+static void exynos_usbdrd_pipe3_set(struct exynos_usbdrd_phy *phy_drd,
+                                               int option, void *info)
+{
+}
+
+static void exynos_usbdrd_utmi_set(struct exynos_usbdrd_phy *phy_drd,
+                                               int option, void *info)
+{
+       switch (option) {
+       case SET_DPPULLUP_ENABLE:
+#if 0
+               phy_exynos_usb_v3p1_enable_dp_pullup(
+                                       &phy_drd->usbphy_info);
+#endif
+               break;
+       case SET_DPPULLUP_DISABLE:
+#if 0
+               phy_exynos_usb_v3p1_disable_dp_pullup(
+                                       &phy_drd->usbphy_info);
+#endif
+               break;
+       case SET_DPDM_PULLDOWN:
+               phy_exynos_usb_v3p1_config_host_mode(
+                                       &phy_drd->usbphy_info);
+       default:
+               break;
+       }
+}
+
+static int exynos_usbdrd_phy_set(struct phy *phy, int option, void *info)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       inst->phy_cfg->phy_set(phy_drd, option, info);
+
+       return 0;
+}
+
+static int exynos_usbdrd_phy_power_on(struct phy *phy)
+{
+       int ret;
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n");
+
+       /* Enable VBUS supply */
+       if (phy_drd->vbus) {
+               ret = regulator_enable(phy_drd->vbus);
+               if (ret) {
+                       dev_err(phy_drd->dev, "Failed to enable VBUS supply\n");
+                       return ret;
+               }
+       }
+
+       inst->phy_cfg->phy_isol(inst, 0, inst->pmu_mask);
+
+       return 0;
+}
+
+static int exynos_usbdrd_phy_power_off(struct phy *phy)
+{
+       struct phy_usb_instance *inst = phy_get_drvdata(phy);
+       struct exynos_usbdrd_phy *phy_drd = to_usbdrd_phy(inst);
+
+       dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n");
+
+       /* Disable VBUS supply */
+       if (phy_drd->vbus)
+               regulator_disable(phy_drd->vbus);
+
+       inst->phy_cfg->phy_isol(inst, 1, inst->pmu_mask);
+
+       return 0;
+}
+
+static struct phy *exynos_usbdrd_phy_xlate(struct device *dev,
+                                       struct of_phandle_args *args)
+{
+       struct exynos_usbdrd_phy *phy_drd = dev_get_drvdata(dev);
+
+       if (WARN_ON(args->args[0] > EXYNOS_DRDPHYS_NUM))
+               return ERR_PTR(-ENODEV);
+
+       return phy_drd->phys[args->args[0]].phy;
+}
+
+static struct phy_ops exynos_usbdrd_phy_ops = {
+       .init           = exynos_usbdrd_phy_init,
+       .exit           = exynos_usbdrd_phy_exit,
+       .tune           = exynos_usbdrd_phy_tune,
+       .set            = exynos_usbdrd_phy_set,
+       .power_on       = exynos_usbdrd_phy_power_on,
+       .power_off      = exynos_usbdrd_phy_power_off,
+       .owner          = THIS_MODULE,
+};
+
+static const struct exynos_usbdrd_phy_config phy_cfg_exynos[] = {
+       {
+               .id             = EXYNOS_DRDPHY_UTMI,
+               .phy_isol       = exynos_usbdrd_utmi_phy_isol,
+               .phy_init       = exynos_usbdrd_utmi_init,
+               .phy_exit       = exynos_usbdrd_utmi_exit,
+               .phy_tune       = exynos_usbdrd_utmi_tune,
+               .phy_set        = exynos_usbdrd_utmi_set,
+               .set_refclk     = exynos_usbdrd_utmi_set_refclk,
+       },
+       {
+               .id             = EXYNOS_DRDPHY_PIPE3,
+               .phy_isol       = exynos_usbdrd_pipe3_phy_isol,
+               .phy_init       = exynos_usbdrd_pipe3_init,
+               .phy_exit       = exynos_usbdrd_pipe3_exit,
+               .phy_tune       = exynos_usbdrd_pipe3_tune,
+               .phy_set        = exynos_usbdrd_pipe3_set,
+               .set_refclk     = exynos_usbdrd_pipe3_set_refclk,
+       },
+};
+
+static const struct exynos_usbdrd_phy_drvdata exynos_usbdrd_phy = {
+       .phy_cfg                = phy_cfg_exynos,
+};
+
+static const struct of_device_id exynos_usbdrd_phy_of_match[] = {
+       {
+               .compatible = "samsung,exynos-usbdrd-phy",
+               .data = &exynos_usbdrd_phy
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, exynos5_usbdrd_phy_of_match);
+
+static int exynos_usbdrd_phy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct exynos_usbdrd_phy *phy_drd;
+       struct phy_provider *phy_provider;
+       struct resource *res;
+       const struct of_device_id *match;
+       const struct exynos_usbdrd_phy_drvdata *drv_data;
+       struct phy_usb_instance *inst;
+       struct regmap *reg_pmu;
+       u32 pmu_offset, pmu_mask;
+       int i, ret;
+
+       pr_info("%s: +++ %s\n", __func__, pdev->name);
+       phy_drd = devm_kzalloc(dev, sizeof(*phy_drd), GFP_KERNEL);
+       if (!phy_drd)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, phy_drd);
+       phy_drd->dev = dev;
+
+       match = of_match_node(exynos_usbdrd_phy_of_match, pdev->dev.of_node);
+
+       drv_data = match->data;
+       phy_drd->drv_data = drv_data;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       phy_drd->reg_phy = devm_ioremap_resource(dev, res);
+       if (IS_ERR(phy_drd->reg_phy))
+               return PTR_ERR(phy_drd->reg_phy);
+
+       ret = exynos_usbdrd_get_iptype(phy_drd);
+       if (ret) {
+               dev_err(dev, "%s: Failed to get ip_type\n", __func__);
+               return ret;
+       }
+
+       ret = exynos_usbdrd_clk_get(phy_drd);
+       if (ret) {
+               dev_err(dev, "%s: Failed to get clocks\n", __func__);
+               return ret;
+       }
+
+       ret = exynos_usbdrd_clk_prepare(phy_drd);
+       if (ret) {
+               dev_err(dev, "%s: Failed to prepare clocks\n", __func__);
+               return ret;
+       }
+
+       reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
+                                                  "samsung,pmu-syscon");
+       if (IS_ERR(reg_pmu)) {
+               dev_err(dev, "Failed to lookup PMU regmap\n");
+               goto err;
+       }
+
+       ret = of_property_read_u32(dev->of_node, "pmu_offset", &pmu_offset);
+       if (ret < 0) {
+               dev_err(dev, "couldn't read pmu_offset on %s node, error = %d\n",
+                                               dev->of_node->name, ret);
+               goto err;
+       }
+
+       ret = of_property_read_u32(dev->of_node, "pmu_mask", &pmu_mask);
+       if (ret < 0) {
+               dev_err(dev, "couldn't read pmu_mask on %s node, error = %d\n",
+                                               dev->of_node->name, ret);
+               goto err;
+       }
+
+       dev_vdbg(dev, "Creating usbdrd_phy phy\n");
+       phy_drd->phy_port =  of_get_named_gpio(dev->of_node,
+                                       "phy,gpio_phy_port", 0);
+       if (gpio_is_valid(phy_drd->phy_port)) {
+               dev_err(dev, "PHY CON Selection OK\n");
+
+               ret = gpio_request(phy_drd->phy_port, "PHY_CON");
+               if (ret)
+                       dev_err(dev, "fail to request gpio %s:%d\n", "PHY_CON", ret);
+               else
+                       gpio_direction_input(phy_drd->phy_port);
+       } else {
+               dev_err(dev, "non-DT: PHY CON Selection\n");
+       }
+
+       if (!of_property_read_u32(dev->of_node, "has_combo_phy", &ret)) {
+               if (ret) {
+                       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+                       phy_drd->reg_phy2 = devm_ioremap_resource(dev, res);
+                       if (IS_ERR(phy_drd->reg_phy2))
+                               return PTR_ERR(phy_drd->reg_phy2);
+
+                       res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+                       phy_drd->reg_phy3 = devm_ioremap_resource(dev, res);
+                       if (IS_ERR(phy_drd->reg_phy3))
+                               return PTR_ERR(phy_drd->reg_phy3);
+
+                       exynos_usbdrd_get_sub_phyinfo(phy_drd);
+               } else {
+                       dev_err(dev, "It has not the other phy\n");
+               }
+       }
+#if IS_ENABLED(CONFIG_EXYNOS_OTP)
+       exynos_usbdrd_phy_get_otp_info(phy_drd);
+#endif
+
+       for (i = 0; i < EXYNOS_DRDPHYS_NUM; i++) {
+               struct phy *phy = devm_phy_create(dev, NULL,
+                                                 &exynos_usbdrd_phy_ops);
+               if (IS_ERR(phy)) {
+                       dev_err(dev, "Failed to create usbdrd_phy phy\n");
+                       goto err;
+               }
+
+               phy_drd->phys[i].phy = phy;
+               phy_drd->phys[i].index = i;
+               phy_drd->phys[i].reg_pmu = reg_pmu;
+               phy_drd->phys[i].pmu_offset = pmu_offset;
+               phy_drd->phys[i].pmu_mask = pmu_mask;
+               phy_drd->phys[i].phy_cfg = &drv_data->phy_cfg[i];
+               phy_set_drvdata(phy, &phy_drd->phys[i]);
+       }
+#if IS_ENABLED(CONFIG_PHY_EXYNOS_DEBUGFS)
+       ret = exynos_usbdrd_debugfs_init(phy_drd);
+       if (ret) {
+               dev_err(dev, "Failed to initialize debugfs\n");
+               goto err;
+       }
+#endif
+
+       inst = &phy_drd->phys[0];
+       inst->phy_cfg->phy_isol(inst, 0, inst->pmu_mask);
+       ret = exynos_rate_to_clk(phy_drd);
+       if (ret) {
+               dev_err(phy_drd->dev, "%s: Not supported ref clock\n",
+                               __func__);
+               goto err;
+       }
+       inst->phy_cfg->phy_isol(inst, 1, inst->pmu_mask);
+
+       ret = exynos_usbdrd_get_phyinfo(phy_drd);
+       if (ret)
+               goto err;
+
+       /*
+        * Both has_other_phy and has_combo_phy can't be enabled at the same time.
+        * It's alternative.
+        */
+       if (!of_property_read_u32(dev->of_node, "has_other_phy", &ret)) {
+               if (ret) {
+                       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+                       phy_drd->reg_phy2 = devm_ioremap_resource(dev, res);
+                       if (IS_ERR(phy_drd->reg_phy2))
+                               return PTR_ERR(phy_drd->reg_phy2);
+
+                       phy_drd->usbphy_info.regs_base_2nd = phy_drd->reg_phy2;
+                       phy_drd->usbphy_info.ss_tune_param =
+                                       phy_drd->usbphy_sub_info.tune_param;
+               } else {
+                       dev_err(dev, "It has not the other phy\n");
+               }
+       }
+
+       phy_provider = devm_of_phy_provider_register(dev,
+                                                    exynos_usbdrd_phy_xlate);
+       if (IS_ERR(phy_provider)) {
+               dev_err(phy_drd->dev, "Failed to register phy provider\n");
+               goto err;
+       }
+
+       pr_info("%s: ---\n", __func__);
+       return 0;
+
+err:
+       exynos_usbdrd_clk_unprepare(phy_drd);
+
+       return ret;
+}
+
+#define EXYNOS_USBDRD_PHY_PM_OPS       NULL
+
+static struct platform_driver phy_exynos_usbdrd = {
+       .probe  = exynos_usbdrd_phy_probe,
+       .driver = {
+               .of_match_table = exynos_usbdrd_phy_of_match,
+               .name           = "phy_exynos_usbdrd",
+               .pm             = EXYNOS_USBDRD_PHY_PM_OPS,
+       }
+};
+
+module_platform_driver(phy_exynos_usbdrd);
+MODULE_DESCRIPTION("Samsung EXYNOS SoCs USB DRD controller PHY driver");
+MODULE_AUTHOR("Vivek Gautam <gautam.vivek@samsung.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:phy_exynos_usbdrd");
diff --git a/drivers/phy/samsung/phy-samsung-usb-cal.h b/drivers/phy/samsung/phy-samsung-usb-cal.h
new file mode 100644 (file)
index 0000000..8f01655
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ *
+ * USBPHY configuration definitions for Samsung USB PHY CAL
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef __PHY_SAMSUNG_USB_FW_CAL_H__
+#define __PHY_SAMSUNG_USB_FW_CAL_H__
+
+#define EXYNOS_USBCON_VER_01_0_0       0x0100  /* Istor        */
+#define EXYNOS_USBCON_VER_01_0_1       0x0101  /* JF 3.0       */
+#define EXYNOS_USBCON_VER_01_1_1       0x0111  /* KC           */
+#define EXYNOS_USBCON_VER_01_MAX       0x01FF
+
+#define EXYNOS_USBCON_VER_02_0_0       0x0200  /* Insel-D, Island      */
+#define EXYNOS_USBCON_VER_02_0_1       0x0201  /* JF EVT0 2.0 Host     */
+#define EXYNOS_USBCON_VER_02_1_0       0x0210
+#define EXYNOS_USBCON_VER_02_1_1       0x0211  /* JF EVT1 2.0 Host     */
+#define EXYNOS_USBCON_VER_02_1_2       0x0212  /* Katmai EVT0 */
+#define EXYNOS_USBCON_VER_02_MAX       0x02FF
+
+#define EXYNOS_USBCON_VER_03_0_0       0x0300  /* Lhotse, Lassen HS, Ramen HS */
+#define EXYNOS_USBCON_VER_03_0_1       0x0301  /* MK */
+#define EXYNOS_USBCON_VER_03_MAX       0x03FF
+
+#define EXYNOS_USBCON_VER_04_0_0       0x0400  /* Lhotse - USB/DP  */
+#define EXYNOS_USBCON_VER_04_MAX       0x04FF
+
+/* Sub phy control - not include System/Link control */
+#define EXYNOS_USBCON_VER_05_0_0       0x0500  /* High Speed Only      */
+#define EXYNOS_USBCON_VER_05_1_0       0x0510  /* Super Speed          */
+#define EXYNOS_USBCON_VER_05_3_0       0x0530  /* Super Speed Dual PHY */
+#define EXYNOS_USBCON_VER_05_MAX       0x05FF
+
+#define EXYNOS_USBCON_VER_F2_0_0       0xF200
+#define EXYNOS_USBCON_VER_F2_MAX       0xF2FF
+
+#define EXYNOS_USBCON_VER_MAJOR_VER_MASK       0xFF00
+#define EXYNOS_USBCON_VER_SS_CAP                       0x0010
+
+#define EXYNOS_USBCON_VER_MINOR(_x)    ((_x) & 0xf)
+#define EXYNOS_USBCON_VER_MID(_x)      ((_x) & 0xf0)
+#define EXYNOS_USBCON_VER_MAJOR(_x)    ((_x) & 0xff00)
+
+enum exynos_usbphy_mode {
+       USBPHY_MODE_DEV = 0,
+       USBPHY_MODE_HOST = 1,
+
+       /* usb phy for uart bypass mode */
+       USBPHY_MODE_BYPASS = 0x10,
+};
+
+enum exynos_usbphy_refclk {
+       USBPHY_REFCLK_DIFF_100MHZ = 0x80 | 0x27,
+       USBPHY_REFCLK_DIFF_52MHZ = 0x80 | 0x02 | 0x40,
+       USBPHY_REFCLK_DIFF_26MHZ = 0x80 | 0x02,
+       USBPHY_REFCLK_DIFF_24MHZ = 0x80 | 0x2a,
+       USBPHY_REFCLK_DIFF_20MHZ = 0x80 | 0x31,
+       USBPHY_REFCLK_DIFF_19_2MHZ = 0x80 | 0x38,
+
+       USBPHY_REFCLK_EXT_50MHZ = 0x07,
+       USBPHY_REFCLK_EXT_26MHZ = 0x06,
+       USBPHY_REFCLK_EXT_24MHZ = 0x05,
+       USBPHY_REFCLK_EXT_20MHZ = 0x04,
+       USBPHY_REFCLK_EXT_12MHZ = 0x02,
+};
+
+enum exynos_usbphy_refsel {
+       USBPHY_REFSEL_CLKCORE = 0x2,
+       USBPHY_REFSEL_EXT_OSC = 0x1,
+       USBPHY_REFSEL_EXT_XTAL = 0x0,
+
+       USBPHY_REFSEL_DIFF_PAD = 0x6,
+       USBPHY_REFSEL_DIFF_INTERNAL = 0x4,
+       USBPHY_REFSEL_DIFF_SINGLE = 0x3,
+};
+
+enum exynos_usbphy_utmi {
+       USBPHY_UTMI_FREECLOCK, USBPHY_UTMI_PHYCLOCK,
+};
+
+enum exynos_usbphy_tune_para {
+       USBPHY_TUNE_HS_COMPDIS = 0x0,
+       USBPHY_TUNE_HS_OTG = 0x1,
+       USBPHY_TUNE_HS_SQRX = 0x2,
+       USBPHY_TUNE_HS_TXFSLS = 0x3,
+       USBPHY_TUNE_HS_TXHSXV = 0x4,
+       USBPHY_TUNE_HS_TXPREEMP = 0x5,
+       USBPHY_TUNE_HS_TXPREEMP_PLUS = 0x6,
+       USBPHY_TUNE_HS_TXRES = 0x7,
+       USBPHY_TUNE_HS_TXRISE = 0x8,
+       USBPHY_TUNE_HS_TXVREF = 0x9,
+
+       USBPHY_TUNE_SS_TX_BOOST = 0x0 | 0x10000,
+       USBPHY_TUNE_SS_TX_SWING = 0x1 | 0x10000,
+       USBPHY_TUNE_SS_TX_DEEMPHASIS = 0x2 | 0x10000,
+       USBPHY_TUNE_SS_LOS_BIAS = 0x3 | 0x10000,
+       USBPHY_TUNE_SS_LOS_MASK_VAL = 0x4 | 0x10000,
+       USBPHY_TUNE_SS_FIX_EQ = 0x5 | 0x10000,
+       USBPHY_TUNE_SS_RX_EQ = 0x6 | 0x10000,
+
+       USBPHY_TUNE_COMBO = 0x20000,
+       USBPHY_TUNE_COMBO_TX_AMP        = USBPHY_TUNE_COMBO | 0x0,
+       USBPHY_TUNE_COMBO_TX_EMPHASIS   = USBPHY_TUNE_COMBO | 0x1,
+       USBPHY_TUNE_COMBO_TX_IDRV       = USBPHY_TUNE_COMBO | 0x2,
+       USBPHY_TUNE_COMBO_TX_ACCDRV     = USBPHY_TUNE_COMBO | 0x3,
+};
+
+enum exynos_usb_bc {
+       BC_NO_CHARGER,
+       BC_SDP,
+       BC_DCP,
+       BC_CDP,
+       BC_ACA_DOCK,
+       BC_ACA_A,
+       BC_ACA_B,
+       BC_ACA_C,
+};
+
+struct exynos_usb_tune_param {
+       char name[30];
+       int value;
+};
+
+#define EXYNOS_USB_TUNE_LAST   0x4C415354
+
+/* HS PHY tune parameter */
+struct exynos_usbphy_hs_tune {
+       u8 tx_vref;
+       u8 tx_pre_emp;
+       u8 tx_pre_emp_puls;
+       u8 tx_res;
+       u8 tx_rise;
+       u8 tx_hsxv;
+       u8 tx_fsls;
+       u8 rx_sqrx;
+       u8 compdis;
+       u8 otg;
+       bool enable_user_imp;
+       u8 user_imp_value;
+       enum exynos_usbphy_utmi utmi_clk;
+};
+
+/* SS PHY tune parameter */
+struct exynos_usbphy_ss_tune {
+       /* TX Swing Level*/
+       u8 tx_boost_level;
+       u8 tx_swing_level;
+       u8 tx_swing_full;
+       u8 tx_swing_low;
+       /* TX De-Emphasis */
+       u8 tx_deemphasis_mode;
+       u8 tx_deemphasis_3p5db;
+       u8 tx_deemphasis_6db;
+       /* SSC Operation*/
+       u8 enable_ssc;
+       u8 ssc_range;
+       /* Loss-of-Signal detector threshold level */
+       u8 los_bias;
+       /* Loss-of-Signal mask width */
+       u16 los_mask_val;
+       /* RX equalizer mode */
+       u8 enable_fixed_rxeq_mode;
+       u8 fix_rxeq_value;
+       /* Decrease TX Impedance */
+       u8 decrease_ss_tx_imp;
+
+       u8 set_crport_level_en;
+       u8 set_crport_mpll_charge_pump;
+       /* RX LFPS(decode) mode */
+       u8 rx_decode_mode;
+};
+
+/**
+ * struct exynos_usbphy_info : USBPHY information to share USBPHY CAL code
+ * @version: PHY controller version
+ *          0x0100 - for EXYNOS_USB3 : EXYNOS7420, EXYNOS7890
+ *          0x0101 -                   EXYNOS8890
+ *          0x0111 -                   EXYNOS8895
+ *          0x0200 - for EXYNOS_USB2 : EXYNOS7580, EXYNOS3475
+ *          0x0210 -                   EXYNOS8890_EVT1
+ *          0xF200 - for EXT         : EXYNOS7420_HSIC
+ * @refclk: reference clock frequency for USBPHY
+ * @refsrc: reference clock source path for USBPHY
+ * @use_io_for_ovc: use over-current notification io for USBLINK
+ * @regs_base: base address of PHY control register *
+ */
+
+struct exynos_usbphy_info {
+       /* Device Information */
+       struct device *dev;
+
+       u32     version;
+       enum exynos_usbphy_refclk refclk;
+       enum exynos_usbphy_refsel refsel;
+
+       bool use_io_for_ovc;
+       bool common_block_disable;
+       bool not_used_vbus_pad;
+
+       void __iomem *regs_base;
+
+       /* HS PHY tune parameter */
+       struct exynos_usbphy_hs_tune *hs_tune;
+
+       /* SS PHY tune parameter */
+       struct exynos_usbphy_ss_tune *ss_tune;
+
+       /* Tune Parma list - Synopsys USB3 PHY */
+       struct exynos_usb_tune_param *ss_tune_param;
+
+       /* Tune Parma list */
+       struct exynos_usb_tune_param *tune_param;
+
+       /* multiple phy */
+       int     hw_version;
+       void __iomem *regs_base_2nd;
+       int     used_phy_port;
+
+       /* Alternative PHY REF_CLK source */
+       bool alt_ref_clk;
+
+       /* Remote Wake-up Advisor */
+       unsigned hs_rewa :1;
+
+       /* Dual PHY */
+       bool dual_phy;
+};
+
+
+#endif /* __PHY_SAMSUNG_USB_FW_CAL_H__ */
diff --git a/drivers/phy/samsung/phy-samsung-usb3-cal-combo.h b/drivers/phy/samsung/phy-samsung-usb3-cal-combo.h
new file mode 100644 (file)
index 0000000..abbabf8
--- /dev/null
@@ -0,0 +1,174 @@
+#ifndef __PHY_SAMSUNG_COMBO_H__
+#define __PHY_SAMSUNG_COMBO_H__
+
+#define EXYNOS_USBCON_CTRLVER  (0x0)
+#define CTRLVER_CTRL_VER_MASK          (0xFFFFFFFF)
+
+#define EXYNOS_USBCON_LINKCTRL         (0x4)
+#define LINKCTRL_FORCE_RXELECIDLE              (0x1 << 18)
+#define LINKCTRL_FORCE_PHYSTATUS               (0x1 << 17)
+#define LINKCTRL_FORCE_PIPE_EN         (0x1 << 16)
+#define LINKCTRL_DIS_BUSPEND_QACT              (0x1 << 13)
+#define LINKCTRL_DIS_LINKGATE_QACT             (0x1 << 12)
+#define LINKCTRL_DIS_ID0_QACT          (0x1 << 11)
+#define LINKCTRL_DIS_VBUSVALID_QACT            (0x1 << 10)
+#define LINKCTRL_DIS_BVALID_QACT               (0x1 << 9)
+#define LINKCTRL_FORCE_QACT            (0x1 << 8)
+#define LINKCTRL_BUS_FILTER_BYPASS_MASK                (0xF << 4)
+#define LINKCTRL_HOST_SYSTEM_ERR                       (0x1 << 2)
+#define LINKCTRL_LINK_PME                      (0x1 << 1)
+#define LINKCTRL_PME_GENERATION                (0x1 << 0)
+
+#define EXYNOS_USBCON_PHYCON_LINKPORT          (0x08)
+#define PHYCON_LINKPORT_HOST_NUM_U3_MASK               (0xF << 16)
+#define PHYCON_LINKPORT_HOST_NUM_U2_MASK               (0xF << 12)
+#define PHYCON_LINKPORT_HOST_U3_PORT_DISABLE                   (0x1 << 9)
+#define PHYCON_LINKPORT_HOST_U2_PORT_DISABLE                   (0x1 << 8)
+#define PHYCON_LINKPORT_HOST_PORT_POWER_CON_PRESENT                    (0x1 << 6)
+#define PHYCON_LINKPORT_HUB_PORT_OVERCURRENT_U3                        (0x1 << 5)
+#define PHYCON_LINKPORT_HUB_PORT_OVERCURRENT_U2                        (0x1 << 4)
+#define PHYCON_LINKPORT_HUB_PORT_OVERCURRENT_SET_U3                    (0x1 << 3)
+#define PHYCON_LINKPORT_HUB_PORT_OVERCURRENT_SET_U2                    (0x1 << 2)
+#define PHYCON_LINKPORT_HUB_PERM_ATTACH_U3                     (0x1 << 1)
+#define PHYCON_LINKPORT_HUB_PERM_ATTACH_U2                     (0x1 << 0)
+
+#define EXYNOS_USBCON_LINK_DEBUG_L     (0xC)
+#define LINK_DEBUG_L_DEBUG_L_MASK              (0xFFFFFFFF)
+
+#define EXYNOS_USBCON_LINK_DEBUG_H     (0x10)
+#define LINK_DEBUG_H_DEBUG_H_MASK              (0xFFFFFFFF)
+
+#define EXYNOS_USBCON_LTSTATE_HIS              (0x14)
+#define LTSTATE_HIS_LINKTRN_DONE               (0x1 << 31)
+#define LTSTATE_HIS_LTSTATE_HIS4_MASK          (0xF << 16)
+#define LTSTATE_HIS_LTSTATE_HIS3_MASK          (0xF << 12)
+#define LTSTATE_HIS_LTSTATE_HIS2_MASK          (0xF << 8)
+#define LTSTATE_HIS_LTSTATE_HIS1_MASK          (0xF << 4)
+#define LTSTATE_HIS_LTSTATE_HIS0_MASK          (0xF << 0)
+
+#define EXYNOS_USBCON_CLKRSTCTRL               (0x20)
+#define CLKRSTCTRL_USBAUDIO_CLK_GATE_EN                (0x1 << 9)
+#define CLKRSTCTRL_USBAUDIO_CLK_SEL            (0x1 << 8)
+#define CLKRSTCTRL_LINK_PCLK_SEL               (0x1 << 7)
+#define CLKRSTCTRL_REFCLKSEL           (0x1 << 4)
+#define CLKRSTCTRL_PHY_SW_RST          (0x1 << 3)
+#define CLKRSTCTRL_PHY_RESET_SEL               (0x1 << 2)
+#define CLKRSTCTRL_PORTRESET           (0x1 << 1)
+#define CLKRSTCTRL_LINK_SW_RST         (0x1 << 0)
+
+#define EXYNOS_USBCON_PWRCTL           (0x24)
+#define PWRCTL_FORCE_POWERDOWN         (0x1 << 2)
+
+#define EXYNOS_USBCON_SSPPLLCTL        (0x30)
+#define SSPPLLCTL_FSEL_MASK            (0x3F << 0)
+
+#define EXYNOS_USBCON_SECPMACTL                (0x48)
+#define SECPMACTL_PMA_PLL_REF_CLK_SEL_MASK             (0x3 << 10)
+#define SECPMACTL_PMA_REF_FREQ_SEL_MASK                (0x3 << 8)
+#define SECPMACTL_PMA_LOW_PWR          (0x1 << 4)
+#define SECPMACTL_PMA_TRSV_SW_RST              (0x1 << 3)
+#define SECPMACTL_PMA_CMN_SW_RST               (0x1 << 2)
+#define SECPMACTL_PMA_INIT_SW_RST              (0x1 << 1)
+#define SECPMACTL_PMA_APB_SW_RST               (0x1 << 0)
+
+#define EXYNOS_USBCON_UTMICTRL         (0x50)
+#define UTMICTRL_OPMODE_EN             (0x1 << 8)
+#define UTMICTRL_FORCE_OPMODE_MASK             (0x3 << 6)
+#define UTMICTRL_FORCE_VBUSVALID               (0x1 << 5)
+#define UTMICTRL_FORCE_BVALID          (0x1 << 4)
+#define UTMICTRL_FORCE_DPPULLDOWN              (0x1 << 3)
+#define UTMICTRL_FORCE_DMPULLDOWN              (0x1 << 2)
+#define UTMICTRL_FORCE_SUSPEND         (0x1 << 1)
+#define UTMICTRL_FORCE_SLEEP           (0x1 << 0)
+
+#define EXYNOS_USBCON_HSPCTRL          (0x54)
+#define HSPCTRL_AUTORSM_ENB            (0x1 << 29)
+#define HSPCTRL_RETENABLE_EN           (0x1 << 28)
+#define HSPCTRL_FSLS_SPEED_SEL         (0x1 << 25)
+#define HSPCTRL_FSV_OUT_EN             (0x1 << 24)
+#define HSPCTRL_HS_XCVR_EXT_CTL                (0x1 << 22)
+#define HSPCTRL_HS_RXDAT               (0x1 << 21)
+#define HSPCTRL_HS_SQUELCH             (0x1 << 20)
+#define HSPCTRL_FSVMINUS               (0x1 << 17)
+#define HSPCTRL_FSVPLUS                (0x1 << 16)
+#define HSPCTRL_VBUSVLDEXTSEL          (0x1 << 13)
+#define HSPCTRL_VBUSVLDEXT             (0x1 << 12)
+#define HSPCTRL_EN_UTMISUSPEND         (0x1 << 9)
+#define HSPCTRL_COMMONONN              (0x1 << 8)
+#define HSPCTRL_VATESTENB              (0x1 << 6)
+#define HSPCTRL_CHGDET         (0x1 << 5)
+#define HSPCTRL_VDATSRCENB             (0x1 << 4)
+#define HSPCTRL_VDATDETENB             (0x1 << 3)
+#define HSPCTRL_CHRGSEL                (0x1 << 2)
+#define HSPCTRL_ACAENB         (0x1 << 1)
+#define HSPCTRL_DEDENB         (0x1 << 0)
+
+#define EXYNOS_USBCON_HSPPARACON               (0x58)
+#define HSPPARACON_TXVREFTUNE_MASK             (0xF << 28)
+#define HSPPARACON_TXRISETUNE_MASK             (0x3 << 24)
+#define HSPPARACON_TXRESTUNE_MASK              (0x3 << 21)
+#define HSPPARACON_TXPREEMPPULSETUNE           (0x1 << 20)
+#define HSPPARACON_TXPREEMPAMPTUNE_MASK                (0x3 << 18)
+#define HSPPARACON_TXHSXVTUNE_MASK             (0x3 << 16)
+#define HSPPARACON_TXFSLSTUNE_MASK             (0xF << 12)
+#define HSPPARACON_SQRXTUNE_MASK               (0x7 << 8)
+#define HSPPARACON_OTGTUNE_MASK                (0x7 << 4)
+#define HSPPARACON_COMPDISTUNE_MASK            (0x7 << 0)
+
+#define EXYNOS_USBCON_HSPTEST          (0x5C)
+#define HSPTEST_SIDDQ_PORT0            (0x1 << 24)
+#define HSPTEST_LINESTATE_PORT0_MASK           (0x3 << 20)
+#define HSPTEST_TESTDATAOUT_PORT0_MASK         (0xF << 16)
+#define HSPTEST_TESTCLK_PORT0          (0x1 << 13)
+#define HSPTEST_TESTDATAOUTSEL_PORT0           (0x1 << 12)
+#define HSPTEST_TESTADDR_PORT0_MASK            (0xF << 8)
+#define HSPTEST_TESTDATAIN_PORT0_MASK          (0xFF << 0)
+
+#define EXYNOS_USBCON_HSPPLLTUNE               (0x60)
+#define HSPPLLTUNE_PLLBTUNE            (0x1 << 8)
+#define HSPPLLTUNE_PLLITUNE_MASK               (0x3 << 4)
+#define HSPPLLTUNE_PLLPTUNE_MASK               (0xF << 0)
+
+#define EXYNOS_USBCON_REWA_CTRL                (0x100)
+#define REWA_CTRL_HSREWA_EN            (0x1 << 0)
+
+#define EXYNOS_USBCON_HSREWA_INTR              (0x104)
+#define HSREWA_INTR_WAKEUP_MASK_MASK                   (0x1 << 12)
+#define HSREWA_INTR_TIMEOUT_INTR_MASK_MASK                     (0x1 << 8)
+#define HSREWA_INTR_EVENT_INT_MASK_MASK                        (0x1 << 4)
+#define HSREWA_INTR_WAKEUP_INTR_MASK_MASK                      (0x1 << 0)
+
+#define EXYNOS_USBCON_HSREWA_CTRL              (0x108)
+#define HSREWA_CTRL_DIG_BYPASS_CON_EN          (0x1 << 28)
+#define HSREWA_CTRL_DPDM_MONITOR_SEL           (0x1 << 24)
+#define HSREWA_CTRL_HS_LINK_READY              (0x1 << 20)
+#define HSREWA_CTRL_HS_SYS_VALID               (0x1 << 16)
+#define HSREWA_CTRL_HS_REWA_ERROR              (0x1 << 4)
+#define HSREWA_CTRL_HS_REWA_DONE               (0x1 << 0)
+
+#define EXYNOS_USBCON_HSREWA_REFTO             (0x10C)
+#define HSREWA_REFTO_HOST_K_TIMEOUT_MASK               (0xFFFFFFFF << 0)
+
+#define EXYNOS_USBCON_HSREWA_HSTK              (0x110)
+#define HSREWA_HSTK_HOST_K_DELAY_MASK          (0xFFFFFFFF << 0)
+
+#define EXYNOS_USBCON_HSREWA_CNT               (0x114)
+#define HSREWA_CNT_WAKEUP_CNT_MASK             (0xFFFFFFFF << 0)
+
+#define EXYNOS_USBCON_HSREWA_INT1_EVNT         (0x118)
+#define HSREWA_INT1_EVNT_ERR_SUS               (0x1 << 18)
+#define HSREWA_INT1_EVNT_ERR_DEV_K             (0x1 << 17)
+#define HSREWA_INT1_EVNT_DISCON                (0x1 << 16)
+#define HSREWA_INT1_EVNT_BYPASS_DIS            (0x1 << 2)
+#define HSREWA_INT1_EVNT_RET_DIS               (0x1 << 1)
+#define HSREWA_INT1_EVNT_RET_EN                (0x1 << 0)
+
+#define EXYNOS_USBCON_HSREWA_INT1_EVNT_MSK             (0x11C)
+#define HSREWA_INT1_EVNT_MSK_ERR_SUS_MASK                      (0x1 << 18)
+#define HSREWA_INT1_EVNT_MSK_ERR_DEV_K_MASK                    (0x1 << 17)
+#define HSREWA_INT1_EVNT_MSK_DISCON_MASK                       (0x1 << 16)
+#define HSREWA_INT1_EVNT_MSK_BYPASS_DIS_MASK                   (0x1 << 2)
+#define HSREWA_INT1_EVNT_MSK_RET_DIS_MASK                      (0x1 << 1)
+#define HSREWA_INT1_EVNT_MSK_RET_EN_MASK                       (0x1 << 0)
+
+#endif
diff --git a/drivers/phy/samsung/phy-samsung-usb3-cal.c b/drivers/phy/samsung/phy-samsung-usb3-cal.c
new file mode 100644 (file)
index 0000000..68685ed
--- /dev/null
@@ -0,0 +1,1207 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *              http://www.samsung.com
+ *
+ * Author: Sung-Hyun Na <sunghyun.na@samsung.com>
+ * Author: Minho Lee <minho55.lee@samsung.com>
+ *
+ * Chip Abstraction Layer for USB PHY
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifdef __KERNEL__
+
+#ifndef __EXCITE__
+#include <linux/delay.h>
+#include <linux/io.h>
+#endif
+
+#include <linux/platform_device.h>
+
+#else
+
+#include "types.h"
+#include "customfunctions.h"
+#include "mct.h"
+
+#endif
+
+#include "phy-samsung-usb-cal.h"
+#include "phy-samsung-usb3-cal.h"
+
+#define USB_SS_TX_TUNE_PCS
+
+//#define USB_MUX_UTMI_ENABLE
+
+enum exynos_usbcon_cr {
+       USBCON_CR_ADDR = 0,
+       USBCON_CR_DATA = 1,
+       USBCON_CR_READ = 18,
+       USBCON_CR_WRITE = 19,
+};
+
+static u16 samsung_exynos_cal_cr_access(struct exynos_usbphy_info *usbphy_info,
+               enum exynos_usbcon_cr cr_bit, u16 data)
+{
+       void __iomem *base;
+       u32 phyreg0;
+       u32 phyreg1;
+       u32 loop;
+       u32 loop_cnt;
+
+       if (usbphy_info->used_phy_port != -1) {
+               if (usbphy_info->used_phy_port == 0)
+                       base = usbphy_info->regs_base;
+               else
+                       base = usbphy_info->regs_base_2nd;
+
+       } else
+               base = usbphy_info->regs_base;
+
+       /* Clear CR port register */
+       phyreg0 = readl(base + EXYNOS_USBCON_PHYREG0);
+       phyreg0 &= ~(0xfffff);
+       writel(phyreg0, base + EXYNOS_USBCON_PHYREG0);
+
+       /* Set Data for cr port */
+       phyreg0 &= ~PHYREG0_CR_DATA_MASK;
+       phyreg0 |= PHYREG0_CR_DATA_IN(data);
+       writel(phyreg0, base + EXYNOS_USBCON_PHYREG0);
+
+       if (cr_bit == USBCON_CR_ADDR)
+               loop = 1;
+       else
+               loop = 2;
+
+       for (loop_cnt = 0; loop_cnt < loop; loop_cnt++) {
+               u32 trigger_bit = 0;
+               u32 handshake_cnt = 2;
+               /* Trigger cr port */
+               if (cr_bit == USBCON_CR_ADDR)
+                       trigger_bit = PHYREG0_CR_CR_CAP_ADDR;
+               else {
+                       if (loop_cnt == 0)
+                               trigger_bit = PHYREG0_CR_CR_CAP_DATA;
+                       else {
+                               if (cr_bit == USBCON_CR_READ)
+                                       trigger_bit = PHYREG0_CR_READ;
+                               else
+                                       trigger_bit = PHYREG0_CR_WRITE;
+                       }
+               }
+               /* Handshake Procedure */
+               do {
+                       u32 usec = 100;
+                       if (handshake_cnt == 2)
+                               phyreg0 |= trigger_bit;
+                       else
+                               phyreg0 &= ~trigger_bit;
+                       writel(phyreg0, base + EXYNOS_USBCON_PHYREG0);
+
+                       /* Handshake */
+                       do {
+                               phyreg1 = readl(base + EXYNOS_USBCON_PHYREG1);
+                               if ((handshake_cnt == 2)
+                                               && (phyreg1 & PHYREG1_CR_ACK))
+                                       break;
+                               else if ((handshake_cnt == 1)
+                                               && !(phyreg1 & PHYREG1_CR_ACK))
+                                       break;
+
+                               udelay(1);
+                       } while (usec-- > 0);
+
+                       if (!usec)
+                               pr_err("CRPORT handshake timeout1 (0x%08x)\n",
+                                               phyreg0);
+
+                       udelay(5);
+                       handshake_cnt--;
+               } while (handshake_cnt != 0);
+               udelay(50);
+       }
+       return (u16) ((phyreg1 & PHYREG1_CR_DATA_OUT_MASK) >> 1);
+}
+
+void samsung_exynos_cal_cr_write(struct exynos_usbphy_info *usbphy_info,
+               u16 addr, u16 data)
+{
+       samsung_exynos_cal_cr_access(usbphy_info, USBCON_CR_ADDR, addr);
+       samsung_exynos_cal_cr_access(usbphy_info, USBCON_CR_WRITE, data);
+}
+
+u16 samsung_exynos_cal_cr_read(struct exynos_usbphy_info *usbphy_info, u16 addr)
+{
+       samsung_exynos_cal_cr_access(usbphy_info, USBCON_CR_ADDR, addr);
+       return samsung_exynos_cal_cr_access(usbphy_info, USBCON_CR_READ, 0);
+}
+
+void samsung_exynos_cal_usb3phy_tune_fix_rxeq(
+       struct exynos_usbphy_info *usbphy_info)
+{
+       u16 reg;
+       struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune;
+
+       if (!tune)
+               return;
+
+       reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1006);
+       reg &= ~(1 << 6);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg);
+
+       udelay(10);
+
+       reg |= (1 << 7);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg);
+
+       udelay(10);
+
+       reg &= ~(0x7 << 0x8);
+       reg |= (tune->fix_rxeq_value << 8);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg);
+
+       udelay(10);
+
+       reg |= (1 << 11);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg);
+
+       printk("Reg RX_OVRD_IN_HI : 0x%x\n",
+               samsung_exynos_cal_cr_read(usbphy_info, 0x1006));
+
+       printk("Reg RX_CDR_CDR_FSM_DEBUG : 0x%x\n",
+               samsung_exynos_cal_cr_read(usbphy_info, 0x101c));
+}
+
+static void set_ss_tx_impedance(struct exynos_usbphy_info *usbphy_info)
+{
+       u16 rtune_debug, tx_ovrd_in_hi;
+       u8 tx_imp;
+
+       /* obtain calibration code for 45Ohm impedance */
+       rtune_debug = samsung_exynos_cal_cr_read(usbphy_info, 0x3);
+       /* set SUP.DIG.RTUNE_DEBUG.TYPE = 2 */
+       rtune_debug &= ~(0x3 << 3);
+       rtune_debug |= (0x2 << 3);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug);
+
+       /* read SUP.DIG.RTUNE_STAT (0x0004[9:0]) */
+       tx_imp = samsung_exynos_cal_cr_read(usbphy_info, 0x4);
+       /* current_tx_cal_code[9:0] = SUP.DIG.RTUNE_STAT (0x0004[9:0]) */
+       tx_imp += 8;
+       /* tx_cal_code[9:0] = current_tx_cal_code[9:0] + 8(decimal)
+        * NOTE, max value is 63;
+        * i.e. if tx_cal_code[9:0] > 63, tx_cal_code[9:0]==63; */
+       if (tx_imp > 63)
+               tx_imp = 63;
+
+       /* set LANEX_DIG_TX_OVRD_IN_HI.TX_RESET_OVRD = 1 */
+       tx_ovrd_in_hi = samsung_exynos_cal_cr_read(usbphy_info, 0x1001);
+       tx_ovrd_in_hi |= (1 << 7);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x1001, tx_ovrd_in_hi);
+
+       /* SUP.DIG.RTUNE_DEBUG.MAN_TUNE = 0 */
+       rtune_debug &= ~(1 << 1);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug);
+
+       /* set SUP.DIG.RTUNE_DEBUG.VALUE = tx_cal_code[9:0] */
+       rtune_debug &= ~(0x1ff << 5);
+       rtune_debug |= (tx_imp << 5);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug);
+
+       /* set SUP.DIG.RTUNE_DEBUG.SET_VAL = 1 */
+       rtune_debug |= (1 << 2);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug);
+
+       /* set SUP.DIG.RTUNE_DEBUG.SET_VAL = 0 */
+       rtune_debug &= ~(1 << 2);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x3, rtune_debug);
+
+       /* set LANEX_DIG_TX_OVRD_IN_HI.TX_RESET = 1 */
+       tx_ovrd_in_hi |= (1 << 6);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x1001, tx_ovrd_in_hi);
+
+       /* set LANEX_DIG_TX_OVRD_IN_HI.TX_RESET = 0 */
+       tx_ovrd_in_hi &= ~(1 << 6);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x1001, tx_ovrd_in_hi);
+}
+
+void samsung_exynos_cal_usb3phy_tune_adaptive_eq(
+       struct exynos_usbphy_info *usbphy_info, u8 eq_fix)
+{
+       u16 reg;
+
+       reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1006);
+       if (eq_fix) {
+               reg |= (1 << 6);
+               reg &= ~(1 << 7);
+       } else {
+               reg &= ~(1 << 6);
+               reg |= (1 << 7);
+       }
+       samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg);
+}
+
+void samsung_exynos_cal_usb3phy_tune_chg_rxeq(
+       struct exynos_usbphy_info *usbphy_info, u8 eq_val)
+{
+       u16 reg;
+
+       reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1006);
+       reg &= ~(0x7 << 0x8);
+       reg |= ((eq_val & 0x7) << 8);
+       reg |= (1 << 11);
+       samsung_exynos_cal_cr_write(usbphy_info, 0x1006, reg);
+}
+
+static void exynos_cal_ss_enable(struct exynos_usbphy_info *info,
+       u32 *arg_phyclkrst, u8 port_num)
+{
+       u32 phyclkrst = *arg_phyclkrst;
+       u32 phypipe;
+       u32 phyparam0;
+       u32 phyreg0;
+       void *reg_base;
+
+       if (port_num == 0)
+               reg_base = info->regs_base;
+       else
+               reg_base = info->regs_base_2nd;
+
+       if (info->version < EXYNOS_USBCON_VER_01_0_1)
+               phyclkrst |= PHYCLKRST_COMMONONN;
+
+       /* Disable Common block control by link */
+       phyclkrst &= ~PHYCLKRST_EN_UTMISUSPEND;
+
+       /* Digital Supply Mode : normal operating mode */
+       phyclkrst |= PHYCLKRST_RETENABLEN;
+
+       /* ref. clock enable for ss function */
+       phyclkrst |= PHYCLKRST_REF_SSP_EN;
+
+       phyparam0 = readl(info->regs_base + EXYNOS_USBCON_PHYPARAM0);
+       if (info->refsel == USBPHY_REFSEL_DIFF_PAD)
+               phyparam0 |= PHYPARAM0_REF_USE_PAD;
+       else
+               phyparam0 &= ~PHYPARAM0_REF_USE_PAD;
+       writel(phyparam0, reg_base + EXYNOS_USBCON_PHYPARAM0);
+
+       if (info->version >= EXYNOS_USBCON_VER_01_0_1)
+               phyreg0 = readl(reg_base + EXYNOS_USBCON_PHYREG0);
+
+       switch (info->refclk) {
+       case USBPHY_REFCLK_DIFF_100MHZ:
+               phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK;
+               phyclkrst |= PHYCLKRST_MPLL_MULTIPLIER(0x00);
+               phyclkrst &= ~PHYCLKRST_REF_CLKDIV2;
+               if (info->version == EXYNOS_USBCON_VER_01_0_1) {
+                       phyreg0 &= ~PHYREG0_SSC_REFCLKSEL_MASK;
+                       phyreg0 |= PHYREG0_SSC_REFCLKSEL(0x00);
+               } else {
+                       phyclkrst &= ~PHYCLKRST_SSC_REFCLKSEL_MASK;
+                       phyclkrst |= PHYCLKRST_SSC_REFCLKSEL(0x00);
+               }
+               break;
+       case USBPHY_REFCLK_DIFF_26MHZ:
+       case USBPHY_REFCLK_DIFF_52MHZ:
+               phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK;
+               phyclkrst |= PHYCLKRST_MPLL_MULTIPLIER(0x60);
+               if (info->refclk & 0x40)
+                       phyclkrst |= PHYCLKRST_REF_CLKDIV2;
+               else
+                       phyclkrst &= ~PHYCLKRST_REF_CLKDIV2;
+               if (info->version == EXYNOS_USBCON_VER_01_0_1) {
+                       phyreg0 &= ~PHYREG0_SSC_REFCLKSEL_MASK;
+                       phyreg0 |= PHYREG0_SSC_REFCLKSEL(0x108);
+               } else {
+                       phyclkrst &= ~PHYCLKRST_SSC_REFCLKSEL_MASK;
+                       phyclkrst |= PHYCLKRST_SSC_REFCLKSEL(0x108);
+               }
+               break;
+       case USBPHY_REFCLK_DIFF_24MHZ:
+       case USBPHY_REFCLK_EXT_24MHZ:
+               phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK;
+               phyclkrst |= PHYCLKRST_MPLL_MULTIPLIER(0x00);
+               phyclkrst &= ~PHYCLKRST_REF_CLKDIV2;
+               if (info->version != EXYNOS_USBCON_VER_01_0_1) {
+                       phyclkrst &= ~PHYCLKRST_SSC_REFCLKSEL_MASK;
+                       phyclkrst |= PHYCLKRST_SSC_REFCLKSEL(0x88);
+               } else {
+                       phyreg0 &= ~PHYREG0_SSC_REFCLKSEL_MASK;
+                       phyreg0 |= PHYREG0_SSC_REFCLKSEL(0x88);
+               }
+               break;
+       case USBPHY_REFCLK_DIFF_20MHZ:
+       case USBPHY_REFCLK_DIFF_19_2MHZ:
+               phyclkrst &= ~PHYCLKRST_MPLL_MULTIPLIER_MASK;
+               phyclkrst &= ~PHYCLKRST_REF_CLKDIV2;
+               if (info->version == EXYNOS_USBCON_VER_01_0_1)
+                       phyreg0 &= ~PHYREG0_SSC_REFCLKSEL_MASK;
+               else
+                       phyclkrst &= ~PHYCLKRST_SSC_REFCLKSEL_MASK;
+               break;
+       default:
+               break;
+       }
+       /* SSC Enable */
+       if (info->ss_tune) {
+               u32 range = info->ss_tune->ssc_range;
+
+               if (info->ss_tune->enable_ssc)
+                       phyclkrst |= PHYCLKRST_SSC_EN;
+               else
+                       phyclkrst &= ~PHYCLKRST_SSC_EN;
+
+               if (info->version != EXYNOS_USBCON_VER_01_0_1) {
+                       phyclkrst &= ~PHYCLKRST_SSC_RANGE_MASK;
+                       phyclkrst |= PHYCLKRST_SSC_RANGE(range);
+               } else {
+                       phyreg0 &= ~PHYREG0_SSC_RANGE_MASK;
+                       phyreg0 |= PHYREG0_SSC_RAMGE(range);
+               }
+       } else {
+               /* Default Value : SSC Enable */
+               phyclkrst |= PHYCLKRST_SSC_EN;
+               if (info->version != EXYNOS_USBCON_VER_01_0_1) {
+                       phyclkrst &= ~PHYCLKRST_SSC_RANGE_MASK;
+                       phyclkrst |= PHYCLKRST_SSC_RANGE(0x0);
+               } else {
+                       phyreg0 &= ~PHYREG0_SSC_RANGE_MASK;
+                       phyreg0 |= PHYREG0_SSC_RAMGE(0x0);
+               }
+       }
+
+       /* Select UTMI CLOCK 0 : PHY CLOCK, 1 : FREE CLOCK */
+       phypipe = readl(reg_base + EXYNOS_USBCON_PHYPIPE);
+       phypipe |= PHY_CLOCK_SEL;
+       writel(phypipe, reg_base + EXYNOS_USBCON_PHYPIPE);
+
+       if (info->version >= EXYNOS_USBCON_VER_01_0_1)
+               writel(phyreg0, reg_base + EXYNOS_USBCON_PHYREG0);
+
+       *arg_phyclkrst = phyclkrst;
+}
+
+static void exynos_cal_ss_power_down(struct exynos_usbphy_info *info, bool en)
+{
+       u32 phytest;
+
+       phytest = readl(info->regs_base + EXYNOS_USBCON_PHYTEST);
+       if (en == 1) {
+               phytest &= ~PHYTEST_POWERDOWN_HSP;
+               phytest &= ~PHYTEST_POWERDOWN_SSP;
+               writel(phytest, info->regs_base + EXYNOS_USBCON_PHYTEST);
+               if (info->used_phy_port == 1) {
+                       void *reg_base = info->regs_base_2nd;
+
+                       phytest |= PHYTEST_POWERDOWN_SSP;
+                       writel(phytest, info->regs_base + EXYNOS_USBCON_PHYTEST);
+
+                       phytest = readl(reg_base + EXYNOS_USBCON_PHYTEST);
+                       phytest &= ~PHYTEST_POWERDOWN_HSP;
+                       phytest &= ~PHYTEST_POWERDOWN_SSP;
+                       writel(phytest, reg_base + EXYNOS_USBCON_PHYTEST);
+               }
+       } else {
+               phytest |= PHYTEST_POWERDOWN_HSP;
+               phytest |= PHYTEST_POWERDOWN_SSP;
+               writel(phytest, info->regs_base + EXYNOS_USBCON_PHYTEST);
+               if (info->used_phy_port == 1) {
+                       void *reg_base = info->regs_base_2nd;
+
+                       phytest = readl(reg_base + EXYNOS_USBCON_PHYTEST);
+                       phytest |= PHYTEST_POWERDOWN_HSP;
+                       phytest |= PHYTEST_POWERDOWN_SSP;
+                       writel(phytest, reg_base + EXYNOS_USBCON_PHYTEST);
+               }
+       }
+}
+
+static void exynos_cal_hs_enable(struct exynos_usbphy_info *info,
+       u32 *arg_phyclkrst)
+{
+       u32 phyclkrst = *arg_phyclkrst;
+
+       u32 hsphyplltune = readl(info->regs_base + EXYNOS_USBCON_HSPHYPLLTUNE);
+
+       if ((info->version & 0xf0) >= 0x10) {
+               /* Disable Common block control by link */
+               phyclkrst |= PHYCLKRST_EN_UTMISUSPEND;
+               phyclkrst |= PHYCLKRST_COMMONONN;
+       } else {
+               phyclkrst |= PHYCLKRST_EN_UTMISUSPEND;
+               phyclkrst |= PHYCLKRST_COMMONONN;
+       }
+
+       /* Change PHY PLL Tune value */
+       if (info->refclk == USBPHY_REFCLK_EXT_24MHZ)
+               hsphyplltune |= HSPHYPLLTUNE_PLL_B_TUNE;
+       else
+               hsphyplltune &= ~HSPHYPLLTUNE_PLL_B_TUNE;
+       hsphyplltune |= HSPHYPLLTUNE_PLL_P_TUNE(0xe);
+       writel(hsphyplltune, info->regs_base + EXYNOS_USBCON_HSPHYPLLTUNE);
+
+       *arg_phyclkrst = phyclkrst;
+}
+
+static void exynos_cal_hs_power_down(struct exynos_usbphy_info *info, bool en)
+{
+       u32 hsphyctrl;
+
+       hsphyctrl = readl(info->regs_base + EXYNOS_USBCON_HSPHYCTRL);
+       if (en) {
+               hsphyctrl &= ~HSPHYCTRL_SIDDQ;
+               hsphyctrl &= ~HSPHYCTRL_PHYSWRST;
+               hsphyctrl &= ~HSPHYCTRL_PHYSWRSTALL;
+       } else {
+               hsphyctrl |= HSPHYCTRL_SIDDQ;
+       }
+       writel(hsphyctrl, info->regs_base + EXYNOS_USBCON_HSPHYCTRL);
+}
+
+static void exynos_cal_usbphy_q_ch(void *regs_base, u8 enable)
+{
+       u32 phy_resume;
+
+       if (enable) {
+               /* WA for Q-channel: disable all q-act from usb */
+               phy_resume = readl(regs_base + EXYNOS_USBCON_PHYRESUME);
+               phy_resume |= PHYRESUME_DIS_ID0_QACT;
+               phy_resume |= PHYRESUME_DIS_VBUSVALID_QACT;
+               phy_resume |= PHYRESUME_DIS_BVALID_QACT;
+               phy_resume |= PHYRESUME_DIS_LINKGATE_QACT;
+               //phy_resume |= PHYRESUME_DIS_BUSPEND_QACT;
+               phy_resume &= ~PHYRESUME_FORCE_QACT;
+               udelay(500);
+               writel(phy_resume, regs_base + EXYNOS_USBCON_PHYRESUME);
+               udelay(500);
+               phy_resume = readl(regs_base + EXYNOS_USBCON_PHYRESUME);
+               phy_resume |= PHYRESUME_FORCE_QACT;
+               udelay(500);
+               writel(phy_resume, regs_base + EXYNOS_USBCON_PHYRESUME);
+       } else {
+               phy_resume = readl(regs_base + EXYNOS_USBCON_PHYRESUME);
+               phy_resume &= ~PHYRESUME_FORCE_QACT;
+               phy_resume |= PHYRESUME_DIS_ID0_QACT;
+               phy_resume |= PHYRESUME_DIS_VBUSVALID_QACT;
+               phy_resume |= PHYRESUME_DIS_BVALID_QACT;
+               phy_resume |= PHYRESUME_DIS_LINKGATE_QACT;
+               //phy_resume |= PHYRESUME_DIS_BUSPEND_QACT;
+               writel(phy_resume, regs_base + EXYNOS_USBCON_PHYRESUME);
+       }
+}
+
+void samsung_exynos_cal_usb3phy_enable(struct exynos_usbphy_info *usbphy_info)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 version = usbphy_info->version;
+       enum exynos_usbphy_refclk refclkfreq = usbphy_info->refclk;
+       u32 phyutmi;
+       u32 phyclkrst;
+       u32 linkport;
+
+       /* check phycon version */
+       if (!usbphy_info->hw_version) {
+               u32 phyversion = readl(regs_base);
+
+               if (!phyversion) {
+                       usbphy_info->hw_version = -1;
+                       usbphy_info->used_phy_port = -1;
+               } else {
+                       usbphy_info->hw_version = phyversion;
+                       usbphy_info->regs_base += 4;
+                       regs_base = usbphy_info->regs_base;
+
+                       if (usbphy_info->regs_base_2nd)
+                               usbphy_info->regs_base_2nd += 4;
+               }
+       }
+
+       /* Set force q-channel */
+       if ((version & 0xf) >= 0x01)
+               exynos_cal_usbphy_q_ch(regs_base, 1);
+
+       /* Select PHY MUX */
+       if (usbphy_info->used_phy_port != -1) {
+               u32 physel;
+
+               physel = readl(regs_base + EXYNOS_USBCON_PHYSELECTION);
+               if (usbphy_info->used_phy_port == 0) {
+                       physel &= ~PHYSEL_PIPE;
+                       physel &= ~PHYSEL_PIPE_CLK;
+#if defined(USB_MUX_UTMI_ENABLE)
+                       /* UE_TASK: for utmi 2nd port test : will be removed */
+                       physel &= ~PHYSEL_UTMI_CLK;
+                       physel &= ~PHYSEL_UTMI;
+                       physel &= ~PHYSEL_SIDEBAND;
+#endif
+               } else {
+                       physel |= PHYSEL_PIPE;
+                       physel |= PHYSEL_PIPE_CLK;
+#if defined(USB_MUX_UTMI_ENABLE)
+                       /* UE_TASK: for utmi 2nd port test : will be removed */
+                       physel |= PHYSEL_UTMI_CLK;
+                       physel |= PHYSEL_UTMI;
+                       physel |= PHYSEL_SIDEBAND;
+#endif
+               }
+               writel(physel, regs_base + EXYNOS_USBCON_PHYSELECTION);
+       }
+
+       /* set phy clock & control HS phy */
+       phyclkrst = readl(regs_base + EXYNOS_USBCON_PHYCLKRST);
+
+       /* assert port_reset */
+       phyclkrst |= PHYCLKRST_PORTRESET;
+
+       /* Select Reference clock source path */
+       phyclkrst &= ~PHYCLKRST_REFCLKSEL_MASK;
+       phyclkrst |= PHYCLKRST_REFCLKSEL(usbphy_info->refsel);
+
+       /* Select ref clk */
+       phyclkrst &= ~PHYCLKRST_FSEL_MASK;
+       phyclkrst |= PHYCLKRST_FSEL(refclkfreq & 0x3f);
+
+       /* Enable Common Block in suspend/sleep mode */
+       phyclkrst &= ~PHYCLKRST_COMMONONN;
+
+       /* Additional control for 3.0 PHY */
+       if ((EXYNOS_USBCON_VER_01_0_0 <= version)
+                       && (version <= EXYNOS_USBCON_VER_01_MAX)) {
+               exynos_cal_ss_enable(usbphy_info, &phyclkrst, 0);
+               /* select used phy port */
+               if (usbphy_info->used_phy_port == 1) {
+                       void *reg_2nd = usbphy_info->regs_base_2nd;
+
+                       exynos_cal_ss_enable(usbphy_info, &phyclkrst, 1);
+
+                       writel(phyclkrst,
+                              reg_2nd + EXYNOS_USBCON_PHYCLKRST);
+                       udelay(10);
+
+                       phyclkrst &= ~PHYCLKRST_PORTRESET;
+                       writel(phyclkrst,
+                              reg_2nd + EXYNOS_USBCON_PHYCLKRST);
+
+                       phyclkrst |= PHYCLKRST_PORTRESET;
+               }
+       } else if ((EXYNOS_USBCON_VER_02_0_0 <= version)
+                       && (version <= EXYNOS_USBCON_VER_02_MAX))
+               exynos_cal_hs_enable(usbphy_info, &phyclkrst);
+
+       writel(phyclkrst, regs_base + EXYNOS_USBCON_PHYCLKRST);
+       udelay(10);
+
+       phyclkrst &= ~PHYCLKRST_PORTRESET;
+       writel(phyclkrst, regs_base + EXYNOS_USBCON_PHYCLKRST);
+
+       if ((EXYNOS_USBCON_VER_01_0_0 <= version)
+                       && (version <= EXYNOS_USBCON_VER_01_MAX)) {
+               exynos_cal_ss_power_down(usbphy_info, 1);
+       } else if (version >= EXYNOS_USBCON_VER_02_0_0
+                       && version <= EXYNOS_USBCON_VER_02_MAX) {
+               exynos_cal_hs_power_down(usbphy_info, 1);
+       }
+       udelay(500);
+
+       /* release force_sleep & force_suspend */
+       phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI);
+       phyutmi &= ~PHYUTMI_FORCESLEEP;
+       phyutmi &= ~PHYUTMI_FORCESUSPEND;
+
+       /* DP/DM Pull Down Control */
+       phyutmi &= ~PHYUTMI_DMPULLDOWN;
+       phyutmi &= ~PHYUTMI_DPPULLDOWN;
+
+       /* Set VBUSVALID signal if VBUS pad is not used */
+       if (usbphy_info->not_used_vbus_pad) {
+               u32 linksystem;
+
+               linksystem = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM);
+               linksystem |= LINKSYSTEM_FORCE_BVALID;
+               linksystem |= LINKSYSTEM_FORCE_VBUSVALID;
+               writel(linksystem, regs_base + EXYNOS_USBCON_LINKSYSTEM);
+#if defined(USB_MUX_UTMI_ENABLE)
+               /* UE_TASK: for utmi 2nd port test : will be removed */
+               if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1) {
+                       linksystem = readl(usbphy_info->regs_base_2nd + EXYNOS_USBCON_LINKSYSTEM);
+                       linksystem |= LINKSYSTEM_FORCE_BVALID;
+                       linksystem |= LINKSYSTEM_FORCE_VBUSVALID;
+                       writel(linksystem, usbphy_info->regs_base_2nd + EXYNOS_USBCON_LINKSYSTEM);
+               }
+#endif
+               phyutmi |= PHYUTMI_VBUSVLDEXTSEL;
+               phyutmi |= PHYUTMI_VBUSVLDEXT;
+       }
+
+       /* disable OTG block and VBUS valid comparator */
+       phyutmi &= ~PHYUTMI_DRVVBUS;
+       phyutmi |= PHYUTMI_OTGDISABLE;
+       writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI);
+
+#if defined(USB_MUX_UTMI_ENABLE)
+       /* UE_TASK: for utmi 2nd port test : will be removed */
+       if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1)
+               writel(phyutmi, usbphy_info->regs_base_2nd + EXYNOS_USBCON_PHYUTMI);
+#endif
+
+       /* OVC io usage */
+       linkport = readl(regs_base + EXYNOS_USBCON_LINKPORT);
+       if (usbphy_info->use_io_for_ovc) {
+               linkport &= ~LINKPORT_HOST_PORT_OVCR_U3_SEL;
+               linkport &= ~LINKPORT_HOST_PORT_OVCR_U2_SEL;
+       } else {
+               linkport |= LINKPORT_HOST_PORT_OVCR_U3_SEL;
+               linkport |= LINKPORT_HOST_PORT_OVCR_U2_SEL;
+       }
+       writel(linkport, regs_base + EXYNOS_USBCON_LINKPORT);
+
+       if ((EXYNOS_USBCON_VER_02_0_0 <= version)
+                               && (version <= EXYNOS_USBCON_VER_02_MAX)) {
+
+               u32 hsphyctrl;
+
+               hsphyctrl = readl(regs_base + EXYNOS_USBCON_HSPHYCTRL);
+               hsphyctrl |= HSPHYCTRL_PHYSWRST;
+               writel(hsphyctrl, regs_base + EXYNOS_USBCON_HSPHYCTRL);
+               udelay(20);
+               hsphyctrl = readl(regs_base + EXYNOS_USBCON_HSPHYCTRL);
+               hsphyctrl &= ~HSPHYCTRL_PHYSWRST;
+               writel(hsphyctrl, regs_base + EXYNOS_USBCON_HSPHYCTRL);
+       }
+}
+
+void samsung_exynos_cal_usb3phy_late_enable(
+       struct exynos_usbphy_info *usbphy_info)
+{
+       u32 version = usbphy_info->version;
+       struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune;
+
+       if (EXYNOS_USBCON_VER_01_0_0 <= version
+                       && version <= EXYNOS_USBCON_VER_01_MAX) {
+               /* Set RXDET_MEAS_TIME[11:4] each reference clock */
+               samsung_exynos_cal_cr_write(usbphy_info, 0x1010, 0x80);
+               printk("Check CR Port write 0x1010: 0x%x\n",
+                       samsung_exynos_cal_cr_read(usbphy_info, 0x1010));
+               if (tune) {
+#if defined(USB_SS_TX_TUNE_PCS)
+                       samsung_exynos_cal_cr_write(usbphy_info,
+                                       0x1002, 0x4000 |
+                                       (tune->tx_deemphasis_3p5db << 7) |
+                                       tune->tx_swing_full);
+#else
+                       samsung_exynos_cal_cr_write(usbphy_info, 0x1002, 0x0);
+#endif
+                       /* Set RX_SCOPE_LFPS_EN */
+                       if (tune->rx_decode_mode) {
+                               samsung_exynos_cal_cr_write(usbphy_info,
+                                                           0x1026, 0x1);
+                       }
+                       if (tune->set_crport_level_en) {
+                               /* Enable override los_bias, los_level and
+                                * tx_vboost_lvl, Set los_bias to 0x5 and
+                                * los_level to 0x9 */
+                               samsung_exynos_cal_cr_write(usbphy_info,
+                                                           0x15, 0xA409);
+                               /* Set TX_VBOOST_LEVLE to default Value (0x4) */
+                               samsung_exynos_cal_cr_write(usbphy_info,
+                                       0x12, 0x8000);
+                       }
+                       /* to set the charge pump proportional current */
+                       if (tune->set_crport_mpll_charge_pump) {
+                               samsung_exynos_cal_cr_write(usbphy_info,
+                                                           0x30, 0xC0);
+                       }
+                       if (tune->enable_fixed_rxeq_mode) {
+                               samsung_exynos_cal_usb3phy_tune_fix_rxeq(
+                                               usbphy_info);
+                       }
+                       set_ss_tx_impedance(usbphy_info);
+               }
+       }
+}
+
+void samsung_exynos_cal_usb3phy_disable(struct exynos_usbphy_info *usbphy_info)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 version = usbphy_info->version;
+       u32 phyutmi;
+       u32 phyclkrst;
+
+       phyclkrst = readl(regs_base + EXYNOS_USBCON_PHYCLKRST);
+       phyclkrst |= PHYCLKRST_EN_UTMISUSPEND;
+       phyclkrst |= PHYCLKRST_COMMONONN;
+       phyclkrst |= PHYCLKRST_RETENABLEN;
+       phyclkrst &= ~PHYCLKRST_REF_SSP_EN;
+       phyclkrst &= ~PHYCLKRST_SSC_EN;
+       /* Select Reference clock source path */
+       phyclkrst &= ~PHYCLKRST_REFCLKSEL_MASK;
+       phyclkrst |= PHYCLKRST_REFCLKSEL(usbphy_info->refsel);
+
+       /* Select ref clk */
+       phyclkrst &= ~PHYCLKRST_FSEL_MASK;
+       phyclkrst |= PHYCLKRST_FSEL(usbphy_info->refclk & 0x3f);
+       writel(phyclkrst, regs_base + EXYNOS_USBCON_PHYCLKRST);
+
+       phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI);
+       phyutmi &= ~PHYUTMI_IDPULLUP;
+       phyutmi &= ~PHYUTMI_DRVVBUS;
+       phyutmi |= PHYUTMI_FORCESUSPEND;
+       phyutmi |= PHYUTMI_FORCESLEEP;
+       if (usbphy_info->not_used_vbus_pad) {
+               phyutmi &= ~PHYUTMI_VBUSVLDEXTSEL;
+               phyutmi &= ~PHYUTMI_VBUSVLDEXT;
+       }
+       writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI);
+
+       if ((EXYNOS_USBCON_VER_01_0_0 <= version)
+                       && (version <= EXYNOS_USBCON_VER_01_MAX)) {
+               exynos_cal_ss_power_down(usbphy_info, 0);
+       } else if (version >= EXYNOS_USBCON_VER_02_0_0
+                       && version <= EXYNOS_USBCON_VER_02_MAX) {
+               exynos_cal_hs_power_down(usbphy_info, 0);
+       }
+
+       /* Clear VBUSVALID signal if VBUS pad is not used */
+       if (usbphy_info->not_used_vbus_pad) {
+               u32 linksystem;
+
+               linksystem = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM);
+               linksystem &= ~LINKSYSTEM_FORCE_BVALID;
+               linksystem &= ~LINKSYSTEM_FORCE_VBUSVALID;
+               writel(linksystem, regs_base + EXYNOS_USBCON_LINKSYSTEM);
+       }
+
+       /* Set force q-channel */
+       if ((version & 0xf) >= 0x01)
+               exynos_cal_usbphy_q_ch(regs_base, 0);
+}
+
+void samsung_exynos_cal_usb3phy_config_host_mode(
+               struct exynos_usbphy_info *usbphy_info)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 phyutmi;
+
+       phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI);
+       phyutmi |= PHYUTMI_DMPULLDOWN;
+       phyutmi |= PHYUTMI_DPPULLDOWN;
+       phyutmi &= ~PHYUTMI_VBUSVLDEXTSEL;
+       phyutmi &= ~PHYUTMI_VBUSVLDEXT;
+       writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI);
+}
+
+void samsung_exynos_cal_usb3phy_enable_dp_pullup(
+               struct exynos_usbphy_info *usbphy_info)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 phyutmi;
+
+       phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI);
+       phyutmi |= PHYUTMI_VBUSVLDEXT;
+       writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI);
+}
+
+void samsung_exynos_cal_usb3phy_disable_dp_pullup(
+               struct exynos_usbphy_info *usbphy_info)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 phyutmi;
+
+       phyutmi = readl(regs_base + EXYNOS_USBCON_PHYUTMI);
+       phyutmi &= ~PHYUTMI_VBUSVLDEXT;
+       writel(phyutmi, regs_base + EXYNOS_USBCON_PHYUTMI);
+}
+
+void samsung_exynos_cal_usb3phy_tune_each(
+       struct exynos_usbphy_info *usbphy_info,
+       enum exynos_usbphy_tune_para para,
+       int val)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 reg;
+
+#if defined(USB_MUX_UTMI_ENABLE)
+       /* UE_TASK: for utmi 2nd port test : will be removed */
+       if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1)
+               regs_base = usbphy_info->regs_base_2nd;
+#endif
+
+       if (para < 0x10000) {
+               struct exynos_usbphy_hs_tune *tune = usbphy_info->hs_tune;
+
+               reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM0);
+               switch ((int) para) {
+               case USBPHY_TUNE_HS_COMPDIS:
+                       reg &= ~PHYPARAM0_COMPDISTUNE_MASK;
+                       reg |= PHYPARAM0_COMPDISTUNE(val);
+                       if (tune)
+                               tune->compdis = val;
+                       break;
+               case USBPHY_TUNE_HS_OTG:
+                       reg &= ~PHYPARAM0_OTGTUNE_MASK;
+                       reg |= PHYPARAM0_OTGTUNE(val);
+                       if (tune)
+                               tune->otg = val;
+                       break;
+               case USBPHY_TUNE_HS_SQRX:
+                       reg &= ~PHYPARAM0_SQRXTUNE_MASK;
+                       reg |= PHYPARAM0_SQRXTUNE(val);
+                       if (tune)
+                               tune->rx_sqrx = val;
+                       break;
+               case USBPHY_TUNE_HS_TXFSLS:
+                       reg &= ~PHYPARAM0_TXFSLSTUNE_MASK;
+                       reg |= PHYPARAM0_TXFSLSTUNE(val);
+                       if (tune)
+                               tune->tx_fsls = val;
+                       break;
+               case USBPHY_TUNE_HS_TXHSXV:
+                       reg &= ~PHYPARAM0_TXHSXVTUNE_MASK;
+                       reg |= PHYPARAM0_TXHSXVTUNE(val);
+                       if (tune)
+                               tune->tx_hsxv = val;
+                       break;
+               case USBPHY_TUNE_HS_TXPREEMP:
+                       reg &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK;
+                       reg |= PHYPARAM0_TXPREEMPAMPTUNE(val);
+                       if (tune)
+                               tune->tx_pre_emp = val;
+                       break;
+               case USBPHY_TUNE_HS_TXPREEMP_PLUS:
+                       if (val)
+                               reg |= PHYPARAM0_TXPREEMPPULSETUNE;
+                       else
+                               reg &= ~PHYPARAM0_TXPREEMPPULSETUNE;
+                       if (tune)
+                               tune->tx_pre_emp_plus = val & 0x1;
+                       break;
+               case USBPHY_TUNE_HS_TXRES:
+                       reg &= ~PHYPARAM0_TXRESTUNE_MASK;
+                       reg |= PHYPARAM0_TXRESTUNE(val);
+                       if (tune)
+                               tune->tx_res = val;
+                       break;
+               case USBPHY_TUNE_HS_TXRISE:
+                       reg &= ~PHYPARAM0_TXRISETUNE_MASK;
+                       reg |= PHYPARAM0_TXRISETUNE(val);
+                       if (tune)
+                               tune->tx_rise = val;
+                       break;
+               case USBPHY_TUNE_HS_TXVREF:
+                       reg &= ~PHYPARAM0_TXVREFTUNE_MASK;
+                       reg |= PHYPARAM0_TXVREFTUNE(val);
+                       if (tune)
+                               tune->tx_vref = val;
+                       break;
+               }
+               writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM0);
+       } else {
+               struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune;
+
+               if (usbphy_info->used_phy_port != -1) {
+                       if (usbphy_info->used_phy_port == 0)
+                               regs_base = usbphy_info->regs_base;
+                       else
+                               regs_base = usbphy_info->regs_base_2nd;
+               }
+
+               switch ((int) para) {
+               case USBPHY_TUNE_SS_FIX_EQ:
+                       samsung_exynos_cal_usb3phy_tune_adaptive_eq(usbphy_info,
+                                                                   val);
+                       if (tune)
+                               tune->enable_fixed_rxeq_mode = val & 0x1;
+                       break;
+               case USBPHY_TUNE_SS_RX_EQ:
+                       samsung_exynos_cal_usb3phy_tune_chg_rxeq(usbphy_info,
+                                                                val);
+                       if (tune)
+                               tune->fix_rxeq_value = val & 0xf;
+                       break;
+               case USBPHY_TUNE_SS_TX_BOOST:
+                       reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM2);
+                       reg &= ~PHYPARAM2_TX_VBOOST_LVL_MASK;
+                       reg |= PHYPARAM2_TX_VBOOST_LVL(val);
+                       writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM2);
+                       if (tune)
+                               tune->tx_boost_level = val;
+                       break;
+               case USBPHY_TUNE_SS_TX_SWING:
+#if !defined(USB_SS_TX_TUNE_PCS)
+                       reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM1);
+                       reg &= ~PHYPARAM1_PCS_TXSWING_FULL_MASK;
+                       reg |= PHYPARAM1_PCS_TXSWING_FULL(val);
+                       writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM1);
+#else
+                       reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1002);
+                       reg &= ~0x7f;
+                       reg |= val;
+                       samsung_exynos_cal_cr_write(usbphy_info,
+                                                        0x1002, 0x4000 | reg);
+#endif
+                       if (tune)
+                               tune->tx_swing_full = val;
+                       break;
+               case USBPHY_TUNE_SS_TX_DEEMPHASIS:
+#if !defined(USB_SS_TX_TUNE_PCS)
+                       reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM1);
+                       reg &= ~PHYPARAM1_PCS_TXDEEMPH_3P5DB_MASK;
+                       reg |= PHYPARAM1_PCS_TXDEEMPH_3P5DB(val);
+                       writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM1);
+#else
+                       reg = samsung_exynos_cal_cr_read(usbphy_info, 0x1002);
+                       reg &= ~(0x3f << 7);
+                       reg |= (val & 0x3f) << 7;
+                       samsung_exynos_cal_cr_write(usbphy_info,
+                                                        0x1002, 0x4000 | reg);
+#endif
+                       if (tune)
+                               tune->tx_deemphasis_3p5db = val;
+                       break;
+               }
+
+       }
+}
+
+void samsung_exynos_cal_usb3phy_hs_tune_extract(
+       struct exynos_usbphy_info *usbphy_info)
+{
+       struct exynos_usbphy_hs_tune *hs_tune;
+       u32 reg;
+
+       hs_tune = usbphy_info->hs_tune;
+
+       if (!hs_tune)
+               return;
+
+       reg = readl(usbphy_info->regs_base + EXYNOS_USBCON_PHYPARAM0);
+
+       hs_tune->tx_vref = PHYPARAM0_TXVREFTUNE_EXT(reg);
+       hs_tune->tx_rise = PHYPARAM0_TXRISETUNE_EXT(reg);
+       hs_tune->tx_res = PHYPARAM0_TXRESTUNE_EXT(reg);
+       hs_tune->tx_pre_emp_plus = PHYPARAM0_TXPREEMPPULSETUNE_EXT(reg);
+       hs_tune->tx_pre_emp = PHYPARAM0_TXPREEMPAMPTUNE_EXT(reg);
+       hs_tune->tx_hsxv = PHYPARAM0_TXHSXVTUNE_EXT(reg);
+       hs_tune->tx_fsls = PHYPARAM0_TXFSLSTUNE_EXT(reg);
+       hs_tune->rx_sqrx = PHYPARAM0_SQRXTUNE_EXT(reg);
+       hs_tune->otg = PHYPARAM0_OTGTUNE_EXT(reg);
+       hs_tune->compdis = PHYPARAM0_COMPDISTUNE_EXT(reg);
+}
+
+void samsung_exynos_cal_usb3phy_tune_dev(struct exynos_usbphy_info *usbphy_info)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 reg;
+
+#if defined(USB_MUX_UTMI_ENABLE)
+       /* UE_TASK: for utmi 2nd port test : will be removed */
+       if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1)
+               regs_base = usbphy_info->regs_base_2nd;
+#endif
+
+       /* Set the LINK Version Control and Frame Adjust Value */
+       reg = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM);
+       reg &= ~LINKSYSTEM_FLADJ_MASK;
+       reg |= LINKSYSTEM_FLADJ(0x20);
+       reg |= LINKSYSTEM_XHCI_VERSION_CONTROL;
+       writel(reg, regs_base + EXYNOS_USBCON_LINKSYSTEM);
+
+       /* Tuning the HS Block of phy */
+       if (usbphy_info->hs_tune) {
+               struct exynos_usbphy_hs_tune *tune = usbphy_info->hs_tune;
+
+               /* Set tune value for 2.0(HS/FS) function */
+               reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM0);
+               /* TX VREF TUNE */
+               reg &= ~PHYPARAM0_TXVREFTUNE_MASK;
+               reg |= PHYPARAM0_TXVREFTUNE(tune->tx_vref);
+               /* TX RISE TUNE */
+               reg &= ~PHYPARAM0_TXRISETUNE_MASK;
+               reg |= PHYPARAM0_TXRISETUNE(tune->tx_rise);
+               /* TX RES TUNE */
+               reg &= ~PHYPARAM0_TXRESTUNE_MASK;
+               reg |= PHYPARAM0_TXRESTUNE(tune->tx_res);
+               /* TX PRE EMPHASIS PLUS */
+               if (tune->tx_pre_emp_plus)
+                       reg |= PHYPARAM0_TXPREEMPPULSETUNE;
+               else
+                       reg &= ~PHYPARAM0_TXPREEMPPULSETUNE;
+               /* TX PRE EMPHASIS */
+               reg &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK;
+               reg |= PHYPARAM0_TXPREEMPAMPTUNE(tune->tx_pre_emp);
+               /* TX HS XV TUNE */
+               reg &= ~PHYPARAM0_TXHSXVTUNE_MASK;
+               reg |= PHYPARAM0_TXHSXVTUNE(tune->tx_hsxv);
+               /* TX FSLS TUNE */
+               reg &= ~PHYPARAM0_TXFSLSTUNE_MASK;
+               reg |= PHYPARAM0_TXFSLSTUNE(tune->tx_fsls);
+               /* RX SQ TUNE */
+               reg &= ~PHYPARAM0_SQRXTUNE_MASK;
+               reg |= PHYPARAM0_SQRXTUNE(tune->rx_sqrx);
+               /* OTG TUNE */
+               reg &= ~PHYPARAM0_OTGTUNE_MASK;
+               reg |= PHYPARAM0_OTGTUNE(tune->otg);
+               /* COM DIS TUNE */
+               reg &= ~PHYPARAM0_COMPDISTUNE_MASK;
+               reg |= PHYPARAM0_COMPDISTUNE(tune->compdis);
+
+               writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM0);
+       }
+
+       /* Tuning the SS Block of phy */
+       if (usbphy_info->ss_tune) {
+               struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune;
+
+               if (usbphy_info->used_phy_port != -1) {
+                       if (usbphy_info->used_phy_port == 0)
+                               regs_base = usbphy_info->regs_base;
+                       else
+                               regs_base = usbphy_info->regs_base_2nd;
+               }
+#if !defined(USB_SS_TX_TUNE_PCS)
+               /* Set the PHY Signal Quality Tuning Value */
+               reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM1);
+               /* TX SWING FULL */
+               reg &= ~PHYPARAM1_PCS_TXSWING_FULL_MASK;
+               reg |= PHYPARAM1_PCS_TXSWING_FULL(tune->tx_swing_full);
+               /* TX DE EMPHASIS 3.5 dB */
+               reg &= ~PHYPARAM1_PCS_TXDEEMPH_3P5DB_MASK;
+               reg |= PHYPARAM1_PCS_TXDEEMPH_3P5DB(
+                               tune->tx_deemphasis_3p5db);
+               writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM1);
+#endif
+
+               /* Set vboost value for eye diagram */
+               reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM2);
+               /* TX VBOOST Value */
+               reg &= ~PHYPARAM2_TX_VBOOST_LVL_MASK;
+               reg |= PHYPARAM2_TX_VBOOST_LVL(tune->tx_boost_level);
+               /* LOS BIAS */
+               reg &= ~PHYPARAM2_LOS_BIAS_MASK;
+               reg |= PHYPARAM2_LOS_BIAS(tune->los_bias);
+               writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM2);
+
+               /*
+                * Set pcs_rx_los_mask_val for 14nm PHY to mask the abnormal
+                * LFPS and glitches
+                */
+               reg = readl(regs_base + EXYNOS_USBCON_PHYPCSVAL);
+               reg &= ~PHYPCSVAL_PCS_RX_LOS_MASK_VAL_MASK;
+               reg |= PHYPCSVAL_PCS_RX_LOS_MASK_VAL(tune->los_mask_val);
+               writel(reg, regs_base + EXYNOS_USBCON_PHYPCSVAL);
+       }
+}
+
+void samsung_exynos_cal_usb3phy_tune_host(
+               struct exynos_usbphy_info *usbphy_info)
+{
+       void __iomem *regs_base = usbphy_info->regs_base;
+       u32 reg;
+
+#if defined(USB_MUX_UTMI_ENABLE)
+       /* UE_TASK: for utmi 2nd port test : will be removed */
+       if (usbphy_info->regs_base_2nd && usbphy_info->used_phy_port == 1)
+               regs_base = usbphy_info->regs_base_2nd;
+#endif
+
+       /* Set the LINK Version Control and Frame Adjust Value */
+       reg = readl(regs_base + EXYNOS_USBCON_LINKSYSTEM);
+       reg &= ~LINKSYSTEM_FLADJ_MASK;
+       reg |= LINKSYSTEM_FLADJ(0x20);
+       reg |= LINKSYSTEM_XHCI_VERSION_CONTROL;
+       writel(reg, regs_base + EXYNOS_USBCON_LINKSYSTEM);
+
+       /* Tuning the HS Block of phy */
+       if (usbphy_info->hs_tune) {
+               struct exynos_usbphy_hs_tune *tune = usbphy_info->hs_tune;
+
+               /* Set tune value for 2.0(HS/FS) function */
+               reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM0);
+               /* TX VREF TUNE */
+               reg &= ~PHYPARAM0_TXVREFTUNE_MASK;
+               reg |= PHYPARAM0_TXVREFTUNE(tune->tx_vref);
+               /* TX RISE TUNE */
+               reg &= ~PHYPARAM0_TXRISETUNE_MASK;
+               reg |= PHYPARAM0_TXRISETUNE(tune->tx_rise);
+               /* TX RES TUNE */
+               reg &= ~PHYPARAM0_TXRESTUNE_MASK;
+               reg |= PHYPARAM0_TXRESTUNE(tune->tx_res);
+               /* TX PRE EMPHASIS PLUS */
+               if (tune->tx_pre_emp_plus)
+                       reg |= PHYPARAM0_TXPREEMPPULSETUNE;
+               else
+                       reg &= ~PHYPARAM0_TXPREEMPPULSETUNE;
+               /* TX PRE EMPHASIS */
+               reg &= ~PHYPARAM0_TXPREEMPAMPTUNE_MASK;
+               reg |= PHYPARAM0_TXPREEMPAMPTUNE(tune->tx_pre_emp);
+               /* TX HS XV TUNE */
+               reg &= ~PHYPARAM0_TXHSXVTUNE_MASK;
+               reg |= PHYPARAM0_TXHSXVTUNE(tune->tx_hsxv);
+               /* TX FSLS TUNE */
+               reg &= ~PHYPARAM0_TXFSLSTUNE_MASK;
+               reg |= PHYPARAM0_TXFSLSTUNE(tune->tx_fsls);
+               /* RX SQ TUNE */
+               reg &= ~PHYPARAM0_SQRXTUNE_MASK;
+               reg |= PHYPARAM0_SQRXTUNE(tune->rx_sqrx);
+               /* OTG TUNE */
+               reg &= ~PHYPARAM0_OTGTUNE_MASK;
+               reg |= PHYPARAM0_OTGTUNE(tune->otg);
+               /* COM DIS TUNE */
+               reg &= ~PHYPARAM0_COMPDISTUNE_MASK;
+               reg |= PHYPARAM0_COMPDISTUNE(tune->compdis);
+
+               writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM0);
+       }
+
+       /* Tuning the SS Block of phy */
+       if (usbphy_info->ss_tune) {
+               struct exynos_usbphy_ss_tune *tune = usbphy_info->ss_tune;
+
+               if (usbphy_info->used_phy_port != -1) {
+                       if (usbphy_info->used_phy_port == 0)
+                               regs_base = usbphy_info->regs_base;
+                       else
+                               regs_base = usbphy_info->regs_base_2nd;
+               }
+#if !defined(USB_SS_TX_TUNE_PCS)
+               /* Set the PHY Signal Quality Tuning Value */
+               reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM1);
+               /* TX SWING FULL */
+               reg &= ~PHYPARAM1_PCS_TXSWING_FULL_MASK;
+               reg |= PHYPARAM1_PCS_TXSWING_FULL(tune->tx_swing_full);
+               /* TX DE EMPHASIS 3.5 dB */
+               reg &= ~PHYPARAM1_PCS_TXDEEMPH_3P5DB_MASK;
+               reg |= PHYPARAM1_PCS_TXDEEMPH_3P5DB(
+                               tune->tx_deemphasis_3p5db);
+               writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM1);
+#endif
+
+               /* Set vboost value for eye diagram */
+               reg = readl(regs_base + EXYNOS_USBCON_PHYPARAM2);
+               /* TX VBOOST Value */
+               reg &= ~PHYPARAM2_TX_VBOOST_LVL_MASK;
+               reg |= PHYPARAM2_TX_VBOOST_LVL(tune->tx_boost_level);
+               /* LOS BIAS */
+               reg &= ~PHYPARAM2_LOS_BIAS_MASK;
+               reg |= PHYPARAM2_LOS_BIAS(tune->los_bias);
+               writel(reg, regs_base + EXYNOS_USBCON_PHYPARAM2);
+
+               /*
+                * Set pcs_rx_los_mask_val for 14nm PHY to mask the abnormal
+                * LFPS and glitches
+                */
+               reg = readl(regs_base + EXYNOS_USBCON_PHYPCSVAL);
+               reg &= ~PHYPCSVAL_PCS_RX_LOS_MASK_VAL_MASK;
+               reg |= PHYPCSVAL_PCS_RX_LOS_MASK_VAL(tune->los_mask_val);
+               writel(reg, regs_base + EXYNOS_USBCON_PHYPCSVAL);
+       }
+}
diff --git a/drivers/phy/samsung/phy-samsung-usb3-cal.h b/drivers/phy/samsung/phy-samsung-usb3-cal.h
new file mode 100644 (file)
index 0000000..af1e416
--- /dev/null
@@ -0,0 +1,278 @@
+#ifndef __PHY_SAMSUNG_USB3_FW_CAL_H__
+#define __PHY_SAMSUNG_USB3_FW_CAL_H__
+
+#define EXYNOS_USBCON_LINKSYSTEM       (0x04)
+#define LINKSYSTEM_HOST_SYSTEM_ERR             (0x1 << 31)
+#define LINKSYSTEM_PHY_POWER_DOWN              (0x1 << 30)
+#define LINKSYSTEM_PHY_SW_RESET                        (0x1 << 29)
+#define LINKSYSTEM_LINK_SW_RESET               (0x1 << 28)
+#define LINKSYSTEM_XHCI_VERSION_CONTROL                (0x1 << 27)
+#define LINKSYSTEM_FLADJ_MASK                  (0x3f << 1)
+#define LINKSYSTEM_FLADJ(_x)                   ((_x) << 1)
+#define LINKSYSTEM_FORCE_BVALID                        (0x1 << 7)
+#define LINKSYSTEM_FORCE_VBUSVALID             (0x1 << 8)
+
+#define EXYNOS_USBCON_PHYUTMI          (0x08)
+#define PHYUTMI_UTMI_SUSPEND_COM_N             (0x1 << 12)
+#define PHYUTMI_UTMI_L1_SUSPEND_COM_N          (0x1 << 11)
+#define PHYUTMI_VBUSVLDEXTSEL                  (0x1 << 10)
+#define PHYUTMI_VBUSVLDEXT                     (0x1 << 9)
+#define PHYUTMI_TXBITSTUFFENH                  (0x1 << 8)
+#define PHYUTMI_TXBITSTUFFEN                   (0x1 << 7)
+#define PHYUTMI_OTGDISABLE                     (0x1 << 6)
+#define PHYUTMI_OTGDISABLE                     (0x1 << 6)
+#define PHYUTMI_IDPULLUP                       (0x1 << 5)
+#define PHYUTMI_DRVVBUS                                (0x1 << 4)
+#define PHYUTMI_DPPULLDOWN                     (0x1 << 3)
+#define PHYUTMI_DMPULLDOWN                     (0x1 << 2)
+#define PHYUTMI_FORCESUSPEND                   (0x1 << 1)
+#define PHYUTMI_FORCESLEEP                     (0x1 << 0)
+
+#define EXYNOS_USBCON_PHYCLKRST                (0x10)
+#define PHYCLKRST_EN_UTMISUSPEND               (0x1 << 31)
+#define PHYCLKRST_SSC_REFCLKSEL_MASK           (0xff << 23)
+#define PHYCLKRST_SSC_REFCLKSEL(_x)            ((_x) << 23)
+#define PHYCLKRST_SSC_RANGE_MASK               (0x03 << 21)
+#define PHYCLKRST_SSC_RANGE(_x)                        ((_x) << 21)
+#define PHYCLKRST_SSC_EN                       (0x1 << 20)
+#define PHYCLKRST_REF_SSP_EN                   (0x1 << 19)
+#define PHYCLKRST_REF_CLKDIV2                  (0x1 << 18)
+#define PHYCLKRST_MPLL_MULTIPLIER_MASK         (0x7f << 11)
+#define PHYCLKRST_MPLL_MULTIPLIER(_x)          ((_x) << 11)
+#define PHYCLKRST_FSEL_MASK                    (0x3f << 5)
+#define PHYCLKRST_FSEL(_x)                     ((_x) << 5)
+#define PHYCLKRST_RETENABLEN                   (0x1 << 4)
+#define PHYCLKRST_REFCLKSEL_MASK               (0x03 << 2)
+#define PHYCLKRST_REFCLKSEL(_x)                        ((_x) << 2)
+#define PHYCLKRST_PORTRESET                    (0x1 << 1)
+#define PHYCLKRST_COMMONONN                    (0x1 << 0)
+
+#define EXYNOS_USBCON_PHYPIPE          (0x0c)
+#define PHYPIPE_PHY_CLOCK_SEL                          (0x1 << 4)
+
+#define EXYNOS_USBCON_PHYREG0          (0x14)
+#define PHYREG0_SSC_REFCLKSEL_MASK             (0x1ff << 23)
+#define PHYREG0_SSC_REFCLKSEL(_x)              ((_x) << 23)
+#define PHYREG0_SSC_RANGE_MASK                 (0x7 << 20)
+#define PHYREG0_SSC_RAMGE(_x)                  ((_x) << 20)
+#define PHYREG0_CR_WRITE                       (1 << 19)
+#define PHYREG0_CR_READ                                (1 << 18)
+#define PHYREG0_CR_DATA_MASK                   (0xffff << 2)
+#define PHYREG0_CR_DATA_IN(_x)                 ((_x) << 2)
+#define PHYREG0_CR_CR_CAP_DATA                 (1 << 1)
+#define PHYREG0_CR_CR_CAP_ADDR                 (1 << 0)
+
+#define EXYNOS_USBCON_PHYREG1          (0x18)
+#define PHYREG1_CR_DATA_OUT_MASK               (0xffff << 1)
+#define PHYREG1_CR_DATA_OUT(_x)                        ((_x) << 1)
+#define PHYREG1_CR_ACK                         (1 << 0)
+
+#define EXYNOS_USBCON_PHYPARAM0                (0x1c)
+#define PHYPARAM0_REF_USE_PAD                  (0x1 << 31)
+#define PHYPARAM0_VDATAREFTUNE_MASK            (0x3 << 26)
+#define PHYPARAM0_VDATAREFTUNE(_x)             ((_x) << 26)
+#define PHYPARAM0_REF_LOSLEVEL_MASK            (0x1f << 26)
+#define PHYPARAM0_REF_LOSLEVEL_EXT(_x)         ((_x & (0x1f << 26)) >> 26)
+#define PHYPARAM0_REF_LOSLEVEL                 (0x9 << 26)
+#define PHYPARAM0_TXVREFTUNE_MASK              (0xf << 22)
+#define PHYPARAM0_TXVREFTUNE_EXT(_x)           ((_x & (0xf << 22)) >> 22)
+#define PHYPARAM0_TXVREFTUNE(_x)               ((_x) << 22)
+#define PHYPARAM0_TXRISETUNE_MASK              (0x3 << 20)
+#define PHYPARAM0_TXRISETUNE_EXT(_x)           ((_x & (0x3 << 20)) >> 20)
+#define PHYPARAM0_TXRISETUNE(_x)               ((_x) << 20)
+#define PHYPARAM0_TXRESTUNE_MASK               (0x3 << 18)
+#define PHYPARAM0_TXRESTUNE_EXT(_x)            ((_x & (0x3 << 18)) >> 18)
+#define PHYPARAM0_TXRESTUNE(_x)                        ((_x) << 18)
+#define PHYPARAM0_TXPREEMPPULSETUNE            (0x1 << 17)
+#define PHYPARAM0_TXPREEMPPULSETUNE_EXT(_x)    ((_x & (0x1 << 17)) >> 17)
+#define PHYPARAM0_TXPREEMPAMPTUNE_MASK         (0x3 << 15)
+#define PHYPARAM0_TXPREEMPAMPTUNE_EXT(_x)      ((_x & (0x3 << 15)) >> 15)
+#define PHYPARAM0_TXPREEMPAMPTUNE(_x)          ((_x) << 15)
+#define PHYPARAM0_TXHSXVTUNE_MASK              (0x3 << 13)
+#define PHYPARAM0_TXHSXVTUNE_EXT(_x)           ((_x & (0x3 << 13)) >> 13)
+#define PHYPARAM0_TXHSXVTUNE(_x)               ((_x) << 13)
+#define PHYPARAM0_TXFSLSTUNE_MASK              (0xf << 9)
+#define PHYPARAM0_TXFSLSTUNE_EXT(_x)           ((_x & (0xf << 9)) >> 9)
+#define PHYPARAM0_TXFSLSTUNE(_x)               ((_x) << 9)
+#define PHYPARAM0_SQRXTUNE_MASK                        (0x7 << 6)
+#define PHYPARAM0_SQRXTUNE_EXT(_x)             ((_x & (0x7 << 6)) >> 6)
+#define PHYPARAM0_SQRXTUNE(_x)                 ((_x) << 6)
+#define PHYPARAM0_OTGTUNE_MASK                 (0x7 << 3)
+#define PHYPARAM0_OTGTUNE_EXT(_x)              ((_x & (0x7 << 3)) >> 3)
+#define PHYPARAM0_OTGTUNE(_x)                  ((_x) << 3)
+#define PHYPARAM0_COMPDISTUNE_MASK             (0x7 << 0)
+#define PHYPARAM0_COMPDISTUNE_EXT(_x)          (_x & (0x7 << 0))
+#define PHYPARAM0_COMPDISTUNE(_x)              ((_x) << 0)
+
+#define EXYNOS_USBCON_PHYPARAM1        (0x20)
+#define PHYPARAM1_TX0_TERM_OFFSET_MASK         (0x1f << 26)
+#define PHYPARAM1_TX0_TERM_OFFSET(_x)          ((_x) << 26)
+#define PHYPARAM1_PCS_TXSWING_FULL_MASK                (0x7f << 12)
+#define PHYPARAM1_PCS_TXSWING_FULL(_x)         ((_x) << 12)
+#define PHYPARAM1_PCS_TXDEEMPH_3P5DB_MASK      (0x3f << 0)
+#define PHYPARAM1_PCS_TXDEEMPH_3P5DB(_x)       ((_x) << 0)
+
+#define EXYNOS_USBCON_PHYTEST          (0x28)
+#define PHYTEST_POWERDOWN_SSP                  (0x1 << 3)
+#define PHYTEST_POWERDOWN_HSP                  (0x1 << 2)
+
+#define EXYNOS_USBCON_PHYPOWERDOWN             (0x28)
+#define PHYPOWERDOWN_VATESTENB                 (0x1 << 6)
+#define PHYPOWERDOWN_TEST_BURNIN_MASK          (0x3 << 4)
+#define PHYPOWERDOWN_TEST_BURNIN               ((_x) << 4)
+
+#define EXYNOS_USBCON_PHYBATCHG                (0x30)
+#define PHYBATCHG_CHGDET                       (0x1 << 10)
+#define PHYBATCHG_RIDC                         (0x1 << 9)
+#define PHYBATCHG_RIDB                         (0x1 << 8)
+#define PHYBATCHG_RIDA                         (0x1 << 7)
+#define PHYBATCHG_RIDGND                       (0x1 << 6)
+#define PHYBATCHG_RIDFLOAT                     (0x1 << 5)
+#define PHYBATCHG_VDATSRCENB                   (0x1 << 4)
+#define PHYBATCHG_VDATDETENB                   (0x1 << 3)
+#define PHYBATCHG_CHRGSEL                      (0x1 << 2)
+#define PHYBATCHG_ACAENB                       (0x1 << 1)
+#define PHYBATCHG_DCDENB                       (0x1 << 0)
+
+#define EXYNOS_USBCON_PHYRESUME                (0x34)
+#define PHYRESUME_DIS_BUSPEND_QACT             (0x1 << 14)
+#define PHYRESUME_DIS_LINKGATE_QACT            (0x1 << 13)
+#define PHYRESUME_DIS_ID0_QACT                 (0x1 << 12)
+#define PHYRESUME_DIS_VBUSVALID_QACT           (0x1 << 11)
+#define PHYRESUME_DIS_BVALID_QACT              (0x1 << 10)
+#define PHYRESUME_FORCE_QACT                   (0x1 << 9)
+#define PHYRESUME_FORCE_OPMODE_MASK            (0x3 << 7)
+#define PHYRESUME_FORCE_OPMODE(_x)             ((_x) << 7)
+#define PHYRESUME_OPMODE_EN                    (0x1 << 6)
+#define PHYRESUME_AUTORESUME_EN                        (0x1 << 5)
+#define PHYRESUME_BYPASS_SEL                   (0x1 << 4)
+#define PHYRESUME_BYPASS_DM_EN                 (0x1 << 3)
+#define PHYRESUME_BYPASS_DP_EN                 (0x1 << 2)
+#define PHYRESUME_BYPASS_DM_DATA               (0x1 << 1)
+#define PHYRESUME_BYPASS_DP_DATA               (0x1 << 0)
+
+#define EXYNOS_USBCON_PHYPCSVAL                (0x3C)
+#define PHYPCSVAL_PCS_RX_LOS_MASK_VAL_MASK     (0x3FF << 0)
+#define PHYPCSVAL_PCS_RX_LOS_MASK_VAL(_x)      ((_x & 0x3FF) << 0)
+
+#define EXYNOS_USBCON_LINKPORT         (0x44)
+#define LINKPORT_HOST_NUM_U3_PORT_MASK         (0xf << 13)
+#define LINKPORT_HOST_NUM_U3_PORT(_x)          ((_x) << 13)
+#define LINKPORT_HOST_NUM_U2_PORT_MASK         (0xf << 9)
+#define LINKPORT_HOST_NUM_U2_PORT(_x)  ((_x) << 9)
+#define LINKPORT_HOST_U3_PORT_DISABLE          (1 << 8)
+#define LINKPORT_HOST_U2_PORT_DISABLE          (1 << 7)
+#define LINKPORT_PORT_POWER_CONTROL            (0x1 << 6)
+#define LINKPORT_HOST_PORT_OVCR_U3             (1 << 5)
+#define LINKPORT_HOST_PORT_OVCR_U2             (1 << 4)
+#define LINKPORT_HOST_PORT_OVCR_U3_SEL         (1 << 3)
+#define LINKPORT_HOST_PORT_OVCR_U2_SEL         (1 << 2)
+#define LINKPORT_PERM_ATTACH_U3                        (0x << 1)
+#define LINKPORT_PERM_ATTACH_U2                        (0x1 << 0)
+
+#define EXYNOS_USBCON_PHYPARAM2                (0x50)
+#define PHYPARAM2_TX_VBOOST_LVL_MASK           (0x7 << 4)
+#define PHYPARAM2_TX_VBOOST_LVL(_x)            ((_x) << 4)
+#define PHYPARAM2_LOS_BIAS_MASK                        (0x7 << 0)
+#define PHYPARAM2_LOS_BIAS(_x)                 ((_x) << 0)
+
+#define EXYNOS_USBCON_HSPHYCTRL                (0x54)
+#define HSPHYCTRL_PHYSWRSTALL                  (0x1 << 31)
+#define HSPHYCTRL_SIDDQ                                (0x1 << 6)
+#define HSPHYCTRL_PHYSWRST                     (0x1 << 0)
+
+#define EXYNOS_USBCON_HSPHYTESTIF      (0x5c)
+#define HSPHYTESTIF_LINESTATE_MASK             (0x3 << 20)
+#define HSPHYTESTIF_DATAOUT_MASK               (0xf << 16)
+#define HSPHYTESTIF_CLKEN                      (0x1 << 13)
+#define HSPHYTESTIF_DATAOUTSEL                 (0x2 << 12)
+#define HSPHYTESTIF_ADDR_MASK                  (0xf << 8)
+#define HSPHYTESTIF_ADDR(_x)                   ((_x) << 8)
+#define HSPHYTESTIF_DATAIN_MASK                        (0xff << 0)
+#define HSPHYTESTIF_DATAIN(_x)                 ((_x) << 0)
+
+#define EXYNOS_USBCON_PHYSELECTION     (0x6c)
+#define PHYSEL_U3RST                           (0x1 << 5)
+#define PHYSEL_UTMI_CLK                                (0x1 << 4)
+#define PHYSEL_PIPE_CLK                                (0x1 << 3)
+#define PHYSEL_UTMI                            (0x1 << 2)
+#define PHYSEL_PIPE                            (0x1 << 1)
+#define PHYSEL_SIDEBAND                                (0x1 << 0)
+
+#define EXYNOS_USBCON_HSPHYPLLTUNE     (0x70)
+#define HSPHYPLLTUNE_PLL_B_TUNE                        (0x1 << 6)
+#define HSPHYPLLTUNE_PLL_I_TUNE(_x)            ((_x) << 4)
+#define HSPHYPLLTUNE_PLL_I_TUNE_MASK           (0x3 << 4)
+#define HSPHYPLLTUNE_PLL_P_TUNE(_x)            ((_x) << 0)
+#define HSPHYPLLTUNE_PLL_P_TUNE_MASK           (0xf << 0)
+
+#define EXYNOS_USBCON_EHCICTRL         (0x80)
+#define EHCICTRL_EHCI64BITEN                   (0x1 << 31)
+#define EHCICTRL_EN_INCRX_ALIGN                        (0x1 << 30)
+#define EHCICTRL_EN_INCR4                      (0x1 << 29)
+#define EHCICTRL_EN_INCR8                      (0x1 << 28)
+#define EHCICTRL_EN_INCR16                     (0x1 << 26)
+#define EHCICTRL_EN_AUTO_PPDON_OVRCUR          (0x1 << 25)
+#define EHCICTRL_FLADJVAL0_MASK                        (0x3f << 19)
+#define EHCICTRL_FLADJVAL0(_x)                 ((_x) << 19)
+#define EHCICTRL_FLADJVAL1_MASK                        (0x3f << 13)
+#define EHCICTRL_FLADJVAL1(_x)                 ((_x) << 13)
+#define EHCICTRL_FLADJVAL2_MASK                        (0x3f << 7)
+#define EHCICTRL_FLADJVAL2(_x)                 ((_x) << 7)
+#define EHCICTRL_FLADJVALHOST_MASK             (0x3f << 1)
+#define EHCICTRL_FLADJVALHOST(_x)              ((_x) << 1)
+
+#define EXYNOS_USBCON_OHCICTRL         (0x84)
+#define OHCICTRL_RESET_PORT0                   (0x1 << 29)
+#define OHCICTRL_HUBSETUP_MIN                  (0x1 << 4)
+#define OHCICTRL_OHCISUSPLGCY                  (0x1 << 3)
+#define OHCICTRL_APPSTARTCLK                   (0x1 << 2)
+#define OHCICTRL_OHCICNTSELN                   (0x1 << 1)
+#define OHCICTRL_OHCICLKCKTRSTN                        (0x1 << 0)
+
+#define EXYNOS_USBCON_HOSTLINKCTRL     (0x88)
+#define HOSTLINKCTRL_EN_SLEEP_HOST_P2          (0x1 << 31)
+#define HOSTLINKCTRL_EN_SLEEP_HOST_P1          (0x1 << 30)
+#define HOSTLINKCTRL_EN_SLEEP_HOST_P0          (0x1 << 29)
+#define HOSTLINKCTRL_EN_SLEEP_OTG              (0x1 << 28)
+#define HOSTLINKCTRL_EN_SUSPEND_HOST_P2                (0x1 << 27)
+#define HOSTLINKCTRL_EN_SUSPEND_HOST_P1                (0x1 << 26)
+#define HOSTLINKCTRL_EN_SUSPEND_HOST_P0                (0x1 << 25)
+#define HOSTLINKCTRL_EN_SUSPEND_OTG            (0x1 << 24)
+#define HOSTLINKCTRL_FORCE_HOST_OVRCUR_P2      (0x1 << 17)
+#define HOSTLINKCTRL_FORCE_HOST_OVRCUR         (0x1 << 16)
+#define HOSTLINKCTRL_SW_RESET_PORT2            (0x1 << 3)
+#define HOSTLINKCTRL_SW_RESET_PORT1            (0x1 << 2)
+#define HOSTLINKCTRL_SW_RESET_PORT0            (0x1 << 1)
+#define HOSTLINKCTRL_LINKSWRST                 (0x1 << 0)
+
+#define EXYNOS_USBCON_OTGLINKCTRL      (0x8C)
+#define OTGINKCTRL_AVALID                      (0x1 << 14)
+#define OTGINKCTRL_BVALID                      (0x1 << 13)
+#define OTGINKCTRL_IDDIG                       (0x1 << 12)
+#define OTGINKCTRL_VBUSDETECT                  (0x1 << 11)
+#define OTGINKCTRL_VBUSVLDSEL_MASK             (0x3 << 9)
+#define OTGINKCTRL_VBUSVLDSEL(_x)              ((_x) << 9)
+#define OTGINKCTRL_LINK_PRST                   (0x1 << 4)
+#define OTGINKCTRL_SW_RESET_ALL                        (0x1 << 3)
+#define OTGINKCTRL_SW_RESET                    (0x1 << 2)
+
+void samsung_exynos_cal_usb3phy_enable(struct exynos_usbphy_info *usbphy_info);
+void samsung_exynos_cal_usb3phy_late_enable(struct exynos_usbphy_info *usbphy_info);
+void samsung_exynos_cal_usb3phy_disable(struct exynos_usbphy_info *usbphy_info);
+void samsung_exynos_cal_usb3phy_tune_each(struct exynos_usbphy_info *usbphy_info,
+       enum exynos_usbphy_tune_para para, int val);
+void samsung_exynos_cal_usb3phy_hs_tune_extract(struct exynos_usbphy_info *usbphy_info);
+void samsung_exynos_cal_usb3phy_tune_dev(struct exynos_usbphy_info *usbphy_info);
+void samsung_exynos_cal_usb3phy_tune_host(struct exynos_usbphy_info *usbphy_info);
+void samsung_exynos_cal_cr_write(struct exynos_usbphy_info *usbphy_info, u16 addr, u16 data);
+u16 samsung_exynos_cal_cr_read(struct exynos_usbphy_info *usbphy_info, u16 addr);
+void samsung_cal_usb3phy_tune(struct exynos_usbphy_info *usbphy_info);
+void samsung_exynos_cal_usb3phy_config_host_mode(
+               struct exynos_usbphy_info *usbphy_info);
+void samsung_exynos_cal_usb3phy_enable_dp_pullup(
+               struct exynos_usbphy_info *usbphy_info);
+void samsung_exynos_cal_usb3phy_disable_dp_pullup(
+               struct exynos_usbphy_info *usbphy_info);
+
+#endif
index 15e822e55a726170e8f1c665da2c92c7cc6ebc3d..20b2bcf34072203260a32efc5f41e27f26e92efc 100644 (file)
@@ -83,6 +83,14 @@ config AM335X_PHY_USB
          This driver provides PHY support for that phy which part for the
          AM335x SoC.
 
+config DUAL_ROLE_USB_INTF
+       bool "Generic DUAL ROLE sysfs interface"
+       help
+         A generic sysfs interface to track and change the state of
+         dual role usb phys. The usb phy drivers can register to
+         this interface to expose it capabilities to the userspace
+         and thereby allowing userspace to change the port mode.
+
 config TWL6030_USB
        tristate "TWL6030 USB Transceiver Driver"
        depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
index e694d4008c4a9121cbf1c8b6b0731f890b3570b3..216f3c3d7f2c134266ab523144d947257f27b24a 100644 (file)
@@ -44,6 +44,11 @@ enum phy_mode {
 struct phy_ops {
        int     (*init)(struct phy *phy);
        int     (*exit)(struct phy *phy);
+       int     (*tune)(struct phy *phy, int phy_state);
+       int     (*vendor_set)(struct phy *phy, int is_enable, int is_cancel);
+       void     (*conn)(struct phy *phy, int is_conn);
+       int     (*ilbk)(struct phy *phy);
+       int     (*set)(struct phy *phy, int option, void *info);
        int     (*power_on)(struct phy *phy);
        int     (*power_off)(struct phy *phy);
        int     (*set_mode)(struct phy *phy, enum phy_mode mode);
@@ -137,6 +142,11 @@ void phy_pm_runtime_allow(struct phy *phy);
 void phy_pm_runtime_forbid(struct phy *phy);
 int phy_init(struct phy *phy);
 int phy_exit(struct phy *phy);
+int phy_tune(struct phy *phy, int phy_state);
+int phy_vendor_set(struct phy *phy, int is_enable, int is_cancel);
+void phy_conn(struct phy *phy, int is_conn);
+int phy_ilbk(struct phy *phy);
+int phy_set(struct phy *phy, int option, void *info);
 int phy_power_on(struct phy *phy);
 int phy_power_off(struct phy *phy);
 int phy_set_mode(struct phy *phy, enum phy_mode mode);
@@ -234,6 +244,41 @@ static inline int phy_exit(struct phy *phy)
        return -ENOSYS;
 }
 
+static inline int phy_tune(struct phy *phy, int phy_state)
+{
+       if (!phy)
+               return 0;
+       return -ENOSYS;
+}
+
+static inline int phy_vendor_set(struct phy *phy, int is_enable, int is_rewa)
+{
+       if (!phy)
+               return 0;
+       return -ENOSYS;
+}
+
+static inline int phy_conn(struct phy *phy, int is_conn)
+{
+       if (!phy)
+               return 0;
+       return -ENOSYS;
+}
+
+static inline int phy_ilbk(struct phy *phy)
+{
+       if (!phy)
+               return 0;
+       return -ENOSYS;
+}
+
+static inline int phy_set(struct phy *phy, int option, void *info)
+{
+       if (!phy)
+               return 0;
+       return -ENOSYS;
+}
+
 static inline int phy_power_on(struct phy *phy)
 {
        if (!phy)