2 * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4x12 support
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5 * Author: Kamil Debski <k.debski@samsung.com>
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.
12 #include <linux/delay.h>
14 #include <linux/phy/phy.h>
15 #include <linux/regmap.h>
16 #include "phy-samsung-usb2.h"
18 /* Exynos USB PHY registers */
20 /* PHY power control */
21 #define EXYNOS_4x12_UPHYPWR 0x0
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)
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)
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)
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)
57 /* PHY clock control */
58 #define EXYNOS_4x12_UPHYCLK 0x4
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)
70 #define EXYNOS_3250_UPHYCLK_REFCLKSEL (0x2 << 8)
72 #define EXYNOS_4x12_UPHYCLK_PHY0_ID_PULLUP BIT(3)
73 #define EXYNOS_4x12_UPHYCLK_PHY0_COMMON_ON BIT(4)
74 #define EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON BIT(7)
76 #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_MASK (0x7f << 10)
77 #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_OFFSET 10
78 #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_12MHZ (0x24 << 10)
79 #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_15MHZ (0x1c << 10)
80 #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_16MHZ (0x1a << 10)
81 #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_19MHZ2 (0x15 << 10)
82 #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_20MHZ (0x14 << 10)
84 /* PHY reset control */
85 #define EXYNOS_4x12_UPHYRST 0x8
87 #define EXYNOS_4x12_URSTCON_PHY0 BIT(0)
88 #define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1)
89 #define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2)
90 #define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3)
91 /* The following bit defines are presented in the
92 * order taken from the Exynos4412 reference manual.
94 * During experiments with the hardware and debugging
95 * it was determined that the hardware behaves contrary
98 * The following bit values were chaned accordingly to the
99 * results of real hardware experiments.
101 #define EXYNOS_4x12_URSTCON_PHY1 BIT(4)
102 #define EXYNOS_4x12_URSTCON_HSIC0 BIT(6)
103 #define EXYNOS_4x12_URSTCON_HSIC1 BIT(5)
104 #define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7)
105 #define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(10)
106 #define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9)
107 #define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(8)
109 /* Isolation, configured in the power management unit */
110 #define EXYNOS_4x12_USB_ISOL_OFFSET 0x704
111 #define EXYNOS_4x12_USB_ISOL_OTG BIT(0)
112 #define EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET 0x708
113 #define EXYNOS_4x12_USB_ISOL_HSIC0 BIT(0)
114 #define EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET 0x70c
115 #define EXYNOS_4x12_USB_ISOL_HSIC1 BIT(0)
117 /* Mode switching SUB Device <-> Host */
118 #define EXYNOS_4x12_MODE_SWITCH_OFFSET 0x21c
119 #define EXYNOS_4x12_MODE_SWITCH_MASK 1
120 #define EXYNOS_4x12_MODE_SWITCH_DEVICE 0
121 #define EXYNOS_4x12_MODE_SWITCH_HOST 1
123 enum exynos4x12_phy_id
{
132 * exynos4x12_rate_to_clk() converts the supplied clock rate to the value that
133 * can be written to the phy register.
135 static int exynos4x12_rate_to_clk(unsigned long rate
, u32
*reg
)
137 /* EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK */
141 *reg
= EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6
;
144 *reg
= EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ
;
147 *reg
= EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ
;
150 *reg
= EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2
;
153 *reg
= EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ
;
156 *reg
= EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ
;
159 *reg
= EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ
;
168 static void exynos4x12_isol(struct samsung_usb2_phy_instance
*inst
, bool on
)
170 struct samsung_usb2_phy_driver
*drv
= inst
->drv
;
174 switch (inst
->cfg
->id
) {
175 case EXYNOS4x12_DEVICE
:
176 case EXYNOS4x12_HOST
:
177 offset
= EXYNOS_4x12_USB_ISOL_OFFSET
;
178 mask
= EXYNOS_4x12_USB_ISOL_OTG
;
180 case EXYNOS4x12_HSIC0
:
181 offset
= EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET
;
182 mask
= EXYNOS_4x12_USB_ISOL_HSIC0
;
184 case EXYNOS4x12_HSIC1
:
185 offset
= EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET
;
186 mask
= EXYNOS_4x12_USB_ISOL_HSIC1
;
192 regmap_update_bits(drv
->reg_pmu
, offset
, mask
, on
? 0 : mask
);
195 static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance
*inst
)
197 struct samsung_usb2_phy_driver
*drv
= inst
->drv
;
200 clk
= readl(drv
->reg_phy
+ EXYNOS_4x12_UPHYCLK
);
201 clk
&= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK
;
203 if (drv
->cfg
->has_refclk_sel
)
204 clk
= EXYNOS_3250_UPHYCLK_REFCLKSEL
;
206 clk
|= drv
->ref_reg_val
<< EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET
;
207 clk
|= EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON
;
208 writel(clk
, drv
->reg_phy
+ EXYNOS_4x12_UPHYCLK
);
211 static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance
*inst
, bool on
)
213 struct samsung_usb2_phy_driver
*drv
= inst
->drv
;
219 switch (inst
->cfg
->id
) {
220 case EXYNOS4x12_DEVICE
:
221 phypwr
= EXYNOS_4x12_UPHYPWR_PHY0
;
222 rstbits
= EXYNOS_4x12_URSTCON_PHY0
;
224 case EXYNOS4x12_HOST
:
225 phypwr
= EXYNOS_4x12_UPHYPWR_PHY1
;
226 rstbits
= EXYNOS_4x12_URSTCON_HOST_PHY
|
227 EXYNOS_4x12_URSTCON_PHY1
|
228 EXYNOS_4x12_URSTCON_HOST_LINK_P0
;
230 case EXYNOS4x12_HSIC0
:
231 phypwr
= EXYNOS_4x12_UPHYPWR_HSIC0
;
232 rstbits
= EXYNOS_4x12_URSTCON_HSIC0
|
233 EXYNOS_4x12_URSTCON_HOST_LINK_P1
;
235 case EXYNOS4x12_HSIC1
:
236 phypwr
= EXYNOS_4x12_UPHYPWR_HSIC1
;
237 rstbits
= EXYNOS_4x12_URSTCON_HSIC1
|
238 EXYNOS_4x12_URSTCON_HOST_LINK_P1
;
243 pwr
= readl(drv
->reg_phy
+ EXYNOS_4x12_UPHYPWR
);
245 writel(pwr
, drv
->reg_phy
+ EXYNOS_4x12_UPHYPWR
);
247 rst
= readl(drv
->reg_phy
+ EXYNOS_4x12_UPHYRST
);
249 writel(rst
, drv
->reg_phy
+ EXYNOS_4x12_UPHYRST
);
252 writel(rst
, drv
->reg_phy
+ EXYNOS_4x12_UPHYRST
);
253 /* The following delay is necessary for the reset sequence to be
257 pwr
= readl(drv
->reg_phy
+ EXYNOS_4x12_UPHYPWR
);
259 writel(pwr
, drv
->reg_phy
+ EXYNOS_4x12_UPHYPWR
);
263 static void exynos4x12_power_on_int(struct samsung_usb2_phy_instance
*inst
)
265 if (inst
->int_cnt
++ > 0)
268 exynos4x12_setup_clk(inst
);
269 exynos4x12_isol(inst
, 0);
270 exynos4x12_phy_pwr(inst
, 1);
273 static int exynos4x12_power_on(struct samsung_usb2_phy_instance
*inst
)
275 struct samsung_usb2_phy_driver
*drv
= inst
->drv
;
277 if (inst
->ext_cnt
++ > 0)
280 if (inst
->cfg
->id
== EXYNOS4x12_HOST
) {
281 regmap_update_bits(drv
->reg_sys
, EXYNOS_4x12_MODE_SWITCH_OFFSET
,
282 EXYNOS_4x12_MODE_SWITCH_MASK
,
283 EXYNOS_4x12_MODE_SWITCH_HOST
);
284 exynos4x12_power_on_int(&drv
->instances
[EXYNOS4x12_DEVICE
]);
287 if (inst
->cfg
->id
== EXYNOS4x12_DEVICE
&& drv
->cfg
->has_mode_switch
)
288 regmap_update_bits(drv
->reg_sys
, EXYNOS_4x12_MODE_SWITCH_OFFSET
,
289 EXYNOS_4x12_MODE_SWITCH_MASK
,
290 EXYNOS_4x12_MODE_SWITCH_DEVICE
);
292 if (inst
->cfg
->id
== EXYNOS4x12_HSIC0
||
293 inst
->cfg
->id
== EXYNOS4x12_HSIC1
) {
294 exynos4x12_power_on_int(&drv
->instances
[EXYNOS4x12_DEVICE
]);
295 exynos4x12_power_on_int(&drv
->instances
[EXYNOS4x12_HOST
]);
298 exynos4x12_power_on_int(inst
);
303 static void exynos4x12_power_off_int(struct samsung_usb2_phy_instance
*inst
)
305 if (inst
->int_cnt
-- > 1)
308 exynos4x12_isol(inst
, 1);
309 exynos4x12_phy_pwr(inst
, 0);
312 static int exynos4x12_power_off(struct samsung_usb2_phy_instance
*inst
)
314 struct samsung_usb2_phy_driver
*drv
= inst
->drv
;
316 if (inst
->ext_cnt
-- > 1)
319 if (inst
->cfg
->id
== EXYNOS4x12_DEVICE
&& drv
->cfg
->has_mode_switch
)
320 regmap_update_bits(drv
->reg_sys
, EXYNOS_4x12_MODE_SWITCH_OFFSET
,
321 EXYNOS_4x12_MODE_SWITCH_MASK
,
322 EXYNOS_4x12_MODE_SWITCH_HOST
);
324 if (inst
->cfg
->id
== EXYNOS4x12_HOST
)
325 exynos4x12_power_off_int(&drv
->instances
[EXYNOS4x12_DEVICE
]);
327 if (inst
->cfg
->id
== EXYNOS4x12_HSIC0
||
328 inst
->cfg
->id
== EXYNOS4x12_HSIC1
) {
329 exynos4x12_power_off_int(&drv
->instances
[EXYNOS4x12_DEVICE
]);
330 exynos4x12_power_off_int(&drv
->instances
[EXYNOS4x12_HOST
]);
333 exynos4x12_power_off_int(inst
);
339 static const struct samsung_usb2_common_phy exynos4x12_phys
[] = {
342 .id
= EXYNOS4x12_DEVICE
,
343 .power_on
= exynos4x12_power_on
,
344 .power_off
= exynos4x12_power_off
,
348 .id
= EXYNOS4x12_HOST
,
349 .power_on
= exynos4x12_power_on
,
350 .power_off
= exynos4x12_power_off
,
354 .id
= EXYNOS4x12_HSIC0
,
355 .power_on
= exynos4x12_power_on
,
356 .power_off
= exynos4x12_power_off
,
360 .id
= EXYNOS4x12_HSIC1
,
361 .power_on
= exynos4x12_power_on
,
362 .power_off
= exynos4x12_power_off
,
366 const struct samsung_usb2_phy_config exynos3250_usb2_phy_config
= {
369 .phys
= exynos4x12_phys
,
370 .rate_to_clk
= exynos4x12_rate_to_clk
,
373 const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config
= {
374 .has_mode_switch
= 1,
375 .num_phys
= EXYNOS4x12_NUM_PHYS
,
376 .phys
= exynos4x12_phys
,
377 .rate_to_clk
= exynos4x12_rate_to_clk
,