Code still needs some reorganization which will come in later patches but we can already put omap3 in host mode by echo:ing sysfs node.
Signed-off-by: Felipe Balbi <[EMAIL PROTECTED]> --- drivers/i2c/chips/twl4030-usb.c | 111 ++++++++++++++++++++++++++++++++++++--- drivers/usb/musb/musb_core.h | 4 +- drivers/usb/musb/omap2430.c | 30 +++++++--- drivers/usb/musb/omap2430.h | 8 --- 4 files changed, 126 insertions(+), 27 deletions(-) diff --git a/drivers/i2c/chips/twl4030-usb.c b/drivers/i2c/chips/twl4030-usb.c index eca5aef..136e1c6 100644 --- a/drivers/i2c/chips/twl4030-usb.c +++ b/drivers/i2c/chips/twl4030-usb.c @@ -28,7 +28,11 @@ #include <linux/time.h> #include <linux/interrupt.h> #include <linux/usb.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> #include <linux/i2c/twl4030.h> +#include <asm/arch/usb.h> /* Register defines */ @@ -245,9 +249,28 @@ #define REG_PWR_SIH_CTRL 0x07 #define COR (1 << 2) +/* internal define on top of container_of */ +#define xceiv_to_twl(x) container_of((x), struct twl4030_usb, otg); + +/* bits in OTG_CTRL_REG */ + +#define OTG_XCEIV_OUTPUTS \ + (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID) +#define OTG_XCEIV_INPUTS \ + (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID) +#define OTG_CTRL_BITS \ + (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP) + /* and OTG_PULLUP is sometimes written */ + +#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \ + OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \ + OTG_CTRL_BITS) + + /*-------------------------------------------------------------------------*/ struct twl4030_usb { + struct otg_transceiver otg; int irq; u8 usb_mode; /* pin configuration */ #define T2_USB_MODE_ULPI 1 @@ -328,6 +351,7 @@ static inline int twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits) { return twl4030_usb_write(reg + 2, bits); + } /*-------------------------------------------------------------------------*/ @@ -472,8 +496,8 @@ static void usb_irq_disable(void) return; } -void twl4030_phy_suspend(int controller_off); -void twl4030_phy_resume(void); +static void twl4030_phy_suspend(int controller_off); +static void twl4030_phy_resume(void); static irqreturn_t twl4030_usb_irq(int irq, void *_twl) { @@ -565,7 +589,7 @@ static void twl4030_usb_ldo_init(struct twl4030_usb *twl) twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, PROTECT_KEY); } -void twl4030_phy_suspend(int controller_off) +static void twl4030_phy_suspend(int controller_off) { struct twl4030_usb *twl = the_transceiver; @@ -583,10 +607,8 @@ void twl4030_phy_suspend(int controller_off) twl->asleep = 1; return; } -EXPORT_SYMBOL(twl4030_phy_suspend); - -void twl4030_phy_resume(void) +static void twl4030_phy_resume(void) { struct twl4030_usb *twl = the_transceiver; @@ -604,8 +626,76 @@ void twl4030_phy_resume(void) twl->asleep = 0; return; } -EXPORT_SYMBOL(twl4030_phy_resume); +static int twl4030_set_suspend(struct otg_transceiver *x, int suspend) +{ + if (suspend) + twl4030_phy_suspend(1); + else + twl4030_phy_resume(); + + return 0; +} + +static int twl4030_set_peripheral(struct otg_transceiver *xceiv, struct usb_gadget *gadget) +{ + struct twl4030_usb *twl = xceiv_to_twl(xceiv); + + if (!xceiv) + return -ENODEV; + + if (!gadget) { + OTG_IRQ_EN_REG = 0; + twl4030_phy_suspend(1); + twl->otg.gadget = NULL; + + return -ENODEV; + } + + twl->otg.gadget = gadget; + twl4030_phy_resume(); + + OTG_CTRL_REG = (OTG_CTRL_REG & OTG_CTRL_MASK + & ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS)) + | OTG_ID; + + twl->otg.state = OTG_STATE_B_IDLE; + + twl4030_usb_set_bits(twl, USB_INT_EN_RISE, + USB_INT_SESSVALID | USB_INT_VBUSVALID); + twl4030_usb_set_bits(twl, USB_INT_EN_FALL, + USB_INT_SESSVALID | USB_INT_VBUSVALID); + + return 0; +} + +static int twl4030_set_host(struct otg_transceiver *xceiv, struct usb_bus *host) +{ + struct twl4030_usb *twl = xceiv_to_twl(xceiv); + + if (!xceiv) + return -ENODEV; + + if (!host) { + OTG_IRQ_EN_REG = 0; + twl4030_phy_suspend(1); + twl->otg.host = NULL; + + return -ENODEV; + } + + twl->otg.host = host; + twl4030_phy_resume(); + + twl4030_usb_set_bits(twl, OTG_CTRL, + OTG_CTRL_DMPULLDOWN | OTG_CTRL_DPPULLDOWN); + twl4030_usb_set_bits(twl, USB_INT_EN_RISE, USB_INT_IDGND); + twl4030_usb_set_bits(twl, USB_INT_EN_FALL, USB_INT_IDGND); + twl4030_usb_set_bits(twl, FUNC_CTRL, FUNC_CTRL_SUSPENDM); + twl4030_usb_set_bits(twl, OTG_CTRL, OTG_CTRL_DRVVBUS); + + return 0; +} static int __init twl4030_usb_init(void) { @@ -621,7 +711,10 @@ static int __init twl4030_usb_init(void) the_transceiver = twl; - twl->irq = TWL4030_MODIRQ_PWR; + twl->irq = TWL4030_MODIRQ_PWR; + twl->otg.set_host = twl4030_set_host; + twl->otg.set_peripheral = twl4030_set_peripheral; + twl->otg.set_suspend = twl4030_set_suspend; usb_irq_disable(); status = request_irq(twl->irq, twl4030_usb_irq, @@ -648,6 +741,8 @@ static int __init twl4030_usb_init(void) if (twl->usb_mode == T2_USB_MODE_ULPI) twl4030_phy_suspend(1); + otg_set_transceiver(&twl->otg); + printk(KERN_INFO "Initialized TWL4030 USB module"); return 0; diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index a76ed82..3494b99 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -476,6 +476,8 @@ extern void musb_platform_disable(struct musb *musb); extern void musb_hnp_stop(struct musb *musb); +extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode); + #if defined(CONFIG_USB_TUSB6010) || \ defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout); @@ -485,10 +487,8 @@ extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout); #ifdef CONFIG_USB_TUSB6010 extern int musb_platform_get_vbus_status(struct musb *musb); -extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode); #else #define musb_platform_get_vbus_status(x) 0 -#define musb_platform_set_mode(x, y) do {} while (0) #endif extern int __init musb_platform_init(struct musb *musb); diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index eacd6c4..caae81b 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -192,19 +192,31 @@ static int omap_set_power(struct otg_transceiver *x, unsigned mA) return 0; } -static int omap_set_suspend(struct otg_transceiver *x, int suspend) +int musb_platform_resume(struct musb *musb); + +void musb_platform_set_mode(struct musb *musb, u8 musb_mode) { - if (suspend) - twl4030_phy_suspend(1); - else - twl4030_phy_resume(); - return 0; -} + u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); -int musb_platform_resume(struct musb *musb); + devctl |= MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + + switch (musb_mode) { + case MUSB_HOST: + otg_set_host(&musb->xceiv, musb->xceiv.host); + break; + case MUSB_PERIPHERAL: + otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget); + break; + case MUSB_OTG: + break; + } +} int __init musb_platform_init(struct musb *musb) { + struct otg_transceiver *xceiv = otg_get_transceiver(); + #if defined(CONFIG_ARCH_OMAP2430) omap_cfg_reg(AE5_2430_USB0HS_STP); /* get the clock */ @@ -215,7 +227,7 @@ int __init musb_platform_init(struct musb *musb) if(IS_ERR(musb->clock)) return PTR_ERR(musb->clock); - musb->xceiv.set_suspend = omap_set_suspend; + musb->xceiv = *xceiv; musb_platform_resume(musb); OTG_INTERFSEL_REG |= ULPI_12PIN; diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h index e89d7bd..d036382 100644 --- a/drivers/usb/musb/omap2430.h +++ b/drivers/usb/musb/omap2430.h @@ -14,14 +14,6 @@ #include <asm/arch/hardware.h> #include <asm/arch/usb.h> -#if defined(CONFIG_TWL4030_USB_HS_ULPI) -extern void twl4030_phy_suspend(int controller_off); -extern void twl4030_phy_resume(void); -#else -#define twl4030_phy_suspend(x) do {} while (0) -#define twl4030_phy_resume() do {} while (0) -#endif - /* * OMAP2430-specific definitions */ -- 1.5.5.rc1.12.g660b9 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html