USB PowerShare is a policy which affects charging via the special USB PowerShare port (marked with a small lightning bolt or battery icon) when in low power states: - In S0, the port will always provide power. - In S0ix, if power_share is enabled, then power will be supplied to the port when on AC or if battery is > 50%. Else no power is supplied. - In S5, if power_share is enabled, then power will be supplied to the port when on AC. Else no power is supplied.
Signed-off-by: Nick Crews <ncr...@chromium.org> --- drivers/platform/chrome/wilco_ec/Makefile | 2 +- drivers/platform/chrome/wilco_ec/core.c | 9 ++ drivers/platform/chrome/wilco_ec/sysfs.c | 129 ++++++++++++++++++++++ include/linux/platform_data/wilco-ec.h | 3 + 4 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 drivers/platform/chrome/wilco_ec/sysfs.c diff --git a/drivers/platform/chrome/wilco_ec/Makefile b/drivers/platform/chrome/wilco_ec/Makefile index 063e7fb4ea17..1281dd7737c4 100644 --- a/drivers/platform/chrome/wilco_ec/Makefile +++ b/drivers/platform/chrome/wilco_ec/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -wilco_ec-objs := core.o mailbox.o +wilco_ec-objs := core.o mailbox.o sysfs.o obj-$(CONFIG_WILCO_EC) += wilco_ec.o wilco_ec_debugfs-objs := debugfs.o obj-$(CONFIG_WILCO_EC_DEBUGFS) += wilco_ec_debugfs.o diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c index 05e1e2be1c91..abd15d04e57b 100644 --- a/drivers/platform/chrome/wilco_ec/core.c +++ b/drivers/platform/chrome/wilco_ec/core.c @@ -89,8 +89,16 @@ static int wilco_ec_probe(struct platform_device *pdev) goto unregister_debugfs; } + ret = wilco_ec_add_sysfs(ec); + if (ret < 0) { + dev_err(dev, "Failed to create sysfs entries: %d", ret); + goto unregister_rtc; + } + return 0; +unregister_rtc: + platform_device_unregister(ec->rtc_pdev); unregister_debugfs: if (ec->debugfs_pdev) platform_device_unregister(ec->debugfs_pdev); @@ -102,6 +110,7 @@ static int wilco_ec_remove(struct platform_device *pdev) { struct wilco_ec_device *ec = platform_get_drvdata(pdev); + wilco_ec_remove_sysfs(ec); platform_device_unregister(ec->rtc_pdev); if (ec->debugfs_pdev) platform_device_unregister(ec->debugfs_pdev); diff --git a/drivers/platform/chrome/wilco_ec/sysfs.c b/drivers/platform/chrome/wilco_ec/sysfs.c new file mode 100644 index 000000000000..ec5211257a58 --- /dev/null +++ b/drivers/platform/chrome/wilco_ec/sysfs.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + * + * Sysfs properties used to modify EC-controlled features on Wilco devices. + * The entries will appear under /sys/bus/platform/devices/GOOG000C:00/ + * + * USB PowerShare is a policy which affects charging via the special + * USB PowerShare port (marked with a small lightning bolt or battery icon) + * when in low power states: + * - In S0, the port will always provide power. + * - In S0ix, if power_share is enabled, then power will be supplied to + * the port when on AC or if battery is > 50%. Else no power is supplied. + * - In S5, if power_share is enabled, then power will be supplied to + * the port when on AC. Else no power is supplied. + */ + +#include <linux/platform_data/wilco-ec.h> +#include <linux/sysfs.h> + +#define CMD_USB_POWER_SHARE 0x39 + +enum usb_power_share_op { + POWER_SHARE_GET = 0, + POWER_SHARE_SET = 1, +}; + +struct usb_power_share_request { + u8 cmd; /* Always CMD_USB_POWER_SHARE */ + u8 reserved; + u8 op; /* One of enum usb_power_share_op */ + u8 val; /* When setting, either 0 or 1 */ +} __packed; + +struct usb_power_share_response { + u8 reserved; + u8 status; /* Set by EC to 0 on success, other value on failure */ + u8 val; /* When getting, set by EC to either 0 or 1 */ +} __packed; + +static int send_usb_power_share(struct wilco_ec_device *ec, + struct usb_power_share_request *rq, + struct usb_power_share_response *rs) +{ + struct wilco_ec_message msg; + int ret; + + memset(&msg, 0, sizeof(msg)); + msg.type = WILCO_EC_MSG_LEGACY; + msg.request_data = rq; + msg.request_size = sizeof(*rq); + msg.response_data = rs; + msg.response_size = sizeof(*rs); + ret = wilco_ec_mailbox(ec, &msg); + if (ret < 0) + return ret; + + if (rs->status) + return -EIO; + + return 0; +} + +static ssize_t usb_power_share_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct wilco_ec_device *ec = dev_get_drvdata(dev); + struct usb_power_share_request rq; + struct usb_power_share_response rs; + int ret; + + rq.cmd = CMD_USB_POWER_SHARE; + rq.op = POWER_SHARE_GET; + + ret = send_usb_power_share(ec, &rq, &rs); + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", rs.val); +} + +static ssize_t usb_power_share_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wilco_ec_device *ec = dev_get_drvdata(dev); + struct usb_power_share_request rq; + struct usb_power_share_response rs; + int ret; + u8 val; + + ret = kstrtou8(buf, 10, &val); + if (ret < 0) + return ret; + + if (val != 0 && val != 1) + return -EINVAL; + + rq.cmd = CMD_USB_POWER_SHARE; + rq.op = POWER_SHARE_SET; + rq.val = val; + + ret = send_usb_power_share(ec, &rq, &rs); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR_RW(usb_power_share); + +static struct attribute *wilco_dev_attrs[] = { + &dev_attr_usb_power_share.attr, + NULL, +}; + +static struct attribute_group wilco_dev_attr_group = { + .attrs = wilco_dev_attrs, +}; + +int wilco_ec_add_sysfs(struct wilco_ec_device *ec) +{ + return sysfs_create_group(&ec->dev->kobj, &wilco_dev_attr_group); +} + +void wilco_ec_remove_sysfs(struct wilco_ec_device *ec) +{ + sysfs_create_group(&ec->dev->kobj, &wilco_dev_attr_group); +} diff --git a/include/linux/platform_data/wilco-ec.h b/include/linux/platform_data/wilco-ec.h index 1ff224793c99..05d011605b85 100644 --- a/include/linux/platform_data/wilco-ec.h +++ b/include/linux/platform_data/wilco-ec.h @@ -123,4 +123,7 @@ struct wilco_ec_message { */ int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg); +int wilco_ec_add_sysfs(struct wilco_ec_device *ec); +void wilco_ec_remove_sysfs(struct wilco_ec_device *ec); + #endif /* WILCO_EC_H */ -- 2.20.1