greybus: svc: add Interface power measurements support
authorDavid Lin <dtwlin@google.com>
Fri, 8 Apr 2016 03:15:30 +0000 (20:15 -0700)
committerGreg Kroah-Hartman <gregkh@google.com>
Fri, 8 Apr 2016 04:37:59 +0000 (21:37 -0700)
This change implements the AP Power Monitor functions for obtaining
current/voltage/power on a specific rail of an Interface.

Testing Done:

$ cat /sys/bus/greybus/devices/1-3/current_now
103
$ cat /sys/bus/greybus/devices/1-3/power_now
303
$ cat /sys/bus/greybus/devices/1-3/voltage_now
203

Signed-off-by: David Lin <dtwlin@google.com>
Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/Documentation/sysfs-bus-greybus
drivers/staging/greybus/greybus_protocols.h
drivers/staging/greybus/interface.c
drivers/staging/greybus/svc.c
drivers/staging/greybus/svc.h

index 17b1a29..281b05c 100644 (file)
@@ -164,3 +164,24 @@ Contact:   Greg Kroah-Hartman <greg@kroah.com>
 Description:
                If the SVC watchdog is enabled or not.  Writing 0 to this
                file will disable the watchdog, writing 1 will enable it.
+
+What:          /sys/bus/greybus/device/N-I/voltage_now
+Date:          March 2016
+KernelVersion: 4.XX
+Contact:       Greg Kroah-Hartman <greg@kroah.com>
+Description:
+               Voltage measurement of the interface in microvolts (uV)
+
+What:          /sys/bus/greybus/device/N-I/current_now
+Date:          March 2016
+KernelVersion: 4.XX
+Contact:       Greg Kroah-Hartman <greg@kroah.com>
+Description:
+               Current measurement of the interface in microamps (uA)
+
+What:          /sys/bus/greybus/device/N-I/power_now
+Date:          March 2016
+KernelVersion: 4.XX
+Contact:       Greg Kroah-Hartman <greg@kroah.com>
+Description:
+               Power measurement of the interface in microwatts (uW)
index 959ff1b..e3ef3c9 100644 (file)
@@ -798,6 +798,10 @@ struct gb_spi_transfer_response {
 #define GB_SVC_TYPE_INTF_EJECT                 0x11
 #define GB_SVC_TYPE_KEY_EVENT                  0x12
 #define GB_SVC_TYPE_PING                       0x13
+#define GB_SVC_TYPE_PWRMON_RAIL_COUNT_GET      0x14
+#define GB_SVC_TYPE_PWRMON_RAIL_NAMES_GET      0x15
+#define GB_SVC_TYPE_PWRMON_SAMPLE_GET          0x16
+#define GB_SVC_TYPE_PWRMON_INTF_SAMPLE_GET     0x17
 
 /*
  * SVC version request/response has the same payload as
@@ -963,6 +967,25 @@ struct gb_svc_key_event_request {
 #define GB_SVC_KEY_PRESSED     0x01
 } __packed;
 
+#define GB_SVC_PWRMON_TYPE_CURR                        0x01
+#define GB_SVC_PWRMON_TYPE_VOL                 0x02
+#define GB_SVC_PWRMON_TYPE_PWR                 0x03
+
+#define GB_SVC_PWRMON_GET_SAMPLE_OK            0x00
+#define GB_SVC_PWRMON_GET_SAMPLE_INVAL         0x01
+#define GB_SVC_PWRMON_GET_SAMPLE_NOSUPP                0x02
+#define GB_SVC_PWRMON_GET_SAMPLE_HWERR         0x03
+
+struct gb_svc_pwrmon_intf_sample_get_request {
+       __u8    intf_id;
+       __u8    measurement_type;
+} __packed;
+
+struct gb_svc_pwrmon_intf_sample_get_response {
+       __u8    result;
+       __le32  measurement;
+} __packed;
+
 /* RAW */
 
 /* Version of the Greybus raw protocol we support */
index 27dbd79..a4bee41 100644 (file)
@@ -263,6 +263,63 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RO(version);
 
+static ssize_t voltage_now_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct gb_interface *intf = to_gb_interface(dev);
+       int ret;
+       u32 measurement;
+
+       ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
+                                           GB_SVC_PWRMON_TYPE_VOL,
+                                           &measurement);
+       if (ret) {
+               dev_err(&intf->dev, "failed to get voltage sample (%d)\n", ret);
+               return ret;
+       }
+
+       return sprintf(buf, "%u\n", measurement);
+}
+static DEVICE_ATTR_RO(voltage_now);
+
+static ssize_t current_now_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct gb_interface *intf = to_gb_interface(dev);
+       int ret;
+       u32 measurement;
+
+       ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
+                                           GB_SVC_PWRMON_TYPE_CURR,
+                                           &measurement);
+       if (ret) {
+               dev_err(&intf->dev, "failed to get current sample (%d)\n", ret);
+               return ret;
+       }
+
+       return sprintf(buf, "%u\n", measurement);
+}
+static DEVICE_ATTR_RO(current_now);
+
+static ssize_t power_now_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct gb_interface *intf = to_gb_interface(dev);
+       int ret;
+       u32 measurement;
+
+       ret = gb_svc_pwrmon_intf_sample_get(intf->hd->svc, intf->interface_id,
+                                           GB_SVC_PWRMON_TYPE_PWR,
+                                           &measurement);
+       if (ret) {
+               dev_err(&intf->dev, "failed to get power sample (%d)\n", ret);
+               return ret;
+       }
+
+       return sprintf(buf, "%u\n", measurement);
+}
+static DEVICE_ATTR_RO(power_now);
+
 static struct attribute *interface_attrs[] = {
        &dev_attr_ddbl1_manufacturer_id.attr,
        &dev_attr_ddbl1_product_id.attr,
@@ -273,6 +330,9 @@ static struct attribute *interface_attrs[] = {
        &dev_attr_product_string.attr,
        &dev_attr_serial_number.attr,
        &dev_attr_version.attr,
+       &dev_attr_voltage_now.attr,
+       &dev_attr_current_now.attr,
+       &dev_attr_power_now.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(interface);
index a19e575..b79d817 100644 (file)
@@ -99,6 +99,44 @@ static ssize_t watchdog_store(struct device *dev,
 }
 static DEVICE_ATTR_RW(watchdog);
 
+int gb_svc_pwrmon_intf_sample_get(struct gb_svc *svc, u8 intf_id,
+                                 u8 measurement_type, u32 *value)
+{
+       struct gb_svc_pwrmon_intf_sample_get_request request;
+       struct gb_svc_pwrmon_intf_sample_get_response response;
+       int ret;
+
+       request.intf_id = intf_id;
+       request.measurement_type = measurement_type;
+
+       ret = gb_operation_sync(svc->connection,
+                               GB_SVC_TYPE_PWRMON_INTF_SAMPLE_GET,
+                               &request, sizeof(request),
+                               &response, sizeof(response));
+       if (ret) {
+               dev_err(&svc->dev, "failed to get intf sample (%d)\n", ret);
+               return ret;
+       }
+
+       if (response.result) {
+               dev_err(&svc->dev,
+                       "UniPro error while getting intf power sample (%d %d): %d\n",
+                       intf_id, measurement_type, response.result);
+               switch (response.result) {
+               case GB_SVC_PWRMON_GET_SAMPLE_INVAL:
+                       return -EINVAL;
+               case GB_SVC_PWRMON_GET_SAMPLE_NOSUPP:
+                       return -ENOSYS;
+               default:
+                       return -EIO;
+               }
+       }
+
+       *value = le32_to_cpu(response.measurement);
+
+       return 0;
+}
+
 static struct attribute *svc_attrs[] = {
        &dev_attr_endo_id.attr,
        &dev_attr_ap_intf_id.attr,
index 8950baf..08f8e37 100644 (file)
@@ -48,6 +48,8 @@ int gb_svc_add(struct gb_svc *svc);
 void gb_svc_del(struct gb_svc *svc);
 void gb_svc_put(struct gb_svc *svc);
 
+int gb_svc_pwrmon_intf_sample_get(struct gb_svc *svc, u8 intf_id,
+                                 u8 measurement_type, u32 *value);
 int gb_svc_intf_device_id(struct gb_svc *svc, u8 intf_id, u8 device_id);
 int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
                               u8 intf2_id, u8 dev2_id);