diff options
author | Johan Hovold <johan@hovoldconsulting.com> | 2016-04-23 18:47:29 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@google.com> | 2016-04-25 11:08:30 -0700 |
commit | ec562f28a7de6a4a4c3f790e5cfb5e61e97419b5 (patch) | |
tree | 717f36fb8e60aa2c468a2e9a9e5982132da4e9fb /drivers/staging/greybus | |
parent | 1e8e22b5cb462e9c4da9c988b3355565cdef1d34 (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.c | 124 |
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; } |