162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AT86RF230/RF231 driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2009-2012 Siemens AG
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Written by:
862306a36Sopenharmony_ci * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
962306a36Sopenharmony_ci * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
1062306a36Sopenharmony_ci * Alexander Aring <aar@pengutronix.de>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/hrtimer.h>
1562306a36Sopenharmony_ci#include <linux/jiffies.h>
1662306a36Sopenharmony_ci#include <linux/interrupt.h>
1762306a36Sopenharmony_ci#include <linux/irq.h>
1862306a36Sopenharmony_ci#include <linux/gpio.h>
1962306a36Sopenharmony_ci#include <linux/delay.h>
2062306a36Sopenharmony_ci#include <linux/property.h>
2162306a36Sopenharmony_ci#include <linux/spi/spi.h>
2262306a36Sopenharmony_ci#include <linux/regmap.h>
2362306a36Sopenharmony_ci#include <linux/skbuff.h>
2462306a36Sopenharmony_ci#include <linux/of_gpio.h>
2562306a36Sopenharmony_ci#include <linux/ieee802154.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <net/mac802154.h>
2862306a36Sopenharmony_ci#include <net/cfg802154.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include "at86rf230.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct at86rf230_local;
3362306a36Sopenharmony_ci/* at86rf2xx chip depend data.
3462306a36Sopenharmony_ci * All timings are in us.
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_cistruct at86rf2xx_chip_data {
3762306a36Sopenharmony_ci	u16 t_sleep_cycle;
3862306a36Sopenharmony_ci	u16 t_channel_switch;
3962306a36Sopenharmony_ci	u16 t_reset_to_off;
4062306a36Sopenharmony_ci	u16 t_off_to_aack;
4162306a36Sopenharmony_ci	u16 t_off_to_tx_on;
4262306a36Sopenharmony_ci	u16 t_off_to_sleep;
4362306a36Sopenharmony_ci	u16 t_sleep_to_off;
4462306a36Sopenharmony_ci	u16 t_frame;
4562306a36Sopenharmony_ci	u16 t_p_ack;
4662306a36Sopenharmony_ci	int rssi_base_val;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	int (*set_channel)(struct at86rf230_local *, u8, u8);
4962306a36Sopenharmony_ci	int (*set_txpower)(struct at86rf230_local *, s32);
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define AT86RF2XX_MAX_BUF		(127 + 3)
5362306a36Sopenharmony_ci/* tx retries to access the TX_ON state
5462306a36Sopenharmony_ci * if it's above then force change will be started.
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci * We assume the max_frame_retries (7) value of 802.15.4 here.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci#define AT86RF2XX_MAX_TX_RETRIES	7
5962306a36Sopenharmony_ci/* We use the recommended 5 minutes timeout to recalibrate */
6062306a36Sopenharmony_ci#define AT86RF2XX_CAL_LOOP_TIMEOUT	(5 * 60 * HZ)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistruct at86rf230_state_change {
6362306a36Sopenharmony_ci	struct at86rf230_local *lp;
6462306a36Sopenharmony_ci	int irq;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	struct hrtimer timer;
6762306a36Sopenharmony_ci	struct spi_message msg;
6862306a36Sopenharmony_ci	struct spi_transfer trx;
6962306a36Sopenharmony_ci	u8 buf[AT86RF2XX_MAX_BUF];
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	void (*complete)(void *context);
7262306a36Sopenharmony_ci	u8 from_state;
7362306a36Sopenharmony_ci	u8 to_state;
7462306a36Sopenharmony_ci	int trac;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	bool free;
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistruct at86rf230_local {
8062306a36Sopenharmony_ci	struct spi_device *spi;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	struct ieee802154_hw *hw;
8362306a36Sopenharmony_ci	struct at86rf2xx_chip_data *data;
8462306a36Sopenharmony_ci	struct regmap *regmap;
8562306a36Sopenharmony_ci	struct gpio_desc *slp_tr;
8662306a36Sopenharmony_ci	bool sleep;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	struct completion state_complete;
8962306a36Sopenharmony_ci	struct at86rf230_state_change state;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	unsigned long cal_timeout;
9262306a36Sopenharmony_ci	bool is_tx;
9362306a36Sopenharmony_ci	bool is_tx_from_off;
9462306a36Sopenharmony_ci	bool was_tx;
9562306a36Sopenharmony_ci	u8 tx_retry;
9662306a36Sopenharmony_ci	struct sk_buff *tx_skb;
9762306a36Sopenharmony_ci	struct at86rf230_state_change tx;
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define AT86RF2XX_NUMREGS 0x3F
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic void
10362306a36Sopenharmony_ciat86rf230_async_state_change(struct at86rf230_local *lp,
10462306a36Sopenharmony_ci			     struct at86rf230_state_change *ctx,
10562306a36Sopenharmony_ci			     const u8 state, void (*complete)(void *context));
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic inline void
10862306a36Sopenharmony_ciat86rf230_sleep(struct at86rf230_local *lp)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	if (lp->slp_tr) {
11162306a36Sopenharmony_ci		gpiod_set_value(lp->slp_tr, 1);
11262306a36Sopenharmony_ci		usleep_range(lp->data->t_off_to_sleep,
11362306a36Sopenharmony_ci			     lp->data->t_off_to_sleep + 10);
11462306a36Sopenharmony_ci		lp->sleep = true;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline void
11962306a36Sopenharmony_ciat86rf230_awake(struct at86rf230_local *lp)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	if (lp->slp_tr) {
12262306a36Sopenharmony_ci		gpiod_set_value(lp->slp_tr, 0);
12362306a36Sopenharmony_ci		usleep_range(lp->data->t_sleep_to_off,
12462306a36Sopenharmony_ci			     lp->data->t_sleep_to_off + 100);
12562306a36Sopenharmony_ci		lp->sleep = false;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic inline int
13062306a36Sopenharmony_ci__at86rf230_write(struct at86rf230_local *lp,
13162306a36Sopenharmony_ci		  unsigned int addr, unsigned int data)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	bool sleep = lp->sleep;
13462306a36Sopenharmony_ci	int ret;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* awake for register setting if sleep */
13762306a36Sopenharmony_ci	if (sleep)
13862306a36Sopenharmony_ci		at86rf230_awake(lp);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	ret = regmap_write(lp->regmap, addr, data);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	/* sleep again if was sleeping */
14362306a36Sopenharmony_ci	if (sleep)
14462306a36Sopenharmony_ci		at86rf230_sleep(lp);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return ret;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic inline int
15062306a36Sopenharmony_ci__at86rf230_read(struct at86rf230_local *lp,
15162306a36Sopenharmony_ci		 unsigned int addr, unsigned int *data)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	bool sleep = lp->sleep;
15462306a36Sopenharmony_ci	int ret;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* awake for register setting if sleep */
15762306a36Sopenharmony_ci	if (sleep)
15862306a36Sopenharmony_ci		at86rf230_awake(lp);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	ret = regmap_read(lp->regmap, addr, data);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* sleep again if was sleeping */
16362306a36Sopenharmony_ci	if (sleep)
16462306a36Sopenharmony_ci		at86rf230_sleep(lp);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return ret;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic inline int
17062306a36Sopenharmony_ciat86rf230_read_subreg(struct at86rf230_local *lp,
17162306a36Sopenharmony_ci		      unsigned int addr, unsigned int mask,
17262306a36Sopenharmony_ci		      unsigned int shift, unsigned int *data)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	int rc;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	rc = __at86rf230_read(lp, addr, data);
17762306a36Sopenharmony_ci	if (!rc)
17862306a36Sopenharmony_ci		*data = (*data & mask) >> shift;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return rc;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic inline int
18462306a36Sopenharmony_ciat86rf230_write_subreg(struct at86rf230_local *lp,
18562306a36Sopenharmony_ci		       unsigned int addr, unsigned int mask,
18662306a36Sopenharmony_ci		       unsigned int shift, unsigned int data)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	bool sleep = lp->sleep;
18962306a36Sopenharmony_ci	int ret;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* awake for register setting if sleep */
19262306a36Sopenharmony_ci	if (sleep)
19362306a36Sopenharmony_ci		at86rf230_awake(lp);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	ret = regmap_update_bits(lp->regmap, addr, mask, data << shift);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/* sleep again if was sleeping */
19862306a36Sopenharmony_ci	if (sleep)
19962306a36Sopenharmony_ci		at86rf230_sleep(lp);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	return ret;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic inline void
20562306a36Sopenharmony_ciat86rf230_slp_tr_rising_edge(struct at86rf230_local *lp)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	gpiod_set_value(lp->slp_tr, 1);
20862306a36Sopenharmony_ci	udelay(1);
20962306a36Sopenharmony_ci	gpiod_set_value(lp->slp_tr, 0);
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic bool
21362306a36Sopenharmony_ciat86rf230_reg_writeable(struct device *dev, unsigned int reg)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	switch (reg) {
21662306a36Sopenharmony_ci	case RG_TRX_STATE:
21762306a36Sopenharmony_ci	case RG_TRX_CTRL_0:
21862306a36Sopenharmony_ci	case RG_TRX_CTRL_1:
21962306a36Sopenharmony_ci	case RG_PHY_TX_PWR:
22062306a36Sopenharmony_ci	case RG_PHY_ED_LEVEL:
22162306a36Sopenharmony_ci	case RG_PHY_CC_CCA:
22262306a36Sopenharmony_ci	case RG_CCA_THRES:
22362306a36Sopenharmony_ci	case RG_RX_CTRL:
22462306a36Sopenharmony_ci	case RG_SFD_VALUE:
22562306a36Sopenharmony_ci	case RG_TRX_CTRL_2:
22662306a36Sopenharmony_ci	case RG_ANT_DIV:
22762306a36Sopenharmony_ci	case RG_IRQ_MASK:
22862306a36Sopenharmony_ci	case RG_VREG_CTRL:
22962306a36Sopenharmony_ci	case RG_BATMON:
23062306a36Sopenharmony_ci	case RG_XOSC_CTRL:
23162306a36Sopenharmony_ci	case RG_RX_SYN:
23262306a36Sopenharmony_ci	case RG_XAH_CTRL_1:
23362306a36Sopenharmony_ci	case RG_FTN_CTRL:
23462306a36Sopenharmony_ci	case RG_PLL_CF:
23562306a36Sopenharmony_ci	case RG_PLL_DCU:
23662306a36Sopenharmony_ci	case RG_SHORT_ADDR_0:
23762306a36Sopenharmony_ci	case RG_SHORT_ADDR_1:
23862306a36Sopenharmony_ci	case RG_PAN_ID_0:
23962306a36Sopenharmony_ci	case RG_PAN_ID_1:
24062306a36Sopenharmony_ci	case RG_IEEE_ADDR_0:
24162306a36Sopenharmony_ci	case RG_IEEE_ADDR_1:
24262306a36Sopenharmony_ci	case RG_IEEE_ADDR_2:
24362306a36Sopenharmony_ci	case RG_IEEE_ADDR_3:
24462306a36Sopenharmony_ci	case RG_IEEE_ADDR_4:
24562306a36Sopenharmony_ci	case RG_IEEE_ADDR_5:
24662306a36Sopenharmony_ci	case RG_IEEE_ADDR_6:
24762306a36Sopenharmony_ci	case RG_IEEE_ADDR_7:
24862306a36Sopenharmony_ci	case RG_XAH_CTRL_0:
24962306a36Sopenharmony_ci	case RG_CSMA_SEED_0:
25062306a36Sopenharmony_ci	case RG_CSMA_SEED_1:
25162306a36Sopenharmony_ci	case RG_CSMA_BE:
25262306a36Sopenharmony_ci		return true;
25362306a36Sopenharmony_ci	default:
25462306a36Sopenharmony_ci		return false;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic bool
25962306a36Sopenharmony_ciat86rf230_reg_readable(struct device *dev, unsigned int reg)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	bool rc;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* all writeable are also readable */
26462306a36Sopenharmony_ci	rc = at86rf230_reg_writeable(dev, reg);
26562306a36Sopenharmony_ci	if (rc)
26662306a36Sopenharmony_ci		return rc;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* readonly regs */
26962306a36Sopenharmony_ci	switch (reg) {
27062306a36Sopenharmony_ci	case RG_TRX_STATUS:
27162306a36Sopenharmony_ci	case RG_PHY_RSSI:
27262306a36Sopenharmony_ci	case RG_IRQ_STATUS:
27362306a36Sopenharmony_ci	case RG_PART_NUM:
27462306a36Sopenharmony_ci	case RG_VERSION_NUM:
27562306a36Sopenharmony_ci	case RG_MAN_ID_1:
27662306a36Sopenharmony_ci	case RG_MAN_ID_0:
27762306a36Sopenharmony_ci		return true;
27862306a36Sopenharmony_ci	default:
27962306a36Sopenharmony_ci		return false;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic bool
28462306a36Sopenharmony_ciat86rf230_reg_volatile(struct device *dev, unsigned int reg)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	/* can be changed during runtime */
28762306a36Sopenharmony_ci	switch (reg) {
28862306a36Sopenharmony_ci	case RG_TRX_STATUS:
28962306a36Sopenharmony_ci	case RG_TRX_STATE:
29062306a36Sopenharmony_ci	case RG_PHY_RSSI:
29162306a36Sopenharmony_ci	case RG_PHY_ED_LEVEL:
29262306a36Sopenharmony_ci	case RG_IRQ_STATUS:
29362306a36Sopenharmony_ci	case RG_VREG_CTRL:
29462306a36Sopenharmony_ci	case RG_PLL_CF:
29562306a36Sopenharmony_ci	case RG_PLL_DCU:
29662306a36Sopenharmony_ci		return true;
29762306a36Sopenharmony_ci	default:
29862306a36Sopenharmony_ci		return false;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic bool
30362306a36Sopenharmony_ciat86rf230_reg_precious(struct device *dev, unsigned int reg)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	/* don't clear irq line on read */
30662306a36Sopenharmony_ci	switch (reg) {
30762306a36Sopenharmony_ci	case RG_IRQ_STATUS:
30862306a36Sopenharmony_ci		return true;
30962306a36Sopenharmony_ci	default:
31062306a36Sopenharmony_ci		return false;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic const struct regmap_config at86rf230_regmap_spi_config = {
31562306a36Sopenharmony_ci	.reg_bits = 8,
31662306a36Sopenharmony_ci	.val_bits = 8,
31762306a36Sopenharmony_ci	.write_flag_mask = CMD_REG | CMD_WRITE,
31862306a36Sopenharmony_ci	.read_flag_mask = CMD_REG,
31962306a36Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
32062306a36Sopenharmony_ci	.max_register = AT86RF2XX_NUMREGS,
32162306a36Sopenharmony_ci	.writeable_reg = at86rf230_reg_writeable,
32262306a36Sopenharmony_ci	.readable_reg = at86rf230_reg_readable,
32362306a36Sopenharmony_ci	.volatile_reg = at86rf230_reg_volatile,
32462306a36Sopenharmony_ci	.precious_reg = at86rf230_reg_precious,
32562306a36Sopenharmony_ci};
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic void
32862306a36Sopenharmony_ciat86rf230_async_error_recover_complete(void *context)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
33162306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (ctx->free)
33462306a36Sopenharmony_ci		kfree(ctx);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (lp->was_tx) {
33762306a36Sopenharmony_ci		lp->was_tx = 0;
33862306a36Sopenharmony_ci		ieee802154_xmit_hw_error(lp->hw, lp->tx_skb);
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic void
34362306a36Sopenharmony_ciat86rf230_async_error_recover(void *context)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
34662306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (lp->is_tx) {
34962306a36Sopenharmony_ci		lp->was_tx = 1;
35062306a36Sopenharmony_ci		lp->is_tx = 0;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
35462306a36Sopenharmony_ci				     at86rf230_async_error_recover_complete);
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic inline void
35862306a36Sopenharmony_ciat86rf230_async_error(struct at86rf230_local *lp,
35962306a36Sopenharmony_ci		      struct at86rf230_state_change *ctx, int rc)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
36462306a36Sopenharmony_ci				     at86rf230_async_error_recover);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci/* Generic function to get some register value in async mode */
36862306a36Sopenharmony_cistatic void
36962306a36Sopenharmony_ciat86rf230_async_read_reg(struct at86rf230_local *lp, u8 reg,
37062306a36Sopenharmony_ci			 struct at86rf230_state_change *ctx,
37162306a36Sopenharmony_ci			 void (*complete)(void *context))
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	int rc;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	u8 *tx_buf = ctx->buf;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
37862306a36Sopenharmony_ci	ctx->msg.complete = complete;
37962306a36Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
38062306a36Sopenharmony_ci	if (rc)
38162306a36Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void
38562306a36Sopenharmony_ciat86rf230_async_write_reg(struct at86rf230_local *lp, u8 reg, u8 val,
38662306a36Sopenharmony_ci			  struct at86rf230_state_change *ctx,
38762306a36Sopenharmony_ci			  void (*complete)(void *context))
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	int rc;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	ctx->buf[0] = (reg & CMD_REG_MASK) | CMD_REG | CMD_WRITE;
39262306a36Sopenharmony_ci	ctx->buf[1] = val;
39362306a36Sopenharmony_ci	ctx->msg.complete = complete;
39462306a36Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
39562306a36Sopenharmony_ci	if (rc)
39662306a36Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic void
40062306a36Sopenharmony_ciat86rf230_async_state_assert(void *context)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
40362306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
40462306a36Sopenharmony_ci	const u8 *buf = ctx->buf;
40562306a36Sopenharmony_ci	const u8 trx_state = buf[1] & TRX_STATE_MASK;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/* Assert state change */
40862306a36Sopenharmony_ci	if (trx_state != ctx->to_state) {
40962306a36Sopenharmony_ci		/* Special handling if transceiver state is in
41062306a36Sopenharmony_ci		 * STATE_BUSY_RX_AACK and a SHR was detected.
41162306a36Sopenharmony_ci		 */
41262306a36Sopenharmony_ci		if  (trx_state == STATE_BUSY_RX_AACK) {
41362306a36Sopenharmony_ci			/* Undocumented race condition. If we send a state
41462306a36Sopenharmony_ci			 * change to STATE_RX_AACK_ON the transceiver could
41562306a36Sopenharmony_ci			 * change his state automatically to STATE_BUSY_RX_AACK
41662306a36Sopenharmony_ci			 * if a SHR was detected. This is not an error, but we
41762306a36Sopenharmony_ci			 * can't assert this.
41862306a36Sopenharmony_ci			 */
41962306a36Sopenharmony_ci			if (ctx->to_state == STATE_RX_AACK_ON)
42062306a36Sopenharmony_ci				goto done;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci			/* If we change to STATE_TX_ON without forcing and
42362306a36Sopenharmony_ci			 * transceiver state is STATE_BUSY_RX_AACK, we wait
42462306a36Sopenharmony_ci			 * 'tFrame + tPAck' receiving time. In this time the
42562306a36Sopenharmony_ci			 * PDU should be received. If the transceiver is still
42662306a36Sopenharmony_ci			 * in STATE_BUSY_RX_AACK, we run a force state change
42762306a36Sopenharmony_ci			 * to STATE_TX_ON. This is a timeout handling, if the
42862306a36Sopenharmony_ci			 * transceiver stucks in STATE_BUSY_RX_AACK.
42962306a36Sopenharmony_ci			 *
43062306a36Sopenharmony_ci			 * Additional we do several retries to try to get into
43162306a36Sopenharmony_ci			 * TX_ON state without forcing. If the retries are
43262306a36Sopenharmony_ci			 * higher or equal than AT86RF2XX_MAX_TX_RETRIES we
43362306a36Sopenharmony_ci			 * will do a force change.
43462306a36Sopenharmony_ci			 */
43562306a36Sopenharmony_ci			if (ctx->to_state == STATE_TX_ON ||
43662306a36Sopenharmony_ci			    ctx->to_state == STATE_TRX_OFF) {
43762306a36Sopenharmony_ci				u8 state = ctx->to_state;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci				if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES)
44062306a36Sopenharmony_ci					state = STATE_FORCE_TRX_OFF;
44162306a36Sopenharmony_ci				lp->tx_retry++;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci				at86rf230_async_state_change(lp, ctx, state,
44462306a36Sopenharmony_ci							     ctx->complete);
44562306a36Sopenharmony_ci				return;
44662306a36Sopenharmony_ci			}
44762306a36Sopenharmony_ci		}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		dev_warn(&lp->spi->dev, "unexcept state change from 0x%02x to 0x%02x. Actual state: 0x%02x\n",
45062306a36Sopenharmony_ci			 ctx->from_state, ctx->to_state, trx_state);
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cidone:
45462306a36Sopenharmony_ci	if (ctx->complete)
45562306a36Sopenharmony_ci		ctx->complete(context);
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic enum hrtimer_restart at86rf230_async_state_timer(struct hrtimer *timer)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct at86rf230_state_change *ctx =
46162306a36Sopenharmony_ci		container_of(timer, struct at86rf230_state_change, timer);
46262306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
46562306a36Sopenharmony_ci				 at86rf230_async_state_assert);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	return HRTIMER_NORESTART;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci/* Do state change timing delay. */
47162306a36Sopenharmony_cistatic void
47262306a36Sopenharmony_ciat86rf230_async_state_delay(void *context)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
47562306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
47662306a36Sopenharmony_ci	struct at86rf2xx_chip_data *c = lp->data;
47762306a36Sopenharmony_ci	bool force = false;
47862306a36Sopenharmony_ci	ktime_t tim;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/* The force state changes are will show as normal states in the
48162306a36Sopenharmony_ci	 * state status subregister. We change the to_state to the
48262306a36Sopenharmony_ci	 * corresponding one and remember if it was a force change, this
48362306a36Sopenharmony_ci	 * differs if we do a state change from STATE_BUSY_RX_AACK.
48462306a36Sopenharmony_ci	 */
48562306a36Sopenharmony_ci	switch (ctx->to_state) {
48662306a36Sopenharmony_ci	case STATE_FORCE_TX_ON:
48762306a36Sopenharmony_ci		ctx->to_state = STATE_TX_ON;
48862306a36Sopenharmony_ci		force = true;
48962306a36Sopenharmony_ci		break;
49062306a36Sopenharmony_ci	case STATE_FORCE_TRX_OFF:
49162306a36Sopenharmony_ci		ctx->to_state = STATE_TRX_OFF;
49262306a36Sopenharmony_ci		force = true;
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci	default:
49562306a36Sopenharmony_ci		break;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	switch (ctx->from_state) {
49962306a36Sopenharmony_ci	case STATE_TRX_OFF:
50062306a36Sopenharmony_ci		switch (ctx->to_state) {
50162306a36Sopenharmony_ci		case STATE_RX_AACK_ON:
50262306a36Sopenharmony_ci			tim = c->t_off_to_aack * NSEC_PER_USEC;
50362306a36Sopenharmony_ci			/* state change from TRX_OFF to RX_AACK_ON to do a
50462306a36Sopenharmony_ci			 * calibration, we need to reset the timeout for the
50562306a36Sopenharmony_ci			 * next one.
50662306a36Sopenharmony_ci			 */
50762306a36Sopenharmony_ci			lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
50862306a36Sopenharmony_ci			goto change;
50962306a36Sopenharmony_ci		case STATE_TX_ARET_ON:
51062306a36Sopenharmony_ci		case STATE_TX_ON:
51162306a36Sopenharmony_ci			tim = c->t_off_to_tx_on * NSEC_PER_USEC;
51262306a36Sopenharmony_ci			/* state change from TRX_OFF to TX_ON or ARET_ON to do
51362306a36Sopenharmony_ci			 * a calibration, we need to reset the timeout for the
51462306a36Sopenharmony_ci			 * next one.
51562306a36Sopenharmony_ci			 */
51662306a36Sopenharmony_ci			lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
51762306a36Sopenharmony_ci			goto change;
51862306a36Sopenharmony_ci		default:
51962306a36Sopenharmony_ci			break;
52062306a36Sopenharmony_ci		}
52162306a36Sopenharmony_ci		break;
52262306a36Sopenharmony_ci	case STATE_BUSY_RX_AACK:
52362306a36Sopenharmony_ci		switch (ctx->to_state) {
52462306a36Sopenharmony_ci		case STATE_TRX_OFF:
52562306a36Sopenharmony_ci		case STATE_TX_ON:
52662306a36Sopenharmony_ci			/* Wait for worst case receiving time if we
52762306a36Sopenharmony_ci			 * didn't make a force change from BUSY_RX_AACK
52862306a36Sopenharmony_ci			 * to TX_ON or TRX_OFF.
52962306a36Sopenharmony_ci			 */
53062306a36Sopenharmony_ci			if (!force) {
53162306a36Sopenharmony_ci				tim = (c->t_frame + c->t_p_ack) * NSEC_PER_USEC;
53262306a36Sopenharmony_ci				goto change;
53362306a36Sopenharmony_ci			}
53462306a36Sopenharmony_ci			break;
53562306a36Sopenharmony_ci		default:
53662306a36Sopenharmony_ci			break;
53762306a36Sopenharmony_ci		}
53862306a36Sopenharmony_ci		break;
53962306a36Sopenharmony_ci	/* Default value, means RESET state */
54062306a36Sopenharmony_ci	case STATE_P_ON:
54162306a36Sopenharmony_ci		switch (ctx->to_state) {
54262306a36Sopenharmony_ci		case STATE_TRX_OFF:
54362306a36Sopenharmony_ci			tim = c->t_reset_to_off * NSEC_PER_USEC;
54462306a36Sopenharmony_ci			goto change;
54562306a36Sopenharmony_ci		default:
54662306a36Sopenharmony_ci			break;
54762306a36Sopenharmony_ci		}
54862306a36Sopenharmony_ci		break;
54962306a36Sopenharmony_ci	default:
55062306a36Sopenharmony_ci		break;
55162306a36Sopenharmony_ci	}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	/* Default delay is 1us in the most cases */
55462306a36Sopenharmony_ci	udelay(1);
55562306a36Sopenharmony_ci	at86rf230_async_state_timer(&ctx->timer);
55662306a36Sopenharmony_ci	return;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cichange:
55962306a36Sopenharmony_ci	hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL);
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic void
56362306a36Sopenharmony_ciat86rf230_async_state_change_start(void *context)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
56662306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
56762306a36Sopenharmony_ci	u8 *buf = ctx->buf;
56862306a36Sopenharmony_ci	const u8 trx_state = buf[1] & TRX_STATE_MASK;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	/* Check for "possible" STATE_TRANSITION_IN_PROGRESS */
57162306a36Sopenharmony_ci	if (trx_state == STATE_TRANSITION_IN_PROGRESS) {
57262306a36Sopenharmony_ci		udelay(1);
57362306a36Sopenharmony_ci		at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
57462306a36Sopenharmony_ci					 at86rf230_async_state_change_start);
57562306a36Sopenharmony_ci		return;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* Check if we already are in the state which we change in */
57962306a36Sopenharmony_ci	if (trx_state == ctx->to_state) {
58062306a36Sopenharmony_ci		if (ctx->complete)
58162306a36Sopenharmony_ci			ctx->complete(context);
58262306a36Sopenharmony_ci		return;
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* Set current state to the context of state change */
58662306a36Sopenharmony_ci	ctx->from_state = trx_state;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* Going into the next step for a state change which do a timing
58962306a36Sopenharmony_ci	 * relevant delay.
59062306a36Sopenharmony_ci	 */
59162306a36Sopenharmony_ci	at86rf230_async_write_reg(lp, RG_TRX_STATE, ctx->to_state, ctx,
59262306a36Sopenharmony_ci				  at86rf230_async_state_delay);
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic void
59662306a36Sopenharmony_ciat86rf230_async_state_change(struct at86rf230_local *lp,
59762306a36Sopenharmony_ci			     struct at86rf230_state_change *ctx,
59862306a36Sopenharmony_ci			     const u8 state, void (*complete)(void *context))
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	/* Initialization for the state change context */
60162306a36Sopenharmony_ci	ctx->to_state = state;
60262306a36Sopenharmony_ci	ctx->complete = complete;
60362306a36Sopenharmony_ci	at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
60462306a36Sopenharmony_ci				 at86rf230_async_state_change_start);
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void
60862306a36Sopenharmony_ciat86rf230_sync_state_change_complete(void *context)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
61162306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	complete(&lp->state_complete);
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci/* This function do a sync framework above the async state change.
61762306a36Sopenharmony_ci * Some callbacks of the IEEE 802.15.4 driver interface need to be
61862306a36Sopenharmony_ci * handled synchronously.
61962306a36Sopenharmony_ci */
62062306a36Sopenharmony_cistatic int
62162306a36Sopenharmony_ciat86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	unsigned long rc;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	at86rf230_async_state_change(lp, &lp->state, state,
62662306a36Sopenharmony_ci				     at86rf230_sync_state_change_complete);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	rc = wait_for_completion_timeout(&lp->state_complete,
62962306a36Sopenharmony_ci					 msecs_to_jiffies(100));
63062306a36Sopenharmony_ci	if (!rc) {
63162306a36Sopenharmony_ci		at86rf230_async_error(lp, &lp->state, -ETIMEDOUT);
63262306a36Sopenharmony_ci		return -ETIMEDOUT;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	return 0;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic void
63962306a36Sopenharmony_ciat86rf230_tx_complete(void *context)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
64262306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	if (ctx->trac == IEEE802154_SUCCESS)
64562306a36Sopenharmony_ci		ieee802154_xmit_complete(lp->hw, lp->tx_skb, false);
64662306a36Sopenharmony_ci	else
64762306a36Sopenharmony_ci		ieee802154_xmit_error(lp->hw, lp->tx_skb, ctx->trac);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	kfree(ctx);
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic void
65362306a36Sopenharmony_ciat86rf230_tx_on(void *context)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
65662306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
65962306a36Sopenharmony_ci				     at86rf230_tx_complete);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic void
66362306a36Sopenharmony_ciat86rf230_tx_trac_check(void *context)
66462306a36Sopenharmony_ci{
66562306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
66662306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
66762306a36Sopenharmony_ci	u8 trac = TRAC_MASK(ctx->buf[1]);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	switch (trac) {
67062306a36Sopenharmony_ci	case TRAC_SUCCESS:
67162306a36Sopenharmony_ci	case TRAC_SUCCESS_DATA_PENDING:
67262306a36Sopenharmony_ci		ctx->trac = IEEE802154_SUCCESS;
67362306a36Sopenharmony_ci		break;
67462306a36Sopenharmony_ci	case TRAC_CHANNEL_ACCESS_FAILURE:
67562306a36Sopenharmony_ci		ctx->trac = IEEE802154_CHANNEL_ACCESS_FAILURE;
67662306a36Sopenharmony_ci		break;
67762306a36Sopenharmony_ci	case TRAC_NO_ACK:
67862306a36Sopenharmony_ci		ctx->trac = IEEE802154_NO_ACK;
67962306a36Sopenharmony_ci		break;
68062306a36Sopenharmony_ci	default:
68162306a36Sopenharmony_ci		ctx->trac = IEEE802154_SYSTEM_ERROR;
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_TX_ON, at86rf230_tx_on);
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_cistatic void
68862306a36Sopenharmony_ciat86rf230_rx_read_frame_complete(void *context)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
69162306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
69262306a36Sopenharmony_ci	const u8 *buf = ctx->buf;
69362306a36Sopenharmony_ci	struct sk_buff *skb;
69462306a36Sopenharmony_ci	u8 len, lqi;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	len = buf[1];
69762306a36Sopenharmony_ci	if (!ieee802154_is_valid_psdu_len(len)) {
69862306a36Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
69962306a36Sopenharmony_ci		len = IEEE802154_MTU;
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ci	lqi = buf[2 + len];
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	skb = dev_alloc_skb(IEEE802154_MTU);
70462306a36Sopenharmony_ci	if (!skb) {
70562306a36Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "failed to allocate sk_buff\n");
70662306a36Sopenharmony_ci		kfree(ctx);
70762306a36Sopenharmony_ci		return;
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	skb_put_data(skb, buf + 2, len);
71162306a36Sopenharmony_ci	ieee802154_rx_irqsafe(lp->hw, skb, lqi);
71262306a36Sopenharmony_ci	kfree(ctx);
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic void
71662306a36Sopenharmony_ciat86rf230_rx_trac_check(void *context)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
71962306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
72062306a36Sopenharmony_ci	u8 *buf = ctx->buf;
72162306a36Sopenharmony_ci	int rc;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	buf[0] = CMD_FB;
72462306a36Sopenharmony_ci	ctx->trx.len = AT86RF2XX_MAX_BUF;
72562306a36Sopenharmony_ci	ctx->msg.complete = at86rf230_rx_read_frame_complete;
72662306a36Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
72762306a36Sopenharmony_ci	if (rc) {
72862306a36Sopenharmony_ci		ctx->trx.len = 2;
72962306a36Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_cistatic void
73462306a36Sopenharmony_ciat86rf230_irq_trx_end(void *context)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
73762306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (lp->is_tx) {
74062306a36Sopenharmony_ci		lp->is_tx = 0;
74162306a36Sopenharmony_ci		at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
74262306a36Sopenharmony_ci					 at86rf230_tx_trac_check);
74362306a36Sopenharmony_ci	} else {
74462306a36Sopenharmony_ci		at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
74562306a36Sopenharmony_ci					 at86rf230_rx_trac_check);
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_cistatic void
75062306a36Sopenharmony_ciat86rf230_irq_status(void *context)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
75362306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
75462306a36Sopenharmony_ci	const u8 *buf = ctx->buf;
75562306a36Sopenharmony_ci	u8 irq = buf[1];
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	enable_irq(lp->spi->irq);
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	if (irq & IRQ_TRX_END) {
76062306a36Sopenharmony_ci		at86rf230_irq_trx_end(ctx);
76162306a36Sopenharmony_ci	} else {
76262306a36Sopenharmony_ci		dev_err(&lp->spi->dev, "not supported irq %02x received\n",
76362306a36Sopenharmony_ci			irq);
76462306a36Sopenharmony_ci		kfree(ctx);
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_cistatic void
76962306a36Sopenharmony_ciat86rf230_setup_spi_messages(struct at86rf230_local *lp,
77062306a36Sopenharmony_ci			     struct at86rf230_state_change *state)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	state->lp = lp;
77362306a36Sopenharmony_ci	state->irq = lp->spi->irq;
77462306a36Sopenharmony_ci	spi_message_init(&state->msg);
77562306a36Sopenharmony_ci	state->msg.context = state;
77662306a36Sopenharmony_ci	state->trx.len = 2;
77762306a36Sopenharmony_ci	state->trx.tx_buf = state->buf;
77862306a36Sopenharmony_ci	state->trx.rx_buf = state->buf;
77962306a36Sopenharmony_ci	spi_message_add_tail(&state->trx, &state->msg);
78062306a36Sopenharmony_ci	hrtimer_init(&state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
78162306a36Sopenharmony_ci	state->timer.function = at86rf230_async_state_timer;
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_cistatic irqreturn_t at86rf230_isr(int irq, void *data)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct at86rf230_local *lp = data;
78762306a36Sopenharmony_ci	struct at86rf230_state_change *ctx;
78862306a36Sopenharmony_ci	int rc;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	disable_irq_nosync(irq);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
79362306a36Sopenharmony_ci	if (!ctx) {
79462306a36Sopenharmony_ci		enable_irq(irq);
79562306a36Sopenharmony_ci		return IRQ_NONE;
79662306a36Sopenharmony_ci	}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	at86rf230_setup_spi_messages(lp, ctx);
79962306a36Sopenharmony_ci	/* tell on error handling to free ctx */
80062306a36Sopenharmony_ci	ctx->free = true;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	ctx->buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG;
80362306a36Sopenharmony_ci	ctx->msg.complete = at86rf230_irq_status;
80462306a36Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
80562306a36Sopenharmony_ci	if (rc) {
80662306a36Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
80762306a36Sopenharmony_ci		enable_irq(irq);
80862306a36Sopenharmony_ci		return IRQ_NONE;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	return IRQ_HANDLED;
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic void
81562306a36Sopenharmony_ciat86rf230_write_frame_complete(void *context)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
81862306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	ctx->trx.len = 2;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	if (lp->slp_tr)
82362306a36Sopenharmony_ci		at86rf230_slp_tr_rising_edge(lp);
82462306a36Sopenharmony_ci	else
82562306a36Sopenharmony_ci		at86rf230_async_write_reg(lp, RG_TRX_STATE, STATE_BUSY_TX, ctx,
82662306a36Sopenharmony_ci					  NULL);
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic void
83062306a36Sopenharmony_ciat86rf230_write_frame(void *context)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
83362306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
83462306a36Sopenharmony_ci	struct sk_buff *skb = lp->tx_skb;
83562306a36Sopenharmony_ci	u8 *buf = ctx->buf;
83662306a36Sopenharmony_ci	int rc;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	lp->is_tx = 1;
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	buf[0] = CMD_FB | CMD_WRITE;
84162306a36Sopenharmony_ci	buf[1] = skb->len + 2;
84262306a36Sopenharmony_ci	memcpy(buf + 2, skb->data, skb->len);
84362306a36Sopenharmony_ci	ctx->trx.len = skb->len + 2;
84462306a36Sopenharmony_ci	ctx->msg.complete = at86rf230_write_frame_complete;
84562306a36Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
84662306a36Sopenharmony_ci	if (rc) {
84762306a36Sopenharmony_ci		ctx->trx.len = 2;
84862306a36Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
84962306a36Sopenharmony_ci	}
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_cistatic void
85362306a36Sopenharmony_ciat86rf230_xmit_tx_on(void *context)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
85662306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
85962306a36Sopenharmony_ci				     at86rf230_write_frame);
86062306a36Sopenharmony_ci}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic void
86362306a36Sopenharmony_ciat86rf230_xmit_start(void *context)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
86662306a36Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	/* check if we change from off state */
86962306a36Sopenharmony_ci	if (lp->is_tx_from_off)
87062306a36Sopenharmony_ci		at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
87162306a36Sopenharmony_ci					     at86rf230_write_frame);
87262306a36Sopenharmony_ci	else
87362306a36Sopenharmony_ci		at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
87462306a36Sopenharmony_ci					     at86rf230_xmit_tx_on);
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic int
87862306a36Sopenharmony_ciat86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
88162306a36Sopenharmony_ci	struct at86rf230_state_change *ctx = &lp->tx;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	lp->tx_skb = skb;
88462306a36Sopenharmony_ci	lp->tx_retry = 0;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* After 5 minutes in PLL and the same frequency we run again the
88762306a36Sopenharmony_ci	 * calibration loops which is recommended by at86rf2xx datasheets.
88862306a36Sopenharmony_ci	 *
88962306a36Sopenharmony_ci	 * The calibration is initiate by a state change from TRX_OFF
89062306a36Sopenharmony_ci	 * to TX_ON, the lp->cal_timeout should be reinit by state_delay
89162306a36Sopenharmony_ci	 * function then to start in the next 5 minutes.
89262306a36Sopenharmony_ci	 */
89362306a36Sopenharmony_ci	if (time_is_before_jiffies(lp->cal_timeout)) {
89462306a36Sopenharmony_ci		lp->is_tx_from_off = true;
89562306a36Sopenharmony_ci		at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF,
89662306a36Sopenharmony_ci					     at86rf230_xmit_start);
89762306a36Sopenharmony_ci	} else {
89862306a36Sopenharmony_ci		lp->is_tx_from_off = false;
89962306a36Sopenharmony_ci		at86rf230_xmit_start(ctx);
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	return 0;
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cistatic int
90662306a36Sopenharmony_ciat86rf230_ed(struct ieee802154_hw *hw, u8 *level)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	WARN_ON(!level);
90962306a36Sopenharmony_ci	*level = 0xbe;
91062306a36Sopenharmony_ci	return 0;
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_cistatic int
91462306a36Sopenharmony_ciat86rf230_start(struct ieee802154_hw *hw)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	at86rf230_awake(lp);
91962306a36Sopenharmony_ci	enable_irq(lp->spi->irq);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	return at86rf230_sync_state_change(lp, STATE_RX_AACK_ON);
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic void
92562306a36Sopenharmony_ciat86rf230_stop(struct ieee802154_hw *hw)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
92862306a36Sopenharmony_ci	u8 csma_seed[2];
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	at86rf230_sync_state_change(lp, STATE_FORCE_TRX_OFF);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	disable_irq(lp->spi->irq);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	/* It's recommended to set random new csma_seeds before sleep state.
93562306a36Sopenharmony_ci	 * Makes only sense in the stop callback, not doing this inside of
93662306a36Sopenharmony_ci	 * at86rf230_sleep, this is also used when we don't transmit afterwards
93762306a36Sopenharmony_ci	 * when calling start callback again.
93862306a36Sopenharmony_ci	 */
93962306a36Sopenharmony_ci	get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed));
94062306a36Sopenharmony_ci	at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]);
94162306a36Sopenharmony_ci	at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	at86rf230_sleep(lp);
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic int
94762306a36Sopenharmony_ciat86rf23x_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
94862306a36Sopenharmony_ci{
94962306a36Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci#define AT86RF2XX_MAX_ED_LEVELS 0xF
95362306a36Sopenharmony_cistatic const s32 at86rf233_ed_levels[AT86RF2XX_MAX_ED_LEVELS + 1] = {
95462306a36Sopenharmony_ci	-9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000, -7800, -7600,
95562306a36Sopenharmony_ci	-7400, -7200, -7000, -6800, -6600, -6400,
95662306a36Sopenharmony_ci};
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_cistatic const s32 at86rf231_ed_levels[AT86RF2XX_MAX_ED_LEVELS + 1] = {
95962306a36Sopenharmony_ci	-9100, -8900, -8700, -8500, -8300, -8100, -7900, -7700, -7500, -7300,
96062306a36Sopenharmony_ci	-7100, -6900, -6700, -6500, -6300, -6100,
96162306a36Sopenharmony_ci};
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic const s32 at86rf212_ed_levels_100[AT86RF2XX_MAX_ED_LEVELS + 1] = {
96462306a36Sopenharmony_ci	-10000, -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200,
96562306a36Sopenharmony_ci	-8000, -7800, -7600, -7400, -7200, -7000,
96662306a36Sopenharmony_ci};
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistatic const s32 at86rf212_ed_levels_98[AT86RF2XX_MAX_ED_LEVELS + 1] = {
96962306a36Sopenharmony_ci	-9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000,
97062306a36Sopenharmony_ci	-7800, -7600, -7400, -7200, -7000, -6800,
97162306a36Sopenharmony_ci};
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_cistatic inline int
97462306a36Sopenharmony_ciat86rf212_update_cca_ed_level(struct at86rf230_local *lp, int rssi_base_val)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	unsigned int cca_ed_thres;
97762306a36Sopenharmony_ci	int rc;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	rc = at86rf230_read_subreg(lp, SR_CCA_ED_THRES, &cca_ed_thres);
98062306a36Sopenharmony_ci	if (rc < 0)
98162306a36Sopenharmony_ci		return rc;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	switch (rssi_base_val) {
98462306a36Sopenharmony_ci	case -98:
98562306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_98;
98662306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_98);
98762306a36Sopenharmony_ci		lp->hw->phy->cca_ed_level = at86rf212_ed_levels_98[cca_ed_thres];
98862306a36Sopenharmony_ci		break;
98962306a36Sopenharmony_ci	case -100:
99062306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100;
99162306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100);
99262306a36Sopenharmony_ci		lp->hw->phy->cca_ed_level = at86rf212_ed_levels_100[cca_ed_thres];
99362306a36Sopenharmony_ci		break;
99462306a36Sopenharmony_ci	default:
99562306a36Sopenharmony_ci		WARN_ON(1);
99662306a36Sopenharmony_ci	}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	return 0;
99962306a36Sopenharmony_ci}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_cistatic int
100262306a36Sopenharmony_ciat86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	int rc;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (channel == 0)
100762306a36Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 0);
100862306a36Sopenharmony_ci	else
100962306a36Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 1);
101062306a36Sopenharmony_ci	if (rc < 0)
101162306a36Sopenharmony_ci		return rc;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if (page == 0) {
101462306a36Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0);
101562306a36Sopenharmony_ci		lp->data->rssi_base_val = -100;
101662306a36Sopenharmony_ci	} else {
101762306a36Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1);
101862306a36Sopenharmony_ci		lp->data->rssi_base_val = -98;
101962306a36Sopenharmony_ci	}
102062306a36Sopenharmony_ci	if (rc < 0)
102162306a36Sopenharmony_ci		return rc;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	rc = at86rf212_update_cca_ed_level(lp, lp->data->rssi_base_val);
102462306a36Sopenharmony_ci	if (rc < 0)
102562306a36Sopenharmony_ci		return rc;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic int
103162306a36Sopenharmony_ciat86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
103462306a36Sopenharmony_ci	int rc;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	rc = lp->data->set_channel(lp, page, channel);
103762306a36Sopenharmony_ci	/* Wait for PLL */
103862306a36Sopenharmony_ci	usleep_range(lp->data->t_channel_switch,
103962306a36Sopenharmony_ci		     lp->data->t_channel_switch + 10);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
104262306a36Sopenharmony_ci	return rc;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic int
104662306a36Sopenharmony_ciat86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
104762306a36Sopenharmony_ci			   struct ieee802154_hw_addr_filt *filt,
104862306a36Sopenharmony_ci			   unsigned long changed)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
105362306a36Sopenharmony_ci		u16 addr = le16_to_cpu(filt->short_addr);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "%s called for saddr\n", __func__);
105662306a36Sopenharmony_ci		__at86rf230_write(lp, RG_SHORT_ADDR_0, addr);
105762306a36Sopenharmony_ci		__at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	if (changed & IEEE802154_AFILT_PANID_CHANGED) {
106162306a36Sopenharmony_ci		u16 pan = le16_to_cpu(filt->pan_id);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "%s called for pan id\n", __func__);
106462306a36Sopenharmony_ci		__at86rf230_write(lp, RG_PAN_ID_0, pan);
106562306a36Sopenharmony_ci		__at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
106962306a36Sopenharmony_ci		u8 i, addr[8];
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci		memcpy(addr, &filt->ieee_addr, 8);
107262306a36Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "%s called for IEEE addr\n", __func__);
107362306a36Sopenharmony_ci		for (i = 0; i < 8; i++)
107462306a36Sopenharmony_ci			__at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
107862306a36Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "%s called for panc change\n", __func__);
107962306a36Sopenharmony_ci		if (filt->pan_coord)
108062306a36Sopenharmony_ci			at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1);
108162306a36Sopenharmony_ci		else
108262306a36Sopenharmony_ci			at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 0);
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	return 0;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci#define AT86RF23X_MAX_TX_POWERS 0xF
108962306a36Sopenharmony_cistatic const s32 at86rf233_powers[AT86RF23X_MAX_TX_POWERS + 1] = {
109062306a36Sopenharmony_ci	400, 370, 340, 300, 250, 200, 100, 0, -100, -200, -300, -400, -600,
109162306a36Sopenharmony_ci	-800, -1200, -1700,
109262306a36Sopenharmony_ci};
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_cistatic const s32 at86rf231_powers[AT86RF23X_MAX_TX_POWERS + 1] = {
109562306a36Sopenharmony_ci	300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700,
109662306a36Sopenharmony_ci	-900, -1200, -1700,
109762306a36Sopenharmony_ci};
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci#define AT86RF212_MAX_TX_POWERS 0x1F
110062306a36Sopenharmony_cistatic const s32 at86rf212_powers[AT86RF212_MAX_TX_POWERS + 1] = {
110162306a36Sopenharmony_ci	500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700,
110262306a36Sopenharmony_ci	-800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700,
110362306a36Sopenharmony_ci	-1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600,
110462306a36Sopenharmony_ci};
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_cistatic int
110762306a36Sopenharmony_ciat86rf23x_set_txpower(struct at86rf230_local *lp, s32 mbm)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	u32 i;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) {
111262306a36Sopenharmony_ci		if (lp->hw->phy->supported.tx_powers[i] == mbm)
111362306a36Sopenharmony_ci			return at86rf230_write_subreg(lp, SR_TX_PWR_23X, i);
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return -EINVAL;
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic int
112062306a36Sopenharmony_ciat86rf212_set_txpower(struct at86rf230_local *lp, s32 mbm)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	u32 i;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) {
112562306a36Sopenharmony_ci		if (lp->hw->phy->supported.tx_powers[i] == mbm)
112662306a36Sopenharmony_ci			return at86rf230_write_subreg(lp, SR_TX_PWR_212, i);
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	return -EINVAL;
113062306a36Sopenharmony_ci}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic int
113362306a36Sopenharmony_ciat86rf230_set_txpower(struct ieee802154_hw *hw, s32 mbm)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	return lp->data->set_txpower(lp, mbm);
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cistatic int
114162306a36Sopenharmony_ciat86rf230_set_lbt(struct ieee802154_hw *hw, bool on)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on);
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistatic int
114962306a36Sopenharmony_ciat86rf230_set_cca_mode(struct ieee802154_hw *hw,
115062306a36Sopenharmony_ci		       const struct wpan_phy_cca *cca)
115162306a36Sopenharmony_ci{
115262306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
115362306a36Sopenharmony_ci	u8 val;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	/* mapping 802.15.4 to driver spec */
115662306a36Sopenharmony_ci	switch (cca->mode) {
115762306a36Sopenharmony_ci	case NL802154_CCA_ENERGY:
115862306a36Sopenharmony_ci		val = 1;
115962306a36Sopenharmony_ci		break;
116062306a36Sopenharmony_ci	case NL802154_CCA_CARRIER:
116162306a36Sopenharmony_ci		val = 2;
116262306a36Sopenharmony_ci		break;
116362306a36Sopenharmony_ci	case NL802154_CCA_ENERGY_CARRIER:
116462306a36Sopenharmony_ci		switch (cca->opt) {
116562306a36Sopenharmony_ci		case NL802154_CCA_OPT_ENERGY_CARRIER_AND:
116662306a36Sopenharmony_ci			val = 3;
116762306a36Sopenharmony_ci			break;
116862306a36Sopenharmony_ci		case NL802154_CCA_OPT_ENERGY_CARRIER_OR:
116962306a36Sopenharmony_ci			val = 0;
117062306a36Sopenharmony_ci			break;
117162306a36Sopenharmony_ci		default:
117262306a36Sopenharmony_ci			return -EINVAL;
117362306a36Sopenharmony_ci		}
117462306a36Sopenharmony_ci		break;
117562306a36Sopenharmony_ci	default:
117662306a36Sopenharmony_ci		return -EINVAL;
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_CCA_MODE, val);
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_cistatic int
118362306a36Sopenharmony_ciat86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
118662306a36Sopenharmony_ci	u32 i;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) {
118962306a36Sopenharmony_ci		if (hw->phy->supported.cca_ed_levels[i] == mbm)
119062306a36Sopenharmony_ci			return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, i);
119162306a36Sopenharmony_ci	}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	return -EINVAL;
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_cistatic int
119762306a36Sopenharmony_ciat86rf230_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be,
119862306a36Sopenharmony_ci			  u8 retries)
119962306a36Sopenharmony_ci{
120062306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
120162306a36Sopenharmony_ci	int rc;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_MIN_BE, min_be);
120462306a36Sopenharmony_ci	if (rc)
120562306a36Sopenharmony_ci		return rc;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_MAX_BE, max_be);
120862306a36Sopenharmony_ci	if (rc)
120962306a36Sopenharmony_ci		return rc;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, retries);
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_cistatic int
121562306a36Sopenharmony_ciat86rf230_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic int
122362306a36Sopenharmony_ciat86rf230_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
122662306a36Sopenharmony_ci	int rc;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	if (on) {
122962306a36Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 1);
123062306a36Sopenharmony_ci		if (rc < 0)
123162306a36Sopenharmony_ci			return rc;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 1);
123462306a36Sopenharmony_ci		if (rc < 0)
123562306a36Sopenharmony_ci			return rc;
123662306a36Sopenharmony_ci	} else {
123762306a36Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 0);
123862306a36Sopenharmony_ci		if (rc < 0)
123962306a36Sopenharmony_ci			return rc;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 0);
124262306a36Sopenharmony_ci		if (rc < 0)
124362306a36Sopenharmony_ci			return rc;
124462306a36Sopenharmony_ci	}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	return 0;
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_cistatic const struct ieee802154_ops at86rf230_ops = {
125062306a36Sopenharmony_ci	.owner = THIS_MODULE,
125162306a36Sopenharmony_ci	.xmit_async = at86rf230_xmit,
125262306a36Sopenharmony_ci	.ed = at86rf230_ed,
125362306a36Sopenharmony_ci	.set_channel = at86rf230_channel,
125462306a36Sopenharmony_ci	.start = at86rf230_start,
125562306a36Sopenharmony_ci	.stop = at86rf230_stop,
125662306a36Sopenharmony_ci	.set_hw_addr_filt = at86rf230_set_hw_addr_filt,
125762306a36Sopenharmony_ci	.set_txpower = at86rf230_set_txpower,
125862306a36Sopenharmony_ci	.set_lbt = at86rf230_set_lbt,
125962306a36Sopenharmony_ci	.set_cca_mode = at86rf230_set_cca_mode,
126062306a36Sopenharmony_ci	.set_cca_ed_level = at86rf230_set_cca_ed_level,
126162306a36Sopenharmony_ci	.set_csma_params = at86rf230_set_csma_params,
126262306a36Sopenharmony_ci	.set_frame_retries = at86rf230_set_frame_retries,
126362306a36Sopenharmony_ci	.set_promiscuous_mode = at86rf230_set_promiscuous_mode,
126462306a36Sopenharmony_ci};
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_cistatic struct at86rf2xx_chip_data at86rf233_data = {
126762306a36Sopenharmony_ci	.t_sleep_cycle = 330,
126862306a36Sopenharmony_ci	.t_channel_switch = 11,
126962306a36Sopenharmony_ci	.t_reset_to_off = 26,
127062306a36Sopenharmony_ci	.t_off_to_aack = 80,
127162306a36Sopenharmony_ci	.t_off_to_tx_on = 80,
127262306a36Sopenharmony_ci	.t_off_to_sleep = 35,
127362306a36Sopenharmony_ci	.t_sleep_to_off = 1000,
127462306a36Sopenharmony_ci	.t_frame = 4096,
127562306a36Sopenharmony_ci	.t_p_ack = 545,
127662306a36Sopenharmony_ci	.rssi_base_val = -94,
127762306a36Sopenharmony_ci	.set_channel = at86rf23x_set_channel,
127862306a36Sopenharmony_ci	.set_txpower = at86rf23x_set_txpower,
127962306a36Sopenharmony_ci};
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_cistatic struct at86rf2xx_chip_data at86rf231_data = {
128262306a36Sopenharmony_ci	.t_sleep_cycle = 330,
128362306a36Sopenharmony_ci	.t_channel_switch = 24,
128462306a36Sopenharmony_ci	.t_reset_to_off = 37,
128562306a36Sopenharmony_ci	.t_off_to_aack = 110,
128662306a36Sopenharmony_ci	.t_off_to_tx_on = 110,
128762306a36Sopenharmony_ci	.t_off_to_sleep = 35,
128862306a36Sopenharmony_ci	.t_sleep_to_off = 1000,
128962306a36Sopenharmony_ci	.t_frame = 4096,
129062306a36Sopenharmony_ci	.t_p_ack = 545,
129162306a36Sopenharmony_ci	.rssi_base_val = -91,
129262306a36Sopenharmony_ci	.set_channel = at86rf23x_set_channel,
129362306a36Sopenharmony_ci	.set_txpower = at86rf23x_set_txpower,
129462306a36Sopenharmony_ci};
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_cistatic struct at86rf2xx_chip_data at86rf212_data = {
129762306a36Sopenharmony_ci	.t_sleep_cycle = 330,
129862306a36Sopenharmony_ci	.t_channel_switch = 11,
129962306a36Sopenharmony_ci	.t_reset_to_off = 26,
130062306a36Sopenharmony_ci	.t_off_to_aack = 200,
130162306a36Sopenharmony_ci	.t_off_to_tx_on = 200,
130262306a36Sopenharmony_ci	.t_off_to_sleep = 35,
130362306a36Sopenharmony_ci	.t_sleep_to_off = 1000,
130462306a36Sopenharmony_ci	.t_frame = 4096,
130562306a36Sopenharmony_ci	.t_p_ack = 545,
130662306a36Sopenharmony_ci	.rssi_base_val = -100,
130762306a36Sopenharmony_ci	.set_channel = at86rf212_set_channel,
130862306a36Sopenharmony_ci	.set_txpower = at86rf212_set_txpower,
130962306a36Sopenharmony_ci};
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic int at86rf230_hw_init(struct at86rf230_local *lp, u8 xtal_trim)
131262306a36Sopenharmony_ci{
131362306a36Sopenharmony_ci	int rc, irq_type, irq_pol = IRQ_ACTIVE_HIGH;
131462306a36Sopenharmony_ci	unsigned int dvdd;
131562306a36Sopenharmony_ci	u8 csma_seed[2];
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	rc = at86rf230_sync_state_change(lp, STATE_FORCE_TRX_OFF);
131862306a36Sopenharmony_ci	if (rc)
131962306a36Sopenharmony_ci		return rc;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	irq_type = irq_get_trigger_type(lp->spi->irq);
132262306a36Sopenharmony_ci	if (irq_type == IRQ_TYPE_EDGE_FALLING ||
132362306a36Sopenharmony_ci	    irq_type == IRQ_TYPE_LEVEL_LOW)
132462306a36Sopenharmony_ci		irq_pol = IRQ_ACTIVE_LOW;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_IRQ_POLARITY, irq_pol);
132762306a36Sopenharmony_ci	if (rc)
132862306a36Sopenharmony_ci		return rc;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_RX_SAFE_MODE, 1);
133162306a36Sopenharmony_ci	if (rc)
133262306a36Sopenharmony_ci		return rc;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, IRQ_TRX_END);
133562306a36Sopenharmony_ci	if (rc)
133662306a36Sopenharmony_ci		return rc;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	/* reset values differs in at86rf231 and at86rf233 */
133962306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_IRQ_MASK_MODE, 0);
134062306a36Sopenharmony_ci	if (rc)
134162306a36Sopenharmony_ci		return rc;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed));
134462306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]);
134562306a36Sopenharmony_ci	if (rc)
134662306a36Sopenharmony_ci		return rc;
134762306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]);
134862306a36Sopenharmony_ci	if (rc)
134962306a36Sopenharmony_ci		return rc;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	/* CLKM changes are applied immediately */
135262306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00);
135362306a36Sopenharmony_ci	if (rc)
135462306a36Sopenharmony_ci		return rc;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	/* Turn CLKM Off */
135762306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_CLKM_CTRL, 0x00);
135862306a36Sopenharmony_ci	if (rc)
135962306a36Sopenharmony_ci		return rc;
136062306a36Sopenharmony_ci	/* Wait the next SLEEP cycle */
136162306a36Sopenharmony_ci	usleep_range(lp->data->t_sleep_cycle,
136262306a36Sopenharmony_ci		     lp->data->t_sleep_cycle + 100);
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	/* xtal_trim value is calculated by:
136562306a36Sopenharmony_ci	 * CL = 0.5 * (CX + CTRIM + CPAR)
136662306a36Sopenharmony_ci	 *
136762306a36Sopenharmony_ci	 * whereas:
136862306a36Sopenharmony_ci	 * CL = capacitor of used crystal
136962306a36Sopenharmony_ci	 * CX = connected capacitors at xtal pins
137062306a36Sopenharmony_ci	 * CPAR = in all at86rf2xx datasheets this is a constant value 3 pF,
137162306a36Sopenharmony_ci	 *	  but this is different on each board setup. You need to fine
137262306a36Sopenharmony_ci	 *	  tuning this value via CTRIM.
137362306a36Sopenharmony_ci	 * CTRIM = variable capacitor setting. Resolution is 0.3 pF range is
137462306a36Sopenharmony_ci	 *	   0 pF upto 4.5 pF.
137562306a36Sopenharmony_ci	 *
137662306a36Sopenharmony_ci	 * Examples:
137762306a36Sopenharmony_ci	 * atben transceiver:
137862306a36Sopenharmony_ci	 *
137962306a36Sopenharmony_ci	 * CL = 8 pF
138062306a36Sopenharmony_ci	 * CX = 12 pF
138162306a36Sopenharmony_ci	 * CPAR = 3 pF (We assume the magic constant from datasheet)
138262306a36Sopenharmony_ci	 * CTRIM = 0.9 pF
138362306a36Sopenharmony_ci	 *
138462306a36Sopenharmony_ci	 * (12+0.9+3)/2 = 7.95 which is nearly at 8 pF
138562306a36Sopenharmony_ci	 *
138662306a36Sopenharmony_ci	 * xtal_trim = 0x3
138762306a36Sopenharmony_ci	 *
138862306a36Sopenharmony_ci	 * openlabs transceiver:
138962306a36Sopenharmony_ci	 *
139062306a36Sopenharmony_ci	 * CL = 16 pF
139162306a36Sopenharmony_ci	 * CX = 22 pF
139262306a36Sopenharmony_ci	 * CPAR = 3 pF (We assume the magic constant from datasheet)
139362306a36Sopenharmony_ci	 * CTRIM = 4.5 pF
139462306a36Sopenharmony_ci	 *
139562306a36Sopenharmony_ci	 * (22+4.5+3)/2 = 14.75 which is the nearest value to 16 pF
139662306a36Sopenharmony_ci	 *
139762306a36Sopenharmony_ci	 * xtal_trim = 0xf
139862306a36Sopenharmony_ci	 */
139962306a36Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_XTAL_TRIM, xtal_trim);
140062306a36Sopenharmony_ci	if (rc)
140162306a36Sopenharmony_ci		return rc;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &dvdd);
140462306a36Sopenharmony_ci	if (rc)
140562306a36Sopenharmony_ci		return rc;
140662306a36Sopenharmony_ci	if (!dvdd) {
140762306a36Sopenharmony_ci		dev_err(&lp->spi->dev, "DVDD error\n");
140862306a36Sopenharmony_ci		return -EINVAL;
140962306a36Sopenharmony_ci	}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	/* Force setting slotted operation bit to 0. Sometimes the atben
141262306a36Sopenharmony_ci	 * sets this bit and I don't know why. We set this always force
141362306a36Sopenharmony_ci	 * to zero while probing.
141462306a36Sopenharmony_ci	 */
141562306a36Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_SLOTTED_OPERATION, 0);
141662306a36Sopenharmony_ci}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_cistatic int
141962306a36Sopenharmony_ciat86rf230_detect_device(struct at86rf230_local *lp)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	unsigned int part, version, val;
142262306a36Sopenharmony_ci	u16 man_id = 0;
142362306a36Sopenharmony_ci	const char *chip;
142462306a36Sopenharmony_ci	int rc;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	rc = __at86rf230_read(lp, RG_MAN_ID_0, &val);
142762306a36Sopenharmony_ci	if (rc)
142862306a36Sopenharmony_ci		return rc;
142962306a36Sopenharmony_ci	man_id |= val;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	rc = __at86rf230_read(lp, RG_MAN_ID_1, &val);
143262306a36Sopenharmony_ci	if (rc)
143362306a36Sopenharmony_ci		return rc;
143462306a36Sopenharmony_ci	man_id |= (val << 8);
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	rc = __at86rf230_read(lp, RG_PART_NUM, &part);
143762306a36Sopenharmony_ci	if (rc)
143862306a36Sopenharmony_ci		return rc;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	rc = __at86rf230_read(lp, RG_VERSION_NUM, &version);
144162306a36Sopenharmony_ci	if (rc)
144262306a36Sopenharmony_ci		return rc;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	if (man_id != 0x001f) {
144562306a36Sopenharmony_ci		dev_err(&lp->spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n",
144662306a36Sopenharmony_ci			man_id >> 8, man_id & 0xFF);
144762306a36Sopenharmony_ci		return -EINVAL;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
145162306a36Sopenharmony_ci			IEEE802154_HW_CSMA_PARAMS |
145262306a36Sopenharmony_ci			IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT |
145362306a36Sopenharmony_ci			IEEE802154_HW_PROMISCUOUS;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	lp->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER |
145662306a36Sopenharmony_ci			     WPAN_PHY_FLAG_CCA_ED_LEVEL |
145762306a36Sopenharmony_ci			     WPAN_PHY_FLAG_CCA_MODE;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	lp->hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) |
146062306a36Sopenharmony_ci		BIT(NL802154_CCA_CARRIER) | BIT(NL802154_CCA_ENERGY_CARRIER);
146162306a36Sopenharmony_ci	lp->hw->phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) |
146262306a36Sopenharmony_ci		BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	lp->hw->phy->cca.mode = NL802154_CCA_ENERGY;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	switch (part) {
146762306a36Sopenharmony_ci	case 2:
146862306a36Sopenharmony_ci		chip = "at86rf230";
146962306a36Sopenharmony_ci		rc = -ENOTSUPP;
147062306a36Sopenharmony_ci		goto not_supp;
147162306a36Sopenharmony_ci	case 3:
147262306a36Sopenharmony_ci		chip = "at86rf231";
147362306a36Sopenharmony_ci		lp->data = &at86rf231_data;
147462306a36Sopenharmony_ci		lp->hw->phy->supported.channels[0] = 0x7FFF800;
147562306a36Sopenharmony_ci		lp->hw->phy->current_channel = 11;
147662306a36Sopenharmony_ci		lp->hw->phy->supported.tx_powers = at86rf231_powers;
147762306a36Sopenharmony_ci		lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf231_powers);
147862306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf231_ed_levels;
147962306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf231_ed_levels);
148062306a36Sopenharmony_ci		break;
148162306a36Sopenharmony_ci	case 7:
148262306a36Sopenharmony_ci		chip = "at86rf212";
148362306a36Sopenharmony_ci		lp->data = &at86rf212_data;
148462306a36Sopenharmony_ci		lp->hw->flags |= IEEE802154_HW_LBT;
148562306a36Sopenharmony_ci		lp->hw->phy->supported.channels[0] = 0x00007FF;
148662306a36Sopenharmony_ci		lp->hw->phy->supported.channels[2] = 0x00007FF;
148762306a36Sopenharmony_ci		lp->hw->phy->current_channel = 5;
148862306a36Sopenharmony_ci		lp->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH;
148962306a36Sopenharmony_ci		lp->hw->phy->supported.tx_powers = at86rf212_powers;
149062306a36Sopenharmony_ci		lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers);
149162306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100;
149262306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100);
149362306a36Sopenharmony_ci		break;
149462306a36Sopenharmony_ci	case 11:
149562306a36Sopenharmony_ci		chip = "at86rf233";
149662306a36Sopenharmony_ci		lp->data = &at86rf233_data;
149762306a36Sopenharmony_ci		lp->hw->phy->supported.channels[0] = 0x7FFF800;
149862306a36Sopenharmony_ci		lp->hw->phy->current_channel = 13;
149962306a36Sopenharmony_ci		lp->hw->phy->supported.tx_powers = at86rf233_powers;
150062306a36Sopenharmony_ci		lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf233_powers);
150162306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf233_ed_levels;
150262306a36Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf233_ed_levels);
150362306a36Sopenharmony_ci		break;
150462306a36Sopenharmony_ci	default:
150562306a36Sopenharmony_ci		chip = "unknown";
150662306a36Sopenharmony_ci		rc = -ENOTSUPP;
150762306a36Sopenharmony_ci		goto not_supp;
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	lp->hw->phy->cca_ed_level = lp->hw->phy->supported.cca_ed_levels[7];
151162306a36Sopenharmony_ci	lp->hw->phy->transmit_power = lp->hw->phy->supported.tx_powers[0];
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_cinot_supp:
151462306a36Sopenharmony_ci	dev_info(&lp->spi->dev, "Detected %s chip version %d\n", chip, version);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	return rc;
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_cistatic int at86rf230_probe(struct spi_device *spi)
152062306a36Sopenharmony_ci{
152162306a36Sopenharmony_ci	struct ieee802154_hw *hw;
152262306a36Sopenharmony_ci	struct at86rf230_local *lp;
152362306a36Sopenharmony_ci	struct gpio_desc *slp_tr;
152462306a36Sopenharmony_ci	struct gpio_desc *rstn;
152562306a36Sopenharmony_ci	unsigned int status;
152662306a36Sopenharmony_ci	int rc, irq_type;
152762306a36Sopenharmony_ci	u8 xtal_trim;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (!spi->irq) {
153062306a36Sopenharmony_ci		dev_err(&spi->dev, "no IRQ specified\n");
153162306a36Sopenharmony_ci		return -EINVAL;
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	rc = device_property_read_u8(&spi->dev, "xtal-trim", &xtal_trim);
153562306a36Sopenharmony_ci	if (rc < 0) {
153662306a36Sopenharmony_ci		if (rc != -EINVAL) {
153762306a36Sopenharmony_ci			dev_err(&spi->dev,
153862306a36Sopenharmony_ci				"failed to parse xtal-trim: %d\n", rc);
153962306a36Sopenharmony_ci			return rc;
154062306a36Sopenharmony_ci		}
154162306a36Sopenharmony_ci		xtal_trim = 0;
154262306a36Sopenharmony_ci	}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	rstn = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW);
154562306a36Sopenharmony_ci	rc = PTR_ERR_OR_ZERO(rstn);
154662306a36Sopenharmony_ci	if (rc)
154762306a36Sopenharmony_ci		return rc;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	gpiod_set_consumer_name(rstn, "rstn");
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	slp_tr = devm_gpiod_get_optional(&spi->dev, "sleep", GPIOD_OUT_LOW);
155262306a36Sopenharmony_ci	rc = PTR_ERR_OR_ZERO(slp_tr);
155362306a36Sopenharmony_ci	if (rc)
155462306a36Sopenharmony_ci		return rc;
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	gpiod_set_consumer_name(slp_tr, "slp_tr");
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	/* Reset */
155962306a36Sopenharmony_ci	if (rstn) {
156062306a36Sopenharmony_ci		udelay(1);
156162306a36Sopenharmony_ci		gpiod_set_value_cansleep(rstn, 1);
156262306a36Sopenharmony_ci		udelay(1);
156362306a36Sopenharmony_ci		gpiod_set_value_cansleep(rstn, 0);
156462306a36Sopenharmony_ci		usleep_range(120, 240);
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	hw = ieee802154_alloc_hw(sizeof(*lp), &at86rf230_ops);
156862306a36Sopenharmony_ci	if (!hw)
156962306a36Sopenharmony_ci		return -ENOMEM;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	lp = hw->priv;
157262306a36Sopenharmony_ci	lp->hw = hw;
157362306a36Sopenharmony_ci	lp->spi = spi;
157462306a36Sopenharmony_ci	lp->slp_tr = slp_tr;
157562306a36Sopenharmony_ci	hw->parent = &spi->dev;
157662306a36Sopenharmony_ci	ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config);
157962306a36Sopenharmony_ci	if (IS_ERR(lp->regmap)) {
158062306a36Sopenharmony_ci		rc = PTR_ERR(lp->regmap);
158162306a36Sopenharmony_ci		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
158262306a36Sopenharmony_ci			rc);
158362306a36Sopenharmony_ci		goto free_dev;
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	at86rf230_setup_spi_messages(lp, &lp->state);
158762306a36Sopenharmony_ci	at86rf230_setup_spi_messages(lp, &lp->tx);
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	rc = at86rf230_detect_device(lp);
159062306a36Sopenharmony_ci	if (rc < 0)
159162306a36Sopenharmony_ci		goto free_dev;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	init_completion(&lp->state_complete);
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	spi_set_drvdata(spi, lp);
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	rc = at86rf230_hw_init(lp, xtal_trim);
159862306a36Sopenharmony_ci	if (rc)
159962306a36Sopenharmony_ci		goto free_dev;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	/* Read irq status register to reset irq line */
160262306a36Sopenharmony_ci	rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status);
160362306a36Sopenharmony_ci	if (rc)
160462306a36Sopenharmony_ci		goto free_dev;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	irq_type = irq_get_trigger_type(spi->irq);
160762306a36Sopenharmony_ci	if (!irq_type)
160862306a36Sopenharmony_ci		irq_type = IRQF_TRIGGER_HIGH;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	rc = devm_request_irq(&spi->dev, spi->irq, at86rf230_isr,
161162306a36Sopenharmony_ci			      IRQF_SHARED | irq_type, dev_name(&spi->dev), lp);
161262306a36Sopenharmony_ci	if (rc)
161362306a36Sopenharmony_ci		goto free_dev;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	/* disable_irq by default and wait for starting hardware */
161662306a36Sopenharmony_ci	disable_irq(spi->irq);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	/* going into sleep by default */
161962306a36Sopenharmony_ci	at86rf230_sleep(lp);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	rc = ieee802154_register_hw(lp->hw);
162262306a36Sopenharmony_ci	if (rc)
162362306a36Sopenharmony_ci		goto free_dev;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	return rc;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_cifree_dev:
162862306a36Sopenharmony_ci	ieee802154_free_hw(lp->hw);
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	return rc;
163162306a36Sopenharmony_ci}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_cistatic void at86rf230_remove(struct spi_device *spi)
163462306a36Sopenharmony_ci{
163562306a36Sopenharmony_ci	struct at86rf230_local *lp = spi_get_drvdata(spi);
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	/* mask all at86rf230 irq's */
163862306a36Sopenharmony_ci	at86rf230_write_subreg(lp, SR_IRQ_MASK, 0);
163962306a36Sopenharmony_ci	ieee802154_unregister_hw(lp->hw);
164062306a36Sopenharmony_ci	ieee802154_free_hw(lp->hw);
164162306a36Sopenharmony_ci	dev_dbg(&spi->dev, "unregistered at86rf230\n");
164262306a36Sopenharmony_ci}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_cistatic const struct of_device_id at86rf230_of_match[] = {
164562306a36Sopenharmony_ci	{ .compatible = "atmel,at86rf230", },
164662306a36Sopenharmony_ci	{ .compatible = "atmel,at86rf231", },
164762306a36Sopenharmony_ci	{ .compatible = "atmel,at86rf233", },
164862306a36Sopenharmony_ci	{ .compatible = "atmel,at86rf212", },
164962306a36Sopenharmony_ci	{ },
165062306a36Sopenharmony_ci};
165162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, at86rf230_of_match);
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_cistatic const struct spi_device_id at86rf230_device_id[] = {
165462306a36Sopenharmony_ci	{ .name = "at86rf230", },
165562306a36Sopenharmony_ci	{ .name = "at86rf231", },
165662306a36Sopenharmony_ci	{ .name = "at86rf233", },
165762306a36Sopenharmony_ci	{ .name = "at86rf212", },
165862306a36Sopenharmony_ci	{ },
165962306a36Sopenharmony_ci};
166062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, at86rf230_device_id);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cistatic struct spi_driver at86rf230_driver = {
166362306a36Sopenharmony_ci	.id_table = at86rf230_device_id,
166462306a36Sopenharmony_ci	.driver = {
166562306a36Sopenharmony_ci		.of_match_table = at86rf230_of_match,
166662306a36Sopenharmony_ci		.name	= "at86rf230",
166762306a36Sopenharmony_ci	},
166862306a36Sopenharmony_ci	.probe      = at86rf230_probe,
166962306a36Sopenharmony_ci	.remove     = at86rf230_remove,
167062306a36Sopenharmony_ci};
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_cimodule_spi_driver(at86rf230_driver);
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ciMODULE_DESCRIPTION("AT86RF230 Transceiver Driver");
167562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1676