2011-01-03 12:33:01 +03:00
/*
* Copyright ( c ) 2009 Daniel Mack < daniel @ caiaq . de >
* Copyright ( C ) 2010 Freescale Semiconductor , Inc .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
*/
# include <linux/platform_device.h>
# include <linux/io.h>
2012-08-24 17:14:29 +04:00
# include <linux/platform_data/usb-ehci-mxc.h>
2011-01-03 12:33:01 +03:00
2012-09-14 10:14:45 +04:00
# include "hardware.h"
2011-01-03 12:33:01 +03:00
# define MXC_OTG_OFFSET 0
# define MXC_H1_OFFSET 0x200
# define MXC_H2_OFFSET 0x400
/* USB_CTRL */
# define MXC_OTG_UCTRL_OWIE_BIT (1 << 27) /* OTG wakeup intr enable */
# define MXC_OTG_UCTRL_OPM_BIT (1 << 24) /* OTG power mask */
# define MXC_H1_UCTRL_H1UIE_BIT (1 << 12) /* Host1 ULPI interrupt enable */
# define MXC_H1_UCTRL_H1WIE_BIT (1 << 11) /* HOST1 wakeup intr enable */
2012-06-28 18:59:23 +04:00
# define MXC_H1_UCTRL_H1PM_BIT (1 << 8) /* HOST1 power mask */
2011-01-03 12:33:01 +03:00
/* USB_PHY_CTRL_FUNC */
2012-06-28 18:59:23 +04:00
# define MXC_OTG_PHYCTRL_OC_POL_BIT (1 << 9) /* OTG Polarity of Overcurrent */
2011-01-03 12:33:01 +03:00
# define MXC_OTG_PHYCTRL_OC_DIS_BIT (1 << 8) /* OTG Disable Overcurrent Event */
2012-06-28 18:59:23 +04:00
# define MXC_H1_OC_POL_BIT (1 << 6) /* UH1 Polarity of Overcurrent */
2011-01-03 12:33:01 +03:00
# define MXC_H1_OC_DIS_BIT (1 << 5) /* UH1 Disable Overcurrent Event */
2012-06-28 18:59:23 +04:00
# define MXC_OTG_PHYCTRL_PWR_POL_BIT (1 << 3) /* OTG Power Pin Polarity */
2011-01-03 12:33:01 +03:00
/* USBH2CTRL */
# define MXC_H2_UCTRL_H2UIE_BIT (1 << 8)
# define MXC_H2_UCTRL_H2WIE_BIT (1 << 7)
# define MXC_H2_UCTRL_H2PM_BIT (1 << 4)
# define MXC_USBCMD_OFFSET 0x140
/* USBCMD */
# define MXC_UCMD_ITC_NO_THRESHOLD_MASK (~(0xff << 16)) /* Interrupt Threshold Control */
int mx51_initialize_usb_hw ( int port , unsigned int flags )
{
unsigned int v ;
void __iomem * usb_base ;
void __iomem * usbotg_base ;
void __iomem * usbother_base ;
int ret = 0 ;
2011-07-31 01:41:49 +04:00
usb_base = ioremap ( MX51_USB_OTG_BASE_ADDR , SZ_4K ) ;
2011-01-03 12:33:01 +03:00
if ( ! usb_base ) {
printk ( KERN_ERR " %s(): ioremap failed \n " , __func__ ) ;
return - ENOMEM ;
}
switch ( port ) {
case 0 : /* OTG port */
usbotg_base = usb_base + MXC_OTG_OFFSET ;
break ;
case 1 : /* Host 1 port */
usbotg_base = usb_base + MXC_H1_OFFSET ;
break ;
case 2 : /* Host 2 port */
usbotg_base = usb_base + MXC_H2_OFFSET ;
break ;
default :
printk ( KERN_ERR " %s no such port %d \n " , __func__ , port ) ;
ret = - ENOENT ;
goto error ;
}
usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET ;
switch ( port ) {
case 0 : /*OTG port */
if ( flags & MXC_EHCI_INTERNAL_PHY ) {
v = __raw_readl ( usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET ) ;
2012-06-28 18:59:23 +04:00
if ( flags & MXC_EHCI_OC_PIN_ACTIVE_LOW )
v | = MXC_OTG_PHYCTRL_OC_POL_BIT ;
else
v & = ~ MXC_OTG_PHYCTRL_OC_POL_BIT ;
2011-01-03 12:33:01 +03:00
if ( flags & MXC_EHCI_POWER_PINS_ENABLED ) {
/* OC/USBPWR is used */
v & = ~ MXC_OTG_PHYCTRL_OC_DIS_BIT ;
2012-06-28 18:59:46 +04:00
} else {
/* OC/USBPWR is not used */
v | = MXC_OTG_PHYCTRL_OC_DIS_BIT ;
2011-01-03 12:33:01 +03:00
}
2012-06-28 18:59:23 +04:00
if ( flags & MXC_EHCI_PWR_PIN_ACTIVE_HIGH )
v | = MXC_OTG_PHYCTRL_PWR_POL_BIT ;
else
v & = ~ MXC_OTG_PHYCTRL_PWR_POL_BIT ;
2011-01-03 12:33:01 +03:00
__raw_writel ( v , usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET ) ;
v = __raw_readl ( usbother_base + MXC_USBCTRL_OFFSET ) ;
if ( flags & MXC_EHCI_WAKEUP_ENABLED )
v | = MXC_OTG_UCTRL_OWIE_BIT ; /* OTG wakeup enable */
else
v & = ~ MXC_OTG_UCTRL_OWIE_BIT ; /* OTG wakeup disable */
if ( flags & MXC_EHCI_POWER_PINS_ENABLED )
v & = ~ MXC_OTG_UCTRL_OPM_BIT ;
2012-06-28 18:59:46 +04:00
else
v | = MXC_OTG_UCTRL_OPM_BIT ;
2011-01-03 12:33:01 +03:00
__raw_writel ( v , usbother_base + MXC_USBCTRL_OFFSET ) ;
}
break ;
case 1 : /* Host 1 */
/*Host ULPI */
v = __raw_readl ( usbother_base + MXC_USBCTRL_OFFSET ) ;
if ( flags & MXC_EHCI_WAKEUP_ENABLED ) {
/* HOST1 wakeup/ULPI intr enable */
v | = ( MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT ) ;
} else {
/* HOST1 wakeup/ULPI intr disable */
v & = ~ ( MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT ) ;
}
if ( flags & MXC_EHCI_POWER_PINS_ENABLED )
2012-06-28 18:59:46 +04:00
v & = ~ MXC_H1_UCTRL_H1PM_BIT ; /* HOST1 power mask unused*/
2011-01-03 12:33:01 +03:00
else
v | = MXC_H1_UCTRL_H1PM_BIT ; /* HOST1 power mask used*/
__raw_writel ( v , usbother_base + MXC_USBCTRL_OFFSET ) ;
v = __raw_readl ( usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET ) ;
2012-06-28 18:59:23 +04:00
if ( flags & MXC_EHCI_OC_PIN_ACTIVE_LOW )
v | = MXC_H1_OC_POL_BIT ;
else
v & = ~ MXC_H1_OC_POL_BIT ;
2011-01-03 12:33:01 +03:00
if ( flags & MXC_EHCI_POWER_PINS_ENABLED )
v & = ~ MXC_H1_OC_DIS_BIT ; /* OC is used */
else
v | = MXC_H1_OC_DIS_BIT ; /* OC is not used */
__raw_writel ( v , usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET ) ;
v = __raw_readl ( usbotg_base + MXC_USBCMD_OFFSET ) ;
if ( flags & MXC_EHCI_ITC_NO_THRESHOLD )
/* Interrupt Threshold Control:Immediate (no threshold) */
v & = MXC_UCMD_ITC_NO_THRESHOLD_MASK ;
__raw_writel ( v , usbotg_base + MXC_USBCMD_OFFSET ) ;
break ;
case 2 : /* Host 2 ULPI */
v = __raw_readl ( usbother_base + MXC_USBH2CTRL_OFFSET ) ;
if ( flags & MXC_EHCI_WAKEUP_ENABLED ) {
/* HOST1 wakeup/ULPI intr enable */
v | = ( MXC_H2_UCTRL_H2WIE_BIT | MXC_H2_UCTRL_H2UIE_BIT ) ;
} else {
/* HOST1 wakeup/ULPI intr disable */
v & = ~ ( MXC_H2_UCTRL_H2WIE_BIT | MXC_H2_UCTRL_H2UIE_BIT ) ;
}
if ( flags & MXC_EHCI_POWER_PINS_ENABLED )
2012-06-28 18:59:46 +04:00
v & = ~ MXC_H2_UCTRL_H2PM_BIT ; /* HOST2 power mask unused*/
2011-01-03 12:33:01 +03:00
else
v | = MXC_H2_UCTRL_H2PM_BIT ; /* HOST2 power mask used*/
__raw_writel ( v , usbother_base + MXC_USBH2CTRL_OFFSET ) ;
break ;
}
error :
iounmap ( usb_base ) ;
return ret ;
}