linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/2] mfd: cros_ec: move cros_ec_dev driver to MFD subdir
@ 2017-11-20 16:15 Thierry Escande
  2017-11-20 16:15 ` [PATCH v2 1/2] cros_ec: Split cros_ec_devs module Thierry Escande
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Thierry Escande @ 2017-11-20 16:15 UTC (permalink / raw)
  To: Lee Jones, Benson Leung
  Cc: Enric Balletbo i Serra, Gwendal Grignou, Guenter Roeck, linux-kernel

Hi,

In order to remove calls to mfd_add_devices() from outside the MFD
subtree, this patchset splits the cros_ec_devs modules in 2 parts. The
cros_ec_dev module, responsible for registering mfd devices, will be
moved to the MFD subtree (drivers/mfd/) and the user-space interfaces,
named cros_ec_ctl will be kept in drivers/platform/chrome/.

Regards,

 Thierry

Thierry Escande (2):
  cros_ec: Split cros_ec_devs module
  cros_ec: Move cros_ec_dev module to drivers/mfd

 drivers/mfd/Kconfig                        |  10 +
 drivers/mfd/Makefile                       |   1 +
 drivers/mfd/cros_ec.c                      |   4 +-
 drivers/mfd/cros_ec_dev.c                  | 549 ++++++++++++++++++++++++++++
 drivers/mfd/cros_ec_dev.h                  |  52 +++
 drivers/platform/chrome/Kconfig            |  10 +-
 drivers/platform/chrome/Makefile           |   7 +-
 drivers/platform/chrome/cros_ec_debugfs.c  |   5 +-
 drivers/platform/chrome/cros_ec_debugfs.h  |  27 --
 drivers/platform/chrome/cros_ec_dev.c      | 550 -----------------------------
 drivers/platform/chrome/cros_ec_dev.h      |  52 ---
 drivers/platform/chrome/cros_ec_lightbar.c |   6 +-
 drivers/platform/chrome/cros_ec_sysfs.c    |   5 +-
 drivers/platform/chrome/cros_ec_vbc.c      |   1 +
 include/linux/mfd/cros_ec.h                |   4 +
 15 files changed, 633 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

-- 
2.7.4

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 1/2] cros_ec: Split cros_ec_devs module
  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 ` Thierry Escande
  2017-11-29 11:34   ` Lee Jones
  2017-11-30 20:49   ` Guenter Roeck
  2017-11-20 16:15 ` [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd Thierry Escande
  2017-12-15 10:48 ` [GIT PULL] Immutable branch between MFD and Platform due for the v4.16 merge window Lee Jones
  2 siblings, 2 replies; 15+ messages in thread
From: Thierry Escande @ 2017-11-20 16:15 UTC (permalink / raw)
  To: Lee Jones, Benson Leung
  Cc: Enric Balletbo i Serra, Gwendal Grignou, Guenter Roeck, linux-kernel

This patch splits the cros_ec_devs module in two parts with a
cros_ec_dev module responsible for handling MFD devices registration and
a cros_ec_ctl module responsible for handling the various user-space
interfaces.

For consistency purpose, the driver name for the cros_ec_dev module is
now cros-ec-dev instead of cros-ec-ctl.

In the next commit, the new cros_ec_dev module will be moved to the MFD
subtree so mfd_add_devices() calls are not done from outside MFD.

Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
---
 drivers/mfd/cros_ec.c                      | 4 ++--
 drivers/platform/chrome/Kconfig            | 4 ++++
 drivers/platform/chrome/Makefile           | 8 ++++----
 drivers/platform/chrome/cros_ec_debugfs.c  | 2 ++
 drivers/platform/chrome/cros_ec_dev.c      | 7 +++++--
 drivers/platform/chrome/cros_ec_lightbar.c | 4 ++++
 drivers/platform/chrome/cros_ec_sysfs.c    | 3 +++
 drivers/platform/chrome/cros_ec_vbc.c      | 1 +
 8 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index b0ca5a4c..d610241 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -40,13 +40,13 @@ static struct cros_ec_platform pd_p = {
 };
 
 static const struct mfd_cell ec_cell = {
-	.name = "cros-ec-ctl",
+	.name = "cros-ec-dev",
 	.platform_data = &ec_p,
 	.pdata_size = sizeof(ec_p),
 };
 
 static const struct mfd_cell ec_pd_cell = {
-	.name = "cros-ec-ctl",
+	.name = "cros-ec-dev",
 	.platform_data = &pd_p,
 	.pdata_size = sizeof(pd_p),
 };
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 0ad6e29..bffc892 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -41,12 +41,16 @@ config 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
+
 config CROS_EC_LPC
         tristate "ChromeOS Embedded Controller (LPC)"
         depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST)
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index a077b1f..bc239ec 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -2,10 +2,10 @@
 
 obj-$(CONFIG_CHROMEOS_LAPTOP)		+= chromeos_laptop.o
 obj-$(CONFIG_CHROMEOS_PSTORE)		+= chromeos_pstore.o
-cros_ec_devs-objs			:= cros_ec_dev.o cros_ec_sysfs.o \
-					   cros_ec_lightbar.o cros_ec_vbc.o \
-					   cros_ec_debugfs.o
-obj-$(CONFIG_CROS_EC_CHARDEV)		+= cros_ec_devs.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 4cc66f4..d0b8ce0 100644
--- a/drivers/platform/chrome/cros_ec_debugfs.c
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -390,6 +390,7 @@ int cros_ec_debugfs_init(struct cros_ec_dev *ec)
 	debugfs_remove_recursive(debug_info->dir);
 	return ret;
 }
+EXPORT_SYMBOL(cros_ec_debugfs_init);
 
 void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
 {
@@ -399,3 +400,4 @@ void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
 	debugfs_remove_recursive(ec->debug_info->dir);
 	cros_ec_cleanup_console_log(ec->debug_info);
 }
