linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Guenter Roeck <groeck@google.com>
To: Thierry Escande <thierry.escande@collabora.com>
Cc: Lee Jones <lee.jones@linaro.org>,
	Benson Leung <bleung@chromium.org>,
	Enric Balletbo i Serra <enric.balletbo@collabora.com>,
	Gwendal Grignou <gwendal@chromium.org>,
	linux-kernel <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd
Date: Thu, 30 Nov 2017 12:50:12 -0800	[thread overview]
Message-ID: <CABXOdTczmg1Atp4nP8vFizvygH=M76gx7J=S3yTXqyC6L1S4sA@mail.gmail.com> (raw)
In-Reply-To: <1511194526-3729-3-git-send-email-thierry.escande@collabora.com>

On Mon, Nov 20, 2017 at 8:15 AM, Thierry Escande
<thierry.escande@collabora.com> wrote:
> The cros_ec_dev module is responsible for registering the MFD devices
> attached to the ChromeOS EC. This patch moves this module to drivers/mfd
> so calls to mfd_add_devices() are not done from outside the MFD subtree
> anymore.
>
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>

Tested-by: Guenter Roeck <groeck@chromium.org>

> ---
>  drivers/mfd/Kconfig                        |  10 +
>  drivers/mfd/Makefile                       |   1 +
>  drivers/mfd/cros_ec_dev.c                  | 552 ++++++++++++++++++++++++++++
>  drivers/mfd/cros_ec_dev.h                  |  52 +++
>  drivers/platform/chrome/Kconfig            |  10 -
>  drivers/platform/chrome/Makefile           |   1 -
>  drivers/platform/chrome/cros_ec_debugfs.c  |   3 -
>  drivers/platform/chrome/cros_ec_debugfs.h  |  27 --
>  drivers/platform/chrome/cros_ec_dev.c      | 553 -----------------------------
>  drivers/platform/chrome/cros_ec_dev.h      |  52 ---
>  drivers/platform/chrome/cros_ec_lightbar.c |   2 -
>  drivers/platform/chrome/cros_ec_sysfs.c    |   2 -
>  include/linux/mfd/cros_ec.h                |   4 +
>  13 files changed, 619 insertions(+), 650 deletions(-)
>  create mode 100644 drivers/mfd/cros_ec_dev.c
>  create mode 100644 drivers/mfd/cros_ec_dev.h
>  delete mode 100644 drivers/platform/chrome/cros_ec_debugfs.h
>  delete mode 100644 drivers/platform/chrome/cros_ec_dev.c
>  delete mode 100644 drivers/platform/chrome/cros_ec_dev.h
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 1d20a80..538a2ae 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -222,6 +222,16 @@ config MFD_CROS_EC_SPI
>           response time cannot be guaranteed, we support ignoring
>           'pre-amble' bytes before the response actually starts.
>
> +config MFD_CROS_EC_CHARDEV
> +        tristate "Chrome OS Embedded Controller userspace device interface"
> +        depends on MFD_CROS_EC
> +        select CROS_EC_CTL
> +        ---help---
> +          This driver adds support to talk with the ChromeOS EC from userspace.
> +
> +          If you have a supported Chromebook, choose Y or M here.
> +          The module will be called cros_ec_dev.
> +
>  config MFD_ASIC3
>         bool "Compaq ASIC3"
>         depends on GPIOLIB && ARM
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index d9474ad..fcd8af8 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -17,6 +17,7 @@ cros_ec_core-$(CONFIG_ACPI)   += cros_ec_acpi_gpe.o
>  obj-$(CONFIG_MFD_CROS_EC)      += cros_ec_core.o
>  obj-$(CONFIG_MFD_CROS_EC_I2C)  += cros_ec_i2c.o
>  obj-$(CONFIG_MFD_CROS_EC_SPI)  += cros_ec_spi.o
> +obj-$(CONFIG_MFD_CROS_EC_CHARDEV) += cros_ec_dev.o
>  obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
>
>  rtsx_pci-objs                  := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
> diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c
> new file mode 100644
> index 0000000..e4fafdd
> --- /dev/null
> +++ b/drivers/mfd/cros_ec_dev.c
> @@ -0,0 +1,552 @@
> +/*
> + * cros_ec_dev - expose the Chrome OS Embedded Controller to user-space
> + *
> + * Copyright (C) 2014 Google, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/fs.h>
> +#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>
> +
> +#include "cros_ec_dev.h"
> +
> +#define DRV_NAME "cros-ec-dev"
> +
> +/* Device variables */
> +#define CROS_MAX_DEV 128
> +static int ec_major;
> +
> +static const struct attribute_group *cros_ec_groups[] = {
> +       &cros_ec_attr_group,
> +       &cros_ec_lightbar_attr_group,
> +       &cros_ec_vbc_attr_group,
> +       NULL,
> +};
> +
> +static struct class cros_class = {
> +       .owner          = THIS_MODULE,
> +       .name           = "chromeos",
> +       .dev_groups     = cros_ec_groups,
> +};
> +
> +/* Basic communication */
> +static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen)
> +{
> +       struct ec_response_get_version *resp;
> +       static const char * const current_image_name[] = {
> +               "unknown", "read-only", "read-write", "invalid",
> +       };
> +       struct cros_ec_command *msg;
> +       int ret;
> +
> +       msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +
> +       msg->version = 0;
> +       msg->command = EC_CMD_GET_VERSION + ec->cmd_offset;
> +       msg->insize = sizeof(*resp);
> +       msg->outsize = 0;
> +
> +       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
> +       if (ret < 0)
> +               goto exit;
> +
> +       if (msg->result != EC_RES_SUCCESS) {
> +               snprintf(str, maxlen,
> +                        "%s\nUnknown EC version: EC returned %d\n",
> +                        CROS_EC_DEV_VERSION, msg->result);
> +               ret = -EINVAL;
> +               goto exit;
> +       }
> +
> +       resp = (struct ec_response_get_version *)msg->data;
> +       if (resp->current_image >= ARRAY_SIZE(current_image_name))
> +               resp->current_image = 3; /* invalid */
> +
> +       snprintf(str, maxlen, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION,
> +                resp->version_string_ro, resp->version_string_rw,
> +                current_image_name[resp->current_image]);
> +
> +       ret = 0;
> +exit:
> +       kfree(msg);
> +       return ret;
> +}
> +
> +static int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
> +{
> +       struct cros_ec_command *msg;
> +       int ret;
> +
> +       if (ec->features[0] == -1U && ec->features[1] == -1U) {
> +               /* features bitmap not read yet */
> +
> +               msg = kmalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
> +               if (!msg)
> +                       return -ENOMEM;
> +
> +               msg->version = 0;
> +               msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
> +               msg->insize = sizeof(ec->features);
> +               msg->outsize = 0;
> +
> +               ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
> +               if (ret < 0 || msg->result != EC_RES_SUCCESS) {
> +                       dev_warn(ec->dev, "cannot get EC features: %d/%d\n",
> +                                ret, msg->result);
> +                       memset(ec->features, 0, sizeof(ec->features));
> +               }
> +
> +               memcpy(ec->features, msg->data, sizeof(ec->features));
> +
> +               dev_dbg(ec->dev, "EC features %08x %08x\n",
> +                       ec->features[0], ec->features[1]);
> +
> +               kfree(msg);
> +       }
> +
> +       return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
> +}
> +
> +/* Device file ops */
> +static int ec_device_open(struct inode *inode, struct file *filp)
> +{
> +       struct cros_ec_dev *ec = container_of(inode->i_cdev,
> +                                             struct cros_ec_dev, cdev);
> +       filp->private_data = ec;
> +       nonseekable_open(inode, filp);
> +       return 0;
> +}
> +
> +static int ec_device_release(struct inode *inode, struct file *filp)
> +{
> +       return 0;
> +}
> +
> +static ssize_t ec_device_read(struct file *filp, char __user *buffer,
> +                             size_t length, loff_t *offset)
> +{
> +       struct cros_ec_dev *ec = filp->private_data;
> +       char msg[sizeof(struct ec_response_get_version) +
> +                sizeof(CROS_EC_DEV_VERSION)];
> +       size_t count;
> +       int ret;
> +
> +       if (*offset != 0)
> +               return 0;
> +
> +       ret = ec_get_version(ec, msg, sizeof(msg));
> +       if (ret)
> +               return ret;
> +
> +       count = min(length, strlen(msg));
> +
> +       if (copy_to_user(buffer, msg, count))
> +               return -EFAULT;
> +
> +       *offset = count;
> +       return count;
> +}
> +
> +/* Ioctls */
> +static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg)
> +{
> +       long ret;
> +       struct cros_ec_command u_cmd;
> +       struct cros_ec_command *s_cmd;
> +
> +       if (copy_from_user(&u_cmd, arg, sizeof(u_cmd)))
> +               return -EFAULT;
> +
> +       if ((u_cmd.outsize > EC_MAX_MSG_BYTES) ||
> +           (u_cmd.insize > EC_MAX_MSG_BYTES))
> +               return -EINVAL;
> +
> +       s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize),
> +                       GFP_KERNEL);
> +       if (!s_cmd)
> +               return -ENOMEM;
> +
> +       if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) {
> +               ret = -EFAULT;
> +               goto exit;
> +       }
> +
> +       if (u_cmd.outsize != s_cmd->outsize ||
> +           u_cmd.insize != s_cmd->insize) {
> +               ret = -EINVAL;
> +               goto exit;
> +       }
> +
> +       s_cmd->command += ec->cmd_offset;
> +       ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
> +       /* Only copy data to userland if data was received. */
> +       if (ret < 0)
> +               goto exit;
> +
> +       if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize))
> +               ret = -EFAULT;
> +exit:
> +       kfree(s_cmd);
> +       return ret;
> +}
> +
> +static long ec_device_ioctl_readmem(struct cros_ec_dev *ec, void __user *arg)
> +{
> +       struct cros_ec_device *ec_dev = ec->ec_dev;
> +       struct cros_ec_readmem s_mem = { };
> +       long num;
> +
> +       /* Not every platform supports direct reads */
> +       if (!ec_dev->cmd_readmem)
> +               return -ENOTTY;
> +
> +       if (copy_from_user(&s_mem, arg, sizeof(s_mem)))
> +               return -EFAULT;
> +
> +       num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes,
> +                                 s_mem.buffer);
> +       if (num <= 0)
> +               return num;
> +
> +       if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem)))
> +               return -EFAULT;
> +
> +       return 0;
> +}
> +
> +static long ec_device_ioctl(struct file *filp, unsigned int cmd,
> +                           unsigned long arg)
> +{
> +       struct cros_ec_dev *ec = filp->private_data;
> +
> +       if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC)
> +               return -ENOTTY;
> +
> +       switch (cmd) {
> +       case CROS_EC_DEV_IOCXCMD:
> +               return ec_device_ioctl_xcmd(ec, (void __user *)arg);
> +       case CROS_EC_DEV_IOCRDMEM:
> +               return ec_device_ioctl_readmem(ec, (void __user *)arg);
> +       }
> +
> +       return -ENOTTY;
> +}
> +
> +/* Module initialization */
> +static const struct file_operations fops = {
> +       .open = ec_device_open,
> +       .release = ec_device_release,
> +       .read = ec_device_read,
> +       .unlocked_ioctl = ec_device_ioctl,
> +#ifdef CONFIG_COMPAT
> +       .compat_ioctl = ec_device_ioctl,
> +#endif
> +};
> +
> +static void __remove(struct device *dev)
> +{
> +       struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
> +                                             class_dev);
> +       kfree(ec);
> +}
> +
> +static void cros_ec_sensors_register(struct cros_ec_dev *ec)
> +{
> +       /*
> +        * Issue a command to get the number of sensor reported.
> +        * Build an array of sensors driver and register them all.
> +        */
> +       int ret, i, id, sensor_num;
> +       struct mfd_cell *sensor_cells;
> +       struct cros_ec_sensor_platform *sensor_platforms;
> +       int sensor_type[MOTIONSENSE_TYPE_MAX];
> +       struct ec_params_motion_sense *params;
> +       struct ec_response_motion_sense *resp;
> +       struct cros_ec_command *msg;
> +
> +       msg = kzalloc(sizeof(struct cros_ec_command) +
> +                     max(sizeof(*params), sizeof(*resp)), GFP_KERNEL);
> +       if (msg == NULL)
> +               return;
> +
> +       msg->version = 2;
> +       msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
> +       msg->outsize = sizeof(*params);
> +       msg->insize = sizeof(*resp);
> +
> +       params = (struct ec_params_motion_sense *)msg->data;
> +       params->cmd = MOTIONSENSE_CMD_DUMP;
> +
> +       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
> +       if (ret < 0 || msg->result != EC_RES_SUCCESS) {
> +               dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n",
> +                        ret, msg->result);
> +               goto error;
> +       }
> +
> +       resp = (struct ec_response_motion_sense *)msg->data;
> +       sensor_num = resp->dump.sensor_count;
> +       /* Allocate 2 extra sensors in case lid angle or FIFO are needed */
> +       sensor_cells = kzalloc(sizeof(struct mfd_cell) * (sensor_num + 2),
> +                              GFP_KERNEL);
> +       if (sensor_cells == NULL)
> +               goto error;
> +
> +       sensor_platforms = kzalloc(sizeof(struct cros_ec_sensor_platform) *
> +                 (sensor_num + 1), GFP_KERNEL);
> +       if (sensor_platforms == NULL)
> +               goto error_platforms;
> +
> +       memset(sensor_type, 0, sizeof(sensor_type));
> +       id = 0;
> +       for (i = 0; i < sensor_num; i++) {
> +               params->cmd = MOTIONSENSE_CMD_INFO;
> +               params->info.sensor_num = i;
> +               ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
> +               if (ret < 0 || msg->result != EC_RES_SUCCESS) {
> +                       dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n",
> +                                i, ret, msg->result);
> +                       continue;
> +               }
> +               switch (resp->info.type) {
> +               case MOTIONSENSE_TYPE_ACCEL:
> +                       sensor_cells[id].name = "cros-ec-accel";
> +                       break;
> +               case MOTIONSENSE_TYPE_BARO:
> +                       sensor_cells[id].name = "cros-ec-baro";
> +                       break;
> +               case MOTIONSENSE_TYPE_GYRO:
> +                       sensor_cells[id].name = "cros-ec-gyro";
> +                       break;
> +               case MOTIONSENSE_TYPE_MAG:
> +                       sensor_cells[id].name = "cros-ec-mag";
> +                       break;
> +               case MOTIONSENSE_TYPE_PROX:
> +                       sensor_cells[id].name = "cros-ec-prox";
> +                       break;
> +               case MOTIONSENSE_TYPE_LIGHT:
> +                       sensor_cells[id].name = "cros-ec-light";
> +                       break;
> +               case MOTIONSENSE_TYPE_ACTIVITY:
> +                       sensor_cells[id].name = "cros-ec-activity";
> +                       break;
> +               default:
> +                       dev_warn(ec->dev, "unknown type %d\n", resp->info.type);
> +                       continue;
> +               }
> +               sensor_platforms[id].sensor_num = i;
> +               sensor_cells[id].id = sensor_type[resp->info.type];
> +               sensor_cells[id].platform_data = &sensor_platforms[id];
> +               sensor_cells[id].pdata_size =
> +                       sizeof(struct cros_ec_sensor_platform);
> +
> +               sensor_type[resp->info.type]++;
> +               id++;
> +       }
> +       if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) {
> +               sensor_platforms[id].sensor_num = sensor_num;
> +
> +               sensor_cells[id].name = "cros-ec-angle";
> +               sensor_cells[id].id = 0;
> +               sensor_cells[id].platform_data = &sensor_platforms[id];
> +               sensor_cells[id].pdata_size =
> +                       sizeof(struct cros_ec_sensor_platform);
> +               id++;
> +       }
> +       if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
> +               sensor_cells[id].name = "cros-ec-ring";
> +               id++;
> +       }
> +
> +       ret = mfd_add_devices(ec->dev, 0, sensor_cells, id,
> +                             NULL, 0, NULL);
> +       if (ret)
> +               dev_err(ec->dev, "failed to add EC sensors\n");
> +
> +       kfree(sensor_platforms);
> +error_platforms:
> +       kfree(sensor_cells);
> +error:
> +       kfree(msg);
> +}
> +
> +static int ec_device_probe(struct platform_device *pdev)
> +{
> +       int retval = -ENOMEM;
> +       struct device *dev = &pdev->dev;
> +       struct cros_ec_platform *ec_platform = dev_get_platdata(dev);
> +       struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL);
> +
> +       if (!ec)
> +               return retval;
> +
> +       dev_set_drvdata(dev, ec);
> +       ec->ec_dev = dev_get_drvdata(dev->parent);
> +       ec->dev = dev;
> +       ec->cmd_offset = ec_platform->cmd_offset;
> +       ec->features[0] = -1U; /* Not cached yet */
> +       ec->features[1] = -1U; /* Not cached yet */
> +       device_initialize(&ec->class_dev);
> +       cdev_init(&ec->cdev, &fops);
> +
> +       /*
> +        * Add the class device
> +        * Link to the character device for creating the /dev entry
> +        * in devtmpfs.
> +        */
> +       ec->class_dev.devt = MKDEV(ec_major, pdev->id);
> +       ec->class_dev.class = &cros_class;
> +       ec->class_dev.parent = dev;
> +       ec->class_dev.release = __remove;
> +
> +       retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name);
> +       if (retval) {
> +               dev_err(dev, "dev_set_name failed => %d\n", retval);
> +               goto failed;
> +       }
> +
> +       retval = cdev_device_add(&ec->cdev, &ec->class_dev);
> +       if (retval) {
> +               dev_err(dev, "cdev_device_add failed => %d\n", retval);
> +               goto failed;
> +       }
> +
> +       if (cros_ec_debugfs_init(ec))
> +               dev_warn(dev, "failed to create debugfs directory\n");
> +
> +       /* check whether this EC is a sensor hub. */
> +       if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE))
> +               cros_ec_sensors_register(ec);
> +
> +       /* Take control of the lightbar from the EC. */
> +       lb_manual_suspend_ctrl(ec, 1);
> +
> +       return 0;
> +
> +failed:
> +       put_device(&ec->class_dev);
> +       return retval;
> +}
> +
> +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. */
> +       lb_manual_suspend_ctrl(ec, 0);
> +
> +       cros_ec_debugfs_remove(ec);
> +
> +       cdev_del(&ec->cdev);
> +       device_unregister(&ec->class_dev);
> +       return 0;
> +}
> +
> +static const struct platform_device_id cros_ec_id[] = {
> +       { DRV_NAME, 0 },
> +       { /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(platform, cros_ec_id);
> +
> +static __maybe_unused int ec_device_suspend(struct device *dev)
> +{
> +       struct cros_ec_dev *ec = dev_get_drvdata(dev);
> +
> +       lb_suspend(ec);
> +
> +       return 0;
> +}
> +
> +static __maybe_unused int ec_device_resume(struct device *dev)
> +{
> +       struct cros_ec_dev *ec = dev_get_drvdata(dev);
> +
> +       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 = DRV_NAME,
> +               .pm = &cros_ec_dev_pm_ops,
> +       },
> +       .probe = ec_device_probe,
> +       .remove = ec_device_remove,
> +};
> +
> +static int __init cros_ec_dev_init(void)
> +{
> +       int ret;
> +       dev_t dev = 0;
> +
> +       ret  = class_register(&cros_class);
> +       if (ret) {
> +               pr_err(CROS_EC_DEV_NAME ": failed to register device class\n");
> +               return ret;
> +       }
> +
> +       /* Get a range of minor numbers (starting with 0) to work with */
> +       ret = alloc_chrdev_region(&dev, 0, CROS_MAX_DEV, CROS_EC_DEV_NAME);
> +       if (ret < 0) {
> +               pr_err(CROS_EC_DEV_NAME ": alloc_chrdev_region() failed\n");
> +               goto failed_chrdevreg;
> +       }
> +       ec_major = MAJOR(dev);
> +
> +       /* Register the driver */
> +       ret = platform_driver_register(&cros_ec_dev_driver);
> +       if (ret < 0) {
> +               pr_warn(CROS_EC_DEV_NAME ": can't register driver: %d\n", ret);
> +               goto failed_devreg;
> +       }
> +       return 0;
> +
> +failed_devreg:
> +       unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV);
> +failed_chrdevreg:
> +       class_unregister(&cros_class);
> +       return ret;
> +}
> +
> +static void __exit cros_ec_dev_exit(void)
> +{
> +       platform_driver_unregister(&cros_ec_dev_driver);
> +       unregister_chrdev(ec_major, CROS_EC_DEV_NAME);
> +       class_unregister(&cros_class);
> +}
> +
> +module_init(cros_ec_dev_init);
> +module_exit(cros_ec_dev_exit);
> +
> +MODULE_ALIAS("platform:" DRV_NAME);
> +MODULE_AUTHOR("Bill Richardson <wfrichar@chromium.org>");
> +MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller");
> +MODULE_VERSION("1.0");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/mfd/cros_ec_dev.h b/drivers/mfd/cros_ec_dev.h
> new file mode 100644
> index 0000000..45e9453
> --- /dev/null
> +++ b/drivers/mfd/cros_ec_dev.h
> @@ -0,0 +1,52 @@
> +/*
> + * cros_ec_dev - expose the Chrome OS Embedded Controller to userspace
> + *
> + * Copyright (C) 2014 Google, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef _CROS_EC_DEV_H_
> +#define _CROS_EC_DEV_H_
> +
> +#include <linux/ioctl.h>
> +#include <linux/types.h>
> +#include <linux/mfd/cros_ec.h>
> +
> +#define CROS_EC_DEV_VERSION "1.0.0"
> +
> +/*
> + * @offset: within EC_LPC_ADDR_MEMMAP region
> + * @bytes: number of bytes to read. zero means "read a string" (including '\0')
> + *         (at most only EC_MEMMAP_SIZE bytes can be read)
> + * @buffer: where to store the result
> + * ioctl returns the number of bytes read, negative on error
> + */
> +struct cros_ec_readmem {
> +       uint32_t offset;
> +       uint32_t bytes;
> +       uint8_t buffer[EC_MEMMAP_SIZE];
> +};
> +
> +#define CROS_EC_DEV_IOC       0xEC
> +#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/Kconfig b/drivers/platform/chrome/Kconfig
> index bffc892..e728a96 100644
> --- a/drivers/platform/chrome/Kconfig
> +++ b/drivers/platform/chrome/Kconfig
> @@ -38,16 +38,6 @@ config CHROMEOS_PSTORE
>           If you have a supported Chromebook, choose Y or M here.
>           The module will be called chromeos_pstore.
>
> -config CROS_EC_CHARDEV
> -        tristate "Chrome OS Embedded Controller userspace device interface"
> -        depends on MFD_CROS_EC
> -        select CROS_EC_CTL
> -        ---help---
> -          This driver adds support to talk with the ChromeOS EC from userspace.
> -
> -          If you have a supported Chromebook, choose Y or M here.
> -          The module will be called cros_ec_dev.
> -
>  config CROS_EC_CTL
>          tristate
>
> diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
> index bc239ec..ff3b369 100644
> --- a/drivers/platform/chrome/Makefile
> +++ b/drivers/platform/chrome/Makefile
> @@ -5,7 +5,6 @@ obj-$(CONFIG_CHROMEOS_PSTORE)           += chromeos_pstore.o
>  cros_ec_ctl-objs                       := cros_ec_sysfs.o cros_ec_lightbar.o \
>                                            cros_ec_vbc.o cros_ec_debugfs.o
>  obj-$(CONFIG_CROS_EC_CTL)              += cros_ec_ctl.o
> -obj-$(CONFIG_CROS_EC_CHARDEV)          += cros_ec_dev.o
>  cros_ec_lpcs-objs                      := cros_ec_lpc.o cros_ec_lpc_reg.o
>  cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o
>  obj-$(CONFIG_CROS_EC_LPC)              += cros_ec_lpcs.o
> diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
> index d0b8ce0..98a35d3 100644
> --- a/drivers/platform/chrome/cros_ec_debugfs.c
> +++ b/drivers/platform/chrome/cros_ec_debugfs.c
> @@ -29,9 +29,6 @@
>  #include <linux/slab.h>
>  #include <linux/wait.h>
>
> -#include "cros_ec_dev.h"
> -#include "cros_ec_debugfs.h"
> -
>  #define LOG_SHIFT              14
>  #define LOG_SIZE               (1 << LOG_SHIFT)
>  #define LOG_POLL_SEC           10
> diff --git a/drivers/platform/chrome/cros_ec_debugfs.h b/drivers/platform/chrome/cros_ec_debugfs.h
> deleted file mode 100644
> index 1ff3a50..0000000
> --- a/drivers/platform/chrome/cros_ec_debugfs.h
> +++ /dev/null
> @@ -1,27 +0,0 @@
> -/*
> - * Copyright 2015 Google, Inc.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef _DRV_CROS_EC_DEBUGFS_H_
> -#define _DRV_CROS_EC_DEBUGFS_H_
> -
> -#include "cros_ec_dev.h"
> -
> -/* debugfs stuff */
> -int cros_ec_debugfs_init(struct cros_ec_dev *ec);
> -void cros_ec_debugfs_remove(struct cros_ec_dev *ec);
> -
> -#endif  /* _DRV_CROS_EC_DEBUGFS_H_ */
> diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
> deleted file mode 100644
> index daf0ffd..0000000
> --- a/drivers/platform/chrome/cros_ec_dev.c
> +++ /dev/null
> @@ -1,553 +0,0 @@
> -/*
> - * cros_ec_dev - expose the Chrome OS Embedded Controller to user-space
> - *
> - * Copyright (C) 2014 Google, Inc.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#include <linux/fs.h>
> -#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>
> -
> -#include "cros_ec_debugfs.h"
> -#include "cros_ec_dev.h"
> -
> -#define DRV_NAME "cros-ec-dev"
> -
> -/* Device variables */
> -#define CROS_MAX_DEV 128
> -static int ec_major;
> -
> -static const struct attribute_group *cros_ec_groups[] = {
> -       &cros_ec_attr_group,
> -       &cros_ec_lightbar_attr_group,
> -       &cros_ec_vbc_attr_group,
> -       NULL,
> -};
> -
> -static struct class cros_class = {
> -       .owner          = THIS_MODULE,
> -       .name           = "chromeos",
> -       .dev_groups     = cros_ec_groups,
> -};
> -
> -/* Basic communication */
> -static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen)
> -{
> -       struct ec_response_get_version *resp;
> -       static const char * const current_image_name[] = {
> -               "unknown", "read-only", "read-write", "invalid",
> -       };
> -       struct cros_ec_command *msg;
> -       int ret;
> -
> -       msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL);
> -       if (!msg)
> -               return -ENOMEM;
> -
> -       msg->version = 0;
> -       msg->command = EC_CMD_GET_VERSION + ec->cmd_offset;
> -       msg->insize = sizeof(*resp);
> -       msg->outsize = 0;
> -
> -       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
> -       if (ret < 0)
> -               goto exit;
> -
> -       if (msg->result != EC_RES_SUCCESS) {
> -               snprintf(str, maxlen,
> -                        "%s\nUnknown EC version: EC returned %d\n",
> -                        CROS_EC_DEV_VERSION, msg->result);
> -               ret = -EINVAL;
> -               goto exit;
> -       }
> -
> -       resp = (struct ec_response_get_version *)msg->data;
> -       if (resp->current_image >= ARRAY_SIZE(current_image_name))
> -               resp->current_image = 3; /* invalid */
> -
> -       snprintf(str, maxlen, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION,
> -                resp->version_string_ro, resp->version_string_rw,
> -                current_image_name[resp->current_image]);
> -
> -       ret = 0;
> -exit:
> -       kfree(msg);
> -       return ret;
> -}
> -
> -static int cros_ec_check_features(struct cros_ec_dev *ec, int feature)
> -{
> -       struct cros_ec_command *msg;
> -       int ret;
> -
> -       if (ec->features[0] == -1U && ec->features[1] == -1U) {
> -               /* features bitmap not read yet */
> -
> -               msg = kmalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL);
> -               if (!msg)
> -                       return -ENOMEM;
> -
> -               msg->version = 0;
> -               msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset;
> -               msg->insize = sizeof(ec->features);
> -               msg->outsize = 0;
> -
> -               ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
> -               if (ret < 0 || msg->result != EC_RES_SUCCESS) {
> -                       dev_warn(ec->dev, "cannot get EC features: %d/%d\n",
> -                                ret, msg->result);
> -                       memset(ec->features, 0, sizeof(ec->features));
> -               }
> -
> -               memcpy(ec->features, msg->data, sizeof(ec->features));
> -
> -               dev_dbg(ec->dev, "EC features %08x %08x\n",
> -                       ec->features[0], ec->features[1]);
> -
> -               kfree(msg);
> -       }
> -
> -       return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature);
> -}
> -
> -/* Device file ops */
> -static int ec_device_open(struct inode *inode, struct file *filp)
> -{
> -       struct cros_ec_dev *ec = container_of(inode->i_cdev,
> -                                             struct cros_ec_dev, cdev);
> -       filp->private_data = ec;
> -       nonseekable_open(inode, filp);
> -       return 0;
> -}
> -
> -static int ec_device_release(struct inode *inode, struct file *filp)
> -{
> -       return 0;
> -}
> -
> -static ssize_t ec_device_read(struct file *filp, char __user *buffer,
> -                             size_t length, loff_t *offset)
> -{
> -       struct cros_ec_dev *ec = filp->private_data;
> -       char msg[sizeof(struct ec_response_get_version) +
> -                sizeof(CROS_EC_DEV_VERSION)];
> -       size_t count;
> -       int ret;
> -
> -       if (*offset != 0)
> -               return 0;
> -
> -       ret = ec_get_version(ec, msg, sizeof(msg));
> -       if (ret)
> -               return ret;
> -
> -       count = min(length, strlen(msg));
> -
> -       if (copy_to_user(buffer, msg, count))
> -               return -EFAULT;
> -
> -       *offset = count;
> -       return count;
> -}
> -
> -/* Ioctls */
> -static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg)
> -{
> -       long ret;
> -       struct cros_ec_command u_cmd;
> -       struct cros_ec_command *s_cmd;
> -
> -       if (copy_from_user(&u_cmd, arg, sizeof(u_cmd)))
> -               return -EFAULT;
> -
> -       if ((u_cmd.outsize > EC_MAX_MSG_BYTES) ||
> -           (u_cmd.insize > EC_MAX_MSG_BYTES))
> -               return -EINVAL;
> -
> -       s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize),
> -                       GFP_KERNEL);
> -       if (!s_cmd)
> -               return -ENOMEM;
> -
> -       if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) {
> -               ret = -EFAULT;
> -               goto exit;
> -       }
> -
> -       if (u_cmd.outsize != s_cmd->outsize ||
> -           u_cmd.insize != s_cmd->insize) {
> -               ret = -EINVAL;
> -               goto exit;
> -       }
> -
> -       s_cmd->command += ec->cmd_offset;
> -       ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd);
> -       /* Only copy data to userland if data was received. */
> -       if (ret < 0)
> -               goto exit;
> -
> -       if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize))
> -               ret = -EFAULT;
> -exit:
> -       kfree(s_cmd);
> -       return ret;
> -}
> -
> -static long ec_device_ioctl_readmem(struct cros_ec_dev *ec, void __user *arg)
> -{
> -       struct cros_ec_device *ec_dev = ec->ec_dev;
> -       struct cros_ec_readmem s_mem = { };
> -       long num;
> -
> -       /* Not every platform supports direct reads */
> -       if (!ec_dev->cmd_readmem)
> -               return -ENOTTY;
> -
> -       if (copy_from_user(&s_mem, arg, sizeof(s_mem)))
> -               return -EFAULT;
> -
> -       num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes,
> -                                 s_mem.buffer);
> -       if (num <= 0)
> -               return num;
> -
> -       if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem)))
> -               return -EFAULT;
> -
> -       return 0;
> -}
> -
> -static long ec_device_ioctl(struct file *filp, unsigned int cmd,
> -                           unsigned long arg)
> -{
> -       struct cros_ec_dev *ec = filp->private_data;
> -
> -       if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC)
> -               return -ENOTTY;
> -
> -       switch (cmd) {
> -       case CROS_EC_DEV_IOCXCMD:
> -               return ec_device_ioctl_xcmd(ec, (void __user *)arg);
> -       case CROS_EC_DEV_IOCRDMEM:
> -               return ec_device_ioctl_readmem(ec, (void __user *)arg);
> -       }
> -
> -       return -ENOTTY;
> -}
> -
> -/* Module initialization */
> -static const struct file_operations fops = {
> -       .open = ec_device_open,
> -       .release = ec_device_release,
> -       .read = ec_device_read,
> -       .unlocked_ioctl = ec_device_ioctl,
> -#ifdef CONFIG_COMPAT
> -       .compat_ioctl = ec_device_ioctl,
> -#endif
> -};
> -
> -static void __remove(struct device *dev)
> -{
> -       struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
> -                                             class_dev);
> -       kfree(ec);
> -}
> -
> -static void cros_ec_sensors_register(struct cros_ec_dev *ec)
> -{
> -       /*
> -        * Issue a command to get the number of sensor reported.
> -        * Build an array of sensors driver and register them all.
> -        */
> -       int ret, i, id, sensor_num;
> -       struct mfd_cell *sensor_cells;
> -       struct cros_ec_sensor_platform *sensor_platforms;
> -       int sensor_type[MOTIONSENSE_TYPE_MAX];
> -       struct ec_params_motion_sense *params;
> -       struct ec_response_motion_sense *resp;
> -       struct cros_ec_command *msg;
> -
> -       msg = kzalloc(sizeof(struct cros_ec_command) +
> -                     max(sizeof(*params), sizeof(*resp)), GFP_KERNEL);
> -       if (msg == NULL)
> -               return;
> -
> -       msg->version = 2;
> -       msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
> -       msg->outsize = sizeof(*params);
> -       msg->insize = sizeof(*resp);
> -
> -       params = (struct ec_params_motion_sense *)msg->data;
> -       params->cmd = MOTIONSENSE_CMD_DUMP;
> -
> -       ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
> -       if (ret < 0 || msg->result != EC_RES_SUCCESS) {
> -               dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n",
> -                        ret, msg->result);
> -               goto error;
> -       }
> -
> -       resp = (struct ec_response_motion_sense *)msg->data;
> -       sensor_num = resp->dump.sensor_count;
> -       /* Allocate 2 extra sensors in case lid angle or FIFO are needed */
> -       sensor_cells = kzalloc(sizeof(struct mfd_cell) * (sensor_num + 2),
> -                              GFP_KERNEL);
> -       if (sensor_cells == NULL)
> -               goto error;
> -
> -       sensor_platforms = kzalloc(sizeof(struct cros_ec_sensor_platform) *
> -                 (sensor_num + 1), GFP_KERNEL);
> -       if (sensor_platforms == NULL)
> -               goto error_platforms;
> -
> -       memset(sensor_type, 0, sizeof(sensor_type));
> -       id = 0;
> -       for (i = 0; i < sensor_num; i++) {
> -               params->cmd = MOTIONSENSE_CMD_INFO;
> -               params->info.sensor_num = i;
> -               ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
> -               if (ret < 0 || msg->result != EC_RES_SUCCESS) {
> -                       dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n",
> -                                i, ret, msg->result);
> -                       continue;
> -               }
> -               switch (resp->info.type) {
> -               case MOTIONSENSE_TYPE_ACCEL:
> -                       sensor_cells[id].name = "cros-ec-accel";
> -                       break;
> -               case MOTIONSENSE_TYPE_BARO:
> -                       sensor_cells[id].name = "cros-ec-baro";
> -                       break;
> -               case MOTIONSENSE_TYPE_GYRO:
> -                       sensor_cells[id].name = "cros-ec-gyro";
> -                       break;
> -               case MOTIONSENSE_TYPE_MAG:
> -                       sensor_cells[id].name = "cros-ec-mag";
> -                       break;
> -               case MOTIONSENSE_TYPE_PROX:
> -                       sensor_cells[id].name = "cros-ec-prox";
> -                       break;
> -               case MOTIONSENSE_TYPE_LIGHT:
> -                       sensor_cells[id].name = "cros-ec-light";
> -                       break;
> -               case MOTIONSENSE_TYPE_ACTIVITY:
> -                       sensor_cells[id].name = "cros-ec-activity";
> -                       break;
> -               default:
> -                       dev_warn(ec->dev, "unknown type %d\n", resp->info.type);
> -                       continue;
> -               }
> -               sensor_platforms[id].sensor_num = i;
> -               sensor_cells[id].id = sensor_type[resp->info.type];
> -               sensor_cells[id].platform_data = &sensor_platforms[id];
> -               sensor_cells[id].pdata_size =
> -                       sizeof(struct cros_ec_sensor_platform);
> -
> -               sensor_type[resp->info.type]++;
> -               id++;
> -       }
> -       if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) {
> -               sensor_platforms[id].sensor_num = sensor_num;
> -
> -               sensor_cells[id].name = "cros-ec-angle";
> -               sensor_cells[id].id = 0;
> -               sensor_cells[id].platform_data = &sensor_platforms[id];
> -               sensor_cells[id].pdata_size =
> -                       sizeof(struct cros_ec_sensor_platform);
> -               id++;
> -       }
> -       if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) {
> -               sensor_cells[id].name = "cros-ec-ring";
> -               id++;
> -       }
> -
> -       ret = mfd_add_devices(ec->dev, 0, sensor_cells, id,
> -                             NULL, 0, NULL);
> -       if (ret)
> -               dev_err(ec->dev, "failed to add EC sensors\n");
> -
> -       kfree(sensor_platforms);
> -error_platforms:
> -       kfree(sensor_cells);
> -error:
> -       kfree(msg);
> -}
> -
> -static int ec_device_probe(struct platform_device *pdev)
> -{
> -       int retval = -ENOMEM;
> -       struct device *dev = &pdev->dev;
> -       struct cros_ec_platform *ec_platform = dev_get_platdata(dev);
> -       struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL);
> -
> -       if (!ec)
> -               return retval;
> -
> -       dev_set_drvdata(dev, ec);
> -       ec->ec_dev = dev_get_drvdata(dev->parent);
> -       ec->dev = dev;
> -       ec->cmd_offset = ec_platform->cmd_offset;
> -       ec->features[0] = -1U; /* Not cached yet */
> -       ec->features[1] = -1U; /* Not cached yet */
> -       device_initialize(&ec->class_dev);
> -       cdev_init(&ec->cdev, &fops);
> -
> -       /*
> -        * Add the class device
> -        * Link to the character device for creating the /dev entry
> -        * in devtmpfs.
> -        */
> -       ec->class_dev.devt = MKDEV(ec_major, pdev->id);
> -       ec->class_dev.class = &cros_class;
> -       ec->class_dev.parent = dev;
> -       ec->class_dev.release = __remove;
> -
> -       retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name);
> -       if (retval) {
> -               dev_err(dev, "dev_set_name failed => %d\n", retval);
> -               goto failed;
> -       }
> -
> -       retval = cdev_device_add(&ec->cdev, &ec->class_dev);
> -       if (retval) {
> -               dev_err(dev, "cdev_device_add failed => %d\n", retval);
> -               goto failed;
> -       }
> -
> -       if (cros_ec_debugfs_init(ec))
> -               dev_warn(dev, "failed to create debugfs directory\n");
> -
> -       /* check whether this EC is a sensor hub. */
> -       if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE))
> -               cros_ec_sensors_register(ec);
> -
> -       /* Take control of the lightbar from the EC. */
> -       lb_manual_suspend_ctrl(ec, 1);
> -
> -       return 0;
> -
> -failed:
> -       put_device(&ec->class_dev);
> -       return retval;
> -}
> -
> -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. */
> -       lb_manual_suspend_ctrl(ec, 0);
> -
> -       cros_ec_debugfs_remove(ec);
> -
> -       cdev_del(&ec->cdev);
> -       device_unregister(&ec->class_dev);
> -       return 0;
> -}
> -
> -static const struct platform_device_id cros_ec_id[] = {
> -       { DRV_NAME, 0 },
> -       { /* sentinel */ },
> -};
> -MODULE_DEVICE_TABLE(platform, cros_ec_id);
> -
> -static __maybe_unused int ec_device_suspend(struct device *dev)
> -{
> -       struct cros_ec_dev *ec = dev_get_drvdata(dev);
> -
> -       lb_suspend(ec);
> -
> -       return 0;
> -}
> -
> -static __maybe_unused int ec_device_resume(struct device *dev)
> -{
> -       struct cros_ec_dev *ec = dev_get_drvdata(dev);
> -
> -       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 = DRV_NAME,
> -               .pm = &cros_ec_dev_pm_ops,
> -       },
> -       .probe = ec_device_probe,
> -       .remove = ec_device_remove,
> -};
> -
> -static int __init cros_ec_dev_init(void)
> -{
> -       int ret;
> -       dev_t dev = 0;
> -
> -       ret  = class_register(&cros_class);
> -       if (ret) {
> -               pr_err(CROS_EC_DEV_NAME ": failed to register device class\n");
> -               return ret;
> -       }
> -
> -       /* Get a range of minor numbers (starting with 0) to work with */
> -       ret = alloc_chrdev_region(&dev, 0, CROS_MAX_DEV, CROS_EC_DEV_NAME);
> -       if (ret < 0) {
> -               pr_err(CROS_EC_DEV_NAME ": alloc_chrdev_region() failed\n");
> -               goto failed_chrdevreg;
> -       }
> -       ec_major = MAJOR(dev);
> -
> -       /* Register the driver */
> -       ret = platform_driver_register(&cros_ec_dev_driver);
> -       if (ret < 0) {
> -               pr_warn(CROS_EC_DEV_NAME ": can't register driver: %d\n", ret);
> -               goto failed_devreg;
> -       }
> -       return 0;
> -
> -failed_devreg:
> -       unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV);
> -failed_chrdevreg:
> -       class_unregister(&cros_class);
> -       return ret;
> -}
> -
> -static void __exit cros_ec_dev_exit(void)
> -{
> -       platform_driver_unregister(&cros_ec_dev_driver);
> -       unregister_chrdev(ec_major, CROS_EC_DEV_NAME);
> -       class_unregister(&cros_class);
> -}
> -
> -module_init(cros_ec_dev_init);
> -module_exit(cros_ec_dev_exit);
> -
> -MODULE_ALIAS("platform:" DRV_NAME);
> -MODULE_AUTHOR("Bill Richardson <wfrichar@chromium.org>");
> -MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller");
> -MODULE_VERSION("1.0");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/platform/chrome/cros_ec_dev.h b/drivers/platform/chrome/cros_ec_dev.h
> deleted file mode 100644
> index 45e9453..0000000
> --- a/drivers/platform/chrome/cros_ec_dev.h
> +++ /dev/null
> @@ -1,52 +0,0 @@
> -/*
> - * cros_ec_dev - expose the Chrome OS Embedded Controller to userspace
> - *
> - * Copyright (C) 2014 Google, Inc.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program. If not, see <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef _CROS_EC_DEV_H_
> -#define _CROS_EC_DEV_H_
> -
> -#include <linux/ioctl.h>
> -#include <linux/types.h>
> -#include <linux/mfd/cros_ec.h>
> -
> -#define CROS_EC_DEV_VERSION "1.0.0"
> -
> -/*
> - * @offset: within EC_LPC_ADDR_MEMMAP region
> - * @bytes: number of bytes to read. zero means "read a string" (including '\0')
> - *         (at most only EC_MEMMAP_SIZE bytes can be read)
> - * @buffer: where to store the result
> - * ioctl returns the number of bytes read, negative on error
> - */
> -struct cros_ec_readmem {
> -       uint32_t offset;
> -       uint32_t bytes;
> -       uint8_t buffer[EC_MEMMAP_SIZE];
> -};
> -
> -#define CROS_EC_DEV_IOC       0xEC
> -#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 925d91c..6ea79d4 100644
> --- a/drivers/platform/chrome/cros_ec_lightbar.c
> +++ b/drivers/platform/chrome/cros_ec_lightbar.c
> @@ -33,8 +33,6 @@
>  #include <linux/uaccess.h>
>  #include <linux/slab.h>
>
> -#include "cros_ec_dev.h"
> -
>  /* Rate-limit the lightbar interface to prevent DoS. */
>  static unsigned long lb_interval_jiffies = 50 * HZ / 1000;
>
> diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
> index 201f11a..d6eebe8 100644
> --- a/drivers/platform/chrome/cros_ec_sysfs.c
> +++ b/drivers/platform/chrome/cros_ec_sysfs.c
> @@ -34,8 +34,6 @@
>  #include <linux/types.h>
>  #include <linux/uaccess.h>
>
> -#include "cros_ec_dev.h"
> -
>  /* Accessor functions */
>
>  static ssize_t show_ec_reboot(struct device *dev,
> diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
> index 4e887ba..c615359 100644
> --- a/include/linux/mfd/cros_ec.h
> +++ b/include/linux/mfd/cros_ec.h
> @@ -322,6 +322,10 @@ extern struct attribute_group cros_ec_attr_group;
>  extern struct attribute_group cros_ec_lightbar_attr_group;
>  extern struct attribute_group cros_ec_vbc_attr_group;
>
> +/* debugfs stuff */
> +int cros_ec_debugfs_init(struct cros_ec_dev *ec);
> +void cros_ec_debugfs_remove(struct cros_ec_dev *ec);
> +
>  /* ACPI GPE handler */
>  #ifdef CONFIG_ACPI
>
> --
> 2.7.4
>

  parent reply	other threads:[~2017-11-30 20:50 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-20 16:15 [PATCH v2 0/2] mfd: cros_ec: move cros_ec_dev driver to MFD subdir Thierry Escande
2017-11-20 16:15 ` [PATCH v2 1/2] cros_ec: Split cros_ec_devs module Thierry Escande
2017-11-29 11:34   ` Lee Jones
2017-11-30 20:49   ` Guenter Roeck
2017-12-01 19:24     ` Gwendal Grignou
2017-11-20 16:15 ` [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd Thierry Escande
2017-11-29 11:35   ` Lee Jones
2017-11-30 20:50   ` Guenter Roeck [this message]
2017-12-01 19:23     ` Gwendal Grignou
2017-12-04  9:10       ` Lee Jones
2018-06-20 23:05   ` Dmitry Torokhov
2018-06-21  8:42     ` Enric Balletbo i Serra
2018-07-03  9:03     ` Lee Jones
2017-12-15 10:48 ` [GIT PULL] Immutable branch between MFD and Platform due for the v4.16 merge window Lee Jones
2017-12-16  4:50   ` Benson Leung

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CABXOdTczmg1Atp4nP8vFizvygH=M76gx7J=S3yTXqyC6L1S4sA@mail.gmail.com' \
    --to=groeck@google.com \
    --cc=bleung@chromium.org \
    --cc=enric.balletbo@collabora.com \
    --cc=gwendal@chromium.org \
    --cc=lee.jones@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=thierry.escande@collabora.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).