1 /* linux/drivers/usb/phy/samsung-usbphy.c
3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
6 * Author: Praveen Paneri <p.paneri@samsung.com>
8 * Samsung USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and
9 * OHCI-EXYNOS controllers.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include <linux/module.h>
22 #include <linux/platform_device.h>
23 #include <linux/clk.h>
24 #include <linux/delay.h>
25 #include <linux/device.h>
26 #include <linux/err.h>
29 #include <linux/of_address.h>
30 #include <linux/usb/otg.h>
31 #include <linux/usb/samsung_usb_phy.h>
32 #include <linux/platform_data/samsung-usbphy.h>
34 /* Register definitions */
36 #define SAMSUNG_PHYPWR (0x00)
38 #define PHYPWR_NORMAL_MASK (0x19 << 0)
39 #define PHYPWR_OTG_DISABLE (0x1 << 4)
40 #define PHYPWR_ANALOG_POWERDOWN (0x1 << 3)
41 #define PHYPWR_FORCE_SUSPEND (0x1 << 1)
43 #define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0)
44 #define PHYPWR_SLEEP_PHY0 (0x1 << 5)
46 #define SAMSUNG_PHYCLK (0x04)
48 #define PHYCLK_MODE_USB11 (0x1 << 6)
49 #define PHYCLK_EXT_OSC (0x1 << 5)
50 #define PHYCLK_COMMON_ON_N (0x1 << 4)
51 #define PHYCLK_ID_PULL (0x1 << 2)
52 #define PHYCLK_CLKSEL_MASK (0x3 << 0)
53 #define PHYCLK_CLKSEL_48M (0x0 << 0)
54 #define PHYCLK_CLKSEL_12M (0x2 << 0)
55 #define PHYCLK_CLKSEL_24M (0x3 << 0)
57 #define SAMSUNG_RSTCON (0x08)
59 #define RSTCON_PHYLINK_SWRST (0x1 << 2)
60 #define RSTCON_HLINK_SWRST (0x1 << 1)
61 #define RSTCON_SWRST (0x1 << 0)
64 #define EXYNOS5_PHY_HOST_CTRL0 (0x00)
66 #define HOST_CTRL0_PHYSWRSTALL (0x1 << 31)
68 #define HOST_CTRL0_REFCLKSEL_MASK (0x3 << 19)
69 #define HOST_CTRL0_REFCLKSEL_XTAL (0x0 << 19)
70 #define HOST_CTRL0_REFCLKSEL_EXTL (0x1 << 19)
71 #define HOST_CTRL0_REFCLKSEL_CLKCORE (0x2 << 19)
73 #define HOST_CTRL0_FSEL_MASK (0x7 << 16)
74 #define HOST_CTRL0_FSEL(_x) ((_x) << 16)
76 #define FSEL_CLKSEL_50M (0x7)
77 #define FSEL_CLKSEL_24M (0x5)
78 #define FSEL_CLKSEL_20M (0x4)
79 #define FSEL_CLKSEL_19200K (0x3)
80 #define FSEL_CLKSEL_12M (0x2)
81 #define FSEL_CLKSEL_10M (0x1)
82 #define FSEL_CLKSEL_9600K (0x0)
84 #define HOST_CTRL0_TESTBURNIN (0x1 << 11)
85 #define HOST_CTRL0_RETENABLE (0x1 << 10)
86 #define HOST_CTRL0_COMMONON_N (0x1 << 9)
87 #define HOST_CTRL0_SIDDQ (0x1 << 6)
88 #define HOST_CTRL0_FORCESLEEP (0x1 << 5)
89 #define HOST_CTRL0_FORCESUSPEND (0x1 << 4)
90 #define HOST_CTRL0_WORDINTERFACE (0x1 << 3)
91 #define HOST_CTRL0_UTMISWRST (0x1 << 2)
92 #define HOST_CTRL0_LINKSWRST (0x1 << 1)
93 #define HOST_CTRL0_PHYSWRST (0x1 << 0)
95 #define EXYNOS5_PHY_HOST_TUNE0 (0x04)
97 #define EXYNOS5_PHY_HSIC_CTRL1 (0x10)
99 #define EXYNOS5_PHY_HSIC_TUNE1 (0x14)
101 #define EXYNOS5_PHY_HSIC_CTRL2 (0x20)
103 #define EXYNOS5_PHY_HSIC_TUNE2 (0x24)
105 #define HSIC_CTRL_REFCLKSEL_MASK (0x3 << 23)
106 #define HSIC_CTRL_REFCLKSEL (0x2 << 23)
108 #define HSIC_CTRL_REFCLKDIV_MASK (0x7f << 16)
109 #define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16)
110 #define HSIC_CTRL_REFCLKDIV_12 (0x24 << 16)
111 #define HSIC_CTRL_REFCLKDIV_15 (0x1c << 16)
112 #define HSIC_CTRL_REFCLKDIV_16 (0x1a << 16)
113 #define HSIC_CTRL_REFCLKDIV_19_2 (0x15 << 16)
114 #define HSIC_CTRL_REFCLKDIV_20 (0x14 << 16)
116 #define HSIC_CTRL_SIDDQ (0x1 << 6)
117 #define HSIC_CTRL_FORCESLEEP (0x1 << 5)
118 #define HSIC_CTRL_FORCESUSPEND (0x1 << 4)
119 #define HSIC_CTRL_WORDINTERFACE (0x1 << 3)
120 #define HSIC_CTRL_UTMISWRST (0x1 << 2)
121 #define HSIC_CTRL_PHYSWRST (0x1 << 0)
123 #define EXYNOS5_PHY_HOST_EHCICTRL (0x30)
125 #define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29)
126 #define HOST_EHCICTRL_ENAINCR4 (0x1 << 28)
127 #define HOST_EHCICTRL_ENAINCR8 (0x1 << 27)
128 #define HOST_EHCICTRL_ENAINCR16 (0x1 << 26)
130 #define EXYNOS5_PHY_HOST_OHCICTRL (0x34)
132 #define HOST_OHCICTRL_SUSPLGCY (0x1 << 3)
133 #define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2)
134 #define HOST_OHCICTRL_CNTSEL (0x1 << 1)
135 #define HOST_OHCICTRL_CLKCKTRST (0x1 << 0)
137 #define EXYNOS5_PHY_OTG_SYS (0x38)
139 #define OTG_SYS_PHYLINK_SWRESET (0x1 << 14)
140 #define OTG_SYS_LINKSWRST_UOTG (0x1 << 13)
141 #define OTG_SYS_PHY0_SWRST (0x1 << 12)
143 #define OTG_SYS_REFCLKSEL_MASK (0x3 << 9)
144 #define OTG_SYS_REFCLKSEL_XTAL (0x0 << 9)
145 #define OTG_SYS_REFCLKSEL_EXTL (0x1 << 9)
146 #define OTG_SYS_REFCLKSEL_CLKCORE (0x2 << 9)
148 #define OTG_SYS_IDPULLUP_UOTG (0x1 << 8)
149 #define OTG_SYS_COMMON_ON (0x1 << 7)
151 #define OTG_SYS_FSEL_MASK (0x7 << 4)
152 #define OTG_SYS_FSEL(_x) ((_x) << 4)
154 #define OTG_SYS_FORCESLEEP (0x1 << 3)
155 #define OTG_SYS_OTGDISABLE (0x1 << 2)
156 #define OTG_SYS_SIDDQ_UOTG (0x1 << 1)
157 #define OTG_SYS_FORCESUSPEND (0x1 << 0)
159 #define EXYNOS5_PHY_OTG_TUNE (0x40)
162 #define MHZ (1000*1000)
169 #define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4)
170 #define S3C64XX_USBPHY_ENABLE (0x1 << 16)
171 #define EXYNOS_USBPHY_ENABLE (0x1 << 0)
172 #define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0)
174 enum samsung_cpu_type
{
181 * struct samsung_usbphy_drvdata - driver data for various SoC variants
182 * @cpu_type: machine identifier
183 * @devphy_en_mask: device phy enable mask for PHY CONTROL register
184 * @hostphy_en_mask: host phy enable mask for PHY CONTROL register
185 * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from
186 * mapped address of system controller.
187 * @hostphy_reg_offset: offset to HOST PHY CONTROL register from
188 * mapped address of system controller.
190 * Here we have a separate mask for device type phy.
191 * Having different masks for host and device type phy helps
192 * in setting independent masks in case of SoCs like S5PV210,
193 * in which PHY0 and PHY1 enable bits belong to same register
194 * placed at position 0 and 1 respectively.
195 * Although for newer SoCs like exynos these bits belong to
196 * different registers altogether placed at position 0.
198 struct samsung_usbphy_drvdata
{
202 u32 devphy_reg_offset
;
203 u32 hostphy_reg_offset
;
207 * struct samsung_usbphy - transceiver driver state
208 * @phy: transceiver structure
209 * @plat: platform data
210 * @dev: The parent device supplied to the probe function
211 * @clk: usb phy clock
212 * @regs: usb phy controller registers memory base
213 * @pmuregs: USB device PHY_CONTROL register memory base
214 * @sysreg: USB2.0 PHY_CFG register memory base
215 * @ref_clk_freq: reference clock frequency selection
216 * @drv_data: driver data available for different SoCs
217 * @phy_type: Samsung SoCs specific phy types: #HOST
219 * @phy_usage: usage count for phy
220 * @lock: lock for phy operations
222 struct samsung_usbphy
{
224 struct samsung_usbphy_data
*plat
;
228 void __iomem
*pmuregs
;
229 void __iomem
*sysreg
;
231 const struct samsung_usbphy_drvdata
*drv_data
;
232 enum samsung_usb_phy_type phy_type
;
237 #define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy)
239 int samsung_usbphy_set_host(struct usb_otg
*otg
, struct usb_bus
*host
)
250 static int samsung_usbphy_parse_dt(struct samsung_usbphy
*sphy
)
252 struct device_node
*usbphy_sys
;
254 /* Getting node for system controller interface for usb-phy */
255 usbphy_sys
= of_get_child_by_name(sphy
->dev
->of_node
, "usbphy-sys");
257 dev_err(sphy
->dev
, "No sys-controller interface for usb-phy\n");
261 sphy
->pmuregs
= of_iomap(usbphy_sys
, 0);
263 if (sphy
->pmuregs
== NULL
) {
264 dev_err(sphy
->dev
, "Can't get usb-phy pmu control register\n");
268 sphy
->sysreg
= of_iomap(usbphy_sys
, 1);
271 * Not returning error code here, since this situation is not fatal.
272 * Few SoCs may not have this switch available
274 if (sphy
->sysreg
== NULL
)
275 dev_warn(sphy
->dev
, "Can't get usb-phy sysreg cfg register\n");
277 of_node_put(usbphy_sys
);
282 of_node_put(usbphy_sys
);
287 * Set isolation here for phy.
288 * Here 'on = true' would mean USB PHY block is isolated, hence
289 * de-activated and vice-versa.
291 static void samsung_usbphy_set_isolation(struct samsung_usbphy
*sphy
, bool on
)
293 void __iomem
*reg
= NULL
;
297 if (!sphy
->pmuregs
) {
298 dev_warn(sphy
->dev
, "Can't set pmu isolation\n");
302 switch (sphy
->drv_data
->cpu_type
) {
305 * Do nothing: We will add here once S3C64xx goes for DT support
308 case TYPE_EXYNOS4210
:
310 * Fall through since exynos4210 and exynos5250 have similar
311 * register architecture: two separate registers for host and
312 * device phy control with enable bit at position 0.
314 case TYPE_EXYNOS5250
:
315 if (sphy
->phy_type
== USB_PHY_TYPE_DEVICE
) {
316 reg
= sphy
->pmuregs
+
317 sphy
->drv_data
->devphy_reg_offset
;
318 en_mask
= sphy
->drv_data
->devphy_en_mask
;
319 } else if (sphy
->phy_type
== USB_PHY_TYPE_HOST
) {
320 reg
= sphy
->pmuregs
+
321 sphy
->drv_data
->hostphy_reg_offset
;
322 en_mask
= sphy
->drv_data
->hostphy_en_mask
;
326 dev_err(sphy
->dev
, "Invalid SoC type\n");
330 reg_val
= readl(reg
);
337 writel(reg_val
, reg
);
341 * Configure the mode of working of usb-phy here: HOST/DEVICE.
343 static void samsung_usbphy_cfg_sel(struct samsung_usbphy
*sphy
)
348 dev_warn(sphy
->dev
, "Can't configure specified phy mode\n");
352 reg
= readl(sphy
->sysreg
);
354 if (sphy
->phy_type
== USB_PHY_TYPE_DEVICE
)
355 reg
&= ~EXYNOS_USB20PHY_CFG_HOST_LINK
;
356 else if (sphy
->phy_type
== USB_PHY_TYPE_HOST
)
357 reg
|= EXYNOS_USB20PHY_CFG_HOST_LINK
;
359 writel(reg
, sphy
->sysreg
);
363 * PHYs are different for USB Device and USB Host.
364 * This make sure that correct PHY type is selected before
365 * any operation on PHY.
367 static int samsung_usbphy_set_type(struct usb_phy
*phy
,
368 enum samsung_usb_phy_type phy_type
)
370 struct samsung_usbphy
*sphy
= phy_to_sphy(phy
);
372 sphy
->phy_type
= phy_type
;
378 * Returns reference clock frequency selection value
380 static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy
*sphy
)
386 * In exynos5250 USB host and device PHY use
387 * external crystal clock XXTI
389 if (sphy
->drv_data
->cpu_type
== TYPE_EXYNOS5250
)
390 ref_clk
= clk_get(sphy
->dev
, "ext_xtal");
392 ref_clk
= clk_get(sphy
->dev
, "xusbxti");
393 if (IS_ERR(ref_clk
)) {
394 dev_err(sphy
->dev
, "Failed to get reference clock\n");
395 return PTR_ERR(ref_clk
);
398 if (sphy
->drv_data
->cpu_type
== TYPE_EXYNOS5250
) {
399 /* set clock frequency for PLL */
400 switch (clk_get_rate(ref_clk
)) {
402 refclk_freq
= FSEL_CLKSEL_9600K
;
405 refclk_freq
= FSEL_CLKSEL_10M
;
408 refclk_freq
= FSEL_CLKSEL_12M
;
411 refclk_freq
= FSEL_CLKSEL_19200K
;
414 refclk_freq
= FSEL_CLKSEL_20M
;
417 refclk_freq
= FSEL_CLKSEL_50M
;
421 /* default reference clock */
422 refclk_freq
= FSEL_CLKSEL_24M
;
426 switch (clk_get_rate(ref_clk
)) {
428 refclk_freq
= PHYCLK_CLKSEL_12M
;
431 refclk_freq
= PHYCLK_CLKSEL_24M
;
434 refclk_freq
= PHYCLK_CLKSEL_48M
;
437 if (sphy
->drv_data
->cpu_type
== TYPE_S3C64XX
)
438 refclk_freq
= PHYCLK_CLKSEL_48M
;
440 refclk_freq
= PHYCLK_CLKSEL_24M
;
449 static bool exynos5_phyhost_is_on(void *regs
)
453 reg
= readl(regs
+ EXYNOS5_PHY_HOST_CTRL0
);
455 return !(reg
& HOST_CTRL0_SIDDQ
);
458 static void samsung_exynos5_usbphy_enable(struct samsung_usbphy
*sphy
)
460 void __iomem
*regs
= sphy
->regs
;
461 u32 phyclk
= sphy
->ref_clk_freq
;
469 * phy_usage helps in keeping usage count for phy
470 * so that the first consumer enabling the phy is also
471 * the last consumer to disable it.
474 atomic_inc(&sphy
->phy_usage
);
476 if (exynos5_phyhost_is_on(regs
)) {
477 dev_info(sphy
->dev
, "Already power on PHY\n");
481 /* Host configuration */
482 phyhost
= readl(regs
+ EXYNOS5_PHY_HOST_CTRL0
);
484 /* phy reference clock configuration */
485 phyhost
&= ~HOST_CTRL0_FSEL_MASK
;
486 phyhost
|= HOST_CTRL0_FSEL(phyclk
);
489 phyhost
&= ~(HOST_CTRL0_PHYSWRST
|
490 HOST_CTRL0_PHYSWRSTALL
|
492 /* Enable normal mode of operation */
493 HOST_CTRL0_FORCESUSPEND
|
494 HOST_CTRL0_FORCESLEEP
);
497 phyhost
|= (HOST_CTRL0_LINKSWRST
|
498 HOST_CTRL0_UTMISWRST
|
499 /* COMMON Block configuration during suspend */
500 HOST_CTRL0_COMMONON_N
);
501 writel(phyhost
, regs
+ EXYNOS5_PHY_HOST_CTRL0
);
503 phyhost
&= ~(HOST_CTRL0_LINKSWRST
|
504 HOST_CTRL0_UTMISWRST
);
505 writel(phyhost
, regs
+ EXYNOS5_PHY_HOST_CTRL0
);
507 /* OTG configuration */
508 phyotg
= readl(regs
+ EXYNOS5_PHY_OTG_SYS
);
510 /* phy reference clock configuration */
511 phyotg
&= ~OTG_SYS_FSEL_MASK
;
512 phyotg
|= OTG_SYS_FSEL(phyclk
);
514 /* Enable normal mode of operation */
515 phyotg
&= ~(OTG_SYS_FORCESUSPEND
|
518 OTG_SYS_REFCLKSEL_MASK
|
519 /* COMMON Block configuration during suspend */
522 /* OTG phy & link reset */
523 phyotg
|= (OTG_SYS_PHY0_SWRST
|
524 OTG_SYS_LINKSWRST_UOTG
|
525 OTG_SYS_PHYLINK_SWRESET
|
528 OTG_SYS_REFCLKSEL_CLKCORE
);
530 writel(phyotg
, regs
+ EXYNOS5_PHY_OTG_SYS
);
532 phyotg
&= ~(OTG_SYS_PHY0_SWRST
|
533 OTG_SYS_LINKSWRST_UOTG
|
534 OTG_SYS_PHYLINK_SWRESET
);
535 writel(phyotg
, regs
+ EXYNOS5_PHY_OTG_SYS
);
537 /* HSIC phy configuration */
538 phyhsic
= (HSIC_CTRL_REFCLKDIV_12
|
539 HSIC_CTRL_REFCLKSEL
|
541 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL1
);
542 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL2
);
544 phyhsic
&= ~HSIC_CTRL_PHYSWRST
;
545 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL1
);
546 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL2
);
550 /* enable EHCI DMA burst */
551 ehcictrl
= readl(regs
+ EXYNOS5_PHY_HOST_EHCICTRL
);
552 ehcictrl
|= (HOST_EHCICTRL_ENAINCRXALIGN
|
553 HOST_EHCICTRL_ENAINCR4
|
554 HOST_EHCICTRL_ENAINCR8
|
555 HOST_EHCICTRL_ENAINCR16
);
556 writel(ehcictrl
, regs
+ EXYNOS5_PHY_HOST_EHCICTRL
);
558 /* set ohci_suspend_on_n */
559 ohcictrl
= readl(regs
+ EXYNOS5_PHY_HOST_OHCICTRL
);
560 ohcictrl
|= HOST_OHCICTRL_SUSPLGCY
;
561 writel(ohcictrl
, regs
+ EXYNOS5_PHY_HOST_OHCICTRL
);
564 static void samsung_usbphy_enable(struct samsung_usbphy
*sphy
)
566 void __iomem
*regs
= sphy
->regs
;
571 /* set clock frequency for PLL */
572 phyclk
= sphy
->ref_clk_freq
;
573 phypwr
= readl(regs
+ SAMSUNG_PHYPWR
);
574 rstcon
= readl(regs
+ SAMSUNG_RSTCON
);
576 switch (sphy
->drv_data
->cpu_type
) {
578 phyclk
&= ~PHYCLK_COMMON_ON_N
;
579 phypwr
&= ~PHYPWR_NORMAL_MASK
;
580 rstcon
|= RSTCON_SWRST
;
582 case TYPE_EXYNOS4210
:
583 phypwr
&= ~PHYPWR_NORMAL_MASK_PHY0
;
584 rstcon
|= RSTCON_SWRST
;
589 writel(phyclk
, regs
+ SAMSUNG_PHYCLK
);
590 /* Configure PHY0 for normal operation*/
591 writel(phypwr
, regs
+ SAMSUNG_PHYPWR
);
592 /* reset all ports of PHY and Link */
593 writel(rstcon
, regs
+ SAMSUNG_RSTCON
);
595 rstcon
&= ~RSTCON_SWRST
;
596 writel(rstcon
, regs
+ SAMSUNG_RSTCON
);
599 static void samsung_exynos5_usbphy_disable(struct samsung_usbphy
*sphy
)
601 void __iomem
*regs
= sphy
->regs
;
606 if (atomic_dec_return(&sphy
->phy_usage
) > 0) {
607 dev_info(sphy
->dev
, "still being used\n");
611 phyhsic
= (HSIC_CTRL_REFCLKDIV_12
|
612 HSIC_CTRL_REFCLKSEL
|
614 HSIC_CTRL_FORCESLEEP
|
615 HSIC_CTRL_FORCESUSPEND
);
616 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL1
);
617 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL2
);
619 phyhost
= readl(regs
+ EXYNOS5_PHY_HOST_CTRL0
);
620 phyhost
|= (HOST_CTRL0_SIDDQ
|
621 HOST_CTRL0_FORCESUSPEND
|
622 HOST_CTRL0_FORCESLEEP
|
623 HOST_CTRL0_PHYSWRST
|
624 HOST_CTRL0_PHYSWRSTALL
);
625 writel(phyhost
, regs
+ EXYNOS5_PHY_HOST_CTRL0
);
627 phyotg
= readl(regs
+ EXYNOS5_PHY_OTG_SYS
);
628 phyotg
|= (OTG_SYS_FORCESUSPEND
|
631 writel(phyotg
, regs
+ EXYNOS5_PHY_OTG_SYS
);
634 static void samsung_usbphy_disable(struct samsung_usbphy
*sphy
)
636 void __iomem
*regs
= sphy
->regs
;
639 phypwr
= readl(regs
+ SAMSUNG_PHYPWR
);
641 switch (sphy
->drv_data
->cpu_type
) {
643 phypwr
|= PHYPWR_NORMAL_MASK
;
645 case TYPE_EXYNOS4210
:
646 phypwr
|= PHYPWR_NORMAL_MASK_PHY0
;
651 /* Disable analog and otg block power */
652 writel(phypwr
, regs
+ SAMSUNG_PHYPWR
);
656 * The function passed to the usb driver for phy initialization
658 static int samsung_usbphy_init(struct usb_phy
*phy
)
660 struct samsung_usbphy
*sphy
;
661 struct usb_bus
*host
= NULL
;
665 sphy
= phy_to_sphy(phy
);
667 host
= phy
->otg
->host
;
669 /* Enable the phy clock */
670 ret
= clk_prepare_enable(sphy
->clk
);
672 dev_err(sphy
->dev
, "%s: clk_prepare_enable failed\n", __func__
);
676 spin_lock_irqsave(&sphy
->lock
, flags
);
679 /* setting default phy-type for USB 2.0 */
680 if (!strstr(dev_name(host
->controller
), "ehci") ||
681 !strstr(dev_name(host
->controller
), "ohci"))
682 samsung_usbphy_set_type(&sphy
->phy
, USB_PHY_TYPE_HOST
);
684 samsung_usbphy_set_type(&sphy
->phy
, USB_PHY_TYPE_DEVICE
);
687 /* Disable phy isolation */
688 if (sphy
->plat
&& sphy
->plat
->pmu_isolation
)
689 sphy
->plat
->pmu_isolation(false);
691 samsung_usbphy_set_isolation(sphy
, false);
693 /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
694 samsung_usbphy_cfg_sel(sphy
);
696 /* Initialize usb phy registers */
697 if (sphy
->drv_data
->cpu_type
== TYPE_EXYNOS5250
)
698 samsung_exynos5_usbphy_enable(sphy
);
700 samsung_usbphy_enable(sphy
);
702 spin_unlock_irqrestore(&sphy
->lock
, flags
);
704 /* Disable the phy clock */
705 clk_disable_unprepare(sphy
->clk
);
711 * The function passed to the usb driver for phy shutdown
713 static void samsung_usbphy_shutdown(struct usb_phy
*phy
)
715 struct samsung_usbphy
*sphy
;
716 struct usb_bus
*host
= NULL
;
719 sphy
= phy_to_sphy(phy
);
721 host
= phy
->otg
->host
;
723 if (clk_prepare_enable(sphy
->clk
)) {
724 dev_err(sphy
->dev
, "%s: clk_prepare_enable failed\n", __func__
);
728 spin_lock_irqsave(&sphy
->lock
, flags
);
731 /* setting default phy-type for USB 2.0 */
732 if (!strstr(dev_name(host
->controller
), "ehci") ||
733 !strstr(dev_name(host
->controller
), "ohci"))
734 samsung_usbphy_set_type(&sphy
->phy
, USB_PHY_TYPE_HOST
);
736 samsung_usbphy_set_type(&sphy
->phy
, USB_PHY_TYPE_DEVICE
);
739 /* De-initialize usb phy registers */
740 if (sphy
->drv_data
->cpu_type
== TYPE_EXYNOS5250
)
741 samsung_exynos5_usbphy_disable(sphy
);
743 samsung_usbphy_disable(sphy
);
745 /* Enable phy isolation */
746 if (sphy
->plat
&& sphy
->plat
->pmu_isolation
)
747 sphy
->plat
->pmu_isolation(true);
749 samsung_usbphy_set_isolation(sphy
, true);
751 spin_unlock_irqrestore(&sphy
->lock
, flags
);
753 clk_disable_unprepare(sphy
->clk
);
756 static const struct of_device_id samsung_usbphy_dt_match
[];
758 static inline const struct samsung_usbphy_drvdata
759 *samsung_usbphy_get_driver_data(struct platform_device
*pdev
)
761 if (pdev
->dev
.of_node
) {
762 const struct of_device_id
*match
;
763 match
= of_match_node(samsung_usbphy_dt_match
,
768 return (struct samsung_usbphy_drvdata
*)
769 platform_get_device_id(pdev
)->driver_data
;
772 static int samsung_usbphy_probe(struct platform_device
*pdev
)
774 struct samsung_usbphy
*sphy
;
776 struct samsung_usbphy_data
*pdata
= pdev
->dev
.platform_data
;
777 const struct samsung_usbphy_drvdata
*drv_data
;
778 struct device
*dev
= &pdev
->dev
;
779 struct resource
*phy_mem
;
780 void __iomem
*phy_base
;
784 phy_mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
786 dev_err(dev
, "%s: missing mem resource\n", __func__
);
790 phy_base
= devm_ioremap_resource(dev
, phy_mem
);
791 if (IS_ERR(phy_base
))
792 return PTR_ERR(phy_base
);
794 sphy
= devm_kzalloc(dev
, sizeof(*sphy
), GFP_KERNEL
);
798 otg
= devm_kzalloc(dev
, sizeof(*otg
), GFP_KERNEL
);
802 drv_data
= samsung_usbphy_get_driver_data(pdev
);
804 if (drv_data
->cpu_type
== TYPE_EXYNOS5250
)
805 clk
= devm_clk_get(dev
, "usbhost");
807 clk
= devm_clk_get(dev
, "otg");
810 dev_err(dev
, "Failed to get otg clock\n");
817 ret
= samsung_usbphy_parse_dt(sphy
);
822 dev_err(dev
, "no platform data specified\n");
828 sphy
->regs
= phy_base
;
830 sphy
->drv_data
= drv_data
;
831 sphy
->phy
.dev
= sphy
->dev
;
832 sphy
->phy
.label
= "samsung-usbphy";
833 sphy
->phy
.init
= samsung_usbphy_init
;
834 sphy
->phy
.shutdown
= samsung_usbphy_shutdown
;
835 sphy
->ref_clk_freq
= samsung_usbphy_get_refclk_freq(sphy
);
838 sphy
->phy
.otg
->phy
= &sphy
->phy
;
839 sphy
->phy
.otg
->set_host
= samsung_usbphy_set_host
;
841 spin_lock_init(&sphy
->lock
);
843 platform_set_drvdata(pdev
, sphy
);
845 return usb_add_phy(&sphy
->phy
, USB_PHY_TYPE_USB2
);
848 static int samsung_usbphy_remove(struct platform_device
*pdev
)
850 struct samsung_usbphy
*sphy
= platform_get_drvdata(pdev
);
852 usb_remove_phy(&sphy
->phy
);
855 iounmap(sphy
->pmuregs
);
857 iounmap(sphy
->sysreg
);
862 static const struct samsung_usbphy_drvdata usbphy_s3c64xx
= {
863 .cpu_type
= TYPE_S3C64XX
,
864 .devphy_en_mask
= S3C64XX_USBPHY_ENABLE
,
867 static const struct samsung_usbphy_drvdata usbphy_exynos4
= {
868 .cpu_type
= TYPE_EXYNOS4210
,
869 .devphy_en_mask
= EXYNOS_USBPHY_ENABLE
,
870 .hostphy_en_mask
= EXYNOS_USBPHY_ENABLE
,
873 static struct samsung_usbphy_drvdata usbphy_exynos5
= {
874 .cpu_type
= TYPE_EXYNOS5250
,
875 .hostphy_en_mask
= EXYNOS_USBPHY_ENABLE
,
876 .hostphy_reg_offset
= EXYNOS_USBHOST_PHY_CTRL_OFFSET
,
880 static const struct of_device_id samsung_usbphy_dt_match
[] = {
882 .compatible
= "samsung,s3c64xx-usbphy",
883 .data
= &usbphy_s3c64xx
,
885 .compatible
= "samsung,exynos4210-usbphy",
886 .data
= &usbphy_exynos4
,
888 .compatible
= "samsung,exynos5250-usbphy",
889 .data
= &usbphy_exynos5
893 MODULE_DEVICE_TABLE(of
, samsung_usbphy_dt_match
);
896 static struct platform_device_id samsung_usbphy_driver_ids
[] = {
898 .name
= "s3c64xx-usbphy",
899 .driver_data
= (unsigned long)&usbphy_s3c64xx
,
901 .name
= "exynos4210-usbphy",
902 .driver_data
= (unsigned long)&usbphy_exynos4
,
904 .name
= "exynos5250-usbphy",
905 .driver_data
= (unsigned long)&usbphy_exynos5
,
910 MODULE_DEVICE_TABLE(platform
, samsung_usbphy_driver_ids
);
912 static struct platform_driver samsung_usbphy_driver
= {
913 .probe
= samsung_usbphy_probe
,
914 .remove
= samsung_usbphy_remove
,
915 .id_table
= samsung_usbphy_driver_ids
,
917 .name
= "samsung-usbphy",
918 .owner
= THIS_MODULE
,
919 .of_match_table
= of_match_ptr(samsung_usbphy_dt_match
),
923 module_platform_driver(samsung_usbphy_driver
);
925 MODULE_DESCRIPTION("Samsung USB phy controller");
926 MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
927 MODULE_LICENSE("GPL");
928 MODULE_ALIAS("platform:samsung-usbphy");