Commit 65960c4d authored by Gerson Fernando Budke's avatar Gerson Fernando Budke Committed by Martí Bolívar
Browse files

drivers: ieee802154: rf2xx: Move power table to devicetree



The current version of power table is hardcoded in the driver which is a
problem when use devices in production. This change remove all hardcode
from driver and reimplement the feature to allow people create a table
which is defined in devicetree. The big advantage is that each board can
define their own table based on lab tests and allows use of FEM devices
inclusive.

Signed-off-by: default avatarGerson Fernando Budke <nandojve@gmail.com>
parent b17823d0
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -160,6 +160,14 @@
		slptr-gpios = <&porta 20 GPIO_ACTIVE_HIGH>;
		dig2-gpios = <&portb 17 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>;
		status = "okay";
		tx-pwr-min = [01 11];	/* -17.0 dBm */
		tx-pwr-max = [00 04];	/*   4.0 dBm */
		tx-pwr-table = [00 01 03 04 05 05 06 06
				07 07 07 08 08 09 09 0a
				0a 0a 0b 0b 0b 0b 0c 0c
				0c 0c 0d 0d 0d 0d 0d 0d
				0d 0d 0e 0e 0e 0e 0e 0e
				0e 0e 0e 0e 0e 0e 0f 0f];
	};
};

+94 −67
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

#include <zephyr/kernel.h>
#include <zephyr/arch/cpu.h>
@@ -66,48 +67,6 @@ static struct net_pkt rf2xx_ack_pkt = {
};
#endif /* CONFIG_NET_L2_OPENTHREAD */

/**
 * RF output power for RF2xx
 *
 * The table below is exact for RF233. For RF231/2 the TX power might
 * be a bit off, but good enough.
 *
 * RF233: http://ww1.microchip.com/downloads/en/devicedoc/atmel-8351-mcu_wireless-at86rf233_datasheet.pdf
 * 9.2.5 Register Description Register 0x05 (PHY_TX_PWR)
 * 0x0 = 4dBm .. 0xF = -17dBm
 *
 * RF232: http://ww1.microchip.com/downloads/en/DeviceDoc/doc8321.pdf
 * 9.2.5 Register Description Register 0x05 (PHY_TX_PWR)
 * 0x0 = 3dBm .. 0xF = -17dBm
 *
 * RF231: http://ww1.microchip.com/downloads/en/DeviceDoc/doc8111.pdf
 * 9.2.5 Register Description Register 0x05 (PHY_TX_PWR)
 * 0x0 = 3dBm .. 0xF = -17dBm
 */

#define RF2XX_OUTPUT_POWER_MAX		4
#define RF2XX_OUTPUT_POWER_MIN		(-17)

/* Lookup table for PHY_TX_PWR register for RF233 */
static const uint8_t phy_tx_pwr_lt[] = {
	0xf,                     /* -17  dBm: -17 */
	0xe, 0xe, 0xe, 0xe, 0xe, /* -12  dBm: -16, -15, -14, -13, -12 */
	0xd, 0xd, 0xd, 0xd,      /* -8   dBm: -11, -10, -9, -8 */
	0xc, 0xc,                /* -6   dBm: -7, -6 */
	0xb, 0xb,                /* -4   dBm: -5, -4 */
	0xa,                     /* -3   dBm: -3 */
	0x9,                     /* -2   dBm: -2 */
	0x8,                     /* -1   dBm: -1 */
	0x7,                     /*  0.0 dBm:  0 */
	0x6,                     /*  1   dBm:  1 */
	0x5,                     /*  2   dBm:  2 */
	/* 0x4, */               /*  2.5 dBm */
	0x3,                     /*  3   dBm:  3 */
	/* 0x2, */               /*  3.4 dBm */
	/* 0x1, */               /*  3.7 dBm */
	0x0                      /*  4   dBm: 4 */
};

