aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm43xx/bcm43xx_power.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_power.c')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_power.c393
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 */
39static 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 */
74static 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 */
151int 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
188out:
189 return err;
190}
191
192u16 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
216out:
217 return delay;
218}
219
220/* set the powercontrol clock
221 * as described in http://bcm-specs.sipsolutions.net/PowerControl
222 */
223int 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
269out:
270 return err;
271}
272
273int 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
342out:
343 return err;
344
345err_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 */
357void 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:
364bit25 = 0;
365bit26 = 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}