aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/phy/samsung-phy.txt53
-rw-r--r--Documentation/phy/samsung-usb2.txt135
-rw-r--r--drivers/phy/Kconfig29
-rw-r--r--drivers/phy/Makefile3
-rw-r--r--drivers/phy/phy-exynos4210-usb2.c261
-rw-r--r--drivers/phy/phy-exynos4x12-usb2.c328
-rw-r--r--drivers/phy/phy-samsung-usb2.c222
-rw-r--r--drivers/phy/phy-samsung-usb2.h66
8 files changed, 1097 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/phy/samsung-phy.txt b/Documentation/devicetree/bindings/phy/samsung-phy.txt
index c0fccaa1671e..bf955abba5d9 100644
--- a/Documentation/devicetree/bindings/phy/samsung-phy.txt
+++ b/Documentation/devicetree/bindings/phy/samsung-phy.txt
@@ -20,3 +20,56 @@ Required properties:
20- compatible : should be "samsung,exynos5250-dp-video-phy"; 20- compatible : should be "samsung,exynos5250-dp-video-phy";
21- reg : offset and length of the Display Port PHY register set; 21- reg : offset and length of the Display Port PHY register set;
22- #phy-cells : from the generic PHY bindings, must be 0; 22- #phy-cells : from the generic PHY bindings, must be 0;
23
24Samsung S5P/EXYNOS SoC series USB PHY
25-------------------------------------------------
26
27Required properties:
28- compatible : should be one of the listed compatibles:
29 - "samsung,exynos4210-usb2-phy"
30 - "samsung,exynos4x12-usb2-phy"
31- reg : a list of registers used by phy driver
32 - first and obligatory is the location of phy modules registers
33- samsung,sysreg-phandle - handle to syscon used to control the system registers
34- samsung,pmureg-phandle - handle to syscon used to control PMU registers
35- #phy-cells : from the generic phy bindings, must be 1;
36- clocks and clock-names:
37 - the "phy" clock is required by the phy module, used as a gate
38 - the "ref" clock is used to get the rate of the clock provided to the
39 PHY module
40
41The first phandle argument in the PHY specifier identifies the PHY, its
42meaning is compatible dependent. For the currently supported SoCs (Exynos 4210
43and Exynos 4212) it is as follows:
44 0 - USB device ("device"),
45 1 - USB host ("host"),
46 2 - HSIC0 ("hsic0"),
47 3 - HSIC1 ("hsic1"),
48
49Exynos 4210 and Exynos 4212 use mode switching and require that mode switch
50register is supplied.
51
52Example:
53
54For Exynos 4412 (compatible with Exynos 4212):
55
56usbphy: phy@125b0000 {
57 compatible = "samsung,exynos4x12-usb2-phy";
58 reg = <0x125b0000 0x100>;
59 clocks = <&clock 305>, <&clock 2>;
60 clock-names = "phy", "ref";
61 status = "okay";
62 #phy-cells = <1>;
63 samsung,sysreg-phandle = <&sys_reg>;
64 samsung,pmureg-phandle = <&pmu_reg>;
65};
66
67Then the PHY can be used in other nodes such as:
68
69phy-consumer@12340000 {
70 phys = <&usbphy 2>;
71 phy-names = "phy";
72};
73
74Refer to DT bindings documentation of particular PHY consumer devices for more
75information about required PHYs and the way of specification.
diff --git a/Documentation/phy/samsung-usb2.txt b/Documentation/phy/samsung-usb2.txt
new file mode 100644
index 000000000000..ed12d437189d
--- /dev/null
+++ b/Documentation/phy/samsung-usb2.txt
@@ -0,0 +1,135 @@
1.------------------------------------------------------------------------------+
2| Samsung USB 2.0 PHY adaptation layer |
3+-----------------------------------------------------------------------------+'
4
5| 1. Description
6+----------------
7
8The architecture of the USB 2.0 PHY module in Samsung SoCs is similar
9among many SoCs. In spite of the similarities it proved difficult to
10create a one driver that would fit all these PHY controllers. Often
11the differences were minor and were found in particular bits of the
12registers of the PHY. In some rare cases the order of register writes or
13the PHY powering up process had to be altered. This adaptation layer is
14a compromise between having separate drivers and having a single driver
15with added support for many special cases.
16
17| 2. Files description
18+----------------------
19
20- phy-samsung-usb2.c
21 This is the main file of the adaptation layer. This file contains
22 the probe function and provides two callbacks to the Generic PHY
23 Framework. This two callbacks are used to power on and power off the
24 phy. They carry out the common work that has to be done on all version
25 of the PHY module. Depending on which SoC was chosen they execute SoC
26 specific callbacks. The specific SoC version is selected by choosing
27 the appropriate compatible string. In addition, this file contains
28 struct of_device_id definitions for particular SoCs.
29
30- phy-samsung-usb2.h
31 This is the include file. It declares the structures used by this
32 driver. In addition it should contain extern declarations for
33 structures that describe particular SoCs.
34
35| 3. Supporting SoCs
36+--------------------
37
38To support a new SoC a new file should be added to the drivers/phy
39directory. Each SoC's configuration is stored in an instance of the
40struct samsung_usb2_phy_config.
41
42struct samsung_usb2_phy_config {
43 const struct samsung_usb2_common_phy *phys;
44 int (*rate_to_clk)(unsigned long, u32 *);
45 unsigned int num_phys;
46 bool has_mode_switch;
47};
48
49The num_phys is the number of phys handled by the driver. *phys is an
50array that contains the configuration for each phy. The has_mode_switch
51property is a boolean flag that determines whether the SoC has USB host
52and device on a single pair of pins. If so, a special register has to
53be modified to change the internal routing of these pins between a USB
54device or host module.
55
56For example the configuration for Exynos 4210 is following:
57
58const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
59 .has_mode_switch = 0,
60 .num_phys = EXYNOS4210_NUM_PHYS,
61 .phys = exynos4210_phys,
62 .rate_to_clk = exynos4210_rate_to_clk,
63}
64
65- int (*rate_to_clk)(unsigned long, u32 *)
66 The rate_to_clk callback is to convert the rate of the clock
67 used as the reference clock for the PHY module to the value
68 that should be written in the hardware register.
69
70The exynos4210_phys configuration array is as follows:
71
72static const struct samsung_usb2_common_phy exynos4210_phys[] = {
73 {
74 .label = "device",
75 .id = EXYNOS4210_DEVICE,
76 .power_on = exynos4210_power_on,
77 .power_off = exynos4210_power_off,
78 },
79 {
80 .label = "host",
81 .id = EXYNOS4210_HOST,
82 .power_on = exynos4210_power_on,
83 .power_off = exynos4210_power_off,
84 },
85 {
86 .label = "hsic0",
87 .id = EXYNOS4210_HSIC0,
88 .power_on = exynos4210_power_on,
89 .power_off = exynos4210_power_off,
90 },
91 {
92 .label = "hsic1",
93 .id = EXYNOS4210_HSIC1,
94 .power_on = exynos4210_power_on,
95 .power_off = exynos4210_power_off,
96 },
97 {},
98};
99
100- int (*power_on)(struct samsung_usb2_phy_instance *);
101- int (*power_off)(struct samsung_usb2_phy_instance *);
102 These two callbacks are used to power on and power off the phy
103 by modifying appropriate registers.
104
105Final change to the driver is adding appropriate compatible value to the
106phy-samsung-usb2.c file. In case of Exynos 4210 the following lines were
107added to the struct of_device_id samsung_usb2_phy_of_match[] array:
108
109#ifdef CONFIG_PHY_EXYNOS4210_USB2
110 {
111 .compatible = "samsung,exynos4210-usb2-phy",
112 .data = &exynos4210_usb2_phy_config,
113 },
114#endif
115
116To add further flexibility to the driver the Kconfig file enables to
117include support for selected SoCs in the compiled driver. The Kconfig
118entry for Exynos 4210 is following:
119
120config PHY_EXYNOS4210_USB2
121 bool "Support for Exynos 4210"
122 depends on PHY_SAMSUNG_USB2
123 depends on CPU_EXYNOS4210
124 help
125 Enable USB PHY support for Exynos 4210. This option requires that
126 Samsung USB 2.0 PHY driver is enabled and means that support for this
127 particular SoC is compiled in the driver. In case of Exynos 4210 four
128 phys are available - device, host, HSCI0 and HSCI1.
129
130The newly created file that supports the new SoC has to be also added to the
131Makefile. In case of Exynos 4210 the added line is following:
132
133obj-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
134
135After completing these steps the support for the new SoC should be ready.
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index fde4192cc322..337483653754 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -107,4 +107,33 @@ config PHY_SUN4I_USB
107 This driver controls the entire USB PHY block, both the USB OTG 107 This driver controls the entire USB PHY block, both the USB OTG
108 parts, as well as the 2 regular USB 2 host PHYs. 108 parts, as well as the 2 regular USB 2 host PHYs.
109 109
110config PHY_SAMSUNG_USB2
111 tristate "Samsung USB 2.0 PHY driver"
112 select GENERIC_PHY
113 select MFD_SYSCON
114 help
115 Enable this to support the Samsung USB 2.0 PHY driver for Samsung
116 SoCs. This driver provides the interface for USB 2.0 PHY. Support for
117 particular SoCs has to be enabled in addition to this driver. Number
118 and type of supported phys depends on the SoC.
119
120config PHY_EXYNOS4210_USB2
121 bool "Support for Exynos 4210"
122 depends on PHY_SAMSUNG_USB2
123 depends on CPU_EXYNOS4210
124 help
125 Enable USB PHY support for Exynos 4210. This option requires that
126 Samsung USB 2.0 PHY driver is enabled and means that support for this
127 particular SoC is compiled in the driver. In case of Exynos 4210 four
128 phys are available - device, host, HSIC0 and HSIC1.
129
130config PHY_EXYNOS4X12_USB2
131 bool "Support for Exynos 4x12"
132 depends on PHY_SAMSUNG_USB2
133 depends on (SOC_EXYNOS4212 || SOC_EXYNOS4412)
134 help
135 Enable USB PHY support for Exynos 4x12. This option requires that
136 Samsung USB 2.0 PHY driver is enabled and means that support for this
137 particular SoC is compiled in the driver. In case of Exynos 4x12 four
138 phys are available - device, host, HSIC0 and HSIC1.
110endmenu 139endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 977a50ead5a4..c4ddd23d6d24 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -12,3 +12,6 @@ obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o
12obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o 12obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
13obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o 13obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o
14obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o 14obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
15obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-samsung-usb2.o
16obj-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o
17obj-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o
diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/phy-exynos4210-usb2.c
new file mode 100644
index 000000000000..236a52ad94eb
--- /dev/null
+++ b/drivers/phy/phy-exynos4210-usb2.c
@@ -0,0 +1,261 @@
1/*
2 * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
3 *
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5 * Author: 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 <linux/regmap.h>
16#include "phy-samsung-usb2.h"
17
18/* Exynos USB PHY registers */
19
20/* PHY power control */
21#define EXYNOS_4210_UPHYPWR 0x0
22
23#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND BIT(0)
24#define EXYNOS_4210_UPHYPWR_PHY0_PWR BIT(3)
25#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR BIT(4)
26#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP BIT(5)
27#define EXYNOS_4210_UPHYPWR_PHY0 ( \
28 EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
29 EXYNOS_4210_UPHYPWR_PHY0_PWR | \
30 EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
31 EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
32
33#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND BIT(6)
34#define EXYNOS_4210_UPHYPWR_PHY1_PWR BIT(7)
35#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP BIT(8)
36#define EXYNOS_4210_UPHYPWR_PHY1 ( \
37 EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
38 EXYNOS_4210_UPHYPWR_PHY1_PWR | \
39 EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
40
41#define EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND BIT(9)
42#define EXYNOS_4210_UPHYPWR_HSIC0_SLEEP BIT(10)
43#define EXYNOS_4210_UPHYPWR_HSIC0 ( \
44 EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND | \
45 EXYNOS_4210_UPHYPWR_HSIC0_SLEEP)
46
47#define EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND BIT(11)
48#define EXYNOS_4210_UPHYPWR_HSIC1_SLEEP BIT(12)
49#define EXYNOS_4210_UPHYPWR_HSIC1 ( \
50 EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND | \
51 EXYNOS_4210_UPHYPWR_HSIC1_SLEEP)
52
53/* PHY clock control */
54#define EXYNOS_4210_UPHYCLK 0x4
55
56#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK (0x3 << 0)
57#define EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET 0
58#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ (0x0 << 0)
59#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ (0x3 << 0)
60#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ (0x2 << 0)
61
62#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP BIT(2)
63#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON BIT(4)
64#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON BIT(7)
65
66/* PHY reset control */
67#define EXYNOS_4210_UPHYRST 0x8
68
69#define EXYNOS_4210_URSTCON_PHY0 BIT(0)
70#define EXYNOS_4210_URSTCON_OTG_HLINK BIT(1)
71#define EXYNOS_4210_URSTCON_OTG_PHYLINK BIT(2)
72#define EXYNOS_4210_URSTCON_PHY1_ALL BIT(3)
73#define EXYNOS_4210_URSTCON_PHY1_P0 BIT(4)
74#define EXYNOS_4210_URSTCON_PHY1_P1P2 BIT(5)
75#define EXYNOS_4210_URSTCON_HOST_LINK_ALL BIT(6)
76#define EXYNOS_4210_URSTCON_HOST_LINK_P0 BIT(7)
77#define EXYNOS_4210_URSTCON_HOST_LINK_P1 BIT(8)
78#define EXYNOS_4210_URSTCON_HOST_LINK_P2 BIT(9)
79
80/* Isolation, configured in the power management unit */
81#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET 0x704
82#define EXYNOS_4210_USB_ISOL_DEVICE BIT(0)
83#define EXYNOS_4210_USB_ISOL_HOST_OFFSET 0x708
84#define EXYNOS_4210_USB_ISOL_HOST BIT(0)
85
86/* USBYPHY1 Floating prevention */
87#define EXYNOS_4210_UPHY1CON 0x34
88#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION 0x1
89
90/* Mode switching SUB Device <-> Host */
91#define EXYNOS_4210_MODE_SWITCH_OFFSET 0x21c
92#define EXYNOS_4210_MODE_SWITCH_MASK 1
93#define EXYNOS_4210_MODE_SWITCH_DEVICE 0
94#define EXYNOS_4210_MODE_SWITCH_HOST 1
95
96enum exynos4210_phy_id {
97 EXYNOS4210_DEVICE,
98 EXYNOS4210_HOST,
99 EXYNOS4210_HSIC0,
100 EXYNOS4210_HSIC1,
101 EXYNOS4210_NUM_PHYS,
102};
103
104/*
105 * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
106 * can be written to the phy register.
107 */
108static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
109{
110 switch (rate) {
111 case 12 * MHZ:
112 *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
113 break;
114 case 24 * MHZ:
115 *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
116 break;
117 case 48 * MHZ:
118 *reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
119 break;
120 default:
121 return -EINVAL;
122 }
123
124 return 0;
125}
126
127static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
128{
129 struct samsung_usb2_phy_driver *drv = inst->drv;
130 u32 offset;
131 u32 mask;
132
133 switch (inst->cfg->id) {
134 case EXYNOS4210_DEVICE:
135 offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
136 mask = EXYNOS_4210_USB_ISOL_DEVICE;
137 break;
138 case EXYNOS4210_HOST:
139 offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
140 mask = EXYNOS_4210_USB_ISOL_HOST;
141 break;
142 default:
143 return;
144 };
145
146 regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
147}
148
149static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
150{
151 struct samsung_usb2_phy_driver *drv = inst->drv;
152 u32 rstbits = 0;
153 u32 phypwr = 0;
154 u32 rst;
155 u32 pwr;
156 u32 clk;
157
158 switch (inst->cfg->id) {
159 case EXYNOS4210_DEVICE:
160 phypwr = EXYNOS_4210_UPHYPWR_PHY0;
161 rstbits = EXYNOS_4210_URSTCON_PHY0;
162 break;
163 case EXYNOS4210_HOST:
164 phypwr = EXYNOS_4210_UPHYPWR_PHY1;
165 rstbits = EXYNOS_4210_URSTCON_PHY1_ALL |
166 EXYNOS_4210_URSTCON_PHY1_P0 |
167 EXYNOS_4210_URSTCON_PHY1_P1P2 |
168 EXYNOS_4210_URSTCON_HOST_LINK_ALL |
169 EXYNOS_4210_URSTCON_HOST_LINK_P0;
170 writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
171 break;
172 case EXYNOS4210_HSIC0:
173 phypwr = EXYNOS_4210_UPHYPWR_HSIC0;
174 rstbits = EXYNOS_4210_URSTCON_PHY1_P1P2 |
175 EXYNOS_4210_URSTCON_HOST_LINK_P1;
176 break;
177 case EXYNOS4210_HSIC1:
178 phypwr = EXYNOS_4210_UPHYPWR_HSIC1;
179 rstbits = EXYNOS_4210_URSTCON_PHY1_P1P2 |
180 EXYNOS_4210_URSTCON_HOST_LINK_P2;
181 break;
182 };
183
184 if (on) {
185 clk = readl(drv->reg_phy + EXYNOS_4210_UPHYCLK);
186 clk &= ~EXYNOS_4210_UPHYCLK_PHYFSEL_MASK;
187 clk |= drv->ref_reg_val << EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET;
188 writel(clk, drv->reg_phy + EXYNOS_4210_UPHYCLK);
189
190 pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
191 pwr &= ~phypwr;
192 writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
193
194 rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
195 rst |= rstbits;
196 writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
197 udelay(10);
198 rst &= ~rstbits;
199 writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
200 /* The following delay is necessary for the reset sequence to be
201 * completed */
202 udelay(80);
203 } else {
204 pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
205 pwr |= phypwr;
206 writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
207 }
208}
209
210static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
211{
212 /* Order of initialisation is important - first power then isolation */
213 exynos4210_phy_pwr(inst, 1);
214 exynos4210_isol(inst, 0);
215
216 return 0;
217}
218
219static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
220{
221 exynos4210_isol(inst, 1);
222 exynos4210_phy_pwr(inst, 0);
223
224 return 0;
225}
226
227
228static const struct samsung_usb2_common_phy exynos4210_phys[] = {
229 {
230 .label = "device",
231 .id = EXYNOS4210_DEVICE,
232 .power_on = exynos4210_power_on,
233 .power_off = exynos4210_power_off,
234 },
235 {
236 .label = "host",
237 .id = EXYNOS4210_HOST,
238 .power_on = exynos4210_power_on,
239 .power_off = exynos4210_power_off,
240 },
241 {
242 .label = "hsic0",
243 .id = EXYNOS4210_HSIC0,
244 .power_on = exynos4210_power_on,
245 .power_off = exynos4210_power_off,
246 },
247 {
248 .label = "hsic1",
249 .id = EXYNOS4210_HSIC1,
250 .power_on = exynos4210_power_on,
251 .power_off = exynos4210_power_off,
252 },
253 {},
254};
255
256const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
257 .has_mode_switch = 0,
258 .num_phys = EXYNOS4210_NUM_PHYS,
259 .phys = exynos4210_phys,
260 .rate_to_clk = exynos4210_rate_to_clk,
261};
diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/phy-exynos4x12-usb2.c
new file mode 100644
index 000000000000..d92a7cc5698a
--- /dev/null
+++ b/drivers/phy/phy-exynos4x12-usb2.c
@@ -0,0 +1,328 @@
1/*
2 * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4x12 support
3 *
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5 * Author: 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 <linux/regmap.h>
16#include "phy-samsung-usb2.h"
17
18/* Exynos USB PHY registers */
19
20/* PHY power control */
21#define EXYNOS_4x12_UPHYPWR 0x0
22
23#define EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND BIT(0)
24#define EXYNOS_4x12_UPHYPWR_PHY0_PWR BIT(3)
25#define EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR BIT(4)
26#define EXYNOS_4x12_UPHYPWR_PHY0_SLEEP BIT(5)
27#define EXYNOS_4x12_UPHYPWR_PHY0 ( \
28 EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND | \
29 EXYNOS_4x12_UPHYPWR_PHY0_PWR | \
30 EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR | \
31 EXYNOS_4x12_UPHYPWR_PHY0_SLEEP)
32
33#define EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND BIT(6)
34#define EXYNOS_4x12_UPHYPWR_PHY1_PWR BIT(7)
35#define EXYNOS_4x12_UPHYPWR_PHY1_SLEEP BIT(8)
36#define EXYNOS_4x12_UPHYPWR_PHY1 ( \
37 EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND | \
38 EXYNOS_4x12_UPHYPWR_PHY1_PWR | \
39 EXYNOS_4x12_UPHYPWR_PHY1_SLEEP)
40
41#define EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND BIT(9)
42#define EXYNOS_4x12_UPHYPWR_HSIC0_PWR BIT(10)
43#define EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP BIT(11)
44#define EXYNOS_4x12_UPHYPWR_HSIC0 ( \
45 EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND | \
46 EXYNOS_4x12_UPHYPWR_HSIC0_PWR | \
47 EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP)
48
49#define EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND BIT(12)
50#define EXYNOS_4x12_UPHYPWR_HSIC1_PWR BIT(13)
51#define EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP BIT(14)
52#define EXYNOS_4x12_UPHYPWR_HSIC1 ( \
53 EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND | \
54 EXYNOS_4x12_UPHYPWR_HSIC1_PWR | \
55 EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP)
56
57/* PHY clock control */
58#define EXYNOS_4x12_UPHYCLK 0x4
59
60#define EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK (0x7 << 0)
61#define EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET 0
62#define EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6 (0x0 << 0)
63#define EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ (0x1 << 0)
64#define EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ (0x2 << 0)
65#define EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2 (0x3 << 0)
66#define EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ (0x4 << 0)
67#define EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ (0x5 << 0)
68#define EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ (0x7 << 0)
69
70#define EXYNOS_4x12_UPHYCLK_PHY0_ID_PULLUP BIT(3)
71#define EXYNOS_4x12_UPHYCLK_PHY0_COMMON_ON BIT(4)
72#define EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON BIT(7)
73
74#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_MASK (0x7f << 10)
75#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_OFFSET 10
76#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_12MHZ (0x24 << 10)
77#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_15MHZ (0x1c << 10)
78#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_16MHZ (0x1a << 10)
79#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_19MHZ2 (0x15 << 10)
80#define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_20MHZ (0x14 << 10)
81
82/* PHY reset control */
83#define EXYNOS_4x12_UPHYRST 0x8
84
85#define EXYNOS_4x12_URSTCON_PHY0 BIT(0)
86#define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1)
87#define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2)
88#define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3)
89#define EXYNOS_4x12_URSTCON_PHY1 BIT(4)
90#define EXYNOS_4x12_URSTCON_HSIC0 BIT(5)
91#define EXYNOS_4x12_URSTCON_HSIC1 BIT(6)
92#define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7)
93#define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(8)
94#define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9)
95#define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(10)
96
97/* Isolation, configured in the power management unit */
98#define EXYNOS_4x12_USB_ISOL_OFFSET 0x704
99#define EXYNOS_4x12_USB_ISOL_OTG BIT(0)
100#define EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET 0x708
101#define EXYNOS_4x12_USB_ISOL_HSIC0 BIT(0)
102#define EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET 0x70c
103#define EXYNOS_4x12_USB_ISOL_HSIC1 BIT(0)
104
105/* Mode switching SUB Device <-> Host */
106#define EXYNOS_4x12_MODE_SWITCH_OFFSET 0x21c
107#define EXYNOS_4x12_MODE_SWITCH_MASK 1
108#define EXYNOS_4x12_MODE_SWITCH_DEVICE 0
109#define EXYNOS_4x12_MODE_SWITCH_HOST 1
110
111enum exynos4x12_phy_id {
112 EXYNOS4x12_DEVICE,
113 EXYNOS4x12_HOST,
114 EXYNOS4x12_HSIC0,
115 EXYNOS4x12_HSIC1,
116 EXYNOS4x12_NUM_PHYS,
117};
118
119/*
120 * exynos4x12_rate_to_clk() converts the supplied clock rate to the value that
121 * can be written to the phy register.
122 */
123static int exynos4x12_rate_to_clk(unsigned long rate, u32 *reg)
124{
125 /* EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK */
126
127 switch (rate) {
128 case 9600 * KHZ:
129 *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6;
130 break;
131 case 10 * MHZ:
132 *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ;
133 break;
134 case 12 * MHZ:
135 *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ;
136 break;
137 case 19200 * KHZ:
138 *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2;
139 break;
140 case 20 * MHZ:
141 *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ;
142 break;
143 case 24 * MHZ:
144 *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ;
145 break;
146 case 50 * MHZ:
147 *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ;
148 break;
149 default:
150 return -EINVAL;
151 }
152
153 return 0;
154}
155
156static void exynos4x12_isol(struct samsung_usb2_phy_instance *inst, bool on)
157{
158 struct samsung_usb2_phy_driver *drv = inst->drv;
159 u32 offset;
160 u32 mask;
161
162 switch (inst->cfg->id) {
163 case EXYNOS4x12_DEVICE:
164 case EXYNOS4x12_HOST:
165 offset = EXYNOS_4x12_USB_ISOL_OFFSET;
166 mask = EXYNOS_4x12_USB_ISOL_OTG;
167 break;
168 case EXYNOS4x12_HSIC0:
169 offset = EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET;
170 mask = EXYNOS_4x12_USB_ISOL_HSIC0;
171 break;
172 case EXYNOS4x12_HSIC1:
173 offset = EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET;
174 mask = EXYNOS_4x12_USB_ISOL_HSIC1;
175 break;
176 default:
177 return;
178 };
179
180 regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
181}
182
183static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst)
184{
185 struct samsung_usb2_phy_driver *drv = inst->drv;
186 u32 clk;
187
188 clk = readl(drv->reg_phy + EXYNOS_4x12_UPHYCLK);
189 clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK;
190 clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET;
191 writel(clk, drv->reg_phy + EXYNOS_4x12_UPHYCLK);
192}
193
194static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
195{
196 struct samsung_usb2_phy_driver *drv = inst->drv;
197 u32 rstbits = 0;
198 u32 phypwr = 0;
199 u32 rst;
200 u32 pwr;
201 u32 mode = 0;
202 u32 switch_mode = 0;
203
204 switch (inst->cfg->id) {
205 case EXYNOS4x12_DEVICE:
206 phypwr = EXYNOS_4x12_UPHYPWR_PHY0;
207 rstbits = EXYNOS_4x12_URSTCON_PHY0;
208 mode = EXYNOS_4x12_MODE_SWITCH_DEVICE;
209 switch_mode = 1;
210 break;
211 case EXYNOS4x12_HOST:
212 phypwr = EXYNOS_4x12_UPHYPWR_PHY1;
213 rstbits = EXYNOS_4x12_URSTCON_HOST_PHY;
214 mode = EXYNOS_4x12_MODE_SWITCH_HOST;
215 switch_mode = 1;
216 break;
217 case EXYNOS4x12_HSIC0:
218 phypwr = EXYNOS_4x12_UPHYPWR_HSIC0;
219 rstbits = EXYNOS_4x12_URSTCON_HSIC1 |
220 EXYNOS_4x12_URSTCON_HOST_LINK_P0 |
221 EXYNOS_4x12_URSTCON_HOST_PHY;
222 break;
223 case EXYNOS4x12_HSIC1:
224 phypwr = EXYNOS_4x12_UPHYPWR_HSIC1;
225 rstbits = EXYNOS_4x12_URSTCON_HSIC1 |
226 EXYNOS_4x12_URSTCON_HOST_LINK_P1;
227 break;
228 };
229
230 if (on) {
231 if (switch_mode)
232 regmap_update_bits(drv->reg_sys,
233 EXYNOS_4x12_MODE_SWITCH_OFFSET,
234 EXYNOS_4x12_MODE_SWITCH_MASK, mode);
235
236 pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
237 pwr &= ~phypwr;
238 writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR);
239
240 rst = readl(drv->reg_phy + EXYNOS_4x12_UPHYRST);
241 rst |= rstbits;
242 writel(rst, drv->reg_phy + EXYNOS_4x12_UPHYRST);
243 udelay(10);
244 rst &= ~rstbits;
245 writel(rst, drv->reg_phy + EXYNOS_4x12_UPHYRST);
246 /* The following delay is necessary for the reset sequence to be
247 * completed */
248 udelay(80);
249 } else {
250 pwr = readl(drv->reg_phy + EXYNOS_4x12_UPHYPWR);
251 pwr |= phypwr;
252 writel(pwr, drv->reg_phy + EXYNOS_4x12_UPHYPWR);
253 }
254}
255
256static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst)
257{
258 struct samsung_usb2_phy_driver *drv = inst->drv;
259
260 inst->enabled = 1;
261 exynos4x12_setup_clk(inst);
262 exynos4x12_phy_pwr(inst, 1);
263 exynos4x12_isol(inst, 0);
264
265 /* Power on the device, as it is necessary for HSIC to work */
266 if (inst->cfg->id == EXYNOS4x12_HSIC0) {
267 struct samsung_usb2_phy_instance *device =
268 &drv->instances[EXYNOS4x12_DEVICE];
269 exynos4x12_phy_pwr(device, 1);
270 exynos4x12_isol(device, 0);
271 }
272
273 return 0;
274}
275
276static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst)
277{
278 struct samsung_usb2_phy_driver *drv = inst->drv;
279 struct samsung_usb2_phy_instance *device =
280 &drv->instances[EXYNOS4x12_DEVICE];
281
282 inst->enabled = 0;
283 exynos4x12_isol(inst, 1);
284 exynos4x12_phy_pwr(inst, 0);
285
286 if (inst->cfg->id == EXYNOS4x12_HSIC0 && !device->enabled) {
287 exynos4x12_isol(device, 1);
288 exynos4x12_phy_pwr(device, 0);
289 }
290
291 return 0;
292}
293
294
295static const struct samsung_usb2_common_phy exynos4x12_phys[] = {
296 {
297 .label = "device",
298 .id = EXYNOS4x12_DEVICE,
299 .power_on = exynos4x12_power_on,
300 .power_off = exynos4x12_power_off,
301 },
302 {
303 .label = "host",
304 .id = EXYNOS4x12_HOST,
305 .power_on = exynos4x12_power_on,
306 .power_off = exynos4x12_power_off,
307 },
308 {
309 .label = "hsic0",
310 .id = EXYNOS4x12_HSIC0,
311 .power_on = exynos4x12_power_on,
312 .power_off = exynos4x12_power_off,
313 },
314 {
315 .label = "hsic1",
316 .id = EXYNOS4x12_HSIC1,
317 .power_on = exynos4x12_power_on,
318 .power_off = exynos4x12_power_off,
319 },
320 {},
321};
322
323const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config = {
324 .has_mode_switch = 1,
325 .num_phys = EXYNOS4x12_NUM_PHYS,
326 .phys = exynos4x12_phys,
327 .rate_to_clk = exynos4x12_rate_to_clk,
328};
diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/phy-samsung-usb2.c
new file mode 100644
index 000000000000..c3b771907f18
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.c
@@ -0,0 +1,222 @@
1/*
2 * Samsung SoC USB 1.1/2.0 PHY driver
3 *
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5 * Author: 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/clk.h>
13#include <linux/mfd/syscon.h>
14#include <linux/module.h>
15#include <linux/of.h>
16#include <linux/of_address.h>
17#include <linux/phy/phy.h>
18#include <linux/platform_device.h>
19#include <linux/spinlock.h>
20#include "phy-samsung-usb2.h"
21
22static int samsung_usb2_phy_power_on(struct phy *phy)
23{
24 struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
25 struct samsung_usb2_phy_driver *drv = inst->drv;
26 int ret;
27
28 dev_dbg(drv->dev, "Request to power_on \"%s\" usb phy\n",
29 inst->cfg->label);
30 ret = clk_prepare_enable(drv->clk);
31 if (ret)
32 goto err_main_clk;
33 ret = clk_prepare_enable(drv->ref_clk);
34 if (ret)
35 goto err_instance_clk;
36 if (inst->cfg->power_on) {
37 spin_lock(&drv->lock);
38 ret = inst->cfg->power_on(inst);
39 spin_unlock(&drv->lock);
40 }
41
42 return 0;
43
44err_instance_clk:
45 clk_disable_unprepare(drv->clk);
46err_main_clk:
47 return ret;
48}
49
50static int samsung_usb2_phy_power_off(struct phy *phy)
51{
52 struct samsung_usb2_phy_instance *inst = phy_get_drvdata(phy);
53 struct samsung_usb2_phy_driver *drv = inst->drv;
54 int ret = 0;
55
56 dev_dbg(drv->dev, "Request to power_off \"%s\" usb phy\n",
57 inst->cfg->label);
58 if (inst->cfg->power_off) {
59 spin_lock(&drv->lock);
60 ret = inst->cfg->power_off(inst);
61 spin_unlock(&drv->lock);
62 }
63 clk_disable_unprepare(drv->ref_clk);
64 clk_disable_unprepare(drv->clk);
65 return ret;
66}
67
68static struct phy_ops samsung_usb2_phy_ops = {
69 .power_on = samsung_usb2_phy_power_on,
70 .power_off = samsung_usb2_phy_power_off,
71 .owner = THIS_MODULE,
72};
73
74static struct phy *samsung_usb2_phy_xlate(struct device *dev,
75 struct of_phandle_args *args)
76{
77 struct samsung_usb2_phy_driver *drv;
78
79 drv = dev_get_drvdata(dev);
80 if (!drv)
81 return ERR_PTR(-EINVAL);
82
83 if (WARN_ON(args->args[0] >= drv->cfg->num_phys))
84 return ERR_PTR(-ENODEV);
85
86 return drv->instances[args->args[0]].phy;
87}
88
89static const struct of_device_id samsung_usb2_phy_of_match[] = {
90#ifdef CONFIG_PHY_EXYNOS4210_USB2
91 {
92 .compatible = "samsung,exynos4210-usb2-phy",
93 .data = &exynos4210_usb2_phy_config,
94 },
95#endif
96#ifdef CONFIG_PHY_EXYNOS4X12_USB2
97 {
98 .compatible = "samsung,exynos4x12-usb2-phy",
99 .data = &exynos4x12_usb2_phy_config,
100 },
101#endif
102 { },
103};
104
105static int samsung_usb2_phy_probe(struct platform_device *pdev)
106{
107 const struct of_device_id *match;
108 const struct samsung_usb2_phy_config *cfg;
109 struct device *dev = &pdev->dev;
110 struct phy_provider *phy_provider;
111 struct resource *mem;
112 struct samsung_usb2_phy_driver *drv;
113 int i, ret;
114
115 if (!pdev->dev.of_node) {
116 dev_err(dev, "This driver is required to be instantiated from device tree\n");
117 return -EINVAL;
118 }
119
120 match = of_match_node(samsung_usb2_phy_of_match, pdev->dev.of_node);
121 if (!match) {
122 dev_err(dev, "of_match_node() failed\n");
123 return -EINVAL;
124 }
125 cfg = match->data;
126
127 drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +
128 cfg->num_phys * sizeof(struct samsung_usb2_phy_instance),
129 GFP_KERNEL);
130 if (!drv)
131 return -ENOMEM;
132
133 dev_set_drvdata(dev, drv);
134 spin_lock_init(&drv->lock);
135
136 drv->cfg = cfg;
137 drv->dev = dev;
138
139 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
140 drv->reg_phy = devm_ioremap_resource(dev, mem);
141 if (IS_ERR(drv->reg_phy)) {
142 dev_err(dev, "Failed to map register memory (phy)\n");
143 return PTR_ERR(drv->reg_phy);
144 }
145
146 drv->reg_pmu = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
147 "samsung,pmureg-phandle");
148 if (IS_ERR(drv->reg_pmu)) {
149 dev_err(dev, "Failed to map PMU registers (via syscon)\n");
150 return PTR_ERR(drv->reg_pmu);
151 }
152
153 if (drv->cfg->has_mode_switch) {
154 drv->reg_sys = syscon_regmap_lookup_by_phandle(
155 pdev->dev.of_node, "samsung,sysreg-phandle");
156 if (IS_ERR(drv->reg_sys)) {
157 dev_err(dev, "Failed to map system registers (via syscon)\n");
158 return PTR_ERR(drv->reg_sys);
159 }
160 }
161
162 drv->clk = devm_clk_get(dev, "phy");
163 if (IS_ERR(drv->clk)) {
164 dev_err(dev, "Failed to get clock of phy controller\n");
165 return PTR_ERR(drv->clk);
166 }
167
168 drv->ref_clk = devm_clk_get(dev, "ref");
169 if (IS_ERR(drv->ref_clk)) {
170 dev_err(dev, "Failed to get reference clock for the phy controller\n");
171 return PTR_ERR(drv->ref_clk);
172 }
173
174 drv->ref_rate = clk_get_rate(drv->ref_clk);
175 if (drv->cfg->rate_to_clk) {
176 ret = drv->cfg->rate_to_clk(drv->ref_rate, &drv->ref_reg_val);
177 if (ret)
178 return ret;
179 }
180
181 for (i = 0; i < drv->cfg->num_phys; i++) {
182 char *label = drv->cfg->phys[i].label;
183 struct samsung_usb2_phy_instance *p = &drv->instances[i];
184
185 dev_dbg(dev, "Creating phy \"%s\"\n", label);
186 p->phy = devm_phy_create(dev, &samsung_usb2_phy_ops, NULL);
187 if (IS_ERR(p->phy)) {
188 dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
189 label);
190 return PTR_ERR(p->phy);
191 }
192
193 p->cfg = &drv->cfg->phys[i];
194 p->drv = drv;
195 phy_set_bus_width(p->phy, 8);
196 phy_set_drvdata(p->phy, p);
197 }
198
199 phy_provider = devm_of_phy_provider_register(dev,
200 samsung_usb2_phy_xlate);
201 if (IS_ERR(phy_provider)) {
202 dev_err(drv->dev, "Failed to register phy provider\n");
203 return PTR_ERR(phy_provider);
204 }
205
206 return 0;
207}
208
209static struct platform_driver samsung_usb2_phy_driver = {
210 .probe = samsung_usb2_phy_probe,
211 .driver = {
212 .of_match_table = samsung_usb2_phy_of_match,
213 .name = "samsung-usb2-phy",
214 .owner = THIS_MODULE,
215 }
216};
217
218module_platform_driver(samsung_usb2_phy_driver);
219MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC USB PHY driver");
220MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
221MODULE_LICENSE("GPL v2");
222MODULE_ALIAS("platform:samsung-usb2-phy");
diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/phy-samsung-usb2.h
new file mode 100644
index 000000000000..51a16016a214
--- /dev/null
+++ b/drivers/phy/phy-samsung-usb2.h
@@ -0,0 +1,66 @@
1/*
2 * Samsung SoC USB 1.1/2.0 PHY driver
3 *
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5 * Author: 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#ifndef _PHY_EXYNOS_USB2_H
13#define _PHY_EXYNOS_USB2_H
14
15#include <linux/clk.h>
16#include <linux/phy/phy.h>
17#include <linux/device.h>
18#include <linux/regmap.h>
19#include <linux/spinlock.h>
20
21#define KHZ 1000
22#define MHZ (KHZ * KHZ)
23
24struct samsung_usb2_phy_driver;
25struct samsung_usb2_phy_instance;
26struct samsung_usb2_phy_config;
27
28struct samsung_usb2_phy_instance {
29 const struct samsung_usb2_common_phy *cfg;
30 struct phy *phy;
31 struct samsung_usb2_phy_driver *drv;
32 bool enabled;
33};
34
35struct samsung_usb2_phy_driver {
36 const struct samsung_usb2_phy_config *cfg;
37 struct clk *clk;
38 struct clk *ref_clk;
39 unsigned long ref_rate;
40 u32 ref_reg_val;
41 struct device *dev;
42 void __iomem *reg_phy;
43 struct regmap *reg_pmu;
44 struct regmap *reg_sys;
45 spinlock_t lock;
46 struct samsung_usb2_phy_instance instances[0];
47};
48
49struct samsung_usb2_common_phy {
50 int (*power_on)(struct samsung_usb2_phy_instance *);
51 int (*power_off)(struct samsung_usb2_phy_instance *);
52 unsigned int id;
53 char *label;
54};
55
56
57struct samsung_usb2_phy_config {
58 const struct samsung_usb2_common_phy *phys;
59 int (*rate_to_clk)(unsigned long, u32 *);
60 unsigned int num_phys;
61 bool has_mode_switch;
62};
63
64extern const struct samsung_usb2_phy_config exynos4210_usb2_phy_config;
65extern const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config;
66#endif