xref: /openbmc/linux/arch/arm/mach-s3c/setup-usb-phy-s3c64xx.c (revision 71b9114d2c13a648fbe6523dd859e611c316ad90)
1*71b9114dSArnd Bergmann // SPDX-License-Identifier: GPL-2.0+
2*71b9114dSArnd Bergmann //
3*71b9114dSArnd Bergmann // Copyright (C) 2011 Samsung Electronics Co.Ltd
4*71b9114dSArnd Bergmann // Author: Joonyoung Shim <jy0922.shim@samsung.com>
5*71b9114dSArnd Bergmann 
6*71b9114dSArnd Bergmann #include <linux/clk.h>
7*71b9114dSArnd Bergmann #include <linux/delay.h>
8*71b9114dSArnd Bergmann #include <linux/err.h>
9*71b9114dSArnd Bergmann #include <linux/io.h>
10*71b9114dSArnd Bergmann #include <linux/platform_device.h>
11*71b9114dSArnd Bergmann #include <mach/map.h>
12*71b9114dSArnd Bergmann #include <plat/cpu.h>
13*71b9114dSArnd Bergmann #include <plat/usb-phy.h>
14*71b9114dSArnd Bergmann 
15*71b9114dSArnd Bergmann #include "regs-sys-s3c64xx.h"
16*71b9114dSArnd Bergmann #include "regs-usb-hsotg-phy-s3c64xx.h"
17*71b9114dSArnd Bergmann 
18*71b9114dSArnd Bergmann enum samsung_usb_phy_type {
19*71b9114dSArnd Bergmann 	USB_PHY_TYPE_DEVICE,
20*71b9114dSArnd Bergmann 	USB_PHY_TYPE_HOST,
21*71b9114dSArnd Bergmann };
22*71b9114dSArnd Bergmann 
23*71b9114dSArnd Bergmann static int s3c_usb_otgphy_init(struct platform_device *pdev)
24*71b9114dSArnd Bergmann {
25*71b9114dSArnd Bergmann 	struct clk *xusbxti;
26*71b9114dSArnd Bergmann 	u32 phyclk;
27*71b9114dSArnd Bergmann 
28*71b9114dSArnd Bergmann 	writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
29*71b9114dSArnd Bergmann 
30*71b9114dSArnd Bergmann 	/* set clock frequency for PLL */
31*71b9114dSArnd Bergmann 	phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK;
32*71b9114dSArnd Bergmann 
33*71b9114dSArnd Bergmann 	xusbxti = clk_get(&pdev->dev, "xusbxti");
34*71b9114dSArnd Bergmann 	if (!IS_ERR(xusbxti)) {
35*71b9114dSArnd Bergmann 		switch (clk_get_rate(xusbxti)) {
36*71b9114dSArnd Bergmann 		case 12 * MHZ:
37*71b9114dSArnd Bergmann 			phyclk |= S3C_PHYCLK_CLKSEL_12M;
38*71b9114dSArnd Bergmann 			break;
39*71b9114dSArnd Bergmann 		case 24 * MHZ:
40*71b9114dSArnd Bergmann 			phyclk |= S3C_PHYCLK_CLKSEL_24M;
41*71b9114dSArnd Bergmann 			break;
42*71b9114dSArnd Bergmann 		default:
43*71b9114dSArnd Bergmann 		case 48 * MHZ:
44*71b9114dSArnd Bergmann 			/* default reference clock */
45*71b9114dSArnd Bergmann 			break;
46*71b9114dSArnd Bergmann 		}
47*71b9114dSArnd Bergmann 		clk_put(xusbxti);
48*71b9114dSArnd Bergmann 	}
49*71b9114dSArnd Bergmann 
50*71b9114dSArnd Bergmann 	/* TODO: select external clock/oscillator */
51*71b9114dSArnd Bergmann 	writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
52*71b9114dSArnd Bergmann 
53*71b9114dSArnd Bergmann 	/* set to normal OTG PHY */
54*71b9114dSArnd Bergmann 	writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR);
55*71b9114dSArnd Bergmann 	mdelay(1);
56*71b9114dSArnd Bergmann 
57*71b9114dSArnd Bergmann 	/* reset OTG PHY and Link */
58*71b9114dSArnd Bergmann 	writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK,
59*71b9114dSArnd Bergmann 			S3C_RSTCON);
60*71b9114dSArnd Bergmann 	udelay(20);	/* at-least 10uS */
61*71b9114dSArnd Bergmann 	writel(0, S3C_RSTCON);
62*71b9114dSArnd Bergmann 
63*71b9114dSArnd Bergmann 	return 0;
64*71b9114dSArnd Bergmann }
65*71b9114dSArnd Bergmann 
66*71b9114dSArnd Bergmann static int s3c_usb_otgphy_exit(struct platform_device *pdev)
67*71b9114dSArnd Bergmann {
68*71b9114dSArnd Bergmann 	writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN |
69*71b9114dSArnd Bergmann 				S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR);
70*71b9114dSArnd Bergmann 
71*71b9114dSArnd Bergmann 	writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
72*71b9114dSArnd Bergmann 
73*71b9114dSArnd Bergmann 	return 0;
74*71b9114dSArnd Bergmann }
75*71b9114dSArnd Bergmann 
76*71b9114dSArnd Bergmann int s3c_usb_phy_init(struct platform_device *pdev, int type)
77*71b9114dSArnd Bergmann {
78*71b9114dSArnd Bergmann 	if (type == USB_PHY_TYPE_DEVICE)
79*71b9114dSArnd Bergmann 		return s3c_usb_otgphy_init(pdev);
80*71b9114dSArnd Bergmann 
81*71b9114dSArnd Bergmann 	return -EINVAL;
82*71b9114dSArnd Bergmann }
83*71b9114dSArnd Bergmann 
84*71b9114dSArnd Bergmann int s3c_usb_phy_exit(struct platform_device *pdev, int type)
85*71b9114dSArnd Bergmann {
86*71b9114dSArnd Bergmann 	if (type == USB_PHY_TYPE_DEVICE)
87*71b9114dSArnd Bergmann 		return s3c_usb_otgphy_exit(pdev);
88*71b9114dSArnd Bergmann 
89*71b9114dSArnd Bergmann 	return -EINVAL;
90*71b9114dSArnd Bergmann }
91