Commit fa1df691 authored by Andres Salomon's avatar Andres Salomon Committed by Samuel Ortiz

mfd: Add mfd_clone_cell(), convert cs5535-mfd/olpc-xo1 to it

Replace mfd_shared_platform_driver_register with mfd_clone_cell.  The
former was called by an mfd client, and registered both a platform driver
and device.  The latter is called by an mfd driver, and registers only a
platform device.

The downside of this is that mfd drivers need to be modified whenever
new clients are added that share a cell; the upside is that it fits
Linux's driver model better.  It's also simpler.

This also converts cs5535-mfd/olpc-xo1 from the old API.  cs5535-mfd
now creates the olpc-xo1-{acpi,pms} devices, while olpc-xo1 binds to
them via platform drivers.
Signed-off-by: default avatarAndres Salomon <dilinger@queued.net>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 16c29daf
...@@ -121,22 +121,21 @@ static int __init olpc_xo1_init(void) ...@@ -121,22 +121,21 @@ static int __init olpc_xo1_init(void)
{ {
int r; int r;
r = mfd_shared_platform_driver_register(&cs5535_pms_drv, "cs5535-pms"); r = platform_driver_register(&cs5535_pms_drv);
if (r) if (r)
return r; return r;
r = mfd_shared_platform_driver_register(&cs5535_acpi_drv, r = platform_driver_register(&cs5535_acpi_drv);
"cs5535-acpi");
if (r) if (r)
mfd_shared_platform_driver_unregister(&cs5535_pms_drv); platform_driver_unregister(&cs5535_pms_drv);
return r; return r;
} }
static void __exit olpc_xo1_exit(void) static void __exit olpc_xo1_exit(void)
{ {
mfd_shared_platform_driver_unregister(&cs5535_acpi_drv); platform_driver_unregister(&cs5535_acpi_drv);
mfd_shared_platform_driver_unregister(&cs5535_pms_drv); platform_driver_unregister(&cs5535_pms_drv);
} }
MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>"); MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/olpc.h>
#define DRV_NAME "cs5535-mfd" #define DRV_NAME "cs5535-mfd"
...@@ -111,6 +112,22 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { ...@@ -111,6 +112,22 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = {
}, },
}; };
#ifdef CONFIG_OLPC
static void __devinit cs5535_clone_olpc_cells(void)
{
const char *acpi_clones[] = { "olpc-xo1-acpi" };
const char *pms_clones[] = { "olpc-xo1-pms" };
if (!machine_is_olpc())
return;
mfd_clone_cell("cs5535-acpi", acpi_clones, ARRAY_SIZE(acpi_clones));
mfd_clone_cell("cs5535-pms", pms_clones, ARRAY_SIZE(pms_clones));
}
#else
static void cs5535_clone_olpc_cells(void) { }
#endif
static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, static int __devinit cs5535_mfd_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
...@@ -139,6 +156,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, ...@@ -139,6 +156,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev,
dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); dev_err(&pdev->dev, "MFD add devices failed: %d\n", err);
goto err_disable; goto err_disable;
} }
cs5535_clone_olpc_cells();
dev_info(&pdev->dev, "%zu devices registered.\n", dev_info(&pdev->dev, "%zu devices registered.\n",
ARRAY_SIZE(cs5535_mfd_cells)); ARRAY_SIZE(cs5535_mfd_cells));
......
...@@ -184,16 +184,12 @@ void mfd_remove_devices(struct device *parent) ...@@ -184,16 +184,12 @@ void mfd_remove_devices(struct device *parent)
} }
EXPORT_SYMBOL(mfd_remove_devices); EXPORT_SYMBOL(mfd_remove_devices);
static int add_shared_platform_device(const char *cell, const char *name) int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones)
{ {
struct mfd_cell cell_entry; struct mfd_cell cell_entry;
struct device *dev; struct device *dev;
struct platform_device *pdev; struct platform_device *pdev;
int err; int i;
/* check if we've already registered a device (don't fail if we have) */
if (bus_find_device_by_name(&platform_bus_type, NULL, name))
return 0;
/* fetch the parent cell's device (should already be registered!) */ /* fetch the parent cell's device (should already be registered!) */
dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); dev = bus_find_device_by_name(&platform_bus_type, NULL, cell);
...@@ -206,44 +202,17 @@ static int add_shared_platform_device(const char *cell, const char *name) ...@@ -206,44 +202,17 @@ static int add_shared_platform_device(const char *cell, const char *name)
WARN_ON(!cell_entry.enable); WARN_ON(!cell_entry.enable);
cell_entry.name = name; for (i = 0; i < n_clones; i++) {
err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0); cell_entry.name = clones[i];
if (err) /* don't give up if a single call fails; just report error */
dev_err(dev, "MFD add devices failed: %d\n", err); if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0))
return err; dev_err(dev, "failed to create platform device '%s'\n",
} clones[i]);
}
int mfd_shared_platform_driver_register(struct platform_driver *drv,
const char *cellname)
{
int err;
err = add_shared_platform_device(cellname, drv->driver.name);
if (err)
printk(KERN_ERR "failed to add platform device %s\n",
drv->driver.name);
err = platform_driver_register(drv);
if (err)
printk(KERN_ERR "failed to add platform driver %s\n",
drv->driver.name);
return err;
}
EXPORT_SYMBOL(mfd_shared_platform_driver_register);
void mfd_shared_platform_driver_unregister(struct platform_driver *drv)
{
struct device *dev;
dev = bus_find_device_by_name(&platform_bus_type, NULL,
drv->driver.name);
if (dev)
platform_device_unregister(to_platform_device(dev));
platform_driver_unregister(drv); return 0;
} }
EXPORT_SYMBOL(mfd_shared_platform_driver_unregister); EXPORT_SYMBOL(mfd_clone_cell);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");
...@@ -62,6 +62,24 @@ struct mfd_cell { ...@@ -62,6 +62,24 @@ struct mfd_cell {
extern int mfd_cell_enable(struct platform_device *pdev); extern int mfd_cell_enable(struct platform_device *pdev);
extern int mfd_cell_disable(struct platform_device *pdev); extern int mfd_cell_disable(struct platform_device *pdev);
/*
* "Clone" multiple platform devices for a single cell. This is to be used
* for devices that have multiple users of a cell. For example, if an mfd
* driver wants the cell "foo" to be used by a GPIO driver, an MTD driver,
* and a platform driver, the following bit of code would be use after first
* calling mfd_add_devices():
*
* const char *fclones[] = { "foo-gpio", "foo-mtd" };
* err = mfd_clone_cells("foo", fclones, ARRAY_SIZE(fclones));
*
* Each driver (MTD, GPIO, and platform driver) would then register
* platform_drivers for "foo-mtd", "foo-gpio", and "foo", respectively.
* The cell's .enable/.disable hooks should be used to deal with hardware
* resource contention.
*/
extern int mfd_clone_cell(const char *cell, const char **clones,
size_t n_clones);
/* /*
* Given a platform device that's been created by mfd_add_devices(), fetch * Given a platform device that's been created by mfd_add_devices(), fetch
* the mfd_cell that created it. * the mfd_cell that created it.
...@@ -87,13 +105,4 @@ extern int mfd_add_devices(struct device *parent, int id, ...@@ -87,13 +105,4 @@ extern int mfd_add_devices(struct device *parent, int id,
extern void mfd_remove_devices(struct device *parent); extern void mfd_remove_devices(struct device *parent);
/*
* For MFD drivers with clients sharing access to resources, these create
* multiple platform devices per cell. Contention handling must still be
* handled via drivers (ie, with enable/disable hooks).
*/
extern int mfd_shared_platform_driver_register(struct platform_driver *drv,
const char *cellname);
extern void mfd_shared_platform_driver_unregister(struct platform_driver *drv);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment