b43: Add LP-PHY template
[linux-2.6] / drivers / net / wireless / b43 / phy_common.c
1 /*
2
3   Broadcom B43 wireless driver
4   Common PHY routines
5
6   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
7   Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
8   Copyright (c) 2005-2008 Michael Buesch <mb@bu3sch.de>
9   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
10   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
11
12   This program is free software; you can redistribute it and/or modify
13   it under the terms of the GNU General Public License as published by
14   the Free Software Foundation; either version 2 of the License, or
15   (at your option) any later version.
16
17   This program is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20   GNU General Public License for more details.
21
22   You should have received a copy of the GNU General Public License
23   along with this program; see the file COPYING.  If not, write to
24   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
25   Boston, MA 02110-1301, USA.
26
27 */
28
29 #include "phy_common.h"
30 #include "phy_g.h"
31 #include "phy_a.h"
32 #include "phy_n.h"
33 #include "phy_lp.h"
34 #include "b43.h"
35 #include "main.h"
36
37
38 int b43_phy_operations_setup(struct b43_wldev *dev)
39 {
40         struct b43_phy *phy = &(dev->phy);
41         int err;
42
43         phy->ops = NULL;
44
45         switch (phy->type) {
46         case B43_PHYTYPE_A:
47                 phy->ops = &b43_phyops_a;
48                 break;
49         case B43_PHYTYPE_G:
50                 phy->ops = &b43_phyops_g;
51                 break;
52         case B43_PHYTYPE_N:
53 #ifdef CONFIG_B43_NPHY
54                 phy->ops = &b43_phyops_n;
55 #endif
56                 break;
57         case B43_PHYTYPE_LP:
58 #ifdef CONFIG_B43_PHY_LP
59                 phy->ops = &b43_phyops_lp;
60 #endif
61                 break;
62         }
63         if (B43_WARN_ON(!phy->ops))
64                 return -ENODEV;
65
66         err = phy->ops->allocate(dev);
67         if (err)
68                 phy->ops = NULL;
69
70         return err;
71 }
72
73 int b43_phy_init(struct b43_wldev *dev)
74 {
75         struct b43_phy *phy = &dev->phy;
76         const struct b43_phy_operations *ops = phy->ops;
77         int err;
78
79         phy->channel = ops->get_default_chan(dev);
80
81         ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
82         err = ops->init(dev);
83         if (err) {
84                 b43err(dev->wl, "PHY init failed\n");
85                 goto err_block_rf;
86         }
87         /* Make sure to switch hardware and firmware (SHM) to
88          * the default channel. */
89         err = b43_switch_channel(dev, ops->get_default_chan(dev));
90         if (err) {
91                 b43err(dev->wl, "PHY init: Channel switch to default failed\n");
92                 goto err_phy_exit;
93         }
94
95         return 0;
96
97 err_phy_exit:
98         if (ops->exit)
99                 ops->exit(dev);
100 err_block_rf:
101         ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
102
103         return err;
104 }
105
106 void b43_phy_exit(struct b43_wldev *dev)
107 {
108         const struct b43_phy_operations *ops = dev->phy.ops;
109
110         ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
111         if (ops->exit)
112                 ops->exit(dev);
113 }
114
115 bool b43_has_hardware_pctl(struct b43_wldev *dev)
116 {
117         if (!dev->phy.hardware_power_control)
118                 return 0;
119         if (!dev->phy.ops->supports_hwpctl)
120                 return 0;
121         return dev->phy.ops->supports_hwpctl(dev);
122 }
123
124 void b43_radio_lock(struct b43_wldev *dev)
125 {
126         u32 macctl;
127
128         macctl = b43_read32(dev, B43_MMIO_MACCTL);
129         B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
130         macctl |= B43_MACCTL_RADIOLOCK;
131         b43_write32(dev, B43_MMIO_MACCTL, macctl);
132         /* Commit the write and wait for the device
133          * to exit any radio register access. */
134         b43_read32(dev, B43_MMIO_MACCTL);
135         udelay(10);
136 }
137
138 void b43_radio_unlock(struct b43_wldev *dev)
139 {
140         u32 macctl;
141
142         /* Commit any write */
143         b43_read16(dev, B43_MMIO_PHY_VER);
144         /* unlock */
145         macctl = b43_read32(dev, B43_MMIO_MACCTL);
146         B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
147         macctl &= ~B43_MACCTL_RADIOLOCK;
148         b43_write32(dev, B43_MMIO_MACCTL, macctl);
149 }
150
151 void b43_phy_lock(struct b43_wldev *dev)
152 {
153 #if B43_DEBUG
154         B43_WARN_ON(dev->phy.phy_locked);
155         dev->phy.phy_locked = 1;
156 #endif
157         B43_WARN_ON(dev->dev->id.revision < 3);
158
159         if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
160                 b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
161 }
162
163 void b43_phy_unlock(struct b43_wldev *dev)
164 {
165 #if B43_DEBUG
166         B43_WARN_ON(!dev->phy.phy_locked);
167         dev->phy.phy_locked = 0;
168 #endif
169         B43_WARN_ON(dev->dev->id.revision < 3);
170
171         if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
172                 b43_power_saving_ctl_bits(dev, 0);
173 }
174
175 u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
176 {
177         return dev->phy.ops->radio_read(dev, reg);
178 }
179
180 void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
181 {
182         dev->phy.ops->radio_write(dev, reg, value);
183 }
184
185 void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
186 {
187         b43_radio_write16(dev, offset,
188                           b43_radio_read16(dev, offset) & mask);
189 }
190
191 void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
192 {
193         b43_radio_write16(dev, offset,
194                           b43_radio_read16(dev, offset) | set);
195 }
196
197 void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
198 {
199         b43_radio_write16(dev, offset,
200                           (b43_radio_read16(dev, offset) & mask) | set);
201 }
202
203 u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
204 {
205         return dev->phy.ops->phy_read(dev, reg);
206 }
207
208 void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
209 {
210         dev->phy.ops->phy_write(dev, reg, value);
211 }
212
213 void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
214 {
215         b43_phy_write(dev, offset,
216                       b43_phy_read(dev, offset) & mask);
217 }
218
219 void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
220 {
221         b43_phy_write(dev, offset,
222                       b43_phy_read(dev, offset) | set);
223 }
224
225 void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
226 {
227         b43_phy_write(dev, offset,
228                       (b43_phy_read(dev, offset) & mask) | set);
229 }
230
231 int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
232 {
233         struct b43_phy *phy = &(dev->phy);
234         u16 channelcookie, savedcookie;
235         int err;
236
237         if (new_channel == B43_DEFAULT_CHANNEL)
238                 new_channel = phy->ops->get_default_chan(dev);
239
240         /* First we set the channel radio code to prevent the
241          * firmware from sending ghost packets.
242          */
243         channelcookie = new_channel;
244         if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
245                 channelcookie |= 0x100;
246         //FIXME set 40Mhz flag if required
247         savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
248         b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
249
250         /* Now try to switch the PHY hardware channel. */
251         err = phy->ops->switch_channel(dev, new_channel);
252         if (err)
253                 goto err_restore_cookie;
254
255         dev->phy.channel = new_channel;
256         /* Wait for the radio to tune to the channel and stabilize. */
257         msleep(8);
258
259         return 0;
260
261 err_restore_cookie:
262         b43_shm_write16(dev, B43_SHM_SHARED,
263                         B43_SHM_SH_CHAN, savedcookie);
264
265         return err;
266 }
267
268 void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state)
269 {
270         struct b43_phy *phy = &dev->phy;
271
272         if (state == RFKILL_STATE_HARD_BLOCKED) {
273                 /* We cannot hardware-block the device */
274                 state = RFKILL_STATE_SOFT_BLOCKED;
275         }
276
277         phy->ops->software_rfkill(dev, state);
278         phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
279 }
280
281 /**
282  * b43_phy_txpower_adjust_work - TX power workqueue.
283  *
284  * Workqueue for updating the TX power parameters in hardware.
285  */
286 void b43_phy_txpower_adjust_work(struct work_struct *work)
287 {
288         struct b43_wl *wl = container_of(work, struct b43_wl,
289                                          txpower_adjust_work);
290         struct b43_wldev *dev;
291
292         mutex_lock(&wl->mutex);
293         dev = wl->current_dev;
294
295         if (likely(dev && (b43_status(dev) >= B43_STAT_STARTED)))
296                 dev->phy.ops->adjust_txpower(dev);
297
298         mutex_unlock(&wl->mutex);
299 }
300
301 /* Called with wl->irq_lock locked */
302 void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
303 {
304         struct b43_phy *phy = &dev->phy;
305         unsigned long now = jiffies;
306         enum b43_txpwr_result result;
307
308         if (!(flags & B43_TXPWR_IGNORE_TIME)) {
309                 /* Check if it's time for a TXpower check. */
310                 if (time_before(now, phy->next_txpwr_check_time))
311                         return; /* Not yet */
312         }
313         /* The next check will be needed in two seconds, or later. */
314         phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2));
315
316         if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
317             (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306))
318                 return; /* No software txpower adjustment needed */
319
320         result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI));
321         if (result == B43_TXPWR_RES_DONE)
322                 return; /* We are done. */
323         B43_WARN_ON(result != B43_TXPWR_RES_NEED_ADJUST);
324         B43_WARN_ON(phy->ops->adjust_txpower == NULL);
325
326         /* We must adjust the transmission power in hardware.
327          * Schedule b43_phy_txpower_adjust_work(). */
328         queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work);
329 }
330
331 int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
332 {
333         const bool is_ofdm = (shm_offset != B43_SHM_SH_TSSI_CCK);
334         unsigned int a, b, c, d;
335         unsigned int average;
336         u32 tmp;
337
338         tmp = b43_shm_read32(dev, B43_SHM_SHARED, shm_offset);
339         a = tmp & 0xFF;
340         b = (tmp >> 8) & 0xFF;
341         c = (tmp >> 16) & 0xFF;
342         d = (tmp >> 24) & 0xFF;
343         if (a == 0 || a == B43_TSSI_MAX ||
344             b == 0 || b == B43_TSSI_MAX ||
345             c == 0 || c == B43_TSSI_MAX ||
346             d == 0 || d == B43_TSSI_MAX)
347                 return -ENOENT;
348         /* The values are OK. Clear them. */
349         tmp = B43_TSSI_MAX | (B43_TSSI_MAX << 8) |
350               (B43_TSSI_MAX << 16) | (B43_TSSI_MAX << 24);
351         b43_shm_write32(dev, B43_SHM_SHARED, shm_offset, tmp);
352
353         if (is_ofdm) {
354                 a = (a + 32) & 0x3F;
355                 b = (b + 32) & 0x3F;
356                 c = (c + 32) & 0x3F;
357                 d = (d + 32) & 0x3F;
358         }
359
360         /* Get the average of the values with 0.5 added to each value. */
361         average = (a + b + c + d + 2) / 4;
362         if (is_ofdm) {
363                 /* Adjust for CCK-boost */
364                 if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO)
365                     & B43_HF_CCKBOOST)
366                         average = (average >= 13) ? (average - 13) : 0;
367         }
368
369         return average;
370 }