diff mbox

usb: phy: Add USB host phy support on Exyno4412

Message ID 1360024635-15181-1-git-send-email-tobetter@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dongjin Kim Feb. 5, 2013, 12:37 a.m. UTC
This patch adds host phy support for Samsung's Exynos4412 SoC to
samsung-usbphy driver and its device node.

Cc: Praveen Paneri <p.paneri@samsung.com>
Signed-off-by: Dongjin Kim <tobetter@gmail.com>
---
 arch/arm/boot/dts/exynos4412.dtsi |   13 ++++
 drivers/usb/phy/samsung-usbphy.c  |  156 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 167 insertions(+), 2 deletions(-)

Comments

Kyungmin Park Feb. 5, 2013, 1:02 a.m. UTC | #1
Hi,

Can split patch into two parts?
One for USB tree, another for samsung tree.

Thank you,
Kyungmin Park

On Tue, Feb 5, 2013 at 9:37 AM, Dongjin Kim <tobetter@gmail.com> wrote:
> This patch adds host phy support for Samsung's Exynos4412 SoC to
> samsung-usbphy driver and its device node.
>
> Cc: Praveen Paneri <p.paneri@samsung.com>
> Signed-off-by: Dongjin Kim <tobetter@gmail.com>
> ---
>  arch/arm/boot/dts/exynos4412.dtsi |   13 ++++
>  drivers/usb/phy/samsung-usbphy.c  |  156 ++++++++++++++++++++++++++++++++++++-
>  2 files changed, 167 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi
> index 387aa27..c01d841 100644
> --- a/arch/arm/boot/dts/exynos4412.dtsi
> +++ b/arch/arm/boot/dts/exynos4412.dtsi
> @@ -33,4 +33,17 @@
>                 #address-cells = <1>;
>                 #size-cells = <0>;
>         };
> +
> +       usbphy@125B0000 {
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +               compatible = "samsung,exynos4412-usbphy";
> +               reg = <0x125B0000 0x100>;
> +               status = "disabled";
> +               ranges;
> +
> +               usbphy-sys {
> +                       reg = <0x10020704 0xc>;
> +               };
> +       };
>  };
> diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c
> index 6ea5537..c800fa4 100644
> --- a/drivers/usb/phy/samsung-usbphy.c
> +++ b/drivers/usb/phy/samsung-usbphy.c
> @@ -47,7 +47,7 @@
>
>  #define PHYCLK_MODE_USB11                      (0x1 << 6)
>  #define PHYCLK_EXT_OSC                         (0x1 << 5)
> -#define PHYCLK_COMMON_ON_N                     (0x1 << 4)
> +#define PHYCLK_COMMON_ON_N_PHY0                        (0x1 << 4)
>  #define PHYCLK_ID_PULL                         (0x1 << 2)
>  #define PHYCLK_CLKSEL_MASK                     (0x3 << 0)
>  #define PHYCLK_CLKSEL_48M                      (0x0 << 0)
> @@ -60,6 +60,22 @@
>  #define RSTCON_HLINK_SWRST                     (0x1 << 1)
>  #define RSTCON_SWRST                           (0x1 << 0)
>
> +/* For Exynos4412 */
> +#define PHYCLK_COMMON_ON_N_PHY1                        (0x1 << 7)
> +
> +#define PHYPWR_NORMAL_MASK_HSIC1               (0x7 << 12)
> +#define PHYPWR_NORMAL_MASK_HSIC0               (0x7 << 9)
> +#define PHYPWR_NORMAL_MASK_PHY1                        (0x7 << 6)
> +
> +#define PHYPWR_ANALOG_POWERDOWN_PHY1           (0x1 << 7)
> +
> +#define RSTCON_HLINK_SWRST_MASK                        (0xf << 7)
> +#define RSTCON_PHY1_SWRST_MASK                 (0xf << 3)
> +#define RSTCON_PHY0_SWRST_MASK                 (0x7 << 0)
> +
> +#define EXYNOS4_PHY_HSIC_CTRL0                 (0x04)
> +#define EXYNOS4_PHY_HSIC_CTRL1                 (0x08)
> +
>  /* EXYNOS5 */
>  #define EXYNOS5_PHY_HOST_CTRL0                 (0x00)
>
> @@ -174,6 +190,7 @@
>  enum samsung_cpu_type {
>         TYPE_S3C64XX,
>         TYPE_EXYNOS4210,
> +       TYPE_EXYNOS4412,
>         TYPE_EXYNOS5250,
>  };
>
> @@ -322,6 +339,17 @@ static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
>                         en_mask = sphy->drv_data->hostphy_en_mask;
>                 }
>                 break;
> +       case TYPE_EXYNOS4412:
> +               if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
> +                       reg = sphy->pmuregs +
> +                               sphy->drv_data->devphy_reg_offset;
> +                       en_mask = sphy->drv_data->devphy_en_mask;
> +               } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
> +                       reg = sphy->pmuregs +
> +                               sphy->drv_data->hostphy_reg_offset;
> +                       en_mask = sphy->drv_data->hostphy_en_mask;
> +               }
> +               break;
>         default:
>                 dev_err(sphy->dev, "Invalid SoC type\n");
>                 return;
> @@ -422,6 +450,29 @@ static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
>                         refclk_freq = FSEL_CLKSEL_24M;
>                         break;
>                 }
> +       } else if (sphy->drv_data->cpu_type == TYPE_EXYNOS4412) {
> +               switch (clk_get_rate(ref_clk)) {
> +               case 9600 * KHZ:
> +                       refclk_freq = FSEL_CLKSEL_9600K;
> +                       break;
> +               case 10 * MHZ:
> +                       refclk_freq = FSEL_CLKSEL_10M;
> +                       break;
> +               case 12 * MHZ:
> +                       refclk_freq = FSEL_CLKSEL_12M;
> +                       break;
> +               case 19200 * KHZ:
> +                       refclk_freq = FSEL_CLKSEL_19200K;
> +                       break;
> +               case 20 * MHZ:
> +                       refclk_freq = FSEL_CLKSEL_20M;
> +                       break;
> +               case 24 * MHZ:
> +               default:
> +                       /* default reference clock */
> +                       refclk_freq = FSEL_CLKSEL_24M;
> +                       break;
> +               }
>         } else {
>                 switch (clk_get_rate(ref_clk)) {
>                 case 12 * MHZ:
> @@ -561,6 +612,69 @@ static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy)
>         writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
>  }
>
> +static bool exynos4_phyhost_is_on(void *regs)
> +{
> +       u32 reg;
> +
> +       reg = readl(regs + SAMSUNG_PHYPWR);
> +
> +       return !(reg & PHYPWR_ANALOG_POWERDOWN_PHY1);
> +}
> +
> +static void samsung_exynos4412_usbphy_enable(struct samsung_usbphy *sphy)
> +{
> +       void __iomem *regs = sphy->regs;
> +       u32 phypwr;
> +       u32 phyclk;
> +       u32 rstcon;
> +
> +       /*
> +        * phy_usage helps in keeping usage count for phy
> +        * so that the first consumer enabling the phy is also
> +        * the last consumer to disable it.
> +        */
> +
> +       atomic_inc(&sphy->phy_usage);
> +
> +       if (exynos4_phyhost_is_on(regs)) {
> +               dev_info(sphy->dev, "Already power on PHY\n");
> +               return;
> +       }
> +
> +       writel(EXYNOS_USBPHY_ENABLE, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL0);
> +       writel(EXYNOS_USBPHY_ENABLE, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL1);
> +
> +       /* Common block configuration during suspend */
> +       phyclk = sphy->ref_clk_freq
> +               & ~(PHYCLK_COMMON_ON_N_PHY0 | PHYCLK_COMMON_ON_N_PHY1);
> +       writel(phyclk, regs + SAMSUNG_PHYCLK);
> +
> +       /* set to normal of Device */
> +       phypwr = readl(regs + SAMSUNG_PHYPWR) & ~PHYPWR_NORMAL_MASK_PHY0;
> +       writel(phypwr, regs + SAMSUNG_PHYPWR);
> +
> +       /* set to normal of Host */
> +       phypwr &= ~(PHYPWR_NORMAL_MASK_HSIC0 | PHYPWR_NORMAL_MASK_HSIC1
> +                       | PHYPWR_NORMAL_MASK_PHY1);
> +       writel(phypwr, regs + SAMSUNG_PHYPWR);
> +
> +       /* reset both PHY and Link of Device */
> +       rstcon = readl(regs + SAMSUNG_RSTCON) | RSTCON_PHY0_SWRST_MASK;
> +       writel(rstcon, regs + SAMSUNG_RSTCON);
> +       udelay(10);
> +       rstcon &= ~RSTCON_PHY0_SWRST_MASK;
> +       writel(rstcon, regs + SAMSUNG_RSTCON);
> +
> +       /* reset both PHY and Link of Host */
> +       rstcon = readl(regs + SAMSUNG_RSTCON)
> +               | (RSTCON_HLINK_SWRST_MASK | RSTCON_PHY1_SWRST_MASK);
> +       writel(rstcon, regs + SAMSUNG_RSTCON);
> +       udelay(10);
> +       rstcon &= ~(RSTCON_HLINK_SWRST_MASK | RSTCON_PHY1_SWRST_MASK);
> +       writel(rstcon, regs + SAMSUNG_RSTCON);
> +       udelay(80);
> +}
> +
>  static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
>  {
>         void __iomem *regs = sphy->regs;
> @@ -575,7 +689,7 @@ static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
>
>         switch (sphy->drv_data->cpu_type) {
>         case TYPE_S3C64XX:
> -               phyclk &= ~PHYCLK_COMMON_ON_N;
> +               phyclk &= ~PHYCLK_COMMON_ON_N_PHY0;
>                 phypwr &= ~PHYPWR_NORMAL_MASK;
>                 rstcon |= RSTCON_SWRST;
>                 break;
> @@ -631,6 +745,28 @@ static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy)
>         writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
>  }
>
> +static void samsung_exynos4412_usbphy_disable(struct samsung_usbphy *sphy)
> +{
> +       void __iomem *regs = sphy->regs;
> +       u32 phypwr;
> +
> +       if (atomic_dec_return(&sphy->phy_usage) > 0) {
> +               dev_info(sphy->dev, "still being used\n");
> +               return;
> +       }
> +
> +       /* unset to normal of Host and Device */
> +       phypwr = readl(regs + SAMSUNG_PHYPWR);
> +       phypwr |= (PHYPWR_NORMAL_MASK_HSIC0
> +                       | PHYPWR_NORMAL_MASK_HSIC1
> +                       | PHYPWR_NORMAL_MASK_PHY1
> +                       | PHYPWR_NORMAL_MASK_PHY0);
> +       writel(phypwr, regs + SAMSUNG_PHYPWR);
> +
> +       writel(0, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL0);
> +       writel(0, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL1);
> +}
> +
>  static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
>  {
>         void __iomem *regs = sphy->regs;
> @@ -696,6 +832,8 @@ static int samsung_usbphy_init(struct usb_phy *phy)
>         /* Initialize usb phy registers */
>         if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
>                 samsung_exynos5_usbphy_enable(sphy);
> +       else if (sphy->drv_data->cpu_type == TYPE_EXYNOS4412)
> +               samsung_exynos4412_usbphy_enable(sphy);
>         else
>                 samsung_usbphy_enable(sphy);
>
> @@ -739,6 +877,8 @@ static void samsung_usbphy_shutdown(struct usb_phy *phy)
>         /* De-initialize usb phy registers */
>         if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
>                 samsung_exynos5_usbphy_disable(sphy);
> +       else if (sphy->drv_data->cpu_type == TYPE_EXYNOS4412)
> +               samsung_exynos4412_usbphy_disable(sphy);
>         else
>                 samsung_usbphy_disable(sphy);
>
> @@ -872,6 +1012,12 @@ static const struct samsung_usbphy_drvdata usbphy_exynos4 = {
>         .hostphy_en_mask        = EXYNOS_USBPHY_ENABLE,
>  };
>
> +static const struct samsung_usbphy_drvdata usbphy_exynos4412 = {
> +       .cpu_type               = TYPE_EXYNOS4412,
> +       .devphy_en_mask         = EXYNOS_USBPHY_ENABLE,
> +       .hostphy_en_mask        = EXYNOS_USBPHY_ENABLE,
> +};
> +
>  static struct samsung_usbphy_drvdata usbphy_exynos5 = {
>         .cpu_type               = TYPE_EXYNOS5250,
>         .hostphy_en_mask        = EXYNOS_USBPHY_ENABLE,
> @@ -887,6 +1033,9 @@ static const struct of_device_id samsung_usbphy_dt_match[] = {
>                 .compatible = "samsung,exynos4210-usbphy",
>                 .data = &usbphy_exynos4,
>         }, {
> +               .compatible = "samsung,exynos4412-usbphy",
> +               .data = &usbphy_exynos4412,
> +       }, {
>                 .compatible = "samsung,exynos5250-usbphy",
>                 .data = &usbphy_exynos5
>         },
> @@ -903,6 +1052,9 @@ static struct platform_device_id samsung_usbphy_driver_ids[] = {
>                 .name           = "exynos4210-usbphy",
>                 .driver_data    = (unsigned long)&usbphy_exynos4,
>         }, {
> +               .name           = "exynos4412-usbphy",
> +               .driver_data    = (unsigned long)&usbphy_exynos4412,
> +       }, {
>                 .name           = "exynos5250-usbphy",
>                 .driver_data    = (unsigned long)&usbphy_exynos5,
>         },
> --
> 1.7.10.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
diff mbox

Patch

diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi
index 387aa27..c01d841 100644
--- a/arch/arm/boot/dts/exynos4412.dtsi
+++ b/arch/arm/boot/dts/exynos4412.dtsi
@@ -33,4 +33,17 @@ 
 		#address-cells = <1>;
 		#size-cells = <0>;
 	};
+
+	usbphy@125B0000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "samsung,exynos4412-usbphy";
+		reg = <0x125B0000 0x100>;
+		status = "disabled";
+		ranges;
+
+		usbphy-sys {
+			reg = <0x10020704 0xc>;
+		};
+	};
 };
diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c
index 6ea5537..c800fa4 100644
--- a/drivers/usb/phy/samsung-usbphy.c
+++ b/drivers/usb/phy/samsung-usbphy.c
@@ -47,7 +47,7 @@ 
 
 #define PHYCLK_MODE_USB11			(0x1 << 6)
 #define PHYCLK_EXT_OSC				(0x1 << 5)
-#define PHYCLK_COMMON_ON_N			(0x1 << 4)
+#define PHYCLK_COMMON_ON_N_PHY0			(0x1 << 4)
 #define PHYCLK_ID_PULL				(0x1 << 2)
 #define PHYCLK_CLKSEL_MASK			(0x3 << 0)
 #define PHYCLK_CLKSEL_48M			(0x0 << 0)
@@ -60,6 +60,22 @@ 
 #define RSTCON_HLINK_SWRST			(0x1 << 1)
 #define RSTCON_SWRST				(0x1 << 0)
 
+/* For Exynos4412 */
+#define PHYCLK_COMMON_ON_N_PHY1			(0x1 << 7)
+
+#define PHYPWR_NORMAL_MASK_HSIC1		(0x7 << 12)
+#define PHYPWR_NORMAL_MASK_HSIC0		(0x7 << 9)
+#define PHYPWR_NORMAL_MASK_PHY1			(0x7 << 6)
+
+#define PHYPWR_ANALOG_POWERDOWN_PHY1		(0x1 << 7)
+
+#define RSTCON_HLINK_SWRST_MASK			(0xf << 7)
+#define RSTCON_PHY1_SWRST_MASK			(0xf << 3)
+#define RSTCON_PHY0_SWRST_MASK			(0x7 << 0)
+
+#define EXYNOS4_PHY_HSIC_CTRL0			(0x04)
+#define EXYNOS4_PHY_HSIC_CTRL1			(0x08)
+
 /* EXYNOS5 */
 #define EXYNOS5_PHY_HOST_CTRL0			(0x00)
 
