aboutsummaryrefslogtreecommitdiff
path: root/drivers/mfd
diff options
context:
space:
mode:
authorEnric Balletbo i Serra <enric.balletbo@collabora.com>2019-09-02 11:53:00 +0200
committerLee Jones <lee.jones@linaro.org>2019-09-02 11:32:57 +0100
commit7aa703bb8824384baad732043a925b46a4f3efa8 (patch)
treef20c98444eb7ad23266bdc603e7c4cf6793bcccf /drivers/mfd
parent5f9e832c137075045d15cd6899ab0505cfb2ca4b (diff)
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 <enric.balletbo@collabora.com> Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Reviewed-by: Gwendal Grignou <gwendal@chromium.org> Tested-by: Gwendal Grignou <gwendal@chromium.org> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/cros_ec.c61
1 files changed, 31 insertions, 30 deletions
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 <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/mfd/core.h>
#include <linux/mfd/cros_ec.h>
#include <linux/suspend.h>
#include <asm/unaligned.h>
@@ -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)
{