summaryrefslogtreecommitdiff
path: root/drivers/staging
diff options
context:
space:
mode:
authorDavid Lin <dtwlin@google.com>2016-04-07 20:15:30 -0700
committerGreg Kroah-Hartman <gregkh@google.com>2016-04-07 21:37:59 -0700
commitddb10c8acc8554ffb68bdb6d80d0e277e124cb2b (patch)
tree93c3a6e93f4b5fbe6bdab7993c66863a77a55872 /drivers/staging
parent89de9a06213240b9266f9f368a867cf90d0024bf (diff)
greybus: svc: add Interface power measurements support
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>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/greybus/Documentation/sysfs-bus-greybus21
-rw-r--r--drivers/staging/greybus/greybus_protocols.h23
-rw-r--r--drivers/staging/greybus/interface.c60
-rw-r--r--drivers/staging/greybus/svc.c38
-rw-r--r--drivers/staging/greybus/svc.h2
5 files changed, 144 insertions, 0 deletions
diff --git a/drivers/staging/greybus/Documentation/sysfs-bus-greybus b/drivers/staging/greybus/Documentation/sysfs-bus-greybus
index 17b1a2919ef9..281b05cb889c 100644
--- a/drivers/staging/greybus/Documentation/sysfs-bus-greybus
+++ b/drivers/staging/greybus/Documentation/sysfs-bus-greybus
@@ -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)
diff --git a/drivers/staging/greybus/greybus_protocols.h b/drivers/staging/greybus/greybus_protocols.h
index 959ff1b7d8ce..e3ef3c96456d 100644
--- a/drivers/staging/greybus/greybus_protocols.h
+++ b/drivers/staging/greybus/greybus_protocols.h
@@ -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 */
diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c
index 27dbd79d2e19..a4bee41feec4 100644
--- a/drivers/staging/greybus/interface.c
+++ b/drivers/staging/greybus/interface.c
@@ -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);
diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c
index a19e575de029..b79d81717360 100644
--- a/drivers/staging/greybus/svc.c
+++ b/drivers/staging/greybus/svc.c
@@ -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,
diff --git a/drivers/staging/greybus/svc.h b/drivers/staging/greybus/svc.h
index 8950baff9aef..08f8e3705b43 100644
--- a/drivers/staging/greybus/svc.h
+++ b/drivers/staging/greybus/svc.h
@@ -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);