diff options
Diffstat (limited to 'drivers/ssb/main.c')
-rw-r--r-- | drivers/ssb/main.c | 130 |
1 files changed, 67 insertions, 63 deletions
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 579b114be412..80ff7d9e60de 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
19 | #include <linux/pci.h> | 19 | #include <linux/pci.h> |
20 | #include <linux/mmc/sdio_func.h> | 20 | #include <linux/mmc/sdio_func.h> |
21 | #include <linux/slab.h> | ||
21 | 22 | ||
22 | #include <pcmcia/cs_types.h> | 23 | #include <pcmcia/cs_types.h> |
23 | #include <pcmcia/cs.h> | 24 | #include <pcmcia/cs.h> |
@@ -140,6 +141,19 @@ static void ssb_device_put(struct ssb_device *dev) | |||
140 | put_device(dev->dev); | 141 | put_device(dev->dev); |
141 | } | 142 | } |
142 | 143 | ||
144 | static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv) | ||
145 | { | ||
146 | if (drv) | ||
147 | get_driver(&drv->drv); | ||
148 | return drv; | ||
149 | } | ||
150 | |||
151 | static inline void ssb_driver_put(struct ssb_driver *drv) | ||
152 | { | ||
153 | if (drv) | ||
154 | put_driver(&drv->drv); | ||
155 | } | ||
156 | |||
143 | static int ssb_device_resume(struct device *dev) | 157 | static int ssb_device_resume(struct device *dev) |
144 | { | 158 | { |
145 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | 159 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); |
@@ -210,90 +224,81 @@ int ssb_bus_suspend(struct ssb_bus *bus) | |||
210 | EXPORT_SYMBOL(ssb_bus_suspend); | 224 | EXPORT_SYMBOL(ssb_bus_suspend); |
211 | 225 | ||
212 | #ifdef CONFIG_SSB_SPROM | 226 | #ifdef CONFIG_SSB_SPROM |
213 | int ssb_devices_freeze(struct ssb_bus *bus) | 227 | /** ssb_devices_freeze - Freeze all devices on the bus. |
228 | * | ||
229 | * After freezing no device driver will be handling a device | ||
230 | * on this bus anymore. ssb_devices_thaw() must be called after | ||
231 | * a successful freeze to reactivate the devices. | ||
232 | * | ||
233 | * @bus: The bus. | ||
234 | * @ctx: Context structure. Pass this to ssb_devices_thaw(). | ||
235 | */ | ||
236 | int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx) | ||
214 | { | 237 | { |
215 | struct ssb_device *dev; | 238 | struct ssb_device *sdev; |
216 | struct ssb_driver *drv; | 239 | struct ssb_driver *sdrv; |
217 | int err = 0; | 240 | unsigned int i; |
218 | int i; | 241 | |
219 | pm_message_t state = PMSG_FREEZE; | 242 | memset(ctx, 0, sizeof(*ctx)); |
243 | ctx->bus = bus; | ||
244 | SSB_WARN_ON(bus->nr_devices > ARRAY_SIZE(ctx->device_frozen)); | ||
220 | 245 | ||
221 | /* First check that we are capable to freeze all devices. */ | ||
222 | for (i = 0; i < bus->nr_devices; i++) { | 246 | for (i = 0; i < bus->nr_devices; i++) { |
223 | dev = &(bus->devices[i]); | 247 | sdev = ssb_device_get(&bus->devices[i]); |
224 | if (!dev->dev || | 248 | |
225 | !dev->dev->driver || | 249 | if (!sdev->dev || !sdev->dev->driver || |
226 | !device_is_registered(dev->dev)) | 250 | !device_is_registered(sdev->dev)) { |
227 | continue; | 251 | ssb_device_put(sdev); |
228 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
229 | if (!drv) | ||
230 | continue; | 252 | continue; |
231 | if (!drv->suspend) { | ||
232 | /* Nope, can't suspend this one. */ | ||
233 | return -EOPNOTSUPP; | ||
234 | } | 253 | } |
235 | } | 254 | sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver)); |
236 | /* Now suspend all devices */ | 255 | if (!sdrv || SSB_WARN_ON(!sdrv->remove)) { |
237 | for (i = 0; i < bus->nr_devices; i++) { | 256 | ssb_device_put(sdev); |
238 | dev = &(bus->devices[i]); | ||
239 | if (!dev->dev || | ||
240 | !dev->dev->driver || | ||
241 | !device_is_registered(dev->dev)) | ||
242 | continue; | 257 | continue; |
243 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
244 | if (!drv) | ||
245 | continue; | ||
246 | err = drv->suspend(dev, state); | ||
247 | if (err) { | ||
248 | ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n", | ||
249 | dev_name(dev->dev)); | ||
250 | goto err_unwind; | ||
251 | } | 258 | } |
259 | sdrv->remove(sdev); | ||
260 | ctx->device_frozen[i] = 1; | ||
252 | } | 261 | } |
253 | 262 | ||
254 | return 0; | 263 | return 0; |
255 | err_unwind: | ||
256 | for (i--; i >= 0; i--) { | ||
257 | dev = &(bus->devices[i]); | ||
258 | if (!dev->dev || | ||
259 | !dev->dev->driver || | ||
260 | !device_is_registered(dev->dev)) | ||
261 | continue; | ||
262 | drv = drv_to_ssb_drv(dev->dev->driver); | ||
263 | if (!drv) | ||
264 | continue; | ||
265 | if (drv->resume) | ||
266 | drv->resume(dev); | ||
267 | } | ||
268 | return err; | ||
269 | } | 264 | } |
270 | 265 | ||
271 | int ssb_devices_thaw(struct ssb_bus *bus) | 266 | /** ssb_devices_thaw - Unfreeze all devices on the bus. |
267 | * | ||
268 | * This will re-attach the device drivers and re-init the devices. | ||
269 | * | ||
270 | * @ctx: The context structure from ssb_devices_freeze() | ||
271 | */ | ||
272 | int ssb_devices_thaw(struct ssb_freeze_context *ctx) | ||
272 | { | 273 | { |
273 | struct ssb_device *dev; | 274 | struct ssb_bus *bus = ctx->bus; |
274 | struct ssb_driver *drv; | 275 | struct ssb_device *sdev; |
275 | int err; | 276 | struct ssb_driver *sdrv; |
276 | int i; | 277 | unsigned int i; |
278 | int err, result = 0; | ||
277 | 279 | ||
278 | for (i = 0; i < bus->nr_devices; i++) { | 280 | for (i = 0; i < bus->nr_devices; i++) { |
279 | dev = &(bus->devices[i]); | 281 | if (!ctx->device_frozen[i]) |
280 | if (!dev->dev || | ||
281 | !dev->dev->driver || | ||
282 | !device_is_registered(dev->dev)) | ||
283 | continue; | 282 | continue; |
284 | drv = drv_to_ssb_drv(dev->dev->driver); | 283 | sdev = &bus->devices[i]; |
285 | if (!drv) | 284 | |
285 | if (SSB_WARN_ON(!sdev->dev || !sdev->dev->driver)) | ||
286 | continue; | 286 | continue; |
287 | if (SSB_WARN_ON(!drv->resume)) | 287 | sdrv = drv_to_ssb_drv(sdev->dev->driver); |
288 | if (SSB_WARN_ON(!sdrv || !sdrv->probe)) | ||
288 | continue; | 289 | continue; |
289 | err = drv->resume(dev); | 290 | |
291 | err = sdrv->probe(sdev, &sdev->id); | ||
290 | if (err) { | 292 | if (err) { |
291 | ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", | 293 | ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", |
292 | dev_name(dev->dev)); | 294 | dev_name(sdev->dev)); |
295 | result = err; | ||
293 | } | 296 | } |
297 | ssb_driver_put(sdrv); | ||
298 | ssb_device_put(sdev); | ||
294 | } | 299 | } |
295 | 300 | ||
296 | return 0; | 301 | return result; |
297 | } | 302 | } |
298 | #endif /* CONFIG_SSB_SPROM */ | 303 | #endif /* CONFIG_SSB_SPROM */ |
299 | 304 | ||
@@ -490,8 +495,7 @@ static int ssb_devices_register(struct ssb_bus *bus) | |||
490 | #endif | 495 | #endif |
491 | break; | 496 | break; |
492 | case SSB_BUSTYPE_SDIO: | 497 | case SSB_BUSTYPE_SDIO: |
493 | #ifdef CONFIG_SSB_SDIO | 498 | #ifdef CONFIG_SSB_SDIOHOST |
494 | sdev->irq = bus->host_sdio->dev.irq; | ||
495 | dev->parent = &bus->host_sdio->dev; | 499 | dev->parent = &bus->host_sdio->dev; |
496 | #endif | 500 | #endif |
497 | break; | 501 | break; |