All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-04  9:09 ` michael.hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: michael.hennerich @ 2015-12-04  9:09 UTC (permalink / raw)
  To: alex.aring, stefan, marcel; +Cc: linux-wpan, linux-bluetooth, Michael Hennerich

From: Michael Hennerich <michael.hennerich@analog.com>

This driver has been sitting in the linux-zigbee[2] repository for a long
time. We updated it from time to time and made it available via our
github kernel repository. The Linux MAC802.15.4 support has improved a lot
since then. Thanks to all! So it’s finally time to upstream this driver.

The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
operating modes. The firmware file is currently made available on the
ADF7242 wiki page here [1]

[1] http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
[2] http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
---
 .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
 drivers/net/ieee802154/Kconfig                     |    5 +
 drivers/net/ieee802154/Makefile                    |    1 +
 drivers/net/ieee802154/adf7242.c                   | 1183 ++++++++++++++++++++
 4 files changed, 1207 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
 create mode 100644 drivers/net/ieee802154/adf7242.c

diff --git a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
new file mode 100644
index 0000000..dea5124
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
@@ -0,0 +1,18 @@
+* ADF7242 IEEE 802.15.4 *
+
+Required properties:
+  - compatible:		should be "adi,adf7242"
+  - spi-max-frequency:	maximal bus speed (12.5 MHz)
+  - reg:		the chipselect index
+  - interrupts:		the interrupt generated by the device via pin IRQ1.
+			IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
+
+Example:
+
+	adf7242@0 {
+		compatible = "adi,adf7242";
+		spi-max-frequency = <10000000>;
+		reg = <0>;
+		interrupts = <98 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gpio3>;
+	};
diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig
index ce5f1a2..fd17598 100644
--- a/drivers/net/ieee802154/Kconfig
+++ b/drivers/net/ieee802154/Kconfig
@@ -71,3 +71,8 @@ config IEEE802154_ATUSB
 
 	  This driver can also be built as a module. To do so say M here.
 	  The module will be called 'atusb'.
+
+config IEEE802154_ADF7242
+       tristate "ADF7242 transceiver driver"
+       depends on IEEE802154_DRIVERS && MAC802154
+       depends on SPI
diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile
index cf1d2a6..3a923d3 100644
--- a/drivers/net/ieee802154/Makefile
+++ b/drivers/net/ieee802154/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
 obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
 obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o
 obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o
+obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o
diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c
new file mode 100644
index 0000000..48268b1
--- /dev/null
+++ b/drivers/net/ieee802154/adf7242.c
@@ -0,0 +1,1183 @@
+/*
+ * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver
+ *
+ * Copyright 2009-2015 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/firmware.h>
+#include <linux/spi/spi.h>
+#include <linux/skbuff.h>
+#include <linux/of.h>
+#include <linux/ieee802154.h>
+#include <net/mac802154.h>
+#include <net/cfg802154.h>
+
+#define FIRMWARE "adf7242_firmware.bin"
+#define MAX_POLL_LOOPS 50
+
+/* All Registers */
+
+#define REG_EXT_CTRL	0x100	/* RW External LNA/PA and internal PA control */
+#define REG_TX_FSK_TEST 0x101	/* RW TX FSK test mode configuration */
+#define REG_CCA1	0x105	/* RW RSSI threshold for CCA */
+#define REG_CCA2	0x106	/* RW CCA mode configuration */
+#define REG_BUFFERCFG	0x107	/* RW RX_BUFFER overwrite control */
+#define REG_PKT_CFG	0x108	/* RW FCS evaluation configuration */
+#define REG_DELAYCFG0	0x109	/* RW RC_RX command to SFD or sync word delay */
+#define REG_DELAYCFG1	0x10A	/* RW RC_TX command to TX state */
+#define REG_DELAYCFG2	0x10B	/* RW Mac delay extension */
+#define REG_SYNC_WORD0	0x10C	/* RW sync word bits [7:0] of [23:0]  */
+#define REG_SYNC_WORD1	0x10D	/* RW sync word bits [15:8] of [23:0]  */
+#define REG_SYNC_WORD2	0x10E	/* RW sync word bits [23:16] of [23:0]	*/
+#define REG_SYNC_CONFIG	0x10F	/* RW sync word configuration */
+#define REG_RC_CFG	0x13E	/* RW RX / TX packet configuration */
+#define REG_RC_VAR44	0x13F	/* RW RESERVED */
+#define REG_CH_FREQ0	0x300	/* RW Channel Frequency Settings - Low */
+#define REG_CH_FREQ1	0x301	/* RW Channel Frequency Settings - Middle */
+#define REG_CH_FREQ2	0x302	/* RW Channel Frequency Settings - High */
+#define REG_TX_FD	0x304	/* RW TX Frequency Deviation Register */
+#define REG_DM_CFG0	0x305	/* RW RX Discriminator BW Register */
+#define REG_TX_M	0x306	/* RW TX Mode Register */
+#define REG_RX_M	0x307	/* RW RX Mode Register */
+#define REG_RRB		0x30C	/* R RSSI Readback Register */
+#define REG_LRB		0x30D	/* R Link Quality Readback Register */
+#define REG_DR0		0x30E	/* RW bits [15:8] of [15:0] data rate setting */
+#define REG_DR1		0x30F	/* RW bits [7:0] of [15:0] data rate setting */
+#define REG_PRAMPG	0x313	/* RW RESERVED */
+#define REG_TXPB	0x314	/* RW TX Packet Storage Base Address */
+#define REG_RXPB	0x315	/* RW RX Packet Storage Base Address */
+#define REG_TMR_CFG0	0x316	/* RW Wake up Timer Conf Register - High */
+#define REG_TMR_CFG1	0x317	/* RW Wake up Timer Conf Register - Low */
+#define REG_TMR_RLD0	0x318	/* RW Wake up Timer Value Register - High */
+#define REG_TMR_RLD1	0x319	/* RW Wake up Timer Value Register - Low  */
+#define REG_TMR_CTRL	0x31A	/* RW Wake up Timer Timeout flag */
+#define REG_PD_AUX	0x31E	/* RW Battmon enable */
+#define REG_GP_CFG	0x32C	/* RW GPIO Configuration */
+#define REG_GP_OUT	0x32D	/* RW GPIO Configuration */
+#define REG_GP_IN	0x32E	/* R GPIO Configuration */
+#define REG_SYNT	0x335	/* RW bandwidth calibration timers */
+#define REG_CAL_CFG	0x33D	/* RW Calibration Settings */
+#define REG_PA_BIAS	0x36E	/* RW PA BIAS */
+#define REG_SYNT_CAL	0x371	/* RW Oscillator and Doubler Configuration */
+#define REG_IIRF_CFG	0x389	/* RW BB Filter Decimation Rate */
+#define REG_CDR_CFG	0x38A	/* RW CDR kVCO */
+#define REG_DM_CFG1	0x38B	/* RW Postdemodulator Filter */
+#define REG_AGCSTAT	0x38E	/* R RXBB Ref Osc Calibration Engine Readback */
+#define REG_RXCAL0	0x395	/* RW RX BB filter tuning, LSB */
+#define REG_RXCAL1	0x396	/* RW RX BB filter tuning, MSB */
+#define REG_RXFE_CFG	0x39B	/* RW RXBB Ref Osc & RXFE Calibration */
+#define REG_PA_RR	0x3A7	/* RW Set PA ramp rate */
+#define REG_PA_CFG	0x3A8	/* RW PA enable */
+#define REG_EXTPA_CFG	0x3A9	/* RW External PA BIAS DAC */
+#define REG_EXTPA_MSC	0x3AA	/* RW PA Bias Mode */
+#define REG_ADC_RBK	0x3AE	/* R Readback temp */
+#define REG_AGC_CFG1	0x3B2	/* RW GC Parameters */
+#define REG_AGC_MAX	0x3B4	/* RW Slew rate	 */
+#define REG_AGC_CFG2	0x3B6	/* RW RSSI Parameters */
+#define REG_AGC_CFG3	0x3B7	/* RW RSSI Parameters */
+#define REG_AGC_CFG4	0x3B8	/* RW RSSI Parameters */
+#define REG_AGC_CFG5	0x3B9	/* RW RSSI & NDEC Parameters */
+#define REG_AGC_CFG6	0x3BA	/* RW NDEC Parameters */
+#define REG_OCL_CFG1	0x3C4	/* RW OCL System Parameters */
+#define REG_IRQ1_EN0	0x3C7	/* RW Interrupt Mask set bits for IRQ1 */
+#define REG_IRQ1_EN1	0x3C8	/* RW Interrupt Mask set bits for IRQ1 */
+#define REG_IRQ2_EN0	0x3C9	/* RW Interrupt Mask set bits for IRQ2 */
+#define REG_IRQ2_EN1	0x3CA	/* RW Interrupt Mask set bits for IRQ2 */
+#define REG_IRQ1_SRC0	0x3CB	/* RW Interrupt Source bits for IRQ */
+#define REG_IRQ1_SRC1	0x3CC	/* RW Interrupt Source bits for IRQ */
+#define REG_OCL_BW0	0x3D2	/* RW OCL System Parameters */
+#define REG_OCL_BW1	0x3D3	/* RW OCL System Parameters */
+#define REG_OCL_BW2	0x3D4	/* RW OCL System Parameters */
+#define REG_OCL_BW3	0x3D5	/* RW OCL System Parameters */
+#define REG_OCL_BW4	0x3D6	/* RW OCL System Parameters */
+#define REG_OCL_BWS	0x3D7	/* RW OCL System Parameters */
+#define REG_OCL_CFG13	0x3E0	/* RW OCL System Parameters */
+#define REG_GP_DRV	0x3E3	/* RW I/O pads Configuration and bg trim */
+#define REG_BM_CFG	0x3E6	/* RW Batt. Monitor Threshold Voltage setting */
+#define REG_SFD_15_4	0x3F4	/* RW Option to set non standard SFD */
+#define REG_AFC_CFG	0x3F7	/* RW AFC mode and polarity */
+#define REG_AFC_KI_KP	0x3F8	/* RW AFC ki and kp */
+#define REG_AFC_RANGE	0x3F9	/* RW AFC range */
+#define REG_AFC_READ	0x3FA	/* RW Readback frequency error */
+
+/* REG_EXTPA_MSC */
+#define PA_PWR(x)		(((x) & 0xF) << 4)
+#define EXTPA_BIAS_SRC		BIT(3)
+#define EXTPA_BIAS_MODE(x)	(((x) & 0x7) << 0)
+
+/* REG_PA_CFG */
+#define PA_BRIDGE_DBIAS(x)	(((x) & 0x1F) << 0)
+
+/* REG_PA_BIAS */
+#define PA_BIAS_CTRL(x)		(((x) & 0x1F) << 1)
+#define REG_PA_BIAS_DFL		BIT(0)
+
+#define REG_PAN_ID0		0x112
+#define REG_PAN_ID1		0x113
+#define REG_SHORT_ADDR_0	0x114
+#define REG_SHORT_ADDR_1	0x115
+#define REG_IEEE_ADDR_0		0x116
+#define REG_IEEE_ADDR_1		0x117
+#define REG_IEEE_ADDR_2		0x118
+#define REG_IEEE_ADDR_3		0x119
+#define REG_IEEE_ADDR_4		0x11A
+#define REG_IEEE_ADDR_5		0x11B
+#define REG_IEEE_ADDR_6		0x11C
+#define REG_IEEE_ADDR_7		0x11D
+#define REG_FFILT_CFG		0x11E
+#define REG_AUTO_CFG		0x11F
+#define REG_AUTO_TX1		0x120
+#define REG_AUTO_TX2		0x121
+#define REG_AUTO_STATUS		0x122
+
+/* REG_FFILT_CFG */
+#define ACCEPT_BEACON_FRAMES   BIT(0)
+#define ACCEPT_DATA_FRAMES     BIT(1)
+#define ACCEPT_ACK_FRAMES      BIT(2)
+#define ACCEPT_MACCMD_FRAMES   BIT(3)
+#define ACCEPT_RESERVED_FRAMES BIT(4)
+#define ACCEPT_ALL_ADDRESS     BIT(5)
+
+/* REG_AUTO_CFG */
+#define AUTO_ACK_FRAMEPEND     BIT(0)
+#define IS_PANCOORD	       BIT(1)
+#define RX_AUTO_ACK_EN	       BIT(3)
+#define CSMA_CA_RX_TURNAROUND  BIT(4)
+
+/* REG_AUTO_TX1 */
+#define MAX_FRAME_RETRIES(x)   ((x) & 0xF)
+#define MAX_CCA_RETRIES(x)     (((x) & 0x7) << 4)
+
+/* REG_AUTO_TX2 */
+#define CSMA_MAX_BE(x)	       ((x) & 0xF)
+#define CSMA_MIN_BE(x)	       (((x) & 0xF) << 4)
+
+#define CMD_SPI_NOP		0xFF /* No operation. Use for dummy writes */
+#define CMD_SPI_PKT_WR		0x10 /* Write telegram to the Packet RAM
+				      * starting from the TX packet base address
+				      * pointer tx_packet_base
+				      */
+#define CMD_SPI_PKT_RD		0x30 /* Read telegram from the Packet RAM
+				      * starting from RX packet base address
+				      * pointer rxpb.rx_packet_base
+				      */
+#define CMD_SPI_MEM_WR(x)	(0x18 + (x >> 8)) /* Write data to MCR or
+						   * Packet RAM sequentially
+						   */
+#define CMD_SPI_MEM_RD(x)	(0x38 + (x >> 8)) /* Read data from MCR or
+						   * Packet RAM sequentially
+						   */
+#define CMD_SPI_MEMR_WR(x)	(0x08 + (x >> 8)) /* Write data to MCR or Packet
+						   * RAM as random block
+						   */
+#define CMD_SPI_MEMR_RD(x)	(0x28 + (x >> 8)) /* Read data from MCR or
+						   * Packet RAM random block
+						   */
+#define CMD_SPI_PRAM_WR		0x1E /* Write data sequentially to current
+				      * PRAM page selected
+				      */
+#define CMD_SPI_PRAM_RD		0x3E /* Read data sequentially from current
+				      * PRAM page selected
+				      */
+#define CMD_RC_SLEEP		0xB1 /* Invoke transition of radio controller
+				      * into SLEEP state
+				      */
+#define CMD_RC_IDLE		0xB2 /* Invoke transition of radio controller
+				      * into IDLE state
+				      */
+#define CMD_RC_PHY_RDY		0xB3 /* Invoke transition of radio controller
+				      * into PHY_RDY state
+				      */
+#define CMD_RC_RX		0xB4 /* Invoke transition of radio controller
+				      * into RX state
+				      */
+#define CMD_RC_TX		0xB5 /* Invoke transition of radio controller
+				      * into TX state
+				      */
+#define CMD_RC_MEAS		0xB6 /* Invoke transition of radio controller
+				      * into MEAS state
+				      */
+#define CMD_RC_CCA		0xB7 /* Invoke Clear channel assessment */
+#define CMD_RC_CSMACA		0xC1 /* initiates CSMA-CA channel access
+				      * sequence and frame transmission
+				      */
+#define CMD_RC_PC_RESET		0xC7 /* Program counter reset */
+#define CMD_RC_RESET		0xC8 /* Resets the ADF7242 and puts it in
+				      * the sleep state
+				      */
+
+/* STATUS */
+
+#define STAT_SPI_READY		BIT(7)
+#define STAT_IRQ_STATUS		BIT(6)
+#define STAT_RC_READY		BIT(5)
+#define STAT_CCA_RESULT		BIT(4)
+#define RC_STATUS_IDLE		1
+#define RC_STATUS_MEAS		2
+#define RC_STATUS_PHY_RDY	3
+#define RC_STATUS_RX		4
+#define RC_STATUS_TX		5
+#define RC_STATUS_MASK		0xF
+
+/* AUTO_STATUS */
+
+#define SUCCESS			0
+#define SUCCESS_DATPEND		1
+#define FAILURE_CSMACA		2
+#define FAILURE_NOACK		3
+#define AUTO_STATUS_MASK	0x3
+
+#define PRAM_PAGESIZE		256
+
+/* IRQ1 */
+
+#define IRQ_CCA_COMPLETE	BIT(0)
+#define IRQ_SFD_RX		BIT(1)
+#define IRQ_SFD_TX		BIT(2)
+#define IRQ_RX_PKT_RCVD		BIT(3)
+#define IRQ_TX_PKT_SENT		BIT(4)
+#define IRQ_FRAME_VALID		BIT(5)
+#define IRQ_ADDRESS_VALID	BIT(6)
+#define IRQ_CSMA_CA		BIT(7)
+
+#define AUTO_TX_TURNAROUND	BIT(3)
+#define ADDON_EN		BIT(4)
+
+struct adf7242_local {
+	struct spi_device *spi;
+	struct completion tx_complete;
+	struct ieee802154_hw *hw;
+	struct mutex bmux; /* protect SPI messages */
+	struct spi_message stat_msg;
+	struct spi_transfer stat_xfer;
+	int tx_stat;
+	s8 rssi;
+	u8 max_frame_retries;
+	u8 max_cca_retries;
+
+	/* DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+
+	u8 buf[3] ____cacheline_aligned;
+	u8 buf_reg_tx[3];
+	u8 buf_read_tx[4];
+	u8 buf_read_rx[4];
+	u8 buf_stat_rx;
+	u8 buf_stat_tx;
+	u8 buf_cmd;
+};
+
+static int adf7242_status(struct adf7242_local *lp, u8 *stat)
+{
+	int status;
+
+	mutex_lock(&lp->bmux);
+	status = spi_sync(lp->spi, &lp->stat_msg);
+	*stat = lp->buf_stat_rx;
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int adf7242_wait_ready(struct adf7242_local *lp, int line)
+{
+	int cnt = 0, ret = 0;
+	u8 stat;
+
+	do {
+		adf7242_status(lp, &stat);
+		cnt++;
+	} while (!((stat & STAT_RC_READY) && (stat & STAT_SPI_READY)) &&
+		(cnt < MAX_POLL_LOOPS));
+
+	if (cnt >= MAX_POLL_LOOPS) {
+		dev_warn(&lp->spi->dev, "%s:line %d Timeout\n", __func__, line);
+		ret = -ETIMEDOUT;
+	}
+
+	dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
+
+	return ret;
+}
+
+static int adf7242_wait_status(struct adf7242_local *lp, int status, int line)
+{
+	int cnt = 0, ret = 0;
+	u8 stat;
+
+	do {
+		adf7242_status(lp, &stat);
+		stat &= RC_STATUS_MASK;
+		cnt++;
+	} while ((stat != status) && (cnt < MAX_POLL_LOOPS));
+
+	if (cnt >= MAX_POLL_LOOPS) {
+		dev_warn(&lp->spi->dev, "%s:line %d Timeout status 0x%x\n",
+			 __func__, line, stat);
+		ret = -ETIMEDOUT;
+	}
+
+	dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
+
+	return ret;
+}
+
+static int adf7242_write_fbuf(struct adf7242_local *lp, u8 *data, u8 len)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer_head = {
+		.len = 2,
+		.tx_buf = buf,
+
+	};
+	struct spi_transfer xfer_buf = {
+		.len = len,
+		.tx_buf = data,
+	};
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	buf[0] = CMD_SPI_PKT_WR;
+	buf[1] = len + 2;
+
+	status = spi_sync(lp->spi, &msg);
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int adf7242_read_fbuf(struct adf7242_local *lp,
+			     u8 *data, size_t len, bool packet_read)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer_head = {
+		.len = 3,
+		.tx_buf = buf,
+		.rx_buf = buf,
+	};
+	struct spi_transfer xfer_buf = {
+		.len = len,
+		.rx_buf = data,
+	};
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	if (packet_read) {
+		buf[0] = CMD_SPI_PKT_RD;
+		buf[1] = CMD_SPI_NOP;
+		buf[2] = 0;	/* PHR */
+	} else {
+		buf[0] = CMD_SPI_PRAM_RD;
+		buf[1] = 0;
+		buf[2] = CMD_SPI_NOP;
+	}
+
+	status = spi_sync(lp->spi, &msg);
+
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int adf7242_read_reg(struct adf7242_local *lp, u16 addr, u8 *data)
+{
+	int status;
+	struct spi_message msg;
+
+	struct spi_transfer xfer = {
+		.len = 4,
+		.tx_buf = lp->buf_read_tx,
+		.rx_buf = lp->buf_read_rx,
+	};
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	lp->buf_read_tx[0] = CMD_SPI_MEM_RD(addr);
+	lp->buf_read_tx[1] = addr;
+	lp->buf_read_tx[2] = CMD_SPI_NOP;
+	lp->buf_read_tx[3] = CMD_SPI_NOP;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	if (msg.status)
+		status = msg.status;
+
+	if (!status)
+		*data = lp->buf_read_rx[3];
+
+	mutex_unlock(&lp->bmux);
+
+	dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n", __func__,
+		 addr, *data);
+
+	return status;
+}
+
+static int adf7242_write_reg(struct adf7242_local *lp, u16 addr, u8 data)
+{
+	int status;
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	lp->buf_reg_tx[0] = CMD_SPI_MEM_WR(addr);
+	lp->buf_reg_tx[1] = addr;
+	lp->buf_reg_tx[2] = data;
+	status = spi_write(lp->spi, lp->buf_reg_tx, 3);
+	mutex_unlock(&lp->bmux);
+
+	dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n",
+		 __func__, addr, data);
+
+	return status;
+}
+
+static int adf7242_cmd(struct adf7242_local *lp, u8 cmd)
+{
+	int status;
+
+	dev_vdbg(&lp->spi->dev, "%s : CMD=0x%X\n", __func__, cmd);
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	lp->buf_cmd = cmd;
+	status = spi_write(lp->spi, &lp->buf_cmd, 1);
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int adf7242_upload_firmware(struct adf7242_local *lp, u8 *data, u16 len)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer_buf = { };
+	int status, i, page = 0;
+	u8 *buf = lp->buf;
+
+	struct spi_transfer xfer_head = {
+		.len = 2,
+		.tx_buf = buf,
+	};
+
+	buf[0] = CMD_SPI_PRAM_WR;
+	buf[1] = 0;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	for (i = len; i >= 0; i -= PRAM_PAGESIZE) {
+		adf7242_write_reg(lp, REG_PRAMPG, page);
+
+		xfer_buf.len = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
+		xfer_buf.tx_buf = &data[page * PRAM_PAGESIZE];
+
+		mutex_lock(&lp->bmux);
+		status = spi_sync(lp->spi, &msg);
+		mutex_unlock(&lp->bmux);
+		page++;
+	}
+
+	return status;
+}
+
+static int adf7242_verify_firmware(struct adf7242_local *lp,
+				   const u8 *data, size_t len)
+{
+	int i, j;
+	unsigned int page;
+	u8 *buf = kmalloc(PRAM_PAGESIZE, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	for (page = 0, i = len; i >= 0; i -= PRAM_PAGESIZE, page++) {
+		size_t nb = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
+
+		adf7242_write_reg(lp, REG_PRAMPG, page);
+		adf7242_read_fbuf(lp, buf, nb, false);
+
+		for (j = 0; j < nb; j++) {
+			if (buf[j] != data[page * PRAM_PAGESIZE + j]) {
+				kfree(buf);
+				return -EIO;
+			}
+		}
+	}
+	kfree(buf);
+
+	return 0;
+}
+
+static int adf7242_set_txpower(struct ieee802154_hw *hw, int mbm)
+{
+	struct adf7242_local *lp = hw->priv;
+	u8 pwr, bias_ctrl, dbias, tmp;
+	int db = mbm / 100;
+
+	dev_vdbg(&lp->spi->dev, "%s : Power %d dB\n", __func__, db);
+
+	if (db > 5 || db < -26)
+		return -EINVAL;
+
+	db = DIV_ROUND_CLOSEST(db + 29, 2);
+
+	if (db > 15) {
+		dbias = 21;
+		bias_ctrl = 63;
+	} else {
+		dbias = 13;
+		bias_ctrl = 55;
+	}
+
+	pwr = clamp_t(u8, db, 3, 15);
+
+	adf7242_read_reg(lp, REG_PA_CFG, &tmp);
+	tmp &= ~PA_BRIDGE_DBIAS(~0);
+	tmp |= PA_BRIDGE_DBIAS(dbias);
+	adf7242_write_reg(lp, REG_PA_CFG, tmp);
+
+	adf7242_read_reg(lp, REG_PA_BIAS, &tmp);
+	tmp &= ~PA_BIAS_CTRL(~0);
+	tmp |= PA_BIAS_CTRL(bias_ctrl);
+	adf7242_write_reg(lp, REG_PA_BIAS, tmp);
+
+	adf7242_read_reg(lp, REG_EXTPA_MSC, &tmp);
+	tmp &= ~PA_PWR(~0);
+	tmp |= PA_PWR(pwr);
+
+	return adf7242_write_reg(lp, REG_EXTPA_MSC, tmp);
+}
+
+static int adf7242_set_csma_params(struct ieee802154_hw *hw, u8 min_be,
+				   u8 max_be, u8 retries)
+{
+	struct adf7242_local *lp = hw->priv;
+	int ret;
+
+	dev_vdbg(&lp->spi->dev, "%s : min_be=%d max_be=%d retries=%d\n",
+		 __func__, min_be, max_be, retries);
+
+	if (min_be > max_be || max_be > 8 || retries > 5)
+		return -EINVAL;
+
+	ret = adf7242_write_reg(lp, REG_AUTO_TX1,
+				MAX_FRAME_RETRIES(lp->max_frame_retries) |
+				MAX_CCA_RETRIES(retries));
+	if (ret)
+		return ret;
+
+	lp->max_cca_retries = retries;
+
+	return adf7242_write_reg(lp, REG_AUTO_TX2, CSMA_MAX_BE(max_be) |
+			CSMA_MIN_BE(min_be));
+}
+
+static int adf7242_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
+{
+	struct adf7242_local *lp = hw->priv;
+	int ret = 0;
+
+	dev_vdbg(&lp->spi->dev, "%s : Retries = %d\n", __func__, retries);
+
+	if (retries < -1 || retries > 15)
+		return -EINVAL;
+
+	if (retries >= 0)
+		ret = adf7242_write_reg(lp, REG_AUTO_TX1,
+					MAX_FRAME_RETRIES(retries) |
+					MAX_CCA_RETRIES(lp->max_cca_retries));
+
+	lp->max_frame_retries = retries;
+
+	return ret;
+}
+
+static int adf7242_ed(struct ieee802154_hw *hw, u8 *level)
+{
+	struct adf7242_local *lp = hw->priv;
+
+	*level = lp->rssi;
+
+	dev_vdbg(&lp->spi->dev, "%s :Exit level=%d\n",
+		 __func__, *level);
+
+	return 0;
+}
+
+static int adf7242_start(struct ieee802154_hw *hw)
+{
+	struct adf7242_local *lp = hw->priv;
+
+	adf7242_cmd(lp, CMD_RC_PHY_RDY);
+	return adf7242_cmd(lp, CMD_RC_RX);
+}
+
+static void adf7242_stop(struct ieee802154_hw *hw)
+{
+	struct adf7242_local *lp = hw->priv;
+
+	adf7242_cmd(lp, CMD_RC_IDLE);
+	adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
+}
+
+static int adf7242_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
+{
+	struct adf7242_local *lp = hw->priv;
+	unsigned long freq;
+
+	dev_dbg(&lp->spi->dev, "%s :Channel=%d\n", __func__, channel);
+
+	might_sleep();
+
+	WARN_ON(page != 0);
+	WARN_ON(channel < 11);
+	WARN_ON(channel > 26);
+
+	freq = (2405 + 5 * (channel - 11)) * 100;
+	adf7242_cmd(lp, CMD_RC_PHY_RDY);
+
+	adf7242_write_reg(lp, REG_CH_FREQ0, freq);
+	adf7242_write_reg(lp, REG_CH_FREQ1, freq >> 8);
+	adf7242_write_reg(lp, REG_CH_FREQ2, freq >> 16);
+
+	return adf7242_cmd(lp, CMD_RC_RX);
+}
+
+static int adf7242_set_hw_addr_filt(struct ieee802154_hw *hw,
+				    struct ieee802154_hw_addr_filt *filt,
+				    unsigned long changed)
+{
+	struct adf7242_local *lp = hw->priv;
+	u8 reg;
+
+	dev_dbg(&lp->spi->dev, "%s :Changed=0x%lX\n", __func__, changed);
+
+	might_sleep();
+
+	if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
+		u8 addr[8], i;
+
+		memcpy(addr, &filt->ieee_addr, 8);
+
+		for (i = 0; i < 8; i++)
+			adf7242_write_reg(lp, REG_IEEE_ADDR_0 + i, addr[i]);
+	}
+
+	if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
+		u16 saddr = le16_to_cpu(filt->short_addr);
+
+		adf7242_write_reg(lp, REG_SHORT_ADDR_0, saddr);
+		adf7242_write_reg(lp, REG_SHORT_ADDR_1, saddr >> 8);
+	}
+
+	if (changed & IEEE802154_AFILT_PANID_CHANGED) {
+		u16 pan_id = le16_to_cpu(filt->pan_id);
+
+		adf7242_write_reg(lp, REG_PAN_ID0, pan_id);
+		adf7242_write_reg(lp, REG_PAN_ID1, pan_id >> 8);
+	}
+
+	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
+		adf7242_read_reg(lp, REG_AUTO_CFG, &reg);
+		if (filt->pan_coord)
+			reg |= IS_PANCOORD;
+		else
+			reg &= ~IS_PANCOORD;
+		adf7242_write_reg(lp, REG_AUTO_CFG, reg);
+	}
+
+	return 0;
+}
+
+static int adf7242_set_promiscuous_mode(struct ieee802154_hw *hw, bool on)
+{
+	struct adf7242_local *lp = hw->priv;
+
+	dev_dbg(&lp->spi->dev, "%s : mode %d\n", __func__, on);
+
+	if (on) {
+		adf7242_write_reg(lp, REG_AUTO_CFG, 0);
+		return adf7242_write_reg(lp, REG_FFILT_CFG,
+				  ACCEPT_BEACON_FRAMES |
+				  ACCEPT_DATA_FRAMES |
+				  ACCEPT_MACCMD_FRAMES |
+				  ACCEPT_ALL_ADDRESS |
+				  ACCEPT_ACK_FRAMES |
+				  ACCEPT_RESERVED_FRAMES);
+	} else {
+		adf7242_write_reg(lp, REG_FFILT_CFG,
+				  ACCEPT_BEACON_FRAMES |
+				  ACCEPT_DATA_FRAMES |
+				  ACCEPT_MACCMD_FRAMES |
+				  ACCEPT_RESERVED_FRAMES);
+
+		return adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
+	}
+}
+
+static int adf7242_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
+{
+	struct adf7242_local *lp = hw->priv;
+	s8 level = clamp_t(s8, mbm / 100, S8_MIN, S8_MAX);
+
+	dev_dbg(&lp->spi->dev, "%s : level %d\n", __func__, level);
+
+	return adf7242_write_reg(lp, REG_CCA1, level);
+}
+
+static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
+{
+	struct adf7242_local *lp = hw->priv;
+	int ret;
+
+	reinit_completion(&lp->tx_complete);
+
+	ret = adf7242_write_fbuf(lp, skb->data, skb->len);
+	if (ret)
+		goto err;
+
+	ret = adf7242_cmd(lp, CMD_RC_PHY_RDY);
+	ret |= adf7242_cmd(lp, CMD_RC_CSMACA);
+
+	if (ret)
+		goto err;
+
+	ret = wait_for_completion_interruptible_timeout(&lp->tx_complete, HZ);
+	if (ret == -ERESTARTSYS)
+		goto err;
+	if (ret == 0) {
+		dev_warn(&lp->spi->dev, "Timeout waiting for TX interrupt\n");
+		ret = -ETIMEDOUT;
+		goto err;
+	}
+
+	if (lp->tx_stat != SUCCESS) {
+		dev_warn(&lp->spi->dev,
+			 "Error xmit: Retry count exceeded Status=0x%x\n",
+			 lp->tx_stat);
+		ret = -ECOMM;
+	} else {
+		ret = 0;
+	}
+
+err:
+	adf7242_cmd(lp, CMD_RC_RX);
+	return ret;
+}
+
+static int adf7242_rx(struct adf7242_local *lp)
+{
+	struct sk_buff *skb;
+	size_t len;
+	int ret;
+	u8 lqi, len_u8, *data;
+
+	adf7242_read_reg(lp, 0, &len_u8);
+
+	len = len_u8;
+
+	if (!ieee802154_is_valid_psdu_len(len)) {
+		dev_dbg(&lp->spi->dev,
+			"corrupted frame received len %d\n", len);
+		len = IEEE802154_MTU;
+	}
+
+	skb = dev_alloc_skb(len);
+	if (!skb)
+		return -ENOMEM;
+
+	data = skb_put(skb, len);
+	ret = adf7242_read_fbuf(lp, data, len, true);
+
+	if (!ret) {
+		lqi = data[len - 2];
+		lp->rssi = data[len - 1];
+	}
+
+	adf7242_cmd(lp, CMD_RC_RX);
+
+	skb_trim(skb, len - 2);	/* Don't put RSSI/LQI or CRC into the frame */
+
+	ieee802154_rx_irqsafe(lp->hw, skb, lqi);
+
+	dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n",
+		__func__, ret, len, lqi, lp->rssi);
+
+	return 0;
+}
+
+static struct ieee802154_ops adf7242_ops = {
+	.owner = THIS_MODULE,
+	.xmit_sync = adf7242_xmit,
+	.ed = adf7242_ed,
+	.set_channel = adf7242_channel,
+	.set_hw_addr_filt = adf7242_set_hw_addr_filt,
+	.start = adf7242_start,
+	.stop = adf7242_stop,
+	.set_csma_params = adf7242_set_csma_params,
+	.set_frame_retries = adf7242_set_frame_retries,
+	.set_txpower = adf7242_set_txpower,
+	.set_promiscuous_mode = adf7242_set_promiscuous_mode,
+	.set_cca_ed_level = adf7242_set_cca_ed_level,
+};
+
+static irqreturn_t adf7242_isr(int irq, void *data)
+{
+	struct adf7242_local *lp = data;
+	u8 irq1, auto_stat = 0, stat = 0, rx_en = 0;
+
+	adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
+	adf7242_write_reg(lp, REG_IRQ1_SRC1, irq1);
+
+	if (!(irq1 & (IRQ_RX_PKT_RCVD | IRQ_CSMA_CA)))
+		dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n",
+			__func__, irq1);
+
+	dev_dbg(&lp->spi->dev, "%s IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n",
+		__func__, irq1,
+		irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
+		irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
+		irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
+		irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
+		irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
+		irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
+		irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
+		irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
+
+	adf7242_status(lp, &stat);
+
+	dev_dbg(&lp->spi->dev, "%s STATUS = %X:\n%s\n%s%s%s%s%s\n",
+		__func__, stat,
+		stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
+		(stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
+		(stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
+		(stat & 0xf) == RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
+		(stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
+		(stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
+
+	if ((irq1 & IRQ_RX_PKT_RCVD) && (irq1 & IRQ_FRAME_VALID)) {
+		/* Wait until ACK is processed */
+		if ((stat & RC_STATUS_MASK) != RC_STATUS_PHY_RDY)
+			adf7242_wait_status(lp, RC_STATUS_PHY_RDY, __LINE__);
+
+		adf7242_rx(lp);
+		rx_en = 1;
+	}
+
+	if (irq1 & IRQ_CSMA_CA) {
+		adf7242_read_reg(lp, REG_AUTO_STATUS, &auto_stat);
+		auto_stat &= AUTO_STATUS_MASK;
+
+		dev_dbg(&lp->spi->dev, "%s AUTO_STATUS = %X:\n%s%s%s%s\n",
+			__func__, auto_stat,
+			auto_stat == SUCCESS ? "SUCCESS" : "",
+			auto_stat ==
+			SUCCESS_DATPEND ? "SUCCESS_DATPEND" : "",
+			auto_stat == FAILURE_CSMACA ? "FAILURE_CSMACA" : "",
+			auto_stat == FAILURE_NOACK ? "FAILURE_NOACK" : "");
+
+		/* save CSMA-CA completion status */
+		lp->tx_stat = auto_stat;
+		rx_en = 1;
+
+		complete(&lp->tx_complete);
+	}
+
+	if (!rx_en)
+		adf7242_cmd(lp, CMD_RC_RX);
+
+	return IRQ_HANDLED;
+}
+
+static int adf7242_hw_init(struct adf7242_local *lp)
+{
+	int ret;
+	const struct firmware *fw;
+
+	adf7242_cmd(lp, CMD_RC_RESET);
+	adf7242_cmd(lp, CMD_RC_IDLE);
+
+	/* get ADF7242 addon firmware
+	 * build this driver as module
+	 * and place under /lib/firmware/adf7242_firmware.bin
+	 */
+	ret = request_firmware(&fw, FIRMWARE, &lp->spi->dev);
+	if (ret) {
+		dev_err(&lp->spi->dev,
+			"request_firmware() failed with %d\n", ret);
+		return ret;
+	}
+
+	ret = adf7242_upload_firmware(lp, (u8 *)fw->data, fw->size);
+	if (ret) {
+		dev_err(&lp->spi->dev,
+			"upload firmware failed with %d\n", ret);
+		return ret;
+	}
+
+	ret = adf7242_verify_firmware(lp, (u8 *)fw->data, fw->size);
+	if (ret) {
+		dev_err(&lp->spi->dev,
+			"verify firmware failed with %d\n", ret);
+		return ret;
+	}
+
+	adf7242_cmd(lp, CMD_RC_PC_RESET);
+
+	release_firmware(fw);
+
+	adf7242_write_reg(lp, REG_FFILT_CFG,
+			  ACCEPT_BEACON_FRAMES |
+			  ACCEPT_DATA_FRAMES |
+			  ACCEPT_MACCMD_FRAMES |
+			  ACCEPT_RESERVED_FRAMES);
+
+	adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
+
+	adf7242_write_reg(lp, REG_PKT_CFG, ADDON_EN | BIT(2));
+
+	adf7242_write_reg(lp, REG_EXTPA_MSC, 0xF1);
+	adf7242_write_reg(lp, REG_RXFE_CFG, 0x1D);
+
+	adf7242_write_reg(lp, REG_IRQ1_EN0, 0);
+	adf7242_write_reg(lp, REG_IRQ1_EN1, IRQ_RX_PKT_RCVD | IRQ_CSMA_CA);
+
+	adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
+	adf7242_write_reg(lp, REG_IRQ1_SRC0, 0xFF);
+
+	adf7242_cmd(lp, CMD_RC_IDLE);
+
+	return 0;
+}
+
+static ssize_t adf7242_show(struct device *dev,
+			    struct device_attribute *devattr, char *buf)
+{
+	struct adf7242_local *lp = dev_get_drvdata(dev);
+	u8 stat, irq1;
+	size_t len;
+
+	adf7242_status(lp, &stat);
+
+	adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
+
+	len = sprintf(buf, "IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n", irq1,
+		      irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
+		      irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
+		      irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
+		      irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
+		      irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
+		      irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
+		      irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
+		      irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
+
+	len += sprintf(buf + len, "STATUS = %X:\n%s\n%s%s%s%s%s\n", stat,
+		       stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
+		       (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
+		       (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
+		       (stat & 0xf) ==
+				RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
+		       (stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
+		       (stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
+
+	len += sprintf(buf + len, "RSSI = %d\n", lp->rssi);
+
+	return len;
+}
+static DEVICE_ATTR(status, 0664, adf7242_show, NULL);
+
+static const s32 adf7242_powers[] = {
+	500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700,
+	-800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700,
+	-1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600,
+};
+
+static const s32 adf7242_ed_levels[] = {
+	-9000, -8900, -8800, -8700, -8600, -8500, -8400, -8300, -8200, -8100,
+	-8000, -7900, -7800, -7700, -7600, -7500, -7400, -7300, -7200, -7100,
+	-7000, -6900, -6800, -6700, -6600, -6500, -6400, -6300, -6200, -6100,
+	-6000, -5900, -5800, -5700, -5600, -5500, -5400, -5300, -5200, -5100,
+	-5000, -4900, -4800, -4700, -4600, -4500, -4400, -4300, -4200, -4100,
+	-4000, -3900, -3800, -3700, -3600, -3500, -3400, -3200, -3100, -3000
+};
+
+static int adf7242_probe(struct spi_device *spi)
+{
+	struct ieee802154_hw *hw;
+	struct adf7242_local *lp;
+	int ret, irq_type;
+
+	if (!spi->irq) {
+		dev_err(&spi->dev, "no IRQ specified\n");
+		return -EINVAL;
+	}
+
+	hw = ieee802154_alloc_hw(sizeof(*lp), &adf7242_ops);
+	if (!hw)
+		return -ENOMEM;
+
+	lp = hw->priv;
+	lp->hw = hw;
+	lp->spi = spi;
+
+	hw->priv = lp;
+	hw->parent = &spi->dev;
+	hw->extra_tx_headroom = 0;
+
+	/* We support only 2.4 Ghz */
+	hw->phy->supported.channels[0] = 0x7FFF800;
+
+	hw->flags = IEEE802154_HW_OMIT_CKSUM |
+		    IEEE802154_HW_CSMA_PARAMS |
+		    IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT |
+		    IEEE802154_HW_PROMISCUOUS;
+
+	hw->phy->flags = WPAN_PHY_FLAG_TXPOWER |
+			 WPAN_PHY_FLAG_CCA_ED_LEVEL |
+			 WPAN_PHY_FLAG_CCA_MODE;
+
+	hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY);
+
+	hw->phy->supported.cca_ed_levels = adf7242_ed_levels;
+	hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(adf7242_ed_levels);
+
+	hw->phy->cca.mode = NL802154_CCA_ENERGY;
+
+	hw->phy->supported.tx_powers = adf7242_powers;
+	hw->phy->supported.tx_powers_size = ARRAY_SIZE(adf7242_powers);
+
+	hw->phy->supported.min_minbe = 0;
+	hw->phy->supported.max_minbe = 8;
+
+	hw->phy->supported.min_maxbe = 3;
+	hw->phy->supported.max_maxbe = 8;
+
+	hw->phy->supported.min_frame_retries = 0;
+	hw->phy->supported.max_frame_retries = 15;
+
+	hw->phy->supported.min_csma_backoffs = 0;
+	hw->phy->supported.max_csma_backoffs = 5;
+
+	ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
+
+	mutex_init(&lp->bmux);
+	init_completion(&lp->tx_complete);
+
+	/* Setup Status Message */
+	lp->stat_xfer.len = 1;
+	lp->stat_xfer.tx_buf = &lp->buf_stat_tx;
+	lp->stat_xfer.rx_buf = &lp->buf_stat_rx;
+	lp->buf_stat_tx = CMD_SPI_NOP;
+
+	spi_message_init(&lp->stat_msg);
+	spi_message_add_tail(&lp->stat_xfer, &lp->stat_msg);
+
+	spi_set_drvdata(spi, lp);
+
+	ret = adf7242_hw_init(lp);
+	if (ret)
+		goto err_hw_init;
+
+	irq_type = irq_get_trigger_type(spi->irq);
+	if (!irq_type)
+		irq_type = IRQF_TRIGGER_HIGH;
+
+	ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, adf7242_isr,
+					irq_type | IRQF_ONESHOT,
+					dev_name(&spi->dev), lp);
+	if (ret)
+		goto err_hw_init;
+
+	ret = ieee802154_register_hw(lp->hw);
+	if (ret)
+		goto err_hw_init;
+
+	dev_set_drvdata(&spi->dev, lp);
+
+	/* move to debugfs, maybe add some helper to ieee802154_ops ? */
+	ret = sysfs_create_file(&spi->dev.kobj, &dev_attr_status.attr);
+	if (ret)
+		goto out;
+
+	dev_info(&spi->dev, "mac802154 IRQ-%d registered\n", spi->irq);
+
+	return ret;
+
+out:
+	ieee802154_unregister_hw(lp->hw);
+err_hw_init:
+	mutex_destroy(&lp->bmux);
+	ieee802154_free_hw(lp->hw);
+
+	return ret;
+}
+
+static int adf7242_remove(struct spi_device *spi)
+{
+	struct adf7242_local *lp = spi_get_drvdata(spi);
+
+	sysfs_remove_file(&spi->dev.kobj, &dev_attr_status.attr);
+	ieee802154_unregister_hw(lp->hw);
+	mutex_destroy(&lp->bmux);
+	ieee802154_free_hw(lp->hw);
+
+	return 0;
+}
+
+static const struct of_device_id adf7242_of_match[] = {
+	{ .compatible = "adi,adf7242", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, adf7242_of_match);
+
+static const struct spi_device_id adf7242_device_id[] = {
+	{ .name = "adf7242", },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, adf7242_device_id);
+
+static struct spi_driver adf7242_driver = {
+	.id_table = adf7242_device_id,
+	.driver = {
+		   .of_match_table = of_match_ptr(adf7242_of_match),
+		   .name = "adf7242",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = adf7242_probe,
+	.remove = adf7242_remove,
+};
+
+module_spi_driver(adf7242_driver);
+
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
+MODULE_DESCRIPTION("ADF7242 IEEE802.15.4 Transceiver Driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-04  9:09 ` michael.hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: michael.hennerich @ 2015-12-04  9:09 UTC (permalink / raw)
  To: alex.aring, stefan, marcel; +Cc: linux-wpan, linux-bluetooth, Michael Hennerich

From: Michael Hennerich <michael.hennerich@analog.com>

This driver has been sitting in the linux-zigbee[2] repository for a long
time. We updated it from time to time and made it available via our
github kernel repository. The Linux MAC802.15.4 support has improved a lot
since then. Thanks to all! So it’s finally time to upstream this driver.

The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
operating modes. The firmware file is currently made available on the
ADF7242 wiki page here [1]

[1] http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
[2] http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
---
 .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
 drivers/net/ieee802154/Kconfig                     |    5 +
 drivers/net/ieee802154/Makefile                    |    1 +
 drivers/net/ieee802154/adf7242.c                   | 1183 ++++++++++++++++++++
 4 files changed, 1207 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
 create mode 100644 drivers/net/ieee802154/adf7242.c

diff --git a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
new file mode 100644
index 0000000..dea5124
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
@@ -0,0 +1,18 @@
+* ADF7242 IEEE 802.15.4 *
+
+Required properties:
+  - compatible:		should be "adi,adf7242"
+  - spi-max-frequency:	maximal bus speed (12.5 MHz)
+  - reg:		the chipselect index
+  - interrupts:		the interrupt generated by the device via pin IRQ1.
+			IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
+
+Example:
+
+	adf7242@0 {
+		compatible = "adi,adf7242";
+		spi-max-frequency = <10000000>;
+		reg = <0>;
+		interrupts = <98 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-parent = <&gpio3>;
+	};
diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig
index ce5f1a2..fd17598 100644
--- a/drivers/net/ieee802154/Kconfig
+++ b/drivers/net/ieee802154/Kconfig
@@ -71,3 +71,8 @@ config IEEE802154_ATUSB
 
 	  This driver can also be built as a module. To do so say M here.
 	  The module will be called 'atusb'.
+
+config IEEE802154_ADF7242
+       tristate "ADF7242 transceiver driver"
+       depends on IEEE802154_DRIVERS && MAC802154
+       depends on SPI
diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile
index cf1d2a6..3a923d3 100644
--- a/drivers/net/ieee802154/Makefile
+++ b/drivers/net/ieee802154/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
 obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
 obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o
 obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o
+obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o
diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c
new file mode 100644
index 0000000..48268b1
--- /dev/null
+++ b/drivers/net/ieee802154/adf7242.c
@@ -0,0 +1,1183 @@
+/*
+ * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver
+ *
+ * Copyright 2009-2015 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/firmware.h>
+#include <linux/spi/spi.h>
+#include <linux/skbuff.h>
+#include <linux/of.h>
+#include <linux/ieee802154.h>
+#include <net/mac802154.h>
+#include <net/cfg802154.h>
+
+#define FIRMWARE "adf7242_firmware.bin"
+#define MAX_POLL_LOOPS 50
+
+/* All Registers */
+
+#define REG_EXT_CTRL	0x100	/* RW External LNA/PA and internal PA control */
+#define REG_TX_FSK_TEST 0x101	/* RW TX FSK test mode configuration */
+#define REG_CCA1	0x105	/* RW RSSI threshold for CCA */
+#define REG_CCA2	0x106	/* RW CCA mode configuration */
+#define REG_BUFFERCFG	0x107	/* RW RX_BUFFER overwrite control */
+#define REG_PKT_CFG	0x108	/* RW FCS evaluation configuration */
+#define REG_DELAYCFG0	0x109	/* RW RC_RX command to SFD or sync word delay */
+#define REG_DELAYCFG1	0x10A	/* RW RC_TX command to TX state */
+#define REG_DELAYCFG2	0x10B	/* RW Mac delay extension */
+#define REG_SYNC_WORD0	0x10C	/* RW sync word bits [7:0] of [23:0]  */
+#define REG_SYNC_WORD1	0x10D	/* RW sync word bits [15:8] of [23:0]  */
+#define REG_SYNC_WORD2	0x10E	/* RW sync word bits [23:16] of [23:0]	*/
+#define REG_SYNC_CONFIG	0x10F	/* RW sync word configuration */
+#define REG_RC_CFG	0x13E	/* RW RX / TX packet configuration */
+#define REG_RC_VAR44	0x13F	/* RW RESERVED */
+#define REG_CH_FREQ0	0x300	/* RW Channel Frequency Settings - Low */
+#define REG_CH_FREQ1	0x301	/* RW Channel Frequency Settings - Middle */
+#define REG_CH_FREQ2	0x302	/* RW Channel Frequency Settings - High */
+#define REG_TX_FD	0x304	/* RW TX Frequency Deviation Register */
+#define REG_DM_CFG0	0x305	/* RW RX Discriminator BW Register */
+#define REG_TX_M	0x306	/* RW TX Mode Register */
+#define REG_RX_M	0x307	/* RW RX Mode Register */
+#define REG_RRB		0x30C	/* R RSSI Readback Register */
+#define REG_LRB		0x30D	/* R Link Quality Readback Register */
+#define REG_DR0		0x30E	/* RW bits [15:8] of [15:0] data rate setting */
+#define REG_DR1		0x30F	/* RW bits [7:0] of [15:0] data rate setting */
+#define REG_PRAMPG	0x313	/* RW RESERVED */
+#define REG_TXPB	0x314	/* RW TX Packet Storage Base Address */
+#define REG_RXPB	0x315	/* RW RX Packet Storage Base Address */
+#define REG_TMR_CFG0	0x316	/* RW Wake up Timer Conf Register - High */
+#define REG_TMR_CFG1	0x317	/* RW Wake up Timer Conf Register - Low */
+#define REG_TMR_RLD0	0x318	/* RW Wake up Timer Value Register - High */
+#define REG_TMR_RLD1	0x319	/* RW Wake up Timer Value Register - Low  */
+#define REG_TMR_CTRL	0x31A	/* RW Wake up Timer Timeout flag */
+#define REG_PD_AUX	0x31E	/* RW Battmon enable */
+#define REG_GP_CFG	0x32C	/* RW GPIO Configuration */
+#define REG_GP_OUT	0x32D	/* RW GPIO Configuration */
+#define REG_GP_IN	0x32E	/* R GPIO Configuration */
+#define REG_SYNT	0x335	/* RW bandwidth calibration timers */
+#define REG_CAL_CFG	0x33D	/* RW Calibration Settings */
+#define REG_PA_BIAS	0x36E	/* RW PA BIAS */
+#define REG_SYNT_CAL	0x371	/* RW Oscillator and Doubler Configuration */
+#define REG_IIRF_CFG	0x389	/* RW BB Filter Decimation Rate */
+#define REG_CDR_CFG	0x38A	/* RW CDR kVCO */
+#define REG_DM_CFG1	0x38B	/* RW Postdemodulator Filter */
+#define REG_AGCSTAT	0x38E	/* R RXBB Ref Osc Calibration Engine Readback */
+#define REG_RXCAL0	0x395	/* RW RX BB filter tuning, LSB */
+#define REG_RXCAL1	0x396	/* RW RX BB filter tuning, MSB */
+#define REG_RXFE_CFG	0x39B	/* RW RXBB Ref Osc & RXFE Calibration */
+#define REG_PA_RR	0x3A7	/* RW Set PA ramp rate */
+#define REG_PA_CFG	0x3A8	/* RW PA enable */
+#define REG_EXTPA_CFG	0x3A9	/* RW External PA BIAS DAC */
+#define REG_EXTPA_MSC	0x3AA	/* RW PA Bias Mode */
+#define REG_ADC_RBK	0x3AE	/* R Readback temp */
+#define REG_AGC_CFG1	0x3B2	/* RW GC Parameters */
+#define REG_AGC_MAX	0x3B4	/* RW Slew rate	 */
+#define REG_AGC_CFG2	0x3B6	/* RW RSSI Parameters */
+#define REG_AGC_CFG3	0x3B7	/* RW RSSI Parameters */
+#define REG_AGC_CFG4	0x3B8	/* RW RSSI Parameters */
+#define REG_AGC_CFG5	0x3B9	/* RW RSSI & NDEC Parameters */
+#define REG_AGC_CFG6	0x3BA	/* RW NDEC Parameters */
+#define REG_OCL_CFG1	0x3C4	/* RW OCL System Parameters */
+#define REG_IRQ1_EN0	0x3C7	/* RW Interrupt Mask set bits for IRQ1 */
+#define REG_IRQ1_EN1	0x3C8	/* RW Interrupt Mask set bits for IRQ1 */
+#define REG_IRQ2_EN0	0x3C9	/* RW Interrupt Mask set bits for IRQ2 */
+#define REG_IRQ2_EN1	0x3CA	/* RW Interrupt Mask set bits for IRQ2 */
+#define REG_IRQ1_SRC0	0x3CB	/* RW Interrupt Source bits for IRQ */
+#define REG_IRQ1_SRC1	0x3CC	/* RW Interrupt Source bits for IRQ */
+#define REG_OCL_BW0	0x3D2	/* RW OCL System Parameters */
+#define REG_OCL_BW1	0x3D3	/* RW OCL System Parameters */
+#define REG_OCL_BW2	0x3D4	/* RW OCL System Parameters */
+#define REG_OCL_BW3	0x3D5	/* RW OCL System Parameters */
+#define REG_OCL_BW4	0x3D6	/* RW OCL System Parameters */
+#define REG_OCL_BWS	0x3D7	/* RW OCL System Parameters */
+#define REG_OCL_CFG13	0x3E0	/* RW OCL System Parameters */
+#define REG_GP_DRV	0x3E3	/* RW I/O pads Configuration and bg trim */
+#define REG_BM_CFG	0x3E6	/* RW Batt. Monitor Threshold Voltage setting */
+#define REG_SFD_15_4	0x3F4	/* RW Option to set non standard SFD */
+#define REG_AFC_CFG	0x3F7	/* RW AFC mode and polarity */
+#define REG_AFC_KI_KP	0x3F8	/* RW AFC ki and kp */
+#define REG_AFC_RANGE	0x3F9	/* RW AFC range */
+#define REG_AFC_READ	0x3FA	/* RW Readback frequency error */
+
+/* REG_EXTPA_MSC */
+#define PA_PWR(x)		(((x) & 0xF) << 4)
+#define EXTPA_BIAS_SRC		BIT(3)
+#define EXTPA_BIAS_MODE(x)	(((x) & 0x7) << 0)
+
+/* REG_PA_CFG */
+#define PA_BRIDGE_DBIAS(x)	(((x) & 0x1F) << 0)
+
+/* REG_PA_BIAS */
+#define PA_BIAS_CTRL(x)		(((x) & 0x1F) << 1)
+#define REG_PA_BIAS_DFL		BIT(0)
+
+#define REG_PAN_ID0		0x112
+#define REG_PAN_ID1		0x113
+#define REG_SHORT_ADDR_0	0x114
+#define REG_SHORT_ADDR_1	0x115
+#define REG_IEEE_ADDR_0		0x116
+#define REG_IEEE_ADDR_1		0x117
+#define REG_IEEE_ADDR_2		0x118
+#define REG_IEEE_ADDR_3		0x119
+#define REG_IEEE_ADDR_4		0x11A
+#define REG_IEEE_ADDR_5		0x11B
+#define REG_IEEE_ADDR_6		0x11C
+#define REG_IEEE_ADDR_7		0x11D
+#define REG_FFILT_CFG		0x11E
+#define REG_AUTO_CFG		0x11F
+#define REG_AUTO_TX1		0x120
+#define REG_AUTO_TX2		0x121
+#define REG_AUTO_STATUS		0x122
+
+/* REG_FFILT_CFG */
+#define ACCEPT_BEACON_FRAMES   BIT(0)
+#define ACCEPT_DATA_FRAMES     BIT(1)
+#define ACCEPT_ACK_FRAMES      BIT(2)
+#define ACCEPT_MACCMD_FRAMES   BIT(3)
+#define ACCEPT_RESERVED_FRAMES BIT(4)
+#define ACCEPT_ALL_ADDRESS     BIT(5)
+
+/* REG_AUTO_CFG */
+#define AUTO_ACK_FRAMEPEND     BIT(0)
+#define IS_PANCOORD	       BIT(1)
+#define RX_AUTO_ACK_EN	       BIT(3)
+#define CSMA_CA_RX_TURNAROUND  BIT(4)
+
+/* REG_AUTO_TX1 */
+#define MAX_FRAME_RETRIES(x)   ((x) & 0xF)
+#define MAX_CCA_RETRIES(x)     (((x) & 0x7) << 4)
+
+/* REG_AUTO_TX2 */
+#define CSMA_MAX_BE(x)	       ((x) & 0xF)
+#define CSMA_MIN_BE(x)	       (((x) & 0xF) << 4)
+
+#define CMD_SPI_NOP		0xFF /* No operation. Use for dummy writes */
+#define CMD_SPI_PKT_WR		0x10 /* Write telegram to the Packet RAM
+				      * starting from the TX packet base address
+				      * pointer tx_packet_base
+				      */
+#define CMD_SPI_PKT_RD		0x30 /* Read telegram from the Packet RAM
+				      * starting from RX packet base address
+				      * pointer rxpb.rx_packet_base
+				      */
+#define CMD_SPI_MEM_WR(x)	(0x18 + (x >> 8)) /* Write data to MCR or
+						   * Packet RAM sequentially
+						   */
+#define CMD_SPI_MEM_RD(x)	(0x38 + (x >> 8)) /* Read data from MCR or
+						   * Packet RAM sequentially
+						   */
+#define CMD_SPI_MEMR_WR(x)	(0x08 + (x >> 8)) /* Write data to MCR or Packet
+						   * RAM as random block
+						   */
+#define CMD_SPI_MEMR_RD(x)	(0x28 + (x >> 8)) /* Read data from MCR or
+						   * Packet RAM random block
+						   */
+#define CMD_SPI_PRAM_WR		0x1E /* Write data sequentially to current
+				      * PRAM page selected
+				      */
+#define CMD_SPI_PRAM_RD		0x3E /* Read data sequentially from current
+				      * PRAM page selected
+				      */
+#define CMD_RC_SLEEP		0xB1 /* Invoke transition of radio controller
+				      * into SLEEP state
+				      */
+#define CMD_RC_IDLE		0xB2 /* Invoke transition of radio controller
+				      * into IDLE state
+				      */
+#define CMD_RC_PHY_RDY		0xB3 /* Invoke transition of radio controller
+				      * into PHY_RDY state
+				      */
+#define CMD_RC_RX		0xB4 /* Invoke transition of radio controller
+				      * into RX state
+				      */
+#define CMD_RC_TX		0xB5 /* Invoke transition of radio controller
+				      * into TX state
+				      */
+#define CMD_RC_MEAS		0xB6 /* Invoke transition of radio controller
+				      * into MEAS state
+				      */
+#define CMD_RC_CCA		0xB7 /* Invoke Clear channel assessment */
+#define CMD_RC_CSMACA		0xC1 /* initiates CSMA-CA channel access
+				      * sequence and frame transmission
+				      */
+#define CMD_RC_PC_RESET		0xC7 /* Program counter reset */
+#define CMD_RC_RESET		0xC8 /* Resets the ADF7242 and puts it in
+				      * the sleep state
+				      */
+
+/* STATUS */
+
+#define STAT_SPI_READY		BIT(7)
+#define STAT_IRQ_STATUS		BIT(6)
+#define STAT_RC_READY		BIT(5)
+#define STAT_CCA_RESULT		BIT(4)
+#define RC_STATUS_IDLE		1
+#define RC_STATUS_MEAS		2
+#define RC_STATUS_PHY_RDY	3
+#define RC_STATUS_RX		4
+#define RC_STATUS_TX		5
+#define RC_STATUS_MASK		0xF
+
+/* AUTO_STATUS */
+
+#define SUCCESS			0
+#define SUCCESS_DATPEND		1
+#define FAILURE_CSMACA		2
+#define FAILURE_NOACK		3
+#define AUTO_STATUS_MASK	0x3
+
+#define PRAM_PAGESIZE		256
+
+/* IRQ1 */
+
+#define IRQ_CCA_COMPLETE	BIT(0)
+#define IRQ_SFD_RX		BIT(1)
+#define IRQ_SFD_TX		BIT(2)
+#define IRQ_RX_PKT_RCVD		BIT(3)
+#define IRQ_TX_PKT_SENT		BIT(4)
+#define IRQ_FRAME_VALID		BIT(5)
+#define IRQ_ADDRESS_VALID	BIT(6)
+#define IRQ_CSMA_CA		BIT(7)
+
+#define AUTO_TX_TURNAROUND	BIT(3)
+#define ADDON_EN		BIT(4)
+
+struct adf7242_local {
+	struct spi_device *spi;
+	struct completion tx_complete;
+	struct ieee802154_hw *hw;
+	struct mutex bmux; /* protect SPI messages */
+	struct spi_message stat_msg;
+	struct spi_transfer stat_xfer;
+	int tx_stat;
+	s8 rssi;
+	u8 max_frame_retries;
+	u8 max_cca_retries;
+
+	/* DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+
+	u8 buf[3] ____cacheline_aligned;
+	u8 buf_reg_tx[3];
+	u8 buf_read_tx[4];
+	u8 buf_read_rx[4];
+	u8 buf_stat_rx;
+	u8 buf_stat_tx;
+	u8 buf_cmd;
+};
+
+static int adf7242_status(struct adf7242_local *lp, u8 *stat)
+{
+	int status;
+
+	mutex_lock(&lp->bmux);
+	status = spi_sync(lp->spi, &lp->stat_msg);
+	*stat = lp->buf_stat_rx;
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int adf7242_wait_ready(struct adf7242_local *lp, int line)
+{
+	int cnt = 0, ret = 0;
+	u8 stat;
+
+	do {
+		adf7242_status(lp, &stat);
+		cnt++;
+	} while (!((stat & STAT_RC_READY) && (stat & STAT_SPI_READY)) &&
+		(cnt < MAX_POLL_LOOPS));
+
+	if (cnt >= MAX_POLL_LOOPS) {
+		dev_warn(&lp->spi->dev, "%s:line %d Timeout\n", __func__, line);
+		ret = -ETIMEDOUT;
+	}
+
+	dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
+
+	return ret;
+}
+
+static int adf7242_wait_status(struct adf7242_local *lp, int status, int line)
+{
+	int cnt = 0, ret = 0;
+	u8 stat;
+
+	do {
+		adf7242_status(lp, &stat);
+		stat &= RC_STATUS_MASK;
+		cnt++;
+	} while ((stat != status) && (cnt < MAX_POLL_LOOPS));
+
+	if (cnt >= MAX_POLL_LOOPS) {
+		dev_warn(&lp->spi->dev, "%s:line %d Timeout status 0x%x\n",
+			 __func__, line, stat);
+		ret = -ETIMEDOUT;
+	}
+
+	dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
+
+	return ret;
+}
+
+static int adf7242_write_fbuf(struct adf7242_local *lp, u8 *data, u8 len)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer_head = {
+		.len = 2,
+		.tx_buf = buf,
+
+	};
+	struct spi_transfer xfer_buf = {
+		.len = len,
+		.tx_buf = data,
+	};
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	buf[0] = CMD_SPI_PKT_WR;
+	buf[1] = len + 2;
+
+	status = spi_sync(lp->spi, &msg);
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int adf7242_read_fbuf(struct adf7242_local *lp,
+			     u8 *data, size_t len, bool packet_read)
+{
+	u8 *buf = lp->buf;
+	int status;
+	struct spi_message msg;
+	struct spi_transfer xfer_head = {
+		.len = 3,
+		.tx_buf = buf,
+		.rx_buf = buf,
+	};
+	struct spi_transfer xfer_buf = {
+		.len = len,
+		.rx_buf = data,
+	};
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	if (packet_read) {
+		buf[0] = CMD_SPI_PKT_RD;
+		buf[1] = CMD_SPI_NOP;
+		buf[2] = 0;	/* PHR */
+	} else {
+		buf[0] = CMD_SPI_PRAM_RD;
+		buf[1] = 0;
+		buf[2] = CMD_SPI_NOP;
+	}
+
+	status = spi_sync(lp->spi, &msg);
+
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int adf7242_read_reg(struct adf7242_local *lp, u16 addr, u8 *data)
+{
+	int status;
+	struct spi_message msg;
+
+	struct spi_transfer xfer = {
+		.len = 4,
+		.tx_buf = lp->buf_read_tx,
+		.rx_buf = lp->buf_read_rx,
+	};
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	lp->buf_read_tx[0] = CMD_SPI_MEM_RD(addr);
+	lp->buf_read_tx[1] = addr;
+	lp->buf_read_tx[2] = CMD_SPI_NOP;
+	lp->buf_read_tx[3] = CMD_SPI_NOP;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	status = spi_sync(lp->spi, &msg);
+	if (msg.status)
+		status = msg.status;
+
+	if (!status)
+		*data = lp->buf_read_rx[3];
+
+	mutex_unlock(&lp->bmux);
+
+	dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n", __func__,
+		 addr, *data);
+
+	return status;
+}
+
+static int adf7242_write_reg(struct adf7242_local *lp, u16 addr, u8 data)
+{
+	int status;
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	lp->buf_reg_tx[0] = CMD_SPI_MEM_WR(addr);
+	lp->buf_reg_tx[1] = addr;
+	lp->buf_reg_tx[2] = data;
+	status = spi_write(lp->spi, lp->buf_reg_tx, 3);
+	mutex_unlock(&lp->bmux);
+
+	dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n",
+		 __func__, addr, data);
+
+	return status;
+}
+
+static int adf7242_cmd(struct adf7242_local *lp, u8 cmd)
+{
+	int status;
+
+	dev_vdbg(&lp->spi->dev, "%s : CMD=0x%X\n", __func__, cmd);
+
+	adf7242_wait_ready(lp, __LINE__);
+
+	mutex_lock(&lp->bmux);
+	lp->buf_cmd = cmd;
+	status = spi_write(lp->spi, &lp->buf_cmd, 1);
+	mutex_unlock(&lp->bmux);
+
+	return status;
+}
+
+static int adf7242_upload_firmware(struct adf7242_local *lp, u8 *data, u16 len)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer_buf = { };
+	int status, i, page = 0;
+	u8 *buf = lp->buf;
+
+	struct spi_transfer xfer_head = {
+		.len = 2,
+		.tx_buf = buf,
+	};
+
+	buf[0] = CMD_SPI_PRAM_WR;
+	buf[1] = 0;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer_head, &msg);
+	spi_message_add_tail(&xfer_buf, &msg);
+
+	for (i = len; i >= 0; i -= PRAM_PAGESIZE) {
+		adf7242_write_reg(lp, REG_PRAMPG, page);
+
+		xfer_buf.len = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
+		xfer_buf.tx_buf = &data[page * PRAM_PAGESIZE];
+
+		mutex_lock(&lp->bmux);
+		status = spi_sync(lp->spi, &msg);
+		mutex_unlock(&lp->bmux);
+		page++;
+	}
+
+	return status;
+}
+
+static int adf7242_verify_firmware(struct adf7242_local *lp,
+				   const u8 *data, size_t len)
+{
+	int i, j;
+	unsigned int page;
+	u8 *buf = kmalloc(PRAM_PAGESIZE, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	for (page = 0, i = len; i >= 0; i -= PRAM_PAGESIZE, page++) {
+		size_t nb = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
+
+		adf7242_write_reg(lp, REG_PRAMPG, page);
+		adf7242_read_fbuf(lp, buf, nb, false);
+
+		for (j = 0; j < nb; j++) {
+			if (buf[j] != data[page * PRAM_PAGESIZE + j]) {
+				kfree(buf);
+				return -EIO;
+			}
+		}
+	}
+	kfree(buf);
+
+	return 0;
+}
+
+static int adf7242_set_txpower(struct ieee802154_hw *hw, int mbm)
+{
+	struct adf7242_local *lp = hw->priv;
+	u8 pwr, bias_ctrl, dbias, tmp;
+	int db = mbm / 100;
+
+	dev_vdbg(&lp->spi->dev, "%s : Power %d dB\n", __func__, db);
+
+	if (db > 5 || db < -26)
+		return -EINVAL;
+
+	db = DIV_ROUND_CLOSEST(db + 29, 2);
+
+	if (db > 15) {
+		dbias = 21;
+		bias_ctrl = 63;
+	} else {
+		dbias = 13;
+		bias_ctrl = 55;
+	}
+
+	pwr = clamp_t(u8, db, 3, 15);
+
+	adf7242_read_reg(lp, REG_PA_CFG, &tmp);
+	tmp &= ~PA_BRIDGE_DBIAS(~0);
+	tmp |= PA_BRIDGE_DBIAS(dbias);
+	adf7242_write_reg(lp, REG_PA_CFG, tmp);
+
+	adf7242_read_reg(lp, REG_PA_BIAS, &tmp);
+	tmp &= ~PA_BIAS_CTRL(~0);
+	tmp |= PA_BIAS_CTRL(bias_ctrl);
+	adf7242_write_reg(lp, REG_PA_BIAS, tmp);
+
+	adf7242_read_reg(lp, REG_EXTPA_MSC, &tmp);
+	tmp &= ~PA_PWR(~0);
+	tmp |= PA_PWR(pwr);
+
+	return adf7242_write_reg(lp, REG_EXTPA_MSC, tmp);
+}
+
+static int adf7242_set_csma_params(struct ieee802154_hw *hw, u8 min_be,
+				   u8 max_be, u8 retries)
+{
+	struct adf7242_local *lp = hw->priv;
+	int ret;
+
+	dev_vdbg(&lp->spi->dev, "%s : min_be=%d max_be=%d retries=%d\n",
+		 __func__, min_be, max_be, retries);
+
+	if (min_be > max_be || max_be > 8 || retries > 5)
+		return -EINVAL;
+
+	ret = adf7242_write_reg(lp, REG_AUTO_TX1,
+				MAX_FRAME_RETRIES(lp->max_frame_retries) |
+				MAX_CCA_RETRIES(retries));
+	if (ret)
+		return ret;
+
+	lp->max_cca_retries = retries;
+
+	return adf7242_write_reg(lp, REG_AUTO_TX2, CSMA_MAX_BE(max_be) |
+			CSMA_MIN_BE(min_be));
+}
+
+static int adf7242_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
+{
+	struct adf7242_local *lp = hw->priv;
+	int ret = 0;
+
+	dev_vdbg(&lp->spi->dev, "%s : Retries = %d\n", __func__, retries);
+
+	if (retries < -1 || retries > 15)
+		return -EINVAL;
+
+	if (retries >= 0)
+		ret = adf7242_write_reg(lp, REG_AUTO_TX1,
+					MAX_FRAME_RETRIES(retries) |
+					MAX_CCA_RETRIES(lp->max_cca_retries));
+
+	lp->max_frame_retries = retries;
+
+	return ret;
+}
+
+static int adf7242_ed(struct ieee802154_hw *hw, u8 *level)
+{
+	struct adf7242_local *lp = hw->priv;
+
+	*level = lp->rssi;
+
+	dev_vdbg(&lp->spi->dev, "%s :Exit level=%d\n",
+		 __func__, *level);
+
+	return 0;
+}
+
+static int adf7242_start(struct ieee802154_hw *hw)
+{
+	struct adf7242_local *lp = hw->priv;
+
+	adf7242_cmd(lp, CMD_RC_PHY_RDY);
+	return adf7242_cmd(lp, CMD_RC_RX);
+}
+
+static void adf7242_stop(struct ieee802154_hw *hw)
+{
+	struct adf7242_local *lp = hw->priv;
+
+	adf7242_cmd(lp, CMD_RC_IDLE);
+	adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
+}
+
+static int adf7242_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
+{
+	struct adf7242_local *lp = hw->priv;
+	unsigned long freq;
+
+	dev_dbg(&lp->spi->dev, "%s :Channel=%d\n", __func__, channel);
+
+	might_sleep();
+
+	WARN_ON(page != 0);
+	WARN_ON(channel < 11);
+	WARN_ON(channel > 26);
+
+	freq = (2405 + 5 * (channel - 11)) * 100;
+	adf7242_cmd(lp, CMD_RC_PHY_RDY);
+
+	adf7242_write_reg(lp, REG_CH_FREQ0, freq);
+	adf7242_write_reg(lp, REG_CH_FREQ1, freq >> 8);
+	adf7242_write_reg(lp, REG_CH_FREQ2, freq >> 16);
+
+	return adf7242_cmd(lp, CMD_RC_RX);
+}
+
+static int adf7242_set_hw_addr_filt(struct ieee802154_hw *hw,
+				    struct ieee802154_hw_addr_filt *filt,
+				    unsigned long changed)
+{
+	struct adf7242_local *lp = hw->priv;
+	u8 reg;
+
+	dev_dbg(&lp->spi->dev, "%s :Changed=0x%lX\n", __func__, changed);
+
+	might_sleep();
+
+	if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
+		u8 addr[8], i;
+
+		memcpy(addr, &filt->ieee_addr, 8);
+
+		for (i = 0; i < 8; i++)
+			adf7242_write_reg(lp, REG_IEEE_ADDR_0 + i, addr[i]);
+	}
+
+	if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
+		u16 saddr = le16_to_cpu(filt->short_addr);
+
+		adf7242_write_reg(lp, REG_SHORT_ADDR_0, saddr);
+		adf7242_write_reg(lp, REG_SHORT_ADDR_1, saddr >> 8);
+	}
+
+	if (changed & IEEE802154_AFILT_PANID_CHANGED) {
+		u16 pan_id = le16_to_cpu(filt->pan_id);
+
+		adf7242_write_reg(lp, REG_PAN_ID0, pan_id);
+		adf7242_write_reg(lp, REG_PAN_ID1, pan_id >> 8);
+	}
+
+	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
+		adf7242_read_reg(lp, REG_AUTO_CFG, &reg);
+		if (filt->pan_coord)
+			reg |= IS_PANCOORD;
+		else
+			reg &= ~IS_PANCOORD;
+		adf7242_write_reg(lp, REG_AUTO_CFG, reg);
+	}
+
+	return 0;
+}
+
+static int adf7242_set_promiscuous_mode(struct ieee802154_hw *hw, bool on)
+{
+	struct adf7242_local *lp = hw->priv;
+
+	dev_dbg(&lp->spi->dev, "%s : mode %d\n", __func__, on);
+
+	if (on) {
+		adf7242_write_reg(lp, REG_AUTO_CFG, 0);
+		return adf7242_write_reg(lp, REG_FFILT_CFG,
+				  ACCEPT_BEACON_FRAMES |
+				  ACCEPT_DATA_FRAMES |
+				  ACCEPT_MACCMD_FRAMES |
+				  ACCEPT_ALL_ADDRESS |
+				  ACCEPT_ACK_FRAMES |
+				  ACCEPT_RESERVED_FRAMES);
+	} else {
+		adf7242_write_reg(lp, REG_FFILT_CFG,
+				  ACCEPT_BEACON_FRAMES |
+				  ACCEPT_DATA_FRAMES |
+				  ACCEPT_MACCMD_FRAMES |
+				  ACCEPT_RESERVED_FRAMES);
+
+		return adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
+	}
+}
+
+static int adf7242_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
+{
+	struct adf7242_local *lp = hw->priv;
+	s8 level = clamp_t(s8, mbm / 100, S8_MIN, S8_MAX);
+
+	dev_dbg(&lp->spi->dev, "%s : level %d\n", __func__, level);
+
+	return adf7242_write_reg(lp, REG_CCA1, level);
+}
+
+static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
+{
+	struct adf7242_local *lp = hw->priv;
+	int ret;
+
+	reinit_completion(&lp->tx_complete);
+
+	ret = adf7242_write_fbuf(lp, skb->data, skb->len);
+	if (ret)
+		goto err;
+
+	ret = adf7242_cmd(lp, CMD_RC_PHY_RDY);
+	ret |= adf7242_cmd(lp, CMD_RC_CSMACA);
+
+	if (ret)
+		goto err;
+
+	ret = wait_for_completion_interruptible_timeout(&lp->tx_complete, HZ);
+	if (ret == -ERESTARTSYS)
+		goto err;
+	if (ret == 0) {
+		dev_warn(&lp->spi->dev, "Timeout waiting for TX interrupt\n");
+		ret = -ETIMEDOUT;
+		goto err;
+	}
+
+	if (lp->tx_stat != SUCCESS) {
+		dev_warn(&lp->spi->dev,
+			 "Error xmit: Retry count exceeded Status=0x%x\n",
+			 lp->tx_stat);
+		ret = -ECOMM;
+	} else {
+		ret = 0;
+	}
+
+err:
+	adf7242_cmd(lp, CMD_RC_RX);
+	return ret;
+}
+
+static int adf7242_rx(struct adf7242_local *lp)
+{
+	struct sk_buff *skb;
+	size_t len;
+	int ret;
+	u8 lqi, len_u8, *data;
+
+	adf7242_read_reg(lp, 0, &len_u8);
+
+	len = len_u8;
+
+	if (!ieee802154_is_valid_psdu_len(len)) {
+		dev_dbg(&lp->spi->dev,
+			"corrupted frame received len %d\n", len);
+		len = IEEE802154_MTU;
+	}
+
+	skb = dev_alloc_skb(len);
+	if (!skb)
+		return -ENOMEM;
+
+	data = skb_put(skb, len);
+	ret = adf7242_read_fbuf(lp, data, len, true);
+
+	if (!ret) {
+		lqi = data[len - 2];
+		lp->rssi = data[len - 1];
+	}
+
+	adf7242_cmd(lp, CMD_RC_RX);
+
+	skb_trim(skb, len - 2);	/* Don't put RSSI/LQI or CRC into the frame */
+
+	ieee802154_rx_irqsafe(lp->hw, skb, lqi);
+
+	dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n",
+		__func__, ret, len, lqi, lp->rssi);
+
+	return 0;
+}
+
+static struct ieee802154_ops adf7242_ops = {
+	.owner = THIS_MODULE,
+	.xmit_sync = adf7242_xmit,
+	.ed = adf7242_ed,
+	.set_channel = adf7242_channel,
+	.set_hw_addr_filt = adf7242_set_hw_addr_filt,
+	.start = adf7242_start,
+	.stop = adf7242_stop,
+	.set_csma_params = adf7242_set_csma_params,
+	.set_frame_retries = adf7242_set_frame_retries,
+	.set_txpower = adf7242_set_txpower,
+	.set_promiscuous_mode = adf7242_set_promiscuous_mode,
+	.set_cca_ed_level = adf7242_set_cca_ed_level,
+};
+
+static irqreturn_t adf7242_isr(int irq, void *data)
+{
+	struct adf7242_local *lp = data;
+	u8 irq1, auto_stat = 0, stat = 0, rx_en = 0;
+
+	adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
+	adf7242_write_reg(lp, REG_IRQ1_SRC1, irq1);
+
+	if (!(irq1 & (IRQ_RX_PKT_RCVD | IRQ_CSMA_CA)))
+		dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n",
+			__func__, irq1);
+
+	dev_dbg(&lp->spi->dev, "%s IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n",
+		__func__, irq1,
+		irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
+		irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
+		irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
+		irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
+		irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
+		irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
+		irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
+		irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
+
+	adf7242_status(lp, &stat);
+
+	dev_dbg(&lp->spi->dev, "%s STATUS = %X:\n%s\n%s%s%s%s%s\n",
+		__func__, stat,
+		stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
+		(stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
+		(stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
+		(stat & 0xf) == RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
+		(stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
+		(stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
+
+	if ((irq1 & IRQ_RX_PKT_RCVD) && (irq1 & IRQ_FRAME_VALID)) {
+		/* Wait until ACK is processed */
+		if ((stat & RC_STATUS_MASK) != RC_STATUS_PHY_RDY)
+			adf7242_wait_status(lp, RC_STATUS_PHY_RDY, __LINE__);
+
+		adf7242_rx(lp);
+		rx_en = 1;
+	}
+
+	if (irq1 & IRQ_CSMA_CA) {
+		adf7242_read_reg(lp, REG_AUTO_STATUS, &auto_stat);
+		auto_stat &= AUTO_STATUS_MASK;
+
+		dev_dbg(&lp->spi->dev, "%s AUTO_STATUS = %X:\n%s%s%s%s\n",
+			__func__, auto_stat,
+			auto_stat == SUCCESS ? "SUCCESS" : "",
+			auto_stat ==
+			SUCCESS_DATPEND ? "SUCCESS_DATPEND" : "",
+			auto_stat == FAILURE_CSMACA ? "FAILURE_CSMACA" : "",
+			auto_stat == FAILURE_NOACK ? "FAILURE_NOACK" : "");
+
+		/* save CSMA-CA completion status */
+		lp->tx_stat = auto_stat;
+		rx_en = 1;
+
+		complete(&lp->tx_complete);
+	}
+
+	if (!rx_en)
+		adf7242_cmd(lp, CMD_RC_RX);
+
+	return IRQ_HANDLED;
+}
+
+static int adf7242_hw_init(struct adf7242_local *lp)
+{
+	int ret;
+	const struct firmware *fw;
+
+	adf7242_cmd(lp, CMD_RC_RESET);
+	adf7242_cmd(lp, CMD_RC_IDLE);
+
+	/* get ADF7242 addon firmware
+	 * build this driver as module
+	 * and place under /lib/firmware/adf7242_firmware.bin
+	 */
+	ret = request_firmware(&fw, FIRMWARE, &lp->spi->dev);
+	if (ret) {
+		dev_err(&lp->spi->dev,
+			"request_firmware() failed with %d\n", ret);
+		return ret;
+	}
+
+	ret = adf7242_upload_firmware(lp, (u8 *)fw->data, fw->size);
+	if (ret) {
+		dev_err(&lp->spi->dev,
+			"upload firmware failed with %d\n", ret);
+		return ret;
+	}
+
+	ret = adf7242_verify_firmware(lp, (u8 *)fw->data, fw->size);
+	if (ret) {
+		dev_err(&lp->spi->dev,
+			"verify firmware failed with %d\n", ret);
+		return ret;
+	}
+
+	adf7242_cmd(lp, CMD_RC_PC_RESET);
+
+	release_firmware(fw);
+
+	adf7242_write_reg(lp, REG_FFILT_CFG,
+			  ACCEPT_BEACON_FRAMES |
+			  ACCEPT_DATA_FRAMES |
+			  ACCEPT_MACCMD_FRAMES |
+			  ACCEPT_RESERVED_FRAMES);
+
+	adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
+
+	adf7242_write_reg(lp, REG_PKT_CFG, ADDON_EN | BIT(2));
+
+	adf7242_write_reg(lp, REG_EXTPA_MSC, 0xF1);
+	adf7242_write_reg(lp, REG_RXFE_CFG, 0x1D);
+
+	adf7242_write_reg(lp, REG_IRQ1_EN0, 0);
+	adf7242_write_reg(lp, REG_IRQ1_EN1, IRQ_RX_PKT_RCVD | IRQ_CSMA_CA);
+
+	adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
+	adf7242_write_reg(lp, REG_IRQ1_SRC0, 0xFF);
+
+	adf7242_cmd(lp, CMD_RC_IDLE);
+
+	return 0;
+}
+
+static ssize_t adf7242_show(struct device *dev,
+			    struct device_attribute *devattr, char *buf)
+{
+	struct adf7242_local *lp = dev_get_drvdata(dev);
+	u8 stat, irq1;
+	size_t len;
+
+	adf7242_status(lp, &stat);
+
+	adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
+
+	len = sprintf(buf, "IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n", irq1,
+		      irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
+		      irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
+		      irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
+		      irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
+		      irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
+		      irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
+		      irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
+		      irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
+
+	len += sprintf(buf + len, "STATUS = %X:\n%s\n%s%s%s%s%s\n", stat,
+		       stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
+		       (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
+		       (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
+		       (stat & 0xf) ==
+				RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
+		       (stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
+		       (stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
+
+	len += sprintf(buf + len, "RSSI = %d\n", lp->rssi);
+
+	return len;
+}
+static DEVICE_ATTR(status, 0664, adf7242_show, NULL);
+
+static const s32 adf7242_powers[] = {
+	500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700,
+	-800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700,
+	-1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600,
+};
+
+static const s32 adf7242_ed_levels[] = {
+	-9000, -8900, -8800, -8700, -8600, -8500, -8400, -8300, -8200, -8100,
+	-8000, -7900, -7800, -7700, -7600, -7500, -7400, -7300, -7200, -7100,
+	-7000, -6900, -6800, -6700, -6600, -6500, -6400, -6300, -6200, -6100,
+	-6000, -5900, -5800, -5700, -5600, -5500, -5400, -5300, -5200, -5100,
+	-5000, -4900, -4800, -4700, -4600, -4500, -4400, -4300, -4200, -4100,
+	-4000, -3900, -3800, -3700, -3600, -3500, -3400, -3200, -3100, -3000
+};
+
+static int adf7242_probe(struct spi_device *spi)
+{
+	struct ieee802154_hw *hw;
+	struct adf7242_local *lp;
+	int ret, irq_type;
+
+	if (!spi->irq) {
+		dev_err(&spi->dev, "no IRQ specified\n");
+		return -EINVAL;
+	}
+
+	hw = ieee802154_alloc_hw(sizeof(*lp), &adf7242_ops);
+	if (!hw)
+		return -ENOMEM;
+
+	lp = hw->priv;
+	lp->hw = hw;
+	lp->spi = spi;
+
+	hw->priv = lp;
+	hw->parent = &spi->dev;
+	hw->extra_tx_headroom = 0;
+
+	/* We support only 2.4 Ghz */
+	hw->phy->supported.channels[0] = 0x7FFF800;
+
+	hw->flags = IEEE802154_HW_OMIT_CKSUM |
+		    IEEE802154_HW_CSMA_PARAMS |
+		    IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT |
+		    IEEE802154_HW_PROMISCUOUS;
+
+	hw->phy->flags = WPAN_PHY_FLAG_TXPOWER |
+			 WPAN_PHY_FLAG_CCA_ED_LEVEL |
+			 WPAN_PHY_FLAG_CCA_MODE;
+
+	hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY);
+
+	hw->phy->supported.cca_ed_levels = adf7242_ed_levels;
+	hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(adf7242_ed_levels);
+
+	hw->phy->cca.mode = NL802154_CCA_ENERGY;
+
+	hw->phy->supported.tx_powers = adf7242_powers;
+	hw->phy->supported.tx_powers_size = ARRAY_SIZE(adf7242_powers);
+
+	hw->phy->supported.min_minbe = 0;
+	hw->phy->supported.max_minbe = 8;
+
+	hw->phy->supported.min_maxbe = 3;
+	hw->phy->supported.max_maxbe = 8;
+
+	hw->phy->supported.min_frame_retries = 0;
+	hw->phy->supported.max_frame_retries = 15;
+
+	hw->phy->supported.min_csma_backoffs = 0;
+	hw->phy->supported.max_csma_backoffs = 5;
+
+	ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
+
+	mutex_init(&lp->bmux);
+	init_completion(&lp->tx_complete);
+
+	/* Setup Status Message */
+	lp->stat_xfer.len = 1;
+	lp->stat_xfer.tx_buf = &lp->buf_stat_tx;
+	lp->stat_xfer.rx_buf = &lp->buf_stat_rx;
+	lp->buf_stat_tx = CMD_SPI_NOP;
+
+	spi_message_init(&lp->stat_msg);
+	spi_message_add_tail(&lp->stat_xfer, &lp->stat_msg);
+
+	spi_set_drvdata(spi, lp);
+
+	ret = adf7242_hw_init(lp);
+	if (ret)
+		goto err_hw_init;
+
+	irq_type = irq_get_trigger_type(spi->irq);
+	if (!irq_type)
+		irq_type = IRQF_TRIGGER_HIGH;
+
+	ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, adf7242_isr,
+					irq_type | IRQF_ONESHOT,
+					dev_name(&spi->dev), lp);
+	if (ret)
+		goto err_hw_init;
+
+	ret = ieee802154_register_hw(lp->hw);
+	if (ret)
+		goto err_hw_init;
+
+	dev_set_drvdata(&spi->dev, lp);
+
+	/* move to debugfs, maybe add some helper to ieee802154_ops ? */
+	ret = sysfs_create_file(&spi->dev.kobj, &dev_attr_status.attr);
+	if (ret)
+		goto out;
+
+	dev_info(&spi->dev, "mac802154 IRQ-%d registered\n", spi->irq);
+
+	return ret;
+
+out:
+	ieee802154_unregister_hw(lp->hw);
+err_hw_init:
+	mutex_destroy(&lp->bmux);
+	ieee802154_free_hw(lp->hw);
+
+	return ret;
+}
+
+static int adf7242_remove(struct spi_device *spi)
+{
+	struct adf7242_local *lp = spi_get_drvdata(spi);
+
+	sysfs_remove_file(&spi->dev.kobj, &dev_attr_status.attr);
+	ieee802154_unregister_hw(lp->hw);
+	mutex_destroy(&lp->bmux);
+	ieee802154_free_hw(lp->hw);
+
+	return 0;
+}
+
+static const struct of_device_id adf7242_of_match[] = {
+	{ .compatible = "adi,adf7242", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, adf7242_of_match);
+
+static const struct spi_device_id adf7242_device_id[] = {
+	{ .name = "adf7242", },
+	{ },
+};
+MODULE_DEVICE_TABLE(spi, adf7242_device_id);
+
+static struct spi_driver adf7242_driver = {
+	.id_table = adf7242_device_id,
+	.driver = {
+		   .of_match_table = of_match_ptr(adf7242_of_match),
+		   .name = "adf7242",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = adf7242_probe,
+	.remove = adf7242_remove,
+};
+
+module_spi_driver(adf7242_driver);
+
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
+MODULE_DESCRIPTION("ADF7242 IEEE802.15.4 Transceiver Driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-04  9:09 ` michael.hennerich
  (?)
@ 2015-12-04 12:07 ` Stefan Schmidt
  2015-12-07 12:02   ` Stefan Schmidt
  2015-12-07 12:47     ` Michael Hennerich
  -1 siblings, 2 replies; 36+ messages in thread
From: Stefan Schmidt @ 2015-12-04 12:07 UTC (permalink / raw)
  To: michael.hennerich, alex.aring, marcel; +Cc: linux-wpan, linux-bluetooth

Hello.

On 04/12/15 10:09, michael.hennerich@analog.com wrote:
> From: Michael Hennerich <michael.hennerich@analog.com>
>
> This driver has been sitting in the linux-zigbee[2] repository for a long
> time. We updated it from time to time and made it available via our
> github kernel repository. The Linux MAC802.15.4 support has improved a lot
> since then. Thanks to all! So it’s finally time to upstream this driver.

Thanks for taking the time and bringing it back to mainline!

> The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
> operating modes. The firmware file is currently made available on the
> ADF7242 wiki page here [1]

Just being curious here. Is there any way to get the firmware source 
and/or compile your own? Its the first hardware for IEEE 802.15.4 I have 
seen that have a special firmware for this which triggers my curiosity. :)

Anyway, this has not that much to do with the driver review here as it 
can obviously go in with the binary firmware. We just need to make sure 
to also bring the firmware into the linux-firmware repo in time.

> [1] http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
> [2] http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
>
> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
> ---
>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>   drivers/net/ieee802154/Kconfig                     |    5 +
>   drivers/net/ieee802154/Makefile                    |    1 +
>   drivers/net/ieee802154/adf7242.c                   | 1183 ++++++++++++++++++++
>   4 files changed, 1207 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>   create mode 100644 drivers/net/ieee802154/adf7242.c
>
> diff --git a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
> new file mode 100644
> index 0000000..dea5124
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
> @@ -0,0 +1,18 @@
> +* ADF7242 IEEE 802.15.4 *
> +
> +Required properties:
> +  - compatible:		should be "adi,adf7242"
> +  - spi-max-frequency:	maximal bus speed (12.5 MHz)
> +  - reg:		the chipselect index
> +  - interrupts:		the interrupt generated by the device via pin IRQ1.
> +			IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
> +
> +Example:
> +
> +	adf7242@0 {
> +		compatible = "adi,adf7242";
> +		spi-max-frequency = <10000000>;
> +		reg = <0>;
> +		interrupts = <98 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupt-parent = <&gpio3>;
> +	};
> diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig
> index ce5f1a2..fd17598 100644
> --- a/drivers/net/ieee802154/Kconfig
> +++ b/drivers/net/ieee802154/Kconfig
> @@ -71,3 +71,8 @@ config IEEE802154_ATUSB
>   
>   	  This driver can also be built as a module. To do so say M here.
>   	  The module will be called 'atusb'.
> +
> +config IEEE802154_ADF7242
> +       tristate "ADF7242 transceiver driver"
> +       depends on IEEE802154_DRIVERS && MAC802154
> +       depends on SPI

Maybe some help text here?

> diff --git a/drivers/net/ieee802154/Makefile b/drivers/net/ieee802154/Makefile
> index cf1d2a6..3a923d3 100644
> --- a/drivers/net/ieee802154/Makefile
> +++ b/drivers/net/ieee802154/Makefile
> @@ -3,3 +3,4 @@ obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
>   obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
>   obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o
>   obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o
> +obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o
> diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c
> new file mode 100644
> index 0000000..48268b1
> --- /dev/null
> +++ b/drivers/net/ieee802154/adf7242.c
> @@ -0,0 +1,1183 @@
> +/*
> + * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver
> + *
> + * Copyright 2009-2015 Analog Devices Inc.
> + *

Personally I like having a link to the actual data sheet inside the 
driver header. This makes only sense if it is a stable URI.

> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>

You also want #include <linux/irq.h> here. Without it the compilation 
fails for me with:

drivers/net/ieee802154/adf7242.c: In function 'adf7242_probe':
drivers/net/ieee802154/adf7242.c:1110:13: error: implicit declaration of 
function 'irq_get_trigger_type' [-Werror=implicit-function-declaration]
   irq_type = irq_get_trigger_type(spi->irq);
              ^
cc1: some warnings being treated as errors


> +#include <linux/delay.h>
> +#include <linux/mutex.h>
> +#include <linux/workqueue.h>
> +#include <linux/spinlock.h>
> +#include <linux/firmware.h>
> +#include <linux/spi/spi.h>
> +#include <linux/skbuff.h>
> +#include <linux/of.h>
> +#include <linux/ieee802154.h>
> +#include <net/mac802154.h>
> +#include <net/cfg802154.h>
> +
> +#define FIRMWARE "adf7242_firmware.bin"
> +#define MAX_POLL_LOOPS 50
> +
> +/* All Registers */
> +
> +#define REG_EXT_CTRL	0x100	/* RW External LNA/PA and internal PA control */
> +#define REG_TX_FSK_TEST 0x101	/* RW TX FSK test mode configuration */
> +#define REG_CCA1	0x105	/* RW RSSI threshold for CCA */
> +#define REG_CCA2	0x106	/* RW CCA mode configuration */
> +#define REG_BUFFERCFG	0x107	/* RW RX_BUFFER overwrite control */
> +#define REG_PKT_CFG	0x108	/* RW FCS evaluation configuration */
> +#define REG_DELAYCFG0	0x109	/* RW RC_RX command to SFD or sync word delay */
> +#define REG_DELAYCFG1	0x10A	/* RW RC_TX command to TX state */
> +#define REG_DELAYCFG2	0x10B	/* RW Mac delay extension */
> +#define REG_SYNC_WORD0	0x10C	/* RW sync word bits [7:0] of [23:0]  */
> +#define REG_SYNC_WORD1	0x10D	/* RW sync word bits [15:8] of [23:0]  */
> +#define REG_SYNC_WORD2	0x10E	/* RW sync word bits [23:16] of [23:0]	*/
> +#define REG_SYNC_CONFIG	0x10F	/* RW sync word configuration */
> +#define REG_RC_CFG	0x13E	/* RW RX / TX packet configuration */
> +#define REG_RC_VAR44	0x13F	/* RW RESERVED */
> +#define REG_CH_FREQ0	0x300	/* RW Channel Frequency Settings - Low */
> +#define REG_CH_FREQ1	0x301	/* RW Channel Frequency Settings - Middle */
> +#define REG_CH_FREQ2	0x302	/* RW Channel Frequency Settings - High */
> +#define REG_TX_FD	0x304	/* RW TX Frequency Deviation Register */
> +#define REG_DM_CFG0	0x305	/* RW RX Discriminator BW Register */
> +#define REG_TX_M	0x306	/* RW TX Mode Register */
> +#define REG_RX_M	0x307	/* RW RX Mode Register */
> +#define REG_RRB		0x30C	/* R RSSI Readback Register */
> +#define REG_LRB		0x30D	/* R Link Quality Readback Register */
> +#define REG_DR0		0x30E	/* RW bits [15:8] of [15:0] data rate setting */
> +#define REG_DR1		0x30F	/* RW bits [7:0] of [15:0] data rate setting */
> +#define REG_PRAMPG	0x313	/* RW RESERVED */
> +#define REG_TXPB	0x314	/* RW TX Packet Storage Base Address */
> +#define REG_RXPB	0x315	/* RW RX Packet Storage Base Address */
> +#define REG_TMR_CFG0	0x316	/* RW Wake up Timer Conf Register - High */
> +#define REG_TMR_CFG1	0x317	/* RW Wake up Timer Conf Register - Low */
> +#define REG_TMR_RLD0	0x318	/* RW Wake up Timer Value Register - High */
> +#define REG_TMR_RLD1	0x319	/* RW Wake up Timer Value Register - Low  */
> +#define REG_TMR_CTRL	0x31A	/* RW Wake up Timer Timeout flag */
> +#define REG_PD_AUX	0x31E	/* RW Battmon enable */
> +#define REG_GP_CFG	0x32C	/* RW GPIO Configuration */
> +#define REG_GP_OUT	0x32D	/* RW GPIO Configuration */
> +#define REG_GP_IN	0x32E	/* R GPIO Configuration */
> +#define REG_SYNT	0x335	/* RW bandwidth calibration timers */
> +#define REG_CAL_CFG	0x33D	/* RW Calibration Settings */
> +#define REG_PA_BIAS	0x36E	/* RW PA BIAS */
> +#define REG_SYNT_CAL	0x371	/* RW Oscillator and Doubler Configuration */
> +#define REG_IIRF_CFG	0x389	/* RW BB Filter Decimation Rate */
> +#define REG_CDR_CFG	0x38A	/* RW CDR kVCO */
> +#define REG_DM_CFG1	0x38B	/* RW Postdemodulator Filter */
> +#define REG_AGCSTAT	0x38E	/* R RXBB Ref Osc Calibration Engine Readback */
> +#define REG_RXCAL0	0x395	/* RW RX BB filter tuning, LSB */
> +#define REG_RXCAL1	0x396	/* RW RX BB filter tuning, MSB */
> +#define REG_RXFE_CFG	0x39B	/* RW RXBB Ref Osc & RXFE Calibration */
> +#define REG_PA_RR	0x3A7	/* RW Set PA ramp rate */
> +#define REG_PA_CFG	0x3A8	/* RW PA enable */
> +#define REG_EXTPA_CFG	0x3A9	/* RW External PA BIAS DAC */
> +#define REG_EXTPA_MSC	0x3AA	/* RW PA Bias Mode */
> +#define REG_ADC_RBK	0x3AE	/* R Readback temp */
> +#define REG_AGC_CFG1	0x3B2	/* RW GC Parameters */
> +#define REG_AGC_MAX	0x3B4	/* RW Slew rate	 */
> +#define REG_AGC_CFG2	0x3B6	/* RW RSSI Parameters */
> +#define REG_AGC_CFG3	0x3B7	/* RW RSSI Parameters */
> +#define REG_AGC_CFG4	0x3B8	/* RW RSSI Parameters */
> +#define REG_AGC_CFG5	0x3B9	/* RW RSSI & NDEC Parameters */
> +#define REG_AGC_CFG6	0x3BA	/* RW NDEC Parameters */
> +#define REG_OCL_CFG1	0x3C4	/* RW OCL System Parameters */
> +#define REG_IRQ1_EN0	0x3C7	/* RW Interrupt Mask set bits for IRQ1 */
> +#define REG_IRQ1_EN1	0x3C8	/* RW Interrupt Mask set bits for IRQ1 */
> +#define REG_IRQ2_EN0	0x3C9	/* RW Interrupt Mask set bits for IRQ2 */
> +#define REG_IRQ2_EN1	0x3CA	/* RW Interrupt Mask set bits for IRQ2 */
> +#define REG_IRQ1_SRC0	0x3CB	/* RW Interrupt Source bits for IRQ */
> +#define REG_IRQ1_SRC1	0x3CC	/* RW Interrupt Source bits for IRQ */
> +#define REG_OCL_BW0	0x3D2	/* RW OCL System Parameters */
> +#define REG_OCL_BW1	0x3D3	/* RW OCL System Parameters */
> +#define REG_OCL_BW2	0x3D4	/* RW OCL System Parameters */
> +#define REG_OCL_BW3	0x3D5	/* RW OCL System Parameters */
> +#define REG_OCL_BW4	0x3D6	/* RW OCL System Parameters */
> +#define REG_OCL_BWS	0x3D7	/* RW OCL System Parameters */
> +#define REG_OCL_CFG13	0x3E0	/* RW OCL System Parameters */
> +#define REG_GP_DRV	0x3E3	/* RW I/O pads Configuration and bg trim */
> +#define REG_BM_CFG	0x3E6	/* RW Batt. Monitor Threshold Voltage setting */
> +#define REG_SFD_15_4	0x3F4	/* RW Option to set non standard SFD */
> +#define REG_AFC_CFG	0x3F7	/* RW AFC mode and polarity */
> +#define REG_AFC_KI_KP	0x3F8	/* RW AFC ki and kp */
> +#define REG_AFC_RANGE	0x3F9	/* RW AFC range */
> +#define REG_AFC_READ	0x3FA	/* RW Readback frequency error */
> +
> +/* REG_EXTPA_MSC */
> +#define PA_PWR(x)		(((x) & 0xF) << 4)
> +#define EXTPA_BIAS_SRC		BIT(3)
> +#define EXTPA_BIAS_MODE(x)	(((x) & 0x7) << 0)
> +
> +/* REG_PA_CFG */
> +#define PA_BRIDGE_DBIAS(x)	(((x) & 0x1F) << 0)
> +
> +/* REG_PA_BIAS */
> +#define PA_BIAS_CTRL(x)		(((x) & 0x1F) << 1)
> +#define REG_PA_BIAS_DFL		BIT(0)
> +
> +#define REG_PAN_ID0		0x112
> +#define REG_PAN_ID1		0x113
> +#define REG_SHORT_ADDR_0	0x114
> +#define REG_SHORT_ADDR_1	0x115
> +#define REG_IEEE_ADDR_0		0x116
> +#define REG_IEEE_ADDR_1		0x117
> +#define REG_IEEE_ADDR_2		0x118
> +#define REG_IEEE_ADDR_3		0x119
> +#define REG_IEEE_ADDR_4		0x11A
> +#define REG_IEEE_ADDR_5		0x11B
> +#define REG_IEEE_ADDR_6		0x11C
> +#define REG_IEEE_ADDR_7		0x11D
> +#define REG_FFILT_CFG		0x11E
> +#define REG_AUTO_CFG		0x11F
> +#define REG_AUTO_TX1		0x120
> +#define REG_AUTO_TX2		0x121
> +#define REG_AUTO_STATUS		0x122
> +
> +/* REG_FFILT_CFG */
> +#define ACCEPT_BEACON_FRAMES   BIT(0)
> +#define ACCEPT_DATA_FRAMES     BIT(1)
> +#define ACCEPT_ACK_FRAMES      BIT(2)
> +#define ACCEPT_MACCMD_FRAMES   BIT(3)
> +#define ACCEPT_RESERVED_FRAMES BIT(4)
> +#define ACCEPT_ALL_ADDRESS     BIT(5)
> +
> +/* REG_AUTO_CFG */
> +#define AUTO_ACK_FRAMEPEND     BIT(0)
> +#define IS_PANCOORD	       BIT(1)
> +#define RX_AUTO_ACK_EN	       BIT(3)
> +#define CSMA_CA_RX_TURNAROUND  BIT(4)
> +
> +/* REG_AUTO_TX1 */
> +#define MAX_FRAME_RETRIES(x)   ((x) & 0xF)
> +#define MAX_CCA_RETRIES(x)     (((x) & 0x7) << 4)
> +
> +/* REG_AUTO_TX2 */
> +#define CSMA_MAX_BE(x)	       ((x) & 0xF)
> +#define CSMA_MIN_BE(x)	       (((x) & 0xF) << 4)
> +
> +#define CMD_SPI_NOP		0xFF /* No operation. Use for dummy writes */
> +#define CMD_SPI_PKT_WR		0x10 /* Write telegram to the Packet RAM
> +				      * starting from the TX packet base address
> +				      * pointer tx_packet_base
> +				      */
> +#define CMD_SPI_PKT_RD		0x30 /* Read telegram from the Packet RAM
> +				      * starting from RX packet base address
> +				      * pointer rxpb.rx_packet_base
> +				      */
> +#define CMD_SPI_MEM_WR(x)	(0x18 + (x >> 8)) /* Write data to MCR or
> +						   * Packet RAM sequentially
> +						   */
> +#define CMD_SPI_MEM_RD(x)	(0x38 + (x >> 8)) /* Read data from MCR or
> +						   * Packet RAM sequentially
> +						   */
> +#define CMD_SPI_MEMR_WR(x)	(0x08 + (x >> 8)) /* Write data to MCR or Packet
> +						   * RAM as random block
> +						   */
> +#define CMD_SPI_MEMR_RD(x)	(0x28 + (x >> 8)) /* Read data from MCR or
> +						   * Packet RAM random block
> +						   */
> +#define CMD_SPI_PRAM_WR		0x1E /* Write data sequentially to current
> +				      * PRAM page selected
> +				      */
> +#define CMD_SPI_PRAM_RD		0x3E /* Read data sequentially from current
> +				      * PRAM page selected
> +				      */
> +#define CMD_RC_SLEEP		0xB1 /* Invoke transition of radio controller
> +				      * into SLEEP state
> +				      */
> +#define CMD_RC_IDLE		0xB2 /* Invoke transition of radio controller
> +				      * into IDLE state
> +				      */
> +#define CMD_RC_PHY_RDY		0xB3 /* Invoke transition of radio controller
> +				      * into PHY_RDY state
> +				      */
> +#define CMD_RC_RX		0xB4 /* Invoke transition of radio controller
> +				      * into RX state
> +				      */
> +#define CMD_RC_TX		0xB5 /* Invoke transition of radio controller
> +				      * into TX state
> +				      */
> +#define CMD_RC_MEAS		0xB6 /* Invoke transition of radio controller
> +				      * into MEAS state
> +				      */
> +#define CMD_RC_CCA		0xB7 /* Invoke Clear channel assessment */
> +#define CMD_RC_CSMACA		0xC1 /* initiates CSMA-CA channel access
> +				      * sequence and frame transmission
> +				      */
> +#define CMD_RC_PC_RESET		0xC7 /* Program counter reset */
> +#define CMD_RC_RESET		0xC8 /* Resets the ADF7242 and puts it in
> +				      * the sleep state
> +				      */
> +
> +/* STATUS */
> +
> +#define STAT_SPI_READY		BIT(7)
> +#define STAT_IRQ_STATUS		BIT(6)
> +#define STAT_RC_READY		BIT(5)
> +#define STAT_CCA_RESULT		BIT(4)
> +#define RC_STATUS_IDLE		1
> +#define RC_STATUS_MEAS		2
> +#define RC_STATUS_PHY_RDY	3
> +#define RC_STATUS_RX		4
> +#define RC_STATUS_TX		5
> +#define RC_STATUS_MASK		0xF
> +
> +/* AUTO_STATUS */
> +
> +#define SUCCESS			0
> +#define SUCCESS_DATPEND		1
> +#define FAILURE_CSMACA		2
> +#define FAILURE_NOACK		3
> +#define AUTO_STATUS_MASK	0x3
> +
> +#define PRAM_PAGESIZE		256
> +
> +/* IRQ1 */
> +
> +#define IRQ_CCA_COMPLETE	BIT(0)
> +#define IRQ_SFD_RX		BIT(1)
> +#define IRQ_SFD_TX		BIT(2)
> +#define IRQ_RX_PKT_RCVD		BIT(3)
> +#define IRQ_TX_PKT_SENT		BIT(4)
> +#define IRQ_FRAME_VALID		BIT(5)
> +#define IRQ_ADDRESS_VALID	BIT(6)
> +#define IRQ_CSMA_CA		BIT(7)
> +
> +#define AUTO_TX_TURNAROUND	BIT(3)
> +#define ADDON_EN		BIT(4)
> +
> +struct adf7242_local {
> +	struct spi_device *spi;
> +	struct completion tx_complete;
> +	struct ieee802154_hw *hw;
> +	struct mutex bmux; /* protect SPI messages */
> +	struct spi_message stat_msg;
> +	struct spi_transfer stat_xfer;
> +	int tx_stat;
> +	s8 rssi;
> +	u8 max_frame_retries;
> +	u8 max_cca_retries;
> +
> +	/* DMA (thus cache coherency maintenance) requires the
> +	 * transfer buffers to live in their own cache lines.
> +	 */
> +
> +	u8 buf[3] ____cacheline_aligned;
> +	u8 buf_reg_tx[3];
> +	u8 buf_read_tx[4];
> +	u8 buf_read_rx[4];
> +	u8 buf_stat_rx;
> +	u8 buf_stat_tx;
> +	u8 buf_cmd;
> +};
> +
> +static int adf7242_status(struct adf7242_local *lp, u8 *stat)
> +{
> +	int status;
> +
> +	mutex_lock(&lp->bmux);
> +	status = spi_sync(lp->spi, &lp->stat_msg);
> +	*stat = lp->buf_stat_rx;
> +	mutex_unlock(&lp->bmux);
> +
> +	return status;
> +}
> +
> +static int adf7242_wait_ready(struct adf7242_local *lp, int line)
> +{
> +	int cnt = 0, ret = 0;
> +	u8 stat;
> +
> +	do {
> +		adf7242_status(lp, &stat);
> +		cnt++;
> +	} while (!((stat & STAT_RC_READY) && (stat & STAT_SPI_READY)) &&
> +		(cnt < MAX_POLL_LOOPS));
> +
> +	if (cnt >= MAX_POLL_LOOPS) {
> +		dev_warn(&lp->spi->dev, "%s:line %d Timeout\n", __func__, line);
> +		ret = -ETIMEDOUT;
> +	}
> +
> +	dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
> +
> +	return ret;
> +}
> +
> +static int adf7242_wait_status(struct adf7242_local *lp, int status, int line)
> +{
> +	int cnt = 0, ret = 0;
> +	u8 stat;
> +
> +	do {
> +		adf7242_status(lp, &stat);
> +		stat &= RC_STATUS_MASK;
> +		cnt++;
> +	} while ((stat != status) && (cnt < MAX_POLL_LOOPS));
> +
> +	if (cnt >= MAX_POLL_LOOPS) {
> +		dev_warn(&lp->spi->dev, "%s:line %d Timeout status 0x%x\n",
> +			 __func__, line, stat);
> +		ret = -ETIMEDOUT;
> +	}
> +
> +	dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
> +
> +	return ret;
> +}
> +
> +static int adf7242_write_fbuf(struct adf7242_local *lp, u8 *data, u8 len)
> +{
> +	u8 *buf = lp->buf;
> +	int status;
> +	struct spi_message msg;
> +	struct spi_transfer xfer_head = {
> +		.len = 2,
> +		.tx_buf = buf,
> +
> +	};
> +	struct spi_transfer xfer_buf = {
> +		.len = len,
> +		.tx_buf = data,
> +	};
> +
> +	spi_message_init(&msg);
> +	spi_message_add_tail(&xfer_head, &msg);
> +	spi_message_add_tail(&xfer_buf, &msg);
> +
> +	adf7242_wait_ready(lp, __LINE__);
> +
> +	mutex_lock(&lp->bmux);
> +	buf[0] = CMD_SPI_PKT_WR;
> +	buf[1] = len + 2;
> +
> +	status = spi_sync(lp->spi, &msg);
> +	mutex_unlock(&lp->bmux);
> +
> +	return status;
> +}
> +
> +static int adf7242_read_fbuf(struct adf7242_local *lp,
> +			     u8 *data, size_t len, bool packet_read)
> +{
> +	u8 *buf = lp->buf;
> +	int status;
> +	struct spi_message msg;
> +	struct spi_transfer xfer_head = {
> +		.len = 3,
> +		.tx_buf = buf,
> +		.rx_buf = buf,
> +	};
> +	struct spi_transfer xfer_buf = {
> +		.len = len,
> +		.rx_buf = data,
> +	};
> +
> +	spi_message_init(&msg);
> +	spi_message_add_tail(&xfer_head, &msg);
> +	spi_message_add_tail(&xfer_buf, &msg);
> +
> +	adf7242_wait_ready(lp, __LINE__);
> +
> +	mutex_lock(&lp->bmux);
> +	if (packet_read) {
> +		buf[0] = CMD_SPI_PKT_RD;
> +		buf[1] = CMD_SPI_NOP;
> +		buf[2] = 0;	/* PHR */
> +	} else {
> +		buf[0] = CMD_SPI_PRAM_RD;
> +		buf[1] = 0;
> +		buf[2] = CMD_SPI_NOP;
> +	}
> +
> +	status = spi_sync(lp->spi, &msg);
> +
> +	mutex_unlock(&lp->bmux);
> +
> +	return status;
> +}
> +
> +static int adf7242_read_reg(struct adf7242_local *lp, u16 addr, u8 *data)
> +{
> +	int status;
> +	struct spi_message msg;
> +
> +	struct spi_transfer xfer = {
> +		.len = 4,
> +		.tx_buf = lp->buf_read_tx,
> +		.rx_buf = lp->buf_read_rx,
> +	};
> +
> +	adf7242_wait_ready(lp, __LINE__);
> +
> +	mutex_lock(&lp->bmux);
> +	lp->buf_read_tx[0] = CMD_SPI_MEM_RD(addr);
> +	lp->buf_read_tx[1] = addr;
> +	lp->buf_read_tx[2] = CMD_SPI_NOP;
> +	lp->buf_read_tx[3] = CMD_SPI_NOP;
> +
> +	spi_message_init(&msg);
> +	spi_message_add_tail(&xfer, &msg);
> +
> +	status = spi_sync(lp->spi, &msg);
> +	if (msg.status)
> +		status = msg.status;
> +
> +	if (!status)
> +		*data = lp->buf_read_rx[3];
> +
> +	mutex_unlock(&lp->bmux);
> +
> +	dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n", __func__,
> +		 addr, *data);
> +
> +	return status;
> +}
> +
> +static int adf7242_write_reg(struct adf7242_local *lp, u16 addr, u8 data)
> +{
> +	int status;
> +
> +	adf7242_wait_ready(lp, __LINE__);
> +
> +	mutex_lock(&lp->bmux);
> +	lp->buf_reg_tx[0] = CMD_SPI_MEM_WR(addr);
> +	lp->buf_reg_tx[1] = addr;
> +	lp->buf_reg_tx[2] = data;
> +	status = spi_write(lp->spi, lp->buf_reg_tx, 3);
> +	mutex_unlock(&lp->bmux);
> +
> +	dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n",
> +		 __func__, addr, data);
> +
> +	return status;
> +}
> +
> +static int adf7242_cmd(struct adf7242_local *lp, u8 cmd)
> +{
> +	int status;
> +
> +	dev_vdbg(&lp->spi->dev, "%s : CMD=0x%X\n", __func__, cmd);
> +
> +	adf7242_wait_ready(lp, __LINE__);
> +
> +	mutex_lock(&lp->bmux);
> +	lp->buf_cmd = cmd;
> +	status = spi_write(lp->spi, &lp->buf_cmd, 1);
> +	mutex_unlock(&lp->bmux);
> +
> +	return status;
> +}
> +
> +static int adf7242_upload_firmware(struct adf7242_local *lp, u8 *data, u16 len)
> +{
> +	struct spi_message msg;
> +	struct spi_transfer xfer_buf = { };
> +	int status, i, page = 0;
> +	u8 *buf = lp->buf;
> +
> +	struct spi_transfer xfer_head = {
> +		.len = 2,
> +		.tx_buf = buf,
> +	};
> +
> +	buf[0] = CMD_SPI_PRAM_WR;
> +	buf[1] = 0;
> +
> +	spi_message_init(&msg);
> +	spi_message_add_tail(&xfer_head, &msg);
> +	spi_message_add_tail(&xfer_buf, &msg);
> +
> +	for (i = len; i >= 0; i -= PRAM_PAGESIZE) {
> +		adf7242_write_reg(lp, REG_PRAMPG, page);
> +
> +		xfer_buf.len = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
> +		xfer_buf.tx_buf = &data[page * PRAM_PAGESIZE];
> +
> +		mutex_lock(&lp->bmux);
> +		status = spi_sync(lp->spi, &msg);
> +		mutex_unlock(&lp->bmux);
> +		page++;
> +	}
> +
> +	return status;
> +}
> +
> +static int adf7242_verify_firmware(struct adf7242_local *lp,
> +				   const u8 *data, size_t len)

Could it really happen that we upload the firmware, getting fine status 
codes back from spi_sync and this have a broken firmware in ram? To me 
it looks like a safety measure for something that should never happen. 
But I don't know the hardware.
> +{
> +	int i, j;
> +	unsigned int page;
> +	u8 *buf = kmalloc(PRAM_PAGESIZE, GFP_KERNEL);
> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	for (page = 0, i = len; i >= 0; i -= PRAM_PAGESIZE, page++) {
> +		size_t nb = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
> +
> +		adf7242_write_reg(lp, REG_PRAMPG, page);
> +		adf7242_read_fbuf(lp, buf, nb, false);
> +
> +		for (j = 0; j < nb; j++) {
> +			if (buf[j] != data[page * PRAM_PAGESIZE + j]) {
> +				kfree(buf);
> +				return -EIO;
> +			}
> +		}
> +	}
> +	kfree(buf);
> +
> +	return 0;
> +}
> +
> +static int adf7242_set_txpower(struct ieee802154_hw *hw, int mbm)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +	u8 pwr, bias_ctrl, dbias, tmp;
> +	int db = mbm / 100;
> +
> +	dev_vdbg(&lp->spi->dev, "%s : Power %d dB\n", __func__, db);
> +
> +	if (db > 5 || db < -26)
> +		return -EINVAL;
> +
> +	db = DIV_ROUND_CLOSEST(db + 29, 2);
> +
> +	if (db > 15) {
> +		dbias = 21;
> +		bias_ctrl = 63;
> +	} else {
> +		dbias = 13;
> +		bias_ctrl = 55;

What the meaning of the values here? 21, 63, 13, 55

> +	}
> +
> +	pwr = clamp_t(u8, db, 3, 15);
> +
> +	adf7242_read_reg(lp, REG_PA_CFG, &tmp);
> +	tmp &= ~PA_BRIDGE_DBIAS(~0);
> +	tmp |= PA_BRIDGE_DBIAS(dbias);
> +	adf7242_write_reg(lp, REG_PA_CFG, tmp);
> +
> +	adf7242_read_reg(lp, REG_PA_BIAS, &tmp);
> +	tmp &= ~PA_BIAS_CTRL(~0);
> +	tmp |= PA_BIAS_CTRL(bias_ctrl);
> +	adf7242_write_reg(lp, REG_PA_BIAS, tmp);
> +
> +	adf7242_read_reg(lp, REG_EXTPA_MSC, &tmp);
> +	tmp &= ~PA_PWR(~0);
> +	tmp |= PA_PWR(pwr);
> +
> +	return adf7242_write_reg(lp, REG_EXTPA_MSC, tmp);
> +}
> +
> +static int adf7242_set_csma_params(struct ieee802154_hw *hw, u8 min_be,
> +				   u8 max_be, u8 retries)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +	int ret;
> +
> +	dev_vdbg(&lp->spi->dev, "%s : min_be=%d max_be=%d retries=%d\n",
> +		 __func__, min_be, max_be, retries);
> +
> +	if (min_be > max_be || max_be > 8 || retries > 5)
> +		return -EINVAL;
> +
> +	ret = adf7242_write_reg(lp, REG_AUTO_TX1,
> +				MAX_FRAME_RETRIES(lp->max_frame_retries) |
> +				MAX_CCA_RETRIES(retries));
> +	if (ret)
> +		return ret;
> +
> +	lp->max_cca_retries = retries;
> +
> +	return adf7242_write_reg(lp, REG_AUTO_TX2, CSMA_MAX_BE(max_be) |
> +			CSMA_MIN_BE(min_be));
> +}
> +
> +static int adf7242_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +	int ret = 0;
> +
> +	dev_vdbg(&lp->spi->dev, "%s : Retries = %d\n", __func__, retries);
> +
> +	if (retries < -1 || retries > 15)
> +		return -EINVAL;
> +
> +	if (retries >= 0)
> +		ret = adf7242_write_reg(lp, REG_AUTO_TX1,
> +					MAX_FRAME_RETRIES(retries) |
> +					MAX_CCA_RETRIES(lp->max_cca_retries));
> +
> +	lp->max_frame_retries = retries;
> +
> +	return ret;
> +}
> +
> +static int adf7242_ed(struct ieee802154_hw *hw, u8 *level)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +
> +	*level = lp->rssi;
> +
> +	dev_vdbg(&lp->spi->dev, "%s :Exit level=%d\n",
> +		 __func__, *level);
> +
> +	return 0;
> +}
> +
> +static int adf7242_start(struct ieee802154_hw *hw)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +
> +	adf7242_cmd(lp, CMD_RC_PHY_RDY);
> +	return adf7242_cmd(lp, CMD_RC_RX);
> +}
> +
> +static void adf7242_stop(struct ieee802154_hw *hw)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +
> +	adf7242_cmd(lp, CMD_RC_IDLE);
> +	adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
> +}
> +
> +static int adf7242_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +	unsigned long freq;
> +
> +	dev_dbg(&lp->spi->dev, "%s :Channel=%d\n", __func__, channel);
> +
> +	might_sleep();
> +
> +	WARN_ON(page != 0);
> +	WARN_ON(channel < 11);
> +	WARN_ON(channel > 26);
> +
> +	freq = (2405 + 5 * (channel - 11)) * 100;
> +	adf7242_cmd(lp, CMD_RC_PHY_RDY);
> +
> +	adf7242_write_reg(lp, REG_CH_FREQ0, freq);
> +	adf7242_write_reg(lp, REG_CH_FREQ1, freq >> 8);
> +	adf7242_write_reg(lp, REG_CH_FREQ2, freq >> 16);
> +
> +	return adf7242_cmd(lp, CMD_RC_RX);
> +}
> +
> +static int adf7242_set_hw_addr_filt(struct ieee802154_hw *hw,
> +				    struct ieee802154_hw_addr_filt *filt,
> +				    unsigned long changed)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +	u8 reg;
> +
> +	dev_dbg(&lp->spi->dev, "%s :Changed=0x%lX\n", __func__, changed);
> +
> +	might_sleep();
> +
> +	if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
> +		u8 addr[8], i;
> +
> +		memcpy(addr, &filt->ieee_addr, 8);
> +
> +		for (i = 0; i < 8; i++)
> +			adf7242_write_reg(lp, REG_IEEE_ADDR_0 + i, addr[i]);
> +	}
> +
> +	if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
> +		u16 saddr = le16_to_cpu(filt->short_addr);
> +
> +		adf7242_write_reg(lp, REG_SHORT_ADDR_0, saddr);
> +		adf7242_write_reg(lp, REG_SHORT_ADDR_1, saddr >> 8);
> +	}
> +
> +	if (changed & IEEE802154_AFILT_PANID_CHANGED) {
> +		u16 pan_id = le16_to_cpu(filt->pan_id);
> +
> +		adf7242_write_reg(lp, REG_PAN_ID0, pan_id);
> +		adf7242_write_reg(lp, REG_PAN_ID1, pan_id >> 8);
> +	}
> +
> +	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
> +		adf7242_read_reg(lp, REG_AUTO_CFG, &reg);
> +		if (filt->pan_coord)
> +			reg |= IS_PANCOORD;
> +		else
> +			reg &= ~IS_PANCOORD;
> +		adf7242_write_reg(lp, REG_AUTO_CFG, reg);
> +	}
> +
> +	return 0;
> +}
> +
> +static int adf7242_set_promiscuous_mode(struct ieee802154_hw *hw, bool on)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +
> +	dev_dbg(&lp->spi->dev, "%s : mode %d\n", __func__, on);
> +
> +	if (on) {
> +		adf7242_write_reg(lp, REG_AUTO_CFG, 0);
> +		return adf7242_write_reg(lp, REG_FFILT_CFG,
> +				  ACCEPT_BEACON_FRAMES |
> +				  ACCEPT_DATA_FRAMES |
> +				  ACCEPT_MACCMD_FRAMES |
> +				  ACCEPT_ALL_ADDRESS |
> +				  ACCEPT_ACK_FRAMES |
> +				  ACCEPT_RESERVED_FRAMES);
> +	} else {
> +		adf7242_write_reg(lp, REG_FFILT_CFG,
> +				  ACCEPT_BEACON_FRAMES |
> +				  ACCEPT_DATA_FRAMES |
> +				  ACCEPT_MACCMD_FRAMES |
> +				  ACCEPT_RESERVED_FRAMES);
> +
> +		return adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
> +	}
> +}
> +
> +static int adf7242_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +	s8 level = clamp_t(s8, mbm / 100, S8_MIN, S8_MAX);
> +
> +	dev_dbg(&lp->spi->dev, "%s : level %d\n", __func__, level);
> +
> +	return adf7242_write_reg(lp, REG_CCA1, level);
> +}
> +
> +static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
> +{
> +	struct adf7242_local *lp = hw->priv;
> +	int ret;
> +
> +	reinit_completion(&lp->tx_complete);
> +
> +	ret = adf7242_write_fbuf(lp, skb->data, skb->len);
> +	if (ret)
> +		goto err;
> +
> +	ret = adf7242_cmd(lp, CMD_RC_PHY_RDY);
> +	ret |= adf7242_cmd(lp, CMD_RC_CSMACA);
> +
> +	if (ret)
> +		goto err;
> +
> +	ret = wait_for_completion_interruptible_timeout(&lp->tx_complete, HZ);
> +	if (ret == -ERESTARTSYS)
> +		goto err;
> +	if (ret == 0) {
> +		dev_warn(&lp->spi->dev, "Timeout waiting for TX interrupt\n");
> +		ret = -ETIMEDOUT;
> +		goto err;
> +	}
> +
> +	if (lp->tx_stat != SUCCESS) {
> +		dev_warn(&lp->spi->dev,
> +			 "Error xmit: Retry count exceeded Status=0x%x\n",
> +			 lp->tx_stat);
> +		ret = -ECOMM;
> +	} else {
> +		ret = 0;
> +	}
> +
> +err:
> +	adf7242_cmd(lp, CMD_RC_RX);
> +	return ret;
> +}
> +
> +static int adf7242_rx(struct adf7242_local *lp)
> +{
> +	struct sk_buff *skb;
> +	size_t len;
> +	int ret;
> +	u8 lqi, len_u8, *data;
> +
> +	adf7242_read_reg(lp, 0, &len_u8);
> +
> +	len = len_u8;
> +
> +	if (!ieee802154_is_valid_psdu_len(len)) {
> +		dev_dbg(&lp->spi->dev,
> +			"corrupted frame received len %d\n", len);
> +		len = IEEE802154_MTU;
> +	}
> +
> +	skb = dev_alloc_skb(len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	data = skb_put(skb, len);
> +	ret = adf7242_read_fbuf(lp, data, len, true);
> +
> +	if (!ret) {
> +		lqi = data[len - 2];
> +		lp->rssi = data[len - 1];
> +	}
> +
> +	adf7242_cmd(lp, CMD_RC_RX);
> +
> +	skb_trim(skb, len - 2);	/* Don't put RSSI/LQI or CRC into the frame */
> +
> +	ieee802154_rx_irqsafe(lp->hw, skb, lqi);
> +
> +	dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n",
> +		__func__, ret, len, lqi, lp->rssi);
> +
> +	return 0;
> +}
> +
> +static struct ieee802154_ops adf7242_ops = {
> +	.owner = THIS_MODULE,
> +	.xmit_sync = adf7242_xmit,
> +	.ed = adf7242_ed,
> +	.set_channel = adf7242_channel,
> +	.set_hw_addr_filt = adf7242_set_hw_addr_filt,
> +	.start = adf7242_start,
> +	.stop = adf7242_stop,
> +	.set_csma_params = adf7242_set_csma_params,
> +	.set_frame_retries = adf7242_set_frame_retries,
> +	.set_txpower = adf7242_set_txpower,
> +	.set_promiscuous_mode = adf7242_set_promiscuous_mode,
> +	.set_cca_ed_level = adf7242_set_cca_ed_level,

Nice to see so many callbacks implemented. The only things I see missing 
is xmit_async, set_lbt and set_cca_mode. I would not make it a 
requirements to get these hooked up before merging this patch but we 
should consider it as todo items.

> +};
> +
> +static irqreturn_t adf7242_isr(int irq, void *data)
> +{
> +	struct adf7242_local *lp = data;
> +	u8 irq1, auto_stat = 0, stat = 0, rx_en = 0;
> +
> +	adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
> +	adf7242_write_reg(lp, REG_IRQ1_SRC1, irq1);
> +
> +	if (!(irq1 & (IRQ_RX_PKT_RCVD | IRQ_CSMA_CA)))
> +		dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n",
> +			__func__, irq1);
> +
> +	dev_dbg(&lp->spi->dev, "%s IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n",
> +		__func__, irq1,
> +		irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
> +		irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
> +		irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
> +		irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
> +		irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
> +		irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
> +		irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
> +		irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
> +
> +	adf7242_status(lp, &stat);
> +
> +	dev_dbg(&lp->spi->dev, "%s STATUS = %X:\n%s\n%s%s%s%s%s\n",
> +		__func__, stat,
> +		stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
> +		(stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
> +		(stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
> +		(stat & 0xf) == RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
> +		(stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
> +		(stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
> +
> +	if ((irq1 & IRQ_RX_PKT_RCVD) && (irq1 & IRQ_FRAME_VALID)) {
> +		/* Wait until ACK is processed */
> +		if ((stat & RC_STATUS_MASK) != RC_STATUS_PHY_RDY)
> +			adf7242_wait_status(lp, RC_STATUS_PHY_RDY, __LINE__);
> +
> +		adf7242_rx(lp);
> +		rx_en = 1;
> +	}
> +
> +	if (irq1 & IRQ_CSMA_CA) {
> +		adf7242_read_reg(lp, REG_AUTO_STATUS, &auto_stat);
> +		auto_stat &= AUTO_STATUS_MASK;
> +
> +		dev_dbg(&lp->spi->dev, "%s AUTO_STATUS = %X:\n%s%s%s%s\n",
> +			__func__, auto_stat,
> +			auto_stat == SUCCESS ? "SUCCESS" : "",
> +			auto_stat ==
> +			SUCCESS_DATPEND ? "SUCCESS_DATPEND" : "",
> +			auto_stat == FAILURE_CSMACA ? "FAILURE_CSMACA" : "",
> +			auto_stat == FAILURE_NOACK ? "FAILURE_NOACK" : "");
> +
> +		/* save CSMA-CA completion status */
> +		lp->tx_stat = auto_stat;
> +		rx_en = 1;
> +
> +		complete(&lp->tx_complete);
> +	}
> +
> +	if (!rx_en)
> +		adf7242_cmd(lp, CMD_RC_RX);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int adf7242_hw_init(struct adf7242_local *lp)
> +{
> +	int ret;
> +	const struct firmware *fw;
> +
> +	adf7242_cmd(lp, CMD_RC_RESET);
> +	adf7242_cmd(lp, CMD_RC_IDLE);
> +
> +	/* get ADF7242 addon firmware
> +	 * build this driver as module

Hmm, this brings up the question if the firmware is also fetched if the 
driver is built into the kernel directly?
> +	 * and place under /lib/firmware/adf7242_firmware.bin
> +	 */
> +	ret = request_firmware(&fw, FIRMWARE, &lp->spi->dev);
> +	if (ret) {
> +		dev_err(&lp->spi->dev,
> +			"request_firmware() failed with %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = adf7242_upload_firmware(lp, (u8 *)fw->data, fw->size);
> +	if (ret) {
> +		dev_err(&lp->spi->dev,
> +			"upload firmware failed with %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = adf7242_verify_firmware(lp, (u8 *)fw->data, fw->size);
> +	if (ret) {
> +		dev_err(&lp->spi->dev,
> +			"verify firmware failed with %d\n", ret);
> +		return ret;
> +	}
> +
> +	adf7242_cmd(lp, CMD_RC_PC_RESET);
> +
> +	release_firmware(fw);
> +
> +	adf7242_write_reg(lp, REG_FFILT_CFG,
> +			  ACCEPT_BEACON_FRAMES |
> +			  ACCEPT_DATA_FRAMES |
> +			  ACCEPT_MACCMD_FRAMES |
> +			  ACCEPT_RESERVED_FRAMES);
> +
> +	adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
> +
> +	adf7242_write_reg(lp, REG_PKT_CFG, ADDON_EN | BIT(2));
> +
> +	adf7242_write_reg(lp, REG_EXTPA_MSC, 0xF1);
> +	adf7242_write_reg(lp, REG_RXFE_CFG, 0x1D);
> +
> +	adf7242_write_reg(lp, REG_IRQ1_EN0, 0);
> +	adf7242_write_reg(lp, REG_IRQ1_EN1, IRQ_RX_PKT_RCVD | IRQ_CSMA_CA);
> +
> +	adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
> +	adf7242_write_reg(lp, REG_IRQ1_SRC0, 0xFF);
> +
> +	adf7242_cmd(lp, CMD_RC_IDLE);
> +
> +	return 0;
> +}
> +
> +static ssize_t adf7242_show(struct device *dev,
> +			    struct device_attribute *devattr, char *buf)
> +{
> +	struct adf7242_local *lp = dev_get_drvdata(dev);
> +	u8 stat, irq1;
> +	size_t len;
> +
> +	adf7242_status(lp, &stat);
> +
> +	adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
> +
> +	len = sprintf(buf, "IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n", irq1,
> +		      irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
> +		      irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
> +		      irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
> +		      irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
> +		      irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
> +		      irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
> +		      irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
> +		      irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
> +
> +	len += sprintf(buf + len, "STATUS = %X:\n%s\n%s%s%s%s%s\n", stat,
> +		       stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
> +		       (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
> +		       (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
> +		       (stat & 0xf) ==
> +				RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
> +		       (stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
> +		       (stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
> +
> +	len += sprintf(buf + len, "RSSI = %d\n", lp->rssi);
> +
> +	return len;
> +}
> +static DEVICE_ATTR(status, 0664, adf7242_show, NULL);

The show function and its sysfs entry shoudl go into debugfs, no? Having 
a sysfs entry here make sit a kernel ABI which we cannot change later 
and it looks like debugging only to me.

> +
> +static const s32 adf7242_powers[] = {
> +	500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700,
> +	-800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700,
> +	-1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600,
> +};
> +
> +static const s32 adf7242_ed_levels[] = {
> +	-9000, -8900, -8800, -8700, -8600, -8500, -8400, -8300, -8200, -8100,
> +	-8000, -7900, -7800, -7700, -7600, -7500, -7400, -7300, -7200, -7100,
> +	-7000, -6900, -6800, -6700, -6600, -6500, -6400, -6300, -6200, -6100,
> +	-6000, -5900, -5800, -5700, -5600, -5500, -5400, -5300, -5200, -5100,
> +	-5000, -4900, -4800, -4700, -4600, -4500, -4400, -4300, -4200, -4100,
> +	-4000, -3900, -3800, -3700, -3600, -3500, -3400, -3200, -3100, -3000
> +};
> +
> +static int adf7242_probe(struct spi_device *spi)
> +{
> +	struct ieee802154_hw *hw;
> +	struct adf7242_local *lp;
> +	int ret, irq_type;
> +
> +	if (!spi->irq) {
> +		dev_err(&spi->dev, "no IRQ specified\n");
> +		return -EINVAL;
> +	}
> +
> +	hw = ieee802154_alloc_hw(sizeof(*lp), &adf7242_ops);
> +	if (!hw)
> +		return -ENOMEM;
> +
> +	lp = hw->priv;
> +	lp->hw = hw;
> +	lp->spi = spi;
> +
> +	hw->priv = lp;
> +	hw->parent = &spi->dev;
> +	hw->extra_tx_headroom = 0;
> +
> +	/* We support only 2.4 Ghz */
> +	hw->phy->supported.channels[0] = 0x7FFF800;
> +
> +	hw->flags = IEEE802154_HW_OMIT_CKSUM |
> +		    IEEE802154_HW_CSMA_PARAMS |
> +		    IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT |
> +		    IEEE802154_HW_PROMISCUOUS;
> +
> +	hw->phy->flags = WPAN_PHY_FLAG_TXPOWER |
> +			 WPAN_PHY_FLAG_CCA_ED_LEVEL |
> +			 WPAN_PHY_FLAG_CCA_MODE;

Is this hardware really only supporting the one CCA_MODE?

> +
> +	hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY);
> +
> +	hw->phy->supported.cca_ed_levels = adf7242_ed_levels;
> +	hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(adf7242_ed_levels);
> +
> +	hw->phy->cca.mode = NL802154_CCA_ENERGY;
> +
> +	hw->phy->supported.tx_powers = adf7242_powers;
> +	hw->phy->supported.tx_powers_size = ARRAY_SIZE(adf7242_powers);
> +
> +	hw->phy->supported.min_minbe = 0;
> +	hw->phy->supported.max_minbe = 8;
> +
> +	hw->phy->supported.min_maxbe = 3;
> +	hw->phy->supported.max_maxbe = 8;
> +
> +	hw->phy->supported.min_frame_retries = 0;
> +	hw->phy->supported.max_frame_retries = 15;
> +
> +	hw->phy->supported.min_csma_backoffs = 0;
> +	hw->phy->supported.max_csma_backoffs = 5;
> +
> +	ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
> +
> +	mutex_init(&lp->bmux);
> +	init_completion(&lp->tx_complete);
> +
> +	/* Setup Status Message */
> +	lp->stat_xfer.len = 1;
> +	lp->stat_xfer.tx_buf = &lp->buf_stat_tx;
> +	lp->stat_xfer.rx_buf = &lp->buf_stat_rx;
> +	lp->buf_stat_tx = CMD_SPI_NOP;
> +
> +	spi_message_init(&lp->stat_msg);
> +	spi_message_add_tail(&lp->stat_xfer, &lp->stat_msg);
> +
> +	spi_set_drvdata(spi, lp);
> +
> +	ret = adf7242_hw_init(lp);
> +	if (ret)
> +		goto err_hw_init;
> +
> +	irq_type = irq_get_trigger_type(spi->irq);
> +	if (!irq_type)
> +		irq_type = IRQF_TRIGGER_HIGH;
> +
> +	ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, adf7242_isr,
> +					irq_type | IRQF_ONESHOT,
> +					dev_name(&spi->dev), lp);
> +	if (ret)
> +		goto err_hw_init;
> +
> +	ret = ieee802154_register_hw(lp->hw);
> +	if (ret)
> +		goto err_hw_init;
> +
> +	dev_set_drvdata(&spi->dev, lp);
> +
> +	/* move to debugfs, maybe add some helper to ieee802154_ops ? */
> +	ret = sysfs_create_file(&spi->dev.kobj, &dev_attr_status.attr);

This needs to be decided before we can merge this patch. To me this 
looks a debugfs candiate.
> +	if (ret)
> +		goto out;
> +
> +	dev_info(&spi->dev, "mac802154 IRQ-%d registered\n", spi->irq);
> +
> +	return ret;
> +
> +out:
> +	ieee802154_unregister_hw(lp->hw);
> +err_hw_init:
> +	mutex_destroy(&lp->bmux);
> +	ieee802154_free_hw(lp->hw);
> +
> +	return ret;
> +}
> +
> +static int adf7242_remove(struct spi_device *spi)
> +{
> +	struct adf7242_local *lp = spi_get_drvdata(spi);
> +
> +	sysfs_remove_file(&spi->dev.kobj, &dev_attr_status.attr);
> +	ieee802154_unregister_hw(lp->hw);
> +	mutex_destroy(&lp->bmux);
> +	ieee802154_free_hw(lp->hw);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id adf7242_of_match[] = {
> +	{ .compatible = "adi,adf7242", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, adf7242_of_match);
> +
> +static const struct spi_device_id adf7242_device_id[] = {
> +	{ .name = "adf7242", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(spi, adf7242_device_id);
> +
> +static struct spi_driver adf7242_driver = {
> +	.id_table = adf7242_device_id,
> +	.driver = {
> +		   .of_match_table = of_match_ptr(adf7242_of_match),
> +		   .name = "adf7242",
> +		   .owner = THIS_MODULE,
> +		   },
> +	.probe = adf7242_probe,
> +	.remove = adf7242_remove,
> +};
> +
> +module_spi_driver(adf7242_driver);
> +
> +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
> +MODULE_DESCRIPTION("ADF7242 IEEE802.15.4 Transceiver Driver");
> +MODULE_LICENSE("GPL");


Something worth thinking about might also be the usage of regmap.
After the include fix teh driver compiled fine. I will try to find some 
time connecting my adf7242 module to a pi and giving the driver some 
real testing over the next week.

regards
Stefan Schmidt

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-04  9:09 ` michael.hennerich
  (?)
  (?)
@ 2015-12-04 12:42 ` Christopher Friedt
  -1 siblings, 0 replies; 36+ messages in thread
From: Christopher Friedt @ 2015-12-04 12:42 UTC (permalink / raw)
  To: michael.hennerich
  Cc: alex.aring, Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

Awesome! Thanks Michael & Analog :-)

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-04  9:09 ` michael.hennerich
@ 2015-12-04 13:34   ` kbuild test robot
  -1 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2015-12-04 13:34 UTC (permalink / raw)
  To: michael.hennerich
  Cc: kbuild-all, alex.aring, stefan, marcel, linux-wpan,
	linux-bluetooth, Michael Hennerich

[-- Attachment #1: Type: text/plain, Size: 1630 bytes --]

Hi Michael,

[auto build test ERROR on net-next/master]
[also build test ERROR on v4.4-rc3 next-20151203]

url:    https://github.com/0day-ci/linux/commits/michael-hennerich-analog-com/drivers-net-ieee802154-adf7242-Driver-for-ADF7242-MAC-IEEE802154/20151204-203347
config: tile-allyesconfig (attached as .config)
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=tile 

All error/warnings (new ones prefixed by >>):

   drivers/net/ieee802154/adf7242.c: In function 'adf7242_rx':
>> drivers/net/ieee802154/adf7242.c:809:3: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t'
   drivers/net/ieee802154/adf7242.c:832:2: warning: format '%d' expects argument of type 'int', but argument 6 has type 'size_t'
   drivers/net/ieee802154/adf7242.c: In function 'adf7242_probe':
>> drivers/net/ieee802154/adf7242.c:1110:2: error: implicit declaration of function 'irq_get_trigger_type'
   cc1: some warnings being treated as errors

vim +/irq_get_trigger_type +1110 drivers/net/ieee802154/adf7242.c

  1104		spi_set_drvdata(spi, lp);
  1105	
  1106		ret = adf7242_hw_init(lp);
  1107		if (ret)
  1108			goto err_hw_init;
  1109	
> 1110		irq_type = irq_get_trigger_type(spi->irq);
  1111		if (!irq_type)
  1112			irq_type = IRQF_TRIGGER_HIGH;
  1113	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 42477 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-04 13:34   ` kbuild test robot
  0 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2015-12-04 13:34 UTC (permalink / raw)
  To: michael.hennerich
  Cc: kbuild-all, alex.aring, stefan, marcel, linux-wpan, linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 1630 bytes --]

Hi Michael,

[auto build test ERROR on net-next/master]
[also build test ERROR on v4.4-rc3 next-20151203]

url:    https://github.com/0day-ci/linux/commits/michael-hennerich-analog-com/drivers-net-ieee802154-adf7242-Driver-for-ADF7242-MAC-IEEE802154/20151204-203347
config: tile-allyesconfig (attached as .config)
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=tile 

All error/warnings (new ones prefixed by >>):

   drivers/net/ieee802154/adf7242.c: In function 'adf7242_rx':
>> drivers/net/ieee802154/adf7242.c:809:3: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t'
   drivers/net/ieee802154/adf7242.c:832:2: warning: format '%d' expects argument of type 'int', but argument 6 has type 'size_t'
   drivers/net/ieee802154/adf7242.c: In function 'adf7242_probe':
>> drivers/net/ieee802154/adf7242.c:1110:2: error: implicit declaration of function 'irq_get_trigger_type'
   cc1: some warnings being treated as errors

vim +/irq_get_trigger_type +1110 drivers/net/ieee802154/adf7242.c

  1104		spi_set_drvdata(spi, lp);
  1105	
  1106		ret = adf7242_hw_init(lp);
  1107		if (ret)
  1108			goto err_hw_init;
  1109	
> 1110		irq_type = irq_get_trigger_type(spi->irq);
  1111		if (!irq_type)
  1112			irq_type = IRQF_TRIGGER_HIGH;
  1113	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 42477 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-04  9:09 ` michael.hennerich
@ 2015-12-04 13:41   ` kbuild test robot
  -1 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2015-12-04 13:41 UTC (permalink / raw)
  To: michael.hennerich
  Cc: kbuild-all, alex.aring, stefan, marcel, linux-wpan,
	linux-bluetooth, Michael Hennerich

[-- Attachment #1: Type: text/plain, Size: 2281 bytes --]

Hi Michael,

[auto build test WARNING on net-next/master]
[also build test WARNING on v4.4-rc3 next-20151203]

url:    https://github.com/0day-ci/linux/commits/michael-hennerich-analog-com/drivers-net-ieee802154-adf7242-Driver-for-ADF7242-MAC-IEEE802154/20151204-203347
config: x86_64-allmodconfig (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   In file included from include/linux/printk.h:277:0,
                    from include/linux/kernel.h:13,
                    from drivers/net/ieee802154/adf7242.c:9:
   drivers/net/ieee802154/adf7242.c: In function 'adf7242_rx':
>> drivers/net/ieee802154/adf7242.c:810:4: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t {aka long unsigned int}' [-Wformat=]
       "corrupted frame received len %d\n", len);
       ^
   include/linux/dynamic_debug.h:86:39: note: in definition of macro 'dynamic_dev_dbg'
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
                                          ^
>> drivers/net/ieee802154/adf7242.c:809:3: note: in expansion of macro 'dev_dbg'
      dev_dbg(&lp->spi->dev,
      ^
   drivers/net/ieee802154/adf7242.c:832:25: warning: format '%d' expects argument of type 'int', but argument 6 has type 'size_t {aka long unsigned int}' [-Wformat=]
     dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n",
                            ^
   include/linux/dynamic_debug.h:86:39: note: in definition of macro 'dynamic_dev_dbg'
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
                                          ^
   drivers/net/ieee802154/adf7242.c:832:2: note: in expansion of macro 'dev_dbg'
     dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n",
     ^

vim +810 drivers/net/ieee802154/adf7242.c

   803	
   804		adf7242_read_reg(lp, 0, &len_u8);
   805	
   806		len = len_u8;
   807	
   808		if (!ieee802154_is_valid_psdu_len(len)) {
 > 809			dev_dbg(&lp->spi->dev,
 > 810				"corrupted frame received len %d\n", len);
   811			len = IEEE802154_MTU;
   812		}
   813	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 51185 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-04 13:41   ` kbuild test robot
  0 siblings, 0 replies; 36+ messages in thread
From: kbuild test robot @ 2015-12-04 13:41 UTC (permalink / raw)
  To: michael.hennerich
  Cc: kbuild-all, alex.aring, stefan, marcel, linux-wpan, linux-bluetooth

[-- Attachment #1: Type: text/plain, Size: 2281 bytes --]

Hi Michael,

[auto build test WARNING on net-next/master]
[also build test WARNING on v4.4-rc3 next-20151203]

url:    https://github.com/0day-ci/linux/commits/michael-hennerich-analog-com/drivers-net-ieee802154-adf7242-Driver-for-ADF7242-MAC-IEEE802154/20151204-203347
config: x86_64-allmodconfig (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   In file included from include/linux/printk.h:277:0,
                    from include/linux/kernel.h:13,
                    from drivers/net/ieee802154/adf7242.c:9:
   drivers/net/ieee802154/adf7242.c: In function 'adf7242_rx':
>> drivers/net/ieee802154/adf7242.c:810:4: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t {aka long unsigned int}' [-Wformat=]
       "corrupted frame received len %d\n", len);
       ^
   include/linux/dynamic_debug.h:86:39: note: in definition of macro 'dynamic_dev_dbg'
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
                                          ^
>> drivers/net/ieee802154/adf7242.c:809:3: note: in expansion of macro 'dev_dbg'
      dev_dbg(&lp->spi->dev,
      ^
   drivers/net/ieee802154/adf7242.c:832:25: warning: format '%d' expects argument of type 'int', but argument 6 has type 'size_t {aka long unsigned int}' [-Wformat=]
     dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n",
                            ^
   include/linux/dynamic_debug.h:86:39: note: in definition of macro 'dynamic_dev_dbg'
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
                                          ^
   drivers/net/ieee802154/adf7242.c:832:2: note: in expansion of macro 'dev_dbg'
     dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n",
     ^

vim +810 drivers/net/ieee802154/adf7242.c

   803	
   804		adf7242_read_reg(lp, 0, &len_u8);
   805	
   806		len = len_u8;
   807	
   808		if (!ieee802154_is_valid_psdu_len(len)) {
 > 809			dev_dbg(&lp->spi->dev,
 > 810				"corrupted frame received len %d\n", len);
   811			len = IEEE802154_MTU;
   812		}
   813	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 51185 bytes --]

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-04 12:07 ` Stefan Schmidt
@ 2015-12-07 12:02   ` Stefan Schmidt
  2015-12-07 12:18       ` Michael Hennerich
  2015-12-07 12:47     ` Michael Hennerich
  1 sibling, 1 reply; 36+ messages in thread
From: Stefan Schmidt @ 2015-12-07 12:02 UTC (permalink / raw)
  To: michael.hennerich, alex.aring, marcel; +Cc: linux-wpan, linux-bluetooth

Hello.

I found some time at the weekend hooking it up on my raspberry pi.

On 04/12/15 13:07, Stefan Schmidt wrote:
> Hello.
>
> On 04/12/15 10:09, michael.hennerich@analog.com wrote:
>
>> The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
>> operating modes. The firmware file is currently made available on the
>> ADF7242 wiki page here [1]
>
> Just being curious here. Is there any way to get the firmware source 
> and/or compile your own? Its the first hardware for IEEE 802.15.4 I 
> have seen that have a special firmware for this which triggers my 
> curiosity. :)
>
> Anyway, this has not that much to do with the driver review here as it 
> can obviously go in with the binary firmware. We just need to make 
> sure to also bring the firmware into the linux-firmware repo in time.
>
>> [1] 
>> http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242

There are two firmware zip files listed:
ram_lab_7242_2_0_ieee15dot4_full_r5.zip 
<https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/ram_lab_7242_2_0_ieee15dot4_full_r5.zip>
rom_ram_7242_2_0_ieee15dot4_full_r3.zip 
<https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/rom_ram_7242_2_0_ieee15dot4_full_r3.zip>

Both contain a adf7242_firmware.bin file but also some different data 
file. Which one is the correct one here? Some explanation would be helpful.


>> [2] 
>> http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
>>
>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>> ---
>>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>>   drivers/net/ieee802154/Kconfig                     |    5 +
>>   drivers/net/ieee802154/Makefile                    |    1 +
>>   drivers/net/ieee802154/adf7242.c                   | 1183 
>> ++++++++++++++++++++
>>   4 files changed, 1207 insertions(+)
>>   create mode 100644 
>> Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>   create mode 100644 drivers/net/ieee802154/adf7242.c
>>
>> diff --git 
>> a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt 
>> b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>> new file mode 100644
>> index 0000000..dea5124
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>> @@ -0,0 +1,18 @@
>> +* ADF7242 IEEE 802.15.4 *
>> +
>> +Required properties:
>> +  - compatible:        should be "adi,adf7242"
>> +  - spi-max-frequency:    maximal bus speed (12.5 MHz)
>> +  - reg:        the chipselect index
>> +  - interrupts:        the interrupt generated by the device via pin 
>> IRQ1.
>> +            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)


IRQ1 would be pin7 on the interface connector, right? I'm using this one 
but I have trouble when transmitting

adf7242 spi32766.0: Error xmit: Retry count exceeded Status=0x3

and I was wondering if this comes from trouble setting the IRQ up 
correctly. The driver comes up fine, loads the firmware and I can 
configure it with iwpan. Device tree config looks like this, which is 
the same SPI port and IRQ I successfully use for two other transceivers:

&spi {
     status = "okay";
     adf7242@0 {
         compatible = "adi,adf7242";
         spi-max-frequency = <6000000>;
         reg = <0>;
         interrupts = <23 4>;
         interrupt-parent = <&gpio>;
     };
};


>
>
>> diff --git a/drivers/net/ieee802154/Makefile 
>> b/drivers/net/ieee802154/Makefile
>> index cf1d2a6..3a923d3 100644
>> --- a/drivers/net/ieee802154/Makefile
>> +++ b/drivers/net/ieee802154/Makefile
>> @@ -3,3 +3,4 @@ obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
>>   obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
>>   obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o
>>   obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o
>> +obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o
>> diff --git a/drivers/net/ieee802154/adf7242.c 
>> b/drivers/net/ieee802154/adf7242.c
>> new file mode 100644
>> index 0000000..48268b1
>> --- /dev/null
>> +++ b/drivers/net/ieee802154/adf7242.c
>> @@ -0,0 +1,1183 @@
>> +/*
>> + * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver
>> + *
>> + * Copyright 2009-2015 Analog Devices Inc.
>> + *
>
> Personally I like having a link to the actual data sheet inside the 
> driver header. This makes only sense if it is a stable URI.
>

The one I found and looking at is this one:
http://www.analog.com/media/en/technical-documentation/data-sheets/ADF7242.pdf


>> +static int adf7242_hw_init(struct adf7242_local *lp)
>> +{
>> +    int ret;
>> +    const struct firmware *fw;
>> +
>> +    adf7242_cmd(lp, CMD_RC_RESET);
>> +    adf7242_cmd(lp, CMD_RC_IDLE);
>> +
>> +    /* get ADF7242 addon firmware
>> +     * build this driver as module
>
> Hmm, this brings up the question if the firmware is also fetched if 
> the driver is built into the kernel directly?

Let me answer this myself here. If you build everything into the kernel 
you might run into trouble when the drivers is initialised before the fs 
system is up. That way the driver has no access to the fs and is unable 
to load the firmware. You can either switch this driver to a module or 
you can supply the kernel with the needed firmware during compile so it 
will be inside the kernel binary. Copy the file into the firmware 
directory inside your kernel tree and use these options:

CONFIG_EXTRA_FIRMWARE="adf7242_firmware.bin"
CONFIG_EXTRA_FIRMWARE_DIR="firmware"

That way the firmware loading worked for me for a kernel with everything 
build into big blob.

regards
Stefan Schmidt

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 12:02   ` Stefan Schmidt
@ 2015-12-07 12:18       ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-07 12:18 UTC (permalink / raw)
  To: Stefan Schmidt, alex.aring, marcel; +Cc: linux-wpan, linux-bluetooth

On 12/07/2015 01:02 PM, Stefan Schmidt wrote:
> Hello.
>
> I found some time at the weekend hooking it up on my raspberry pi.
>
> On 04/12/15 13:07, Stefan Schmidt wrote:
>> Hello.
>>
>> On 04/12/15 10:09, michael.hennerich@analog.com wrote:
>>
>>> The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
>>> operating modes. The firmware file is currently made available on the
>>> ADF7242 wiki page here [1]
>>
>> Just being curious here. Is there any way to get the firmware source
>> and/or compile your own? Its the first hardware for IEEE 802.15.4 I
>> have seen that have a special firmware for this which triggers my
>> curiosity. :)


Unfortunately No - We don't release the firmware assembly code.
Or the required compiler.


>>
>> Anyway, this has not that much to do with the driver review here as it
>> can obviously go in with the binary firmware. We just need to make
>> sure to also bring the firmware into the linux-firmware repo in time.
>>
>>> [1]
>>> http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
>>>
>
> There are two firmware zip files listed:
> ram_lab_7242_2_0_ieee15dot4_full_r5.zip
> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/ram_lab_7242_2_0_ieee15dot4_full_r5.zip>
>
> rom_ram_7242_2_0_ieee15dot4_full_r3.zip
> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/rom_ram_7242_2_0_ieee15dot4_full_r3.zip>
>
>
> Both contain a adf7242_firmware.bin file but also some different data
> file. Which one is the correct one here? Some explanation would be helpful.

Please use the latest R5 release file. I'll remove the old one soon.
The older firmware had problems with the back-off exponent randomization.


>
>
>>> [2]
>>> http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
>>>
>>>
>>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>>> ---
>>>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>>>   drivers/net/ieee802154/Kconfig                     |    5 +
>>>   drivers/net/ieee802154/Makefile                    |    1 +
>>>   drivers/net/ieee802154/adf7242.c                   | 1183
>>> ++++++++++++++++++++
>>>   4 files changed, 1207 insertions(+)
>>>   create mode 100644
>>> Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>   create mode 100644 drivers/net/ieee802154/adf7242.c
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>> b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>> new file mode 100644
>>> index 0000000..dea5124
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>> @@ -0,0 +1,18 @@
>>> +* ADF7242 IEEE 802.15.4 *
>>> +
>>> +Required properties:
>>> +  - compatible:        should be "adi,adf7242"
>>> +  - spi-max-frequency:    maximal bus speed (12.5 MHz)
>>> +  - reg:        the chipselect index
>>> +  - interrupts:        the interrupt generated by the device via pin
>>> IRQ1.
>>> +            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
>
>
> IRQ1 would be pin7 on the interface connector, right? I'm using this one
> but I have trouble when transmitting

Yes IRQ1 is Pin7 on the PMOD connector.

>
> adf7242 spi32766.0: Error xmit: Retry count exceeded Status=0x3


That's failure NOACK. Is there a node on the same channel/PAN which 
could response?
reading proc/interrupts should show some interrupts in this case...

>
> and I was wondering if this comes from trouble setting the IRQ up
> correctly. The driver comes up fine, loads the firmware and I can
> configure it with iwpan. Device tree config looks like this, which is
> the same SPI port and IRQ I successfully use for two other transceivers:
>
> &spi {
>      status = "okay";
>      adf7242@0 {
>          compatible = "adi,adf7242";
>          spi-max-frequency = <6000000>;
>          reg = <0>;
>          interrupts = <23 4>;
>          interrupt-parent = <&gpio>;
>      };
> };
>
>
>>
>>
>>> diff --git a/drivers/net/ieee802154/Makefile
>>> b/drivers/net/ieee802154/Makefile
>>> index cf1d2a6..3a923d3 100644
>>> --- a/drivers/net/ieee802154/Makefile
>>> +++ b/drivers/net/ieee802154/Makefile
>>> @@ -3,3 +3,4 @@ obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
>>>   obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
>>>   obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o
>>>   obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o
>>> +obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o
>>> diff --git a/drivers/net/ieee802154/adf7242.c
>>> b/drivers/net/ieee802154/adf7242.c
>>> new file mode 100644
>>> index 0000000..48268b1
>>> --- /dev/null
>>> +++ b/drivers/net/ieee802154/adf7242.c
>>> @@ -0,0 +1,1183 @@
>>> +/*
>>> + * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver
>>> + *
>>> + * Copyright 2009-2015 Analog Devices Inc.
>>> + *
>>
>> Personally I like having a link to the actual data sheet inside the
>> driver header. This makes only sense if it is a stable URI.
>>
>
> The one I found and looking at is this one:
> http://www.analog.com/media/en/technical-documentation/data-sheets/ADF7242.pdf


This one is pretty static.
We can also use the short link:
www.analog.com/ADF7242 which brings you to the product page.
the datasheet is right below the block diagram.


>
>
>
>>> +static int adf7242_hw_init(struct adf7242_local *lp)
>>> +{
>>> +    int ret;
>>> +    const struct firmware *fw;
>>> +
>>> +    adf7242_cmd(lp, CMD_RC_RESET);
>>> +    adf7242_cmd(lp, CMD_RC_IDLE);
>>> +
>>> +    /* get ADF7242 addon firmware
>>> +     * build this driver as module
>>
>> Hmm, this brings up the question if the firmware is also fetched if
>> the driver is built into the kernel directly?
>
> Let me answer this myself here. If you build everything into the kernel
> you might run into trouble when the drivers is initialised before the fs
> system is up. That way the driver has no access to the fs and is unable
> to load the firmware. You can either switch this driver to a module or
> you can supply the kernel with the needed firmware during compile so it
> will be inside the kernel binary. Copy the file into the firmware
> directory inside your kernel tree and use these options:
>
> CONFIG_EXTRA_FIRMWARE="adf7242_firmware.bin"
> CONFIG_EXTRA_FIRMWARE_DIR="firmware"
>
> That way the firmware loading worked for me for a kernel with everything
> build into big blob.

That's what I do.

>
> regards
> Stefan Schmidt
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wpan" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-07 12:18       ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-07 12:18 UTC (permalink / raw)
  To: Stefan Schmidt, alex.aring, marcel; +Cc: linux-wpan, linux-bluetooth

On 12/07/2015 01:02 PM, Stefan Schmidt wrote:
> Hello.
>
> I found some time at the weekend hooking it up on my raspberry pi.
>
> On 04/12/15 13:07, Stefan Schmidt wrote:
>> Hello.
>>
>> On 04/12/15 10:09, michael.hennerich@analog.com wrote:
>>
>>> The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
>>> operating modes. The firmware file is currently made available on the
>>> ADF7242 wiki page here [1]
>>
>> Just being curious here. Is there any way to get the firmware source
>> and/or compile your own? Its the first hardware for IEEE 802.15.4 I
>> have seen that have a special firmware for this which triggers my
>> curiosity. :)


Unfortunately No - We don't release the firmware assembly code.
Or the required compiler.


>>
>> Anyway, this has not that much to do with the driver review here as it
>> can obviously go in with the binary firmware. We just need to make
>> sure to also bring the firmware into the linux-firmware repo in time.
>>
>>> [1]
>>> http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
>>>
>
> There are two firmware zip files listed:
> ram_lab_7242_2_0_ieee15dot4_full_r5.zip
> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/ram_lab_7242_2_0_ieee15dot4_full_r5.zip>
>
> rom_ram_7242_2_0_ieee15dot4_full_r3.zip
> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/rom_ram_7242_2_0_ieee15dot4_full_r3.zip>
>
>
> Both contain a adf7242_firmware.bin file but also some different data
> file. Which one is the correct one here? Some explanation would be helpful.

Please use the latest R5 release file. I'll remove the old one soon.
The older firmware had problems with the back-off exponent randomization.


>
>
>>> [2]
>>> http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
>>>
>>>
>>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>>> ---
>>>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>>>   drivers/net/ieee802154/Kconfig                     |    5 +
>>>   drivers/net/ieee802154/Makefile                    |    1 +
>>>   drivers/net/ieee802154/adf7242.c                   | 1183
>>> ++++++++++++++++++++
>>>   4 files changed, 1207 insertions(+)
>>>   create mode 100644
>>> Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>   create mode 100644 drivers/net/ieee802154/adf7242.c
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>> b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>> new file mode 100644
>>> index 0000000..dea5124
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>> @@ -0,0 +1,18 @@
>>> +* ADF7242 IEEE 802.15.4 *
>>> +
>>> +Required properties:
>>> +  - compatible:        should be "adi,adf7242"
>>> +  - spi-max-frequency:    maximal bus speed (12.5 MHz)
>>> +  - reg:        the chipselect index
>>> +  - interrupts:        the interrupt generated by the device via pin
>>> IRQ1.
>>> +            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
>
>
> IRQ1 would be pin7 on the interface connector, right? I'm using this one
> but I have trouble when transmitting

Yes IRQ1 is Pin7 on the PMOD connector.

>
> adf7242 spi32766.0: Error xmit: Retry count exceeded Status=0x3


That's failure NOACK. Is there a node on the same channel/PAN which 
could response?
reading proc/interrupts should show some interrupts in this case...

>
> and I was wondering if this comes from trouble setting the IRQ up
> correctly. The driver comes up fine, loads the firmware and I can
> configure it with iwpan. Device tree config looks like this, which is
> the same SPI port and IRQ I successfully use for two other transceivers:
>
> &spi {
>      status = "okay";
>      adf7242@0 {
>          compatible = "adi,adf7242";
>          spi-max-frequency = <6000000>;
>          reg = <0>;
>          interrupts = <23 4>;
>          interrupt-parent = <&gpio>;
>      };
> };
>
>
>>
>>
>>> diff --git a/drivers/net/ieee802154/Makefile
>>> b/drivers/net/ieee802154/Makefile
>>> index cf1d2a6..3a923d3 100644
>>> --- a/drivers/net/ieee802154/Makefile
>>> +++ b/drivers/net/ieee802154/Makefile
>>> @@ -3,3 +3,4 @@ obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
>>>   obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
>>>   obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o
>>>   obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o
>>> +obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o
>>> diff --git a/drivers/net/ieee802154/adf7242.c
>>> b/drivers/net/ieee802154/adf7242.c
>>> new file mode 100644
>>> index 0000000..48268b1
>>> --- /dev/null
>>> +++ b/drivers/net/ieee802154/adf7242.c
>>> @@ -0,0 +1,1183 @@
>>> +/*
>>> + * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver
>>> + *
>>> + * Copyright 2009-2015 Analog Devices Inc.
>>> + *
>>
>> Personally I like having a link to the actual data sheet inside the
>> driver header. This makes only sense if it is a stable URI.
>>
>
> The one I found and looking at is this one:
> http://www.analog.com/media/en/technical-documentation/data-sheets/ADF7242.pdf


This one is pretty static.
We can also use the short link:
www.analog.com/ADF7242 which brings you to the product page.
the datasheet is right below the block diagram.


>
>
>
>>> +static int adf7242_hw_init(struct adf7242_local *lp)
>>> +{
>>> +    int ret;
>>> +    const struct firmware *fw;
>>> +
>>> +    adf7242_cmd(lp, CMD_RC_RESET);
>>> +    adf7242_cmd(lp, CMD_RC_IDLE);
>>> +
>>> +    /* get ADF7242 addon firmware
>>> +     * build this driver as module
>>
>> Hmm, this brings up the question if the firmware is also fetched if
>> the driver is built into the kernel directly?
>
> Let me answer this myself here. If you build everything into the kernel
> you might run into trouble when the drivers is initialised before the fs
> system is up. That way the driver has no access to the fs and is unable
> to load the firmware. You can either switch this driver to a module or
> you can supply the kernel with the needed firmware during compile so it
> will be inside the kernel binary. Copy the file into the firmware
> directory inside your kernel tree and use these options:
>
> CONFIG_EXTRA_FIRMWARE="adf7242_firmware.bin"
> CONFIG_EXTRA_FIRMWARE_DIR="firmware"
>
> That way the firmware loading worked for me for a kernel with everything
> build into big blob.

That's what I do.

>
> regards
> Stefan Schmidt
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wpan" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-04 12:07 ` Stefan Schmidt
@ 2015-12-07 12:47     ` Michael Hennerich
  2015-12-07 12:47     ` Michael Hennerich
  1 sibling, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-07 12:47 UTC (permalink / raw)
  To: Stefan Schmidt, alex.aring, marcel; +Cc: linux-wpan, linux-bluetooth

On 12/04/2015 01:07 PM, Stefan Schmidt wrote:
> Hello.
>
> On 04/12/15 10:09, michael.hennerich@analog.com wrote:
>> From: Michael Hennerich <michael.hennerich@analog.com>
>>
>> This driver has been sitting in the linux-zigbee[2] repository for a long
>> time. We updated it from time to time and made it available via our
>> github kernel repository. The Linux MAC802.15.4 support has improved a
>> lot
>> since then. Thanks to all! So it’s finally time to upstream this driver.
>
> Thanks for taking the time and bringing it back to mainline!
>
>> The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
>> operating modes. The firmware file is currently made available on the
>> ADF7242 wiki page here [1]
>
> Just being curious here. Is there any way to get the firmware source
> and/or compile your own? Its the first hardware for IEEE 802.15.4 I have
> seen that have a special firmware for this which triggers my curiosity. :)
>
> Anyway, this has not that much to do with the driver review here as it
> can obviously go in with the binary firmware. We just need to make sure
> to also bring the firmware into the linux-firmware repo in time.
>
>> [1]
>> http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
>>
>> [2]
>> http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
>>
>>
>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>> ---
>>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>>   drivers/net/ieee802154/Kconfig                     |    5 +
>>   drivers/net/ieee802154/Makefile                    |    1 +
>>   drivers/net/ieee802154/adf7242.c                   | 1183
>> ++++++++++++++++++++
>>   4 files changed, 1207 insertions(+)
>>   create mode 100644
>> Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>   create mode 100644 drivers/net/ieee802154/adf7242.c
>>
>> diff --git
>> a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>> b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>> new file mode 100644
>> index 0000000..dea5124
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>> @@ -0,0 +1,18 @@
>> +* ADF7242 IEEE 802.15.4 *
>> +
>> +Required properties:
>> +  - compatible:        should be "adi,adf7242"
>> +  - spi-max-frequency:    maximal bus speed (12.5 MHz)
>> +  - reg:        the chipselect index
>> +  - interrupts:        the interrupt generated by the device via pin
>> IRQ1.
>> +            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
>> +
>> +Example:
>> +
>> +    adf7242@0 {
>> +        compatible = "adi,adf7242";
>> +        spi-max-frequency = <10000000>;
>> +        reg = <0>;
>> +        interrupts = <98 IRQ_TYPE_LEVEL_HIGH>;
>> +        interrupt-parent = <&gpio3>;
>> +    };
>> diff --git a/drivers/net/ieee802154/Kconfig
>> b/drivers/net/ieee802154/Kconfig
>> index ce5f1a2..fd17598 100644
>> --- a/drivers/net/ieee802154/Kconfig
>> +++ b/drivers/net/ieee802154/Kconfig
>> @@ -71,3 +71,8 @@ config IEEE802154_ATUSB
>>         This driver can also be built as a module. To do so say M here.
>>         The module will be called 'atusb'.
>> +
>> +config IEEE802154_ADF7242
>> +       tristate "ADF7242 transceiver driver"
>> +       depends on IEEE802154_DRIVERS && MAC802154
>> +       depends on SPI
>
> Maybe some help text here?

Yeah will do.


>
>> diff --git a/drivers/net/ieee802154/Makefile
>> b/drivers/net/ieee802154/Makefile
>> index cf1d2a6..3a923d3 100644
>> --- a/drivers/net/ieee802154/Makefile
>> +++ b/drivers/net/ieee802154/Makefile
>> @@ -3,3 +3,4 @@ obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
>>   obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
>>   obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o
>>   obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o
>> +obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o
>> diff --git a/drivers/net/ieee802154/adf7242.c
>> b/drivers/net/ieee802154/adf7242.c
>> new file mode 100644
>> index 0000000..48268b1
>> --- /dev/null
>> +++ b/drivers/net/ieee802154/adf7242.c
>> @@ -0,0 +1,1183 @@
>> +/*
>> + * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver
>> + *
>> + * Copyright 2009-2015 Analog Devices Inc.
>> + *
>
> Personally I like having a link to the actual data sheet inside the
> driver header. This makes only sense if it is a stable URI.

ok

>
>> + * Licensed under the GPL-2 or later.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/interrupt.h>
>
> You also want #include <linux/irq.h> here. Without it the compilation
> fails for me with:
>
> drivers/net/ieee802154/adf7242.c: In function 'adf7242_probe':
> drivers/net/ieee802154/adf7242.c:1110:13: error: implicit declaration of
> function 'irq_get_trigger_type' [-Werror=implicit-function-declaration]
>    irq_type = irq_get_trigger_type(spi->irq);
>               ^
> cc1: some warnings being treated as errors

Ups - my test platform seems to include it via some other header.
I'll fix it.


>
>
>> +#include <linux/delay.h>
>> +#include <linux/mutex.h>
>> +#include <linux/workqueue.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/firmware.h>
>> +#include <linux/spi/spi.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/of.h>
>> +#include <linux/ieee802154.h>
>> +#include <net/mac802154.h>
>> +#include <net/cfg802154.h>
>> +
>> +#define FIRMWARE "adf7242_firmware.bin"
>> +#define MAX_POLL_LOOPS 50
>> +
>> +/* All Registers */
>> +
>> +#define REG_EXT_CTRL    0x100    /* RW External LNA/PA and internal
>> PA control */
>> +#define REG_TX_FSK_TEST 0x101    /* RW TX FSK test mode configuration */
>> +#define REG_CCA1    0x105    /* RW RSSI threshold for CCA */
>> +#define REG_CCA2    0x106    /* RW CCA mode configuration */
>> +#define REG_BUFFERCFG    0x107    /* RW RX_BUFFER overwrite control */
>> +#define REG_PKT_CFG    0x108    /* RW FCS evaluation configuration */
>> +#define REG_DELAYCFG0    0x109    /* RW RC_RX command to SFD or sync
>> word delay */
>> +#define REG_DELAYCFG1    0x10A    /* RW RC_TX command to TX state */
>> +#define REG_DELAYCFG2    0x10B    /* RW Mac delay extension */
>> +#define REG_SYNC_WORD0    0x10C    /* RW sync word bits [7:0] of
>> [23:0]  */
>> +#define REG_SYNC_WORD1    0x10D    /* RW sync word bits [15:8] of
>> [23:0]  */
>> +#define REG_SYNC_WORD2    0x10E    /* RW sync word bits [23:16] of
>> [23:0]    */
>> +#define REG_SYNC_CONFIG    0x10F    /* RW sync word configuration */
>> +#define REG_RC_CFG    0x13E    /* RW RX / TX packet configuration */
>> +#define REG_RC_VAR44    0x13F    /* RW RESERVED */
>> +#define REG_CH_FREQ0    0x300    /* RW Channel Frequency Settings -
>> Low */
>> +#define REG_CH_FREQ1    0x301    /* RW Channel Frequency Settings -
>> Middle */
>> +#define REG_CH_FREQ2    0x302    /* RW Channel Frequency Settings -
>> High */
>> +#define REG_TX_FD    0x304    /* RW TX Frequency Deviation Register */
>> +#define REG_DM_CFG0    0x305    /* RW RX Discriminator BW Register */
>> +#define REG_TX_M    0x306    /* RW TX Mode Register */
>> +#define REG_RX_M    0x307    /* RW RX Mode Register */
>> +#define REG_RRB        0x30C    /* R RSSI Readback Register */
>> +#define REG_LRB        0x30D    /* R Link Quality Readback Register */
>> +#define REG_DR0        0x30E    /* RW bits [15:8] of [15:0] data rate
>> setting */
>> +#define REG_DR1        0x30F    /* RW bits [7:0] of [15:0] data rate
>> setting */
>> +#define REG_PRAMPG    0x313    /* RW RESERVED */
>> +#define REG_TXPB    0x314    /* RW TX Packet Storage Base Address */
>> +#define REG_RXPB    0x315    /* RW RX Packet Storage Base Address */
>> +#define REG_TMR_CFG0    0x316    /* RW Wake up Timer Conf Register -
>> High */
>> +#define REG_TMR_CFG1    0x317    /* RW Wake up Timer Conf Register -
>> Low */
>> +#define REG_TMR_RLD0    0x318    /* RW Wake up Timer Value Register -
>> High */
>> +#define REG_TMR_RLD1    0x319    /* RW Wake up Timer Value Register -
>> Low  */
>> +#define REG_TMR_CTRL    0x31A    /* RW Wake up Timer Timeout flag */
>> +#define REG_PD_AUX    0x31E    /* RW Battmon enable */
>> +#define REG_GP_CFG    0x32C    /* RW GPIO Configuration */
>> +#define REG_GP_OUT    0x32D    /* RW GPIO Configuration */
>> +#define REG_GP_IN    0x32E    /* R GPIO Configuration */
>> +#define REG_SYNT    0x335    /* RW bandwidth calibration timers */
>> +#define REG_CAL_CFG    0x33D    /* RW Calibration Settings */
>> +#define REG_PA_BIAS    0x36E    /* RW PA BIAS */
>> +#define REG_SYNT_CAL    0x371    /* RW Oscillator and Doubler
>> Configuration */
>> +#define REG_IIRF_CFG    0x389    /* RW BB Filter Decimation Rate */
>> +#define REG_CDR_CFG    0x38A    /* RW CDR kVCO */
>> +#define REG_DM_CFG1    0x38B    /* RW Postdemodulator Filter */
>> +#define REG_AGCSTAT    0x38E    /* R RXBB Ref Osc Calibration Engine
>> Readback */
>> +#define REG_RXCAL0    0x395    /* RW RX BB filter tuning, LSB */
>> +#define REG_RXCAL1    0x396    /* RW RX BB filter tuning, MSB */
>> +#define REG_RXFE_CFG    0x39B    /* RW RXBB Ref Osc & RXFE
>> Calibration */
>> +#define REG_PA_RR    0x3A7    /* RW Set PA ramp rate */
>> +#define REG_PA_CFG    0x3A8    /* RW PA enable */
>> +#define REG_EXTPA_CFG    0x3A9    /* RW External PA BIAS DAC */
>> +#define REG_EXTPA_MSC    0x3AA    /* RW PA Bias Mode */
>> +#define REG_ADC_RBK    0x3AE    /* R Readback temp */
>> +#define REG_AGC_CFG1    0x3B2    /* RW GC Parameters */
>> +#define REG_AGC_MAX    0x3B4    /* RW Slew rate     */
>> +#define REG_AGC_CFG2    0x3B6    /* RW RSSI Parameters */
>> +#define REG_AGC_CFG3    0x3B7    /* RW RSSI Parameters */
>> +#define REG_AGC_CFG4    0x3B8    /* RW RSSI Parameters */
>> +#define REG_AGC_CFG5    0x3B9    /* RW RSSI & NDEC Parameters */
>> +#define REG_AGC_CFG6    0x3BA    /* RW NDEC Parameters */
>> +#define REG_OCL_CFG1    0x3C4    /* RW OCL System Parameters */
>> +#define REG_IRQ1_EN0    0x3C7    /* RW Interrupt Mask set bits for
>> IRQ1 */
>> +#define REG_IRQ1_EN1    0x3C8    /* RW Interrupt Mask set bits for
>> IRQ1 */
>> +#define REG_IRQ2_EN0    0x3C9    /* RW Interrupt Mask set bits for
>> IRQ2 */
>> +#define REG_IRQ2_EN1    0x3CA    /* RW Interrupt Mask set bits for
>> IRQ2 */
>> +#define REG_IRQ1_SRC0    0x3CB    /* RW Interrupt Source bits for IRQ */
>> +#define REG_IRQ1_SRC1    0x3CC    /* RW Interrupt Source bits for IRQ */
>> +#define REG_OCL_BW0    0x3D2    /* RW OCL System Parameters */
>> +#define REG_OCL_BW1    0x3D3    /* RW OCL System Parameters */
>> +#define REG_OCL_BW2    0x3D4    /* RW OCL System Parameters */
>> +#define REG_OCL_BW3    0x3D5    /* RW OCL System Parameters */
>> +#define REG_OCL_BW4    0x3D6    /* RW OCL System Parameters */
>> +#define REG_OCL_BWS    0x3D7    /* RW OCL System Parameters */
>> +#define REG_OCL_CFG13    0x3E0    /* RW OCL System Parameters */
>> +#define REG_GP_DRV    0x3E3    /* RW I/O pads Configuration and bg
>> trim */
>> +#define REG_BM_CFG    0x3E6    /* RW Batt. Monitor Threshold Voltage
>> setting */
>> +#define REG_SFD_15_4    0x3F4    /* RW Option to set non standard SFD */
>> +#define REG_AFC_CFG    0x3F7    /* RW AFC mode and polarity */
>> +#define REG_AFC_KI_KP    0x3F8    /* RW AFC ki and kp */
>> +#define REG_AFC_RANGE    0x3F9    /* RW AFC range */
>> +#define REG_AFC_READ    0x3FA    /* RW Readback frequency error */
>> +
>> +/* REG_EXTPA_MSC */
>> +#define PA_PWR(x)        (((x) & 0xF) << 4)
>> +#define EXTPA_BIAS_SRC        BIT(3)
>> +#define EXTPA_BIAS_MODE(x)    (((x) & 0x7) << 0)
>> +
>> +/* REG_PA_CFG */
>> +#define PA_BRIDGE_DBIAS(x)    (((x) & 0x1F) << 0)
>> +
>> +/* REG_PA_BIAS */
>> +#define PA_BIAS_CTRL(x)        (((x) & 0x1F) << 1)
>> +#define REG_PA_BIAS_DFL        BIT(0)
>> +
>> +#define REG_PAN_ID0        0x112
>> +#define REG_PAN_ID1        0x113
>> +#define REG_SHORT_ADDR_0    0x114
>> +#define REG_SHORT_ADDR_1    0x115
>> +#define REG_IEEE_ADDR_0        0x116
>> +#define REG_IEEE_ADDR_1        0x117
>> +#define REG_IEEE_ADDR_2        0x118
>> +#define REG_IEEE_ADDR_3        0x119
>> +#define REG_IEEE_ADDR_4        0x11A
>> +#define REG_IEEE_ADDR_5        0x11B
>> +#define REG_IEEE_ADDR_6        0x11C
>> +#define REG_IEEE_ADDR_7        0x11D
>> +#define REG_FFILT_CFG        0x11E
>> +#define REG_AUTO_CFG        0x11F
>> +#define REG_AUTO_TX1        0x120
>> +#define REG_AUTO_TX2        0x121
>> +#define REG_AUTO_STATUS        0x122
>> +
>> +/* REG_FFILT_CFG */
>> +#define ACCEPT_BEACON_FRAMES   BIT(0)
>> +#define ACCEPT_DATA_FRAMES     BIT(1)
>> +#define ACCEPT_ACK_FRAMES      BIT(2)
>> +#define ACCEPT_MACCMD_FRAMES   BIT(3)
>> +#define ACCEPT_RESERVED_FRAMES BIT(4)
>> +#define ACCEPT_ALL_ADDRESS     BIT(5)
>> +
>> +/* REG_AUTO_CFG */
>> +#define AUTO_ACK_FRAMEPEND     BIT(0)
>> +#define IS_PANCOORD           BIT(1)
>> +#define RX_AUTO_ACK_EN           BIT(3)
>> +#define CSMA_CA_RX_TURNAROUND  BIT(4)
>> +
>> +/* REG_AUTO_TX1 */
>> +#define MAX_FRAME_RETRIES(x)   ((x) & 0xF)
>> +#define MAX_CCA_RETRIES(x)     (((x) & 0x7) << 4)
>> +
>> +/* REG_AUTO_TX2 */
>> +#define CSMA_MAX_BE(x)           ((x) & 0xF)
>> +#define CSMA_MIN_BE(x)           (((x) & 0xF) << 4)
>> +
>> +#define CMD_SPI_NOP        0xFF /* No operation. Use for dummy writes */
>> +#define CMD_SPI_PKT_WR        0x10 /* Write telegram to the Packet RAM
>> +                      * starting from the TX packet base address
>> +                      * pointer tx_packet_base
>> +                      */
>> +#define CMD_SPI_PKT_RD        0x30 /* Read telegram from the Packet RAM
>> +                      * starting from RX packet base address
>> +                      * pointer rxpb.rx_packet_base
>> +                      */
>> +#define CMD_SPI_MEM_WR(x)    (0x18 + (x >> 8)) /* Write data to MCR or
>> +                           * Packet RAM sequentially
>> +                           */
>> +#define CMD_SPI_MEM_RD(x)    (0x38 + (x >> 8)) /* Read data from MCR or
>> +                           * Packet RAM sequentially
>> +                           */
>> +#define CMD_SPI_MEMR_WR(x)    (0x08 + (x >> 8)) /* Write data to MCR
>> or Packet
>> +                           * RAM as random block
>> +                           */
>> +#define CMD_SPI_MEMR_RD(x)    (0x28 + (x >> 8)) /* Read data from MCR or
>> +                           * Packet RAM random block
>> +                           */
>> +#define CMD_SPI_PRAM_WR        0x1E /* Write data sequentially to
>> current
>> +                      * PRAM page selected
>> +                      */
>> +#define CMD_SPI_PRAM_RD        0x3E /* Read data sequentially from
>> current
>> +                      * PRAM page selected
>> +                      */
>> +#define CMD_RC_SLEEP        0xB1 /* Invoke transition of radio
>> controller
>> +                      * into SLEEP state
>> +                      */
>> +#define CMD_RC_IDLE        0xB2 /* Invoke transition of radio controller
>> +                      * into IDLE state
>> +                      */
>> +#define CMD_RC_PHY_RDY        0xB3 /* Invoke transition of radio
>> controller
>> +                      * into PHY_RDY state
>> +                      */
>> +#define CMD_RC_RX        0xB4 /* Invoke transition of radio controller
>> +                      * into RX state
>> +                      */
>> +#define CMD_RC_TX        0xB5 /* Invoke transition of radio controller
>> +                      * into TX state
>> +                      */
>> +#define CMD_RC_MEAS        0xB6 /* Invoke transition of radio controller
>> +                      * into MEAS state
>> +                      */
>> +#define CMD_RC_CCA        0xB7 /* Invoke Clear channel assessment */
>> +#define CMD_RC_CSMACA        0xC1 /* initiates CSMA-CA channel access
>> +                      * sequence and frame transmission
>> +                      */
>> +#define CMD_RC_PC_RESET        0xC7 /* Program counter reset */
>> +#define CMD_RC_RESET        0xC8 /* Resets the ADF7242 and puts it in
>> +                      * the sleep state
>> +                      */
>> +
>> +/* STATUS */
>> +
>> +#define STAT_SPI_READY        BIT(7)
>> +#define STAT_IRQ_STATUS        BIT(6)
>> +#define STAT_RC_READY        BIT(5)
>> +#define STAT_CCA_RESULT        BIT(4)
>> +#define RC_STATUS_IDLE        1
>> +#define RC_STATUS_MEAS        2
>> +#define RC_STATUS_PHY_RDY    3
>> +#define RC_STATUS_RX        4
>> +#define RC_STATUS_TX        5
>> +#define RC_STATUS_MASK        0xF
>> +
>> +/* AUTO_STATUS */
>> +
>> +#define SUCCESS            0
>> +#define SUCCESS_DATPEND        1
>> +#define FAILURE_CSMACA        2
>> +#define FAILURE_NOACK        3
>> +#define AUTO_STATUS_MASK    0x3
>> +
>> +#define PRAM_PAGESIZE        256
>> +
>> +/* IRQ1 */
>> +
>> +#define IRQ_CCA_COMPLETE    BIT(0)
>> +#define IRQ_SFD_RX        BIT(1)
>> +#define IRQ_SFD_TX        BIT(2)
>> +#define IRQ_RX_PKT_RCVD        BIT(3)
>> +#define IRQ_TX_PKT_SENT        BIT(4)
>> +#define IRQ_FRAME_VALID        BIT(5)
>> +#define IRQ_ADDRESS_VALID    BIT(6)
>> +#define IRQ_CSMA_CA        BIT(7)
>> +
>> +#define AUTO_TX_TURNAROUND    BIT(3)
>> +#define ADDON_EN        BIT(4)
>> +
>> +struct adf7242_local {
>> +    struct spi_device *spi;
>> +    struct completion tx_complete;
>> +    struct ieee802154_hw *hw;
>> +    struct mutex bmux; /* protect SPI messages */
>> +    struct spi_message stat_msg;
>> +    struct spi_transfer stat_xfer;
>> +    int tx_stat;
>> +    s8 rssi;
>> +    u8 max_frame_retries;
>> +    u8 max_cca_retries;
>> +
>> +    /* DMA (thus cache coherency maintenance) requires the
>> +     * transfer buffers to live in their own cache lines.
>> +     */
>> +
>> +    u8 buf[3] ____cacheline_aligned;
>> +    u8 buf_reg_tx[3];
>> +    u8 buf_read_tx[4];
>> +    u8 buf_read_rx[4];
>> +    u8 buf_stat_rx;
>> +    u8 buf_stat_tx;
>> +    u8 buf_cmd;
>> +};
>> +
>> +static int adf7242_status(struct adf7242_local *lp, u8 *stat)
>> +{
>> +    int status;
>> +
>> +    mutex_lock(&lp->bmux);
>> +    status = spi_sync(lp->spi, &lp->stat_msg);
>> +    *stat = lp->buf_stat_rx;
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_wait_ready(struct adf7242_local *lp, int line)
>> +{
>> +    int cnt = 0, ret = 0;
>> +    u8 stat;
>> +
>> +    do {
>> +        adf7242_status(lp, &stat);
>> +        cnt++;
>> +    } while (!((stat & STAT_RC_READY) && (stat & STAT_SPI_READY)) &&
>> +        (cnt < MAX_POLL_LOOPS));
>> +
>> +    if (cnt >= MAX_POLL_LOOPS) {
>> +        dev_warn(&lp->spi->dev, "%s:line %d Timeout\n", __func__, line);
>> +        ret = -ETIMEDOUT;
>> +    }
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
>> +
>> +    return ret;
>> +}
>> +
>> +static int adf7242_wait_status(struct adf7242_local *lp, int status,
>> int line)
>> +{
>> +    int cnt = 0, ret = 0;
>> +    u8 stat;
>> +
>> +    do {
>> +        adf7242_status(lp, &stat);
>> +        stat &= RC_STATUS_MASK;
>> +        cnt++;
>> +    } while ((stat != status) && (cnt < MAX_POLL_LOOPS));
>> +
>> +    if (cnt >= MAX_POLL_LOOPS) {
>> +        dev_warn(&lp->spi->dev, "%s:line %d Timeout status 0x%x\n",
>> +             __func__, line, stat);
>> +        ret = -ETIMEDOUT;
>> +    }
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
>> +
>> +    return ret;
>> +}
>> +
>> +static int adf7242_write_fbuf(struct adf7242_local *lp, u8 *data, u8
>> len)
>> +{
>> +    u8 *buf = lp->buf;
>> +    int status;
>> +    struct spi_message msg;
>> +    struct spi_transfer xfer_head = {
>> +        .len = 2,
>> +        .tx_buf = buf,
>> +
>> +    };
>> +    struct spi_transfer xfer_buf = {
>> +        .len = len,
>> +        .tx_buf = data,
>> +    };
>> +
>> +    spi_message_init(&msg);
>> +    spi_message_add_tail(&xfer_head, &msg);
>> +    spi_message_add_tail(&xfer_buf, &msg);
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    buf[0] = CMD_SPI_PKT_WR;
>> +    buf[1] = len + 2;
>> +
>> +    status = spi_sync(lp->spi, &msg);
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_read_fbuf(struct adf7242_local *lp,
>> +                 u8 *data, size_t len, bool packet_read)
>> +{
>> +    u8 *buf = lp->buf;
>> +    int status;
>> +    struct spi_message msg;
>> +    struct spi_transfer xfer_head = {
>> +        .len = 3,
>> +        .tx_buf = buf,
>> +        .rx_buf = buf,
>> +    };
>> +    struct spi_transfer xfer_buf = {
>> +        .len = len,
>> +        .rx_buf = data,
>> +    };
>> +
>> +    spi_message_init(&msg);
>> +    spi_message_add_tail(&xfer_head, &msg);
>> +    spi_message_add_tail(&xfer_buf, &msg);
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    if (packet_read) {
>> +        buf[0] = CMD_SPI_PKT_RD;
>> +        buf[1] = CMD_SPI_NOP;
>> +        buf[2] = 0;    /* PHR */
>> +    } else {
>> +        buf[0] = CMD_SPI_PRAM_RD;
>> +        buf[1] = 0;
>> +        buf[2] = CMD_SPI_NOP;
>> +    }
>> +
>> +    status = spi_sync(lp->spi, &msg);
>> +
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_read_reg(struct adf7242_local *lp, u16 addr, u8
>> *data)
>> +{
>> +    int status;
>> +    struct spi_message msg;
>> +
>> +    struct spi_transfer xfer = {
>> +        .len = 4,
>> +        .tx_buf = lp->buf_read_tx,
>> +        .rx_buf = lp->buf_read_rx,
>> +    };
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    lp->buf_read_tx[0] = CMD_SPI_MEM_RD(addr);
>> +    lp->buf_read_tx[1] = addr;
>> +    lp->buf_read_tx[2] = CMD_SPI_NOP;
>> +    lp->buf_read_tx[3] = CMD_SPI_NOP;
>> +
>> +    spi_message_init(&msg);
>> +    spi_message_add_tail(&xfer, &msg);
>> +
>> +    status = spi_sync(lp->spi, &msg);
>> +    if (msg.status)
>> +        status = msg.status;
>> +
>> +    if (!status)
>> +        *data = lp->buf_read_rx[3];
>> +
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n", __func__,
>> +         addr, *data);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_write_reg(struct adf7242_local *lp, u16 addr, u8
>> data)
>> +{
>> +    int status;
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    lp->buf_reg_tx[0] = CMD_SPI_MEM_WR(addr);
>> +    lp->buf_reg_tx[1] = addr;
>> +    lp->buf_reg_tx[2] = data;
>> +    status = spi_write(lp->spi, lp->buf_reg_tx, 3);
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n",
>> +         __func__, addr, data);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_cmd(struct adf7242_local *lp, u8 cmd)
>> +{
>> +    int status;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : CMD=0x%X\n", __func__, cmd);
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    lp->buf_cmd = cmd;
>> +    status = spi_write(lp->spi, &lp->buf_cmd, 1);
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_upload_firmware(struct adf7242_local *lp, u8
>> *data, u16 len)
>> +{
>> +    struct spi_message msg;
>> +    struct spi_transfer xfer_buf = { };
>> +    int status, i, page = 0;
>> +    u8 *buf = lp->buf;
>> +
>> +    struct spi_transfer xfer_head = {
>> +        .len = 2,
>> +        .tx_buf = buf,
>> +    };
>> +
>> +    buf[0] = CMD_SPI_PRAM_WR;
>> +    buf[1] = 0;
>> +
>> +    spi_message_init(&msg);
>> +    spi_message_add_tail(&xfer_head, &msg);
>> +    spi_message_add_tail(&xfer_buf, &msg);
>> +
>> +    for (i = len; i >= 0; i -= PRAM_PAGESIZE) {
>> +        adf7242_write_reg(lp, REG_PRAMPG, page);
>> +
>> +        xfer_buf.len = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
>> +        xfer_buf.tx_buf = &data[page * PRAM_PAGESIZE];
>> +
>> +        mutex_lock(&lp->bmux);
>> +        status = spi_sync(lp->spi, &msg);
>> +        mutex_unlock(&lp->bmux);
>> +        page++;
>> +    }
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_verify_firmware(struct adf7242_local *lp,
>> +                   const u8 *data, size_t len)
>
> Could it really happen that we upload the firmware, getting fine status
> codes back from spi_sync and this have a broken firmware in ram? To me
> it looks like a safety measure for something that should never happen.
> But I don't know the hardware.

It's a safety measure and should never happen.
I've added it while working with some broken SPI master driver some time 
ago. I can remove it.


>> +{
>> +    int i, j;
>> +    unsigned int page;
>> +    u8 *buf = kmalloc(PRAM_PAGESIZE, GFP_KERNEL);
>> +
>> +    if (!buf)
>> +        return -ENOMEM;
>> +
>> +    for (page = 0, i = len; i >= 0; i -= PRAM_PAGESIZE, page++) {
>> +        size_t nb = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
>> +
>> +        adf7242_write_reg(lp, REG_PRAMPG, page);
>> +        adf7242_read_fbuf(lp, buf, nb, false);
>> +
>> +        for (j = 0; j < nb; j++) {
>> +            if (buf[j] != data[page * PRAM_PAGESIZE + j]) {
>> +                kfree(buf);
>> +                return -EIO;
>> +            }
>> +        }
>> +    }
>> +    kfree(buf);
>> +
>> +    return 0;
>> +}
>> +
>> +static int adf7242_set_txpower(struct ieee802154_hw *hw, int mbm)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    u8 pwr, bias_ctrl, dbias, tmp;
>> +    int db = mbm / 100;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : Power %d dB\n", __func__, db);
>> +
>> +    if (db > 5 || db < -26)
>> +        return -EINVAL;
>> +
>> +    db = DIV_ROUND_CLOSEST(db + 29, 2);
>> +
>> +    if (db > 15) {
>> +        dbias = 21;
>> +        bias_ctrl = 63;
>> +    } else {
>> +        dbias = 13;
>> +        bias_ctrl = 55;
>
> What the meaning of the values here? 21, 63, 13, 55

Some BIAS values from the datasheet.
IIRC starting some power level they need to be set differently.

>
>> +    }
>> +
>> +    pwr = clamp_t(u8, db, 3, 15);
>> +
>> +    adf7242_read_reg(lp, REG_PA_CFG, &tmp);
>> +    tmp &= ~PA_BRIDGE_DBIAS(~0);
>> +    tmp |= PA_BRIDGE_DBIAS(dbias);
>> +    adf7242_write_reg(lp, REG_PA_CFG, tmp);
>> +
>> +    adf7242_read_reg(lp, REG_PA_BIAS, &tmp);
>> +    tmp &= ~PA_BIAS_CTRL(~0);
>> +    tmp |= PA_BIAS_CTRL(bias_ctrl);
>> +    adf7242_write_reg(lp, REG_PA_BIAS, tmp);
>> +
>> +    adf7242_read_reg(lp, REG_EXTPA_MSC, &tmp);
>> +    tmp &= ~PA_PWR(~0);
>> +    tmp |= PA_PWR(pwr);
>> +
>> +    return adf7242_write_reg(lp, REG_EXTPA_MSC, tmp);
>> +}
>> +
>> +static int adf7242_set_csma_params(struct ieee802154_hw *hw, u8 min_be,
>> +                   u8 max_be, u8 retries)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    int ret;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : min_be=%d max_be=%d retries=%d\n",
>> +         __func__, min_be, max_be, retries);
>> +
>> +    if (min_be > max_be || max_be > 8 || retries > 5)
>> +        return -EINVAL;
>> +
>> +    ret = adf7242_write_reg(lp, REG_AUTO_TX1,
>> +                MAX_FRAME_RETRIES(lp->max_frame_retries) |
>> +                MAX_CCA_RETRIES(retries));
>> +    if (ret)
>> +        return ret;
>> +
>> +    lp->max_cca_retries = retries;
>> +
>> +    return adf7242_write_reg(lp, REG_AUTO_TX2, CSMA_MAX_BE(max_be) |
>> +            CSMA_MIN_BE(min_be));
>> +}
>> +
>> +static int adf7242_set_frame_retries(struct ieee802154_hw *hw, s8
>> retries)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    int ret = 0;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : Retries = %d\n", __func__, retries);
>> +
>> +    if (retries < -1 || retries > 15)
>> +        return -EINVAL;
>> +
>> +    if (retries >= 0)
>> +        ret = adf7242_write_reg(lp, REG_AUTO_TX1,
>> +                    MAX_FRAME_RETRIES(retries) |
>> +                    MAX_CCA_RETRIES(lp->max_cca_retries));
>> +
>> +    lp->max_frame_retries = retries;
>> +
>> +    return ret;
>> +}
>> +
>> +static int adf7242_ed(struct ieee802154_hw *hw, u8 *level)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +
>> +    *level = lp->rssi;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s :Exit level=%d\n",
>> +         __func__, *level);
>> +
>> +    return 0;
>> +}
>> +
>> +static int adf7242_start(struct ieee802154_hw *hw)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +
>> +    adf7242_cmd(lp, CMD_RC_PHY_RDY);
>> +    return adf7242_cmd(lp, CMD_RC_RX);
>> +}
>> +
>> +static void adf7242_stop(struct ieee802154_hw *hw)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +
>> +    adf7242_cmd(lp, CMD_RC_IDLE);
>> +    adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
>> +}
>> +
>> +static int adf7242_channel(struct ieee802154_hw *hw, u8 page, u8
>> channel)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    unsigned long freq;
>> +
>> +    dev_dbg(&lp->spi->dev, "%s :Channel=%d\n", __func__, channel);
>> +
>> +    might_sleep();
>> +
>> +    WARN_ON(page != 0);
>> +    WARN_ON(channel < 11);
>> +    WARN_ON(channel > 26);
>> +
>> +    freq = (2405 + 5 * (channel - 11)) * 100;
>> +    adf7242_cmd(lp, CMD_RC_PHY_RDY);
>> +
>> +    adf7242_write_reg(lp, REG_CH_FREQ0, freq);
>> +    adf7242_write_reg(lp, REG_CH_FREQ1, freq >> 8);
>> +    adf7242_write_reg(lp, REG_CH_FREQ2, freq >> 16);
>> +
>> +    return adf7242_cmd(lp, CMD_RC_RX);
>> +}
>> +
>> +static int adf7242_set_hw_addr_filt(struct ieee802154_hw *hw,
>> +                    struct ieee802154_hw_addr_filt *filt,
>> +                    unsigned long changed)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    u8 reg;
>> +
>> +    dev_dbg(&lp->spi->dev, "%s :Changed=0x%lX\n", __func__, changed);
>> +
>> +    might_sleep();
>> +
>> +    if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
>> +        u8 addr[8], i;
>> +
>> +        memcpy(addr, &filt->ieee_addr, 8);
>> +
>> +        for (i = 0; i < 8; i++)
>> +            adf7242_write_reg(lp, REG_IEEE_ADDR_0 + i, addr[i]);
>> +    }
>> +
>> +    if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
>> +        u16 saddr = le16_to_cpu(filt->short_addr);
>> +
>> +        adf7242_write_reg(lp, REG_SHORT_ADDR_0, saddr);
>> +        adf7242_write_reg(lp, REG_SHORT_ADDR_1, saddr >> 8);
>> +    }
>> +
>> +    if (changed & IEEE802154_AFILT_PANID_CHANGED) {
>> +        u16 pan_id = le16_to_cpu(filt->pan_id);
>> +
>> +        adf7242_write_reg(lp, REG_PAN_ID0, pan_id);
>> +        adf7242_write_reg(lp, REG_PAN_ID1, pan_id >> 8);
>> +    }
>> +
>> +    if (changed & IEEE802154_AFILT_PANC_CHANGED) {
>> +        adf7242_read_reg(lp, REG_AUTO_CFG, &reg);
>> +        if (filt->pan_coord)
>> +            reg |= IS_PANCOORD;
>> +        else
>> +            reg &= ~IS_PANCOORD;
>> +        adf7242_write_reg(lp, REG_AUTO_CFG, reg);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int adf7242_set_promiscuous_mode(struct ieee802154_hw *hw,
>> bool on)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +
>> +    dev_dbg(&lp->spi->dev, "%s : mode %d\n", __func__, on);
>> +
>> +    if (on) {
>> +        adf7242_write_reg(lp, REG_AUTO_CFG, 0);
>> +        return adf7242_write_reg(lp, REG_FFILT_CFG,
>> +                  ACCEPT_BEACON_FRAMES |
>> +                  ACCEPT_DATA_FRAMES |
>> +                  ACCEPT_MACCMD_FRAMES |
>> +                  ACCEPT_ALL_ADDRESS |
>> +                  ACCEPT_ACK_FRAMES |
>> +                  ACCEPT_RESERVED_FRAMES);
>> +    } else {
>> +        adf7242_write_reg(lp, REG_FFILT_CFG,
>> +                  ACCEPT_BEACON_FRAMES |
>> +                  ACCEPT_DATA_FRAMES |
>> +                  ACCEPT_MACCMD_FRAMES |
>> +                  ACCEPT_RESERVED_FRAMES);
>> +
>> +        return adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
>> +    }
>> +}
>> +
>> +static int adf7242_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    s8 level = clamp_t(s8, mbm / 100, S8_MIN, S8_MAX);
>> +
>> +    dev_dbg(&lp->spi->dev, "%s : level %d\n", __func__, level);
>> +
>> +    return adf7242_write_reg(lp, REG_CCA1, level);
>> +}
>> +
>> +static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    int ret;
>> +
>> +    reinit_completion(&lp->tx_complete);
>> +
>> +    ret = adf7242_write_fbuf(lp, skb->data, skb->len);
>> +    if (ret)
>> +        goto err;
>> +
>> +    ret = adf7242_cmd(lp, CMD_RC_PHY_RDY);
>> +    ret |= adf7242_cmd(lp, CMD_RC_CSMACA);
>> +
>> +    if (ret)
>> +        goto err;
>> +
>> +    ret = wait_for_completion_interruptible_timeout(&lp->tx_complete,
>> HZ);
>> +    if (ret == -ERESTARTSYS)
>> +        goto err;
>> +    if (ret == 0) {
>> +        dev_warn(&lp->spi->dev, "Timeout waiting for TX interrupt\n");
>> +        ret = -ETIMEDOUT;
>> +        goto err;
>> +    }
>> +
>> +    if (lp->tx_stat != SUCCESS) {
>> +        dev_warn(&lp->spi->dev,
>> +             "Error xmit: Retry count exceeded Status=0x%x\n",
>> +             lp->tx_stat);
>> +        ret = -ECOMM;
>> +    } else {
>> +        ret = 0;
>> +    }
>> +
>> +err:
>> +    adf7242_cmd(lp, CMD_RC_RX);
>> +    return ret;
>> +}
>> +
>> +static int adf7242_rx(struct adf7242_local *lp)
>> +{
>> +    struct sk_buff *skb;
>> +    size_t len;
>> +    int ret;
>> +    u8 lqi, len_u8, *data;
>> +
>> +    adf7242_read_reg(lp, 0, &len_u8);
>> +
>> +    len = len_u8;
>> +
>> +    if (!ieee802154_is_valid_psdu_len(len)) {
>> +        dev_dbg(&lp->spi->dev,
>> +            "corrupted frame received len %d\n", len);
>> +        len = IEEE802154_MTU;
>> +    }
>> +
>> +    skb = dev_alloc_skb(len);
>> +    if (!skb)
>> +        return -ENOMEM;
>> +
>> +    data = skb_put(skb, len);
>> +    ret = adf7242_read_fbuf(lp, data, len, true);
>> +
>> +    if (!ret) {
>> +        lqi = data[len - 2];
>> +        lp->rssi = data[len - 1];
>> +    }
>> +
>> +    adf7242_cmd(lp, CMD_RC_RX);
>> +
>> +    skb_trim(skb, len - 2);    /* Don't put RSSI/LQI or CRC into the
>> frame */
>> +
>> +    ieee802154_rx_irqsafe(lp->hw, skb, lqi);
>> +
>> +    dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n",
>> +        __func__, ret, len, lqi, lp->rssi);
>> +
>> +    return 0;
>> +}
>> +
>> +static struct ieee802154_ops adf7242_ops = {
>> +    .owner = THIS_MODULE,
>> +    .xmit_sync = adf7242_xmit,
>> +    .ed = adf7242_ed,
>> +    .set_channel = adf7242_channel,
>> +    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
>> +    .start = adf7242_start,
>> +    .stop = adf7242_stop,
>> +    .set_csma_params = adf7242_set_csma_params,
>> +    .set_frame_retries = adf7242_set_frame_retries,
>> +    .set_txpower = adf7242_set_txpower,
>> +    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
>> +    .set_cca_ed_level = adf7242_set_cca_ed_level,
>
> Nice to see so many callbacks implemented. The only things I see missing
> is xmit_async, set_lbt and set_cca_mode. I would not make it a
> requirements to get these hooked up before merging this patch but we
> should consider it as todo items.

The part only supports CCA mode Energy above threshold.
Not sure what this LBT mode does on the AT86RFxxx driver.
The ADF7242 only supports CSMA-CA and not some other listen before talk 
flavour. The only oher option is to turn CSMA-CA completly off.
I'm also not sure if we need to supprot the async mode, while the sync 
mode is working. For me the async mode looks like it tries to workaround 
some HW access issues.



>
>> +};
>> +
>> +static irqreturn_t adf7242_isr(int irq, void *data)
>> +{
>> +    struct adf7242_local *lp = data;
>> +    u8 irq1, auto_stat = 0, stat = 0, rx_en = 0;
>> +
>> +    adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
>> +    adf7242_write_reg(lp, REG_IRQ1_SRC1, irq1);
>> +
>> +    if (!(irq1 & (IRQ_RX_PKT_RCVD | IRQ_CSMA_CA)))
>> +        dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n",
>> +            __func__, irq1);
>> +
>> +    dev_dbg(&lp->spi->dev, "%s IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n",
>> +        __func__, irq1,
>> +        irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
>> +        irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
>> +        irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
>> +        irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
>> +        irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
>> +        irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
>> +        irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
>> +        irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
>> +
>> +    adf7242_status(lp, &stat);
>> +
>> +    dev_dbg(&lp->spi->dev, "%s STATUS = %X:\n%s\n%s%s%s%s%s\n",
>> +        __func__, stat,
>> +        stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
>> +        (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
>> +        (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
>> +        (stat & 0xf) == RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
>> +        (stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
>> +        (stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
>> +
>> +    if ((irq1 & IRQ_RX_PKT_RCVD) && (irq1 & IRQ_FRAME_VALID)) {
>> +        /* Wait until ACK is processed */
>> +        if ((stat & RC_STATUS_MASK) != RC_STATUS_PHY_RDY)
>> +            adf7242_wait_status(lp, RC_STATUS_PHY_RDY, __LINE__);
>> +
>> +        adf7242_rx(lp);
>> +        rx_en = 1;
>> +    }
>> +
>> +    if (irq1 & IRQ_CSMA_CA) {
>> +        adf7242_read_reg(lp, REG_AUTO_STATUS, &auto_stat);
>> +        auto_stat &= AUTO_STATUS_MASK;
>> +
>> +        dev_dbg(&lp->spi->dev, "%s AUTO_STATUS = %X:\n%s%s%s%s\n",
>> +            __func__, auto_stat,
>> +            auto_stat == SUCCESS ? "SUCCESS" : "",
>> +            auto_stat ==
>> +            SUCCESS_DATPEND ? "SUCCESS_DATPEND" : "",
>> +            auto_stat == FAILURE_CSMACA ? "FAILURE_CSMACA" : "",
>> +            auto_stat == FAILURE_NOACK ? "FAILURE_NOACK" : "");
>> +
>> +        /* save CSMA-CA completion status */
>> +        lp->tx_stat = auto_stat;
>> +        rx_en = 1;
>> +
>> +        complete(&lp->tx_complete);
>> +    }
>> +
>> +    if (!rx_en)
>> +        adf7242_cmd(lp, CMD_RC_RX);
>> +
>> +    return IRQ_HANDLED;
>> +}
>> +
>> +static int adf7242_hw_init(struct adf7242_local *lp)
>> +{
>> +    int ret;
>> +    const struct firmware *fw;
>> +
>> +    adf7242_cmd(lp, CMD_RC_RESET);
>> +    adf7242_cmd(lp, CMD_RC_IDLE);
>> +
>> +    /* get ADF7242 addon firmware
>> +     * build this driver as module
>
> Hmm, this brings up the question if the firmware is also fetched if the
> driver is built into the kernel directly?


Compile firmware blob into the kernel.


>> +     * and place under /lib/firmware/adf7242_firmware.bin
>> +     */
>> +    ret = request_firmware(&fw, FIRMWARE, &lp->spi->dev);
>> +    if (ret) {
>> +        dev_err(&lp->spi->dev,
>> +            "request_firmware() failed with %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    ret = adf7242_upload_firmware(lp, (u8 *)fw->data, fw->size);
>> +    if (ret) {
>> +        dev_err(&lp->spi->dev,
>> +            "upload firmware failed with %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    ret = adf7242_verify_firmware(lp, (u8 *)fw->data, fw->size);
>> +    if (ret) {
>> +        dev_err(&lp->spi->dev,
>> +            "verify firmware failed with %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    adf7242_cmd(lp, CMD_RC_PC_RESET);
>> +
>> +    release_firmware(fw);
>> +
>> +    adf7242_write_reg(lp, REG_FFILT_CFG,
>> +              ACCEPT_BEACON_FRAMES |
>> +              ACCEPT_DATA_FRAMES |
>> +              ACCEPT_MACCMD_FRAMES |
>> +              ACCEPT_RESERVED_FRAMES);
>> +
>> +    adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
>> +
>> +    adf7242_write_reg(lp, REG_PKT_CFG, ADDON_EN | BIT(2));
>> +
>> +    adf7242_write_reg(lp, REG_EXTPA_MSC, 0xF1);
>> +    adf7242_write_reg(lp, REG_RXFE_CFG, 0x1D);
>> +
>> +    adf7242_write_reg(lp, REG_IRQ1_EN0, 0);
>> +    adf7242_write_reg(lp, REG_IRQ1_EN1, IRQ_RX_PKT_RCVD | IRQ_CSMA_CA);
>> +
>> +    adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
>> +    adf7242_write_reg(lp, REG_IRQ1_SRC0, 0xFF);
>> +
>> +    adf7242_cmd(lp, CMD_RC_IDLE);
>> +
>> +    return 0;
>> +}
>> +
>> +static ssize_t adf7242_show(struct device *dev,
>> +                struct device_attribute *devattr, char *buf)
>> +{
>> +    struct adf7242_local *lp = dev_get_drvdata(dev);
>> +    u8 stat, irq1;
>> +    size_t len;
>> +
>> +    adf7242_status(lp, &stat);
>> +
>> +    adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
>> +
>> +    len = sprintf(buf, "IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n", irq1,
>> +              irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
>> +              irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
>> +              irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
>> +              irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
>> +              irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
>> +              irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
>> +              irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
>> +              irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
>> +
>> +    len += sprintf(buf + len, "STATUS = %X:\n%s\n%s%s%s%s%s\n", stat,
>> +               stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
>> +               (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
>> +               (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
>> +               (stat & 0xf) ==
>> +                RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
>> +               (stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
>> +               (stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
>> +
>> +    len += sprintf(buf + len, "RSSI = %d\n", lp->rssi);
>> +
>> +    return len;
>> +}
>> +static DEVICE_ATTR(status, 0664, adf7242_show, NULL);
>
> The show function and its sysfs entry shoudl go into debugfs, no? Having
> a sysfs entry here make sit a kernel ABI which we cannot change later
> and it looks like debugging only to me.


See question below - ok - I'll more this into debugfs.


>
>> +
>> +static const s32 adf7242_powers[] = {
>> +    500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600,
>> -700,
>> +    -800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700,
>> +    -1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600,
>> +};
>> +
>> +static const s32 adf7242_ed_levels[] = {
>> +    -9000, -8900, -8800, -8700, -8600, -8500, -8400, -8300, -8200,
>> -8100,
>> +    -8000, -7900, -7800, -7700, -7600, -7500, -7400, -7300, -7200,
>> -7100,
>> +    -7000, -6900, -6800, -6700, -6600, -6500, -6400, -6300, -6200,
>> -6100,
>> +    -6000, -5900, -5800, -5700, -5600, -5500, -5400, -5300, -5200,
>> -5100,
>> +    -5000, -4900, -4800, -4700, -4600, -4500, -4400, -4300, -4200,
>> -4100,
>> +    -4000, -3900, -3800, -3700, -3600, -3500, -3400, -3200, -3100, -3000
>> +};
>> +
>> +static int adf7242_probe(struct spi_device *spi)
>> +{
>> +    struct ieee802154_hw *hw;
>> +    struct adf7242_local *lp;
>> +    int ret, irq_type;
>> +
>> +    if (!spi->irq) {
>> +        dev_err(&spi->dev, "no IRQ specified\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    hw = ieee802154_alloc_hw(sizeof(*lp), &adf7242_ops);
>> +    if (!hw)
>> +        return -ENOMEM;
>> +
>> +    lp = hw->priv;
>> +    lp->hw = hw;
>> +    lp->spi = spi;
>> +
>> +    hw->priv = lp;
>> +    hw->parent = &spi->dev;
>> +    hw->extra_tx_headroom = 0;
>> +
>> +    /* We support only 2.4 Ghz */
>> +    hw->phy->supported.channels[0] = 0x7FFF800;
>> +
>> +    hw->flags = IEEE802154_HW_OMIT_CKSUM |
>> +            IEEE802154_HW_CSMA_PARAMS |
>> +            IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT |
>> +            IEEE802154_HW_PROMISCUOUS;
>> +
>> +    hw->phy->flags = WPAN_PHY_FLAG_TXPOWER |
>> +             WPAN_PHY_FLAG_CCA_ED_LEVEL |
>> +             WPAN_PHY_FLAG_CCA_MODE;
>
> Is this hardware really only supporting the one CCA_MODE?

Yes

>
>> +
>> +    hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY);
>> +
>> +    hw->phy->supported.cca_ed_levels = adf7242_ed_levels;
>> +    hw->phy->supported.cca_ed_levels_size =
>> ARRAY_SIZE(adf7242_ed_levels);
>> +
>> +    hw->phy->cca.mode = NL802154_CCA_ENERGY;
>> +
>> +    hw->phy->supported.tx_powers = adf7242_powers;
>> +    hw->phy->supported.tx_powers_size = ARRAY_SIZE(adf7242_powers);
>> +
>> +    hw->phy->supported.min_minbe = 0;
>> +    hw->phy->supported.max_minbe = 8;
>> +
>> +    hw->phy->supported.min_maxbe = 3;
>> +    hw->phy->supported.max_maxbe = 8;
>> +
>> +    hw->phy->supported.min_frame_retries = 0;
>> +    hw->phy->supported.max_frame_retries = 15;
>> +
>> +    hw->phy->supported.min_csma_backoffs = 0;
>> +    hw->phy->supported.max_csma_backoffs = 5;
>> +
>> +    ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
>> +
>> +    mutex_init(&lp->bmux);
>> +    init_completion(&lp->tx_complete);
>> +
>> +    /* Setup Status Message */
>> +    lp->stat_xfer.len = 1;
>> +    lp->stat_xfer.tx_buf = &lp->buf_stat_tx;
>> +    lp->stat_xfer.rx_buf = &lp->buf_stat_rx;
>> +    lp->buf_stat_tx = CMD_SPI_NOP;
>> +
>> +    spi_message_init(&lp->stat_msg);
>> +    spi_message_add_tail(&lp->stat_xfer, &lp->stat_msg);
>> +
>> +    spi_set_drvdata(spi, lp);
>> +
>> +    ret = adf7242_hw_init(lp);
>> +    if (ret)
>> +        goto err_hw_init;
>> +
>> +    irq_type = irq_get_trigger_type(spi->irq);
>> +    if (!irq_type)
>> +        irq_type = IRQF_TRIGGER_HIGH;
>> +
>> +    ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
>> adf7242_isr,
>> +                    irq_type | IRQF_ONESHOT,
>> +                    dev_name(&spi->dev), lp);
>> +    if (ret)
>> +        goto err_hw_init;
>> +
>> +    ret = ieee802154_register_hw(lp->hw);
>> +    if (ret)
>> +        goto err_hw_init;
>> +
>> +    dev_set_drvdata(&spi->dev, lp);
>> +
>> +    /* move to debugfs, maybe add some helper to ieee802154_ops ? */
>> +    ret = sysfs_create_file(&spi->dev.kobj, &dev_attr_status.attr);
>
> This needs to be decided before we can merge this patch. To me this
> looks a debugfs candiate.

ok

>> +    if (ret)
>> +        goto out;
>> +
>> +    dev_info(&spi->dev, "mac802154 IRQ-%d registered\n", spi->irq);
>> +
>> +    return ret;
>> +
>> +out:
>> +    ieee802154_unregister_hw(lp->hw);
>> +err_hw_init:
>> +    mutex_destroy(&lp->bmux);
>> +    ieee802154_free_hw(lp->hw);
>> +
>> +    return ret;
>> +}
>> +
>> +static int adf7242_remove(struct spi_device *spi)
>> +{
>> +    struct adf7242_local *lp = spi_get_drvdata(spi);
>> +
>> +    sysfs_remove_file(&spi->dev.kobj, &dev_attr_status.attr);
>> +    ieee802154_unregister_hw(lp->hw);
>> +    mutex_destroy(&lp->bmux);
>> +    ieee802154_free_hw(lp->hw);
>> +
>> +    return 0;
>> +}
>> +
>> +static const struct of_device_id adf7242_of_match[] = {
>> +    { .compatible = "adi,adf7242", },
>> +    { },
>> +};
>> +MODULE_DEVICE_TABLE(of, adf7242_of_match);
>> +
>> +static const struct spi_device_id adf7242_device_id[] = {
>> +    { .name = "adf7242", },
>> +    { },
>> +};
>> +MODULE_DEVICE_TABLE(spi, adf7242_device_id);
>> +
>> +static struct spi_driver adf7242_driver = {
>> +    .id_table = adf7242_device_id,
>> +    .driver = {
>> +           .of_match_table = of_match_ptr(adf7242_of_match),
>> +           .name = "adf7242",
>> +           .owner = THIS_MODULE,
>> +           },
>> +    .probe = adf7242_probe,
>> +    .remove = adf7242_remove,
>> +};
>> +
>> +module_spi_driver(adf7242_driver);
>> +
>> +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
>> +MODULE_DESCRIPTION("ADF7242 IEEE802.15.4 Transceiver Driver");
>> +MODULE_LICENSE("GPL");
>
>
> Something worth thinking about might also be the usage of regmap.

Given the number of different spi transaction formats I don't think a 
regmap only approach can work here.
Mixing things will not improve things either. So I prefer it the way it 
is right now.



> After the include fix teh driver compiled fine. I will try to find some
> time connecting my adf7242 module to a pi and giving the driver some
> real testing over the next week.
>
> regards
> Stefan Schmidt
>
>

Thanks for taking the time to review things!
I'll send V2 later this week.

-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-07 12:47     ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-07 12:47 UTC (permalink / raw)
  To: Stefan Schmidt, alex.aring, marcel; +Cc: linux-wpan, linux-bluetooth

On 12/04/2015 01:07 PM, Stefan Schmidt wrote:
> Hello.
>
> On 04/12/15 10:09, michael.hennerich@analog.com wrote:
>> From: Michael Hennerich <michael.hennerich@analog.com>
>>
>> This driver has been sitting in the linux-zigbee[2] repository for a long
>> time. We updated it from time to time and made it available via our
>> github kernel repository. The Linux MAC802.15.4 support has improved a
>> lot
>> since then. Thanks to all! So it’s finally time to upstream this driver.
>
> Thanks for taking the time and bringing it back to mainline!
>
>> The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
>> operating modes. The firmware file is currently made available on the
>> ADF7242 wiki page here [1]
>
> Just being curious here. Is there any way to get the firmware source
> and/or compile your own? Its the first hardware for IEEE 802.15.4 I have
> seen that have a special firmware for this which triggers my curiosity. :)
>
> Anyway, this has not that much to do with the driver review here as it
> can obviously go in with the binary firmware. We just need to make sure
> to also bring the firmware into the linux-firmware repo in time.
>
>> [1]
>> http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
>>
>> [2]
>> http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
>>
>>
>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>> ---
>>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>>   drivers/net/ieee802154/Kconfig                     |    5 +
>>   drivers/net/ieee802154/Makefile                    |    1 +
>>   drivers/net/ieee802154/adf7242.c                   | 1183
>> ++++++++++++++++++++
>>   4 files changed, 1207 insertions(+)
>>   create mode 100644
>> Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>   create mode 100644 drivers/net/ieee802154/adf7242.c
>>
>> diff --git
>> a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>> b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>> new file mode 100644
>> index 0000000..dea5124
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>> @@ -0,0 +1,18 @@
>> +* ADF7242 IEEE 802.15.4 *
>> +
>> +Required properties:
>> +  - compatible:        should be "adi,adf7242"
>> +  - spi-max-frequency:    maximal bus speed (12.5 MHz)
>> +  - reg:        the chipselect index
>> +  - interrupts:        the interrupt generated by the device via pin
>> IRQ1.
>> +            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
>> +
>> +Example:
>> +
>> +    adf7242@0 {
>> +        compatible = "adi,adf7242";
>> +        spi-max-frequency = <10000000>;
>> +        reg = <0>;
>> +        interrupts = <98 IRQ_TYPE_LEVEL_HIGH>;
>> +        interrupt-parent = <&gpio3>;
>> +    };
>> diff --git a/drivers/net/ieee802154/Kconfig
>> b/drivers/net/ieee802154/Kconfig
>> index ce5f1a2..fd17598 100644
>> --- a/drivers/net/ieee802154/Kconfig
>> +++ b/drivers/net/ieee802154/Kconfig
>> @@ -71,3 +71,8 @@ config IEEE802154_ATUSB
>>         This driver can also be built as a module. To do so say M here.
>>         The module will be called 'atusb'.
>> +
>> +config IEEE802154_ADF7242
>> +       tristate "ADF7242 transceiver driver"
>> +       depends on IEEE802154_DRIVERS && MAC802154
>> +       depends on SPI
>
> Maybe some help text here?

Yeah will do.


>
>> diff --git a/drivers/net/ieee802154/Makefile
>> b/drivers/net/ieee802154/Makefile
>> index cf1d2a6..3a923d3 100644
>> --- a/drivers/net/ieee802154/Makefile
>> +++ b/drivers/net/ieee802154/Makefile
>> @@ -3,3 +3,4 @@ obj-$(CONFIG_IEEE802154_AT86RF230) += at86rf230.o
>>   obj-$(CONFIG_IEEE802154_MRF24J40) += mrf24j40.o
>>   obj-$(CONFIG_IEEE802154_CC2520) += cc2520.o
>>   obj-$(CONFIG_IEEE802154_ATUSB) += atusb.o
>> +obj-$(CONFIG_IEEE802154_ADF7242) += adf7242.o
>> diff --git a/drivers/net/ieee802154/adf7242.c
>> b/drivers/net/ieee802154/adf7242.c
>> new file mode 100644
>> index 0000000..48268b1
>> --- /dev/null
>> +++ b/drivers/net/ieee802154/adf7242.c
>> @@ -0,0 +1,1183 @@
>> +/*
>> + * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver
>> + *
>> + * Copyright 2009-2015 Analog Devices Inc.
>> + *
>
> Personally I like having a link to the actual data sheet inside the
> driver header. This makes only sense if it is a stable URI.

ok

>
>> + * Licensed under the GPL-2 or later.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/interrupt.h>
>
> You also want #include <linux/irq.h> here. Without it the compilation
> fails for me with:
>
> drivers/net/ieee802154/adf7242.c: In function 'adf7242_probe':
> drivers/net/ieee802154/adf7242.c:1110:13: error: implicit declaration of
> function 'irq_get_trigger_type' [-Werror=implicit-function-declaration]
>    irq_type = irq_get_trigger_type(spi->irq);
>               ^
> cc1: some warnings being treated as errors

Ups - my test platform seems to include it via some other header.
I'll fix it.


>
>
>> +#include <linux/delay.h>
>> +#include <linux/mutex.h>
>> +#include <linux/workqueue.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/firmware.h>
>> +#include <linux/spi/spi.h>
>> +#include <linux/skbuff.h>
>> +#include <linux/of.h>
>> +#include <linux/ieee802154.h>
>> +#include <net/mac802154.h>
>> +#include <net/cfg802154.h>
>> +
>> +#define FIRMWARE "adf7242_firmware.bin"
>> +#define MAX_POLL_LOOPS 50
>> +
>> +/* All Registers */
>> +
>> +#define REG_EXT_CTRL    0x100    /* RW External LNA/PA and internal
>> PA control */
>> +#define REG_TX_FSK_TEST 0x101    /* RW TX FSK test mode configuration */
>> +#define REG_CCA1    0x105    /* RW RSSI threshold for CCA */
>> +#define REG_CCA2    0x106    /* RW CCA mode configuration */
>> +#define REG_BUFFERCFG    0x107    /* RW RX_BUFFER overwrite control */
>> +#define REG_PKT_CFG    0x108    /* RW FCS evaluation configuration */
>> +#define REG_DELAYCFG0    0x109    /* RW RC_RX command to SFD or sync
>> word delay */
>> +#define REG_DELAYCFG1    0x10A    /* RW RC_TX command to TX state */
>> +#define REG_DELAYCFG2    0x10B    /* RW Mac delay extension */
>> +#define REG_SYNC_WORD0    0x10C    /* RW sync word bits [7:0] of
>> [23:0]  */
>> +#define REG_SYNC_WORD1    0x10D    /* RW sync word bits [15:8] of
>> [23:0]  */
>> +#define REG_SYNC_WORD2    0x10E    /* RW sync word bits [23:16] of
>> [23:0]    */
>> +#define REG_SYNC_CONFIG    0x10F    /* RW sync word configuration */
>> +#define REG_RC_CFG    0x13E    /* RW RX / TX packet configuration */
>> +#define REG_RC_VAR44    0x13F    /* RW RESERVED */
>> +#define REG_CH_FREQ0    0x300    /* RW Channel Frequency Settings -
>> Low */
>> +#define REG_CH_FREQ1    0x301    /* RW Channel Frequency Settings -
>> Middle */
>> +#define REG_CH_FREQ2    0x302    /* RW Channel Frequency Settings -
>> High */
>> +#define REG_TX_FD    0x304    /* RW TX Frequency Deviation Register */
>> +#define REG_DM_CFG0    0x305    /* RW RX Discriminator BW Register */
>> +#define REG_TX_M    0x306    /* RW TX Mode Register */
>> +#define REG_RX_M    0x307    /* RW RX Mode Register */
>> +#define REG_RRB        0x30C    /* R RSSI Readback Register */
>> +#define REG_LRB        0x30D    /* R Link Quality Readback Register */
>> +#define REG_DR0        0x30E    /* RW bits [15:8] of [15:0] data rate
>> setting */
>> +#define REG_DR1        0x30F    /* RW bits [7:0] of [15:0] data rate
>> setting */
>> +#define REG_PRAMPG    0x313    /* RW RESERVED */
>> +#define REG_TXPB    0x314    /* RW TX Packet Storage Base Address */
>> +#define REG_RXPB    0x315    /* RW RX Packet Storage Base Address */
>> +#define REG_TMR_CFG0    0x316    /* RW Wake up Timer Conf Register -
>> High */
>> +#define REG_TMR_CFG1    0x317    /* RW Wake up Timer Conf Register -
>> Low */
>> +#define REG_TMR_RLD0    0x318    /* RW Wake up Timer Value Register -
>> High */
>> +#define REG_TMR_RLD1    0x319    /* RW Wake up Timer Value Register -
>> Low  */
>> +#define REG_TMR_CTRL    0x31A    /* RW Wake up Timer Timeout flag */
>> +#define REG_PD_AUX    0x31E    /* RW Battmon enable */
>> +#define REG_GP_CFG    0x32C    /* RW GPIO Configuration */
>> +#define REG_GP_OUT    0x32D    /* RW GPIO Configuration */
>> +#define REG_GP_IN    0x32E    /* R GPIO Configuration */
>> +#define REG_SYNT    0x335    /* RW bandwidth calibration timers */
>> +#define REG_CAL_CFG    0x33D    /* RW Calibration Settings */
>> +#define REG_PA_BIAS    0x36E    /* RW PA BIAS */
>> +#define REG_SYNT_CAL    0x371    /* RW Oscillator and Doubler
>> Configuration */
>> +#define REG_IIRF_CFG    0x389    /* RW BB Filter Decimation Rate */
>> +#define REG_CDR_CFG    0x38A    /* RW CDR kVCO */
>> +#define REG_DM_CFG1    0x38B    /* RW Postdemodulator Filter */
>> +#define REG_AGCSTAT    0x38E    /* R RXBB Ref Osc Calibration Engine
>> Readback */
>> +#define REG_RXCAL0    0x395    /* RW RX BB filter tuning, LSB */
>> +#define REG_RXCAL1    0x396    /* RW RX BB filter tuning, MSB */
>> +#define REG_RXFE_CFG    0x39B    /* RW RXBB Ref Osc & RXFE
>> Calibration */
>> +#define REG_PA_RR    0x3A7    /* RW Set PA ramp rate */
>> +#define REG_PA_CFG    0x3A8    /* RW PA enable */
>> +#define REG_EXTPA_CFG    0x3A9    /* RW External PA BIAS DAC */
>> +#define REG_EXTPA_MSC    0x3AA    /* RW PA Bias Mode */
>> +#define REG_ADC_RBK    0x3AE    /* R Readback temp */
>> +#define REG_AGC_CFG1    0x3B2    /* RW GC Parameters */
>> +#define REG_AGC_MAX    0x3B4    /* RW Slew rate     */
>> +#define REG_AGC_CFG2    0x3B6    /* RW RSSI Parameters */
>> +#define REG_AGC_CFG3    0x3B7    /* RW RSSI Parameters */
>> +#define REG_AGC_CFG4    0x3B8    /* RW RSSI Parameters */
>> +#define REG_AGC_CFG5    0x3B9    /* RW RSSI & NDEC Parameters */
>> +#define REG_AGC_CFG6    0x3BA    /* RW NDEC Parameters */
>> +#define REG_OCL_CFG1    0x3C4    /* RW OCL System Parameters */
>> +#define REG_IRQ1_EN0    0x3C7    /* RW Interrupt Mask set bits for
>> IRQ1 */
>> +#define REG_IRQ1_EN1    0x3C8    /* RW Interrupt Mask set bits for
>> IRQ1 */
>> +#define REG_IRQ2_EN0    0x3C9    /* RW Interrupt Mask set bits for
>> IRQ2 */
>> +#define REG_IRQ2_EN1    0x3CA    /* RW Interrupt Mask set bits for
>> IRQ2 */
>> +#define REG_IRQ1_SRC0    0x3CB    /* RW Interrupt Source bits for IRQ */
>> +#define REG_IRQ1_SRC1    0x3CC    /* RW Interrupt Source bits for IRQ */
>> +#define REG_OCL_BW0    0x3D2    /* RW OCL System Parameters */
>> +#define REG_OCL_BW1    0x3D3    /* RW OCL System Parameters */
>> +#define REG_OCL_BW2    0x3D4    /* RW OCL System Parameters */
>> +#define REG_OCL_BW3    0x3D5    /* RW OCL System Parameters */
>> +#define REG_OCL_BW4    0x3D6    /* RW OCL System Parameters */
>> +#define REG_OCL_BWS    0x3D7    /* RW OCL System Parameters */
>> +#define REG_OCL_CFG13    0x3E0    /* RW OCL System Parameters */
>> +#define REG_GP_DRV    0x3E3    /* RW I/O pads Configuration and bg
>> trim */
>> +#define REG_BM_CFG    0x3E6    /* RW Batt. Monitor Threshold Voltage
>> setting */
>> +#define REG_SFD_15_4    0x3F4    /* RW Option to set non standard SFD */
>> +#define REG_AFC_CFG    0x3F7    /* RW AFC mode and polarity */
>> +#define REG_AFC_KI_KP    0x3F8    /* RW AFC ki and kp */
>> +#define REG_AFC_RANGE    0x3F9    /* RW AFC range */
>> +#define REG_AFC_READ    0x3FA    /* RW Readback frequency error */
>> +
>> +/* REG_EXTPA_MSC */
>> +#define PA_PWR(x)        (((x) & 0xF) << 4)
>> +#define EXTPA_BIAS_SRC        BIT(3)
>> +#define EXTPA_BIAS_MODE(x)    (((x) & 0x7) << 0)
>> +
>> +/* REG_PA_CFG */
>> +#define PA_BRIDGE_DBIAS(x)    (((x) & 0x1F) << 0)
>> +
>> +/* REG_PA_BIAS */
>> +#define PA_BIAS_CTRL(x)        (((x) & 0x1F) << 1)
>> +#define REG_PA_BIAS_DFL        BIT(0)
>> +
>> +#define REG_PAN_ID0        0x112
>> +#define REG_PAN_ID1        0x113
>> +#define REG_SHORT_ADDR_0    0x114
>> +#define REG_SHORT_ADDR_1    0x115
>> +#define REG_IEEE_ADDR_0        0x116
>> +#define REG_IEEE_ADDR_1        0x117
>> +#define REG_IEEE_ADDR_2        0x118
>> +#define REG_IEEE_ADDR_3        0x119
>> +#define REG_IEEE_ADDR_4        0x11A
>> +#define REG_IEEE_ADDR_5        0x11B
>> +#define REG_IEEE_ADDR_6        0x11C
>> +#define REG_IEEE_ADDR_7        0x11D
>> +#define REG_FFILT_CFG        0x11E
>> +#define REG_AUTO_CFG        0x11F
>> +#define REG_AUTO_TX1        0x120
>> +#define REG_AUTO_TX2        0x121
>> +#define REG_AUTO_STATUS        0x122
>> +
>> +/* REG_FFILT_CFG */
>> +#define ACCEPT_BEACON_FRAMES   BIT(0)
>> +#define ACCEPT_DATA_FRAMES     BIT(1)
>> +#define ACCEPT_ACK_FRAMES      BIT(2)
>> +#define ACCEPT_MACCMD_FRAMES   BIT(3)
>> +#define ACCEPT_RESERVED_FRAMES BIT(4)
>> +#define ACCEPT_ALL_ADDRESS     BIT(5)
>> +
>> +/* REG_AUTO_CFG */
>> +#define AUTO_ACK_FRAMEPEND     BIT(0)
>> +#define IS_PANCOORD           BIT(1)
>> +#define RX_AUTO_ACK_EN           BIT(3)
>> +#define CSMA_CA_RX_TURNAROUND  BIT(4)
>> +
>> +/* REG_AUTO_TX1 */
>> +#define MAX_FRAME_RETRIES(x)   ((x) & 0xF)
>> +#define MAX_CCA_RETRIES(x)     (((x) & 0x7) << 4)
>> +
>> +/* REG_AUTO_TX2 */
>> +#define CSMA_MAX_BE(x)           ((x) & 0xF)
>> +#define CSMA_MIN_BE(x)           (((x) & 0xF) << 4)
>> +
>> +#define CMD_SPI_NOP        0xFF /* No operation. Use for dummy writes */
>> +#define CMD_SPI_PKT_WR        0x10 /* Write telegram to the Packet RAM
>> +                      * starting from the TX packet base address
>> +                      * pointer tx_packet_base
>> +                      */
>> +#define CMD_SPI_PKT_RD        0x30 /* Read telegram from the Packet RAM
>> +                      * starting from RX packet base address
>> +                      * pointer rxpb.rx_packet_base
>> +                      */
>> +#define CMD_SPI_MEM_WR(x)    (0x18 + (x >> 8)) /* Write data to MCR or
>> +                           * Packet RAM sequentially
>> +                           */
>> +#define CMD_SPI_MEM_RD(x)    (0x38 + (x >> 8)) /* Read data from MCR or
>> +                           * Packet RAM sequentially
>> +                           */
>> +#define CMD_SPI_MEMR_WR(x)    (0x08 + (x >> 8)) /* Write data to MCR
>> or Packet
>> +                           * RAM as random block
>> +                           */
>> +#define CMD_SPI_MEMR_RD(x)    (0x28 + (x >> 8)) /* Read data from MCR or
>> +                           * Packet RAM random block
>> +                           */
>> +#define CMD_SPI_PRAM_WR        0x1E /* Write data sequentially to
>> current
>> +                      * PRAM page selected
>> +                      */
>> +#define CMD_SPI_PRAM_RD        0x3E /* Read data sequentially from
>> current
>> +                      * PRAM page selected
>> +                      */
>> +#define CMD_RC_SLEEP        0xB1 /* Invoke transition of radio
>> controller
>> +                      * into SLEEP state
>> +                      */
>> +#define CMD_RC_IDLE        0xB2 /* Invoke transition of radio controller
>> +                      * into IDLE state
>> +                      */
>> +#define CMD_RC_PHY_RDY        0xB3 /* Invoke transition of radio
>> controller
>> +                      * into PHY_RDY state
>> +                      */
>> +#define CMD_RC_RX        0xB4 /* Invoke transition of radio controller
>> +                      * into RX state
>> +                      */
>> +#define CMD_RC_TX        0xB5 /* Invoke transition of radio controller
>> +                      * into TX state
>> +                      */
>> +#define CMD_RC_MEAS        0xB6 /* Invoke transition of radio controller
>> +                      * into MEAS state
>> +                      */
>> +#define CMD_RC_CCA        0xB7 /* Invoke Clear channel assessment */
>> +#define CMD_RC_CSMACA        0xC1 /* initiates CSMA-CA channel access
>> +                      * sequence and frame transmission
>> +                      */
>> +#define CMD_RC_PC_RESET        0xC7 /* Program counter reset */
>> +#define CMD_RC_RESET        0xC8 /* Resets the ADF7242 and puts it in
>> +                      * the sleep state
>> +                      */
>> +
>> +/* STATUS */
>> +
>> +#define STAT_SPI_READY        BIT(7)
>> +#define STAT_IRQ_STATUS        BIT(6)
>> +#define STAT_RC_READY        BIT(5)
>> +#define STAT_CCA_RESULT        BIT(4)
>> +#define RC_STATUS_IDLE        1
>> +#define RC_STATUS_MEAS        2
>> +#define RC_STATUS_PHY_RDY    3
>> +#define RC_STATUS_RX        4
>> +#define RC_STATUS_TX        5
>> +#define RC_STATUS_MASK        0xF
>> +
>> +/* AUTO_STATUS */
>> +
>> +#define SUCCESS            0
>> +#define SUCCESS_DATPEND        1
>> +#define FAILURE_CSMACA        2
>> +#define FAILURE_NOACK        3
>> +#define AUTO_STATUS_MASK    0x3
>> +
>> +#define PRAM_PAGESIZE        256
>> +
>> +/* IRQ1 */
>> +
>> +#define IRQ_CCA_COMPLETE    BIT(0)
>> +#define IRQ_SFD_RX        BIT(1)
>> +#define IRQ_SFD_TX        BIT(2)
>> +#define IRQ_RX_PKT_RCVD        BIT(3)
>> +#define IRQ_TX_PKT_SENT        BIT(4)
>> +#define IRQ_FRAME_VALID        BIT(5)
>> +#define IRQ_ADDRESS_VALID    BIT(6)
>> +#define IRQ_CSMA_CA        BIT(7)
>> +
>> +#define AUTO_TX_TURNAROUND    BIT(3)
>> +#define ADDON_EN        BIT(4)
>> +
>> +struct adf7242_local {
>> +    struct spi_device *spi;
>> +    struct completion tx_complete;
>> +    struct ieee802154_hw *hw;
>> +    struct mutex bmux; /* protect SPI messages */
>> +    struct spi_message stat_msg;
>> +    struct spi_transfer stat_xfer;
>> +    int tx_stat;
>> +    s8 rssi;
>> +    u8 max_frame_retries;
>> +    u8 max_cca_retries;
>> +
>> +    /* DMA (thus cache coherency maintenance) requires the
>> +     * transfer buffers to live in their own cache lines.
>> +     */
>> +
>> +    u8 buf[3] ____cacheline_aligned;
>> +    u8 buf_reg_tx[3];
>> +    u8 buf_read_tx[4];
>> +    u8 buf_read_rx[4];
>> +    u8 buf_stat_rx;
>> +    u8 buf_stat_tx;
>> +    u8 buf_cmd;
>> +};
>> +
>> +static int adf7242_status(struct adf7242_local *lp, u8 *stat)
>> +{
>> +    int status;
>> +
>> +    mutex_lock(&lp->bmux);
>> +    status = spi_sync(lp->spi, &lp->stat_msg);
>> +    *stat = lp->buf_stat_rx;
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_wait_ready(struct adf7242_local *lp, int line)
>> +{
>> +    int cnt = 0, ret = 0;
>> +    u8 stat;
>> +
>> +    do {
>> +        adf7242_status(lp, &stat);
>> +        cnt++;
>> +    } while (!((stat & STAT_RC_READY) && (stat & STAT_SPI_READY)) &&
>> +        (cnt < MAX_POLL_LOOPS));
>> +
>> +    if (cnt >= MAX_POLL_LOOPS) {
>> +        dev_warn(&lp->spi->dev, "%s:line %d Timeout\n", __func__, line);
>> +        ret = -ETIMEDOUT;
>> +    }
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
>> +
>> +    return ret;
>> +}
>> +
>> +static int adf7242_wait_status(struct adf7242_local *lp, int status,
>> int line)
>> +{
>> +    int cnt = 0, ret = 0;
>> +    u8 stat;
>> +
>> +    do {
>> +        adf7242_status(lp, &stat);
>> +        stat &= RC_STATUS_MASK;
>> +        cnt++;
>> +    } while ((stat != status) && (cnt < MAX_POLL_LOOPS));
>> +
>> +    if (cnt >= MAX_POLL_LOOPS) {
>> +        dev_warn(&lp->spi->dev, "%s:line %d Timeout status 0x%x\n",
>> +             __func__, line, stat);
>> +        ret = -ETIMEDOUT;
>> +    }
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : loops=%d\n", __func__, cnt);
>> +
>> +    return ret;
>> +}
>> +
>> +static int adf7242_write_fbuf(struct adf7242_local *lp, u8 *data, u8
>> len)
>> +{
>> +    u8 *buf = lp->buf;
>> +    int status;
>> +    struct spi_message msg;
>> +    struct spi_transfer xfer_head = {
>> +        .len = 2,
>> +        .tx_buf = buf,
>> +
>> +    };
>> +    struct spi_transfer xfer_buf = {
>> +        .len = len,
>> +        .tx_buf = data,
>> +    };
>> +
>> +    spi_message_init(&msg);
>> +    spi_message_add_tail(&xfer_head, &msg);
>> +    spi_message_add_tail(&xfer_buf, &msg);
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    buf[0] = CMD_SPI_PKT_WR;
>> +    buf[1] = len + 2;
>> +
>> +    status = spi_sync(lp->spi, &msg);
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_read_fbuf(struct adf7242_local *lp,
>> +                 u8 *data, size_t len, bool packet_read)
>> +{
>> +    u8 *buf = lp->buf;
>> +    int status;
>> +    struct spi_message msg;
>> +    struct spi_transfer xfer_head = {
>> +        .len = 3,
>> +        .tx_buf = buf,
>> +        .rx_buf = buf,
>> +    };
>> +    struct spi_transfer xfer_buf = {
>> +        .len = len,
>> +        .rx_buf = data,
>> +    };
>> +
>> +    spi_message_init(&msg);
>> +    spi_message_add_tail(&xfer_head, &msg);
>> +    spi_message_add_tail(&xfer_buf, &msg);
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    if (packet_read) {
>> +        buf[0] = CMD_SPI_PKT_RD;
>> +        buf[1] = CMD_SPI_NOP;
>> +        buf[2] = 0;    /* PHR */
>> +    } else {
>> +        buf[0] = CMD_SPI_PRAM_RD;
>> +        buf[1] = 0;
>> +        buf[2] = CMD_SPI_NOP;
>> +    }
>> +
>> +    status = spi_sync(lp->spi, &msg);
>> +
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_read_reg(struct adf7242_local *lp, u16 addr, u8
>> *data)
>> +{
>> +    int status;
>> +    struct spi_message msg;
>> +
>> +    struct spi_transfer xfer = {
>> +        .len = 4,
>> +        .tx_buf = lp->buf_read_tx,
>> +        .rx_buf = lp->buf_read_rx,
>> +    };
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    lp->buf_read_tx[0] = CMD_SPI_MEM_RD(addr);
>> +    lp->buf_read_tx[1] = addr;
>> +    lp->buf_read_tx[2] = CMD_SPI_NOP;
>> +    lp->buf_read_tx[3] = CMD_SPI_NOP;
>> +
>> +    spi_message_init(&msg);
>> +    spi_message_add_tail(&xfer, &msg);
>> +
>> +    status = spi_sync(lp->spi, &msg);
>> +    if (msg.status)
>> +        status = msg.status;
>> +
>> +    if (!status)
>> +        *data = lp->buf_read_rx[3];
>> +
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n", __func__,
>> +         addr, *data);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_write_reg(struct adf7242_local *lp, u16 addr, u8
>> data)
>> +{
>> +    int status;
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    lp->buf_reg_tx[0] = CMD_SPI_MEM_WR(addr);
>> +    lp->buf_reg_tx[1] = addr;
>> +    lp->buf_reg_tx[2] = data;
>> +    status = spi_write(lp->spi, lp->buf_reg_tx, 3);
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n",
>> +         __func__, addr, data);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_cmd(struct adf7242_local *lp, u8 cmd)
>> +{
>> +    int status;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : CMD=0x%X\n", __func__, cmd);
>> +
>> +    adf7242_wait_ready(lp, __LINE__);
>> +
>> +    mutex_lock(&lp->bmux);
>> +    lp->buf_cmd = cmd;
>> +    status = spi_write(lp->spi, &lp->buf_cmd, 1);
>> +    mutex_unlock(&lp->bmux);
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_upload_firmware(struct adf7242_local *lp, u8
>> *data, u16 len)
>> +{
>> +    struct spi_message msg;
>> +    struct spi_transfer xfer_buf = { };
>> +    int status, i, page = 0;
>> +    u8 *buf = lp->buf;
>> +
>> +    struct spi_transfer xfer_head = {
>> +        .len = 2,
>> +        .tx_buf = buf,
>> +    };
>> +
>> +    buf[0] = CMD_SPI_PRAM_WR;
>> +    buf[1] = 0;
>> +
>> +    spi_message_init(&msg);
>> +    spi_message_add_tail(&xfer_head, &msg);
>> +    spi_message_add_tail(&xfer_buf, &msg);
>> +
>> +    for (i = len; i >= 0; i -= PRAM_PAGESIZE) {
>> +        adf7242_write_reg(lp, REG_PRAMPG, page);
>> +
>> +        xfer_buf.len = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
>> +        xfer_buf.tx_buf = &data[page * PRAM_PAGESIZE];
>> +
>> +        mutex_lock(&lp->bmux);
>> +        status = spi_sync(lp->spi, &msg);
>> +        mutex_unlock(&lp->bmux);
>> +        page++;
>> +    }
>> +
>> +    return status;
>> +}
>> +
>> +static int adf7242_verify_firmware(struct adf7242_local *lp,
>> +                   const u8 *data, size_t len)
>
> Could it really happen that we upload the firmware, getting fine status
> codes back from spi_sync and this have a broken firmware in ram? To me
> it looks like a safety measure for something that should never happen.
> But I don't know the hardware.

It's a safety measure and should never happen.
I've added it while working with some broken SPI master driver some time 
ago. I can remove it.


>> +{
>> +    int i, j;
>> +    unsigned int page;
>> +    u8 *buf = kmalloc(PRAM_PAGESIZE, GFP_KERNEL);
>> +
>> +    if (!buf)
>> +        return -ENOMEM;
>> +
>> +    for (page = 0, i = len; i >= 0; i -= PRAM_PAGESIZE, page++) {
>> +        size_t nb = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i;
>> +
>> +        adf7242_write_reg(lp, REG_PRAMPG, page);
>> +        adf7242_read_fbuf(lp, buf, nb, false);
>> +
>> +        for (j = 0; j < nb; j++) {
>> +            if (buf[j] != data[page * PRAM_PAGESIZE + j]) {
>> +                kfree(buf);
>> +                return -EIO;
>> +            }
>> +        }
>> +    }
>> +    kfree(buf);
>> +
>> +    return 0;
>> +}
>> +
>> +static int adf7242_set_txpower(struct ieee802154_hw *hw, int mbm)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    u8 pwr, bias_ctrl, dbias, tmp;
>> +    int db = mbm / 100;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : Power %d dB\n", __func__, db);
>> +
>> +    if (db > 5 || db < -26)
>> +        return -EINVAL;
>> +
>> +    db = DIV_ROUND_CLOSEST(db + 29, 2);
>> +
>> +    if (db > 15) {
>> +        dbias = 21;
>> +        bias_ctrl = 63;
>> +    } else {
>> +        dbias = 13;
>> +        bias_ctrl = 55;
>
> What the meaning of the values here? 21, 63, 13, 55

Some BIAS values from the datasheet.
IIRC starting some power level they need to be set differently.

>
>> +    }
>> +
>> +    pwr = clamp_t(u8, db, 3, 15);
>> +
>> +    adf7242_read_reg(lp, REG_PA_CFG, &tmp);
>> +    tmp &= ~PA_BRIDGE_DBIAS(~0);
>> +    tmp |= PA_BRIDGE_DBIAS(dbias);
>> +    adf7242_write_reg(lp, REG_PA_CFG, tmp);
>> +
>> +    adf7242_read_reg(lp, REG_PA_BIAS, &tmp);
>> +    tmp &= ~PA_BIAS_CTRL(~0);
>> +    tmp |= PA_BIAS_CTRL(bias_ctrl);
>> +    adf7242_write_reg(lp, REG_PA_BIAS, tmp);
>> +
>> +    adf7242_read_reg(lp, REG_EXTPA_MSC, &tmp);
>> +    tmp &= ~PA_PWR(~0);
>> +    tmp |= PA_PWR(pwr);
>> +
>> +    return adf7242_write_reg(lp, REG_EXTPA_MSC, tmp);
>> +}
>> +
>> +static int adf7242_set_csma_params(struct ieee802154_hw *hw, u8 min_be,
>> +                   u8 max_be, u8 retries)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    int ret;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : min_be=%d max_be=%d retries=%d\n",
>> +         __func__, min_be, max_be, retries);
>> +
>> +    if (min_be > max_be || max_be > 8 || retries > 5)
>> +        return -EINVAL;
>> +
>> +    ret = adf7242_write_reg(lp, REG_AUTO_TX1,
>> +                MAX_FRAME_RETRIES(lp->max_frame_retries) |
>> +                MAX_CCA_RETRIES(retries));
>> +    if (ret)
>> +        return ret;
>> +
>> +    lp->max_cca_retries = retries;
>> +
>> +    return adf7242_write_reg(lp, REG_AUTO_TX2, CSMA_MAX_BE(max_be) |
>> +            CSMA_MIN_BE(min_be));
>> +}
>> +
>> +static int adf7242_set_frame_retries(struct ieee802154_hw *hw, s8
>> retries)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    int ret = 0;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s : Retries = %d\n", __func__, retries);
>> +
>> +    if (retries < -1 || retries > 15)
>> +        return -EINVAL;
>> +
>> +    if (retries >= 0)
>> +        ret = adf7242_write_reg(lp, REG_AUTO_TX1,
>> +                    MAX_FRAME_RETRIES(retries) |
>> +                    MAX_CCA_RETRIES(lp->max_cca_retries));
>> +
>> +    lp->max_frame_retries = retries;
>> +
>> +    return ret;
>> +}
>> +
>> +static int adf7242_ed(struct ieee802154_hw *hw, u8 *level)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +
>> +    *level = lp->rssi;
>> +
>> +    dev_vdbg(&lp->spi->dev, "%s :Exit level=%d\n",
>> +         __func__, *level);
>> +
>> +    return 0;
>> +}
>> +
>> +static int adf7242_start(struct ieee802154_hw *hw)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +
>> +    adf7242_cmd(lp, CMD_RC_PHY_RDY);
>> +    return adf7242_cmd(lp, CMD_RC_RX);
>> +}
>> +
>> +static void adf7242_stop(struct ieee802154_hw *hw)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +
>> +    adf7242_cmd(lp, CMD_RC_IDLE);
>> +    adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
>> +}
>> +
>> +static int adf7242_channel(struct ieee802154_hw *hw, u8 page, u8
>> channel)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    unsigned long freq;
>> +
>> +    dev_dbg(&lp->spi->dev, "%s :Channel=%d\n", __func__, channel);
>> +
>> +    might_sleep();
>> +
>> +    WARN_ON(page != 0);
>> +    WARN_ON(channel < 11);
>> +    WARN_ON(channel > 26);
>> +
>> +    freq = (2405 + 5 * (channel - 11)) * 100;
>> +    adf7242_cmd(lp, CMD_RC_PHY_RDY);
>> +
>> +    adf7242_write_reg(lp, REG_CH_FREQ0, freq);
>> +    adf7242_write_reg(lp, REG_CH_FREQ1, freq >> 8);
>> +    adf7242_write_reg(lp, REG_CH_FREQ2, freq >> 16);
>> +
>> +    return adf7242_cmd(lp, CMD_RC_RX);
>> +}
>> +
>> +static int adf7242_set_hw_addr_filt(struct ieee802154_hw *hw,
>> +                    struct ieee802154_hw_addr_filt *filt,
>> +                    unsigned long changed)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    u8 reg;
>> +
>> +    dev_dbg(&lp->spi->dev, "%s :Changed=0x%lX\n", __func__, changed);
>> +
>> +    might_sleep();
>> +
>> +    if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
>> +        u8 addr[8], i;
>> +
>> +        memcpy(addr, &filt->ieee_addr, 8);
>> +
>> +        for (i = 0; i < 8; i++)
>> +            adf7242_write_reg(lp, REG_IEEE_ADDR_0 + i, addr[i]);
>> +    }
>> +
>> +    if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
>> +        u16 saddr = le16_to_cpu(filt->short_addr);
>> +
>> +        adf7242_write_reg(lp, REG_SHORT_ADDR_0, saddr);
>> +        adf7242_write_reg(lp, REG_SHORT_ADDR_1, saddr >> 8);
>> +    }
>> +
>> +    if (changed & IEEE802154_AFILT_PANID_CHANGED) {
>> +        u16 pan_id = le16_to_cpu(filt->pan_id);
>> +
>> +        adf7242_write_reg(lp, REG_PAN_ID0, pan_id);
>> +        adf7242_write_reg(lp, REG_PAN_ID1, pan_id >> 8);
>> +    }
>> +
>> +    if (changed & IEEE802154_AFILT_PANC_CHANGED) {
>> +        adf7242_read_reg(lp, REG_AUTO_CFG, &reg);
>> +        if (filt->pan_coord)
>> +            reg |= IS_PANCOORD;
>> +        else
>> +            reg &= ~IS_PANCOORD;
>> +        adf7242_write_reg(lp, REG_AUTO_CFG, reg);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int adf7242_set_promiscuous_mode(struct ieee802154_hw *hw,
>> bool on)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +
>> +    dev_dbg(&lp->spi->dev, "%s : mode %d\n", __func__, on);
>> +
>> +    if (on) {
>> +        adf7242_write_reg(lp, REG_AUTO_CFG, 0);
>> +        return adf7242_write_reg(lp, REG_FFILT_CFG,
>> +                  ACCEPT_BEACON_FRAMES |
>> +                  ACCEPT_DATA_FRAMES |
>> +                  ACCEPT_MACCMD_FRAMES |
>> +                  ACCEPT_ALL_ADDRESS |
>> +                  ACCEPT_ACK_FRAMES |
>> +                  ACCEPT_RESERVED_FRAMES);
>> +    } else {
>> +        adf7242_write_reg(lp, REG_FFILT_CFG,
>> +                  ACCEPT_BEACON_FRAMES |
>> +                  ACCEPT_DATA_FRAMES |
>> +                  ACCEPT_MACCMD_FRAMES |
>> +                  ACCEPT_RESERVED_FRAMES);
>> +
>> +        return adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
>> +    }
>> +}
>> +
>> +static int adf7242_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    s8 level = clamp_t(s8, mbm / 100, S8_MIN, S8_MAX);
>> +
>> +    dev_dbg(&lp->spi->dev, "%s : level %d\n", __func__, level);
>> +
>> +    return adf7242_write_reg(lp, REG_CCA1, level);
>> +}
>> +
>> +static int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
>> +{
>> +    struct adf7242_local *lp = hw->priv;
>> +    int ret;
>> +
>> +    reinit_completion(&lp->tx_complete);
>> +
>> +    ret = adf7242_write_fbuf(lp, skb->data, skb->len);
>> +    if (ret)
>> +        goto err;
>> +
>> +    ret = adf7242_cmd(lp, CMD_RC_PHY_RDY);
>> +    ret |= adf7242_cmd(lp, CMD_RC_CSMACA);
>> +
>> +    if (ret)
>> +        goto err;
>> +
>> +    ret = wait_for_completion_interruptible_timeout(&lp->tx_complete,
>> HZ);
>> +    if (ret == -ERESTARTSYS)
>> +        goto err;
>> +    if (ret == 0) {
>> +        dev_warn(&lp->spi->dev, "Timeout waiting for TX interrupt\n");
>> +        ret = -ETIMEDOUT;
>> +        goto err;
>> +    }
>> +
>> +    if (lp->tx_stat != SUCCESS) {
>> +        dev_warn(&lp->spi->dev,
>> +             "Error xmit: Retry count exceeded Status=0x%x\n",
>> +             lp->tx_stat);
>> +        ret = -ECOMM;
>> +    } else {
>> +        ret = 0;
>> +    }
>> +
>> +err:
>> +    adf7242_cmd(lp, CMD_RC_RX);
>> +    return ret;
>> +}
>> +
>> +static int adf7242_rx(struct adf7242_local *lp)
>> +{
>> +    struct sk_buff *skb;
>> +    size_t len;
>> +    int ret;
>> +    u8 lqi, len_u8, *data;
>> +
>> +    adf7242_read_reg(lp, 0, &len_u8);
>> +
>> +    len = len_u8;
>> +
>> +    if (!ieee802154_is_valid_psdu_len(len)) {
>> +        dev_dbg(&lp->spi->dev,
>> +            "corrupted frame received len %d\n", len);
>> +        len = IEEE802154_MTU;
>> +    }
>> +
>> +    skb = dev_alloc_skb(len);
>> +    if (!skb)
>> +        return -ENOMEM;
>> +
>> +    data = skb_put(skb, len);
>> +    ret = adf7242_read_fbuf(lp, data, len, true);
>> +
>> +    if (!ret) {
>> +        lqi = data[len - 2];
>> +        lp->rssi = data[len - 1];
>> +    }
>> +
>> +    adf7242_cmd(lp, CMD_RC_RX);
>> +
>> +    skb_trim(skb, len - 2);    /* Don't put RSSI/LQI or CRC into the
>> frame */
>> +
>> +    ieee802154_rx_irqsafe(lp->hw, skb, lqi);
>> +
>> +    dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n",
>> +        __func__, ret, len, lqi, lp->rssi);
>> +
>> +    return 0;
>> +}
>> +
>> +static struct ieee802154_ops adf7242_ops = {
>> +    .owner = THIS_MODULE,
>> +    .xmit_sync = adf7242_xmit,
>> +    .ed = adf7242_ed,
>> +    .set_channel = adf7242_channel,
>> +    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
>> +    .start = adf7242_start,
>> +    .stop = adf7242_stop,
>> +    .set_csma_params = adf7242_set_csma_params,
>> +    .set_frame_retries = adf7242_set_frame_retries,
>> +    .set_txpower = adf7242_set_txpower,
>> +    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
>> +    .set_cca_ed_level = adf7242_set_cca_ed_level,
>
> Nice to see so many callbacks implemented. The only things I see missing
> is xmit_async, set_lbt and set_cca_mode. I would not make it a
> requirements to get these hooked up before merging this patch but we
> should consider it as todo items.

The part only supports CCA mode Energy above threshold.
Not sure what this LBT mode does on the AT86RFxxx driver.
The ADF7242 only supports CSMA-CA and not some other listen before talk 
flavour. The only oher option is to turn CSMA-CA completly off.
I'm also not sure if we need to supprot the async mode, while the sync 
mode is working. For me the async mode looks like it tries to workaround 
some HW access issues.



>
>> +};
>> +
>> +static irqreturn_t adf7242_isr(int irq, void *data)
>> +{
>> +    struct adf7242_local *lp = data;
>> +    u8 irq1, auto_stat = 0, stat = 0, rx_en = 0;
>> +
>> +    adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
>> +    adf7242_write_reg(lp, REG_IRQ1_SRC1, irq1);
>> +
>> +    if (!(irq1 & (IRQ_RX_PKT_RCVD | IRQ_CSMA_CA)))
>> +        dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n",
>> +            __func__, irq1);
>> +
>> +    dev_dbg(&lp->spi->dev, "%s IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n",
>> +        __func__, irq1,
>> +        irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
>> +        irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
>> +        irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
>> +        irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
>> +        irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
>> +        irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
>> +        irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
>> +        irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
>> +
>> +    adf7242_status(lp, &stat);
>> +
>> +    dev_dbg(&lp->spi->dev, "%s STATUS = %X:\n%s\n%s%s%s%s%s\n",
>> +        __func__, stat,
>> +        stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
>> +        (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
>> +        (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
>> +        (stat & 0xf) == RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
>> +        (stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
>> +        (stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
>> +
>> +    if ((irq1 & IRQ_RX_PKT_RCVD) && (irq1 & IRQ_FRAME_VALID)) {
>> +        /* Wait until ACK is processed */
>> +        if ((stat & RC_STATUS_MASK) != RC_STATUS_PHY_RDY)
>> +            adf7242_wait_status(lp, RC_STATUS_PHY_RDY, __LINE__);
>> +
>> +        adf7242_rx(lp);
>> +        rx_en = 1;
>> +    }
>> +
>> +    if (irq1 & IRQ_CSMA_CA) {
>> +        adf7242_read_reg(lp, REG_AUTO_STATUS, &auto_stat);
>> +        auto_stat &= AUTO_STATUS_MASK;
>> +
>> +        dev_dbg(&lp->spi->dev, "%s AUTO_STATUS = %X:\n%s%s%s%s\n",
>> +            __func__, auto_stat,
>> +            auto_stat == SUCCESS ? "SUCCESS" : "",
>> +            auto_stat ==
>> +            SUCCESS_DATPEND ? "SUCCESS_DATPEND" : "",
>> +            auto_stat == FAILURE_CSMACA ? "FAILURE_CSMACA" : "",
>> +            auto_stat == FAILURE_NOACK ? "FAILURE_NOACK" : "");
>> +
>> +        /* save CSMA-CA completion status */
>> +        lp->tx_stat = auto_stat;
>> +        rx_en = 1;
>> +
>> +        complete(&lp->tx_complete);
>> +    }
>> +
>> +    if (!rx_en)
>> +        adf7242_cmd(lp, CMD_RC_RX);
>> +
>> +    return IRQ_HANDLED;
>> +}
>> +
>> +static int adf7242_hw_init(struct adf7242_local *lp)
>> +{
>> +    int ret;
>> +    const struct firmware *fw;
>> +
>> +    adf7242_cmd(lp, CMD_RC_RESET);
>> +    adf7242_cmd(lp, CMD_RC_IDLE);
>> +
>> +    /* get ADF7242 addon firmware
>> +     * build this driver as module
>
> Hmm, this brings up the question if the firmware is also fetched if the
> driver is built into the kernel directly?


Compile firmware blob into the kernel.


>> +     * and place under /lib/firmware/adf7242_firmware.bin
>> +     */
>> +    ret = request_firmware(&fw, FIRMWARE, &lp->spi->dev);
>> +    if (ret) {
>> +        dev_err(&lp->spi->dev,
>> +            "request_firmware() failed with %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    ret = adf7242_upload_firmware(lp, (u8 *)fw->data, fw->size);
>> +    if (ret) {
>> +        dev_err(&lp->spi->dev,
>> +            "upload firmware failed with %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    ret = adf7242_verify_firmware(lp, (u8 *)fw->data, fw->size);
>> +    if (ret) {
>> +        dev_err(&lp->spi->dev,
>> +            "verify firmware failed with %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    adf7242_cmd(lp, CMD_RC_PC_RESET);
>> +
>> +    release_firmware(fw);
>> +
>> +    adf7242_write_reg(lp, REG_FFILT_CFG,
>> +              ACCEPT_BEACON_FRAMES |
>> +              ACCEPT_DATA_FRAMES |
>> +              ACCEPT_MACCMD_FRAMES |
>> +              ACCEPT_RESERVED_FRAMES);
>> +
>> +    adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN);
>> +
>> +    adf7242_write_reg(lp, REG_PKT_CFG, ADDON_EN | BIT(2));
>> +
>> +    adf7242_write_reg(lp, REG_EXTPA_MSC, 0xF1);
>> +    adf7242_write_reg(lp, REG_RXFE_CFG, 0x1D);
>> +
>> +    adf7242_write_reg(lp, REG_IRQ1_EN0, 0);
>> +    adf7242_write_reg(lp, REG_IRQ1_EN1, IRQ_RX_PKT_RCVD | IRQ_CSMA_CA);
>> +
>> +    adf7242_write_reg(lp, REG_IRQ1_SRC1, 0xFF);
>> +    adf7242_write_reg(lp, REG_IRQ1_SRC0, 0xFF);
>> +
>> +    adf7242_cmd(lp, CMD_RC_IDLE);
>> +
>> +    return 0;
>> +}
>> +
>> +static ssize_t adf7242_show(struct device *dev,
>> +                struct device_attribute *devattr, char *buf)
>> +{
>> +    struct adf7242_local *lp = dev_get_drvdata(dev);
>> +    u8 stat, irq1;
>> +    size_t len;
>> +
>> +    adf7242_status(lp, &stat);
>> +
>> +    adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1);
>> +
>> +    len = sprintf(buf, "IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n", irq1,
>> +              irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "",
>> +              irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "",
>> +              irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "",
>> +              irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "",
>> +              irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "",
>> +              irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "",
>> +              irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "",
>> +              irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : "");
>> +
>> +    len += sprintf(buf + len, "STATUS = %X:\n%s\n%s%s%s%s%s\n", stat,
>> +               stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY",
>> +               (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "",
>> +               (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "",
>> +               (stat & 0xf) ==
>> +                RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "",
>> +               (stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "",
>> +               (stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : "");
>> +
>> +    len += sprintf(buf + len, "RSSI = %d\n", lp->rssi);
>> +
>> +    return len;
>> +}
>> +static DEVICE_ATTR(status, 0664, adf7242_show, NULL);
>
> The show function and its sysfs entry shoudl go into debugfs, no? Having
> a sysfs entry here make sit a kernel ABI which we cannot change later
> and it looks like debugging only to me.


See question below - ok - I'll more this into debugfs.


>
>> +
>> +static const s32 adf7242_powers[] = {
>> +    500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600,
>> -700,
>> +    -800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700,
>> +    -1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600,
>> +};
>> +
>> +static const s32 adf7242_ed_levels[] = {
>> +    -9000, -8900, -8800, -8700, -8600, -8500, -8400, -8300, -8200,
>> -8100,
>> +    -8000, -7900, -7800, -7700, -7600, -7500, -7400, -7300, -7200,
>> -7100,
>> +    -7000, -6900, -6800, -6700, -6600, -6500, -6400, -6300, -6200,
>> -6100,
>> +    -6000, -5900, -5800, -5700, -5600, -5500, -5400, -5300, -5200,
>> -5100,
>> +    -5000, -4900, -4800, -4700, -4600, -4500, -4400, -4300, -4200,
>> -4100,
>> +    -4000, -3900, -3800, -3700, -3600, -3500, -3400, -3200, -3100, -3000
>> +};
>> +
>> +static int adf7242_probe(struct spi_device *spi)
>> +{
>> +    struct ieee802154_hw *hw;
>> +    struct adf7242_local *lp;
>> +    int ret, irq_type;
>> +
>> +    if (!spi->irq) {
>> +        dev_err(&spi->dev, "no IRQ specified\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    hw = ieee802154_alloc_hw(sizeof(*lp), &adf7242_ops);
>> +    if (!hw)
>> +        return -ENOMEM;
>> +
>> +    lp = hw->priv;
>> +    lp->hw = hw;
>> +    lp->spi = spi;
>> +
>> +    hw->priv = lp;
>> +    hw->parent = &spi->dev;
>> +    hw->extra_tx_headroom = 0;
>> +
>> +    /* We support only 2.4 Ghz */
>> +    hw->phy->supported.channels[0] = 0x7FFF800;
>> +
>> +    hw->flags = IEEE802154_HW_OMIT_CKSUM |
>> +            IEEE802154_HW_CSMA_PARAMS |
>> +            IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT |
>> +            IEEE802154_HW_PROMISCUOUS;
>> +
>> +    hw->phy->flags = WPAN_PHY_FLAG_TXPOWER |
>> +             WPAN_PHY_FLAG_CCA_ED_LEVEL |
>> +             WPAN_PHY_FLAG_CCA_MODE;
>
> Is this hardware really only supporting the one CCA_MODE?

Yes

>
>> +
>> +    hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY);
>> +
>> +    hw->phy->supported.cca_ed_levels = adf7242_ed_levels;
>> +    hw->phy->supported.cca_ed_levels_size =
>> ARRAY_SIZE(adf7242_ed_levels);
>> +
>> +    hw->phy->cca.mode = NL802154_CCA_ENERGY;
>> +
>> +    hw->phy->supported.tx_powers = adf7242_powers;
>> +    hw->phy->supported.tx_powers_size = ARRAY_SIZE(adf7242_powers);
>> +
>> +    hw->phy->supported.min_minbe = 0;
>> +    hw->phy->supported.max_minbe = 8;
>> +
>> +    hw->phy->supported.min_maxbe = 3;
>> +    hw->phy->supported.max_maxbe = 8;
>> +
>> +    hw->phy->supported.min_frame_retries = 0;
>> +    hw->phy->supported.max_frame_retries = 15;
>> +
>> +    hw->phy->supported.min_csma_backoffs = 0;
>> +    hw->phy->supported.max_csma_backoffs = 5;
>> +
>> +    ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
>> +
>> +    mutex_init(&lp->bmux);
>> +    init_completion(&lp->tx_complete);
>> +
>> +    /* Setup Status Message */
>> +    lp->stat_xfer.len = 1;
>> +    lp->stat_xfer.tx_buf = &lp->buf_stat_tx;
>> +    lp->stat_xfer.rx_buf = &lp->buf_stat_rx;
>> +    lp->buf_stat_tx = CMD_SPI_NOP;
>> +
>> +    spi_message_init(&lp->stat_msg);
>> +    spi_message_add_tail(&lp->stat_xfer, &lp->stat_msg);
>> +
>> +    spi_set_drvdata(spi, lp);
>> +
>> +    ret = adf7242_hw_init(lp);
>> +    if (ret)
>> +        goto err_hw_init;
>> +
>> +    irq_type = irq_get_trigger_type(spi->irq);
>> +    if (!irq_type)
>> +        irq_type = IRQF_TRIGGER_HIGH;
>> +
>> +    ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
>> adf7242_isr,
>> +                    irq_type | IRQF_ONESHOT,
>> +                    dev_name(&spi->dev), lp);
>> +    if (ret)
>> +        goto err_hw_init;
>> +
>> +    ret = ieee802154_register_hw(lp->hw);
>> +    if (ret)
>> +        goto err_hw_init;
>> +
>> +    dev_set_drvdata(&spi->dev, lp);
>> +
>> +    /* move to debugfs, maybe add some helper to ieee802154_ops ? */
>> +    ret = sysfs_create_file(&spi->dev.kobj, &dev_attr_status.attr);
>
> This needs to be decided before we can merge this patch. To me this
> looks a debugfs candiate.

ok

>> +    if (ret)
>> +        goto out;
>> +
>> +    dev_info(&spi->dev, "mac802154 IRQ-%d registered\n", spi->irq);
>> +
>> +    return ret;
>> +
>> +out:
>> +    ieee802154_unregister_hw(lp->hw);
>> +err_hw_init:
>> +    mutex_destroy(&lp->bmux);
>> +    ieee802154_free_hw(lp->hw);
>> +
>> +    return ret;
>> +}
>> +
>> +static int adf7242_remove(struct spi_device *spi)
>> +{
>> +    struct adf7242_local *lp = spi_get_drvdata(spi);
>> +
>> +    sysfs_remove_file(&spi->dev.kobj, &dev_attr_status.attr);
>> +    ieee802154_unregister_hw(lp->hw);
>> +    mutex_destroy(&lp->bmux);
>> +    ieee802154_free_hw(lp->hw);
>> +
>> +    return 0;
>> +}
>> +
>> +static const struct of_device_id adf7242_of_match[] = {
>> +    { .compatible = "adi,adf7242", },
>> +    { },
>> +};
>> +MODULE_DEVICE_TABLE(of, adf7242_of_match);
>> +
>> +static const struct spi_device_id adf7242_device_id[] = {
>> +    { .name = "adf7242", },
>> +    { },
>> +};
>> +MODULE_DEVICE_TABLE(spi, adf7242_device_id);
>> +
>> +static struct spi_driver adf7242_driver = {
>> +    .id_table = adf7242_device_id,
>> +    .driver = {
>> +           .of_match_table = of_match_ptr(adf7242_of_match),
>> +           .name = "adf7242",
>> +           .owner = THIS_MODULE,
>> +           },
>> +    .probe = adf7242_probe,
>> +    .remove = adf7242_remove,
>> +};
>> +
>> +module_spi_driver(adf7242_driver);
>> +
>> +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
>> +MODULE_DESCRIPTION("ADF7242 IEEE802.15.4 Transceiver Driver");
>> +MODULE_LICENSE("GPL");
>
>
> Something worth thinking about might also be the usage of regmap.

Given the number of different spi transaction formats I don't think a 
regmap only approach can work here.
Mixing things will not improve things either. So I prefer it the way it 
is right now.



> After the include fix teh driver compiled fine. I will try to find some
> time connecting my adf7242 module to a pi and giving the driver some
> real testing over the next week.
>
> regards
> Stefan Schmidt
>
>

Thanks for taking the time to review things!
I'll send V2 later this week.

-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 12:18       ` Michael Hennerich
  (?)
@ 2015-12-07 13:25       ` Alexander Aring
  2015-12-07 13:34           ` Michael Hennerich
  2015-12-07 15:08         ` Stefan Schmidt
  -1 siblings, 2 replies; 36+ messages in thread
From: Alexander Aring @ 2015-12-07 13:25 UTC (permalink / raw)
  To: Michael Hennerich; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

Hi,

On Mon, Dec 07, 2015 at 01:18:46PM +0100, Michael Hennerich wrote:
> On 12/07/2015 01:02 PM, Stefan Schmidt wrote:
> >Hello.
> >
> >I found some time at the weekend hooking it up on my raspberry pi.
> >
> >On 04/12/15 13:07, Stefan Schmidt wrote:
> >>Hello.
> >>
> >>On 04/12/15 10:09, michael.hennerich@analog.com wrote:
> >>
> >>>The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
> >>>operating modes. The firmware file is currently made available on the
> >>>ADF7242 wiki page here [1]
> >>
> >>Just being curious here. Is there any way to get the firmware source
> >>and/or compile your own? Its the first hardware for IEEE 802.15.4 I
> >>have seen that have a special firmware for this which triggers my
> >>curiosity. :)
> 
> 
> Unfortunately No - We don't release the firmware assembly code.
> Or the required compiler.
> 
> 
> >>
> >>Anyway, this has not that much to do with the driver review here as it
> >>can obviously go in with the binary firmware. We just need to make
> >>sure to also bring the firmware into the linux-firmware repo in time.
> >>
> >>>[1]
> >>>http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
> >>>
> >
> >There are two firmware zip files listed:
> >ram_lab_7242_2_0_ieee15dot4_full_r5.zip
> ><https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/ram_lab_7242_2_0_ieee15dot4_full_r5.zip>
> >
> >rom_ram_7242_2_0_ieee15dot4_full_r3.zip
> ><https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/rom_ram_7242_2_0_ieee15dot4_full_r3.zip>
> >
> >
> >Both contain a adf7242_firmware.bin file but also some different data
> >file. Which one is the correct one here? Some explanation would be helpful.
> 
> Please use the latest R5 release file. I'll remove the old one soon.
> The older firmware had problems with the back-off exponent randomization.
> 
> 
> >
> >
> >>>[2]
> >>>http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
> >>>
> >>>
> >>>Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
> >>>---
> >>>  .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
> >>>  drivers/net/ieee802154/Kconfig                     |    5 +
> >>>  drivers/net/ieee802154/Makefile                    |    1 +
> >>>  drivers/net/ieee802154/adf7242.c                   | 1183
> >>>++++++++++++++++++++
> >>>  4 files changed, 1207 insertions(+)
> >>>  create mode 100644
> >>>Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
> >>>  create mode 100644 drivers/net/ieee802154/adf7242.c
> >>>
> >>>diff --git
> >>>a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
> >>>b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
> >>>new file mode 100644
> >>>index 0000000..dea5124
> >>>--- /dev/null
> >>>+++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
> >>>@@ -0,0 +1,18 @@
> >>>+* ADF7242 IEEE 802.15.4 *
> >>>+
> >>>+Required properties:
> >>>+  - compatible:        should be "adi,adf7242"
> >>>+  - spi-max-frequency:    maximal bus speed (12.5 MHz)
> >>>+  - reg:        the chipselect index
> >>>+  - interrupts:        the interrupt generated by the device via pin
> >>>IRQ1.
> >>>+            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
> >
> >
> >IRQ1 would be pin7 on the interface connector, right? I'm using this one
> >but I have trouble when transmitting
> 
> Yes IRQ1 is Pin7 on the PMOD connector.
> 
> >
> >adf7242 spi32766.0: Error xmit: Retry count exceeded Status=0x3
> 
> 
> That's failure NOACK. Is there a node on the same channel/PAN which could
> response?
> reading proc/interrupts should show some interrupts in this case...
> 

Stefan, maybe you testing with the ATUSB firmware which going _not_
into RX_AACK_ON. This was one of my lastest changes according to the
ATUSB firmware. Please check that, otherwise the atusb doesn't send
ack frames if ackrequest bit is set after receiving.

- Alex

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 13:25       ` Alexander Aring
@ 2015-12-07 13:34           ` Michael Hennerich
  2015-12-07 15:08         ` Stefan Schmidt
  1 sibling, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-07 13:34 UTC (permalink / raw)
  To: Alexander Aring; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

On 12/07/2015 02:25 PM, Alexander Aring wrote:
> Hi,
>
> On Mon, Dec 07, 2015 at 01:18:46PM +0100, Michael Hennerich wrote:
>> On 12/07/2015 01:02 PM, Stefan Schmidt wrote:
>>> Hello.
>>>
>>> I found some time at the weekend hooking it up on my raspberry pi.
>>>
>>> On 04/12/15 13:07, Stefan Schmidt wrote:
>>>> Hello.
>>>>
>>>> On 04/12/15 10:09, michael.hennerich@analog.com wrote:
>>>>
>>>>> The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
>>>>> operating modes. The firmware file is currently made available on the
>>>>> ADF7242 wiki page here [1]
>>>>
>>>> Just being curious here. Is there any way to get the firmware source
>>>> and/or compile your own? Its the first hardware for IEEE 802.15.4 I
>>>> have seen that have a special firmware for this which triggers my
>>>> curiosity. :)
>>
>>
>> Unfortunately No - We don't release the firmware assembly code.
>> Or the required compiler.
>>
>>
>>>>
>>>> Anyway, this has not that much to do with the driver review here as it
>>>> can obviously go in with the binary firmware. We just need to make
>>>> sure to also bring the firmware into the linux-firmware repo in time.
>>>>
>>>>> [1]
>>>>> http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
>>>>>
>>>
>>> There are two firmware zip files listed:
>>> ram_lab_7242_2_0_ieee15dot4_full_r5.zip
>>> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/ram_lab_7242_2_0_ieee15dot4_full_r5.zip>
>>>
>>> rom_ram_7242_2_0_ieee15dot4_full_r3.zip
>>> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/rom_ram_7242_2_0_ieee15dot4_full_r3.zip>
>>>
>>>
>>> Both contain a adf7242_firmware.bin file but also some different data
>>> file. Which one is the correct one here? Some explanation would be helpful.
>>
>> Please use the latest R5 release file. I'll remove the old one soon.
>> The older firmware had problems with the back-off exponent randomization.
>>
>>
>>>
>>>
>>>>> [2]
>>>>> http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
>>>>>
>>>>>
>>>>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>>>>> ---
>>>>>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>>>>>   drivers/net/ieee802154/Kconfig                     |    5 +
>>>>>   drivers/net/ieee802154/Makefile                    |    1 +
>>>>>   drivers/net/ieee802154/adf7242.c                   | 1183
>>>>> ++++++++++++++++++++
>>>>>   4 files changed, 1207 insertions(+)
>>>>>   create mode 100644
>>>>> Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>>   create mode 100644 drivers/net/ieee802154/adf7242.c
>>>>>
>>>>> diff --git
>>>>> a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>> b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>> new file mode 100644
>>>>> index 0000000..dea5124
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>> @@ -0,0 +1,18 @@
>>>>> +* ADF7242 IEEE 802.15.4 *
>>>>> +
>>>>> +Required properties:
>>>>> +  - compatible:        should be "adi,adf7242"
>>>>> +  - spi-max-frequency:    maximal bus speed (12.5 MHz)
>>>>> +  - reg:        the chipselect index
>>>>> +  - interrupts:        the interrupt generated by the device via pin
>>>>> IRQ1.
>>>>> +            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
>>>
>>>
>>> IRQ1 would be pin7 on the interface connector, right? I'm using this one
>>> but I have trouble when transmitting
>>
>> Yes IRQ1 is Pin7 on the PMOD connector.
>>
>>>
>>> adf7242 spi32766.0: Error xmit: Retry count exceeded Status=0x3
>>
>>
>> That's failure NOACK. Is there a node on the same channel/PAN which could
>> response?
>> reading proc/interrupts should show some interrupts in this case...
>>
>
> Stefan, maybe you testing with the ATUSB firmware which going _not_
> into RX_AACK_ON. This was one of my lastest changes according to the
> ATUSB firmware. Please check that, otherwise the atusb doesn't send
> ack frames if ackrequest bit is set after receiving.

I was wondering where can I buy the ATUSB?
On the pulster page I can't find it.

In general why is the framework not requesting ACKs on all non broadcast 
DATA frames?

There is an option if turned on - it'll also request ACks on broadcasts...

-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-07 13:34           ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-07 13:34 UTC (permalink / raw)
  To: Alexander Aring; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

On 12/07/2015 02:25 PM, Alexander Aring wrote:
> Hi,
>
> On Mon, Dec 07, 2015 at 01:18:46PM +0100, Michael Hennerich wrote:
>> On 12/07/2015 01:02 PM, Stefan Schmidt wrote:
>>> Hello.
>>>
>>> I found some time at the weekend hooking it up on my raspberry pi.
>>>
>>> On 04/12/15 13:07, Stefan Schmidt wrote:
>>>> Hello.
>>>>
>>>> On 04/12/15 10:09, michael.hennerich@analog.com wrote:
>>>>
>>>>> The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
>>>>> operating modes. The firmware file is currently made available on the
>>>>> ADF7242 wiki page here [1]
>>>>
>>>> Just being curious here. Is there any way to get the firmware source
>>>> and/or compile your own? Its the first hardware for IEEE 802.15.4 I
>>>> have seen that have a special firmware for this which triggers my
>>>> curiosity. :)
>>
>>
>> Unfortunately No - We don't release the firmware assembly code.
>> Or the required compiler.
>>
>>
>>>>
>>>> Anyway, this has not that much to do with the driver review here as it
>>>> can obviously go in with the binary firmware. We just need to make
>>>> sure to also bring the firmware into the linux-firmware repo in time.
>>>>
>>>>> [1]
>>>>> http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
>>>>>
>>>
>>> There are two firmware zip files listed:
>>> ram_lab_7242_2_0_ieee15dot4_full_r5.zip
>>> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/ram_lab_7242_2_0_ieee15dot4_full_r5.zip>
>>>
>>> rom_ram_7242_2_0_ieee15dot4_full_r3.zip
>>> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/rom_ram_7242_2_0_ieee15dot4_full_r3.zip>
>>>
>>>
>>> Both contain a adf7242_firmware.bin file but also some different data
>>> file. Which one is the correct one here? Some explanation would be helpful.
>>
>> Please use the latest R5 release file. I'll remove the old one soon.
>> The older firmware had problems with the back-off exponent randomization.
>>
>>
>>>
>>>
>>>>> [2]
>>>>> http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
>>>>>
>>>>>
>>>>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>>>>> ---
>>>>>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>>>>>   drivers/net/ieee802154/Kconfig                     |    5 +
>>>>>   drivers/net/ieee802154/Makefile                    |    1 +
>>>>>   drivers/net/ieee802154/adf7242.c                   | 1183
>>>>> ++++++++++++++++++++
>>>>>   4 files changed, 1207 insertions(+)
>>>>>   create mode 100644
>>>>> Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>>   create mode 100644 drivers/net/ieee802154/adf7242.c
>>>>>
>>>>> diff --git
>>>>> a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>> b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>> new file mode 100644
>>>>> index 0000000..dea5124
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>> @@ -0,0 +1,18 @@
>>>>> +* ADF7242 IEEE 802.15.4 *
>>>>> +
>>>>> +Required properties:
>>>>> +  - compatible:        should be "adi,adf7242"
>>>>> +  - spi-max-frequency:    maximal bus speed (12.5 MHz)
>>>>> +  - reg:        the chipselect index
>>>>> +  - interrupts:        the interrupt generated by the device via pin
>>>>> IRQ1.
>>>>> +            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
>>>
>>>
>>> IRQ1 would be pin7 on the interface connector, right? I'm using this one
>>> but I have trouble when transmitting
>>
>> Yes IRQ1 is Pin7 on the PMOD connector.
>>
>>>
>>> adf7242 spi32766.0: Error xmit: Retry count exceeded Status=0x3
>>
>>
>> That's failure NOACK. Is there a node on the same channel/PAN which could
>> response?
>> reading proc/interrupts should show some interrupts in this case...
>>
>
> Stefan, maybe you testing with the ATUSB firmware which going _not_
> into RX_AACK_ON. This was one of my lastest changes according to the
> ATUSB firmware. Please check that, otherwise the atusb doesn't send
> ack frames if ackrequest bit is set after receiving.

I was wondering where can I buy the ATUSB?
On the pulster page I can't find it.

In general why is the framework not requesting ACKs on all non broadcast 
DATA frames?

There is an option if turned on - it'll also request ACks on broadcasts...

-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 12:47     ` Michael Hennerich
  (?)
@ 2015-12-07 13:53     ` Alexander Aring
  2015-12-08  8:43         ` Michael Hennerich
  -1 siblings, 1 reply; 36+ messages in thread
From: Alexander Aring @ 2015-12-07 13:53 UTC (permalink / raw)
  To: Michael Hennerich; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

Hi,

On Mon, Dec 07, 2015 at 01:47:06PM +0100, Michael Hennerich wrote:
...
> >>+static struct ieee802154_ops adf7242_ops = {
> >>+    .owner = THIS_MODULE,
> >>+    .xmit_sync = adf7242_xmit,
> >>+    .ed = adf7242_ed,
> >>+    .set_channel = adf7242_channel,
> >>+    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
> >>+    .start = adf7242_start,
> >>+    .stop = adf7242_stop,
> >>+    .set_csma_params = adf7242_set_csma_params,
> >>+    .set_frame_retries = adf7242_set_frame_retries,
> >>+    .set_txpower = adf7242_set_txpower,
> >>+    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
> >>+    .set_cca_ed_level = adf7242_set_cca_ed_level,
> >
> >Nice to see so many callbacks implemented. The only things I see missing
> >is xmit_async, set_lbt and set_cca_mode. I would not make it a
> >requirements to get these hooked up before merging this patch but we
> >should consider it as todo items.
> 
> The part only supports CCA mode Energy above threshold.
> Not sure what this LBT mode does on the AT86RFxxx driver.

This is for sub 1Ghz regulations in some country (Japan/Europe) area,
there CSMA/CA accoridng 802.15.4 isn't allowed at sub 1-Ghz, that's why
they introduced LBT.

That reminds me to work on a regulator db, again. :-)

Nevertheless it should not related to 2.4 Ghz global ISM band, so far I
know.

> The ADF7242 only supports CSMA-CA and not some other listen before talk
> flavour. The only oher option is to turn CSMA-CA completly off.

Another thing for ToDo list, add support for turning CSMA-CA handling
complete off, many transceiver has such option.

There exists ways currently to turn off CSMA handling only by choosing
the right backoff exponents, 802.15.4 writes:

Note that if macMinBE is set to zero, collision avoidance will be
disabled during the first iteration of this algorithm.

Okay then another ToDo for wpan-tools would be to make a nice printout
that CSMA is disabled if "macMinBE is set to zero".

> I'm also not sure if we need to supprot the async mode, while the sync mode
> is working. For me the async mode looks like it tries to workaround some HW
> access issues.
> 

We came to the conclusion that "sync" callback is a workaround that
people can use spi_sync. :-)

Ununfortunately the nfc subsystem works also which such sync callback.

Currently working of sync xmit:

 - ieee802154_tx (softirq context, might_sleep() will fail).
    - set parameters schedule workqueue /* queue_work(...) */
      /* sleeping phase */ <-- we lost the context of ieee802154_tx, the
                               locks are not held anymore. Others
                               netdev_ops are possible.
 - ieee802154_xmit_worker will be scheduled <--- Does this still
 						 working if a stop
						 callback was running
						 inside the
						 "sleeping phase"?
    - /* sleeping: wait for completion */ when tx complete is triggered
                                          irq triggered.

With async:

The context of ieee802154_tx will be held until the driver "xmit_async"
callback is done. This callback should call spi_async which cannot be
interrupted until the "last" complete callback is done.

Then a stop callback can occur at the time where the hardware "actually"
transmit the frame. This is a complete async process, there is no "wait
for completion" anymore. The complete replacement would be
"ieee802154_xmit_complete".

Drivers should also disable/enable the tx/rx irq's when doing stop/start,
if possible.

- Alex

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 13:34           ` Michael Hennerich
  (?)
@ 2015-12-07 14:12           ` Alexander Aring
  2015-12-08  8:07               ` Michael Hennerich
  -1 siblings, 1 reply; 36+ messages in thread
From: Alexander Aring @ 2015-12-07 14:12 UTC (permalink / raw)
  To: Michael Hennerich
  Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth, chrisfriedt

On Mon, Dec 07, 2015 at 02:34:29PM +0100, Michael Hennerich wrote:
...
> >Stefan, maybe you testing with the ATUSB firmware which going _not_
> >into RX_AACK_ON. This was one of my lastest changes according to the
> >ATUSB firmware. Please check that, otherwise the atusb doesn't send
> >ack frames if ackrequest bit is set after receiving.
> 
> I was wondering where can I buy the ATUSB?
> On the pulster page I can't find it.
> 

They are all out of stock, everywhere. I cc Werner maybe he will bring
back the atusb again. He do his stuff all open source and a possible
solution would be a Kickstarter project.

Another option would be:

 - Produce your own atusb
 - I know that "Christopher Friedt" produced some, maybe he will give/sell
   some. :-) I cc'ed him here.
 - use the experimental firmware [1] on RZUSBStick [0] support. Basics
   functionality only and not stable such atusb. I ported the firmware
   to this stick, it can be used by atusb driver. The transceiver is a
   different -> at86rf230... and this transceiver we also doesn't
   support by the at86rf230 because it's too different and a huge
   errata.

> In general why is the framework not requesting ACKs on all non broadcast
> DATA frames?
> 
> There is an option if turned on - it'll also request ACks on broadcasts...

I suppose you use the af802154 socket family. I didn't touched the code
and this socket family is full of bugs. We need a replacement for that.

The socket code which I was working is AF_PACKET.

In case of AF_PACKET:

 dgram sockets: extended address and intra_pan communciaton only. The
                AF_PACKET UAPI doesn't offer more address information.
		We do a mapping to this currently, other option would be
		to disable DGRAM on AF_PACKET. It's not possible to send
		broadcast frames with that.
		If you need that, something similar like af802154 should
		be available, but it's currently broken.

 raw sockets:   You can build the mac frame inside userspace with
                complete control fc and address settings. We don't check
		this frame if it's valid. This is not a bug.


and 6LoWPAN:

6LoWPAN doesn't do that, the check should be at [2]. If it's currently
broken at your side?

- Alex

[0] http://www.atmel.com/tools/RZUSBSTICK.aspx
[1] http://alex.my-webspace.org/firmwares/rzusb.bin
    Note: This is temprorary website, I know wpan.cakelab.org is down
    currently and I working already to a DNS solution to redirect
    wpan.cakelab.org -> /alex.my-webspace.org . At the moment it looks
    like the provide has bugs inside his DNS web-frontend configuration
    page. ;-)
[2] http://lxr.free-electrons.com/source/net/ieee802154/6lowpan/tx.c#L220

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 12:18       ` Michael Hennerich
  (?)
  (?)
@ 2015-12-07 14:54       ` Stefan Schmidt
  -1 siblings, 0 replies; 36+ messages in thread
From: Stefan Schmidt @ 2015-12-07 14:54 UTC (permalink / raw)
  To: michael.hennerich, alex.aring, marcel; +Cc: linux-wpan, linux-bluetooth

Hello.

On 07/12/15 13:18, Michael Hennerich wrote:
> On 12/07/2015 01:02 PM, Stefan Schmidt wrote:
>> Hello.
>>
>> I found some time at the weekend hooking it up on my raspberry pi.
>>
>> On 04/12/15 13:07, Stefan Schmidt wrote:
>>> Hello.
>>>
>>> On 04/12/15 10:09, michael.hennerich@analog.com wrote:
>>>
>>>> The ADF7242 requires an add-on firmware for the automatic IEEE 
>>>> 802.15.4
>>>> operating modes. The firmware file is currently made available on the
>>>> ADF7242 wiki page here [1]
>>>
>>> Just being curious here. Is there any way to get the firmware source
>>> and/or compile your own? Its the first hardware for IEEE 802.15.4 I
>>> have seen that have a special firmware for this which triggers my
>>> curiosity. :)
>
>
> Unfortunately No - We don't release the firmware assembly code.
> Or the required compiler.
>

Fair enough.

>
>>>
>>> Anyway, this has not that much to do with the driver review here as it
>>> can obviously go in with the binary firmware. We just need to make
>>> sure to also bring the firmware into the linux-firmware repo in time.
>>>
>>>> [1]
>>>> http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242 
>>>>
>>>>
>>
>> There are two firmware zip files listed:
>> ram_lab_7242_2_0_ieee15dot4_full_r5.zip
>> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/ram_lab_7242_2_0_ieee15dot4_full_r5.zip> 
>>
>>
>> rom_ram_7242_2_0_ieee15dot4_full_r3.zip
>> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/rom_ram_7242_2_0_ieee15dot4_full_r3.zip> 
>>
>>
>>
>> Both contain a adf7242_firmware.bin file but also some different data
>> file. Which one is the correct one here? Some explanation would be 
>> helpful.
>
> Please use the latest R5 release file. I'll remove the old one soon.
> The older firmware had problems with the back-off exponent randomization.
>

OK

>
>>
>>
>>>> [2]
>>>> http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c 
>>>>
>>>>
>>>>
>>>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>>>> ---
>>>>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>>>>   drivers/net/ieee802154/Kconfig                     |    5 +
>>>>   drivers/net/ieee802154/Makefile                    |    1 +
>>>>   drivers/net/ieee802154/adf7242.c                   | 1183
>>>> ++++++++++++++++++++
>>>>   4 files changed, 1207 insertions(+)
>>>>   create mode 100644
>>>> Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>   create mode 100644 drivers/net/ieee802154/adf7242.c
>>>>
>>>> diff --git
>>>> a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>> b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>> new file mode 100644
>>>> index 0000000..dea5124
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>> @@ -0,0 +1,18 @@
>>>> +* ADF7242 IEEE 802.15.4 *
>>>> +
>>>> +Required properties:
>>>> +  - compatible:        should be "adi,adf7242"
>>>> +  - spi-max-frequency:    maximal bus speed (12.5 MHz)
>>>> +  - reg:        the chipselect index
>>>> +  - interrupts:        the interrupt generated by the device via pin
>>>> IRQ1.
>>>> +            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
>>
>>
>> IRQ1 would be pin7 on the interface connector, right? I'm using this one
>> but I have trouble when transmitting
>
> Yes IRQ1 is Pin7 on the PMOD connector.
>

Good, so my wiring was ok.

>>
>> adf7242 spi32766.0: Error xmit: Retry count exceeded Status=0x3
>
>
> That's failure NOACK. Is there a node on the same channel/PAN which 
> could response?
> reading proc/interrupts should show some interrupts in this case...
>

Turns out it was a failure on the configuration side of the other node. :/
I had security enabled on the other node and my reset scripts did not 
catch this. Disabling it and rebooting the node made it work.

Which means I can confirm that IEEE 802.15.4 (wpan-ping) as well as 
6LoWPAN (ping6) communication between a at86rf233 and the adf7242 works 
fine. Nice!

regards
Stefan Schmidt

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 12:47     ` Michael Hennerich
  (?)
  (?)
@ 2015-12-07 15:03     ` Stefan Schmidt
  -1 siblings, 0 replies; 36+ messages in thread
From: Stefan Schmidt @ 2015-12-07 15:03 UTC (permalink / raw)
  To: michael.hennerich, alex.aring, marcel; +Cc: linux-wpan, linux-bluetooth

Hello.

On 07/12/15 13:47, Michael Hennerich wrote:
> On 12/04/2015 01:07 PM, Stefan Schmidt wrote:

[snip]

>>> +}
>>> +
>>> +static int adf7242_verify_firmware(struct adf7242_local *lp,
>>> +                   const u8 *data, size_t len)
>>
>> Could it really happen that we upload the firmware, getting fine status
>> codes back from spi_sync and this have a broken firmware in ram? To me
>> it looks like a safety measure for something that should never happen.
>> But I don't know the hardware.
>
> It's a safety measure and should never happen.
> I've added it while working with some broken SPI master driver some 
> time ago. I can remove it.
>

Hmm, I would not have it running for every init as almost all device 
should be fine. On the other hand having it for debugging might be handy 
as you already needed it once. I would say its up to you if you want to 
keep it in the driver. If you do please but is also behind the debugfs 
interface you will add for the status. That way you can keep the code 
around but only use it for its intended debugging purpose.
>>> +
>>> +    db = DIV_ROUND_CLOSEST(db + 29, 2);
>>> +
>>> +    if (db > 15) {
>>> +        dbias = 21;
>>> +        bias_ctrl = 63;
>>> +    } else {
>>> +        dbias = 13;
>>> +        bias_ctrl = 55;
>>
>> What the meaning of the values here? 21, 63, 13, 55
>
> Some BIAS values from the datasheet.
> IIRC starting some power level they need to be set differently.
>

Maybe some define's here instead of some magic values?
>>> +
>>> +static struct ieee802154_ops adf7242_ops = {
>>> +    .owner = THIS_MODULE,
>>> +    .xmit_sync = adf7242_xmit,
>>> +    .ed = adf7242_ed,
>>> +    .set_channel = adf7242_channel,
>>> +    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
>>> +    .start = adf7242_start,
>>> +    .stop = adf7242_stop,
>>> +    .set_csma_params = adf7242_set_csma_params,
>>> +    .set_frame_retries = adf7242_set_frame_retries,
>>> +    .set_txpower = adf7242_set_txpower,
>>> +    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
>>> +    .set_cca_ed_level = adf7242_set_cca_ed_level,
>>
>> Nice to see so many callbacks implemented. The only things I see missing
>> is xmit_async, set_lbt and set_cca_mode. I would not make it a
>> requirements to get these hooked up before merging this patch but we
>> should consider it as todo items.
>
> The part only supports CCA mode Energy above threshold.
> Not sure what this LBT mode does on the AT86RFxxx driver.

Sorry, my bad. Alex already pointed it out in the other mail. That is a 
sub-GHz requirement but adf7242 is a 2.4 GHz driver only so no need for lbt.

> The ADF7242 only supports CSMA-CA and not some other listen before 
> talk flavour. The only oher option is to turn CSMA-CA completly off.
> I'm also not sure if we need to supprot the async mode, while the sync 
> mode is working. For me the async mode looks like it tries to 
> workaround some HW access issues.
>

I will comment on these on the other mails Alex already answered.

>
>> Something worth thinking about might also be the usage of regmap.
>
> Given the number of different spi transaction formats I don't think a 
> regmap only approach can work here.
> Mixing things will not improve things either. So I prefer it the way 
> it is right now.

That would be ok with me. We did it for some other drivers and in my 
opinion it helped readability but if you think it would be worse for 
your driver I'm not demanding it.
>
> Thanks for taking the time to review things!
> I'll send V2 later this week.
>

Cool. Looking forward to it.

regards
Stefan Schmidt

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 13:25       ` Alexander Aring
  2015-12-07 13:34           ` Michael Hennerich
@ 2015-12-07 15:08         ` Stefan Schmidt
  1 sibling, 0 replies; 36+ messages in thread
From: Stefan Schmidt @ 2015-12-07 15:08 UTC (permalink / raw)
  To: Alexander Aring, Michael Hennerich; +Cc: marcel, linux-wpan, linux-bluetooth

Hello.

On 07/12/15 14:25, Alexander Aring wrote:
> Hi,
>
> On Mon, Dec 07, 2015 at 01:18:46PM +0100, Michael Hennerich wrote:
>> On 12/07/2015 01:02 PM, Stefan Schmidt wrote:
>>> Hello.
>>>
>>> I found some time at the weekend hooking it up on my raspberry pi.
>>>
>>> On 04/12/15 13:07, Stefan Schmidt wrote:
>>>> Hello.
>>>>
>>>> On 04/12/15 10:09, michael.hennerich@analog.com wrote:
>>>>
>>>>> The ADF7242 requires an add-on firmware for the automatic IEEE 802.15.4
>>>>> operating modes. The firmware file is currently made available on the
>>>>> ADF7242 wiki page here [1]
>>>> Just being curious here. Is there any way to get the firmware source
>>>> and/or compile your own? Its the first hardware for IEEE 802.15.4 I
>>>> have seen that have a special firmware for this which triggers my
>>>> curiosity. :)
>>
>> Unfortunately No - We don't release the firmware assembly code.
>> Or the required compiler.
>>
>>
>>>> Anyway, this has not that much to do with the driver review here as it
>>>> can obviously go in with the binary firmware. We just need to make
>>>> sure to also bring the firmware into the linux-firmware repo in time.
>>>>
>>>>> [1]
>>>>> http://wiki.analog.com/resources/tools-software/linux-drivers/networking-mac802154/adf7242
>>>>>
>>> There are two firmware zip files listed:
>>> ram_lab_7242_2_0_ieee15dot4_full_r5.zip
>>> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/ram_lab_7242_2_0_ieee15dot4_full_r5.zip>
>>>
>>> rom_ram_7242_2_0_ieee15dot4_full_r3.zip
>>> <https://wiki.analog.com/_media/resources/tools-software/linux-drivers/networking-mac802154/rom_ram_7242_2_0_ieee15dot4_full_r3.zip>
>>>
>>>
>>> Both contain a adf7242_firmware.bin file but also some different data
>>> file. Which one is the correct one here? Some explanation would be helpful.
>> Please use the latest R5 release file. I'll remove the old one soon.
>> The older firmware had problems with the back-off exponent randomization.
>>
>>
>>>
>>>>> [2]
>>>>> http://sourceforge.net/p/linux-zigbee/kernel/ci/devel/tree/drivers/ieee802154/adf7242.c
>>>>>
>>>>>
>>>>> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>>>>> ---
>>>>>   .../devicetree/bindings/net/ieee802154/adf7242.txt |   18 +
>>>>>   drivers/net/ieee802154/Kconfig                     |    5 +
>>>>>   drivers/net/ieee802154/Makefile                    |    1 +
>>>>>   drivers/net/ieee802154/adf7242.c                   | 1183
>>>>> ++++++++++++++++++++
>>>>>   4 files changed, 1207 insertions(+)
>>>>>   create mode 100644
>>>>> Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>>   create mode 100644 drivers/net/ieee802154/adf7242.c
>>>>>
>>>>> diff --git
>>>>> a/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>> b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>> new file mode 100644
>>>>> index 0000000..dea5124
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/net/ieee802154/adf7242.txt
>>>>> @@ -0,0 +1,18 @@
>>>>> +* ADF7242 IEEE 802.15.4 *
>>>>> +
>>>>> +Required properties:
>>>>> +  - compatible:        should be "adi,adf7242"
>>>>> +  - spi-max-frequency:    maximal bus speed (12.5 MHz)
>>>>> +  - reg:        the chipselect index
>>>>> +  - interrupts:        the interrupt generated by the device via pin
>>>>> IRQ1.
>>>>> +            IRQ_TYPE_LEVEL_HIGH (4) or IRQ_TYPE_EDGE_FALLING (1)
>>>
>>> IRQ1 would be pin7 on the interface connector, right? I'm using this one
>>> but I have trouble when transmitting
>> Yes IRQ1 is Pin7 on the PMOD connector.
>>
>>> adf7242 spi32766.0: Error xmit: Retry count exceeded Status=0x3
>>
>> That's failure NOACK. Is there a node on the same channel/PAN which could
>> response?
>> reading proc/interrupts should show some interrupts in this case...
>>
> Stefan, maybe you testing with the ATUSB firmware which going _not_
> into RX_AACK_ON.

Nope, turned out it was some stale security setting on a node with an 
at86rf233 which my testing scripts did not reset. After that is cleaned 
I can successfully wpan-ping and ping6 from and to the adf7242.

> This was one of my lastest changes according to the
> ATUSB firmware. Please check that, otherwise the atusb doesn't send
> ack frames if ackrequest bit is set after receiving.

Right, this is still pending. :/ I added it to my atusb firmware todo 
list which I hope to have some time tackling during 32C3.

regards
Stefan Schmidt

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 14:12           ` Alexander Aring
@ 2015-12-08  8:07               ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-08  8:07 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth, chrisfriedt

On 12/07/2015 03:12 PM, Alexander Aring wrote:
> On Mon, Dec 07, 2015 at 02:34:29PM +0100, Michael Hennerich wrote:
> ...
>>> Stefan, maybe you testing with the ATUSB firmware which going _not_
>>> into RX_AACK_ON. This was one of my lastest changes according to the
>>> ATUSB firmware. Please check that, otherwise the atusb doesn't send
>>> ack frames if ackrequest bit is set after receiving.
>>
>> I was wondering where can I buy the ATUSB?
>> On the pulster page I can't find it.
>>
>
> They are all out of stock, everywhere. I cc Werner maybe he will bring
> back the atusb again. He do his stuff all open source and a possible
> solution would be a Kickstarter project.
>
> Another option would be:
>
>   - Produce your own atusb
>   - I know that "Christopher Friedt" produced some, maybe he will give/sell
>     some. :-) I cc'ed him here.
>   - use the experimental firmware [1] on RZUSBStick [0] support. Basics
>     functionality only and not stable such atusb. I ported the firmware
>     to this stick, it can be used by atusb driver. The transceiver is a
>     different -> at86rf230... and this transceiver we also doesn't
>     support by the at86rf230 because it's too different and a huge
>     errata.

Would be nice to have a USB MAC8021511.
Guess I need to wait for the next lot being produced.


>
>> In general why is the framework not requesting ACKs on all non broadcast
>> DATA frames?
>>
>> There is an option if turned on - it'll also request ACks on broadcasts...
>
> I suppose you use the af802154 socket family. I didn't touched the code
> and this socket family is full of bugs. We need a replacement for that.
>
> The socket code which I was working is AF_PACKET.
>
> In case of AF_PACKET:
>
>   dgram sockets: extended address and intra_pan communciaton only. The
>                  AF_PACKET UAPI doesn't offer more address information.
> 		We do a mapping to this currently, other option would be
> 		to disable DGRAM on AF_PACKET. It's not possible to send
> 		broadcast frames with that.
> 		If you need that, something similar like af802154 should
> 		be available, but it's currently broken.
>
>   raw sockets:   You can build the mac frame inside userspace with
>                  complete control fc and address settings. We don't check
> 		this frame if it's valid. This is not a bug.
>
>
> and 6LoWPAN:
>
> 6LoWPAN doesn't do that, the check should be at [2]. If it's currently
> broken at your side?

Maybe - I still use the lowpan-tools.
And it locks like ACKs must be enabled via 
NL802154_CMD_SET_ACKREQ_DEFAULT, which lowpan-tools doesn't do.
Wondering why it's not by default enabled...
So I patched my kernel, probably in the wrong place.



>
> - Alex
>
> [0] http://www.atmel.com/tools/RZUSBSTICK.aspx
> [1] http://alex.my-webspace.org/firmwares/rzusb.bin
>      Note: This is temprorary website, I know wpan.cakelab.org is down
>      currently and I working already to a DNS solution to redirect
>      wpan.cakelab.org -> /alex.my-webspace.org . At the moment it looks
>      like the provide has bugs inside his DNS web-frontend configuration
>      page. ;-)
> [2] http://lxr.free-electrons.com/source/net/ieee802154/6lowpan/tx.c#L220
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-08  8:07               ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-08  8:07 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth, chrisfriedt

On 12/07/2015 03:12 PM, Alexander Aring wrote:
> On Mon, Dec 07, 2015 at 02:34:29PM +0100, Michael Hennerich wrote:
> ...
>>> Stefan, maybe you testing with the ATUSB firmware which going _not_
>>> into RX_AACK_ON. This was one of my lastest changes according to the
>>> ATUSB firmware. Please check that, otherwise the atusb doesn't send
>>> ack frames if ackrequest bit is set after receiving.
>>
>> I was wondering where can I buy the ATUSB?
>> On the pulster page I can't find it.
>>
>
> They are all out of stock, everywhere. I cc Werner maybe he will bring
> back the atusb again. He do his stuff all open source and a possible
> solution would be a Kickstarter project.
>
> Another option would be:
>
>   - Produce your own atusb
>   - I know that "Christopher Friedt" produced some, maybe he will give/sell
>     some. :-) I cc'ed him here.
>   - use the experimental firmware [1] on RZUSBStick [0] support. Basics
>     functionality only and not stable such atusb. I ported the firmware
>     to this stick, it can be used by atusb driver. The transceiver is a
>     different -> at86rf230... and this transceiver we also doesn't
>     support by the at86rf230 because it's too different and a huge
>     errata.

Would be nice to have a USB MAC8021511.
Guess I need to wait for the next lot being produced.


>
>> In general why is the framework not requesting ACKs on all non broadcast
>> DATA frames?
>>
>> There is an option if turned on - it'll also request ACks on broadcasts...
>
> I suppose you use the af802154 socket family. I didn't touched the code
> and this socket family is full of bugs. We need a replacement for that.
>
> The socket code which I was working is AF_PACKET.
>
> In case of AF_PACKET:
>
>   dgram sockets: extended address and intra_pan communciaton only. The
>                  AF_PACKET UAPI doesn't offer more address information.
> 		We do a mapping to this currently, other option would be
> 		to disable DGRAM on AF_PACKET. It's not possible to send
> 		broadcast frames with that.
> 		If you need that, something similar like af802154 should
> 		be available, but it's currently broken.
>
>   raw sockets:   You can build the mac frame inside userspace with
>                  complete control fc and address settings. We don't check
> 		this frame if it's valid. This is not a bug.
>
>
> and 6LoWPAN:
>
> 6LoWPAN doesn't do that, the check should be at [2]. If it's currently
> broken at your side?

Maybe - I still use the lowpan-tools.
And it locks like ACKs must be enabled via 
NL802154_CMD_SET_ACKREQ_DEFAULT, which lowpan-tools doesn't do.
Wondering why it's not by default enabled...
So I patched my kernel, probably in the wrong place.



>
> - Alex
>
> [0] http://www.atmel.com/tools/RZUSBSTICK.aspx
> [1] http://alex.my-webspace.org/firmwares/rzusb.bin
>      Note: This is temprorary website, I know wpan.cakelab.org is down
>      currently and I working already to a DNS solution to redirect
>      wpan.cakelab.org -> /alex.my-webspace.org . At the moment it looks
>      like the provide has bugs inside his DNS web-frontend configuration
>      page. ;-)
> [2] http://lxr.free-electrons.com/source/net/ieee802154/6lowpan/tx.c#L220
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-07 13:53     ` Alexander Aring
@ 2015-12-08  8:43         ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-08  8:43 UTC (permalink / raw)
  To: Alexander Aring; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

On 12/07/2015 02:53 PM, Alexander Aring wrote:
> Hi,
>
> On Mon, Dec 07, 2015 at 01:47:06PM +0100, Michael Hennerich wrote:
> ...
>>>> +static struct ieee802154_ops adf7242_ops = {
>>>> +    .owner = THIS_MODULE,
>>>> +    .xmit_sync = adf7242_xmit,
>>>> +    .ed = adf7242_ed,
>>>> +    .set_channel = adf7242_channel,
>>>> +    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
>>>> +    .start = adf7242_start,
>>>> +    .stop = adf7242_stop,
>>>> +    .set_csma_params = adf7242_set_csma_params,
>>>> +    .set_frame_retries = adf7242_set_frame_retries,
>>>> +    .set_txpower = adf7242_set_txpower,
>>>> +    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
>>>> +    .set_cca_ed_level = adf7242_set_cca_ed_level,
>>>
>>> Nice to see so many callbacks implemented. The only things I see missing
>>> is xmit_async, set_lbt and set_cca_mode. I would not make it a
>>> requirements to get these hooked up before merging this patch but we
>>> should consider it as todo items.
>>
>> The part only supports CCA mode Energy above threshold.
>> Not sure what this LBT mode does on the AT86RFxxx driver.
>
> This is for sub 1Ghz regulations in some country (Japan/Europe) area,
> there CSMA/CA accoridng 802.15.4 isn't allowed at sub 1-Ghz, that's why
> they introduced LBT.
>
> That reminds me to work on a regulator db, again. :-)
>
> Nevertheless it should not related to 2.4 Ghz global ISM band, so far I
> know.
>
>> The ADF7242 only supports CSMA-CA and not some other listen before talk
>> flavour. The only oher option is to turn CSMA-CA completly off.
>
> Another thing for ToDo list, add support for turning CSMA-CA handling
> complete off, many transceiver has such option.
>
> There exists ways currently to turn off CSMA handling only by choosing
> the right backoff exponents, 802.15.4 writes:
>
> Note that if macMinBE is set to zero, collision avoidance will be
> disabled during the first iteration of this algorithm.

First iteration only? And I think that is for slotted operation.
I wouldn't overload MinBe with an option to disable CSMA-CA.
Maybe add a new command?


>
> Okay then another ToDo for wpan-tools would be to make a nice printout
> that CSMA is disabled if "macMinBE is set to zero".
>
>> I'm also not sure if we need to supprot the async mode, while the sync mode
>> is working. For me the async mode looks like it tries to workaround some HW
>> access issues.
>>
>
> We came to the conclusion that "sync" callback is a workaround that
> people can use spi_sync. :-)

Hmmm - I don't quite understand.

The difference is that xmit_sync blocks until the packet is transmitted, 
while async returns immediately.
spi_sync can be only used from context that can sleep. While spi_async
runs it's own queue and provides a completion callback.

These radios can only do one thing at the time. And in both cases there 
are queues that are being stopped while the radio driver is busy doing 
something.

So the only thing is the IF down/up issue?

The ADF7242 would actually return an error if the packet wasn’t sent
or ACKed by the receiver. It's still looks like this information
isn’t being used anywhere.

Not a big deal - but in addition received ACKs (that would potentially 
indicate that the packet was successfully delivered) cause warnings and 
are completely dropped as well.


>
> Ununfortunately the nfc subsystem works also which such sync callback.
>
> Currently working of sync xmit:
>
>   - ieee802154_tx (softirq context, might_sleep() will fail).
>      - set parameters schedule workqueue /* queue_work(...) */
>        /* sleeping phase */ <-- we lost the context of ieee802154_tx, the
>                                 locks are not held anymore. Others
>                                 netdev_ops are possible.
>   - ieee802154_xmit_worker will be scheduled <--- Does this still
>   						 working if a stop
> 						 callback was running
> 						 inside the
> 						 "sleeping phase"?
>      - /* sleeping: wait for completion */ when tx complete is triggered
>                                            irq triggered.
>
> With async:
>
> The context of ieee802154_tx will be held until the driver "xmit_async"
> callback is done. This callback should call spi_async which cannot be
> interrupted until the "last" complete callback is done.
>
> Then a stop callback can occur at the time where the hardware "actually"
> transmit the frame. This is a complete async process, there is no "wait
> for completion" anymore. The complete replacement would be
> "ieee802154_xmit_complete".
>
> Drivers should also disable/enable the tx/rx irq's when doing stop/start,
> if possible.
>
> - Alex
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-08  8:43         ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-08  8:43 UTC (permalink / raw)
  To: Alexander Aring; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

On 12/07/2015 02:53 PM, Alexander Aring wrote:
> Hi,
>
> On Mon, Dec 07, 2015 at 01:47:06PM +0100, Michael Hennerich wrote:
> ...
>>>> +static struct ieee802154_ops adf7242_ops = {
>>>> +    .owner = THIS_MODULE,
>>>> +    .xmit_sync = adf7242_xmit,
>>>> +    .ed = adf7242_ed,
>>>> +    .set_channel = adf7242_channel,
>>>> +    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
>>>> +    .start = adf7242_start,
>>>> +    .stop = adf7242_stop,
>>>> +    .set_csma_params = adf7242_set_csma_params,
>>>> +    .set_frame_retries = adf7242_set_frame_retries,
>>>> +    .set_txpower = adf7242_set_txpower,
>>>> +    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
>>>> +    .set_cca_ed_level = adf7242_set_cca_ed_level,
>>>
>>> Nice to see so many callbacks implemented. The only things I see missing
>>> is xmit_async, set_lbt and set_cca_mode. I would not make it a
>>> requirements to get these hooked up before merging this patch but we
>>> should consider it as todo items.
>>
>> The part only supports CCA mode Energy above threshold.
>> Not sure what this LBT mode does on the AT86RFxxx driver.
>
> This is for sub 1Ghz regulations in some country (Japan/Europe) area,
> there CSMA/CA accoridng 802.15.4 isn't allowed at sub 1-Ghz, that's why
> they introduced LBT.
>
> That reminds me to work on a regulator db, again. :-)
>
> Nevertheless it should not related to 2.4 Ghz global ISM band, so far I
> know.
>
>> The ADF7242 only supports CSMA-CA and not some other listen before talk
>> flavour. The only oher option is to turn CSMA-CA completly off.
>
> Another thing for ToDo list, add support for turning CSMA-CA handling
> complete off, many transceiver has such option.
>
> There exists ways currently to turn off CSMA handling only by choosing
> the right backoff exponents, 802.15.4 writes:
>
> Note that if macMinBE is set to zero, collision avoidance will be
> disabled during the first iteration of this algorithm.

First iteration only? And I think that is for slotted operation.
I wouldn't overload MinBe with an option to disable CSMA-CA.
Maybe add a new command?


>
> Okay then another ToDo for wpan-tools would be to make a nice printout
> that CSMA is disabled if "macMinBE is set to zero".
>
>> I'm also not sure if we need to supprot the async mode, while the sync mode
>> is working. For me the async mode looks like it tries to workaround some HW
>> access issues.
>>
>
> We came to the conclusion that "sync" callback is a workaround that
> people can use spi_sync. :-)

Hmmm - I don't quite understand.

The difference is that xmit_sync blocks until the packet is transmitted, 
while async returns immediately.
spi_sync can be only used from context that can sleep. While spi_async
runs it's own queue and provides a completion callback.

These radios can only do one thing at the time. And in both cases there 
are queues that are being stopped while the radio driver is busy doing 
something.

So the only thing is the IF down/up issue?

The ADF7242 would actually return an error if the packet wasn’t sent
or ACKed by the receiver. It's still looks like this information
isn’t being used anywhere.

Not a big deal - but in addition received ACKs (that would potentially 
indicate that the packet was successfully delivered) cause warnings and 
are completely dropped as well.


>
> Ununfortunately the nfc subsystem works also which such sync callback.
>
> Currently working of sync xmit:
>
>   - ieee802154_tx (softirq context, might_sleep() will fail).
>      - set parameters schedule workqueue /* queue_work(...) */
>        /* sleeping phase */ <-- we lost the context of ieee802154_tx, the
>                                 locks are not held anymore. Others
>                                 netdev_ops are possible.
>   - ieee802154_xmit_worker will be scheduled <--- Does this still
>   						 working if a stop
> 						 callback was running
> 						 inside the
> 						 "sleeping phase"?
>      - /* sleeping: wait for completion */ when tx complete is triggered
>                                            irq triggered.
>
> With async:
>
> The context of ieee802154_tx will be held until the driver "xmit_async"
> callback is done. This callback should call spi_async which cannot be
> interrupted until the "last" complete callback is done.
>
> Then a stop callback can occur at the time where the hardware "actually"
> transmit the frame. This is a complete async process, there is no "wait
> for completion" anymore. The complete replacement would be
> "ieee802154_xmit_complete".
>
> Drivers should also disable/enable the tx/rx irq's when doing stop/start,
> if possible.
>
> - Alex
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-08  8:07               ` Michael Hennerich
  (?)
@ 2015-12-08 15:53               ` Alexander Aring
  2015-12-08 16:02                   ` Michael Hennerich
  -1 siblings, 1 reply; 36+ messages in thread
From: Alexander Aring @ 2015-12-08 15:53 UTC (permalink / raw)
  To: Michael Hennerich
  Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth, chrisfriedt

Hi,

On Tue, Dec 08, 2015 at 09:07:43AM +0100, Michael Hennerich wrote:
> On 12/07/2015 03:12 PM, Alexander Aring wrote:
> >On Mon, Dec 07, 2015 at 02:34:29PM +0100, Michael Hennerich wrote:
> >...
> >>>Stefan, maybe you testing with the ATUSB firmware which going _not_
> >>>into RX_AACK_ON. This was one of my lastest changes according to the
> >>>ATUSB firmware. Please check that, otherwise the atusb doesn't send
> >>>ack frames if ackrequest bit is set after receiving.
> >>
> >>I was wondering where can I buy the ATUSB?
> >>On the pulster page I can't find it.
> >>
> >
> >They are all out of stock, everywhere. I cc Werner maybe he will bring
> >back the atusb again. He do his stuff all open source and a possible
> >solution would be a Kickstarter project.
> >
> >Another option would be:
> >
> >  - Produce your own atusb
> >  - I know that "Christopher Friedt" produced some, maybe he will give/sell
> >    some. :-) I cc'ed him here.
> >  - use the experimental firmware [1] on RZUSBStick [0] support. Basics
> >    functionality only and not stable such atusb. I ported the firmware
> >    to this stick, it can be used by atusb driver. The transceiver is a
> >    different -> at86rf230... and this transceiver we also doesn't
> >    support by the at86rf230 because it's too different and a huge
> >    errata.
> 
> Would be nice to have a USB MAC8021511.
> Guess I need to wait for the next lot being produced.
> 
> 

ok. The RZUSBSTICK is still available but very poor state.

> >
> >>In general why is the framework not requesting ACKs on all non broadcast
> >>DATA frames?
> >>
> >>There is an option if turned on - it'll also request ACks on broadcasts...
> >
> >I suppose you use the af802154 socket family. I didn't touched the code
> >and this socket family is full of bugs. We need a replacement for that.
> >
> >The socket code which I was working is AF_PACKET.
> >
> >In case of AF_PACKET:
> >
> >  dgram sockets: extended address and intra_pan communciaton only. The
> >                 AF_PACKET UAPI doesn't offer more address information.
> >		We do a mapping to this currently, other option would be
> >		to disable DGRAM on AF_PACKET. It's not possible to send
> >		broadcast frames with that.
> >		If you need that, something similar like af802154 should
> >		be available, but it's currently broken.
> >
> >  raw sockets:   You can build the mac frame inside userspace with
> >                 complete control fc and address settings. We don't check
> >		this frame if it's valid. This is not a bug.
> >
> >
> >and 6LoWPAN:
> >
> >6LoWPAN doesn't do that, the check should be at [2]. If it's currently
> >broken at your side?
> 
> Maybe - I still use the lowpan-tools.
> And it locks like ACKs must be enabled via NL802154_CMD_SET_ACKREQ_DEFAULT,
> which lowpan-tools doesn't do.
> Wondering why it's not by default enabled...
> So I patched my kernel, probably in the wrong place.
> 

The lowpan-tools are deprecated. The official website is back (from what
I recovered), you can get wpan-tools at [0].

The ackreq_default is false by default (which indicates no ARET
handling/no ackrequest bit is set) because this requires that the other
side can deal with ack handling. Otherwise the node will get the frame 3
times.

The conclusion is to set the ack handling default to false, if you know
your network can do ack handling then you can turn it on with the
wpan-tools.

Do you think we should enable it by default and if there are non IEEE
802.15.4 valid nodes around which doesn't support ACK handling we should
simple ignore that?

- Alex

[0] http://wpan.cakelab.org/releases/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-08 15:53               ` Alexander Aring
@ 2015-12-08 16:02                   ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-08 16:02 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth, chrisfriedt

On 12/08/2015 04:53 PM, Alexander Aring wrote:
> Hi,
>
> On Tue, Dec 08, 2015 at 09:07:43AM +0100, Michael Hennerich wrote:
>> On 12/07/2015 03:12 PM, Alexander Aring wrote:
>>> On Mon, Dec 07, 2015 at 02:34:29PM +0100, Michael Hennerich wrote:
>>> ...
>>>>> Stefan, maybe you testing with the ATUSB firmware which going _not_
>>>>> into RX_AACK_ON. This was one of my lastest changes according to the
>>>>> ATUSB firmware. Please check that, otherwise the atusb doesn't send
>>>>> ack frames if ackrequest bit is set after receiving.
>>>>
>>>> I was wondering where can I buy the ATUSB?
>>>> On the pulster page I can't find it.
>>>>
>>>
>>> They are all out of stock, everywhere. I cc Werner maybe he will bring
>>> back the atusb again. He do his stuff all open source and a possible
>>> solution would be a Kickstarter project.
>>>
>>> Another option would be:
>>>
>>>   - Produce your own atusb
>>>   - I know that "Christopher Friedt" produced some, maybe he will give/sell
>>>     some. :-) I cc'ed him here.
>>>   - use the experimental firmware [1] on RZUSBStick [0] support. Basics
>>>     functionality only and not stable such atusb. I ported the firmware
>>>     to this stick, it can be used by atusb driver. The transceiver is a
>>>     different -> at86rf230... and this transceiver we also doesn't
>>>     support by the at86rf230 because it's too different and a huge
>>>     errata.
>>
>> Would be nice to have a USB MAC8021511.
>> Guess I need to wait for the next lot being produced.
>>
>>
>
> ok. The RZUSBSTICK is still available but very poor state.
>
>>>
>>>> In general why is the framework not requesting ACKs on all non broadcast
>>>> DATA frames?
>>>>
>>>> There is an option if turned on - it'll also request ACks on broadcasts...
>>>
>>> I suppose you use the af802154 socket family. I didn't touched the code
>>> and this socket family is full of bugs. We need a replacement for that.
>>>
>>> The socket code which I was working is AF_PACKET.
>>>
>>> In case of AF_PACKET:
>>>
>>>   dgram sockets: extended address and intra_pan communciaton only. The
>>>                  AF_PACKET UAPI doesn't offer more address information.
>>> 		We do a mapping to this currently, other option would be
>>> 		to disable DGRAM on AF_PACKET. It's not possible to send
>>> 		broadcast frames with that.
>>> 		If you need that, something similar like af802154 should
>>> 		be available, but it's currently broken.
>>>
>>>   raw sockets:   You can build the mac frame inside userspace with
>>>                  complete control fc and address settings. We don't check
>>> 		this frame if it's valid. This is not a bug.
>>>
>>>
>>> and 6LoWPAN:
>>>
>>> 6LoWPAN doesn't do that, the check should be at [2]. If it's currently
>>> broken at your side?
>>
>> Maybe - I still use the lowpan-tools.
>> And it locks like ACKs must be enabled via NL802154_CMD_SET_ACKREQ_DEFAULT,
>> which lowpan-tools doesn't do.
>> Wondering why it's not by default enabled...
>> So I patched my kernel, probably in the wrong place.
>>
>
> The lowpan-tools are deprecated. The official website is back (from what
> I recovered), you can get wpan-tools at [0].
>
> The ackreq_default is false by default (which indicates no ARET
> handling/no ackrequest bit is set) because this requires that the other
> side can deal with ack handling. Otherwise the node will get the frame 3
> times.
>
> The conclusion is to set the ack handling default to false, if you know
> your network can do ack handling then you can turn it on with the
> wpan-tools.
>
> Do you think we should enable it by default and if there are non IEEE
> 802.15.4 valid nodes around which doesn't support ACK handling we should
> simple ignore that?

I thought that ACK handling is mandatory for 802.15.4.
So if there are non compliant IEEE802154 nodes around we can turn it off.

Either way is fine with me.


>
> - Alex
>
> [0] http://wpan.cakelab.org/releases/
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-08 16:02                   ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-08 16:02 UTC (permalink / raw)
  To: Alexander Aring
  Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth, chrisfriedt

On 12/08/2015 04:53 PM, Alexander Aring wrote:
> Hi,
>
> On Tue, Dec 08, 2015 at 09:07:43AM +0100, Michael Hennerich wrote:
>> On 12/07/2015 03:12 PM, Alexander Aring wrote:
>>> On Mon, Dec 07, 2015 at 02:34:29PM +0100, Michael Hennerich wrote:
>>> ...
>>>>> Stefan, maybe you testing with the ATUSB firmware which going _not_
>>>>> into RX_AACK_ON. This was one of my lastest changes according to the
>>>>> ATUSB firmware. Please check that, otherwise the atusb doesn't send
>>>>> ack frames if ackrequest bit is set after receiving.
>>>>
>>>> I was wondering where can I buy the ATUSB?
>>>> On the pulster page I can't find it.
>>>>
>>>
>>> They are all out of stock, everywhere. I cc Werner maybe he will bring
>>> back the atusb again. He do his stuff all open source and a possible
>>> solution would be a Kickstarter project.
>>>
>>> Another option would be:
>>>
>>>   - Produce your own atusb
>>>   - I know that "Christopher Friedt" produced some, maybe he will give/sell
>>>     some. :-) I cc'ed him here.
>>>   - use the experimental firmware [1] on RZUSBStick [0] support. Basics
>>>     functionality only and not stable such atusb. I ported the firmware
>>>     to this stick, it can be used by atusb driver. The transceiver is a
>>>     different -> at86rf230... and this transceiver we also doesn't
>>>     support by the at86rf230 because it's too different and a huge
>>>     errata.
>>
>> Would be nice to have a USB MAC8021511.
>> Guess I need to wait for the next lot being produced.
>>
>>
>
> ok. The RZUSBSTICK is still available but very poor state.
>
>>>
>>>> In general why is the framework not requesting ACKs on all non broadcast
>>>> DATA frames?
>>>>
>>>> There is an option if turned on - it'll also request ACks on broadcasts...
>>>
>>> I suppose you use the af802154 socket family. I didn't touched the code
>>> and this socket family is full of bugs. We need a replacement for that.
>>>
>>> The socket code which I was working is AF_PACKET.
>>>
>>> In case of AF_PACKET:
>>>
>>>   dgram sockets: extended address and intra_pan communciaton only. The
>>>                  AF_PACKET UAPI doesn't offer more address information.
>>> 		We do a mapping to this currently, other option would be
>>> 		to disable DGRAM on AF_PACKET. It's not possible to send
>>> 		broadcast frames with that.
>>> 		If you need that, something similar like af802154 should
>>> 		be available, but it's currently broken.
>>>
>>>   raw sockets:   You can build the mac frame inside userspace with
>>>                  complete control fc and address settings. We don't check
>>> 		this frame if it's valid. This is not a bug.
>>>
>>>
>>> and 6LoWPAN:
>>>
>>> 6LoWPAN doesn't do that, the check should be at [2]. If it's currently
>>> broken at your side?
>>
>> Maybe - I still use the lowpan-tools.
>> And it locks like ACKs must be enabled via NL802154_CMD_SET_ACKREQ_DEFAULT,
>> which lowpan-tools doesn't do.
>> Wondering why it's not by default enabled...
>> So I patched my kernel, probably in the wrong place.
>>
>
> The lowpan-tools are deprecated. The official website is back (from what
> I recovered), you can get wpan-tools at [0].
>
> The ackreq_default is false by default (which indicates no ARET
> handling/no ackrequest bit is set) because this requires that the other
> side can deal with ack handling. Otherwise the node will get the frame 3
> times.
>
> The conclusion is to set the ack handling default to false, if you know
> your network can do ack handling then you can turn it on with the
> wpan-tools.
>
> Do you think we should enable it by default and if there are non IEEE
> 802.15.4 valid nodes around which doesn't support ACK handling we should
> simple ignore that?

I thought that ACK handling is mandatory for 802.15.4.
So if there are non compliant IEEE802154 nodes around we can turn it off.

Either way is fine with me.


>
> - Alex
>
> [0] http://wpan.cakelab.org/releases/
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-08  8:43         ` Michael Hennerich
  (?)
@ 2015-12-08 17:11         ` Alexander Aring
  2015-12-09  9:53             ` Michael Hennerich
  -1 siblings, 1 reply; 36+ messages in thread
From: Alexander Aring @ 2015-12-08 17:11 UTC (permalink / raw)
  To: Michael Hennerich; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

Hi,

On Tue, Dec 08, 2015 at 09:43:20AM +0100, Michael Hennerich wrote:
> On 12/07/2015 02:53 PM, Alexander Aring wrote:
> >Hi,
> >
> >On Mon, Dec 07, 2015 at 01:47:06PM +0100, Michael Hennerich wrote:
> >...
> >>>>+static struct ieee802154_ops adf7242_ops = {
> >>>>+    .owner = THIS_MODULE,
> >>>>+    .xmit_sync = adf7242_xmit,
> >>>>+    .ed = adf7242_ed,
> >>>>+    .set_channel = adf7242_channel,
> >>>>+    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
> >>>>+    .start = adf7242_start,
> >>>>+    .stop = adf7242_stop,
> >>>>+    .set_csma_params = adf7242_set_csma_params,
> >>>>+    .set_frame_retries = adf7242_set_frame_retries,
> >>>>+    .set_txpower = adf7242_set_txpower,
> >>>>+    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
> >>>>+    .set_cca_ed_level = adf7242_set_cca_ed_level,
> >>>
> >>>Nice to see so many callbacks implemented. The only things I see missing
> >>>is xmit_async, set_lbt and set_cca_mode. I would not make it a
> >>>requirements to get these hooked up before merging this patch but we
> >>>should consider it as todo items.
> >>
> >>The part only supports CCA mode Energy above threshold.
> >>Not sure what this LBT mode does on the AT86RFxxx driver.
> >
> >This is for sub 1Ghz regulations in some country (Japan/Europe) area,
> >there CSMA/CA accoridng 802.15.4 isn't allowed at sub 1-Ghz, that's why
> >they introduced LBT.
> >
> >That reminds me to work on a regulator db, again. :-)
> >
> >Nevertheless it should not related to 2.4 Ghz global ISM band, so far I
> >know.
> >
> >>The ADF7242 only supports CSMA-CA and not some other listen before talk
> >>flavour. The only oher option is to turn CSMA-CA completly off.
> >
> >Another thing for ToDo list, add support for turning CSMA-CA handling
> >complete off, many transceiver has such option.
> >
> >There exists ways currently to turn off CSMA handling only by choosing
> >the right backoff exponents, 802.15.4 writes:
> >
> >Note that if macMinBE is set to zero, collision avoidance will be
> >disabled during the first iteration of this algorithm.
> 
> First iteration only? And I think that is for slotted operation.
> I wouldn't overload MinBe with an option to disable CSMA-CA.
> Maybe add a new command?
> 
> 

"CSMA" != "CSMA-CA"

The calculation is for backoff periods (aUnitBackoffPeriod) is:

2^(MINBE + 1) - 1

doesn't matter if slotted/unslotted. See page 23 at [0].

By disable CSMA-CA I usually assume that the CCA status will not
performed. Disable CSMA -> CCA status will be performed.

I agree to add an own command to disable "CSMA-CA", to disable "CSMA" we
have minBe.

> >
> >Okay then another ToDo for wpan-tools would be to make a nice printout
> >that CSMA is disabled if "macMinBE is set to zero".
> >
> >>I'm also not sure if we need to supprot the async mode, while the sync mode
> >>is working. For me the async mode looks like it tries to workaround some HW
> >>access issues.
> >>
> >
> >We came to the conclusion that "sync" callback is a workaround that
> >people can use spi_sync. :-)
> 
> Hmmm - I don't quite understand.
> 
> The difference is that xmit_sync blocks until the packet is transmitted,
> while async returns immediately.

Exact, and "blocking" is not what the netdev api offers by callback
".ndo_start_xmit".

> spi_sync can be only used from context that can sleep. While spi_async
> runs it's own queue and provides a completion callback.
> 
> These radios can only do one thing at the time. And in both cases there are
> queues that are being stopped while the radio driver is busy doing
> something.
> 

Yes, most transceivers has only one framebuffer. Btw: AT86RFxxx has
really only one for rx/tx.

> So the only thing is the IF down/up issue?
> 

I am not sure, I thought about that the whole day and I need to admit: I
think both ways have some races _currently_.

What I am suppose is that we can easier deal which such races when we
use xmit_async without having a workqueue in the middle of
"ndo_start_xmit" and "driver xmit" callback.

Furthermore, with MLME-ops we need to send frames out which are triggered
by a workqueue as well, mac80211 MLME-ops do the same.

But there exist a difference by starting a xmit workqueue from "ndo_start_xmit"
or "netlink command".


----

Btw: while thinking the whole day I detected a "deadlock" (maybe
somebody can confirm it).

At [1], we have ndo_stop callback which is called under RTNL lock. This
will call ieee802154_stop_device, which also flushed the xmit workqueue
(That means it will wait until the workqueue is complete scheduled).
Now the "worker" callback of the xmit workqueue also hold the RTNL lock,
see [2]. If this is called when "stop callback" [1] is waiting for the
workqueue it will wait forever, because the xmit workqueue will wait on
RTNL lock.

That the workqueue held the rtnl lock while transmit was one of my
earlier changes, where somebody had some issues when doing ifdown. Maybe
this change do "something" which fixed it but the real issue was an
another. Now, when stop doing "flush_workqueue" and all netdev queues
(which belongs to a phy) are stopped, then there can't be a 802.15.4
driver "stop" callback.

Also if we wait for the workqueue and the netdev queue was stopped
before, it will be awake again because the driver will finish it.


I have some headache now and I think we need to discuss again about the
correct handling of "transmit" and look if everything works fine then
without races, but it isn't easy. What I currently think is that
"xmit_async" goes to the right direction, that we don't need to deal
with the loosing context of "ndo_start_xmit" when call driver xmit
callback.

> The ADF7242 would actually return an error if the packet wasn’t sent
> or ACKed by the receiver. It's still looks like this information
> isn’t being used anywhere.
> 

Yes, MLME-ops needs this option, we don't have currently any functionality to
tell the "why transmit failed" to upper-layers (mac802154).

Such stats should be available by "iwpan", like "iw station dump" in wireless.
Then you can do some statistic counts. (Maybe the first use case to see
that it works.)

> Not a big deal - but in addition received ACKs (that would potentially
> indicate that the packet was successfully delivered) cause warnings and are
> completely dropped as well.
> 

- Alex

[0] ISBN 978-0-7381-6684-1 STDPD97126 (I hope they handle revisions of
				       802.15.4 standard with this
				       number).
    or simple use this link (found by google):
    http://ecee.colorado.edu/~liue/teaching/comm_standards/2015S_zigbee/802.15.4-2011.pdf
    it's pdf page 43.
[1] http://lxr.free-electrons.com/source/net/mac802154/iface.c#L333
[2] http://lxr.free-electrons.com/source/net/mac802154/tx.c#L41

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-08 17:11         ` Alexander Aring
@ 2015-12-09  9:53             ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-09  9:53 UTC (permalink / raw)
  To: Alexander Aring; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

On 12/08/2015 06:11 PM, Alexander Aring wrote:
> Hi,
>
> On Tue, Dec 08, 2015 at 09:43:20AM +0100, Michael Hennerich wrote:
>> On 12/07/2015 02:53 PM, Alexander Aring wrote:
>>> Hi,
>>>
>>> On Mon, Dec 07, 2015 at 01:47:06PM +0100, Michael Hennerich wrote:
>>> ...
>>>>>> +static struct ieee802154_ops adf7242_ops = {
>>>>>> +    .owner = THIS_MODULE,
>>>>>> +    .xmit_sync = adf7242_xmit,
>>>>>> +    .ed = adf7242_ed,
>>>>>> +    .set_channel = adf7242_channel,
>>>>>> +    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
>>>>>> +    .start = adf7242_start,
>>>>>> +    .stop = adf7242_stop,
>>>>>> +    .set_csma_params = adf7242_set_csma_params,
>>>>>> +    .set_frame_retries = adf7242_set_frame_retries,
>>>>>> +    .set_txpower = adf7242_set_txpower,
>>>>>> +    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
>>>>>> +    .set_cca_ed_level = adf7242_set_cca_ed_level,
>>>>>
>>>>> Nice to see so many callbacks implemented. The only things I see missing
>>>>> is xmit_async, set_lbt and set_cca_mode. I would not make it a
>>>>> requirements to get these hooked up before merging this patch but we
>>>>> should consider it as todo items.
>>>>
>>>> The part only supports CCA mode Energy above threshold.
>>>> Not sure what this LBT mode does on the AT86RFxxx driver.
>>>
>>> This is for sub 1Ghz regulations in some country (Japan/Europe) area,
>>> there CSMA/CA accoridng 802.15.4 isn't allowed at sub 1-Ghz, that's why
>>> they introduced LBT.
>>>
>>> That reminds me to work on a regulator db, again. :-)
>>>
>>> Nevertheless it should not related to 2.4 Ghz global ISM band, so far I
>>> know.
>>>
>>>> The ADF7242 only supports CSMA-CA and not some other listen before talk
>>>> flavour. The only oher option is to turn CSMA-CA completly off.
>>>
>>> Another thing for ToDo list, add support for turning CSMA-CA handling
>>> complete off, many transceiver has such option.
>>>
>>> There exists ways currently to turn off CSMA handling only by choosing
>>> the right backoff exponents, 802.15.4 writes:
>>>
>>> Note that if macMinBE is set to zero, collision avoidance will be
>>> disabled during the first iteration of this algorithm.
>>
>> First iteration only? And I think that is for slotted operation.
>> I wouldn't overload MinBe with an option to disable CSMA-CA.
>> Maybe add a new command?
>>
>>
>
> "CSMA" != "CSMA-CA"
>
> The calculation is for backoff periods (aUnitBackoffPeriod) is:
>
> 2^(MINBE + 1) - 1
>
> doesn't matter if slotted/unslotted. See page 23 at [0].
>
> By disable CSMA-CA I usually assume that the CCA status will not
> performed. Disable CSMA -> CCA status will be performed.
>
> I agree to add an own command to disable "CSMA-CA", to disable "CSMA" we
> have minBe.
>

Hi Alex,

ok - I see.



>>>
>>> Okay then another ToDo for wpan-tools would be to make a nice printout
>>> that CSMA is disabled if "macMinBE is set to zero".
>>>
>>>> I'm also not sure if we need to supprot the async mode, while the sync mode
>>>> is working. For me the async mode looks like it tries to workaround some HW
>>>> access issues.
>>>>
>>>
>>> We came to the conclusion that "sync" callback is a workaround that
>>> people can use spi_sync. :-)
>>
>> Hmmm - I don't quite understand.
>>
>> The difference is that xmit_sync blocks until the packet is transmitted,
>> while async returns immediately.
>
> Exact, and "blocking" is not what the netdev api offers by callback
> ".ndo_start_xmit".

I know.


>
>> spi_sync can be only used from context that can sleep. While spi_async
>> runs it's own queue and provides a completion callback.
>>
>> These radios can only do one thing at the time. And in both cases there are
>> queues that are being stopped while the radio driver is busy doing
>> something.
>>
>
> Yes, most transceivers has only one framebuffer. Btw: AT86RFxxx has
> really only one for rx/tx.

Yeah - the ADF7242 also has two buffers. But still 802.15.4 is 
TDD/Simplex. So either RX or TX. And in fact while TX with ACKreq, the 
RX buffer is used to store the ACK, and while RX data in the TX buffer 
might be overwritten by the ACK that is being transmitted.


>
>> So the only thing is the IF down/up issue?
>>
>
> I am not sure, I thought about that the whole day and I need to admit: I
> think both ways have some races _currently_.
>
> What I am suppose is that we can easier deal which such races when we
> use xmit_async without having a workqueue in the middle of
> "ndo_start_xmit" and "driver xmit" callback.


I don't see the difference with using spi_async here.
Instead of your own workqueue. You defer the work to the SPI master 
queue (kthread)...
In both cases all messages are sequential. And I don't see any timing 
benefit. It actually makes things more complex.
Think about the case during xmit where you have to check status -> write 
some registers -> check some other status -> write some more 
regsiters/data -> ...

For this to work you have to chain multiple async messages.
And rely on the goodwill of the SPI master kthread to pump them out.



>
> Furthermore, with MLME-ops we need to send frames out which are triggered
> by a workqueue as well, mac80211 MLME-ops do the same.
>
> But there exist a difference by starting a xmit workqueue from "ndo_start_xmit"
> or "netlink command".
>
>
> ----
>
> Btw: while thinking the whole day I detected a "deadlock" (maybe
> somebody can confirm it).
>
> At [1], we have ndo_stop callback which is called under RTNL lock. This
> will call ieee802154_stop_device, which also flushed the xmit workqueue
> (That means it will wait until the workqueue is complete scheduled).
> Now the "worker" callback of the xmit workqueue also hold the RTNL lock,
> see [2]. If this is called when "stop callback" [1] is waiting for the
> workqueue it will wait forever, because the xmit workqueue will wait on
> RTNL lock.


That looks racy.
In the xmit_async path there is no such lock.
I don't know why sync versus async would need it
- remove it altogether with the netif_running check.


>
> That the workqueue held the rtnl lock while transmit was one of my
> earlier changes, where somebody had some issues when doing ifdown. Maybe
> this change do "something" which fixed it but the real issue was an
> another. Now, when stop doing "flush_workqueue" and all netdev queues
> (which belongs to a phy) are stopped, then there can't be a 802.15.4
> driver "stop" callback.
>
> Also if we wait for the workqueue and the netdev queue was stopped
> before, it will be awake again because the driver will finish it.
>
>
> I have some headache now and I think we need to discuss again about the
> correct handling of "transmit" and look if everything works fine then
> without races, but it isn't easy. What I currently think is that
> "xmit_async" goes to the right direction, that we don't need to deal
> with the loosing context of "ndo_start_xmit" when call driver xmit
> callback.
>
>> The ADF7242 would actually return an error if the packet wasn’t sent
>> or ACKed by the receiver. It's still looks like this information
>> isn’t being used anywhere.
>>
>
> Yes, MLME-ops needs this option, we don't have currently any functionality to
> tell the "why transmit failed" to upper-layers (mac802154).
>
> Such stats should be available by "iwpan", like "iw station dump" in wireless.
> Then you can do some statistic counts. (Maybe the first use case to see
> that it works.)
>
>> Not a big deal - but in addition received ACKs (that would potentially
>> indicate that the packet was successfully delivered) cause warnings and are
>> completely dropped as well.
>>
>
> - Alex
>
> [0] ISBN 978-0-7381-6684-1 STDPD97126 (I hope they handle revisions of
> 				       802.15.4 standard with this
> 				       number).
>      or simple use this link (found by google):
>      http://ecee.colorado.edu/~liue/teaching/comm_standards/2015S_zigbee/802.15.4-2011.pdf
>      it's pdf page 43.
> [1] http://lxr.free-electrons.com/source/net/mac802154/iface.c#L333
> [2] http://lxr.free-electrons.com/source/net/mac802154/tx.c#L41
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-09  9:53             ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-09  9:53 UTC (permalink / raw)
  To: Alexander Aring; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

On 12/08/2015 06:11 PM, Alexander Aring wrote:
> Hi,
>
> On Tue, Dec 08, 2015 at 09:43:20AM +0100, Michael Hennerich wrote:
>> On 12/07/2015 02:53 PM, Alexander Aring wrote:
>>> Hi,
>>>
>>> On Mon, Dec 07, 2015 at 01:47:06PM +0100, Michael Hennerich wrote:
>>> ...
>>>>>> +static struct ieee802154_ops adf7242_ops = {
>>>>>> +    .owner = THIS_MODULE,
>>>>>> +    .xmit_sync = adf7242_xmit,
>>>>>> +    .ed = adf7242_ed,
>>>>>> +    .set_channel = adf7242_channel,
>>>>>> +    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
>>>>>> +    .start = adf7242_start,
>>>>>> +    .stop = adf7242_stop,
>>>>>> +    .set_csma_params = adf7242_set_csma_params,
>>>>>> +    .set_frame_retries = adf7242_set_frame_retries,
>>>>>> +    .set_txpower = adf7242_set_txpower,
>>>>>> +    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
>>>>>> +    .set_cca_ed_level = adf7242_set_cca_ed_level,
>>>>>
>>>>> Nice to see so many callbacks implemented. The only things I see missing
>>>>> is xmit_async, set_lbt and set_cca_mode. I would not make it a
>>>>> requirements to get these hooked up before merging this patch but we
>>>>> should consider it as todo items.
>>>>
>>>> The part only supports CCA mode Energy above threshold.
>>>> Not sure what this LBT mode does on the AT86RFxxx driver.
>>>
>>> This is for sub 1Ghz regulations in some country (Japan/Europe) area,
>>> there CSMA/CA accoridng 802.15.4 isn't allowed at sub 1-Ghz, that's why
>>> they introduced LBT.
>>>
>>> That reminds me to work on a regulator db, again. :-)
>>>
>>> Nevertheless it should not related to 2.4 Ghz global ISM band, so far I
>>> know.
>>>
>>>> The ADF7242 only supports CSMA-CA and not some other listen before talk
>>>> flavour. The only oher option is to turn CSMA-CA completly off.
>>>
>>> Another thing for ToDo list, add support for turning CSMA-CA handling
>>> complete off, many transceiver has such option.
>>>
>>> There exists ways currently to turn off CSMA handling only by choosing
>>> the right backoff exponents, 802.15.4 writes:
>>>
>>> Note that if macMinBE is set to zero, collision avoidance will be
>>> disabled during the first iteration of this algorithm.
>>
>> First iteration only? And I think that is for slotted operation.
>> I wouldn't overload MinBe with an option to disable CSMA-CA.
>> Maybe add a new command?
>>
>>
>
> "CSMA" != "CSMA-CA"
>
> The calculation is for backoff periods (aUnitBackoffPeriod) is:
>
> 2^(MINBE + 1) - 1
>
> doesn't matter if slotted/unslotted. See page 23 at [0].
>
> By disable CSMA-CA I usually assume that the CCA status will not
> performed. Disable CSMA -> CCA status will be performed.
>
> I agree to add an own command to disable "CSMA-CA", to disable "CSMA" we
> have minBe.
>

Hi Alex,

ok - I see.



>>>
>>> Okay then another ToDo for wpan-tools would be to make a nice printout
>>> that CSMA is disabled if "macMinBE is set to zero".
>>>
>>>> I'm also not sure if we need to supprot the async mode, while the sync mode
>>>> is working. For me the async mode looks like it tries to workaround some HW
>>>> access issues.
>>>>
>>>
>>> We came to the conclusion that "sync" callback is a workaround that
>>> people can use spi_sync. :-)
>>
>> Hmmm - I don't quite understand.
>>
>> The difference is that xmit_sync blocks until the packet is transmitted,
>> while async returns immediately.
>
> Exact, and "blocking" is not what the netdev api offers by callback
> ".ndo_start_xmit".

I know.


>
>> spi_sync can be only used from context that can sleep. While spi_async
>> runs it's own queue and provides a completion callback.
>>
>> These radios can only do one thing at the time. And in both cases there are
>> queues that are being stopped while the radio driver is busy doing
>> something.
>>
>
> Yes, most transceivers has only one framebuffer. Btw: AT86RFxxx has
> really only one for rx/tx.

Yeah - the ADF7242 also has two buffers. But still 802.15.4 is 
TDD/Simplex. So either RX or TX. And in fact while TX with ACKreq, the 
RX buffer is used to store the ACK, and while RX data in the TX buffer 
might be overwritten by the ACK that is being transmitted.


>
>> So the only thing is the IF down/up issue?
>>
>
> I am not sure, I thought about that the whole day and I need to admit: I
> think both ways have some races _currently_.
>
> What I am suppose is that we can easier deal which such races when we
> use xmit_async without having a workqueue in the middle of
> "ndo_start_xmit" and "driver xmit" callback.


I don't see the difference with using spi_async here.
Instead of your own workqueue. You defer the work to the SPI master 
queue (kthread)...
In both cases all messages are sequential. And I don't see any timing 
benefit. It actually makes things more complex.
Think about the case during xmit where you have to check status -> write 
some registers -> check some other status -> write some more 
regsiters/data -> ...

For this to work you have to chain multiple async messages.
And rely on the goodwill of the SPI master kthread to pump them out.



>
> Furthermore, with MLME-ops we need to send frames out which are triggered
> by a workqueue as well, mac80211 MLME-ops do the same.
>
> But there exist a difference by starting a xmit workqueue from "ndo_start_xmit"
> or "netlink command".
>
>
> ----
>
> Btw: while thinking the whole day I detected a "deadlock" (maybe
> somebody can confirm it).
>
> At [1], we have ndo_stop callback which is called under RTNL lock. This
> will call ieee802154_stop_device, which also flushed the xmit workqueue
> (That means it will wait until the workqueue is complete scheduled).
> Now the "worker" callback of the xmit workqueue also hold the RTNL lock,
> see [2]. If this is called when "stop callback" [1] is waiting for the
> workqueue it will wait forever, because the xmit workqueue will wait on
> RTNL lock.


That looks racy.
In the xmit_async path there is no such lock.
I don't know why sync versus async would need it
- remove it altogether with the netif_running check.


>
> That the workqueue held the rtnl lock while transmit was one of my
> earlier changes, where somebody had some issues when doing ifdown. Maybe
> this change do "something" which fixed it but the real issue was an
> another. Now, when stop doing "flush_workqueue" and all netdev queues
> (which belongs to a phy) are stopped, then there can't be a 802.15.4
> driver "stop" callback.
>
> Also if we wait for the workqueue and the netdev queue was stopped
> before, it will be awake again because the driver will finish it.
>
>
> I have some headache now and I think we need to discuss again about the
> correct handling of "transmit" and look if everything works fine then
> without races, but it isn't easy. What I currently think is that
> "xmit_async" goes to the right direction, that we don't need to deal
> with the loosing context of "ndo_start_xmit" when call driver xmit
> callback.
>
>> The ADF7242 would actually return an error if the packet wasn’t sent
>> or ACKed by the receiver. It's still looks like this information
>> isn’t being used anywhere.
>>
>
> Yes, MLME-ops needs this option, we don't have currently any functionality to
> tell the "why transmit failed" to upper-layers (mac802154).
>
> Such stats should be available by "iwpan", like "iw station dump" in wireless.
> Then you can do some statistic counts. (Maybe the first use case to see
> that it works.)
>
>> Not a big deal - but in addition received ACKs (that would potentially
>> indicate that the packet was successfully delivered) cause warnings and are
>> completely dropped as well.
>>
>
> - Alex
>
> [0] ISBN 978-0-7381-6684-1 STDPD97126 (I hope they handle revisions of
> 				       802.15.4 standard with this
> 				       number).
>      or simple use this link (found by google):
>      http://ecee.colorado.edu/~liue/teaching/comm_standards/2015S_zigbee/802.15.4-2011.pdf
>      it's pdf page 43.
> [1] http://lxr.free-electrons.com/source/net/mac802154/iface.c#L333
> [2] http://lxr.free-electrons.com/source/net/mac802154/tx.c#L41
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-08 16:02                   ` Michael Hennerich
  (?)
@ 2015-12-09 10:31                   ` Alexander Aring
  2015-12-10  0:04                     ` Stefan Schmidt
  -1 siblings, 1 reply; 36+ messages in thread
From: Alexander Aring @ 2015-12-09 10:31 UTC (permalink / raw)
  To: Michael Hennerich
  Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth, chrisfriedt

Hi,

On Tue, Dec 08, 2015 at 05:02:15PM +0100, Michael Hennerich wrote:
> On 12/08/2015 04:53 PM, Alexander Aring wrote:
> >Hi,
> >
> >On Tue, Dec 08, 2015 at 09:07:43AM +0100, Michael Hennerich wrote:
> >>On 12/07/2015 03:12 PM, Alexander Aring wrote:
> >>>On Mon, Dec 07, 2015 at 02:34:29PM +0100, Michael Hennerich wrote:
> >>>...
> >>>>>Stefan, maybe you testing with the ATUSB firmware which going _not_
> >>>>>into RX_AACK_ON. This was one of my lastest changes according to the
> >>>>>ATUSB firmware. Please check that, otherwise the atusb doesn't send
> >>>>>ack frames if ackrequest bit is set after receiving.
> >>>>
> >>>>I was wondering where can I buy the ATUSB?
> >>>>On the pulster page I can't find it.
> >>>>
> >>>
> >>>They are all out of stock, everywhere. I cc Werner maybe he will bring
> >>>back the atusb again. He do his stuff all open source and a possible
> >>>solution would be a Kickstarter project.
> >>>
> >>>Another option would be:
> >>>
> >>>  - Produce your own atusb
> >>>  - I know that "Christopher Friedt" produced some, maybe he will give/sell
> >>>    some. :-) I cc'ed him here.
> >>>  - use the experimental firmware [1] on RZUSBStick [0] support. Basics
> >>>    functionality only and not stable such atusb. I ported the firmware
> >>>    to this stick, it can be used by atusb driver. The transceiver is a
> >>>    different -> at86rf230... and this transceiver we also doesn't
> >>>    support by the at86rf230 because it's too different and a huge
> >>>    errata.
> >>
> >>Would be nice to have a USB MAC8021511.
> >>Guess I need to wait for the next lot being produced.
> >>
> >>
> >
> >ok. The RZUSBSTICK is still available but very poor state.
> >
> >>>
> >>>>In general why is the framework not requesting ACKs on all non broadcast
> >>>>DATA frames?
> >>>>
> >>>>There is an option if turned on - it'll also request ACks on broadcasts...
> >>>
> >>>I suppose you use the af802154 socket family. I didn't touched the code
> >>>and this socket family is full of bugs. We need a replacement for that.
> >>>
> >>>The socket code which I was working is AF_PACKET.
> >>>
> >>>In case of AF_PACKET:
> >>>
> >>>  dgram sockets: extended address and intra_pan communciaton only. The
> >>>                 AF_PACKET UAPI doesn't offer more address information.
> >>>		We do a mapping to this currently, other option would be
> >>>		to disable DGRAM on AF_PACKET. It's not possible to send
> >>>		broadcast frames with that.
> >>>		If you need that, something similar like af802154 should
> >>>		be available, but it's currently broken.
> >>>
> >>>  raw sockets:   You can build the mac frame inside userspace with
> >>>                 complete control fc and address settings. We don't check
> >>>		this frame if it's valid. This is not a bug.
> >>>
> >>>
> >>>and 6LoWPAN:
> >>>
> >>>6LoWPAN doesn't do that, the check should be at [2]. If it's currently
> >>>broken at your side?
> >>
> >>Maybe - I still use the lowpan-tools.
> >>And it locks like ACKs must be enabled via NL802154_CMD_SET_ACKREQ_DEFAULT,
> >>which lowpan-tools doesn't do.
> >>Wondering why it's not by default enabled...
> >>So I patched my kernel, probably in the wrong place.
> >>
> >
> >The lowpan-tools are deprecated. The official website is back (from what
> >I recovered), you can get wpan-tools at [0].
> >
> >The ackreq_default is false by default (which indicates no ARET
> >handling/no ackrequest bit is set) because this requires that the other
> >side can deal with ack handling. Otherwise the node will get the frame 3
> >times.
> >
> >The conclusion is to set the ack handling default to false, if you know
> >your network can do ack handling then you can turn it on with the
> >wpan-tools.
> >
> >Do you think we should enable it by default and if there are non IEEE
> >802.15.4 valid nodes around which doesn't support ACK handling we should
> >simple ignore that?
> 
> I thought that ACK handling is mandatory for 802.15.4.

It is, otherwise some MLME-ops would not functional. The _open_ _source_
reality outside looks different. There are of course nodes which doesn't
support ack handling (I have some contiki nodes with cc2520, but so far
I know contiki also handles dataframes with 6LoWPAN only).

I also didn't saw any OS implementation for MLME-ops :( I know the Xbee [0]
transceiver which is a "kind" of HardMAC transceiver. MLME-ops can be
triggered by right "AT-FOO" uart command.

I know that Christopher Friedt want to have some MLME features inside
the kernel and already worked on some parts for scanning.

> So if there are non compliant IEEE802154 nodes around we can turn it off.
> 
> Either way is fine with me.
> 

Okay. It's one simple switch to change it. I would wait here for Stefans
opinion about that.


- Alex

[0] https://www.sparkfun.com/datasheets/Wireless/Zigbee/XBee-Datasheet.pdf

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-09  9:53             ` Michael Hennerich
  (?)
@ 2015-12-09 14:55             ` Alexander Aring
  2015-12-09 16:09                 ` Michael Hennerich
  -1 siblings, 1 reply; 36+ messages in thread
From: Alexander Aring @ 2015-12-09 14:55 UTC (permalink / raw)
  To: Michael Hennerich; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

Hi,

On Wed, Dec 09, 2015 at 10:53:06AM +0100, Michael Hennerich wrote:
> On 12/08/2015 06:11 PM, Alexander Aring wrote:
> >Hi,
> >
> >On Tue, Dec 08, 2015 at 09:43:20AM +0100, Michael Hennerich wrote:
> >>On 12/07/2015 02:53 PM, Alexander Aring wrote:
> >>>Hi,
> >>>
> >>>On Mon, Dec 07, 2015 at 01:47:06PM +0100, Michael Hennerich wrote:
> >>>...
> >>>>>>+static struct ieee802154_ops adf7242_ops = {
> >>>>>>+    .owner = THIS_MODULE,
> >>>>>>+    .xmit_sync = adf7242_xmit,
> >>>>>>+    .ed = adf7242_ed,
> >>>>>>+    .set_channel = adf7242_channel,
> >>>>>>+    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
> >>>>>>+    .start = adf7242_start,
> >>>>>>+    .stop = adf7242_stop,
> >>>>>>+    .set_csma_params = adf7242_set_csma_params,
> >>>>>>+    .set_frame_retries = adf7242_set_frame_retries,
> >>>>>>+    .set_txpower = adf7242_set_txpower,
> >>>>>>+    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
> >>>>>>+    .set_cca_ed_level = adf7242_set_cca_ed_level,
> >>>>>
> >>>>>Nice to see so many callbacks implemented. The only things I see missing
> >>>>>is xmit_async, set_lbt and set_cca_mode. I would not make it a
> >>>>>requirements to get these hooked up before merging this patch but we
> >>>>>should consider it as todo items.
> >>>>
> >>>>The part only supports CCA mode Energy above threshold.
> >>>>Not sure what this LBT mode does on the AT86RFxxx driver.
> >>>
> >>>This is for sub 1Ghz regulations in some country (Japan/Europe) area,
> >>>there CSMA/CA accoridng 802.15.4 isn't allowed at sub 1-Ghz, that's why
> >>>they introduced LBT.
> >>>
> >>>That reminds me to work on a regulator db, again. :-)
> >>>
> >>>Nevertheless it should not related to 2.4 Ghz global ISM band, so far I
> >>>know.
> >>>
> >>>>The ADF7242 only supports CSMA-CA and not some other listen before talk
> >>>>flavour. The only oher option is to turn CSMA-CA completly off.
> >>>
> >>>Another thing for ToDo list, add support for turning CSMA-CA handling
> >>>complete off, many transceiver has such option.
> >>>
> >>>There exists ways currently to turn off CSMA handling only by choosing
> >>>the right backoff exponents, 802.15.4 writes:
> >>>
> >>>Note that if macMinBE is set to zero, collision avoidance will be
> >>>disabled during the first iteration of this algorithm.
> >>
> >>First iteration only? And I think that is for slotted operation.
> >>I wouldn't overload MinBe with an option to disable CSMA-CA.
> >>Maybe add a new command?
> >>
> >>
> >
> >"CSMA" != "CSMA-CA"
> >
> >The calculation is for backoff periods (aUnitBackoffPeriod) is:
> >
> >2^(MINBE + 1) - 1
> >
> >doesn't matter if slotted/unslotted. See page 23 at [0].
> >
> >By disable CSMA-CA I usually assume that the CCA status will not
> >performed. Disable CSMA -> CCA status will be performed.
> >
> >I agree to add an own command to disable "CSMA-CA", to disable "CSMA" we
> >have minBe.
> >
> 
> Hi Alex,
> 
> ok - I see.
> 

ok.

Anyway the backoff period should be one aUnitBackoffPeriod, because

2^(0 + 1) - 1 = 1;

I excepted zero. :-) Maybe one aUnitBackoffPeriod doesn't matter then.

> 
> >>>
> >>>Okay then another ToDo for wpan-tools would be to make a nice printout
> >>>that CSMA is disabled if "macMinBE is set to zero".
> >>>
> >>>>I'm also not sure if we need to supprot the async mode, while the sync mode
> >>>>is working. For me the async mode looks like it tries to workaround some HW
> >>>>access issues.
> >>>>
> >>>
> >>>We came to the conclusion that "sync" callback is a workaround that
> >>>people can use spi_sync. :-)
> >>
> >>Hmmm - I don't quite understand.
> >>
> >>The difference is that xmit_sync blocks until the packet is transmitted,
> >>while async returns immediately.
> >
> >Exact, and "blocking" is not what the netdev api offers by callback
> >".ndo_start_xmit".
> 
> I know.
> 
> 

ok.

> >
> >>spi_sync can be only used from context that can sleep. While spi_async
> >>runs it's own queue and provides a completion callback.
> >>
> >>These radios can only do one thing at the time. And in both cases there are
> >>queues that are being stopped while the radio driver is busy doing
> >>something.
> >>
> >
> >Yes, most transceivers has only one framebuffer. Btw: AT86RFxxx has
> >really only one for rx/tx.
> 
> Yeah - the ADF7242 also has two buffers. But still 802.15.4 is TDD/Simplex.
> So either RX or TX. And in fact while TX with ACKreq, the RX buffer is used
> to store the ACK, and while RX data in the TX buffer might be overwritten by
> the ACK that is being transmitted.
> 

Is the buffer locked somehow in a "safe" mode? E.g. rx/tx irq ensure
that you can (on rx) the buffer can't be overwritten by other frames.
(On tx) the on tx complete irq you are sure the transmit is done?

This is something which AT86RFxxx provides, well there exists _under_
real time condition, we can do some read while receive/write buffer while
transmit. But we don't use such feature, we use the "safe" mode.

> 
> >
> >>So the only thing is the IF down/up issue?
> >>
> >
> >I am not sure, I thought about that the whole day and I need to admit: I
> >think both ways have some races _currently_.
> >
> >What I am suppose is that we can easier deal which such races when we
> >use xmit_async without having a workqueue in the middle of
> >"ndo_start_xmit" and "driver xmit" callback.
> 
> 
> I don't see the difference with using spi_async here.

The difference was said already: "the .ndo_start_xmit callback tells you:
transmit the skb buffer _now_" (or maybe, so fast you can).

Not knowning what we side effects we will get when we doing it
delayed with a workqueue and loosing context of ".ndo_start_xmit". I
currently have no overlook (and I think only few people has it) but I
suppose the complete queue discipline also depends on that mechanism.

> Instead of your own workqueue. You defer the work to the SPI master queue
> (kthread)...
> In both cases all messages are sequential. And I don't see any timing
> benefit. It actually makes things more complex.

There exists a little timing benefits, but when we talking about
802.15.4 then this may not important. The netdev queue for transmit is
longer blocked by stop and wake.

Also "async" is always faster than "sync", the synced spi framework is
mostly build on-top of async framework with wait_for_completion.

> Think about the case during xmit where you have to check status -> write
> some registers -> check some other status -> write some more regsiters/data
> -> ...
> 

That's also what you need to do when you will call spi_async inside your
spi irq handler. (Except you use a threaded irq handler).

> For this to work you have to chain multiple async messages.

yes. My intention is to have on hotpath -> irq context, use spi_async,
for the rest of callbacks "might_sleep" is possible and you can use
synced functionality.

> And rely on the goodwill of the SPI master kthread to pump them out.
> 

My issue is not that "the background will do the same", it's about to
start transmit.

> >
> >Furthermore, with MLME-ops we need to send frames out which are triggered
> >by a workqueue as well, mac80211 MLME-ops do the same.
> >
> >But there exist a difference by starting a xmit workqueue from "ndo_start_xmit"
> >or "netlink command".
> >
> >
> >----
> >
> >Btw: while thinking the whole day I detected a "deadlock" (maybe
> >somebody can confirm it).
> >
> >At [1], we have ndo_stop callback which is called under RTNL lock. This
> >will call ieee802154_stop_device, which also flushed the xmit workqueue
> >(That means it will wait until the workqueue is complete scheduled).
> >Now the "worker" callback of the xmit workqueue also hold the RTNL lock,
> >see [2]. If this is called when "stop callback" [1] is waiting for the
> >workqueue it will wait forever, because the xmit workqueue will wait on
> >RTNL lock.
> 
> 
> That looks racy.
> In the xmit_async path there is no such lock.
> I don't know why sync versus async would need it.

The ".ndo_start_xmit" says here "transmit the socket buffer now" like
what I said above. Others netdev operation (Okay, start/stop can't
happend here but others which are not protected by "flush_workqueue",
means if interface still up can be handled.) can be occured between
".ndo_start_xmit" and schedule the workqueue.

> - remove it altogether with the netif_running check.
> 

ok.


Anyway, I am willing to ack the driver with xmit_sync callback. I/Somebody
can try to do some work on it. Then you can test sync vs async on your own
and decide if you see an improvement.

- Alex

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-09 14:55             ` Alexander Aring
@ 2015-12-09 16:09                 ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-09 16:09 UTC (permalink / raw)
  To: Alexander Aring; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

On 12/09/2015 03:55 PM, Alexander Aring wrote:
> Hi,
>
> On Wed, Dec 09, 2015 at 10:53:06AM +0100, Michael Hennerich wrote:
>> On 12/08/2015 06:11 PM, Alexander Aring wrote:
>>> Hi,
>>>
>>> On Tue, Dec 08, 2015 at 09:43:20AM +0100, Michael Hennerich wrote:
>>>> On 12/07/2015 02:53 PM, Alexander Aring wrote:
>>>>> Hi,
>>>>>
>>>>> On Mon, Dec 07, 2015 at 01:47:06PM +0100, Michael Hennerich wrote:
>>>>> ...
>>>>>>>> +static struct ieee802154_ops adf7242_ops = {
>>>>>>>> +    .owner = THIS_MODULE,
>>>>>>>> +    .xmit_sync = adf7242_xmit,
>>>>>>>> +    .ed = adf7242_ed,
>>>>>>>> +    .set_channel = adf7242_channel,
>>>>>>>> +    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
>>>>>>>> +    .start = adf7242_start,
>>>>>>>> +    .stop = adf7242_stop,
>>>>>>>> +    .set_csma_params = adf7242_set_csma_params,
>>>>>>>> +    .set_frame_retries = adf7242_set_frame_retries,
>>>>>>>> +    .set_txpower = adf7242_set_txpower,
>>>>>>>> +    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
>>>>>>>> +    .set_cca_ed_level = adf7242_set_cca_ed_level,
>>>>>>>
>>>>>>> Nice to see so many callbacks implemented. The only things I see missing
>>>>>>> is xmit_async, set_lbt and set_cca_mode. I would not make it a
>>>>>>> requirements to get these hooked up before merging this patch but we
>>>>>>> should consider it as todo items.
>>>>>>
>>>>>> The part only supports CCA mode Energy above threshold.
>>>>>> Not sure what this LBT mode does on the AT86RFxxx driver.
>>>>>
>>>>> This is for sub 1Ghz regulations in some country (Japan/Europe) area,
>>>>> there CSMA/CA accoridng 802.15.4 isn't allowed at sub 1-Ghz, that's why
>>>>> they introduced LBT.
>>>>>
>>>>> That reminds me to work on a regulator db, again. :-)
>>>>>
>>>>> Nevertheless it should not related to 2.4 Ghz global ISM band, so far I
>>>>> know.
>>>>>
>>>>>> The ADF7242 only supports CSMA-CA and not some other listen before talk
>>>>>> flavour. The only oher option is to turn CSMA-CA completly off.
>>>>>
>>>>> Another thing for ToDo list, add support for turning CSMA-CA handling
>>>>> complete off, many transceiver has such option.
>>>>>
>>>>> There exists ways currently to turn off CSMA handling only by choosing
>>>>> the right backoff exponents, 802.15.4 writes:
>>>>>
>>>>> Note that if macMinBE is set to zero, collision avoidance will be
>>>>> disabled during the first iteration of this algorithm.
>>>>
>>>> First iteration only? And I think that is for slotted operation.
>>>> I wouldn't overload MinBe with an option to disable CSMA-CA.
>>>> Maybe add a new command?
>>>>
>>>>
>>>
>>> "CSMA" != "CSMA-CA"
>>>
>>> The calculation is for backoff periods (aUnitBackoffPeriod) is:
>>>
>>> 2^(MINBE + 1) - 1
>>>
>>> doesn't matter if slotted/unslotted. See page 23 at [0].
>>>
>>> By disable CSMA-CA I usually assume that the CCA status will not
>>> performed. Disable CSMA -> CCA status will be performed.
>>>
>>> I agree to add an own command to disable "CSMA-CA", to disable "CSMA" we
>>> have minBe.
>>>
>>
>> Hi Alex,
>>
>> ok - I see.
>>
>
> ok.
>
> Anyway the backoff period should be one aUnitBackoffPeriod, because
>
> 2^(0 + 1) - 1 = 1;
>
> I excepted zero. :-) Maybe one aUnitBackoffPeriod doesn't matter then.
>
>>
>>>>>
>>>>> Okay then another ToDo for wpan-tools would be to make a nice printout
>>>>> that CSMA is disabled if "macMinBE is set to zero".
>>>>>
>>>>>> I'm also not sure if we need to supprot the async mode, while the sync mode
>>>>>> is working. For me the async mode looks like it tries to workaround some HW
>>>>>> access issues.
>>>>>>
>>>>>
>>>>> We came to the conclusion that "sync" callback is a workaround that
>>>>> people can use spi_sync. :-)
>>>>
>>>> Hmmm - I don't quite understand.
>>>>
>>>> The difference is that xmit_sync blocks until the packet is transmitted,
>>>> while async returns immediately.
>>>
>>> Exact, and "blocking" is not what the netdev api offers by callback
>>> ".ndo_start_xmit".
>>
>> I know.
>>
>>
>
> ok.
>
>>>
>>>> spi_sync can be only used from context that can sleep. While spi_async
>>>> runs it's own queue and provides a completion callback.
>>>>
>>>> These radios can only do one thing at the time. And in both cases there are
>>>> queues that are being stopped while the radio driver is busy doing
>>>> something.
>>>>
>>>
>>> Yes, most transceivers has only one framebuffer. Btw: AT86RFxxx has
>>> really only one for rx/tx.
>>
>> Yeah - the ADF7242 also has two buffers. But still 802.15.4 is TDD/Simplex.
>> So either RX or TX. And in fact while TX with ACKreq, the RX buffer is used
>> to store the ACK, and while RX data in the TX buffer might be overwritten by
>> the ACK that is being transmitted.
>>
>
> Is the buffer locked somehow in a "safe" mode? E.g. rx/tx irq ensure
> that you can (on rx) the buffer can't be overwritten by other frames.
> (On tx) the on tx complete irq you are sure the transmit is done?

Hi Alex,

There are automatic TX_CSMA_CA to RX and other turnaround modes.
But afaict we're better off not using them.

The way it is set-up right now is that we always return to state PHY_READY.

On TX - we force CMD_RC_PHY_RDY (to exit RX), write the packet to the TX 
buf and then set CMD_RC_CSMACA. Which then starts the CSMA_CA algo. and 
generates an interrupt when the packet was transmitted and the ACK was 
or was not received. We're then again in state PHY_READY. The threaded 
IRQ handler saves the CSMA_CA status and triggers the completion and 
xmit_sync returns and enables CMD_RC_RX.

On RX we receive an interrupt when a valid packet is received which 
passes the frame filtering. The device enters state PHY_READY once the 
ACK was sent. Therefore we always wait for state PHY_READY in the 
threaded ISR. Ideally we would get the interrupt only after the ACK was 
sent if requested. (I brought this up for a firmware feature, maybe it 
gets implemented some day).


>
> This is something which AT86RFxxx provides, well there exists _under_
> real time condition, we can do some read while receive/write buffer while
> transmit. But we don't use such feature, we use the "safe" mode.
>
>>
>>>
>>>> So the only thing is the IF down/up issue?
>>>>
>>>
>>> I am not sure, I thought about that the whole day and I need to admit: I
>>> think both ways have some races _currently_.
>>>
>>> What I am suppose is that we can easier deal which such races when we
>>> use xmit_async without having a workqueue in the middle of
>>> "ndo_start_xmit" and "driver xmit" callback.
>>
>>
>> I don't see the difference with using spi_async here.
>
> The difference was said already: "the .ndo_start_xmit callback tells you:
> transmit the skb buffer _now_" (or maybe, so fast you can).
>
> Not knowning what we side effects we will get when we doing it
> delayed with a workqueue and loosing context of ".ndo_start_xmit". I
> currently have no overlook (and I think only few people has it) but I
> suppose the complete queue discipline also depends on that mechanism.
>
>> Instead of your own workqueue. You defer the work to the SPI master queue
>> (kthread)...
>> In both cases all messages are sequential. And I don't see any timing
>> benefit. It actually makes things more complex.
>
> There exists a little timing benefits, but when we talking about
> 802.15.4 then this may not important. The netdev queue for transmit is
> longer blocked by stop and wake.
>
> Also "async" is always faster than "sync", the synced spi framework is
> mostly build on-top of async framework with wait_for_completion.
>
>> Think about the case during xmit where you have to check status -> write
>> some registers -> check some other status -> write some more regsiters/data
>> -> ...
>>
>
> That's also what you need to do when you will call spi_async inside your
> spi irq handler. (Except you use a threaded irq handler).
>
>> For this to work you have to chain multiple async messages.
>
> yes. My intention is to have on hotpath -> irq context, use spi_async,
> for the rest of callbacks "might_sleep" is possible and you can use
> synced functionality.
>
>> And rely on the goodwill of the SPI master kthread to pump them out.
>>
>
> My issue is not that "the background will do the same", it's about to
> start transmit.
>
>>>
>>> Furthermore, with MLME-ops we need to send frames out which are triggered
>>> by a workqueue as well, mac80211 MLME-ops do the same.
>>>
>>> But there exist a difference by starting a xmit workqueue from "ndo_start_xmit"
>>> or "netlink command".
>>>
>>>
>>> ----
>>>
>>> Btw: while thinking the whole day I detected a "deadlock" (maybe
>>> somebody can confirm it).
>>>
>>> At [1], we have ndo_stop callback which is called under RTNL lock. This
>>> will call ieee802154_stop_device, which also flushed the xmit workqueue
>>> (That means it will wait until the workqueue is complete scheduled).
>>> Now the "worker" callback of the xmit workqueue also hold the RTNL lock,
>>> see [2]. If this is called when "stop callback" [1] is waiting for the
>>> workqueue it will wait forever, because the xmit workqueue will wait on
>>> RTNL lock.
>>
>>
>> That looks racy.
>> In the xmit_async path there is no such lock.
>> I don't know why sync versus async would need it.
>
> The ".ndo_start_xmit" says here "transmit the socket buffer now" like
> what I said above. Others netdev operation (Okay, start/stop can't
> happend here but others which are not protected by "flush_workqueue",
> means if interface still up can be handled.) can be occured between
> ".ndo_start_xmit" and schedule the workqueue.
>
>> - remove it altogether with the netif_running check.
>>
>
> ok.
>
>
> Anyway, I am willing to ack the driver with xmit_sync callback. I/Somebody
> can try to do some work on it. Then you can test sync vs async on your own
> and decide if you see an improvement.
>
> - Alex
>

Great. I looked a bit around and all wired or wireless SPI network 
drivers I’ve found all use workqueue and spi_sync in xmit.

-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
@ 2015-12-09 16:09                 ` Michael Hennerich
  0 siblings, 0 replies; 36+ messages in thread
From: Michael Hennerich @ 2015-12-09 16:09 UTC (permalink / raw)
  To: Alexander Aring; +Cc: Stefan Schmidt, marcel, linux-wpan, linux-bluetooth

On 12/09/2015 03:55 PM, Alexander Aring wrote:
> Hi,
>
> On Wed, Dec 09, 2015 at 10:53:06AM +0100, Michael Hennerich wrote:
>> On 12/08/2015 06:11 PM, Alexander Aring wrote:
>>> Hi,
>>>
>>> On Tue, Dec 08, 2015 at 09:43:20AM +0100, Michael Hennerich wrote:
>>>> On 12/07/2015 02:53 PM, Alexander Aring wrote:
>>>>> Hi,
>>>>>
>>>>> On Mon, Dec 07, 2015 at 01:47:06PM +0100, Michael Hennerich wrote:
>>>>> ...
>>>>>>>> +static struct ieee802154_ops adf7242_ops = {
>>>>>>>> +    .owner = THIS_MODULE,
>>>>>>>> +    .xmit_sync = adf7242_xmit,
>>>>>>>> +    .ed = adf7242_ed,
>>>>>>>> +    .set_channel = adf7242_channel,
>>>>>>>> +    .set_hw_addr_filt = adf7242_set_hw_addr_filt,
>>>>>>>> +    .start = adf7242_start,
>>>>>>>> +    .stop = adf7242_stop,
>>>>>>>> +    .set_csma_params = adf7242_set_csma_params,
>>>>>>>> +    .set_frame_retries = adf7242_set_frame_retries,
>>>>>>>> +    .set_txpower = adf7242_set_txpower,
>>>>>>>> +    .set_promiscuous_mode = adf7242_set_promiscuous_mode,
>>>>>>>> +    .set_cca_ed_level = adf7242_set_cca_ed_level,
>>>>>>>
>>>>>>> Nice to see so many callbacks implemented. The only things I see missing
>>>>>>> is xmit_async, set_lbt and set_cca_mode. I would not make it a
>>>>>>> requirements to get these hooked up before merging this patch but we
>>>>>>> should consider it as todo items.
>>>>>>
>>>>>> The part only supports CCA mode Energy above threshold.
>>>>>> Not sure what this LBT mode does on the AT86RFxxx driver.
>>>>>
>>>>> This is for sub 1Ghz regulations in some country (Japan/Europe) area,
>>>>> there CSMA/CA accoridng 802.15.4 isn't allowed at sub 1-Ghz, that's why
>>>>> they introduced LBT.
>>>>>
>>>>> That reminds me to work on a regulator db, again. :-)
>>>>>
>>>>> Nevertheless it should not related to 2.4 Ghz global ISM band, so far I
>>>>> know.
>>>>>
>>>>>> The ADF7242 only supports CSMA-CA and not some other listen before talk
>>>>>> flavour. The only oher option is to turn CSMA-CA completly off.
>>>>>
>>>>> Another thing for ToDo list, add support for turning CSMA-CA handling
>>>>> complete off, many transceiver has such option.
>>>>>
>>>>> There exists ways currently to turn off CSMA handling only by choosing
>>>>> the right backoff exponents, 802.15.4 writes:
>>>>>
>>>>> Note that if macMinBE is set to zero, collision avoidance will be
>>>>> disabled during the first iteration of this algorithm.
>>>>
>>>> First iteration only? And I think that is for slotted operation.
>>>> I wouldn't overload MinBe with an option to disable CSMA-CA.
>>>> Maybe add a new command?
>>>>
>>>>
>>>
>>> "CSMA" != "CSMA-CA"
>>>
>>> The calculation is for backoff periods (aUnitBackoffPeriod) is:
>>>
>>> 2^(MINBE + 1) - 1
>>>
>>> doesn't matter if slotted/unslotted. See page 23 at [0].
>>>
>>> By disable CSMA-CA I usually assume that the CCA status will not
>>> performed. Disable CSMA -> CCA status will be performed.
>>>
>>> I agree to add an own command to disable "CSMA-CA", to disable "CSMA" we
>>> have minBe.
>>>
>>
>> Hi Alex,
>>
>> ok - I see.
>>
>
> ok.
>
> Anyway the backoff period should be one aUnitBackoffPeriod, because
>
> 2^(0 + 1) - 1 = 1;
>
> I excepted zero. :-) Maybe one aUnitBackoffPeriod doesn't matter then.
>
>>
>>>>>
>>>>> Okay then another ToDo for wpan-tools would be to make a nice printout
>>>>> that CSMA is disabled if "macMinBE is set to zero".
>>>>>
>>>>>> I'm also not sure if we need to supprot the async mode, while the sync mode
>>>>>> is working. For me the async mode looks like it tries to workaround some HW
>>>>>> access issues.
>>>>>>
>>>>>
>>>>> We came to the conclusion that "sync" callback is a workaround that
>>>>> people can use spi_sync. :-)
>>>>
>>>> Hmmm - I don't quite understand.
>>>>
>>>> The difference is that xmit_sync blocks until the packet is transmitted,
>>>> while async returns immediately.
>>>
>>> Exact, and "blocking" is not what the netdev api offers by callback
>>> ".ndo_start_xmit".
>>
>> I know.
>>
>>
>
> ok.
>
>>>
>>>> spi_sync can be only used from context that can sleep. While spi_async
>>>> runs it's own queue and provides a completion callback.
>>>>
>>>> These radios can only do one thing at the time. And in both cases there are
>>>> queues that are being stopped while the radio driver is busy doing
>>>> something.
>>>>
>>>
>>> Yes, most transceivers has only one framebuffer. Btw: AT86RFxxx has
>>> really only one for rx/tx.
>>
>> Yeah - the ADF7242 also has two buffers. But still 802.15.4 is TDD/Simplex.
>> So either RX or TX. And in fact while TX with ACKreq, the RX buffer is used
>> to store the ACK, and while RX data in the TX buffer might be overwritten by
>> the ACK that is being transmitted.
>>
>
> Is the buffer locked somehow in a "safe" mode? E.g. rx/tx irq ensure
> that you can (on rx) the buffer can't be overwritten by other frames.
> (On tx) the on tx complete irq you are sure the transmit is done?

Hi Alex,

There are automatic TX_CSMA_CA to RX and other turnaround modes.
But afaict we're better off not using them.

The way it is set-up right now is that we always return to state PHY_READY.

On TX - we force CMD_RC_PHY_RDY (to exit RX), write the packet to the TX 
buf and then set CMD_RC_CSMACA. Which then starts the CSMA_CA algo. and 
generates an interrupt when the packet was transmitted and the ACK was 
or was not received. We're then again in state PHY_READY. The threaded 
IRQ handler saves the CSMA_CA status and triggers the completion and 
xmit_sync returns and enables CMD_RC_RX.

On RX we receive an interrupt when a valid packet is received which 
passes the frame filtering. The device enters state PHY_READY once the 
ACK was sent. Therefore we always wait for state PHY_READY in the 
threaded ISR. Ideally we would get the interrupt only after the ACK was 
sent if requested. (I brought this up for a firmware feature, maybe it 
gets implemented some day).


>
> This is something which AT86RFxxx provides, well there exists _under_
> real time condition, we can do some read while receive/write buffer while
> transmit. But we don't use such feature, we use the "safe" mode.
>
>>
>>>
>>>> So the only thing is the IF down/up issue?
>>>>
>>>
>>> I am not sure, I thought about that the whole day and I need to admit: I
>>> think both ways have some races _currently_.
>>>
>>> What I am suppose is that we can easier deal which such races when we
>>> use xmit_async without having a workqueue in the middle of
>>> "ndo_start_xmit" and "driver xmit" callback.
>>
>>
>> I don't see the difference with using spi_async here.
>
> The difference was said already: "the .ndo_start_xmit callback tells you:
> transmit the skb buffer _now_" (or maybe, so fast you can).
>
> Not knowning what we side effects we will get when we doing it
> delayed with a workqueue and loosing context of ".ndo_start_xmit". I
> currently have no overlook (and I think only few people has it) but I
> suppose the complete queue discipline also depends on that mechanism.
>
>> Instead of your own workqueue. You defer the work to the SPI master queue
>> (kthread)...
>> In both cases all messages are sequential. And I don't see any timing
>> benefit. It actually makes things more complex.
>
> There exists a little timing benefits, but when we talking about
> 802.15.4 then this may not important. The netdev queue for transmit is
> longer blocked by stop and wake.
>
> Also "async" is always faster than "sync", the synced spi framework is
> mostly build on-top of async framework with wait_for_completion.
>
>> Think about the case during xmit where you have to check status -> write
>> some registers -> check some other status -> write some more regsiters/data
>> -> ...
>>
>
> That's also what you need to do when you will call spi_async inside your
> spi irq handler. (Except you use a threaded irq handler).
>
>> For this to work you have to chain multiple async messages.
>
> yes. My intention is to have on hotpath -> irq context, use spi_async,
> for the rest of callbacks "might_sleep" is possible and you can use
> synced functionality.
>
>> And rely on the goodwill of the SPI master kthread to pump them out.
>>
>
> My issue is not that "the background will do the same", it's about to
> start transmit.
>
>>>
>>> Furthermore, with MLME-ops we need to send frames out which are triggered
>>> by a workqueue as well, mac80211 MLME-ops do the same.
>>>
>>> But there exist a difference by starting a xmit workqueue from "ndo_start_xmit"
>>> or "netlink command".
>>>
>>>
>>> ----
>>>
>>> Btw: while thinking the whole day I detected a "deadlock" (maybe
>>> somebody can confirm it).
>>>
>>> At [1], we have ndo_stop callback which is called under RTNL lock. This
>>> will call ieee802154_stop_device, which also flushed the xmit workqueue
>>> (That means it will wait until the workqueue is complete scheduled).
>>> Now the "worker" callback of the xmit workqueue also hold the RTNL lock,
>>> see [2]. If this is called when "stop callback" [1] is waiting for the
>>> workqueue it will wait forever, because the xmit workqueue will wait on
>>> RTNL lock.
>>
>>
>> That looks racy.
>> In the xmit_async path there is no such lock.
>> I don't know why sync versus async would need it.
>
> The ".ndo_start_xmit" says here "transmit the socket buffer now" like
> what I said above. Others netdev operation (Okay, start/stop can't
> happend here but others which are not protected by "flush_workqueue",
> means if interface still up can be handled.) can be occured between
> ".ndo_start_xmit" and schedule the workqueue.
>
>> - remove it altogether with the netif_running check.
>>
>
> ok.
>
>
> Anyway, I am willing to ack the driver with xmit_sync callback. I/Somebody
> can try to do some work on it. Then you can test sync vs async on your own
> and decide if you see an improvement.
>
> - Alex
>

Great. I looked a bit around and all wired or wireless SPI network 
drivers I’ve found all use workqueue and spi_sync in xmit.

-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154
  2015-12-09 10:31                   ` Alexander Aring
@ 2015-12-10  0:04                     ` Stefan Schmidt
  0 siblings, 0 replies; 36+ messages in thread
From: Stefan Schmidt @ 2015-12-10  0:04 UTC (permalink / raw)
  To: Alexander Aring, Michael Hennerich
  Cc: marcel, linux-wpan, linux-bluetooth, chrisfriedt

Hello.

On 09/12/15 11:31, Alexander Aring wrote:
> Hi,
>
> On Tue, Dec 08, 2015 at 05:02:15PM +0100, Michael Hennerich wrote:
>> On 12/08/2015 04:53 PM, Alexander Aring wrote:
>>> Hi,
>>>
>>> On Tue, Dec 08, 2015 at 09:07:43AM +0100, Michael Hennerich wrote:
>>>> On 12/07/2015 03:12 PM, Alexander Aring wrote:
>>>>> On Mon, Dec 07, 2015 at 02:34:29PM +0100, Michael Hennerich wrote:
>>>>> ...
>>>>>>> Stefan, maybe you testing with the ATUSB firmware which going _not_
>>>>>>> into RX_AACK_ON. This was one of my lastest changes according to the
>>>>>>> ATUSB firmware. Please check that, otherwise the atusb doesn't send
>>>>>>> ack frames if ackrequest bit is set after receiving.
>>>>>> I was wondering where can I buy the ATUSB?
>>>>>> On the pulster page I can't find it.
>>>>>>
>>>>> They are all out of stock, everywhere. I cc Werner maybe he will bring
>>>>> back the atusb again. He do his stuff all open source and a possible
>>>>> solution would be a Kickstarter project.
>>>>>
>>>>> Another option would be:
>>>>>
>>>>>   - Produce your own atusb
>>>>>   - I know that "Christopher Friedt" produced some, maybe he will give/sell
>>>>>     some. :-) I cc'ed him here.
>>>>>   - use the experimental firmware [1] on RZUSBStick [0] support. Basics
>>>>>     functionality only and not stable such atusb. I ported the firmware
>>>>>     to this stick, it can be used by atusb driver. The transceiver is a
>>>>>     different -> at86rf230... and this transceiver we also doesn't
>>>>>     support by the at86rf230 because it's too different and a huge
>>>>>     errata.
>>>> Would be nice to have a USB MAC8021511.
>>>> Guess I need to wait for the next lot being produced.
>>>>
>>>>
>>> ok. The RZUSBSTICK is still available but very poor state.
>>>
>>>>>> In general why is the framework not requesting ACKs on all non broadcast
>>>>>> DATA frames?
>>>>>>
>>>>>> There is an option if turned on - it'll also request ACks on broadcasts...
>>>>> I suppose you use the af802154 socket family. I didn't touched the code
>>>>> and this socket family is full of bugs. We need a replacement for that.
>>>>>
>>>>> The socket code which I was working is AF_PACKET.
>>>>>
>>>>> In case of AF_PACKET:
>>>>>
>>>>>   dgram sockets: extended address and intra_pan communciaton only. The
>>>>>                  AF_PACKET UAPI doesn't offer more address information.
>>>>> 		We do a mapping to this currently, other option would be
>>>>> 		to disable DGRAM on AF_PACKET. It's not possible to send
>>>>> 		broadcast frames with that.
>>>>> 		If you need that, something similar like af802154 should
>>>>> 		be available, but it's currently broken.
>>>>>
>>>>>   raw sockets:   You can build the mac frame inside userspace with
>>>>>                  complete control fc and address settings. We don't check
>>>>> 		this frame if it's valid. This is not a bug.
>>>>>
>>>>>
>>>>> and 6LoWPAN:
>>>>>
>>>>> 6LoWPAN doesn't do that, the check should be at [2]. If it's currently
>>>>> broken at your side?
>>>> Maybe - I still use the lowpan-tools.
>>>> And it locks like ACKs must be enabled via NL802154_CMD_SET_ACKREQ_DEFAULT,
>>>> which lowpan-tools doesn't do.
>>>> Wondering why it's not by default enabled...
>>>> So I patched my kernel, probably in the wrong place.
>>>>
>>> The lowpan-tools are deprecated. The official website is back (from what
>>> I recovered), you can get wpan-tools at [0].
>>>
>>> The ackreq_default is false by default (which indicates no ARET
>>> handling/no ackrequest bit is set) because this requires that the other
>>> side can deal with ack handling. Otherwise the node will get the frame 3
>>> times.
>>>
>>> The conclusion is to set the ack handling default to false, if you know
>>> your network can do ack handling then you can turn it on with the
>>> wpan-tools.
>>>
>>> Do you think we should enable it by default and if there are non IEEE
>>> 802.15.4 valid nodes around which doesn't support ACK handling we should
>>> simple ignore that?
>> I thought that ACK handling is mandatory for 802.15.4.
> It is, otherwise some MLME-ops would not functional. The _open_ _source_
> reality outside looks different. There are of course nodes which doesn't
> support ack handling (I have some contiki nodes with cc2520, but so far
> I know contiki also handles dataframes with 6LoWPAN only).
>
> I also didn't saw any OS implementation for MLME-ops :( I know the Xbee [0]
> transceiver which is a "kind" of HardMAC transceiver. MLME-ops can be
> triggered by right "AT-FOO" uart command.
>
> I know that Christopher Friedt want to have some MLME features inside
> the kernel and already worked on some parts for scanning.
>
>> So if there are non compliant IEEE802154 nodes around we can turn it off.
>>
>> Either way is fine with me.
>>
> Okay. It's one simple switch to change it. I would wait here for Stefans
> opinion about that.
>

Before we are going to switch it back on by default we really need more 
data to understand the situation in my opinion.

Pro enabled by default:
o Spec compliant
o More reliable connection as l2 cares about resend
o Needed for some MLME-ops we want to support later on

Pro disabled by default:
o Avoid problems with hardware and or software which does not support 
the ACK request bit (we need a list here)


To understand better what kind of hardware and software we have out 
there which does not support the ack requests correctly we need to look 
around.
o What hardware do we know about that does not have a hardware 
accelerated ACK handling (sometimes called automatic ACK or AACK)? The 
transceivers I have seen so far all have support for it (at86rf2xx, 
cc24xx, cc25xx, adf7242, mrf24j40)
o How is the status in other OSes for this? Do they enable the hardware 
feature? Do they have software fallback support?
   o Contiki might be hard to track here with different forks and releases.
   o What is the status in RIOT?

Not an easy answer as you can see. :) I would suggest we keep it as is 
for now (disabled by default) and try to collect some of the above 
mentioned data to base our decision on. With the need of some MLME-ops 
we might have a deal breaker here anyway.

regards
Stefan Schmidt

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2015-12-10  0:04 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-04  9:09 [PATCH] drivers/net/ieee802154/adf7242: Driver for ADF7242 MAC IEEE802154 michael.hennerich
2015-12-04  9:09 ` michael.hennerich
2015-12-04 12:07 ` Stefan Schmidt
2015-12-07 12:02   ` Stefan Schmidt
2015-12-07 12:18     ` Michael Hennerich
2015-12-07 12:18       ` Michael Hennerich
2015-12-07 13:25       ` Alexander Aring
2015-12-07 13:34         ` Michael Hennerich
2015-12-07 13:34           ` Michael Hennerich
2015-12-07 14:12           ` Alexander Aring
2015-12-08  8:07             ` Michael Hennerich
2015-12-08  8:07               ` Michael Hennerich
2015-12-08 15:53               ` Alexander Aring
2015-12-08 16:02                 ` Michael Hennerich
2015-12-08 16:02                   ` Michael Hennerich
2015-12-09 10:31                   ` Alexander Aring
2015-12-10  0:04                     ` Stefan Schmidt
2015-12-07 15:08         ` Stefan Schmidt
2015-12-07 14:54       ` Stefan Schmidt
2015-12-07 12:47   ` Michael Hennerich
2015-12-07 12:47     ` Michael Hennerich
2015-12-07 13:53     ` Alexander Aring
2015-12-08  8:43       ` Michael Hennerich
2015-12-08  8:43         ` Michael Hennerich
2015-12-08 17:11         ` Alexander Aring
2015-12-09  9:53           ` Michael Hennerich
2015-12-09  9:53             ` Michael Hennerich
2015-12-09 14:55             ` Alexander Aring
2015-12-09 16:09               ` Michael Hennerich
2015-12-09 16:09                 ` Michael Hennerich
2015-12-07 15:03     ` Stefan Schmidt
2015-12-04 12:42 ` Christopher Friedt
2015-12-04 13:34 ` kbuild test robot
2015-12-04 13:34   ` kbuild test robot
2015-12-04 13:41 ` kbuild test robot
2015-12-04 13:41   ` kbuild test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.