diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-03-30 00:10:50 +0100 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-08 15:05:57 -0400 |
commit | 8fe2b65a18e49bfde56a59ed4ab3fc7aa0c2f325 (patch) | |
tree | a813fe635b7a8c248c586de847d1501c4ccaab6b /drivers/ssb | |
parent | 5100d5ac81b9330dc57e35adbe50923ba6107b8f (diff) | |
download | lwn-8fe2b65a18e49bfde56a59ed4ab3fc7aa0c2f325.tar.gz lwn-8fe2b65a18e49bfde56a59ed4ab3fc7aa0c2f325.zip |
ssb: Turn suspend/resume upside down
Turn the SSB bus suspend mechanism upside down.
Instead of deciding by an internal reference count when to suspend/resume,
let the parent bus call us in their suspend/resume routine.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/ssb')
-rw-r--r-- | drivers/ssb/driver_chipcommon.c | 2 | ||||
-rw-r--r-- | drivers/ssb/main.c | 81 | ||||
-rw-r--r-- | drivers/ssb/pcihost_wrapper.c | 10 | ||||
-rw-r--r-- | drivers/ssb/pcmcia.c | 34 | ||||
-rw-r--r-- | drivers/ssb/ssb_private.h | 5 |
5 files changed, 74 insertions, 58 deletions
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) { } |