summary refs log tree commit diff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/b43/pcmcia.c10
-rw-r--r--drivers/ssb/driver_chipcommon.c2
-rw-r--r--drivers/ssb/main.c81
-rw-r--r--drivers/ssb/pcihost_wrapper.c10
-rw-r--r--drivers/ssb/pcmcia.c34
-rw-r--r--drivers/ssb/ssb_private.h5
6 files changed, 80 insertions, 62 deletions
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
index 371e4a119511..b8aa16307f79 100644
--- a/drivers/net/wireless/b43/pcmcia.c
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -43,14 +43,16 @@ MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl);
 #ifdef CONFIG_PM
 static int b43_pcmcia_suspend(struct pcmcia_device *dev)
 {
-	//TODO
-	return 0;
+	struct ssb_bus *ssb = dev->priv;
+
+	return ssb_bus_suspend(ssb);
 }
 
 static int b43_pcmcia_resume(struct pcmcia_device *dev)
 {
-	//TODO
-	return 0;
+	struct ssb_bus *ssb = dev->priv;
+
+	return ssb_bus_resume(ssb);
 }
 #else /* CONFIG_PM */
 # define b43_pcmcia_suspend		NULL
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 45b672a69003..571f4fd55236 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -251,7 +251,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
 	calc_fast_powerup_delay(cc);
 }
 
-void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state)
+void ssb_chipco_suspend(struct ssb_chipcommon *cc)
 {
 	if (!cc->dev)
 		return;
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 2fcfd73b3b6e..c0cbdba07aee 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -120,35 +120,12 @@ static void ssb_device_put(struct ssb_device *dev)
 		put_device(dev->dev);
 }
 
-static int ssb_bus_resume(struct ssb_bus *bus)
-{
-	int err;
-
-	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
-	err = ssb_pcmcia_init(bus);
-	if (err) {
-		/* No need to disable XTAL, as we don't have one on PCMCIA. */
-		return err;
-	}
-	ssb_chipco_resume(&bus->chipco);
-
-	return 0;
-}
-
 static int ssb_device_resume(struct device *dev)
 {
 	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
 	struct ssb_driver *ssb_drv;
-	struct ssb_bus *bus;
 	int err = 0;
 
-	bus = ssb_dev->bus;
-	if (bus->suspend_cnt == bus->nr_devices) {
-		err = ssb_bus_resume(bus);
-		if (err)
-			return err;
-	}
-	bus->suspend_cnt--;
 	if (dev->driver) {
 		ssb_drv = drv_to_ssb_drv(dev->driver);
 		if (ssb_drv && ssb_drv->resume)
@@ -160,27 +137,10 @@ out:
 	return err;
 }
 
-static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state)
-{
-	ssb_chipco_suspend(&bus->chipco, state);
-	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
-
-	/* Reset HW state information in memory, so that HW is
-	 * completely reinitialized on resume. */
-	bus->mapped_device = NULL;
-#ifdef CONFIG_SSB_DRIVER_PCICORE
-	bus->pcicore.setup_done = 0;
-#endif
-#ifdef CONFIG_SSB_DEBUG
-	bus->powered_up = 0;
-#endif
-}
-
 static int ssb_device_suspend(struct device *dev, pm_message_t state)
 {
 	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
 	struct ssb_driver *ssb_drv;
-	struct ssb_bus *bus;
 	int err = 0;
 
 	if (dev->driver) {
@@ -190,17 +150,44 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state)
 		if (err)
 			goto out;
 	}
