Commit 88d7747b authored by David Brownell's avatar David Brownell Committed by Tony Lindgren

MUSB: PM cleanup

Second pass over TUSB power related code:

  - Add new field in board-specific platform data, giving a nonzero floor to
    the amount of VBUS power that peripherals could draw; pass that to the
    platform code.

  - Implement the call letting gadget drivers say how much VBUS power their
    current configuration may draw, and use that to initialize appropriately
    (pure-peripheral vs OTG modes) on USB reset and disconnect.

  - Provide TUSB-specific hook into OTG transceiver logic to support that
    VBUS call; and _only_ change the VBUS usage through that call.

  - Remove obsolete comment and bitmask declarations.

On one board I measured 36 mA (at 5.1V) coming from VBUS not the battery
using the default gadget drivers in non-OTG TUSB configuration.
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
parent 32655109
......@@ -1513,6 +1513,15 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
}
#endif
static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
struct musb *musb = gadget_to_musb(gadget);
if (!musb->xceiv.set_power)
return -EOPNOTSUPP;
return otg_set_power(&musb->xceiv, mA);
}
static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
{
struct musb *musb = gadget_to_musb(gadget);
......@@ -1537,7 +1546,7 @@ static const struct usb_gadget_ops musb_gadget_operations = {
.wakeup = musb_gadget_wakeup,
.set_selfpowered = musb_gadget_set_self_powered,
//.vbus_session = musb_gadget_vbus_session,
//.vbus_draw = musb_gadget_vbus_draw,
.vbus_draw = musb_gadget_vbus_draw,
.pullup = musb_gadget_pullup,
};
......@@ -1925,6 +1934,9 @@ void musb_g_disconnect(struct musb *pThis)
{
DBG(3, "devctl %02x\n", musb_readb(pThis->pRegs, MGC_O_HDRC_DEVCTL));
/* don't draw vbus until new b-default session */
(void) musb_gadget_vbus_draw(&pThis->g, 0);
pThis->g.speed = USB_SPEED_UNKNOWN;
if (pThis->pGadgetDriver && pThis->pGadgetDriver->disconnect) {
spin_unlock(&pThis->Lock);
......@@ -2002,4 +2014,8 @@ __acquires(pThis->Lock)
pThis->g.is_a_peripheral = 1;
} else
WARN_ON(1);
/* start with default limits on VBUS power draw */
(void) musb_gadget_vbus_draw(&pThis->g,
is_otg_enabled(pThis) ? 8 : 100);
}
......@@ -448,6 +448,8 @@ struct musb {
s8 bFailCode; /* one of MUSB_ERR_* failure code */
u8 min_power; /* vbus for periph, in mA/2 */
/* active means connected and not suspended */
unsigned is_active:1;
......
......@@ -1601,6 +1601,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
spin_lock_init(&pThis->Lock);
pThis->board_mode = plat->mode;
pThis->board_set_power = plat->set_power;
pThis->min_power = plat->min_power;
/* assume vbus is off */
......
......@@ -143,23 +143,36 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
}
}
/*
* Enables TUSB6010 to use VBUS as power source in peripheral mode.
* In host mode, a local battery must power the TUSB chip as well as
* (through the charge pump) VBUS. For OTG peripherals, the battery
* must power the chip until it enters a confguration that's allowed
* to draw enough current (call it 100mA).
/* This is used by gadget drivers, and OTG transceiver logic, allowing
* at most mA current to be drawn from VBUS during a Default-B session
* (that is, while VBUS exceeds 4.4V). In Default-A (including pure host
* mode), or low power Default-B sessions, something else supplies power.
*/
static inline void tusb_enable_vbus_charge(struct musb *musb)
static int tusb_set_power(struct otg_transceiver *x, unsigned mA)
{
struct musb *musb = container_of(x, struct musb, xceiv);
void __iomem *base = musb->ctrl_base;
u32 reg;
musb_writel(base, TUSB_PRCM_WAKEUP_MASK, 0xffff);
/* tps65030 seems to consume max 100mA, with maybe 60mA available
* (measured on one board) for things other than tps and tusb.
*
* REVISIT we could use VBUS to supply only _one_ of { 1.5V, 3.3V }.
* The actual current usage would be very board-specific. For now,
* it's simpler to just use an aggregate (also board-specific).
*/
if (x->default_a || mA < (musb->min_power << 1))
mA = 0;
reg = musb_readl(base, TUSB_PRCM_MNGMT);
reg &= ~TUSB_PRCM_MNGMT_SUSPEND_MASK;
reg |= TUSB_PRCM_MNGMT_CPEN_MASK;
if (mA)
reg |= TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN;
else
reg &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
musb_writel(base, TUSB_PRCM_MNGMT, reg);
DBG(3, "draw max %d mA VBUS\n", mA);
return 0;
}
/* workaround for issue 13: change clock during chip idle
......@@ -184,7 +197,7 @@ void tusb_set_clock_source(struct musb *musb, int mode)
* Idle TUSB6010 until next wake-up event; NOR access always wakes.
* Other code ensures that we idle unless we're connected _and_ the
* USB link is not suspended ... and tells us the relevant wakeup
* events.
* events. SW_EN for voltage is handled separately.
*/
static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
{
......@@ -197,9 +210,7 @@ static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
musb_writel(base, TUSB_PRCM_WAKEUP_MASK, ~wakeup_enables);
reg = musb_readl(base, TUSB_PRCM_MNGMT);
reg &= ~( TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN
| TUSB_PRCM_MNGMT_15_SW_EN
| TUSB_PRCM_MNGMT_33_SW_EN );
reg &= ~TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN; /* REVISIT leave alone? */
reg |= TUSB_PRCM_MNGMT_OTG_SESS_END_EN
| TUSB_PRCM_MNGMT_PM_IDLE
| TUSB_PRCM_MNGMT_DEV_IDLE;
......@@ -318,12 +329,6 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *base)
/* no vbus ~= disconnect */
if (!is_host_enabled(musb) || !musb->xceiv.default_a) {
/* REVISIT in B-Default state machine, use VBUS power
* for the USB link when (a) non-OTG, since 100 mA is
* always available; or (b) OTG after SET_CONFIGURATION
* enabling 100+ (?) mA draw.
*/
/* REVISIT use the b_sess_valid comparator, not
* lowpower one; TUSB_DEV_OTG_STAT_SESS_VALID ?
*/
......@@ -671,6 +676,7 @@ int __devinit musb_platform_init(struct musb *musb)
return -ENODEV;
}
musb->isr = tusb_interrupt;
musb->xceiv.set_power = tusb_set_power;
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
......
......@@ -104,20 +104,6 @@
#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1)
#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0)
#define TUSB_PRCM_MNGMT_PM_CLEAR_MASK \
( TUSB_PRCM_MNGMT_15_SW_EN \
| TUSB_PRCM_MNGMT_33_SW_EN \
| TUSB_PRCM_MNGMT_PM_IDLE \
| TUSB_PRCM_MNGMT_DEV_IDLE )
#define TUSB_PRCM_MNGMT_CPEN_MASK \
( TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN \
| TUSB_PRCM_MNGMT_15_SW_EN \
| TUSB_PRCM_MNGMT_33_SW_EN )
#define TUSB_PRCM_MNGMT_SUSPEND_MASK \
( TUSB_PRCM_MNGMT_OTG_SESS_END_EN \
| TUSB_PRCM_MNGMT_PM_IDLE \
| TUSB_PRCM_MNGMT_DEV_IDLE )
/* Wake-up source clear and mask registers */
#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020)
#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028)
......
......@@ -27,6 +27,9 @@ struct musb_hdrc_platform_data {
/* (HOST or OTG) mA/2 power supplied on (default = 8mA) */
u8 power;
/* (PERIPHERAL) mA/2 max power consumed (default = 100mA) */
u8 min_power;
/* (HOST or OTG) msec/2 after VBUS on till power good */
u8 potpgt;
......
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