Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 }
394 
  This page was automatically generated by the LXR engine.