Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-exynos4/setup-usb-phy.c
10817 views
1
/*
2
* Copyright (C) 2011 Samsung Electronics Co.Ltd
3
* Author: Joonyoung Shim <[email protected]>
4
*
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License as published by the
7
* Free Software Foundation; either version 2 of the License, or (at your
8
* option) any later version.
9
*
10
*/
11
12
#include <linux/clk.h>
13
#include <linux/delay.h>
14
#include <linux/err.h>
15
#include <linux/io.h>
16
#include <linux/platform_device.h>
17
#include <mach/regs-pmu.h>
18
#include <mach/regs-usb-phy.h>
19
#include <plat/cpu.h>
20
#include <plat/usb-phy.h>
21
22
static int exynos4_usb_phy1_init(struct platform_device *pdev)
23
{
24
struct clk *otg_clk;
25
struct clk *xusbxti_clk;
26
u32 phyclk;
27
u32 rstcon;
28
int err;
29
30
otg_clk = clk_get(&pdev->dev, "otg");
31
if (IS_ERR(otg_clk)) {
32
dev_err(&pdev->dev, "Failed to get otg clock\n");
33
return PTR_ERR(otg_clk);
34
}
35
36
err = clk_enable(otg_clk);
37
if (err) {
38
clk_put(otg_clk);
39
return err;
40
}
41
42
writel(readl(S5P_USBHOST_PHY_CONTROL) | S5P_USBHOST_PHY_ENABLE,
43
S5P_USBHOST_PHY_CONTROL);
44
45
/* set clock frequency for PLL */
46
phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
47
48
xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
49
if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
50
switch (clk_get_rate(xusbxti_clk)) {
51
case 12 * MHZ:
52
phyclk |= CLKSEL_12M;
53
break;
54
case 24 * MHZ:
55
phyclk |= CLKSEL_24M;
56
break;
57
default:
58
case 48 * MHZ:
59
/* default reference clock */
60
break;
61
}
62
clk_put(xusbxti_clk);
63
}
64
65
writel(phyclk, EXYNOS4_PHYCLK);
66
67
/* floating prevention logic: disable */
68
writel((readl(EXYNOS4_PHY1CON) | FPENABLEN), EXYNOS4_PHY1CON);
69
70
/* set to normal HSIC 0 and 1 of PHY1 */
71
writel((readl(EXYNOS4_PHYPWR) & ~PHY1_HSIC_NORMAL_MASK),
72
EXYNOS4_PHYPWR);
73
74
/* set to normal standard USB of PHY1 */
75
writel((readl(EXYNOS4_PHYPWR) & ~PHY1_STD_NORMAL_MASK), EXYNOS4_PHYPWR);
76
77
/* reset all ports of both PHY and Link */
78
rstcon = readl(EXYNOS4_RSTCON) | HOST_LINK_PORT_SWRST_MASK |
79
PHY1_SWRST_MASK;
80
writel(rstcon, EXYNOS4_RSTCON);
81
udelay(10);
82
83
rstcon &= ~(HOST_LINK_PORT_SWRST_MASK | PHY1_SWRST_MASK);
84
writel(rstcon, EXYNOS4_RSTCON);
85
udelay(50);
86
87
clk_disable(otg_clk);
88
clk_put(otg_clk);
89
90
return 0;
91
}
92
93
static int exynos4_usb_phy1_exit(struct platform_device *pdev)
94
{
95
struct clk *otg_clk;
96
int err;
97
98
otg_clk = clk_get(&pdev->dev, "otg");
99
if (IS_ERR(otg_clk)) {
100
dev_err(&pdev->dev, "Failed to get otg clock\n");
101
return PTR_ERR(otg_clk);
102
}
103
104
err = clk_enable(otg_clk);
105
if (err) {
106
clk_put(otg_clk);
107
return err;
108
}
109
110
writel((readl(EXYNOS4_PHYPWR) | PHY1_STD_ANALOG_POWERDOWN),
111
EXYNOS4_PHYPWR);
112
113
writel(readl(S5P_USBHOST_PHY_CONTROL) & ~S5P_USBHOST_PHY_ENABLE,
114
S5P_USBHOST_PHY_CONTROL);
115
116
clk_disable(otg_clk);
117
clk_put(otg_clk);
118
119
return 0;
120
}
121
122
int s5p_usb_phy_init(struct platform_device *pdev, int type)
123
{
124
if (type == S5P_USB_PHY_HOST)
125
return exynos4_usb_phy1_init(pdev);
126
127
return -EINVAL;
128
}
129
130
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
131
{
132
if (type == S5P_USB_PHY_HOST)
133
return exynos4_usb_phy1_exit(pdev);
134
135
return -EINVAL;
136
}
137
138