[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20181219155616.9547-3-ben.whitten@lairdtech.com>
Date: Wed, 19 Dec 2018 15:56:14 +0000
From: Ben Whitten <ben.whitten@...il.com>
To: starnight@...cu.edu.tw, jiri@...nulli.us, afaerber@...e.de
Cc: linux-lpwan@...ts.infradead.org,
linux-arm-kernel@...ts.infradead.org, netdev@...r.kernel.org,
Ben Whitten <ben.whitten@...rdtech.com>,
"David S. Miller" <davem@...emloft.net>,
linux-kernel@...r.kernel.org
Subject: [PATCH RFC lora-next 2/4] net: lora: sx1301: add minimal to get AGC working prior to tx work
As part of initialisation when opening the lora device after loading
the AGC firmware we need to satisfy its startup procedure which involves
a few steps;
Loading a 16 entry lookup table.
For this I have hard coded the laird ETSI certified table for use on the
RG186-M2 (EU) cards, this will need investigation on how other devices
load calibration data.
Selecting the correct channel to transmit on.
Currently always 0 for the reference design.
Then ending the AGC init procedure and seeing that it has come up.
Signed-off-by: Ben Whitten <ben.whitten@...rdtech.com>
---
drivers/net/lora/sx1301.c | 254 +++++++++++++++++++++++++++++++++++++-
drivers/net/lora/sx1301.h | 16 +++
2 files changed, 268 insertions(+), 2 deletions(-)
diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c
index e75df93b96d8..0c7b6d0b31af 100644
--- a/drivers/net/lora/sx1301.c
+++ b/drivers/net/lora/sx1301.c
@@ -24,6 +24,121 @@
#include "sx1301.h"
+static struct sx1301_tx_gain_lut tx_gain_lut[] = {
+ {
+ .dig_gain = 0,
+ .pa_gain = 0,
+ .dac_gain = 3,
+ .mix_gain = 8,
+ .rf_power = -3,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 0,
+ .dac_gain = 3,
+ .mix_gain = 9,
+ .rf_power = 0,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 0,
+ .dac_gain = 3,
+ .mix_gain = 12,
+ .rf_power = 3,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 0,
+ .dac_gain = 3,
+ .mix_gain = 13,
+ .rf_power = 4,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 1,
+ .dac_gain = 3,
+ .mix_gain = 8,
+ .rf_power = 6,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 1,
+ .dac_gain = 3,
+ .mix_gain = 9,
+ .rf_power = 9,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 1,
+ .dac_gain = 3,
+ .mix_gain = 10,
+ .rf_power = 10,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 1,
+ .dac_gain = 3,
+ .mix_gain = 11,
+ .rf_power = 12,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 1,
+ .dac_gain = 3,
+ .mix_gain = 12,
+ .rf_power = 13,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 1,
+ .dac_gain = 3,
+ .mix_gain = 13,
+ .rf_power = 14,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 1,
+ .dac_gain = 3,
+ .mix_gain = 15,
+ .rf_power = 16,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 2,
+ .dac_gain = 3,
+ .mix_gain = 10,
+ .rf_power = 19,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 2,
+ .dac_gain = 3,
+ .mix_gain = 11,
+ .rf_power = 21,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 2,
+ .dac_gain = 3,
+ .mix_gain = 12,
+ .rf_power = 22,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 2,
+ .dac_gain = 3,
+ .mix_gain = 13,
+ .rf_power = 24,
+ },
+ {
+ .dig_gain = 0,
+ .pa_gain = 2,
+ .dac_gain = 3,
+ .mix_gain = 14,
+ .rf_power = 25,
+ },
+};
+
static const struct regmap_range_cfg sx1301_regmap_ranges[] = {
{
.name = "Pages",
@@ -184,6 +299,34 @@ static int sx1301_load_firmware(struct sx1301_priv *priv, int mcu,
return 0;
}
+static int sx1301_agc_transaction(struct sx1301_priv *priv, unsigned int val,
+ unsigned int *status)
+{
+ int ret;
+
+ ret = regmap_write(priv->regmap, SX1301_CHRS, SX1301_AGC_CMD_WAIT);
+ if (ret) {
+ dev_err(priv->dev, "AGC transaction start failed\n");
+ return ret;
+ }
+ usleep_range(1000, 2000);
+
+ ret = regmap_write(priv->regmap, SX1301_CHRS, val);
+ if (ret) {
+ dev_err(priv->dev, "AGC transaction value failed\n");
+ return ret;
+ }
+ usleep_range(1000, 2000);
+
+ ret = regmap_read(priv->regmap, SX1301_AGCSTS, status);
+ if (ret) {
+ dev_err(priv->dev, "AGC status read failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int sx1301_agc_calibrate(struct sx1301_priv *priv)
{
const struct firmware *fw;
@@ -356,9 +499,53 @@ static int sx1301_load_all_firmware(struct sx1301_priv *priv)
return -ENXIO;
}
- return 0;
+ return ret;
}
+static int sx1301_load_tx_gain_lut(struct sx1301_priv *priv)
+{
+ struct sx1301_tx_gain_lut *lut = priv->tx_gain_lut;
+ unsigned int val, status;
+ int ret, i;
+
+ /* HACK use internal gain table in the short term */
+ lut = tx_gain_lut;
+ priv->tx_gain_lut_size = ARRAY_SIZE(tx_gain_lut);
+
+ for (i = 0; i < priv->tx_gain_lut_size; i++) {
+ val = lut->mix_gain + (lut->dac_gain << 4) +
+ (lut->pa_gain << 6);
+
+ ret = sx1301_agc_transaction(priv, val, &status);
+ if (ret) {
+ dev_err(priv->dev, "AGC LUT load failed\n");
+ return ret;
+ }
+ if (status != (0x30 + i)) {
+ dev_err(priv->dev,
+ "AGC firmware LUT init error: 0x%02X\n", val);
+ return -ENXIO;
+ }
+ lut++;
+ }
+
+ /* Abort the transaction if there are less then 16 entries */
+ if (priv->tx_gain_lut_size < SX1301_TX_GAIN_LUT_MAX) {
+ ret = sx1301_agc_transaction(priv, SX1301_AGC_CMD_ABORT, &val);
+ if (ret) {
+ dev_err(priv->dev, "AGC LUT abort failed\n");
+ return ret;
+ }
+ if (val != 0x30) {
+ dev_err(priv->dev,
+ "AGC firmware LUT abort error: 0x%02X\n", val);
+ return -ENXIO;
+ }
+ }
+
+ return ret;
+};
+
static netdev_tx_t sx130x_loradev_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
@@ -378,6 +565,7 @@ static int sx130x_loradev_open(struct net_device *netdev)
{
struct sx1301_priv *priv = netdev_priv(netdev);
int ret;
+ unsigned int val;
netdev_dbg(netdev, "%s", __func__);
@@ -416,12 +604,74 @@ static int sx130x_loradev_open(struct net_device *netdev)
if (ret)
return ret;
- /* TODO */
+ /* TODO Load constant adjustments, patches */
+
+ /* TODO Frequency time drift */
+
+ /* TODO Configure lora multi demods, bitfield of active */
+
+ /* TODO Load concenrator multi channel frequencies */
+
+ /* TODO enale to correlator on enabled frequenies */
+
+ /* TODO PPMi, and modem enable */
ret = sx1301_load_all_firmware(priv);
if (ret)
return ret;
+ usleep_range(1000, 2000);
+
+ ret = regmap_read(priv->regmap, SX1301_AGCSTS, &val);
+ if (ret) {
+ dev_err(priv->dev, "AGC status read failed\n");
+ return ret;
+ }
+ if (val != 0x10) {
+ dev_err(priv->dev, "AGC firmware init failure: 0x%02X\n", val);
+ return -ENXIO;
+ }
+
+ ret = sx1301_load_tx_gain_lut(priv);
+ if (ret)
+ return ret;
+
+ /* Load Tx freq MSBs
+ * Always 3 if f > 768 for SX1257 or f > 384 for SX1255
+ */
+ ret = sx1301_agc_transaction(priv, 3, &val);
+ if (ret) {
+ dev_err(priv->dev, "AGC Tx MSBs load failed\n");
+ return ret;
+ }
+ if (val != 0x33) {
+ dev_err(priv->dev, "AGC firmware Tx MSBs error: 0x%02X\n", val);
+ return -ENXIO;
+ }
+
+ /* Load chan_select firmware option */
+ ret = sx1301_agc_transaction(priv, 0, &val);
+ if (ret) {
+ dev_err(priv->dev, "AGC chan select failed\n");
+ return ret;
+ }
+ if (val != 0x30) {
+ dev_err(priv->dev,
+ "AGC firmware chan select error: 0x%02X", val);
+ return -ENXIO;
+ }
+
+ /* End AGC firmware init and check status */
+ ret = sx1301_agc_transaction(priv, 0, &val);
+ if (ret) {
+ dev_err(priv->dev, "AGC radio select failed\n");
+ return ret;
+ }
+ if (val != 0x40) {
+ dev_err(priv->dev, "AGC firmware init error: 0x%02X", val);
+ return -ENXIO;
+ }
+
ret = open_loradev(netdev);
if (ret)
return ret;
diff --git a/drivers/net/lora/sx1301.h b/drivers/net/lora/sx1301.h
index dd2b7da94fcc..04c9af64c181 100644
--- a/drivers/net/lora/sx1301.h
+++ b/drivers/net/lora/sx1301.h
@@ -20,6 +20,11 @@
#define SX1301_MCU_AGC_FW_VERSION 4
#define SX1301_MCU_AGC_CAL_FW_VERSION 2
+#define SX1301_AGC_CMD_WAIT 16
+#define SX1301_AGC_CMD_ABORT 17
+
+#define SX1301_TX_GAIN_LUT_MAX 16
+
/* Page independent */
#define SX1301_PAGE 0x00
#define SX1301_VER 0x01
@@ -105,6 +110,14 @@ static const struct reg_field sx1301_regmap_fields[] = {
REG_FIELD(SX1301_EMERGENCY_FORCE_HOST_CTRL, 0, 0),
};
+struct sx1301_tx_gain_lut {
+ unsigned int dig_gain;
+ unsigned int pa_gain;
+ unsigned int dac_gain;
+ unsigned int mix_gain;
+ int rf_power; /* dBm measured at board connector */
+};
+
struct sx1301_priv {
struct lora_dev_priv lora;
struct device *dev;
@@ -112,6 +125,9 @@ struct sx1301_priv {
struct gpio_desc *rst_gpio;
struct regmap *regmap;
struct regmap_field *regmap_fields[ARRAY_SIZE(sx1301_regmap_fields)];
+
+ struct sx1301_tx_gain_lut tx_gain_lut[SX1301_TX_GAIN_LUT_MAX];
+ u8 tx_gain_lut_size;
};
int __init sx130x_radio_init(void);
--
2.17.1
Powered by blists - more mailing lists