|
|
@@ -128,7 +128,170 @@
|
|
|
+EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
|
|
|
--- a/drivers/ssb/main.c
|
|
|
+++ b/drivers/ssb/main.c
|
|
|
-@@ -472,6 +472,8 @@ static int ssb_devices_register(struct s
|
|
|
+@@ -120,6 +120,19 @@ static void ssb_device_put(struct ssb_de
|
|
|
+ put_device(dev->dev);
|
|
|
+ }
|
|
|
+
|
|
|
++static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv)
|
|
|
++{
|
|
|
++ if (drv)
|
|
|
++ get_driver(&drv->drv);
|
|
|
++ return drv;
|
|
|
++}
|
|
|
++
|
|
|
++static inline void ssb_driver_put(struct ssb_driver *drv)
|
|
|
++{
|
|
|
++ if (drv)
|
|
|
++ put_driver(&drv->drv);
|
|
|
++}
|
|
|
++
|
|
|
+ static int ssb_device_resume(struct device *dev)
|
|
|
+ {
|
|
|
+ struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
|
|
|
+@@ -190,90 +203,81 @@ int ssb_bus_suspend(struct ssb_bus *bus)
|
|
|
+ EXPORT_SYMBOL(ssb_bus_suspend);
|
|
|
+
|
|
|
+ #ifdef CONFIG_SSB_SPROM
|
|
|
+-int ssb_devices_freeze(struct ssb_bus *bus)
|
|
|
++/** ssb_devices_freeze - Freeze all devices on the bus.
|
|
|
++ *
|
|
|
++ * After freezing no device driver will be handling a device
|
|
|
++ * on this bus anymore. ssb_devices_thaw() must be called after
|
|
|
++ * a successful freeze to reactivate the devices.
|
|
|
++ *
|
|
|
++ * @bus: The bus.
|
|
|
++ * @ctx: Context structure. Pass this to ssb_devices_thaw().
|
|
|
++ */
|
|
|
++int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx)
|
|
|
+ {
|
|
|
+- struct ssb_device *dev;
|
|
|
+- struct ssb_driver *drv;
|
|
|
+- int err = 0;
|
|
|
+- int i;
|
|
|
+- pm_message_t state = PMSG_FREEZE;
|
|
|
++ struct ssb_device *sdev;
|
|
|
++ struct ssb_driver *sdrv;
|
|
|
++ unsigned int i;
|
|
|
++
|
|
|
++ memset(ctx, 0, sizeof(*ctx));
|
|
|
++ ctx->bus = bus;
|
|
|
++ SSB_WARN_ON(bus->nr_devices > ARRAY_SIZE(ctx->device_frozen));
|
|
|
+
|
|
|
+- /* First check that we are capable to freeze all devices. */
|
|
|
+ for (i = 0; i < bus->nr_devices; i++) {
|
|
|
+- dev = &(bus->devices[i]);
|
|
|
+- if (!dev->dev ||
|
|
|
+- !dev->dev->driver ||
|
|
|
+- !device_is_registered(dev->dev))
|
|
|
+- continue;
|
|
|
+- drv = drv_to_ssb_drv(dev->dev->driver);
|
|
|
+- if (!drv)
|
|
|
++ sdev = ssb_device_get(&bus->devices[i]);
|
|
|
++
|
|
|
++ if (!sdev->dev || !sdev->dev->driver ||
|
|
|
++ !device_is_registered(sdev->dev)) {
|
|
|
++ ssb_device_put(sdev);
|
|
|
+ continue;
|
|
|
+- if (!drv->suspend) {
|
|
|
+- /* Nope, can't suspend this one. */
|
|
|
+- return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+- }
|
|
|
+- /* Now suspend all devices */
|
|
|
+- for (i = 0; i < bus->nr_devices; i++) {
|
|
|
+- dev = &(bus->devices[i]);
|
|
|
+- if (!dev->dev ||
|
|
|
+- !dev->dev->driver ||
|
|
|
+- !device_is_registered(dev->dev))
|
|
|
+- continue;
|
|
|
+- drv = drv_to_ssb_drv(dev->dev->driver);
|
|
|
+- if (!drv)
|
|
|
++ sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
|
|
|
++ if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
|
|
|
++ ssb_device_put(sdev);
|
|
|
+ continue;
|
|
|
+- err = drv->suspend(dev, state);
|
|
|
+- if (err) {
|
|
|
+- ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
|
|
|
+- dev_name(dev->dev));
|
|
|
+- goto err_unwind;
|
|
|
+ }
|
|
|
++ sdrv->remove(sdev);
|
|
|
++ ctx->device_frozen[i] = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+-err_unwind:
|
|
|
+- for (i--; i >= 0; i--) {
|
|
|
+- dev = &(bus->devices[i]);
|
|
|
+- if (!dev->dev ||
|
|
|
+- !dev->dev->driver ||
|
|
|
+- !device_is_registered(dev->dev))
|
|
|
+- continue;
|
|
|
+- drv = drv_to_ssb_drv(dev->dev->driver);
|
|
|
+- if (!drv)
|
|
|
+- continue;
|
|
|
+- if (drv->resume)
|
|
|
+- drv->resume(dev);
|
|
|
+- }
|
|
|
+- return err;
|
|
|
+ }
|
|
|
+
|
|
|
+-int ssb_devices_thaw(struct ssb_bus *bus)
|
|
|
++/** ssb_devices_thaw - Unfreeze all devices on the bus.
|
|
|
++ *
|
|
|
++ * This will re-attach the device drivers and re-init the devices.
|
|
|
++ *
|
|
|
++ * @ctx: The context structure from ssb_devices_freeze()
|
|
|
++ */
|
|
|
++int ssb_devices_thaw(struct ssb_freeze_context *ctx)
|
|
|
+ {
|
|
|
+- struct ssb_device *dev;
|
|
|
+- struct ssb_driver *drv;
|
|
|
+- int err;
|
|
|
+- int i;
|
|
|
++ struct ssb_bus *bus = ctx->bus;
|
|
|
++ struct ssb_device *sdev;
|
|
|
++ struct ssb_driver *sdrv;
|
|
|
++ unsigned int i;
|
|
|
++ int err, result = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < bus->nr_devices; i++) {
|
|
|
+- dev = &(bus->devices[i]);
|
|
|
+- if (!dev->dev ||
|
|
|
+- !dev->dev->driver ||
|
|
|
+- !device_is_registered(dev->dev))
|
|
|
++ if (!ctx->device_frozen[i])
|
|
|
+ continue;
|
|
|
+- drv = drv_to_ssb_drv(dev->dev->driver);
|
|
|
+- if (!drv)
|
|
|
++ sdev = &bus->devices[i];
|
|
|
++
|
|
|
++ if (SSB_WARN_ON(!sdev->dev || !sdev->dev->driver))
|
|
|
+ continue;
|
|
|
+- if (SSB_WARN_ON(!drv->resume))
|
|
|
++ sdrv = drv_to_ssb_drv(sdev->dev->driver);
|
|
|
++ if (SSB_WARN_ON(!sdrv || !sdrv->probe))
|
|
|
+ continue;
|
|
|
+- err = drv->resume(dev);
|
|
|
++
|
|
|
++ err = sdrv->probe(sdev, &sdev->id);
|
|
|
+ if (err) {
|
|
|
+ ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
|
|
|
+- dev_name(dev->dev));
|
|
|
++ dev_name(sdev->dev));
|
|
|
++ result = err;
|
|
|
+ }
|
|
|
++ ssb_driver_put(sdrv);
|
|
|
++ ssb_device_put(sdev);
|
|
|
+ }
|
|
|
+
|
|
|
+- return 0;
|
|
|
++ return result;
|
|
|
+ }
|
|
|
+ #endif /* CONFIG_SSB_SPROM */
|
|
|
+
|
|
|
+@@ -472,6 +476,8 @@ static int ssb_devices_register(struct s
|
|
|
case SSB_BUSTYPE_SSB:
|
|
|
dev->dma_mask = &dev->coherent_dma_mask;
|
|
|
break;
|
|
|
@@ -137,7 +300,7 @@
|
|
|
}
|
|
|
|
|
|
sdev->dev = dev;
|
|
|
-@@ -1358,8 +1360,10 @@ static int __init ssb_modinit(void)
|
|
|
+@@ -1358,8 +1364,10 @@ static int __init ssb_modinit(void)
|
|
|
ssb_buses_lock();
|
|
|
err = ssb_attach_queued_buses();
|
|
|
ssb_buses_unlock();
|
|
|
@@ -149,7 +312,7 @@
|
|
|
|
|
|
err = b43_pci_ssb_bridge_init();
|
|
|
if (err) {
|
|
|
-@@ -1375,7 +1379,7 @@ static int __init ssb_modinit(void)
|
|
|
+@@ -1375,7 +1383,7 @@ static int __init ssb_modinit(void)
|
|
|
/* don't fail SSB init because of this */
|
|
|
err = 0;
|
|
|
}
|