@@ -174,6 +190,7 @@ 
 enum samsung_cpu_type {
 	TYPE_S3C64XX,
 	TYPE_EXYNOS4210,
+	TYPE_EXYNOS4412,
 	TYPE_EXYNOS5250,
 };
 
@@ -322,6 +339,17 @@  static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on)
 			en_mask = sphy->drv_data->hostphy_en_mask;
 		}
 		break;
+	case TYPE_EXYNOS4412:
+		if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
+			reg = sphy->pmuregs +
+				sphy->drv_data->devphy_reg_offset;
+			en_mask = sphy->drv_data->devphy_en_mask;
+		} else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
+			reg = sphy->pmuregs +
+				sphy->drv_data->hostphy_reg_offset;
+			en_mask = sphy->drv_data->hostphy_en_mask;
+		}
+		break;
 	default:
 		dev_err(sphy->dev, "Invalid SoC type\n");
 		return;
@@ -422,6 +450,29 @@  static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
 			refclk_freq = FSEL_CLKSEL_24M;
 			break;
 		}
+	} else if (sphy->drv_data->cpu_type == TYPE_EXYNOS4412) {
+		switch (clk_get_rate(ref_clk)) {
+		case 9600 * KHZ:
+			refclk_freq = FSEL_CLKSEL_9600K;
+			break;
+		case 10 * MHZ:
+			refclk_freq = FSEL_CLKSEL_10M;
+			break;
+		case 12 * MHZ:
+			refclk_freq = FSEL_CLKSEL_12M;
+			break;
+		case 19200 * KHZ:
+			refclk_freq = FSEL_CLKSEL_19200K;
+			break;
+		case 20 * MHZ:
+			refclk_freq = FSEL_CLKSEL_20M;
+			break;
+		case 24 * MHZ:
+		default:
+			/* default reference clock */
+			refclk_freq = FSEL_CLKSEL_24M;
+			break;
+		}
 	} else {
 		switch (clk_get_rate(ref_clk)) {
 		case 12 * MHZ:
@@ -561,6 +612,69 @@  static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy)
 	writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL);
 }
 
