diff options
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_power.c')
-rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_power.c | 393 |
1 files changed, 0 insertions, 393 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c deleted file mode 100644 index 7e774f410953..000000000000 --- a/drivers/net/wireless/bcm43xx/bcm43xx_power.c +++ /dev/null | |||
@@ -1,393 +0,0 @@ | |||
1 | /* | ||
2 | |||
3 | Broadcom BCM43xx wireless driver | ||
4 | |||
5 | Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, | ||
6 | Stefano Brivio <st3@riseup.net> | ||
7 | Michael Buesch <mbuesch@freenet.de> | ||
8 | Danny van Dyk <kugelfang@gentoo.org> | ||
9 | Andreas Jaggi <andreas.jaggi@waterwave.ch> | ||
10 | |||
11 | Some parts of the code in this file are derived from the ipw2200 | ||
12 | driver Copyright(c) 2003 - 2004 Intel Corporation. | ||
13 | |||
14 | This program is free software; you can redistribute it and/or modify | ||
15 | it under the terms of the GNU General Public License as published by | ||
16 | the Free Software Foundation; either version 2 of the License, or | ||
17 | (at your option) any later version. | ||
18 | |||
19 | This program is distributed in the hope that it will be useful, | ||
20 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | GNU General Public License for more details. | ||
23 | |||
24 | You should have received a copy of the GNU General Public License | ||
25 | along with this program; see the file COPYING. If not, write to | ||
26 | the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, | ||
27 | Boston, MA 02110-1301, USA. | ||
28 | |||
29 | */ | ||
30 | |||
31 | #include <linux/delay.h> | ||
32 | |||
33 | #include "bcm43xx.h" | ||
34 | #include "bcm43xx_power.h" | ||
35 | #include "bcm43xx_main.h" | ||
36 | |||
37 | |||
38 | /* Get the Slow Clock Source */ | ||
39 | static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm) | ||
40 | { | ||
41 | u32 tmp; | ||
42 | int err; | ||
43 | |||
44 | assert(bcm->current_core == &bcm->core_chipcommon); | ||
45 | if (bcm->current_core->rev < 6) { | ||
46 | if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA || | ||
47 | bcm->bustype == BCM43xx_BUSTYPE_SB) | ||
48 | return BCM43xx_PCTL_CLKSRC_XTALOS; | ||
49 | if (bcm->bustype == BCM43xx_BUSTYPE_PCI) { | ||
50 | err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); | ||
51 | assert(!err); | ||
52 | if (tmp & 0x10) | ||
53 | return BCM43xx_PCTL_CLKSRC_PCI; | ||
54 | return BCM43xx_PCTL_CLKSRC_XTALOS; | ||
55 | } | ||
56 | } | ||
57 | if (bcm->current_core->rev < 10) { | ||
58 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); | ||
59 | tmp &= 0x7; | ||
60 | if (tmp == 0) | ||
61 | return BCM43xx_PCTL_CLKSRC_LOPWROS; | ||
62 | if (tmp == 1) | ||
63 | return BCM43xx_PCTL_CLKSRC_XTALOS; | ||
64 | if (tmp == 2) | ||
65 | return BCM43xx_PCTL_CLKSRC_PCI; | ||
66 | } | ||
67 | |||
68 | return BCM43xx_PCTL_CLKSRC_XTALOS; | ||
69 | } | ||
70 | |||
71 | /* Get max/min slowclock frequency | ||
72 | * as described in http://bcm-specs.sipsolutions.net/PowerControl | ||
73 | */ | ||
74 | static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, | ||
75 | int get_max) | ||
76 | { | ||
77 | int limit; | ||
78 | int clocksrc; | ||
79 | int divisor; | ||
80 | u32 tmp; | ||
81 | |||
82 | assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL); | ||
83 | assert(bcm->current_core == &bcm->core_chipcommon); | ||
84 | |||
85 | clocksrc = bcm43xx_pctl_get_slowclksrc(bcm); | ||
86 | if (bcm->current_core->rev < 6) { | ||
87 | switch (clocksrc) { | ||
88 | case BCM43xx_PCTL_CLKSRC_PCI: | ||
89 | divisor = 64; | ||
90 | break; | ||
91 | case BCM43xx_PCTL_CLKSRC_XTALOS: | ||
92 | divisor = 32; | ||
93 | break; | ||
94 | default: | ||
95 | assert(0); | ||
96 | divisor = 1; | ||
97 | } | ||
98 | } else if (bcm->current_core->rev < 10) { | ||
99 | switch (clocksrc) { | ||
100 | case BCM43xx_PCTL_CLKSRC_LOPWROS: | ||
101 | divisor = 1; | ||
102 | break; | ||
103 | case BCM43xx_PCTL_CLKSRC_XTALOS: | ||
104 | case BCM43xx_PCTL_CLKSRC_PCI: | ||
105 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); | ||
106 | divisor = ((tmp & 0xFFFF0000) >> 16) + 1; | ||
107 | divisor *= 4; | ||
108 | break; | ||
109 | default: | ||
110 | assert(0); | ||
111 | divisor = 1; | ||
112 | } | ||
113 | } else { | ||
114 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); | ||
115 | divisor = ((tmp & 0xFFFF0000) >> 16) + 1; | ||
116 | divisor *= 4; | ||
117 | } | ||
118 | |||
119 | switch (clocksrc) { | ||
120 | case BCM43xx_PCTL_CLKSRC_LOPWROS: | ||
121 | if (get_max) | ||
122 | limit = 43000; | ||
123 | else | ||
124 | limit = 25000; | ||
125 | break; | ||
126 | case BCM43xx_PCTL_CLKSRC_XTALOS: | ||
127 | if (get_max) | ||
128 | limit = 20200000; | ||
129 | else | ||
130 | limit = 19800000; | ||
131 | break; | ||
132 | case BCM43xx_PCTL_CLKSRC_PCI: | ||
133 | if (get_max) | ||
134 | limit = 34000000; | ||
135 | else | ||
136 | limit = 25000000; | ||
137 | break; | ||
138 | default: | ||
139 | assert(0); | ||
140 | limit = 0; | ||
141 | } | ||
142 | limit /= divisor; | ||
143 | |||
144 | return limit; | ||
145 | } | ||
146 | |||
147 | |||
148 | /* init power control | ||
149 | * as described in http://bcm-specs.sipsolutions.net/PowerControl | ||
150 | */ | ||
151 | int bcm43xx_pctl_init(struct bcm43xx_private *bcm) | ||
152 | { | ||
153 | int err, maxfreq; | ||
154 | struct bcm43xx_coreinfo *old_core; | ||
155 | |||
156 | old_core = bcm->current_core; | ||
157 | err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); | ||
158 | if (err == -ENODEV) | ||
159 | return 0; | ||
160 | if (err) | ||
161 | goto out; | ||
162 | |||
163 | if (bcm->chip_id == 0x4321) { | ||
164 | if (bcm->chip_rev == 0) | ||
165 | bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x03A4); | ||
166 | if (bcm->chip_rev == 1) | ||
167 | bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_CTL, 0x00A4); | ||
168 | } | ||
169 | |||
170 | if (bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) { | ||
171 | if (bcm->current_core->rev >= 10) { | ||
172 | /* Set Idle Power clock rate to 1Mhz */ | ||
173 | bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL, | ||
174 | (bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL) | ||
175 | & 0x0000FFFF) | 0x40000); | ||
176 | } else { | ||
177 | maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1); | ||
178 | bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY, | ||
179 | (maxfreq * 150 + 999999) / 1000000); | ||
180 | bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY, | ||
181 | (maxfreq * 15 + 999999) / 1000000); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | err = bcm43xx_switch_core(bcm, old_core); | ||
186 | assert(err == 0); | ||
187 | |||
188 | out: | ||
189 | return err; | ||
190 | } | ||
191 | |||
192 | u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm) | ||
193 | { | ||
194 | u16 delay = 0; | ||
195 | int err; | ||
196 | u32 pll_on_delay; | ||
197 | struct bcm43xx_coreinfo *old_core; | ||
198 | int minfreq; | ||
199 | |||
200 | if (bcm->bustype != BCM43xx_BUSTYPE_PCI) | ||
201 | goto out; | ||
202 | if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) | ||
203 | goto out; | ||
204 | old_core = bcm->current_core; | ||
205 | err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); | ||
206 | if (err == -ENODEV) | ||
207 | goto out; | ||
208 | |||
209 | minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0); | ||
210 | pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY); | ||
211 | delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; | ||
212 | |||
213 | err = bcm43xx_switch_core(bcm, old_core); | ||
214 | assert(err == 0); | ||
215 | |||
216 | out: | ||
217 | return delay; | ||
218 | } | ||
219 | |||
220 | /* set the powercontrol clock | ||
221 | * as described in http://bcm-specs.sipsolutions.net/PowerControl | ||
222 | */ | ||
223 | int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode) | ||
224 | { | ||
225 | int err; | ||
226 | struct bcm43xx_coreinfo *old_core; | ||
227 | u32 tmp; | ||
228 | |||
229 | old_core = bcm->current_core; | ||
230 | err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); | ||
231 | if (err == -ENODEV) | ||
232 | return 0; | ||
233 | if (err) | ||
234 | goto out; | ||
235 | |||
236 | if (bcm->core_chipcommon.rev < 6) { | ||
237 | if (mode == BCM43xx_PCTL_CLK_FAST) { | ||
238 | err = bcm43xx_pctl_set_crystal(bcm, 1); | ||
239 | if (err) | ||
240 | goto out; | ||
241 | } | ||
242 | } else { | ||
243 | if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) && | ||
244 | (bcm->core_chipcommon.rev < 10)) { | ||
245 | switch (mode) { | ||
246 | case BCM43xx_PCTL_CLK_FAST: | ||
247 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); | ||
248 | tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL; | ||
249 | bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); | ||
250 | break; | ||
251 | case BCM43xx_PCTL_CLK_SLOW: | ||
252 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); | ||
253 | tmp |= BCM43xx_PCTL_FORCE_SLOW; | ||
254 | bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); | ||
255 | break; | ||
256 | case BCM43xx_PCTL_CLK_DYNAMIC: | ||
257 | tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); | ||
258 | tmp &= ~BCM43xx_PCTL_FORCE_SLOW; | ||
259 | tmp |= BCM43xx_PCTL_FORCE_PLL; | ||
260 | tmp &= ~BCM43xx_PCTL_DYN_XTAL; | ||
261 | bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | |||
266 | err = bcm43xx_switch_core(bcm, old_core); | ||
267 | assert(err == 0); | ||
268 | |||
269 | out: | ||
270 | return err; | ||
271 | } | ||
272 | |||
273 | int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on) | ||
274 | { | ||
275 | int err; | ||
276 | u32 in, out, outenable; | ||
277 | |||
278 | err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in); | ||
279 | if (err) | ||
280 | goto err_pci; | ||
281 | err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out); | ||
282 | if (err) | ||
283 | goto err_pci; | ||
284 | err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable); | ||
285 | if (err) | ||
286 | goto err_pci; | ||
287 | |||
288 | outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); | ||
289 | |||
290 | if (on) { | ||
291 | if (in & 0x40) | ||
292 | return 0; | ||
293 | |||
294 | out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); | ||
295 | |||
296 | err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); | ||
297 | if (err) | ||
298 | goto err_pci; | ||
299 | err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); | ||
300 | if (err) | ||
301 | goto err_pci; | ||
302 | udelay(1000); | ||
303 | |||
304 | out &= ~BCM43xx_PCTL_PLL_POWERDOWN; | ||
305 | err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); | ||
306 | if (err) | ||
307 | goto err_pci; | ||
308 | udelay(5000); | ||
309 | } else { | ||
310 | if (bcm->current_core->rev < 5) | ||
311 | return 0; | ||
312 | if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW) | ||
313 | return 0; | ||
314 | |||
315 | /* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time? | ||
316 | * err = bcm43xx_switch_core(bcm, bcm->active_80211_core); | ||
317 | * if (err) | ||
318 | * return err; | ||
319 | * if (((bcm->current_core->rev >= 3) && | ||
320 | * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) || | ||
321 | * ((bcm->current_core->rev < 3) && | ||
322 | * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4)))) | ||
323 | * return 0; | ||
324 | * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); | ||
325 | * if (err) | ||
326 | * return err; | ||
327 | */ | ||
328 | |||
329 | err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); | ||
330 | if (err) | ||
331 | goto out; | ||
332 | out &= ~BCM43xx_PCTL_XTAL_POWERUP; | ||
333 | out |= BCM43xx_PCTL_PLL_POWERDOWN; | ||
334 | err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); | ||
335 | if (err) | ||
336 | goto err_pci; | ||
337 | err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); | ||
338 | if (err) | ||
339 | goto err_pci; | ||
340 | } | ||
341 | |||
342 | out: | ||
343 | return err; | ||
344 | |||
345 | err_pci: | ||
346 | printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n"); | ||
347 | err = -EBUSY; | ||
348 | goto out; | ||
349 | } | ||
350 | |||
351 | /* Set the PowerSavingControlBits. | ||
352 | * Bitvalues: | ||
353 | * 0 => unset the bit | ||
354 | * 1 => set the bit | ||
355 | * -1 => calculate the bit | ||
356 | */ | ||
357 | void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, | ||
358 | int bit25, int bit26) | ||
359 | { | ||
360 | int i; | ||
361 | u32 status; | ||
362 | |||
363 | //FIXME: Force 25 to off and 26 to on for now: | ||
364 | bit25 = 0; | ||
365 | bit26 = 1; | ||
366 | |||
367 | if (bit25 == -1) { | ||
368 | //TODO: If powersave is not off and FIXME is not set and we are not in adhoc | ||
369 | // and thus is not an AP and we are associated, set bit 25 | ||
370 | } | ||
371 | if (bit26 == -1) { | ||
372 | //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME, | ||
373 | // or we are associated, or FIXME, or the latest PS-Poll packet sent was | ||
374 | // successful, set bit26 | ||
375 | } | ||
376 | status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); | ||
377 | if (bit25) | ||
378 | status |= BCM43xx_SBF_PS1; | ||
379 | else | ||
380 | status &= ~BCM43xx_SBF_PS1; | ||
381 | if (bit26) | ||
382 | status |= BCM43xx_SBF_PS2; | ||
383 | else | ||
384 | status &= ~BCM43xx_SBF_PS2; | ||
385 | bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); | ||
386 | if (bit26 && bcm->current_core->rev >= 5) { | ||
387 | for (i = 0; i < 100; i++) { | ||
388 | if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4) | ||
389 | break; | ||
390 | udelay(10); | ||
391 | } | ||
392 | } | ||
393 | } | ||