greybus: interface: add power_state attribute
authorViresh Kumar <viresh.kumar@linaro.org>
Wed, 20 Jul 2016 14:40:25 +0000 (16:40 +0200)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 20 Jul 2016 17:16:54 +0000 (10:16 -0700)
User space needs the capability of powering ON or OFF an Interface for
multiple use cases. For example, userspace may want an Interface
currently in its S3 boot stage, to boot into its S2 Loader stage to
update the bridge SPI flash. Or the Interface is running its S2 Loader
stage and updated the SPI flash with the new S2 Loader firmware and
wants to boot into the new S2 Loader firmware.

Another use case can be, Android wants to disable (not eject) a
misbehaving module.

Add a 'power_state' sysfs file within the interface directory. It can be
read to know the current power state of the Interface and can be written
to power ON or power OFF an Interface. Possible values that can be
written or read from it are: "on" and "off".

Testing Done: Tested by enabling/disabling camera module on EVT 2.0.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
CC: David Lin <dtwlin@google.com>
Reviewed-by: Johan Hovold <johan@hovoldconsulting.com>
[johan: drop es3-quirk duplication, add to power attribute group, fix
return value, drop tags ]
Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Reviewed-by: Alex Elder <elder@linaro.org>
Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Sandeep Patil <sspatil@google.com>
Reviewed-by: Patrick Titiano <ptitiano@baylibre.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/Documentation/sysfs-bus-greybus
drivers/staging/greybus/interface.c

index 721010e..62d03af 100644 (file)
@@ -97,6 +97,23 @@ Contact:     Greg Kroah-Hartman <greg@kroah.com>
 Description:
                Power measurement of the interface in microwatts (uW)
 
+What:          /sys/bus/greybus/devices/N-M.I/power_state
+Date:          March 2016
+KernelVersion: 4.XX
+Contact:       Greg Kroah-Hartman <greg@kroah.com>
+Description:
+               This reflects the power state of a Greybus Interface. If the
+               value read from it is "on", then power is currently supplied to
+               the Interface. Otherwise this will read "off" and the power is
+               currently not supplied to the Interface.
+
+               If the value read is "off", then writing "on" (or '1', 'y',
+               'Y') to it will enable power to the Interface. If the value
+               read is "on", then writing "off" (or '0', 'n', 'N') to it will
+               disable power to the Interface.
+
+               Writing the currently read value to it has no effect.
+
 What:          /sys/bus/greybus/devices/N-M.I/product_id
 Date:          October 2015
 KernelVersion: 4.XX
index 3ad1c75..f5ed79c 100644 (file)
@@ -501,6 +501,63 @@ static ssize_t power_now_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(power_now);
 
+static ssize_t power_state_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct gb_interface *intf = to_gb_interface(dev);
+
+       if (intf->active)
+               return scnprintf(buf, PAGE_SIZE, "on\n");
+       else
+               return scnprintf(buf, PAGE_SIZE, "off\n");
+}
+
+static ssize_t power_state_store(struct device *dev,
+                                struct device_attribute *attr, const char *buf,
+                                size_t len)
+{
+       struct gb_interface *intf = to_gb_interface(dev);
+       bool activate;
+       int ret = 0;
+
+       if (kstrtobool(buf, &activate))
+               return -EINVAL;
+
+       mutex_lock(&intf->mutex);
+
+       if (activate == intf->active)
+               goto unlock;
+
+       if (activate) {
+               ret = gb_interface_activate(intf);
+               if (ret) {
+                       dev_err(&intf->dev,
+                               "failed to activate interface: %d\n", ret);
+                       goto unlock;
+               }
+
+               ret = gb_interface_enable(intf);
+               if (ret) {
+                       dev_err(&intf->dev,
+                               "failed to enable interface: %d\n", ret);
+                       gb_interface_deactivate(intf);
+                       goto unlock;
+               }
+       } else {
+               gb_interface_disable(intf);
+               gb_interface_deactivate(intf);
+       }
+
+unlock:
+       mutex_unlock(&intf->mutex);
+
+       if (ret)
+               return ret;
+
+       return len;
+}
+static DEVICE_ATTR_RW(power_state);
+
 static const char *gb_interface_type_string(struct gb_interface *intf)
 {
        static const char * const types[] = {
@@ -541,6 +598,7 @@ static struct attribute *interface_power_attrs[] = {
        &dev_attr_voltage_now.attr,
        &dev_attr_current_now.attr,
        &dev_attr_power_now.attr,
+       &dev_attr_power_state.attr,
        NULL
 };