1 /* linux/drivers/usb/phy/phy-samsung-usb2.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/usb/otg.h>
30 #include <linux/usb/samsung_usb_phy.h>
31 #include <linux/platform_data/samsung-usbphy.h>
33 #include "phy-samsung-usb.h"
35 static int samsung_usbphy_set_host(struct usb_otg
*otg
, struct usb_bus
*host
)
46 static bool exynos5_phyhost_is_on(void __iomem
*regs
)
50 reg
= readl(regs
+ EXYNOS5_PHY_HOST_CTRL0
);
52 return !(reg
& HOST_CTRL0_SIDDQ
);
55 static void samsung_exynos5_usb2phy_enable(struct samsung_usbphy
*sphy
)
57 void __iomem
*regs
= sphy
->regs
;
58 u32 phyclk
= sphy
->ref_clk_freq
;
66 * phy_usage helps in keeping usage count for phy
67 * so that the first consumer enabling the phy is also
68 * the last consumer to disable it.
71 atomic_inc(&sphy
->phy_usage
);
73 if (exynos5_phyhost_is_on(regs
)) {
74 dev_info(sphy
->dev
, "Already power on PHY\n");
78 /* Host configuration */
79 phyhost
= readl(regs
+ EXYNOS5_PHY_HOST_CTRL0
);
81 /* phy reference clock configuration */
82 phyhost
&= ~HOST_CTRL0_FSEL_MASK
;
83 phyhost
|= HOST_CTRL0_FSEL(phyclk
);
86 phyhost
&= ~(HOST_CTRL0_PHYSWRST
|
87 HOST_CTRL0_PHYSWRSTALL
|
89 /* Enable normal mode of operation */
90 HOST_CTRL0_FORCESUSPEND
|
91 HOST_CTRL0_FORCESLEEP
);
94 phyhost
|= (HOST_CTRL0_LINKSWRST
|
95 HOST_CTRL0_UTMISWRST
|
96 /* COMMON Block configuration during suspend */
97 HOST_CTRL0_COMMONON_N
);
98 writel(phyhost
, regs
+ EXYNOS5_PHY_HOST_CTRL0
);
100 phyhost
&= ~(HOST_CTRL0_LINKSWRST
|
101 HOST_CTRL0_UTMISWRST
);
102 writel(phyhost
, regs
+ EXYNOS5_PHY_HOST_CTRL0
);
104 /* OTG configuration */
105 phyotg
= readl(regs
+ EXYNOS5_PHY_OTG_SYS
);
107 /* phy reference clock configuration */
108 phyotg
&= ~OTG_SYS_FSEL_MASK
;
109 phyotg
|= OTG_SYS_FSEL(phyclk
);
111 /* Enable normal mode of operation */
112 phyotg
&= ~(OTG_SYS_FORCESUSPEND
|
115 OTG_SYS_REFCLKSEL_MASK
|
116 /* COMMON Block configuration during suspend */
119 /* OTG phy & link reset */
120 phyotg
|= (OTG_SYS_PHY0_SWRST
|
121 OTG_SYS_LINKSWRST_UOTG
|
122 OTG_SYS_PHYLINK_SWRESET
|
125 OTG_SYS_REFCLKSEL_CLKCORE
);
127 writel(phyotg
, regs
+ EXYNOS5_PHY_OTG_SYS
);
129 phyotg
&= ~(OTG_SYS_PHY0_SWRST
|
130 OTG_SYS_LINKSWRST_UOTG
|
131 OTG_SYS_PHYLINK_SWRESET
);
132 writel(phyotg
, regs
+ EXYNOS5_PHY_OTG_SYS
);
134 /* HSIC phy configuration */
135 phyhsic
= (HSIC_CTRL_REFCLKDIV_12
|
136 HSIC_CTRL_REFCLKSEL
|
138 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL1
);
139 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL2
);
141 phyhsic
&= ~HSIC_CTRL_PHYSWRST
;
142 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL1
);
143 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL2
);
147 /* enable EHCI DMA burst */
148 ehcictrl
= readl(regs
+ EXYNOS5_PHY_HOST_EHCICTRL
);
149 ehcictrl
|= (HOST_EHCICTRL_ENAINCRXALIGN
|
150 HOST_EHCICTRL_ENAINCR4
|
151 HOST_EHCICTRL_ENAINCR8
|
152 HOST_EHCICTRL_ENAINCR16
);
153 writel(ehcictrl
, regs
+ EXYNOS5_PHY_HOST_EHCICTRL
);
155 /* set ohci_suspend_on_n */
156 ohcictrl
= readl(regs
+ EXYNOS5_PHY_HOST_OHCICTRL
);
157 ohcictrl
|= HOST_OHCICTRL_SUSPLGCY
;
158 writel(ohcictrl
, regs
+ EXYNOS5_PHY_HOST_OHCICTRL
);
161 static void samsung_usb2phy_enable(struct samsung_usbphy
*sphy
)
163 void __iomem
*regs
= sphy
->regs
;
168 /* set clock frequency for PLL */
169 phyclk
= sphy
->ref_clk_freq
;
170 phypwr
= readl(regs
+ SAMSUNG_PHYPWR
);
171 rstcon
= readl(regs
+ SAMSUNG_RSTCON
);
173 switch (sphy
->drv_data
->cpu_type
) {
175 phyclk
&= ~PHYCLK_COMMON_ON_N
;
176 phypwr
&= ~PHYPWR_NORMAL_MASK
;
177 rstcon
|= RSTCON_SWRST
;
179 case TYPE_EXYNOS4X12
:
180 phypwr
&= ~(PHYPWR_NORMAL_MASK_HSIC0
|
181 PHYPWR_NORMAL_MASK_HSIC1
|
182 PHYPWR_NORMAL_MASK_PHY1
);
183 rstcon
|= RSTCON_HOSTPHY_SWRST
;
184 case TYPE_EXYNOS4210
:
185 phypwr
&= ~PHYPWR_NORMAL_MASK_PHY0
;
186 rstcon
|= RSTCON_SWRST
;
191 writel(phyclk
, regs
+ SAMSUNG_PHYCLK
);
192 /* Configure PHY0 for normal operation*/
193 writel(phypwr
, regs
+ SAMSUNG_PHYPWR
);
194 /* reset all ports of PHY and Link */
195 writel(rstcon
, regs
+ SAMSUNG_RSTCON
);
197 if (sphy
->drv_data
->cpu_type
== TYPE_EXYNOS4X12
)
198 rstcon
&= ~RSTCON_HOSTPHY_SWRST
;
199 rstcon
&= ~RSTCON_SWRST
;
200 writel(rstcon
, regs
+ SAMSUNG_RSTCON
);
203 static void samsung_exynos5_usb2phy_disable(struct samsung_usbphy
*sphy
)
205 void __iomem
*regs
= sphy
->regs
;
210 if (atomic_dec_return(&sphy
->phy_usage
) > 0) {
211 dev_info(sphy
->dev
, "still being used\n");
215 phyhsic
= (HSIC_CTRL_REFCLKDIV_12
|
216 HSIC_CTRL_REFCLKSEL
|
218 HSIC_CTRL_FORCESLEEP
|
219 HSIC_CTRL_FORCESUSPEND
);
220 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL1
);
221 writel(phyhsic
, regs
+ EXYNOS5_PHY_HSIC_CTRL2
);
223 phyhost
= readl(regs
+ EXYNOS5_PHY_HOST_CTRL0
);
224 phyhost
|= (HOST_CTRL0_SIDDQ
|
225 HOST_CTRL0_FORCESUSPEND
|
226 HOST_CTRL0_FORCESLEEP
|
227 HOST_CTRL0_PHYSWRST
|
228 HOST_CTRL0_PHYSWRSTALL
);
229 writel(phyhost
, regs
+ EXYNOS5_PHY_HOST_CTRL0
);
231 phyotg
= readl(regs
+ EXYNOS5_PHY_OTG_SYS
);
232 phyotg
|= (OTG_SYS_FORCESUSPEND
|
235 writel(phyotg
, regs
+ EXYNOS5_PHY_OTG_SYS
);
238 static void samsung_usb2phy_disable(struct samsung_usbphy
*sphy
)
240 void __iomem
*regs
= sphy
->regs
;
243 phypwr
= readl(regs
+ SAMSUNG_PHYPWR
);
245 switch (sphy
->drv_data
->cpu_type
) {
247 phypwr
|= PHYPWR_NORMAL_MASK
;
249 case TYPE_EXYNOS4X12
:
250 phypwr
|= (PHYPWR_NORMAL_MASK_HSIC0
|
251 PHYPWR_NORMAL_MASK_HSIC1
|
252 PHYPWR_NORMAL_MASK_PHY1
);
253 case TYPE_EXYNOS4210
:
254 phypwr
|= PHYPWR_NORMAL_MASK_PHY0
;
259 /* Disable analog and otg block power */
260 writel(phypwr
, regs
+ SAMSUNG_PHYPWR
);
264 * The function passed to the usb driver for phy initialization
266 static int samsung_usb2phy_init(struct usb_phy
*phy
)
268 struct samsung_usbphy
*sphy
;
269 struct usb_bus
*host
= NULL
;
273 sphy
= phy_to_sphy(phy
);
275 host
= phy
->otg
->host
;
277 /* Enable the phy clock */
278 ret
= clk_prepare_enable(sphy
->clk
);
280 dev_err(sphy
->dev
, "%s: clk_prepare_enable failed\n", __func__
);
284 spin_lock_irqsave(&sphy
->lock
, flags
);
287 /* setting default phy-type for USB 2.0 */
288 if (!strstr(dev_name(host
->controller
), "ehci") ||
289 !strstr(dev_name(host
->controller
), "ohci"))
290 samsung_usbphy_set_type(&sphy
->phy
, USB_PHY_TYPE_HOST
);
292 samsung_usbphy_set_type(&sphy
->phy
, USB_PHY_TYPE_DEVICE
);
295 /* Disable phy isolation */
296 if (sphy
->plat
&& sphy
->plat
->pmu_isolation
)
297 sphy
->plat
->pmu_isolation(false);
298 else if (sphy
->drv_data
->set_isolation
)
299 sphy
->drv_data
->set_isolation(sphy
, false);
301 /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */
302 samsung_usbphy_cfg_sel(sphy
);
304 /* Initialize usb phy registers */
305 sphy
->drv_data
->phy_enable(sphy
);
307 spin_unlock_irqrestore(&sphy
->lock
, flags
);
309 /* Disable the phy clock */
310 clk_disable_unprepare(sphy
->clk
);
316 * The function passed to the usb driver for phy shutdown
318 static void samsung_usb2phy_shutdown(struct usb_phy
*phy
)
320 struct samsung_usbphy
*sphy
;
321 struct usb_bus
*host
= NULL
;
324 sphy
= phy_to_sphy(phy
);
326 host
= phy
->otg
->host
;
328 if (clk_prepare_enable(sphy
->clk
)) {
329 dev_err(sphy
->dev
, "%s: clk_prepare_enable failed\n", __func__
);
333 spin_lock_irqsave(&sphy
->lock
, flags
);
336 /* setting default phy-type for USB 2.0 */
337 if (!strstr(dev_name(host
->controller
), "ehci") ||
338 !strstr(dev_name(host
->controller
), "ohci"))
339 samsung_usbphy_set_type(&sphy
->phy
, USB_PHY_TYPE_HOST
);
341 samsung_usbphy_set_type(&sphy
->phy
, USB_PHY_TYPE_DEVICE
);
344 /* De-initialize usb phy registers */
345 sphy
->drv_data
->phy_disable(sphy
);
347 /* Enable phy isolation */
348 if (sphy
->plat
&& sphy
->plat
->pmu_isolation
)
349 sphy
->plat
->pmu_isolation(true);
350 else if (sphy
->drv_data
->set_isolation
)
351 sphy
->drv_data
->set_isolation(sphy
, true);
353 spin_unlock_irqrestore(&sphy
->lock
, flags
);
355 clk_disable_unprepare(sphy
->clk
);
358 static int samsung_usb2phy_probe(struct platform_device
*pdev
)
360 struct samsung_usbphy
*sphy
;
362 struct samsung_usbphy_data
*pdata
= dev_get_platdata(&pdev
->dev
);
363 const struct samsung_usbphy_drvdata
*drv_data
;
364 struct device
*dev
= &pdev
->dev
;
365 struct resource
*phy_mem
;
366 void __iomem
*phy_base
;
370 phy_mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
371 phy_base
= devm_ioremap_resource(dev
, phy_mem
);
372 if (IS_ERR(phy_base
))
373 return PTR_ERR(phy_base
);
375 sphy
= devm_kzalloc(dev
, sizeof(*sphy
), GFP_KERNEL
);
379 otg
= devm_kzalloc(dev
, sizeof(*otg
), GFP_KERNEL
);
383 drv_data
= samsung_usbphy_get_driver_data(pdev
);
385 if (drv_data
->cpu_type
== TYPE_EXYNOS5250
)
386 clk
= devm_clk_get(dev
, "usbhost");
388 clk
= devm_clk_get(dev
, "otg");
391 dev_err(dev
, "Failed to get usbhost/otg clock\n");
398 ret
= samsung_usbphy_parse_dt(sphy
);
403 dev_err(dev
, "no platform data specified\n");
409 sphy
->regs
= phy_base
;
411 sphy
->drv_data
= drv_data
;
412 sphy
->phy
.dev
= sphy
->dev
;
413 sphy
->phy
.label
= "samsung-usb2phy";
414 sphy
->phy
.type
= USB_PHY_TYPE_USB2
;
415 sphy
->phy
.init
= samsung_usb2phy_init
;
416 sphy
->phy
.shutdown
= samsung_usb2phy_shutdown
;
418 sphy
->ref_clk_freq
= samsung_usbphy_get_refclk_freq(sphy
);
419 if (sphy
->ref_clk_freq
< 0)
423 sphy
->phy
.otg
->phy
= &sphy
->phy
;
424 sphy
->phy
.otg
->set_host
= samsung_usbphy_set_host
;
426 spin_lock_init(&sphy
->lock
);
428 platform_set_drvdata(pdev
, sphy
);
430 return usb_add_phy_dev(&sphy
->phy
);
433 static int samsung_usb2phy_remove(struct platform_device
*pdev
)
435 struct samsung_usbphy
*sphy
= platform_get_drvdata(pdev
);
437 usb_remove_phy(&sphy
->phy
);
440 iounmap(sphy
->pmuregs
);
442 iounmap(sphy
->sysreg
);
447 static const struct samsung_usbphy_drvdata usb2phy_s3c64xx
= {
448 .cpu_type
= TYPE_S3C64XX
,
449 .devphy_en_mask
= S3C64XX_USBPHY_ENABLE
,
450 .rate_to_clksel
= samsung_usbphy_rate_to_clksel_64xx
,
451 .set_isolation
= NULL
, /* TODO */
452 .phy_enable
= samsung_usb2phy_enable
,
453 .phy_disable
= samsung_usb2phy_disable
,
456 static const struct samsung_usbphy_drvdata usb2phy_exynos4
= {
457 .cpu_type
= TYPE_EXYNOS4210
,
458 .devphy_en_mask
= EXYNOS_USBPHY_ENABLE
,
459 .hostphy_en_mask
= EXYNOS_USBPHY_ENABLE
,
460 .rate_to_clksel
= samsung_usbphy_rate_to_clksel_64xx
,
461 .set_isolation
= samsung_usbphy_set_isolation_4210
,
462 .phy_enable
= samsung_usb2phy_enable
,
463 .phy_disable
= samsung_usb2phy_disable
,
466 static const struct samsung_usbphy_drvdata usb2phy_exynos4x12
= {
467 .cpu_type
= TYPE_EXYNOS4X12
,
468 .devphy_en_mask
= EXYNOS_USBPHY_ENABLE
,
469 .hostphy_en_mask
= EXYNOS_USBPHY_ENABLE
,
470 .rate_to_clksel
= samsung_usbphy_rate_to_clksel_4x12
,
471 .set_isolation
= samsung_usbphy_set_isolation_4210
,
472 .phy_enable
= samsung_usb2phy_enable
,
473 .phy_disable
= samsung_usb2phy_disable
,
476 static struct samsung_usbphy_drvdata usb2phy_exynos5
= {
477 .cpu_type
= TYPE_EXYNOS5250
,
478 .hostphy_en_mask
= EXYNOS_USBPHY_ENABLE
,
479 .hostphy_reg_offset
= EXYNOS_USBHOST_PHY_CTRL_OFFSET
,
480 .rate_to_clksel
= samsung_usbphy_rate_to_clksel_4x12
,
481 .set_isolation
= samsung_usbphy_set_isolation_4210
,
482 .phy_enable
= samsung_exynos5_usb2phy_enable
,
483 .phy_disable
= samsung_exynos5_usb2phy_disable
,
487 static const struct of_device_id samsung_usbphy_dt_match
[] = {
489 .compatible
= "samsung,s3c64xx-usb2phy",
490 .data
= &usb2phy_s3c64xx
,
492 .compatible
= "samsung,exynos4210-usb2phy",
493 .data
= &usb2phy_exynos4
,
495 .compatible
= "samsung,exynos4x12-usb2phy",
496 .data
= &usb2phy_exynos4x12
,
498 .compatible
= "samsung,exynos5250-usb2phy",
499 .data
= &usb2phy_exynos5
503 MODULE_DEVICE_TABLE(of
, samsung_usbphy_dt_match
);
506 static struct platform_device_id samsung_usbphy_driver_ids
[] = {
508 .name
= "s3c64xx-usb2phy",
509 .driver_data
= (unsigned long)&usb2phy_s3c64xx
,
511 .name
= "exynos4210-usb2phy",
512 .driver_data
= (unsigned long)&usb2phy_exynos4
,
514 .name
= "exynos4x12-usb2phy",
515 .driver_data
= (unsigned long)&usb2phy_exynos4x12
,
517 .name
= "exynos5250-usb2phy",
518 .driver_data
= (unsigned long)&usb2phy_exynos5
,
523 MODULE_DEVICE_TABLE(platform
, samsung_usbphy_driver_ids
);
525 static struct platform_driver samsung_usb2phy_driver
= {
526 .probe
= samsung_usb2phy_probe
,
527 .remove
= samsung_usb2phy_remove
,
528 .id_table
= samsung_usbphy_driver_ids
,
530 .name
= "samsung-usb2phy",
531 .owner
= THIS_MODULE
,
532 .of_match_table
= of_match_ptr(samsung_usbphy_dt_match
),
536 module_platform_driver(samsung_usb2phy_driver
);
538 MODULE_DESCRIPTION("Samsung USB 2.0 phy controller");
539 MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>");
540 MODULE_LICENSE("GPL");
541 MODULE_ALIAS("platform:samsung-usb2phy");