usb: dwc3-msm: Set PROP_BOOST_CURRENT for direct attach devices

If PMIC provides boost power for VBUS in host mode, it may
need to know the amount of current of an attached device
in order to optimize for overall power consumption. We can
pass the bMaxPower obtained from a device's configuration
descriptor when it is attached. This only affects devices
(including hubs) directly attached to the root port, as
any device downstream of a hub will either consume part of
the hub's budget or has external power.

Change-Id: I1ad2cfecb7a2f6bdeaced29a1753cdc1bf3849db
Signed-off-by: Jack Pham <jackp@codeaurora.org>
This commit is contained in:
Jack Pham 2016-12-07 19:25:02 -08:00
parent a5dea1fbd6
commit 7d34e07588

View file

@ -210,6 +210,8 @@ struct dwc3_msm {
struct notifier_block vbus_nb;
struct notifier_block id_nb;
struct notifier_block host_nb;
int pwr_event_irq;
atomic_t in_p3;
unsigned int lpm_to_suspend_delay;
@ -3023,6 +3025,53 @@ static int dwc3_msm_remove(struct platform_device *pdev)
return 0;
}
static int dwc3_msm_host_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, host_nb);
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
struct usb_device *udev = ptr;
union power_supply_propval pval;
unsigned max_power;
if (event != USB_DEVICE_ADD && event != USB_DEVICE_REMOVE)
return NOTIFY_DONE;
if (!mdwc->usb_psy) {
mdwc->usb_psy = power_supply_get_by_name("usb");
if (!mdwc->usb_psy)
return NOTIFY_DONE;
}
/*
* For direct-attach devices, new udev is direct child of root hub
* i.e. dwc -> xhci -> root_hub -> udev
* root_hub's udev->parent==NULL, so traverse struct device hierarchy
*/
if (udev->parent && !udev->parent->parent &&
udev->dev.parent->parent == &dwc->xhci->dev) {
if (event == USB_DEVICE_ADD && udev->actconfig) {
if (udev->speed >= USB_SPEED_SUPER)
max_power = udev->actconfig->desc.bMaxPower * 8;
else
max_power = udev->actconfig->desc.bMaxPower * 2;
dev_dbg(mdwc->dev, "%s configured bMaxPower:%d (mA)\n",
dev_name(&udev->dev), max_power);
/* inform PMIC of max power so it can optimize boost */
pval.intval = max_power * 1000;
power_supply_set_property(mdwc->usb_psy,
POWER_SUPPLY_PROP_BOOST_CURRENT, &pval);
} else {
pval.intval = 0;
power_supply_set_property(mdwc->usb_psy,
POWER_SUPPLY_PROP_BOOST_CURRENT, &pval);
}
}
return NOTIFY_DONE;
}
#define VBUS_REG_CHECK_DELAY (msecs_to_jiffies(1000))
/**
@ -3083,6 +3132,9 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
mdwc->host_nb.notifier_call = dwc3_msm_host_notifier;
usb_register_notify(&mdwc->host_nb);
/*
* FIXME If micro A cable is disconnected during system suspend,
* xhci platform device will be removed before runtime pm is
@ -3103,6 +3155,7 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
pm_runtime_put_sync(mdwc->dev);
dbg_event(0xFF, "pdeverr psync",
atomic_read(&mdwc->dev->power.usage_count));
usb_unregister_notify(&mdwc->host_nb);
return ret;
}
@ -3139,6 +3192,7 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
mdwc->hs_phy->flags &= ~PHY_HOST_MODE;
mdwc->ss_phy->flags &= ~PHY_HOST_MODE;
platform_device_del(dwc->xhci);
usb_unregister_notify(&mdwc->host_nb);
/*
* Perform USB hardware RESET (both core reset and DBM reset)