1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 5250 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#define EXYNOS_5250_REFCLKSEL_CRYSTAL 0x0
17#define EXYNOS_5250_REFCLKSEL_XO 0x1
18#define EXYNOS_5250_REFCLKSEL_CLKCORE 0x2
19
20#define EXYNOS_5250_FSEL_9MHZ6 0x0
21#define EXYNOS_5250_FSEL_10MHZ 0x1
22#define EXYNOS_5250_FSEL_12MHZ 0x2
23#define EXYNOS_5250_FSEL_19MHZ2 0x3
24#define EXYNOS_5250_FSEL_20MHZ 0x4
25#define EXYNOS_5250_FSEL_24MHZ 0x5
26#define EXYNOS_5250_FSEL_50MHZ 0x7
27
28/* Normal host */
29#define EXYNOS_5250_HOSTPHYCTRL0 0x0
30
31#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL BIT(31)
32#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT 19
33#define EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_MASK \
34 (0x3 << EXYNOS_5250_HOSTPHYCTRL0_REFCLKSEL_SHIFT)
35#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT 16
36#define EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK \
37 (0x7 << EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT)
38#define EXYNOS_5250_HOSTPHYCTRL0_TESTBURNIN BIT(11)
39#define EXYNOS_5250_HOSTPHYCTRL0_RETENABLE BIT(10)
40#define EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N BIT(9)
41#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_MASK (0x3 << 7)
42#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_DUAL (0x0 << 7)
43#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ID0 (0x1 << 7)
44#define EXYNOS_5250_HOSTPHYCTRL0_VATESTENB_ANALOGTEST (0x2 << 7)
45#define EXYNOS_5250_HOSTPHYCTRL0_SIDDQ BIT(6)
46#define EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP BIT(5)
47#define EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND BIT(4)
48#define EXYNOS_5250_HOSTPHYCTRL0_WORDINTERFACE BIT(3)
49#define EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST BIT(2)
50#define EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST BIT(1)
51#define EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST BIT(0)
52
53/* HSIC0 & HSIC1 */
54#define EXYNOS_5250_HSICPHYCTRL1 0x10
55#define EXYNOS_5250_HSICPHYCTRL2 0x20
56
57#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_MASK (0x3 << 23)
58#define EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT (0x2 << 23)
59#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_MASK (0x7f << 16)
60#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 (0x24 << 16)
61#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_15 (0x1c << 16)
62#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_16 (0x1a << 16)
63#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_19_2 (0x15 << 16)
64#define EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_20 (0x14 << 16)
65#define EXYNOS_5250_HSICPHYCTRLX_SIDDQ BIT(6)
66#define EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP BIT(5)
67#define EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND BIT(4)
68#define EXYNOS_5250_HSICPHYCTRLX_WORDINTERFACE BIT(3)
69#define EXYNOS_5250_HSICPHYCTRLX_UTMISWRST BIT(2)
70#define EXYNOS_5250_HSICPHYCTRLX_PHYSWRST BIT(0)
71
72/* EHCI control */
73#define EXYNOS_5250_HOSTEHCICTRL 0x30
74#define EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN BIT(29)
75#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 BIT(28)
76#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 BIT(27)
77#define EXYNOS_5250_HOSTEHCICTRL_ENAINCR16 BIT(26)
78#define EXYNOS_5250_HOSTEHCICTRL_AUTOPPDONOVRCUREN BIT(25)
79#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT 19
80#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK \
81 (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
82#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT 13
83#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_MASK \
84 (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL1_SHIFT)
85#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL2_SHIFT 7
86#define EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_MASK \
87 (0x3f << EXYNOS_5250_HOSTEHCICTRL_FLADJVAL0_SHIFT)
88#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT 1
89#define EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_MASK \
90 (0x1 << EXYNOS_5250_HOSTEHCICTRL_FLADJVALHOST_SHIFT)
91#define EXYNOS_5250_HOSTEHCICTRL_SIMULATIONMODE BIT(0)
92
93/* OHCI control */
94#define EXYNOS_5250_HOSTOHCICTRL 0x34
95#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT 1
96#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_MASK \
97 (0x3ff << EXYNOS_5250_HOSTOHCICTRL_FRAMELENVAL_SHIFT)
98#define EXYNOS_5250_HOSTOHCICTRL_FRAMELENVALEN BIT(0)
99
100/* USBOTG */
101#define EXYNOS_5250_USBOTGSYS 0x38
102#define EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET BIT(14)
103#define EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG BIT(13)
104#define EXYNOS_5250_USBOTGSYS_PHY_SW_RST BIT(12)
105#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT 9
106#define EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK \
107 (0x3 << EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT)
108#define EXYNOS_5250_USBOTGSYS_ID_PULLUP BIT(8)
109#define EXYNOS_5250_USBOTGSYS_COMMON_ON BIT(7)
110#define EXYNOS_5250_USBOTGSYS_FSEL_SHIFT 4
111#define EXYNOS_5250_USBOTGSYS_FSEL_MASK \
112 (0x3 << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT)
113#define EXYNOS_5250_USBOTGSYS_FORCE_SLEEP BIT(3)
114#define EXYNOS_5250_USBOTGSYS_OTGDISABLE BIT(2)
115#define EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG BIT(1)
116#define EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND BIT(0)
117
118/* Isolation, configured in the power management unit */
119#define EXYNOS_5250_USB_ISOL_OTG_OFFSET 0x704
120#define EXYNOS_5250_USB_ISOL_HOST_OFFSET 0x708
121#define EXYNOS_5420_USB_ISOL_HOST_OFFSET 0x70C
122#define EXYNOS_5250_USB_ISOL_ENABLE BIT(0)
123
124/* Mode swtich register */
125#define EXYNOS_5250_MODE_SWITCH_OFFSET 0x230
126#define EXYNOS_5250_MODE_SWITCH_MASK 1
127#define EXYNOS_5250_MODE_SWITCH_DEVICE 0
128#define EXYNOS_5250_MODE_SWITCH_HOST 1
129
130enum exynos4x12_phy_id {
131 EXYNOS5250_DEVICE,
132 EXYNOS5250_HOST,
133 EXYNOS5250_HSIC0,
134 EXYNOS5250_HSIC1,
135};
136
137/*
138 * exynos5250_rate_to_clk() converts the supplied clock rate to the value that
139 * can be written to the phy register.
140 */
141static int exynos5250_rate_to_clk(unsigned long rate, u32 *reg)
142{
143 /* EXYNOS_5250_FSEL_MASK */
144
145 switch (rate) {
146 case 9600 * KHZ:
147 *reg = EXYNOS_5250_FSEL_9MHZ6;
148 break;
149 case 10 * MHZ:
150 *reg = EXYNOS_5250_FSEL_10MHZ;
151 break;
152 case 12 * MHZ:
153 *reg = EXYNOS_5250_FSEL_12MHZ;
154 break;
155 case 19200 * KHZ:
156 *reg = EXYNOS_5250_FSEL_19MHZ2;
157 break;
158 case 20 * MHZ:
159 *reg = EXYNOS_5250_FSEL_20MHZ;
160 break;
161 case 24 * MHZ:
162 *reg = EXYNOS_5250_FSEL_24MHZ;
163 break;
164 case 50 * MHZ:
165 *reg = EXYNOS_5250_FSEL_50MHZ;
166 break;
167 default:
168 return -EINVAL;
169 }
170
171 return 0;
172}
173
174static void exynos5250_isol(struct samsung_usb2_phy_instance *inst, bool on)
175{
176 struct samsung_usb2_phy_driver *drv = inst->drv;
177 u32 offset;
178 u32 mask = EXYNOS_5250_USB_ISOL_ENABLE;
179
180 if (drv->cfg == &exynos5250_usb2_phy_config &&
181 inst->cfg->id == EXYNOS5250_DEVICE)
182 offset = EXYNOS_5250_USB_ISOL_OTG_OFFSET;
183 else if (drv->cfg == &exynos5250_usb2_phy_config &&
184 inst->cfg->id == EXYNOS5250_HOST)
185 offset = EXYNOS_5250_USB_ISOL_HOST_OFFSET;
186 else if (drv->cfg == &exynos5420_usb2_phy_config &&
187 inst->cfg->id == EXYNOS5250_HOST)
188 offset = EXYNOS_5420_USB_ISOL_HOST_OFFSET;
189 else
190 return;
191
192 regmap_update_bits(map: drv->reg_pmu, reg: offset, mask, val: on ? 0 : mask);
193}
194
195static int exynos5250_power_on(struct samsung_usb2_phy_instance *inst)
196{
197 struct samsung_usb2_phy_driver *drv = inst->drv;
198 u32 ctrl0;
199 u32 otg;
200 u32 ehci;
201 u32 ohci;
202 u32 hsic;
203
204 switch (inst->cfg->id) {
205 case EXYNOS5250_DEVICE:
206 regmap_update_bits(map: drv->reg_sys,
207 EXYNOS_5250_MODE_SWITCH_OFFSET,
208 EXYNOS_5250_MODE_SWITCH_MASK,
209 EXYNOS_5250_MODE_SWITCH_DEVICE);
210
211 /* OTG configuration */
212 otg = readl(addr: drv->reg_phy + EXYNOS_5250_USBOTGSYS);
213 /* The clock */
214 otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
215 otg |= drv->ref_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
216 /* Reset */
217 otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
218 EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
219 EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
220 otg |= EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
221 EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
222 EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
223 EXYNOS_5250_USBOTGSYS_OTGDISABLE;
224 /* Ref clock */
225 otg &= ~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
226 otg |= EXYNOS_5250_REFCLKSEL_CLKCORE <<
227 EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
228 writel(val: otg, addr: drv->reg_phy + EXYNOS_5250_USBOTGSYS);
229 udelay(100);
230 otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
231 EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
232 EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
233 EXYNOS_5250_USBOTGSYS_OTGDISABLE);
234 writel(val: otg, addr: drv->reg_phy + EXYNOS_5250_USBOTGSYS);
235
236
237 break;
238 case EXYNOS5250_HOST:
239 case EXYNOS5250_HSIC0:
240 case EXYNOS5250_HSIC1:
241 /* Host registers configuration */
242 ctrl0 = readl(addr: drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
243 /* The clock */
244 ctrl0 &= ~EXYNOS_5250_HOSTPHYCTRL0_FSEL_MASK;
245 ctrl0 |= drv->ref_reg_val <<
246 EXYNOS_5250_HOSTPHYCTRL0_FSEL_SHIFT;
247
248 /* Reset */
249 ctrl0 &= ~(EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
250 EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL |
251 EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
252 EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
253 EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP);
254 ctrl0 |= EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
255 EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST |
256 EXYNOS_5250_HOSTPHYCTRL0_COMMON_ON_N;
257 writel(val: ctrl0, addr: drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
258 udelay(10);
259 ctrl0 &= ~(EXYNOS_5250_HOSTPHYCTRL0_LINKSWRST |
260 EXYNOS_5250_HOSTPHYCTRL0_UTMISWRST);
261 writel(val: ctrl0, addr: drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
262
263 /* OTG configuration */
264 otg = readl(addr: drv->reg_phy + EXYNOS_5250_USBOTGSYS);
265 /* The clock */
266 otg &= ~EXYNOS_5250_USBOTGSYS_FSEL_MASK;
267 otg |= drv->ref_reg_val << EXYNOS_5250_USBOTGSYS_FSEL_SHIFT;
268 /* Reset */
269 otg &= ~(EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
270 EXYNOS_5250_USBOTGSYS_FORCE_SLEEP |
271 EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG);
272 otg |= EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
273 EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET |
274 EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
275 EXYNOS_5250_USBOTGSYS_OTGDISABLE;
276 /* Ref clock */
277 otg &= ~EXYNOS_5250_USBOTGSYS_REFCLKSEL_MASK;
278 otg |= EXYNOS_5250_REFCLKSEL_CLKCORE <<
279 EXYNOS_5250_USBOTGSYS_REFCLKSEL_SHIFT;
280 writel(val: otg, addr: drv->reg_phy + EXYNOS_5250_USBOTGSYS);
281 udelay(10);
282 otg &= ~(EXYNOS_5250_USBOTGSYS_PHY_SW_RST |
283 EXYNOS_5250_USBOTGSYS_LINK_SW_RST_UOTG |
284 EXYNOS_5250_USBOTGSYS_PHYLINK_SW_RESET);
285
286 /* HSIC phy configuration */
287 hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 |
288 EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT |
289 EXYNOS_5250_HSICPHYCTRLX_PHYSWRST);
290 writel(val: hsic, addr: drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
291 writel(val: hsic, addr: drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
292 udelay(10);
293 hsic &= ~EXYNOS_5250_HSICPHYCTRLX_PHYSWRST;
294 writel(val: hsic, addr: drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
295 writel(val: hsic, addr: drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
296 /* The following delay is necessary for the reset sequence to be
297 * completed */
298 udelay(80);
299
300 /* Enable EHCI DMA burst */
301 ehci = readl(addr: drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
302 ehci |= EXYNOS_5250_HOSTEHCICTRL_ENAINCRXALIGN |
303 EXYNOS_5250_HOSTEHCICTRL_ENAINCR4 |
304 EXYNOS_5250_HOSTEHCICTRL_ENAINCR8 |
305 EXYNOS_5250_HOSTEHCICTRL_ENAINCR16;
306 writel(val: ehci, addr: drv->reg_phy + EXYNOS_5250_HOSTEHCICTRL);
307
308 /* OHCI settings */
309 ohci = readl(addr: drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
310 /* Following code is based on the old driver */
311 ohci |= 0x1 << 3;
312 writel(val: ohci, addr: drv->reg_phy + EXYNOS_5250_HOSTOHCICTRL);
313
314 break;
315 }
316 exynos5250_isol(inst, on: 0);
317
318 return 0;
319}
320
321static int exynos5250_power_off(struct samsung_usb2_phy_instance *inst)
322{
323 struct samsung_usb2_phy_driver *drv = inst->drv;
324 u32 ctrl0;
325 u32 otg;
326 u32 hsic;
327
328 exynos5250_isol(inst, on: 1);
329
330 switch (inst->cfg->id) {
331 case EXYNOS5250_DEVICE:
332 otg = readl(addr: drv->reg_phy + EXYNOS_5250_USBOTGSYS);
333 otg |= (EXYNOS_5250_USBOTGSYS_FORCE_SUSPEND |
334 EXYNOS_5250_USBOTGSYS_SIDDQ_UOTG |
335 EXYNOS_5250_USBOTGSYS_FORCE_SLEEP);
336 writel(val: otg, addr: drv->reg_phy + EXYNOS_5250_USBOTGSYS);
337 break;
338 case EXYNOS5250_HOST:
339 ctrl0 = readl(addr: drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
340 ctrl0 |= (EXYNOS_5250_HOSTPHYCTRL0_SIDDQ |
341 EXYNOS_5250_HOSTPHYCTRL0_FORCESUSPEND |
342 EXYNOS_5250_HOSTPHYCTRL0_FORCESLEEP |
343 EXYNOS_5250_HOSTPHYCTRL0_PHYSWRST |
344 EXYNOS_5250_HOSTPHYCTRL0_PHYSWRSTALL);
345 writel(val: ctrl0, addr: drv->reg_phy + EXYNOS_5250_HOSTPHYCTRL0);
346 break;
347 case EXYNOS5250_HSIC0:
348 case EXYNOS5250_HSIC1:
349 hsic = (EXYNOS_5250_HSICPHYCTRLX_REFCLKDIV_12 |
350 EXYNOS_5250_HSICPHYCTRLX_REFCLKSEL_DEFAULT |
351 EXYNOS_5250_HSICPHYCTRLX_SIDDQ |
352 EXYNOS_5250_HSICPHYCTRLX_FORCESLEEP |
353 EXYNOS_5250_HSICPHYCTRLX_FORCESUSPEND
354 );
355 writel(val: hsic, addr: drv->reg_phy + EXYNOS_5250_HSICPHYCTRL1);
356 writel(val: hsic, addr: drv->reg_phy + EXYNOS_5250_HSICPHYCTRL2);
357 break;
358 }
359
360 return 0;
361}
362
363
364static const struct samsung_usb2_common_phy exynos5250_phys[] = {
365 {
366 .label = "device",
367 .id = EXYNOS5250_DEVICE,
368 .power_on = exynos5250_power_on,
369 .power_off = exynos5250_power_off,
370 },
371 {
372 .label = "host",
373 .id = EXYNOS5250_HOST,
374 .power_on = exynos5250_power_on,
375 .power_off = exynos5250_power_off,
376 },
377 {
378 .label = "hsic0",
379 .id = EXYNOS5250_HSIC0,
380 .power_on = exynos5250_power_on,
381 .power_off = exynos5250_power_off,
382 },
383 {
384 .label = "hsic1",
385 .id = EXYNOS5250_HSIC1,
386 .power_on = exynos5250_power_on,
387 .power_off = exynos5250_power_off,
388 },
389};
390
391static const struct samsung_usb2_common_phy exynos5420_phys[] = {
392 {
393 .label = "host",
394 .id = EXYNOS5250_HOST,
395 .power_on = exynos5250_power_on,
396 .power_off = exynos5250_power_off,
397 },
398 {
399 .label = "hsic",
400 .id = EXYNOS5250_HSIC0,
401 .power_on = exynos5250_power_on,
402 .power_off = exynos5250_power_off,
403 },
404};
405
406const struct samsung_usb2_phy_config exynos5250_usb2_phy_config = {
407 .has_mode_switch = 1,
408 .num_phys = ARRAY_SIZE(exynos5250_phys),
409 .phys = exynos5250_phys,
410 .rate_to_clk = exynos5250_rate_to_clk,
411};
412
413const struct samsung_usb2_phy_config exynos5420_usb2_phy_config = {
414 .has_mode_switch = 1,
415 .num_phys = ARRAY_SIZE(exynos5420_phys),
416 .phys = exynos5420_phys,
417 .rate_to_clk = exynos5250_rate_to_clk,
418};
419

source code of linux/drivers/phy/samsung/phy-exynos5250-usb2.c