summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEnric Balletbo i Serra <enric.balletbo@collabora.com>2019-09-02 05:53:00 -0400
committerLee Jones <lee.jones@linaro.org>2019-09-02 06:32:57 -0400
commit7aa703bb8824384baad732043a925b46a4f3efa8 (patch)
treef20c98444eb7ad23266bdc603e7c4cf6793bcccf
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>
-rw-r--r--drivers/mfd/cros_ec.c61
-rw-r--r--drivers/platform/chrome/cros_ec_i2c.c8
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c3
-rw-r--r--drivers/platform/chrome/cros_ec_rpmsg.c2
-rw-r--r--drivers/platform/chrome/cros_ec_spi.c8
-rw-r--r--include/linux/mfd/cros_ec.h18
6 files changed, 69 insertions, 31 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 @@
13#include <linux/interrupt.h> 13#include <linux/interrupt.h>
14#include <linux/slab.h> 14#include <linux/slab.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/mfd/core.h>
17#include <linux/mfd/cros_ec.h> 16#include <linux/mfd/cros_ec.h>
18#include <linux/suspend.h> 17#include <linux/suspend.h>
19#include <asm/unaligned.h> 18#include <asm/unaligned.h>
@@ -31,18 +30,6 @@ static struct cros_ec_platform pd_p = {
31 .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX), 30 .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX),
32}; 31};
33 32
34static const struct mfd_cell ec_cell = {
35 .name = "cros-ec-dev",
36 .platform_data = &ec_p,
37 .pdata_size = sizeof(ec_p),
38};
39
40static const struct mfd_cell ec_pd_cell = {
41 .name = "cros-ec-dev",
42 .platform_data = &pd_p,
43 .pdata_size = sizeof(pd_p),
44};
45
46static irqreturn_t ec_irq_thread(int irq, void *data) 33static irqreturn_t ec_irq_thread(int irq, void *data)
47{ 34{
48 struct cros_ec_device *ec_dev = data; 35 struct cros_ec_device *ec_dev = data;
@@ -154,38 +141,42 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
154 } 141 }
155 } 142 }
156 143
157 err = devm_mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell, 144 /* Register a platform device for the main EC instance */
158 1, NULL, ec_dev->irq, NULL); 145 ec_dev->ec = platform_device_register_data(ec_dev->dev, "cros-ec-dev",
159 if (err) { 146 PLATFORM_DEVID_AUTO, &ec_p,
160 dev_err(dev, 147 sizeof(struct cros_ec_platform));
161 "Failed to register Embedded Controller subdevice %d\n", 148 if (IS_ERR(ec_dev->ec)) {
162 err); 149 dev_err(ec_dev->dev,
163 return err; 150 "Failed to create CrOS EC platform device\n");
151 return PTR_ERR(ec_dev->ec);
164 } 152 }
165 153
166 if (ec_dev->max_passthru) { 154 if (ec_dev->max_passthru) {
167 /* 155 /*
168 * Register a PD device as well on top of this device. 156 * Register a platform device for the PD behind the main EC.
169 * We make the following assumptions: 157 * We make the following assumptions:
170 * - behind an EC, we have a pd 158 * - behind an EC, we have a pd
171 * - only one device added. 159 * - only one device added.
172 * - the EC is responsive at init time (it is not true for a 160 * - the EC is responsive at init time (it is not true for a
173 * sensor hub. 161 * sensor hub).
174 */ 162 */
175 err = devm_mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, 163 ec_dev->pd = platform_device_register_data(ec_dev->dev,
176 &ec_pd_cell, 1, NULL, ec_dev->irq, NULL); 164 "cros-ec-dev",
177 if (err) { 165 PLATFORM_DEVID_AUTO, &pd_p,
178 dev_err(dev, 166 sizeof(struct cros_ec_platform));
179 "Failed to register Power Delivery subdevice %d\n", 167 if (IS_ERR(ec_dev->pd)) {
180 err); 168 dev_err(ec_dev->dev,
181 return err; 169 "Failed to create CrOS PD platform device\n");
170 platform_device_unregister(ec_dev->ec);
171 return PTR_ERR(ec_dev->pd);
182 } 172 }
183 } 173 }
184 174
185 if (IS_ENABLED(CONFIG_OF) && dev->of_node) { 175 if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
186 err = devm_of_platform_populate(dev); 176 err = devm_of_platform_populate(dev);
187 if (err) { 177 if (err) {
188 mfd_remove_devices(dev); 178 platform_device_unregister(ec_dev->pd);
179 platform_device_unregister(ec_dev->ec);
189 dev_err(dev, "Failed to register sub-devices\n"); 180 dev_err(dev, "Failed to register sub-devices\n");
190 return err; 181 return err;
191 } 182 }
@@ -206,6 +197,16 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
206} 197}
207EXPORT_SYMBOL(cros_ec_register); 198EXPORT_SYMBOL(cros_ec_register);
208 199
200int cros_ec_unregister(struct cros_ec_device *ec_dev)
201{
202 if (ec_dev->pd)
203 platform_device_unregister(ec_dev->pd);
204 platform_device_unregister(ec_dev->ec);
205
206 return 0;
207}
208EXPORT_SYMBOL(cros_ec_unregister);
209
209#ifdef CONFIG_PM_SLEEP 210#ifdef CONFIG_PM_SLEEP
210int cros_ec_suspend(struct cros_ec_device *ec_dev) 211int cros_ec_suspend(struct cros_ec_device *ec_dev)
211{ 212{
diff --git a/drivers/platform/chrome/cros_ec_i2c.c b/drivers/platform/chrome/cros_ec_i2c.c
index 61d75395f86d..6bb82dfa7dae 100644
--- a/drivers/platform/chrome/cros_ec_i2c.c
+++ b/drivers/platform/chrome/cros_ec_i2c.c
@@ -307,6 +307,13 @@ static int cros_ec_i2c_probe(struct i2c_client *client,
307 return 0; 307 return 0;
308} 308}
309 309
310static int cros_ec_i2c_remove(struct i2c_client *client)
311{
312 struct cros_ec_device *ec_dev = i2c_get_clientdata(client);
313
314 return cros_ec_unregister(ec_dev);
315}
316
310#ifdef CONFIG_PM_SLEEP 317#ifdef CONFIG_PM_SLEEP
311static int cros_ec_i2c_suspend(struct device *dev) 318static int cros_ec_i2c_suspend(struct device *dev)
312{ 319{
@@ -357,6 +364,7 @@ static struct i2c_driver cros_ec_driver = {
357 .pm = &cros_ec_i2c_pm_ops, 364 .pm = &cros_ec_i2c_pm_ops,
358 }, 365 },
359 .probe = cros_ec_i2c_probe, 366 .probe = cros_ec_i2c_probe,
367 .remove = cros_ec_i2c_remove,
360 .id_table = cros_ec_i2c_id, 368 .id_table = cros_ec_i2c_id,
361}; 369};
362 370
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index 2c44c7f3322a..5939c4a5869c 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -421,6 +421,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
421 421
422static int cros_ec_lpc_remove(struct platform_device *pdev) 422static int cros_ec_lpc_remove(struct platform_device *pdev)
423{ 423{
424 struct cros_ec_device *ec_dev = platform_get_drvdata(pdev);
424 struct acpi_device *adev; 425 struct acpi_device *adev;
425 426
426 adev = ACPI_COMPANION(&pdev->dev); 427 adev = ACPI_COMPANION(&pdev->dev);
@@ -428,7 +429,7 @@ static int cros_ec_lpc_remove(struct platform_device *pdev)
428 acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY, 429 acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY,
429 cros_ec_lpc_acpi_notify); 430 cros_ec_lpc_acpi_notify);
430 431
431 return 0; 432 return cros_ec_unregister(ec_dev);
432} 433}
433 434
434static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = { 435static const struct acpi_device_id cros_ec_lpc_acpi_device_ids[] = {
diff --git a/drivers/platform/chrome/cros_ec_rpmsg.c b/drivers/platform/chrome/cros_ec_rpmsg.c
index 5d3fb2abad1d..520e507bfa54 100644
--- a/drivers/platform/chrome/cros_ec_rpmsg.c
+++ b/drivers/platform/chrome/cros_ec_rpmsg.c
@@ -233,6 +233,8 @@ static void cros_ec_rpmsg_remove(struct rpmsg_device *rpdev)
233 struct cros_ec_device *ec_dev = dev_get_drvdata(&rpdev->dev); 233 struct cros_ec_device *ec_dev = dev_get_drvdata(&rpdev->dev);
234 struct cros_ec_rpmsg *ec_rpmsg = ec_dev->priv; 234 struct cros_ec_rpmsg *ec_rpmsg = ec_dev->priv;
235 235
236 cros_ec_unregister(ec_dev);
237
236 cancel_work_sync(&ec_rpmsg->host_event_work); 238 cancel_work_sync(&ec_rpmsg->host_event_work);
237} 239}
238 240
diff --git a/drivers/platform/chrome/cros_ec_spi.c b/drivers/platform/chrome/cros_ec_spi.c
index 006a8ff64057..2e21f2776063 100644
--- a/drivers/platform/chrome/cros_ec_spi.c
+++ b/drivers/platform/chrome/cros_ec_spi.c
@@ -785,6 +785,13 @@ static int cros_ec_spi_probe(struct spi_device *spi)
785 return 0; 785 return 0;
786} 786}
787 787
788static int cros_ec_spi_remove(struct spi_device *spi)
789{
790 struct cros_ec_device *ec_dev = spi_get_drvdata(spi);
791
792 return cros_ec_unregister(ec_dev);
793}
794
788#ifdef CONFIG_PM_SLEEP 795#ifdef CONFIG_PM_SLEEP
789static int cros_ec_spi_suspend(struct device *dev) 796static int cros_ec_spi_suspend(struct device *dev)
790{ 797{
@@ -823,6 +830,7 @@ static struct spi_driver cros_ec_driver_spi = {
823 .pm = &cros_ec_spi_pm_ops, 830 .pm = &cros_ec_spi_pm_ops,
824 }, 831 },
825 .probe = cros_ec_spi_probe, 832 .probe = cros_ec_spi_probe,
833 .remove = cros_ec_spi_remove,
826 .id_table = cros_ec_spi_id, 834 .id_table = cros_ec_spi_id,
827}; 835};
828 836
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
index 77805c3f2de7..bcccda0257ff 100644
--- a/include/linux/mfd/cros_ec.h
+++ b/include/linux/mfd/cros_ec.h
@@ -121,6 +121,10 @@ struct cros_ec_command {
121 * @event_data: Raw payload transferred with the MKBP event. 121 * @event_data: Raw payload transferred with the MKBP event.
122 * @event_size: Size in bytes of the event data. 122 * @event_size: Size in bytes of the event data.
123 * @host_event_wake_mask: Mask of host events that cause wake from suspend. 123 * @host_event_wake_mask: Mask of host events that cause wake from suspend.
124 * @ec: The platform_device used by the mfd driver to interface with the
125 * main EC.
126 * @pd: The platform_device used by the mfd driver to interface with the
127 * PD behind an EC.
124 */ 128 */
125struct cros_ec_device { 129struct cros_ec_device {
126 /* These are used by other drivers that want to talk to the EC */ 130 /* These are used by other drivers that want to talk to the EC */
@@ -157,6 +161,10 @@ struct cros_ec_device {
157 int event_size; 161 int event_size;
158 u32 host_event_wake_mask; 162 u32 host_event_wake_mask;
159 u32 last_resume_result; 163 u32 last_resume_result;
164
165 /* The platform devices used by the mfd driver */
166 struct platform_device *ec;
167 struct platform_device *pd;
160}; 168};
161 169
162/** 170/**
@@ -292,6 +300,16 @@ int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
292int cros_ec_register(struct cros_ec_device *ec_dev); 300int cros_ec_register(struct cros_ec_device *ec_dev);
293 301
294/** 302/**
303 * cros_ec_unregister() - Remove a ChromeOS EC.
304 * @ec_dev: Device to unregister.
305 *
306 * Call this to deregister a ChromeOS EC, then clean up any private data.
307 *
308 * Return: 0 on success or negative error code.
309 */
310int cros_ec_unregister(struct cros_ec_device *ec_dev);
311
312/**
295 * cros_ec_query_all() - Query the protocol version supported by the 313 * cros_ec_query_all() - Query the protocol version supported by the
296 * ChromeOS EC. 314 * ChromeOS EC.
297 * @ec_dev: Device to register. 315 * @ec_dev: Device to register.