// SPDX-License-Identifier: GPL-2.0-or-later
/*
Broadcom B43 wireless driver
IEEE 802.11n HT-PHY support
Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com>
*/
#include <linux/slab.h>
#include "b43.h"
#include "phy_ht.h"
#include "tables_phy_ht.h"
#include "radio_2059.h"
#include "main.h"
/* Force values to keep compatibility with wl */
enum ht_rssi_type {
HT_RSSI_W1 = 0,
HT_RSSI_W2 = 1,
HT_RSSI_NB = 2,
HT_RSSI_IQ = 3,
HT_RSSI_TSSI_2G = 4,
HT_RSSI_TSSI_5G = 5,
HT_RSSI_TBD = 6,
};
/**************************************************
* Radio 2059.
**************************************************/
static void b43_radio_2059_channel_setup(struct b43_wldev *dev,
const struct b43_phy_ht_channeltab_e_radio2059 *e)
{
static const u16 routing[] = { R2059_C1, R2059_C2, R2059_C3, };
u16 r;
int core;
b43_radio_write(dev, 0x16, e->radio_syn16);
b43_radio_write(dev, 0x17, e->radio_syn17);
b43_radio_write(dev, 0x22, e->radio_syn22);
b43_radio_write(dev, 0x25, e->radio_syn25);
b43_radio_write(dev, 0x27, e->radio_syn27);
b43_radio_write(dev, 0x28, e->radio_syn28);
b43_radio_write(dev, 0x29, e->radio_syn29);
b43_radio_write(dev, 0x2c, e->radio_syn2c);
b43_radio_write(dev, 0x2d, e->radio_syn2d);
b43_radio_write(dev, 0x37, e->radio_syn37);
b43_radio_write(dev, 0x41, e->radio_syn41);
b43_radio_write(dev, 0x43, e->radio_syn43);
b43_radio_write(dev, 0x47, e->radio_syn47);
for (core = 0; core < 3; core++) {
r = routing[core];
b43_radio_write(dev, r | 0x4a, e->radio_rxtx4a);
b43_radio_write(dev, r | 0x58, e->radio_rxtx58);
b43_radio_write(dev, r | 0x5a, e->radio_rxtx5a);
b43_radio_write(dev, r | 0x6a, e->radio_rxtx6a);
b43_radio_write(dev, r | 0x6d, e->radio_rxtx6d);
b43_radio_write(dev, r | 0x6e, e->radio_rxtx6e);
b43_radio_write(dev, r | 0x92, e->radio_rxtx92);
b43_radio_write(dev, r | 0x98, e->radio_rxtx98);
}
udelay(50);
/* Calibration */
b43_radio_mask(dev, R2059_RFPLL_MISC_EN, ~0x1);
b43_radio_mask(dev, R2059_RFPLL_MISC_CAL_RESETN, ~0x4);
b43_radio_set(dev, R2059_RFPLL_MISC_CAL_RESETN, 0x4);
b43_radio_set(dev, R2059_RFPLL_MISC_EN, 0x1);
udelay(300);
}
/* Calibrate resistors in LPF of PLL? */
static void b43_radio_2059_rcal(struct b43_wldev *dev)
{
/* Enable */
b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x1);
usleep_range(10, 20);
b43_radio_set(dev, R2059_C3 | 0x0BF, 0x1);
b43_radio_maskset(dev, R2059_C3 | 0x19B, 0x3, 0x2);
/* Start */
b43_radio_set(dev, R2059_C3 | R2059_RCAL_CONFIG, 0x2);
usleep_range(100, 200);
/* Stop */
b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x2);
if (!b43_radio_wait_value(dev, R2059_C3 | R2059_RCAL_STATUS, 1, 1, 100,
1000000))
b43err(dev->wl, "Radio 0x2059 rcal timeout\n");
/* Disable */
b43_radio_mask(dev, R2059_C3 | R2059_RCAL_CONFIG, ~0x1);
b43_radio_set(dev, 0xa, 0x60);
}
/* Calibrate the internal RC oscillator? */
static void b43_radio_2057_rccal(struct b43_wldev *dev)
{
static const u16 radio_values[3][2] = {
{ 0x61, 0xE9 }, { 0x69, 0xD5 }, { 0x73, 0x99 },
};
int i;
for (i = 0; i < 3; i++) {
b43_radio_write(dev, R2059_RCCAL_MASTER, radio_values[i][0]);
b43_radio_write(dev, R2059_RCCAL_X1, 0x6E);
b43_radio_write(dev, R2059_RCCAL_TRC0, radio_values[i][1]);
/* Start */
b43_radio_write(dev, R2059_RCCAL_START_R1_Q1_P1, 0x55);
/* Wait */
if