summaryrefslogtreecommitdiff
path: root/drivers/staging/greybus/arche-apb-ctrl.c
diff options
context:
space:
mode:
authorVaibhav Hiremath <vaibhav.hiremath@linaro.org>2016-02-13 02:04:13 +0530
committerGreg Kroah-Hartman <gregkh@google.com>2016-02-15 13:18:40 -0800
commit33d76291073dd9408055a23cd96a23c375944377 (patch)
tree7c7275ecc58ca605ca4d27359c44b42651c1fdeb /drivers/staging/greybus/arche-apb-ctrl.c
parent6961e0466575608639e91ddbcc62d9385d45a198 (diff)
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.c115
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 8f6f0962421e..e4fd34ddf465 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);