From 1f77b363bef417e28d8556a11c9a82f3e6cf24f0 Mon Sep 17 00:00:00 2001 From: David Lin Date: Tue, 12 Jul 2016 17:41:21 -0700 Subject: [PATCH] greybus: hd: arche-platform: implement greybus shutdown 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 Reviewed-by: Vaibhav Hiremath Reviewed-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/arche-apb-ctrl.c | 6 ++++++ drivers/staging/greybus/arche-platform.c | 10 ++++++++++ drivers/staging/greybus/core.c | 11 +++++++++++ drivers/staging/greybus/hd.c | 6 ++++++ drivers/staging/greybus/hd.h | 1 + 5 files changed, 34 insertions(+) diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c index fce6a187ecfe..cae56fc0a6e5 100644 --- a/drivers/staging/greybus/arche-apb-ctrl.c +++ b/drivers/staging/greybus/arche-apb-ctrl.c @@ -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, diff --git a/drivers/staging/greybus/arche-platform.c b/drivers/staging/greybus/arche-platform.c index 31c952454cff..af784204973f 100644 --- a/drivers/staging/greybus/arche-platform.c +++ b/drivers/staging/greybus/arche-platform.c @@ -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, diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 53d9ba151aeb..2c94bbb1748f 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -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) diff --git a/drivers/staging/greybus/hd.c b/drivers/staging/greybus/hd.c index 8ef849a8300f..185ae3fa10fd 100644 --- a/drivers/staging/greybus/hd.c +++ b/drivers/staging/greybus/hd.c @@ -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); diff --git a/drivers/staging/greybus/hd.h b/drivers/staging/greybus/hd.h index d5d8c67551f2..6ea5e28d9eb9 100644 --- a/drivers/staging/greybus/hd.h +++ b/drivers/staging/greybus/hd.h @@ -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);