2009-01-20 09:15:18 +03:00
/*
* linux / arch / arm / mach - mmp / devices . c
*
* 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/init.h>
# include <linux/platform_device.h>
# include <linux/dma-mapping.h>
2012-05-03 10:19:13 +04:00
# include <linux/delay.h>
2009-01-20 09:15:18 +03:00
# include <asm/irq.h>
2012-05-03 10:19:13 +04:00
# include <mach/irqs.h>
2009-01-20 09:15:18 +03:00
# include <mach/devices.h>
2012-05-03 10:19:13 +04:00
# include <mach/cputype.h>
# include <mach/regs-usb.h>
2009-01-20 09:15:18 +03:00
int __init pxa_register_device ( struct pxa_device_desc * desc ,
void * data , size_t size )
{
struct platform_device * pdev ;
struct resource res [ 2 + MAX_RESOURCE_DMA ] ;
int i , ret = 0 , nres = 0 ;
pdev = platform_device_alloc ( desc - > drv_name , desc - > id ) ;
if ( pdev = = NULL )
return - ENOMEM ;
pdev - > dev . coherent_dma_mask = DMA_BIT_MASK ( 32 ) ;
memset ( res , 0 , sizeof ( res ) ) ;
if ( desc - > start ! = - 1ul & & desc - > size > 0 ) {
res [ nres ] . start = desc - > start ;
res [ nres ] . end = desc - > start + desc - > size - 1 ;
res [ nres ] . flags = IORESOURCE_MEM ;
nres + + ;
}
if ( desc - > irq ! = NO_IRQ ) {
res [ nres ] . start = desc - > irq ;
res [ nres ] . end = desc - > irq ;
res [ nres ] . flags = IORESOURCE_IRQ ;
nres + + ;
}
for ( i = 0 ; i < MAX_RESOURCE_DMA ; i + + , nres + + ) {
if ( desc - > dma [ i ] = = 0 )
break ;
res [ nres ] . start = desc - > dma [ i ] ;
res [ nres ] . end = desc - > dma [ i ] ;
res [ nres ] . flags = IORESOURCE_DMA ;
}
ret = platform_device_add_resources ( pdev , res , nres ) ;
if ( ret ) {
platform_device_put ( pdev ) ;
return ret ;
}
if ( data & & size ) {
ret = platform_device_add_data ( pdev , data , size ) ;
if ( ret ) {
platform_device_put ( pdev ) ;
return ret ;
}
}
return platform_device_add ( pdev ) ;
}
2012-05-03 10:19:13 +04:00
2014-03-12 18:29:22 +04:00
# if IS_ENABLED(CONFIG_USB) || IS_ENABLED(CONFIG_USB_GADGET)
2012-05-03 10:19:13 +04:00
/*****************************************************************************
* The registers read / write routines
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static unsigned int u2o_get ( void __iomem * base , unsigned int offset )
{
return readl_relaxed ( base + offset ) ;
}
static void u2o_set ( void __iomem * base , unsigned int offset ,
unsigned int value )
{
u32 reg ;
reg = readl_relaxed ( base + offset ) ;
reg | = value ;
writel_relaxed ( reg , base + offset ) ;
readl_relaxed ( base + offset ) ;
}
static void u2o_clear ( void __iomem * base , unsigned int offset ,
unsigned int value )
{
u32 reg ;
reg = readl_relaxed ( base + offset ) ;
reg & = ~ value ;
writel_relaxed ( reg , base + offset ) ;
readl_relaxed ( base + offset ) ;
}
static void u2o_write ( void __iomem * base , unsigned int offset ,
unsigned int value )
{
writel_relaxed ( value , base + offset ) ;
readl_relaxed ( base + offset ) ;
}
2014-03-12 18:29:22 +04:00
# if IS_ENABLED(CONFIG_USB_MV_UDC) || IS_ENABLED(CONFIG_USB_EHCI_MV)
2012-05-03 10:19:13 +04:00
2014-03-12 18:29:22 +04:00
# if IS_ENABLED(CONFIG_CPU_PXA910) || IS_ENABLED(CONFIG_CPU_PXA168)
2012-05-03 10:19:13 +04:00
static DEFINE_MUTEX ( phy_lock ) ;
static int phy_init_cnt ;
static int usb_phy_init_internal ( void __iomem * base )
{
int loops ;
pr_info ( " Init usb phy!!! \n " ) ;
/* Initialize the USB PHY power */
if ( cpu_is_pxa910 ( ) ) {
u2o_set ( base , UTMI_CTRL , ( 1 < < UTMI_CTRL_INPKT_DELAY_SOF_SHIFT )
| ( 1 < < UTMI_CTRL_PU_REF_SHIFT ) ) ;
}
u2o_set ( base , UTMI_CTRL , 1 < < UTMI_CTRL_PLL_PWR_UP_SHIFT ) ;
u2o_set ( base , UTMI_CTRL , 1 < < UTMI_CTRL_PWR_UP_SHIFT ) ;
/* UTMI_PLL settings */
u2o_clear ( base , UTMI_PLL , UTMI_PLL_PLLVDD18_MASK
| UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
| UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
| UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK ) ;
u2o_set ( base , UTMI_PLL , 0xee < < UTMI_PLL_FBDIV_SHIFT
| 0xb < < UTMI_PLL_REFDIV_SHIFT | 3 < < UTMI_PLL_PLLVDD18_SHIFT
| 3 < < UTMI_PLL_PLLVDD12_SHIFT | 3 < < UTMI_PLL_PLLCALI12_SHIFT
| 1 < < UTMI_PLL_ICP_SHIFT | 3 < < UTMI_PLL_KVCO_SHIFT ) ;
/* UTMI_TX */
u2o_clear ( base , UTMI_TX , UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
| UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
| UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
| UTMI_TX_AMP_MASK ) ;
u2o_set ( base , UTMI_TX , 3 < < UTMI_TX_TXVDD12_SHIFT
| 4 < < UTMI_TX_CK60_PHSEL_SHIFT | 4 < < UTMI_TX_IMPCAL_VTH_SHIFT
| 8 < < UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3 < < UTMI_TX_AMP_SHIFT ) ;
/* UTMI_RX */
u2o_clear ( base , UTMI_RX , UTMI_RX_SQ_THRESH_MASK
| UTMI_REG_SQ_LENGTH_MASK ) ;
u2o_set ( base , UTMI_RX , 7 < < UTMI_RX_SQ_THRESH_SHIFT
| 2 < < UTMI_REG_SQ_LENGTH_SHIFT ) ;
/* UTMI_IVREF */
if ( cpu_is_pxa168 ( ) )
/* fixing Microsoft Altair board interface with NEC hub issue -
* Set UTMI_IVREF from 0x4a3 to 0x4bf */
u2o_write ( base , UTMI_IVREF , 0x4bf ) ;
/* toggle VCOCAL_START bit of UTMI_PLL */
udelay ( 200 ) ;
u2o_set ( base , UTMI_PLL , VCOCAL_START ) ;
udelay ( 40 ) ;
u2o_clear ( base , UTMI_PLL , VCOCAL_START ) ;
/* toggle REG_RCAL_START bit of UTMI_TX */
udelay ( 400 ) ;
u2o_set ( base , UTMI_TX , REG_RCAL_START ) ;
udelay ( 40 ) ;
u2o_clear ( base , UTMI_TX , REG_RCAL_START ) ;
udelay ( 400 ) ;
/* Make sure PHY PLL is ready */
loops = 0 ;
while ( ( u2o_get ( base , UTMI_PLL ) & PLL_READY ) = = 0 ) {
mdelay ( 1 ) ;
loops + + ;
if ( loops > 100 ) {
printk ( KERN_WARNING " calibrate timeout, UTMI_PLL %x \n " ,
u2o_get ( base , UTMI_PLL ) ) ;
break ;
}
}
if ( cpu_is_pxa168 ( ) ) {
u2o_set ( base , UTMI_RESERVE , 1 < < 5 ) ;
/* Turn on UTMI PHY OTG extension */
u2o_write ( base , UTMI_OTG_ADDON , 1 ) ;
}
return 0 ;
}
static int usb_phy_deinit_internal ( void __iomem * base )
{
pr_info ( " Deinit usb phy!!! \n " ) ;
if ( cpu_is_pxa168 ( ) )
u2o_clear ( base , UTMI_OTG_ADDON , UTMI_OTG_ADDON_OTG_ON ) ;
u2o_clear ( base , UTMI_CTRL , UTMI_CTRL_RXBUF_PDWN ) ;
u2o_clear ( base , UTMI_CTRL , UTMI_CTRL_TXBUF_PDWN ) ;
u2o_clear ( base , UTMI_CTRL , UTMI_CTRL_USB_CLK_EN ) ;
u2o_clear ( base , UTMI_CTRL , 1 < < UTMI_CTRL_PWR_UP_SHIFT ) ;
u2o_clear ( base , UTMI_CTRL , 1 < < UTMI_CTRL_PLL_PWR_UP_SHIFT ) ;
return 0 ;
}
int pxa_usb_phy_init ( void __iomem * phy_reg )
{
mutex_lock ( & phy_lock ) ;
if ( phy_init_cnt + + = = 0 )
usb_phy_init_internal ( phy_reg ) ;
mutex_unlock ( & phy_lock ) ;
return 0 ;
}
void pxa_usb_phy_deinit ( void __iomem * phy_reg )
{
WARN_ON ( phy_init_cnt = = 0 ) ;
mutex_lock ( & phy_lock ) ;
if ( - - phy_init_cnt = = 0 )
usb_phy_deinit_internal ( phy_reg ) ;
mutex_unlock ( & phy_lock ) ;
}
# endif
# endif
# endif
2014-03-12 18:29:22 +04:00
# if IS_ENABLED(CONFIG_USB_SUPPORT)
2012-05-03 10:19:13 +04:00
static u64 usb_dma_mask = ~ ( u32 ) 0 ;
2014-03-12 18:29:22 +04:00
# if IS_ENABLED(CONFIG_USB_MV_UDC)
2012-05-03 10:19:13 +04:00
struct resource pxa168_u2o_resources [ ] = {
/* regbase */
[ 0 ] = {
. start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET ,
. end = PXA168_U2O_REGBASE + USB_REG_RANGE ,
. flags = IORESOURCE_MEM ,
. name = " capregs " ,
} ,
/* phybase */
[ 1 ] = {
. start = PXA168_U2O_PHYBASE ,
. end = PXA168_U2O_PHYBASE + USB_PHY_RANGE ,
. flags = IORESOURCE_MEM ,
. name = " phyregs " ,
} ,
[ 2 ] = {
. start = IRQ_PXA168_USB1 ,
. end = IRQ_PXA168_USB1 ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
struct platform_device pxa168_device_u2o = {
. name = " mv-udc " ,
. id = - 1 ,
. resource = pxa168_u2o_resources ,
. num_resources = ARRAY_SIZE ( pxa168_u2o_resources ) ,
. dev = {
. dma_mask = & usb_dma_mask ,
. coherent_dma_mask = 0xffffffff ,
}
} ;
# endif /* CONFIG_USB_MV_UDC */
2014-03-12 18:29:22 +04:00
# if IS_ENABLED(CONFIG_USB_EHCI_MV_U2O)
2012-05-03 10:19:13 +04:00
struct resource pxa168_u2oehci_resources [ ] = {
/* regbase */
[ 0 ] = {
. start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET ,
. end = PXA168_U2O_REGBASE + USB_REG_RANGE ,
. flags = IORESOURCE_MEM ,
. name = " capregs " ,
} ,
/* phybase */
[ 1 ] = {
. start = PXA168_U2O_PHYBASE ,
. end = PXA168_U2O_PHYBASE + USB_PHY_RANGE ,
. flags = IORESOURCE_MEM ,
. name = " phyregs " ,
} ,
[ 2 ] = {
. start = IRQ_PXA168_USB1 ,
. end = IRQ_PXA168_USB1 ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
struct platform_device pxa168_device_u2oehci = {
. name = " pxa-u2oehci " ,
. id = - 1 ,
. dev = {
. dma_mask = & usb_dma_mask ,
. coherent_dma_mask = 0xffffffff ,
} ,
. num_resources = ARRAY_SIZE ( pxa168_u2oehci_resources ) ,
. resource = pxa168_u2oehci_resources ,
} ;
# endif
2014-03-12 18:29:22 +04:00
# if IS_ENABLED(CONFIG_USB_MV_OTG)
2012-05-03 10:19:13 +04:00
struct resource pxa168_u2ootg_resources [ ] = {
/* regbase */
[ 0 ] = {
. start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET ,
. end = PXA168_U2O_REGBASE + USB_REG_RANGE ,
. flags = IORESOURCE_MEM ,
. name = " capregs " ,
} ,
/* phybase */
[ 1 ] = {
. start = PXA168_U2O_PHYBASE ,
. end = PXA168_U2O_PHYBASE + USB_PHY_RANGE ,
. flags = IORESOURCE_MEM ,
. name = " phyregs " ,
} ,
[ 2 ] = {
. start = IRQ_PXA168_USB1 ,
. end = IRQ_PXA168_USB1 ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
struct platform_device pxa168_device_u2ootg = {
. name = " mv-otg " ,
. id = - 1 ,
. dev = {
. dma_mask = & usb_dma_mask ,
. coherent_dma_mask = 0xffffffff ,
} ,
. num_resources = ARRAY_SIZE ( pxa168_u2ootg_resources ) ,
. resource = pxa168_u2ootg_resources ,
} ;
# endif /* CONFIG_USB_MV_OTG */
# endif