1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun Broadcom B43 wireless driver
4*4882a593Smuzhiyun IEEE 802.11n LCN-PHY support
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun This program is free software; you can redistribute it and/or modify
9*4882a593Smuzhiyun it under the terms of the GNU General Public License as published by
10*4882a593Smuzhiyun the Free Software Foundation; either version 2 of the License, or
11*4882a593Smuzhiyun (at your option) any later version.
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun This program is distributed in the hope that it will be useful,
14*4882a593Smuzhiyun but WITHOUT ANY WARRANTY; without even the implied warranty of
15*4882a593Smuzhiyun MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*4882a593Smuzhiyun GNU General Public License for more details.
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun You should have received a copy of the GNU General Public License
19*4882a593Smuzhiyun along with this program; see the file COPYING. If not, write to
20*4882a593Smuzhiyun the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
21*4882a593Smuzhiyun Boston, MA 02110-1301, USA.
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun This file incorporates work covered by the following copyright and
24*4882a593Smuzhiyun permission notice:
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun Copyright (c) 2010 Broadcom Corporation
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun Permission to use, copy, modify, and/or distribute this software for any
29*4882a593Smuzhiyun purpose with or without fee is hereby granted, provided that the above
30*4882a593Smuzhiyun copyright notice and this permission notice appear in all copies.
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include <linux/slab.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include "b43.h"
36*4882a593Smuzhiyun #include "phy_lcn.h"
37*4882a593Smuzhiyun #include "tables_phy_lcn.h"
38*4882a593Smuzhiyun #include "main.h"
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun struct lcn_tx_gains {
41*4882a593Smuzhiyun u16 gm_gain;
42*4882a593Smuzhiyun u16 pga_gain;
43*4882a593Smuzhiyun u16 pad_gain;
44*4882a593Smuzhiyun u16 dac_gain;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun struct lcn_tx_iir_filter {
48*4882a593Smuzhiyun u8 type;
49*4882a593Smuzhiyun u16 values[16];
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun enum lcn_sense_type {
53*4882a593Smuzhiyun B43_SENSE_TEMP,
54*4882a593Smuzhiyun B43_SENSE_VBAT,
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /**************************************************
58*4882a593Smuzhiyun * Radio 2064.
59*4882a593Smuzhiyun **************************************************/
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* wlc_lcnphy_radio_2064_channel_tune_4313 */
b43_radio_2064_channel_setup(struct b43_wldev * dev)62*4882a593Smuzhiyun static void b43_radio_2064_channel_setup(struct b43_wldev *dev)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun u16 save[2];
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun b43_radio_set(dev, 0x09d, 0x4);
67*4882a593Smuzhiyun b43_radio_write(dev, 0x09e, 0xf);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* Channel specific values in theory, in practice always the same */
70*4882a593Smuzhiyun b43_radio_write(dev, 0x02a, 0xb);
71*4882a593Smuzhiyun b43_radio_maskset(dev, 0x030, ~0x3, 0xa);
72*4882a593Smuzhiyun b43_radio_maskset(dev, 0x091, ~0x3, 0);
73*4882a593Smuzhiyun b43_radio_maskset(dev, 0x038, ~0xf, 0x7);
74*4882a593Smuzhiyun b43_radio_maskset(dev, 0x030, ~0xc, 0x8);
75*4882a593Smuzhiyun b43_radio_maskset(dev, 0x05e, ~0xf, 0x8);
76*4882a593Smuzhiyun b43_radio_maskset(dev, 0x05e, ~0xf0, 0x80);
77*4882a593Smuzhiyun b43_radio_write(dev, 0x06c, 0x80);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun save[0] = b43_radio_read(dev, 0x044);
80*4882a593Smuzhiyun save[1] = b43_radio_read(dev, 0x12b);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun b43_radio_set(dev, 0x044, 0x7);
83*4882a593Smuzhiyun b43_radio_set(dev, 0x12b, 0xe);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* TODO */
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun b43_radio_write(dev, 0x040, 0xfb);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun b43_radio_write(dev, 0x041, 0x9a);
90*4882a593Smuzhiyun b43_radio_write(dev, 0x042, 0xa3);
91*4882a593Smuzhiyun b43_radio_write(dev, 0x043, 0x0c);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /* TODO */
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun b43_radio_set(dev, 0x044, 0x0c);
96*4882a593Smuzhiyun udelay(1);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun b43_radio_write(dev, 0x044, save[0]);
99*4882a593Smuzhiyun b43_radio_write(dev, 0x12b, save[1]);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun if (dev->phy.rev == 1) {
102*4882a593Smuzhiyun /* brcmsmac uses outdated 0x3 for 0x038 */
103*4882a593Smuzhiyun b43_radio_write(dev, 0x038, 0x0);
104*4882a593Smuzhiyun b43_radio_write(dev, 0x091, 0x7);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* wlc_radio_2064_init */
b43_radio_2064_init(struct b43_wldev * dev)109*4882a593Smuzhiyun static void b43_radio_2064_init(struct b43_wldev *dev)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
112*4882a593Smuzhiyun b43_radio_write(dev, 0x09c, 0x0020);
113*4882a593Smuzhiyun b43_radio_write(dev, 0x105, 0x0008);
114*4882a593Smuzhiyun } else {
115*4882a593Smuzhiyun /* TODO */
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun b43_radio_write(dev, 0x032, 0x0062);
118*4882a593Smuzhiyun b43_radio_write(dev, 0x033, 0x0019);
119*4882a593Smuzhiyun b43_radio_write(dev, 0x090, 0x0010);
120*4882a593Smuzhiyun b43_radio_write(dev, 0x010, 0x0000);
121*4882a593Smuzhiyun if (dev->phy.rev == 1) {
122*4882a593Smuzhiyun b43_radio_write(dev, 0x060, 0x007f);
123*4882a593Smuzhiyun b43_radio_write(dev, 0x061, 0x0072);
124*4882a593Smuzhiyun b43_radio_write(dev, 0x062, 0x007f);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun b43_radio_write(dev, 0x01d, 0x0002);
127*4882a593Smuzhiyun b43_radio_write(dev, 0x01e, 0x0006);
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun b43_phy_write(dev, 0x4ea, 0x4688);
130*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4eb, ~0x7, 0x2);
131*4882a593Smuzhiyun b43_phy_mask(dev, 0x4eb, ~0x01c0);
132*4882a593Smuzhiyun b43_phy_maskset(dev, 0x46a, 0xff00, 0x19);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x55), 0);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
137*4882a593Smuzhiyun b43_radio_set(dev, 0x004, 0x40);
138*4882a593Smuzhiyun b43_radio_set(dev, 0x120, 0x10);
139*4882a593Smuzhiyun b43_radio_set(dev, 0x078, 0x80);
140*4882a593Smuzhiyun b43_radio_set(dev, 0x129, 0x2);
141*4882a593Smuzhiyun b43_radio_set(dev, 0x057, 0x1);
142*4882a593Smuzhiyun b43_radio_set(dev, 0x05b, 0x2);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /* TODO: wait for some bit to be set */
145*4882a593Smuzhiyun b43_radio_read(dev, 0x05c);
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
148*4882a593Smuzhiyun b43_radio_mask(dev, 0x057, (u16) ~0xff01);
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun b43_phy_write(dev, 0x933, 0x2d6b);
151*4882a593Smuzhiyun b43_phy_write(dev, 0x934, 0x2d6b);
152*4882a593Smuzhiyun b43_phy_write(dev, 0x935, 0x2d6b);
153*4882a593Smuzhiyun b43_phy_write(dev, 0x936, 0x2d6b);
154*4882a593Smuzhiyun b43_phy_write(dev, 0x937, 0x016b);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun b43_radio_mask(dev, 0x057, (u16) ~0xff02);
157*4882a593Smuzhiyun b43_radio_write(dev, 0x0c2, 0x006f);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /**************************************************
161*4882a593Smuzhiyun * Various PHY ops
162*4882a593Smuzhiyun **************************************************/
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /* wlc_lcnphy_toggle_afe_pwdn */
b43_phy_lcn_afe_set_unset(struct b43_wldev * dev)165*4882a593Smuzhiyun static void b43_phy_lcn_afe_set_unset(struct b43_wldev *dev)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun u16 afe_ctl2 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL2);
168*4882a593Smuzhiyun u16 afe_ctl1 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL1);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 | 0x1);
171*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 | 0x1);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 & ~0x1);
174*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 & ~0x1);
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2);
177*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* wlc_lcnphy_get_pa_gain */
b43_phy_lcn_get_pa_gain(struct b43_wldev * dev)181*4882a593Smuzhiyun static u16 b43_phy_lcn_get_pa_gain(struct b43_wldev *dev)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun return (b43_phy_read(dev, 0x4fb) & 0x7f00) >> 8;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* wlc_lcnphy_set_dac_gain */
b43_phy_lcn_set_dac_gain(struct b43_wldev * dev,u16 dac_gain)187*4882a593Smuzhiyun static void b43_phy_lcn_set_dac_gain(struct b43_wldev *dev, u16 dac_gain)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun u16 dac_ctrl;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun dac_ctrl = b43_phy_read(dev, 0x439);
192*4882a593Smuzhiyun dac_ctrl = dac_ctrl & 0xc7f;
193*4882a593Smuzhiyun dac_ctrl = dac_ctrl | (dac_gain << 7);
194*4882a593Smuzhiyun b43_phy_maskset(dev, 0x439, ~0xfff, dac_ctrl);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /* wlc_lcnphy_set_bbmult */
b43_phy_lcn_set_bbmult(struct b43_wldev * dev,u8 m0)198*4882a593Smuzhiyun static void b43_phy_lcn_set_bbmult(struct b43_wldev *dev, u8 m0)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x57), m0 << 8);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /* wlc_lcnphy_clear_tx_power_offsets */
b43_phy_lcn_clear_tx_power_offsets(struct b43_wldev * dev)204*4882a593Smuzhiyun static void b43_phy_lcn_clear_tx_power_offsets(struct b43_wldev *dev)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun u8 i;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (1) { /* FIXME */
209*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x340);
210*4882a593Smuzhiyun for (i = 0; i < 30; i++) {
211*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
212*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x80);
217*4882a593Smuzhiyun for (i = 0; i < 64; i++) {
218*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
219*4882a593Smuzhiyun b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /* wlc_lcnphy_rev0_baseband_init */
b43_phy_lcn_rev0_baseband_init(struct b43_wldev * dev)224*4882a593Smuzhiyun static void b43_phy_lcn_rev0_baseband_init(struct b43_wldev *dev)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun b43_radio_write(dev, 0x11c, 0);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun b43_phy_write(dev, 0x43b, 0);
229*4882a593Smuzhiyun b43_phy_write(dev, 0x43c, 0);
230*4882a593Smuzhiyun b43_phy_write(dev, 0x44c, 0);
231*4882a593Smuzhiyun b43_phy_write(dev, 0x4e6, 0);
232*4882a593Smuzhiyun b43_phy_write(dev, 0x4f9, 0);
233*4882a593Smuzhiyun b43_phy_write(dev, 0x4b0, 0);
234*4882a593Smuzhiyun b43_phy_write(dev, 0x938, 0);
235*4882a593Smuzhiyun b43_phy_write(dev, 0x4b0, 0);
236*4882a593Smuzhiyun b43_phy_write(dev, 0x44e, 0);
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun b43_phy_set(dev, 0x567, 0x03);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun b43_phy_set(dev, 0x44a, 0x44);
241*4882a593Smuzhiyun b43_phy_write(dev, 0x44a, 0x80);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM))
244*4882a593Smuzhiyun ; /* TODO */
245*4882a593Smuzhiyun b43_phy_maskset(dev, 0x634, ~0xff, 0xc);
246*4882a593Smuzhiyun if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM) {
247*4882a593Smuzhiyun b43_phy_maskset(dev, 0x634, ~0xff, 0xa);
248*4882a593Smuzhiyun b43_phy_write(dev, 0x910, 0x1);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun b43_phy_write(dev, 0x910, 0x1);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun b43_phy_maskset(dev, 0x448, ~0x300, 0x100);
254*4882a593Smuzhiyun b43_phy_maskset(dev, 0x608, ~0xff, 0x17);
255*4882a593Smuzhiyun b43_phy_maskset(dev, 0x604, ~0x7ff, 0x3ea);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun /* wlc_lcnphy_bu_tweaks */
b43_phy_lcn_bu_tweaks(struct b43_wldev * dev)259*4882a593Smuzhiyun static void b43_phy_lcn_bu_tweaks(struct b43_wldev *dev)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun b43_phy_set(dev, 0x805, 0x1);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun b43_phy_maskset(dev, 0x42f, ~0x7, 0x3);
264*4882a593Smuzhiyun b43_phy_maskset(dev, 0x030, ~0x7, 0x3);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun b43_phy_write(dev, 0x414, 0x1e10);
267*4882a593Smuzhiyun b43_phy_write(dev, 0x415, 0x0640);
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4df, (u16) ~0xff00, 0xf700);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun b43_phy_set(dev, 0x44a, 0x44);
272*4882a593Smuzhiyun b43_phy_write(dev, 0x44a, 0x80);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun b43_phy_maskset(dev, 0x434, ~0xff, 0xfd);
275*4882a593Smuzhiyun b43_phy_maskset(dev, 0x420, ~0xff, 0x10);
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun if (dev->dev->bus_sprom->board_rev >= 0x1204)
278*4882a593Smuzhiyun b43_radio_set(dev, 0x09b, 0xf0);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun b43_phy_write(dev, 0x7d6, 0x0902);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun b43_phy_maskset(dev, 0x429, ~0xf, 0x9);
283*4882a593Smuzhiyun b43_phy_maskset(dev, 0x429, ~(0x3f << 4), 0xe << 4);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun if (dev->phy.rev == 1) {
286*4882a593Smuzhiyun b43_phy_maskset(dev, 0x423, ~0xff, 0x46);
287*4882a593Smuzhiyun b43_phy_maskset(dev, 0x411, ~0xff, 1);
288*4882a593Smuzhiyun b43_phy_set(dev, 0x434, 0xff); /* FIXME: update to wl */
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun /* TODO: wl operates on PHY 0x416, brcmsmac is outdated here */
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun b43_phy_maskset(dev, 0x656, ~0xf, 2);
293*4882a593Smuzhiyun b43_phy_set(dev, 0x44d, 4);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun b43_radio_set(dev, 0x0f7, 0x4);
296*4882a593Smuzhiyun b43_radio_mask(dev, 0x0f1, ~0x3);
297*4882a593Smuzhiyun b43_radio_maskset(dev, 0x0f2, ~0xf8, 0x90);
298*4882a593Smuzhiyun b43_radio_maskset(dev, 0x0f3, ~0x3, 0x2);
299*4882a593Smuzhiyun b43_radio_maskset(dev, 0x0f3, ~0xf0, 0xa0);
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun b43_radio_set(dev, 0x11f, 0x2);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun b43_phy_lcn_clear_tx_power_offsets(dev);
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun /* TODO: something more? */
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /* wlc_lcnphy_vbat_temp_sense_setup */
b43_phy_lcn_sense_setup(struct b43_wldev * dev,enum lcn_sense_type sense_type)310*4882a593Smuzhiyun static void b43_phy_lcn_sense_setup(struct b43_wldev *dev,
311*4882a593Smuzhiyun enum lcn_sense_type sense_type)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
314*4882a593Smuzhiyun u16 auxpga_vmid;
315*4882a593Smuzhiyun u8 tx_pwr_idx;
316*4882a593Smuzhiyun u8 i;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun u16 save_radio_regs[6][2] = {
319*4882a593Smuzhiyun { 0x007, 0 }, { 0x0ff, 0 }, { 0x11f, 0 }, { 0x005, 0 },
320*4882a593Smuzhiyun { 0x025, 0 }, { 0x112, 0 },
321*4882a593Smuzhiyun };
322*4882a593Smuzhiyun u16 save_phy_regs[14][2] = {
323*4882a593Smuzhiyun { 0x503, 0 }, { 0x4a4, 0 }, { 0x4d0, 0 }, { 0x4d9, 0 },
324*4882a593Smuzhiyun { 0x4da, 0 }, { 0x4a6, 0 }, { 0x938, 0 }, { 0x939, 0 },
325*4882a593Smuzhiyun { 0x4d8, 0 }, { 0x4d0, 0 }, { 0x4d7, 0 }, { 0x4a5, 0 },
326*4882a593Smuzhiyun { 0x40d, 0 }, { 0x4a2, 0 },
327*4882a593Smuzhiyun };
328*4882a593Smuzhiyun u16 save_radio_4a4;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun msleep(1);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun /* Save */
333*4882a593Smuzhiyun for (i = 0; i < 6; i++)
334*4882a593Smuzhiyun save_radio_regs[i][1] = b43_radio_read(dev,
335*4882a593Smuzhiyun save_radio_regs[i][0]);
336*4882a593Smuzhiyun for (i = 0; i < 14; i++)
337*4882a593Smuzhiyun save_phy_regs[i][1] = b43_phy_read(dev, save_phy_regs[i][0]);
338*4882a593Smuzhiyun b43_mac_suspend(dev);
339*4882a593Smuzhiyun save_radio_4a4 = b43_radio_read(dev, 0x4a4);
340*4882a593Smuzhiyun /* wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); */
341*4882a593Smuzhiyun tx_pwr_idx = dev->phy.lcn->tx_pwr_curr_idx;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun /* Setup */
344*4882a593Smuzhiyun /* TODO: wlc_lcnphy_set_tx_pwr_by_index(pi, 127); */
345*4882a593Smuzhiyun b43_radio_set(dev, 0x007, 0x1);
346*4882a593Smuzhiyun b43_radio_set(dev, 0x0ff, 0x10);
347*4882a593Smuzhiyun b43_radio_set(dev, 0x11f, 0x4);
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun b43_phy_mask(dev, 0x503, ~0x1);
350*4882a593Smuzhiyun b43_phy_mask(dev, 0x503, ~0x4);
351*4882a593Smuzhiyun b43_phy_mask(dev, 0x4a4, ~0x4000);
352*4882a593Smuzhiyun b43_phy_mask(dev, 0x4a4, (u16) ~0x8000);
353*4882a593Smuzhiyun b43_phy_mask(dev, 0x4d0, ~0x20);
354*4882a593Smuzhiyun b43_phy_set(dev, 0x4a5, 0xff);
355*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4a5, ~0x7000, 0x5000);
356*4882a593Smuzhiyun b43_phy_mask(dev, 0x4a5, ~0x700);
357*4882a593Smuzhiyun b43_phy_maskset(dev, 0x40d, ~0xff, 64);
358*4882a593Smuzhiyun b43_phy_maskset(dev, 0x40d, ~0x700, 0x600);
359*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4a2, ~0xff, 64);
360*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4a2, ~0x700, 0x600);
361*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4d9, ~0x70, 0x20);
362*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4d9, ~0x700, 0x300);
363*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4d9, ~0x7000, 0x1000);
364*4882a593Smuzhiyun b43_phy_mask(dev, 0x4da, ~0x1000);
365*4882a593Smuzhiyun b43_phy_set(dev, 0x4da, 0x2000);
366*4882a593Smuzhiyun b43_phy_set(dev, 0x4a6, 0x8000);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun b43_radio_write(dev, 0x025, 0xc);
369*4882a593Smuzhiyun b43_radio_set(dev, 0x005, 0x8);
370*4882a593Smuzhiyun b43_phy_set(dev, 0x938, 0x4);
371*4882a593Smuzhiyun b43_phy_set(dev, 0x939, 0x4);
372*4882a593Smuzhiyun b43_phy_set(dev, 0x4a4, 0x1000);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun /* FIXME: don't hardcode */
375*4882a593Smuzhiyun b43_lcntab_write(dev, B43_LCNTAB16(0x8, 0x6), 0x640);
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun switch (sense_type) {
378*4882a593Smuzhiyun case B43_SENSE_TEMP:
379*4882a593Smuzhiyun b43_phy_set(dev, 0x4d7, 0x8);
380*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x1000);
381*4882a593Smuzhiyun auxpga_vmidcourse = 8;
382*4882a593Smuzhiyun auxpga_vmidfine = 0x4;
383*4882a593Smuzhiyun auxpga_gain = 2;
384*4882a593Smuzhiyun b43_radio_set(dev, 0x082, 0x20);
385*4882a593Smuzhiyun break;
386*4882a593Smuzhiyun case B43_SENSE_VBAT:
387*4882a593Smuzhiyun b43_phy_set(dev, 0x4d7, 0x8);
388*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x3000);
389*4882a593Smuzhiyun auxpga_vmidcourse = 7;
390*4882a593Smuzhiyun auxpga_vmidfine = 0xa;
391*4882a593Smuzhiyun auxpga_gain = 2;
392*4882a593Smuzhiyun break;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun auxpga_vmid = (0x200 | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun b43_phy_set(dev, 0x4d8, 0x1);
397*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4d8, ~(0x3ff << 2), auxpga_vmid << 2);
398*4882a593Smuzhiyun b43_phy_set(dev, 0x4d8, 0x2);
399*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4d8, ~(0x7 << 12), auxpga_gain << 12);
400*4882a593Smuzhiyun b43_phy_set(dev, 0x4d0, 0x20);
401*4882a593Smuzhiyun b43_radio_write(dev, 0x112, 0x6);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun b43_dummy_transmission(dev, true, false);
404*4882a593Smuzhiyun /* Wait if not done */
405*4882a593Smuzhiyun if (!(b43_phy_read(dev, 0x476) & 0x8000))
406*4882a593Smuzhiyun udelay(10);
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun /* Restore */
409*4882a593Smuzhiyun for (i = 0; i < 6; i++)
410*4882a593Smuzhiyun b43_radio_write(dev, save_radio_regs[i][0],
411*4882a593Smuzhiyun save_radio_regs[i][1]);
412*4882a593Smuzhiyun for (i = 0; i < 14; i++)
413*4882a593Smuzhiyun b43_phy_write(dev, save_phy_regs[i][0], save_phy_regs[i][1]);
414*4882a593Smuzhiyun /* TODO: wlc_lcnphy_set_tx_pwr_by_index(tx_pwr_idx) */
415*4882a593Smuzhiyun b43_radio_write(dev, 0x4a4, save_radio_4a4);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun b43_mac_enable(dev);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun msleep(1);
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
b43_phy_lcn_load_tx_iir_cck_filter(struct b43_wldev * dev,u8 filter_type)422*4882a593Smuzhiyun static bool b43_phy_lcn_load_tx_iir_cck_filter(struct b43_wldev *dev,
423*4882a593Smuzhiyun u8 filter_type)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun int i, j;
426*4882a593Smuzhiyun u16 phy_regs[] = { 0x910, 0x91e, 0x91f, 0x924, 0x925, 0x926, 0x920,
427*4882a593Smuzhiyun 0x921, 0x927, 0x928, 0x929, 0x922, 0x923, 0x930,
428*4882a593Smuzhiyun 0x931, 0x932 };
429*4882a593Smuzhiyun /* Table is from brcmsmac, values for type 25 were outdated, probably
430*4882a593Smuzhiyun * others need updating too */
431*4882a593Smuzhiyun struct lcn_tx_iir_filter tx_iir_filters_cck[] = {
432*4882a593Smuzhiyun { 0, { 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778,
433*4882a593Smuzhiyun 1582, 64, 128, 64 } },
434*4882a593Smuzhiyun { 1, { 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608,
435*4882a593Smuzhiyun 1863, 93, 167, 93 } },
436*4882a593Smuzhiyun { 2, { 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192,
437*4882a593Smuzhiyun 778, 1582, 64, 128, 64 } },
438*4882a593Smuzhiyun { 3, { 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205,
439*4882a593Smuzhiyun 754, 1760, 170, 340, 170 } },
440*4882a593Smuzhiyun { 20, { 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205,
441*4882a593Smuzhiyun 767, 1760, 256, 185, 256 } },
442*4882a593Smuzhiyun { 21, { 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205,
443*4882a593Smuzhiyun 767, 1760, 256, 273, 256 } },
444*4882a593Smuzhiyun { 22, { 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205,
445*4882a593Smuzhiyun 767, 1760, 256, 352, 256 } },
446*4882a593Smuzhiyun { 23, { 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205,
447*4882a593Smuzhiyun 767, 1760, 128, 233, 128 } },
448*4882a593Smuzhiyun { 24, { 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766,
449*4882a593Smuzhiyun 1760, 256, 1881, 256 } },
450*4882a593Smuzhiyun { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765,
451*4882a593Smuzhiyun 1760, 262, 1878, 262 } },
452*4882a593Smuzhiyun /* brcmsmac version { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720,
453*4882a593Smuzhiyun * 256, 471, 256, 765, 1760, 256, 1881, 256 } }, */
454*4882a593Smuzhiyun { 26, { 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614,
455*4882a593Smuzhiyun 1864, 128, 384, 288 } },
456*4882a593Smuzhiyun { 27, { 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576,
457*4882a593Smuzhiyun 613, 1864, 128, 384, 288 } },
458*4882a593Smuzhiyun { 30, { 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205,
459*4882a593Smuzhiyun 754, 1760, 170, 340, 170 } },
460*4882a593Smuzhiyun };
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(tx_iir_filters_cck); i++) {
463*4882a593Smuzhiyun if (tx_iir_filters_cck[i].type == filter_type) {
464*4882a593Smuzhiyun for (j = 0; j < 16; j++)
465*4882a593Smuzhiyun b43_phy_write(dev, phy_regs[j],
466*4882a593Smuzhiyun tx_iir_filters_cck[i].values[j]);
467*4882a593Smuzhiyun return true;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun return false;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
b43_phy_lcn_load_tx_iir_ofdm_filter(struct b43_wldev * dev,u8 filter_type)474*4882a593Smuzhiyun static bool b43_phy_lcn_load_tx_iir_ofdm_filter(struct b43_wldev *dev,
475*4882a593Smuzhiyun u8 filter_type)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun int i, j;
478*4882a593Smuzhiyun u16 phy_regs[] = { 0x90f, 0x900, 0x901, 0x906, 0x907, 0x908, 0x902,
479*4882a593Smuzhiyun 0x903, 0x909, 0x90a, 0x90b, 0x904, 0x905, 0x90c,
480*4882a593Smuzhiyun 0x90d, 0x90e };
481*4882a593Smuzhiyun struct lcn_tx_iir_filter tx_iir_filters_ofdm[] = {
482*4882a593Smuzhiyun { 0, { 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0,
483*4882a593Smuzhiyun 0x0, 0x278, 0xfea0, 0x80, 0x100, 0x80 } },
484*4882a593Smuzhiyun { 1, { 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, 750,
485*4882a593Smuzhiyun 0xFE2B, 212, 0xFFCE, 212 } },
486*4882a593Smuzhiyun { 2, { 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
487*4882a593Smuzhiyun 0xFEF2, 128, 0xFFE2, 128 } },
488*4882a593Smuzhiyun };
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(tx_iir_filters_ofdm); i++) {
491*4882a593Smuzhiyun if (tx_iir_filters_ofdm[i].type == filter_type) {
492*4882a593Smuzhiyun for (j = 0; j < 16; j++)
493*4882a593Smuzhiyun b43_phy_write(dev, phy_regs[j],
494*4882a593Smuzhiyun tx_iir_filters_ofdm[i].values[j]);
495*4882a593Smuzhiyun return true;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return false;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* wlc_lcnphy_set_tx_gain_override */
b43_phy_lcn_set_tx_gain_override(struct b43_wldev * dev,bool enable)503*4882a593Smuzhiyun static void b43_phy_lcn_set_tx_gain_override(struct b43_wldev *dev, bool enable)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4b0, ~(0x1 << 7), enable << 7);
506*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4b0, ~(0x1 << 14), enable << 14);
507*4882a593Smuzhiyun b43_phy_maskset(dev, 0x43b, ~(0x1 << 6), enable << 6);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun /* wlc_lcnphy_set_tx_gain */
b43_phy_lcn_set_tx_gain(struct b43_wldev * dev,struct lcn_tx_gains * target_gains)511*4882a593Smuzhiyun static void b43_phy_lcn_set_tx_gain(struct b43_wldev *dev,
512*4882a593Smuzhiyun struct lcn_tx_gains *target_gains)
513*4882a593Smuzhiyun {
514*4882a593Smuzhiyun u16 pa_gain = b43_phy_lcn_get_pa_gain(dev);
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun b43_phy_write(dev, 0x4b5,
517*4882a593Smuzhiyun (target_gains->gm_gain | (target_gains->pga_gain << 8)));
518*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4fb, ~0x7fff,
519*4882a593Smuzhiyun (target_gains->pad_gain | (pa_gain << 8)));
520*4882a593Smuzhiyun b43_phy_write(dev, 0x4fc,
521*4882a593Smuzhiyun (target_gains->gm_gain | (target_gains->pga_gain << 8)));
522*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4fd, ~0x7fff,
523*4882a593Smuzhiyun (target_gains->pad_gain | (pa_gain << 8)));
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun b43_phy_lcn_set_dac_gain(dev, target_gains->dac_gain);
526*4882a593Smuzhiyun b43_phy_lcn_set_tx_gain_override(dev, true);
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /* wlc_lcnphy_tx_pwr_ctrl_init */
b43_phy_lcn_tx_pwr_ctl_init(struct b43_wldev * dev)530*4882a593Smuzhiyun static void b43_phy_lcn_tx_pwr_ctl_init(struct b43_wldev *dev)
531*4882a593Smuzhiyun {
532*4882a593Smuzhiyun struct lcn_tx_gains tx_gains;
533*4882a593Smuzhiyun u8 bbmult;
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun b43_mac_suspend(dev);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun if (!dev->phy.lcn->hw_pwr_ctl_capable) {
538*4882a593Smuzhiyun if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
539*4882a593Smuzhiyun tx_gains.gm_gain = 4;
540*4882a593Smuzhiyun tx_gains.pga_gain = 12;
541*4882a593Smuzhiyun tx_gains.pad_gain = 12;
542*4882a593Smuzhiyun tx_gains.dac_gain = 0;
543*4882a593Smuzhiyun bbmult = 150;
544*4882a593Smuzhiyun } else {
545*4882a593Smuzhiyun tx_gains.gm_gain = 7;
546*4882a593Smuzhiyun tx_gains.pga_gain = 15;
547*4882a593Smuzhiyun tx_gains.pad_gain = 14;
548*4882a593Smuzhiyun tx_gains.dac_gain = 0;
549*4882a593Smuzhiyun bbmult = 150;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun b43_phy_lcn_set_tx_gain(dev, &tx_gains);
552*4882a593Smuzhiyun b43_phy_lcn_set_bbmult(dev, bbmult);
553*4882a593Smuzhiyun b43_phy_lcn_sense_setup(dev, B43_SENSE_TEMP);
554*4882a593Smuzhiyun } else {
555*4882a593Smuzhiyun b43err(dev->wl, "TX power control not supported for this HW\n");
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun b43_mac_enable(dev);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun /* wlc_lcnphy_txrx_spur_avoidance_mode */
b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev * dev,bool enable)562*4882a593Smuzhiyun static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev,
563*4882a593Smuzhiyun bool enable)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun if (enable) {
566*4882a593Smuzhiyun b43_phy_write(dev, 0x942, 0x7);
567*4882a593Smuzhiyun b43_phy_write(dev, 0x93b, ((1 << 13) + 23));
568*4882a593Smuzhiyun b43_phy_write(dev, 0x93c, ((1 << 13) + 1989));
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun b43_phy_write(dev, 0x44a, 0x084);
571*4882a593Smuzhiyun b43_phy_write(dev, 0x44a, 0x080);
572*4882a593Smuzhiyun b43_phy_write(dev, 0x6d3, 0x2222);
573*4882a593Smuzhiyun b43_phy_write(dev, 0x6d3, 0x2220);
574*4882a593Smuzhiyun } else {
575*4882a593Smuzhiyun b43_phy_write(dev, 0x942, 0x0);
576*4882a593Smuzhiyun b43_phy_write(dev, 0x93b, ((0 << 13) + 23));
577*4882a593Smuzhiyun b43_phy_write(dev, 0x93c, ((0 << 13) + 1989));
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun b43_mac_switch_freq(dev, enable);
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /**************************************************
583*4882a593Smuzhiyun * Channel switching ops.
584*4882a593Smuzhiyun **************************************************/
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun /* wlc_lcnphy_set_chanspec_tweaks */
b43_phy_lcn_set_channel_tweaks(struct b43_wldev * dev,int channel)587*4882a593Smuzhiyun static void b43_phy_lcn_set_channel_tweaks(struct b43_wldev *dev, int channel)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun b43_phy_maskset(dev, 0x448, ~0x300, (channel == 14) ? 0x200 : 0x100);
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (channel == 1 || channel == 2 || channel == 3 || channel == 4 ||
594*4882a593Smuzhiyun channel == 9 || channel == 10 || channel == 11 || channel == 12) {
595*4882a593Smuzhiyun bcma_chipco_pll_write(cc, 0x2, 0x03000c04);
596*4882a593Smuzhiyun bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x0);
597*4882a593Smuzhiyun bcma_chipco_pll_write(cc, 0x4, 0x200005c0);
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun b43_phy_write(dev, 0x942, 0);
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun b43_phy_lcn_txrx_spur_avoidance_mode(dev, false);
604*4882a593Smuzhiyun b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1b00);
605*4882a593Smuzhiyun b43_phy_write(dev, 0x425, 0x5907);
606*4882a593Smuzhiyun } else {
607*4882a593Smuzhiyun bcma_chipco_pll_write(cc, 0x2, 0x03140c04);
608*4882a593Smuzhiyun bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x333333);
609*4882a593Smuzhiyun bcma_chipco_pll_write(cc, 0x4, 0x202c2820);
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun b43_phy_write(dev, 0x942, 0);
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun b43_phy_lcn_txrx_spur_avoidance_mode(dev, true);
616*4882a593Smuzhiyun b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1f00);
617*4882a593Smuzhiyun b43_phy_write(dev, 0x425, 0x590a);
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun b43_phy_set(dev, 0x44a, 0x44);
621*4882a593Smuzhiyun b43_phy_write(dev, 0x44a, 0x80);
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun /* wlc_phy_chanspec_set_lcnphy */
b43_phy_lcn_set_channel(struct b43_wldev * dev,struct ieee80211_channel * channel,enum nl80211_channel_type channel_type)625*4882a593Smuzhiyun static int b43_phy_lcn_set_channel(struct b43_wldev *dev,
626*4882a593Smuzhiyun struct ieee80211_channel *channel,
627*4882a593Smuzhiyun enum nl80211_channel_type channel_type)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun static const u16 sfo_cfg[14][2] = {
630*4882a593Smuzhiyun {965, 1087}, {967, 1085}, {969, 1082}, {971, 1080}, {973, 1078},
631*4882a593Smuzhiyun {975, 1076}, {977, 1073}, {979, 1071}, {981, 1069}, {983, 1067},
632*4882a593Smuzhiyun {985, 1065}, {987, 1063}, {989, 1060}, {994, 1055},
633*4882a593Smuzhiyun };
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun b43_phy_lcn_set_channel_tweaks(dev, channel->hw_value);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun b43_phy_set(dev, 0x44a, 0x44);
638*4882a593Smuzhiyun b43_phy_write(dev, 0x44a, 0x80);
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun b43_radio_2064_channel_setup(dev);
641*4882a593Smuzhiyun mdelay(1);
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun b43_phy_lcn_afe_set_unset(dev);
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun b43_phy_write(dev, 0x657, sfo_cfg[channel->hw_value - 1][0]);
646*4882a593Smuzhiyun b43_phy_write(dev, 0x658, sfo_cfg[channel->hw_value - 1][1]);
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun if (channel->hw_value == 14) {
649*4882a593Smuzhiyun b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (2) << 8);
650*4882a593Smuzhiyun b43_phy_lcn_load_tx_iir_cck_filter(dev, 3);
651*4882a593Smuzhiyun } else {
652*4882a593Smuzhiyun b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (1) << 8);
653*4882a593Smuzhiyun /* brcmsmac uses filter_type 2, we follow wl with 25 */
654*4882a593Smuzhiyun b43_phy_lcn_load_tx_iir_cck_filter(dev, 25);
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun /* brcmsmac uses filter_type 2, we follow wl with 0 */
657*4882a593Smuzhiyun b43_phy_lcn_load_tx_iir_ofdm_filter(dev, 0);
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun b43_phy_maskset(dev, 0x4eb, ~(0x7 << 3), 0x1 << 3);
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun return 0;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun /**************************************************
665*4882a593Smuzhiyun * Basic PHY ops.
666*4882a593Smuzhiyun **************************************************/
667*4882a593Smuzhiyun
b43_phy_lcn_op_allocate(struct b43_wldev * dev)668*4882a593Smuzhiyun static int b43_phy_lcn_op_allocate(struct b43_wldev *dev)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun struct b43_phy_lcn *phy_lcn;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun phy_lcn = kzalloc(sizeof(*phy_lcn), GFP_KERNEL);
673*4882a593Smuzhiyun if (!phy_lcn)
674*4882a593Smuzhiyun return -ENOMEM;
675*4882a593Smuzhiyun dev->phy.lcn = phy_lcn;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun return 0;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
b43_phy_lcn_op_free(struct b43_wldev * dev)680*4882a593Smuzhiyun static void b43_phy_lcn_op_free(struct b43_wldev *dev)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
683*4882a593Smuzhiyun struct b43_phy_lcn *phy_lcn = phy->lcn;
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun kfree(phy_lcn);
686*4882a593Smuzhiyun phy->lcn = NULL;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun
b43_phy_lcn_op_prepare_structs(struct b43_wldev * dev)689*4882a593Smuzhiyun static void b43_phy_lcn_op_prepare_structs(struct b43_wldev *dev)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun struct b43_phy *phy = &dev->phy;
692*4882a593Smuzhiyun struct b43_phy_lcn *phy_lcn = phy->lcn;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun memset(phy_lcn, 0, sizeof(*phy_lcn));
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun /* wlc_phy_init_lcnphy */
b43_phy_lcn_op_init(struct b43_wldev * dev)698*4882a593Smuzhiyun static int b43_phy_lcn_op_init(struct b43_wldev *dev)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun b43_phy_set(dev, 0x44a, 0x80);
703*4882a593Smuzhiyun b43_phy_mask(dev, 0x44a, 0x7f);
704*4882a593Smuzhiyun b43_phy_set(dev, 0x6d1, 0x80);
705*4882a593Smuzhiyun b43_phy_write(dev, 0x6d0, 0x7);
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun b43_phy_lcn_afe_set_unset(dev);
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun b43_phy_write(dev, 0x60a, 0xa0);
710*4882a593Smuzhiyun b43_phy_write(dev, 0x46a, 0x19);
711*4882a593Smuzhiyun b43_phy_maskset(dev, 0x663, 0xFF00, 0x64);
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun b43_phy_lcn_tables_init(dev);
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun b43_phy_lcn_rev0_baseband_init(dev);
716*4882a593Smuzhiyun b43_phy_lcn_bu_tweaks(dev);
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun if (dev->phy.radio_ver == 0x2064)
719*4882a593Smuzhiyun b43_radio_2064_init(dev);
720*4882a593Smuzhiyun else
721*4882a593Smuzhiyun B43_WARN_ON(1);
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
724*4882a593Smuzhiyun b43_phy_lcn_tx_pwr_ctl_init(dev);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun b43_switch_channel(dev, dev->phy.channel);
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun bcma_chipco_regctl_maskset(cc, 0, 0xf, 0x9);
729*4882a593Smuzhiyun bcma_chipco_chipctl_maskset(cc, 0, 0, 0x03cddddd);
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun /* TODO */
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun b43_phy_set(dev, 0x448, 0x4000);
734*4882a593Smuzhiyun udelay(100);
735*4882a593Smuzhiyun b43_phy_mask(dev, 0x448, ~0x4000);
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun /* TODO */
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun return 0;
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun
b43_phy_lcn_op_software_rfkill(struct b43_wldev * dev,bool blocked)742*4882a593Smuzhiyun static void b43_phy_lcn_op_software_rfkill(struct b43_wldev *dev,
743*4882a593Smuzhiyun bool blocked)
744*4882a593Smuzhiyun {
745*4882a593Smuzhiyun if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
746*4882a593Smuzhiyun b43err(dev->wl, "MAC not suspended\n");
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun if (blocked) {
749*4882a593Smuzhiyun b43_phy_mask(dev, B43_PHY_LCN_RF_CTL2, ~0x7c00);
750*4882a593Smuzhiyun b43_phy_set(dev, B43_PHY_LCN_RF_CTL1, 0x1f00);
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun b43_phy_mask(dev, B43_PHY_LCN_RF_CTL5, ~0x7f00);
753*4882a593Smuzhiyun b43_phy_mask(dev, B43_PHY_LCN_RF_CTL4, ~0x2);
754*4882a593Smuzhiyun b43_phy_set(dev, B43_PHY_LCN_RF_CTL3, 0x808);
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun b43_phy_mask(dev, B43_PHY_LCN_RF_CTL7, ~0x8);
757*4882a593Smuzhiyun b43_phy_set(dev, B43_PHY_LCN_RF_CTL6, 0x8);
758*4882a593Smuzhiyun } else {
759*4882a593Smuzhiyun b43_phy_mask(dev, B43_PHY_LCN_RF_CTL1, ~0x1f00);
760*4882a593Smuzhiyun b43_phy_mask(dev, B43_PHY_LCN_RF_CTL3, ~0x808);
761*4882a593Smuzhiyun b43_phy_mask(dev, B43_PHY_LCN_RF_CTL6, ~0x8);
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun
b43_phy_lcn_op_switch_analog(struct b43_wldev * dev,bool on)765*4882a593Smuzhiyun static void b43_phy_lcn_op_switch_analog(struct b43_wldev *dev, bool on)
766*4882a593Smuzhiyun {
767*4882a593Smuzhiyun if (on) {
768*4882a593Smuzhiyun b43_phy_mask(dev, B43_PHY_LCN_AFE_CTL1, ~0x7);
769*4882a593Smuzhiyun } else {
770*4882a593Smuzhiyun b43_phy_set(dev, B43_PHY_LCN_AFE_CTL2, 0x7);
771*4882a593Smuzhiyun b43_phy_set(dev, B43_PHY_LCN_AFE_CTL1, 0x7);
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
b43_phy_lcn_op_switch_channel(struct b43_wldev * dev,unsigned int new_channel)775*4882a593Smuzhiyun static int b43_phy_lcn_op_switch_channel(struct b43_wldev *dev,
776*4882a593Smuzhiyun unsigned int new_channel)
777*4882a593Smuzhiyun {
778*4882a593Smuzhiyun struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
779*4882a593Smuzhiyun enum nl80211_channel_type channel_type =
780*4882a593Smuzhiyun cfg80211_get_chandef_type(&dev->wl->hw->conf.chandef);
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
783*4882a593Smuzhiyun if ((new_channel < 1) || (new_channel > 14))
784*4882a593Smuzhiyun return -EINVAL;
785*4882a593Smuzhiyun } else {
786*4882a593Smuzhiyun return -EINVAL;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun return b43_phy_lcn_set_channel(dev, channel, channel_type);
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
b43_phy_lcn_op_get_default_chan(struct b43_wldev * dev)792*4882a593Smuzhiyun static unsigned int b43_phy_lcn_op_get_default_chan(struct b43_wldev *dev)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
795*4882a593Smuzhiyun return 1;
796*4882a593Smuzhiyun return 36;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun static enum b43_txpwr_result
b43_phy_lcn_op_recalc_txpower(struct b43_wldev * dev,bool ignore_tssi)800*4882a593Smuzhiyun b43_phy_lcn_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
801*4882a593Smuzhiyun {
802*4882a593Smuzhiyun return B43_TXPWR_RES_DONE;
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun
b43_phy_lcn_op_adjust_txpower(struct b43_wldev * dev)805*4882a593Smuzhiyun static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
806*4882a593Smuzhiyun {
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun /**************************************************
810*4882a593Smuzhiyun * R/W ops.
811*4882a593Smuzhiyun **************************************************/
812*4882a593Smuzhiyun
b43_phy_lcn_op_maskset(struct b43_wldev * dev,u16 reg,u16 mask,u16 set)813*4882a593Smuzhiyun static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
814*4882a593Smuzhiyun u16 set)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
817*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_PHY_DATA,
818*4882a593Smuzhiyun (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun
b43_phy_lcn_op_radio_read(struct b43_wldev * dev,u16 reg)821*4882a593Smuzhiyun static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg)
822*4882a593Smuzhiyun {
823*4882a593Smuzhiyun /* LCN-PHY needs 0x200 for read access */
824*4882a593Smuzhiyun reg |= 0x200;
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
827*4882a593Smuzhiyun return b43_read16(dev, B43_MMIO_RADIO24_DATA);
828*4882a593Smuzhiyun }
829*4882a593Smuzhiyun
b43_phy_lcn_op_radio_write(struct b43_wldev * dev,u16 reg,u16 value)830*4882a593Smuzhiyun static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
831*4882a593Smuzhiyun u16 value)
832*4882a593Smuzhiyun {
833*4882a593Smuzhiyun b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
834*4882a593Smuzhiyun b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
835*4882a593Smuzhiyun }
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun /**************************************************
838*4882a593Smuzhiyun * PHY ops struct.
839*4882a593Smuzhiyun **************************************************/
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun const struct b43_phy_operations b43_phyops_lcn = {
842*4882a593Smuzhiyun .allocate = b43_phy_lcn_op_allocate,
843*4882a593Smuzhiyun .free = b43_phy_lcn_op_free,
844*4882a593Smuzhiyun .prepare_structs = b43_phy_lcn_op_prepare_structs,
845*4882a593Smuzhiyun .init = b43_phy_lcn_op_init,
846*4882a593Smuzhiyun .phy_maskset = b43_phy_lcn_op_maskset,
847*4882a593Smuzhiyun .radio_read = b43_phy_lcn_op_radio_read,
848*4882a593Smuzhiyun .radio_write = b43_phy_lcn_op_radio_write,
849*4882a593Smuzhiyun .software_rfkill = b43_phy_lcn_op_software_rfkill,
850*4882a593Smuzhiyun .switch_analog = b43_phy_lcn_op_switch_analog,
851*4882a593Smuzhiyun .switch_channel = b43_phy_lcn_op_switch_channel,
852*4882a593Smuzhiyun .get_default_chan = b43_phy_lcn_op_get_default_chan,
853*4882a593Smuzhiyun .recalc_txpower = b43_phy_lcn_op_recalc_txpower,
854*4882a593Smuzhiyun .adjust_txpower = b43_phy_lcn_op_adjust_txpower,
855*4882a593Smuzhiyun };
856