Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ddb10c8a authored by David Lin's avatar David Lin Committed by Greg Kroah-Hartman
Browse files

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: default avatarDavid Lin <dtwlin@google.com>
Reviewed-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: default avatarBartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 89de9a06
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -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)
+23 −0
Original line number Diff line number Diff line
@@ -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 */
+60 −0
Original line number Diff line number Diff line
@@ -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);
+38 −0
Original line number Diff line number Diff line
@@ -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,
+2 −0
Original line number Diff line number Diff line
@@ -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);