2009-03-23 18:34:06 -07:00
/*
* linux / arch / arm / mach - omap2 / usb - musb . c
*
* This file will contain the board specific details for the
* MENTOR USB OTG controller on OMAP3430
*
* Copyright ( C ) 2007 - 2008 Texas Instruments
* Copyright ( C ) 2008 Nokia Corporation
* Author : Vikram Pandita
*
* Generalization by :
* Felipe Balbi < felipe . balbi @ nokia . 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 Foundation .
*/
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/delay.h>
# include <linux/platform_device.h>
# include <linux/clk.h>
# include <linux/dma-mapping.h>
# include <linux/io.h>
# include <linux/usb/musb.h>
# include <mach/hardware.h>
# include <mach/irqs.h>
2010-10-19 10:08:11 +03:00
# include <mach/am35xx.h>
2009-10-20 09:40:47 -07:00
# include <plat/usb.h>
2010-12-07 18:57:45 +05:30
# include "control.h"
2009-03-23 18:34:06 -07:00
2010-12-01 14:23:48 +02:00
# if defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined (CONFIG_USB_MUSB_AM35X)
2009-01-19 19:09:22 +02:00
2010-12-07 18:57:45 +05:30
static void am35x_musb_reset ( void )
{
u32 regval ;
/* Reset the musb interface */
regval = omap_ctrl_readl ( AM35XX_CONTROL_IP_SW_RESET ) ;
regval | = AM35XX_USBOTGSS_SW_RST ;
omap_ctrl_writel ( regval , AM35XX_CONTROL_IP_SW_RESET ) ;
regval & = ~ AM35XX_USBOTGSS_SW_RST ;
omap_ctrl_writel ( regval , AM35XX_CONTROL_IP_SW_RESET ) ;
regval = omap_ctrl_readl ( AM35XX_CONTROL_IP_SW_RESET ) ;
}
static void am35x_musb_phy_power ( u8 on )
{
unsigned long timeout = jiffies + msecs_to_jiffies ( 100 ) ;
u32 devconf2 ;
if ( on ) {
/*
* Start the on - chip PHY and its PLL .
*/
devconf2 = omap_ctrl_readl ( AM35XX_CONTROL_DEVCONF2 ) ;
devconf2 & = ~ ( CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN ) ;
devconf2 | = CONF2_PHY_PLLON ;
omap_ctrl_writel ( devconf2 , AM35XX_CONTROL_DEVCONF2 ) ;
pr_info ( KERN_INFO " Waiting for PHY clock good... \n " ) ;
while ( ! ( omap_ctrl_readl ( AM35XX_CONTROL_DEVCONF2 )
& CONF2_PHYCLKGD ) ) {
cpu_relax ( ) ;
if ( time_after ( jiffies , timeout ) ) {
pr_err ( KERN_ERR " musb PHY clock good timed out \n " ) ;
break ;
}
}
} else {
/*
* Power down the on - chip PHY .
*/
devconf2 = omap_ctrl_readl ( AM35XX_CONTROL_DEVCONF2 ) ;
devconf2 & = ~ CONF2_PHY_PLLON ;
devconf2 | = CONF2_PHYPWRDN | CONF2_OTGPWRDN ;
omap_ctrl_writel ( devconf2 , AM35XX_CONTROL_DEVCONF2 ) ;
}
}
static void am35x_musb_clear_irq ( void )
{
u32 regval ;
regval = omap_ctrl_readl ( AM35XX_CONTROL_LVL_INTR_CLEAR ) ;
regval | = AM35XX_USBOTGSS_INT_CLR ;
omap_ctrl_writel ( regval , AM35XX_CONTROL_LVL_INTR_CLEAR ) ;
regval = omap_ctrl_readl ( AM35XX_CONTROL_LVL_INTR_CLEAR ) ;
}
static void am35x_musb_set_mode ( u8 musb_mode )
{
u32 devconf2 = omap_ctrl_readl ( AM35XX_CONTROL_DEVCONF2 ) ;
devconf2 & = ~ CONF2_OTGMODE ;
switch ( musb_mode ) {
# ifdef CONFIG_USB_MUSB_HDRC_HCD
case MUSB_HOST : /* Force VBUS valid, ID = 0 */
devconf2 | = CONF2_FORCE_HOST ;
break ;
# endif
# ifdef CONFIG_USB_GADGET_MUSB_HDRC
case MUSB_PERIPHERAL : /* Force VBUS valid, ID = 1 */
devconf2 | = CONF2_FORCE_DEVICE ;
break ;
# endif
# ifdef CONFIG_USB_MUSB_OTG
case MUSB_OTG : /* Don't override the VBUS/ID comparators */
devconf2 | = CONF2_NO_OVERRIDE ;
break ;
# endif
default :
pr_info ( KERN_INFO " Unsupported mode %u \n " , musb_mode ) ;
}
omap_ctrl_writel ( devconf2 , AM35XX_CONTROL_DEVCONF2 ) ;
}
2009-03-23 18:34:06 -07:00
static struct resource musb_resources [ ] = {
[ 0 ] = { /* start and end set dynamically */
. flags = IORESOURCE_MEM ,
} ,
[ 1 ] = { /* general IRQ */
. start = INT_243X_HS_USB_MC ,
. flags = IORESOURCE_IRQ ,
2010-09-29 11:26:39 -05:00
. name = " mc " ,
2009-03-23 18:34:06 -07:00
} ,
[ 2 ] = { /* DMA IRQ */
. start = INT_243X_HS_USB_DMA ,
. flags = IORESOURCE_IRQ ,
2010-09-29 11:26:39 -05:00
. name = " dma " ,
2009-03-23 18:34:06 -07:00
} ,
} ;
static struct musb_hdrc_config musb_config = {
. multipoint = 1 ,
. dyn_fifo = 1 ,
. num_eps = 16 ,
. ram_bits = 12 ,
} ;
static struct musb_hdrc_platform_data musb_plat = {
# ifdef CONFIG_USB_MUSB_OTG
. mode = MUSB_OTG ,
# elif defined(CONFIG_USB_MUSB_HDRC_HCD)
. mode = MUSB_HOST ,
# elif defined(CONFIG_USB_GADGET_MUSB_HDRC)
. mode = MUSB_PERIPHERAL ,
# endif
/* .clock is set dynamically */
. config = & musb_config ,
/* REVISIT charge pump on TWL4030 can supply up to
* 100 mA . . . but this value is board - specific , like
* " mode " , and should be passed to usb_musb_init ( ) .
*/
. power = 50 , /* up to 100 mA */
} ;
2009-04-13 14:40:14 -07:00
static u64 musb_dmamask = DMA_BIT_MASK ( 32 ) ;
2009-03-23 18:34:06 -07:00
static struct platform_device musb_device = {
2010-12-01 15:01:11 +02:00
. name = " musb-omap2430 " ,
2009-03-23 18:34:06 -07:00
. id = - 1 ,
. dev = {
. dma_mask = & musb_dmamask ,
2009-04-13 14:40:14 -07:00
. coherent_dma_mask = DMA_BIT_MASK ( 32 ) ,
2009-03-23 18:34:06 -07:00
. platform_data = & musb_plat ,
} ,
. num_resources = ARRAY_SIZE ( musb_resources ) ,
. resource = musb_resources ,
} ;
2010-02-17 14:09:30 -08:00
void __init usb_musb_init ( struct omap_musb_board_data * board_data )
2009-03-23 18:34:06 -07:00
{
2010-02-17 14:09:32 -08:00
if ( cpu_is_omap243x ( ) ) {
2009-03-23 18:34:06 -07:00
musb_resources [ 0 ] . start = OMAP243X_HS_BASE ;
2010-10-19 10:08:11 +03:00
} else if ( cpu_is_omap3517 ( ) | | cpu_is_omap3505 ( ) ) {
2010-12-02 09:06:51 +02:00
musb_device . name = " musb-am35x " ;
2010-10-19 10:08:11 +03:00
musb_resources [ 0 ] . start = AM35XX_IPSS_USBOTGSS_BASE ;
musb_resources [ 1 ] . start = INT_35XX_USBOTG_IRQ ;
2010-12-07 18:57:45 +05:30
board_data - > set_phy_power = am35x_musb_phy_power ;
board_data - > clear_irq = am35x_musb_clear_irq ;
board_data - > set_mode = am35x_musb_set_mode ;
board_data - > reset = am35x_musb_reset ;
2010-02-17 14:09:32 -08:00
} else if ( cpu_is_omap34xx ( ) ) {
2009-03-23 18:34:06 -07:00
musb_resources [ 0 ] . start = OMAP34XX_HSUSB_OTG_BASE ;
2010-02-17 14:09:32 -08:00
} else if ( cpu_is_omap44xx ( ) ) {
musb_resources [ 0 ] . start = OMAP44XX_HSUSB_OTG_BASE ;
2010-02-18 03:14:12 +05:30
musb_resources [ 1 ] . start = OMAP44XX_IRQ_HS_USB_MC_N ;
musb_resources [ 2 ] . start = OMAP44XX_IRQ_HS_USB_DMA_N ;
2010-02-17 14:09:32 -08:00
}
2010-02-17 14:09:29 -08:00
musb_resources [ 0 ] . end = musb_resources [ 0 ] . start + SZ_4K - 1 ;
2009-03-23 18:34:06 -07:00
/*
* REVISIT : This line can be removed once all the platforms using
* musb_core . c have been converted to use use clkdev .
*/
musb_plat . clock = " ick " ;
2010-02-17 14:09:30 -08:00
musb_plat . board_data = board_data ;
musb_plat . power = board_data - > power > > 1 ;
musb_plat . mode = board_data - > mode ;
2010-03-25 13:25:27 +02:00
musb_plat . extvbus = board_data - > extvbus ;
2009-03-23 18:34:06 -07:00
2010-02-17 14:09:31 -08:00
if ( platform_device_register ( & musb_device ) < 0 )
2009-03-23 18:34:06 -07:00
printk ( KERN_ERR " Unable to register HS-USB (MUSB) device \n " ) ;
2009-01-19 19:09:22 +02:00
}
# else
2010-02-17 14:09:30 -08:00
void __init usb_musb_init ( struct omap_musb_board_data * board_data )
2009-01-19 19:09:22 +02:00
{
2009-03-23 18:34:06 -07:00
}
2009-01-19 19:09:22 +02:00
# endif /* CONFIG_USB_MUSB_SOC */