linux/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010 Broadcom Corporation
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include <linux/kernel.h>
  18#include <linux/delay.h>
  19#include <linux/cordic.h>
  20
  21#include <pmu.h>
  22#include <d11.h>
  23#include <phy_shim.h>
  24#include "phy_qmath.h"
  25#include "phy_hal.h"
  26#include "phy_radio.h"
  27#include "phytbl_lcn.h"
  28#include "phy_lcn.h"
  29
  30#define PLL_2064_NDIV           90
  31#define PLL_2064_LOW_END_VCO    3000
  32#define PLL_2064_LOW_END_KVCO   27
  33#define PLL_2064_HIGH_END_VCO   4200
  34#define PLL_2064_HIGH_END_KVCO  68
  35#define PLL_2064_LOOP_BW_DOUBLER        200
  36#define PLL_2064_D30_DOUBLER            10500
  37#define PLL_2064_LOOP_BW        260
  38#define PLL_2064_D30            8000
  39#define PLL_2064_CAL_REF_TO     8
  40#define PLL_2064_MHZ            1000000
  41#define PLL_2064_OPEN_LOOP_DELAY        5
  42
  43#define TEMPSENSE                       1
  44#define VBATSENSE           2
  45
  46#define NOISE_IF_UPD_CHK_INTERVAL       1
  47#define NOISE_IF_UPD_RST_INTERVAL       60
  48#define NOISE_IF_UPD_THRESHOLD_CNT      1
  49#define NOISE_IF_UPD_TRHRESHOLD 50
  50#define NOISE_IF_UPD_TIMEOUT            1000
  51#define NOISE_IF_OFF                    0
  52#define NOISE_IF_CHK                    1
  53#define NOISE_IF_ON                     2
  54
  55#define PAPD_BLANKING_PROFILE           3
  56#define PAPD2LUT                        0
  57#define PAPD_CORR_NORM                  0
  58#define PAPD_BLANKING_THRESHOLD         0
  59#define PAPD_STOP_AFTER_LAST_UPDATE     0
  60
  61#define LCN_TARGET_PWR  60
  62
  63#define LCN_VBAT_OFFSET_433X 34649679
  64#define LCN_VBAT_SLOPE_433X  8258032
  65
  66#define LCN_VBAT_SCALE_NOM  53
  67#define LCN_VBAT_SCALE_DEN  432
  68
  69#define LCN_TEMPSENSE_OFFSET  80812
  70#define LCN_TEMPSENSE_DEN  2647
  71
  72#define LCN_BW_LMT      200
  73#define LCN_CUR_LMT     1250
  74#define LCN_MULT        1
  75#define LCN_VCO_DIV     30
  76#define LCN_OFFSET      680
  77#define LCN_FACT        490
  78#define LCN_CUR_DIV     2640
  79
  80#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
  81        (0 + 8)
  82#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
  83        (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT)
  84
  85#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \
  86        (0 + 8)
  87#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \
  88        (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT)
  89
  90#define wlc_lcnphy_enable_tx_gain_override(pi) \
  91        wlc_lcnphy_set_tx_gain_override(pi, true)
  92#define wlc_lcnphy_disable_tx_gain_override(pi) \
  93        wlc_lcnphy_set_tx_gain_override(pi, false)
  94
  95#define wlc_lcnphy_iqcal_active(pi)     \
  96        (read_phy_reg((pi), 0x451) & \
  97         ((0x1 << 15) | (0x1 << 14)))
  98
  99#define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
 100#define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
 101        (pi->temppwrctrl_capable)
 102#define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
 103        (pi->hwpwrctrl_capable)
 104
 105#define SWCTRL_BT_TX            0x18
 106#define SWCTRL_OVR_DISABLE      0x40
 107
 108#define AFE_CLK_INIT_MODE_TXRX2X        1
 109#define AFE_CLK_INIT_MODE_PAPD          0
 110
 111#define LCNPHY_TBL_ID_IQLOCAL                   0x00
 112
 113#define LCNPHY_TBL_ID_RFSEQ         0x08
 114#define LCNPHY_TBL_ID_GAIN_IDX          0x0d
 115#define LCNPHY_TBL_ID_SW_CTRL                   0x0f
 116#define LCNPHY_TBL_ID_GAIN_TBL          0x12
 117#define LCNPHY_TBL_ID_SPUR                      0x14
 118#define LCNPHY_TBL_ID_SAMPLEPLAY                0x15
 119#define LCNPHY_TBL_ID_SAMPLEPLAY1               0x16
 120
 121#define LCNPHY_TX_PWR_CTRL_RATE_OFFSET  832
 122#define LCNPHY_TX_PWR_CTRL_MAC_OFFSET   128
 123#define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET  192
 124#define LCNPHY_TX_PWR_CTRL_IQ_OFFSET            320
 125#define LCNPHY_TX_PWR_CTRL_LO_OFFSET            448
 126#define LCNPHY_TX_PWR_CTRL_PWR_OFFSET           576
 127
 128#define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313  140
 129
 130#define LCNPHY_TX_PWR_CTRL_START_NPT            1
 131#define LCNPHY_TX_PWR_CTRL_MAX_NPT                      7
 132
 133#define LCNPHY_NOISE_SAMPLES_DEFAULT 5000
 134
 135#define LCNPHY_ACI_DETECT_START      1
 136#define LCNPHY_ACI_DETECT_PROGRESS   2
 137#define LCNPHY_ACI_DETECT_STOP       3
 138
 139#define LCNPHY_ACI_CRSHIFRMLO_TRSH 100
 140#define LCNPHY_ACI_GLITCH_TRSH 2000
 141#define LCNPHY_ACI_TMOUT 250
 142#define LCNPHY_ACI_DETECT_TIMEOUT  2
 143#define LCNPHY_ACI_START_DELAY 0
 144
 145#define wlc_lcnphy_tx_gain_override_enabled(pi) \
 146        (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
 147
 148#define wlc_lcnphy_total_tx_frames(pi) \
 149        wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \
 150                            offsetof(struct macstat, txallfrm))
 151
 152struct lcnphy_txgains {
 153        u16 gm_gain;
 154        u16 pga_gain;
 155        u16 pad_gain;
 156        u16 dac_gain;
 157};
 158
 159enum lcnphy_cal_mode {
 160        LCNPHY_CAL_FULL,
 161        LCNPHY_CAL_RECAL,
 162        LCNPHY_CAL_CURRECAL,
 163        LCNPHY_CAL_DIGCAL,
 164        LCNPHY_CAL_GCTRL
 165};
 166
 167struct lcnphy_rx_iqcomp {
 168        u8 chan;
 169        s16 a;
 170        s16 b;
 171};
 172
 173struct lcnphy_spb_tone {
 174        s16 re;
 175        s16 im;
 176};
 177
 178struct lcnphy_unsign16_struct {
 179        u16 re;
 180        u16 im;
 181};
 182
 183struct lcnphy_iq_est {
 184        u32 iq_prod;
 185        u32 i_pwr;
 186        u32 q_pwr;
 187};
 188
 189struct lcnphy_sfo_cfg {
 190        u16 ptcentreTs20;
 191        u16 ptcentreFactor;
 192};
 193
 194enum lcnphy_papd_cal_type {
 195        LCNPHY_PAPD_CAL_CW,
 196        LCNPHY_PAPD_CAL_OFDM
 197};
 198
 199typedef u16 iqcal_gain_params_lcnphy[9];
 200
 201static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = {
 202        {0, 0, 0, 0, 0, 0, 0, 0, 0},
 203};
 204
 205static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
 206        tbl_iqcal_gainparams_lcnphy_2G,
 207};
 208
 209static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
 210        ARRAY_SIZE(tbl_iqcal_gainparams_lcnphy_2G),
 211};
 212
 213static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {
 214        {965, 1087},
 215        {967, 1085},
 216        {969, 1082},
 217        {971, 1080},
 218        {973, 1078},
 219        {975, 1076},
 220        {977, 1073},
 221        {979, 1071},
 222        {981, 1069},
 223        {983, 1067},
 224        {985, 1065},
 225        {987, 1063},
 226        {989, 1060},
 227        {994, 1055}
 228};
 229
 230static const
 231u16 lcnphy_iqcal_loft_gainladder[] = {
 232        ((2 << 8) | 0),
 233        ((3 << 8) | 0),
 234        ((4 << 8) | 0),
 235        ((6 << 8) | 0),
 236        ((8 << 8) | 0),
 237        ((11 << 8) | 0),
 238        ((16 << 8) | 0),
 239        ((16 << 8) | 1),
 240        ((16 << 8) | 2),
 241        ((16 << 8) | 3),
 242        ((16 << 8) | 4),
 243        ((16 << 8) | 5),
 244        ((16 << 8) | 6),
 245        ((16 << 8) | 7),
 246        ((23 << 8) | 7),
 247        ((32 << 8) | 7),
 248        ((45 << 8) | 7),
 249        ((64 << 8) | 7),
 250        ((91 << 8) | 7),
 251        ((128 << 8) | 7)
 252};
 253
 254static const
 255u16 lcnphy_iqcal_ir_gainladder[] = {
 256        ((1 << 8) | 0),
 257        ((2 << 8) | 0),
 258        ((4 << 8) | 0),
 259        ((6 << 8) | 0),
 260        ((8 << 8) | 0),
 261        ((11 << 8) | 0),
 262        ((16 << 8) | 0),
 263        ((23 << 8) | 0),
 264        ((32 << 8) | 0),
 265        ((45 << 8) | 0),
 266        ((64 << 8) | 0),
 267        ((64 << 8) | 1),
 268        ((64 << 8) | 2),
 269        ((64 << 8) | 3),
 270        ((64 << 8) | 4),
 271        ((64 << 8) | 5),
 272        ((64 << 8) | 6),
 273        ((64 << 8) | 7),
 274        ((91 << 8) | 7),
 275        ((128 << 8) | 7)
 276};
 277
 278static const
 279struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = {
 280        {88, 0},
 281        {73, 49},
 282        {34, 81},
 283        {-17, 86},
 284        {-62, 62},
 285        {-86, 17},
 286        {-81, -34},
 287        {-49, -73},
 288        {0, -88},
 289        {49, -73},
 290        {81, -34},
 291        {86, 17},
 292        {62, 62},
 293        {17, 86},
 294        {-34, 81},
 295        {-73, 49},
 296        {-88, 0},
 297        {-73, -49},
 298        {-34, -81},
 299        {17, -86},
 300        {62, -62},
 301        {86, -17},
 302        {81, 34},
 303        {49, 73},
 304        {0, 88},
 305        {-49, 73},
 306        {-81, 34},
 307        {-86, -17},
 308        {-62, -62},
 309        {-17, -86},
 310        {34, -81},
 311        {73, -49},
 312};
 313
 314static const
 315u16 iqlo_loopback_rf_regs[20] = {
 316        RADIO_2064_REG036,
 317        RADIO_2064_REG11A,
 318        RADIO_2064_REG03A,
 319        RADIO_2064_REG025,
 320        RADIO_2064_REG028,
 321        RADIO_2064_REG005,
 322        RADIO_2064_REG112,
 323        RADIO_2064_REG0FF,
 324        RADIO_2064_REG11F,
 325        RADIO_2064_REG00B,
 326        RADIO_2064_REG113,
 327        RADIO_2064_REG007,
 328        RADIO_2064_REG0FC,
 329        RADIO_2064_REG0FD,
 330        RADIO_2064_REG012,
 331        RADIO_2064_REG057,
 332        RADIO_2064_REG059,
 333        RADIO_2064_REG05C,
 334        RADIO_2064_REG078,
 335        RADIO_2064_REG092,
 336};
 337
 338static const
 339u16 tempsense_phy_regs[14] = {
 340        0x503,
 341        0x4a4,
 342        0x4d0,
 343        0x4d9,
 344        0x4da,
 345        0x4a6,
 346        0x938,
 347        0x939,
 348        0x4d8,
 349        0x4d0,
 350        0x4d7,
 351        0x4a5,
 352        0x40d,
 353        0x4a2,
 354};
 355
 356static const
 357u16 rxiq_cal_rf_reg[11] = {
 358        RADIO_2064_REG098,
 359        RADIO_2064_REG116,
 360        RADIO_2064_REG12C,
 361        RADIO_2064_REG06A,
 362        RADIO_2064_REG00B,
 363        RADIO_2064_REG01B,
 364        RADIO_2064_REG113,
 365        RADIO_2064_REG01D,
 366        RADIO_2064_REG114,
 367        RADIO_2064_REG02E,
 368        RADIO_2064_REG12A,
 369};
 370
 371static const
 372struct lcnphy_rx_iqcomp lcnphy_rx_iqcomp_table_rev0[] = {
 373        {1, 0, 0},
 374        {2, 0, 0},
 375        {3, 0, 0},
 376        {4, 0, 0},
 377        {5, 0, 0},
 378        {6, 0, 0},
 379        {7, 0, 0},
 380        {8, 0, 0},
 381        {9, 0, 0},
 382        {10, 0, 0},
 383        {11, 0, 0},
 384        {12, 0, 0},
 385        {13, 0, 0},
 386        {14, 0, 0},
 387        {34, 0, 0},
 388        {38, 0, 0},
 389        {42, 0, 0},
 390        {46, 0, 0},
 391        {36, 0, 0},
 392        {40, 0, 0},
 393        {44, 0, 0},
 394        {48, 0, 0},
 395        {52, 0, 0},
 396        {56, 0, 0},
 397        {60, 0, 0},
 398        {64, 0, 0},
 399        {100, 0, 0},
 400        {104, 0, 0},
 401        {108, 0, 0},
 402        {112, 0, 0},
 403        {116, 0, 0},
 404        {120, 0, 0},
 405        {124, 0, 0},
 406        {128, 0, 0},
 407        {132, 0, 0},
 408        {136, 0, 0},
 409        {140, 0, 0},
 410        {149, 0, 0},
 411        {153, 0, 0},
 412        {157, 0, 0},
 413        {161, 0, 0},
 414        {165, 0, 0},
 415        {184, 0, 0},
 416        {188, 0, 0},
 417        {192, 0, 0},
 418        {196, 0, 0},
 419        {200, 0, 0},
 420        {204, 0, 0},
 421        {208, 0, 0},
 422        {212, 0, 0},
 423        {216, 0, 0},
 424};
 425
 426static const u32 lcnphy_23bitgaincode_table[] = {
 427        0x200100,
 428        0x200200,
 429        0x200004,
 430        0x200014,
 431        0x200024,
 432        0x200034,
 433        0x200134,
 434        0x200234,
 435        0x200334,
 436        0x200434,
 437        0x200037,
 438        0x200137,
 439        0x200237,
 440        0x200337,
 441        0x200437,
 442        0x000035,
 443        0x000135,
 444        0x000235,
 445        0x000037,
 446        0x000137,
 447        0x000237,
 448        0x000337,
 449        0x00013f,
 450        0x00023f,
 451        0x00033f,
 452        0x00034f,
 453        0x00044f,
 454        0x00144f,
 455        0x00244f,
 456        0x00254f,
 457        0x00354f,
 458        0x00454f,
 459        0x00464f,
 460        0x01464f,
 461        0x02464f,
 462        0x03464f,
 463        0x04464f,
 464};
 465
 466static const s8 lcnphy_gain_table[] = {
 467        -16,
 468        -13,
 469        10,
 470        7,
 471        4,
 472        0,
 473        3,
 474        6,
 475        9,
 476        12,
 477        15,
 478        18,
 479        21,
 480        24,
 481        27,
 482        30,
 483        33,
 484        36,
 485        39,
 486        42,
 487        45,
 488        48,
 489        50,
 490        53,
 491        56,
 492        59,
 493        62,
 494        65,
 495        68,
 496        71,
 497        74,
 498        77,
 499        80,
 500        83,
 501        86,
 502        89,
 503        92,
 504};
 505
 506static const s8 lcnphy_gain_index_offset_for_rssi[] = {
 507        7,
 508        7,
 509        7,
 510        7,
 511        7,
 512        7,
 513        7,
 514        8,
 515        7,
 516        7,
 517        6,
 518        7,
 519        7,
 520        4,
 521        4,
 522        4,
 523        4,
 524        4,
 525        4,
 526        4,
 527        4,
 528        3,
 529        3,
 530        3,
 531        3,
 532        3,
 533        3,
 534        4,
 535        2,
 536        2,
 537        2,
 538        2,
 539        2,
 540        2,
 541        -1,
 542        -2,
 543        -2,
 544        -2
 545};
 546
 547struct chan_info_2064_lcnphy {
 548        uint chan;
 549        uint freq;
 550        u8 logen_buftune;
 551        u8 logen_rccr_tx;
 552        u8 txrf_mix_tune_ctrl;
 553        u8 pa_input_tune_g;
 554        u8 logen_rccr_rx;
 555        u8 pa_rxrf_lna1_freq_tune;
 556        u8 pa_rxrf_lna2_freq_tune;
 557        u8 rxrf_rxrf_spare1;
 558};
 559
 560static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
 561        {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 562        {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 563        {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 564        {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 565        {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 566        {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 567        {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 568        {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 569        {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 570        {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 571        {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 572        {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 573        {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 574        {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
 575};
 576
 577static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
 578        {0x00, 0, 0, 0, 0},
 579        {0x01, 0x64, 0x64, 0, 0},
 580        {0x02, 0x20, 0x20, 0, 0},
 581        {0x03, 0x66, 0x66, 0, 0},
 582        {0x04, 0xf8, 0xf8, 0, 0},
 583        {0x05, 0, 0, 0, 0},
 584        {0x06, 0x10, 0x10, 0, 0},
 585        {0x07, 0, 0, 0, 0},
 586        {0x08, 0, 0, 0, 0},
 587        {0x09, 0, 0, 0, 0},
 588        {0x0A, 0x37, 0x37, 0, 0},
 589        {0x0B, 0x6, 0x6, 0, 0},
 590        {0x0C, 0x55, 0x55, 0, 0},
 591        {0x0D, 0x8b, 0x8b, 0, 0},
 592        {0x0E, 0, 0, 0, 0},
 593        {0x0F, 0x5, 0x5, 0, 0},
 594        {0x10, 0, 0, 0, 0},
 595        {0x11, 0xe, 0xe, 0, 0},
 596        {0x12, 0, 0, 0, 0},
 597        {0x13, 0xb, 0xb, 0, 0},
 598        {0x14, 0x2, 0x2, 0, 0},
 599        {0x15, 0x12, 0x12, 0, 0},
 600        {0x16, 0x12, 0x12, 0, 0},
 601        {0x17, 0xc, 0xc, 0, 0},
 602        {0x18, 0xc, 0xc, 0, 0},
 603        {0x19, 0xc, 0xc, 0, 0},
 604        {0x1A, 0x8, 0x8, 0, 0},
 605        {0x1B, 0x2, 0x2, 0, 0},
 606        {0x1C, 0, 0, 0, 0},
 607        {0x1D, 0x1, 0x1, 0, 0},
 608        {0x1E, 0x12, 0x12, 0, 0},
 609        {0x1F, 0x6e, 0x6e, 0, 0},
 610        {0x20, 0x2, 0x2, 0, 0},
 611        {0x21, 0x23, 0x23, 0, 0},
 612        {0x22, 0x8, 0x8, 0, 0},
 613        {0x23, 0, 0, 0, 0},
 614        {0x24, 0, 0, 0, 0},
 615        {0x25, 0xc, 0xc, 0, 0},
 616        {0x26, 0x33, 0x33, 0, 0},
 617        {0x27, 0x55, 0x55, 0, 0},
 618        {0x28, 0, 0, 0, 0},
 619        {0x29, 0x30, 0x30, 0, 0},
 620        {0x2A, 0xb, 0xb, 0, 0},
 621        {0x2B, 0x1b, 0x1b, 0, 0},
 622        {0x2C, 0x3, 0x3, 0, 0},
 623        {0x2D, 0x1b, 0x1b, 0, 0},
 624        {0x2E, 0, 0, 0, 0},
 625        {0x2F, 0x20, 0x20, 0, 0},
 626        {0x30, 0xa, 0xa, 0, 0},
 627        {0x31, 0, 0, 0, 0},
 628        {0x32, 0x62, 0x62, 0, 0},
 629        {0x33, 0x19, 0x19, 0, 0},
 630        {0x34, 0x33, 0x33, 0, 0},
 631        {0x35, 0x77, 0x77, 0, 0},
 632        {0x36, 0, 0, 0, 0},
 633        {0x37, 0x70, 0x70, 0, 0},
 634        {0x38, 0x3, 0x3, 0, 0},
 635        {0x39, 0xf, 0xf, 0, 0},
 636        {0x3A, 0x6, 0x6, 0, 0},
 637        {0x3B, 0xcf, 0xcf, 0, 0},
 638        {0x3C, 0x1a, 0x1a, 0, 0},
 639        {0x3D, 0x6, 0x6, 0, 0},
 640        {0x3E, 0x42, 0x42, 0, 0},
 641        {0x3F, 0, 0, 0, 0},
 642        {0x40, 0xfb, 0xfb, 0, 0},
 643        {0x41, 0x9a, 0x9a, 0, 0},
 644        {0x42, 0x7a, 0x7a, 0, 0},
 645        {0x43, 0x29, 0x29, 0, 0},
 646        {0x44, 0, 0, 0, 0},
 647        {0x45, 0x8, 0x8, 0, 0},
 648        {0x46, 0xce, 0xce, 0, 0},
 649        {0x47, 0x27, 0x27, 0, 0},
 650        {0x48, 0x62, 0x62, 0, 0},
 651        {0x49, 0x6, 0x6, 0, 0},
 652        {0x4A, 0x58, 0x58, 0, 0},
 653        {0x4B, 0xf7, 0xf7, 0, 0},
 654        {0x4C, 0, 0, 0, 0},
 655        {0x4D, 0xb3, 0xb3, 0, 0},
 656        {0x4E, 0, 0, 0, 0},
 657        {0x4F, 0x2, 0x2, 0, 0},
 658        {0x50, 0, 0, 0, 0},
 659        {0x51, 0x9, 0x9, 0, 0},
 660        {0x52, 0x5, 0x5, 0, 0},
 661        {0x53, 0x17, 0x17, 0, 0},
 662        {0x54, 0x38, 0x38, 0, 0},
 663        {0x55, 0, 0, 0, 0},
 664        {0x56, 0, 0, 0, 0},
 665        {0x57, 0xb, 0xb, 0, 0},
 666        {0x58, 0, 0, 0, 0},
 667        {0x59, 0, 0, 0, 0},
 668        {0x5A, 0, 0, 0, 0},
 669        {0x5B, 0, 0, 0, 0},
 670        {0x5C, 0, 0, 0, 0},
 671        {0x5D, 0, 0, 0, 0},
 672        {0x5E, 0x88, 0x88, 0, 0},
 673        {0x5F, 0xcc, 0xcc, 0, 0},
 674        {0x60, 0x74, 0x74, 0, 0},
 675        {0x61, 0x74, 0x74, 0, 0},
 676        {0x62, 0x74, 0x74, 0, 0},
 677        {0x63, 0x44, 0x44, 0, 0},
 678        {0x64, 0x77, 0x77, 0, 0},
 679        {0x65, 0x44, 0x44, 0, 0},
 680        {0x66, 0x77, 0x77, 0, 0},
 681        {0x67, 0x55, 0x55, 0, 0},
 682        {0x68, 0x77, 0x77, 0, 0},
 683        {0x69, 0x77, 0x77, 0, 0},
 684        {0x6A, 0, 0, 0, 0},
 685        {0x6B, 0x7f, 0x7f, 0, 0},
 686        {0x6C, 0x8, 0x8, 0, 0},
 687        {0x6D, 0, 0, 0, 0},
 688        {0x6E, 0x88, 0x88, 0, 0},
 689        {0x6F, 0x66, 0x66, 0, 0},
 690        {0x70, 0x66, 0x66, 0, 0},
 691        {0x71, 0x28, 0x28, 0, 0},
 692        {0x72, 0x55, 0x55, 0, 0},
 693        {0x73, 0x4, 0x4, 0, 0},
 694        {0x74, 0, 0, 0, 0},
 695        {0x75, 0, 0, 0, 0},
 696        {0x76, 0, 0, 0, 0},
 697        {0x77, 0x1, 0x1, 0, 0},
 698        {0x78, 0xd6, 0xd6, 0, 0},
 699        {0x79, 0, 0, 0, 0},
 700        {0x7A, 0, 0, 0, 0},
 701        {0x7B, 0, 0, 0, 0},
 702        {0x7C, 0, 0, 0, 0},
 703        {0x7D, 0, 0, 0, 0},
 704        {0x7E, 0, 0, 0, 0},
 705        {0x7F, 0, 0, 0, 0},
 706        {0x80, 0, 0, 0, 0},
 707        {0x81, 0, 0, 0, 0},
 708        {0x82, 0, 0, 0, 0},
 709        {0x83, 0xb4, 0xb4, 0, 0},
 710        {0x84, 0x1, 0x1, 0, 0},
 711        {0x85, 0x20, 0x20, 0, 0},
 712        {0x86, 0x5, 0x5, 0, 0},
 713        {0x87, 0xff, 0xff, 0, 0},
 714        {0x88, 0x7, 0x7, 0, 0},
 715        {0x89, 0x77, 0x77, 0, 0},
 716        {0x8A, 0x77, 0x77, 0, 0},
 717        {0x8B, 0x77, 0x77, 0, 0},
 718        {0x8C, 0x77, 0x77, 0, 0},
 719        {0x8D, 0x8, 0x8, 0, 0},
 720        {0x8E, 0xa, 0xa, 0, 0},
 721        {0x8F, 0x8, 0x8, 0, 0},
 722        {0x90, 0x18, 0x18, 0, 0},
 723        {0x91, 0x5, 0x5, 0, 0},
 724        {0x92, 0x1f, 0x1f, 0, 0},
 725        {0x93, 0x10, 0x10, 0, 0},
 726        {0x94, 0x3, 0x3, 0, 0},
 727        {0x95, 0, 0, 0, 0},
 728        {0x96, 0, 0, 0, 0},
 729        {0x97, 0xaa, 0xaa, 0, 0},
 730        {0x98, 0, 0, 0, 0},
 731        {0x99, 0x23, 0x23, 0, 0},
 732        {0x9A, 0x7, 0x7, 0, 0},
 733        {0x9B, 0xf, 0xf, 0, 0},
 734        {0x9C, 0x10, 0x10, 0, 0},
 735        {0x9D, 0x3, 0x3, 0, 0},
 736        {0x9E, 0x4, 0x4, 0, 0},
 737        {0x9F, 0x20, 0x20, 0, 0},
 738        {0xA0, 0, 0, 0, 0},
 739        {0xA1, 0, 0, 0, 0},
 740        {0xA2, 0, 0, 0, 0},
 741        {0xA3, 0, 0, 0, 0},
 742        {0xA4, 0x1, 0x1, 0, 0},
 743        {0xA5, 0x77, 0x77, 0, 0},
 744        {0xA6, 0x77, 0x77, 0, 0},
 745        {0xA7, 0x77, 0x77, 0, 0},
 746        {0xA8, 0x77, 0x77, 0, 0},
 747        {0xA9, 0x8c, 0x8c, 0, 0},
 748        {0xAA, 0x88, 0x88, 0, 0},
 749        {0xAB, 0x78, 0x78, 0, 0},
 750        {0xAC, 0x57, 0x57, 0, 0},
 751        {0xAD, 0x88, 0x88, 0, 0},
 752        {0xAE, 0, 0, 0, 0},
 753        {0xAF, 0x8, 0x8, 0, 0},
 754        {0xB0, 0x88, 0x88, 0, 0},
 755        {0xB1, 0, 0, 0, 0},
 756        {0xB2, 0x1b, 0x1b, 0, 0},
 757        {0xB3, 0x3, 0x3, 0, 0},
 758        {0xB4, 0x24, 0x24, 0, 0},
 759        {0xB5, 0x3, 0x3, 0, 0},
 760        {0xB6, 0x1b, 0x1b, 0, 0},
 761        {0xB7, 0x24, 0x24, 0, 0},
 762        {0xB8, 0x3, 0x3, 0, 0},
 763        {0xB9, 0, 0, 0, 0},
 764        {0xBA, 0xaa, 0xaa, 0, 0},
 765        {0xBB, 0, 0, 0, 0},
 766        {0xBC, 0x4, 0x4, 0, 0},
 767        {0xBD, 0, 0, 0, 0},
 768        {0xBE, 0x8, 0x8, 0, 0},
 769        {0xBF, 0x11, 0x11, 0, 0},
 770        {0xC0, 0, 0, 0, 0},
 771        {0xC1, 0, 0, 0, 0},
 772        {0xC2, 0x62, 0x62, 0, 0},
 773        {0xC3, 0x1e, 0x1e, 0, 0},
 774        {0xC4, 0x33, 0x33, 0, 0},
 775        {0xC5, 0x37, 0x37, 0, 0},
 776        {0xC6, 0, 0, 0, 0},
 777        {0xC7, 0x70, 0x70, 0, 0},
 778        {0xC8, 0x1e, 0x1e, 0, 0},
 779        {0xC9, 0x6, 0x6, 0, 0},
 780        {0xCA, 0x4, 0x4, 0, 0},
 781        {0xCB, 0x2f, 0x2f, 0, 0},
 782        {0xCC, 0xf, 0xf, 0, 0},
 783        {0xCD, 0, 0, 0, 0},
 784        {0xCE, 0xff, 0xff, 0, 0},
 785        {0xCF, 0x8, 0x8, 0, 0},
 786        {0xD0, 0x3f, 0x3f, 0, 0},
 787        {0xD1, 0x3f, 0x3f, 0, 0},
 788        {0xD2, 0x3f, 0x3f, 0, 0},
 789        {0xD3, 0, 0, 0, 0},
 790        {0xD4, 0, 0, 0, 0},
 791        {0xD5, 0, 0, 0, 0},
 792        {0xD6, 0xcc, 0xcc, 0, 0},
 793        {0xD7, 0, 0, 0, 0},
 794        {0xD8, 0x8, 0x8, 0, 0},
 795        {0xD9, 0x8, 0x8, 0, 0},
 796        {0xDA, 0x8, 0x8, 0, 0},
 797        {0xDB, 0x11, 0x11, 0, 0},
 798        {0xDC, 0, 0, 0, 0},
 799        {0xDD, 0x87, 0x87, 0, 0},
 800        {0xDE, 0x88, 0x88, 0, 0},
 801        {0xDF, 0x8, 0x8, 0, 0},
 802        {0xE0, 0x8, 0x8, 0, 0},
 803        {0xE1, 0x8, 0x8, 0, 0},
 804        {0xE2, 0, 0, 0, 0},
 805        {0xE3, 0, 0, 0, 0},
 806        {0xE4, 0, 0, 0, 0},
 807        {0xE5, 0xf5, 0xf5, 0, 0},
 808        {0xE6, 0x30, 0x30, 0, 0},
 809        {0xE7, 0x1, 0x1, 0, 0},
 810        {0xE8, 0, 0, 0, 0},
 811        {0xE9, 0xff, 0xff, 0, 0},
 812        {0xEA, 0, 0, 0, 0},
 813        {0xEB, 0, 0, 0, 0},
 814        {0xEC, 0x22, 0x22, 0, 0},
 815        {0xED, 0, 0, 0, 0},
 816        {0xEE, 0, 0, 0, 0},
 817        {0xEF, 0, 0, 0, 0},
 818        {0xF0, 0x3, 0x3, 0, 0},
 819        {0xF1, 0x1, 0x1, 0, 0},
 820        {0xF2, 0, 0, 0, 0},
 821        {0xF3, 0, 0, 0, 0},
 822        {0xF4, 0, 0, 0, 0},
 823        {0xF5, 0, 0, 0, 0},
 824        {0xF6, 0, 0, 0, 0},
 825        {0xF7, 0x6, 0x6, 0, 0},
 826        {0xF8, 0, 0, 0, 0},
 827        {0xF9, 0, 0, 0, 0},
 828        {0xFA, 0x40, 0x40, 0, 0},
 829        {0xFB, 0, 0, 0, 0},
 830        {0xFC, 0x1, 0x1, 0, 0},
 831        {0xFD, 0x80, 0x80, 0, 0},
 832        {0xFE, 0x2, 0x2, 0, 0},
 833        {0xFF, 0x10, 0x10, 0, 0},
 834        {0x100, 0x2, 0x2, 0, 0},
 835        {0x101, 0x1e, 0x1e, 0, 0},
 836        {0x102, 0x1e, 0x1e, 0, 0},
 837        {0x103, 0, 0, 0, 0},
 838        {0x104, 0x1f, 0x1f, 0, 0},
 839        {0x105, 0, 0x8, 0, 1},
 840        {0x106, 0x2a, 0x2a, 0, 0},
 841        {0x107, 0xf, 0xf, 0, 0},
 842        {0x108, 0, 0, 0, 0},
 843        {0x109, 0, 0, 0, 0},
 844        {0x10A, 0, 0, 0, 0},
 845        {0x10B, 0, 0, 0, 0},
 846        {0x10C, 0, 0, 0, 0},
 847        {0x10D, 0, 0, 0, 0},
 848        {0x10E, 0, 0, 0, 0},
 849        {0x10F, 0, 0, 0, 0},
 850        {0x110, 0, 0, 0, 0},
 851        {0x111, 0, 0, 0, 0},
 852        {0x112, 0, 0, 0, 0},
 853        {0x113, 0, 0, 0, 0},
 854        {0x114, 0, 0, 0, 0},
 855        {0x115, 0, 0, 0, 0},
 856        {0x116, 0, 0, 0, 0},
 857        {0x117, 0, 0, 0, 0},
 858        {0x118, 0, 0, 0, 0},
 859        {0x119, 0, 0, 0, 0},
 860        {0x11A, 0, 0, 0, 0},
 861        {0x11B, 0, 0, 0, 0},
 862        {0x11C, 0x1, 0x1, 0, 0},
 863        {0x11D, 0, 0, 0, 0},
 864        {0x11E, 0, 0, 0, 0},
 865        {0x11F, 0, 0, 0, 0},
 866        {0x120, 0, 0, 0, 0},
 867        {0x121, 0, 0, 0, 0},
 868        {0x122, 0x80, 0x80, 0, 0},
 869        {0x123, 0, 0, 0, 0},
 870        {0x124, 0xf8, 0xf8, 0, 0},
 871        {0x125, 0, 0, 0, 0},
 872        {0x126, 0, 0, 0, 0},
 873        {0x127, 0, 0, 0, 0},
 874        {0x128, 0, 0, 0, 0},
 875        {0x129, 0, 0, 0, 0},
 876        {0x12A, 0, 0, 0, 0},
 877        {0x12B, 0, 0, 0, 0},
 878        {0x12C, 0, 0, 0, 0},
 879        {0x12D, 0, 0, 0, 0},
 880        {0x12E, 0, 0, 0, 0},
 881        {0x12F, 0, 0, 0, 0},
 882        {0x130, 0, 0, 0, 0},
 883        {0xFFFF, 0, 0, 0, 0}
 884};
 885
 886#define LCNPHY_NUM_DIG_FILT_COEFFS 16
 887#define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
 888
 889static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
 890        [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
 891        {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
 892         128, 64,},
 893        {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93,
 894         167, 93,},
 895        {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64,
 896         128, 64,},
 897        {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760,
 898         170, 340, 170,},
 899        {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760,
 900         256, 185, 256,},
 901        {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760,
 902         256, 273, 256,},
 903        {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760,
 904         256, 352, 256,},
 905        {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760,
 906         128, 233, 128,},
 907        {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256,
 908         1881, 256,},
 909        {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256,
 910         1881, 256,},
 911        {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128,
 912         384, 288,},
 913        {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864,
 914         128, 384, 288,},
 915        {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760,
 916         170, 340, 170,},
 917};
 918
 919#define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
 920static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
 921        [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
 922        {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
 923         0x278, 0xfea0, 0x80, 0x100, 0x80,},
 924        {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50,
 925         750, 0xFE2B, 212, 0xFFCE, 212,},
 926        {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
 927         0xFEF2, 128, 0xFFE2, 128}
 928};
 929
 930#define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
 931        mod_phy_reg(pi, 0x4a4, \
 932                    (0x1ff << 0), \
 933                    (u16)(idx) << 0)
 934
 935#define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
 936        mod_phy_reg(pi, 0x4a5, \
 937                    (0x7 << 8), \
 938                    (u16)(npt) << 8)
 939
 940#define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
 941        (read_phy_reg((pi), 0x4a4) & \
 942         ((0x1 << 15) | \
 943          (0x1 << 14) | \
 944          (0x1 << 13)))
 945
 946#define wlc_lcnphy_get_tx_pwr_npt(pi) \
 947        ((read_phy_reg(pi, 0x4a5) & \
 948          (0x7 << 8)) >> \
 949         8)
 950
 951#define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
 952        (read_phy_reg(pi, 0x473) & 0x1ff)
 953
 954#define wlc_lcnphy_get_target_tx_pwr(pi) \
 955        ((read_phy_reg(pi, 0x4a7) & \
 956          (0xff << 0)) >> \
 957         0)
 958
 959#define wlc_lcnphy_set_target_tx_pwr(pi, target) \
 960        mod_phy_reg(pi, 0x4a7, \
 961                    (0xff << 0), \
 962                    (u16)(target) << 0)
 963
 964#define wlc_radio_2064_rcal_done(pi) \
 965        (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
 966
 967#define tempsense_done(pi) \
 968        (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
 969
 970#define LCNPHY_IQLOCC_READ(val) \
 971        ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
 972
 973#define FIXED_TXPWR 78
 974#define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))
 975
 976void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti)
 977{
 978        wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
 979}
 980
 981void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti)
 982{
 983        wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456);
 984}
 985
 986static void
 987wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,
 988                             const u16 *tbl_ptr, u32 tbl_len,
 989                             u32 tbl_width, u32 tbl_offset)
 990{
 991        struct phytbl_info tab;
 992        tab.tbl_id = tbl_id;
 993        tab.tbl_ptr = tbl_ptr;
 994        tab.tbl_len = tbl_len;
 995        tab.tbl_width = tbl_width;
 996        tab.tbl_offset = tbl_offset;
 997        wlc_lcnphy_read_table(pi, &tab);
 998}
 999
1000static void
1001wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id,
1002                              const u16 *tbl_ptr, u32 tbl_len,
1003                              u32 tbl_width, u32 tbl_offset)
1004{
1005
1006        struct phytbl_info tab;
1007        tab.tbl_id = tbl_id;
1008        tab.tbl_ptr = tbl_ptr;
1009        tab.tbl_len = tbl_len;
1010        tab.tbl_width = tbl_width;
1011        tab.tbl_offset = tbl_offset;
1012        wlc_lcnphy_write_table(pi, &tab);
1013}
1014
1015static u32
1016wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision)
1017{
1018        u32 quotient, remainder, roundup, rbit;
1019
1020        quotient = dividend / divisor;
1021        remainder = dividend % divisor;
1022        rbit = divisor & 1;
1023        roundup = (divisor >> 1) + rbit;
1024
1025        while (precision--) {
1026                quotient <<= 1;
1027                if (remainder >= roundup) {
1028                        quotient++;
1029                        remainder = ((remainder - roundup) << 1) + rbit;
1030                } else {
1031                        remainder <<= 1;
1032                }
1033        }
1034
1035        if (remainder >= roundup)
1036                quotient++;
1037
1038        return quotient;
1039}
1040
1041static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
1042{
1043        int k;
1044        k = 0;
1045        if (type == 0) {
1046                if (coeff_x < 0)
1047                        k = (coeff_x - 1) / 2;
1048                else
1049                        k = coeff_x / 2;
1050        }
1051
1052        if (type == 1) {
1053                if ((coeff_x + 1) < 0)
1054                        k = (coeff_x) / 2;
1055                else
1056                        k = (coeff_x + 1) / 2;
1057        }
1058        return k;
1059}
1060
1061static void
1062wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)
1063{
1064        u16 dac_gain, rfgain0, rfgain1;
1065
1066        dac_gain = read_phy_reg(pi, 0x439) >> 0;
1067        gains->dac_gain = (dac_gain & 0x380) >> 7;
1068
1069        rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
1070        rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
1071
1072        gains->gm_gain = rfgain0 & 0xff;
1073        gains->pga_gain = (rfgain0 >> 8) & 0xff;
1074        gains->pad_gain = rfgain1 & 0xff;
1075}
1076
1077
1078static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain)
1079{
1080        u16 dac_ctrl;
1081
1082        dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
1083        dac_ctrl = dac_ctrl & 0xc7f;
1084        dac_ctrl = dac_ctrl | (dac_gain << 7);
1085        mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
1086
1087}
1088
1089static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable)
1090{
1091        u16 bit = bEnable ? 1 : 0;
1092
1093        mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
1094
1095        mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
1096
1097        mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
1098}
1099
1100static void
1101wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable)
1102{
1103        u16 ebit = enable ? 1 : 0;
1104
1105        mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
1106
1107        mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
1108
1109        if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1110                mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
1111                mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
1112                mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1113                mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
1114        } else {
1115                mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
1116                mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
1117                mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
1118        }
1119
1120        if (CHSPEC_IS2G(pi->radio_chanspec)) {
1121                mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
1122                mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
1123        }
1124}
1125
1126static void
1127wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
1128                                       u16 trsw,
1129                                       u16 ext_lna,
1130                                       u16 biq2,
1131                                       u16 biq1,
1132                                       u16 tia, u16 lna2, u16 lna1)
1133{
1134        u16 gain0_15, gain16_19;
1135
1136        gain16_19 = biq2 & 0xf;
1137        gain0_15 = ((biq1 & 0xf) << 12) |
1138                   ((tia & 0xf) << 8) |
1139                   ((lna2 & 0x3) << 6) |
1140                   ((lna2 & 0x3) << 4) |
1141                   ((lna1 & 0x3) << 2) |
1142                   ((lna1 & 0x3) << 0);
1143
1144        mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
1145        mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
1146        mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
1147
1148        if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
1149                mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1150                mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
1151        } else {
1152                mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
1153
1154                mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
1155
1156                mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
1157        }
1158
1159        mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
1160
1161}
1162
1163static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx)
1164{
1165
1166        mod_phy_reg(pi, 0x44d,
1167                    (0x1 << 1) |
1168                    (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
1169
1170        or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
1171}
1172
1173static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi)
1174{
1175
1176        and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
1177}
1178
1179static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b)
1180{
1181        mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
1182
1183        mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
1184
1185        mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
1186
1187        mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
1188
1189        mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
1190
1191        mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
1192
1193}
1194
1195static bool
1196wlc_lcnphy_rx_iq_est(struct brcms_phy *pi,
1197                     u16 num_samps,
1198                     u8 wait_time, struct lcnphy_iq_est *iq_est)
1199{
1200        int wait_count = 0;
1201        bool result = true;
1202        u8 phybw40;
1203        phybw40 = CHSPEC_IS40(pi->radio_chanspec);
1204
1205        mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
1206
1207        mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
1208
1209        mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
1210
1211        mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
1212
1213        mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
1214
1215        mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
1216
1217        while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
1218
1219                if (wait_count > (10 * 500)) {
1220                        result = false;
1221                        goto cleanup;
1222                }
1223                udelay(100);
1224                wait_count++;
1225        }
1226
1227        iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
1228                          (u32) read_phy_reg(pi, 0x484);
1229        iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
1230                        (u32) read_phy_reg(pi, 0x486);
1231        iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
1232                        (u32) read_phy_reg(pi, 0x488);
1233
1234cleanup:
1235        mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
1236
1237        mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
1238
1239        return result;
1240}
1241
1242static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps)
1243{
1244#define LCNPHY_MIN_RXIQ_PWR 2
1245        bool result;
1246        u16 a0_new, b0_new;
1247        struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1248        s32 a, b, temp;
1249        s16 iq_nbits, qq_nbits, arsh, brsh;
1250        s32 iq;
1251        u32 ii, qq;
1252        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1253
1254        a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
1255        b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
1256        mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
1257
1258        mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
1259
1260        wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
1261
1262        result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
1263        if (!result)
1264                goto cleanup;
1265
1266        iq = (s32) iq_est.iq_prod;
1267        ii = iq_est.i_pwr;
1268        qq = iq_est.q_pwr;
1269
1270        if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
1271                result = false;
1272                goto cleanup;
1273        }
1274
1275        iq_nbits = wlc_phy_nbits(iq);
1276        qq_nbits = wlc_phy_nbits(qq);
1277
1278        arsh = 10 - (30 - iq_nbits);
1279        if (arsh >= 0) {
1280                a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
1281                temp = (s32) (ii >> arsh);
1282                if (temp == 0)
1283                        return false;
1284        } else {
1285                a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
1286                temp = (s32) (ii << -arsh);
1287                if (temp == 0)
1288                        return false;
1289        }
1290        a /= temp;
1291        brsh = qq_nbits - 31 + 20;
1292        if (brsh >= 0) {
1293                b = (qq << (31 - qq_nbits));
1294                temp = (s32) (ii >> brsh);
1295                if (temp == 0)
1296                        return false;
1297        } else {
1298                b = (qq << (31 - qq_nbits));
1299                temp = (s32) (ii << -brsh);
1300                if (temp == 0)
1301                        return false;
1302        }
1303        b /= temp;
1304        b -= a * a;
1305        b = (s32) int_sqrt((unsigned long) b);
1306        b -= (1 << 10);
1307        a0_new = (u16) (a & 0x3ff);
1308        b0_new = (u16) (b & 0x3ff);
1309cleanup:
1310
1311        wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
1312
1313        mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
1314
1315        mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
1316
1317        pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
1318        pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
1319
1320        return result;
1321}
1322
1323static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
1324{
1325        struct lcnphy_iq_est iq_est = { 0, 0, 0 };
1326
1327        if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est))
1328                return 0;
1329        return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
1330}
1331
1332static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
1333                                      u16 tia_gain, u16 lna2_gain)
1334{
1335        u32 i_thresh_l, q_thresh_l;
1336        u32 i_thresh_h, q_thresh_h;
1337        struct lcnphy_iq_est iq_est_h, iq_est_l;
1338
1339        wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain,
1340                                               lna2_gain, 0);
1341
1342        wlc_lcnphy_rx_gain_override_enable(pi, true);
1343        wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
1344        udelay(500);
1345        write_radio_reg(pi, RADIO_2064_REG112, 0);
1346        if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
1347                return false;
1348
1349        wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
1350        udelay(500);
1351        write_radio_reg(pi, RADIO_2064_REG112, 0);
1352        if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
1353                return false;
1354
1355        i_thresh_l = (iq_est_l.i_pwr << 1);
1356        i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr;
1357
1358        q_thresh_l = (iq_est_l.q_pwr << 1);
1359        q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr;
1360        if ((iq_est_h.i_pwr > i_thresh_l) &&
1361            (iq_est_h.i_pwr < i_thresh_h) &&
1362            (iq_est_h.q_pwr > q_thresh_l) &&
1363            (iq_est_h.q_pwr < q_thresh_h))
1364                return true;
1365
1366        return false;
1367}
1368
1369static bool
1370wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
1371                     const struct lcnphy_rx_iqcomp *iqcomp,
1372                     int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
1373                     int tx_gain_idx)
1374{
1375        struct lcnphy_txgains old_gains;
1376        u16 tx_pwr_ctrl;
1377        u8 tx_gain_index_old = 0;
1378        bool result = false, tx_gain_override_old = false;
1379        u16 i, Core1TxControl_old, RFOverride0_old,
1380            RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
1381            rfoverride3_old, rfoverride3val_old, rfoverride4_old,
1382            rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
1383        int tia_gain, lna2_gain, biq1_gain;
1384        bool set_gain;
1385        u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
1386        u16 values_to_save[11];
1387        s16 *ptr;
1388        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1389
1390        ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
1391        if (NULL == ptr)
1392                return false;
1393        if (module == 2) {
1394                while (iqcomp_sz--) {
1395                        if (iqcomp[iqcomp_sz].chan ==
1396                            CHSPEC_CHANNEL(pi->radio_chanspec)) {
1397                                wlc_lcnphy_set_rx_iq_comp(pi,
1398                                                          (u16)
1399                                                          iqcomp[iqcomp_sz].a,
1400                                                          (u16)
1401                                                          iqcomp[iqcomp_sz].b);
1402                                result = true;
1403                                break;
1404                        }
1405                }
1406                goto cal_done;
1407        }
1408
1409        WARN_ON(module != 1);
1410        tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
1411        wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
1412
1413        for (i = 0; i < 11; i++)
1414                values_to_save[i] =
1415                        read_radio_reg(pi, rxiq_cal_rf_reg[i]);
1416        Core1TxControl_old = read_phy_reg(pi, 0x631);
1417
1418        or_phy_reg(pi, 0x631, 0x0015);
1419
1420        RFOverride0_old = read_phy_reg(pi, 0x44c);
1421        RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
1422        rfoverride2_old = read_phy_reg(pi, 0x4b0);
1423        rfoverride2val_old = read_phy_reg(pi, 0x4b1);
1424        rfoverride3_old = read_phy_reg(pi, 0x4f9);
1425        rfoverride3val_old = read_phy_reg(pi, 0x4fa);
1426        rfoverride4_old = read_phy_reg(pi, 0x938);
1427        rfoverride4val_old = read_phy_reg(pi, 0x939);
1428        afectrlovr_old = read_phy_reg(pi, 0x43b);
1429        afectrlovrval_old = read_phy_reg(pi, 0x43c);
1430        old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
1431        old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
1432
1433        tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
1434        if (tx_gain_override_old) {
1435                wlc_lcnphy_get_tx_gain(pi, &old_gains);
1436                tx_gain_index_old = pi_lcn->lcnphy_current_index;
1437        }
1438
1439        wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
1440
1441        mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
1442        mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
1443
1444        mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
1445        mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
1446
1447        write_radio_reg(pi, RADIO_2064_REG116, 0x06);
1448        write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
1449        write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
1450        write_radio_reg(pi, RADIO_2064_REG098, 0x03);
1451        write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
1452        mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
1453        write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
1454        write_radio_reg(pi, RADIO_2064_REG114, 0x01);
1455        write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
1456        write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
1457
1458        mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
1459        mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
1460        mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
1461        mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
1462        mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
1463        mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
1464        mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
1465        mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
1466        mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
1467        mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
1468
1469        mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
1470        mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
1471
1472        write_phy_reg(pi, 0x6da, 0xffff);
1473        or_phy_reg(pi, 0x6db, 0x3);
1474
1475        wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
1476        for (lna2_gain = 3; lna2_gain >= 0; lna2_gain--) {
1477                for (tia_gain = 4; tia_gain >= 0; tia_gain--) {
1478                        for (biq1_gain = 6; biq1_gain >= 0; biq1_gain--) {
1479                                set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,
1480                                                                     (u16)
1481                                                                     biq1_gain,
1482                                                                     (u16)
1483                                                                     tia_gain,
1484                                                                     (u16)
1485                                                                     lna2_gain);
1486                                if (!set_gain)
1487                                        continue;
1488
1489                                result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);
1490                                goto stop_tone;
1491                        }
1492                }
1493        }
1494
1495stop_tone:
1496        wlc_lcnphy_stop_tx_tone(pi);
1497
1498        write_phy_reg(pi, 0x631, Core1TxControl_old);
1499
1500        write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
1501        write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
1502        write_phy_reg(pi, 0x4b0, rfoverride2_old);
1503        write_phy_reg(pi, 0x4b1, rfoverride2val_old);
1504        write_phy_reg(pi, 0x4f9, rfoverride3_old);
1505        write_phy_reg(pi, 0x4fa, rfoverride3val_old);
1506        write_phy_reg(pi, 0x938, rfoverride4_old);
1507        write_phy_reg(pi, 0x939, rfoverride4val_old);
1508        write_phy_reg(pi, 0x43b, afectrlovr_old);
1509        write_phy_reg(pi, 0x43c, afectrlovrval_old);
1510        write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
1511        write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
1512
1513        wlc_lcnphy_clear_trsw_override(pi);
1514
1515        mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
1516
1517        for (i = 0; i < 11; i++)
1518                write_radio_reg(pi, rxiq_cal_rf_reg[i],
1519                                values_to_save[i]);
1520
1521        if (tx_gain_override_old)
1522                wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
1523        else
1524                wlc_lcnphy_disable_tx_gain_override(pi);
1525
1526        wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
1527        wlc_lcnphy_rx_gain_override_enable(pi, false);
1528
1529cal_done:
1530        kfree(ptr);
1531        return result;
1532}
1533
1534s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)
1535{
1536        s8 index;
1537        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1538
1539        if (txpwrctrl_off(pi))
1540                index = pi_lcn->lcnphy_current_index;
1541        else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
1542                index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(
1543                              pi) / 2);
1544        else
1545                index = pi_lcn->lcnphy_current_index;
1546        return index;
1547}
1548
1549void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel)
1550{
1551        u16 afectrlovr, afectrlovrval;
1552        afectrlovr = read_phy_reg(pi, 0x43b);
1553        afectrlovrval = read_phy_reg(pi, 0x43c);
1554        if (channel != 0) {
1555                mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1);
1556
1557                mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1);
1558
1559                mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4);
1560
1561                mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6);
1562
1563                write_phy_reg(pi, 0x44b, 0xffff);
1564                wlc_lcnphy_tx_pu(pi, 1);
1565
1566                mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8);
1567
1568                or_phy_reg(pi, 0x6da, 0x0080);
1569
1570                or_phy_reg(pi, 0x00a, 0x228);
1571        } else {
1572                and_phy_reg(pi, 0x00a, ~(0x228));
1573
1574                and_phy_reg(pi, 0x6da, 0xFF7F);
1575                write_phy_reg(pi, 0x43b, afectrlovr);
1576                write_phy_reg(pi, 0x43c, afectrlovrval);
1577        }
1578}
1579
1580static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi)
1581{
1582        u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr;
1583
1584        save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c);
1585        save_AfeCtrlOvr = read_phy_reg(pi, 0x43b);
1586
1587        write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1);
1588        write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1);
1589
1590        write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe);
1591        write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe);
1592
1593        write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal);
1594        write_phy_reg(pi, 0x43b, save_AfeCtrlOvr);
1595}
1596
1597static void
1598wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable)
1599{
1600        if (enable) {
1601                write_phy_reg(pi, 0x942, 0x7);
1602                write_phy_reg(pi, 0x93b, ((1 << 13) + 23));
1603                write_phy_reg(pi, 0x93c, ((1 << 13) + 1989));
1604
1605                write_phy_reg(pi, 0x44a, 0x084);
1606                write_phy_reg(pi, 0x44a, 0x080);
1607                write_phy_reg(pi, 0x6d3, 0x2222);
1608                write_phy_reg(pi, 0x6d3, 0x2220);
1609        } else {
1610                write_phy_reg(pi, 0x942, 0x0);
1611                write_phy_reg(pi, 0x93b, ((0 << 13) + 23));
1612                write_phy_reg(pi, 0x93c, ((0 << 13) + 1989));
1613        }
1614        wlapi_switch_macfreq(pi->sh->physhim, enable);
1615}
1616
1617static void
1618wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
1619{
1620        u8 channel = CHSPEC_CHANNEL(chanspec);
1621        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
1622
1623        if (channel == 14)
1624                mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
1625        else
1626                mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
1627
1628        pi_lcn->lcnphy_bandedge_corr = 2;
1629        if (channel == 1)
1630                pi_lcn->lcnphy_bandedge_corr = 4;
1631
1632        if (channel == 1 || channel == 2 || channel == 3 ||
1633            channel == 4 || channel == 9 ||
1634            channel == 10 || channel == 11 || channel == 12) {
1635                bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
1636                                      0x03000c04);
1637                bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
1638                                        ~0x00ffffff, 0x0);
1639                bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
1640                                      0x200005c0);
1641
1642                bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
1643                              BCMA_CC_PMU_CTL_PLL_UPD);
1644                write_phy_reg(pi, 0x942, 0);
1645                wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
1646                pi_lcn->lcnphy_spurmod = false;
1647                mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
1648
1649                write_phy_reg(pi, 0x425, 0x5907);
1650        } else {
1651                bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x2,
1652                                      0x03140c04);
1653                bcma_chipco_pll_maskset(&pi->d11core->bus->drv_cc, 0x3,
1654                                        ~0x00ffffff, 0x333333);
1655                bcma_chipco_pll_write(&pi->d11core->bus->drv_cc, 0x4,
1656                                      0x202c2820);
1657
1658                bcma_cc_set32(&pi->d11core->bus->drv_cc, BCMA_CC_PMU_CTL,
1659                              BCMA_CC_PMU_CTL_PLL_UPD);
1660                write_phy_reg(pi, 0x942, 0);
1661                wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
1662
1663                pi_lcn->lcnphy_spurmod = false;
1664                mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
1665
1666                write_phy_reg(pi, 0x425, 0x590a);
1667        }
1668
1669        or_phy_reg(pi, 0x44a, 0x44);
1670        write_phy_reg(pi, 0x44a, 0x80);
1671}
1672
1673static void
1674wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
1675{
1676        uint i;
1677        const struct chan_info_2064_lcnphy *ci;
1678        u8 rfpll_doubler = 0;
1679        u8 pll_pwrup, pll_pwrup_ovr;
1680        s32 qFxtal, qFref, qFvco, qFcal;
1681        u8 d15, d16, f16, e44, e45;
1682        u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
1683        u16 loop_bw, d30, setCount;
1684
1685        u8 h29, h28_ten, e30, h30_ten, cp_current;
1686        u16 g30, d28;
1687
1688        ci = &chan_info_2064_lcnphy[0];
1689        rfpll_doubler = 1;
1690
1691        mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
1692
1693        write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
1694        if (!rfpll_doubler) {
1695                loop_bw = PLL_2064_LOOP_BW;
1696                d30 = PLL_2064_D30;
1697        } else {
1698                loop_bw = PLL_2064_LOOP_BW_DOUBLER;
1699                d30 = PLL_2064_D30_DOUBLER;
1700        }
1701
1702        if (CHSPEC_IS2G(pi->radio_chanspec)) {
1703                for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
1704                        if (chan_info_2064_lcnphy[i].chan == channel)
1705                                break;
1706
1707                if (i >= ARRAY_SIZE(chan_info_2064_lcnphy))
1708                        return;
1709
1710                ci = &chan_info_2064_lcnphy[i];
1711        }
1712
1713        write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
1714
1715        mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
1716
1717        mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
1718
1719        mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
1720
1721        mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
1722                      (ci->logen_rccr_rx) << 2);
1723
1724        mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
1725
1726        mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
1727                      (ci->pa_rxrf_lna2_freq_tune) << 4);
1728
1729        write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
1730
1731        pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
1732        pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
1733
1734        or_radio_reg(pi, RADIO_2064_REG044, 0x07);
1735
1736        or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
1737        e44 = 0;
1738        e45 = 0;
1739
1740        fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
1741        if (pi->xtalfreq > 26000000)
1742                e44 = 1;
1743        if (pi->xtalfreq > 52000000)
1744                e45 = 1;
1745        if (e44 == 0)
1746                fcal_div = 1;
1747        else if (e45 == 0)
1748                fcal_div = 2;
1749        else
1750                fcal_div = 4;
1751        fvco3 = (ci->freq * 3);
1752        fref3 = 2 * fpfd;
1753
1754        qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
1755        qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
1756        qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
1757        qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
1758
1759        write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
1760
1761        d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
1762        write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
1763        write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
1764
1765        d16 = (qFcal * 8 / (d15 + 1)) - 1;
1766        write_radio_reg(pi, RADIO_2064_REG051, d16);
1767
1768        f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
1769        setCount = f16 * 3 * (ci->freq) / 32 - 1;
1770        mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
1771                      (u8) (setCount >> 8));
1772
1773        or_radio_reg(pi, RADIO_2064_REG053, 0x10);
1774        write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
1775
1776        div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
1777
1778        div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
1779        while (div_frac >= fref3) {
1780                div_int++;
1781                div_frac -= fref3;
1782        }
1783        div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
1784
1785        mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
1786                      (u8) (div_int >> 4));
1787        mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
1788                      (u8) (div_int << 4));
1789        mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
1790                      (u8) (div_frac >> 16));
1791        write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
1792        write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
1793
1794        write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
1795
1796        write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
1797        write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
1798        write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
1799
1800        h29 = LCN_BW_LMT / loop_bw;
1801        d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
1802                (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
1803               (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
1804              + PLL_2064_LOW_END_KVCO;
1805        h28_ten = (d28 * 10) / LCN_VCO_DIV;
1806        e30 = (d30 - LCN_OFFSET) / LCN_FACT;
1807        g30 = LCN_OFFSET + (e30 * LCN_FACT);
1808        h30_ten = (g30 * 10) / LCN_CUR_DIV;
1809        cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten;
1810        mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
1811
1812        if (channel >= 1 && channel <= 5)
1813                write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
1814        else
1815                write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
1816        write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
1817
1818        mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
1819        udelay(1);
1820
1821        wlc_2064_vco_cal(pi);
1822
1823        write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
1824        write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
1825        if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
1826                write_radio_reg(pi, RADIO_2064_REG038, 3);
1827                write_radio_reg(pi, RADIO_2064_REG091, 7);
1828        }
1829
1830        if (!(pi->sh->boardflags & BFL_FEM)) {
1831                static const u8 reg038[14] = {
1832                        0xd, 0xe, 0xd, 0xd, 0xd, 0xc, 0xa,
1833                        0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0
1834                };
1835
1836                write_radio_reg(pi, RADIO_2064_REG02A, 0xf);
1837                write_radio_reg(pi, RADIO_2064_REG091, 0x3);
1838                write_radio_reg(pi, RADIO_2064_REG038, 0x3);
1839
1840                write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]);
1841        }
1842}
1843
1844static int
1845wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)
1846{
1847        s16 filt_index = -1;
1848        int j;
1849
1850        u16 addr[] = {
1851                0x910,
1852                0x91e,
1853                0x91f,
1854                0x924,
1855                0x925,
1856                0x926,
1857                0x920,
1858                0x921,
1859                0x927,
1860                0x928,
1861                0x929,
1862                0x922,
1863                0x923,
1864                0x930,
1865                0x931,
1866                0x932
1867        };
1868
1869        u16 addr_ofdm[] = {
1870                0x90f,
1871                0x900,
1872                0x901,
1873                0x906,
1874                0x907,
1875                0x908,
1876                0x902,
1877                0x903,
1878                0x909,
1879                0x90a,
1880                0x90b,
1881                0x904,
1882                0x905,
1883                0x90c,
1884                0x90d,
1885                0x90e
1886        };
1887
1888        if (!is_ofdm) {
1889                for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
1890                        if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
1891                                filt_index = (s16) j;
1892                                break;
1893                        }
1894                }
1895
1896                if (filt_index != -1) {
1897                        for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1898                                write_phy_reg(pi, addr[j],
1899                                              LCNPHY_txdigfiltcoeffs_cck
1900                                              [filt_index][j + 1]);
1901                }
1902        } else {
1903                for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
1904                        if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
1905                                filt_index = (s16) j;
1906                                break;
1907                        }
1908                }
1909
1910                if (filt_index != -1) {
1911                        for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
1912                                write_phy_reg(pi, addr_ofdm[j],
1913                                              LCNPHY_txdigfiltcoeffs_ofdm
1914                                              [filt_index][j + 1]);
1915                }
1916        }
1917
1918        return (filt_index != -1) ? 0 : -1;
1919}
1920
1921static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)
1922{
1923        u16 pa_gain;
1924
1925        pa_gain = (read_phy_reg(pi, 0x4fb) &
1926                   LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
1927                  LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
1928
1929        return pa_gain;
1930}
1931
1932static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
1933                                   struct lcnphy_txgains *target_gains)
1934{
1935        u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
1936
1937        mod_phy_reg(
1938                pi, 0x4b5,
1939                (0xffff << 0),
1940                ((target_gains->gm_gain) |
1941                 (target_gains->pga_gain << 8)) <<
1942                0);
1943        mod_phy_reg(pi, 0x4fb,
1944                    (0x7fff << 0),
1945                    ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1946
1947        mod_phy_reg(
1948                pi, 0x4fc,
1949                (0xffff << 0),
1950                ((target_gains->gm_gain) |
1951                 (target_gains->pga_gain << 8)) <<
1952                0);
1953        mod_phy_reg(pi, 0x4fd,
1954                    (0x7fff << 0),
1955                    ((target_gains->pad_gain) | (pa_gain << 8)) << 0);
1956
1957        wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain);
1958
1959        wlc_lcnphy_enable_tx_gain_override(pi);
1960}
1961
1962static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi)
1963{
1964        u16 m0m1;
1965        struct phytbl_info tab;
1966
1967        tab.tbl_ptr = &m0m1;
1968        tab.tbl_len = 1;
1969        tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1970        tab.tbl_offset = 87;
1971        tab.tbl_width = 16;
1972        wlc_lcnphy_read_table(pi, &tab);
1973
1974        return (u8) ((m0m1 & 0xff00) >> 8);
1975}
1976
1977static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0)
1978{
1979        u16 m0m1 = (u16) m0 << 8;
1980        struct phytbl_info tab;
1981
1982        tab.tbl_ptr = &m0m1;
1983        tab.tbl_len = 1;
1984        tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
1985        tab.tbl_offset = 87;
1986        tab.tbl_width = 16;
1987        wlc_lcnphy_write_table(pi, &tab);
1988}
1989
1990static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi)
1991{
1992        u32 data_buf[64];
1993        struct phytbl_info tab;
1994
1995        memset(data_buf, 0, sizeof(data_buf));
1996
1997        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
1998        tab.tbl_width = 32;
1999        tab.tbl_ptr = data_buf;
2000
2001        if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
2002
2003                tab.tbl_len = 30;
2004                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2005                wlc_lcnphy_write_table(pi, &tab);
2006        }
2007
2008        tab.tbl_len = 64;
2009        tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET;
2010        wlc_lcnphy_write_table(pi, &tab);
2011}
2012
2013enum lcnphy_tssi_mode {
2014        LCNPHY_TSSI_PRE_PA,
2015        LCNPHY_TSSI_POST_PA,
2016        LCNPHY_TSSI_EXT
2017};
2018
2019static void
2020wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
2021{
2022        mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0);
2023
2024        mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6);
2025
2026        if (LCNPHY_TSSI_POST_PA == pos) {
2027                mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2);
2028
2029                mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3);
2030
2031                if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2032                        mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2033                } else {
2034                        mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
2035                        mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2036                        mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0);
2037                        mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2);
2038                        mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0);
2039                        mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4);
2040                        mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
2041                        mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77);
2042                        mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1);
2043                        mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7);
2044                        mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1);
2045                        mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);
2046                }
2047        } else {
2048                mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
2049
2050                mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3);
2051
2052                if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2053                        mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2054                } else {
2055                        mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2056                        mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2057                }
2058        }
2059        mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14);
2060
2061        if (LCNPHY_TSSI_EXT == pos) {
2062                write_radio_reg(pi, RADIO_2064_REG07F, 1);
2063                mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2);
2064                mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7);
2065                mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3);
2066        }
2067}
2068
2069static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi)
2070{
2071        u16 N1, N2, N3, N4, N5, N6, N;
2072        N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0))
2073              >> 0);
2074        N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12))
2075                   >> 12);
2076        N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0))
2077              >> 0);
2078        N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8))
2079                   >> 8);
2080        N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0))
2081              >> 0);
2082        N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8))
2083                   >> 8);
2084        N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80;
2085        if (N < 1600)
2086                N = 1600;
2087        return N;
2088}
2089
2090static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
2091{
2092        u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
2093        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2094
2095        auxpga_vmid = (2 << 8) |
2096                      (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
2097        auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
2098        auxpga_gain_temp = 2;
2099
2100        mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0);
2101
2102        mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1);
2103
2104        mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3);
2105
2106        mod_phy_reg(pi, 0x4db,
2107                    (0x3ff << 0) |
2108                    (0x7 << 12),
2109                    (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2110
2111        mod_phy_reg(pi, 0x4dc,
2112                    (0x3ff << 0) |
2113                    (0x7 << 12),
2114                    (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2115
2116        mod_phy_reg(pi, 0x40a,
2117                    (0x3ff << 0) |
2118                    (0x7 << 12),
2119                    (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12));
2120
2121        mod_phy_reg(pi, 0x40b,
2122                    (0x3ff << 0) |
2123                    (0x7 << 12),
2124                    (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2125
2126        mod_phy_reg(pi, 0x40c,
2127                    (0x3ff << 0) |
2128                    (0x7 << 12),
2129                    (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
2130
2131        mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
2132        mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));
2133}
2134
2135static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
2136{
2137        struct phytbl_info tab;
2138        u32 rfseq, ind;
2139        enum lcnphy_tssi_mode mode;
2140        u8 tssi_sel;
2141
2142        if (pi->sh->boardflags & BFL_FEM) {
2143                tssi_sel = 0x1;
2144                mode = LCNPHY_TSSI_EXT;
2145        } else {
2146                tssi_sel = 0xe;
2147                mode = LCNPHY_TSSI_POST_PA;
2148        }
2149        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2150        tab.tbl_width = 32;
2151        tab.tbl_ptr = &ind;
2152        tab.tbl_len = 1;
2153        tab.tbl_offset = 0;
2154        for (ind = 0; ind < 128; ind++) {
2155                wlc_lcnphy_write_table(pi, &tab);
2156                tab.tbl_offset++;
2157        }
2158        tab.tbl_offset = 704;
2159        for (ind = 0; ind < 128; ind++) {
2160                wlc_lcnphy_write_table(pi, &tab);
2161                tab.tbl_offset++;
2162        }
2163        mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2164
2165        mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2166
2167        mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
2168
2169        wlc_lcnphy_set_tssi_mux(pi, mode);
2170        mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2171
2172        mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
2173
2174        mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2175
2176        mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0);
2177
2178        mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2179
2180        mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2181
2182        mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2183
2184        mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2185
2186        mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8);
2187
2188        mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2189
2190        mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8);
2191
2192        mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6);
2193
2194        mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0);
2195
2196        wlc_lcnphy_clear_tx_power_offsets(pi);
2197
2198        mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
2199
2200        mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0);
2201
2202        mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
2203
2204        if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2205                mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel);
2206                mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
2207        } else {
2208                mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);
2209                mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2210                mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
2211        }
2212
2213        write_radio_reg(pi, RADIO_2064_REG025, 0xc);
2214
2215        if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2216                mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
2217        } else {
2218                if (CHSPEC_IS2G(pi->radio_chanspec))
2219                        mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2220                else
2221                        mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1);
2222        }
2223
2224        if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2225                mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1);
2226        else
2227                mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2);
2228
2229        mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0);
2230
2231        mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
2232
2233        if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2234                mod_phy_reg(pi, 0x4d7,
2235                            (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
2236
2237        rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
2238        tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
2239        tab.tbl_width = 16;
2240        tab.tbl_ptr = &rfseq;
2241        tab.tbl_len = 1;
2242        tab.tbl_offset = 6;
2243        wlc_lcnphy_write_table(pi, &tab);
2244
2245        mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
2246
2247        mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
2248
2249        mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2250
2251        mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2);
2252
2253        mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
2254
2255        mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0);
2256        mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
2257        mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
2258
2259        wlc_lcnphy_pwrctrl_rssiparams(pi);
2260}
2261
2262void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi)
2263{
2264        u16 tx_cnt, tx_total, npt;
2265        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2266
2267        tx_total = wlc_lcnphy_total_tx_frames(pi);
2268        tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt;
2269        npt = wlc_lcnphy_get_tx_pwr_npt(pi);
2270
2271        if (tx_cnt > (1 << npt)) {
2272
2273                pi_lcn->lcnphy_tssi_tx_cnt = tx_total;
2274
2275                pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi);
2276                pi_lcn->lcnphy_tssi_npt = npt;
2277
2278        }
2279}
2280
2281s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1)
2282{
2283        s32 a, b, p;
2284
2285        a = 32768 + (a1 * tssi);
2286        b = (1024 * b0) + (64 * b1 * tssi);
2287        p = ((2 * b) + a) / (2 * a);
2288
2289        return p;
2290}
2291
2292static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi)
2293{
2294        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2295        if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2296                return;
2297
2298        pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313;
2299        pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT;
2300}
2301
2302void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)
2303{
2304        struct phytbl_info tab;
2305        u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +
2306                       BRCMS_NUM_RATES_MCS_1_STREAM];
2307        uint i, j;
2308        if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
2309                return;
2310
2311        for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) {
2312
2313                if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM)
2314                        j = TXP_FIRST_MCS_20_SISO;
2315
2316                rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j]));
2317        }
2318
2319        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2320        tab.tbl_width = 32;
2321        tab.tbl_len = ARRAY_SIZE(rate_table);
2322        tab.tbl_ptr = rate_table;
2323        tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2324        wlc_lcnphy_write_table(pi, &tab);
2325
2326        if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) {
2327                wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min);
2328
2329                wlc_lcnphy_txpower_reset_npt(pi);
2330        }
2331}
2332
2333static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index)
2334{
2335        u32 cck_offset[4] = { 22, 22, 22, 22 };
2336        u32 ofdm_offset, reg_offset_cck;
2337        int i;
2338        u16 index2;
2339        struct phytbl_info tab;
2340
2341        if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2342                return;
2343
2344        mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2345
2346        mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14);
2347
2348        or_phy_reg(pi, 0x6da, 0x0040);
2349
2350        reg_offset_cck = 0;
2351        for (i = 0; i < 4; i++)
2352                cck_offset[i] -= reg_offset_cck;
2353        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
2354        tab.tbl_width = 32;
2355        tab.tbl_len = 4;
2356        tab.tbl_ptr = cck_offset;
2357        tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
2358        wlc_lcnphy_write_table(pi, &tab);
2359        ofdm_offset = 0;
2360        tab.tbl_len = 1;
2361        tab.tbl_ptr = &ofdm_offset;
2362        for (i = 836; i < 862; i++) {
2363                tab.tbl_offset = i;
2364                wlc_lcnphy_write_table(pi, &tab);
2365        }
2366
2367        mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15);
2368
2369        mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14);
2370
2371        mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13);
2372
2373        mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7);
2374
2375        mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6);
2376
2377        mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15);
2378
2379        index2 = (u16) (index * 2);
2380        mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
2381
2382        mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4);
2383
2384}
2385
2386static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
2387{
2388        s8 index, delta_brd, delta_temp, new_index, tempcorrx;
2389        s16 manp, meas_temp, temp_diff;
2390        bool neg = false;
2391        u16 temp;
2392        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2393
2394        if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
2395                return pi_lcn->lcnphy_current_index;
2396
2397        index = FIXED_TXPWR;
2398
2399        if (pi_lcn->lcnphy_tempsense_slope == 0)
2400                return index;
2401
2402        temp = (u16) wlc_lcnphy_tempsense(pi, 0);
2403        meas_temp = LCNPHY_TEMPSENSE(temp);
2404
2405        if (pi->tx_power_min != 0)
2406                delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
2407        else
2408                delta_brd = 0;
2409
2410        manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
2411        temp_diff = manp - meas_temp;
2412        if (temp_diff < 0) {
2413                neg = true;
2414                temp_diff = -temp_diff;
2415        }
2416
2417        delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
2418                                                  (u32) (pi_lcn->
2419                                                         lcnphy_tempsense_slope
2420                                                         * 10), 0);
2421        if (neg)
2422                delta_temp = -delta_temp;
2423
2424        if (pi_lcn->lcnphy_tempsense_option == 3
2425            && LCNREV_IS(pi->pubpi.phy_rev, 0))
2426                delta_temp = 0;
2427        if (pi_lcn->lcnphy_tempcorrx > 31)
2428                tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64);
2429        else
2430                tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx;
2431        if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2432                tempcorrx = 4;
2433        new_index =
2434                index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
2435        new_index += tempcorrx;
2436
2437        if (LCNREV_IS(pi->pubpi.phy_rev, 1))
2438                index = 127;
2439
2440        if (new_index < 0 || new_index > 126)
2441                return index;
2442
2443        return new_index;
2444}
2445
2446static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode)
2447{
2448
2449        u16 current_mode = mode;
2450        if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
2451            mode == LCNPHY_TX_PWR_CTRL_HW)
2452                current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED;
2453        if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
2454            mode == LCNPHY_TX_PWR_CTRL_TEMPBASED)
2455                current_mode = LCNPHY_TX_PWR_CTRL_HW;
2456        return current_mode;
2457}
2458
2459void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
2460{
2461        u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2462        s8 index;
2463        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2464
2465        mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode);
2466        old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode);
2467
2468        mod_phy_reg(pi, 0x6da, (0x1 << 6),
2469                    ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6);
2470
2471        mod_phy_reg(pi, 0x6a3, (0x1 << 4),
2472                    ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4);
2473
2474        if (old_mode != mode) {
2475                if (LCNPHY_TX_PWR_CTRL_HW == old_mode) {
2476
2477                        wlc_lcnphy_tx_pwr_update_npt(pi);
2478
2479                        wlc_lcnphy_clear_tx_power_offsets(pi);
2480                }
2481                if (LCNPHY_TX_PWR_CTRL_HW == mode) {
2482
2483                        wlc_lcnphy_txpower_recalc_target(pi);
2484
2485                        wlc_lcnphy_set_start_tx_pwr_idx(pi,
2486                                                        pi_lcn->
2487                                                        lcnphy_tssi_idx);
2488                        wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt);
2489                        mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
2490
2491                        pi_lcn->lcnphy_tssi_tx_cnt =
2492                                wlc_lcnphy_total_tx_frames(pi);
2493
2494                        wlc_lcnphy_disable_tx_gain_override(pi);
2495                        pi_lcn->lcnphy_tx_power_idx_override = -1;
2496                } else
2497                        wlc_lcnphy_enable_tx_gain_override(pi);
2498
2499                mod_phy_reg(pi, 0x4a4,
2500                            ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode);
2501                if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) {
2502                        index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
2503                        wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
2504                        pi_lcn->lcnphy_current_index = (s8)
2505                                                       ((read_phy_reg(pi,
2506                                                                      0x4a9) &
2507                                                         0xFF) / 2);
2508                }
2509        }
2510}
2511
2512static void
2513wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
2514{
2515        u16 vmid;
2516        int i;
2517        for (i = 0; i < 20; i++)
2518                values_to_save[i] =
2519                        read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
2520
2521        mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
2522        mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
2523
2524        mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
2525        mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
2526
2527        mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
2528        mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
2529
2530        mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
2531        mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
2532
2533        if (LCNREV_IS(pi->pubpi.phy_rev, 2))
2534                and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
2535        else
2536                and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
2537        or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
2538
2539        or_radio_reg(pi, RADIO_2064_REG036, 0x01);
2540        or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
2541        udelay(20);
2542
2543        if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2544                if (CHSPEC_IS5G(pi->radio_chanspec))
2545                        mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
2546                else
2547                        or_radio_reg(pi, RADIO_2064_REG03A, 1);
2548        } else {
2549                if (CHSPEC_IS5G(pi->radio_chanspec))
2550                        mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
2551                else
2552                        or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
2553        }
2554
2555        udelay(20);
2556
2557        write_radio_reg(pi, RADIO_2064_REG025, 0xF);
2558        if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
2559                if (CHSPEC_IS5G(pi->radio_chanspec))
2560                        mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
2561                else
2562                        mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
2563        } else {
2564                if (CHSPEC_IS5G(pi->radio_chanspec))
2565                        mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
2566                else
2567                        mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
2568        }
2569
2570        udelay(20);
2571
2572        write_radio_reg(pi, RADIO_2064_REG005, 0x8);
2573        or_radio_reg(pi, RADIO_2064_REG112, 0x80);
2574        udelay(20);
2575
2576        or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2577        or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2578        udelay(20);
2579
2580        or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
2581        or_radio_reg(pi, RADIO_2064_REG113, 0x10);
2582        udelay(20);
2583
2584        write_radio_reg(pi, RADIO_2064_REG007, 0x1);
2585        udelay(20);
2586
2587        vmid = 0x2A6;
2588        mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
2589        write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
2590        or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
2591        udelay(20);
2592
2593        or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
2594        udelay(20);
2595        write_radio_reg(pi, RADIO_2064_REG012, 0x02);
2596        or_radio_reg(pi, RADIO_2064_REG112, 0x06);
2597        write_radio_reg(pi, RADIO_2064_REG036, 0x11);
2598        write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
2599        write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
2600        write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
2601        write_radio_reg(pi, RADIO_2064_REG092, 0x15);
2602}
2603
2604static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
2605{
2606        uint delay_count = 0;
2607
2608        while (wlc_lcnphy_iqcal_active(pi)) {
2609                udelay(100);
2610                delay_count++;
2611
2612                if (delay_count > (10 * 500))
2613                        break;
2614        }
2615
2616        return (0 == wlc_lcnphy_iqcal_active(pi));
2617}
2618
2619static void
2620wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
2621{
2622        int i;
2623
2624        and_phy_reg(pi, 0x44c, 0x0 >> 11);
2625
2626        and_phy_reg(pi, 0x43b, 0xC);
2627
2628        for (i = 0; i < 20; i++)
2629                write_radio_reg(pi, iqlo_loopback_rf_regs[i],
2630                                values_to_save[i]);
2631}
2632
2633static void
2634wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
2635                       struct lcnphy_txgains *target_gains,
2636                       enum lcnphy_cal_mode cal_mode, bool keep_tone)
2637{
2638
2639        struct lcnphy_txgains cal_gains, temp_gains;
2640        u16 hash;
2641        u8 band_idx;
2642        int j;
2643        u16 ncorr_override[5];
2644        u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
2645                              0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
2646
2647        u16 commands_fullcal[] = {
2648                0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2649        };
2650
2651        u16 commands_recal[] = {
2652                0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
2653        };
2654
2655        u16 command_nums_fullcal[] = {
2656                0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2657        };
2658
2659        u16 command_nums_recal[] = {
2660                0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
2661        };
2662        u16 *command_nums = command_nums_fullcal;
2663
2664        u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
2665        u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2;
2666        u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl;
2667        bool tx_gain_override_old;
2668        struct lcnphy_txgains old_gains;
2669        uint i, n_cal_cmds = 0, n_cal_start = 0;
2670        u16 *values_to_save;
2671        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2672
2673        values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
2674        if (NULL == values_to_save)
2675                return;
2676
2677        save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
2678        save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
2679
2680        or_phy_reg(pi, 0x6da, 0x40);
2681        or_phy_reg(pi, 0x6db, 0x3);
2682
2683        switch (cal_mode) {
2684        case LCNPHY_CAL_FULL:
2685                start_coeffs = syst_coeffs;
2686                cal_cmds = commands_fullcal;
2687                n_cal_cmds = ARRAY_SIZE(commands_fullcal);
2688                break;
2689
2690        case LCNPHY_CAL_RECAL:
2691                start_coeffs = syst_coeffs;
2692                cal_cmds = commands_recal;
2693                n_cal_cmds = ARRAY_SIZE(commands_recal);
2694                command_nums = command_nums_recal;
2695                break;
2696
2697        default:
2698                break;
2699        }
2700
2701        wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2702                                      start_coeffs, 11, 16, 64);
2703
2704        write_phy_reg(pi, 0x6da, 0xffff);
2705        mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3);
2706
2707        tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2708
2709        mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
2710
2711        wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2712
2713        save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db);
2714
2715        mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0);
2716
2717        mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12);
2718
2719        wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save);
2720
2721        tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2722        if (tx_gain_override_old)
2723                wlc_lcnphy_get_tx_gain(pi, &old_gains);
2724
2725        if (!target_gains) {
2726                if (!tx_gain_override_old)
2727                        wlc_lcnphy_set_tx_pwr_by_index(pi,
2728                                                       pi_lcn->lcnphy_tssi_idx);
2729                wlc_lcnphy_get_tx_gain(pi, &temp_gains);
2730                target_gains = &temp_gains;
2731        }
2732
2733        hash = (target_gains->gm_gain << 8) |
2734               (target_gains->pga_gain << 4) | (target_gains->pad_gain);
2735
2736        band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
2737
2738        cal_gains = *target_gains;
2739        memset(ncorr_override, 0, sizeof(ncorr_override));
2740        for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
2741                if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
2742                        cal_gains.gm_gain =
2743                                tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
2744                        cal_gains.pga_gain =
2745                                tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
2746                        cal_gains.pad_gain =
2747                                tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
2748                        memcpy(ncorr_override,
2749                               &tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
2750                               sizeof(ncorr_override));
2751                        break;
2752                }
2753        }
2754
2755        wlc_lcnphy_set_tx_gain(pi, &cal_gains);
2756
2757        write_phy_reg(pi, 0x453, 0xaa9);
2758        write_phy_reg(pi, 0x93d, 0xc0);
2759
2760        wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2761                                      lcnphy_iqcal_loft_gainladder,
2762                                      ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
2763                                      16, 0);
2764
2765        wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2766                                      lcnphy_iqcal_ir_gainladder,
2767                                      ARRAY_SIZE(
2768                                              lcnphy_iqcal_ir_gainladder), 16,
2769                                      32);
2770
2771        if (pi->phy_tx_tone_freq) {
2772
2773                wlc_lcnphy_stop_tx_tone(pi);
2774                udelay(5);
2775                wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2776        } else {
2777                wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1);
2778        }
2779
2780        write_phy_reg(pi, 0x6da, 0xffff);
2781
2782        for (i = n_cal_start; i < n_cal_cmds; i++) {
2783                u16 zero_diq = 0;
2784                u16 best_coeffs[11];
2785                u16 command_num;
2786
2787                cal_type = (cal_cmds[i] & 0x0f00) >> 8;
2788
2789                command_num = command_nums[i];
2790                if (ncorr_override[cal_type])
2791                        command_num =
2792                                ncorr_override[cal_type] << 8 | (command_num &
2793                                                                 0xff);
2794
2795                write_phy_reg(pi, 0x452, command_num);
2796
2797                if ((cal_type == 3) || (cal_type == 4)) {
2798                        wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2799                                                     &diq_start, 1, 16, 69);
2800
2801                        wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2802                                                      &zero_diq, 1, 16, 69);
2803                }
2804
2805                write_phy_reg(pi, 0x451, cal_cmds[i]);
2806
2807                if (!wlc_lcnphy_iqcal_wait(pi))
2808                        goto cleanup;
2809
2810                wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2811                                             best_coeffs,
2812                                             ARRAY_SIZE(best_coeffs), 16, 96);
2813                wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2814                                              best_coeffs,
2815                                              ARRAY_SIZE(best_coeffs), 16, 64);
2816
2817                if ((cal_type == 3) || (cal_type == 4))
2818                        wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2819                                                      &diq_start, 1, 16, 69);
2820                wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2821                                             pi_lcn->lcnphy_cal_results.
2822                                             txiqlocal_bestcoeffs,
2823                                             ARRAY_SIZE(pi_lcn->
2824                                                        lcnphy_cal_results.
2825                                                        txiqlocal_bestcoeffs),
2826                                             16, 96);
2827        }
2828
2829        wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2830                                     pi_lcn->lcnphy_cal_results.
2831                                     txiqlocal_bestcoeffs,
2832                                     ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
2833                                                txiqlocal_bestcoeffs), 16, 96);
2834        pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
2835
2836        wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2837                                      &pi_lcn->lcnphy_cal_results.
2838                                      txiqlocal_bestcoeffs[0], 4, 16, 80);
2839
2840        wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
2841                                      &pi_lcn->lcnphy_cal_results.
2842                                      txiqlocal_bestcoeffs[5], 2, 16, 85);
2843
2844cleanup:
2845        wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
2846        kfree(values_to_save);
2847
2848        if (!keep_tone)
2849                wlc_lcnphy_stop_tx_tone(pi);
2850
2851        write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2);
2852
2853        write_phy_reg(pi, 0x453, 0);
2854
2855        if (tx_gain_override_old)
2856                wlc_lcnphy_set_tx_gain(pi, &old_gains);
2857        wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old);
2858
2859        write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl);
2860        write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl);
2861
2862}
2863
2864static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
2865{
2866        bool suspend, tx_gain_override_old;
2867        struct lcnphy_txgains old_gains;
2868        struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
2869        u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB,
2870            idleTssi0_regvalue_2C;
2871        u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
2872        u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
2873        u16 SAVE_jtag_bb_afe_switch =
2874                read_radio_reg(pi, RADIO_2064_REG007) & 1;
2875        u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
2876        u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
2877        u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi);
2878
2879        idleTssi = read_phy_reg(pi, 0x4ab);
2880        suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2881                         MCTL_EN_MAC));
2882        if (!suspend)
2883                wlapi_suspend_mac_and_wait(pi->sh->physhim);
2884        wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2885
2886        tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
2887        wlc_lcnphy_get_tx_gain(pi, &old_gains);
2888
2889        wlc_lcnphy_enable_tx_gain_override(pi);
2890        wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2891        write_radio_reg(pi, RADIO_2064_REG112, 0x6);
2892        mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1);
2893        mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
2894        mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
2895        wlc_lcnphy_tssi_setup(pi);
2896
2897        mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0));
2898        mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6));
2899
2900        wlc_lcnphy_set_bbmult(pi, 0x0);
2901
2902        wlc_phy_do_dummy_tx(pi, true, OFF);
2903        idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
2904                    >> 0);
2905
2906        idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0))
2907                        >> 0);
2908
2909        if (idleTssi0_2C >= 256)
2910                idleTssi0_OB = idleTssi0_2C - 256;
2911        else
2912                idleTssi0_OB = idleTssi0_2C + 256;
2913
2914        idleTssi0_regvalue_OB = idleTssi0_OB;
2915        if (idleTssi0_regvalue_OB >= 256)
2916                idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256;
2917        else
2918                idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256;
2919        mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0);
2920
2921        mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
2922
2923        wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);
2924        wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
2925        wlc_lcnphy_set_tx_gain(pi, &old_gains);
2926        wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
2927
2928        write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain);
2929        mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch);
2930        mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga);
2931        mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en);
2932        mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7);
2933        if (!suspend)
2934                wlapi_enable_mac(pi->sh->physhim);
2935}
2936
2937static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
2938{
2939        bool suspend;
2940        u16 save_txpwrCtrlEn;
2941        u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
2942        u16 auxpga_vmid;
2943        struct phytbl_info tab;
2944        u32 val;
2945        u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
2946           save_reg112;
2947        u16 values_to_save[14];
2948        s8 index;
2949        int i;
2950        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
2951        udelay(999);
2952
2953        save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007);
2954        save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF);
2955        save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F);
2956        save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005);
2957        save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025);
2958        save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112);
2959
2960        for (i = 0; i < 14; i++)
2961                values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
2962        suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
2963                         MCTL_EN_MAC));
2964        if (!suspend)
2965                wlapi_suspend_mac_and_wait(pi->sh->physhim);
2966        save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
2967
2968        wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
2969        index = pi_lcn->lcnphy_current_index;
2970        wlc_lcnphy_set_tx_pwr_by_index(pi, 127);
2971        mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1);
2972        mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4);
2973        mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2);
2974        mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0);
2975
2976        mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2);
2977
2978        mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
2979
2980        mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15);
2981
2982        mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5);
2983
2984        mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0);
2985
2986        mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12);
2987
2988        mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8);
2989
2990        mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0);
2991
2992        mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8);
2993
2994        mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0);
2995
2996        mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8);
2997
2998        mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4);
2999
3000        mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8);
3001
3002        mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12);
3003
3004        mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12);
3005
3006        mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13);
3007
3008        mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15);
3009
3010        write_radio_reg(pi, RADIO_2064_REG025, 0xC);
3011
3012        mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3);
3013
3014        mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2);
3015
3016        mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2);
3017
3018        mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12);
3019
3020        val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
3021        tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
3022        tab.tbl_width = 16;
3023        tab.tbl_len = 1;
3024        tab.tbl_ptr = &val;
3025        tab.tbl_offset = 6;
3026        wlc_lcnphy_write_table(pi, &tab);
3027        if (mode == TEMPSENSE) {
3028                mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
3029
3030                mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12);
3031
3032                auxpga_vmidcourse = 8;
3033                auxpga_vmidfine = 0x4;
3034                auxpga_gain = 2;
3035                mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5);
3036        } else {
3037                mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3);
3038
3039                mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12);
3040
3041                auxpga_vmidcourse = 7;
3042                auxpga_vmidfine = 0xa;
3043                auxpga_gain = 2;
3044        }
3045        auxpga_vmid =
3046                (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
3047        mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
3048
3049        mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
3050
3051        mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1);
3052
3053        mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12);
3054
3055        mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5);
3056
3057        write_radio_reg(pi, RADIO_2064_REG112, 0x6);
3058
3059        wlc_phy_do_dummy_tx(pi, true, OFF);
3060        if (!tempsense_done(pi))
3061                udelay(10);
3062
3063        write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007);
3064        write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF);
3065        write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F);
3066        write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005);
3067        write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025);
3068        write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112);
3069        for (i = 0; i < 14; i++)
3070                write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]);
3071        wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index);
3072
3073        write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn);
3074        if (!suspend)
3075                wlapi_enable_mac(pi->sh->physhim);
3076        udelay(999);
3077}
3078
3079static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
3080{
3081        struct lcnphy_txgains tx_gains;
3082        u8 bbmult;
3083        struct phytbl_info tab;
3084        s32 a1, b0, b1;
3085        s32 tssi, pwr, maxtargetpwr, mintargetpwr;
3086        bool suspend;
3087        struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
3088
3089        suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
3090                         MCTL_EN_MAC));
3091        if (!suspend)
3092                wlapi_suspend_mac_and_wait(pi->sh->physhim);
3093
3094        if (!pi->hwpwrctrl_capable) {
3095                if (CHSPEC_IS2G(pi->radio_chanspec)) {
3096                        tx_gains.gm_gain = 4;
3097                        tx_gains.pga_gain = 12;
3098                        tx_gains.pad_gain = 12;
3099                        tx_gains.dac_gain = 0;
3100
3101                        bbmult = 150;
3102                } else {
3103                        tx_gains.gm_gain = 7;
3104                        tx_gains.pga_gain = 15;
3105                        tx_gains.pad_gain = 14;
3106                        tx_gains.dac_gain = 0;
3107
3108                        bbmult = 150;
3109                }
3110                wlc_lcnphy_set_tx_gain(pi, &tx_gains);
3111                wlc_lcnphy_set_bbmult(pi, bbmult);
3112                wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
3113        } else {
3114
3115                wlc_lcnphy_idle_tssi_est(ppi);
3116
3117                wlc_lcnphy_clear_tx_power_offsets(pi);
3118
3119                b0 = pi->txpa_2g[0];
3120                b1 = pi->txpa_2g[1];
3121                a1 = pi->txpa_2g[2];
3122                maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
3123                mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
3124
3125                tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3126                tab.tbl_width = 32;
3127                tab.tbl_ptr = &pwr;
3128                tab.tbl_len = 1;
3129                tab.tbl_offset = 0;
3130                for (tssi = 0; tssi < 128; tssi++) {
3131                        pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
3132
3133                        pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
3134                        wlc_lcnphy_write_table(pi, &tab);
3135                        tab.tbl_offset++;
3136                }
3137                mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0);
3138                mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0);
3139                mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8);
3140                mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4);
3141                mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);
3142
3143                mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
3144
3145                write_phy_reg(pi, 0x4a8, 10);
3146
3147                wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR);
3148
3149                wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
3150        }
3151        if (!suspend)
3152                wlapi_enable_mac(pi->sh->physhim);
3153}
3154
3155static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain)
3156{
3157        mod_phy_reg(pi, 0x4fb,
3158                    LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK,
3159                    gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT);
3160        mod_phy_reg(pi, 0x4fd,
3161                    LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK,
3162                    gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT);
3163}
3164
3165void
3166wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,
3167                          u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0)
3168{
3169        *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089));
3170        *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A));
3171        *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B));
3172        *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
3173}
3174
3175void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)
3176{
3177        struct phytbl_info tab;
3178        u16 iqcc[2];
3179
3180        iqcc[0] = a;
3181        iqcc[1] = b;
3182
3183        tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3184        tab.tbl_width = 16;
3185        tab.tbl_ptr = iqcc;
3186        tab.tbl_len = 2;
3187        tab.tbl_offset = 80;
3188        wlc_lcnphy_write_table(pi, &tab);
3189}
3190
3191void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq)
3192{
3193        struct phytbl_info tab;
3194
3195        tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL;
3196        tab.tbl_width = 16;
3197        tab.tbl_ptr = &didq;
3198        tab.tbl_len = 1;
3199        tab.tbl_offset = 85;
3200        wlc_lcnphy_write_table(pi, &tab);
3201}
3202
3203void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)
3204{
3205        struct phytbl_info tab;
3206        u16 a, b;
3207        u8 bb_mult;
3208        u32 bbmultiqcomp, txgain, locoeffs, rfpower;
3209        struct lcnphy_txgains gains;
3210        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3211
3212        pi_lcn->lcnphy_tx_power_idx_override = (s8) index;
3213        pi_lcn->lcnphy_current_index = (u8) index;
3214
3215        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3216        tab.tbl_width = 32;
3217        tab.tbl_len = 1;
3218
3219        wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3220
3221        tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
3222        tab.tbl_ptr = &bbmultiqcomp;
3223        wlc_lcnphy_read_table(pi, &tab);
3224
3225        tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
3226        tab.tbl_width = 32;
3227        tab.tbl_ptr = &txgain;
3228        wlc_lcnphy_read_table(pi, &tab);
3229
3230        gains.gm_gain = (u16) (txgain & 0xff);
3231        gains.pga_gain = (u16) (txgain >> 8) & 0xff;
3232        gains.pad_gain = (u16) (txgain >> 16) & 0xff;
3233        gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07;
3234        wlc_lcnphy_set_tx_gain(pi, &gains);
3235        wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f);
3236
3237        bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff);
3238        wlc_lcnphy_set_bbmult(pi, bb_mult);
3239
3240        wlc_lcnphy_enable_tx_gain_override(pi);
3241
3242        if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
3243
3244                a = (u16) ((bbmultiqcomp >> 10) & 0x3ff);
3245                b = (u16) (bbmultiqcomp & 0x3ff);
3246                wlc_lcnphy_set_tx_iqcc(pi, a, b);
3247
3248                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index;
3249                tab.tbl_ptr = &locoeffs;
3250                wlc_lcnphy_read_table(pi, &tab);
3251
3252                wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs);
3253
3254                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
3255                tab.tbl_ptr = &rfpower;
3256                wlc_lcnphy_read_table(pi, &tab);
3257                mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0);
3258
3259        }
3260}
3261
3262static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
3263{
3264        u32 j;
3265        struct phytbl_info tab;
3266        u32 temp_offset[128];
3267        tab.tbl_ptr = temp_offset;
3268        tab.tbl_len = 128;
3269        tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL;
3270        tab.tbl_width = 32;
3271        tab.tbl_offset = 0;
3272
3273        memset(temp_offset, 0, sizeof(temp_offset));
3274        for (j = 1; j < 128; j += 2)
3275                temp_offset[j] = 0x80000;
3276
3277        wlc_lcnphy_write_table(pi, &tab);
3278        return;
3279}
3280
3281void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
3282{
3283        if (!bEnable) {
3284
3285                and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4)));
3286
3287                mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1);
3288
3289                and_phy_reg(pi, 0x44c,
3290                            ~(u16) ((0x1 << 3) |
3291                                    (0x1 << 5) |
3292                                    (0x1 << 12) |
3293                                    (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3294
3295                and_phy_reg(pi, 0x44d,
3296                            ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
3297                mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2);
3298
3299                mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0));
3300
3301                and_phy_reg(pi, 0x4f9,
3302                            ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3303
3304                and_phy_reg(pi, 0x4fa,
3305                            ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
3306        } else {
3307
3308                mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
3309                mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
3310
3311                mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4);
3312                mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6);
3313
3314                mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
3315                mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
3316
3317                wlc_lcnphy_set_trsw_override(pi, true, false);
3318
3319                mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2);
3320                mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2);
3321
3322                if (CHSPEC_IS2G(pi->radio_chanspec)) {
3323
3324                        mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3325                        mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3);
3326
3327                        mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3328                        mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5);
3329
3330                        mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3331                        mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1);
3332
3333                        mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3334                        mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2);
3335
3336                        mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3337                        mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0);
3338                } else {
3339
3340                        mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3);
3341                        mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3);
3342
3343                        mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5);
3344                        mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5);
3345
3346                        mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1);
3347                        mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1);
3348
3349                        mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2);
3350                        mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2);
3351
3352                        mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
3353                        mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
3354                }
3355        }
3356}
3357
3358static void
3359wlc_lcnphy_run_samples(struct brcms_phy *pi,
3360                       u16 num_samps,
3361                       u16 num_loops, u16 wait, bool iqcalmode)
3362{
3363
3364        or_phy_reg(pi, 0x6da, 0x8080);
3365
3366        mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0);
3367        if (num_loops != 0xffff)
3368                num_loops--;
3369        mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0);
3370
3371        mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0);
3372
3373        if (iqcalmode) {
3374
3375                and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15));
3376                or_phy_reg(pi, 0x453, (0x1 << 15));
3377        } else {
3378                write_phy_reg(pi, 0x63f, 1);
3379                wlc_lcnphy_tx_pu(pi, 1);
3380        }
3381
3382        or_radio_reg(pi, RADIO_2064_REG112, 0x6);
3383}
3384
3385void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
3386{
3387
3388        u8 phybw40;
3389        phybw40 = CHSPEC_IS40(pi->radio_chanspec);
3390
3391        if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
3392                mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3393                mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3394        } else {
3395                mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3396                mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3397        }
3398
3399        if (phybw40 == 0) {
3400                mod_phy_reg((pi), 0x410,
3401                            (0x1 << 6) |
3402                            (0x1 << 5),
3403                            ((CHSPEC_IS2G(
3404                                      pi->radio_chanspec)) ? (!mode) : 0) <<
3405                            6 | (!mode) << 5);
3406                mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3407        }
3408}
3409
3410void
3411wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3412                         bool iqcalmode)
3413{
3414        u8 phy_bw;
3415        u16 num_samps, t, k;
3416        u32 bw;
3417        s32 theta = 0, rot = 0;
3418        struct cordic_iq tone_samp;
3419        u32 data_buf[64];
3420        u16 i_samp, q_samp;
3421        struct phytbl_info tab;
3422        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3423
3424        pi->phy_tx_tone_freq = f_kHz;
3425
3426        wlc_lcnphy_deaf_mode(pi, true);
3427
3428        phy_bw = 40;
3429        if (pi_lcn->lcnphy_spurmod) {
3430                write_phy_reg(pi, 0x942, 0x2);
3431                write_phy_reg(pi, 0x93b, 0x0);
3432                write_phy_reg(pi, 0x93c, 0x0);
3433                wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3434        }
3435
3436        if (f_kHz) {
3437                k = 1;
3438                do {
3439                        bw = phy_bw * 1000 * k;
3440                        num_samps = bw / abs(f_kHz);
3441                        k++;
3442                } while ((num_samps * (u32) (abs(f_kHz))) != bw);
3443        } else
3444                num_samps = 2;
3445
3446        rot = ((f_kHz * 36) / phy_bw) / 100;
3447        theta = 0;
3448
3449        for (t = 0; t < num_samps; t++) {
3450
3451                tone_samp = cordic_calc_iq(theta);
3452
3453                theta += rot;
3454
3455                i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
3456                q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
3457                data_buf[t] = (i_samp << 10) | q_samp;
3458        }
3459
3460        mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3461
3462        mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3463
3464        tab.tbl_ptr = data_buf;
3465        tab.tbl_len = num_samps;
3466        tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3467        tab.tbl_offset = 0;
3468        tab.tbl_width = 32;
3469        wlc_lcnphy_write_table(pi, &tab);
3470
3471        wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3472}
3473
3474void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3475{
3476        s16 playback_status;
3477        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3478
3479        pi->phy_tx_tone_freq = 0;
3480        if (pi_lcn->lcnphy_spurmod) {
3481                write_phy_reg(pi, 0x942, 0x7);
3482                write_phy_reg(pi, 0x93b, 0x2017);
3483                write_phy_reg(pi, 0x93c, 0x27c5);
3484                wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3485        }
3486
3487        playback_status = read_phy_reg(pi, 0x644);
3488        if (playback_status & (0x1 << 0)) {
3489                wlc_lcnphy_tx_pu(pi, 0);
3490                mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3491        } else if (playback_status & (0x1 << 1))
3492                mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3493
3494        mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3495
3496        mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3497
3498        mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3499
3500        and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3501
3502        wlc_lcnphy_deaf_mode(pi, false);
3503}
3504
3505static void
3506wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3507{
3508        u16 di0dq0;
3509        u16 x, y, data_rf;
3510        int k;
3511        switch (cal_type) {
3512        case 0:
3513                wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3514                break;
3515        case 2:
3516                di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3517                wlc_lcnphy_set_tx_locc(pi, di0dq0);
3518                break;
3519        case 3:
3520                k = wlc_lcnphy_calc_floor(coeff_x, 0);
3521                y = 8 + k;
3522                k = wlc_lcnphy_calc_floor(coeff_x, 1);
3523                x = 8 - k;
3524                data_rf = (x * 16 + y);
3525                write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3526                k = wlc_lcnphy_calc_floor(coeff_y, 0);
3527                y = 8 + k;
3528                k = wlc_lcnphy_calc_floor(coeff_y, 1);
3529                x = 8 - k;
3530                data_rf = (x * 16 + y);
3531                write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3532                break;
3533        case 4:
3534                k = wlc_lcnphy_calc_floor(coeff_x, 0);
3535                y = 8 + k;
3536                k = wlc_lcnphy_calc_floor(coeff_x, 1);
3537                x = 8 - k;
3538                data_rf = (x * 16 + y);
3539                write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3540                k = wlc_lcnphy_calc_floor(coeff_y, 0);
3541                y = 8 + k;
3542                k = wlc_lcnphy_calc_floor(coeff_y, 1);
3543                x = 8 - k;
3544                data_rf = (x * 16 + y);
3545                write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3546                break;
3547        }
3548}
3549
3550static struct lcnphy_unsign16_struct
3551wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3552{
3553        u16 a, b, didq;
3554        u8 di0, dq0, ei, eq, fi, fq;
3555        struct lcnphy_unsign16_struct cc;
3556        cc.re = 0;
3557        cc.im = 0;
3558        switch (cal_type) {
3559        case 0:
3560                wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3561                cc.re = a;
3562                cc.im = b;
3563                break;
3564        case 2:
3565                didq = wlc_lcnphy_get_tx_locc(pi);
3566                di0 = (((didq & 0xff00) << 16) >> 24);
3567                dq0 = (((didq & 0x00ff) << 24) >> 24);
3568                cc.re = (u16) di0;
3569                cc.im = (u16) dq0;
3570                break;
3571        case 3:
3572                wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3573                cc.re = (u16) ei;
3574                cc.im = (u16) eq;
3575                break;
3576        case 4:
3577                wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3578                cc.re = (u16) fi;
3579                cc.im = (u16) fq;
3580                break;
3581        }
3582        return cc;
3583}
3584
3585static void
3586wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3587                    s16 *ptr, int mode)
3588{
3589        u32 curval1, curval2, stpptr, curptr, strptr, val;
3590        u16 sslpnCalibClkEnCtrl, timer;
3591        u16 old_sslpnCalibClkEnCtrl;
3592        s16 imag, real;
3593        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3594
3595        timer = 0;
3596        old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3597
3598        curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
3599        ptr[130] = 0;
3600        bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3601                     ((1 << 6) | curval1));
3602
3603        bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3604        bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
3605        udelay(20);
3606        curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3607        bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3608                     curval2 | 0x30);
3609
3610        write_phy_reg(pi, 0x555, 0x0);
3611        write_phy_reg(pi, 0x5a6, 0x5);
3612
3613        write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3614        write_phy_reg(pi, 0x5cf, 3);
3615        write_phy_reg(pi, 0x5a5, 0x3);
3616        write_phy_reg(pi, 0x583, 0x0);
3617        write_phy_reg(pi, 0x584, 0x0);
3618        write_phy_reg(pi, 0x585, 0x0fff);
3619        write_phy_reg(pi, 0x586, 0x0000);
3620
3621        write_phy_reg(pi, 0x580, 0x4501);
3622
3623        sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3624        write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3625        stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3626        curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3627        do {
3628                udelay(10);
3629                curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3630                timer++;
3631        } while ((curptr != stpptr) && (timer < 500));
3632
3633        bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
3634        strptr = 0x7E00;
3635        bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
3636        while (strptr < 0x8000) {
3637                val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
3638                imag = ((val >> 16) & 0x3ff);
3639                real = ((val) & 0x3ff);
3640                if (imag > 511)
3641                        imag -= 1024;
3642
3643                if (real > 511)
3644                        real -= 1024;
3645
3646                if (pi_lcn->lcnphy_iqcal_swp_dis)
3647                        ptr[(strptr - 0x7E00) / 4] = real;
3648                else
3649                        ptr[(strptr - 0x7E00) / 4] = imag;
3650
3651                if (clip_detect_algo) {
3652                        if (imag > thresh || imag < -thresh) {
3653                                strptr = 0x8000;
3654                                ptr[130] = 1;
3655                        }
3656                }
3657
3658                strptr += 4;
3659        }
3660
3661        write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3662        bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3663        bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
3664}
3665
3666static void
3667wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3668              int step_size_lg2)
3669{
3670        const struct lcnphy_spb_tone *phy_c1;
3671        struct lcnphy_spb_tone phy_c2;
3672        struct lcnphy_unsign16_struct phy_c3;
3673        int phy_c4, phy_c5, k, l, j, phy_c6;
3674        u16 phy_c7, phy_c8, phy_c9;
3675        s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3676        s16 *ptr, phy_c17;
3677        s32 phy_c18, phy_c19;
3678        u32 phy_c20, phy_c21;
3679        bool phy_c22, phy_c23, phy_c24, phy_c25;
3680        u16 phy_c26, phy_c27;
3681        u16 phy_c28, phy_c29, phy_c30;
3682        u16 phy_c31;
3683        u16 *phy_c32;
3684        phy_c21 = 0;
3685        phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3686        ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
3687        if (NULL == ptr)
3688                return;
3689
3690        phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
3691        if (NULL == phy_c32) {
3692                kfree(ptr);
3693                return;
3694        }
3695        phy_c26 = read_phy_reg(pi, 0x6da);
3696        phy_c27 = read_phy_reg(pi, 0x6db);
3697        phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3698        write_phy_reg(pi, 0x93d, 0xC0);
3699
3700        wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3701        write_phy_reg(pi, 0x6da, 0xffff);
3702        or_phy_reg(pi, 0x6db, 0x3);
3703
3704        wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3705        udelay(500);
3706        phy_c28 = read_phy_reg(pi, 0x938);
3707        phy_c29 = read_phy_reg(pi, 0x4d7);
3708        phy_c30 = read_phy_reg(pi, 0x4d8);
3709        or_phy_reg(pi, 0x938, 0x1 << 2);
3710        or_phy_reg(pi, 0x4d7, 0x1 << 2);
3711        or_phy_reg(pi, 0x4d7, 0x1 << 3);
3712        mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3713        or_phy_reg(pi, 0x4d8, 1 << 0);
3714        or_phy_reg(pi, 0x4d8, 1 << 1);
3715        mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3716        mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3717        phy_c1 = &lcnphy_spb_tone_3750[0];
3718        phy_c4 = 32;
3719
3720        if (num_levels == 0) {
3721                if (cal_type != 0)
3722                        num_levels = 4;
3723                else
3724                        num_levels = 9;
3725        }
3726        if (step_size_lg2 == 0) {
3727                if (cal_type != 0)
3728                        step_size_lg2 = 3;
3729                else
3730                        step_size_lg2 = 8;
3731        }
3732
3733        phy_c7 = (1 << step_size_lg2);
3734        phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3735        phy_c15 = (s16) phy_c3.re;
3736        phy_c16 = (s16) phy_c3.im;
3737        if (cal_type == 2) {
3738                if (phy_c3.re > 127)
3739                        phy_c15 = phy_c3.re - 256;
3740                if (phy_c3.im > 127)
3741                        phy_c16 = phy_c3.im - 256;
3742        }
3743        wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3744        udelay(20);
3745        for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3746                phy_c23 = true;
3747                phy_c22 = false;
3748                switch (cal_type) {
3749                case 0:
3750                        phy_c10 = 511;
3751                        break;
3752                case 2:
3753                        phy_c10 = 127;
3754                        break;
3755                case 3:
3756                        phy_c10 = 15;
3757                        break;
3758                case 4:
3759                        phy_c10 = 15;
3760                        break;
3761                }
3762
3763                phy_c9 = read_phy_reg(pi, 0x93d);
3764                phy_c9 = 2 * phy_c9;
3765                phy_c24 = false;
3766                phy_c5 = 7;
3767                phy_c25 = true;
3768                while (1) {
3769                        write_radio_reg(pi, RADIO_2064_REG026,
3770                                        (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3771                        udelay(50);
3772                        phy_c22 = false;
3773                        ptr[130] = 0;
3774                        wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3775                        if (ptr[130] == 1)
3776                                phy_c22 = true;
3777                        if (phy_c22)
3778                                phy_c5 -= 1;
3779                        if ((phy_c22 != phy_c24) && (!phy_c25))
3780                                break;
3781                        if (!phy_c22)
3782                                phy_c5 += 1;
3783                        if (phy_c5 <= 0 || phy_c5 >= 7)
3784                                break;
3785                        phy_c24 = phy_c22;
3786                        phy_c25 = false;
3787                }
3788
3789                if (phy_c5 < 0)
3790                        phy_c5 = 0;
3791                else if (phy_c5 > 7)
3792                        phy_c5 = 7;
3793
3794                for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3795                        for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3796                                phy_c11 = phy_c15 + k;
3797                                phy_c12 = phy_c16 + l;
3798
3799                                if (phy_c11 < -phy_c10)
3800                                        phy_c11 = -phy_c10;
3801                                else if (phy_c11 > phy_c10)
3802                                        phy_c11 = phy_c10;
3803                                if (phy_c12 < -phy_c10)
3804                                        phy_c12 = -phy_c10;
3805                                else if (phy_c12 > phy_c10)
3806                                        phy_c12 = phy_c10;
3807                                wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3808                                                  phy_c12);
3809                                udelay(20);
3810                                wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3811
3812                                phy_c18 = 0;
3813                                phy_c19 = 0;
3814                                for (j = 0; j < 128; j++) {
3815                                        if (cal_type != 0)
3816                                                phy_c6 = j % phy_c4;
3817                                        else
3818                                                phy_c6 = (2 * j) % phy_c4;
3819
3820                                        phy_c2.re = phy_c1[phy_c6].re;
3821                                        phy_c2.im = phy_c1[phy_c6].im;
3822                                        phy_c17 = ptr[j];
3823                                        phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3824                                        phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3825                                }
3826
3827                                phy_c18 = phy_c18 >> 10;
3828                                phy_c19 = phy_c19 >> 10;
3829                                phy_c20 = ((phy_c18 * phy_c18) +
3830                                           (phy_c19 * phy_c19));
3831
3832                                if (phy_c23 || phy_c20 < phy_c21) {
3833                                        phy_c21 = phy_c20;
3834                                        phy_c13 = phy_c11;
3835                                        phy_c14 = phy_c12;
3836                                }
3837                                phy_c23 = false;
3838                        }
3839                }
3840                phy_c23 = true;
3841                phy_c15 = phy_c13;
3842                phy_c16 = phy_c14;
3843                phy_c7 = phy_c7 >> 1;
3844                wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3845                udelay(20);
3846        }
3847        goto cleanup;
3848cleanup:
3849        wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3850        wlc_lcnphy_stop_tx_tone(pi);
3851        write_phy_reg(pi, 0x6da, phy_c26);
3852        write_phy_reg(pi, 0x6db, phy_c27);
3853        write_phy_reg(pi, 0x938, phy_c28);
3854        write_phy_reg(pi, 0x4d7, phy_c29);
3855        write_phy_reg(pi, 0x4d8, phy_c30);
3856        write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3857
3858        kfree(phy_c32);
3859        kfree(ptr);
3860}
3861
3862void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3863{
3864        u16 iqcc[2];
3865        struct phytbl_info tab;
3866
3867        tab.tbl_ptr = iqcc;
3868        tab.tbl_len = 2;
3869        tab.tbl_id = 0;
3870        tab.tbl_offset = 80;
3871        tab.tbl_width = 16;
3872        wlc_lcnphy_read_table(pi, &tab);
3873
3874        *a = iqcc[0];
3875        *b = iqcc[1];
3876}
3877
3878static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3879{
3880        struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3881
3882        wlc_lcnphy_set_cc(pi, 0, 0, 0);
3883        wlc_lcnphy_set_cc(pi, 2, 0, 0);
3884        wlc_lcnphy_set_cc(pi, 3, 0, 0);
3885        wlc_lcnphy_set_cc(pi, 4, 0, 0);
3886
3887        wlc_lcnphy_a1(pi, 4, 0, 0);
3888        wlc_lcnphy_a1(pi, 3, 0, 0);
3889        wlc_lcnphy_a1(pi, 2, 3, 2);
3890        wlc_lcnphy_a1(pi, 0, 5, 8);
3891        wlc_lcnphy_a1(pi, 2, 2, 1);
3892        wlc_lcnphy_a1(pi, 0, 4, 3);
3893
3894        iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3895        locc2 = wlc_lcnphy_get_cc(pi, 2);
3896        locc3 = wlc_lcnphy_get_cc(pi, 3);
3897        locc4 = wlc_lcnphy_get_cc(pi, 4);
3898}
3899
3900u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3901{
3902        struct phytbl_info tab;
3903        u16 didq;
3904
3905        tab.tbl_id = 0;
3906        tab.tbl_width = 16;
3907        tab.tbl_ptr = &didq;
3908        tab.tbl_len = 1;
3909        tab.tbl_offset = 85;
3910        wlc_lcnphy_read_table(pi, &tab);
3911
3912        return didq;
3913}
3914
3915static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3916{
3917
3918        struct lcnphy_txgains target_gains, old_gains;
3919        u8 save_bb_mult;
3920        u16 a, b, didq, save_pa_gain = 0;
3921        uint idx, SAVE_txpwrindex = 0xFF;
3922        u32 val;
3923        u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3924        struct phytbl_info tab;
3925        u8 ei0, eq0, fi0, fq0;
3926        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3927
3928        wlc_lcnphy_get_tx_gain(pi, &old_gains);
3929        save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3930
3931        save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3932
3933        if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3934                SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3935
3936        wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3937
3938        target_gains.gm_gain = 7;
3939        target_gains.pga_gain = 0;
3940        target_gains.pad_gain = 21;
3941        target_gains.dac_gain = 0;
3942        wlc_lcnphy_set_tx_gain(pi, &target_gains);
3943
3944        if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3945
3946                wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3947
3948                wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3949                                       (pi_lcn->
3950                                        lcnphy_recal ? LCNPHY_CAL_RECAL :
3951                                        LCNPHY_CAL_FULL), false);
3952        } else {
3953                wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3954                wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3955        }
3956
3957        wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3958        if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3959                if (CHSPEC_IS5G(pi->radio_chanspec)) {
3960                        target_gains.gm_gain = 255;
3961                        target_gains.pga_gain = 255;
3962                        target_gains.pad_gain = 0xf0;
3963                        target_gains.dac_gain = 0;
3964                } else {
3965                        target_gains.gm_gain = 7;
3966                        target_gains.pga_gain = 45;
3967                        target_gains.pad_gain = 186;
3968                        target_gains.dac_gain = 0;
3969                }
3970
3971                if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3972                    || pi_lcn->lcnphy_hw_iqcal_en) {
3973
3974                        target_gains.pga_gain = 0;
3975                        target_gains.pad_gain = 30;
3976                        wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3977                        wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3978                                               LCNPHY_CAL_FULL, false);
3979                } else {
3980                        wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3981                }
3982        }
3983
3984        wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3985
3986        didq = wlc_lcnphy_get_tx_locc(pi);
3987
3988        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3989        tab.tbl_width = 32;
3990        tab.tbl_ptr = &val;
3991
3992        tab.tbl_len = 1;
3993        tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3994
3995        for (idx = 0; idx < 128; idx++) {
3996                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3997
3998                wlc_lcnphy_read_table(pi, &tab);
3999                val = (val & 0xfff00000) |
4000                      ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
4001                wlc_lcnphy_write_table(pi, &tab);
4002
4003                val = didq;
4004                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
4005                wlc_lcnphy_write_table(pi, &tab);
4006        }
4007
4008        pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
4009        pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
4010        pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
4011        pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
4012        pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
4013        pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
4014        pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
4015
4016        wlc_lcnphy_set_bbmult(pi, save_bb_mult);
4017        wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
4018        wlc_lcnphy_set_tx_gain(pi, &old_gains);
4019
4020        if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
4021                wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4022        else
4023                wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
4024}
4025
4026s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
4027{
4028        u16 tempsenseval1, tempsenseval2;
4029        s16 avg = 0;
4030        bool suspend = false;
4031
4032        if (mode == 1) {
4033                suspend = (0 == (bcma_read32(pi->d11core,
4034                                             D11REGOFFS(maccontrol)) &
4035                                 MCTL_EN_MAC));
4036                if (!suspend)
4037                        wlapi_suspend_mac_and_wait(pi->sh->physhim);
4038                wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4039        }
4040        tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4041        tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4042
4043        if (tempsenseval1 > 255)
4044                avg = (s16) (tempsenseval1 - 512);
4045        else
4046                avg = (s16) tempsenseval1;
4047
4048        if (tempsenseval2 > 255)
4049                avg += (s16) (tempsenseval2 - 512);
4050        else
4051                avg += (s16) tempsenseval2;
4052
4053        avg /= 2;
4054
4055        if (mode == 1) {
4056
4057                mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4058
4059                udelay(100);
4060                mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4061
4062                if (!suspend)
4063                        wlapi_enable_mac(pi->sh->physhim);
4064        }
4065        return avg;
4066}
4067
4068u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
4069{
4070        u16 tempsenseval1, tempsenseval2;
4071        s32 avg = 0;
4072        bool suspend = false;
4073        u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4074        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4075
4076        if (mode == 1) {
4077                suspend = (0 == (bcma_read32(pi->d11core,
4078                                             D11REGOFFS(maccontrol)) &
4079                                 MCTL_EN_MAC));
4080                if (!suspend)
4081                        wlapi_suspend_mac_and_wait(pi->sh->physhim);
4082                wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4083        }
4084        tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4085        tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4086
4087        if (tempsenseval1 > 255)
4088                avg = (int)(tempsenseval1 - 512);
4089        else
4090                avg = (int)tempsenseval1;
4091
4092        if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4093                if (tempsenseval2 > 255)
4094                        avg = (int)(avg - tempsenseval2 + 512);
4095                else
4096                        avg = (int)(avg - tempsenseval2);
4097        } else {
4098                if (tempsenseval2 > 255)
4099                        avg = (int)(avg + tempsenseval2 - 512);
4100                else
4101                        avg = (int)(avg + tempsenseval2);
4102                avg = avg / 2;
4103        }
4104        if (avg < 0)
4105                avg = avg + 512;
4106
4107        if (pi_lcn->lcnphy_tempsense_option == 2)
4108                avg = tempsenseval1;
4109
4110        if (mode)
4111                wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4112
4113        if (mode == 1) {
4114
4115                mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4116
4117                udelay(100);
4118                mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4119
4120                if (!suspend)
4121                        wlapi_enable_mac(pi->sh->physhim);
4122        }
4123        return (u16) avg;
4124}
4125
4126s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4127{
4128        s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4129        degree =
4130                ((degree <<
4131                  10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4132                / LCN_TEMPSENSE_DEN;
4133        return (s8) degree;
4134}
4135
4136s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4137{
4138        u16 vbatsenseval;
4139        s32 avg = 0;
4140        bool suspend = false;
4141
4142        if (mode == 1) {
4143                suspend = (0 == (bcma_read32(pi->d11core,
4144                                             D11REGOFFS(maccontrol)) &
4145                                 MCTL_EN_MAC));
4146                if (!suspend)
4147                        wlapi_suspend_mac_and_wait(pi->sh->physhim);
4148                wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4149        }
4150
4151        vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4152
4153        if (vbatsenseval > 255)
4154                avg = (s32) (vbatsenseval - 512);
4155        else
4156                avg = (s32) vbatsenseval;
4157
4158        avg =   (avg * LCN_VBAT_SCALE_NOM +
4159                 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4160
4161        if (mode == 1) {
4162                if (!suspend)
4163                        wlapi_enable_mac(pi->sh->physhim);
4164        }
4165        return (s8) avg;
4166}
4167
4168static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4169{
4170        u8 phybw40;
4171        phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4172
4173        mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4174
4175        if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4176            (mode == AFE_CLK_INIT_MODE_TXRX2X))
4177                write_phy_reg(pi, 0x6d0, 0x7);
4178
4179        wlc_lcnphy_toggle_afe_pwdn(pi);
4180}
4181
4182static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4183{
4184}
4185
4186static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4187{
4188        bool suspend;
4189        s8 index;
4190        u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4191        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4192        suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4193                         MCTL_EN_MAC));
4194        if (!suspend)
4195                wlapi_suspend_mac_and_wait(pi->sh->physhim);
4196        wlc_lcnphy_deaf_mode(pi, true);
4197        pi->phy_lastcal = pi->sh->now;
4198        pi->phy_forcecal = false;
4199        index = pi_lcn->lcnphy_current_index;
4200
4201        wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4202
4203        wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4204        wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4205        wlc_lcnphy_deaf_mode(pi, false);
4206        if (!suspend)
4207                wlapi_enable_mac(pi->sh->physhim);
4208
4209}
4210
4211static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4212{
4213        bool suspend, full_cal;
4214        const struct lcnphy_rx_iqcomp *rx_iqcomp;
4215        int rx_iqcomp_sz;
4216        u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4217        s8 index;
4218        struct phytbl_info tab;
4219        s32 a1, b0, b1;
4220        s32 tssi, pwr, maxtargetpwr, mintargetpwr;
4221        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4222
4223        pi->phy_lastcal = pi->sh->now;
4224        pi->phy_forcecal = false;
4225        full_cal =
4226                (pi_lcn->lcnphy_full_cal_channel !=
4227                 CHSPEC_CHANNEL(pi->radio_chanspec));
4228        pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4229        index = pi_lcn->lcnphy_current_index;
4230
4231        suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4232                         MCTL_EN_MAC));
4233        if (!suspend) {
4234                wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4235                wlapi_suspend_mac_and_wait(pi->sh->physhim);
4236        }
4237
4238        wlc_lcnphy_deaf_mode(pi, true);
4239
4240        wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4241
4242        rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
4243        rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
4244
4245        if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4246                wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4247        else
4248                wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4249
4250        if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4251
4252                wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4253
4254                b0 = pi->txpa_2g[0];
4255                b1 = pi->txpa_2g[1];
4256                a1 = pi->txpa_2g[2];
4257                maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
4258                mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4259
4260                tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4261                tab.tbl_width = 32;
4262                tab.tbl_ptr = &pwr;
4263                tab.tbl_len = 1;
4264                tab.tbl_offset = 0;
4265                for (tssi = 0; tssi < 128; tssi++) {
4266                        pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4267                        pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4268                        wlc_lcnphy_write_table(pi, &tab);
4269                        tab.tbl_offset++;
4270                }
4271        }
4272
4273        wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4274        wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4275        wlc_lcnphy_deaf_mode(pi, false);
4276        if (!suspend)
4277                wlapi_enable_mac(pi->sh->physhim);
4278}
4279
4280void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4281{
4282        u16 temp_new;
4283        int temp1, temp2, temp_diff;
4284        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4285
4286        switch (mode) {
4287        case PHY_PERICAL_CHAN:
4288                break;
4289        case PHY_FULLCAL:
4290                wlc_lcnphy_periodic_cal(pi);
4291                break;
4292        case PHY_PERICAL_PHYINIT:
4293                wlc_lcnphy_periodic_cal(pi);
4294                break;
4295        case PHY_PERICAL_WATCHDOG:
4296                if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4297                        temp_new = wlc_lcnphy_tempsense(pi, 0);
4298                        temp1 = LCNPHY_TEMPSENSE(temp_new);
4299                        temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4300                        temp_diff = temp1 - temp2;
4301                        if ((pi_lcn->lcnphy_cal_counter > 90) ||
4302                            (temp_diff > 60) || (temp_diff < -60)) {
4303                                wlc_lcnphy_glacial_timer_based_cal(pi);
4304                                wlc_2064_vco_cal(pi);
4305                                pi_lcn->lcnphy_cal_temper = temp_new;
4306                                pi_lcn->lcnphy_cal_counter = 0;
4307                        } else
4308                                pi_lcn->lcnphy_cal_counter++;
4309                }
4310                break;
4311        case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4312                if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4313                        wlc_lcnphy_tx_power_adjustment(
4314                                (struct brcms_phy_pub *) pi);
4315                break;
4316        }
4317}
4318
4319void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4320{
4321        s8 cck_offset;
4322        u16 status;
4323        status = (read_phy_reg(pi, 0x4ab));
4324        if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4325            (status  & (0x1 << 15))) {
4326                *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4327                                   >> 0) >> 1);
4328
4329                if (wlc_phy_tpc_isenabled_lcnphy(pi))
4330                        cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4331                else
4332                        cck_offset = 0;
4333
4334                *cck_pwr = *ofdm_pwr + cck_offset;
4335        } else {
4336                *cck_pwr = 0;
4337                *ofdm_pwr = 0;
4338        }
4339}
4340
4341void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4342{
4343        return;
4344
4345}
4346
4347void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4348{
4349        s8 index;
4350        u16 index2;
4351        struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
4352        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4353        u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4354        if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4355            SAVE_txpwrctrl) {
4356                index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4357                index2 = (u16) (index * 2);
4358                mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4359
4360                pi_lcn->lcnphy_current_index =
4361                        (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4362        }
4363}
4364
4365static void
4366wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4367                              const struct lcnphy_tx_gain_tbl_entry *gain_table)
4368{
4369        u32 j;
4370        struct phytbl_info tab;
4371        u32 val;
4372        u16 pa_gain;
4373        u16 gm_gain;
4374
4375        if (pi->sh->boardflags & BFL_FEM)
4376                pa_gain = 0x10;
4377        else
4378                pa_gain = 0x60;
4379        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4380        tab.tbl_width = 32;
4381        tab.tbl_len = 1;
4382        tab.tbl_ptr = &val;
4383
4384        /* fixed gm_gain value for iPA */
4385        gm_gain = 15;
4386        for (j = 0; j < 128; j++) {
4387                if (pi->sh->boardflags & BFL_FEM)
4388                        gm_gain = gain_table[j].gm;
4389                val = (((u32) pa_gain << 24) |
4390                       (gain_table[j].pad << 16) |
4391                       (gain_table[j].pga << 8) | gm_gain);
4392
4393                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4394                wlc_lcnphy_write_table(pi, &tab);
4395
4396                val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4397                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4398                wlc_lcnphy_write_table(pi, &tab);
4399        }
4400}
4401
4402static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4403{
4404        struct phytbl_info tab;
4405        u32 val, bbmult, rfgain;
4406        u8 index;
4407        u8 scale_factor = 1;
4408        s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4409
4410        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4411        tab.tbl_width = 32;
4412        tab.tbl_len = 1;
4413
4414        for (index = 0; index < 128; index++) {
4415                tab.tbl_ptr = &bbmult;
4416                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4417                wlc_lcnphy_read_table(pi, &tab);
4418                bbmult = bbmult >> 20;
4419
4420                tab.tbl_ptr = &rfgain;
4421                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4422                wlc_lcnphy_read_table(pi, &tab);
4423
4424                qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4425                qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4426
4427                if (qQ1 < qQ2) {
4428                        temp2 = qm_shr16(temp2, qQ2 - qQ1);
4429                        qQ = qQ1;
4430                } else {
4431                        temp1 = qm_shr16(temp1, qQ1 - qQ2);
4432                        qQ = qQ2;
4433                }
4434                temp = qm_sub16(temp1, temp2);
4435
4436                if (qQ >= 4)
4437                        shift = qQ - 4;
4438                else
4439                        shift = 4 - qQ;
4440
4441                val = (((index << shift) + (5 * temp) +
4442                        (1 << (scale_factor + shift - 3))) >> (scale_factor +
4443                                                               shift - 2));
4444
4445                tab.tbl_ptr = &val;
4446                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4447                wlc_lcnphy_write_table(pi, &tab);
4448        }
4449}
4450
4451static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4452{
4453        or_phy_reg(pi, 0x805, 0x1);
4454
4455        mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4456
4457        mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4458
4459        write_phy_reg(pi, 0x414, 0x1e10);
4460        write_phy_reg(pi, 0x415, 0x0640);
4461
4462        mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4463
4464        or_phy_reg(pi, 0x44a, 0x44);
4465        write_phy_reg(pi, 0x44a, 0x80);
4466        mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4467
4468        mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4469
4470        if (!(pi->sh->boardrev < 0x1204))
4471                mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4472
4473        write_phy_reg(pi, 0x7d6, 0x0902);
4474        mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4475
4476        mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4477
4478        if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4479                mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4480
4481                mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4482
4483                mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4484
4485                mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4486
4487                mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4488
4489                mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4490                mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4491                mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4492                mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4493                mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4494
4495                mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4496
4497                wlc_lcnphy_clear_tx_power_offsets(pi);
4498                mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4499
4500        }
4501}
4502
4503static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4504{
4505        u8 rcal_value;
4506
4507        and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4508
4509        or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4510        or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4511
4512        or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4513        or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4514
4515        or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4516
4517        or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4518        mdelay(5);
4519        SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4520
4521        if (wlc_radio_2064_rcal_done(pi)) {
4522                rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4523                rcal_value = rcal_value & 0x1f;
4524        }
4525
4526        and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4527
4528        and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4529}
4530
4531static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4532{
4533        u8 dflt_rc_cal_val;
4534        u16 flt_val;
4535
4536        dflt_rc_cal_val = 7;
4537        if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4538                dflt_rc_cal_val = 11;
4539        flt_val =
4540                (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4541                (dflt_rc_cal_val);
4542        write_phy_reg(pi, 0x933, flt_val);
4543        write_phy_reg(pi, 0x934, flt_val);
4544        write_phy_reg(pi, 0x935, flt_val);
4545        write_phy_reg(pi, 0x936, flt_val);
4546        write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4547
4548        return;
4549}
4550
4551static void wlc_radio_2064_init(struct brcms_phy *pi)
4552{
4553        u32 i;
4554        const struct lcnphy_radio_regs *lcnphyregs = NULL;
4555
4556        lcnphyregs = lcnphy_radio_regs_2064;
4557
4558        for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4559                if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4560                        write_radio_reg(pi,
4561                                        ((lcnphyregs[i].address & 0x3fff) |
4562                                         RADIO_DEFAULT_CORE),
4563                                        (u16) lcnphyregs[i].init_a);
4564                else if (lcnphyregs[i].do_init_g)
4565                        write_radio_reg(pi,
4566                                        ((lcnphyregs[i].address & 0x3fff) |
4567                                         RADIO_DEFAULT_CORE),
4568                                        (u16) lcnphyregs[i].init_g);
4569
4570        write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4571        write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4572
4573        write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4574
4575        write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4576
4577        if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4578
4579                write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4580                write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4581                write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4582        }
4583
4584        write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4585        write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4586
4587        mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4588
4589        mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4590
4591        mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4592
4593        mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4594
4595        mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4596
4597        write_phy_reg(pi, 0x4ea, 0x4688);
4598
4599        if (pi->sh->boardflags & BFL_FEM)
4600                mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4601        else
4602                mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
4603
4604        mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4605
4606        mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4607
4608        wlc_lcnphy_set_tx_locc(pi, 0);
4609
4610        wlc_lcnphy_rcal(pi);
4611
4612        wlc_lcnphy_rc_cal(pi);
4613
4614        if (!(pi->sh->boardflags & BFL_FEM)) {
4615                write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
4616                write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4617                write_radio_reg(pi, RADIO_2064_REG039, 0xe);
4618        }
4619
4620}
4621
4622static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4623{
4624        wlc_radio_2064_init(pi);
4625}
4626
4627static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4628{
4629        uint idx;
4630        u8 phybw40;
4631        struct phytbl_info tab;
4632        const struct phytbl_info *tb;
4633        u32 val;
4634
4635        phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4636
4637        for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4638                wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4639
4640        if (pi->sh->boardflags & BFL_FEM_BT) {
4641                tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4642                tab.tbl_width = 16;
4643                tab.tbl_ptr = &val;
4644                tab.tbl_len = 1;
4645                val = 100;
4646                tab.tbl_offset = 4;
4647                wlc_lcnphy_write_table(pi, &tab);
4648        }
4649
4650        if (!(pi->sh->boardflags & BFL_FEM)) {
4651                tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4652                tab.tbl_width = 16;
4653                tab.tbl_ptr = &val;
4654                tab.tbl_len = 1;
4655
4656                val = 150;
4657                tab.tbl_offset = 0;
4658                wlc_lcnphy_write_table(pi, &tab);
4659
4660                val = 220;
4661                tab.tbl_offset = 1;
4662                wlc_lcnphy_write_table(pi, &tab);
4663        }
4664
4665        if (CHSPEC_IS2G(pi->radio_chanspec)) {
4666                if (pi->sh->boardflags & BFL_FEM)
4667                        wlc_lcnphy_load_tx_gain_table(
4668                                pi,
4669                                dot11lcnphy_2GHz_extPA_gaintable_rev0);
4670                else
4671                        wlc_lcnphy_load_tx_gain_table(
4672                                pi,
4673                                dot11lcnphy_2GHz_gaintable_rev0);
4674        }
4675
4676        if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4677                int l;
4678
4679                if (CHSPEC_IS2G(pi->radio_chanspec)) {
4680                        l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4681                        if (pi->sh->boardflags & BFL_EXTLNA)
4682                                tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4683                        else
4684                                tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4685                } else {
4686                        l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4687                        if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4688                                tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4689                        else
4690                                tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4691                }
4692
4693                for (idx = 0; idx < l; idx++)
4694                        wlc_lcnphy_write_table(pi, &tb[idx]);
4695        }
4696
4697        if (pi->sh->boardflags & BFL_FEM) {
4698                if (pi->sh->boardflags & BFL_FEM_BT) {
4699                        if (pi->sh->boardrev < 0x1250)
4700                                tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
4701                        else
4702                                tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
4703                } else {
4704                        tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa;
4705                }
4706        } else {
4707                if (pi->sh->boardflags & BFL_FEM_BT)
4708                        tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa;
4709                else
4710                        tb = &dot11lcn_sw_ctrl_tbl_info_4313;
4711        }
4712        wlc_lcnphy_write_table(pi, tb);
4713        wlc_lcnphy_load_rfpower(pi);
4714
4715        wlc_lcnphy_clear_papd_comptable(pi);
4716}
4717
4718static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4719{
4720        u16 afectrl1;
4721        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4722
4723        write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4724
4725        write_phy_reg(pi, 0x43b, 0x0);
4726        write_phy_reg(pi, 0x43c, 0x0);
4727        write_phy_reg(pi, 0x44c, 0x0);
4728        write_phy_reg(pi, 0x4e6, 0x0);
4729        write_phy_reg(pi, 0x4f9, 0x0);
4730        write_phy_reg(pi, 0x4b0, 0x0);
4731        write_phy_reg(pi, 0x938, 0x0);
4732        write_phy_reg(pi, 0x4b0, 0x0);
4733        write_phy_reg(pi, 0x44e, 0);
4734
4735        or_phy_reg(pi, 0x567, 0x03);
4736
4737        or_phy_reg(pi, 0x44a, 0x44);
4738        write_phy_reg(pi, 0x44a, 0x80);
4739
4740        if (!(pi->sh->boardflags & BFL_FEM))
4741                wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4742
4743        if (0) {
4744                afectrl1 = 0;
4745                afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4746                                  (pi_lcn->lcnphy_rssi_vc << 4) |
4747                                  (pi_lcn->lcnphy_rssi_gs << 10));
4748                write_phy_reg(pi, 0x43e, afectrl1);
4749        }
4750
4751        mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4752        if (pi->sh->boardflags & BFL_FEM) {
4753                mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4754
4755                write_phy_reg(pi, 0x910, 0x1);
4756        }
4757
4758        mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4759        mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4760        mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4761
4762}
4763
4764static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4765{
4766        if (CHSPEC_IS5G(pi->radio_chanspec)) {
4767                mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4768                mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4769        }
4770}
4771
4772static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4773{
4774        s16 temp;
4775        struct phytbl_info tab;
4776        u32 tableBuffer[2];
4777        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4778
4779        temp = (s16) read_phy_reg(pi, 0x4df);
4780        pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4781
4782        if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4783                pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4784
4785        pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4786
4787        if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4788                pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4789
4790        tab.tbl_ptr = tableBuffer;
4791        tab.tbl_len = 2;
4792        tab.tbl_id = 17;
4793        tab.tbl_offset = 59;
4794        tab.tbl_width = 32;
4795        wlc_lcnphy_read_table(pi, &tab);
4796
4797        if (tableBuffer[0] > 63)
4798                tableBuffer[0] -= 128;
4799        pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4800
4801        if (tableBuffer[1] > 63)
4802                tableBuffer[1] -= 128;
4803        pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4804
4805        temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4806        if (temp > 127)
4807                temp -= 256;
4808        pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4809
4810        pi_lcn->lcnphy_Med_Low_Gain_db =
4811                (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4812        pi_lcn->lcnphy_Very_Low_Gain_db =
4813                (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4814
4815        tab.tbl_ptr = tableBuffer;
4816        tab.tbl_len = 2;
4817        tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4818        tab.tbl_offset = 28;
4819        tab.tbl_width = 32;
4820        wlc_lcnphy_read_table(pi, &tab);
4821
4822        pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4823        pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4824
4825}
4826
4827static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4828{
4829
4830        wlc_lcnphy_tbl_init(pi);
4831        wlc_lcnphy_rev0_baseband_init(pi);
4832        if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4833                wlc_lcnphy_rev2_baseband_init(pi);
4834        wlc_lcnphy_bu_tweaks(pi);
4835}
4836
4837void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4838{
4839        u8 phybw40;
4840        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4841        phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4842
4843        pi_lcn->lcnphy_cal_counter = 0;
4844        pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4845
4846        or_phy_reg(pi, 0x44a, 0x80);
4847        and_phy_reg(pi, 0x44a, 0x7f);
4848
4849        wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4850
4851        write_phy_reg(pi, 0x60a, 160);
4852
4853        write_phy_reg(pi, 0x46a, 25);
4854
4855        wlc_lcnphy_baseband_init(pi);
4856
4857        wlc_lcnphy_radio_init(pi);
4858
4859        if (CHSPEC_IS2G(pi->radio_chanspec))
4860                wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4861
4862        wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4863
4864        bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);
4865
4866        bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,
4867                                    0x03CDDDDD);
4868
4869        if ((pi->sh->boardflags & BFL_FEM)
4870            && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4871                wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4872
4873        wlc_lcnphy_agc_temp_init(pi);
4874
4875        wlc_lcnphy_temp_adj(pi);
4876
4877        mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4878
4879        udelay(100);
4880        mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4881
4882        wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4883        pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4884        wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4885}
4886
4887static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4888{
4889        s8 txpwr = 0;
4890        int i;
4891        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4892        struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
4893
4894        if (CHSPEC_IS2G(pi->radio_chanspec)) {
4895                u16 cckpo = 0;
4896                u32 offset_ofdm, offset_mcs;
4897
4898                pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
4899
4900                pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
4901
4902                pi->txpa_2g[0] = sprom->pa0b0;
4903                pi->txpa_2g[1] = sprom->pa0b1;
4904                pi->txpa_2g[2] = sprom->pa0b2;
4905
4906                pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
4907                pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
4908                pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
4909
4910                pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4911                pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4912                pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4913
4914                pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4915                pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4916                pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4917
4918                txpwr = sprom->core_pwr_info[0].maxpwr_2g;
4919                pi->tx_srom_max_2g = txpwr;
4920
4921                for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4922                        pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4923                        pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4924                }
4925
4926                cckpo = sprom->cck2gpo;
4927                offset_ofdm = sprom->ofdm2gpo;
4928                if (cckpo) {
4929                        uint max_pwr_chan = txpwr;
4930
4931                        for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4932                                pi->tx_srom_max_rate_2g[i] =
4933                                        max_pwr_chan - ((cckpo & 0xf) * 2);
4934                                cckpo >>= 4;
4935                        }
4936
4937                        for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4938                                pi->tx_srom_max_rate_2g[i] =
4939                                        max_pwr_chan -
4940                                        ((offset_ofdm & 0xf) * 2);
4941                                offset_ofdm >>= 4;
4942                        }
4943                } else {
4944                        u8 opo = 0;
4945
4946                        opo = sprom->opo;
4947
4948                        for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4949                                pi->tx_srom_max_rate_2g[i] = txpwr;
4950
4951                        for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4952                                pi->tx_srom_max_rate_2g[i] = txpwr -
4953                                                ((offset_ofdm & 0xf) * 2);
4954                                offset_ofdm >>= 4;
4955                        }
4956                        offset_mcs = sprom->mcs2gpo[1] << 16;
4957                        offset_mcs |= sprom->mcs2gpo[0];
4958                        pi_lcn->lcnphy_mcs20_po = offset_mcs;
4959                        for (i = TXP_FIRST_SISO_MCS_20;
4960                             i <= TXP_LAST_SISO_MCS_20; i++) {
4961                                pi->tx_srom_max_rate_2g[i] =
4962                                        txpwr - ((offset_mcs & 0xf) * 2);
4963                                offset_mcs >>= 4;
4964                        }
4965                }
4966
4967                pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
4968                pi_lcn->lcnphy_measPower = sprom->measpower;
4969                pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
4970                pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
4971                pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
4972                pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
4973                pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
4974                pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
4975                if (sprom->ant_available_bg > 1)
4976                        wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
4977                                sprom->ant_available_bg);
4978        }
4979        pi_lcn->lcnphy_cck_dig_filt_type = -1;
4980
4981        return true;
4982}
4983
4984void wlc_2064_vco_cal(struct brcms_phy *pi)
4985{
4986        u8 calnrst;
4987
4988        mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4989        calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4990        write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4991        udelay(1);
4992        write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4993        udelay(1);
4994        write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4995        udelay(300);
4996        mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4997}
4998
4999bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
5000{
5001        if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
5002                return false;
5003        else
5004                return (LCNPHY_TX_PWR_CTRL_HW ==
5005                        wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5006}
5007
5008void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
5009{
5010        u16 pwr_ctrl;
5011        if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5012                wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5013        } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5014                pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5015                wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5016                wlc_lcnphy_txpower_recalc_target(pi);
5017                wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5018        }
5019}
5020
5021void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
5022{
5023        u8 channel = CHSPEC_CHANNEL(chanspec);
5024
5025        wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec);
5026
5027        wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
5028
5029        or_phy_reg(pi, 0x44a, 0x44);
5030        write_phy_reg(pi, 0x44a, 0x80);
5031
5032        wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
5033        udelay(1000);
5034
5035        wlc_lcnphy_toggle_afe_pwdn(pi);
5036
5037        write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
5038        write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
5039
5040        if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
5041                mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
5042
5043                wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
5044        } else {
5045                mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
5046
5047                wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
5048        }
5049
5050        if (pi->sh->boardflags & BFL_FEM)
5051                wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
5052        else
5053                wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
5054
5055        mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
5056        if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
5057                wlc_lcnphy_tssi_setup(pi);
5058}
5059
5060void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
5061{
5062        kfree(pi->u.pi_lcnphy);
5063}
5064
5065bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
5066{
5067        struct brcms_phy_lcnphy *pi_lcn;
5068
5069        pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
5070        if (pi->u.pi_lcnphy == NULL)
5071                return false;
5072
5073        pi_lcn = pi->u.pi_lcnphy;
5074
5075        if (0 == (pi->sh->boardflags & BFL_NOPA)) {
5076                pi->hwpwrctrl = true;
5077                pi->hwpwrctrl_capable = true;
5078        }
5079
5080        pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);
5081        pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5082
5083        pi->pi_fptr.init = wlc_phy_init_lcnphy;
5084        pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5085        pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5086        pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5087        pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5088        pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5089        pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5090        pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5091        pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5092
5093        if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5094                return false;
5095
5096        if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5097                if (pi_lcn->lcnphy_tempsense_option == 3) {
5098                        pi->hwpwrctrl = true;
5099                        pi->hwpwrctrl_capable = true;
5100                        pi->temppwrctrl_capable = false;
5101                } else {
5102                        pi->hwpwrctrl = false;
5103                        pi->hwpwrctrl_capable = false;
5104                        pi->temppwrctrl_capable = true;
5105                }
5106        }
5107
5108        return true;
5109}
5110
5111static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5112{
5113        u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5114
5115        trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5116        ext_lna = (u16) (gain >> 29) & 0x01;
5117        lna1 = (u16) (gain >> 0) & 0x0f;
5118        lna2 = (u16) (gain >> 4) & 0x0f;
5119        tia = (u16) (gain >> 8) & 0xf;
5120        biq0 = (u16) (gain >> 12) & 0xf;
5121        biq1 = (u16) (gain >> 16) & 0xf;
5122
5123        gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5124                          ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5125                          ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5126        gain16_19 = biq1;
5127
5128        mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5129        mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5130        mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5131        mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5132        mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5133
5134        if (CHSPEC_IS2G(pi->radio_chanspec)) {
5135                mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5136                mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5137        }
5138        wlc_lcnphy_rx_gain_override_enable(pi, true);
5139}
5140
5141static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5142{
5143        u32 received_power = 0;
5144        s32 max_index = 0;
5145        u32 gain_code = 0;
5146        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5147
5148        max_index = 36;
5149        if (*gain_index >= 0)
5150                gain_code = lcnphy_23bitgaincode_table[*gain_index];
5151
5152        if (-1 == *gain_index) {
5153                *gain_index = 0;
5154                while ((*gain_index <= (s32) max_index)
5155                       && (received_power < 700)) {
5156                        wlc_lcnphy_set_rx_gain(pi,
5157                                               lcnphy_23bitgaincode_table
5158                                               [*gain_index]);
5159                        received_power =
5160                                wlc_lcnphy_measure_digital_power(
5161                                        pi,
5162                                        pi_lcn->
5163                                        lcnphy_noise_samples);
5164                        (*gain_index)++;
5165                }
5166                (*gain_index)--;
5167        } else {
5168                wlc_lcnphy_set_rx_gain(pi, gain_code);
5169                received_power =
5170                        wlc_lcnphy_measure_digital_power(pi,
5171                                                         pi_lcn->
5172                                                         lcnphy_noise_samples);
5173        }
5174
5175        return received_power;
5176}
5177
5178s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5179{
5180        s32 gain = 0;
5181        s32 nominal_power_db;
5182        s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5183            input_power_db;
5184        s32 received_power, temperature;
5185        u32 power;
5186        u32 msb1, msb2, val1, val2, diff1, diff2;
5187        uint freq;
5188        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5189
5190        received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5191
5192        gain = lcnphy_gain_table[gain_index];
5193
5194        nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5195
5196        power = (received_power * 16);
5197        msb1 = ffs(power) - 1;
5198        msb2 = msb1 + 1;
5199        val1 = 1 << msb1;
5200        val2 = 1 << msb2;
5201        diff1 = (power - val1);
5202        diff2 = (val2 - power);
5203        if (diff1 < diff2)
5204                log_val = msb1;
5205        else
5206                log_val = msb2;
5207
5208        log_val = log_val * 3;
5209
5210        gain_mismatch = (nominal_power_db / 2) - (log_val);
5211
5212        desired_gain = gain + gain_mismatch;
5213
5214        input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5215
5216        if (input_power_offset_db > 127)
5217                input_power_offset_db -= 256;
5218
5219        input_power_db = input_power_offset_db - desired_gain;
5220
5221        input_power_db =
5222                input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5223
5224        freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5225        if ((freq > 2427) && (freq <= 2467))
5226                input_power_db = input_power_db - 1;
5227
5228        temperature = pi_lcn->lcnphy_lastsensed_temperature;
5229
5230        if ((temperature - 15) < -30)
5231                input_power_db =
5232                        input_power_db +
5233                        (((temperature - 10 - 25) * 286) >> 12) -
5234                        7;
5235        else if ((temperature - 15) < 4)
5236                input_power_db =
5237                        input_power_db +
5238                        (((temperature - 10 - 25) * 286) >> 12) -
5239                        3;
5240        else
5241                input_power_db = input_power_db +
5242                                        (((temperature - 10 - 25) * 286) >> 12);
5243
5244        wlc_lcnphy_rx_gain_override_enable(pi, 0);
5245
5246        return input_power_db;
5247}
5248