2 * Samsung SoC USB 1.1/2.0 PHY driver - S5PV210 support
4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
5 * Authors: 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 "phy-samsung-usb2.h"
17 /* Exynos USB PHY registers */
19 /* PHY power control */
20 #define S5PV210_UPHYPWR 0x0
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)
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)
36 /* PHY clock control */
37 #define S5PV210_UPHYCLK 0x4
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)
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)
48 /* PHY reset control */
49 #define S5PV210_UPHYRST 0x8
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)
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)
70 * s5pv210_rate_to_clk() converts the supplied clock rate to the value that
71 * can be written to the phy register.
73 static int s5pv210_rate_to_clk(unsigned long rate
, u32
*reg
)
77 *reg
= S5PV210_UPHYCLK_PHYFSEL_12MHZ
;
80 *reg
= S5PV210_UPHYCLK_PHYFSEL_24MHZ
;
83 *reg
= S5PV210_UPHYCLK_PHYFSEL_48MHZ
;
92 static void s5pv210_isol(struct samsung_usb2_phy_instance
*inst
, bool on
)
94 struct samsung_usb2_phy_driver
*drv
= inst
->drv
;
97 switch (inst
->cfg
->id
) {
99 mask
= S5PV210_USB_ISOL_DEVICE
;
102 mask
= S5PV210_USB_ISOL_HOST
;
108 regmap_update_bits(drv
->reg_pmu
, S5PV210_USB_ISOL_OFFSET
,
109 mask
, on
? 0 : mask
);
112 static void s5pv210_phy_pwr(struct samsung_usb2_phy_instance
*inst
, bool on
)
114 struct samsung_usb2_phy_driver
*drv
= inst
->drv
;
120 switch (inst
->cfg
->id
) {
122 phypwr
= S5PV210_UPHYPWR_PHY0
;
123 rstbits
= S5PV210_URSTCON_PHY0
;
126 phypwr
= S5PV210_UPHYPWR_PHY1
;
127 rstbits
= S5PV210_URSTCON_PHY1_ALL
|
128 S5PV210_URSTCON_HOST_LINK_ALL
;
133 writel(drv
->ref_reg_val
, drv
->reg_phy
+ S5PV210_UPHYCLK
);
135 pwr
= readl(drv
->reg_phy
+ S5PV210_UPHYPWR
);
137 writel(pwr
, drv
->reg_phy
+ S5PV210_UPHYPWR
);
139 rst
= readl(drv
->reg_phy
+ S5PV210_UPHYRST
);
141 writel(rst
, drv
->reg_phy
+ S5PV210_UPHYRST
);
144 writel(rst
, drv
->reg_phy
+ S5PV210_UPHYRST
);
145 /* The following delay is necessary for the reset sequence to be
150 pwr
= readl(drv
->reg_phy
+ S5PV210_UPHYPWR
);
152 writel(pwr
, drv
->reg_phy
+ S5PV210_UPHYPWR
);
156 static int s5pv210_power_on(struct samsung_usb2_phy_instance
*inst
)
158 s5pv210_isol(inst
, 0);
159 s5pv210_phy_pwr(inst
, 1);
164 static int s5pv210_power_off(struct samsung_usb2_phy_instance
*inst
)
166 s5pv210_phy_pwr(inst
, 0);
167 s5pv210_isol(inst
, 1);
172 static const struct samsung_usb2_common_phy s5pv210_phys
[S5PV210_NUM_PHYS
] = {
175 .id
= S5PV210_DEVICE
,
176 .power_on
= s5pv210_power_on
,
177 .power_off
= s5pv210_power_off
,
182 .power_on
= s5pv210_power_on
,
183 .power_off
= s5pv210_power_off
,
187 const struct samsung_usb2_phy_config s5pv210_usb2_phy_config
= {
188 .num_phys
= ARRAY_SIZE(s5pv210_phys
),
189 .phys
= s5pv210_phys
,
190 .rate_to_clk
= s5pv210_rate_to_clk
,