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: Andres Salomon <dilinger@queued.net>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
	
	
This commit is contained in:
		
					parent
					
						
							
								16c29dafcc
							
						
					
				
			
			
				commit
				
					
						fa1df69168
					
				
			
		
					 4 changed files with 53 additions and 58 deletions
				
			
		| 
						 | 
					@ -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 @@
 | 
				
			||||||
#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[] = {
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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,
 | 
				
			||||||
		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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(mfd_clone_cell);
 | 
				
			||||||
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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
EXPORT_SYMBOL(mfd_shared_platform_driver_unregister);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 {
 | 
				
			||||||
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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue