162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Analog Devices ADF7242 Low-Power IEEE 802.15.4 Transceiver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2009-2017 Analog Devices Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * https://www.analog.com/ADF7242 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/mutex.h> 1562306a36Sopenharmony_ci#include <linux/workqueue.h> 1662306a36Sopenharmony_ci#include <linux/spinlock.h> 1762306a36Sopenharmony_ci#include <linux/firmware.h> 1862306a36Sopenharmony_ci#include <linux/spi/spi.h> 1962306a36Sopenharmony_ci#include <linux/skbuff.h> 2062306a36Sopenharmony_ci#include <linux/of.h> 2162306a36Sopenharmony_ci#include <linux/irq.h> 2262306a36Sopenharmony_ci#include <linux/debugfs.h> 2362306a36Sopenharmony_ci#include <linux/bitops.h> 2462306a36Sopenharmony_ci#include <linux/ieee802154.h> 2562306a36Sopenharmony_ci#include <net/mac802154.h> 2662306a36Sopenharmony_ci#include <net/cfg802154.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define FIRMWARE "adf7242_firmware.bin" 2962306a36Sopenharmony_ci#define MAX_POLL_LOOPS 200 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* All Registers */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define REG_EXT_CTRL 0x100 /* RW External LNA/PA and internal PA control */ 3462306a36Sopenharmony_ci#define REG_TX_FSK_TEST 0x101 /* RW TX FSK test mode configuration */ 3562306a36Sopenharmony_ci#define REG_CCA1 0x105 /* RW RSSI threshold for CCA */ 3662306a36Sopenharmony_ci#define REG_CCA2 0x106 /* RW CCA mode configuration */ 3762306a36Sopenharmony_ci#define REG_BUFFERCFG 0x107 /* RW RX_BUFFER overwrite control */ 3862306a36Sopenharmony_ci#define REG_PKT_CFG 0x108 /* RW FCS evaluation configuration */ 3962306a36Sopenharmony_ci#define REG_DELAYCFG0 0x109 /* RW RC_RX command to SFD or sync word delay */ 4062306a36Sopenharmony_ci#define REG_DELAYCFG1 0x10A /* RW RC_TX command to TX state */ 4162306a36Sopenharmony_ci#define REG_DELAYCFG2 0x10B /* RW Mac delay extension */ 4262306a36Sopenharmony_ci#define REG_SYNC_WORD0 0x10C /* RW sync word bits [7:0] of [23:0] */ 4362306a36Sopenharmony_ci#define REG_SYNC_WORD1 0x10D /* RW sync word bits [15:8] of [23:0] */ 4462306a36Sopenharmony_ci#define REG_SYNC_WORD2 0x10E /* RW sync word bits [23:16] of [23:0] */ 4562306a36Sopenharmony_ci#define REG_SYNC_CONFIG 0x10F /* RW sync word configuration */ 4662306a36Sopenharmony_ci#define REG_RC_CFG 0x13E /* RW RX / TX packet configuration */ 4762306a36Sopenharmony_ci#define REG_RC_VAR44 0x13F /* RW RESERVED */ 4862306a36Sopenharmony_ci#define REG_CH_FREQ0 0x300 /* RW Channel Frequency Settings - Low */ 4962306a36Sopenharmony_ci#define REG_CH_FREQ1 0x301 /* RW Channel Frequency Settings - Middle */ 5062306a36Sopenharmony_ci#define REG_CH_FREQ2 0x302 /* RW Channel Frequency Settings - High */ 5162306a36Sopenharmony_ci#define REG_TX_FD 0x304 /* RW TX Frequency Deviation Register */ 5262306a36Sopenharmony_ci#define REG_DM_CFG0 0x305 /* RW RX Discriminator BW Register */ 5362306a36Sopenharmony_ci#define REG_TX_M 0x306 /* RW TX Mode Register */ 5462306a36Sopenharmony_ci#define REG_RX_M 0x307 /* RW RX Mode Register */ 5562306a36Sopenharmony_ci#define REG_RRB 0x30C /* R RSSI Readback Register */ 5662306a36Sopenharmony_ci#define REG_LRB 0x30D /* R Link Quality Readback Register */ 5762306a36Sopenharmony_ci#define REG_DR0 0x30E /* RW bits [15:8] of [15:0] data rate setting */ 5862306a36Sopenharmony_ci#define REG_DR1 0x30F /* RW bits [7:0] of [15:0] data rate setting */ 5962306a36Sopenharmony_ci#define REG_PRAMPG 0x313 /* RW RESERVED */ 6062306a36Sopenharmony_ci#define REG_TXPB 0x314 /* RW TX Packet Storage Base Address */ 6162306a36Sopenharmony_ci#define REG_RXPB 0x315 /* RW RX Packet Storage Base Address */ 6262306a36Sopenharmony_ci#define REG_TMR_CFG0 0x316 /* RW Wake up Timer Conf Register - High */ 6362306a36Sopenharmony_ci#define REG_TMR_CFG1 0x317 /* RW Wake up Timer Conf Register - Low */ 6462306a36Sopenharmony_ci#define REG_TMR_RLD0 0x318 /* RW Wake up Timer Value Register - High */ 6562306a36Sopenharmony_ci#define REG_TMR_RLD1 0x319 /* RW Wake up Timer Value Register - Low */ 6662306a36Sopenharmony_ci#define REG_TMR_CTRL 0x31A /* RW Wake up Timer Timeout flag */ 6762306a36Sopenharmony_ci#define REG_PD_AUX 0x31E /* RW Battmon enable */ 6862306a36Sopenharmony_ci#define REG_GP_CFG 0x32C /* RW GPIO Configuration */ 6962306a36Sopenharmony_ci#define REG_GP_OUT 0x32D /* RW GPIO Configuration */ 7062306a36Sopenharmony_ci#define REG_GP_IN 0x32E /* R GPIO Configuration */ 7162306a36Sopenharmony_ci#define REG_SYNT 0x335 /* RW bandwidth calibration timers */ 7262306a36Sopenharmony_ci#define REG_CAL_CFG 0x33D /* RW Calibration Settings */ 7362306a36Sopenharmony_ci#define REG_PA_BIAS 0x36E /* RW PA BIAS */ 7462306a36Sopenharmony_ci#define REG_SYNT_CAL 0x371 /* RW Oscillator and Doubler Configuration */ 7562306a36Sopenharmony_ci#define REG_IIRF_CFG 0x389 /* RW BB Filter Decimation Rate */ 7662306a36Sopenharmony_ci#define REG_CDR_CFG 0x38A /* RW CDR kVCO */ 7762306a36Sopenharmony_ci#define REG_DM_CFG1 0x38B /* RW Postdemodulator Filter */ 7862306a36Sopenharmony_ci#define REG_AGCSTAT 0x38E /* R RXBB Ref Osc Calibration Engine Readback */ 7962306a36Sopenharmony_ci#define REG_RXCAL0 0x395 /* RW RX BB filter tuning, LSB */ 8062306a36Sopenharmony_ci#define REG_RXCAL1 0x396 /* RW RX BB filter tuning, MSB */ 8162306a36Sopenharmony_ci#define REG_RXFE_CFG 0x39B /* RW RXBB Ref Osc & RXFE Calibration */ 8262306a36Sopenharmony_ci#define REG_PA_RR 0x3A7 /* RW Set PA ramp rate */ 8362306a36Sopenharmony_ci#define REG_PA_CFG 0x3A8 /* RW PA enable */ 8462306a36Sopenharmony_ci#define REG_EXTPA_CFG 0x3A9 /* RW External PA BIAS DAC */ 8562306a36Sopenharmony_ci#define REG_EXTPA_MSC 0x3AA /* RW PA Bias Mode */ 8662306a36Sopenharmony_ci#define REG_ADC_RBK 0x3AE /* R Readback temp */ 8762306a36Sopenharmony_ci#define REG_AGC_CFG1 0x3B2 /* RW GC Parameters */ 8862306a36Sopenharmony_ci#define REG_AGC_MAX 0x3B4 /* RW Slew rate */ 8962306a36Sopenharmony_ci#define REG_AGC_CFG2 0x3B6 /* RW RSSI Parameters */ 9062306a36Sopenharmony_ci#define REG_AGC_CFG3 0x3B7 /* RW RSSI Parameters */ 9162306a36Sopenharmony_ci#define REG_AGC_CFG4 0x3B8 /* RW RSSI Parameters */ 9262306a36Sopenharmony_ci#define REG_AGC_CFG5 0x3B9 /* RW RSSI & NDEC Parameters */ 9362306a36Sopenharmony_ci#define REG_AGC_CFG6 0x3BA /* RW NDEC Parameters */ 9462306a36Sopenharmony_ci#define REG_OCL_CFG1 0x3C4 /* RW OCL System Parameters */ 9562306a36Sopenharmony_ci#define REG_IRQ1_EN0 0x3C7 /* RW Interrupt Mask set bits for IRQ1 */ 9662306a36Sopenharmony_ci#define REG_IRQ1_EN1 0x3C8 /* RW Interrupt Mask set bits for IRQ1 */ 9762306a36Sopenharmony_ci#define REG_IRQ2_EN0 0x3C9 /* RW Interrupt Mask set bits for IRQ2 */ 9862306a36Sopenharmony_ci#define REG_IRQ2_EN1 0x3CA /* RW Interrupt Mask set bits for IRQ2 */ 9962306a36Sopenharmony_ci#define REG_IRQ1_SRC0 0x3CB /* RW Interrupt Source bits for IRQ */ 10062306a36Sopenharmony_ci#define REG_IRQ1_SRC1 0x3CC /* RW Interrupt Source bits for IRQ */ 10162306a36Sopenharmony_ci#define REG_OCL_BW0 0x3D2 /* RW OCL System Parameters */ 10262306a36Sopenharmony_ci#define REG_OCL_BW1 0x3D3 /* RW OCL System Parameters */ 10362306a36Sopenharmony_ci#define REG_OCL_BW2 0x3D4 /* RW OCL System Parameters */ 10462306a36Sopenharmony_ci#define REG_OCL_BW3 0x3D5 /* RW OCL System Parameters */ 10562306a36Sopenharmony_ci#define REG_OCL_BW4 0x3D6 /* RW OCL System Parameters */ 10662306a36Sopenharmony_ci#define REG_OCL_BWS 0x3D7 /* RW OCL System Parameters */ 10762306a36Sopenharmony_ci#define REG_OCL_CFG13 0x3E0 /* RW OCL System Parameters */ 10862306a36Sopenharmony_ci#define REG_GP_DRV 0x3E3 /* RW I/O pads Configuration and bg trim */ 10962306a36Sopenharmony_ci#define REG_BM_CFG 0x3E6 /* RW Batt. Monitor Threshold Voltage setting */ 11062306a36Sopenharmony_ci#define REG_SFD_15_4 0x3F4 /* RW Option to set non standard SFD */ 11162306a36Sopenharmony_ci#define REG_AFC_CFG 0x3F7 /* RW AFC mode and polarity */ 11262306a36Sopenharmony_ci#define REG_AFC_KI_KP 0x3F8 /* RW AFC ki and kp */ 11362306a36Sopenharmony_ci#define REG_AFC_RANGE 0x3F9 /* RW AFC range */ 11462306a36Sopenharmony_ci#define REG_AFC_READ 0x3FA /* RW Readback frequency error */ 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* REG_EXTPA_MSC */ 11762306a36Sopenharmony_ci#define PA_PWR(x) (((x) & 0xF) << 4) 11862306a36Sopenharmony_ci#define EXTPA_BIAS_SRC BIT(3) 11962306a36Sopenharmony_ci#define EXTPA_BIAS_MODE(x) (((x) & 0x7) << 0) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* REG_PA_CFG */ 12262306a36Sopenharmony_ci#define PA_BRIDGE_DBIAS(x) (((x) & 0x1F) << 0) 12362306a36Sopenharmony_ci#define PA_DBIAS_HIGH_POWER 21 12462306a36Sopenharmony_ci#define PA_DBIAS_LOW_POWER 13 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* REG_PA_BIAS */ 12762306a36Sopenharmony_ci#define PA_BIAS_CTRL(x) (((x) & 0x1F) << 1) 12862306a36Sopenharmony_ci#define REG_PA_BIAS_DFL BIT(0) 12962306a36Sopenharmony_ci#define PA_BIAS_HIGH_POWER 63 13062306a36Sopenharmony_ci#define PA_BIAS_LOW_POWER 55 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#define REG_PAN_ID0 0x112 13362306a36Sopenharmony_ci#define REG_PAN_ID1 0x113 13462306a36Sopenharmony_ci#define REG_SHORT_ADDR_0 0x114 13562306a36Sopenharmony_ci#define REG_SHORT_ADDR_1 0x115 13662306a36Sopenharmony_ci#define REG_IEEE_ADDR_0 0x116 13762306a36Sopenharmony_ci#define REG_IEEE_ADDR_1 0x117 13862306a36Sopenharmony_ci#define REG_IEEE_ADDR_2 0x118 13962306a36Sopenharmony_ci#define REG_IEEE_ADDR_3 0x119 14062306a36Sopenharmony_ci#define REG_IEEE_ADDR_4 0x11A 14162306a36Sopenharmony_ci#define REG_IEEE_ADDR_5 0x11B 14262306a36Sopenharmony_ci#define REG_IEEE_ADDR_6 0x11C 14362306a36Sopenharmony_ci#define REG_IEEE_ADDR_7 0x11D 14462306a36Sopenharmony_ci#define REG_FFILT_CFG 0x11E 14562306a36Sopenharmony_ci#define REG_AUTO_CFG 0x11F 14662306a36Sopenharmony_ci#define REG_AUTO_TX1 0x120 14762306a36Sopenharmony_ci#define REG_AUTO_TX2 0x121 14862306a36Sopenharmony_ci#define REG_AUTO_STATUS 0x122 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* REG_FFILT_CFG */ 15162306a36Sopenharmony_ci#define ACCEPT_BEACON_FRAMES BIT(0) 15262306a36Sopenharmony_ci#define ACCEPT_DATA_FRAMES BIT(1) 15362306a36Sopenharmony_ci#define ACCEPT_ACK_FRAMES BIT(2) 15462306a36Sopenharmony_ci#define ACCEPT_MACCMD_FRAMES BIT(3) 15562306a36Sopenharmony_ci#define ACCEPT_RESERVED_FRAMES BIT(4) 15662306a36Sopenharmony_ci#define ACCEPT_ALL_ADDRESS BIT(5) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* REG_AUTO_CFG */ 15962306a36Sopenharmony_ci#define AUTO_ACK_FRAMEPEND BIT(0) 16062306a36Sopenharmony_ci#define IS_PANCOORD BIT(1) 16162306a36Sopenharmony_ci#define RX_AUTO_ACK_EN BIT(3) 16262306a36Sopenharmony_ci#define CSMA_CA_RX_TURNAROUND BIT(4) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* REG_AUTO_TX1 */ 16562306a36Sopenharmony_ci#define MAX_FRAME_RETRIES(x) ((x) & 0xF) 16662306a36Sopenharmony_ci#define MAX_CCA_RETRIES(x) (((x) & 0x7) << 4) 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* REG_AUTO_TX2 */ 16962306a36Sopenharmony_ci#define CSMA_MAX_BE(x) ((x) & 0xF) 17062306a36Sopenharmony_ci#define CSMA_MIN_BE(x) (((x) & 0xF) << 4) 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci#define CMD_SPI_NOP 0xFF /* No operation. Use for dummy writes */ 17362306a36Sopenharmony_ci#define CMD_SPI_PKT_WR 0x10 /* Write telegram to the Packet RAM 17462306a36Sopenharmony_ci * starting from the TX packet base address 17562306a36Sopenharmony_ci * pointer tx_packet_base 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci#define CMD_SPI_PKT_RD 0x30 /* Read telegram from the Packet RAM 17862306a36Sopenharmony_ci * starting from RX packet base address 17962306a36Sopenharmony_ci * pointer rxpb.rx_packet_base 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci#define CMD_SPI_MEM_WR(x) (0x18 + (x >> 8)) /* Write data to MCR or 18262306a36Sopenharmony_ci * Packet RAM sequentially 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_ci#define CMD_SPI_MEM_RD(x) (0x38 + (x >> 8)) /* Read data from MCR or 18562306a36Sopenharmony_ci * Packet RAM sequentially 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci#define CMD_SPI_MEMR_WR(x) (0x08 + (x >> 8)) /* Write data to MCR or Packet 18862306a36Sopenharmony_ci * RAM as random block 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ci#define CMD_SPI_MEMR_RD(x) (0x28 + (x >> 8)) /* Read data from MCR or 19162306a36Sopenharmony_ci * Packet RAM random block 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci#define CMD_SPI_PRAM_WR 0x1E /* Write data sequentially to current 19462306a36Sopenharmony_ci * PRAM page selected 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci#define CMD_SPI_PRAM_RD 0x3E /* Read data sequentially from current 19762306a36Sopenharmony_ci * PRAM page selected 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci#define CMD_RC_SLEEP 0xB1 /* Invoke transition of radio controller 20062306a36Sopenharmony_ci * into SLEEP state 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci#define CMD_RC_IDLE 0xB2 /* Invoke transition of radio controller 20362306a36Sopenharmony_ci * into IDLE state 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci#define CMD_RC_PHY_RDY 0xB3 /* Invoke transition of radio controller 20662306a36Sopenharmony_ci * into PHY_RDY state 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci#define CMD_RC_RX 0xB4 /* Invoke transition of radio controller 20962306a36Sopenharmony_ci * into RX state 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci#define CMD_RC_TX 0xB5 /* Invoke transition of radio controller 21262306a36Sopenharmony_ci * into TX state 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_ci#define CMD_RC_MEAS 0xB6 /* Invoke transition of radio controller 21562306a36Sopenharmony_ci * into MEAS state 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci#define CMD_RC_CCA 0xB7 /* Invoke Clear channel assessment */ 21862306a36Sopenharmony_ci#define CMD_RC_CSMACA 0xC1 /* initiates CSMA-CA channel access 21962306a36Sopenharmony_ci * sequence and frame transmission 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_ci#define CMD_RC_PC_RESET 0xC7 /* Program counter reset */ 22262306a36Sopenharmony_ci#define CMD_RC_RESET 0xC8 /* Resets the ADF7242 and puts it in 22362306a36Sopenharmony_ci * the sleep state 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci#define CMD_RC_PC_RESET_NO_WAIT (CMD_RC_PC_RESET | BIT(31)) 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* STATUS */ 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define STAT_SPI_READY BIT(7) 23062306a36Sopenharmony_ci#define STAT_IRQ_STATUS BIT(6) 23162306a36Sopenharmony_ci#define STAT_RC_READY BIT(5) 23262306a36Sopenharmony_ci#define STAT_CCA_RESULT BIT(4) 23362306a36Sopenharmony_ci#define RC_STATUS_IDLE 1 23462306a36Sopenharmony_ci#define RC_STATUS_MEAS 2 23562306a36Sopenharmony_ci#define RC_STATUS_PHY_RDY 3 23662306a36Sopenharmony_ci#define RC_STATUS_RX 4 23762306a36Sopenharmony_ci#define RC_STATUS_TX 5 23862306a36Sopenharmony_ci#define RC_STATUS_MASK 0xF 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* AUTO_STATUS */ 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci#define SUCCESS 0 24362306a36Sopenharmony_ci#define SUCCESS_DATPEND 1 24462306a36Sopenharmony_ci#define FAILURE_CSMACA 2 24562306a36Sopenharmony_ci#define FAILURE_NOACK 3 24662306a36Sopenharmony_ci#define AUTO_STATUS_MASK 0x3 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci#define PRAM_PAGESIZE 256 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* IRQ1 */ 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci#define IRQ_CCA_COMPLETE BIT(0) 25362306a36Sopenharmony_ci#define IRQ_SFD_RX BIT(1) 25462306a36Sopenharmony_ci#define IRQ_SFD_TX BIT(2) 25562306a36Sopenharmony_ci#define IRQ_RX_PKT_RCVD BIT(3) 25662306a36Sopenharmony_ci#define IRQ_TX_PKT_SENT BIT(4) 25762306a36Sopenharmony_ci#define IRQ_FRAME_VALID BIT(5) 25862306a36Sopenharmony_ci#define IRQ_ADDRESS_VALID BIT(6) 25962306a36Sopenharmony_ci#define IRQ_CSMA_CA BIT(7) 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci#define AUTO_TX_TURNAROUND BIT(3) 26262306a36Sopenharmony_ci#define ADDON_EN BIT(4) 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci#define FLAG_XMIT 0 26562306a36Sopenharmony_ci#define FLAG_START 1 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci#define ADF7242_REPORT_CSMA_CA_STAT 0 /* framework doesn't handle yet */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistruct adf7242_local { 27062306a36Sopenharmony_ci struct spi_device *spi; 27162306a36Sopenharmony_ci struct completion tx_complete; 27262306a36Sopenharmony_ci struct ieee802154_hw *hw; 27362306a36Sopenharmony_ci struct mutex bmux; /* protect SPI messages */ 27462306a36Sopenharmony_ci struct spi_message stat_msg; 27562306a36Sopenharmony_ci struct spi_transfer stat_xfer; 27662306a36Sopenharmony_ci struct dentry *debugfs_root; 27762306a36Sopenharmony_ci struct delayed_work work; 27862306a36Sopenharmony_ci struct workqueue_struct *wqueue; 27962306a36Sopenharmony_ci unsigned long flags; 28062306a36Sopenharmony_ci int tx_stat; 28162306a36Sopenharmony_ci bool promiscuous; 28262306a36Sopenharmony_ci s8 rssi; 28362306a36Sopenharmony_ci u8 max_frame_retries; 28462306a36Sopenharmony_ci u8 max_cca_retries; 28562306a36Sopenharmony_ci u8 max_be; 28662306a36Sopenharmony_ci u8 min_be; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* DMA (thus cache coherency maintenance) requires the 28962306a36Sopenharmony_ci * transfer buffers to live in their own cache lines. 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci u8 buf[3] ____cacheline_aligned; 29362306a36Sopenharmony_ci u8 buf_reg_tx[3]; 29462306a36Sopenharmony_ci u8 buf_read_tx[4]; 29562306a36Sopenharmony_ci u8 buf_read_rx[4]; 29662306a36Sopenharmony_ci u8 buf_stat_rx; 29762306a36Sopenharmony_ci u8 buf_stat_tx; 29862306a36Sopenharmony_ci u8 buf_cmd; 29962306a36Sopenharmony_ci}; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic int adf7242_soft_reset(struct adf7242_local *lp, int line); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int adf7242_status(struct adf7242_local *lp, u8 *stat) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci int status; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci mutex_lock(&lp->bmux); 30862306a36Sopenharmony_ci status = spi_sync(lp->spi, &lp->stat_msg); 30962306a36Sopenharmony_ci *stat = lp->buf_stat_rx; 31062306a36Sopenharmony_ci mutex_unlock(&lp->bmux); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return status; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int adf7242_wait_status(struct adf7242_local *lp, unsigned int status, 31662306a36Sopenharmony_ci unsigned int mask, int line) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci int cnt = 0, ret = 0; 31962306a36Sopenharmony_ci u8 stat; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci do { 32262306a36Sopenharmony_ci adf7242_status(lp, &stat); 32362306a36Sopenharmony_ci cnt++; 32462306a36Sopenharmony_ci } while (((stat & mask) != status) && (cnt < MAX_POLL_LOOPS)); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (cnt >= MAX_POLL_LOOPS) { 32762306a36Sopenharmony_ci ret = -ETIMEDOUT; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (!(stat & STAT_RC_READY)) { 33062306a36Sopenharmony_ci adf7242_soft_reset(lp, line); 33162306a36Sopenharmony_ci adf7242_status(lp, &stat); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci if ((stat & mask) == status) 33462306a36Sopenharmony_ci ret = 0; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (ret < 0) 33862306a36Sopenharmony_ci dev_warn(&lp->spi->dev, 33962306a36Sopenharmony_ci "%s:line %d Timeout status 0x%x (%d)\n", 34062306a36Sopenharmony_ci __func__, line, stat, cnt); 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci dev_vdbg(&lp->spi->dev, "%s : loops=%d line %d\n", __func__, cnt, line); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return ret; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int adf7242_wait_rc_ready(struct adf7242_local *lp, int line) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci return adf7242_wait_status(lp, STAT_RC_READY | STAT_SPI_READY, 35162306a36Sopenharmony_ci STAT_RC_READY | STAT_SPI_READY, line); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic int adf7242_wait_spi_ready(struct adf7242_local *lp, int line) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci return adf7242_wait_status(lp, STAT_SPI_READY, 35762306a36Sopenharmony_ci STAT_SPI_READY, line); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic int adf7242_write_fbuf(struct adf7242_local *lp, u8 *data, u8 len) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci u8 *buf = lp->buf; 36362306a36Sopenharmony_ci int status; 36462306a36Sopenharmony_ci struct spi_message msg; 36562306a36Sopenharmony_ci struct spi_transfer xfer_head = { 36662306a36Sopenharmony_ci .len = 2, 36762306a36Sopenharmony_ci .tx_buf = buf, 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci }; 37062306a36Sopenharmony_ci struct spi_transfer xfer_buf = { 37162306a36Sopenharmony_ci .len = len, 37262306a36Sopenharmony_ci .tx_buf = data, 37362306a36Sopenharmony_ci }; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci spi_message_init(&msg); 37662306a36Sopenharmony_ci spi_message_add_tail(&xfer_head, &msg); 37762306a36Sopenharmony_ci spi_message_add_tail(&xfer_buf, &msg); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci adf7242_wait_spi_ready(lp, __LINE__); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci mutex_lock(&lp->bmux); 38262306a36Sopenharmony_ci buf[0] = CMD_SPI_PKT_WR; 38362306a36Sopenharmony_ci buf[1] = len + 2; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci status = spi_sync(lp->spi, &msg); 38662306a36Sopenharmony_ci mutex_unlock(&lp->bmux); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return status; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic int adf7242_read_fbuf(struct adf7242_local *lp, 39262306a36Sopenharmony_ci u8 *data, size_t len, bool packet_read) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci u8 *buf = lp->buf; 39562306a36Sopenharmony_ci int status; 39662306a36Sopenharmony_ci struct spi_message msg; 39762306a36Sopenharmony_ci struct spi_transfer xfer_head = { 39862306a36Sopenharmony_ci .len = 3, 39962306a36Sopenharmony_ci .tx_buf = buf, 40062306a36Sopenharmony_ci .rx_buf = buf, 40162306a36Sopenharmony_ci }; 40262306a36Sopenharmony_ci struct spi_transfer xfer_buf = { 40362306a36Sopenharmony_ci .len = len, 40462306a36Sopenharmony_ci .rx_buf = data, 40562306a36Sopenharmony_ci }; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci spi_message_init(&msg); 40862306a36Sopenharmony_ci spi_message_add_tail(&xfer_head, &msg); 40962306a36Sopenharmony_ci spi_message_add_tail(&xfer_buf, &msg); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci adf7242_wait_spi_ready(lp, __LINE__); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mutex_lock(&lp->bmux); 41462306a36Sopenharmony_ci if (packet_read) { 41562306a36Sopenharmony_ci buf[0] = CMD_SPI_PKT_RD; 41662306a36Sopenharmony_ci buf[1] = CMD_SPI_NOP; 41762306a36Sopenharmony_ci buf[2] = 0; /* PHR */ 41862306a36Sopenharmony_ci } else { 41962306a36Sopenharmony_ci buf[0] = CMD_SPI_PRAM_RD; 42062306a36Sopenharmony_ci buf[1] = 0; 42162306a36Sopenharmony_ci buf[2] = CMD_SPI_NOP; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci status = spi_sync(lp->spi, &msg); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci mutex_unlock(&lp->bmux); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return status; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int adf7242_read_reg(struct adf7242_local *lp, u16 addr, u8 *data) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci int status; 43462306a36Sopenharmony_ci struct spi_message msg; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci struct spi_transfer xfer = { 43762306a36Sopenharmony_ci .len = 4, 43862306a36Sopenharmony_ci .tx_buf = lp->buf_read_tx, 43962306a36Sopenharmony_ci .rx_buf = lp->buf_read_rx, 44062306a36Sopenharmony_ci }; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci adf7242_wait_spi_ready(lp, __LINE__); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci mutex_lock(&lp->bmux); 44562306a36Sopenharmony_ci lp->buf_read_tx[0] = CMD_SPI_MEM_RD(addr); 44662306a36Sopenharmony_ci lp->buf_read_tx[1] = addr; 44762306a36Sopenharmony_ci lp->buf_read_tx[2] = CMD_SPI_NOP; 44862306a36Sopenharmony_ci lp->buf_read_tx[3] = CMD_SPI_NOP; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci spi_message_init(&msg); 45162306a36Sopenharmony_ci spi_message_add_tail(&xfer, &msg); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci status = spi_sync(lp->spi, &msg); 45462306a36Sopenharmony_ci if (msg.status) 45562306a36Sopenharmony_ci status = msg.status; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (!status) 45862306a36Sopenharmony_ci *data = lp->buf_read_rx[3]; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci mutex_unlock(&lp->bmux); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n", __func__, 46362306a36Sopenharmony_ci addr, *data); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci return status; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int adf7242_write_reg(struct adf7242_local *lp, u16 addr, u8 data) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci int status; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci adf7242_wait_spi_ready(lp, __LINE__); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci mutex_lock(&lp->bmux); 47562306a36Sopenharmony_ci lp->buf_reg_tx[0] = CMD_SPI_MEM_WR(addr); 47662306a36Sopenharmony_ci lp->buf_reg_tx[1] = addr; 47762306a36Sopenharmony_ci lp->buf_reg_tx[2] = data; 47862306a36Sopenharmony_ci status = spi_write(lp->spi, lp->buf_reg_tx, 3); 47962306a36Sopenharmony_ci mutex_unlock(&lp->bmux); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci dev_vdbg(&lp->spi->dev, "%s : REG 0x%X, VAL 0x%X\n", 48262306a36Sopenharmony_ci __func__, addr, data); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return status; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int adf7242_cmd(struct adf7242_local *lp, unsigned int cmd) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci int status; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci dev_vdbg(&lp->spi->dev, "%s : CMD=0x%X\n", __func__, cmd); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (cmd != CMD_RC_PC_RESET_NO_WAIT) 49462306a36Sopenharmony_ci adf7242_wait_rc_ready(lp, __LINE__); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci mutex_lock(&lp->bmux); 49762306a36Sopenharmony_ci lp->buf_cmd = cmd; 49862306a36Sopenharmony_ci status = spi_write(lp->spi, &lp->buf_cmd, 1); 49962306a36Sopenharmony_ci mutex_unlock(&lp->bmux); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return status; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int adf7242_upload_firmware(struct adf7242_local *lp, u8 *data, u16 len) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct spi_message msg; 50762306a36Sopenharmony_ci struct spi_transfer xfer_buf = { }; 50862306a36Sopenharmony_ci int status, i, page = 0; 50962306a36Sopenharmony_ci u8 *buf = lp->buf; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci struct spi_transfer xfer_head = { 51262306a36Sopenharmony_ci .len = 2, 51362306a36Sopenharmony_ci .tx_buf = buf, 51462306a36Sopenharmony_ci }; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci buf[0] = CMD_SPI_PRAM_WR; 51762306a36Sopenharmony_ci buf[1] = 0; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci spi_message_init(&msg); 52062306a36Sopenharmony_ci spi_message_add_tail(&xfer_head, &msg); 52162306a36Sopenharmony_ci spi_message_add_tail(&xfer_buf, &msg); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci for (i = len; i >= 0; i -= PRAM_PAGESIZE) { 52462306a36Sopenharmony_ci adf7242_write_reg(lp, REG_PRAMPG, page); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci xfer_buf.len = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i; 52762306a36Sopenharmony_ci xfer_buf.tx_buf = &data[page * PRAM_PAGESIZE]; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci mutex_lock(&lp->bmux); 53062306a36Sopenharmony_ci status = spi_sync(lp->spi, &msg); 53162306a36Sopenharmony_ci mutex_unlock(&lp->bmux); 53262306a36Sopenharmony_ci page++; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return status; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int adf7242_verify_firmware(struct adf7242_local *lp, 53962306a36Sopenharmony_ci const u8 *data, size_t len) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci#ifdef DEBUG 54262306a36Sopenharmony_ci int i, j; 54362306a36Sopenharmony_ci unsigned int page; 54462306a36Sopenharmony_ci u8 *buf = kmalloc(PRAM_PAGESIZE, GFP_KERNEL); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (!buf) 54762306a36Sopenharmony_ci return -ENOMEM; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci for (page = 0, i = len; i >= 0; i -= PRAM_PAGESIZE, page++) { 55062306a36Sopenharmony_ci size_t nb = (i >= PRAM_PAGESIZE) ? PRAM_PAGESIZE : i; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci adf7242_write_reg(lp, REG_PRAMPG, page); 55362306a36Sopenharmony_ci adf7242_read_fbuf(lp, buf, nb, false); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci for (j = 0; j < nb; j++) { 55662306a36Sopenharmony_ci if (buf[j] != data[page * PRAM_PAGESIZE + j]) { 55762306a36Sopenharmony_ci kfree(buf); 55862306a36Sopenharmony_ci return -EIO; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci kfree(buf); 56362306a36Sopenharmony_ci#endif 56462306a36Sopenharmony_ci return 0; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic void adf7242_clear_irqstat(struct adf7242_local *lp) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci adf7242_write_reg(lp, REG_IRQ1_SRC1, IRQ_CCA_COMPLETE | IRQ_SFD_RX | 57062306a36Sopenharmony_ci IRQ_SFD_TX | IRQ_RX_PKT_RCVD | IRQ_TX_PKT_SENT | 57162306a36Sopenharmony_ci IRQ_FRAME_VALID | IRQ_ADDRESS_VALID | IRQ_CSMA_CA); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic int adf7242_cmd_rx(struct adf7242_local *lp) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci /* Wait until the ACK is sent */ 57762306a36Sopenharmony_ci adf7242_wait_status(lp, RC_STATUS_PHY_RDY, RC_STATUS_MASK, __LINE__); 57862306a36Sopenharmony_ci adf7242_clear_irqstat(lp); 57962306a36Sopenharmony_ci mod_delayed_work(lp->wqueue, &lp->work, msecs_to_jiffies(400)); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return adf7242_cmd(lp, CMD_RC_RX); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic void adf7242_rx_cal_work(struct work_struct *work) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct adf7242_local *lp = 58762306a36Sopenharmony_ci container_of(work, struct adf7242_local, work.work); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* Reissuing RC_RX every 400ms - to adjust for offset 59062306a36Sopenharmony_ci * drift in receiver (datasheet page 61, OCL section) 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (!test_bit(FLAG_XMIT, &lp->flags)) { 59462306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_PHY_RDY); 59562306a36Sopenharmony_ci adf7242_cmd_rx(lp); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int adf7242_set_txpower(struct ieee802154_hw *hw, int mbm) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 60262306a36Sopenharmony_ci u8 pwr, bias_ctrl, dbias, tmp; 60362306a36Sopenharmony_ci int db = mbm / 100; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci dev_vdbg(&lp->spi->dev, "%s : Power %d dB\n", __func__, db); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (db > 5 || db < -26) 60862306a36Sopenharmony_ci return -EINVAL; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci db = DIV_ROUND_CLOSEST(db + 29, 2); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (db > 15) { 61362306a36Sopenharmony_ci dbias = PA_DBIAS_HIGH_POWER; 61462306a36Sopenharmony_ci bias_ctrl = PA_BIAS_HIGH_POWER; 61562306a36Sopenharmony_ci } else { 61662306a36Sopenharmony_ci dbias = PA_DBIAS_LOW_POWER; 61762306a36Sopenharmony_ci bias_ctrl = PA_BIAS_LOW_POWER; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci pwr = clamp_t(u8, db, 3, 15); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci adf7242_read_reg(lp, REG_PA_CFG, &tmp); 62362306a36Sopenharmony_ci tmp &= ~PA_BRIDGE_DBIAS(~0); 62462306a36Sopenharmony_ci tmp |= PA_BRIDGE_DBIAS(dbias); 62562306a36Sopenharmony_ci adf7242_write_reg(lp, REG_PA_CFG, tmp); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci adf7242_read_reg(lp, REG_PA_BIAS, &tmp); 62862306a36Sopenharmony_ci tmp &= ~PA_BIAS_CTRL(~0); 62962306a36Sopenharmony_ci tmp |= PA_BIAS_CTRL(bias_ctrl); 63062306a36Sopenharmony_ci adf7242_write_reg(lp, REG_PA_BIAS, tmp); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci adf7242_read_reg(lp, REG_EXTPA_MSC, &tmp); 63362306a36Sopenharmony_ci tmp &= ~PA_PWR(~0); 63462306a36Sopenharmony_ci tmp |= PA_PWR(pwr); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci return adf7242_write_reg(lp, REG_EXTPA_MSC, tmp); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic int adf7242_set_csma_params(struct ieee802154_hw *hw, u8 min_be, 64062306a36Sopenharmony_ci u8 max_be, u8 retries) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 64362306a36Sopenharmony_ci int ret; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci dev_vdbg(&lp->spi->dev, "%s : min_be=%d max_be=%d retries=%d\n", 64662306a36Sopenharmony_ci __func__, min_be, max_be, retries); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (min_be > max_be || max_be > 8 || retries > 5) 64962306a36Sopenharmony_ci return -EINVAL; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci ret = adf7242_write_reg(lp, REG_AUTO_TX1, 65262306a36Sopenharmony_ci MAX_FRAME_RETRIES(lp->max_frame_retries) | 65362306a36Sopenharmony_ci MAX_CCA_RETRIES(retries)); 65462306a36Sopenharmony_ci if (ret) 65562306a36Sopenharmony_ci return ret; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci lp->max_cca_retries = retries; 65862306a36Sopenharmony_ci lp->max_be = max_be; 65962306a36Sopenharmony_ci lp->min_be = min_be; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci return adf7242_write_reg(lp, REG_AUTO_TX2, CSMA_MAX_BE(max_be) | 66262306a36Sopenharmony_ci CSMA_MIN_BE(min_be)); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int adf7242_set_frame_retries(struct ieee802154_hw *hw, s8 retries) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 66862306a36Sopenharmony_ci int ret = 0; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci dev_vdbg(&lp->spi->dev, "%s : Retries = %d\n", __func__, retries); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (retries < -1 || retries > 15) 67362306a36Sopenharmony_ci return -EINVAL; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if (retries >= 0) 67662306a36Sopenharmony_ci ret = adf7242_write_reg(lp, REG_AUTO_TX1, 67762306a36Sopenharmony_ci MAX_FRAME_RETRIES(retries) | 67862306a36Sopenharmony_ci MAX_CCA_RETRIES(lp->max_cca_retries)); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci lp->max_frame_retries = retries; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci return ret; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic int adf7242_ed(struct ieee802154_hw *hw, u8 *level) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci *level = lp->rssi; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci dev_vdbg(&lp->spi->dev, "%s :Exit level=%d\n", 69262306a36Sopenharmony_ci __func__, *level); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci return 0; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic int adf7242_start(struct ieee802154_hw *hw) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_PHY_RDY); 70262306a36Sopenharmony_ci adf7242_clear_irqstat(lp); 70362306a36Sopenharmony_ci enable_irq(lp->spi->irq); 70462306a36Sopenharmony_ci set_bit(FLAG_START, &lp->flags); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return adf7242_cmd_rx(lp); 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic void adf7242_stop(struct ieee802154_hw *hw) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci disable_irq(lp->spi->irq); 71462306a36Sopenharmony_ci cancel_delayed_work_sync(&lp->work); 71562306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_IDLE); 71662306a36Sopenharmony_ci clear_bit(FLAG_START, &lp->flags); 71762306a36Sopenharmony_ci adf7242_clear_irqstat(lp); 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int adf7242_channel(struct ieee802154_hw *hw, u8 page, u8 channel) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 72362306a36Sopenharmony_ci unsigned long freq; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "%s :Channel=%d\n", __func__, channel); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci might_sleep(); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci WARN_ON(page != 0); 73062306a36Sopenharmony_ci WARN_ON(channel < 11); 73162306a36Sopenharmony_ci WARN_ON(channel > 26); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci freq = (2405 + 5 * (channel - 11)) * 100; 73462306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_PHY_RDY); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci adf7242_write_reg(lp, REG_CH_FREQ0, freq); 73762306a36Sopenharmony_ci adf7242_write_reg(lp, REG_CH_FREQ1, freq >> 8); 73862306a36Sopenharmony_ci adf7242_write_reg(lp, REG_CH_FREQ2, freq >> 16); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (test_bit(FLAG_START, &lp->flags)) 74162306a36Sopenharmony_ci return adf7242_cmd_rx(lp); 74262306a36Sopenharmony_ci else 74362306a36Sopenharmony_ci return adf7242_cmd(lp, CMD_RC_PHY_RDY); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic int adf7242_set_hw_addr_filt(struct ieee802154_hw *hw, 74762306a36Sopenharmony_ci struct ieee802154_hw_addr_filt *filt, 74862306a36Sopenharmony_ci unsigned long changed) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 75162306a36Sopenharmony_ci u8 reg; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "%s :Changed=0x%lX\n", __func__, changed); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci might_sleep(); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) { 75862306a36Sopenharmony_ci u8 addr[8], i; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci memcpy(addr, &filt->ieee_addr, 8); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci for (i = 0; i < 8; i++) 76362306a36Sopenharmony_ci adf7242_write_reg(lp, REG_IEEE_ADDR_0 + i, addr[i]); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (changed & IEEE802154_AFILT_SADDR_CHANGED) { 76762306a36Sopenharmony_ci u16 saddr = le16_to_cpu(filt->short_addr); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci adf7242_write_reg(lp, REG_SHORT_ADDR_0, saddr); 77062306a36Sopenharmony_ci adf7242_write_reg(lp, REG_SHORT_ADDR_1, saddr >> 8); 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (changed & IEEE802154_AFILT_PANID_CHANGED) { 77462306a36Sopenharmony_ci u16 pan_id = le16_to_cpu(filt->pan_id); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci adf7242_write_reg(lp, REG_PAN_ID0, pan_id); 77762306a36Sopenharmony_ci adf7242_write_reg(lp, REG_PAN_ID1, pan_id >> 8); 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (changed & IEEE802154_AFILT_PANC_CHANGED) { 78162306a36Sopenharmony_ci adf7242_read_reg(lp, REG_AUTO_CFG, ®); 78262306a36Sopenharmony_ci if (filt->pan_coord) 78362306a36Sopenharmony_ci reg |= IS_PANCOORD; 78462306a36Sopenharmony_ci else 78562306a36Sopenharmony_ci reg &= ~IS_PANCOORD; 78662306a36Sopenharmony_ci adf7242_write_reg(lp, REG_AUTO_CFG, reg); 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci return 0; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic int adf7242_set_promiscuous_mode(struct ieee802154_hw *hw, bool on) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "%s : mode %d\n", __func__, on); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci lp->promiscuous = on; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (on) { 80162306a36Sopenharmony_ci adf7242_write_reg(lp, REG_AUTO_CFG, 0); 80262306a36Sopenharmony_ci return adf7242_write_reg(lp, REG_FFILT_CFG, 80362306a36Sopenharmony_ci ACCEPT_BEACON_FRAMES | 80462306a36Sopenharmony_ci ACCEPT_DATA_FRAMES | 80562306a36Sopenharmony_ci ACCEPT_MACCMD_FRAMES | 80662306a36Sopenharmony_ci ACCEPT_ALL_ADDRESS | 80762306a36Sopenharmony_ci ACCEPT_ACK_FRAMES | 80862306a36Sopenharmony_ci ACCEPT_RESERVED_FRAMES); 80962306a36Sopenharmony_ci } else { 81062306a36Sopenharmony_ci adf7242_write_reg(lp, REG_FFILT_CFG, 81162306a36Sopenharmony_ci ACCEPT_BEACON_FRAMES | 81262306a36Sopenharmony_ci ACCEPT_DATA_FRAMES | 81362306a36Sopenharmony_ci ACCEPT_MACCMD_FRAMES | 81462306a36Sopenharmony_ci ACCEPT_RESERVED_FRAMES); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci return adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic int adf7242_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 82362306a36Sopenharmony_ci s8 level = clamp_t(s8, mbm / 100, S8_MIN, S8_MAX); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "%s : level %d\n", __func__, level); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci return adf7242_write_reg(lp, REG_CCA1, level); 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic int adf7242_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct adf7242_local *lp = hw->priv; 83362306a36Sopenharmony_ci int ret; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* ensure existing instances of the IRQ handler have completed */ 83662306a36Sopenharmony_ci disable_irq(lp->spi->irq); 83762306a36Sopenharmony_ci set_bit(FLAG_XMIT, &lp->flags); 83862306a36Sopenharmony_ci cancel_delayed_work_sync(&lp->work); 83962306a36Sopenharmony_ci reinit_completion(&lp->tx_complete); 84062306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_PHY_RDY); 84162306a36Sopenharmony_ci adf7242_clear_irqstat(lp); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci ret = adf7242_write_fbuf(lp, skb->data, skb->len); 84462306a36Sopenharmony_ci if (ret) 84562306a36Sopenharmony_ci goto err; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci ret = adf7242_cmd(lp, CMD_RC_CSMACA); 84862306a36Sopenharmony_ci if (ret) 84962306a36Sopenharmony_ci goto err; 85062306a36Sopenharmony_ci enable_irq(lp->spi->irq); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci ret = wait_for_completion_interruptible_timeout(&lp->tx_complete, 85362306a36Sopenharmony_ci HZ / 10); 85462306a36Sopenharmony_ci if (ret < 0) 85562306a36Sopenharmony_ci goto err; 85662306a36Sopenharmony_ci if (ret == 0) { 85762306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "Timeout waiting for TX interrupt\n"); 85862306a36Sopenharmony_ci ret = -ETIMEDOUT; 85962306a36Sopenharmony_ci goto err; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (lp->tx_stat != SUCCESS) { 86362306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, 86462306a36Sopenharmony_ci "Error xmit: Retry count exceeded Status=0x%x\n", 86562306a36Sopenharmony_ci lp->tx_stat); 86662306a36Sopenharmony_ci ret = -ECOMM; 86762306a36Sopenharmony_ci } else { 86862306a36Sopenharmony_ci ret = 0; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cierr: 87262306a36Sopenharmony_ci clear_bit(FLAG_XMIT, &lp->flags); 87362306a36Sopenharmony_ci adf7242_cmd_rx(lp); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci return ret; 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_cistatic int adf7242_rx(struct adf7242_local *lp) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci struct sk_buff *skb; 88162306a36Sopenharmony_ci size_t len; 88262306a36Sopenharmony_ci int ret; 88362306a36Sopenharmony_ci u8 lqi, len_u8, *data; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci ret = adf7242_read_reg(lp, 0, &len_u8); 88662306a36Sopenharmony_ci if (ret) 88762306a36Sopenharmony_ci return ret; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci len = len_u8; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (!ieee802154_is_valid_psdu_len(len)) { 89262306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, 89362306a36Sopenharmony_ci "corrupted frame received len %d\n", (int)len); 89462306a36Sopenharmony_ci len = IEEE802154_MTU; 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci skb = dev_alloc_skb(len); 89862306a36Sopenharmony_ci if (!skb) { 89962306a36Sopenharmony_ci adf7242_cmd_rx(lp); 90062306a36Sopenharmony_ci return -ENOMEM; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci data = skb_put(skb, len); 90462306a36Sopenharmony_ci ret = adf7242_read_fbuf(lp, data, len, true); 90562306a36Sopenharmony_ci if (ret < 0) { 90662306a36Sopenharmony_ci kfree_skb(skb); 90762306a36Sopenharmony_ci adf7242_cmd_rx(lp); 90862306a36Sopenharmony_ci return ret; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci lqi = data[len - 2]; 91262306a36Sopenharmony_ci lp->rssi = data[len - 1]; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci ret = adf7242_cmd_rx(lp); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci skb_trim(skb, len - 2); /* Don't put RSSI/LQI or CRC into the frame */ 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci ieee802154_rx_irqsafe(lp->hw, skb, lqi); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "%s: ret=%d len=%d lqi=%d rssi=%d\n", 92162306a36Sopenharmony_ci __func__, ret, (int)len, (int)lqi, lp->rssi); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci return ret; 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_cistatic const struct ieee802154_ops adf7242_ops = { 92762306a36Sopenharmony_ci .owner = THIS_MODULE, 92862306a36Sopenharmony_ci .xmit_sync = adf7242_xmit, 92962306a36Sopenharmony_ci .ed = adf7242_ed, 93062306a36Sopenharmony_ci .set_channel = adf7242_channel, 93162306a36Sopenharmony_ci .set_hw_addr_filt = adf7242_set_hw_addr_filt, 93262306a36Sopenharmony_ci .start = adf7242_start, 93362306a36Sopenharmony_ci .stop = adf7242_stop, 93462306a36Sopenharmony_ci .set_csma_params = adf7242_set_csma_params, 93562306a36Sopenharmony_ci .set_frame_retries = adf7242_set_frame_retries, 93662306a36Sopenharmony_ci .set_txpower = adf7242_set_txpower, 93762306a36Sopenharmony_ci .set_promiscuous_mode = adf7242_set_promiscuous_mode, 93862306a36Sopenharmony_ci .set_cca_ed_level = adf7242_set_cca_ed_level, 93962306a36Sopenharmony_ci}; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic void adf7242_debug(struct adf7242_local *lp, u8 irq1) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci#ifdef DEBUG 94462306a36Sopenharmony_ci u8 stat; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci adf7242_status(lp, &stat); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "%s IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n", 94962306a36Sopenharmony_ci __func__, irq1, 95062306a36Sopenharmony_ci irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "", 95162306a36Sopenharmony_ci irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "", 95262306a36Sopenharmony_ci irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "", 95362306a36Sopenharmony_ci irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "", 95462306a36Sopenharmony_ci irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "", 95562306a36Sopenharmony_ci irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "", 95662306a36Sopenharmony_ci irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "", 95762306a36Sopenharmony_ci irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : ""); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "%s STATUS = %X:\n%s\n%s\n%s\n%s\n%s%s%s%s%s\n", 96062306a36Sopenharmony_ci __func__, stat, 96162306a36Sopenharmony_ci stat & STAT_SPI_READY ? "SPI_READY" : "SPI_BUSY", 96262306a36Sopenharmony_ci stat & STAT_IRQ_STATUS ? "IRQ_PENDING" : "IRQ_CLEAR", 96362306a36Sopenharmony_ci stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY", 96462306a36Sopenharmony_ci stat & STAT_CCA_RESULT ? "CHAN_IDLE" : "CHAN_BUSY", 96562306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "", 96662306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "", 96762306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "", 96862306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "", 96962306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : ""); 97062306a36Sopenharmony_ci#endif 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_cistatic irqreturn_t adf7242_isr(int irq, void *data) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci struct adf7242_local *lp = data; 97662306a36Sopenharmony_ci unsigned int xmit; 97762306a36Sopenharmony_ci u8 irq1; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci mod_delayed_work(lp->wqueue, &lp->work, msecs_to_jiffies(400)); 98062306a36Sopenharmony_ci adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci if (!(irq1 & (IRQ_RX_PKT_RCVD | IRQ_CSMA_CA))) 98362306a36Sopenharmony_ci dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n", 98462306a36Sopenharmony_ci __func__, irq1); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci adf7242_debug(lp, irq1); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci xmit = test_bit(FLAG_XMIT, &lp->flags); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (xmit && (irq1 & IRQ_CSMA_CA)) { 99162306a36Sopenharmony_ci adf7242_wait_status(lp, RC_STATUS_PHY_RDY, 99262306a36Sopenharmony_ci RC_STATUS_MASK, __LINE__); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (ADF7242_REPORT_CSMA_CA_STAT) { 99562306a36Sopenharmony_ci u8 astat; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci adf7242_read_reg(lp, REG_AUTO_STATUS, &astat); 99862306a36Sopenharmony_ci astat &= AUTO_STATUS_MASK; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "AUTO_STATUS = %X:\n%s%s%s%s\n", 100162306a36Sopenharmony_ci astat, 100262306a36Sopenharmony_ci astat == SUCCESS ? "SUCCESS" : "", 100362306a36Sopenharmony_ci astat == 100462306a36Sopenharmony_ci SUCCESS_DATPEND ? "SUCCESS_DATPEND" : "", 100562306a36Sopenharmony_ci astat == FAILURE_CSMACA ? "FAILURE_CSMACA" : "", 100662306a36Sopenharmony_ci astat == FAILURE_NOACK ? "FAILURE_NOACK" : ""); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* save CSMA-CA completion status */ 100962306a36Sopenharmony_ci lp->tx_stat = astat; 101062306a36Sopenharmony_ci } else { 101162306a36Sopenharmony_ci lp->tx_stat = SUCCESS; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci complete(&lp->tx_complete); 101462306a36Sopenharmony_ci adf7242_clear_irqstat(lp); 101562306a36Sopenharmony_ci } else if (!xmit && (irq1 & IRQ_RX_PKT_RCVD) && 101662306a36Sopenharmony_ci (irq1 & IRQ_FRAME_VALID)) { 101762306a36Sopenharmony_ci adf7242_rx(lp); 101862306a36Sopenharmony_ci } else if (!xmit && test_bit(FLAG_START, &lp->flags)) { 101962306a36Sopenharmony_ci /* Invalid packet received - drop it and restart */ 102062306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "%s:%d : ERROR IRQ1 = 0x%X\n", 102162306a36Sopenharmony_ci __func__, __LINE__, irq1); 102262306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_PHY_RDY); 102362306a36Sopenharmony_ci adf7242_cmd_rx(lp); 102462306a36Sopenharmony_ci } else { 102562306a36Sopenharmony_ci /* This can only be xmit without IRQ, likely a RX packet. 102662306a36Sopenharmony_ci * we get an TX IRQ shortly - do nothing or let the xmit 102762306a36Sopenharmony_ci * timeout handle this 102862306a36Sopenharmony_ci */ 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci dev_dbg(&lp->spi->dev, "%s:%d : ERROR IRQ1 = 0x%X, xmit %d\n", 103162306a36Sopenharmony_ci __func__, __LINE__, irq1, xmit); 103262306a36Sopenharmony_ci adf7242_wait_status(lp, RC_STATUS_PHY_RDY, 103362306a36Sopenharmony_ci RC_STATUS_MASK, __LINE__); 103462306a36Sopenharmony_ci complete(&lp->tx_complete); 103562306a36Sopenharmony_ci adf7242_clear_irqstat(lp); 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci return IRQ_HANDLED; 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic int adf7242_soft_reset(struct adf7242_local *lp, int line) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci dev_warn(&lp->spi->dev, "%s (line %d)\n", __func__, line); 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci if (test_bit(FLAG_START, &lp->flags)) 104662306a36Sopenharmony_ci disable_irq_nosync(lp->spi->irq); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_PC_RESET_NO_WAIT); 104962306a36Sopenharmony_ci usleep_range(200, 250); 105062306a36Sopenharmony_ci adf7242_write_reg(lp, REG_PKT_CFG, ADDON_EN | BIT(2)); 105162306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_PHY_RDY); 105262306a36Sopenharmony_ci adf7242_set_promiscuous_mode(lp->hw, lp->promiscuous); 105362306a36Sopenharmony_ci adf7242_set_csma_params(lp->hw, lp->min_be, lp->max_be, 105462306a36Sopenharmony_ci lp->max_cca_retries); 105562306a36Sopenharmony_ci adf7242_clear_irqstat(lp); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (test_bit(FLAG_START, &lp->flags)) { 105862306a36Sopenharmony_ci enable_irq(lp->spi->irq); 105962306a36Sopenharmony_ci return adf7242_cmd(lp, CMD_RC_RX); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_cistatic int adf7242_hw_init(struct adf7242_local *lp) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci int ret; 106862306a36Sopenharmony_ci const struct firmware *fw; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_RESET); 107162306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_IDLE); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* get ADF7242 addon firmware 107462306a36Sopenharmony_ci * build this driver as module 107562306a36Sopenharmony_ci * and place under /lib/firmware/adf7242_firmware.bin 107662306a36Sopenharmony_ci * or compile firmware into the kernel. 107762306a36Sopenharmony_ci */ 107862306a36Sopenharmony_ci ret = request_firmware(&fw, FIRMWARE, &lp->spi->dev); 107962306a36Sopenharmony_ci if (ret) { 108062306a36Sopenharmony_ci dev_err(&lp->spi->dev, 108162306a36Sopenharmony_ci "request_firmware() failed with %d\n", ret); 108262306a36Sopenharmony_ci return ret; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci ret = adf7242_upload_firmware(lp, (u8 *)fw->data, fw->size); 108662306a36Sopenharmony_ci if (ret) { 108762306a36Sopenharmony_ci dev_err(&lp->spi->dev, 108862306a36Sopenharmony_ci "upload firmware failed with %d\n", ret); 108962306a36Sopenharmony_ci release_firmware(fw); 109062306a36Sopenharmony_ci return ret; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci ret = adf7242_verify_firmware(lp, (u8 *)fw->data, fw->size); 109462306a36Sopenharmony_ci if (ret) { 109562306a36Sopenharmony_ci dev_err(&lp->spi->dev, 109662306a36Sopenharmony_ci "verify firmware failed with %d\n", ret); 109762306a36Sopenharmony_ci release_firmware(fw); 109862306a36Sopenharmony_ci return ret; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_PC_RESET); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci release_firmware(fw); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci adf7242_write_reg(lp, REG_FFILT_CFG, 110662306a36Sopenharmony_ci ACCEPT_BEACON_FRAMES | 110762306a36Sopenharmony_ci ACCEPT_DATA_FRAMES | 110862306a36Sopenharmony_ci ACCEPT_MACCMD_FRAMES | 110962306a36Sopenharmony_ci ACCEPT_RESERVED_FRAMES); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci adf7242_write_reg(lp, REG_AUTO_CFG, RX_AUTO_ACK_EN); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci adf7242_write_reg(lp, REG_PKT_CFG, ADDON_EN | BIT(2)); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci adf7242_write_reg(lp, REG_EXTPA_MSC, 0xF1); 111662306a36Sopenharmony_ci adf7242_write_reg(lp, REG_RXFE_CFG, 0x1D); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci adf7242_write_reg(lp, REG_IRQ1_EN0, 0); 111962306a36Sopenharmony_ci adf7242_write_reg(lp, REG_IRQ1_EN1, IRQ_RX_PKT_RCVD | IRQ_CSMA_CA); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci adf7242_clear_irqstat(lp); 112262306a36Sopenharmony_ci adf7242_write_reg(lp, REG_IRQ1_SRC0, 0xFF); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci adf7242_cmd(lp, CMD_RC_IDLE); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci return 0; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic int adf7242_stats_show(struct seq_file *file, void *offset) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct adf7242_local *lp = spi_get_drvdata(file->private); 113262306a36Sopenharmony_ci u8 stat, irq1; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci adf7242_status(lp, &stat); 113562306a36Sopenharmony_ci adf7242_read_reg(lp, REG_IRQ1_SRC1, &irq1); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci seq_printf(file, "IRQ1 = %X:\n%s%s%s%s%s%s%s%s\n", irq1, 113862306a36Sopenharmony_ci irq1 & IRQ_CCA_COMPLETE ? "IRQ_CCA_COMPLETE\n" : "", 113962306a36Sopenharmony_ci irq1 & IRQ_SFD_RX ? "IRQ_SFD_RX\n" : "", 114062306a36Sopenharmony_ci irq1 & IRQ_SFD_TX ? "IRQ_SFD_TX\n" : "", 114162306a36Sopenharmony_ci irq1 & IRQ_RX_PKT_RCVD ? "IRQ_RX_PKT_RCVD\n" : "", 114262306a36Sopenharmony_ci irq1 & IRQ_TX_PKT_SENT ? "IRQ_TX_PKT_SENT\n" : "", 114362306a36Sopenharmony_ci irq1 & IRQ_CSMA_CA ? "IRQ_CSMA_CA\n" : "", 114462306a36Sopenharmony_ci irq1 & IRQ_FRAME_VALID ? "IRQ_FRAME_VALID\n" : "", 114562306a36Sopenharmony_ci irq1 & IRQ_ADDRESS_VALID ? "IRQ_ADDRESS_VALID\n" : ""); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci seq_printf(file, "STATUS = %X:\n%s\n%s\n%s\n%s\n%s%s%s%s%s\n", stat, 114862306a36Sopenharmony_ci stat & STAT_SPI_READY ? "SPI_READY" : "SPI_BUSY", 114962306a36Sopenharmony_ci stat & STAT_IRQ_STATUS ? "IRQ_PENDING" : "IRQ_CLEAR", 115062306a36Sopenharmony_ci stat & STAT_RC_READY ? "RC_READY" : "RC_BUSY", 115162306a36Sopenharmony_ci stat & STAT_CCA_RESULT ? "CHAN_IDLE" : "CHAN_BUSY", 115262306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_IDLE ? "RC_STATUS_IDLE" : "", 115362306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_MEAS ? "RC_STATUS_MEAS" : "", 115462306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_PHY_RDY ? "RC_STATUS_PHY_RDY" : "", 115562306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_RX ? "RC_STATUS_RX" : "", 115662306a36Sopenharmony_ci (stat & 0xf) == RC_STATUS_TX ? "RC_STATUS_TX" : ""); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci seq_printf(file, "RSSI = %d\n", lp->rssi); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return 0; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic void adf7242_debugfs_init(struct adf7242_local *lp) 116462306a36Sopenharmony_ci{ 116562306a36Sopenharmony_ci char debugfs_dir_name[DNAME_INLINE_LEN + 1]; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci snprintf(debugfs_dir_name, sizeof(debugfs_dir_name), 116862306a36Sopenharmony_ci "adf7242-%s", dev_name(&lp->spi->dev)); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci lp->debugfs_root = debugfs_create_dir(debugfs_dir_name, NULL); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci debugfs_create_devm_seqfile(&lp->spi->dev, "status", lp->debugfs_root, 117362306a36Sopenharmony_ci adf7242_stats_show); 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic const s32 adf7242_powers[] = { 117762306a36Sopenharmony_ci 500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700, 117862306a36Sopenharmony_ci -800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700, 117962306a36Sopenharmony_ci -1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600, 118062306a36Sopenharmony_ci}; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_cistatic const s32 adf7242_ed_levels[] = { 118362306a36Sopenharmony_ci -9000, -8900, -8800, -8700, -8600, -8500, -8400, -8300, -8200, -8100, 118462306a36Sopenharmony_ci -8000, -7900, -7800, -7700, -7600, -7500, -7400, -7300, -7200, -7100, 118562306a36Sopenharmony_ci -7000, -6900, -6800, -6700, -6600, -6500, -6400, -6300, -6200, -6100, 118662306a36Sopenharmony_ci -6000, -5900, -5800, -5700, -5600, -5500, -5400, -5300, -5200, -5100, 118762306a36Sopenharmony_ci -5000, -4900, -4800, -4700, -4600, -4500, -4400, -4300, -4200, -4100, 118862306a36Sopenharmony_ci -4000, -3900, -3800, -3700, -3600, -3500, -3400, -3200, -3100, -3000 118962306a36Sopenharmony_ci}; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_cistatic int adf7242_probe(struct spi_device *spi) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci struct ieee802154_hw *hw; 119462306a36Sopenharmony_ci struct adf7242_local *lp; 119562306a36Sopenharmony_ci int ret, irq_type; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (!spi->irq) { 119862306a36Sopenharmony_ci dev_err(&spi->dev, "no IRQ specified\n"); 119962306a36Sopenharmony_ci return -EINVAL; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci hw = ieee802154_alloc_hw(sizeof(*lp), &adf7242_ops); 120362306a36Sopenharmony_ci if (!hw) 120462306a36Sopenharmony_ci return -ENOMEM; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci lp = hw->priv; 120762306a36Sopenharmony_ci lp->hw = hw; 120862306a36Sopenharmony_ci lp->spi = spi; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci hw->priv = lp; 121162306a36Sopenharmony_ci hw->parent = &spi->dev; 121262306a36Sopenharmony_ci hw->extra_tx_headroom = 0; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* We support only 2.4 Ghz */ 121562306a36Sopenharmony_ci hw->phy->supported.channels[0] = 0x7FFF800; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci hw->flags = IEEE802154_HW_OMIT_CKSUM | 121862306a36Sopenharmony_ci IEEE802154_HW_CSMA_PARAMS | 121962306a36Sopenharmony_ci IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT | 122062306a36Sopenharmony_ci IEEE802154_HW_PROMISCUOUS; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | 122362306a36Sopenharmony_ci WPAN_PHY_FLAG_CCA_ED_LEVEL | 122462306a36Sopenharmony_ci WPAN_PHY_FLAG_CCA_MODE; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci hw->phy->supported.cca_ed_levels = adf7242_ed_levels; 122962306a36Sopenharmony_ci hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(adf7242_ed_levels); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci hw->phy->cca.mode = NL802154_CCA_ENERGY; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci hw->phy->supported.tx_powers = adf7242_powers; 123462306a36Sopenharmony_ci hw->phy->supported.tx_powers_size = ARRAY_SIZE(adf7242_powers); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci hw->phy->supported.min_minbe = 0; 123762306a36Sopenharmony_ci hw->phy->supported.max_minbe = 8; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci hw->phy->supported.min_maxbe = 3; 124062306a36Sopenharmony_ci hw->phy->supported.max_maxbe = 8; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci hw->phy->supported.min_frame_retries = 0; 124362306a36Sopenharmony_ci hw->phy->supported.max_frame_retries = 15; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci hw->phy->supported.min_csma_backoffs = 0; 124662306a36Sopenharmony_ci hw->phy->supported.max_csma_backoffs = 5; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci mutex_init(&lp->bmux); 125162306a36Sopenharmony_ci init_completion(&lp->tx_complete); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci /* Setup Status Message */ 125462306a36Sopenharmony_ci lp->stat_xfer.len = 1; 125562306a36Sopenharmony_ci lp->stat_xfer.tx_buf = &lp->buf_stat_tx; 125662306a36Sopenharmony_ci lp->stat_xfer.rx_buf = &lp->buf_stat_rx; 125762306a36Sopenharmony_ci lp->buf_stat_tx = CMD_SPI_NOP; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci spi_message_init(&lp->stat_msg); 126062306a36Sopenharmony_ci spi_message_add_tail(&lp->stat_xfer, &lp->stat_msg); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci spi_set_drvdata(spi, lp); 126362306a36Sopenharmony_ci INIT_DELAYED_WORK(&lp->work, adf7242_rx_cal_work); 126462306a36Sopenharmony_ci lp->wqueue = alloc_ordered_workqueue(dev_name(&spi->dev), 126562306a36Sopenharmony_ci WQ_MEM_RECLAIM); 126662306a36Sopenharmony_ci if (unlikely(!lp->wqueue)) { 126762306a36Sopenharmony_ci ret = -ENOMEM; 126862306a36Sopenharmony_ci goto err_alloc_wq; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci ret = adf7242_hw_init(lp); 127262306a36Sopenharmony_ci if (ret) 127362306a36Sopenharmony_ci goto err_hw_init; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci irq_type = irq_get_trigger_type(spi->irq); 127662306a36Sopenharmony_ci if (!irq_type) 127762306a36Sopenharmony_ci irq_type = IRQF_TRIGGER_HIGH; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, adf7242_isr, 128062306a36Sopenharmony_ci irq_type | IRQF_ONESHOT, 128162306a36Sopenharmony_ci dev_name(&spi->dev), lp); 128262306a36Sopenharmony_ci if (ret) 128362306a36Sopenharmony_ci goto err_hw_init; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci disable_irq(spi->irq); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci ret = ieee802154_register_hw(lp->hw); 128862306a36Sopenharmony_ci if (ret) 128962306a36Sopenharmony_ci goto err_hw_init; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci dev_set_drvdata(&spi->dev, lp); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci adf7242_debugfs_init(lp); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci dev_info(&spi->dev, "mac802154 IRQ-%d registered\n", spi->irq); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci return ret; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cierr_hw_init: 130062306a36Sopenharmony_ci destroy_workqueue(lp->wqueue); 130162306a36Sopenharmony_cierr_alloc_wq: 130262306a36Sopenharmony_ci mutex_destroy(&lp->bmux); 130362306a36Sopenharmony_ci ieee802154_free_hw(lp->hw); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci return ret; 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic void adf7242_remove(struct spi_device *spi) 130962306a36Sopenharmony_ci{ 131062306a36Sopenharmony_ci struct adf7242_local *lp = spi_get_drvdata(spi); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci debugfs_remove_recursive(lp->debugfs_root); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci ieee802154_unregister_hw(lp->hw); 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci cancel_delayed_work_sync(&lp->work); 131762306a36Sopenharmony_ci destroy_workqueue(lp->wqueue); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci mutex_destroy(&lp->bmux); 132062306a36Sopenharmony_ci ieee802154_free_hw(lp->hw); 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_cistatic const struct of_device_id adf7242_of_match[] = { 132462306a36Sopenharmony_ci { .compatible = "adi,adf7242", }, 132562306a36Sopenharmony_ci { .compatible = "adi,adf7241", }, 132662306a36Sopenharmony_ci { }, 132762306a36Sopenharmony_ci}; 132862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, adf7242_of_match); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic const struct spi_device_id adf7242_device_id[] = { 133162306a36Sopenharmony_ci { .name = "adf7242", }, 133262306a36Sopenharmony_ci { .name = "adf7241", }, 133362306a36Sopenharmony_ci { }, 133462306a36Sopenharmony_ci}; 133562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, adf7242_device_id); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_cistatic struct spi_driver adf7242_driver = { 133862306a36Sopenharmony_ci .id_table = adf7242_device_id, 133962306a36Sopenharmony_ci .driver = { 134062306a36Sopenharmony_ci .of_match_table = adf7242_of_match, 134162306a36Sopenharmony_ci .name = "adf7242", 134262306a36Sopenharmony_ci }, 134362306a36Sopenharmony_ci .probe = adf7242_probe, 134462306a36Sopenharmony_ci .remove = adf7242_remove, 134562306a36Sopenharmony_ci}; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cimodule_spi_driver(adf7242_driver); 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ciMODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 135062306a36Sopenharmony_ciMODULE_DESCRIPTION("ADF7242 IEEE802.15.4 Transceiver Driver"); 135162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE); 1354