+EXPORT_SYMBOL(cros_ec_debugfs_remove);
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
index cf6c4f0..daf0ffd 100644
--- a/drivers/platform/chrome/cros_ec_dev.c
+++ b/drivers/platform/chrome/cros_ec_dev.c
@@ -28,6 +28,8 @@
 #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;
@@ -461,7 +463,7 @@ static int ec_device_remove(struct platform_device *pdev)
 }
 
 static const struct platform_device_id cros_ec_id[] = {
-	{ "cros-ec-ctl", 0 },
+	{ DRV_NAME, 0 },
 	{ /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(platform, cros_ec_id);
@@ -493,7 +495,7 @@ static const struct dev_pm_ops cros_ec_dev_pm_ops = {
 
 static struct platform_driver cros_ec_dev_driver = {
 	.driver = {
-		.name = "cros-ec-ctl",
+		.name = DRV_NAME,
 		.pm = &cros_ec_dev_pm_ops,
 	},
 	.probe = ec_device_probe,
@@ -544,6 +546,7 @@ static void __exit cros_ec_dev_exit(void)
 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");
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index fd2b047..925d91c 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -414,6 +414,7 @@ int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
 
 	return ret;
 }
+EXPORT_SYMBOL(lb_manual_suspend_ctrl);
 
 int lb_suspend(struct cros_ec_dev *ec)
 {
@@ -422,6 +423,7 @@ int lb_suspend(struct cros_ec_dev *ec)
 
 	return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND);
 }
+EXPORT_SYMBOL(lb_suspend);
 
 int lb_resume(struct cros_ec_dev *ec)
 {
@@ -430,6 +432,7 @@ int lb_resume(struct cros_ec_dev *ec)
 
 	return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME);
 }
+EXPORT_SYMBOL(lb_resume);
 
 static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
 			      const char *buf, size_t count)
@@ -622,3 +625,4 @@ struct attribute_group cros_ec_lightbar_attr_group = {
 	.attrs = __lb_cmds_attrs,
 	.is_visible = cros_ec_lightbar_attrs_are_visible,
 };
+EXPORT_SYMBOL(cros_ec_lightbar_attr_group);
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
index f3baf99..201f11a 100644
--- a/drivers/platform/chrome/cros_ec_sysfs.c
+++ b/drivers/platform/chrome/cros_ec_sysfs.c
@@ -294,4 +294,7 @@ static struct attribute *__ec_attrs[] = {
 struct attribute_group cros_ec_attr_group = {
 	.attrs = __ec_attrs,
 };
+EXPORT_SYMBOL(cros_ec_attr_group);
 
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ChromeOS EC control driver");
diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c
index 564a0d0..6d38e6b 100644
--- a/drivers/platform/chrome/cros_ec_vbc.c
+++ b/drivers/platform/chrome/cros_ec_vbc.c
@@ -135,3 +135,4 @@ struct attribute_group cros_ec_vbc_attr_group = {
 	.bin_attrs = cros_ec_vbc_bin_attrs,
 	.is_bin_visible = cros_ec_vbc_is_visible,
 };
+EXPORT_SYMBOL(cros_ec_vbc_attr_group);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd
  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-20 16:15 ` Thierry Escande
  2017-11-29 11:35   ` Lee Jones
                     ` (2 more replies)
  2017-12-15 10:48 ` [GIT PULL] Immutable branch between MFD and Platform due for the v4.16 merge window Lee Jones
  2 siblings, 3 replies; 15+ messages in thread
From: Thierry Escande @ 2017-11-20 16:15 UTC (permalink / raw)
  To: Lee Jones, Benson Leung
  Cc: Enric Balletbo i Serra, Gwendal Grignou, Guenter Roeck, linux-kernel

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>
---
 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

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/2] cros_ec: Split cros_ec_devs module
  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
  1 sibling, 0 replies; 15+ messages in thread
From: Lee Jones @ 2017-11-29 11:34 UTC (permalink / raw)
  To: Thierry Escande
  Cc: Benson Leung, Enric Balletbo i Serra, Gwendal Grignou,
	Guenter Roeck, linux-kernel

On Mon, 20 Nov 2017, Thierry Escande wrote:

> This patch splits the cros_ec_devs module in two parts with a
> cros_ec_dev module responsible for handling MFD devices registration and
> a cros_ec_ctl module responsible for handling the various user-space
> interfaces.
> 
> For consistency purpose, the driver name for the cros_ec_dev module is
> now cros-ec-dev instead of cros-ec-ctl.
> 
> In the next commit, the new cros_ec_dev module will be moved to the MFD
> subtree so mfd_add_devices() calls are not done from outside MFD.
> 
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
> ---
>  drivers/mfd/cros_ec.c                      | 4 ++--

For the MFD part:
  Acked-by: Lee Jones <lee.jones@linaro.org>

