diff options
| -rw-r--r-- | drivers/net/wireless/b43/pcmcia.c | 10 | ||||
| -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 | ||||
| -rw-r--r-- | include/linux/ssb/ssb.h | 10 | ||||
| -rw-r--r-- | include/linux/ssb/ssb_driver_chipcommon.h | 3 |
8 files changed, 88 insertions, 67 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); | |||
| 43 | #ifdef CONFIG_PM | 43 | #ifdef CONFIG_PM |
| 44 | static int b43_pcmcia_suspend(struct pcmcia_device *dev) | 44 | static int b43_pcmcia_suspend(struct pcmcia_device *dev) |
| 45 | { | 45 | { |
| 46 | //TODO | 46 | struct ssb_bus *ssb = dev->priv; |
| 47 | return 0; | 47 | |
| 48 | return ssb_bus_suspend(ssb); | ||
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | static int b43_pcmcia_resume(struct pcmcia_device *dev) | 51 | static int b43_pcmcia_resume(struct pcmcia_device *dev) |
| 51 | { | 52 | { |
| 52 | //TODO | 53 | struct ssb_bus *ssb = dev->priv; |
| 53 | return 0; | 54 | |
| 55 | return ssb_bus_resume(ssb); | ||
| 54 | } | 56 | } |
| 55 | #else /* CONFIG_PM */ | 57 | #else /* CONFIG_PM */ |
| 56 | # define b43_pcmcia_suspend NULL | 58 | # 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) | |||
| 251 | calc_fast_powerup_delay(cc); | 251 | calc_fast_powerup_delay(cc); |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state) | 254 | void ssb_chipco_suspend(struct ssb_chipcommon *cc) |
| 255 | { | 255 | { |
| 256 | if (!cc->dev) | 256 | if (!cc->dev) |
| 257 | return; | 257 | 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) | |||
| 120 | put_device(dev->dev); | 120 | put_device(dev->dev); |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | static int ssb_bus_resume(struct ssb_bus *bus) | ||
| 124 | { | ||
| 125 | int err; | ||
| 126 | |||
| 127 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); | ||
| 128 | err = ssb_pcmcia_init(bus); | ||
| 129 | if (err) { | ||
| 130 | /* No need to disable XTAL, as we don't have one on PCMCIA. */ | ||
| 131 | return err; | ||
| 132 | } | ||
| 133 | ssb_chipco_resume(&bus->chipco); | ||
| 134 | |||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | static int ssb_device_resume(struct device *dev) | 123 | static int ssb_device_resume(struct device *dev) |
| 139 | { | 124 | { |
| 140 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | 125 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); |
| 141 | struct ssb_driver *ssb_drv; | 126 | struct ssb_driver *ssb_drv; |
| 142 | struct ssb_bus *bus; | ||
| 143 | int err = 0; | 127 | int err = 0; |
| 144 | 128 | ||
| 145 | bus = ssb_dev->bus; | ||
| 146 | if (bus->suspend_cnt == bus->nr_devices) { | ||
| 147 | err = ssb_bus_resume(bus); | ||
| 148 | if (err) | ||
| 149 | return err; | ||
| 150 | } | ||
| 151 | bus->suspend_cnt--; | ||
| 152 | if (dev->driver) { | 129 | if (dev->driver) { |
| 153 | ssb_drv = drv_to_ssb_drv(dev->driver); | 130 | ssb_drv = drv_to_ssb_drv(dev->driver); |
| 154 | if (ssb_drv && ssb_drv->resume) | 131 | if (ssb_drv && ssb_drv->resume) |
| @@ -160,27 +137,10 @@ out: | |||
| 160 | return err; | 137 | return err; |
| 161 | } | 138 | } |
| 162 | 139 | ||
| 163 | static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) | ||
| 164 | { | ||
| 165 | ssb_chipco_suspend(&bus->chipco, state); | ||
| 166 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | ||
| 167 | |||
| 168 | /* Reset HW state information in memory, so that HW is | ||
| 169 | * completely reinitialized on resume. */ | ||
| 170 | bus->mapped_device = NULL; | ||
| 171 | #ifdef CONFIG_SSB_DRIVER_PCICORE | ||
| 172 | bus->pcicore.setup_done = 0; | ||
| 173 | #endif | ||
| 174 | #ifdef CONFIG_SSB_DEBUG | ||
| 175 | bus->powered_up = 0; | ||
| 176 | #endif | ||
| 177 | } | ||
| 178 | |||
| 179 | static int ssb_device_suspend(struct device *dev, pm_message_t state) | 140 | static int ssb_device_suspend(struct device *dev, pm_message_t state) |
| 180 | { | 141 | { |
| 181 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | 142 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); |
| 182 | struct ssb_driver *ssb_drv; | 143 | struct ssb_driver *ssb_drv; |
| 183 | struct ssb_bus *bus; | ||
| 184 | int err = 0; | 144 | int err = 0; |
| 185 | 145 | ||
| 186 | if (dev->driver) { | 146 | if (dev->driver) { |
| @@ -190,17 +150,44 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state) | |||
| 190 | if (err) | 150 | if (err) |
| 191 | goto out; | 151 | goto out; |
| 192 | } | 152 | } |
| 153 | out: | ||
| 154 | return err; | ||
| 155 | } | ||
| 156 | |||
| 157 | int ssb_bus_resume(struct ssb_bus *bus) | ||
| 158 | { | ||
| 159 | int err; | ||
| 193 | 160 | ||
| 194 | bus = ssb_dev->bus; | 161 | /* Reset HW state information in memory, so that HW is |
| 195 | bus->suspend_cnt++; | 162 | * completely reinitialized. */ |
| 196 | if (bus->suspend_cnt == bus->nr_devices) { | 163 | bus->mapped_device = NULL; |
| 197 | /* All devices suspended. Shutdown the bus. */ | 164 | #ifdef CONFIG_SSB_DRIVER_PCICORE |
| 198 | ssb_bus_suspend(bus, state); | 165 | bus->pcicore.setup_done = 0; |
| 166 | #endif | ||
| 167 | |||
| 168 | err = ssb_bus_powerup(bus, 0); | ||
| 169 | if (err) | ||
| 170 | return err; | ||
| 171 | err = ssb_pcmcia_hardware_setup(bus); | ||
| 172 | if (err) { | ||
| 173 | ssb_bus_may_powerdown(bus); | ||
| 174 | return err; | ||
| 199 | } | 175 | } |
| 176 | ssb_chipco_resume(&bus->chipco); | ||
| 177 | ssb_bus_may_powerdown(bus); | ||
| 200 | 178 | ||
| 201 | out: | 179 | return 0; |
| 202 | return err; | 180 | } |
| 181 | EXPORT_SYMBOL(ssb_bus_resume); | ||
| 182 | |||
| 183 | int ssb_bus_suspend(struct ssb_bus *bus) | ||
| 184 | { | ||
| 185 | ssb_chipco_suspend(&bus->chipco); | ||
| 186 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | ||
| 187 | |||
| 188 | return 0; | ||
| 203 | } | 189 | } |
| 190 | EXPORT_SYMBOL(ssb_bus_suspend); | ||
| 204 | 191 | ||
| 205 | #ifdef CONFIG_SSB_PCIHOST | 192 | #ifdef CONFIG_SSB_PCIHOST |
| 206 | int ssb_devices_freeze(struct ssb_bus *bus) | 193 | 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 @@ | |||
| 18 | #ifdef CONFIG_PM | 18 | #ifdef CONFIG_PM |
| 19 | static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) | 19 | static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) |
| 20 | { | 20 | { |
| 21 | struct ssb_bus *ssb = pci_get_drvdata(dev); | ||
| 22 | int err; | ||
| 23 | |||
| 24 | err = ssb_bus_suspend(ssb); | ||
| 25 | if (err) | ||
| 26 | return err; | ||
| 21 | pci_save_state(dev); | 27 | pci_save_state(dev); |
| 22 | pci_disable_device(dev); | 28 | pci_disable_device(dev); |
| 23 | pci_set_power_state(dev, pci_choose_state(dev, state)); | 29 | 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) | |||
| 27 | 33 | ||
| 28 | static int ssb_pcihost_resume(struct pci_dev *dev) | 34 | static int ssb_pcihost_resume(struct pci_dev *dev) |
| 29 | { | 35 | { |
| 36 | struct ssb_bus *ssb = pci_get_drvdata(dev); | ||
| 30 | int err; | 37 | int err; |
| 31 | 38 | ||
| 32 | pci_set_power_state(dev, 0); | 39 | pci_set_power_state(dev, 0); |
| @@ -34,6 +41,9 @@ static int ssb_pcihost_resume(struct pci_dev *dev) | |||
| 34 | if (err) | 41 | if (err) |
| 35 | return err; | 42 | return err; |
| 36 | pci_restore_state(dev); | 43 | pci_restore_state(dev); |
| 44 | err = ssb_bus_resume(ssb); | ||
| 45 | if (err) | ||
| 46 | return err; | ||
| 37 | 47 | ||
| 38 | return 0; | 48 | return 0; |
| 39 | } | 49 | } |
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) | |||
| 684 | return 0; | 684 | return 0; |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | /* Initialize the PCMCIA hardware. This is called on Init and Resume. */ | ||
| 688 | int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) | ||
| 689 | { | ||
| 690 | int err; | ||
| 691 | |||
| 692 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) | ||
| 693 | return 0; | ||
| 694 | |||
| 695 | /* Switch segment to a known state and sync | ||
| 696 | * bus->mapped_pcmcia_seg with hardware state. */ | ||
| 697 | ssb_pcmcia_switch_segment(bus, 0); | ||
| 698 | /* Init the COR register. */ | ||
| 699 | err = ssb_pcmcia_cor_setup(bus, CISREG_COR); | ||
| 700 | if (err) | ||
| 701 | return err; | ||
| 702 | /* Some cards also need this register to get poked. */ | ||
| 703 | err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); | ||
| 704 | if (err) | ||
| 705 | return err; | ||
| 706 | |||
| 707 | return 0; | ||
| 708 | } | ||
| 709 | |||
| 687 | void ssb_pcmcia_exit(struct ssb_bus *bus) | 710 | void ssb_pcmcia_exit(struct ssb_bus *bus) |
| 688 | { | 711 | { |
| 689 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) | 712 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) |
| @@ -699,16 +722,7 @@ int ssb_pcmcia_init(struct ssb_bus *bus) | |||
| 699 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) | 722 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) |
| 700 | return 0; | 723 | return 0; |
| 701 | 724 | ||
| 702 | /* Switch segment to a known state and sync | 725 | err = ssb_pcmcia_hardware_setup(bus); |
| 703 | * bus->mapped_pcmcia_seg with hardware state. */ | ||
| 704 | ssb_pcmcia_switch_segment(bus, 0); | ||
| 705 | |||
| 706 | /* Init the COR register. */ | ||
| 707 | err = ssb_pcmcia_cor_setup(bus, CISREG_COR); | ||
| 708 | if (err) | ||
| 709 | goto error; | ||
| 710 | /* Some cards also need this register to get poked. */ | ||
| 711 | err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); | ||
| 712 | if (err) | 726 | if (err) |
| 713 | goto error; | 727 | goto error; |
| 714 | 728 | ||
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, | |||
| 81 | u8 seg); | 81 | u8 seg); |
| 82 | extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, | 82 | extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, |
| 83 | struct ssb_init_invariants *iv); | 83 | struct ssb_init_invariants *iv); |
| 84 | extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus); | ||
| 84 | extern void ssb_pcmcia_exit(struct ssb_bus *bus); | 85 | extern void ssb_pcmcia_exit(struct ssb_bus *bus); |
| 85 | extern int ssb_pcmcia_init(struct ssb_bus *bus); | 86 | extern int ssb_pcmcia_init(struct ssb_bus *bus); |
| 86 | extern const struct ssb_bus_ops ssb_pcmcia_ops; | 87 | extern const struct ssb_bus_ops ssb_pcmcia_ops; |
| @@ -100,6 +101,10 @@ static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus, | |||
| 100 | { | 101 | { |
| 101 | return 0; | 102 | return 0; |
| 102 | } | 103 | } |
| 104 | static inline int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) | ||
| 105 | { | ||
| 106 | return 0; | ||
| 107 | } | ||
| 103 | static inline void ssb_pcmcia_exit(struct ssb_bus *bus) | 108 | static inline void ssb_pcmcia_exit(struct ssb_bus *bus) |
| 104 | { | 109 | { |
| 105 | } | 110 | } |
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 8644e03cf588..a8ca396f810a 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h | |||
| @@ -260,9 +260,6 @@ struct ssb_bus { | |||
| 260 | struct ssb_device devices[SSB_MAX_NR_CORES]; | 260 | struct ssb_device devices[SSB_MAX_NR_CORES]; |
| 261 | u8 nr_devices; | 261 | u8 nr_devices; |
| 262 | 262 | ||
| 263 | /* Reference count. Number of suspended devices. */ | ||
| 264 | u8 suspend_cnt; | ||
| 265 | |||
| 266 | /* Software ID number for this bus. */ | 263 | /* Software ID number for this bus. */ |
| 267 | unsigned int busnumber; | 264 | unsigned int busnumber; |
| 268 | 265 | ||
| @@ -334,6 +331,13 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, | |||
| 334 | 331 | ||
| 335 | extern void ssb_bus_unregister(struct ssb_bus *bus); | 332 | extern void ssb_bus_unregister(struct ssb_bus *bus); |
| 336 | 333 | ||
| 334 | /* Suspend a SSB bus. | ||
| 335 | * Call this from the parent bus suspend routine. */ | ||
| 336 | extern int ssb_bus_suspend(struct ssb_bus *bus); | ||
| 337 | /* Resume a SSB bus. | ||
| 338 | * Call this from the parent bus resume routine. */ | ||
| 339 | extern int ssb_bus_resume(struct ssb_bus *bus); | ||
| 340 | |||
| 337 | extern u32 ssb_clockspeed(struct ssb_bus *bus); | 341 | extern u32 ssb_clockspeed(struct ssb_bus *bus); |
| 338 | 342 | ||
| 339 | /* Is the device enabled in hardware? */ | 343 | /* Is the device enabled in hardware? */ |
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index b548a54ff1f5..7d7e03dcf77c 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h | |||
| @@ -367,8 +367,7 @@ static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) | |||
| 367 | 367 | ||
| 368 | extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); | 368 | extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); |
| 369 | 369 | ||
| 370 | #include <linux/pm.h> | 370 | extern void ssb_chipco_suspend(struct ssb_chipcommon *cc); |
| 371 | extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); | ||
| 372 | extern void ssb_chipco_resume(struct ssb_chipcommon *cc); | 371 | extern void ssb_chipco_resume(struct ssb_chipcommon *cc); |
| 373 | 372 | ||
| 374 | extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, | 373 | extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, |
