1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4x12 support |
4 | * |
5 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. |
6 | * Author: Kamil Debski <k.debski@samsung.com> |
7 | */ |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/io.h> |
11 | #include <linux/phy/phy.h> |
12 | #include <linux/regmap.h> |
13 | #include "phy-samsung-usb2.h" |
14 | |
15 | /* Exynos USB PHY registers */ |
16 | |
17 | /* PHY power control */ |
18 | #define EXYNOS_4x12_UPHYPWR 0x0 |
19 | |
20 | #define EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND BIT(0) |
21 | #define EXYNOS_4x12_UPHYPWR_PHY0_PWR BIT(3) |
22 | #define EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR BIT(4) |
23 | #define EXYNOS_4x12_UPHYPWR_PHY0_SLEEP BIT(5) |
24 | #define EXYNOS_4x12_UPHYPWR_PHY0 ( \ |
25 | EXYNOS_4x12_UPHYPWR_PHY0_SUSPEND | \ |
26 | EXYNOS_4x12_UPHYPWR_PHY0_PWR | \ |
27 | EXYNOS_4x12_UPHYPWR_PHY0_OTG_PWR | \ |
28 | EXYNOS_4x12_UPHYPWR_PHY0_SLEEP) |
29 | |
30 | #define EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND BIT(6) |
31 | #define EXYNOS_4x12_UPHYPWR_PHY1_PWR BIT(7) |
32 | #define EXYNOS_4x12_UPHYPWR_PHY1_SLEEP BIT(8) |
33 | #define EXYNOS_4x12_UPHYPWR_PHY1 ( \ |
34 | EXYNOS_4x12_UPHYPWR_PHY1_SUSPEND | \ |
35 | EXYNOS_4x12_UPHYPWR_PHY1_PWR | \ |
36 | EXYNOS_4x12_UPHYPWR_PHY1_SLEEP) |
37 | |
38 | #define EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND BIT(9) |
39 | #define EXYNOS_4x12_UPHYPWR_HSIC0_PWR BIT(10) |
40 | #define EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP BIT(11) |
41 | #define EXYNOS_4x12_UPHYPWR_HSIC0 ( \ |
42 | EXYNOS_4x12_UPHYPWR_HSIC0_SUSPEND | \ |
43 | EXYNOS_4x12_UPHYPWR_HSIC0_PWR | \ |
44 | EXYNOS_4x12_UPHYPWR_HSIC0_SLEEP) |
45 | |
46 | #define EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND BIT(12) |
47 | #define EXYNOS_4x12_UPHYPWR_HSIC1_PWR BIT(13) |
48 | #define EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP BIT(14) |
49 | #define EXYNOS_4x12_UPHYPWR_HSIC1 ( \ |
50 | EXYNOS_4x12_UPHYPWR_HSIC1_SUSPEND | \ |
51 | EXYNOS_4x12_UPHYPWR_HSIC1_PWR | \ |
52 | EXYNOS_4x12_UPHYPWR_HSIC1_SLEEP) |
53 | |
54 | /* PHY clock control */ |
55 | #define EXYNOS_4x12_UPHYCLK 0x4 |
56 | |
57 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK (0x7 << 0) |
58 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET 0 |
59 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6 (0x0 << 0) |
60 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ (0x1 << 0) |
61 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ (0x2 << 0) |
62 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2 (0x3 << 0) |
63 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ (0x4 << 0) |
64 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ (0x5 << 0) |
65 | #define EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ (0x7 << 0) |
66 | |
67 | #define EXYNOS_3250_UPHYCLK_REFCLKSEL (0x2 << 8) |
68 | |
69 | #define EXYNOS_4x12_UPHYCLK_PHY0_ID_PULLUP BIT(3) |
70 | #define EXYNOS_4x12_UPHYCLK_PHY0_COMMON_ON BIT(4) |
71 | #define EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON BIT(7) |
72 | |
73 | #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_MASK (0x7f << 10) |
74 | #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_OFFSET 10 |
75 | #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_12MHZ (0x24 << 10) |
76 | #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_15MHZ (0x1c << 10) |
77 | #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_16MHZ (0x1a << 10) |
78 | #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_19MHZ2 (0x15 << 10) |
79 | #define EXYNOS_4x12_UPHYCLK_HSIC_REFCLK_20MHZ (0x14 << 10) |
80 | |
81 | /* PHY reset control */ |
82 | #define EXYNOS_4x12_UPHYRST 0x8 |
83 | |
84 | #define EXYNOS_4x12_URSTCON_PHY0 BIT(0) |
85 | #define EXYNOS_4x12_URSTCON_OTG_HLINK BIT(1) |
86 | #define EXYNOS_4x12_URSTCON_OTG_PHYLINK BIT(2) |
87 | #define EXYNOS_4x12_URSTCON_HOST_PHY BIT(3) |
88 | /* The following bit defines are presented in the |
89 | * order taken from the Exynos4412 reference manual. |
90 | * |
91 | * During experiments with the hardware and debugging |
92 | * it was determined that the hardware behaves contrary |
93 | * to the manual. |
94 | * |
95 | * The following bit values were chaned accordingly to the |
96 | * results of real hardware experiments. |
97 | */ |
98 | #define EXYNOS_4x12_URSTCON_PHY1 BIT(4) |
99 | #define EXYNOS_4x12_URSTCON_HSIC0 BIT(6) |
100 | #define EXYNOS_4x12_URSTCON_HSIC1 BIT(5) |
101 | #define EXYNOS_4x12_URSTCON_HOST_LINK_ALL BIT(7) |
102 | #define EXYNOS_4x12_URSTCON_HOST_LINK_P0 BIT(10) |
103 | #define EXYNOS_4x12_URSTCON_HOST_LINK_P1 BIT(9) |
104 | #define EXYNOS_4x12_URSTCON_HOST_LINK_P2 BIT(8) |
105 | |
106 | /* Isolation, configured in the power management unit */ |
107 | #define EXYNOS_4x12_USB_ISOL_OFFSET 0x704 |
108 | #define EXYNOS_4x12_USB_ISOL_OTG BIT(0) |
109 | #define EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET 0x708 |
110 | #define EXYNOS_4x12_USB_ISOL_HSIC0 BIT(0) |
111 | #define EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET 0x70c |
112 | #define EXYNOS_4x12_USB_ISOL_HSIC1 BIT(0) |
113 | |
114 | /* Mode switching SUB Device <-> Host */ |
115 | #define EXYNOS_4x12_MODE_SWITCH_OFFSET 0x21c |
116 | #define EXYNOS_4x12_MODE_SWITCH_MASK 1 |
117 | #define EXYNOS_4x12_MODE_SWITCH_DEVICE 0 |
118 | #define EXYNOS_4x12_MODE_SWITCH_HOST 1 |
119 | |
120 | enum exynos4x12_phy_id { |
121 | EXYNOS4x12_DEVICE, |
122 | EXYNOS4x12_HOST, |
123 | EXYNOS4x12_HSIC0, |
124 | EXYNOS4x12_HSIC1, |
125 | EXYNOS4x12_NUM_PHYS, |
126 | }; |
127 | |
128 | /* |
129 | * exynos4x12_rate_to_clk() converts the supplied clock rate to the value that |
130 | * can be written to the phy register. |
131 | */ |
132 | static int exynos4x12_rate_to_clk(unsigned long rate, u32 *reg) |
133 | { |
134 | /* EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK */ |
135 | |
136 | switch (rate) { |
137 | case 9600 * KHZ: |
138 | *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_9MHZ6; |
139 | break; |
140 | case 10 * MHZ: |
141 | *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_10MHZ; |
142 | break; |
143 | case 12 * MHZ: |
144 | *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_12MHZ; |
145 | break; |
146 | case 19200 * KHZ: |
147 | *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_19MHZ2; |
148 | break; |
149 | case 20 * MHZ: |
150 | *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_20MHZ; |
151 | break; |
152 | case 24 * MHZ: |
153 | *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_24MHZ; |
154 | break; |
155 | case 50 * MHZ: |
156 | *reg = EXYNOS_4x12_UPHYCLK_PHYFSEL_50MHZ; |
157 | break; |
158 | default: |
159 | return -EINVAL; |
160 | } |
161 | |
162 | return 0; |
163 | } |
164 | |
165 | static void exynos4x12_isol(struct samsung_usb2_phy_instance *inst, bool on) |
166 | { |
167 | struct samsung_usb2_phy_driver *drv = inst->drv; |
168 | u32 offset; |
169 | u32 mask; |
170 | |
171 | switch (inst->cfg->id) { |
172 | case EXYNOS4x12_DEVICE: |
173 | case EXYNOS4x12_HOST: |
174 | offset = EXYNOS_4x12_USB_ISOL_OFFSET; |
175 | mask = EXYNOS_4x12_USB_ISOL_OTG; |
176 | break; |
177 | case EXYNOS4x12_HSIC0: |
178 | offset = EXYNOS_4x12_USB_ISOL_HSIC0_OFFSET; |
179 | mask = EXYNOS_4x12_USB_ISOL_HSIC0; |
180 | break; |
181 | case EXYNOS4x12_HSIC1: |
182 | offset = EXYNOS_4x12_USB_ISOL_HSIC1_OFFSET; |
183 | mask = EXYNOS_4x12_USB_ISOL_HSIC1; |
184 | break; |
185 | default: |
186 | return; |
187 | } |
188 | |
189 | regmap_update_bits(map: drv->reg_pmu, reg: offset, mask, val: on ? 0 : mask); |
190 | } |
191 | |
192 | static void exynos4x12_setup_clk(struct samsung_usb2_phy_instance *inst) |
193 | { |
194 | struct samsung_usb2_phy_driver *drv = inst->drv; |
195 | u32 clk; |
196 | |
197 | clk = readl(addr: drv->reg_phy + EXYNOS_4x12_UPHYCLK); |
198 | clk &= ~EXYNOS_4x12_UPHYCLK_PHYFSEL_MASK; |
199 | |
200 | if (drv->cfg->has_refclk_sel) |
201 | clk = EXYNOS_3250_UPHYCLK_REFCLKSEL; |
202 | |
203 | clk |= drv->ref_reg_val << EXYNOS_4x12_UPHYCLK_PHYFSEL_OFFSET; |
204 | clk |= EXYNOS_4x12_UPHYCLK_PHY1_COMMON_ON; |
205 | writel(val: clk, addr: drv->reg_phy + EXYNOS_4x12_UPHYCLK); |
206 | } |
207 | |
208 | static void exynos4x12_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on) |
209 | { |
210 | struct samsung_usb2_phy_driver *drv = inst->drv; |
211 | u32 rstbits = 0; |
212 | u32 phypwr = 0; |
213 | u32 rst; |
214 | u32 pwr; |
215 | |
216 | switch (inst->cfg->id) { |
217 | case EXYNOS4x12_DEVICE: |
218 | phypwr = EXYNOS_4x12_UPHYPWR_PHY0; |
219 | rstbits = EXYNOS_4x12_URSTCON_PHY0; |
220 | break; |
221 | case EXYNOS4x12_HOST: |
222 | phypwr = EXYNOS_4x12_UPHYPWR_PHY1; |
223 | rstbits = EXYNOS_4x12_URSTCON_HOST_PHY | |
224 | EXYNOS_4x12_URSTCON_PHY1 | |
225 | EXYNOS_4x12_URSTCON_HOST_LINK_P0; |
226 | break; |
227 | case EXYNOS4x12_HSIC0: |
228 | phypwr = EXYNOS_4x12_UPHYPWR_HSIC0; |
229 | rstbits = EXYNOS_4x12_URSTCON_HSIC0 | |
230 | EXYNOS_4x12_URSTCON_HOST_LINK_P1; |
231 | break; |
232 | case EXYNOS4x12_HSIC1: |
233 | phypwr = EXYNOS_4x12_UPHYPWR_HSIC1; |
234 | rstbits = EXYNOS_4x12_URSTCON_HSIC1 | |
235 | EXYNOS_4x12_URSTCON_HOST_LINK_P1; |
236 | break; |
237 | } |
238 | |
239 | if (on) { |
240 | pwr = readl(addr: drv->reg_phy + EXYNOS_4x12_UPHYPWR); |
241 | pwr &= ~phypwr; |
242 | writel(val: pwr, addr: drv->reg_phy + EXYNOS_4x12_UPHYPWR); |
243 | |
244 | rst = readl(addr: drv->reg_phy + EXYNOS_4x12_UPHYRST); |
245 | rst |= rstbits; |
246 | writel(val: rst, addr: drv->reg_phy + EXYNOS_4x12_UPHYRST); |
247 | udelay(10); |
248 | rst &= ~rstbits; |
249 | writel(val: rst, addr: drv->reg_phy + EXYNOS_4x12_UPHYRST); |
250 | /* The following delay is necessary for the reset sequence to be |
251 | * completed */ |
252 | udelay(80); |
253 | } else { |
254 | pwr = readl(addr: drv->reg_phy + EXYNOS_4x12_UPHYPWR); |
255 | pwr |= phypwr; |
256 | writel(val: pwr, addr: drv->reg_phy + EXYNOS_4x12_UPHYPWR); |
257 | } |
258 | } |
259 | |
260 | static void exynos4x12_power_on_int(struct samsung_usb2_phy_instance *inst) |
261 | { |
262 | if (inst->int_cnt++ > 0) |
263 | return; |
264 | |
265 | exynos4x12_setup_clk(inst); |
266 | exynos4x12_isol(inst, on: 0); |
267 | exynos4x12_phy_pwr(inst, on: 1); |
268 | } |
269 | |
270 | static int exynos4x12_power_on(struct samsung_usb2_phy_instance *inst) |
271 | { |
272 | struct samsung_usb2_phy_driver *drv = inst->drv; |
273 | |
274 | if (inst->ext_cnt++ > 0) |
275 | return 0; |
276 | |
277 | if (inst->cfg->id == EXYNOS4x12_HOST) { |
278 | regmap_update_bits(map: drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, |
279 | EXYNOS_4x12_MODE_SWITCH_MASK, |
280 | EXYNOS_4x12_MODE_SWITCH_HOST); |
281 | exynos4x12_power_on_int(inst: &drv->instances[EXYNOS4x12_DEVICE]); |
282 | } |
283 | |
284 | if (inst->cfg->id == EXYNOS4x12_DEVICE && drv->cfg->has_mode_switch) |
285 | regmap_update_bits(map: drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, |
286 | EXYNOS_4x12_MODE_SWITCH_MASK, |
287 | EXYNOS_4x12_MODE_SWITCH_DEVICE); |
288 | |
289 | if (inst->cfg->id == EXYNOS4x12_HSIC0 || |
290 | inst->cfg->id == EXYNOS4x12_HSIC1) { |
291 | exynos4x12_power_on_int(inst: &drv->instances[EXYNOS4x12_DEVICE]); |
292 | exynos4x12_power_on_int(inst: &drv->instances[EXYNOS4x12_HOST]); |
293 | } |
294 | |
295 | exynos4x12_power_on_int(inst); |
296 | |
297 | return 0; |
298 | } |
299 | |
300 | static void exynos4x12_power_off_int(struct samsung_usb2_phy_instance *inst) |
301 | { |
302 | if (inst->int_cnt-- > 1) |
303 | return; |
304 | |
305 | exynos4x12_isol(inst, on: 1); |
306 | exynos4x12_phy_pwr(inst, on: 0); |
307 | } |
308 | |
309 | static int exynos4x12_power_off(struct samsung_usb2_phy_instance *inst) |
310 | { |
311 | struct samsung_usb2_phy_driver *drv = inst->drv; |
312 | |
313 | if (inst->ext_cnt-- > 1) |
314 | return 0; |
315 | |
316 | if (inst->cfg->id == EXYNOS4x12_DEVICE && drv->cfg->has_mode_switch) |
317 | regmap_update_bits(map: drv->reg_sys, EXYNOS_4x12_MODE_SWITCH_OFFSET, |
318 | EXYNOS_4x12_MODE_SWITCH_MASK, |
319 | EXYNOS_4x12_MODE_SWITCH_HOST); |
320 | |
321 | if (inst->cfg->id == EXYNOS4x12_HOST) |
322 | exynos4x12_power_off_int(inst: &drv->instances[EXYNOS4x12_DEVICE]); |
323 | |
324 | if (inst->cfg->id == EXYNOS4x12_HSIC0 || |
325 | inst->cfg->id == EXYNOS4x12_HSIC1) { |
326 | exynos4x12_power_off_int(inst: &drv->instances[EXYNOS4x12_DEVICE]); |
327 | exynos4x12_power_off_int(inst: &drv->instances[EXYNOS4x12_HOST]); |
328 | } |
329 | |
330 | exynos4x12_power_off_int(inst); |
331 | |
332 | return 0; |
333 | } |
334 | |
335 | |
336 | static const struct samsung_usb2_common_phy exynos4x12_phys[] = { |
337 | { |
338 | .label = "device" , |
339 | .id = EXYNOS4x12_DEVICE, |
340 | .power_on = exynos4x12_power_on, |
341 | .power_off = exynos4x12_power_off, |
342 | }, |
343 | { |
344 | .label = "host" , |
345 | .id = EXYNOS4x12_HOST, |
346 | .power_on = exynos4x12_power_on, |
347 | .power_off = exynos4x12_power_off, |
348 | }, |
349 | { |
350 | .label = "hsic0" , |
351 | .id = EXYNOS4x12_HSIC0, |
352 | .power_on = exynos4x12_power_on, |
353 | .power_off = exynos4x12_power_off, |
354 | }, |
355 | { |
356 | .label = "hsic1" , |
357 | .id = EXYNOS4x12_HSIC1, |
358 | .power_on = exynos4x12_power_on, |
359 | .power_off = exynos4x12_power_off, |
360 | }, |
361 | }; |
362 | |
363 | const struct samsung_usb2_phy_config exynos3250_usb2_phy_config = { |
364 | .has_refclk_sel = 1, |
365 | .num_phys = 1, |
366 | .phys = exynos4x12_phys, |
367 | .rate_to_clk = exynos4x12_rate_to_clk, |
368 | }; |
369 | |
370 | const struct samsung_usb2_phy_config exynos4x12_usb2_phy_config = { |
371 | .has_mode_switch = 1, |
372 | .num_phys = EXYNOS4x12_NUM_PHYS, |
373 | .phys = exynos4x12_phys, |
374 | .rate_to_clk = exynos4x12_rate_to_clk, |
375 | }; |
376 | |