aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndres Salomon <dilinger@queued.net>2011-02-17 22:07:35 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2011-03-23 05:41:58 -0400
commita9bbba996302344b1fac7773cf8198f6fee35ac1 (patch)
tree8cd804a7169232bf4a14a575e8b41092fe4e0fdf
parent1e29af62f2b285bd18685da93c3ce8c33ca2d1db (diff)
mfd: add platform_device sharing support for mfd
This adds functions to enable platform_device sharing for mfd clients. Each platform driver (mfd client) that wants to share an mfd_cell's platform_device uses the mfd_shared_platform_driver_{un,}register() functions instead of platform_driver_{un,}register(). Along with registering the platform driver, these also register a new platform device with the same characteristics as the original cell, but a different name. Given an mfd_cell with the name "foo", drivers that want to share access to its resources can call mfd_shared_platform_driver_register with platform drivers named (for example) "bar" and "baz". This will register two platform devices and drivers named "bar" and "baz" that share the same cell as the platform device "foo". The drivers can then call "foo" cell's enable hooks (or mfd_shared_cell_enable) to enable resources, and obtain platform resources as they normally would. This deals with platform handling only; mfd driver-specific details, hardware handling, refcounting, etc are all dealt with separately. Signed-off-by: Andres Salomon <dilinger@queued.net> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/mfd/mfd-core.c61
-rw-r--r--include/linux/mfd/core.h9
2 files changed, 70 insertions, 0 deletions
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index ca789f882305..bb2264cc410b 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -184,5 +184,66 @@ void mfd_remove_devices(struct device *parent)
184} 184}
185EXPORT_SYMBOL(mfd_remove_devices); 185EXPORT_SYMBOL(mfd_remove_devices);
186 186
187static int add_shared_platform_device(const char *cell, const char *name)
188{
189 struct mfd_cell cell_entry;
190 struct device *dev;
191 struct platform_device *pdev;
192 int err;
193
194 /* check if we've already registered a device (don't fail if we have) */
195 if (bus_find_device_by_name(&platform_bus_type, NULL, name))
196 return 0;
197
198 /* fetch the parent cell's device (should already be registered!) */
199 dev = bus_find_device_by_name(&platform_bus_type, NULL, cell);
200 if (!dev) {
201 printk(KERN_ERR "failed to find device for cell %s\n", cell);
202 return -ENODEV;
203 }
204 pdev = to_platform_device(dev);
205 memcpy(&cell_entry, mfd_get_cell(pdev), sizeof(cell_entry));
206
207 WARN_ON(!cell_entry.enable);
208
209 cell_entry.name = name;
210 err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0);
211 if (err)
212 dev_err(dev, "MFD add devices failed: %d\n", err);
213 return err;
214}
215
216int mfd_shared_platform_driver_register(struct platform_driver *drv,
217 const char *cellname)
218{
219 int err;
220
221 err = add_shared_platform_device(cellname, drv->driver.name);
222 if (err)
223 printk(KERN_ERR "failed to add platform device %s\n",
224 drv->driver.name);
225
226 err = platform_driver_register(drv);
227 if (err)
228 printk(KERN_ERR "failed to add platform driver %s\n",
229 drv->driver.name);
230
231 return err;
232}
233EXPORT_SYMBOL(mfd_shared_platform_driver_register);
234
235void mfd_shared_platform_driver_unregister(struct platform_driver *drv)
236{
237 struct device *dev;
238
239 dev = bus_find_device_by_name(&platform_bus_type, NULL,
240 drv->driver.name);
241 if (dev)
242 platform_device_unregister(to_platform_device(dev));
243
244 platform_driver_unregister(drv);
245}
246EXPORT_SYMBOL(mfd_shared_platform_driver_unregister);
247
187MODULE_LICENSE("GPL"); 248MODULE_LICENSE("GPL");
188MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); 249MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index 22a2f5ebd9db..ed9970412cc2 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -87,4 +87,13 @@ extern int mfd_add_devices(struct device *parent, int id,
87 87
88extern void mfd_remove_devices(struct device *parent); 88extern void mfd_remove_devices(struct device *parent);
89 89
90/*
91 * For MFD drivers with clients sharing access to resources, these create
92 * multiple platform devices per cell. Contention handling must still be
93 * handled via drivers (ie, with enable/disable hooks).
94 */
95extern int mfd_shared_platform_driver_register(struct platform_driver *drv,
96 const char *cellname);
97extern void mfd_shared_platform_driver_unregister(struct platform_driver *drv);
98
90#endif 99#endif