@@ -184,6 +184,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
int irq;
int i;
char supply[7];
+ struct port_power_domain *ppd;
if (usb_disabled())
return -ENODEV;
@@ -220,6 +221,17 @@ static int ehci_hcd_omap_probe(struct
platform_device *pdev)
goto err_io;
}
+ /*
+ * register usb per port power domain and enable power on
+ * this port, to which only hardwired and self-powered device
+ * attached. And the platform code should provide the
+ * port power domain list to the usb host controller driver.
+ */
+ list_for_each_entry(ppd, &pdata->port_power_domain, list) {
+ usb_register_port_pm_domain(&hcd->self, ppd);
+ usb_enable_port_pm_domain(&hcd->self, ppd);
+ }
+
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
hcd->regs = regs;
@@ -289,6 +301,12 @@ static int ehci_hcd_omap_remove(struct
platform_device *pdev)
struct device *dev = &pdev->dev;
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_hcd_omap_platform_data *pdata = dev->platform_data;
+ struct port_power_domain *ppd;
+
+ list_for_each_entry(ppd, &pdata->port_power_domain, list) {
+ usb_disable_port_pm_domain(&hcd->self, ppd);
+ usb_unregister_port_pm_domain(&hcd->self, ppd);
+ }
usb_remove_hcd(hcd);
disable_put_regulator(dev->platform_data);
b/include/linux/platform_data/usb-omap.h
@@ -47,6 +47,8 @@ struct ehci_hcd_omap_platform_data {
int reset_gpio_port[OMAP3_HS_USB_PORTS];
struct regulator *regulator[OMAP3_HS_USB_PORTS];
unsigned phy_reset:1;
+
+ struct list_head port_power_domain;
};
struct ohci_hcd_omap_platform_data {
@@ -448,6 +448,39 @@ extern void usb_disconnect(struct usb_device **);
extern int usb_get_configuration(struct usb_device *dev);
extern void usb_destroy_configuration(struct usb_device *dev);
+/*
+ * Only used for describing power domain which provide power to
+ * hardwired self-powered devices
+ */
+struct port_power_domain {
+ struct list_head list;
+ struct usb_bus *bus;
+
+ /*
+ * physical port path, and the power domain of 'port_power' provides
+ * power on the device attatched to the last non-zero port(Pn-1) of
+ * the n-1 tier hub, the first number(P1) is the root hub port in
+ * the path, and the second number(P2) is the port number on the
+ * second tier hub, ..., until the last number Pn which is zero always.
+ */
+ char port_path[32]; /* P1-P2-..Pn-1-Pn */
+
+ /*
+ * struct power_domain should be generic power thing, and should be
+ * defined in device power core, maybe it can reuse some kind of
+ * current power domain structure.
+ *
+ * Many ports can share one same power domain, so make the below field
+ * as pointer.
+ */
+ struct power_domain *port_power;
+};
+
+extern int usb_register_port_pm_domain(struct usb_bus *bus, struct
port_power_domain *ppd);
+extern int usb_unregister_port_pm_domain(struct usb_bus *bus, struct
port_power_domain *ppd);
+extern int usb_enable_port_pm_domain(struct usb_bus *bus, struct
port_power_domain *ppd);
+extern int usb_disable_port_pm_domain(struct usb_bus *bus, struct
port_power_domain *ppd);