+static bool exynos4_phyhost_is_on(void *regs)
+{
+	u32 reg;
+
+	reg = readl(regs + SAMSUNG_PHYPWR);
+
+	return !(reg & PHYPWR_ANALOG_POWERDOWN_PHY1);
+}
+
+static void samsung_exynos4412_usbphy_enable(struct samsung_usbphy *sphy)
+{
+	void __iomem *regs = sphy->regs;
+	u32 phypwr;
+	u32 phyclk;
+	u32 rstcon;
+
+	/*
+	 * phy_usage helps in keeping usage count for phy
+	 * so that the first consumer enabling the phy is also
+	 * the last consumer to disable it.
+	 */
+
+	atomic_inc(&sphy->phy_usage);
+
+	if (exynos4_phyhost_is_on(regs)) {
+		dev_info(sphy->dev, "Already power on PHY\n");
+		return;
+	}
+
+	writel(EXYNOS_USBPHY_ENABLE, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL0);
+	writel(EXYNOS_USBPHY_ENABLE, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL1);
+
+	/* Common block configuration during suspend */
+	phyclk = sphy->ref_clk_freq
+		& ~(PHYCLK_COMMON_ON_N_PHY0 | PHYCLK_COMMON_ON_N_PHY1);
+	writel(phyclk, regs + SAMSUNG_PHYCLK);
+
+	/* set to normal of Device */
+	phypwr = readl(regs + SAMSUNG_PHYPWR) & ~PHYPWR_NORMAL_MASK_PHY0;
+	writel(phypwr, regs + SAMSUNG_PHYPWR);
+
+	/* set to normal of Host */
+	phypwr &= ~(PHYPWR_NORMAL_MASK_HSIC0 | PHYPWR_NORMAL_MASK_HSIC1
+			| PHYPWR_NORMAL_MASK_PHY1);
+	writel(phypwr, regs + SAMSUNG_PHYPWR);
+
+	/* reset both PHY and Link of Device */
+	rstcon = readl(regs + SAMSUNG_RSTCON) | RSTCON_PHY0_SWRST_MASK;
+	writel(rstcon, regs + SAMSUNG_RSTCON);
+	udelay(10);
+	rstcon &= ~RSTCON_PHY0_SWRST_MASK;
+	writel(rstcon, regs + SAMSUNG_RSTCON);
+
+	/* reset both PHY and Link of Host */
+	rstcon = readl(regs + SAMSUNG_RSTCON)
+		| (RSTCON_HLINK_SWRST_MASK | RSTCON_PHY1_SWRST_MASK);
+	writel(rstcon, regs + SAMSUNG_RSTCON);
+	udelay(10);
+	rstcon &= ~(RSTCON_HLINK_SWRST_MASK | RSTCON_PHY1_SWRST_MASK);
+	writel(rstcon, regs + SAMSUNG_RSTCON);
+	udelay(80);
+}
+
 static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
 {
 	void __iomem *regs = sphy->regs;
@@ -575,7 +689,7 @@  static void samsung_usbphy_enable(struct samsung_usbphy *sphy)
 
 	switch (sphy->drv_data->cpu_type) {
 	case TYPE_S3C64XX:
-		phyclk &= ~PHYCLK_COMMON_ON_N;
+		phyclk &= ~PHYCLK_COMMON_ON_N_PHY0;
 		phypwr &= ~PHYPWR_NORMAL_MASK;
 		rstcon |= RSTCON_SWRST;
 		break;
@@ -631,6 +745,28 @@  static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy)
 	writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS);
 }
 
