greybus: arche_platform: Add sysfs to allow user to change state
authorVaibhav Hiremath <vaibhav.hiremath@linaro.org>
Fri, 12 Feb 2016 20:34:07 +0000 (02:04 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Mon, 15 Feb 2016 21:18:40 +0000 (13:18 -0800)
This patch introduces sysfs interface for the user space to enable
operational state change of the driver.
Currently, driver supports, 'off', 'active' and 'standby'

Note that, driver doesn't do anything for standby state as of today.

To see the current state

      # cat /sys/devices/arche_platform.*/state

And to change the state
      # echo [off/active/standby] > /sys/devices/arche_platform.*/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>
drivers/staging/greybus/arche-platform.c

index b2f3919..1dd2b08 100644 (file)
@@ -148,6 +148,55 @@ static void arche_platform_poweroff_seq(struct arche_platform_drvdata *arche_pda
        arche_pdata->state = ARCHE_PLATFORM_STATE_OFF;
 }
 
+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_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
+       int ret = 0;
+
+       if (sysfs_streq(buf, "off")) {
+               if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF)
+                       return count;
+
+               arche_platform_poweroff_seq(arche_pdata);
+       } else if (sysfs_streq(buf, "active")) {
+               if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE)
+                       return count;
+
+               ret = arche_platform_coldboot_seq(arche_pdata);
+       } else if (sysfs_streq(buf, "standby")) {
+               if (arche_pdata->state == ARCHE_PLATFORM_STATE_STANDBY)
+                       return count;
+
+               dev_warn(arche_pdata->dev, "standby state not supported\n");
+       } else {
+               dev_err(arche_pdata->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_platform_drvdata *arche_pdata = dev_get_drvdata(dev);
+
+       switch (arche_pdata->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");
+       default:
+               return sprintf(buf, "unknown state\n");
+       }
+}
+
+static DEVICE_ATTR_RW(state);
+
 static int arche_platform_probe(struct platform_device *pdev)
 {
        struct arche_platform_drvdata *arche_pdata;
@@ -248,6 +297,12 @@ static int arche_platform_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&arche_pdata->delayed_work, svc_delayed_work);
        schedule_delayed_work(&arche_pdata->delayed_work, msecs_to_jiffies(2000));
 
+       ret = device_create_file(dev, &dev_attr_state);
+       if (ret) {
+               dev_err(dev, "failed to create state file in sysfs\n");
+               return ret;
+       }
+
        ret = arche_platform_coldboot_seq(arche_pdata);
        if (ret) {
                dev_err(dev, "Failed to cold boot svc %d\n", ret);
@@ -273,6 +328,7 @@ static int arche_platform_remove(struct platform_device *pdev)
 {
        struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
 
+       device_remove_file(&pdev->dev, &dev_attr_state);
        cancel_delayed_work_sync(&arche_pdata->delayed_work);
        device_for_each_child(&pdev->dev, NULL, arche_remove_child);
        arche_platform_poweroff_seq(arche_pdata);