>  drivers/platform/chrome/Kconfig            | 4 ++++
>  drivers/platform/chrome/Makefile           | 8 ++++----
>  drivers/platform/chrome/cros_ec_debugfs.c  | 2 ++
>  drivers/platform/chrome/cros_ec_dev.c      | 7 +++++--
>  drivers/platform/chrome/cros_ec_lightbar.c | 4 ++++
>  drivers/platform/chrome/cros_ec_sysfs.c    | 3 +++
>  drivers/platform/chrome/cros_ec_vbc.c      | 1 +
>  8 files changed, 25 insertions(+), 8 deletions(-)

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd
  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
  2018-06-20 23:05   ` Dmitry Torokhov
  2 siblings, 0 replies; 15+ messages in thread
From: Lee Jones @ 2017-11-29 11:35 UTC (permalink / raw)
  To: Thierry Escande
  Cc: Benson Leung, Enric Balletbo i Serra, Gwendal Grignou,
	Guenter Roeck, linux-kernel

On Mon, 20 Nov 2017, Thierry Escande 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>
> ---
>  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

For my own reference:
  Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/2] cros_ec: Split cros_ec_devs module
  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
  1 sibling, 1 reply; 15+ messages in thread
From: Guenter Roeck @ 2017-11-30 20:49 UTC (permalink / raw)
  To: Thierry Escande
  Cc: Lee Jones, Benson Leung, Enric Balletbo i Serra, Gwendal Grignou,
	linux-kernel

On Mon, Nov 20, 2017 at 8:15 AM, Thierry Escande
<thierry.escande@collabora.com> wrote:
> This patch splits the cros_ec_devs module in two parts with a
> cros_ec_dev module responsible for handling MFD devices registration and
> a cros_ec_ctl module responsible for handling the various user-space
> interfaces.
>
> For consistency purpose, the driver name for the cros_ec_dev module is
> now cros-ec-dev instead of cros-ec-ctl.
>
> In the next commit, the new cros_ec_dev module will be moved to the MFD
> subtree so mfd_add_devices() calls are not done from outside MFD.
>
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>

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

> ---
>  drivers/mfd/cros_ec.c                      | 4 ++--
>  drivers/platform/chrome/Kconfig            | 4 ++++
>  drivers/platform/chrome/Makefile           | 8 ++++----
>  drivers/platform/chrome/cros_ec_debugfs.c  | 2 ++
>  drivers/platform/chrome/cros_ec_dev.c      | 7 +++++--
>  drivers/platform/chrome/cros_ec_lightbar.c | 4 ++++
>  drivers/platform/chrome/cros_ec_sysfs.c    | 3 +++
>  drivers/platform/chrome/cros_ec_vbc.c      | 1 +
>  8 files changed, 25 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
> index b0ca5a4c..d610241 100644
> --- a/drivers/mfd/cros_ec.c
> +++ b/drivers/mfd/cros_ec.c
> @@ -40,13 +40,13 @@ static struct cros_ec_platform pd_p = {
>  };
>
>  static const struct mfd_cell ec_cell = {
> -       .name = "cros-ec-ctl",
> +       .name = "cros-ec-dev",
>         .platform_data = &ec_p,
>         .pdata_size = sizeof(ec_p),
>  };
>
>  static const struct mfd_cell ec_pd_cell = {
> -       .name = "cros-ec-ctl",
> +       .name = "cros-ec-dev",
>         .platform_data = &pd_p,
>         .pdata_size = sizeof(pd_p),
>  };
> diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
> index 0ad6e29..bffc892 100644
> --- a/drivers/platform/chrome/Kconfig
> +++ b/drivers/platform/chrome/Kconfig
> @@ -41,12 +41,16 @@ config 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
> +
>  config CROS_EC_LPC
>          tristate "ChromeOS Embedded Controller (LPC)"
>          depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST)
> diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
> index a077b1f..bc239ec 100644
> --- a/drivers/platform/chrome/Makefile
> +++ b/drivers/platform/chrome/Makefile
> @@ -2,10 +2,10 @@
>
>  obj-$(CONFIG_CHROMEOS_LAPTOP)          += chromeos_laptop.o
>  obj-$(CONFIG_CHROMEOS_PSTORE)          += chromeos_pstore.o
> -cros_ec_devs-objs                      := cros_ec_dev.o cros_ec_sysfs.o \
> -                                          cros_ec_lightbar.o cros_ec_vbc.o \
> -                                          cros_ec_debugfs.o
> -obj-$(CONFIG_CROS_EC_CHARDEV)          += cros_ec_devs.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 4cc66f4..d0b8ce0 100644
> --- a/drivers/platform/chrome/cros_ec_debugfs.c
> +++ b/drivers/platform/chrome/cros_ec_debugfs.c
> @@ -390,6 +390,7 @@ int cros_ec_debugfs_init(struct cros_ec_dev *ec)
>         debugfs_remove_recursive(debug_info->dir);
>         return ret;
>  }
> +EXPORT_SYMBOL(cros_ec_debugfs_init);
>
>  void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
>  {
> @@ -399,3 +400,4 @@ void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
>         debugfs_remove_recursive(ec->debug_info->dir);
>         cros_ec_cleanup_console_log(ec->debug_info);
>  }
> +EXPORT_SYMBOL(cros_ec_debugfs_remove);
> diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
> index cf6c4f0..daf0ffd 100644
> --- a/drivers/platform/chrome/cros_ec_dev.c
> +++ b/drivers/platform/chrome/cros_ec_dev.c
> @@ -28,6 +28,8 @@
>  #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;
> @@ -461,7 +463,7 @@ static int ec_device_remove(struct platform_device *pdev)
>  }
>
>  static const struct platform_device_id cros_ec_id[] = {
> -       { "cros-ec-ctl", 0 },
> +       { DRV_NAME, 0 },
>         { /* sentinel */ },
>  };
>  MODULE_DEVICE_TABLE(platform, cros_ec_id);
> @@ -493,7 +495,7 @@ static const struct dev_pm_ops cros_ec_dev_pm_ops = {
>
>  static struct platform_driver cros_ec_dev_driver = {
>         .driver = {
> -               .name = "cros-ec-ctl",
> +               .name = DRV_NAME,
>                 .pm = &cros_ec_dev_pm_ops,
>         },
>         .probe = ec_device_probe,
> @@ -544,6 +546,7 @@ static void __exit cros_ec_dev_exit(void)
>  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");
> diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
> index fd2b047..925d91c 100644
> --- a/drivers/platform/chrome/cros_ec_lightbar.c
> +++ b/drivers/platform/chrome/cros_ec_lightbar.c
> @@ -414,6 +414,7 @@ int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
>
>         return ret;
>  }
> +EXPORT_SYMBOL(lb_manual_suspend_ctrl);
>
>  int lb_suspend(struct cros_ec_dev *ec)
>  {
> @@ -422,6 +423,7 @@ int lb_suspend(struct cros_ec_dev *ec)
>
>         return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND);
>  }
> +EXPORT_SYMBOL(lb_suspend);
>
>  int lb_resume(struct cros_ec_dev *ec)
>  {
> @@ -430,6 +432,7 @@ int lb_resume(struct cros_ec_dev *ec)
>
>         return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME);
>  }
> +EXPORT_SYMBOL(lb_resume);
>
>  static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
>                               const char *buf, size_t count)
> @@ -622,3 +625,4 @@ struct attribute_group cros_ec_lightbar_attr_group = {
>         .attrs = __lb_cmds_attrs,
>         .is_visible = cros_ec_lightbar_attrs_are_visible,
>  };
> +EXPORT_SYMBOL(cros_ec_lightbar_attr_group);
> diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
> index f3baf99..201f11a 100644
> --- a/drivers/platform/chrome/cros_ec_sysfs.c
> +++ b/drivers/platform/chrome/cros_ec_sysfs.c
> @@ -294,4 +294,7 @@ static struct attribute *__ec_attrs[] = {
>  struct attribute_group cros_ec_attr_group = {
>         .attrs = __ec_attrs,
>  };
> +EXPORT_SYMBOL(cros_ec_attr_group);
>
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("ChromeOS EC control driver");
> diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c
> index 564a0d0..6d38e6b 100644
> --- a/drivers/platform/chrome/cros_ec_vbc.c
> +++ b/drivers/platform/chrome/cros_ec_vbc.c
> @@ -135,3 +135,4 @@ struct attribute_group cros_ec_vbc_attr_group = {
>         .bin_attrs = cros_ec_vbc_bin_attrs,
>         .is_bin_visible = cros_ec_vbc_is_visible,
>  };
> +EXPORT_SYMBOL(cros_ec_vbc_attr_group);
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd
  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
  2017-12-01 19:23     ` Gwendal Grignou
  2018-06-20 23:05   ` Dmitry Torokhov
  2 siblings, 1 reply; 15+ messages in thread
From: Guenter Roeck @ 2017-11-30 20:50 UTC (permalink / raw)
  To: Thierry Escande
  Cc: Lee Jones, Benson Leung, Enric Balletbo i Serra, Gwendal Grignou,
	linux-kernel

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
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd
  2017-11-30 20:50   ` Guenter Roeck
