From: David Brownell Date: Fri, 8 Sep 2006 07:48:43 +0000 (+0300) Subject: MUSB: PM cleanup X-Git-Tag: v2.6.18-omap1~82 X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=88d7747b05ede027f8be94a316db275b28b3c705;p=linux-2.6-omap-h63xx.git 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: David Brownell --- diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index f6297cbc824..c1652124ebb 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -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); } diff --git a/drivers/usb/musb/musbdefs.h b/drivers/usb/musb/musbdefs.h index 032357d9648..a4512a62c06 100644 --- a/drivers/usb/musb/musbdefs.h +++ b/drivers/usb/musb/musbdefs.h @@ -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; diff --git a/drivers/usb/musb/plat_uds.c b/drivers/usb/musb/plat_uds.c index 2fb0d530375..919fd0c0a8d 100644 --- a/drivers/usb/musb/plat_uds.c +++ b/drivers/usb/musb/plat_uds.c @@ -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 */ diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 2b35d40f29a..9f145e5c165 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -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); diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h index e59d6eed37a..cf30f89a00b 100644 --- a/drivers/usb/musb/tusb6010.h +++ b/drivers/usb/musb/tusb6010.h @@ -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) diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h index a451c2f022f..e7d942b8bd3 100644 --- a/include/linux/usb/musb.h +++ b/include/linux/usb/musb.h @@ -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;