summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus
diff options
context:
space:
mode:
authorJohan Hovold <johan@hovoldconsulting.com>2016-04-23 18:47:29 +0200
committerGreg Kroah-Hartman <gregkh@google.com>2016-04-25 11:08:30 -0700
commitec562f28a7de6a4a4c3f790e5cfb5e61e97419b5 (patch)
tree717f36fb8e60aa2c468a2e9a9e5982132da4e9fb /drivers/staging/greybus
parent1e8e22b5cb462e9c4da9c988b3355565cdef1d34 (diff)
greybus: interface: implement interface activation and power down
Implement the interface activation and power-down sequences. Note that all the required SVC operations have not yet been implemented so some stub functions are used for now. Support for hibernating the UniPro link depends on future power-management work so a stub function is used also for this. Interface type handling will be refined later. Signed-off-by: Johan Hovold <johan@hovoldconsulting.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus')
-rw-r--r--drivers/staging/greybus/interface.c124
1 files changed, 122 insertions, 2 deletions
diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c
index e0c38f158435..f6c058a63fa2 100644
--- a/drivers/staging/greybus/interface.c
+++ b/drivers/staging/greybus/interface.c
@@ -389,6 +389,95 @@ struct gb_interface *gb_interface_create(struct gb_module *module,
return intf;
}
+static int gb_interface_vsys_set(struct gb_interface *intf, bool enable)
+{
+ struct gb_svc *svc = intf->hd->svc;
+ int ret;
+
+ dev_dbg(&intf->dev, "%s - %d\n", __func__, enable);
+
+ ret = gb_svc_intf_vsys_set(svc, intf->interface_id, enable);
+ if (ret) {
+ dev_err(&intf->dev, "failed to enable v_sys: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int gb_interface_refclk_set(struct gb_interface *intf, bool enable)
+{
+ struct gb_svc *svc = intf->hd->svc;
+ int ret;
+
+ dev_dbg(&intf->dev, "%s - %d\n", __func__, enable);
+
+ ret = gb_svc_intf_refclk_set(svc, intf->interface_id, enable);
+ if (ret) {
+ dev_err(&intf->dev, "failed to enable refclk: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int gb_interface_unipro_set(struct gb_interface *intf, bool enable)
+{
+ struct gb_svc *svc = intf->hd->svc;
+ int ret;
+
+ dev_dbg(&intf->dev, "%s - %d\n", __func__, enable);
+
+ ret = gb_svc_intf_unipro_set(svc, intf->interface_id, enable);
+ if (ret) {
+ dev_err(&intf->dev, "failed to enable UniPro: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int gb_interface_activate_operation(struct gb_interface *intf)
+{
+ struct gb_svc *svc = intf->hd->svc;
+ u8 type;
+ int ret;
+
+ dev_dbg(&intf->dev, "%s\n", __func__);
+
+ ret = gb_svc_intf_activate(svc, intf->interface_id, &type);
+ if (ret) {
+ dev_err(&intf->dev, "failed to activate: %d\n", ret);
+ return ret;
+ }
+
+ switch (type) {
+ case GB_SVC_INTF_TYPE_DUMMY:
+ dev_info(&intf->dev, "dummy interface detected\n");
+ /* FIXME: handle as an error for now */
+ return -ENODEV;
+ case GB_SVC_INTF_TYPE_UNIPRO:
+ dev_err(&intf->dev, "interface type UniPro not supported\n");
+ return -ENODEV;
+ case GB_SVC_INTF_TYPE_GREYBUS:
+ break;
+ default:
+ dev_err(&intf->dev, "unknown interface type: %u\n", type);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int gb_interface_hibernate_link(struct gb_interface *intf)
+{
+ dev_dbg(&intf->dev, "%s\n", __func__);
+
+ /* FIXME: implement */
+
+ return 0;
+}
+
/*
* Activate an interface.
*
@@ -401,17 +490,44 @@ int gb_interface_activate(struct gb_interface *intf)
if (intf->ejected)
return -ENODEV;
- ret = gb_interface_read_dme(intf);
+ ret = gb_interface_vsys_set(intf, true);
if (ret)
return ret;
+ ret = gb_interface_refclk_set(intf, true);
+ if (ret)
+ goto err_vsys_disable;
+
+ ret = gb_interface_unipro_set(intf, true);
+ if (ret)
+ goto err_refclk_disable;
+
+ ret = gb_interface_activate_operation(intf);
+ if (ret)
+ goto err_unipro_disable;
+
+ ret = gb_interface_read_dme(intf);
+ if (ret)
+ goto err_hibernate_link;
+
ret = gb_interface_route_create(intf);
if (ret)
- return ret;
+ goto err_hibernate_link;
intf->active = true;
return 0;
+
+err_hibernate_link:
+ gb_interface_hibernate_link(intf);
+err_unipro_disable:
+ gb_interface_unipro_set(intf, false);
+err_refclk_disable:
+ gb_interface_refclk_set(intf, false);
+err_vsys_disable:
+ gb_interface_vsys_set(intf, false);
+
+ return ret;
}
/*
@@ -425,6 +541,10 @@ void gb_interface_deactivate(struct gb_interface *intf)
return;
gb_interface_route_destroy(intf);
+ gb_interface_hibernate_link(intf);
+ gb_interface_unipro_set(intf, false);
+ gb_interface_refclk_set(intf, false);
+ gb_interface_vsys_set(intf, false);
intf->active = false;
}