From 7aa703bb8824384baad732043a925b46a4f3efa8 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:00 +0200 Subject: mfd / platform: cros_ec: Handle chained ECs as platform devices An MFD is a device that contains several sub-devices (cells). For instance, the ChromeOS EC fits in this description as usually contains a charger and can have other devices with different functions like a Real-Time Clock, an Audio codec, a Real-Time Clock, ... If you look at the driver, though, we're doing something odd. We have two MFD cros-ec drivers where one of them (cros-ec-core) instantiates another MFD driver as sub-driver (cros-ec-dev), and the latest instantiates the different sub-devices (Real-Time Clock, Audio codec, etc). MFD ------------------------------------------ cros-ec-core |___ mfd-cellA (cros-ec-dev) | |__ mfd-cell0 | |__ mfd-cell1 | |__ ... | |___ mfd-cellB (cros-ec-dev) |__ mfd-cell0 |__ mfd-cell1 |__ ... The problem that was trying to solve is to describe some kind of topology for the case where we have an EC (cros-ec) chained with another EC (cros-pd). Apart from that this extends the bounds of what MFD was designed to do we might be interested on have other kinds of topology that can't be implemented in that way. Let's prepare the code to move the cros-ec-core part from MFD to platform/chrome as this is clearly a platform specific thing non-related to a MFD device. platform/chrome | MFD ------------------------------------------ | cros-ec ________|___ cros-ec-dev | |__ mfd-cell0 | |__ mfd-cell1 | |__ ... | cros-pd ________|___ cros-ec-dev | |__ mfd-cell0 | |__ mfd-cell1 | |__ ... Signed-off-by: Enric Balletbo i Serra Acked-by: Andy Shevchenko Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Signed-off-by: Lee Jones --- drivers/mfd/cros_ec.c | 61 ++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 2a9ac5213893..a54ad47c7b02 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -31,18 +30,6 @@ static struct cros_ec_platform pd_p = { .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX), }; -static const struct mfd_cell ec_cell = { - .name = "cros-ec-dev", - .platform_data = &ec_p, - .pdata_size = sizeof(ec_p), -}; - -static const struct mfd_cell ec_pd_cell = { - .name = "cros-ec-dev", - .platform_data = &pd_p, - .pdata_size = sizeof(pd_p), -}; - static irqreturn_t ec_irq_thread(int irq, void *data) { struct cros_ec_device *ec_dev = data; @@ -154,38 +141,42 @@ int cros_ec_register(struct cros_ec_device *ec_dev) } } - err = devm_mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell, - 1, NULL, ec_dev->irq, NULL); - if (err) { - dev_err(dev, - "Failed to register Embedded Controller subdevice %d\n", - err); - return err; + /* Register a platform device for the main EC instance */ + ec_dev->ec = platform_device_register_data(ec_dev->dev, "cros-ec-dev", + PLATFORM_DEVID_AUTO, &ec_p, + sizeof(struct cros_ec_platform)); + if (IS_ERR(ec_dev->ec)) { + dev_err(ec_dev->dev, + "Failed to create CrOS EC platform device\n"); + return PTR_ERR(ec_dev->ec); } if (ec_dev->max_passthru) { /* - * Register a PD device as well on top of this device. + * Register a platform device for the PD behind the main EC. * We make the following assumptions: * - behind an EC, we have a pd * - only one device added. * - the EC is responsive at init time (it is not true for a - * sensor hub. + * sensor hub). */ - err = devm_mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, - &ec_pd_cell, 1, NULL, ec_dev->irq, NULL); - if (err) { - dev_err(dev, - "Failed to register Power Delivery subdevice %d\n", - err); - return err; + ec_dev->pd = platform_device_register_data(ec_dev->dev, + "cros-ec-dev", + PLATFORM_DEVID_AUTO, &pd_p, + sizeof(struct cros_ec_platform)); + if (IS_ERR(ec_dev->pd)) { + dev_err(ec_dev->dev, + "Failed to create CrOS PD platform device\n"); + platform_device_unregister(ec_dev->ec); + return PTR_ERR(ec_dev->pd); } } if (IS_ENABLED(CONFIG_OF) && dev->of_node) { err = devm_of_platform_populate(dev); if (err) { - mfd_remove_devices(dev); + platform_device_unregister(ec_dev->pd); + platform_device_unregister(ec_dev->ec); dev_err(dev, "Failed to register sub-devices\n"); return err; } @@ -206,6 +197,16 @@ int cros_ec_register(struct cros_ec_device *ec_dev) } EXPORT_SYMBOL(cros_ec_register); +int cros_ec_unregister(struct cros_ec_device *ec_dev) +{ + if (ec_dev->pd) + platform_device_unregister(ec_dev->pd); + platform_device_unregister(ec_dev->ec); + + return 0; +} +EXPORT_SYMBOL(cros_ec_unregister); + #ifdef CONFIG_PM_SLEEP int cros_ec_suspend(struct cros_ec_device *ec_dev) { -- cgit From 47f11e0b40e97f373da4efbacee0a9526c816ed5 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:01 +0200 Subject: mfd / platform: cros_ec: Move cros-ec core driver out from MFD Now, the ChromeOS EC core driver has nothing related to an MFD device, so move that driver from the MFD subsystem to the platform/chrome subsystem. Signed-off-by: Enric Balletbo i Serra Acked-by: Andy Shevchenko Acked-by: Thierry Reding Acked-by: Mark Brown Acked-by: Wolfram Sang Acked-by: Neil Armstrong Acked-by: Alexandre Belloni Acked-by: Jonathan Cameron Acked-by: Benjamin Tissoires Acked-by: Dmitry Torokhov Acked-by: Sebastian Reichel Acked-by: Chanwoo Choi Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 15 +-- drivers/mfd/Makefile | 2 - drivers/mfd/cros_ec.c | 280 -------------------------------------------------- 3 files changed, 2 insertions(+), 295 deletions(-) delete mode 100644 drivers/mfd/cros_ec.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f129f9678940..d79882b608cf 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -211,21 +211,10 @@ config MFD_AXP20X_RSB components like regulators or the PEK (Power Enable Key) under the corresponding menus. -config MFD_CROS_EC - tristate "ChromeOS Embedded Controller" - select MFD_CORE - select CHROME_PLATFORMS - select CROS_EC_PROTO - depends on X86 || ARM || ARM64 || COMPILE_TEST - help - If you say Y here you get support for the ChromeOS Embedded - Controller (EC) providing keyboard, battery and power services. - You also need to enable the driver for the bus you are using. The - protocol for talking to the EC is defined by the bus driver. - config MFD_CROS_EC_CHARDEV tristate "Chrome OS Embedded Controller userspace device interface" - depends on MFD_CROS_EC + depends on CROS_EC + select MFD_CORE ---help--- This driver adds support to talk with the ChromeOS EC from userspace. diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f026ada68f6a..59ab5bf51b65 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -13,8 +13,6 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o -cros_ec_core-objs := cros_ec.o -obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o obj-$(CONFIG_MFD_CROS_EC_CHARDEV) += cros_ec_dev.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c deleted file mode 100644 index a54ad47c7b02..000000000000 --- a/drivers/mfd/cros_ec.c +++ /dev/null @@ -1,280 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * ChromeOS EC multi-function device - * - * Copyright (C) 2012 Google, Inc - * - * The ChromeOS EC multi function device is used to mux all the requests - * to the EC device for its multiple features: keyboard controller, - * battery charging and regulator control, firmware update. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define CROS_EC_DEV_EC_INDEX 0 -#define CROS_EC_DEV_PD_INDEX 1 - -static struct cros_ec_platform ec_p = { - .ec_name = CROS_EC_DEV_NAME, - .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX), -}; - -static struct cros_ec_platform pd_p = { - .ec_name = CROS_EC_DEV_PD_NAME, - .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX), -}; - -static irqreturn_t ec_irq_thread(int irq, void *data) -{ - struct cros_ec_device *ec_dev = data; - bool wake_event = true; - int ret; - - ret = cros_ec_get_next_event(ec_dev, &wake_event); - - /* - * Signal only if wake host events or any interrupt if - * cros_ec_get_next_event() returned an error (default value for - * wake_event is true) - */ - if (wake_event && device_may_wakeup(ec_dev->dev)) - pm_wakeup_event(ec_dev->dev, 0); - - if (ret > 0) - blocking_notifier_call_chain(&ec_dev->event_notifier, - 0, ec_dev); - return IRQ_HANDLED; -} - -static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event) -{ - int ret; - struct { - struct cros_ec_command msg; - union { - struct ec_params_host_sleep_event req0; - struct ec_params_host_sleep_event_v1 req1; - struct ec_response_host_sleep_event_v1 resp1; - } u; - } __packed buf; - - memset(&buf, 0, sizeof(buf)); - - if (ec_dev->host_sleep_v1) { - buf.u.req1.sleep_event = sleep_event; - buf.u.req1.suspend_params.sleep_timeout_ms = - EC_HOST_SLEEP_TIMEOUT_DEFAULT; - - buf.msg.outsize = sizeof(buf.u.req1); - if ((sleep_event == HOST_SLEEP_EVENT_S3_RESUME) || - (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) - buf.msg.insize = sizeof(buf.u.resp1); - - buf.msg.version = 1; - - } else { - buf.u.req0.sleep_event = sleep_event; - buf.msg.outsize = sizeof(buf.u.req0); - } - - buf.msg.command = EC_CMD_HOST_SLEEP_EVENT; - - ret = cros_ec_cmd_xfer(ec_dev, &buf.msg); - - /* For now, report failure to transition to S0ix with a warning. */ - if (ret >= 0 && ec_dev->host_sleep_v1 && - (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) { - ec_dev->last_resume_result = - buf.u.resp1.resume_response.sleep_transitions; - - WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions & - EC_HOST_RESUME_SLEEP_TIMEOUT, - "EC detected sleep transition timeout. Total slp_s0 transitions: %d", - buf.u.resp1.resume_response.sleep_transitions & - EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK); - } - - return ret; -} - -int cros_ec_register(struct cros_ec_device *ec_dev) -{ - struct device *dev = ec_dev->dev; - int err = 0; - - BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier); - - ec_dev->max_request = sizeof(struct ec_params_hello); - ec_dev->max_response = sizeof(struct ec_response_get_protocol_info); - ec_dev->max_passthru = 0; - - ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL); - if (!ec_dev->din) - return -ENOMEM; - - ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL); - if (!ec_dev->dout) - return -ENOMEM; - - mutex_init(&ec_dev->lock); - - err = cros_ec_query_all(ec_dev); - if (err) { - dev_err(dev, "Cannot identify the EC: error %d\n", err); - return err; - } - - if (ec_dev->irq) { - err = devm_request_threaded_irq(dev, ec_dev->irq, NULL, - ec_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "chromeos-ec", ec_dev); - if (err) { - dev_err(dev, "Failed to request IRQ %d: %d", - ec_dev->irq, err); - return err; - } - } - - /* Register a platform device for the main EC instance */ - ec_dev->ec = platform_device_register_data(ec_dev->dev, "cros-ec-dev", - PLATFORM_DEVID_AUTO, &ec_p, - sizeof(struct cros_ec_platform)); - if (IS_ERR(ec_dev->ec)) { - dev_err(ec_dev->dev, - "Failed to create CrOS EC platform device\n"); - return PTR_ERR(ec_dev->ec); - } - - if (ec_dev->max_passthru) { - /* - * Register a platform device for the PD behind the main EC. - * We make the following assumptions: - * - behind an EC, we have a pd - * - only one device added. - * - the EC is responsive at init time (it is not true for a - * sensor hub). - */ - ec_dev->pd = platform_device_register_data(ec_dev->dev, - "cros-ec-dev", - PLATFORM_DEVID_AUTO, &pd_p, - sizeof(struct cros_ec_platform)); - if (IS_ERR(ec_dev->pd)) { - dev_err(ec_dev->dev, - "Failed to create CrOS PD platform device\n"); - platform_device_unregister(ec_dev->ec); - return PTR_ERR(ec_dev->pd); - } - } - - if (IS_ENABLED(CONFIG_OF) && dev->of_node) { - err = devm_of_platform_populate(dev); - if (err) { - platform_device_unregister(ec_dev->pd); - platform_device_unregister(ec_dev->ec); - dev_err(dev, "Failed to register sub-devices\n"); - return err; - } - } - - /* - * Clear sleep event - this will fail harmlessly on platforms that - * don't implement the sleep event host command. - */ - err = cros_ec_sleep_event(ec_dev, 0); - if (err < 0) - dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec", - err); - - dev_info(dev, "Chrome EC device registered\n"); - - return 0; -} -EXPORT_SYMBOL(cros_ec_register); - -int cros_ec_unregister(struct cros_ec_device *ec_dev) -{ - if (ec_dev->pd) - platform_device_unregister(ec_dev->pd); - platform_device_unregister(ec_dev->ec); - - return 0; -} -EXPORT_SYMBOL(cros_ec_unregister); - -#ifdef CONFIG_PM_SLEEP -int cros_ec_suspend(struct cros_ec_device *ec_dev) -{ - struct device *dev = ec_dev->dev; - int ret; - u8 sleep_event; - - sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ? - HOST_SLEEP_EVENT_S3_SUSPEND : - HOST_SLEEP_EVENT_S0IX_SUSPEND; - - ret = cros_ec_sleep_event(ec_dev, sleep_event); - if (ret < 0) - dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec", - ret); - - if (device_may_wakeup(dev)) - ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq); - - disable_irq(ec_dev->irq); - ec_dev->was_wake_device = ec_dev->wake_enabled; - ec_dev->suspended = true; - - return 0; -} -EXPORT_SYMBOL(cros_ec_suspend); - -static void cros_ec_report_events_during_suspend(struct cros_ec_device *ec_dev) -{ - while (ec_dev->mkbp_event_supported && - cros_ec_get_next_event(ec_dev, NULL) > 0) - blocking_notifier_call_chain(&ec_dev->event_notifier, - 1, ec_dev); -} - -int cros_ec_resume(struct cros_ec_device *ec_dev) -{ - int ret; - u8 sleep_event; - - ec_dev->suspended = false; - enable_irq(ec_dev->irq); - - sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ? - HOST_SLEEP_EVENT_S3_RESUME : - HOST_SLEEP_EVENT_S0IX_RESUME; - - ret = cros_ec_sleep_event(ec_dev, sleep_event); - if (ret < 0) - dev_dbg(ec_dev->dev, "Error %d sending resume event to ec", - ret); - - if (ec_dev->wake_enabled) { - disable_irq_wake(ec_dev->irq); - ec_dev->wake_enabled = 0; - } - /* - * Let the mfd devices know about events that occur during - * suspend. This way the clients know what to do with them. - */ - cros_ec_report_events_during_suspend(ec_dev); - - - return 0; -} -EXPORT_SYMBOL(cros_ec_resume); - -#endif - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("ChromeOS EC core driver"); -- cgit From eda2e30c6684d67288edb841c6125d48c608a242 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:02 +0200 Subject: mfd / platform: cros_ec: Miscellaneous character device to talk with the EC That's a driver to talk with the ChromeOS Embedded Controller via a miscellaneous character device, it creates an entry in /dev for every instance and implements basic file operations for communicating with the Embedded Controller with an userspace application. The API is moved to the uapi folder, which is supposed to contain the user space API of the kernel. Note that this will replace current character device interface implemented in the cros-ec-dev driver in the MFD subsystem. The idea is to move all the functionality that extends the bounds of what MFD was designed to platform/chrome subsystem. Signed-off-by: Enric Balletbo i Serra Acked-by: Andy Shevchenko Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_dev.c | 4 +++- drivers/mfd/cros_ec_dev.h | 35 ----------------------------------- 2 files changed, 3 insertions(+), 36 deletions(-) delete mode 100644 drivers/mfd/cros_ec_dev.h (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 41dccced5026..4c96445b1bf5 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -7,15 +7,17 @@ #include #include +#include +#include #include #include +#include #include #include #include #include #include -#include "cros_ec_dev.h" #define DRV_NAME "cros-ec-dev" diff --git a/drivers/mfd/cros_ec_dev.h b/drivers/mfd/cros_ec_dev.h deleted file mode 100644 index 7a42c3ef50e4..000000000000 --- a/drivers/mfd/cros_ec_dev.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * cros_ec_dev - expose the Chrome OS Embedded Controller to userspace - * - * Copyright (C) 2014 Google, Inc. - */ - -#ifndef _CROS_EC_DEV_H_ -#define _CROS_EC_DEV_H_ - -#include -#include -#include - -#define CROS_EC_DEV_VERSION "1.0.0" - -/** - * struct cros_ec_readmem - Struct used to read mapped memory. - * @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. The ioctl returns the number of bytes - * read or 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) - -#endif /* _CROS_EC_DEV_H_ */ -- cgit From 459aedb9a5d4b92e4aee343ee8ee5aeca8e1d93a Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:03 +0200 Subject: mfd: cros_ec: Switch to use the new cros-ec-chardev driver With the purpose of remove the things that far extends the bounds of what a MFD was designed to do, instantiate the new platform misc cros-ec-chardev driver and get rid of all the unneeded code. After this patch the misc chardev driver is a sub-device of the MFD, and all the new file operations should be implemented there. Signed-off-by: Enric Balletbo i Serra Acked-by: Andy Shevchenko Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_dev.c | 220 ++-------------------------------------------- 1 file changed, 6 insertions(+), 214 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 4c96445b1bf5..0c1c0ce3453e 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -5,76 +5,23 @@ * Copyright (C) 2014 Google, Inc. */ -#include #include #include #include #include #include -#include #include #include -#include +#include #include -#include - #define DRV_NAME "cros-ec-dev" -/* Device variables */ -#define CROS_MAX_DEV 128 -static int ec_major; - static struct class cros_class = { .owner = THIS_MODULE, .name = "chromeos", }; -/* 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; @@ -110,142 +57,6 @@ static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) 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 num; -} - -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 cros_ec_class_release(struct device *dev) { kfree(to_cros_ec_dev(dev)); @@ -453,6 +264,7 @@ static const struct mfd_cell cros_usbpd_charger_cells[] = { }; static const struct mfd_cell cros_ec_platform_cells[] = { + { .name = "cros-ec-chardev" }, { .name = "cros-ec-debugfs" }, { .name = "cros-ec-lightbar" }, { .name = "cros-ec-sysfs" }, @@ -480,7 +292,6 @@ static int ec_device_probe(struct platform_device *pdev) ec->features[0] = -1U; /* Not cached yet */ ec->features[1] = -1U; /* Not cached yet */ device_initialize(&ec->class_dev); - cdev_init(&ec->cdev, &fops); /* Check whether this is actually a Fingerprint MCU rather than an EC */ if (cros_ec_check_features(ec, EC_FEATURE_FINGERPRINT)) { @@ -527,10 +338,7 @@ static int ec_device_probe(struct platform_device *pdev) /* * 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 = cros_ec_class_release; @@ -541,6 +349,10 @@ static int ec_device_probe(struct platform_device *pdev) goto failed; } + retval = device_add(&ec->class_dev); + if (retval) + goto failed; + /* check whether this EC is a sensor hub. */ if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) cros_ec_sensors_register(ec); @@ -584,13 +396,6 @@ static int ec_device_probe(struct platform_device *pdev) retval); } - /* We can now add the sysfs class, we know which parameter to show */ - retval = cdev_device_add(&ec->cdev, &ec->class_dev); - if (retval) { - dev_err(dev, "cdev_device_add failed => %d\n", retval); - goto failed; - } - retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, cros_ec_platform_cells, ARRAY_SIZE(cros_ec_platform_cells), @@ -624,7 +429,6 @@ static int ec_device_remove(struct platform_device *pdev) struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); mfd_remove_devices(ec->dev); - cdev_del(&ec->cdev); device_unregister(&ec->class_dev); return 0; } @@ -647,7 +451,6 @@ static struct platform_driver cros_ec_dev_driver = { static int __init cros_ec_dev_init(void) { int ret; - dev_t dev = 0; ret = class_register(&cros_class); if (ret) { @@ -655,14 +458,6 @@ static int __init cros_ec_dev_init(void) 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) { @@ -672,8 +467,6 @@ static int __init cros_ec_dev_init(void) return 0; failed_devreg: - unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV); -failed_chrdevreg: class_unregister(&cros_class); return ret; } @@ -681,7 +474,6 @@ failed_chrdevreg: 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); } -- cgit From 2fa2b980e3fe187a0b916bfe6bd5822889b44d5e Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:04 +0200 Subject: mfd / platform: cros_ec: Rename config to a better name The cros-ec-dev is a multifunction device that now doesn't implement any chardev communication interface. MFD_CROS_EC_CHARDEV doesn't look a good name to describe that device and can cause confusion. Hence rename it to CROS_EC_DEV. Signed-off-by: Enric Balletbo i Serra Acked-by: Andy Shevchenko Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 17 ++++++++++------- drivers/mfd/Makefile | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d79882b608cf..c5c5ff308881 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -211,15 +211,18 @@ config MFD_AXP20X_RSB components like regulators or the PEK (Power Enable Key) under the corresponding menus. -config MFD_CROS_EC_CHARDEV - tristate "Chrome OS Embedded Controller userspace device interface" - depends on CROS_EC +config MFD_CROS_EC_DEV + tristate "ChromeOS Embedded Controller multifunction device" select MFD_CORE - ---help--- - This driver adds support to talk with the ChromeOS EC from userspace. + depends on CROS_EC + default CROS_EC + help + Select this to get support for ChromeOS Embedded Controller + sub-devices. This driver will instantiate additional drivers such + as RTC, USBPD, etc. but you have to select the individual drivers. - If you have a supported Chromebook, choose Y or M here. - The module will be called cros_ec_dev. + To compile this driver as a module, choose M here: the module will be + called cros-ec-dev. config MFD_MADERA tristate "Cirrus Logic Madera codecs" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 59ab5bf51b65..0c0a848e62df 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o -obj-$(CONFIG_MFD_CROS_EC_CHARDEV) += cros_ec_dev.o +obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o -- cgit From 840d9f131f65b021e0a73f3371f3194897dba6ad Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:05 +0200 Subject: mfd / platform: cros_ec: Reorganize platform and mfd includes There is a bit of mess between cros-ec mfd includes and platform includes. For example, we have a linux/mfd/cros_ec.h include that exports the interface implemented in platform/chrome/cros_ec_proto.c. Or we have a linux/mfd/cros_ec_commands.h file that is non related to the multifunction device (in the sense that is not exporting any function of the mfd device). This causes crossed includes between mfd and platform/chrome subsystems and makes the code difficult to read, apart from creating 'curious' situations where a platform/chrome driver includes a linux/mfd/cros_ec.h file just to get the exported functions that are implemented in another platform/chrome driver. In order to have a better separation on what the cros-ec multifunction driver does and what the cros-ec core provides move and rework the affected includes doing: - Move cros_ec_commands.h to include/linux/platform_data/cros_ec_commands.h - Get rid of the parts that are implemented in the platform/chrome/cros_ec_proto.c driver from include/linux/mfd/cros_ec.h to a new file include/linux/platform_data/cros_ec_proto.h - Update all the drivers with the new includes, so - Drivers that only need to know about the protocol include - linux/platform_data/cros_ec_proto.h - linux/platform_data/cros_ec_commands.h - Drivers that need to know about the cros-ec mfd device also include - linux/mfd/cros_ec.h Signed-off-by: Enric Balletbo i Serra Acked-by: Andy Shevchenko Acked-by: Mark Brown Acked-by: Wolfram Sang Acked-by: Neil Armstrong Acked-by: Alexandre Belloni Acked-by: Jonathan Cameron Acked-by: Benjamin Tissoires Acked-by: Dmitry Torokhov Acked-by: Sebastian Reichel Acked-by: Chanwoo Choi Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Series changes: 3 - Fix dereferencing pointer to incomplete type 'struct cros_ec_dev' (lkp) Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 0c1c0ce3453e..091d428f5531 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -7,12 +7,13 @@ #include #include -#include #include #include #include #include #include +#include +#include #include #define DRV_NAME "cros-ec-dev" -- cgit From 5156fb75ead1dad9cdd250db898011e92c6ecb22 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:06 +0200 Subject: mfd: cros_ec: Use kzalloc and cros_ec_cmd_xfer_status helper This patch makes use of cros_ec_cmd_xfer_status() instead of cros_ec_cmd_xfer() so we can remove some redundant code. It also uses kzalloc instead of kmalloc so we can remove more redundant code. Signed-off-by: Enric Balletbo i Serra Acked-by: Andy Shevchenko Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_dev.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 091d428f5531..148f39c79f41 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -30,18 +30,15 @@ static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) if (ec->features[0] == -1U && ec->features[1] == -1U) { /* features bitmap not read yet */ - - msg = kmalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL); + msg = kzalloc(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) { + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0) { dev_warn(ec->dev, "cannot get EC features: %d/%d\n", ret, msg->result); memset(ec->features, 0, sizeof(ec->features)); @@ -90,8 +87,8 @@ static void cros_ec_sensors_register(struct cros_ec_dev *ec) 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) { + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0) { dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n", ret, msg->result); goto error; @@ -118,8 +115,8 @@ static void cros_ec_sensors_register(struct cros_ec_dev *ec) 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) { + ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); + if (ret < 0) { dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n", i, ret, msg->result); continue; -- cgit From b027dcf7c4c3e0d22b9ce84011eaf02cf0adf559 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:07 +0200 Subject: mfd: cros_ec: Add convenience struct to define dedicated CrOS EC MCUs With the increasing use of dedicated CrOS EC MCUs, it takes a fair amount of boiler plate code to add those devices, add a struct that can be used to specify a dedicated CrOS EC MCU so we can just add a new item to it to define a new dedicated MCU. Signed-off-by: Enric Balletbo i Serra Acked-by: Andy Shevchenko Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_dev.c | 88 ++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 39 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 148f39c79f41..31da038effc0 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -23,6 +23,41 @@ static struct class cros_class = { .name = "chromeos", }; +/** + * cros_feature_to_name - CrOS feature id to name/short description. + * @id: The feature identifier. + * @name: Device name associated with the feature id. + * @desc: Short name that will be displayed. + */ +struct cros_feature_to_name { + unsigned int id; + const char *name; + const char *desc; +}; + +static const struct cros_feature_to_name cros_mcu_devices[] = { + { + .id = EC_FEATURE_FINGERPRINT, + .name = CROS_EC_DEV_FP_NAME, + .desc = "Fingerprint", + }, + { + .id = EC_FEATURE_ISH, + .name = CROS_EC_DEV_ISH_NAME, + .desc = "Integrated Sensor Hub", + }, + { + .id = EC_FEATURE_SCP, + .name = CROS_EC_DEV_SCP_NAME, + .desc = "System Control Processor", + }, + { + .id = EC_FEATURE_TOUCHPAD, + .name = CROS_EC_DEV_TP_NAME, + .desc = "Touchpad", + }, +}; + static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) { struct cros_ec_command *msg; @@ -279,6 +314,7 @@ static int ec_device_probe(struct platform_device *pdev) 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); + int i; if (!ec) return retval; @@ -291,47 +327,21 @@ static int ec_device_probe(struct platform_device *pdev) ec->features[1] = -1U; /* Not cached yet */ device_initialize(&ec->class_dev); - /* Check whether this is actually a Fingerprint MCU rather than an EC */ - if (cros_ec_check_features(ec, EC_FEATURE_FINGERPRINT)) { - dev_info(dev, "CrOS Fingerprint MCU detected.\n"); + for (i = 0; i < ARRAY_SIZE(cros_mcu_devices); i++) { /* - * Help userspace differentiating ECs from FP MCU, - * regardless of the probing order. + * Check whether this is actually a dedicated MCU rather + * than an standard EC. */ - ec_platform->ec_name = CROS_EC_DEV_FP_NAME; - } - - /* - * Check whether this is actually an Integrated Sensor Hub (ISH) - * rather than an EC. - */ - if (cros_ec_check_features(ec, EC_FEATURE_ISH)) { - dev_info(dev, "CrOS ISH MCU detected.\n"); - /* - * Help userspace differentiating ECs from ISH MCU, - * regardless of the probing order. - */ - ec_platform->ec_name = CROS_EC_DEV_ISH_NAME; - } - - /* Check whether this is actually a Touchpad MCU rather than an EC */ - if (cros_ec_check_features(ec, EC_FEATURE_TOUCHPAD)) { - dev_info(dev, "CrOS Touchpad MCU detected.\n"); - /* - * Help userspace differentiating ECs from TP MCU, - * regardless of the probing order. - */ - ec_platform->ec_name = CROS_EC_DEV_TP_NAME; - } - - /* Check whether this is actually a SCP rather than an EC. */ - if (cros_ec_check_features(ec, EC_FEATURE_SCP)) { - dev_info(dev, "CrOS SCP MCU detected.\n"); - /* - * Help userspace differentiating ECs from SCP, - * regardless of the probing order. - */ - ec_platform->ec_name = CROS_EC_DEV_SCP_NAME; + if (cros_ec_check_features(ec, cros_mcu_devices[i].id)) { + dev_info(dev, "CrOS %s MCU detected\n", + cros_mcu_devices[i].desc); + /* + * Help userspace differentiating ECs from other MCU, + * regardless of the probing order. + */ + ec_platform->ec_name = cros_mcu_devices[i].name; + break; + } } /* -- cgit From 832a636f6afe16aa95cb7281c4eb2194b402515d Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:08 +0200 Subject: mfd: cros_ec: Add convenience struct to define autodetectable CrOS EC subdevices The CrOS EC is gaining lots of subdevices that are autodetectable by sending the EC_FEATURE_GET_CMD, it takes fair amount of boiler plate code to add those devices. So, add a struct that can be used to quickly add new subdevices without having to duplicate code. Signed-off-by: Enric Balletbo i Serra Acked-by: Andy Shevchenko Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_dev.c | 131 ++++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 58 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 31da038effc0..90eb02c56b77 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -35,6 +35,18 @@ struct cros_feature_to_name { const char *desc; }; +/** + * cros_feature_to_cells - CrOS feature id to mfd cells association. + * @id: The feature identifier. + * @mfd_cells: Pointer to the array of mfd cells that needs to be added. + * @num_cells: Number of mfd cells into the array. + */ +struct cros_feature_to_cells { + unsigned int id; + const struct mfd_cell *mfd_cells; + unsigned int num_cells; +}; + static const struct cros_feature_to_name cros_mcu_devices[] = { { .id = EC_FEATURE_FINGERPRINT, @@ -58,6 +70,48 @@ static const struct cros_feature_to_name cros_mcu_devices[] = { }, }; +static const struct mfd_cell cros_ec_cec_cells[] = { + { .name = "cros-ec-cec", }, +}; + +static const struct mfd_cell cros_ec_rtc_cells[] = { + { .name = "cros-ec-rtc", }, +}; + +static const struct mfd_cell cros_usbpd_charger_cells[] = { + { .name = "cros-usbpd-charger", }, + { .name = "cros-usbpd-logger", }, +}; + +static const struct cros_feature_to_cells cros_subdevices[] = { + { + .id = EC_FEATURE_CEC, + .mfd_cells = cros_ec_cec_cells, + .num_cells = ARRAY_SIZE(cros_ec_cec_cells), + }, + { + .id = EC_FEATURE_RTC, + .mfd_cells = cros_ec_rtc_cells, + .num_cells = ARRAY_SIZE(cros_ec_rtc_cells), + }, + { + .id = EC_FEATURE_USB_PD, + .mfd_cells = cros_usbpd_charger_cells, + .num_cells = ARRAY_SIZE(cros_usbpd_charger_cells), + }, +}; + +static const struct mfd_cell cros_ec_platform_cells[] = { + { .name = "cros-ec-chardev", }, + { .name = "cros-ec-debugfs", }, + { .name = "cros-ec-lightbar", }, + { .name = "cros-ec-sysfs", }, +}; + +static const struct mfd_cell cros_ec_vbc_cells[] = { + { .name = "cros-ec-vbc", } +}; + static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) { struct cros_ec_command *msg; @@ -283,30 +337,6 @@ static void cros_ec_accel_legacy_register(struct cros_ec_dev *ec) dev_err(ec_dev->dev, "failed to add EC sensors\n"); } -static const struct mfd_cell cros_ec_cec_cells[] = { - { .name = "cros-ec-cec" } -}; - -static const struct mfd_cell cros_ec_rtc_cells[] = { - { .name = "cros-ec-rtc" } -}; - -static const struct mfd_cell cros_usbpd_charger_cells[] = { - { .name = "cros-usbpd-charger" }, - { .name = "cros-usbpd-logger" }, -}; - -static const struct mfd_cell cros_ec_platform_cells[] = { - { .name = "cros-ec-chardev" }, - { .name = "cros-ec-debugfs" }, - { .name = "cros-ec-lightbar" }, - { .name = "cros-ec-sysfs" }, -}; - -static const struct mfd_cell cros_ec_vbc_cells[] = { - { .name = "cros-ec-vbc" } -}; - static int ec_device_probe(struct platform_device *pdev) { int retval = -ENOMEM; @@ -368,42 +398,27 @@ static int ec_device_probe(struct platform_device *pdev) /* Workaroud for older EC firmware */ cros_ec_accel_legacy_register(ec); - /* Check whether this EC instance has CEC host command support */ - if (cros_ec_check_features(ec, EC_FEATURE_CEC)) { - retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, - cros_ec_cec_cells, - ARRAY_SIZE(cros_ec_cec_cells), - NULL, 0, NULL); - if (retval) - dev_err(ec->dev, - "failed to add cros-ec-cec device: %d\n", - retval); - } - - /* Check whether this EC instance has RTC host command support */ - if (cros_ec_check_features(ec, EC_FEATURE_RTC)) { - retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, - cros_ec_rtc_cells, - ARRAY_SIZE(cros_ec_rtc_cells), - NULL, 0, NULL); - if (retval) - dev_err(ec->dev, - "failed to add cros-ec-rtc device: %d\n", - retval); - } - - /* Check whether this EC instance has the PD charge manager */ - if (cros_ec_check_features(ec, EC_FEATURE_USB_PD)) { - retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, - cros_usbpd_charger_cells, - ARRAY_SIZE(cros_usbpd_charger_cells), - NULL, 0, NULL); - if (retval) - dev_err(ec->dev, - "failed to add cros-usbpd-charger device: %d\n", - retval); + /* + * The following subdevices can be detected by sending the + * EC_FEATURE_GET_CMD Embedded Controller device. + */ + for (i = 0; i < ARRAY_SIZE(cros_subdevices); i++) { + if (cros_ec_check_features(ec, cros_subdevices[i].id)) { + retval = mfd_add_hotplug_devices(ec->dev, + cros_subdevices[i].mfd_cells, + cros_subdevices[i].num_cells); + if (retval) + dev_err(ec->dev, + "failed to add %s subdevice: %d\n", + cros_subdevices[i].mfd_cells->name, + retval); + } } + /* + * The following subdevices cannot be detected by sending the + * EC_FEATURE_GET_CMD to the Embedded Controller device. + */ retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, cros_ec_platform_cells, ARRAY_SIZE(cros_ec_platform_cells), -- cgit From 28e6fcc871bcff640c8960448034ea3a7c7fdfa3 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Mon, 2 Sep 2019 11:53:09 +0200 Subject: mfd: cros_ec: Use mfd_add_hotplug_devices() helper Use mfd_add_hotplug_devices() helper to register the subdevices. The helper allows us to reduce the boiler plate and also registers the subdevices in the same way as used in other functions used in this files. Signed-off-by: Enric Balletbo i Serra Reviewed-by: Gwendal Grignou Tested-by: Gwendal Grignou Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_dev.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 90eb02c56b77..6e6dfd6c1871 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -329,10 +329,8 @@ static void cros_ec_accel_legacy_register(struct cros_ec_dev *ec) * Register 2 accelerometers, we will fail in the IIO driver if there * are no sensors. */ - ret = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, - cros_ec_accel_legacy_cells, - ARRAY_SIZE(cros_ec_accel_legacy_cells), - NULL, 0, NULL); + ret = mfd_add_hotplug_devices(ec->dev, cros_ec_accel_legacy_cells, + ARRAY_SIZE(cros_ec_accel_legacy_cells)); if (ret) dev_err(ec_dev->dev, "failed to add EC sensors\n"); } @@ -419,10 +417,8 @@ static int ec_device_probe(struct platform_device *pdev) * The following subdevices cannot be detected by sending the * EC_FEATURE_GET_CMD to the Embedded Controller device. */ - retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, - cros_ec_platform_cells, - ARRAY_SIZE(cros_ec_platform_cells), - NULL, 0, NULL); + retval = mfd_add_hotplug_devices(ec->dev, cros_ec_platform_cells, + ARRAY_SIZE(cros_ec_platform_cells)); if (retval) dev_warn(ec->dev, "failed to add cros-ec platform devices: %d\n", @@ -431,10 +427,8 @@ static int ec_device_probe(struct platform_device *pdev) /* Check whether this EC instance has a VBC NVRAM */ node = ec->ec_dev->dev->of_node; if (of_property_read_bool(node, "google,has-vbc-nvram")) { - retval = mfd_add_devices(ec->dev, PLATFORM_DEVID_AUTO, - cros_ec_vbc_cells, - ARRAY_SIZE(cros_ec_vbc_cells), - NULL, 0, NULL); + retval = mfd_add_hotplug_devices(ec->dev, cros_ec_vbc_cells, + ARRAY_SIZE(cros_ec_vbc_cells)); if (retval) dev_warn(ec->dev, "failed to add VBC devices: %d\n", retval); -- cgit