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_array(131, sizeof(s16), 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_array(20, sizeof(u16), 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        mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5);
3392        mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9);
3393
3394        if (phybw40 == 0) {
3395                mod_phy_reg((pi), 0x410,
3396                            (0x1 << 6) |
3397                            (0x1 << 5),
3398                            ((CHSPEC_IS2G(
3399                                      pi->radio_chanspec)) ? (!mode) : 0) <<
3400                            6 | (!mode) << 5);
3401                mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
3402        }
3403}
3404
3405void
3406wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
3407                         bool iqcalmode)
3408{
3409        u8 phy_bw;
3410        u16 num_samps, t, k;
3411        u32 bw;
3412        s32 theta = 0, rot = 0;
3413        struct cordic_iq tone_samp;
3414        u32 data_buf[64];
3415        u16 i_samp, q_samp;
3416        struct phytbl_info tab;
3417        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3418
3419        pi->phy_tx_tone_freq = f_kHz;
3420
3421        wlc_lcnphy_deaf_mode(pi, true);
3422
3423        phy_bw = 40;
3424        if (pi_lcn->lcnphy_spurmod) {
3425                write_phy_reg(pi, 0x942, 0x2);
3426                write_phy_reg(pi, 0x93b, 0x0);
3427                write_phy_reg(pi, 0x93c, 0x0);
3428                wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
3429        }
3430
3431        if (f_kHz) {
3432                k = 1;
3433                do {
3434                        bw = phy_bw * 1000 * k;
3435                        num_samps = bw / abs(f_kHz);
3436                        k++;
3437                } while ((num_samps * (u32) (abs(f_kHz))) != bw);
3438        } else
3439                num_samps = 2;
3440
3441        rot = ((f_kHz * 36) / phy_bw) / 100;
3442        theta = 0;
3443
3444        for (t = 0; t < num_samps; t++) {
3445
3446                tone_samp = cordic_calc_iq(theta);
3447
3448                theta += rot;
3449
3450                i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff);
3451                q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff);
3452                data_buf[t] = (i_samp << 10) | q_samp;
3453        }
3454
3455        mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0);
3456
3457        mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3);
3458
3459        tab.tbl_ptr = data_buf;
3460        tab.tbl_len = num_samps;
3461        tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY;
3462        tab.tbl_offset = 0;
3463        tab.tbl_width = 32;
3464        wlc_lcnphy_write_table(pi, &tab);
3465
3466        wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode);
3467}
3468
3469void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
3470{
3471        s16 playback_status;
3472        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3473
3474        pi->phy_tx_tone_freq = 0;
3475        if (pi_lcn->lcnphy_spurmod) {
3476                write_phy_reg(pi, 0x942, 0x7);
3477                write_phy_reg(pi, 0x93b, 0x2017);
3478                write_phy_reg(pi, 0x93c, 0x27c5);
3479                wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
3480        }
3481
3482        playback_status = read_phy_reg(pi, 0x644);
3483        if (playback_status & (0x1 << 0)) {
3484                wlc_lcnphy_tx_pu(pi, 0);
3485                mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1);
3486        } else if (playback_status & (0x1 << 1))
3487                mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15);
3488
3489        mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0);
3490
3491        mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3);
3492
3493        mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7);
3494
3495        and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9);
3496
3497        wlc_lcnphy_deaf_mode(pi, false);
3498}
3499
3500static void
3501wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
3502{
3503        u16 di0dq0;
3504        u16 x, y, data_rf;
3505        int k;
3506        switch (cal_type) {
3507        case 0:
3508                wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
3509                break;
3510        case 2:
3511                di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
3512                wlc_lcnphy_set_tx_locc(pi, di0dq0);
3513                break;
3514        case 3:
3515                k = wlc_lcnphy_calc_floor(coeff_x, 0);
3516                y = 8 + k;
3517                k = wlc_lcnphy_calc_floor(coeff_x, 1);
3518                x = 8 - k;
3519                data_rf = (x * 16 + y);
3520                write_radio_reg(pi, RADIO_2064_REG089, data_rf);
3521                k = wlc_lcnphy_calc_floor(coeff_y, 0);
3522                y = 8 + k;
3523                k = wlc_lcnphy_calc_floor(coeff_y, 1);
3524                x = 8 - k;
3525                data_rf = (x * 16 + y);
3526                write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
3527                break;
3528        case 4:
3529                k = wlc_lcnphy_calc_floor(coeff_x, 0);
3530                y = 8 + k;
3531                k = wlc_lcnphy_calc_floor(coeff_x, 1);
3532                x = 8 - k;
3533                data_rf = (x * 16 + y);
3534                write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
3535                k = wlc_lcnphy_calc_floor(coeff_y, 0);
3536                y = 8 + k;
3537                k = wlc_lcnphy_calc_floor(coeff_y, 1);
3538                x = 8 - k;
3539                data_rf = (x * 16 + y);
3540                write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
3541                break;
3542        }
3543}
3544
3545static struct lcnphy_unsign16_struct
3546wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
3547{
3548        u16 a, b, didq;
3549        u8 di0, dq0, ei, eq, fi, fq;
3550        struct lcnphy_unsign16_struct cc;
3551        cc.re = 0;
3552        cc.im = 0;
3553        switch (cal_type) {
3554        case 0:
3555                wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3556                cc.re = a;
3557                cc.im = b;
3558                break;
3559        case 2:
3560                didq = wlc_lcnphy_get_tx_locc(pi);
3561                di0 = (((didq & 0xff00) << 16) >> 24);
3562                dq0 = (((didq & 0x00ff) << 24) >> 24);
3563                cc.re = (u16) di0;
3564                cc.im = (u16) dq0;
3565                break;
3566        case 3:
3567                wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3568                cc.re = (u16) ei;
3569                cc.im = (u16) eq;
3570                break;
3571        case 4:
3572                wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
3573                cc.re = (u16) fi;
3574                cc.im = (u16) fq;
3575                break;
3576        }
3577        return cc;
3578}
3579
3580static void
3581wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
3582                    s16 *ptr, int mode)
3583{
3584        u32 curval1, curval2, stpptr, curptr, strptr, val;
3585        u16 sslpnCalibClkEnCtrl, timer;
3586        u16 old_sslpnCalibClkEnCtrl;
3587        s16 imag, real;
3588        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3589
3590        timer = 0;
3591        old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3592
3593        curval1 = bcma_read16(pi->d11core, D11REGOFFS(psm_corectlsts));
3594        ptr[130] = 0;
3595        bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts),
3596                     ((1 << 6) | curval1));
3597
3598        bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_strptr), 0x7E00);
3599        bcma_write16(pi->d11core, D11REGOFFS(smpl_clct_stpptr), 0x8000);
3600        udelay(20);
3601        curval2 = bcma_read16(pi->d11core, D11REGOFFS(psm_phy_hdr_param));
3602        bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param),
3603                     curval2 | 0x30);
3604
3605        write_phy_reg(pi, 0x555, 0x0);
3606        write_phy_reg(pi, 0x5a6, 0x5);
3607
3608        write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
3609        write_phy_reg(pi, 0x5cf, 3);
3610        write_phy_reg(pi, 0x5a5, 0x3);
3611        write_phy_reg(pi, 0x583, 0x0);
3612        write_phy_reg(pi, 0x584, 0x0);
3613        write_phy_reg(pi, 0x585, 0x0fff);
3614        write_phy_reg(pi, 0x586, 0x0000);
3615
3616        write_phy_reg(pi, 0x580, 0x4501);
3617
3618        sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
3619        write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
3620        stpptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_stpptr));
3621        curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3622        do {
3623                udelay(10);
3624                curptr = bcma_read16(pi->d11core, D11REGOFFS(smpl_clct_curptr));
3625                timer++;
3626        } while ((curptr != stpptr) && (timer < 500));
3627
3628        bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), 0x2);
3629        strptr = 0x7E00;
3630        bcma_write32(pi->d11core, D11REGOFFS(tplatewrptr), strptr);
3631        while (strptr < 0x8000) {
3632                val = bcma_read32(pi->d11core, D11REGOFFS(tplatewrdata));
3633                imag = ((val >> 16) & 0x3ff);
3634                real = ((val) & 0x3ff);
3635                if (imag > 511)
3636                        imag -= 1024;
3637
3638                if (real > 511)
3639                        real -= 1024;
3640
3641                if (pi_lcn->lcnphy_iqcal_swp_dis)
3642                        ptr[(strptr - 0x7E00) / 4] = real;
3643                else
3644                        ptr[(strptr - 0x7E00) / 4] = imag;
3645
3646                if (clip_detect_algo) {
3647                        if (imag > thresh || imag < -thresh) {
3648                                strptr = 0x8000;
3649                                ptr[130] = 1;
3650                        }
3651                }
3652
3653                strptr += 4;
3654        }
3655
3656        write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
3657        bcma_write16(pi->d11core, D11REGOFFS(psm_phy_hdr_param), curval2);
3658        bcma_write16(pi->d11core, D11REGOFFS(psm_corectlsts), curval1);
3659}
3660
3661static void
3662wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
3663              int step_size_lg2)
3664{
3665        const struct lcnphy_spb_tone *phy_c1;
3666        struct lcnphy_spb_tone phy_c2;
3667        struct lcnphy_unsign16_struct phy_c3;
3668        int phy_c4, phy_c5, k, l, j, phy_c6;
3669        u16 phy_c7, phy_c8, phy_c9;
3670        s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
3671        s16 *ptr, phy_c17;
3672        s32 phy_c18, phy_c19;
3673        u32 phy_c20, phy_c21;
3674        bool phy_c22, phy_c23, phy_c24, phy_c25;
3675        u16 phy_c26, phy_c27;
3676        u16 phy_c28, phy_c29, phy_c30;
3677        u16 phy_c31;
3678        u16 *phy_c32;
3679        phy_c21 = 0;
3680        phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
3681        ptr = kmalloc_array(131, sizeof(s16), GFP_ATOMIC);
3682        if (NULL == ptr)
3683                return;
3684
3685        phy_c32 = kmalloc_array(20, sizeof(u16), GFP_ATOMIC);
3686        if (NULL == phy_c32) {
3687                kfree(ptr);
3688                return;
3689        }
3690        phy_c26 = read_phy_reg(pi, 0x6da);
3691        phy_c27 = read_phy_reg(pi, 0x6db);
3692        phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
3693        write_phy_reg(pi, 0x93d, 0xC0);
3694
3695        wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
3696        write_phy_reg(pi, 0x6da, 0xffff);
3697        or_phy_reg(pi, 0x6db, 0x3);
3698
3699        wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
3700        udelay(500);
3701        phy_c28 = read_phy_reg(pi, 0x938);
3702        phy_c29 = read_phy_reg(pi, 0x4d7);
3703        phy_c30 = read_phy_reg(pi, 0x4d8);
3704        or_phy_reg(pi, 0x938, 0x1 << 2);
3705        or_phy_reg(pi, 0x4d7, 0x1 << 2);
3706        or_phy_reg(pi, 0x4d7, 0x1 << 3);
3707        mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
3708        or_phy_reg(pi, 0x4d8, 1 << 0);
3709        or_phy_reg(pi, 0x4d8, 1 << 1);
3710        mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
3711        mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
3712        phy_c1 = &lcnphy_spb_tone_3750[0];
3713        phy_c4 = 32;
3714
3715        if (num_levels == 0) {
3716                if (cal_type != 0)
3717                        num_levels = 4;
3718                else
3719                        num_levels = 9;
3720        }
3721        if (step_size_lg2 == 0) {
3722                if (cal_type != 0)
3723                        step_size_lg2 = 3;
3724                else
3725                        step_size_lg2 = 8;
3726        }
3727
3728        phy_c7 = (1 << step_size_lg2);
3729        phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
3730        phy_c15 = (s16) phy_c3.re;
3731        phy_c16 = (s16) phy_c3.im;
3732        if (cal_type == 2) {
3733                if (phy_c3.re > 127)
3734                        phy_c15 = phy_c3.re - 256;
3735                if (phy_c3.im > 127)
3736                        phy_c16 = phy_c3.im - 256;
3737        }
3738        wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3739        udelay(20);
3740        for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
3741                phy_c23 = true;
3742                phy_c22 = false;
3743                switch (cal_type) {
3744                case 0:
3745                        phy_c10 = 511;
3746                        break;
3747                case 2:
3748                        phy_c10 = 127;
3749                        break;
3750                case 3:
3751                        phy_c10 = 15;
3752                        break;
3753                case 4:
3754                        phy_c10 = 15;
3755                        break;
3756                }
3757
3758                phy_c9 = read_phy_reg(pi, 0x93d);
3759                phy_c9 = 2 * phy_c9;
3760                phy_c24 = false;
3761                phy_c5 = 7;
3762                phy_c25 = true;
3763                while (1) {
3764                        write_radio_reg(pi, RADIO_2064_REG026,
3765                                        (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
3766                        udelay(50);
3767                        phy_c22 = false;
3768                        ptr[130] = 0;
3769                        wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
3770                        if (ptr[130] == 1)
3771                                phy_c22 = true;
3772                        if (phy_c22)
3773                                phy_c5 -= 1;
3774                        if ((phy_c22 != phy_c24) && (!phy_c25))
3775                                break;
3776                        if (!phy_c22)
3777                                phy_c5 += 1;
3778                        if (phy_c5 <= 0 || phy_c5 >= 7)
3779                                break;
3780                        phy_c24 = phy_c22;
3781                        phy_c25 = false;
3782                }
3783
3784                if (phy_c5 < 0)
3785                        phy_c5 = 0;
3786                else if (phy_c5 > 7)
3787                        phy_c5 = 7;
3788
3789                for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
3790                        for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
3791                                phy_c11 = phy_c15 + k;
3792                                phy_c12 = phy_c16 + l;
3793
3794                                if (phy_c11 < -phy_c10)
3795                                        phy_c11 = -phy_c10;
3796                                else if (phy_c11 > phy_c10)
3797                                        phy_c11 = phy_c10;
3798                                if (phy_c12 < -phy_c10)
3799                                        phy_c12 = -phy_c10;
3800                                else if (phy_c12 > phy_c10)
3801                                        phy_c12 = phy_c10;
3802                                wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
3803                                                  phy_c12);
3804                                udelay(20);
3805                                wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
3806
3807                                phy_c18 = 0;
3808                                phy_c19 = 0;
3809                                for (j = 0; j < 128; j++) {
3810                                        if (cal_type != 0)
3811                                                phy_c6 = j % phy_c4;
3812                                        else
3813                                                phy_c6 = (2 * j) % phy_c4;
3814
3815                                        phy_c2.re = phy_c1[phy_c6].re;
3816                                        phy_c2.im = phy_c1[phy_c6].im;
3817                                        phy_c17 = ptr[j];
3818                                        phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
3819                                        phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
3820                                }
3821
3822                                phy_c18 = phy_c18 >> 10;
3823                                phy_c19 = phy_c19 >> 10;
3824                                phy_c20 = ((phy_c18 * phy_c18) +
3825                                           (phy_c19 * phy_c19));
3826
3827                                if (phy_c23 || phy_c20 < phy_c21) {
3828                                        phy_c21 = phy_c20;
3829                                        phy_c13 = phy_c11;
3830                                        phy_c14 = phy_c12;
3831                                }
3832                                phy_c23 = false;
3833                        }
3834                }
3835                phy_c23 = true;
3836                phy_c15 = phy_c13;
3837                phy_c16 = phy_c14;
3838                phy_c7 = phy_c7 >> 1;
3839                wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
3840                udelay(20);
3841        }
3842        goto cleanup;
3843cleanup:
3844        wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
3845        wlc_lcnphy_stop_tx_tone(pi);
3846        write_phy_reg(pi, 0x6da, phy_c26);
3847        write_phy_reg(pi, 0x6db, phy_c27);
3848        write_phy_reg(pi, 0x938, phy_c28);
3849        write_phy_reg(pi, 0x4d7, phy_c29);
3850        write_phy_reg(pi, 0x4d8, phy_c30);
3851        write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
3852
3853        kfree(phy_c32);
3854        kfree(ptr);
3855}
3856
3857void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
3858{
3859        u16 iqcc[2];
3860        struct phytbl_info tab;
3861
3862        tab.tbl_ptr = iqcc;
3863        tab.tbl_len = 2;
3864        tab.tbl_id = 0;
3865        tab.tbl_offset = 80;
3866        tab.tbl_width = 16;
3867        wlc_lcnphy_read_table(pi, &tab);
3868
3869        *a = iqcc[0];
3870        *b = iqcc[1];
3871}
3872
3873static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
3874{
3875        struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
3876
3877        wlc_lcnphy_set_cc(pi, 0, 0, 0);
3878        wlc_lcnphy_set_cc(pi, 2, 0, 0);
3879        wlc_lcnphy_set_cc(pi, 3, 0, 0);
3880        wlc_lcnphy_set_cc(pi, 4, 0, 0);
3881
3882        wlc_lcnphy_a1(pi, 4, 0, 0);
3883        wlc_lcnphy_a1(pi, 3, 0, 0);
3884        wlc_lcnphy_a1(pi, 2, 3, 2);
3885        wlc_lcnphy_a1(pi, 0, 5, 8);
3886        wlc_lcnphy_a1(pi, 2, 2, 1);
3887        wlc_lcnphy_a1(pi, 0, 4, 3);
3888
3889        iqcc0 = wlc_lcnphy_get_cc(pi, 0);
3890        locc2 = wlc_lcnphy_get_cc(pi, 2);
3891        locc3 = wlc_lcnphy_get_cc(pi, 3);
3892        locc4 = wlc_lcnphy_get_cc(pi, 4);
3893}
3894
3895u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
3896{
3897        struct phytbl_info tab;
3898        u16 didq;
3899
3900        tab.tbl_id = 0;
3901        tab.tbl_width = 16;
3902        tab.tbl_ptr = &didq;
3903        tab.tbl_len = 1;
3904        tab.tbl_offset = 85;
3905        wlc_lcnphy_read_table(pi, &tab);
3906
3907        return didq;
3908}
3909
3910static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
3911{
3912
3913        struct lcnphy_txgains target_gains, old_gains;
3914        u8 save_bb_mult;
3915        u16 a, b, didq, save_pa_gain = 0;
3916        uint idx, SAVE_txpwrindex = 0xFF;
3917        u32 val;
3918        u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
3919        struct phytbl_info tab;
3920        u8 ei0, eq0, fi0, fq0;
3921        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
3922
3923        wlc_lcnphy_get_tx_gain(pi, &old_gains);
3924        save_pa_gain = wlc_lcnphy_get_pa_gain(pi);
3925
3926        save_bb_mult = wlc_lcnphy_get_bbmult(pi);
3927
3928        if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF)
3929                SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi);
3930
3931        wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
3932
3933        target_gains.gm_gain = 7;
3934        target_gains.pga_gain = 0;
3935        target_gains.pad_gain = 21;
3936        target_gains.dac_gain = 0;
3937        wlc_lcnphy_set_tx_gain(pi, &target_gains);
3938
3939        if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
3940
3941                wlc_lcnphy_set_tx_pwr_by_index(pi, 30);
3942
3943                wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3944                                       (pi_lcn->
3945                                        lcnphy_recal ? LCNPHY_CAL_RECAL :
3946                                        LCNPHY_CAL_FULL), false);
3947        } else {
3948                wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3949                wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3950        }
3951
3952        wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
3953        if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
3954                if (CHSPEC_IS5G(pi->radio_chanspec)) {
3955                        target_gains.gm_gain = 255;
3956                        target_gains.pga_gain = 255;
3957                        target_gains.pad_gain = 0xf0;
3958                        target_gains.dac_gain = 0;
3959                } else {
3960                        target_gains.gm_gain = 7;
3961                        target_gains.pga_gain = 45;
3962                        target_gains.pad_gain = 186;
3963                        target_gains.dac_gain = 0;
3964                }
3965
3966                if (LCNREV_IS(pi->pubpi.phy_rev, 1)
3967                    || pi_lcn->lcnphy_hw_iqcal_en) {
3968
3969                        target_gains.pga_gain = 0;
3970                        target_gains.pad_gain = 30;
3971                        wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
3972                        wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
3973                                               LCNPHY_CAL_FULL, false);
3974                } else {
3975                        wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
3976                }
3977        }
3978
3979        wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
3980
3981        didq = wlc_lcnphy_get_tx_locc(pi);
3982
3983        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
3984        tab.tbl_width = 32;
3985        tab.tbl_ptr = &val;
3986
3987        tab.tbl_len = 1;
3988        tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET;
3989
3990        for (idx = 0; idx < 128; idx++) {
3991                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx;
3992
3993                wlc_lcnphy_read_table(pi, &tab);
3994                val = (val & 0xfff00000) |
3995                      ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
3996                wlc_lcnphy_write_table(pi, &tab);
3997
3998                val = didq;
3999                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx;
4000                wlc_lcnphy_write_table(pi, &tab);
4001        }
4002
4003        pi_lcn->lcnphy_cal_results.txiqlocal_a = a;
4004        pi_lcn->lcnphy_cal_results.txiqlocal_b = b;
4005        pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq;
4006        pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0;
4007        pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0;
4008        pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0;
4009        pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0;
4010
4011        wlc_lcnphy_set_bbmult(pi, save_bb_mult);
4012        wlc_lcnphy_set_pa_gain(pi, save_pa_gain);
4013        wlc_lcnphy_set_tx_gain(pi, &old_gains);
4014
4015        if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF)
4016                wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4017        else
4018                wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex);
4019}
4020
4021s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
4022{
4023        u16 tempsenseval1, tempsenseval2;
4024        s16 avg = 0;
4025        bool suspend = false;
4026
4027        if (mode == 1) {
4028                suspend = (0 == (bcma_read32(pi->d11core,
4029                                             D11REGOFFS(maccontrol)) &
4030                                 MCTL_EN_MAC));
4031                if (!suspend)
4032                        wlapi_suspend_mac_and_wait(pi->sh->physhim);
4033                wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4034        }
4035        tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4036        tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4037
4038        if (tempsenseval1 > 255)
4039                avg = (s16) (tempsenseval1 - 512);
4040        else
4041                avg = (s16) tempsenseval1;
4042
4043        if (tempsenseval2 > 255)
4044                avg += (s16) (tempsenseval2 - 512);
4045        else
4046                avg += (s16) tempsenseval2;
4047
4048        avg /= 2;
4049
4050        if (mode == 1) {
4051
4052                mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4053
4054                udelay(100);
4055                mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4056
4057                if (!suspend)
4058                        wlapi_enable_mac(pi->sh->physhim);
4059        }
4060        return avg;
4061}
4062
4063u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
4064{
4065        u16 tempsenseval1, tempsenseval2;
4066        s32 avg = 0;
4067        bool suspend = false;
4068        u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4069        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4070
4071        if (mode == 1) {
4072                suspend = (0 == (bcma_read32(pi->d11core,
4073                                             D11REGOFFS(maccontrol)) &
4074                                 MCTL_EN_MAC));
4075                if (!suspend)
4076                        wlapi_suspend_mac_and_wait(pi->sh->physhim);
4077                wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
4078        }
4079        tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF;
4080        tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF;
4081
4082        if (tempsenseval1 > 255)
4083                avg = (int)(tempsenseval1 - 512);
4084        else
4085                avg = (int)tempsenseval1;
4086
4087        if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) {
4088                if (tempsenseval2 > 255)
4089                        avg = (int)(avg - tempsenseval2 + 512);
4090                else
4091                        avg = (int)(avg - tempsenseval2);
4092        } else {
4093                if (tempsenseval2 > 255)
4094                        avg = (int)(avg + tempsenseval2 - 512);
4095                else
4096                        avg = (int)(avg + tempsenseval2);
4097                avg = avg / 2;
4098        }
4099        if (avg < 0)
4100                avg = avg + 512;
4101
4102        if (pi_lcn->lcnphy_tempsense_option == 2)
4103                avg = tempsenseval1;
4104
4105        if (mode)
4106                wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
4107
4108        if (mode == 1) {
4109
4110                mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4111
4112                udelay(100);
4113                mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4114
4115                if (!suspend)
4116                        wlapi_enable_mac(pi->sh->physhim);
4117        }
4118        return (u16) avg;
4119}
4120
4121s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
4122{
4123        s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
4124        degree =
4125                ((degree <<
4126                  10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
4127                / LCN_TEMPSENSE_DEN;
4128        return (s8) degree;
4129}
4130
4131s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
4132{
4133        u16 vbatsenseval;
4134        s32 avg = 0;
4135        bool suspend = false;
4136
4137        if (mode == 1) {
4138                suspend = (0 == (bcma_read32(pi->d11core,
4139                                             D11REGOFFS(maccontrol)) &
4140                                 MCTL_EN_MAC));
4141                if (!suspend)
4142                        wlapi_suspend_mac_and_wait(pi->sh->physhim);
4143                wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
4144        }
4145
4146        vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF;
4147
4148        if (vbatsenseval > 255)
4149                avg = (s32) (vbatsenseval - 512);
4150        else
4151                avg = (s32) vbatsenseval;
4152
4153        avg =   (avg * LCN_VBAT_SCALE_NOM +
4154                 (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
4155
4156        if (mode == 1) {
4157                if (!suspend)
4158                        wlapi_enable_mac(pi->sh->physhim);
4159        }
4160        return (s8) avg;
4161}
4162
4163static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
4164{
4165        u8 phybw40;
4166        phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4167
4168        mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7);
4169
4170        if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) ||
4171            (mode == AFE_CLK_INIT_MODE_TXRX2X))
4172                write_phy_reg(pi, 0x6d0, 0x7);
4173
4174        wlc_lcnphy_toggle_afe_pwdn(pi);
4175}
4176
4177static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
4178{
4179}
4180
4181static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
4182{
4183        bool suspend;
4184        s8 index;
4185        u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4186        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4187        suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4188                         MCTL_EN_MAC));
4189        if (!suspend)
4190                wlapi_suspend_mac_and_wait(pi->sh->physhim);
4191        wlc_lcnphy_deaf_mode(pi, true);
4192        pi->phy_lastcal = pi->sh->now;
4193        pi->phy_forcecal = false;
4194        index = pi_lcn->lcnphy_current_index;
4195
4196        wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4197
4198        wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4199        wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4200        wlc_lcnphy_deaf_mode(pi, false);
4201        if (!suspend)
4202                wlapi_enable_mac(pi->sh->physhim);
4203
4204}
4205
4206static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
4207{
4208        bool suspend, full_cal;
4209        const struct lcnphy_rx_iqcomp *rx_iqcomp;
4210        int rx_iqcomp_sz;
4211        u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4212        s8 index;
4213        struct phytbl_info tab;
4214        s32 a1, b0, b1;
4215        s32 tssi, pwr, maxtargetpwr, mintargetpwr;
4216        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4217
4218        pi->phy_lastcal = pi->sh->now;
4219        pi->phy_forcecal = false;
4220        full_cal =
4221                (pi_lcn->lcnphy_full_cal_channel !=
4222                 CHSPEC_CHANNEL(pi->radio_chanspec));
4223        pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
4224        index = pi_lcn->lcnphy_current_index;
4225
4226        suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
4227                         MCTL_EN_MAC));
4228        if (!suspend) {
4229                wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
4230                wlapi_suspend_mac_and_wait(pi->sh->physhim);
4231        }
4232
4233        wlc_lcnphy_deaf_mode(pi, true);
4234
4235        wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
4236
4237        rx_iqcomp = lcnphy_rx_iqcomp_table_rev0;
4238        rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0);
4239
4240        if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4241                wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40);
4242        else
4243                wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127);
4244
4245        if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
4246
4247                wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi);
4248
4249                b0 = pi->txpa_2g[0];
4250                b1 = pi->txpa_2g[1];
4251                a1 = pi->txpa_2g[2];
4252                maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1);
4253                mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1);
4254
4255                tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4256                tab.tbl_width = 32;
4257                tab.tbl_ptr = &pwr;
4258                tab.tbl_len = 1;
4259                tab.tbl_offset = 0;
4260                for (tssi = 0; tssi < 128; tssi++) {
4261                        pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1);
4262                        pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr;
4263                        wlc_lcnphy_write_table(pi, &tab);
4264                        tab.tbl_offset++;
4265                }
4266        }
4267
4268        wlc_lcnphy_set_tx_pwr_by_index(pi, index);
4269        wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl);
4270        wlc_lcnphy_deaf_mode(pi, false);
4271        if (!suspend)
4272                wlapi_enable_mac(pi->sh->physhim);
4273}
4274
4275void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
4276{
4277        u16 temp_new;
4278        int temp1, temp2, temp_diff;
4279        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4280
4281        switch (mode) {
4282        case PHY_PERICAL_CHAN:
4283                break;
4284        case PHY_FULLCAL:
4285                wlc_lcnphy_periodic_cal(pi);
4286                break;
4287        case PHY_PERICAL_PHYINIT:
4288                wlc_lcnphy_periodic_cal(pi);
4289                break;
4290        case PHY_PERICAL_WATCHDOG:
4291                if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
4292                        temp_new = wlc_lcnphy_tempsense(pi, 0);
4293                        temp1 = LCNPHY_TEMPSENSE(temp_new);
4294                        temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper);
4295                        temp_diff = temp1 - temp2;
4296                        if ((pi_lcn->lcnphy_cal_counter > 90) ||
4297                            (temp_diff > 60) || (temp_diff < -60)) {
4298                                wlc_lcnphy_glacial_timer_based_cal(pi);
4299                                wlc_2064_vco_cal(pi);
4300                                pi_lcn->lcnphy_cal_temper = temp_new;
4301                                pi_lcn->lcnphy_cal_counter = 0;
4302                        } else
4303                                pi_lcn->lcnphy_cal_counter++;
4304                }
4305                break;
4306        case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
4307                if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4308                        wlc_lcnphy_tx_power_adjustment(
4309                                (struct brcms_phy_pub *) pi);
4310                break;
4311        }
4312}
4313
4314void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
4315{
4316        s8 cck_offset;
4317        u16 status;
4318        status = (read_phy_reg(pi, 0x4ab));
4319        if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
4320            (status  & (0x1 << 15))) {
4321                *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
4322                                   >> 0) >> 1);
4323
4324                if (wlc_phy_tpc_isenabled_lcnphy(pi))
4325                        cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
4326                else
4327                        cck_offset = 0;
4328
4329                *cck_pwr = *ofdm_pwr + cck_offset;
4330        } else {
4331                *cck_pwr = 0;
4332                *ofdm_pwr = 0;
4333        }
4334}
4335
4336void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
4337{
4338        return;
4339
4340}
4341
4342void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
4343{
4344        s8 index;
4345        u16 index2;
4346        struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro);
4347        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4348        u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
4349        if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
4350            SAVE_txpwrctrl) {
4351                index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
4352                index2 = (u16) (index * 2);
4353                mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
4354
4355                pi_lcn->lcnphy_current_index =
4356                        (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
4357        }
4358}
4359
4360static void
4361wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
4362                              const struct lcnphy_tx_gain_tbl_entry *gain_table)
4363{
4364        u32 j;
4365        struct phytbl_info tab;
4366        u32 val;
4367        u16 pa_gain;
4368        u16 gm_gain;
4369
4370        if (pi->sh->boardflags & BFL_FEM)
4371                pa_gain = 0x10;
4372        else
4373                pa_gain = 0x60;
4374        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4375        tab.tbl_width = 32;
4376        tab.tbl_len = 1;
4377        tab.tbl_ptr = &val;
4378
4379        /* fixed gm_gain value for iPA */
4380        gm_gain = 15;
4381        for (j = 0; j < 128; j++) {
4382                if (pi->sh->boardflags & BFL_FEM)
4383                        gm_gain = gain_table[j].gm;
4384                val = (((u32) pa_gain << 24) |
4385                       (gain_table[j].pad << 16) |
4386                       (gain_table[j].pga << 8) | gm_gain);
4387
4388                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j;
4389                wlc_lcnphy_write_table(pi, &tab);
4390
4391                val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20);
4392                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j;
4393                wlc_lcnphy_write_table(pi, &tab);
4394        }
4395}
4396
4397static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
4398{
4399        struct phytbl_info tab;
4400        u32 val, bbmult, rfgain;
4401        u8 index;
4402        u8 scale_factor = 1;
4403        s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift;
4404
4405        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
4406        tab.tbl_width = 32;
4407        tab.tbl_len = 1;
4408
4409        for (index = 0; index < 128; index++) {
4410                tab.tbl_ptr = &bbmult;
4411                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index;
4412                wlc_lcnphy_read_table(pi, &tab);
4413                bbmult = bbmult >> 20;
4414
4415                tab.tbl_ptr = &rfgain;
4416                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index;
4417                wlc_lcnphy_read_table(pi, &tab);
4418
4419                qm_log10((s32) (bbmult), 0, &temp1, &qQ1);
4420                qm_log10((s32) (1 << 6), 0, &temp2, &qQ2);
4421
4422                if (qQ1 < qQ2) {
4423                        temp2 = qm_shr16(temp2, qQ2 - qQ1);
4424                        qQ = qQ1;
4425                } else {
4426                        temp1 = qm_shr16(temp1, qQ1 - qQ2);
4427                        qQ = qQ2;
4428                }
4429                temp = qm_sub16(temp1, temp2);
4430
4431                if (qQ >= 4)
4432                        shift = qQ - 4;
4433                else
4434                        shift = 4 - qQ;
4435
4436                val = (((index << shift) + (5 * temp) +
4437                        (1 << (scale_factor + shift - 3))) >> (scale_factor +
4438                                                               shift - 2));
4439
4440                tab.tbl_ptr = &val;
4441                tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index;
4442                wlc_lcnphy_write_table(pi, &tab);
4443        }
4444}
4445
4446static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
4447{
4448        or_phy_reg(pi, 0x805, 0x1);
4449
4450        mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
4451
4452        mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
4453
4454        write_phy_reg(pi, 0x414, 0x1e10);
4455        write_phy_reg(pi, 0x415, 0x0640);
4456
4457        mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
4458
4459        or_phy_reg(pi, 0x44a, 0x44);
4460        write_phy_reg(pi, 0x44a, 0x80);
4461        mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
4462
4463        mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
4464
4465        if (!(pi->sh->boardrev < 0x1204))
4466                mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
4467
4468        write_phy_reg(pi, 0x7d6, 0x0902);
4469        mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
4470
4471        mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
4472
4473        if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4474                mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
4475
4476                mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
4477
4478                mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
4479
4480                mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
4481
4482                mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
4483
4484                mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
4485                mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
4486                mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
4487                mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
4488                mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
4489
4490                mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
4491
4492                wlc_lcnphy_clear_tx_power_offsets(pi);
4493                mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
4494
4495        }
4496}
4497
4498static void wlc_lcnphy_rcal(struct brcms_phy *pi)
4499{
4500        u8 rcal_value;
4501
4502        and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4503
4504        or_radio_reg(pi, RADIO_2064_REG004, 0x40);
4505        or_radio_reg(pi, RADIO_2064_REG120, 0x10);
4506
4507        or_radio_reg(pi, RADIO_2064_REG078, 0x80);
4508        or_radio_reg(pi, RADIO_2064_REG129, 0x02);
4509
4510        or_radio_reg(pi, RADIO_2064_REG057, 0x01);
4511
4512        or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
4513        mdelay(5);
4514        SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
4515
4516        if (wlc_radio_2064_rcal_done(pi)) {
4517                rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
4518                rcal_value = rcal_value & 0x1f;
4519        }
4520
4521        and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
4522
4523        and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
4524}
4525
4526static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
4527{
4528        u8 dflt_rc_cal_val;
4529        u16 flt_val;
4530
4531        dflt_rc_cal_val = 7;
4532        if (LCNREV_IS(pi->pubpi.phy_rev, 1))
4533                dflt_rc_cal_val = 11;
4534        flt_val =
4535                (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
4536                (dflt_rc_cal_val);
4537        write_phy_reg(pi, 0x933, flt_val);
4538        write_phy_reg(pi, 0x934, flt_val);
4539        write_phy_reg(pi, 0x935, flt_val);
4540        write_phy_reg(pi, 0x936, flt_val);
4541        write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
4542
4543        return;
4544}
4545
4546static void wlc_radio_2064_init(struct brcms_phy *pi)
4547{
4548        u32 i;
4549        const struct lcnphy_radio_regs *lcnphyregs = NULL;
4550
4551        lcnphyregs = lcnphy_radio_regs_2064;
4552
4553        for (i = 0; lcnphyregs[i].address != 0xffff; i++)
4554                if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
4555                        write_radio_reg(pi,
4556                                        ((lcnphyregs[i].address & 0x3fff) |
4557                                         RADIO_DEFAULT_CORE),
4558                                        (u16) lcnphyregs[i].init_a);
4559                else if (lcnphyregs[i].do_init_g)
4560                        write_radio_reg(pi,
4561                                        ((lcnphyregs[i].address & 0x3fff) |
4562                                         RADIO_DEFAULT_CORE),
4563                                        (u16) lcnphyregs[i].init_g);
4564
4565        write_radio_reg(pi, RADIO_2064_REG032, 0x62);
4566        write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4567
4568        write_radio_reg(pi, RADIO_2064_REG090, 0x10);
4569
4570        write_radio_reg(pi, RADIO_2064_REG010, 0x00);
4571
4572        if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
4573
4574                write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
4575                write_radio_reg(pi, RADIO_2064_REG061, 0x72);
4576                write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
4577        }
4578
4579        write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
4580        write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
4581
4582        mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
4583
4584        mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
4585
4586        mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
4587
4588        mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
4589
4590        mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
4591
4592        write_phy_reg(pi, 0x4ea, 0x4688);
4593
4594        if (pi->sh->boardflags & BFL_FEM)
4595                mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
4596        else
4597                mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
4598
4599        mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
4600
4601        mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
4602
4603        wlc_lcnphy_set_tx_locc(pi, 0);
4604
4605        wlc_lcnphy_rcal(pi);
4606
4607        wlc_lcnphy_rc_cal(pi);
4608
4609        if (!(pi->sh->boardflags & BFL_FEM)) {
4610                write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
4611                write_radio_reg(pi, RADIO_2064_REG033, 0x19);
4612                write_radio_reg(pi, RADIO_2064_REG039, 0xe);
4613        }
4614
4615}
4616
4617static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
4618{
4619        wlc_radio_2064_init(pi);
4620}
4621
4622static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
4623{
4624        uint idx;
4625        u8 phybw40;
4626        struct phytbl_info tab;
4627        const struct phytbl_info *tb;
4628        u32 val;
4629
4630        phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4631
4632        for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
4633                wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
4634
4635        if (pi->sh->boardflags & BFL_FEM_BT) {
4636                tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4637                tab.tbl_width = 16;
4638                tab.tbl_ptr = &val;
4639                tab.tbl_len = 1;
4640                val = 100;
4641                tab.tbl_offset = 4;
4642                wlc_lcnphy_write_table(pi, &tab);
4643        }
4644
4645        if (!(pi->sh->boardflags & BFL_FEM)) {
4646                tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
4647                tab.tbl_width = 16;
4648                tab.tbl_ptr = &val;
4649                tab.tbl_len = 1;
4650
4651                val = 150;
4652                tab.tbl_offset = 0;
4653                wlc_lcnphy_write_table(pi, &tab);
4654
4655                val = 220;
4656                tab.tbl_offset = 1;
4657                wlc_lcnphy_write_table(pi, &tab);
4658        }
4659
4660        if (CHSPEC_IS2G(pi->radio_chanspec)) {
4661                if (pi->sh->boardflags & BFL_FEM)
4662                        wlc_lcnphy_load_tx_gain_table(
4663                                pi,
4664                                dot11lcnphy_2GHz_extPA_gaintable_rev0);
4665                else
4666                        wlc_lcnphy_load_tx_gain_table(
4667                                pi,
4668                                dot11lcnphy_2GHz_gaintable_rev0);
4669        }
4670
4671        if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
4672                int l;
4673
4674                if (CHSPEC_IS2G(pi->radio_chanspec)) {
4675                        l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
4676                        if (pi->sh->boardflags & BFL_EXTLNA)
4677                                tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
4678                        else
4679                                tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
4680                } else {
4681                        l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
4682                        if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
4683                                tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
4684                        else
4685                                tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
4686                }
4687
4688                for (idx = 0; idx < l; idx++)
4689                        wlc_lcnphy_write_table(pi, &tb[idx]);
4690        }
4691
4692        if (pi->sh->boardflags & BFL_FEM) {
4693                if (pi->sh->boardflags & BFL_FEM_BT) {
4694                        if (pi->sh->boardrev < 0x1250)
4695                                tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa;
4696                        else
4697                                tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250;
4698                } else {
4699                        tb = &dot11lcn_sw_ctrl_tbl_info_4313_epa;
4700                }
4701        } else {
4702                if (pi->sh->boardflags & BFL_FEM_BT)
4703                        tb = &dot11lcn_sw_ctrl_tbl_info_4313_bt_ipa;
4704                else
4705                        tb = &dot11lcn_sw_ctrl_tbl_info_4313;
4706        }
4707        wlc_lcnphy_write_table(pi, tb);
4708        wlc_lcnphy_load_rfpower(pi);
4709
4710        wlc_lcnphy_clear_papd_comptable(pi);
4711}
4712
4713static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
4714{
4715        u16 afectrl1;
4716        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4717
4718        write_radio_reg(pi, RADIO_2064_REG11C, 0x0);
4719
4720        write_phy_reg(pi, 0x43b, 0x0);
4721        write_phy_reg(pi, 0x43c, 0x0);
4722        write_phy_reg(pi, 0x44c, 0x0);
4723        write_phy_reg(pi, 0x4e6, 0x0);
4724        write_phy_reg(pi, 0x4f9, 0x0);
4725        write_phy_reg(pi, 0x4b0, 0x0);
4726        write_phy_reg(pi, 0x938, 0x0);
4727        write_phy_reg(pi, 0x4b0, 0x0);
4728        write_phy_reg(pi, 0x44e, 0);
4729
4730        or_phy_reg(pi, 0x567, 0x03);
4731
4732        or_phy_reg(pi, 0x44a, 0x44);
4733        write_phy_reg(pi, 0x44a, 0x80);
4734
4735        if (!(pi->sh->boardflags & BFL_FEM))
4736                wlc_lcnphy_set_tx_pwr_by_index(pi, 52);
4737
4738        if (0) {
4739                afectrl1 = 0;
4740                afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
4741                                  (pi_lcn->lcnphy_rssi_vc << 4) |
4742                                  (pi_lcn->lcnphy_rssi_gs << 10));
4743                write_phy_reg(pi, 0x43e, afectrl1);
4744        }
4745
4746        mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0);
4747        if (pi->sh->boardflags & BFL_FEM) {
4748                mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0);
4749
4750                write_phy_reg(pi, 0x910, 0x1);
4751        }
4752
4753        mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8);
4754        mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0);
4755        mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0);
4756
4757}
4758
4759static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
4760{
4761        if (CHSPEC_IS5G(pi->radio_chanspec)) {
4762                mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
4763                mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
4764        }
4765}
4766
4767static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
4768{
4769        s16 temp;
4770        struct phytbl_info tab;
4771        u32 tableBuffer[2];
4772        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4773
4774        temp = (s16) read_phy_reg(pi, 0x4df);
4775        pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
4776
4777        if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127)
4778                pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256;
4779
4780        pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8;
4781
4782        if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127)
4783                pi_lcn->lcnphy_dsssgainidxtableoffset -= 256;
4784
4785        tab.tbl_ptr = tableBuffer;
4786        tab.tbl_len = 2;
4787        tab.tbl_id = 17;
4788        tab.tbl_offset = 59;
4789        tab.tbl_width = 32;
4790        wlc_lcnphy_read_table(pi, &tab);
4791
4792        if (tableBuffer[0] > 63)
4793                tableBuffer[0] -= 128;
4794        pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0];
4795
4796        if (tableBuffer[1] > 63)
4797                tableBuffer[1] -= 128;
4798        pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
4799
4800        temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
4801        if (temp > 127)
4802                temp -= 256;
4803        pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
4804
4805        pi_lcn->lcnphy_Med_Low_Gain_db =
4806                (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
4807        pi_lcn->lcnphy_Very_Low_Gain_db =
4808                (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
4809
4810        tab.tbl_ptr = tableBuffer;
4811        tab.tbl_len = 2;
4812        tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX;
4813        tab.tbl_offset = 28;
4814        tab.tbl_width = 32;
4815        wlc_lcnphy_read_table(pi, &tab);
4816
4817        pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0];
4818        pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1];
4819
4820}
4821
4822static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
4823{
4824
4825        wlc_lcnphy_tbl_init(pi);
4826        wlc_lcnphy_rev0_baseband_init(pi);
4827        if (LCNREV_IS(pi->pubpi.phy_rev, 2))
4828                wlc_lcnphy_rev2_baseband_init(pi);
4829        wlc_lcnphy_bu_tweaks(pi);
4830}
4831
4832void wlc_phy_init_lcnphy(struct brcms_phy *pi)
4833{
4834        u8 phybw40;
4835        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4836        phybw40 = CHSPEC_IS40(pi->radio_chanspec);
4837
4838        pi_lcn->lcnphy_cal_counter = 0;
4839        pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
4840
4841        or_phy_reg(pi, 0x44a, 0x80);
4842        and_phy_reg(pi, 0x44a, 0x7f);
4843
4844        wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
4845
4846        write_phy_reg(pi, 0x60a, 160);
4847
4848        write_phy_reg(pi, 0x46a, 25);
4849
4850        wlc_lcnphy_baseband_init(pi);
4851
4852        wlc_lcnphy_radio_init(pi);
4853
4854        if (CHSPEC_IS2G(pi->radio_chanspec))
4855                wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
4856
4857        wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
4858
4859        bcma_chipco_regctl_maskset(&pi->d11core->bus->drv_cc, 0, ~0xf, 0x9);
4860
4861        bcma_chipco_chipctl_maskset(&pi->d11core->bus->drv_cc, 0, 0x0,
4862                                    0x03CDDDDD);
4863
4864        if ((pi->sh->boardflags & BFL_FEM)
4865            && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4866                wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
4867
4868        wlc_lcnphy_agc_temp_init(pi);
4869
4870        wlc_lcnphy_temp_adj(pi);
4871
4872        mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
4873
4874        udelay(100);
4875        mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
4876
4877        wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
4878        pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
4879        wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
4880}
4881
4882static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
4883{
4884        s8 txpwr = 0;
4885        int i;
4886        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
4887        struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
4888
4889        if (CHSPEC_IS2G(pi->radio_chanspec)) {
4890                u16 cckpo = 0;
4891                u32 offset_ofdm, offset_mcs;
4892
4893                pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
4894
4895                pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
4896
4897                pi->txpa_2g[0] = sprom->pa0b0;
4898                pi->txpa_2g[1] = sprom->pa0b1;
4899                pi->txpa_2g[2] = sprom->pa0b2;
4900
4901                pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
4902                pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
4903                pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
4904
4905                pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
4906                pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
4907                pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
4908
4909                pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
4910                pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
4911                pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
4912
4913                txpwr = sprom->core_pwr_info[0].maxpwr_2g;
4914                pi->tx_srom_max_2g = txpwr;
4915
4916                for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
4917                        pi->txpa_2g_low_temp[i] = pi->txpa_2g[i];
4918                        pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
4919                }
4920
4921                cckpo = sprom->cck2gpo;
4922                offset_ofdm = sprom->ofdm2gpo;
4923                if (cckpo) {
4924                        uint max_pwr_chan = txpwr;
4925
4926                        for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
4927                                pi->tx_srom_max_rate_2g[i] =
4928                                        max_pwr_chan - ((cckpo & 0xf) * 2);
4929                                cckpo >>= 4;
4930                        }
4931
4932                        for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4933                                pi->tx_srom_max_rate_2g[i] =
4934                                        max_pwr_chan -
4935                                        ((offset_ofdm & 0xf) * 2);
4936                                offset_ofdm >>= 4;
4937                        }
4938                } else {
4939                        u8 opo = 0;
4940
4941                        opo = sprom->opo;
4942
4943                        for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
4944                                pi->tx_srom_max_rate_2g[i] = txpwr;
4945
4946                        for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
4947                                pi->tx_srom_max_rate_2g[i] = txpwr -
4948                                                ((offset_ofdm & 0xf) * 2);
4949                                offset_ofdm >>= 4;
4950                        }
4951                        offset_mcs = sprom->mcs2gpo[1] << 16;
4952                        offset_mcs |= sprom->mcs2gpo[0];
4953                        pi_lcn->lcnphy_mcs20_po = offset_mcs;
4954                        for (i = TXP_FIRST_SISO_MCS_20;
4955                             i <= TXP_LAST_SISO_MCS_20; i++) {
4956                                pi->tx_srom_max_rate_2g[i] =
4957                                        txpwr - ((offset_mcs & 0xf) * 2);
4958                                offset_mcs >>= 4;
4959                        }
4960                }
4961
4962                pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
4963                pi_lcn->lcnphy_measPower = sprom->measpower;
4964                pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
4965                pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
4966                pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
4967                pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
4968                pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
4969                pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
4970                if (sprom->ant_available_bg > 1)
4971                        wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
4972                                sprom->ant_available_bg);
4973        }
4974        pi_lcn->lcnphy_cck_dig_filt_type = -1;
4975
4976        return true;
4977}
4978
4979void wlc_2064_vco_cal(struct brcms_phy *pi)
4980{
4981        u8 calnrst;
4982
4983        mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3);
4984        calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8;
4985        write_radio_reg(pi, RADIO_2064_REG056, calnrst);
4986        udelay(1);
4987        write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03);
4988        udelay(1);
4989        write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07);
4990        udelay(300);
4991        mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
4992}
4993
4994bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
4995{
4996        if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
4997                return false;
4998        else
4999                return (LCNPHY_TX_PWR_CTRL_HW ==
5000                        wlc_lcnphy_get_tx_pwr_ctrl((pi)));
5001}
5002
5003void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
5004{
5005        u16 pwr_ctrl;
5006        if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
5007                wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
5008        } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
5009                pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
5010                wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
5011                wlc_lcnphy_txpower_recalc_target(pi);
5012                wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
5013        }
5014}
5015
5016void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
5017{
5018        u8 channel = CHSPEC_CHANNEL(chanspec);
5019
5020        wlc_phy_chanspec_radio_set((struct brcms_phy_pub *)pi, chanspec);
5021
5022        wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec);
5023
5024        or_phy_reg(pi, 0x44a, 0x44);
5025        write_phy_reg(pi, 0x44a, 0x80);
5026
5027        wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
5028        udelay(1000);
5029
5030        wlc_lcnphy_toggle_afe_pwdn(pi);
5031
5032        write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20);
5033        write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor);
5034
5035        if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
5036                mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
5037
5038                wlc_lcnphy_load_tx_iir_filter(pi, false, 3);
5039        } else {
5040                mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
5041
5042                wlc_lcnphy_load_tx_iir_filter(pi, false, 2);
5043        }
5044
5045        if (pi->sh->boardflags & BFL_FEM)
5046                wlc_lcnphy_load_tx_iir_filter(pi, true, 0);
5047        else
5048                wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
5049
5050        mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
5051        if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
5052                wlc_lcnphy_tssi_setup(pi);
5053}
5054
5055void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
5056{
5057        kfree(pi->u.pi_lcnphy);
5058}
5059
5060bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
5061{
5062        struct brcms_phy_lcnphy *pi_lcn;
5063
5064        pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
5065        if (pi->u.pi_lcnphy == NULL)
5066                return false;
5067
5068        pi_lcn = pi->u.pi_lcnphy;
5069
5070        if (0 == (pi->sh->boardflags & BFL_NOPA)) {
5071                pi->hwpwrctrl = true;
5072                pi->hwpwrctrl_capable = true;
5073        }
5074
5075        pi->xtalfreq = bcma_chipco_get_alp_clock(&pi->d11core->bus->drv_cc);
5076        pi_lcn->lcnphy_papd_rxGnCtrl_init = 0;
5077
5078        pi->pi_fptr.init = wlc_phy_init_lcnphy;
5079        pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy;
5080        pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy;
5081        pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy;
5082        pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc;
5083        pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc;
5084        pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc;
5085        pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft;
5086        pi->pi_fptr.detach = wlc_phy_detach_lcnphy;
5087
5088        if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
5089                return false;
5090
5091        if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
5092                if (pi_lcn->lcnphy_tempsense_option == 3) {
5093                        pi->hwpwrctrl = true;
5094                        pi->hwpwrctrl_capable = true;
5095                        pi->temppwrctrl_capable = false;
5096                } else {
5097                        pi->hwpwrctrl = false;
5098                        pi->hwpwrctrl_capable = false;
5099                        pi->temppwrctrl_capable = true;
5100                }
5101        }
5102
5103        return true;
5104}
5105
5106static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
5107{
5108        u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19;
5109
5110        trsw = (gain & ((u32) 1 << 28)) ? 0 : 1;
5111        ext_lna = (u16) (gain >> 29) & 0x01;
5112        lna1 = (u16) (gain >> 0) & 0x0f;
5113        lna2 = (u16) (gain >> 4) & 0x0f;
5114        tia = (u16) (gain >> 8) & 0xf;
5115        biq0 = (u16) (gain >> 12) & 0xf;
5116        biq1 = (u16) (gain >> 16) & 0xf;
5117
5118        gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
5119                          ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
5120                          ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
5121        gain16_19 = biq1;
5122
5123        mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
5124        mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
5125        mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
5126        mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
5127        mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
5128
5129        if (CHSPEC_IS2G(pi->radio_chanspec)) {
5130                mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
5131                mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
5132        }
5133        wlc_lcnphy_rx_gain_override_enable(pi, true);
5134}
5135
5136static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
5137{
5138        u32 received_power = 0;
5139        s32 max_index = 0;
5140        u32 gain_code = 0;
5141        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5142
5143        max_index = 36;
5144        if (*gain_index >= 0)
5145                gain_code = lcnphy_23bitgaincode_table[*gain_index];
5146
5147        if (-1 == *gain_index) {
5148                *gain_index = 0;
5149                while ((*gain_index <= (s32) max_index)
5150                       && (received_power < 700)) {
5151                        wlc_lcnphy_set_rx_gain(pi,
5152                                               lcnphy_23bitgaincode_table
5153                                               [*gain_index]);
5154                        received_power =
5155                                wlc_lcnphy_measure_digital_power(
5156                                        pi,
5157                                        pi_lcn->
5158                                        lcnphy_noise_samples);
5159                        (*gain_index)++;
5160                }
5161                (*gain_index)--;
5162        } else {
5163                wlc_lcnphy_set_rx_gain(pi, gain_code);
5164                received_power =
5165                        wlc_lcnphy_measure_digital_power(pi,
5166                                                         pi_lcn->
5167                                                         lcnphy_noise_samples);
5168        }
5169
5170        return received_power;
5171}
5172
5173s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
5174{
5175        s32 gain = 0;
5176        s32 nominal_power_db;
5177        s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
5178            input_power_db;
5179        s32 received_power, temperature;
5180        u32 power;
5181        u32 msb1, msb2, val1, val2, diff1, diff2;
5182        uint freq;
5183        struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
5184
5185        received_power = wlc_lcnphy_get_receive_power(pi, &gain_index);
5186
5187        gain = lcnphy_gain_table[gain_index];
5188
5189        nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
5190
5191        power = (received_power * 16);
5192        msb1 = ffs(power) - 1;
5193        msb2 = msb1 + 1;
5194        val1 = 1 << msb1;
5195        val2 = 1 << msb2;
5196        diff1 = (power - val1);
5197        diff2 = (val2 - power);
5198        if (diff1 < diff2)
5199                log_val = msb1;
5200        else
5201                log_val = msb2;
5202
5203        log_val = log_val * 3;
5204
5205        gain_mismatch = (nominal_power_db / 2) - (log_val);
5206
5207        desired_gain = gain + gain_mismatch;
5208
5209        input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF;
5210
5211        if (input_power_offset_db > 127)
5212                input_power_offset_db -= 256;
5213
5214        input_power_db = input_power_offset_db - desired_gain;
5215
5216        input_power_db =
5217                input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
5218
5219        freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
5220        if ((freq > 2427) && (freq <= 2467))
5221                input_power_db = input_power_db - 1;
5222
5223        temperature = pi_lcn->lcnphy_lastsensed_temperature;
5224
5225        if ((temperature - 15) < -30)
5226                input_power_db =
5227                        input_power_db +
5228                        (((temperature - 10 - 25) * 286) >> 12) -
5229                        7;
5230        else if ((temperature - 15) < 4)
5231                input_power_db =
5232                        input_power_db +
5233                        (((temperature - 10 - 25) * 286) >> 12) -
5234                        3;
5235        else
5236                input_power_db = input_power_db +
5237                                        (((temperature - 10 - 25) * 286) >> 12);
5238
5239        wlc_lcnphy_rx_gain_override_enable(pi, 0);
5240
5241        return input_power_db;
5242}
5243