+out:
+	return err;
+}
+
+int ssb_bus_resume(struct ssb_bus *bus)
+{
+	int err;
 
-	bus = ssb_dev->bus;
-	bus->suspend_cnt++;
-	if (bus->suspend_cnt == bus->nr_devices) {
-		/* All devices suspended. Shutdown the bus. */
-		ssb_bus_suspend(bus, state);
+	/* Reset HW state information in memory, so that HW is
+	 * completely reinitialized. */
+	bus->mapped_device = NULL;
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+	bus->pcicore.setup_done = 0;
+#endif
+
+	err = ssb_bus_powerup(bus, 0);
+	if (err)
+		return err;
+	err = ssb_pcmcia_hardware_setup(bus);
+	if (err) {
+		ssb_bus_may_powerdown(bus);
+		return err;
 	}
+	ssb_chipco_resume(&bus->chipco);
+	ssb_bus_may_powerdown(bus);
 
-out:
-	return err;
+	return 0;
+}
+EXPORT_SYMBOL(ssb_bus_resume);
+
+int ssb_bus_suspend(struct ssb_bus *bus)
+{
+	ssb_chipco_suspend(&bus->chipco);
+	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+
+	return 0;
 }
+EXPORT_SYMBOL(ssb_bus_suspend);
 
 #ifdef CONFIG_SSB_PCIHOST
 int ssb_devices_freeze(struct ssb_bus *bus)
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
index 82a10abef640..e82db4aaa050 100644
--- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -18,6 +18,12 @@
 #ifdef CONFIG_PM
 static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
 {
+	struct ssb_bus *ssb = pci_get_drvdata(dev);
+	int err;
+
+	err = ssb_bus_suspend(ssb);
+	if (err)
+		return err;
 	pci_save_state(dev);
 	pci_disable_device(dev);
 	pci_set_power_state(dev, pci_choose_state(dev, state));
@@ -27,6 +33,7 @@ static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
 
 static int ssb_pcihost_resume(struct pci_dev *dev)
 {
+	struct ssb_bus *ssb = pci_get_drvdata(dev);
 	int err;
 
 	pci_set_power_state(dev, 0);
@@ -34,6 +41,9 @@ static int ssb_pcihost_resume(struct pci_dev *dev)
 	if (err)
 		return err;
 	pci_restore_state(dev);
+	err = ssb_bus_resume(ssb);
+	if (err)
+		return err;
 
 	return 0;
 }
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
index d674cef7210d..dcaf2412bea7 100644
--- a/drivers/ssb/pcmcia.c
+++ b/drivers/ssb/pcmcia.c
@@ -684,6 +684,29 @@ static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor)
 	return 0;
 }
 
+/* Initialize the PCMCIA hardware. This is called on Init and Resume. */
+int ssb_pcmcia_hardware_setup(struct ssb_bus *bus)
+{
+	int err;
+
+	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
+		return 0;
+
+	/* Switch segment to a known state and sync
+	 * bus->mapped_pcmcia_seg with hardware state. */
+	ssb_pcmcia_switch_segment(bus, 0);
+	/* Init the COR register. */
+	err = ssb_pcmcia_cor_setup(bus, CISREG_COR);
+	if (err)
+		return err;
+	/* Some cards also need this register to get poked. */
+	err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80);
+	if (err)
+		return err;
+
+	return 0;
+}
+
 void ssb_pcmcia_exit(struct ssb_bus *bus)
 {
 	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
@@ -699,16 +722,7 @@ int ssb_pcmcia_init(struct ssb_bus *bus)
 	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
 		return 0;
 
-	/* Switch segment to a known state and sync
-	 * bus->mapped_pcmcia_seg with hardware state. */
-	ssb_pcmcia_switch_segment(bus, 0);
-
-	/* Init the COR register. */
-	err = ssb_pcmcia_cor_setup(bus, CISREG_COR);
-	if (err)
-		goto error;
-	/* Some cards also need this register to get poked. */
-	err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80);
+	err = ssb_pcmcia_hardware_setup(bus);
 	if (err)
 		goto error;
 
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
index a83bf7a4d80b..ebc32d8fe15f 100644
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -81,6 +81,7 @@ extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
 				     u8 seg);
 extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
 				     struct ssb_init_invariants *iv);
+extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus);
 extern void ssb_pcmcia_exit(struct ssb_bus *bus);
 extern int ssb_pcmcia_init(struct ssb_bus *bus);
 extern const struct ssb_bus_ops ssb_pcmcia_ops;
@@ -100,6 +101,10 @@ static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
 {
 	return 0;
 }
+static inline int ssb_pcmcia_hardware_setup(struct ssb_bus *bus)
+{
+	return 0;
+}
 static inline void ssb_pcmcia_exit(struct ssb_bus *bus)
 {
 }