blob: 805b783ed1b7ffc7a03a505d2ccc408e6f2a8ab0 [file] [log] [blame]
/*
* This file is part of the UWB stack for linux.
*
* Copyright (c) 2020-2021 Qorvo US, Inc.
*
* This software is provided under the GNU General Public License, version 2
* (GPLv2), as well as under a Qorvo commercial license.
*
* You may choose to use this software under the terms of the GPLv2 License,
* version 2 ("GPLv2"), as published by the Free Software Foundation.
* You should have received a copy of the GPLv2 along with this program. If
* not, see <http://www.gnu.org/licenses/>.
*
* This program is distributed under the GPLv2 in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GPLv2 for more
* details.
*
* If you cannot meet the requirements of the GPLv2, you may not use this
* software for any purpose without first obtaining a commercial license from
* Qorvo. Please contact Qorvo to inquire about licensing terms.
*/
#include "dw3000.h"
#include "dw3000_core.h"
#include "dw3000_core_reg.h"
#include "dw3000_chip_c0.h"
#define DW3000_C0_DGC_DBG_ID 0x30060
static const struct dw3000_chip_register c0_registers[] = {
/* virtual registers for fileID dump */
{ "GEN_CFG0", 0x00, 0x79, 0, DW3000_CHIPREG_DUMP, NULL },
{ "GEN_CFG1", 0x01, 0x64, 0, DW3000_CHIPREG_DUMP, NULL },
{ "STS_CFG", 0x02, 0x2c, 0, DW3000_CHIPREG_DUMP, NULL },
/* No fileID 0x03 documented in DW3000 user manual v0.7. */
{ "EXT_SYNC", 0x04, 0x04, 0, DW3000_CHIPREG_DUMP, NULL },
{ "GPIO_CTRL", 0x05, 0x2e, 0, DW3000_CHIPREG_DUMP, NULL },
{ "DRX_CONF", 0x06, 0x10, 0, DW3000_CHIPREG_DUMP, NULL },
{ "RF_CONF", 0x07, 0x4c, 0, DW3000_CHIPREG_DUMP, NULL },
{ "TX_CAL", 0x08, 0x1e, 0, DW3000_CHIPREG_DUMP, NULL },
{ "FS_CTRL", 0x09, 0x15, 0, DW3000_CHIPREG_DUMP, NULL },
{ "AON", 0x0a, 0x15, 0, DW3000_CHIPREG_DUMP, NULL },
{ "OTP_IF", 0x0b, 0x18, 0, DW3000_CHIPREG_DUMP, NULL },
{ "CIA_1", 0x0c, 0x6c, 0, DW3000_CHIPREG_DUMP, NULL },
{ "CIA_2", 0x0d, 0x6c, 0, DW3000_CHIPREG_DUMP, NULL },
{ "CIA_3", 0x0e, 0x20, 0, DW3000_CHIPREG_DUMP, NULL },
{ "DIG_DIAG", 0x0f, 0x51, 0, DW3000_CHIPREG_DUMP, NULL },
{ "PMSC", 0x11, 0x4a, 0, DW3000_CHIPREG_DUMP, NULL },
/* TODO: RX/TX buffers limited to first 128bytes only.
Shall we dump the whole 1024 bytes? */
{ "RX_BUFFER", 0x12, 0x80, 0, DW3000_CHIPREG_DUMP, NULL },
{ "RX_BUFFER1", 0x13, 0x80, 0, DW3000_CHIPREG_DUMP, NULL },
/* No TX_BUFFER as read isn't supported */
/* CIR memory require 2 bits configured elsewhere, so removed. */
{ "SCRATCH_RAM", 0x16, 0x7f, 0, DW3000_CHIPREG_DUMP, NULL },
{ "AES RAM", 0x17, 0x80, 0, DW3000_CHIPREG_DUMP, NULL },
{ "SET_X", 0x18, 0x1d0, 0, DW3000_CHIPREG_DUMP, NULL },
{ "IN_PTR_CFG", 0x1f, 0x12, 0, DW3000_CHIPREG_DUMP, NULL },
};
const struct dw3000_chip_register *dw3000_c0_get_registers(struct dw3000 *dw,
size_t *count)
{
*count = ARRAY_SIZE(c0_registers);
return c0_registers;
}
const u32 *dw3000_c0_get_config_mrxlut_chan(struct dw3000 *dw, u8 channel)
{
/* Lookup table default values for channel 5 */
static const u32 dw3000_c0_configmrxlut_ch5[DW3000_CONFIGMRXLUT_MAX] = {
0x1c0fd, 0x1c47d, 0x1c67d, 0x1c7fd, 0x1cf7d, 0x1cffd, 0x0fffd
};
/* Lookup table default values for channel 9 */
static const u32 dw3000_c0_configmrxlut_ch9[DW3000_CONFIGMRXLUT_MAX] = {
0x2a07d, 0x2a3fd, 0x2a57d, 0x2a77d, 0x2a7fd, 0x2ad7d, 0x2affd
};
switch (channel) {
case 5:
return dw3000_c0_configmrxlut_ch5;
case 9:
return dw3000_c0_configmrxlut_ch9;
default:
return NULL;
}
}
static int dw3000_c0_softreset(struct dw3000 *dw)
{
/* Reset HIF, TX, RX and PMSC */
return dw3000_reg_write8(dw, DW3000_SOFT_RST_ID, 0, DW3000_RESET_ALL);
}
static int dw3000_c0_init(struct dw3000 *dw)
{
/* TODO */
return 0;
}
static int dw3000_c0_coex_init(struct dw3000 *dw)
{
/* TODO */
return 0;
}
static int dw3000_c0_coex_gpio(struct dw3000 *dw, bool state, int delay_us)
{
/* TODO */
return 0;
}
/**
* dw3000_prog_ldo_and_bias_tune() - Programs the device's LDO and BIAS tuning
* @dw: The DW device.
*
* Return: zero on success, else a negative error code.
*/
static int dw3000_c0_prog_ldo_and_bias_tune(struct dw3000 *dw)
{
const u16 bias_mask = DW3000_BIAS_CTRL_DIG_BIAS_DAC_ULV_BIT_MASK;
struct dw3000_local_data *local = &dw->data;
struct dw3000_otp_data *otp = &dw->otp_data;
int rc;
u16 bias_tune = (otp->bias_tune >> 16) & bias_mask;
if (otp->ldo_tune_lo && otp->ldo_tune_hi && bias_tune) {
rc = dw3000_reg_or16(dw, DW3000_NVM_CFG_ID, 0,
DW3000_LDO_BIAS_KICK);
if (rc)
return rc;
rc = dw3000_reg_modify16(dw, DW3000_BIAS_CTRL_ID, 0, ~bias_mask,
bias_tune);
if (rc)
return rc;
}
local->dgc_otp_set = false;
return 0;
}
/**
* dw3000_c0_pre_read_sys_time() - Ensure SYS_TIME register is cleared
* @dw: The DW device.
*
* On C0 chips, the SYS_TIME register value is latched and any subsequent read
* will return the same value. To clear the current value in the register an SPI
* write transaction is necessary, the following read of the SYS_TIME register will
* return a new value.
*
* Return: zero on success, else a negative error code.
*/
static int dw3000_c0_pre_read_sys_time(struct dw3000 *dw)
{
/* The SPI_COLLISION register is choose to make this SPI write
* transaction because it is unused and it is a small 8 bits register.
*/
return dw3000_clear_spi_collision_status(
dw, DW3000_SPI_COLLISION_STATUS_BIT_MASK);
}
/**
* dw3000_c0_get_dgc_dbg() - Read DGC_DBG register content
* @dw: The DW device.
* @value: Pointer to store DGC DECISION value.
*
* Return: zero on succes, else a negative error code.
*/
int dw3000_c0_get_dgc_dec(struct dw3000 *dw, u8 *value)
{
int rc;
u32 dgc_dbg;
rc = dw3000_reg_read32(dw, DW3000_C0_DGC_DBG_ID, 0, &dgc_dbg);
if (unlikely(rc))
return rc;
/* DGC_DECISION is on bits 28 to 30 of DGC_CFG, cf 8.2.4.2 of DW3700
* User Manual, store it to right the rssi stats entry */
*value = (u8)((dgc_dbg & 0x70000000) >> 0x1c);
return 0;
}
/**
* dw3000_c0_pll_calibration_from_scratch() - Calibrate the PLL from scratch
* @dw: the DW device
*
* Return: zero on success, else a negative error code.
*/
static int dw3000_c0_pll_calibration_from_scratch(struct dw3000 *dw)
{
int rc = 0;
/* Run the PLL calibration from scratch.
* The USE_OLD_BIT_MASK tells the chip to use the an old PLL_CAL_ID to start
* its calculation. This is just in order to fasten the process.
*/
rc = dw3000_reg_or32(dw, DW3000_PLL_CAL_ID, 0,
DW3000_PLL_CAL_PLL_CAL_EN_BIT_MASK |
DW3000_PLL_CAL_PLL_USE_OLD_BIT_MASK);
if (rc)
return rc;
/* Wait for the PLL calibration (needed before read the calibration status register) */
usleep_range(DW3000_C0_PLL_CALIBRATION_FROM_SCRATCH_DELAY_US,
DW3000_C0_PLL_CALIBRATION_FROM_SCRATCH_DELAY_US + 10);
return rc;
}
/**
* dw3000_c0_prog_pll_coarse_code() - Programs the device's coarse code
* @dw: The DW device.
*
* Return: zero on success, else a negative error code.
*/
int dw3000_c0_prog_pll_coarse_code(struct dw3000 *dw)
{
struct dw3000_otp_data *otp = &dw->otp_data;
int rc = 0;
if (otp->pll_coarse_code) {
/* set the coarse code value as read from OTP */
rc = dw3000_reg_write8(dw, DW3000_PLL_COARSE_CODE_ID, 0,
otp->pll_coarse_code);
}
return rc;
}
const struct dw3000_chip_ops dw3000_chip_c0_ops = {
.softreset = dw3000_c0_softreset,
.init = dw3000_c0_init,
.coex_init = dw3000_c0_coex_init,
.coex_gpio = dw3000_c0_coex_gpio,
.prog_ldo_and_bias_tune = dw3000_c0_prog_ldo_and_bias_tune,
.get_config_mrxlut_chan = dw3000_c0_get_config_mrxlut_chan,
.get_dgc_dec = dw3000_c0_get_dgc_dec,
.pre_read_sys_time = dw3000_c0_pre_read_sys_time,
.pll_calibration_from_scratch = dw3000_c0_pll_calibration_from_scratch,
.prog_pll_coarse_code = dw3000_c0_prog_pll_coarse_code,
.get_registers = dw3000_c0_get_registers,
};