On Wed, Nov 28, 2012 at 7:06 AM, Ming Lei <tom.leim...@gmail.com> wrote:
>>> Also from my intuition, power domain should be involved in the problem,
>>> because these hard-wired and self-powered USB devices should have
>>> its own power domains, and the ehci-omap driver may enable/disable
>>> these power domains before adding the bus.
>>
>>
>> I don't know enough to have an opinion, but the arrangement on Panda is
>> literally a linear regulator is being controlled by a gpio, which fits into
>> struct regulator model.  What else would a power domain for that buy us?
>
> One problem is that you are addressing to, another is that we may extend
> Tianyu's per port power off/on mechanism into non-acpi world.
>
> Considered that our discussion has been extended to general case instead
> of pandaboard only, there might be several bus devices which have different
> power control method, which should be the idea of power domain.
>
> I have a draft idea and let me describe it by a pseudo_patch, see below:

Sorry, looks sending it too quick, the below pseudo_patch may be
more readable about the idea.

diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index ac17a7c..c187a11 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -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);
diff --git a/include/linux/platform_data/usb-omap.h
b/include/linux/platform_data/usb-omap.h
index 8570bcf..30516c9 100644
--- a/include/linux/platform_data/usb-omap.h
+++ 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 {
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 608050b..6b86d01 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -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);
+
 /*-------------------------------------------------------------------------*/

 /*


Thanks,
-- 
Ming Lei
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to