aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy
diff options
context:
space:
mode:
authorMateusz Krawczuk <mat.krawczuk@gmail.com>2013-12-20 08:24:12 -0500
committerKukjin Kim <kgene.kim@samsung.com>2014-07-18 15:25:09 -0400
commit949ccc3a93630ed61f0f38fbf76ee2667d11d3f7 (patch)
treec97d3444abf80ba8acd0a75dd0b6bec446f38927 /drivers/phy
parent9978f28f695adb63fa1726744a7f95e12920e8c9 (diff)
phy: Add support for S5PV210 to the Exynos USB 2.0 PHY driver
Add support for the Samsung's S5PV210 SoC to the Exynos USB 2.0 PHY driver. Signed-off-by: Mateusz Krawczuk <m.krawczuk@partner.samsung.com> [k.debski@samsung.com: cleanup and commit description] [k.debski@samsung.com: make changes accordingly to the mailing list comments] Signed-off-by: Kamil Debski <k.debski@samsung.com> Signed-off-by: Tomasz Figa <t.figa@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/Kconfig10
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/phy-s5pv210-usb2.c187
-rw-r--r--drivers/phy/phy-samsung-usb2.c6
-rw-r--r--drivers/phy/phy-samsung-usb2.h1
5 files changed, 205 insertions, 0 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 64b98d242ea6..b0525e03782a 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -132,6 +132,16 @@ config PHY_SAMSUNG_USB2
132 particular SoCs has to be enabled in addition to this driver. Number 132 particular SoCs has to be enabled in addition to this driver. Number
133 and type of supported phys depends on the SoC. 133 and type of supported phys depends on the SoC.
134 134
135config PHY_S5PV210_USB2
136 bool "Support for S5PV210"
137 depends on PHY_SAMSUNG_USB2
138 depends on ARCH_S5PV210
139 help
140 Enable USB PHY support for S5PV210. This option requires that Samsung
141 USB 2.0 PHY driver is enabled and means that support for this
142 particular SoC is compiled in the driver. In case of S5PV210 two phys
143 are available - device and host.
144
135config PHY_EXYNOS4210_USB2 145config PHY_EXYNOS4210_USB2
136 bool "Support for Exynos 4210" 146 bool "Support for Exynos 4210"
137 depends on PHY_SAMSUNG_USB2 147 depends on PHY_SAMSUNG_USB2
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index b4f1d5770601..2983808e1626 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -18,5 +18,6 @@ phy-exynos-usb2-y += phy-samsung-usb2.o
18phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o 18phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
19phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o 19phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o
20phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o 20phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o
21phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o
21obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o 22obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o
22obj-$(CONFIG_PHY_XGENE) += phy-xgene.o 23obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
diff --git a/drivers/phy/phy-s5pv210-usb2.c b/drivers/phy/phy-s5pv210-usb2.c
new file mode 100644
index 000000000000..004d320767e4
--- /dev/null
+++ b/drivers/phy/phy-s5pv210-usb2.c
@@ -0,0 +1,187 @@
1/*
2 * Samsung SoC USB 1.1/2.0 PHY driver - S5PV210 support
3 *
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5 * Authors: Kamil Debski <k.debski@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/delay.h>
13#include <linux/io.h>
14#include <linux/phy/phy.h>
15#include "phy-samsung-usb2.h"
16
17/* Exynos USB PHY registers */
18
19/* PHY power control */
20#define S5PV210_UPHYPWR 0x0
21
22#define S5PV210_UPHYPWR_PHY0_SUSPEND BIT(0)
23#define S5PV210_UPHYPWR_PHY0_PWR BIT(3)
24#define S5PV210_UPHYPWR_PHY0_OTG_PWR BIT(4)
25#define S5PV210_UPHYPWR_PHY0 ( \
26 S5PV210_UPHYPWR_PHY0_SUSPEND | \
27 S5PV210_UPHYPWR_PHY0_PWR | \
28 S5PV210_UPHYPWR_PHY0_OTG_PWR)
29
30#define S5PV210_UPHYPWR_PHY1_SUSPEND BIT(6)
31#define S5PV210_UPHYPWR_PHY1_PWR BIT(7)
32#define S5PV210_UPHYPWR_PHY1 ( \
33 S5PV210_UPHYPWR_PHY1_SUSPEND | \
34 S5PV210_UPHYPWR_PHY1_PWR)
35
36/* PHY clock control */
37#define S5PV210_UPHYCLK 0x4
38
39#define S5PV210_UPHYCLK_PHYFSEL_MASK (0x3 << 0)
40#define S5PV210_UPHYCLK_PHYFSEL_48MHZ (0x0 << 0)
41#define S5PV210_UPHYCLK_PHYFSEL_24MHZ (0x3 << 0)
42#define S5PV210_UPHYCLK_PHYFSEL_12MHZ (0x2 << 0)
43
44#define S5PV210_UPHYCLK_PHY0_ID_PULLUP BIT(2)
45#define S5PV210_UPHYCLK_PHY0_COMMON_ON BIT(4)
46#define S5PV210_UPHYCLK_PHY1_COMMON_ON BIT(7)
47
48/* PHY reset control */
49#define S5PV210_UPHYRST 0x8
50
51#define S5PV210_URSTCON_PHY0 BIT(0)
52#define S5PV210_URSTCON_OTG_HLINK BIT(1)
53#define S5PV210_URSTCON_OTG_PHYLINK BIT(2)
54#define S5PV210_URSTCON_PHY1_ALL BIT(3)
55#define S5PV210_URSTCON_HOST_LINK_ALL BIT(4)
56
57/* Isolation, configured in the power management unit */
58#define S5PV210_USB_ISOL_OFFSET 0x680c
59#define S5PV210_USB_ISOL_DEVICE BIT(0)
60#define S5PV210_USB_ISOL_HOST BIT(1)
61
62
63enum s5pv210_phy_id {
64 S5PV210_DEVICE,
65 S5PV210_HOST,
66 S5PV210_NUM_PHYS,
67};
68
69/*
70 * s5pv210_rate_to_clk() converts the supplied clock rate to the value that
71 * can be written to the phy register.
72 */
73static int s5pv210_rate_to_clk(unsigned long rate, u32 *reg)
74{
75 switch (rate) {
76 case 12 * MHZ:
77 *reg = S5PV210_UPHYCLK_PHYFSEL_12MHZ;
78 break;
79 case 24 * MHZ:
80 *reg = S5PV210_UPHYCLK_PHYFSEL_24MHZ;
81 break;
82 case 48 * MHZ:
83 *reg = S5PV210_UPHYCLK_PHYFSEL_48MHZ;
84 break;
85 default:
86 return -EINVAL;
87 }
88
89 return 0;
90}
91
92static void s5pv210_isol(struct samsung_usb2_phy_instance *inst, bool on)
93{
94 struct samsung_usb2_phy_driver *drv = inst->drv;
95 u32 mask;
96
97 switch (inst->cfg->id) {
98 case S5PV210_DEVICE:
99 mask = S5PV210_USB_ISOL_DEVICE;
100 break;
101 case S5PV210_HOST:
102 mask = S5PV210_USB_ISOL_HOST;
103 break;
104 default:
105 return;
106 };
107
108 regmap_update_bits(drv->reg_pmu, S5PV210_USB_ISOL_OFFSET,
109 mask, on ? 0 : mask);
110}
111
112static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
113{
114 struct samsung_usb2_phy_driver *drv = inst->drv;
115 u32 rstbits = 0;
116 u32 phypwr = 0;
117 u32 rst;
118 u32 pwr;
119
120 switch (inst->cfg->id) {
121 case S5PV210_DEVICE:
122 phypwr = S5PV210_UPHYPWR_PHY0;
123 rstbits = S5PV210_URSTCON_PHY0;
124 break;
125 case S5PV210_HOST:
126 phypwr = S5PV210_UPHYPWR_PHY1;
127 rstbits = S5PV210_URSTCON_PHY1_ALL |
128 S5PV210_URSTCON_HOST_LINK_ALL;
129 break;
130 };
131
132 if (on) {
133 writel(drv->ref_reg_val, drv->reg_phy + S5PV210_UPHYCLK);
134
135 pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
136 pwr &= ~phypwr;
137 writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
138
139 rst = readl(drv->reg_phy + S5PV210_UPHYRST);
140 rst |= rstbits;
141 writel(rst, drv->reg_phy + S5PV210_UPHYRST);
142 udelay(10);
143 rst &= ~rstbits;
144 writel(rst, drv->reg_phy + S5PV210_UPHYRST);
145 } else {
146 pwr = readl(drv->reg_phy + S5PV210_UPHYPWR);
147 pwr |= phypwr;
148 writel(pwr, drv->reg_phy + S5PV210_UPHYPWR);
149 }
150}
151
152static int s5pv210_power_on(struct samsung_usb2_phy_instance *inst)
153{
154 s5pv210_isol(inst, 0);
155 s5pv210_phy_pwr(inst, 1);
156
157 return 0;
158}
159
160static int s5pv210_power_off(struct samsung_usb2_phy_instance *inst)
161{
162 s5pv210_phy_pwr(inst, 0);
163 s5pv210_isol(inst, 1);
164
165 return 0;
166}
167
168static const struct samsung_usb2_common_phy s5pv210_phys[S5PV210_NUM_PHYS] = {
169 [S5PV210_DEVICE] = {
170 .label = "device",
171 .id = S5PV210_DEVICE,
172 .power_on = s5pv210_power_on,
173 .power_off = s5pv210_power_off,
174 },
175 [S5PV210_HOST] = {
176 .label = "host",
177 .id = S5PV210_HOST,
178 .power_on = s5pv210_power_on,
179 .power_off = s5pv210_power_off,
180 },
181};
182
183const struct samsung_usb2_phy_config s5pv210_usb2_phy_config = {
184 .num_phys = ARRAY_SIZE(s5pv210_phys),
185 .phys = s5pv210_phys,
186 .rate_to_clk = s5pv210_rate_to_clk,
187};
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
index 1e69a32c221d..29e4ab987645 100644
--- a/drivers/phy/phy-samsung-usb2.c
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -87,6 +87,12 @@ static struct phy *samsung_usb2_phy_xlate(struct device *dev,
87} 87}
88 88
89static const struct of_device_id samsung_usb2_phy_of_match[] = { 89static const struct of_device_id samsung_usb2_phy_of_match[] = {
90#ifdef CONFIG_PHY_S5PV210_USB2
91 {
92 .compatible = "samsung,s5pv210-usb2-phy",
93 .data = &s5pv210_usb2_phy_config,
94 },
95#endif
90#ifdef CONFIG_PHY_EXYNOS4210_USB2 96#ifdef CONFIG_PHY_EXYNOS4210_USB2
91 { 97 {
92 .compatible = "samsung,exynos4210-usb2-phy", 98 .compatible = "samsung,exynos4210-usb2-phy",
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
index 45b3170652bd..1c55795d4429 100644
--- a/drivers/phy/phy-samsung-usb2.h
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -61,6 +61,7 @@ struct samsung_usb2_phy_config {
61 bool has_mode_switch; 61 bool has_mode_switch;
62}; 62};
63 63
64extern const struct samsung_usb2_phy_config s5pv210_usb2_phy_config;
64extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config; 65extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
65extern const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config; 66extern const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config;
66extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config; 67extern const struct samsung_usb2_phy_config exynos5250_usb2_phy_config;