diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-03-29 19:10:50 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-08 15:05:57 -0400 |
commit | 8fe2b65a18e49bfde56a59ed4ab3fc7aa0c2f325 (patch) | |
tree | a813fe635b7a8c248c586de847d1501c4ccaab6b /drivers/ssb | |
parent | 5100d5ac81b9330dc57e35adbe50923ba6107b8f (diff) |
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) | |||
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 | } |