Merge branch 'misc' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerpc...
[pandora-kernel.git] / drivers / net / wireless / bcm43xx / bcm43xx_power.c
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         if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
157                 return 0;
158         old_core = bcm->current_core;
159         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
160         if (err == -ENODEV)
161                 return 0;
162         if (err)
163                 goto out;
164
165         maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
166         bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
167                         (maxfreq * 150 + 999999) / 1000000);
168         bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
169                         (maxfreq * 15 + 999999) / 1000000);
170
171         err = bcm43xx_switch_core(bcm, old_core);
172         assert(err == 0);
173
174 out:
175         return err;
176 }
177
178 u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm)
179 {
180         u16 delay = 0;
181         int err;
182         u32 pll_on_delay;
183         struct bcm43xx_coreinfo *old_core;
184         int minfreq;
185
186         if (bcm->bustype != BCM43xx_BUSTYPE_PCI)
187                 goto out;
188         if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
189                 goto out;
190         old_core = bcm->current_core;
191         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
192         if (err == -ENODEV)
193                 goto out;
194
195         minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0);
196         pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY);
197         delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
198
199         err = bcm43xx_switch_core(bcm, old_core);
200         assert(err == 0);
201
202 out:
203         return delay;
204 }
205
206 /* set the powercontrol clock
207  * as described in http://bcm-specs.sipsolutions.net/PowerControl
208  */
209 int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode)
210 {
211         int err;
212         struct bcm43xx_coreinfo *old_core;
213         u32 tmp;
214
215         old_core = bcm->current_core;
216         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
217         if (err == -ENODEV)
218                 return 0;
219         if (err)
220                 goto out;
221         
222         if (bcm->core_chipcommon.rev < 6) {
223                 if (mode == BCM43xx_PCTL_CLK_FAST) {
224                         err = bcm43xx_pctl_set_crystal(bcm, 1);
225                         if (err)
226                                 goto out;
227                 }
228         } else {
229                 if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) &&
230                         (bcm->core_chipcommon.rev < 10)) {
231                         switch (mode) {
232                         case BCM43xx_PCTL_CLK_FAST:
233                                 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
234                                 tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL;
235                                 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
236                                 break;
237                         case BCM43xx_PCTL_CLK_SLOW:
238                                 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
239                                 tmp |= BCM43xx_PCTL_FORCE_SLOW;
240                                 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
241                                 break;
242                         case BCM43xx_PCTL_CLK_DYNAMIC:
243                                 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
244                                 tmp &= ~BCM43xx_PCTL_FORCE_SLOW;
245                                 tmp |= BCM43xx_PCTL_FORCE_PLL;
246                                 tmp &= ~BCM43xx_PCTL_DYN_XTAL;
247                                 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
248                         }
249                 }
250         }
251         
252         err = bcm43xx_switch_core(bcm, old_core);
253         assert(err == 0);
254
255 out:
256         return err;
257 }
258
259 int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on)
260 {
261         int err;
262         u32 in, out, outenable;
263
264         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in);
265         if (err)
266                 goto err_pci;
267         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out);
268         if (err)
269                 goto err_pci;
270         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable);
271         if (err)
272                 goto err_pci;
273
274         outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
275
276         if (on) {
277                 if (in & 0x40)
278                         return 0;
279
280                 out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
281
282                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
283                 if (err)
284                         goto err_pci;
285                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
286                 if (err)
287                         goto err_pci;
288                 udelay(1000);
289
290                 out &= ~BCM43xx_PCTL_PLL_POWERDOWN;
291                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
292                 if (err)
293                         goto err_pci;
294                 udelay(5000);
295         } else {
296                 if (bcm->current_core->rev < 5)
297                         return 0;
298                 if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW)
299                         return 0;
300
301 /*              XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time?
302  *              err = bcm43xx_switch_core(bcm, bcm->active_80211_core);
303  *              if (err)
304  *                      return err;
305  *              if (((bcm->current_core->rev >= 3) &&
306  *                      (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) ||
307  *                    ((bcm->current_core->rev < 3) &&
308  *                      !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4))))
309  *                      return 0;
310  *              err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
311  *              if (err)
312  *                      return err;
313  */
314                 
315                 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
316                 if (err)
317                         goto out;
318                 out &= ~BCM43xx_PCTL_XTAL_POWERUP;
319                 out |= BCM43xx_PCTL_PLL_POWERDOWN;
320                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
321                 if (err)
322                         goto err_pci;
323                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
324                 if (err)
325                         goto err_pci;
326         }
327
328 out:
329         return err;
330
331 err_pci:
332         printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n");
333         err = -EBUSY;
334         goto out;
335 }
336
337 /* Set the PowerSavingControlBits.
338  * Bitvalues:
339  *   0  => unset the bit
340  *   1  => set the bit
341  *   -1 => calculate the bit
342  */
343 void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
344                                    int bit25, int bit26)
345 {
346         int i;
347         u32 status;
348
349 //FIXME: Force 25 to off and 26 to on for now:
350 bit25 = 0;
351 bit26 = 1;
352
353         if (bit25 == -1) {
354                 //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
355                 //      and thus is not an AP and we are associated, set bit 25
356         }
357         if (bit26 == -1) {
358                 //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
359                 //      or we are associated, or FIXME, or the latest PS-Poll packet sent was
360                 //      successful, set bit26
361         }
362         status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
363         if (bit25)
364                 status |= BCM43xx_SBF_PS1;
365         else
366                 status &= ~BCM43xx_SBF_PS1;
367         if (bit26)
368                 status |= BCM43xx_SBF_PS2;
369         else
370                 status &= ~BCM43xx_SBF_PS2;
371         bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
372         if (bit26 && bcm->current_core->rev >= 5) {
373                 for (i = 0; i < 100; i++) {
374                         if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4)
375                                 break;
376                         udelay(10);
377                 }
378         }
379 }