diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-08-27 12:53:02 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-08-29 16:24:12 -0400 |
commit | ef1a628d83fc0423c36e773281162be790503168 (patch) | |
tree | 436d3d7d91434febb1813dcea16060e6937288b9 /drivers/net/wireless/b43/phy_common.c | |
parent | 35e032d82f3e2a9b0d92077b4fbc97166525ed53 (diff) |
b43: Implement dynamic PHY API
This patch implements a dynamic "ops" based PHY API.
This is needed in order to conveniently support future PHY types
to avoid the "switch"-hell.
This patch does not change any functionality. It just moves lots
of code from one place to another and adjusts it for the changed
data structures.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/phy_common.c')
-rw-r--r-- | drivers/net/wireless/b43/phy_common.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c new file mode 100644 index 00000000000..45074c05d51 --- /dev/null +++ b/drivers/net/wireless/b43/phy_common.c | |||
@@ -0,0 +1,276 @@ | |||
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 "nphy.h" | ||
33 | #include "b43.h" | ||
34 | #include "main.h" | ||
35 | |||
36 | |||
37 | int b43_phy_operations_setup(struct b43_wldev *dev) | ||
38 | { | ||
39 | struct b43_phy *phy = &(dev->phy); | ||
40 | int err; | ||
41 | |||
42 | phy->ops = NULL; | ||
43 | |||
44 | switch (phy->type) { | ||
45 | case B43_PHYTYPE_A: | ||
46 | phy->ops = &b43_phyops_a; | ||
47 | break; | ||
48 | case B43_PHYTYPE_G: | ||
49 | phy->ops = &b43_phyops_g; | ||
50 | break; | ||
51 | case B43_PHYTYPE_N: | ||
52 | #ifdef CONFIG_B43_NPHY | ||
53 | phy->ops = &b43_phyops_n; | ||
54 | #endif | ||
55 | break; | ||
56 | case B43_PHYTYPE_LP: | ||
57 | /* FIXME: Not yet */ | ||
58 | break; | ||
59 | } | ||
60 | if (B43_WARN_ON(!phy->ops)) | ||
61 | return -ENODEV; | ||
62 | |||
63 | err = phy->ops->allocate(dev); | ||
64 | if (err) | ||
65 | phy->ops = NULL; | ||
66 | |||
67 | return err; | ||
68 | } | ||
69 | |||
70 | int b43_phy_init(struct b43_wldev *dev) | ||
71 | { | ||
72 | struct b43_phy *phy = &dev->phy; | ||
73 | const struct b43_phy_operations *ops = phy->ops; | ||
74 | int err; | ||
75 | |||
76 | phy->channel = ops->get_default_chan(dev); | ||
77 | |||
78 | ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED); | ||
79 | err = ops->init(dev); | ||
80 | if (err) { | ||
81 | b43err(dev->wl, "PHY init failed\n"); | ||
82 | goto err_block_rf; | ||
83 | } | ||
84 | /* Make sure to switch hardware and firmware (SHM) to | ||
85 | * the default channel. */ | ||
86 | err = b43_switch_channel(dev, ops->get_default_chan(dev)); | ||
87 | if (err) { | ||
88 | b43err(dev->wl, "PHY init: Channel switch to default failed\n"); | ||
89 | goto err_phy_exit; | ||
90 | } | ||
91 | |||
92 | return 0; | ||
93 | |||
94 | err_phy_exit: | ||
95 | if (ops->exit) | ||
96 | ops->exit(dev); | ||
97 | err_block_rf: | ||
98 | ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); | ||
99 | |||
100 | return err; | ||
101 | } | ||
102 | |||
103 | void b43_phy_exit(struct b43_wldev *dev) | ||
104 | { | ||
105 | const struct b43_phy_operations *ops = dev->phy.ops; | ||
106 | |||
107 | ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED); | ||
108 | if (ops->exit) | ||
109 | ops->exit(dev); | ||
110 | } | ||
111 | |||
112 | bool b43_has_hardware_pctl(struct b43_wldev *dev) | ||
113 | { | ||
114 | if (!dev->phy.hardware_power_control) | ||
115 | return 0; | ||
116 | if (!dev->phy.ops->supports_hwpctl) | ||
117 | return 0; | ||
118 | return dev->phy.ops->supports_hwpctl(dev); | ||
119 | } | ||
120 | |||
121 | void b43_radio_lock(struct b43_wldev *dev) | ||
122 | { | ||
123 | u32 macctl; | ||
124 | |||
125 | macctl = b43_read32(dev, B43_MMIO_MACCTL); | ||
126 | B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK); | ||
127 | macctl |= B43_MACCTL_RADIOLOCK; | ||
128 | b43_write32(dev, B43_MMIO_MACCTL, macctl); | ||
129 | /* Commit the write and wait for the device | ||
130 | * to exit any radio register access. */ | ||
131 | b43_read32(dev, B43_MMIO_MACCTL); | ||
132 | udelay(10); | ||
133 | } | ||
134 | |||
135 | void b43_radio_unlock(struct b43_wldev *dev) | ||
136 | { | ||
137 | u32 macctl; | ||
138 | |||
139 | /* Commit any write */ | ||
140 | b43_read16(dev, B43_MMIO_PHY_VER); | ||
141 | /* unlock */ | ||
142 | macctl = b43_read32(dev, B43_MMIO_MACCTL); | ||
143 | B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK)); | ||
144 | macctl &= ~B43_MACCTL_RADIOLOCK; | ||
145 | b43_write32(dev, B43_MMIO_MACCTL, macctl); | ||
146 | } | ||
147 | |||
148 | void b43_phy_lock(struct b43_wldev *dev) | ||
149 | { | ||
150 | #if B43_DEBUG | ||
151 | B43_WARN_ON(dev->phy.phy_locked); | ||
152 | dev->phy.phy_locked = 1; | ||
153 | #endif | ||
154 | B43_WARN_ON(dev->dev->id.revision < 3); | ||
155 | |||
156 | if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) | ||
157 | b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); | ||
158 | } | ||
159 | |||
160 | void b43_phy_unlock(struct b43_wldev *dev) | ||
161 | { | ||
162 | #if B43_DEBUG | ||
163 | B43_WARN_ON(!dev->phy.phy_locked); | ||
164 | dev->phy.phy_locked = 0; | ||
165 | #endif | ||
166 | B43_WARN_ON(dev->dev->id.revision < 3); | ||
167 | |||
168 | if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) | ||
169 | b43_power_saving_ctl_bits(dev, 0); | ||
170 | } | ||
171 | |||
172 | u16 b43_radio_read(struct b43_wldev *dev, u16 reg) | ||
173 | { | ||
174 | return dev->phy.ops->radio_read(dev, reg); | ||
175 | } | ||
176 | |||
177 | void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value) | ||
178 | { | ||
179 | dev->phy.ops->radio_write(dev, reg, value); | ||
180 | } | ||
181 | |||
182 | void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask) | ||
183 | { | ||
184 | b43_radio_write16(dev, offset, | ||
185 | b43_radio_read16(dev, offset) & mask); | ||
186 | } | ||
187 | |||
188 | void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set) | ||
189 | { | ||
190 | b43_radio_write16(dev, offset, | ||
191 | b43_radio_read16(dev, offset) | set); | ||
192 | } | ||
193 | |||
194 | void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) | ||
195 | { | ||
196 | b43_radio_write16(dev, offset, | ||
197 | (b43_radio_read16(dev, offset) & mask) | set); | ||
198 | } | ||
199 | |||
200 | u16 b43_phy_read(struct b43_wldev *dev, u16 reg) | ||
201 | { | ||
202 | return dev->phy.ops->phy_read(dev, reg); | ||
203 | } | ||
204 | |||
205 | void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) | ||
206 | { | ||
207 | dev->phy.ops->phy_write(dev, reg, value); | ||
208 | } | ||
209 | |||
210 | void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) | ||
211 | { | ||
212 | b43_phy_write(dev, offset, | ||
213 | b43_phy_read(dev, offset) & mask); | ||
214 | } | ||
215 | |||
216 | void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) | ||
217 | { | ||
218 | b43_phy_write(dev, offset, | ||
219 | b43_phy_read(dev, offset) | set); | ||
220 | } | ||
221 | |||
222 | void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) | ||
223 | { | ||
224 | b43_phy_write(dev, offset, | ||
225 | (b43_phy_read(dev, offset) & mask) | set); | ||
226 | } | ||
227 | |||
228 | int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel) | ||
229 | { | ||
230 | struct b43_phy *phy = &(dev->phy); | ||
231 | u16 channelcookie, savedcookie; | ||
232 | int err; | ||
233 | |||
234 | if (new_channel == B43_DEFAULT_CHANNEL) | ||
235 | new_channel = phy->ops->get_default_chan(dev); | ||
236 | |||
237 | /* First we set the channel radio code to prevent the | ||
238 | * firmware from sending ghost packets. | ||
239 | */ | ||
240 | channelcookie = new_channel; | ||
241 | if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) | ||
242 | channelcookie |= 0x100; | ||
243 | //FIXME set 40Mhz flag if required | ||
244 | savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); | ||
245 | b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); | ||
246 | |||
247 | /* Now try to switch the PHY hardware channel. */ | ||
248 | err = phy->ops->switch_channel(dev, new_channel); | ||
249 | if (err) | ||
250 | goto err_restore_cookie; | ||
251 | |||
252 | dev->phy.channel = new_channel; | ||
253 | /* Wait for the radio to tune to the channel and stabilize. */ | ||
254 | msleep(8); | ||
255 | |||
256 | return 0; | ||
257 | |||
258 | err_restore_cookie: | ||
259 | b43_shm_write16(dev, B43_SHM_SHARED, | ||
260 | B43_SHM_SH_CHAN, savedcookie); | ||
261 | |||
262 | return err; | ||
263 | } | ||
264 | |||
265 | void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) | ||
266 | { | ||
267 | struct b43_phy *phy = &dev->phy; | ||
268 | |||
269 | if (state == RFKILL_STATE_HARD_BLOCKED) { | ||
270 | /* We cannot hardware-block the device */ | ||
271 | state = RFKILL_STATE_SOFT_BLOCKED; | ||
272 | } | ||
273 | |||
274 | phy->ops->software_rfkill(dev, state); | ||
275 | phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); | ||
276 | } | ||