@ 2017-12-01 19:23     ` Gwendal Grignou
  2017-12-04  9:10       ` Lee Jones
  0 siblings, 1 reply; 15+ messages in thread
From: Gwendal Grignou @ 2017-12-01 19:23 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Thierry Escande, Lee Jones, Benson Leung, Enric Balletbo i Serra,
	Gwendal Grignou, linux-kernel

Reviewed-by: Gwendal Grignou <gwendal@chromium.org>

On Thu, Nov 30, 2017 at 12:50 PM, Guenter Roeck <groeck@google.com> wrote:
> 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
>>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 1/2] cros_ec: Split cros_ec_devs module
  2017-11-30 20:49   ` Guenter Roeck
@ 2017-12-01 19:24     ` Gwendal Grignou
  0 siblings, 0 replies; 15+ messages in thread
From: Gwendal Grignou @ 2017-12-01 19:24 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: Thierry Escande, Lee Jones, Benson Leung, Enric Balletbo i Serra,
	Gwendal Grignou, linux-kernel

Reviewed-by: Gwendal Grignou <gwendal@chromium.org>

On Thu, Nov 30, 2017 at 12:49 PM, Guenter Roeck <groeck@google.com> wrote:
> On Mon, Nov 20, 2017 at 8:15 AM, Thierry Escande
> <thierry.escande@collabora.com> wrote:
>> This patch splits the cros_ec_devs module in two parts with a
>> cros_ec_dev module responsible for handling MFD devices registration and
>> a cros_ec_ctl module responsible for handling the various user-space
>> interfaces.
>>
>> For consistency purpose, the driver name for the cros_ec_dev module is
>> now cros-ec-dev instead of cros-ec-ctl.
>>
>> In the next commit, the new cros_ec_dev module will be moved to the MFD
>> subtree so mfd_add_devices() calls are not done from outside MFD.
>>
>> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
>
> Tested-by: Guenter Roeck <groeck@chromium.org>
>
>> ---
>>  drivers/mfd/cros_ec.c                      | 4 ++--
>>  drivers/platform/chrome/Kconfig            | 4 ++++
>>  drivers/platform/chrome/Makefile           | 8 ++++----
>>  drivers/platform/chrome/cros_ec_debugfs.c  | 2 ++
>>  drivers/platform/chrome/cros_ec_dev.c      | 7 +++++--
>>  drivers/platform/chrome/cros_ec_lightbar.c | 4 ++++
>>  drivers/platform/chrome/cros_ec_sysfs.c    | 3 +++
>>  drivers/platform/chrome/cros_ec_vbc.c      | 1 +
>>  8 files changed, 25 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
>> index b0ca5a4c..d610241 100644
>> --- a/drivers/mfd/cros_ec.c
>> +++ b/drivers/mfd/cros_ec.c
>> @@ -40,13 +40,13 @@ static struct cros_ec_platform pd_p = {
>>  };
>>
>>  static const struct mfd_cell ec_cell = {
>> -       .name = "cros-ec-ctl",
>> +       .name = "cros-ec-dev",
>>         .platform_data = &ec_p,
>>         .pdata_size = sizeof(ec_p),
>>  };
>>
>>  static const struct mfd_cell ec_pd_cell = {
>> -       .name = "cros-ec-ctl",
>> +       .name = "cros-ec-dev",
>>         .platform_data = &pd_p,
>>         .pdata_size = sizeof(pd_p),
>>  };
>> diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
>> index 0ad6e29..bffc892 100644
>> --- a/drivers/platform/chrome/Kconfig
>> +++ b/drivers/platform/chrome/Kconfig
>> @@ -41,12 +41,16 @@ config 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
>> +
>>  config CROS_EC_LPC
>>          tristate "ChromeOS Embedded Controller (LPC)"
>>          depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST)
>> diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
>> index a077b1f..bc239ec 100644
>> --- a/drivers/platform/chrome/Makefile
>> +++ b/drivers/platform/chrome/Makefile
>> @@ -2,10 +2,10 @@
>>
>>  obj-$(CONFIG_CHROMEOS_LAPTOP)          += chromeos_laptop.o
>>  obj-$(CONFIG_CHROMEOS_PSTORE)          += chromeos_pstore.o
>> -cros_ec_devs-objs                      := cros_ec_dev.o cros_ec_sysfs.o \
>> -                                          cros_ec_lightbar.o cros_ec_vbc.o \
>> -                                          cros_ec_debugfs.o
>> -obj-$(CONFIG_CROS_EC_CHARDEV)          += cros_ec_devs.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 4cc66f4..d0b8ce0 100644
>> --- a/drivers/platform/chrome/cros_ec_debugfs.c
>> +++ b/drivers/platform/chrome/cros_ec_debugfs.c
>> @@ -390,6 +390,7 @@ int cros_ec_debugfs_init(struct cros_ec_dev *ec)
>>         debugfs_remove_recursive(debug_info->dir);
>>         return ret;
>>  }
>> +EXPORT_SYMBOL(cros_ec_debugfs_init);
>>
>>  void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
>>  {
>> @@ -399,3 +400,4 @@ void cros_ec_debugfs_remove(struct cros_ec_dev *ec)
>>         debugfs_remove_recursive(ec->debug_info->dir);
>>         cros_ec_cleanup_console_log(ec->debug_info);
>>  }
>> +EXPORT_SYMBOL(cros_ec_debugfs_remove);
>> diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
>> index cf6c4f0..daf0ffd 100644
>> --- a/drivers/platform/chrome/cros_ec_dev.c
>> +++ b/drivers/platform/chrome/cros_ec_dev.c
>> @@ -28,6 +28,8 @@
>>  #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;
>> @@ -461,7 +463,7 @@ static int ec_device_remove(struct platform_device *pdev)
>>  }
>>
>>  static const struct platform_device_id cros_ec_id[] = {
>> -       { "cros-ec-ctl", 0 },
>> +       { DRV_NAME, 0 },
>>         { /* sentinel */ },
>>  };
>>  MODULE_DEVICE_TABLE(platform, cros_ec_id);
>> @@ -493,7 +495,7 @@ static const struct dev_pm_ops cros_ec_dev_pm_ops = {
>>
>>  static struct platform_driver cros_ec_dev_driver = {
>>         .driver = {
>> -               .name = "cros-ec-ctl",
>> +               .name = DRV_NAME,
>>                 .pm = &cros_ec_dev_pm_ops,
>>         },
>>         .probe = ec_device_probe,
>> @@ -544,6 +546,7 @@ static void __exit cros_ec_dev_exit(void)
>>  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");
>> diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
>> index fd2b047..925d91c 100644
>> --- a/drivers/platform/chrome/cros_ec_lightbar.c
>> +++ b/drivers/platform/chrome/cros_ec_lightbar.c
>> @@ -414,6 +414,7 @@ int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
>>
>>         return ret;
>>  }
>> +EXPORT_SYMBOL(lb_manual_suspend_ctrl);
>>
>>  int lb_suspend(struct cros_ec_dev *ec)
>>  {
>> @@ -422,6 +423,7 @@ int lb_suspend(struct cros_ec_dev *ec)
>>
>>         return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND);
>>  }
>> +EXPORT_SYMBOL(lb_suspend);
>>
>>  int lb_resume(struct cros_ec_dev *ec)
>>  {
>> @@ -430,6 +432,7 @@ int lb_resume(struct cros_ec_dev *ec)
>>
>>         return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME);
>>  }
>> +EXPORT_SYMBOL(lb_resume);
>>
>>  static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
>>                               const char *buf, size_t count)
>> @@ -622,3 +625,4 @@ struct attribute_group cros_ec_lightbar_attr_group = {
>>         .attrs = __lb_cmds_attrs,
>>         .is_visible = cros_ec_lightbar_attrs_are_visible,
>>  };
>> +EXPORT_SYMBOL(cros_ec_lightbar_attr_group);
>> diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
>> index f3baf99..201f11a 100644
>> --- a/drivers/platform/chrome/cros_ec_sysfs.c
>> +++ b/drivers/platform/chrome/cros_ec_sysfs.c
>> @@ -294,4 +294,7 @@ static struct attribute *__ec_attrs[] = {
>>  struct attribute_group cros_ec_attr_group = {
>>         .attrs = __ec_attrs,
>>  };
>> +EXPORT_SYMBOL(cros_ec_attr_group);
>>
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("ChromeOS EC control driver");
>> diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c
>> index 564a0d0..6d38e6b 100644
>> --- a/drivers/platform/chrome/cros_ec_vbc.c
>> +++ b/drivers/platform/chrome/cros_ec_vbc.c
>> @@ -135,3 +135,4 @@ struct attribute_group cros_ec_vbc_attr_group = {
>>         .bin_attrs = cros_ec_vbc_bin_attrs,
>>         .is_bin_visible = cros_ec_vbc_is_visible,
>>  };
>> +EXPORT_SYMBOL(cros_ec_vbc_attr_group);
>> --
>> 2.7.4
>>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd
  2017-12-01 19:23     ` Gwendal Grignou
@ 2017-12-04  9:10       ` Lee Jones
  0 siblings, 0 replies; 15+ messages in thread
From: Lee Jones @ 2017-12-04  9:10 UTC (permalink / raw)
  To: Gwendal Grignou
  Cc: Guenter Roeck, Thierry Escande, Benson Leung,
	Enric Balletbo i Serra, linux-kernel

On Fri, 01 Dec 2017, Gwendal Grignou wrote:

> Reviewed-by: Gwendal Grignou <gwendal@chromium.org>

Can you please reply inline (where Guenter did is perfect) and snip
the rest please?  Top posting is to be strongly discouraged.

> On Thu, Nov 30, 2017 at 12:50 PM, Guenter Roeck <groeck@google.com> wrote:
> > 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

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [GIT PULL] Immutable branch between MFD and Platform due for the v4.16 merge window
  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-20 16:15 ` [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd Thierry Escande
@ 2017-12-15 10:48 ` Lee Jones
  2017-12-16  4:50   ` Benson Leung
  2 siblings, 1 reply; 15+ messages in thread
From: Lee Jones @ 2017-12-15 10:48 UTC (permalink / raw)
  To: Thierry Escande
  Cc: Benson Leung, Enric Balletbo i Serra, Gwendal Grignou,
	Guenter Roeck, linux-kernel

Enjoy!

The following changes since commit 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323:

  Linux 4.15-rc1 (2017-11-26 16:01:47 -0800)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git ib-mfd-platform-v4.16

for you to fetch changes up to 5e0115581bbc367c7958bf5ab8c511b808558533:

  cros_ec: Move cros_ec_dev module to drivers/mfd (2017-12-15 10:46:06 +0000)

----------------------------------------------------------------
Immutable branch between MFD and Platform due for the v4.16 merge window

----------------------------------------------------------------
Thierry Escande (2):
      cros_ec: Split cros_ec_devs module
      cros_ec: Move cros_ec_dev module to drivers/mfd

 drivers/mfd/Kconfig                            | 10 ++++++++++
 drivers/mfd/Makefile                           |  1 +
 drivers/mfd/cros_ec.c                          |  4 ++--
 drivers/{platform/chrome => mfd}/cros_ec_dev.c |  8 +++++---
 drivers/{platform/chrome => mfd}/cros_ec_dev.h |  0
 drivers/platform/chrome/Kconfig                | 10 ++--------
 drivers/platform/chrome/Makefile               |  7 +++----
 drivers/platform/chrome/cros_ec_debugfs.c      |  5 ++---
 drivers/platform/chrome/cros_ec_debugfs.h      | 27 --------------------------
 drivers/platform/chrome/cros_ec_lightbar.c     |  6 ++++--
 drivers/platform/chrome/cros_ec_sysfs.c        |  5 +++--
 drivers/platform/chrome/cros_ec_vbc.c          |  1 +
 include/linux/mfd/cros_ec.h                    |  4 ++++
 13 files changed, 37 insertions(+), 51 deletions(-)
 rename drivers/{platform/chrome => mfd}/cros_ec_dev.c (99%)
 rename drivers/{platform/chrome => mfd}/cros_ec_dev.h (100%)
 delete mode 100644 drivers/platform/chrome/cros_ec_debugfs.h
 
-- 
Lee Jones
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [GIT PULL] Immutable branch between MFD and Platform due for the v4.16 merge window
  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
  0 siblings, 0 replies; 15+ messages in thread
From: Benson Leung @ 2017-12-16  4:50 UTC (permalink / raw)
  To: Lee Jones
  Cc: Thierry Escande, Benson Leung, Enric Balletbo i Serra,
	Gwendal Grignou, Guenter Roeck, linux-kernel, bleung

[-- Attachment #1: Type: text/plain, Size: 2280 bytes --]

Hi Lee,

On Fri, Dec 15, 2017 at 10:48:20AM +0000, Lee Jones wrote:
> Enjoy!
> 
> The following changes since commit 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323:
> 
>   Linux 4.15-rc1 (2017-11-26 16:01:47 -0800)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git ib-mfd-platform-v4.16
> 
> for you to fetch changes up to 5e0115581bbc367c7958bf5ab8c511b808558533:
> 
>   cros_ec: Move cros_ec_dev module to drivers/mfd (2017-12-15 10:46:06 +0000)
> 
> ----------------------------------------------------------------
> Immutable branch between MFD and Platform due for the v4.16 merge window
> 
> ----------------------------------------------------------------
> Thierry Escande (2):
>       cros_ec: Split cros_ec_devs module
>       cros_ec: Move cros_ec_dev module to drivers/mfd
> 
>  drivers/mfd/Kconfig                            | 10 ++++++++++
>  drivers/mfd/Makefile                           |  1 +
>  drivers/mfd/cros_ec.c                          |  4 ++--
>  drivers/{platform/chrome => mfd}/cros_ec_dev.c |  8 +++++---
>  drivers/{platform/chrome => mfd}/cros_ec_dev.h |  0
>  drivers/platform/chrome/Kconfig                | 10 ++--------
>  drivers/platform/chrome/Makefile               |  7 +++----
>  drivers/platform/chrome/cros_ec_debugfs.c      |  5 ++---
>  drivers/platform/chrome/cros_ec_debugfs.h      | 27 --------------------------
>  drivers/platform/chrome/cros_ec_lightbar.c     |  6 ++++--
>  drivers/platform/chrome/cros_ec_sysfs.c        |  5 +++--
>  drivers/platform/chrome/cros_ec_vbc.c          |  1 +
>  include/linux/mfd/cros_ec.h                    |  4 ++++
>  13 files changed, 37 insertions(+), 51 deletions(-)
>  rename drivers/{platform/chrome => mfd}/cros_ec_dev.c (99%)
>  rename drivers/{platform/chrome => mfd}/cros_ec_dev.h (100%)
>  delete mode 100644 drivers/platform/chrome/cros_ec_debugfs.h
>  
> -- 
> Lee Jones
> Linaro Services Technical Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog


Excellent. Pulled. Thank you so much!

-- 
Benson Leung
Staff Software Engineer
Chrome OS Kernel
Google Inc.
bleung@google.com
Chromium OS Project
bleung@chromium.org

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd
  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
@ 2018-06-20 23:05   ` Dmitry Torokhov
  2018-06-21  8:42     ` Enric Balletbo i Serra
  2018-07-03  9:03     ` Lee Jones
  2 siblings, 2 replies; 15+ messages in thread
From: Dmitry Torokhov @ 2018-06-20 23:05 UTC (permalink / raw)
  To: Lee Jones
  Cc: Benson Leung, Enric Balletbo i Serra, Gwendal Grignou,
	Guenter Roeck, lkml, Thierry Escande

On Mon, Nov 20, 2017 at 8:18 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.

I am quite a bit late to the party, but what's the rationale for not
using mfd_add_devices() from outside of MFD tree? We do allow
registering i2c clients from outside of i2c core, and spi from outside
of spi core, etc, etc.

Right now I see cros_ec being split, quite haphazardly, between
drivers/platform/chrome and drivers/mfd, with some transport drivers
(i2C, SPI) and some interfaces living in MFD, while LPC transport and
host of other stuff living in drivers/platform. On top of that we have
cros_ec_keyb in input, RTC drivers, CEC, and god knows what else
spread across various subsystems:

dtor@dtor-ws:~/kernel/linus $ find -name 'cros_ec*.c'
./drivers/iio/light/cros_ec_light_prox.c
./drivers/iio/accel/cros_ec_accel_legacy.c
./drivers/iio/pressure/cros_ec_baro.c
./drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
./drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
./drivers/mfd/cros_ec_spi.c
./drivers/mfd/cros_ec.c
./drivers/mfd/cros_ec_i2c.c
./drivers/mfd/cros_ec_dev.c
./drivers/input/keyboard/cros_ec_keyb.c
./drivers/platform/chrome/cros_ec_vbc.c
./drivers/platform/chrome/cros_ec_debugfs.c
./drivers/platform/chrome/cros_ec_lpc.c
./drivers/platform/chrome/cros_ec_lightbar.c
./drivers/platform/chrome/cros_ec_lpc_reg.c
./drivers/platform/chrome/cros_ec_proto.c
./drivers/platform/chrome/cros_ec_lpc_mec.c
./drivers/platform/chrome/cros_ec_sysfs.c

The fact that sysfs/debugfs code is in platform but we instantiate it
from MFD is pure madness (it's driver private data, there is no reason
why it should be exported to nclude/linux/mfd/cros_ec.h). This all
creates unnecessary friction and I would love to move most of the code
into drivers/platform/chrome.

I see the wisdom of having code that could potentially be used in
several systems in respective subsystems code (pretty much majority of
drivers/mfd/ drivers are for chips/IP blocks that are used and reused
by different systems and boards), but I think cros ec is quite
different in that regard as it is only used by ChromeOS devices and
has little to no chance to be useful anywhere else.

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd
  2018-06-20 23:05   ` Dmitry Torokhov
@ 2018-06-21  8:42     ` Enric Balletbo i Serra
  2018-07-03  9:03     ` Lee Jones
  1 sibling, 0 replies; 15+ messages in thread
From: Enric Balletbo i Serra @ 2018-06-21  8:42 UTC (permalink / raw)
  To: Dmitry Torokhov, Lee Jones
  Cc: Benson Leung, Gwendal Grignou, Guenter Roeck, lkml,
	thierry.escande, Gwendal Grignou

Hi Dmitry,

I think I can answer some of your questions (not all).

cc'ing the new Thierry's address and Gwendal.

On 21/06/18 01:05, Dmitry Torokhov wrote:
> On Mon, Nov 20, 2017 at 8:18 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.
> 
> I am quite a bit late to the party, but what's the rationale for not
> using mfd_add_devices() from outside of MFD tree? We do allow
> registering i2c clients from outside of i2c core, and spi from outside
> of spi core, etc, etc.
> 

What I can say here is that when I tried to use mfd_add_devices outside the mfd
Lee has the preference to not to do this. That's the main reason why we moved
cros_ec_dev to mfd subsystem. The origin of this discussion started here [1] and
iirc after talk with Lee via irc he was not agree to use mfd_add_devices outside
the mfd subsystem (Lee correct me if I am wrong). So, is Lee who can add the
reasoning here.

[1] https://www.spinics.net/lists/kernel/msg2465099.html

> Right now I see cros_ec being split, quite haphazardly, between
> drivers/platform/chrome and drivers/mfd, with some transport drivers
> (i2C, SPI) and some interfaces living in MFD, while LPC transport and
> host of other stuff living in drivers/platform. On top of that we have
> cros_ec_keyb in input, RTC drivers, CEC, and god knows what else
> spread across various subsystems:
> 

Move the transport driver to platform/chrome is on my TODO, I didn't send the
patches to upstream yet, sorry about that.

About having the driver spread across various subsystem I don't have a hard
opinion. I suppose that this is because is the common way for mfd cells,
although, in this case, it is true that the drivers are very ChromeOS specific,
so maybe has sense have all in platform/chrome. On the other side, if you put
all in platform/chrome you will probably lost the advantage of have the
maintainer of the subsytem reviewing the patches (just because he filters the
drivers that doesn't go their subsystem).

> dtor@dtor-ws:~/kernel/linus $ find -name 'cros_ec*.c'
> ./drivers/iio/light/cros_ec_light_prox.c
> ./drivers/iio/accel/cros_ec_accel_legacy.c
> ./drivers/iio/pressure/cros_ec_baro.c
> ./drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
> ./drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
> ./drivers/mfd/cros_ec_spi.c
> ./drivers/mfd/cros_ec.c
> ./drivers/mfd/cros_ec_i2c.c
> ./drivers/mfd/cros_ec_dev.c
> ./drivers/input/keyboard/cros_ec_keyb.c
> ./drivers/platform/chrome/cros_ec_vbc.c
> ./drivers/platform/chrome/cros_ec_debugfs.c
> ./drivers/platform/chrome/cros_ec_lpc.c
> ./drivers/platform/chrome/cros_ec_lightbar.c
> ./drivers/platform/chrome/cros_ec_lpc_reg.c
> ./drivers/platform/chrome/cros_ec_proto.c
> ./drivers/platform/chrome/cros_ec_lpc_mec.c
> ./drivers/platform/chrome/cros_ec_sysfs.c
> 
> The fact that sysfs/debugfs code is in platform but we instantiate it
> from MFD is pure madness (it's driver private data, there is no reason
> why it should be exported to nclude/linux/mfd/cros_ec.h). This all
> creates unnecessary friction and I would love to move most of the code
> into drivers/platform/chrome.
> 

Ack.

> I see the wisdom of having code that could potentially be used in
> several systems in respective subsystems code (pretty much majority of
> drivers/mfd/ drivers are for chips/IP blocks that are used and reused
> by different systems and boards), but I think cros ec is quite
> different in that regard as it is only used by ChromeOS devices and
> has little to no chance to be useful anywhere else.
> 
> Thanks.
> 

Cheers,
 Enric

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/2] cros_ec: Move cros_ec_dev module to drivers/mfd
  2018-06-20 23:05   ` Dmitry Torokhov
  2018-06-21  8:42     ` Enric Balletbo i Serra
@ 2018-07-03  9:03     ` Lee Jones
  1 sibling, 0 replies; 15+ messages in thread
From: Lee Jones @ 2018-07-03  9:03 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Benson Leung, Enric Balletbo i Serra, Gwendal Grignou,
	Guenter Roeck, lkml, Thierry Escande

On Wed, 20 Jun 2018, Dmitry Torokhov wrote:
> On Mon, Nov 20, 2017 at 8:18 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.
> 
> I am quite a bit late to the party, but what's the rationale for not
> using mfd_add_devices() from outside of MFD tree? We do allow
> registering i2c clients from outside of i2c core, and spi from outside
> of spi core, etc, etc.

The rationale for not using the MFD API outside of drivers/mfd is the
avoidance of (mild) chaos, since the aforementioned API lends itself to
abuse if not diligently monitored - preferably by someone who knows
about MFDs.  Contributors regularly attempt to (ab)use the MFD API to
hack around various problems relating to the registration of devices.
Most of which receive a "this is not an MFD" review comment and sent
on their way!

MFD is not like anything else in the kernel, so comparing it bus types
such as SPI and I2C does not carry much weight.  The MFD Subsystem's
job is simple; slice multi-function ICs into separate functional areas
and register the resultant sub-devices whist managing shared
resources.  The parent drivers should all reside in drivers/mfd.

> Right now I see cros_ec being split, quite haphazardly, between
> drivers/platform/chrome and drivers/mfd, with some transport drivers
> (i2C, SPI) and some interfaces living in MFD, while LPC transport and
> host of other stuff living in drivers/platform. On top of that we have
> cros_ec_keyb in input, RTC drivers, CEC, and god knows what else
> spread across various subsystems:

AFAICS, there aren't any compelling reasons for the CROS drivers to
continue to reside in drivers/mfd or their use of the MFD API.  It
would be better if they moved into drivers/platform and dropped the
use of the MFD API entirely.  Simply use platform_device_add() in its
place.

> dtor@dtor-ws:~/kernel/linus $ find -name 'cros_ec*.c'
> ./drivers/iio/light/cros_ec_light_prox.c
> ./drivers/iio/accel/cros_ec_accel_legacy.c
> ./drivers/iio/pressure/cros_ec_baro.c
> ./drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
> ./drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
> ./drivers/mfd/cros_ec_spi.c
> ./drivers/mfd/cros_ec.c
> ./drivers/mfd/cros_ec_i2c.c
> ./drivers/mfd/cros_ec_dev.c
> ./drivers/input/keyboard/cros_ec_keyb.c
> ./drivers/platform/chrome/cros_ec_vbc.c
> ./drivers/platform/chrome/cros_ec_debugfs.c
> ./drivers/platform/chrome/cros_ec_lpc.c
> ./drivers/platform/chrome/cros_ec_lightbar.c
> ./drivers/platform/chrome/cros_ec_lpc_reg.c
> ./drivers/platform/chrome/cros_ec_proto.c
> ./drivers/platform/chrome/cros_ec_lpc_mec.c
> ./drivers/platform/chrome/cros_ec_sysfs.c
> 
> The fact that sysfs/debugfs code is in platform but we instantiate it
> from MFD is pure madness (it's driver private data, there is no reason
> why it should be exported to nclude/linux/mfd/cros_ec.h). This all
> creates unnecessary friction and I would love to move most of the code
> into drivers/platform/chrome.
> 
> I see the wisdom of having code that could potentially be used in
> several systems in respective subsystems code (pretty much majority of
> drivers/mfd/ drivers are for chips/IP blocks that are used and reused
> by different systems and boards), but I think cros ec is quite
> different in that regard as it is only used by ChromeOS devices and
> has little to no chance to be useful anywhere else.
> 
> Thanks.
> 

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2018-07-03  9:03 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
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

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).