greybus: hd: arche-platform: implement greybus shutdown
authorDavid Lin <dtwlin@google.com>
Wed, 13 Jul 2016 00:41:21 +0000 (17:41 -0700)
committerGreg Kroah-Hartman <gregkh@google.com>
Fri, 15 Jul 2016 22:58:52 +0000 (07:58 +0900)
Implement platform driver shutdown callback to perform proper greybus
shutdown so that the userspace unipro_shutdown service that shuts down
the APB/SVC abruptly can be removed. The shutdown callback in
arche-platform will first remove SVC so that all the Interface can be
Deactivated in a sequence according to the spec before powering off the
APB:

Before:
 -> Arche/APB power off
 -> SoC power off

After this patch:
 -> HD shutdown
     -> SVC shutdown
         -> Module shutdown
             -> Interface shutdown
                 -> Bundle shutdown
 -> Arche/APB power off
 -> SoC power off

Testing Done:
 - Observe all Interfaces are deactivated in the log during shutdown
 - Measure power off current and make sure no regression

Signed-off-by: David Lin <dtwlin@google.com>
Reviewed-by: Vaibhav Hiremath <vaibhav.hiremath@linaro.org>
Reviewed-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/arche-apb-ctrl.c
drivers/staging/greybus/arche-platform.c
drivers/staging/greybus/core.c
drivers/staging/greybus/hd.c
drivers/staging/greybus/hd.h

index fce6a18..cae56fc 100644 (file)
@@ -444,6 +444,11 @@ static int arche_apb_ctrl_resume(struct device *dev)
        return 0;
 }
 
+static void arche_apb_ctrl_shutdown(struct platform_device *pdev)
+{
+       apb_ctrl_poweroff(&pdev->dev);
+}
+
 static SIMPLE_DEV_PM_OPS(arche_apb_ctrl_pm_ops, arche_apb_ctrl_suspend,
                         arche_apb_ctrl_resume);
 
@@ -455,6 +460,7 @@ static struct of_device_id arche_apb_ctrl_of_match[] = {
 static struct platform_driver arche_apb_ctrl_device_driver = {
        .probe          = arche_apb_ctrl_probe,
        .remove         = arche_apb_ctrl_remove,
+       .shutdown       = arche_apb_ctrl_shutdown,
        .driver         = {
                .name   = "arche-apb-ctrl",
                .pm     = &arche_apb_ctrl_pm_ops,
index 31c9524..af78420 100644 (file)
@@ -770,6 +770,15 @@ static int arche_platform_resume(struct device *dev)
        return 0;
 }
 
+static void arche_platform_shutdown(struct platform_device *pdev)
+{
+       struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
+
+       arche_platform_poweroff_seq(arche_pdata);
+
+       usb3613_hub_mode_ctrl(false);
+}
+
 static SIMPLE_DEV_PM_OPS(arche_platform_pm_ops,
                        arche_platform_suspend,
                        arche_platform_resume);
@@ -789,6 +798,7 @@ MODULE_DEVICE_TABLE(of, arche_combined_id);
 static struct platform_driver arche_platform_device_driver = {
        .probe          = arche_platform_probe,
        .remove         = arche_platform_remove,
+       .shutdown       = arche_platform_shutdown,
        .driver         = {
                .name   = "arche-platform-ctrl",
                .pm     = &arche_platform_pm_ops,
index 53d9ba1..2c94bbb 100644 (file)
@@ -146,10 +146,21 @@ static int greybus_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
+static void greybus_shutdown(struct device *dev)
+{
+       if (is_gb_host_device(dev)) {
+               struct gb_host_device *hd;
+
+               hd = to_gb_host_device(dev);
+               gb_hd_shutdown(hd);
+       }
+}
+
 struct bus_type greybus_bus_type = {
        .name =         "greybus",
        .match =        greybus_match_device,
        .uevent =       greybus_uevent,
+       .shutdown =     greybus_shutdown,
 };
 
 static int greybus_probe(struct device *dev)
index 8ef849a..185ae3f 100644 (file)
@@ -232,6 +232,12 @@ void gb_hd_del(struct gb_host_device *hd)
 }
 EXPORT_SYMBOL_GPL(gb_hd_del);
 
+void gb_hd_shutdown(struct gb_host_device *hd)
+{
+       gb_svc_del(hd->svc);
+}
+EXPORT_SYMBOL_GPL(gb_hd_shutdown);
+
 void gb_hd_put(struct gb_host_device *hd)
 {
        put_device(&hd->dev);
index d5d8c67..6ea5e28 100644 (file)
@@ -75,6 +75,7 @@ struct gb_host_device *gb_hd_create(struct gb_hd_driver *driver,
                                        size_t num_cports);
 int gb_hd_add(struct gb_host_device *hd);
 void gb_hd_del(struct gb_host_device *hd);
+void gb_hd_shutdown(struct gb_host_device *hd);
 void gb_hd_put(struct gb_host_device *hd);
 int gb_hd_output(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
                 bool in_irq);