162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for NXP MCR20A 802.15.4 Wireless-PAN Networking controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2018 Xue Liu <liuxuenetmail@gmail.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1062306a36Sopenharmony_ci#include <linux/spi/spi.h>
1162306a36Sopenharmony_ci#include <linux/workqueue.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/irq.h>
1462306a36Sopenharmony_ci#include <linux/skbuff.h>
1562306a36Sopenharmony_ci#include <linux/of_gpio.h>
1662306a36Sopenharmony_ci#include <linux/regmap.h>
1762306a36Sopenharmony_ci#include <linux/ieee802154.h>
1862306a36Sopenharmony_ci#include <linux/debugfs.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <net/mac802154.h>
2162306a36Sopenharmony_ci#include <net/cfg802154.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/device.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include "mcr20a.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define	SPI_COMMAND_BUFFER		3
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define REGISTER_READ			BIT(7)
3062306a36Sopenharmony_ci#define REGISTER_WRITE			(0 << 7)
3162306a36Sopenharmony_ci#define REGISTER_ACCESS			(0 << 6)
3262306a36Sopenharmony_ci#define PACKET_BUFF_BURST_ACCESS	BIT(6)
3362306a36Sopenharmony_ci#define PACKET_BUFF_BYTE_ACCESS		BIT(5)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define MCR20A_WRITE_REG(x)		(x)
3662306a36Sopenharmony_ci#define MCR20A_READ_REG(x)		(REGISTER_READ | (x))
3762306a36Sopenharmony_ci#define MCR20A_BURST_READ_PACKET_BUF	(0xC0)
3862306a36Sopenharmony_ci#define MCR20A_BURST_WRITE_PACKET_BUF	(0x40)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define MCR20A_CMD_REG		0x80
4162306a36Sopenharmony_ci#define MCR20A_CMD_REG_MASK	0x3f
4262306a36Sopenharmony_ci#define MCR20A_CMD_WRITE	0x40
4362306a36Sopenharmony_ci#define MCR20A_CMD_FB		0x20
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* Number of Interrupt Request Status Register */
4662306a36Sopenharmony_ci#define MCR20A_IRQSTS_NUM 2 /* only IRQ_STS1 and IRQ_STS2 */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* MCR20A CCA Type */
4962306a36Sopenharmony_cienum {
5062306a36Sopenharmony_ci	MCR20A_CCA_ED,	  // energy detect - CCA bit not active,
5162306a36Sopenharmony_ci			  // not to be used for T and CCCA sequences
5262306a36Sopenharmony_ci	MCR20A_CCA_MODE1, // energy detect - CCA bit ACTIVE
5362306a36Sopenharmony_ci	MCR20A_CCA_MODE2, // 802.15.4 compliant signal detect - CCA bit ACTIVE
5462306a36Sopenharmony_ci	MCR20A_CCA_MODE3
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cienum {
5862306a36Sopenharmony_ci	MCR20A_XCVSEQ_IDLE	= 0x00,
5962306a36Sopenharmony_ci	MCR20A_XCVSEQ_RX	= 0x01,
6062306a36Sopenharmony_ci	MCR20A_XCVSEQ_TX	= 0x02,
6162306a36Sopenharmony_ci	MCR20A_XCVSEQ_CCA	= 0x03,
6262306a36Sopenharmony_ci	MCR20A_XCVSEQ_TR	= 0x04,
6362306a36Sopenharmony_ci	MCR20A_XCVSEQ_CCCA	= 0x05,
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */
6762306a36Sopenharmony_ci#define	MCR20A_MIN_CHANNEL	(11)
6862306a36Sopenharmony_ci#define	MCR20A_MAX_CHANNEL	(26)
6962306a36Sopenharmony_ci#define	MCR20A_CHANNEL_SPACING	(5)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* MCR20A CCA Threshold constans */
7262306a36Sopenharmony_ci#define MCR20A_MIN_CCA_THRESHOLD (0x6EU)
7362306a36Sopenharmony_ci#define MCR20A_MAX_CCA_THRESHOLD (0x00U)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* version 0C */
7662306a36Sopenharmony_ci#define MCR20A_OVERWRITE_VERSION (0x0C)
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/* MCR20A PLL configurations */
7962306a36Sopenharmony_cistatic const u8  PLL_INT[16] = {
8062306a36Sopenharmony_ci	/* 2405 */ 0x0B,	/* 2410 */ 0x0B,	/* 2415 */ 0x0B,
8162306a36Sopenharmony_ci	/* 2420 */ 0x0B,	/* 2425 */ 0x0B,	/* 2430 */ 0x0B,
8262306a36Sopenharmony_ci	/* 2435 */ 0x0C,	/* 2440 */ 0x0C,	/* 2445 */ 0x0C,
8362306a36Sopenharmony_ci	/* 2450 */ 0x0C,	/* 2455 */ 0x0C,	/* 2460 */ 0x0C,
8462306a36Sopenharmony_ci	/* 2465 */ 0x0D,	/* 2470 */ 0x0D,	/* 2475 */ 0x0D,
8562306a36Sopenharmony_ci	/* 2480 */ 0x0D
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic const u8 PLL_FRAC[16] = {
8962306a36Sopenharmony_ci	/* 2405 */ 0x28,	/* 2410 */ 0x50,	/* 2415 */ 0x78,
9062306a36Sopenharmony_ci	/* 2420 */ 0xA0,	/* 2425 */ 0xC8,	/* 2430 */ 0xF0,
9162306a36Sopenharmony_ci	/* 2435 */ 0x18,	/* 2440 */ 0x40,	/* 2445 */ 0x68,
9262306a36Sopenharmony_ci	/* 2450 */ 0x90,	/* 2455 */ 0xB8,	/* 2460 */ 0xE0,
9362306a36Sopenharmony_ci	/* 2465 */ 0x08,	/* 2470 */ 0x30,	/* 2475 */ 0x58,
9462306a36Sopenharmony_ci	/* 2480 */ 0x80
9562306a36Sopenharmony_ci};
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic const struct reg_sequence mar20a_iar_overwrites[] = {
9862306a36Sopenharmony_ci	{ IAR_MISC_PAD_CTRL,	0x02 },
9962306a36Sopenharmony_ci	{ IAR_VCO_CTRL1,	0xB3 },
10062306a36Sopenharmony_ci	{ IAR_VCO_CTRL2,	0x07 },
10162306a36Sopenharmony_ci	{ IAR_PA_TUNING,	0x71 },
10262306a36Sopenharmony_ci	{ IAR_CHF_IBUF,		0x2F },
10362306a36Sopenharmony_ci	{ IAR_CHF_QBUF,		0x2F },
10462306a36Sopenharmony_ci	{ IAR_CHF_IRIN,		0x24 },
10562306a36Sopenharmony_ci	{ IAR_CHF_QRIN,		0x24 },
10662306a36Sopenharmony_ci	{ IAR_CHF_IL,		0x24 },
10762306a36Sopenharmony_ci	{ IAR_CHF_QL,		0x24 },
10862306a36Sopenharmony_ci	{ IAR_CHF_CC1,		0x32 },
10962306a36Sopenharmony_ci	{ IAR_CHF_CCL,		0x1D },
11062306a36Sopenharmony_ci	{ IAR_CHF_CC2,		0x2D },
11162306a36Sopenharmony_ci	{ IAR_CHF_IROUT,	0x24 },
11262306a36Sopenharmony_ci	{ IAR_CHF_QROUT,	0x24 },
11362306a36Sopenharmony_ci	{ IAR_PA_CAL,		0x28 },
11462306a36Sopenharmony_ci	{ IAR_AGC_THR1,		0x55 },
11562306a36Sopenharmony_ci	{ IAR_AGC_THR2,		0x2D },
11662306a36Sopenharmony_ci	{ IAR_ATT_RSSI1,	0x5F },
11762306a36Sopenharmony_ci	{ IAR_ATT_RSSI2,	0x8F },
11862306a36Sopenharmony_ci	{ IAR_RSSI_OFFSET,	0x61 },
11962306a36Sopenharmony_ci	{ IAR_CHF_PMA_GAIN,	0x03 },
12062306a36Sopenharmony_ci	{ IAR_CCA1_THRESH,	0x50 },
12162306a36Sopenharmony_ci	{ IAR_CORR_NVAL,	0x13 },
12262306a36Sopenharmony_ci	{ IAR_ACKDELAY,		0x3D },
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define MCR20A_VALID_CHANNELS (0x07FFF800)
12662306a36Sopenharmony_ci#define MCR20A_MAX_BUF		(127)
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define printdev(X) (&X->spi->dev)
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/* regmap information for Direct Access Register (DAR) access */
13162306a36Sopenharmony_ci#define MCR20A_DAR_WRITE	0x01
13262306a36Sopenharmony_ci#define MCR20A_DAR_READ		0x00
13362306a36Sopenharmony_ci#define MCR20A_DAR_NUMREGS	0x3F
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/* regmap information for Indirect Access Register (IAR) access */
13662306a36Sopenharmony_ci#define MCR20A_IAR_ACCESS	0x80
13762306a36Sopenharmony_ci#define MCR20A_IAR_NUMREGS	0xBEFF
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/* Read/Write SPI Commands for DAR and IAR registers. */
14062306a36Sopenharmony_ci#define MCR20A_READSHORT(reg)	((reg) << 1)
14162306a36Sopenharmony_ci#define MCR20A_WRITESHORT(reg)	((reg) << 1 | 1)
14262306a36Sopenharmony_ci#define MCR20A_READLONG(reg)	(1 << 15 | (reg) << 5)
14362306a36Sopenharmony_ci#define MCR20A_WRITELONG(reg)	(1 << 15 | (reg) << 5 | 1 << 4)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* Type definitions for link configuration of instantiable layers  */
14662306a36Sopenharmony_ci#define MCR20A_PHY_INDIRECT_QUEUE_SIZE (12)
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic bool
14962306a36Sopenharmony_cimcr20a_dar_writeable(struct device *dev, unsigned int reg)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	switch (reg) {
15262306a36Sopenharmony_ci	case DAR_IRQ_STS1:
15362306a36Sopenharmony_ci	case DAR_IRQ_STS2:
15462306a36Sopenharmony_ci	case DAR_IRQ_STS3:
15562306a36Sopenharmony_ci	case DAR_PHY_CTRL1:
15662306a36Sopenharmony_ci	case DAR_PHY_CTRL2:
15762306a36Sopenharmony_ci	case DAR_PHY_CTRL3:
15862306a36Sopenharmony_ci	case DAR_PHY_CTRL4:
15962306a36Sopenharmony_ci	case DAR_SRC_CTRL:
16062306a36Sopenharmony_ci	case DAR_SRC_ADDRS_SUM_LSB:
16162306a36Sopenharmony_ci	case DAR_SRC_ADDRS_SUM_MSB:
16262306a36Sopenharmony_ci	case DAR_T3CMP_LSB:
16362306a36Sopenharmony_ci	case DAR_T3CMP_MSB:
16462306a36Sopenharmony_ci	case DAR_T3CMP_USB:
16562306a36Sopenharmony_ci	case DAR_T2PRIMECMP_LSB:
16662306a36Sopenharmony_ci	case DAR_T2PRIMECMP_MSB:
16762306a36Sopenharmony_ci	case DAR_T1CMP_LSB:
16862306a36Sopenharmony_ci	case DAR_T1CMP_MSB:
16962306a36Sopenharmony_ci	case DAR_T1CMP_USB:
17062306a36Sopenharmony_ci	case DAR_T2CMP_LSB:
17162306a36Sopenharmony_ci	case DAR_T2CMP_MSB:
17262306a36Sopenharmony_ci	case DAR_T2CMP_USB:
17362306a36Sopenharmony_ci	case DAR_T4CMP_LSB:
17462306a36Sopenharmony_ci	case DAR_T4CMP_MSB:
17562306a36Sopenharmony_ci	case DAR_T4CMP_USB:
17662306a36Sopenharmony_ci	case DAR_PLL_INT0:
17762306a36Sopenharmony_ci	case DAR_PLL_FRAC0_LSB:
17862306a36Sopenharmony_ci	case DAR_PLL_FRAC0_MSB:
17962306a36Sopenharmony_ci	case DAR_PA_PWR:
18062306a36Sopenharmony_ci	/* no DAR_ACM */
18162306a36Sopenharmony_ci	case DAR_OVERWRITE_VER:
18262306a36Sopenharmony_ci	case DAR_CLK_OUT_CTRL:
18362306a36Sopenharmony_ci	case DAR_PWR_MODES:
18462306a36Sopenharmony_ci		return true;
18562306a36Sopenharmony_ci	default:
18662306a36Sopenharmony_ci		return false;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic bool
19162306a36Sopenharmony_cimcr20a_dar_readable(struct device *dev, unsigned int reg)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	bool rc;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* all writeable are also readable */
19662306a36Sopenharmony_ci	rc = mcr20a_dar_writeable(dev, reg);
19762306a36Sopenharmony_ci	if (rc)
19862306a36Sopenharmony_ci		return rc;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	/* readonly regs */
20162306a36Sopenharmony_ci	switch (reg) {
20262306a36Sopenharmony_ci	case DAR_RX_FRM_LEN:
20362306a36Sopenharmony_ci	case DAR_CCA1_ED_FNL:
20462306a36Sopenharmony_ci	case DAR_EVENT_TMR_LSB:
20562306a36Sopenharmony_ci	case DAR_EVENT_TMR_MSB:
20662306a36Sopenharmony_ci	case DAR_EVENT_TMR_USB:
20762306a36Sopenharmony_ci	case DAR_TIMESTAMP_LSB:
20862306a36Sopenharmony_ci	case DAR_TIMESTAMP_MSB:
20962306a36Sopenharmony_ci	case DAR_TIMESTAMP_USB:
21062306a36Sopenharmony_ci	case DAR_SEQ_STATE:
21162306a36Sopenharmony_ci	case DAR_LQI_VALUE:
21262306a36Sopenharmony_ci	case DAR_RSSI_CCA_CONT:
21362306a36Sopenharmony_ci		return true;
21462306a36Sopenharmony_ci	default:
21562306a36Sopenharmony_ci		return false;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic bool
22062306a36Sopenharmony_cimcr20a_dar_volatile(struct device *dev, unsigned int reg)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	/* can be changed during runtime */
22362306a36Sopenharmony_ci	switch (reg) {
22462306a36Sopenharmony_ci	case DAR_IRQ_STS1:
22562306a36Sopenharmony_ci	case DAR_IRQ_STS2:
22662306a36Sopenharmony_ci	case DAR_IRQ_STS3:
22762306a36Sopenharmony_ci	/* use them in spi_async and regmap so it's volatile */
22862306a36Sopenharmony_ci		return true;
22962306a36Sopenharmony_ci	default:
23062306a36Sopenharmony_ci		return false;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic bool
23562306a36Sopenharmony_cimcr20a_dar_precious(struct device *dev, unsigned int reg)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	/* don't clear irq line on read */
23862306a36Sopenharmony_ci	switch (reg) {
23962306a36Sopenharmony_ci	case DAR_IRQ_STS1:
24062306a36Sopenharmony_ci	case DAR_IRQ_STS2:
24162306a36Sopenharmony_ci	case DAR_IRQ_STS3:
24262306a36Sopenharmony_ci		return true;
24362306a36Sopenharmony_ci	default:
24462306a36Sopenharmony_ci		return false;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic const struct regmap_config mcr20a_dar_regmap = {
24962306a36Sopenharmony_ci	.name			= "mcr20a_dar",
25062306a36Sopenharmony_ci	.reg_bits		= 8,
25162306a36Sopenharmony_ci	.val_bits		= 8,
25262306a36Sopenharmony_ci	.write_flag_mask	= REGISTER_ACCESS | REGISTER_WRITE,
25362306a36Sopenharmony_ci	.read_flag_mask		= REGISTER_ACCESS | REGISTER_READ,
25462306a36Sopenharmony_ci	.cache_type		= REGCACHE_RBTREE,
25562306a36Sopenharmony_ci	.writeable_reg		= mcr20a_dar_writeable,
25662306a36Sopenharmony_ci	.readable_reg		= mcr20a_dar_readable,
25762306a36Sopenharmony_ci	.volatile_reg		= mcr20a_dar_volatile,
25862306a36Sopenharmony_ci	.precious_reg		= mcr20a_dar_precious,
25962306a36Sopenharmony_ci	.fast_io		= true,
26062306a36Sopenharmony_ci	.can_multi_write	= true,
26162306a36Sopenharmony_ci};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic bool
26462306a36Sopenharmony_cimcr20a_iar_writeable(struct device *dev, unsigned int reg)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	switch (reg) {
26762306a36Sopenharmony_ci	case IAR_XTAL_TRIM:
26862306a36Sopenharmony_ci	case IAR_PMC_LP_TRIM:
26962306a36Sopenharmony_ci	case IAR_MACPANID0_LSB:
27062306a36Sopenharmony_ci	case IAR_MACPANID0_MSB:
27162306a36Sopenharmony_ci	case IAR_MACSHORTADDRS0_LSB:
27262306a36Sopenharmony_ci	case IAR_MACSHORTADDRS0_MSB:
27362306a36Sopenharmony_ci	case IAR_MACLONGADDRS0_0:
27462306a36Sopenharmony_ci	case IAR_MACLONGADDRS0_8:
27562306a36Sopenharmony_ci	case IAR_MACLONGADDRS0_16:
27662306a36Sopenharmony_ci	case IAR_MACLONGADDRS0_24:
27762306a36Sopenharmony_ci	case IAR_MACLONGADDRS0_32:
27862306a36Sopenharmony_ci	case IAR_MACLONGADDRS0_40:
27962306a36Sopenharmony_ci	case IAR_MACLONGADDRS0_48:
28062306a36Sopenharmony_ci	case IAR_MACLONGADDRS0_56:
28162306a36Sopenharmony_ci	case IAR_RX_FRAME_FILTER:
28262306a36Sopenharmony_ci	case IAR_PLL_INT1:
28362306a36Sopenharmony_ci	case IAR_PLL_FRAC1_LSB:
28462306a36Sopenharmony_ci	case IAR_PLL_FRAC1_MSB:
28562306a36Sopenharmony_ci	case IAR_MACPANID1_LSB:
28662306a36Sopenharmony_ci	case IAR_MACPANID1_MSB:
28762306a36Sopenharmony_ci	case IAR_MACSHORTADDRS1_LSB:
28862306a36Sopenharmony_ci	case IAR_MACSHORTADDRS1_MSB:
28962306a36Sopenharmony_ci	case IAR_MACLONGADDRS1_0:
29062306a36Sopenharmony_ci	case IAR_MACLONGADDRS1_8:
29162306a36Sopenharmony_ci	case IAR_MACLONGADDRS1_16:
29262306a36Sopenharmony_ci	case IAR_MACLONGADDRS1_24:
29362306a36Sopenharmony_ci	case IAR_MACLONGADDRS1_32:
29462306a36Sopenharmony_ci	case IAR_MACLONGADDRS1_40:
29562306a36Sopenharmony_ci	case IAR_MACLONGADDRS1_48:
29662306a36Sopenharmony_ci	case IAR_MACLONGADDRS1_56:
29762306a36Sopenharmony_ci	case IAR_DUAL_PAN_CTRL:
29862306a36Sopenharmony_ci	case IAR_DUAL_PAN_DWELL:
29962306a36Sopenharmony_ci	case IAR_CCA1_THRESH:
30062306a36Sopenharmony_ci	case IAR_CCA1_ED_OFFSET_COMP:
30162306a36Sopenharmony_ci	case IAR_LQI_OFFSET_COMP:
30262306a36Sopenharmony_ci	case IAR_CCA_CTRL:
30362306a36Sopenharmony_ci	case IAR_CCA2_CORR_PEAKS:
30462306a36Sopenharmony_ci	case IAR_CCA2_CORR_THRESH:
30562306a36Sopenharmony_ci	case IAR_TMR_PRESCALE:
30662306a36Sopenharmony_ci	case IAR_ANT_PAD_CTRL:
30762306a36Sopenharmony_ci	case IAR_MISC_PAD_CTRL:
30862306a36Sopenharmony_ci	case IAR_BSM_CTRL:
30962306a36Sopenharmony_ci	case IAR_RNG:
31062306a36Sopenharmony_ci	case IAR_RX_WTR_MARK:
31162306a36Sopenharmony_ci	case IAR_SOFT_RESET:
31262306a36Sopenharmony_ci	case IAR_TXDELAY:
31362306a36Sopenharmony_ci	case IAR_ACKDELAY:
31462306a36Sopenharmony_ci	case IAR_CORR_NVAL:
31562306a36Sopenharmony_ci	case IAR_ANT_AGC_CTRL:
31662306a36Sopenharmony_ci	case IAR_AGC_THR1:
31762306a36Sopenharmony_ci	case IAR_AGC_THR2:
31862306a36Sopenharmony_ci	case IAR_PA_CAL:
31962306a36Sopenharmony_ci	case IAR_ATT_RSSI1:
32062306a36Sopenharmony_ci	case IAR_ATT_RSSI2:
32162306a36Sopenharmony_ci	case IAR_RSSI_OFFSET:
32262306a36Sopenharmony_ci	case IAR_XTAL_CTRL:
32362306a36Sopenharmony_ci	case IAR_CHF_PMA_GAIN:
32462306a36Sopenharmony_ci	case IAR_CHF_IBUF:
32562306a36Sopenharmony_ci	case IAR_CHF_QBUF:
32662306a36Sopenharmony_ci	case IAR_CHF_IRIN:
32762306a36Sopenharmony_ci	case IAR_CHF_QRIN:
32862306a36Sopenharmony_ci	case IAR_CHF_IL:
32962306a36Sopenharmony_ci	case IAR_CHF_QL:
33062306a36Sopenharmony_ci	case IAR_CHF_CC1:
33162306a36Sopenharmony_ci	case IAR_CHF_CCL:
33262306a36Sopenharmony_ci	case IAR_CHF_CC2:
33362306a36Sopenharmony_ci	case IAR_CHF_IROUT:
33462306a36Sopenharmony_ci	case IAR_CHF_QROUT:
33562306a36Sopenharmony_ci	case IAR_PA_TUNING:
33662306a36Sopenharmony_ci	case IAR_VCO_CTRL1:
33762306a36Sopenharmony_ci	case IAR_VCO_CTRL2:
33862306a36Sopenharmony_ci		return true;
33962306a36Sopenharmony_ci	default:
34062306a36Sopenharmony_ci		return false;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic bool
34562306a36Sopenharmony_cimcr20a_iar_readable(struct device *dev, unsigned int reg)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	bool rc;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/* all writeable are also readable */
35062306a36Sopenharmony_ci	rc = mcr20a_iar_writeable(dev, reg);
35162306a36Sopenharmony_ci	if (rc)
35262306a36Sopenharmony_ci		return rc;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* readonly regs */
35562306a36Sopenharmony_ci	switch (reg) {
35662306a36Sopenharmony_ci	case IAR_PART_ID:
35762306a36Sopenharmony_ci	case IAR_DUAL_PAN_STS:
35862306a36Sopenharmony_ci	case IAR_RX_BYTE_COUNT:
35962306a36Sopenharmony_ci	case IAR_FILTERFAIL_CODE1:
36062306a36Sopenharmony_ci	case IAR_FILTERFAIL_CODE2:
36162306a36Sopenharmony_ci	case IAR_RSSI:
36262306a36Sopenharmony_ci		return true;
36362306a36Sopenharmony_ci	default:
36462306a36Sopenharmony_ci		return false;
36562306a36Sopenharmony_ci	}
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic bool
36962306a36Sopenharmony_cimcr20a_iar_volatile(struct device *dev, unsigned int reg)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci/* can be changed during runtime */
37262306a36Sopenharmony_ci	switch (reg) {
37362306a36Sopenharmony_ci	case IAR_DUAL_PAN_STS:
37462306a36Sopenharmony_ci	case IAR_RX_BYTE_COUNT:
37562306a36Sopenharmony_ci	case IAR_FILTERFAIL_CODE1:
37662306a36Sopenharmony_ci	case IAR_FILTERFAIL_CODE2:
37762306a36Sopenharmony_ci	case IAR_RSSI:
37862306a36Sopenharmony_ci		return true;
37962306a36Sopenharmony_ci	default:
38062306a36Sopenharmony_ci		return false;
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic const struct regmap_config mcr20a_iar_regmap = {
38562306a36Sopenharmony_ci	.name			= "mcr20a_iar",
38662306a36Sopenharmony_ci	.reg_bits		= 16,
38762306a36Sopenharmony_ci	.val_bits		= 8,
38862306a36Sopenharmony_ci	.write_flag_mask	= REGISTER_ACCESS | REGISTER_WRITE | IAR_INDEX,
38962306a36Sopenharmony_ci	.read_flag_mask		= REGISTER_ACCESS | REGISTER_READ  | IAR_INDEX,
39062306a36Sopenharmony_ci	.cache_type		= REGCACHE_RBTREE,
39162306a36Sopenharmony_ci	.writeable_reg		= mcr20a_iar_writeable,
39262306a36Sopenharmony_ci	.readable_reg		= mcr20a_iar_readable,
39362306a36Sopenharmony_ci	.volatile_reg		= mcr20a_iar_volatile,
39462306a36Sopenharmony_ci	.fast_io		= true,
39562306a36Sopenharmony_ci};
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistruct mcr20a_local {
39862306a36Sopenharmony_ci	struct spi_device *spi;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	struct ieee802154_hw *hw;
40162306a36Sopenharmony_ci	struct regmap *regmap_dar;
40262306a36Sopenharmony_ci	struct regmap *regmap_iar;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	u8 *buf;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	bool is_tx;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* for writing tx buffer */
40962306a36Sopenharmony_ci	struct spi_message tx_buf_msg;
41062306a36Sopenharmony_ci	u8 tx_header[1];
41162306a36Sopenharmony_ci	/* burst buffer write command */
41262306a36Sopenharmony_ci	struct spi_transfer tx_xfer_header;
41362306a36Sopenharmony_ci	u8 tx_len[1];
41462306a36Sopenharmony_ci	/* len of tx packet */
41562306a36Sopenharmony_ci	struct spi_transfer tx_xfer_len;
41662306a36Sopenharmony_ci	/* data of tx packet */
41762306a36Sopenharmony_ci	struct spi_transfer tx_xfer_buf;
41862306a36Sopenharmony_ci	struct sk_buff *tx_skb;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* for read length rxfifo */
42162306a36Sopenharmony_ci	struct spi_message reg_msg;
42262306a36Sopenharmony_ci	u8 reg_cmd[1];
42362306a36Sopenharmony_ci	u8 reg_data[MCR20A_IRQSTS_NUM];
42462306a36Sopenharmony_ci	struct spi_transfer reg_xfer_cmd;
42562306a36Sopenharmony_ci	struct spi_transfer reg_xfer_data;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* receive handling */
42862306a36Sopenharmony_ci	struct spi_message rx_buf_msg;
42962306a36Sopenharmony_ci	u8 rx_header[1];
43062306a36Sopenharmony_ci	struct spi_transfer rx_xfer_header;
43162306a36Sopenharmony_ci	u8 rx_lqi[1];
43262306a36Sopenharmony_ci	struct spi_transfer rx_xfer_lqi;
43362306a36Sopenharmony_ci	u8 rx_buf[MCR20A_MAX_BUF];
43462306a36Sopenharmony_ci	struct spi_transfer rx_xfer_buf;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/* isr handling for reading intstat */
43762306a36Sopenharmony_ci	struct spi_message irq_msg;
43862306a36Sopenharmony_ci	u8 irq_header[1];
43962306a36Sopenharmony_ci	u8 irq_data[MCR20A_IRQSTS_NUM];
44062306a36Sopenharmony_ci	struct spi_transfer irq_xfer_data;
44162306a36Sopenharmony_ci	struct spi_transfer irq_xfer_header;
44262306a36Sopenharmony_ci};
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic void
44562306a36Sopenharmony_cimcr20a_write_tx_buf_complete(void *context)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct mcr20a_local *lp = context;
44862306a36Sopenharmony_ci	int ret;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	lp->reg_msg.complete = NULL;
45362306a36Sopenharmony_ci	lp->reg_cmd[0]	= MCR20A_WRITE_REG(DAR_PHY_CTRL1);
45462306a36Sopenharmony_ci	lp->reg_data[0] = MCR20A_XCVSEQ_TX;
45562306a36Sopenharmony_ci	lp->reg_xfer_data.len = 1;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	ret = spi_async(lp->spi, &lp->reg_msg);
45862306a36Sopenharmony_ci	if (ret)
45962306a36Sopenharmony_ci		dev_err(printdev(lp), "failed to set SEQ TX\n");
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic int
46362306a36Sopenharmony_cimcr20a_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct mcr20a_local *lp = hw->priv;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	lp->tx_skb = skb;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	print_hex_dump_debug("mcr20a tx: ", DUMP_PREFIX_OFFSET, 16, 1,
47262306a36Sopenharmony_ci			     skb->data, skb->len, 0);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	lp->is_tx = 1;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	lp->reg_msg.complete	= NULL;
47762306a36Sopenharmony_ci	lp->reg_cmd[0]		= MCR20A_WRITE_REG(DAR_PHY_CTRL1);
47862306a36Sopenharmony_ci	lp->reg_data[0]		= MCR20A_XCVSEQ_IDLE;
47962306a36Sopenharmony_ci	lp->reg_xfer_data.len	= 1;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	return spi_async(lp->spi, &lp->reg_msg);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic int
48562306a36Sopenharmony_cimcr20a_ed(struct ieee802154_hw *hw, u8 *level)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	WARN_ON(!level);
48862306a36Sopenharmony_ci	*level = 0xbe;
48962306a36Sopenharmony_ci	return 0;
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic int
49362306a36Sopenharmony_cimcr20a_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct mcr20a_local *lp = hw->priv;
49662306a36Sopenharmony_ci	int ret;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/* freqency = ((PLL_INT+64) + (PLL_FRAC/65536)) * 32 MHz */
50162306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_PLL_INT0, PLL_INT[channel - 11]);
50262306a36Sopenharmony_ci	if (ret)
50362306a36Sopenharmony_ci		return ret;
50462306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_PLL_FRAC0_LSB, 0x00);
50562306a36Sopenharmony_ci	if (ret)
50662306a36Sopenharmony_ci		return ret;
50762306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_PLL_FRAC0_MSB,
50862306a36Sopenharmony_ci			   PLL_FRAC[channel - 11]);
50962306a36Sopenharmony_ci	if (ret)
51062306a36Sopenharmony_ci		return ret;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	return 0;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic int
51662306a36Sopenharmony_cimcr20a_start(struct ieee802154_hw *hw)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct mcr20a_local *lp = hw->priv;
51962306a36Sopenharmony_ci	int ret;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* No slotted operation */
52462306a36Sopenharmony_ci	dev_dbg(printdev(lp), "no slotted operation\n");
52562306a36Sopenharmony_ci	ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1,
52662306a36Sopenharmony_ci				 DAR_PHY_CTRL1_SLOTTED, 0x0);
52762306a36Sopenharmony_ci	if (ret < 0)
52862306a36Sopenharmony_ci		return ret;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* enable irq */
53162306a36Sopenharmony_ci	enable_irq(lp->spi->irq);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	/* Unmask SEQ interrupt */
53462306a36Sopenharmony_ci	ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL2,
53562306a36Sopenharmony_ci				 DAR_PHY_CTRL2_SEQMSK, 0x0);
53662306a36Sopenharmony_ci	if (ret < 0)
53762306a36Sopenharmony_ci		return ret;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/* Start the RX sequence */
54062306a36Sopenharmony_ci	dev_dbg(printdev(lp), "start the RX sequence\n");
54162306a36Sopenharmony_ci	ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1,
54262306a36Sopenharmony_ci				 DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_RX);
54362306a36Sopenharmony_ci	if (ret < 0)
54462306a36Sopenharmony_ci		return ret;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return 0;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic void
55062306a36Sopenharmony_cimcr20a_stop(struct ieee802154_hw *hw)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct mcr20a_local *lp = hw->priv;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	/* stop all running sequence */
55762306a36Sopenharmony_ci	regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1,
55862306a36Sopenharmony_ci			   DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_IDLE);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/* disable irq */
56162306a36Sopenharmony_ci	disable_irq(lp->spi->irq);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic int
56562306a36Sopenharmony_cimcr20a_set_hw_addr_filt(struct ieee802154_hw *hw,
56662306a36Sopenharmony_ci			struct ieee802154_hw_addr_filt *filt,
56762306a36Sopenharmony_ci			unsigned long changed)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	struct mcr20a_local *lp = hw->priv;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
57462306a36Sopenharmony_ci		u16 addr = le16_to_cpu(filt->short_addr);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci		regmap_write(lp->regmap_iar, IAR_MACSHORTADDRS0_LSB, addr);
57762306a36Sopenharmony_ci		regmap_write(lp->regmap_iar, IAR_MACSHORTADDRS0_MSB, addr >> 8);
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if (changed & IEEE802154_AFILT_PANID_CHANGED) {
58162306a36Sopenharmony_ci		u16 pan = le16_to_cpu(filt->pan_id);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		regmap_write(lp->regmap_iar, IAR_MACPANID0_LSB, pan);
58462306a36Sopenharmony_ci		regmap_write(lp->regmap_iar, IAR_MACPANID0_MSB, pan >> 8);
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
58862306a36Sopenharmony_ci		u8 addr[8], i;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		memcpy(addr, &filt->ieee_addr, 8);
59162306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
59262306a36Sopenharmony_ci			regmap_write(lp->regmap_iar,
59362306a36Sopenharmony_ci				     IAR_MACLONGADDRS0_0 + i, addr[i]);
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
59762306a36Sopenharmony_ci		if (filt->pan_coord) {
59862306a36Sopenharmony_ci			regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
59962306a36Sopenharmony_ci					   DAR_PHY_CTRL4_PANCORDNTR0, 0x10);
60062306a36Sopenharmony_ci		} else {
60162306a36Sopenharmony_ci			regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
60262306a36Sopenharmony_ci					   DAR_PHY_CTRL4_PANCORDNTR0, 0x00);
60362306a36Sopenharmony_ci		}
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return 0;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci/* -30 dBm to 10 dBm */
61062306a36Sopenharmony_ci#define MCR20A_MAX_TX_POWERS 0x14
61162306a36Sopenharmony_cistatic const s32 mcr20a_powers[MCR20A_MAX_TX_POWERS + 1] = {
61262306a36Sopenharmony_ci	-3000, -2800, -2600, -2400, -2200, -2000, -1800, -1600, -1400,
61362306a36Sopenharmony_ci	-1200, -1000, -800, -600, -400, -200, 0, 200, 400, 600, 800, 1000
61462306a36Sopenharmony_ci};
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic int
61762306a36Sopenharmony_cimcr20a_set_txpower(struct ieee802154_hw *hw, s32 mbm)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	struct mcr20a_local *lp = hw->priv;
62062306a36Sopenharmony_ci	u32 i;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s(%d)\n", __func__, mbm);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) {
62562306a36Sopenharmony_ci		if (lp->hw->phy->supported.tx_powers[i] == mbm)
62662306a36Sopenharmony_ci			return regmap_write(lp->regmap_dar, DAR_PA_PWR,
62762306a36Sopenharmony_ci					    ((i + 8) & 0x1F));
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	return -EINVAL;
63162306a36Sopenharmony_ci}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci#define MCR20A_MAX_ED_LEVELS MCR20A_MIN_CCA_THRESHOLD
63462306a36Sopenharmony_cistatic s32 mcr20a_ed_levels[MCR20A_MAX_ED_LEVELS + 1];
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic int
63762306a36Sopenharmony_cimcr20a_set_cca_mode(struct ieee802154_hw *hw,
63862306a36Sopenharmony_ci		    const struct wpan_phy_cca *cca)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct mcr20a_local *lp = hw->priv;
64162306a36Sopenharmony_ci	unsigned int cca_mode = 0xff;
64262306a36Sopenharmony_ci	bool cca_mode_and = false;
64362306a36Sopenharmony_ci	int ret;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	/* mapping 802.15.4 to driver spec */
64862306a36Sopenharmony_ci	switch (cca->mode) {
64962306a36Sopenharmony_ci	case NL802154_CCA_ENERGY:
65062306a36Sopenharmony_ci		cca_mode = MCR20A_CCA_MODE1;
65162306a36Sopenharmony_ci		break;
65262306a36Sopenharmony_ci	case NL802154_CCA_CARRIER:
65362306a36Sopenharmony_ci		cca_mode = MCR20A_CCA_MODE2;
65462306a36Sopenharmony_ci		break;
65562306a36Sopenharmony_ci	case NL802154_CCA_ENERGY_CARRIER:
65662306a36Sopenharmony_ci		switch (cca->opt) {
65762306a36Sopenharmony_ci		case NL802154_CCA_OPT_ENERGY_CARRIER_AND:
65862306a36Sopenharmony_ci			cca_mode = MCR20A_CCA_MODE3;
65962306a36Sopenharmony_ci			cca_mode_and = true;
66062306a36Sopenharmony_ci			break;
66162306a36Sopenharmony_ci		case NL802154_CCA_OPT_ENERGY_CARRIER_OR:
66262306a36Sopenharmony_ci			cca_mode = MCR20A_CCA_MODE3;
66362306a36Sopenharmony_ci			cca_mode_and = false;
66462306a36Sopenharmony_ci			break;
66562306a36Sopenharmony_ci		default:
66662306a36Sopenharmony_ci			return -EINVAL;
66762306a36Sopenharmony_ci		}
66862306a36Sopenharmony_ci		break;
66962306a36Sopenharmony_ci	default:
67062306a36Sopenharmony_ci		return -EINVAL;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci	ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
67362306a36Sopenharmony_ci				 DAR_PHY_CTRL4_CCATYPE_MASK,
67462306a36Sopenharmony_ci				 cca_mode << DAR_PHY_CTRL4_CCATYPE_SHIFT);
67562306a36Sopenharmony_ci	if (ret < 0)
67662306a36Sopenharmony_ci		return ret;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (cca_mode == MCR20A_CCA_MODE3) {
67962306a36Sopenharmony_ci		if (cca_mode_and) {
68062306a36Sopenharmony_ci			ret = regmap_update_bits(lp->regmap_iar, IAR_CCA_CTRL,
68162306a36Sopenharmony_ci						 IAR_CCA_CTRL_CCA3_AND_NOT_OR,
68262306a36Sopenharmony_ci						 0x08);
68362306a36Sopenharmony_ci		} else {
68462306a36Sopenharmony_ci			ret = regmap_update_bits(lp->regmap_iar,
68562306a36Sopenharmony_ci						 IAR_CCA_CTRL,
68662306a36Sopenharmony_ci						 IAR_CCA_CTRL_CCA3_AND_NOT_OR,
68762306a36Sopenharmony_ci						 0x00);
68862306a36Sopenharmony_ci		}
68962306a36Sopenharmony_ci		if (ret < 0)
69062306a36Sopenharmony_ci			return ret;
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	return ret;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic int
69762306a36Sopenharmony_cimcr20a_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct mcr20a_local *lp = hw->priv;
70062306a36Sopenharmony_ci	u32 i;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) {
70562306a36Sopenharmony_ci		if (hw->phy->supported.cca_ed_levels[i] == mbm)
70662306a36Sopenharmony_ci			return regmap_write(lp->regmap_iar, IAR_CCA1_THRESH, i);
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	return 0;
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic int
71362306a36Sopenharmony_cimcr20a_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	struct mcr20a_local *lp = hw->priv;
71662306a36Sopenharmony_ci	int ret;
71762306a36Sopenharmony_ci	u8 rx_frame_filter_reg = 0x0;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s(%d)\n", __func__, on);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (on) {
72262306a36Sopenharmony_ci		/* All frame types accepted*/
72362306a36Sopenharmony_ci		rx_frame_filter_reg &= ~(IAR_RX_FRAME_FLT_FRM_VER);
72462306a36Sopenharmony_ci		rx_frame_filter_reg |= (IAR_RX_FRAME_FLT_ACK_FT |
72562306a36Sopenharmony_ci				  IAR_RX_FRAME_FLT_NS_FT);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
72862306a36Sopenharmony_ci					 DAR_PHY_CTRL4_PROMISCUOUS,
72962306a36Sopenharmony_ci					 DAR_PHY_CTRL4_PROMISCUOUS);
73062306a36Sopenharmony_ci		if (ret < 0)
73162306a36Sopenharmony_ci			return ret;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci		ret = regmap_write(lp->regmap_iar, IAR_RX_FRAME_FILTER,
73462306a36Sopenharmony_ci				   rx_frame_filter_reg);
73562306a36Sopenharmony_ci		if (ret < 0)
73662306a36Sopenharmony_ci			return ret;
73762306a36Sopenharmony_ci	} else {
73862306a36Sopenharmony_ci		ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL4,
73962306a36Sopenharmony_ci					 DAR_PHY_CTRL4_PROMISCUOUS, 0x0);
74062306a36Sopenharmony_ci		if (ret < 0)
74162306a36Sopenharmony_ci			return ret;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci		ret = regmap_write(lp->regmap_iar, IAR_RX_FRAME_FILTER,
74462306a36Sopenharmony_ci				   IAR_RX_FRAME_FLT_FRM_VER |
74562306a36Sopenharmony_ci				   IAR_RX_FRAME_FLT_BEACON_FT |
74662306a36Sopenharmony_ci				   IAR_RX_FRAME_FLT_DATA_FT |
74762306a36Sopenharmony_ci				   IAR_RX_FRAME_FLT_CMD_FT);
74862306a36Sopenharmony_ci		if (ret < 0)
74962306a36Sopenharmony_ci			return ret;
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	return 0;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic const struct ieee802154_ops mcr20a_hw_ops = {
75662306a36Sopenharmony_ci	.owner			= THIS_MODULE,
75762306a36Sopenharmony_ci	.xmit_async		= mcr20a_xmit,
75862306a36Sopenharmony_ci	.ed			= mcr20a_ed,
75962306a36Sopenharmony_ci	.set_channel		= mcr20a_set_channel,
76062306a36Sopenharmony_ci	.start			= mcr20a_start,
76162306a36Sopenharmony_ci	.stop			= mcr20a_stop,
76262306a36Sopenharmony_ci	.set_hw_addr_filt	= mcr20a_set_hw_addr_filt,
76362306a36Sopenharmony_ci	.set_txpower		= mcr20a_set_txpower,
76462306a36Sopenharmony_ci	.set_cca_mode		= mcr20a_set_cca_mode,
76562306a36Sopenharmony_ci	.set_cca_ed_level	= mcr20a_set_cca_ed_level,
76662306a36Sopenharmony_ci	.set_promiscuous_mode	= mcr20a_set_promiscuous_mode,
76762306a36Sopenharmony_ci};
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic int
77062306a36Sopenharmony_cimcr20a_request_rx(struct mcr20a_local *lp)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/* Start the RX sequence */
77562306a36Sopenharmony_ci	regmap_update_bits_async(lp->regmap_dar, DAR_PHY_CTRL1,
77662306a36Sopenharmony_ci				 DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_RX);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	return 0;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic void
78262306a36Sopenharmony_cimcr20a_handle_rx_read_buf_complete(void *context)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	struct mcr20a_local *lp = context;
78562306a36Sopenharmony_ci	u8 len = lp->reg_data[0] & DAR_RX_FRAME_LENGTH_MASK;
78662306a36Sopenharmony_ci	struct sk_buff *skb;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	dev_dbg(printdev(lp), "RX is done\n");
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	if (!ieee802154_is_valid_psdu_len(len)) {
79362306a36Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
79462306a36Sopenharmony_ci		len = IEEE802154_MTU;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	len = len - 2;  /* get rid of frame check field */
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	skb = dev_alloc_skb(len);
80062306a36Sopenharmony_ci	if (!skb)
80162306a36Sopenharmony_ci		return;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	__skb_put_data(skb, lp->rx_buf, len);
80462306a36Sopenharmony_ci	ieee802154_rx_irqsafe(lp->hw, skb, lp->rx_lqi[0]);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	print_hex_dump_debug("mcr20a rx: ", DUMP_PREFIX_OFFSET, 16, 1,
80762306a36Sopenharmony_ci			     lp->rx_buf, len, 0);
80862306a36Sopenharmony_ci	pr_debug("mcr20a rx: lqi: %02hhx\n", lp->rx_lqi[0]);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/* start RX sequence */
81162306a36Sopenharmony_ci	mcr20a_request_rx(lp);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic void
81562306a36Sopenharmony_cimcr20a_handle_rx_read_len_complete(void *context)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	struct mcr20a_local *lp = context;
81862306a36Sopenharmony_ci	u8 len;
81962306a36Sopenharmony_ci	int ret;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/* get the length of received frame */
82462306a36Sopenharmony_ci	len = lp->reg_data[0] & DAR_RX_FRAME_LENGTH_MASK;
82562306a36Sopenharmony_ci	dev_dbg(printdev(lp), "frame len : %d\n", len);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/* prepare to read the rx buf */
82862306a36Sopenharmony_ci	lp->rx_buf_msg.complete = mcr20a_handle_rx_read_buf_complete;
82962306a36Sopenharmony_ci	lp->rx_header[0] = MCR20A_BURST_READ_PACKET_BUF;
83062306a36Sopenharmony_ci	lp->rx_xfer_buf.len = len;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	ret = spi_async(lp->spi, &lp->rx_buf_msg);
83362306a36Sopenharmony_ci	if (ret)
83462306a36Sopenharmony_ci		dev_err(printdev(lp), "failed to read rx buffer length\n");
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic int
83862306a36Sopenharmony_cimcr20a_handle_rx(struct mcr20a_local *lp)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
84162306a36Sopenharmony_ci	lp->reg_msg.complete = mcr20a_handle_rx_read_len_complete;
84262306a36Sopenharmony_ci	lp->reg_cmd[0] = MCR20A_READ_REG(DAR_RX_FRM_LEN);
84362306a36Sopenharmony_ci	lp->reg_xfer_data.len	= 1;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	return spi_async(lp->spi, &lp->reg_msg);
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic int
84962306a36Sopenharmony_cimcr20a_handle_tx_complete(struct mcr20a_local *lp)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	ieee802154_xmit_complete(lp->hw, lp->tx_skb, false);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	return mcr20a_request_rx(lp);
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic int
85962306a36Sopenharmony_cimcr20a_handle_tx(struct mcr20a_local *lp)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	int ret;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	/* write tx buffer */
86662306a36Sopenharmony_ci	lp->tx_header[0]	= MCR20A_BURST_WRITE_PACKET_BUF;
86762306a36Sopenharmony_ci	/* add 2 bytes of FCS */
86862306a36Sopenharmony_ci	lp->tx_len[0]		= lp->tx_skb->len + 2;
86962306a36Sopenharmony_ci	lp->tx_xfer_buf.tx_buf	= lp->tx_skb->data;
87062306a36Sopenharmony_ci	/* add 1 byte psduLength */
87162306a36Sopenharmony_ci	lp->tx_xfer_buf.len	= lp->tx_skb->len + 1;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	ret = spi_async(lp->spi, &lp->tx_buf_msg);
87462306a36Sopenharmony_ci	if (ret) {
87562306a36Sopenharmony_ci		dev_err(printdev(lp), "SPI write Failed for TX buf\n");
87662306a36Sopenharmony_ci		return ret;
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	return 0;
88062306a36Sopenharmony_ci}
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_cistatic void
88362306a36Sopenharmony_cimcr20a_irq_clean_complete(void *context)
88462306a36Sopenharmony_ci{
88562306a36Sopenharmony_ci	struct mcr20a_local *lp = context;
88662306a36Sopenharmony_ci	u8 seq_state = lp->irq_data[DAR_IRQ_STS1] & DAR_PHY_CTRL1_XCVSEQ_MASK;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	enable_irq(lp->spi->irq);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	dev_dbg(printdev(lp), "IRQ STA1 (%02x) STA2 (%02x)\n",
89362306a36Sopenharmony_ci		lp->irq_data[DAR_IRQ_STS1], lp->irq_data[DAR_IRQ_STS2]);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	switch (seq_state) {
89662306a36Sopenharmony_ci	/* TX IRQ, RX IRQ and SEQ IRQ */
89762306a36Sopenharmony_ci	case (DAR_IRQSTS1_TXIRQ | DAR_IRQSTS1_SEQIRQ):
89862306a36Sopenharmony_ci		if (lp->is_tx) {
89962306a36Sopenharmony_ci			lp->is_tx = 0;
90062306a36Sopenharmony_ci			dev_dbg(printdev(lp), "TX is done. No ACK\n");
90162306a36Sopenharmony_ci			mcr20a_handle_tx_complete(lp);
90262306a36Sopenharmony_ci		}
90362306a36Sopenharmony_ci		break;
90462306a36Sopenharmony_ci	case (DAR_IRQSTS1_RXIRQ | DAR_IRQSTS1_SEQIRQ):
90562306a36Sopenharmony_ci		/* rx is starting */
90662306a36Sopenharmony_ci		dev_dbg(printdev(lp), "RX is starting\n");
90762306a36Sopenharmony_ci		mcr20a_handle_rx(lp);
90862306a36Sopenharmony_ci		break;
90962306a36Sopenharmony_ci	case (DAR_IRQSTS1_RXIRQ | DAR_IRQSTS1_TXIRQ | DAR_IRQSTS1_SEQIRQ):
91062306a36Sopenharmony_ci		if (lp->is_tx) {
91162306a36Sopenharmony_ci			/* tx is done */
91262306a36Sopenharmony_ci			lp->is_tx = 0;
91362306a36Sopenharmony_ci			dev_dbg(printdev(lp), "TX is done. Get ACK\n");
91462306a36Sopenharmony_ci			mcr20a_handle_tx_complete(lp);
91562306a36Sopenharmony_ci		} else {
91662306a36Sopenharmony_ci			/* rx is starting */
91762306a36Sopenharmony_ci			dev_dbg(printdev(lp), "RX is starting\n");
91862306a36Sopenharmony_ci			mcr20a_handle_rx(lp);
91962306a36Sopenharmony_ci		}
92062306a36Sopenharmony_ci		break;
92162306a36Sopenharmony_ci	case (DAR_IRQSTS1_SEQIRQ):
92262306a36Sopenharmony_ci		if (lp->is_tx) {
92362306a36Sopenharmony_ci			dev_dbg(printdev(lp), "TX is starting\n");
92462306a36Sopenharmony_ci			mcr20a_handle_tx(lp);
92562306a36Sopenharmony_ci		} else {
92662306a36Sopenharmony_ci			dev_dbg(printdev(lp), "MCR20A is stop\n");
92762306a36Sopenharmony_ci		}
92862306a36Sopenharmony_ci		break;
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cistatic void mcr20a_irq_status_complete(void *context)
93362306a36Sopenharmony_ci{
93462306a36Sopenharmony_ci	int ret;
93562306a36Sopenharmony_ci	struct mcr20a_local *lp = context;
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
93862306a36Sopenharmony_ci	regmap_update_bits_async(lp->regmap_dar, DAR_PHY_CTRL1,
93962306a36Sopenharmony_ci				 DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_IDLE);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	lp->reg_msg.complete = mcr20a_irq_clean_complete;
94262306a36Sopenharmony_ci	lp->reg_cmd[0] = MCR20A_WRITE_REG(DAR_IRQ_STS1);
94362306a36Sopenharmony_ci	memcpy(lp->reg_data, lp->irq_data, MCR20A_IRQSTS_NUM);
94462306a36Sopenharmony_ci	lp->reg_xfer_data.len = MCR20A_IRQSTS_NUM;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	ret = spi_async(lp->spi, &lp->reg_msg);
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	if (ret)
94962306a36Sopenharmony_ci		dev_err(printdev(lp), "failed to clean irq status\n");
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic irqreturn_t mcr20a_irq_isr(int irq, void *data)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct mcr20a_local *lp = data;
95562306a36Sopenharmony_ci	int ret;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	disable_irq_nosync(irq);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	lp->irq_header[0] = MCR20A_READ_REG(DAR_IRQ_STS1);
96062306a36Sopenharmony_ci	/* read IRQSTSx */
96162306a36Sopenharmony_ci	ret = spi_async(lp->spi, &lp->irq_msg);
96262306a36Sopenharmony_ci	if (ret) {
96362306a36Sopenharmony_ci		enable_irq(irq);
96462306a36Sopenharmony_ci		return IRQ_NONE;
96562306a36Sopenharmony_ci	}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	return IRQ_HANDLED;
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cistatic void mcr20a_hw_setup(struct mcr20a_local *lp)
97162306a36Sopenharmony_ci{
97262306a36Sopenharmony_ci	u8 i;
97362306a36Sopenharmony_ci	struct ieee802154_hw *hw = lp->hw;
97462306a36Sopenharmony_ci	struct wpan_phy *phy = lp->hw->phy;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
97962306a36Sopenharmony_ci			IEEE802154_HW_AFILT |
98062306a36Sopenharmony_ci			IEEE802154_HW_PROMISCUOUS;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL |
98362306a36Sopenharmony_ci			WPAN_PHY_FLAG_CCA_MODE;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) |
98662306a36Sopenharmony_ci		BIT(NL802154_CCA_CARRIER) | BIT(NL802154_CCA_ENERGY_CARRIER);
98762306a36Sopenharmony_ci	phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) |
98862306a36Sopenharmony_ci		BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR);
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	/* initiating cca_ed_levels */
99162306a36Sopenharmony_ci	for (i = MCR20A_MAX_CCA_THRESHOLD; i < MCR20A_MIN_CCA_THRESHOLD + 1;
99262306a36Sopenharmony_ci	      ++i) {
99362306a36Sopenharmony_ci		mcr20a_ed_levels[i] =  -i * 100;
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	phy->supported.cca_ed_levels = mcr20a_ed_levels;
99762306a36Sopenharmony_ci	phy->supported.cca_ed_levels_size = ARRAY_SIZE(mcr20a_ed_levels);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	phy->cca.mode = NL802154_CCA_ENERGY;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	phy->supported.channels[0] = MCR20A_VALID_CHANNELS;
100262306a36Sopenharmony_ci	phy->current_page = 0;
100362306a36Sopenharmony_ci	/* MCR20A default reset value */
100462306a36Sopenharmony_ci	phy->current_channel = 20;
100562306a36Sopenharmony_ci	phy->supported.tx_powers = mcr20a_powers;
100662306a36Sopenharmony_ci	phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
100762306a36Sopenharmony_ci	phy->cca_ed_level = phy->supported.cca_ed_levels[75];
100862306a36Sopenharmony_ci	phy->transmit_power = phy->supported.tx_powers[0x0F];
100962306a36Sopenharmony_ci}
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic void
101262306a36Sopenharmony_cimcr20a_setup_tx_spi_messages(struct mcr20a_local *lp)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci	spi_message_init(&lp->tx_buf_msg);
101562306a36Sopenharmony_ci	lp->tx_buf_msg.context = lp;
101662306a36Sopenharmony_ci	lp->tx_buf_msg.complete = mcr20a_write_tx_buf_complete;
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	lp->tx_xfer_header.len = 1;
101962306a36Sopenharmony_ci	lp->tx_xfer_header.tx_buf = lp->tx_header;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	lp->tx_xfer_len.len = 1;
102262306a36Sopenharmony_ci	lp->tx_xfer_len.tx_buf = lp->tx_len;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	spi_message_add_tail(&lp->tx_xfer_header, &lp->tx_buf_msg);
102562306a36Sopenharmony_ci	spi_message_add_tail(&lp->tx_xfer_len, &lp->tx_buf_msg);
102662306a36Sopenharmony_ci	spi_message_add_tail(&lp->tx_xfer_buf, &lp->tx_buf_msg);
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic void
103062306a36Sopenharmony_cimcr20a_setup_rx_spi_messages(struct mcr20a_local *lp)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	spi_message_init(&lp->reg_msg);
103362306a36Sopenharmony_ci	lp->reg_msg.context = lp;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	lp->reg_xfer_cmd.len = 1;
103662306a36Sopenharmony_ci	lp->reg_xfer_cmd.tx_buf = lp->reg_cmd;
103762306a36Sopenharmony_ci	lp->reg_xfer_cmd.rx_buf = lp->reg_cmd;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	lp->reg_xfer_data.rx_buf = lp->reg_data;
104062306a36Sopenharmony_ci	lp->reg_xfer_data.tx_buf = lp->reg_data;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	spi_message_add_tail(&lp->reg_xfer_cmd, &lp->reg_msg);
104362306a36Sopenharmony_ci	spi_message_add_tail(&lp->reg_xfer_data, &lp->reg_msg);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	spi_message_init(&lp->rx_buf_msg);
104662306a36Sopenharmony_ci	lp->rx_buf_msg.context = lp;
104762306a36Sopenharmony_ci	lp->rx_buf_msg.complete = mcr20a_handle_rx_read_buf_complete;
104862306a36Sopenharmony_ci	lp->rx_xfer_header.len = 1;
104962306a36Sopenharmony_ci	lp->rx_xfer_header.tx_buf = lp->rx_header;
105062306a36Sopenharmony_ci	lp->rx_xfer_header.rx_buf = lp->rx_header;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	lp->rx_xfer_buf.rx_buf = lp->rx_buf;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	lp->rx_xfer_lqi.len = 1;
105562306a36Sopenharmony_ci	lp->rx_xfer_lqi.rx_buf = lp->rx_lqi;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	spi_message_add_tail(&lp->rx_xfer_header, &lp->rx_buf_msg);
105862306a36Sopenharmony_ci	spi_message_add_tail(&lp->rx_xfer_buf, &lp->rx_buf_msg);
105962306a36Sopenharmony_ci	spi_message_add_tail(&lp->rx_xfer_lqi, &lp->rx_buf_msg);
106062306a36Sopenharmony_ci}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_cistatic void
106362306a36Sopenharmony_cimcr20a_setup_irq_spi_messages(struct mcr20a_local *lp)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	spi_message_init(&lp->irq_msg);
106662306a36Sopenharmony_ci	lp->irq_msg.context		= lp;
106762306a36Sopenharmony_ci	lp->irq_msg.complete	= mcr20a_irq_status_complete;
106862306a36Sopenharmony_ci	lp->irq_xfer_header.len	= 1;
106962306a36Sopenharmony_ci	lp->irq_xfer_header.tx_buf = lp->irq_header;
107062306a36Sopenharmony_ci	lp->irq_xfer_header.rx_buf = lp->irq_header;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	lp->irq_xfer_data.len	= MCR20A_IRQSTS_NUM;
107362306a36Sopenharmony_ci	lp->irq_xfer_data.rx_buf = lp->irq_data;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	spi_message_add_tail(&lp->irq_xfer_header, &lp->irq_msg);
107662306a36Sopenharmony_ci	spi_message_add_tail(&lp->irq_xfer_data, &lp->irq_msg);
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_cistatic int
108062306a36Sopenharmony_cimcr20a_phy_init(struct mcr20a_local *lp)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	u8 index;
108362306a36Sopenharmony_ci	unsigned int phy_reg = 0;
108462306a36Sopenharmony_ci	int ret;
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	dev_dbg(printdev(lp), "%s\n", __func__);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	/* Disable Tristate on COCO MISO for SPI reads */
108962306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_iar, IAR_MISC_PAD_CTRL, 0x02);
109062306a36Sopenharmony_ci	if (ret)
109162306a36Sopenharmony_ci		goto err_ret;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	/* Clear all PP IRQ bits in IRQSTS1 to avoid unexpected interrupts
109462306a36Sopenharmony_ci	 * immediately after init
109562306a36Sopenharmony_ci	 */
109662306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_IRQ_STS1, 0xEF);
109762306a36Sopenharmony_ci	if (ret)
109862306a36Sopenharmony_ci		goto err_ret;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/* Clear all PP IRQ bits in IRQSTS2 */
110162306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_IRQ_STS2,
110262306a36Sopenharmony_ci			   DAR_IRQSTS2_ASM_IRQ | DAR_IRQSTS2_PB_ERR_IRQ |
110362306a36Sopenharmony_ci			   DAR_IRQSTS2_WAKE_IRQ);
110462306a36Sopenharmony_ci	if (ret)
110562306a36Sopenharmony_ci		goto err_ret;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	/* Disable all timer interrupts */
110862306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_IRQ_STS3, 0xFF);
110962306a36Sopenharmony_ci	if (ret)
111062306a36Sopenharmony_ci		goto err_ret;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	/*  PHY_CTRL1 : default HW settings + AUTOACK enabled */
111362306a36Sopenharmony_ci	ret = regmap_update_bits(lp->regmap_dar, DAR_PHY_CTRL1,
111462306a36Sopenharmony_ci				 DAR_PHY_CTRL1_AUTOACK, DAR_PHY_CTRL1_AUTOACK);
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	/*  PHY_CTRL2 : disable all interrupts */
111762306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_PHY_CTRL2, 0xFF);
111862306a36Sopenharmony_ci	if (ret)
111962306a36Sopenharmony_ci		goto err_ret;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	/* PHY_CTRL3 : disable all timers and remaining interrupts */
112262306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_PHY_CTRL3,
112362306a36Sopenharmony_ci			   DAR_PHY_CTRL3_ASM_MSK | DAR_PHY_CTRL3_PB_ERR_MSK |
112462306a36Sopenharmony_ci			   DAR_PHY_CTRL3_WAKE_MSK);
112562306a36Sopenharmony_ci	if (ret)
112662306a36Sopenharmony_ci		goto err_ret;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	/* SRC_CTRL : enable Acknowledge Frame Pending and
112962306a36Sopenharmony_ci	 * Source Address Matching Enable
113062306a36Sopenharmony_ci	 */
113162306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_SRC_CTRL,
113262306a36Sopenharmony_ci			   DAR_SRC_CTRL_ACK_FRM_PND |
113362306a36Sopenharmony_ci			   (DAR_SRC_CTRL_INDEX << DAR_SRC_CTRL_INDEX_SHIFT));
113462306a36Sopenharmony_ci	if (ret)
113562306a36Sopenharmony_ci		goto err_ret;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	/*  RX_FRAME_FILTER */
113862306a36Sopenharmony_ci	/*  FRM_VER[1:0] = b11. Accept FrameVersion 0 and 1 packets */
113962306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_iar, IAR_RX_FRAME_FILTER,
114062306a36Sopenharmony_ci			   IAR_RX_FRAME_FLT_FRM_VER |
114162306a36Sopenharmony_ci			   IAR_RX_FRAME_FLT_BEACON_FT |
114262306a36Sopenharmony_ci			   IAR_RX_FRAME_FLT_DATA_FT |
114362306a36Sopenharmony_ci			   IAR_RX_FRAME_FLT_CMD_FT);
114462306a36Sopenharmony_ci	if (ret)
114562306a36Sopenharmony_ci		goto err_ret;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	dev_info(printdev(lp), "MCR20A DAR overwrites version: 0x%02x\n",
114862306a36Sopenharmony_ci		 MCR20A_OVERWRITE_VERSION);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	/* Overwrites direct registers  */
115162306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_dar, DAR_OVERWRITE_VER,
115262306a36Sopenharmony_ci			   MCR20A_OVERWRITE_VERSION);
115362306a36Sopenharmony_ci	if (ret)
115462306a36Sopenharmony_ci		goto err_ret;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	/* Overwrites indirect registers  */
115762306a36Sopenharmony_ci	ret = regmap_multi_reg_write(lp->regmap_iar, mar20a_iar_overwrites,
115862306a36Sopenharmony_ci				     ARRAY_SIZE(mar20a_iar_overwrites));
115962306a36Sopenharmony_ci	if (ret)
116062306a36Sopenharmony_ci		goto err_ret;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	/* Clear HW indirect queue */
116362306a36Sopenharmony_ci	dev_dbg(printdev(lp), "clear HW indirect queue\n");
116462306a36Sopenharmony_ci	for (index = 0; index < MCR20A_PHY_INDIRECT_QUEUE_SIZE; index++) {
116562306a36Sopenharmony_ci		phy_reg = (u8)(((index & DAR_SRC_CTRL_INDEX) <<
116662306a36Sopenharmony_ci			       DAR_SRC_CTRL_INDEX_SHIFT)
116762306a36Sopenharmony_ci			      | (DAR_SRC_CTRL_SRCADDR_EN)
116862306a36Sopenharmony_ci			      | (DAR_SRC_CTRL_INDEX_DISABLE));
116962306a36Sopenharmony_ci		ret = regmap_write(lp->regmap_dar, DAR_SRC_CTRL, phy_reg);
117062306a36Sopenharmony_ci		if (ret)
117162306a36Sopenharmony_ci			goto err_ret;
117262306a36Sopenharmony_ci		phy_reg = 0;
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/* Assign HW Indirect hash table to PAN0 */
117662306a36Sopenharmony_ci	ret = regmap_read(lp->regmap_iar, IAR_DUAL_PAN_CTRL, &phy_reg);
117762306a36Sopenharmony_ci	if (ret)
117862306a36Sopenharmony_ci		goto err_ret;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* Clear current lvl */
118162306a36Sopenharmony_ci	phy_reg &= ~IAR_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_MSK;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* Set new lvl */
118462306a36Sopenharmony_ci	phy_reg |= MCR20A_PHY_INDIRECT_QUEUE_SIZE <<
118562306a36Sopenharmony_ci		IAR_DUAL_PAN_CTRL_DUAL_PAN_SAM_LVL_SHIFT;
118662306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_iar, IAR_DUAL_PAN_CTRL, phy_reg);
118762306a36Sopenharmony_ci	if (ret)
118862306a36Sopenharmony_ci		goto err_ret;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	/* Set CCA threshold to -75 dBm */
119162306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_iar, IAR_CCA1_THRESH, 0x4B);
119262306a36Sopenharmony_ci	if (ret)
119362306a36Sopenharmony_ci		goto err_ret;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	/* Set prescaller to obtain 1 symbol (16us) timebase */
119662306a36Sopenharmony_ci	ret = regmap_write(lp->regmap_iar, IAR_TMR_PRESCALE, 0x05);
119762306a36Sopenharmony_ci	if (ret)
119862306a36Sopenharmony_ci		goto err_ret;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	/* Enable autodoze mode. */
120162306a36Sopenharmony_ci	ret = regmap_update_bits(lp->regmap_dar, DAR_PWR_MODES,
120262306a36Sopenharmony_ci				 DAR_PWR_MODES_AUTODOZE,
120362306a36Sopenharmony_ci				 DAR_PWR_MODES_AUTODOZE);
120462306a36Sopenharmony_ci	if (ret)
120562306a36Sopenharmony_ci		goto err_ret;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	/* Disable clk_out */
120862306a36Sopenharmony_ci	ret = regmap_update_bits(lp->regmap_dar, DAR_CLK_OUT_CTRL,
120962306a36Sopenharmony_ci				 DAR_CLK_OUT_CTRL_EN, 0x0);
121062306a36Sopenharmony_ci	if (ret)
121162306a36Sopenharmony_ci		goto err_ret;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	return 0;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cierr_ret:
121662306a36Sopenharmony_ci	return ret;
121762306a36Sopenharmony_ci}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_cistatic int
122062306a36Sopenharmony_cimcr20a_probe(struct spi_device *spi)
122162306a36Sopenharmony_ci{
122262306a36Sopenharmony_ci	struct ieee802154_hw *hw;
122362306a36Sopenharmony_ci	struct mcr20a_local *lp;
122462306a36Sopenharmony_ci	struct gpio_desc *rst_b;
122562306a36Sopenharmony_ci	int irq_type;
122662306a36Sopenharmony_ci	int ret = -ENOMEM;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	dev_dbg(&spi->dev, "%s\n", __func__);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	if (!spi->irq) {
123162306a36Sopenharmony_ci		dev_err(&spi->dev, "no IRQ specified\n");
123262306a36Sopenharmony_ci		return -EINVAL;
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	rst_b = devm_gpiod_get(&spi->dev, "rst_b", GPIOD_OUT_HIGH);
123662306a36Sopenharmony_ci	if (IS_ERR(rst_b))
123762306a36Sopenharmony_ci		return dev_err_probe(&spi->dev, PTR_ERR(rst_b),
123862306a36Sopenharmony_ci				     "Failed to get 'rst_b' gpio");
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	/* reset mcr20a */
124162306a36Sopenharmony_ci	usleep_range(10, 20);
124262306a36Sopenharmony_ci	gpiod_set_value_cansleep(rst_b, 1);
124362306a36Sopenharmony_ci	usleep_range(10, 20);
124462306a36Sopenharmony_ci	gpiod_set_value_cansleep(rst_b, 0);
124562306a36Sopenharmony_ci	usleep_range(120, 240);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	/* allocate ieee802154_hw and private data */
124862306a36Sopenharmony_ci	hw = ieee802154_alloc_hw(sizeof(*lp), &mcr20a_hw_ops);
124962306a36Sopenharmony_ci	if (!hw) {
125062306a36Sopenharmony_ci		dev_crit(&spi->dev, "ieee802154_alloc_hw failed\n");
125162306a36Sopenharmony_ci		return ret;
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	/* init mcr20a local data */
125562306a36Sopenharmony_ci	lp = hw->priv;
125662306a36Sopenharmony_ci	lp->hw = hw;
125762306a36Sopenharmony_ci	lp->spi = spi;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/* init ieee802154_hw */
126062306a36Sopenharmony_ci	hw->parent = &spi->dev;
126162306a36Sopenharmony_ci	ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	/* init buf */
126462306a36Sopenharmony_ci	lp->buf = devm_kzalloc(&spi->dev, SPI_COMMAND_BUFFER, GFP_KERNEL);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (!lp->buf) {
126762306a36Sopenharmony_ci		ret = -ENOMEM;
126862306a36Sopenharmony_ci		goto free_dev;
126962306a36Sopenharmony_ci	}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	mcr20a_setup_tx_spi_messages(lp);
127262306a36Sopenharmony_ci	mcr20a_setup_rx_spi_messages(lp);
127362306a36Sopenharmony_ci	mcr20a_setup_irq_spi_messages(lp);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	/* setup regmap */
127662306a36Sopenharmony_ci	lp->regmap_dar = devm_regmap_init_spi(spi, &mcr20a_dar_regmap);
127762306a36Sopenharmony_ci	if (IS_ERR(lp->regmap_dar)) {
127862306a36Sopenharmony_ci		ret = PTR_ERR(lp->regmap_dar);
127962306a36Sopenharmony_ci		dev_err(&spi->dev, "Failed to allocate dar map: %d\n",
128062306a36Sopenharmony_ci			ret);
128162306a36Sopenharmony_ci		goto free_dev;
128262306a36Sopenharmony_ci	}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	lp->regmap_iar = devm_regmap_init_spi(spi, &mcr20a_iar_regmap);
128562306a36Sopenharmony_ci	if (IS_ERR(lp->regmap_iar)) {
128662306a36Sopenharmony_ci		ret = PTR_ERR(lp->regmap_iar);
128762306a36Sopenharmony_ci		dev_err(&spi->dev, "Failed to allocate iar map: %d\n", ret);
128862306a36Sopenharmony_ci		goto free_dev;
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	mcr20a_hw_setup(lp);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	spi_set_drvdata(spi, lp);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci	ret = mcr20a_phy_init(lp);
129662306a36Sopenharmony_ci	if (ret < 0) {
129762306a36Sopenharmony_ci		dev_crit(&spi->dev, "mcr20a_phy_init failed\n");
129862306a36Sopenharmony_ci		goto free_dev;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	irq_type = irq_get_trigger_type(spi->irq);
130262306a36Sopenharmony_ci	if (!irq_type)
130362306a36Sopenharmony_ci		irq_type = IRQF_TRIGGER_FALLING;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	ret = devm_request_irq(&spi->dev, spi->irq, mcr20a_irq_isr,
130662306a36Sopenharmony_ci			       irq_type, dev_name(&spi->dev), lp);
130762306a36Sopenharmony_ci	if (ret) {
130862306a36Sopenharmony_ci		dev_err(&spi->dev, "could not request_irq for mcr20a\n");
130962306a36Sopenharmony_ci		ret = -ENODEV;
131062306a36Sopenharmony_ci		goto free_dev;
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	/* disable_irq by default and wait for starting hardware */
131462306a36Sopenharmony_ci	disable_irq(spi->irq);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	ret = ieee802154_register_hw(hw);
131762306a36Sopenharmony_ci	if (ret) {
131862306a36Sopenharmony_ci		dev_crit(&spi->dev, "ieee802154_register_hw failed\n");
131962306a36Sopenharmony_ci		goto free_dev;
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	return ret;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_cifree_dev:
132562306a36Sopenharmony_ci	ieee802154_free_hw(lp->hw);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	return ret;
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_cistatic void mcr20a_remove(struct spi_device *spi)
133162306a36Sopenharmony_ci{
133262306a36Sopenharmony_ci	struct mcr20a_local *lp = spi_get_drvdata(spi);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	dev_dbg(&spi->dev, "%s\n", __func__);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	ieee802154_unregister_hw(lp->hw);
133762306a36Sopenharmony_ci	ieee802154_free_hw(lp->hw);
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_cistatic const struct of_device_id mcr20a_of_match[] = {
134162306a36Sopenharmony_ci	{ .compatible = "nxp,mcr20a", },
134262306a36Sopenharmony_ci	{ },
134362306a36Sopenharmony_ci};
134462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mcr20a_of_match);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_cistatic const struct spi_device_id mcr20a_device_id[] = {
134762306a36Sopenharmony_ci	{ .name = "mcr20a", },
134862306a36Sopenharmony_ci	{ },
134962306a36Sopenharmony_ci};
135062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, mcr20a_device_id);
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_cistatic struct spi_driver mcr20a_driver = {
135362306a36Sopenharmony_ci	.id_table = mcr20a_device_id,
135462306a36Sopenharmony_ci	.driver = {
135562306a36Sopenharmony_ci		.of_match_table = mcr20a_of_match,
135662306a36Sopenharmony_ci		.name	= "mcr20a",
135762306a36Sopenharmony_ci	},
135862306a36Sopenharmony_ci	.probe      = mcr20a_probe,
135962306a36Sopenharmony_ci	.remove     = mcr20a_remove,
136062306a36Sopenharmony_ci};
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_cimodule_spi_driver(mcr20a_driver);
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ciMODULE_DESCRIPTION("MCR20A Transceiver Driver");
136562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
136662306a36Sopenharmony_ciMODULE_AUTHOR("Xue Liu <liuxuenetmail@gmail>");
1367