2012-03-08 19:52:25 +09:00
/*
* Copyright ( C ) 2012 Samsung Electronics Co . Ltd
* Author : Joonyoung Shim < jy0922 . shim @ samsung . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundationr
*/
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/platform_device.h>
2013-01-01 16:53:07 -08:00
2012-03-08 19:52:25 +09:00
# include <mach/map.h>
2013-01-01 16:53:07 -08:00
2012-03-08 19:52:25 +09:00
# include <plat/cpu.h>
# include <plat/regs-usb-hsotg-phy.h>
# include <plat/usb-phy.h>
2013-01-01 16:53:07 -08:00
# define S5PV210_USB_PHY_CON (S3C_VA_SYS + 0xE80C)
# define S5PV210_USB_PHY0_EN (1 << 0)
# define S5PV210_USB_PHY1_EN (1 << 1)
2012-03-08 19:52:25 +09:00
static int s5pv210_usb_otgphy_init ( struct platform_device * pdev )
{
struct clk * xusbxti ;
u32 phyclk ;
writel ( readl ( S5PV210_USB_PHY_CON ) | S5PV210_USB_PHY0_EN ,
S5PV210_USB_PHY_CON ) ;
/* set clock frequency for PLL */
phyclk = readl ( S3C_PHYCLK ) & ~ S3C_PHYCLK_CLKSEL_MASK ;
xusbxti = clk_get ( & pdev - > dev , " xusbxti " ) ;
if ( xusbxti & & ! IS_ERR ( xusbxti ) ) {
switch ( clk_get_rate ( xusbxti ) ) {
case 12 * MHZ :
phyclk | = S3C_PHYCLK_CLKSEL_12M ;
break ;
case 24 * MHZ :
phyclk | = S3C_PHYCLK_CLKSEL_24M ;
break ;
default :
case 48 * MHZ :
/* default reference clock */
break ;
}
clk_put ( xusbxti ) ;
}
/* TODO: select external clock/oscillator */
writel ( phyclk | S3C_PHYCLK_CLK_FORCE , S3C_PHYCLK ) ;
/* set to normal OTG PHY */
writel ( ( readl ( S3C_PHYPWR ) & ~ S3C_PHYPWR_NORMAL_MASK ) , S3C_PHYPWR ) ;
mdelay ( 1 ) ;
/* reset OTG PHY and Link */
writel ( S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK ,
S3C_RSTCON ) ;
udelay ( 20 ) ; /* at-least 10uS */
writel ( 0 , S3C_RSTCON ) ;
return 0 ;
}
static int s5pv210_usb_otgphy_exit ( struct platform_device * pdev )
{
writel ( ( readl ( S3C_PHYPWR ) | S3C_PHYPWR_ANALOG_POWERDOWN |
S3C_PHYPWR_OTG_DISABLE ) , S3C_PHYPWR ) ;
writel ( readl ( S5PV210_USB_PHY_CON ) & ~ S5PV210_USB_PHY0_EN ,
S5PV210_USB_PHY_CON ) ;
return 0 ;
}
int s5p_usb_phy_init ( struct platform_device * pdev , int type )
{
2013-04-11 22:49:39 +02:00
if ( type = = USB_PHY_TYPE_DEVICE )
2012-03-08 19:52:25 +09:00
return s5pv210_usb_otgphy_init ( pdev ) ;
return - EINVAL ;
}
int s5p_usb_phy_exit ( struct platform_device * pdev , int type )
{
2013-04-11 22:49:39 +02:00
if ( type = = USB_PHY_TYPE_DEVICE )
2012-03-08 19:52:25 +09:00
return s5pv210_usb_otgphy_exit ( pdev ) ;
return - EINVAL ;
}