Commit e45917ba authored by Felipe Balbi's avatar Felipe Balbi Committed by Tony Lindgren

I2C: TWL4030: Make twl4030-usb.c initialize otg_transceiver

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: default avatarFelipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent c43cc5a7
......@@ -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)
{
......@@ -622,6 +712,9 @@ static int __init twl4030_usb_init(void)
the_transceiver = twl;
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;
......
......@@ -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);
......
......@@ -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;
......
......@@ -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
*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment