diff options
author | Vaibhav Hiremath <vaibhav.hiremath@linaro.org> | 2016-02-13 02:04:13 +0530 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@google.com> | 2016-02-15 13:18:40 -0800 |
commit | 33d76291073dd9408055a23cd96a23c375944377 (patch) | |
tree | 7c7275ecc58ca605ca4d27359c44b42651c1fdeb /drivers/staging/greybus/arche-apb-ctrl.c | |
parent | 6961e0466575608639e91ddbcc62d9385d45a198 (diff) | |
download | op-kernel-dev-33d76291073dd9408055a23cd96a23c375944377.zip op-kernel-dev-33d76291073dd9408055a23cd96a23c375944377.tar.gz |
greybus: arche-apb-ctrl: Add sysfs to allow user to change state
This patch introduces sysfs interface for the user space to enable
state change of the driver. Driver supports below operational
states,
- off
- active
- standby
- fw_flashing
To see the current state
i # cat /sys/devices/arche_platform.*/apb*/state
And to change the state
# echo [off/active/standby/fw_flashing] > /sys/devices/arche_platform.*/apb*/state
Testing Done: Tested on EVT1.2 and DB3.5 platform
Signed-off-by: Vaibhav Hiremath <vaibhav.hiremath@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/arche-apb-ctrl.c')
-rw-r--r-- | drivers/staging/greybus/arche-apb-ctrl.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c index 8f6f096..e4fd34d 100644 --- a/drivers/staging/greybus/arche-apb-ctrl.c +++ b/drivers/staging/greybus/arche-apb-ctrl.c @@ -113,6 +113,52 @@ static int apb_ctrl_coldboot_seq(struct platform_device *pdev) return 0; } +static int apb_ctrl_fw_flashing_seq(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); + int ret; + + ret = regulator_enable(apb->vcore); + if (ret) { + dev_err(dev, "failed to enable core regulator\n"); + return ret; + } + + ret = regulator_enable(apb->vio); + if (ret) { + dev_err(dev, "failed to enable IO regulator\n"); + return ret; + } + + /* for flashing device should be in reset state */ + assert_reset(apb->resetn_gpio); + apb->state = ARCHE_PLATFORM_STATE_FW_FLASHING; + + return 0; +} + +static int apb_ctrl_standby_boot_seq(struct platform_device *pdev) +{ + struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); + + /* If it is in OFF state, then we do not want to change the state */ + if (apb->state == ARCHE_PLATFORM_STATE_OFF) + return 0; + + /* + * As per WDM spec, do nothing + * + * Pasted from WDM spec, + * - A falling edge on POWEROFF_L is detected (a) + * - WDM enters standby mode, but no output signals are changed + * */ + + /* TODO: POWEROFF_L is input to WDM module */ + apb->state = ARCHE_PLATFORM_STATE_STANDBY; + return 0; +} + static void apb_ctrl_poweroff_seq(struct platform_device *pdev) { struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); @@ -134,6 +180,66 @@ static void apb_ctrl_poweroff_seq(struct platform_device *pdev) /* TODO: May have to send an event to SVC about this exit */ } +static ssize_t state_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); + int ret = 0; + + if (sysfs_streq(buf, "off")) { + if (apb->state == ARCHE_PLATFORM_STATE_OFF) + return count; + + apb_ctrl_poweroff_seq(pdev); + } else if (sysfs_streq(buf, "active")) { + if (apb->state == ARCHE_PLATFORM_STATE_ACTIVE) + return count; + + apb_ctrl_poweroff_seq(pdev); + ret = apb_ctrl_coldboot_seq(pdev); + } else if (sysfs_streq(buf, "standby")) { + if (apb->state == ARCHE_PLATFORM_STATE_STANDBY) + return count; + + ret = apb_ctrl_standby_boot_seq(pdev); + } else if (sysfs_streq(buf, "fw_flashing")) { + if (apb->state == ARCHE_PLATFORM_STATE_FW_FLASHING) + return count; + + /* First we want to make sure we power off everything + * and then enter FW flashing state */ + apb_ctrl_poweroff_seq(pdev); + ret = apb_ctrl_fw_flashing_seq(pdev); + } else { + dev_err(dev, "unknown state\n"); + ret = -EINVAL; + } + + return ret ? ret : count; +} + +static ssize_t state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct arche_apb_ctrl_drvdata *apb = dev_get_drvdata(dev); + + switch (apb->state) { + case ARCHE_PLATFORM_STATE_OFF: + return sprintf(buf, "off\n"); + case ARCHE_PLATFORM_STATE_ACTIVE: + return sprintf(buf, "active\n"); + case ARCHE_PLATFORM_STATE_STANDBY: + return sprintf(buf, "standby\n"); + case ARCHE_PLATFORM_STATE_FW_FLASHING: + return sprintf(buf, "fw_flashing\n"); + default: + return sprintf(buf, "unknown state\n"); + } +} + +static DEVICE_ATTR_RW(state); + static int apb_ctrl_get_devtree_data(struct platform_device *pdev, struct arche_apb_ctrl_drvdata *apb) { @@ -243,10 +349,18 @@ int arche_apb_ctrl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, apb); + /* Create sysfs interface to allow user to change state dynamically */ + ret = device_create_file(dev, &dev_attr_state); + if (ret) { + dev_err(dev, "failed to create state file in sysfs\n"); + return ret; + } + ret = apb_ctrl_coldboot_seq(pdev); if (ret) { dev_err(dev, "failed to set init state of control signal %d\n", ret); + device_remove_file(dev, &dev_attr_state); platform_set_drvdata(pdev, NULL); return ret; } @@ -261,6 +375,7 @@ int arche_apb_ctrl_remove(struct platform_device *pdev) { struct arche_apb_ctrl_drvdata *apb = platform_get_drvdata(pdev); + device_remove_file(&pdev->dev, &dev_attr_state); apb_ctrl_poweroff_seq(pdev); platform_set_drvdata(pdev, NULL); unexport_gpios(apb); |