From 93e29c8530881766837e62088d54ffb733f8bc2a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 20 Jul 2016 16:40:25 +0200 Subject: [PATCH] greybus: interface: add power_state attribute 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 CC: David Lin Reviewed-by: Johan Hovold [johan: drop es3-quirk duplication, add to power attribute group, fix return value, drop tags ] Signed-off-by: Johan Hovold Reviewed-by: Alex Elder Reviewed-by: Viresh Kumar Reviewed-by: Sandeep Patil Reviewed-by: Patrick Titiano Signed-off-by: Greg Kroah-Hartman --- .../greybus/Documentation/sysfs-bus-greybus | 17 ++++++ drivers/staging/greybus/interface.c | 58 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/drivers/staging/greybus/Documentation/sysfs-bus-greybus b/drivers/staging/greybus/Documentation/sysfs-bus-greybus index 721010e22b25..62d03afe9c85 100644 --- a/drivers/staging/greybus/Documentation/sysfs-bus-greybus +++ b/drivers/staging/greybus/Documentation/sysfs-bus-greybus @@ -97,6 +97,23 @@ Contact: Greg Kroah-Hartman 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 +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 diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c index 3ad1c757d7e7..f5ed79c687d2 100644 --- a/drivers/staging/greybus/interface.c +++ b/drivers/staging/greybus/interface.c @@ -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 };