mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Ben Whitten <ben.whitten@gmail.com>
To: starnight@g.ncu.edu.tw, jiri@resnulli.us, afaerber@suse.de
Cc: linux-lpwan@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org,
	Ben Whitten <ben.whitten@lairdtech.com>,
	"David S. Miller" <davem@davemloft.net>,
	linux-kernel@vger.kernel.org
Subject: [PATCH RFC lora-next 2/4] net: lora: sx1301: add minimal to get AGC working prior to tx work
Date: Wed, 19 Dec 2018 15:56:14 +0000	[thread overview]
Message-ID: <20181219155616.9547-3-ben.whitten@lairdtech.com> (raw)
In-Reply-To: <20181219155616.9547-1-ben.whitten@lairdtech.com>

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@lairdtech.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


  parent reply	other threads:[~2018-12-19 15:56 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20181219155616.9547-1-ben.whitten@lairdtech.com>
2018-12-19 15:56 ` [PATCH RFC lora-next 1/4] net: lora: sx125x sx1301: correct style warnings Ben Whitten
2018-12-29  0:05   ` Andreas Färber
2019-01-05  7:36     ` Ben Whitten
2018-12-19 15:56 ` Ben Whitten [this message]
2018-12-29  0:58   ` [PATCH RFC lora-next 2/4] net: lora: sx1301: add minimal to get AGC working prior to tx work Andreas Färber
2019-01-04 12:42     ` Ben Whitten
2018-12-19 15:56 ` [PATCH RFC lora-next 3/4] net: lora: sx1301: add minimal to get transmission out Ben Whitten
2018-12-30 20:21   ` Andreas Färber
2018-12-19 15:56 ` [PATCH RFC lora-next 4/4] net: lora: sx1301: introduce a lora frame for packet metadata Ben Whitten
2018-12-30 23:38   ` Andreas Färber

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181219155616.9547-3-ben.whitten@lairdtech.com \
    --to=ben.whitten@gmail.com \
    --cc=afaerber@suse.de \
    --cc=ben.whitten@lairdtech.com \
    --cc=davem@davemloft.net \
    --cc=jiri@resnulli.us \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-lpwan@lists.infradead.org \
    --cc=netdev@vger.kernel.org \
    --cc=starnight@g.ncu.edu.tw \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®