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