diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/chrome/cros_ec_dev.c | 37 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_ec_dev.h | 6 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_ec_lightbar.c | 85 |
3 files changed, 125 insertions, 3 deletions
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c index 20ce1c23fb5c..7c2622319211 100644 --- a/drivers/platform/chrome/cros_ec_dev.c +++ b/drivers/platform/chrome/cros_ec_dev.c @@ -21,6 +21,7 @@ #include <linux/mfd/core.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm.h> #include <linux/slab.h> #include <linux/uaccess.h> @@ -435,6 +436,10 @@ static int ec_device_probe(struct platform_device *pdev) if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) cros_ec_sensors_register(ec); + /* Take control of the lightbar from the EC. */ + if (ec_has_lightbar(ec)) + lb_manual_suspend_ctrl(ec, 1); + return 0; failed: @@ -446,6 +451,10 @@ static int ec_device_remove(struct platform_device *pdev) { struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); + /* Let the EC take over the lightbar again. */ + if (ec_has_lightbar(ec)) + lb_manual_suspend_ctrl(ec, 0); + cros_ec_debugfs_remove(ec); cdev_del(&ec->cdev); @@ -459,9 +468,37 @@ static const struct platform_device_id cros_ec_id[] = { }; MODULE_DEVICE_TABLE(platform, cros_ec_id); +static int ec_device_suspend(struct device *dev) +{ + struct cros_ec_dev *ec = dev_get_drvdata(dev); + + if (ec_has_lightbar(ec)) + lb_suspend(ec); + + return 0; +} + +static int ec_device_resume(struct device *dev) +{ + struct cros_ec_dev *ec = dev_get_drvdata(dev); + + if (ec_has_lightbar(ec)) + lb_resume(ec); + + return 0; +} + +static const struct dev_pm_ops cros_ec_dev_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = ec_device_suspend, + .resume = ec_device_resume, +#endif +}; + static struct platform_driver cros_ec_dev_driver = { .driver = { .name = "cros-ec-ctl", + .pm = &cros_ec_dev_pm_ops, }, .probe = ec_device_probe, .remove = ec_device_remove, diff --git a/drivers/platform/chrome/cros_ec_dev.h b/drivers/platform/chrome/cros_ec_dev.h index bfd2c84c3571..45e9453608c5 100644 --- a/drivers/platform/chrome/cros_ec_dev.h +++ b/drivers/platform/chrome/cros_ec_dev.h @@ -43,4 +43,10 @@ struct cros_ec_readmem { #define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command) #define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem) +/* Lightbar utilities */ +extern bool ec_has_lightbar(struct cros_ec_dev *ec); +extern int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable); +extern int lb_suspend(struct cros_ec_dev *ec); +extern int lb_resume(struct cros_ec_dev *ec); + #endif /* _CROS_EC_DEV_H_ */ diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index 26675059707e..4df379dc4bb9 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -341,6 +341,80 @@ exit: return ret; } +static int lb_send_empty_cmd(struct cros_ec_dev *ec, uint8_t cmd) +{ + struct ec_params_lightbar *param; + struct cros_ec_command *msg; + int ret; + + msg = alloc_lightbar_cmd_msg(ec); + if (!msg) + return -ENOMEM; + + param = (struct ec_params_lightbar *)msg->data; + param->cmd = cmd; + + ret = lb_throttle(); + if (ret) + goto error; + + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); + if (ret < 0) + goto error; + if (msg->result != EC_RES_SUCCESS) { + ret = -EINVAL; + goto error; + } + ret = 0; +error: + kfree(msg); + + return ret; +} + +int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable) +{ + struct ec_params_lightbar *param; + struct cros_ec_command *msg; + int ret; + + msg = alloc_lightbar_cmd_msg(ec); + if (!msg) + return -ENOMEM; + + param = (struct ec_params_lightbar *)msg->data; + + param->cmd = LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL; + param->manual_suspend_ctrl.enable = enable; + + ret = lb_throttle(); + if (ret) + goto error; + + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); + if (ret < 0) + goto error; + if (msg->result != EC_RES_SUCCESS) { + ret = -EINVAL; + goto error; + } + ret = 0; +error: + kfree(msg); + + return ret; +} + +int lb_suspend(struct cros_ec_dev *ec) +{ + return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND); +} + +int lb_resume(struct cros_ec_dev *ec) +{ + return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME); +} + static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -473,6 +547,11 @@ static struct attribute *__lb_cmds_attrs[] = { NULL, }; +bool ec_has_lightbar(struct cros_ec_dev *ec) +{ + return !!get_lightbar_version(ec, NULL, NULL); +} + static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj, struct attribute *a, int n) { @@ -489,10 +568,10 @@ static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj, return 0; /* Only instantiate this stuff if the EC has a lightbar */ - if (get_lightbar_version(ec, NULL, NULL)) + if (ec_has_lightbar(ec)) return a->mode; - else - return 0; + + return 0; } struct attribute_group cros_ec_lightbar_attr_group = { |