/* Radio Transceiver ISR */
static inline void trx_isr_handler(const struct device *port,
				   struct gpio_callback *cb,
@@ -409,22 +368,77 @@ static int rf2xx_set_channel(const struct device *dev, uint16_t channel)

static int rf2xx_set_txpower(const struct device *dev, int16_t dbm)
{
	if (dbm < RF2XX_OUTPUT_POWER_MIN) {
		LOG_INF("TX-power %d dBm below min of %d dBm, using %d dBm",
			dbm,
			RF2XX_OUTPUT_POWER_MIN,
			RF2XX_OUTPUT_POWER_MAX);
		dbm = RF2XX_OUTPUT_POWER_MIN;
	} else if (dbm > RF2XX_OUTPUT_POWER_MAX) {
		LOG_INF("TX-power %d dBm above max of %d dBm, using %d dBm",
			dbm,
			RF2XX_OUTPUT_POWER_MIN,
			RF2XX_OUTPUT_POWER_MAX);
		dbm = RF2XX_OUTPUT_POWER_MAX;
	}

	rf2xx_iface_reg_write(dev, RF2XX_PHY_TX_PWR_REG,
		phy_tx_pwr_lt[dbm - RF2XX_OUTPUT_POWER_MIN]);
	const struct rf2xx_config *conf = dev->config;
	struct rf2xx_context *ctx = dev->data;
	float min, max, step;
	uint8_t reg;
	uint8_t idx;
	uint8_t val;

	LOG_DBG("Try set Power to %d", dbm);

	/**
	 * if table size is equal 1 the code assumes a table was not defined. In
	 * this case the transceiver PHY_TX_PWR register will be set with value
	 * zero. This is a safe value for all variants and represents an output
	 * power above 0 dBm.
	 *
	 * Note: This is a special case too which avoid division by zero when
	 * computing the step variable.
	 */
	if (conf->tx_pwr_table_size == 1) {
		rf2xx_iface_reg_write(dev, RF2XX_PHY_TX_PWR_REG, 0);

		return 0;
	}

	min = conf->tx_pwr_min[1];
	if (conf->tx_pwr_min[0] == 0x01) {
		min *= -1.0;
	}

	max = conf->tx_pwr_max[1];
	if (conf->tx_pwr_max[0] == 0x01) {
		min *= -1.0;
	}

	step = (max - min) / ((float)conf->tx_pwr_table_size - 1.0);

	if (step == 0.0) {
		step = 1.0;
	}

	LOG_DBG("Tx-power values: min %f, max %f, step %f, entries %d",
		min, max, step, conf->tx_pwr_table_size);

	if (dbm < min) {
		LOG_INF("TX-power %d dBm below min of %f dBm, using %f dBm",
			dbm, min, max);
		dbm = min;
	} else if (dbm > max) {
		LOG_INF("TX-power %d dBm above max of %f dBm, using %f dBm",
			dbm, min, max);
		dbm = max;
	}

	idx = abs(((float)(dbm - max) / step));
	LOG_DBG("Tx-power idx: %d", idx);

	if (idx >= conf->tx_pwr_table_size) {
		idx = conf->tx_pwr_table_size - 1;
	}

	val = conf->tx_pwr_table[idx];

	if (ctx->trx_model != RF2XX_TRX_MODEL_212) {
		reg = rf2xx_iface_reg_read(dev, RF2XX_PHY_TX_PWR_REG) & 0xf0;
		val = reg + (val & 0x0f);
	}

	LOG_DBG("Tx-power normalized: %d dBm, PHY_TX_PWR 0x%02x, idx %d",
		dbm, val, idx);

	rf2xx_iface_reg_write(dev, RF2XX_PHY_TX_PWR_REG, val);

	return 0;
}
@@ -932,6 +946,14 @@ static struct ieee802154_radio_api rf2xx_radio_api = {
			  DT_INST_PROP(n, local_mac_address)))

#define IEEE802154_RF2XX_DEVICE_CONFIG(n)				  \
	BUILD_ASSERT(DT_INST_PROP_LEN(n, tx_pwr_min) == 2,		  \
	"rf2xx: Error TX-PWR-MIN len is different of two");		  \
	BUILD_ASSERT(DT_INST_PROP_LEN(n, tx_pwr_max) == 2,		  \
	"rf2xx: Error TX-PWR-MAX len is different of two");		  \
	BUILD_ASSERT(DT_INST_PROP_LEN(n, tx_pwr_table) != 0,		  \
	"rf2xx: Error TX-PWR-TABLE len must be greater than zero");	  \
	static const uint8_t rf2xx_pwr_table_##n[] =			  \
		DT_INST_PROP_OR(n, tx_pwr_table, 0);			  \
	static const struct rf2xx_config rf2xx_ctx_config_##n = {	  \
		.inst = n,						  \
		.has_mac = DT_INST_NODE_HAS_PROP(n, local_mac_address),   \
