diff options
author | Andres Salomon <dilinger@queued.net> | 2011-03-21 22:19:35 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2011-03-26 19:09:30 -0400 |
commit | fa1df691688f34cbcd5bf77bd084bbe47e9d6bfe (patch) | |
tree | 83df18f1d427115c0016a059535b04f2d600a2d0 | |
parent | 16c29dafcc86024048f1dbb8349d31cb22c7c55a (diff) |
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>
-rw-r--r-- | arch/x86/platform/olpc/olpc-xo1.c | 11 | ||||
-rw-r--r-- | drivers/mfd/cs5535-mfd.c | 18 | ||||
-rw-r--r-- | drivers/mfd/mfd-core.c | 53 | ||||
-rw-r--r-- | include/linux/mfd/core.h | 27 |
4 files changed, 52 insertions, 57 deletions
diff --git a/arch/x86/platform/olpc/olpc-xo1.c b/arch/x86/platform/olpc/olpc-xo1.c index 99513642a0e6..386e3a159cca 100644 --- a/arch/x86/platform/olpc/olpc-xo1.c +++ b/arch/x86/platform/olpc/olpc-xo1.c | |||
@@ -121,22 +121,21 @@ static int __init olpc_xo1_init(void) | |||
121 | { | 121 | { |
122 | int r; | 122 | int r; |
123 | 123 | ||
124 | r = mfd_shared_platform_driver_register(&cs5535_pms_drv, "cs5535-pms"); | 124 | r = platform_driver_register(&cs5535_pms_drv); |
125 | if (r) | 125 | if (r) |
126 | return r; | 126 | return r; |
127 | 127 | ||
128 | r = mfd_shared_platform_driver_register(&cs5535_acpi_drv, | 128 | r = platform_driver_register(&cs5535_acpi_drv); |
129 | "cs5535-acpi"); | ||
130 | if (r) | 129 | if (r) |
131 | mfd_shared_platform_driver_unregister(&cs5535_pms_drv); | 130 | platform_driver_unregister(&cs5535_pms_drv); |
132 | 131 | ||
133 | return r; | 132 | return r; |
134 | } | 133 | } |
135 | 134 | ||
136 | static void __exit olpc_xo1_exit(void) | 135 | static void __exit olpc_xo1_exit(void) |
137 | { | 136 | { |
138 | mfd_shared_platform_driver_unregister(&cs5535_acpi_drv); | 137 | platform_driver_unregister(&cs5535_acpi_drv); |
139 | mfd_shared_platform_driver_unregister(&cs5535_pms_drv); | 138 | platform_driver_unregister(&cs5535_pms_drv); |
140 | } | 139 | } |
141 | 140 | ||
142 | MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>"); | 141 | MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>"); |
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 886a06871065..24959ddd9324 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/mfd/core.h> | 27 | #include <linux/mfd/core.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <asm/olpc.h> | ||
30 | 31 | ||
31 | #define DRV_NAME "cs5535-mfd" | 32 | #define DRV_NAME "cs5535-mfd" |
32 | 33 | ||
@@ -111,6 +112,22 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { | |||
111 | }, | 112 | }, |
112 | }; | 113 | }; |
113 | 114 | ||
115 | #ifdef CONFIG_OLPC | ||
116 | static void __devinit cs5535_clone_olpc_cells(void) | ||
117 | { | ||
118 | const char *acpi_clones[] = { "olpc-xo1-acpi" }; | ||
119 | const char *pms_clones[] = { "olpc-xo1-pms" }; | ||
120 | |||
121 | if (!machine_is_olpc()) | ||
122 | return; | ||
123 | |||
124 | mfd_clone_cell("cs5535-acpi", acpi_clones, ARRAY_SIZE(acpi_clones)); | ||
125 | mfd_clone_cell("cs5535-pms", pms_clones, ARRAY_SIZE(pms_clones)); | ||
126 | } | ||
127 | #else | ||
128 | static void cs5535_clone_olpc_cells(void) { } | ||
129 | #endif | ||
130 | |||
114 | static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, | 131 | static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, |
115 | const struct pci_device_id *id) | 132 | const struct pci_device_id *id) |
116 | { | 133 | { |
@@ -139,6 +156,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, | |||
139 | dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); | 156 | dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); |
140 | goto err_disable; | 157 | goto err_disable; |
141 | } | 158 | } |
159 | cs5535_clone_olpc_cells(); | ||
142 | 160 | ||
143 | dev_info(&pdev->dev, "%zu devices registered.\n", | 161 | dev_info(&pdev->dev, "%zu devices registered.\n", |
144 | ARRAY_SIZE(cs5535_mfd_cells)); | 162 | ARRAY_SIZE(cs5535_mfd_cells)); |
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 79eda0264fb2..d01574d98870 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -184,16 +184,12 @@ void mfd_remove_devices(struct device *parent) | |||
184 | } | 184 | } |
185 | EXPORT_SYMBOL(mfd_remove_devices); | 185 | EXPORT_SYMBOL(mfd_remove_devices); |
186 | 186 | ||
187 | static int add_shared_platform_device(const char *cell, const char *name) | 187 | int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) |
188 | { | 188 | { |
189 | struct mfd_cell cell_entry; | 189 | struct mfd_cell cell_entry; |
190 | struct device *dev; | 190 | struct device *dev; |
191 | struct platform_device *pdev; | 191 | struct platform_device *pdev; |
192 | int err; | 192 | int i; |
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 | 193 | ||
198 | /* fetch the parent cell's device (should already be registered!) */ | 194 | /* fetch the parent cell's device (should already be registered!) */ |
199 | dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); | 195 | 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 | 202 | ||
207 | WARN_ON(!cell_entry.enable); | 203 | WARN_ON(!cell_entry.enable); |
208 | 204 | ||
209 | cell_entry.name = name; | 205 | for (i = 0; i < n_clones; i++) { |
210 | err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0); | 206 | cell_entry.name = clones[i]; |
211 | if (err) | 207 | /* don't give up if a single call fails; just report error */ |
212 | dev_err(dev, "MFD add devices failed: %d\n", err); | 208 | if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0)) |
213 | return err; | 209 | dev_err(dev, "failed to create platform device '%s'\n", |
214 | } | 210 | clones[i]); |
215 | 211 | } | |
216 | int 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 | } | ||
233 | EXPORT_SYMBOL(mfd_shared_platform_driver_register); | ||
234 | |||
235 | void 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 | 212 | ||
244 | platform_driver_unregister(drv); | 213 | return 0; |
245 | } | 214 | } |
246 | EXPORT_SYMBOL(mfd_shared_platform_driver_unregister); | 215 | EXPORT_SYMBOL(mfd_clone_cell); |
247 | 216 | ||
248 | MODULE_LICENSE("GPL"); | 217 | MODULE_LICENSE("GPL"); |
249 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); | 218 | MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); |
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index 1408bf8eed5f..ad1b19aa6508 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h | |||
@@ -63,6 +63,24 @@ extern int mfd_cell_enable(struct platform_device *pdev); | |||
63 | extern int mfd_cell_disable(struct platform_device *pdev); | 63 | extern int mfd_cell_disable(struct platform_device *pdev); |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * "Clone" multiple platform devices for a single cell. This is to be used | ||
67 | * for devices that have multiple users of a cell. For example, if an mfd | ||
68 | * driver wants the cell "foo" to be used by a GPIO driver, an MTD driver, | ||
69 | * and a platform driver, the following bit of code would be use after first | ||
70 | * calling mfd_add_devices(): | ||
71 | * | ||
72 | * const char *fclones[] = { "foo-gpio", "foo-mtd" }; | ||
73 | * err = mfd_clone_cells("foo", fclones, ARRAY_SIZE(fclones)); | ||
74 | * | ||
75 | * Each driver (MTD, GPIO, and platform driver) would then register | ||
76 | * platform_drivers for "foo-mtd", "foo-gpio", and "foo", respectively. | ||
77 | * The cell's .enable/.disable hooks should be used to deal with hardware | ||
78 | * resource contention. | ||
79 | */ | ||
80 | extern int mfd_clone_cell(const char *cell, const char **clones, | ||
81 | size_t n_clones); | ||
82 | |||
83 | /* | ||
66 | * Given a platform device that's been created by mfd_add_devices(), fetch | 84 | * Given a platform device that's been created by mfd_add_devices(), fetch |
67 | * the mfd_cell that created it. | 85 | * the mfd_cell that created it. |
68 | */ | 86 | */ |
@@ -87,13 +105,4 @@ extern int mfd_add_devices(struct device *parent, int id, | |||
87 | 105 | ||
88 | extern void mfd_remove_devices(struct device *parent); | 106 | extern void mfd_remove_devices(struct device *parent); |
89 | 107 | ||
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 | */ | ||
95 | extern int mfd_shared_platform_driver_register(struct platform_driver *drv, | ||
96 | const char *cellname); | ||
97 | extern void mfd_shared_platform_driver_unregister(struct platform_driver *drv); | ||
98 | |||
99 | #endif | 108 | #endif |