aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2008-03-29 19:10:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-08 15:05:57 -0400
commit8fe2b65a18e49bfde56a59ed4ab3fc7aa0c2f325 (patch)
treea813fe635b7a8c248c586de847d1501c4ccaab6b /drivers/ssb
parent5100d5ac81b9330dc57e35adbe50923ba6107b8f (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.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
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
254void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state) 254void 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
123static 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
138static int ssb_device_resume(struct device *dev) 123static 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
163static 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
179static int ssb_device_suspend(struct device *dev, pm_message_t state) 140static 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 }
153out:
154 return err;
155}
156
157int 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
201out: 179 return 0;
202 return err; 180}
181EXPORT_SYMBOL(ssb_bus_resume);
182
183int 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}
190EXPORT_SYMBOL(ssb_bus_suspend);
204 191
205#ifdef CONFIG_SSB_PCIHOST 192#ifdef CONFIG_SSB_PCIHOST
206int ssb_devices_freeze(struct ssb_bus *bus) 193int 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
19static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) 19static 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
28static int ssb_pcihost_resume(struct pci_dev *dev) 34static 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. */
688int 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
687void ssb_pcmcia_exit(struct ssb_bus *bus) 710void 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);
82extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, 82extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
83 struct ssb_init_invariants *iv); 83 struct ssb_init_invariants *iv);
84extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus);
84extern void ssb_pcmcia_exit(struct ssb_bus *bus); 85extern void ssb_pcmcia_exit(struct ssb_bus *bus);
85extern int ssb_pcmcia_init(struct ssb_bus *bus); 86extern int ssb_pcmcia_init(struct ssb_bus *bus);
86extern const struct ssb_bus_ops ssb_pcmcia_ops; 87extern 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}
104static inline int ssb_pcmcia_hardware_setup(struct ssb_bus *bus)
105{
106 return 0;
107}
103static inline void ssb_pcmcia_exit(struct ssb_bus *bus) 108static inline void ssb_pcmcia_exit(struct ssb_bus *bus)
104{ 109{
105} 110}