Back to home page

OSCL-LXR

 
 

    


0001 /*
0002 
0003   Broadcom B43 wireless driver
0004   IEEE 802.11n LCN-PHY support
0005 
0006   Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
0007 
0008   This program is free software; you can redistribute it and/or modify
0009   it under the terms of the GNU General Public License as published by
0010   the Free Software Foundation; either version 2 of the License, or
0011   (at your option) any later version.
0012 
0013   This program is distributed in the hope that it will be useful,
0014   but WITHOUT ANY WARRANTY; without even the implied warranty of
0015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016   GNU General Public License for more details.
0017 
0018   You should have received a copy of the GNU General Public License
0019   along with this program; see the file COPYING.  If not, write to
0020   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
0021   Boston, MA 02110-1301, USA.
0022 
0023   This file incorporates work covered by the following copyright and
0024   permission notice:
0025 
0026       Copyright (c) 2010 Broadcom Corporation
0027 
0028       Permission to use, copy, modify, and/or distribute this software for any
0029       purpose with or without fee is hereby granted, provided that the above
0030       copyright notice and this permission notice appear in all copies.
0031 */
0032 
0033 #include <linux/slab.h>
0034 
0035 #include "b43.h"
0036 #include "phy_lcn.h"
0037 #include "tables_phy_lcn.h"
0038 #include "main.h"
0039 
0040 struct lcn_tx_gains {
0041     u16 gm_gain;
0042     u16 pga_gain;
0043     u16 pad_gain;
0044     u16 dac_gain;
0045 };
0046 
0047 struct lcn_tx_iir_filter {
0048     u8 type;
0049     u16 values[16];
0050 };
0051 
0052 enum lcn_sense_type {
0053     B43_SENSE_TEMP,
0054     B43_SENSE_VBAT,
0055 };
0056 
0057 /**************************************************
0058  * Radio 2064.
0059  **************************************************/
0060 
0061 /* wlc_lcnphy_radio_2064_channel_tune_4313 */
0062 static void b43_radio_2064_channel_setup(struct b43_wldev *dev)
0063 {
0064     u16 save[2];
0065 
0066     b43_radio_set(dev, 0x09d, 0x4);
0067     b43_radio_write(dev, 0x09e, 0xf);
0068 
0069     /* Channel specific values in theory, in practice always the same */
0070     b43_radio_write(dev, 0x02a, 0xb);
0071     b43_radio_maskset(dev, 0x030, ~0x3, 0xa);
0072     b43_radio_maskset(dev, 0x091, ~0x3, 0);
0073     b43_radio_maskset(dev, 0x038, ~0xf, 0x7);
0074     b43_radio_maskset(dev, 0x030, ~0xc, 0x8);
0075     b43_radio_maskset(dev, 0x05e, ~0xf, 0x8);
0076     b43_radio_maskset(dev, 0x05e, ~0xf0, 0x80);
0077     b43_radio_write(dev, 0x06c, 0x80);
0078 
0079     save[0] = b43_radio_read(dev, 0x044);
0080     save[1] = b43_radio_read(dev, 0x12b);
0081 
0082     b43_radio_set(dev, 0x044, 0x7);
0083     b43_radio_set(dev, 0x12b, 0xe);
0084 
0085     /* TODO */
0086 
0087     b43_radio_write(dev, 0x040, 0xfb);
0088 
0089     b43_radio_write(dev, 0x041, 0x9a);
0090     b43_radio_write(dev, 0x042, 0xa3);
0091     b43_radio_write(dev, 0x043, 0x0c);
0092 
0093     /* TODO */
0094 
0095     b43_radio_set(dev, 0x044, 0x0c);
0096     udelay(1);
0097 
0098     b43_radio_write(dev, 0x044, save[0]);
0099     b43_radio_write(dev, 0x12b, save[1]);
0100 
0101     if (dev->phy.rev == 1) {
0102         /* brcmsmac uses outdated 0x3 for 0x038 */
0103         b43_radio_write(dev, 0x038, 0x0);
0104         b43_radio_write(dev, 0x091, 0x7);
0105     }
0106 }
0107 
0108 /* wlc_radio_2064_init */
0109 static void b43_radio_2064_init(struct b43_wldev *dev)
0110 {
0111     if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
0112         b43_radio_write(dev, 0x09c, 0x0020);
0113         b43_radio_write(dev, 0x105, 0x0008);
0114     } else {
0115         /* TODO */
0116     }
0117     b43_radio_write(dev, 0x032, 0x0062);
0118     b43_radio_write(dev, 0x033, 0x0019);
0119     b43_radio_write(dev, 0x090, 0x0010);
0120     b43_radio_write(dev, 0x010, 0x0000);
0121     if (dev->phy.rev == 1) {
0122         b43_radio_write(dev, 0x060, 0x007f);
0123         b43_radio_write(dev, 0x061, 0x0072);
0124         b43_radio_write(dev, 0x062, 0x007f);
0125     }
0126     b43_radio_write(dev, 0x01d, 0x0002);
0127     b43_radio_write(dev, 0x01e, 0x0006);
0128 
0129     b43_phy_write(dev, 0x4ea, 0x4688);
0130     b43_phy_maskset(dev, 0x4eb, ~0x7, 0x2);
0131     b43_phy_mask(dev, 0x4eb, ~0x01c0);
0132     b43_phy_maskset(dev, 0x46a, 0xff00, 0x19);
0133 
0134     b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x55), 0);
0135 
0136     b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
0137     b43_radio_set(dev, 0x004, 0x40);
0138     b43_radio_set(dev, 0x120, 0x10);
0139     b43_radio_set(dev, 0x078, 0x80);
0140     b43_radio_set(dev, 0x129, 0x2);
0141     b43_radio_set(dev, 0x057, 0x1);
0142     b43_radio_set(dev, 0x05b, 0x2);
0143 
0144     /* TODO: wait for some bit to be set */
0145     b43_radio_read(dev, 0x05c);
0146 
0147     b43_radio_mask(dev, 0x05b, (u16) ~0xff02);
0148     b43_radio_mask(dev, 0x057, (u16) ~0xff01);
0149 
0150     b43_phy_write(dev, 0x933, 0x2d6b);
0151     b43_phy_write(dev, 0x934, 0x2d6b);
0152     b43_phy_write(dev, 0x935, 0x2d6b);
0153     b43_phy_write(dev, 0x936, 0x2d6b);
0154     b43_phy_write(dev, 0x937, 0x016b);
0155 
0156     b43_radio_mask(dev, 0x057, (u16) ~0xff02);
0157     b43_radio_write(dev, 0x0c2, 0x006f);
0158 }
0159 
0160 /**************************************************
0161  * Various PHY ops
0162  **************************************************/
0163 
0164 /* wlc_lcnphy_toggle_afe_pwdn */
0165 static void b43_phy_lcn_afe_set_unset(struct b43_wldev *dev)
0166 {
0167     u16 afe_ctl2 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL2);
0168     u16 afe_ctl1 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL1);
0169 
0170     b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 | 0x1);
0171     b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 | 0x1);
0172 
0173     b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 & ~0x1);
0174     b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 & ~0x1);
0175 
0176     b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2);
0177     b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1);
0178 }
0179 
0180 /* wlc_lcnphy_get_pa_gain */
0181 static u16 b43_phy_lcn_get_pa_gain(struct b43_wldev *dev)
0182 {
0183     return (b43_phy_read(dev, 0x4fb) & 0x7f00) >> 8;
0184 }
0185 
0186 /* wlc_lcnphy_set_dac_gain */
0187 static void b43_phy_lcn_set_dac_gain(struct b43_wldev *dev, u16 dac_gain)
0188 {
0189     u16 dac_ctrl;
0190 
0191     dac_ctrl = b43_phy_read(dev, 0x439);
0192     dac_ctrl = dac_ctrl & 0xc7f;
0193     dac_ctrl = dac_ctrl | (dac_gain << 7);
0194     b43_phy_maskset(dev, 0x439, ~0xfff, dac_ctrl);
0195 }
0196 
0197 /* wlc_lcnphy_set_bbmult */
0198 static void b43_phy_lcn_set_bbmult(struct b43_wldev *dev, u8 m0)
0199 {
0200     b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x57), m0 << 8);
0201 }
0202 
0203 /* wlc_lcnphy_clear_tx_power_offsets */
0204 static void b43_phy_lcn_clear_tx_power_offsets(struct b43_wldev *dev)
0205 {
0206     u8 i;
0207 
0208     if (1) { /* FIXME */
0209         b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x340);
0210         for (i = 0; i < 30; i++) {
0211             b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
0212             b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
0213         }
0214     }
0215 
0216     b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x80);
0217     for (i = 0; i < 64; i++) {
0218         b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0);
0219         b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0);
0220     }
0221 }
0222 
0223 /* wlc_lcnphy_rev0_baseband_init */
0224 static void b43_phy_lcn_rev0_baseband_init(struct b43_wldev *dev)
0225 {
0226     b43_radio_write(dev, 0x11c, 0);
0227 
0228     b43_phy_write(dev, 0x43b, 0);
0229     b43_phy_write(dev, 0x43c, 0);
0230     b43_phy_write(dev, 0x44c, 0);
0231     b43_phy_write(dev, 0x4e6, 0);
0232     b43_phy_write(dev, 0x4f9, 0);
0233     b43_phy_write(dev, 0x4b0, 0);
0234     b43_phy_write(dev, 0x938, 0);
0235     b43_phy_write(dev, 0x4b0, 0);
0236     b43_phy_write(dev, 0x44e, 0);
0237 
0238     b43_phy_set(dev, 0x567, 0x03);
0239 
0240     b43_phy_set(dev, 0x44a, 0x44);
0241     b43_phy_write(dev, 0x44a, 0x80);
0242 
0243     if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM))
0244         ; /* TODO */
0245     b43_phy_maskset(dev, 0x634, ~0xff, 0xc);
0246     if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM) {
0247         b43_phy_maskset(dev, 0x634, ~0xff, 0xa);
0248         b43_phy_write(dev, 0x910, 0x1);
0249     }
0250 
0251     b43_phy_write(dev, 0x910, 0x1);
0252 
0253     b43_phy_maskset(dev, 0x448, ~0x300, 0x100);
0254     b43_phy_maskset(dev, 0x608, ~0xff, 0x17);
0255     b43_phy_maskset(dev, 0x604, ~0x7ff, 0x3ea);
0256 }
0257 
0258 /* wlc_lcnphy_bu_tweaks */
0259 static void b43_phy_lcn_bu_tweaks(struct b43_wldev *dev)
0260 {
0261     b43_phy_set(dev, 0x805, 0x1);
0262 
0263     b43_phy_maskset(dev, 0x42f, ~0x7, 0x3);
0264     b43_phy_maskset(dev, 0x030, ~0x7, 0x3);
0265 
0266     b43_phy_write(dev, 0x414, 0x1e10);
0267     b43_phy_write(dev, 0x415, 0x0640);
0268 
0269     b43_phy_maskset(dev, 0x4df, (u16) ~0xff00, 0xf700);
0270 
0271     b43_phy_set(dev, 0x44a, 0x44);
0272     b43_phy_write(dev, 0x44a, 0x80);
0273 
0274     b43_phy_maskset(dev, 0x434, ~0xff, 0xfd);
0275     b43_phy_maskset(dev, 0x420, ~0xff, 0x10);
0276 
0277     if (dev->dev->bus_sprom->board_rev >= 0x1204)
0278         b43_radio_set(dev, 0x09b, 0xf0);
0279 
0280     b43_phy_write(dev, 0x7d6, 0x0902);
0281 
0282     b43_phy_maskset(dev, 0x429, ~0xf, 0x9);
0283     b43_phy_maskset(dev, 0x429, ~(0x3f << 4), 0xe << 4);
0284 
0285     if (dev->phy.rev == 1) {
0286         b43_phy_maskset(dev, 0x423, ~0xff, 0x46);
0287         b43_phy_maskset(dev, 0x411, ~0xff, 1);
0288         b43_phy_set(dev, 0x434, 0xff); /* FIXME: update to wl */
0289 
0290         /* TODO: wl operates on PHY 0x416, brcmsmac is outdated here */
0291 
0292         b43_phy_maskset(dev, 0x656, ~0xf, 2);
0293         b43_phy_set(dev, 0x44d, 4);
0294 
0295         b43_radio_set(dev, 0x0f7, 0x4);
0296         b43_radio_mask(dev, 0x0f1, ~0x3);
0297         b43_radio_maskset(dev, 0x0f2, ~0xf8, 0x90);
0298         b43_radio_maskset(dev, 0x0f3, ~0x3, 0x2);
0299         b43_radio_maskset(dev, 0x0f3, ~0xf0, 0xa0);
0300 
0301         b43_radio_set(dev, 0x11f, 0x2);
0302 
0303         b43_phy_lcn_clear_tx_power_offsets(dev);
0304 
0305         /* TODO: something more? */
0306     }
0307 }
0308 
0309 /* wlc_lcnphy_vbat_temp_sense_setup */
0310 static void b43_phy_lcn_sense_setup(struct b43_wldev *dev,
0311                     enum lcn_sense_type sense_type)
0312 {
0313     u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
0314     u16 auxpga_vmid;
0315     u8 tx_pwr_idx;
0316     u8 i;
0317 
0318     u16 save_radio_regs[6][2] = {
0319         { 0x007, 0 }, { 0x0ff, 0 }, { 0x11f, 0 }, { 0x005, 0 },
0320         { 0x025, 0 }, { 0x112, 0 },
0321     };
0322     u16 save_phy_regs[14][2] = {
0323         { 0x503, 0 }, { 0x4a4, 0 }, { 0x4d0, 0 }, { 0x4d9, 0 },
0324         { 0x4da, 0 }, { 0x4a6, 0 }, { 0x938, 0 }, { 0x939, 0 },
0325         { 0x4d8, 0 }, { 0x4d0, 0 }, { 0x4d7, 0 }, { 0x4a5, 0 },
0326         { 0x40d, 0 }, { 0x4a2, 0 },
0327     };
0328     u16 save_radio_4a4;
0329 
0330     msleep(1);
0331 
0332     /* Save */
0333     for (i = 0; i < 6; i++)
0334         save_radio_regs[i][1] = b43_radio_read(dev,
0335                                save_radio_regs[i][0]);
0336     for (i = 0; i < 14; i++)
0337         save_phy_regs[i][1] = b43_phy_read(dev, save_phy_regs[i][0]);
0338     b43_mac_suspend(dev);
0339     save_radio_4a4 = b43_radio_read(dev, 0x4a4);
0340     /* wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); */
0341     tx_pwr_idx = dev->phy.lcn->tx_pwr_curr_idx;
0342 
0343     /* Setup */
0344     /* TODO: wlc_lcnphy_set_tx_pwr_by_index(pi, 127); */
0345     b43_radio_set(dev, 0x007, 0x1);
0346     b43_radio_set(dev, 0x0ff, 0x10);
0347     b43_radio_set(dev, 0x11f, 0x4);
0348 
0349     b43_phy_mask(dev, 0x503, ~0x1);
0350     b43_phy_mask(dev, 0x503, ~0x4);
0351     b43_phy_mask(dev, 0x4a4, ~0x4000);
0352     b43_phy_mask(dev, 0x4a4, (u16) ~0x8000);
0353     b43_phy_mask(dev, 0x4d0, ~0x20);
0354     b43_phy_set(dev, 0x4a5, 0xff);
0355     b43_phy_maskset(dev, 0x4a5, ~0x7000, 0x5000);
0356     b43_phy_mask(dev, 0x4a5, ~0x700);
0357     b43_phy_maskset(dev, 0x40d, ~0xff, 64);
0358     b43_phy_maskset(dev, 0x40d, ~0x700, 0x600);
0359     b43_phy_maskset(dev, 0x4a2, ~0xff, 64);
0360     b43_phy_maskset(dev, 0x4a2, ~0x700, 0x600);
0361     b43_phy_maskset(dev, 0x4d9, ~0x70, 0x20);
0362     b43_phy_maskset(dev, 0x4d9, ~0x700, 0x300);
0363     b43_phy_maskset(dev, 0x4d9, ~0x7000, 0x1000);
0364     b43_phy_mask(dev, 0x4da, ~0x1000);
0365     b43_phy_set(dev, 0x4da, 0x2000);
0366     b43_phy_set(dev, 0x4a6, 0x8000);
0367 
0368     b43_radio_write(dev, 0x025, 0xc);
0369     b43_radio_set(dev, 0x005, 0x8);
0370     b43_phy_set(dev, 0x938, 0x4);
0371     b43_phy_set(dev, 0x939, 0x4);
0372     b43_phy_set(dev, 0x4a4, 0x1000);
0373 
0374     /* FIXME: don't hardcode */
0375     b43_lcntab_write(dev, B43_LCNTAB16(0x8, 0x6), 0x640);
0376 
0377     switch (sense_type) {
0378     case B43_SENSE_TEMP:
0379         b43_phy_set(dev, 0x4d7, 0x8);
0380         b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x1000);
0381         auxpga_vmidcourse = 8;
0382         auxpga_vmidfine = 0x4;
0383         auxpga_gain = 2;
0384         b43_radio_set(dev, 0x082, 0x20);
0385         break;
0386     case B43_SENSE_VBAT:
0387         b43_phy_set(dev, 0x4d7, 0x8);
0388         b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x3000);
0389         auxpga_vmidcourse = 7;
0390         auxpga_vmidfine = 0xa;
0391         auxpga_gain = 2;
0392         break;
0393     }
0394     auxpga_vmid = (0x200 | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
0395 
0396     b43_phy_set(dev, 0x4d8, 0x1);
0397     b43_phy_maskset(dev, 0x4d8, ~(0x3ff << 2), auxpga_vmid << 2);
0398     b43_phy_set(dev, 0x4d8, 0x2);
0399     b43_phy_maskset(dev, 0x4d8, ~(0x7 << 12), auxpga_gain << 12);
0400     b43_phy_set(dev, 0x4d0, 0x20);
0401     b43_radio_write(dev, 0x112, 0x6);
0402 
0403     b43_dummy_transmission(dev, true, false);
0404     /* Wait if not done */
0405     if (!(b43_phy_read(dev, 0x476) & 0x8000))
0406         udelay(10);
0407 
0408     /* Restore */
0409     for (i = 0; i < 6; i++)
0410         b43_radio_write(dev, save_radio_regs[i][0],
0411                 save_radio_regs[i][1]);
0412     for (i = 0; i < 14; i++)
0413         b43_phy_write(dev, save_phy_regs[i][0], save_phy_regs[i][1]);
0414     /* TODO: wlc_lcnphy_set_tx_pwr_by_index(tx_pwr_idx) */
0415     b43_radio_write(dev, 0x4a4, save_radio_4a4);
0416 
0417     b43_mac_enable(dev);
0418 
0419     msleep(1);
0420 }
0421 
0422 static bool b43_phy_lcn_load_tx_iir_cck_filter(struct b43_wldev *dev,
0423                            u8 filter_type)
0424 {
0425     int i, j;
0426     u16 phy_regs[] = { 0x910, 0x91e, 0x91f, 0x924, 0x925, 0x926, 0x920,
0427                0x921, 0x927, 0x928, 0x929, 0x922, 0x923, 0x930,
0428                0x931, 0x932 };
0429     /* Table is from brcmsmac, values for type 25 were outdated, probably
0430      * others need updating too */
0431     struct lcn_tx_iir_filter tx_iir_filters_cck[] = {
0432         { 0,  { 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778,
0433             1582, 64, 128, 64 } },
0434         { 1,  { 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608,
0435             1863, 93, 167, 93 } },
0436         { 2,  { 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192,
0437             778, 1582, 64, 128, 64 } },
0438         { 3,  { 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205,
0439             754, 1760, 170, 340, 170 } },
0440         { 20, { 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205,
0441             767, 1760, 256, 185, 256 } },
0442         { 21, { 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205,
0443             767, 1760, 256, 273, 256 } },
0444         { 22, { 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205,
0445             767, 1760, 256, 352, 256 } },
0446         { 23, { 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205,
0447             767, 1760, 128, 233, 128 } },
0448         { 24, { 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766,
0449             1760, 256, 1881, 256 } },
0450         { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765,
0451             1760, 262, 1878, 262 } },
0452         /* brcmsmac version { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720,
0453          * 256, 471, 256, 765, 1760, 256, 1881, 256 } }, */
0454         { 26, { 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614,
0455             1864, 128, 384, 288 } },
0456         { 27, { 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576,
0457             613, 1864, 128, 384, 288 } },
0458         { 30, { 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205,
0459             754, 1760, 170, 340, 170 } },
0460     };
0461 
0462     for (i = 0; i < ARRAY_SIZE(tx_iir_filters_cck); i++) {
0463         if (tx_iir_filters_cck[i].type == filter_type) {
0464             for (j = 0; j < 16; j++)
0465                 b43_phy_write(dev, phy_regs[j],
0466                           tx_iir_filters_cck[i].values[j]);
0467             return true;
0468         }
0469     }
0470 
0471     return false;
0472 }
0473 
0474 static bool b43_phy_lcn_load_tx_iir_ofdm_filter(struct b43_wldev *dev,
0475                         u8 filter_type)
0476 {
0477     int i, j;
0478     u16 phy_regs[] = { 0x90f, 0x900, 0x901, 0x906, 0x907, 0x908, 0x902,
0479                0x903, 0x909, 0x90a, 0x90b, 0x904, 0x905, 0x90c,
0480                0x90d, 0x90e };
0481     struct lcn_tx_iir_filter tx_iir_filters_ofdm[] = {
0482         { 0, { 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0,
0483                0x0, 0x278, 0xfea0, 0x80, 0x100, 0x80 } },
0484         { 1, { 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, 750,
0485                0xFE2B, 212, 0xFFCE, 212 } },
0486         { 2, { 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
0487                0xFEF2, 128, 0xFFE2, 128 } },
0488     };
0489 
0490     for (i = 0; i < ARRAY_SIZE(tx_iir_filters_ofdm); i++) {
0491         if (tx_iir_filters_ofdm[i].type == filter_type) {
0492             for (j = 0; j < 16; j++)
0493                 b43_phy_write(dev, phy_regs[j],
0494                           tx_iir_filters_ofdm[i].values[j]);
0495             return true;
0496         }
0497     }
0498 
0499     return false;
0500 }
0501 
0502 /* wlc_lcnphy_set_tx_gain_override */
0503 static void b43_phy_lcn_set_tx_gain_override(struct b43_wldev *dev, bool enable)
0504 {
0505     b43_phy_maskset(dev, 0x4b0, ~(0x1 << 7), enable << 7);
0506     b43_phy_maskset(dev, 0x4b0, ~(0x1 << 14), enable << 14);
0507     b43_phy_maskset(dev, 0x43b, ~(0x1 << 6), enable << 6);
0508 }
0509 
0510 /* wlc_lcnphy_set_tx_gain */
0511 static void b43_phy_lcn_set_tx_gain(struct b43_wldev *dev,
0512                     struct lcn_tx_gains *target_gains)
0513 {
0514     u16 pa_gain = b43_phy_lcn_get_pa_gain(dev);
0515 
0516     b43_phy_write(dev, 0x4b5,
0517               (target_gains->gm_gain | (target_gains->pga_gain << 8)));
0518     b43_phy_maskset(dev, 0x4fb, ~0x7fff,
0519             (target_gains->pad_gain | (pa_gain << 8)));
0520     b43_phy_write(dev, 0x4fc,
0521               (target_gains->gm_gain | (target_gains->pga_gain << 8)));
0522     b43_phy_maskset(dev, 0x4fd, ~0x7fff,
0523             (target_gains->pad_gain | (pa_gain << 8)));
0524 
0525     b43_phy_lcn_set_dac_gain(dev, target_gains->dac_gain);
0526     b43_phy_lcn_set_tx_gain_override(dev, true);
0527 }
0528 
0529 /* wlc_lcnphy_tx_pwr_ctrl_init */
0530 static void b43_phy_lcn_tx_pwr_ctl_init(struct b43_wldev *dev)
0531 {
0532     struct lcn_tx_gains tx_gains;
0533     u8 bbmult;
0534 
0535     b43_mac_suspend(dev);
0536 
0537     if (!dev->phy.lcn->hw_pwr_ctl_capable) {
0538         if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
0539             tx_gains.gm_gain = 4;
0540             tx_gains.pga_gain = 12;
0541             tx_gains.pad_gain = 12;
0542             tx_gains.dac_gain = 0;
0543             bbmult = 150;
0544         } else {
0545             tx_gains.gm_gain = 7;
0546             tx_gains.pga_gain = 15;
0547             tx_gains.pad_gain = 14;
0548             tx_gains.dac_gain = 0;
0549             bbmult = 150;
0550         }
0551         b43_phy_lcn_set_tx_gain(dev, &tx_gains);
0552         b43_phy_lcn_set_bbmult(dev, bbmult);
0553         b43_phy_lcn_sense_setup(dev, B43_SENSE_TEMP);
0554     } else {
0555         b43err(dev->wl, "TX power control not supported for this HW\n");
0556     }
0557 
0558     b43_mac_enable(dev);
0559 }
0560 
0561 /* wlc_lcnphy_txrx_spur_avoidance_mode */
0562 static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev,
0563                          bool enable)
0564 {
0565     if (enable) {
0566         b43_phy_write(dev, 0x942, 0x7);
0567         b43_phy_write(dev, 0x93b, ((1 << 13) + 23));
0568         b43_phy_write(dev, 0x93c, ((1 << 13) + 1989));
0569 
0570         b43_phy_write(dev, 0x44a, 0x084);
0571         b43_phy_write(dev, 0x44a, 0x080);
0572         b43_phy_write(dev, 0x6d3, 0x2222);
0573         b43_phy_write(dev, 0x6d3, 0x2220);
0574     } else {
0575         b43_phy_write(dev, 0x942, 0x0);
0576         b43_phy_write(dev, 0x93b, ((0 << 13) + 23));
0577         b43_phy_write(dev, 0x93c, ((0 << 13) + 1989));
0578     }
0579     b43_mac_switch_freq(dev, enable);
0580 }
0581 
0582 /**************************************************
0583  * Channel switching ops.
0584  **************************************************/
0585 
0586 /* wlc_lcnphy_set_chanspec_tweaks */
0587 static void b43_phy_lcn_set_channel_tweaks(struct b43_wldev *dev, int channel)
0588 {
0589     struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
0590 
0591     b43_phy_maskset(dev, 0x448, ~0x300, (channel == 14) ? 0x200 : 0x100);
0592 
0593     if (channel == 1 || channel == 2 || channel == 3 || channel == 4 ||
0594         channel == 9 || channel == 10 || channel == 11 || channel == 12) {
0595         bcma_chipco_pll_write(cc, 0x2, 0x03000c04);
0596         bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x0);
0597         bcma_chipco_pll_write(cc, 0x4, 0x200005c0);
0598 
0599         bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
0600 
0601         b43_phy_write(dev, 0x942, 0);
0602 
0603         b43_phy_lcn_txrx_spur_avoidance_mode(dev, false);
0604         b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1b00);
0605         b43_phy_write(dev, 0x425, 0x5907);
0606     } else {
0607         bcma_chipco_pll_write(cc, 0x2, 0x03140c04);
0608         bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x333333);
0609         bcma_chipco_pll_write(cc, 0x4, 0x202c2820);
0610 
0611         bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
0612 
0613         b43_phy_write(dev, 0x942, 0);
0614 
0615         b43_phy_lcn_txrx_spur_avoidance_mode(dev, true);
0616         b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1f00);
0617         b43_phy_write(dev, 0x425, 0x590a);
0618     }
0619 
0620     b43_phy_set(dev, 0x44a, 0x44);
0621     b43_phy_write(dev, 0x44a, 0x80);
0622 }
0623 
0624 /* wlc_phy_chanspec_set_lcnphy */
0625 static int b43_phy_lcn_set_channel(struct b43_wldev *dev,
0626                    struct ieee80211_channel *channel,
0627                    enum nl80211_channel_type channel_type)
0628 {
0629     static const u16 sfo_cfg[14][2] = {
0630         {965, 1087}, {967, 1085}, {969, 1082}, {971, 1080}, {973, 1078},
0631         {975, 1076}, {977, 1073}, {979, 1071}, {981, 1069}, {983, 1067},
0632         {985, 1065}, {987, 1063}, {989, 1060}, {994, 1055},
0633     };
0634 
0635     b43_phy_lcn_set_channel_tweaks(dev, channel->hw_value);
0636 
0637     b43_phy_set(dev, 0x44a, 0x44);
0638     b43_phy_write(dev, 0x44a, 0x80);
0639 
0640     b43_radio_2064_channel_setup(dev);
0641     mdelay(1);
0642 
0643     b43_phy_lcn_afe_set_unset(dev);
0644 
0645     b43_phy_write(dev, 0x657, sfo_cfg[channel->hw_value - 1][0]);
0646     b43_phy_write(dev, 0x658, sfo_cfg[channel->hw_value - 1][1]);
0647 
0648     if (channel->hw_value == 14) {
0649         b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (2) << 8);
0650         b43_phy_lcn_load_tx_iir_cck_filter(dev, 3);
0651     } else {
0652         b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (1) << 8);
0653         /* brcmsmac uses filter_type 2, we follow wl with 25 */
0654         b43_phy_lcn_load_tx_iir_cck_filter(dev, 25);
0655     }
0656     /* brcmsmac uses filter_type 2, we follow wl with 0 */
0657     b43_phy_lcn_load_tx_iir_ofdm_filter(dev, 0);
0658 
0659     b43_phy_maskset(dev, 0x4eb, ~(0x7 << 3), 0x1 << 3);
0660 
0661     return 0;
0662 }
0663 
0664 /**************************************************
0665  * Basic PHY ops.
0666  **************************************************/
0667 
0668 static int b43_phy_lcn_op_allocate(struct b43_wldev *dev)
0669 {
0670     struct b43_phy_lcn *phy_lcn;
0671 
0672     phy_lcn = kzalloc(sizeof(*phy_lcn), GFP_KERNEL);
0673     if (!phy_lcn)
0674         return -ENOMEM;
0675     dev->phy.lcn = phy_lcn;
0676 
0677     return 0;
0678 }
0679 
0680 static void b43_phy_lcn_op_free(struct b43_wldev *dev)
0681 {
0682     struct b43_phy *phy = &dev->phy;
0683     struct b43_phy_lcn *phy_lcn = phy->lcn;
0684 
0685     kfree(phy_lcn);
0686     phy->lcn = NULL;
0687 }
0688 
0689 static void b43_phy_lcn_op_prepare_structs(struct b43_wldev *dev)
0690 {
0691     struct b43_phy *phy = &dev->phy;
0692     struct b43_phy_lcn *phy_lcn = phy->lcn;
0693 
0694     memset(phy_lcn, 0, sizeof(*phy_lcn));
0695 }
0696 
0697 /* wlc_phy_init_lcnphy */
0698 static int b43_phy_lcn_op_init(struct b43_wldev *dev)
0699 {
0700     struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
0701 
0702     b43_phy_set(dev, 0x44a, 0x80);
0703     b43_phy_mask(dev, 0x44a, 0x7f);
0704     b43_phy_set(dev, 0x6d1, 0x80);
0705     b43_phy_write(dev, 0x6d0, 0x7);
0706 
0707     b43_phy_lcn_afe_set_unset(dev);
0708 
0709     b43_phy_write(dev, 0x60a, 0xa0);
0710     b43_phy_write(dev, 0x46a, 0x19);
0711     b43_phy_maskset(dev, 0x663, 0xFF00, 0x64);
0712 
0713     b43_phy_lcn_tables_init(dev);
0714 
0715     b43_phy_lcn_rev0_baseband_init(dev);
0716     b43_phy_lcn_bu_tweaks(dev);
0717 
0718     if (dev->phy.radio_ver == 0x2064)
0719         b43_radio_2064_init(dev);
0720     else
0721         B43_WARN_ON(1);
0722 
0723     if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
0724         b43_phy_lcn_tx_pwr_ctl_init(dev);
0725 
0726     b43_switch_channel(dev, dev->phy.channel);
0727 
0728     bcma_chipco_regctl_maskset(cc, 0, 0xf, 0x9);
0729     bcma_chipco_chipctl_maskset(cc, 0, 0, 0x03cddddd);
0730 
0731     /* TODO */
0732 
0733     b43_phy_set(dev, 0x448, 0x4000);
0734     udelay(100);
0735     b43_phy_mask(dev, 0x448, ~0x4000);
0736 
0737     /* TODO */
0738 
0739     return 0;
0740 }
0741 
0742 static void b43_phy_lcn_op_software_rfkill(struct b43_wldev *dev,
0743                     bool blocked)
0744 {
0745     if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
0746         b43err(dev->wl, "MAC not suspended\n");
0747 
0748     if (blocked) {
0749         b43_phy_mask(dev, B43_PHY_LCN_RF_CTL2, ~0x7c00);
0750         b43_phy_set(dev, B43_PHY_LCN_RF_CTL1, 0x1f00);
0751 
0752         b43_phy_mask(dev, B43_PHY_LCN_RF_CTL5, ~0x7f00);
0753         b43_phy_mask(dev, B43_PHY_LCN_RF_CTL4, ~0x2);
0754         b43_phy_set(dev, B43_PHY_LCN_RF_CTL3, 0x808);
0755 
0756         b43_phy_mask(dev, B43_PHY_LCN_RF_CTL7, ~0x8);
0757         b43_phy_set(dev, B43_PHY_LCN_RF_CTL6, 0x8);
0758     } else {
0759         b43_phy_mask(dev, B43_PHY_LCN_RF_CTL1, ~0x1f00);
0760         b43_phy_mask(dev, B43_PHY_LCN_RF_CTL3, ~0x808);
0761         b43_phy_mask(dev, B43_PHY_LCN_RF_CTL6, ~0x8);
0762     }
0763 }
0764 
0765 static void b43_phy_lcn_op_switch_analog(struct b43_wldev *dev, bool on)
0766 {
0767     if (on) {
0768         b43_phy_mask(dev, B43_PHY_LCN_AFE_CTL1, ~0x7);
0769     } else {
0770         b43_phy_set(dev, B43_PHY_LCN_AFE_CTL2, 0x7);
0771         b43_phy_set(dev, B43_PHY_LCN_AFE_CTL1, 0x7);
0772     }
0773 }
0774 
0775 static int b43_phy_lcn_op_switch_channel(struct b43_wldev *dev,
0776                     unsigned int new_channel)
0777 {
0778     struct ieee80211_channel *channel = dev->wl->hw->conf.chandef.chan;
0779     enum nl80211_channel_type channel_type =
0780         cfg80211_get_chandef_type(&dev->wl->hw->conf.chandef);
0781 
0782     if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ) {
0783         if ((new_channel < 1) || (new_channel > 14))
0784             return -EINVAL;
0785     } else {
0786         return -EINVAL;
0787     }
0788 
0789     return b43_phy_lcn_set_channel(dev, channel, channel_type);
0790 }
0791 
0792 static unsigned int b43_phy_lcn_op_get_default_chan(struct b43_wldev *dev)
0793 {
0794     if (b43_current_band(dev->wl) == NL80211_BAND_2GHZ)
0795         return 1;
0796     return 36;
0797 }
0798 
0799 static enum b43_txpwr_result
0800 b43_phy_lcn_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
0801 {
0802     return B43_TXPWR_RES_DONE;
0803 }
0804 
0805 static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev)
0806 {
0807 }
0808 
0809 /**************************************************
0810  * R/W ops.
0811  **************************************************/
0812 
0813 static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
0814                    u16 set)
0815 {
0816     b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
0817     b43_write16(dev, B43_MMIO_PHY_DATA,
0818             (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
0819 }
0820 
0821 static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg)
0822 {
0823     /* LCN-PHY needs 0x200 for read access */
0824     reg |= 0x200;
0825 
0826     b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
0827     return b43_read16(dev, B43_MMIO_RADIO24_DATA);
0828 }
0829 
0830 static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg,
0831                        u16 value)
0832 {
0833     b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
0834     b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
0835 }
0836 
0837 /**************************************************
0838  * PHY ops struct.
0839  **************************************************/
0840 
0841 const struct b43_phy_operations b43_phyops_lcn = {
0842     .allocate       = b43_phy_lcn_op_allocate,
0843     .free           = b43_phy_lcn_op_free,
0844     .prepare_structs    = b43_phy_lcn_op_prepare_structs,
0845     .init           = b43_phy_lcn_op_init,
0846     .phy_maskset        = b43_phy_lcn_op_maskset,
0847     .radio_read     = b43_phy_lcn_op_radio_read,
0848     .radio_write        = b43_phy_lcn_op_radio_write,
0849     .software_rfkill    = b43_phy_lcn_op_software_rfkill,
0850     .switch_analog      = b43_phy_lcn_op_switch_analog,
0851     .switch_channel     = b43_phy_lcn_op_switch_channel,
0852     .get_default_chan   = b43_phy_lcn_op_get_default_chan,
0853     .recalc_txpower     = b43_phy_lcn_op_recalc_txpower,
0854     .adjust_txpower     = b43_phy_lcn_op_adjust_txpower,
0855 };