ACPI: EC acpi-ecdt-uid-hack
[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 max/min slowclock frequency
39  * as described in http://bcm-specs.sipsolutions.net/PowerControl
40  */
41 static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
42                                        int get_max)
43 {
44         int limit = 0;
45         int divisor;
46         int selection;
47         int err;
48         u32 tmp;
49         struct bcm43xx_coreinfo *old_core;
50
51         if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
52                 goto out;
53         old_core = bcm->current_core;
54         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
55         if (err)
56                 goto out;
57
58         if (bcm->current_core->rev < 6) {
59                 if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) ||
60                         (bcm->bustype == BCM43xx_BUSTYPE_SB)) {
61                         selection = 1;
62                         divisor = 32;
63                 } else {
64                         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
65                         if (err) {
66                                 printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n");
67                                 goto out_switchback;
68                         }
69                         if (tmp & 0x10) {
70                                 /* PCI */
71                                 selection = 2;
72                                 divisor = 64;
73                         } else {
74                                 /* XTAL */
75                                 selection = 1;
76                                 divisor = 32;
77                         }
78                 }
79         } else if (bcm->current_core->rev < 10) {
80                 selection = (tmp & 0x07);
81                 if (selection) {
82                         tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
83                         divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16));
84                 } else
85                         divisor = 1;
86         } else {
87                 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
88                 divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16));
89                 selection = 1;
90         }
91         
92         switch (selection) {
93         case 0:
94                 /* LPO */
95                 if (get_max)
96                         limit = 43000;
97                 else
98                         limit = 25000;
99                 break;
100         case 1:
101                 /* XTAL */
102                 if (get_max)
103                         limit = 20200000;
104                 else
105                         limit = 19800000;
106                 break;
107         case 2:
108                 /* PCI */
109                 if (get_max)
110                         limit = 34000000;
111                 else
112                         limit = 25000000;
113                 break;
114         default:
115                 assert(0);
116         }
117         limit /= divisor;
118
119 out_switchback:
120         err = bcm43xx_switch_core(bcm, old_core);
121         assert(err == 0);
122
123 out:
124         return limit;
125 }
126
127 /* init power control
128  * as described in http://bcm-specs.sipsolutions.net/PowerControl
129  */
130 int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
131 {
132         int err, maxfreq;
133         struct bcm43xx_coreinfo *old_core;
134
135         if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
136                 return 0;
137         old_core = bcm->current_core;
138         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
139         if (err == -ENODEV)
140                 return 0;
141         if (err)
142                 goto out;
143
144         maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1);
145         bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY,
146                         (maxfreq * 150 + 999999) / 1000000);
147         bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY,
148                         (maxfreq * 15 + 999999) / 1000000);
149
150         err = bcm43xx_switch_core(bcm, old_core);
151         assert(err == 0);
152
153 out:
154         return err;
155 }
156
157 u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm)
158 {
159         u16 delay = 0;
160         int err;
161         u32 pll_on_delay;
162         struct bcm43xx_coreinfo *old_core;
163         int minfreq;
164
165         if (bcm->bustype != BCM43xx_BUSTYPE_PCI)
166                 goto out;
167         if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
168                 goto out;
169         old_core = bcm->current_core;
170         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
171         if (err == -ENODEV)
172                 goto out;
173
174         minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0);
175         pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY);
176         delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
177
178         err = bcm43xx_switch_core(bcm, old_core);
179         assert(err == 0);
180
181 out:
182         return delay;
183 }
184
185 /* set the powercontrol clock
186  * as described in http://bcm-specs.sipsolutions.net/PowerControl
187  */
188 int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode)
189 {
190         int err;
191         struct bcm43xx_coreinfo *old_core;
192         u32 tmp;
193
194         old_core = bcm->current_core;
195         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
196         if (err == -ENODEV)
197                 return 0;
198         if (err)
199                 goto out;
200         
201         if (bcm->core_chipcommon.rev < 6) {
202                 if (mode == BCM43xx_PCTL_CLK_FAST) {
203                         err = bcm43xx_pctl_set_crystal(bcm, 1);
204                         if (err)
205                                 goto out;
206                 }
207         } else {
208                 if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) &&
209                         (bcm->core_chipcommon.rev < 10)) {
210                         switch (mode) {
211                         case BCM43xx_PCTL_CLK_FAST:
212                                 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
213                                 tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL;
214                                 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
215                                 break;
216                         case BCM43xx_PCTL_CLK_SLOW:
217                                 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
218                                 tmp |= BCM43xx_PCTL_FORCE_SLOW;
219                                 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
220                                 break;
221                         case BCM43xx_PCTL_CLK_DYNAMIC:
222                                 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
223                                 tmp &= ~BCM43xx_PCTL_FORCE_SLOW;
224                                 tmp |= BCM43xx_PCTL_FORCE_PLL;
225                                 tmp &= ~BCM43xx_PCTL_DYN_XTAL;
226                                 bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp);
227                         }
228                 }
229         }
230         
231         err = bcm43xx_switch_core(bcm, old_core);
232         assert(err == 0);
233
234 out:
235         return err;
236 }
237
238 int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on)
239 {
240         int err;
241         u32 in, out, outenable;
242
243         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in);
244         if (err)
245                 goto err_pci;
246         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out);
247         if (err)
248                 goto err_pci;
249         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable);
250         if (err)
251                 goto err_pci;
252
253         outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
254
255         if (on) {
256                 if (in & 0x40)
257                         return 0;
258
259                 out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
260
261                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
262                 if (err)
263                         goto err_pci;
264                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
265                 if (err)
266                         goto err_pci;
267                 udelay(1000);
268
269                 out &= ~BCM43xx_PCTL_PLL_POWERDOWN;
270                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
271                 if (err)
272                         goto err_pci;
273                 udelay(5000);
274         } else {
275                 if (bcm->current_core->rev < 5)
276                         return 0;
277                 if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW)
278                         return 0;
279
280 /*              XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time?
281  *              err = bcm43xx_switch_core(bcm, bcm->active_80211_core);
282  *              if (err)
283  *                      return err;
284  *              if (((bcm->current_core->rev >= 3) &&
285  *                      (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) ||
286  *                    ((bcm->current_core->rev < 3) &&
287  *                      !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4))))
288  *                      return 0;
289  *              err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
290  *              if (err)
291  *                      return err;
292  */
293                 
294                 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
295                 if (err)
296                         goto out;
297                 out &= ~BCM43xx_PCTL_XTAL_POWERUP;
298                 out |= BCM43xx_PCTL_PLL_POWERDOWN;
299                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
300                 if (err)
301                         goto err_pci;
302                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
303                 if (err)
304                         goto err_pci;
305         }
306
307 out:
308         return err;
309
310 err_pci:
311         printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n");
312         err = -EBUSY;
313         goto out;
314 }
315
316 /* Set the PowerSavingControlBits.
317  * Bitvalues:
318  *   0  => unset the bit
319  *   1  => set the bit
320  *   -1 => calculate the bit
321  */
322 void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
323                                    int bit25, int bit26)
324 {
325         int i;
326         u32 status;
327
328 //FIXME: Force 25 to off and 26 to on for now:
329 bit25 = 0;
330 bit26 = 1;
331
332         if (bit25 == -1) {
333                 //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
334                 //      and thus is not an AP and we are associated, set bit 25
335         }
336         if (bit26 == -1) {
337                 //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
338                 //      or we are associated, or FIXME, or the latest PS-Poll packet sent was
339                 //      successful, set bit26
340         }
341         status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
342         if (bit25)
343                 status |= BCM43xx_SBF_PS1;
344         else
345                 status &= ~BCM43xx_SBF_PS1;
346         if (bit26)
347                 status |= BCM43xx_SBF_PS2;
348         else
349                 status &= ~BCM43xx_SBF_PS2;
350         bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
351         if (bit26 && bcm->current_core->rev >= 5) {
352                 for (i = 0; i < 100; i++) {
353                         if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4)
354                                 break;
355                         udelay(10);
356                 }
357         }
358 }