@@ -942,6 +964,11 @@ static struct ieee802154_radio_api rf2xx_radio_api = {
		.clkm_gpio = GPIO_DT_SPEC_INST_GET_OR(n, clkm_gpios, {}), \
		.spi = SPI_DT_SPEC_INST_GET(n, SPI_WORD_SET(8) |	  \
				 SPI_TRANSFER_MSB, 0),			  \
									  \
		.tx_pwr_min = DT_INST_PROP_OR(n, tx_pwr_min, 0),	  \
		.tx_pwr_max = DT_INST_PROP_OR(n, tx_pwr_max, 0),	  \
		.tx_pwr_table = rf2xx_pwr_table_##n,			  \
		.tx_pwr_table_size = DT_INST_PROP_LEN(n, tx_pwr_table),	  \
	}

#define IEEE802154_RF2XX_DEVICE_DATA(n)                                 \
+5 −0
Original line number Diff line number Diff line
@@ -85,6 +85,11 @@ struct rf2xx_config {

	uint8_t inst;
	uint8_t has_mac;

	uint8_t const *tx_pwr_table;
	uint8_t tx_pwr_table_size;
	int8_t tx_pwr_min[2];
	int8_t tx_pwr_max[2];
};

struct rf2xx_context {
+72 −0
Original line number Diff line number Diff line
@@ -38,3 +38,75 @@ properties:
      description: |
        Specifies the MAC address that was assigned to the network
        device

    tx-pwr-table:
      type: uint8-array
      default: [ 0x00 ]
      description: |
        This is the Transmission Power Mapping Table array used to comply with
        local regulations. By default this value set an output power above 0dBm
        for all transceivers. This property must be used with tx-pwr-min and
        tx-pwr-max for normal operations. The number of elements is defined by
        the size of the tx-pwr-table array property. The max entry value for
        2.4GHz is 0x0f and 0xff for Sub-Giga. See PHY_TX_PWR at datasheet for
        more details.

        The output power is determined by following formula:

          linear_step = (tx-pwr-max - tx-pwr-min)
                      / (sizeof(tx-pwr-table) - 1.0);
          table_index = abs((value_in_dbm - tx-pwr-max) / linear_step);
          output_power = tx-pwr-table[table_index];

        Using AT86RF233 as example without external PA. By the datasheet the
        tx-pwr-min = -17 dBm and tx-pwr-max = +4 dBm. Using 48 elements in the
        tx-pwr-table array. The table array is filled from higher to lower power.

          tx-pwr-min = [01 11];	/* -17.0 dBm */
          tx-pwr-max = [00 04];	/*   4.0 dBm */
          tx-pwr-table = [00 01 03 04 05 05 06 06
                          07 07 07 08 08 09 09 0a
                          0a 0a 0b 0b 0b 0b 0c 0c
                          0c 0c 0d 0d 0d 0d 0d 0d
                          0d 0d 0e 0e 0e 0e 0e 0e
                          0e 0e 0e 0e 0e 0e 0f 0f];

        The values in the table are filled based on table 9-9 [ TX Output Power ]
        using the linear step in dBm as:

          linear_step = (4 - (-17)) / (48 - 1) => ~0.45 dBm

        Assuming that user wants set 0 dBm as output power:

          table_index = abs((0 - 4) / 0.45) => 8.95 ( round to 9 )
          output_power = tx-pwr-table[9] => 0x07 ( 0 dBm as table 9-9 )

        Note when tx-pwr-min is [ 0x00, 0x00 ] and tx-pwr-max is [ 0x00, 0x00 ]
        the linear step is zero. This means that table_index will be always the
        first element of the tx-pwr-table array, which is 0x00 by default. This
        is defined as general case when user not define any tx-pwr-* entries. It
        sets the transceiver to use always a value above 0 dBm as output power.

    tx-pwr-min:
      type: uint8-array
      default: [ 0x00, 0x00 ]
      description: |
        This value represent minimum normalized value in dBm for the transceiver
        output power. This property must be used when tx-pwr-table is defined.
        The value is represented by two entries where first element represents
        the signal indication [ 0x00-positive, 0x01-negative] and second element
        is the minimal value in dBm for the transceiver output power. By default,
        the combination of tx-pwr-min as [ 0x00, 0x00 ] and tx-pwr-max as [ 0x00,
        0x00 ] will create a fixed transmission power.

    tx-pwr-max:
      type: uint8-array
      default: [ 0x00, 0x00 ]
      description: |
        This value represent maximum normalized value in dBm for the transceiver
        output power. This property must be used when tx-pwr-table is defined.
        The value is represented by two entries where first element represents
        the signal indication [ 0x00-positive ] and second element is the maximum
        value in dBm for the transceiver output power. By default, the
        combination of tx-pwr-max as [ 0x00, 0x00 ] and tx-pwr-min as [ 0x00,
        0x00 ] will create a fixed transmission power.