+static void samsung_exynos4412_usbphy_disable(struct samsung_usbphy *sphy)
+{
+	void __iomem *regs = sphy->regs;
+	u32 phypwr;
+
+	if (atomic_dec_return(&sphy->phy_usage) > 0) {
+		dev_info(sphy->dev, "still being used\n");
+		return;
+	}
+
+	/* unset to normal of Host and Device */
+	phypwr = readl(regs + SAMSUNG_PHYPWR);
+	phypwr |= (PHYPWR_NORMAL_MASK_HSIC0
+			| PHYPWR_NORMAL_MASK_HSIC1
+			| PHYPWR_NORMAL_MASK_PHY1
+			| PHYPWR_NORMAL_MASK_PHY0);
+	writel(phypwr, regs + SAMSUNG_PHYPWR);
+
+	writel(0, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL0);
+	writel(0, sphy->pmuregs + EXYNOS4_PHY_HSIC_CTRL1);
+}
+
 static void samsung_usbphy_disable(struct samsung_usbphy *sphy)
 {
 	void __iomem *regs = sphy->regs;
@@ -696,6 +832,8 @@  static int samsung_usbphy_init(struct usb_phy *phy)
 	/* Initialize usb phy registers */
 	if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
 		samsung_exynos5_usbphy_enable(sphy);
+	else if (sphy->drv_data->cpu_type == TYPE_EXYNOS4412)
+		samsung_exynos4412_usbphy_enable(sphy);
 	else
 		samsung_usbphy_enable(sphy);
 
@@ -739,6 +877,8 @@  static void samsung_usbphy_shutdown(struct usb_phy *phy)
 	/* De-initialize usb phy registers */
 	if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
 		samsung_exynos5_usbphy_disable(sphy);
+	else if (sphy->drv_data->cpu_type == TYPE_EXYNOS4412)
+		samsung_exynos4412_usbphy_disable(sphy);
 	else
 		samsung_usbphy_disable(sphy);
 
@@ -872,6 +1012,12 @@  static const struct samsung_usbphy_drvdata usbphy_exynos4 = {
 	.hostphy_en_mask	= EXYNOS_USBPHY_ENABLE,
 };
 
+static const struct samsung_usbphy_drvdata usbphy_exynos4412 = {
+	.cpu_type		= TYPE_EXYNOS4412,
+	.devphy_en_mask		= EXYNOS_USBPHY_ENABLE,
+	.hostphy_en_mask	= EXYNOS_USBPHY_ENABLE,
+};
+
 static struct samsung_usbphy_drvdata usbphy_exynos5 = {
 	.cpu_type		= TYPE_EXYNOS5250,
 	.hostphy_en_mask	= EXYNOS_USBPHY_ENABLE,
@@ -887,6 +1033,9 @@  static const struct of_device_id samsung_usbphy_dt_match[] = {
 		.compatible = "samsung,exynos4210-usbphy",
 		.data = &usbphy_exynos4,
 	}, {
+		.compatible = "samsung,exynos4412-usbphy",
+		.data = &usbphy_exynos4412,
+	}, {
 		.compatible = "samsung,exynos5250-usbphy",
 		.data = &usbphy_exynos5
 	},
@@ -903,6 +1052,9 @@  static struct platform_device_id samsung_usbphy_driver_ids[] = {
 		.name		= "exynos4210-usbphy",
 		.driver_data	= (unsigned long)&usbphy_exynos4,
 	}, {
+		.name		= "exynos4412-usbphy",
+		.driver_data	= (unsigned long)&usbphy_exynos4412,
+	}, {
 		.name		= "exynos5250-usbphy",
 		.driver_data	= (unsigned long)&usbphy_exynos5,
 	},