18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AT86RF230/RF231 driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2009-2012 Siemens AG
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Written by:
88c2ecf20Sopenharmony_ci * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
98c2ecf20Sopenharmony_ci * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
108c2ecf20Sopenharmony_ci * Alexander Aring <aar@pengutronix.de>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/hrtimer.h>
158c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
168c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
178c2ecf20Sopenharmony_ci#include <linux/irq.h>
188c2ecf20Sopenharmony_ci#include <linux/gpio.h>
198c2ecf20Sopenharmony_ci#include <linux/delay.h>
208c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
218c2ecf20Sopenharmony_ci#include <linux/spi/at86rf230.h>
228c2ecf20Sopenharmony_ci#include <linux/regmap.h>
238c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
248c2ecf20Sopenharmony_ci#include <linux/of_gpio.h>
258c2ecf20Sopenharmony_ci#include <linux/ieee802154.h>
268c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <net/mac802154.h>
298c2ecf20Sopenharmony_ci#include <net/cfg802154.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "at86rf230.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistruct at86rf230_local;
348c2ecf20Sopenharmony_ci/* at86rf2xx chip depend data.
358c2ecf20Sopenharmony_ci * All timings are in us.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_cistruct at86rf2xx_chip_data {
388c2ecf20Sopenharmony_ci	u16 t_sleep_cycle;
398c2ecf20Sopenharmony_ci	u16 t_channel_switch;
408c2ecf20Sopenharmony_ci	u16 t_reset_to_off;
418c2ecf20Sopenharmony_ci	u16 t_off_to_aack;
428c2ecf20Sopenharmony_ci	u16 t_off_to_tx_on;
438c2ecf20Sopenharmony_ci	u16 t_off_to_sleep;
448c2ecf20Sopenharmony_ci	u16 t_sleep_to_off;
458c2ecf20Sopenharmony_ci	u16 t_frame;
468c2ecf20Sopenharmony_ci	u16 t_p_ack;
478c2ecf20Sopenharmony_ci	int rssi_base_val;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	int (*set_channel)(struct at86rf230_local *, u8, u8);
508c2ecf20Sopenharmony_ci	int (*set_txpower)(struct at86rf230_local *, s32);
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define AT86RF2XX_MAX_BUF		(127 + 3)
548c2ecf20Sopenharmony_ci/* tx retries to access the TX_ON state
558c2ecf20Sopenharmony_ci * if it's above then force change will be started.
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * We assume the max_frame_retries (7) value of 802.15.4 here.
588c2ecf20Sopenharmony_ci */
598c2ecf20Sopenharmony_ci#define AT86RF2XX_MAX_TX_RETRIES	7
608c2ecf20Sopenharmony_ci/* We use the recommended 5 minutes timeout to recalibrate */
618c2ecf20Sopenharmony_ci#define AT86RF2XX_CAL_LOOP_TIMEOUT	(5 * 60 * HZ)
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistruct at86rf230_state_change {
648c2ecf20Sopenharmony_ci	struct at86rf230_local *lp;
658c2ecf20Sopenharmony_ci	int irq;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	struct hrtimer timer;
688c2ecf20Sopenharmony_ci	struct spi_message msg;
698c2ecf20Sopenharmony_ci	struct spi_transfer trx;
708c2ecf20Sopenharmony_ci	u8 buf[AT86RF2XX_MAX_BUF];
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	void (*complete)(void *context);
738c2ecf20Sopenharmony_ci	u8 from_state;
748c2ecf20Sopenharmony_ci	u8 to_state;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	bool free;
778c2ecf20Sopenharmony_ci};
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistruct at86rf230_trac {
808c2ecf20Sopenharmony_ci	u64 success;
818c2ecf20Sopenharmony_ci	u64 success_data_pending;
828c2ecf20Sopenharmony_ci	u64 success_wait_for_ack;
838c2ecf20Sopenharmony_ci	u64 channel_access_failure;
848c2ecf20Sopenharmony_ci	u64 no_ack;
858c2ecf20Sopenharmony_ci	u64 invalid;
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistruct at86rf230_local {
898c2ecf20Sopenharmony_ci	struct spi_device *spi;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	struct ieee802154_hw *hw;
928c2ecf20Sopenharmony_ci	struct at86rf2xx_chip_data *data;
938c2ecf20Sopenharmony_ci	struct regmap *regmap;
948c2ecf20Sopenharmony_ci	int slp_tr;
958c2ecf20Sopenharmony_ci	bool sleep;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	struct completion state_complete;
988c2ecf20Sopenharmony_ci	struct at86rf230_state_change state;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	unsigned long cal_timeout;
1018c2ecf20Sopenharmony_ci	bool is_tx;
1028c2ecf20Sopenharmony_ci	bool is_tx_from_off;
1038c2ecf20Sopenharmony_ci	bool was_tx;
1048c2ecf20Sopenharmony_ci	u8 tx_retry;
1058c2ecf20Sopenharmony_ci	struct sk_buff *tx_skb;
1068c2ecf20Sopenharmony_ci	struct at86rf230_state_change tx;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	struct at86rf230_trac trac;
1098c2ecf20Sopenharmony_ci};
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci#define AT86RF2XX_NUMREGS 0x3F
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic void
1148c2ecf20Sopenharmony_ciat86rf230_async_state_change(struct at86rf230_local *lp,
1158c2ecf20Sopenharmony_ci			     struct at86rf230_state_change *ctx,
1168c2ecf20Sopenharmony_ci			     const u8 state, void (*complete)(void *context));
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic inline void
1198c2ecf20Sopenharmony_ciat86rf230_sleep(struct at86rf230_local *lp)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	if (gpio_is_valid(lp->slp_tr)) {
1228c2ecf20Sopenharmony_ci		gpio_set_value(lp->slp_tr, 1);
1238c2ecf20Sopenharmony_ci		usleep_range(lp->data->t_off_to_sleep,
1248c2ecf20Sopenharmony_ci			     lp->data->t_off_to_sleep + 10);
1258c2ecf20Sopenharmony_ci		lp->sleep = true;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic inline void
1308c2ecf20Sopenharmony_ciat86rf230_awake(struct at86rf230_local *lp)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	if (gpio_is_valid(lp->slp_tr)) {
1338c2ecf20Sopenharmony_ci		gpio_set_value(lp->slp_tr, 0);
1348c2ecf20Sopenharmony_ci		usleep_range(lp->data->t_sleep_to_off,
1358c2ecf20Sopenharmony_ci			     lp->data->t_sleep_to_off + 100);
1368c2ecf20Sopenharmony_ci		lp->sleep = false;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic inline int
1418c2ecf20Sopenharmony_ci__at86rf230_write(struct at86rf230_local *lp,
1428c2ecf20Sopenharmony_ci		  unsigned int addr, unsigned int data)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	bool sleep = lp->sleep;
1458c2ecf20Sopenharmony_ci	int ret;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* awake for register setting if sleep */
1488c2ecf20Sopenharmony_ci	if (sleep)
1498c2ecf20Sopenharmony_ci		at86rf230_awake(lp);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	ret = regmap_write(lp->regmap, addr, data);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/* sleep again if was sleeping */
1548c2ecf20Sopenharmony_ci	if (sleep)
1558c2ecf20Sopenharmony_ci		at86rf230_sleep(lp);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	return ret;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic inline int
1618c2ecf20Sopenharmony_ci__at86rf230_read(struct at86rf230_local *lp,
1628c2ecf20Sopenharmony_ci		 unsigned int addr, unsigned int *data)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	bool sleep = lp->sleep;
1658c2ecf20Sopenharmony_ci	int ret;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	/* awake for register setting if sleep */
1688c2ecf20Sopenharmony_ci	if (sleep)
1698c2ecf20Sopenharmony_ci		at86rf230_awake(lp);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	ret = regmap_read(lp->regmap, addr, data);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* sleep again if was sleeping */
1748c2ecf20Sopenharmony_ci	if (sleep)
1758c2ecf20Sopenharmony_ci		at86rf230_sleep(lp);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return ret;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic inline int
1818c2ecf20Sopenharmony_ciat86rf230_read_subreg(struct at86rf230_local *lp,
1828c2ecf20Sopenharmony_ci		      unsigned int addr, unsigned int mask,
1838c2ecf20Sopenharmony_ci		      unsigned int shift, unsigned int *data)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	int rc;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	rc = __at86rf230_read(lp, addr, data);
1888c2ecf20Sopenharmony_ci	if (!rc)
1898c2ecf20Sopenharmony_ci		*data = (*data & mask) >> shift;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return rc;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic inline int
1958c2ecf20Sopenharmony_ciat86rf230_write_subreg(struct at86rf230_local *lp,
1968c2ecf20Sopenharmony_ci		       unsigned int addr, unsigned int mask,
1978c2ecf20Sopenharmony_ci		       unsigned int shift, unsigned int data)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	bool sleep = lp->sleep;
2008c2ecf20Sopenharmony_ci	int ret;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	/* awake for register setting if sleep */
2038c2ecf20Sopenharmony_ci	if (sleep)
2048c2ecf20Sopenharmony_ci		at86rf230_awake(lp);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	ret = regmap_update_bits(lp->regmap, addr, mask, data << shift);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* sleep again if was sleeping */
2098c2ecf20Sopenharmony_ci	if (sleep)
2108c2ecf20Sopenharmony_ci		at86rf230_sleep(lp);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return ret;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic inline void
2168c2ecf20Sopenharmony_ciat86rf230_slp_tr_rising_edge(struct at86rf230_local *lp)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	gpio_set_value(lp->slp_tr, 1);
2198c2ecf20Sopenharmony_ci	udelay(1);
2208c2ecf20Sopenharmony_ci	gpio_set_value(lp->slp_tr, 0);
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic bool
2248c2ecf20Sopenharmony_ciat86rf230_reg_writeable(struct device *dev, unsigned int reg)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	switch (reg) {
2278c2ecf20Sopenharmony_ci	case RG_TRX_STATE:
2288c2ecf20Sopenharmony_ci	case RG_TRX_CTRL_0:
2298c2ecf20Sopenharmony_ci	case RG_TRX_CTRL_1:
2308c2ecf20Sopenharmony_ci	case RG_PHY_TX_PWR:
2318c2ecf20Sopenharmony_ci	case RG_PHY_ED_LEVEL:
2328c2ecf20Sopenharmony_ci	case RG_PHY_CC_CCA:
2338c2ecf20Sopenharmony_ci	case RG_CCA_THRES:
2348c2ecf20Sopenharmony_ci	case RG_RX_CTRL:
2358c2ecf20Sopenharmony_ci	case RG_SFD_VALUE:
2368c2ecf20Sopenharmony_ci	case RG_TRX_CTRL_2:
2378c2ecf20Sopenharmony_ci	case RG_ANT_DIV:
2388c2ecf20Sopenharmony_ci	case RG_IRQ_MASK:
2398c2ecf20Sopenharmony_ci	case RG_VREG_CTRL:
2408c2ecf20Sopenharmony_ci	case RG_BATMON:
2418c2ecf20Sopenharmony_ci	case RG_XOSC_CTRL:
2428c2ecf20Sopenharmony_ci	case RG_RX_SYN:
2438c2ecf20Sopenharmony_ci	case RG_XAH_CTRL_1:
2448c2ecf20Sopenharmony_ci	case RG_FTN_CTRL:
2458c2ecf20Sopenharmony_ci	case RG_PLL_CF:
2468c2ecf20Sopenharmony_ci	case RG_PLL_DCU:
2478c2ecf20Sopenharmony_ci	case RG_SHORT_ADDR_0:
2488c2ecf20Sopenharmony_ci	case RG_SHORT_ADDR_1:
2498c2ecf20Sopenharmony_ci	case RG_PAN_ID_0:
2508c2ecf20Sopenharmony_ci	case RG_PAN_ID_1:
2518c2ecf20Sopenharmony_ci	case RG_IEEE_ADDR_0:
2528c2ecf20Sopenharmony_ci	case RG_IEEE_ADDR_1:
2538c2ecf20Sopenharmony_ci	case RG_IEEE_ADDR_2:
2548c2ecf20Sopenharmony_ci	case RG_IEEE_ADDR_3:
2558c2ecf20Sopenharmony_ci	case RG_IEEE_ADDR_4:
2568c2ecf20Sopenharmony_ci	case RG_IEEE_ADDR_5:
2578c2ecf20Sopenharmony_ci	case RG_IEEE_ADDR_6:
2588c2ecf20Sopenharmony_ci	case RG_IEEE_ADDR_7:
2598c2ecf20Sopenharmony_ci	case RG_XAH_CTRL_0:
2608c2ecf20Sopenharmony_ci	case RG_CSMA_SEED_0:
2618c2ecf20Sopenharmony_ci	case RG_CSMA_SEED_1:
2628c2ecf20Sopenharmony_ci	case RG_CSMA_BE:
2638c2ecf20Sopenharmony_ci		return true;
2648c2ecf20Sopenharmony_ci	default:
2658c2ecf20Sopenharmony_ci		return false;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic bool
2708c2ecf20Sopenharmony_ciat86rf230_reg_readable(struct device *dev, unsigned int reg)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	bool rc;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/* all writeable are also readable */
2758c2ecf20Sopenharmony_ci	rc = at86rf230_reg_writeable(dev, reg);
2768c2ecf20Sopenharmony_ci	if (rc)
2778c2ecf20Sopenharmony_ci		return rc;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* readonly regs */
2808c2ecf20Sopenharmony_ci	switch (reg) {
2818c2ecf20Sopenharmony_ci	case RG_TRX_STATUS:
2828c2ecf20Sopenharmony_ci	case RG_PHY_RSSI:
2838c2ecf20Sopenharmony_ci	case RG_IRQ_STATUS:
2848c2ecf20Sopenharmony_ci	case RG_PART_NUM:
2858c2ecf20Sopenharmony_ci	case RG_VERSION_NUM:
2868c2ecf20Sopenharmony_ci	case RG_MAN_ID_1:
2878c2ecf20Sopenharmony_ci	case RG_MAN_ID_0:
2888c2ecf20Sopenharmony_ci		return true;
2898c2ecf20Sopenharmony_ci	default:
2908c2ecf20Sopenharmony_ci		return false;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic bool
2958c2ecf20Sopenharmony_ciat86rf230_reg_volatile(struct device *dev, unsigned int reg)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	/* can be changed during runtime */
2988c2ecf20Sopenharmony_ci	switch (reg) {
2998c2ecf20Sopenharmony_ci	case RG_TRX_STATUS:
3008c2ecf20Sopenharmony_ci	case RG_TRX_STATE:
3018c2ecf20Sopenharmony_ci	case RG_PHY_RSSI:
3028c2ecf20Sopenharmony_ci	case RG_PHY_ED_LEVEL:
3038c2ecf20Sopenharmony_ci	case RG_IRQ_STATUS:
3048c2ecf20Sopenharmony_ci	case RG_VREG_CTRL:
3058c2ecf20Sopenharmony_ci	case RG_PLL_CF:
3068c2ecf20Sopenharmony_ci	case RG_PLL_DCU:
3078c2ecf20Sopenharmony_ci		return true;
3088c2ecf20Sopenharmony_ci	default:
3098c2ecf20Sopenharmony_ci		return false;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic bool
3148c2ecf20Sopenharmony_ciat86rf230_reg_precious(struct device *dev, unsigned int reg)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	/* don't clear irq line on read */
3178c2ecf20Sopenharmony_ci	switch (reg) {
3188c2ecf20Sopenharmony_ci	case RG_IRQ_STATUS:
3198c2ecf20Sopenharmony_ci		return true;
3208c2ecf20Sopenharmony_ci	default:
3218c2ecf20Sopenharmony_ci		return false;
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic const struct regmap_config at86rf230_regmap_spi_config = {
3268c2ecf20Sopenharmony_ci	.reg_bits = 8,
3278c2ecf20Sopenharmony_ci	.val_bits = 8,
3288c2ecf20Sopenharmony_ci	.write_flag_mask = CMD_REG | CMD_WRITE,
3298c2ecf20Sopenharmony_ci	.read_flag_mask = CMD_REG,
3308c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
3318c2ecf20Sopenharmony_ci	.max_register = AT86RF2XX_NUMREGS,
3328c2ecf20Sopenharmony_ci	.writeable_reg = at86rf230_reg_writeable,
3338c2ecf20Sopenharmony_ci	.readable_reg = at86rf230_reg_readable,
3348c2ecf20Sopenharmony_ci	.volatile_reg = at86rf230_reg_volatile,
3358c2ecf20Sopenharmony_ci	.precious_reg = at86rf230_reg_precious,
3368c2ecf20Sopenharmony_ci};
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic void
3398c2ecf20Sopenharmony_ciat86rf230_async_error_recover_complete(void *context)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
3428c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	if (ctx->free)
3458c2ecf20Sopenharmony_ci		kfree(ctx);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (lp->was_tx) {
3488c2ecf20Sopenharmony_ci		lp->was_tx = 0;
3498c2ecf20Sopenharmony_ci		dev_kfree_skb_any(lp->tx_skb);
3508c2ecf20Sopenharmony_ci		ieee802154_wake_queue(lp->hw);
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic void
3558c2ecf20Sopenharmony_ciat86rf230_async_error_recover(void *context)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
3588c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (lp->is_tx) {
3618c2ecf20Sopenharmony_ci		lp->was_tx = 1;
3628c2ecf20Sopenharmony_ci		lp->is_tx = 0;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
3668c2ecf20Sopenharmony_ci				     at86rf230_async_error_recover_complete);
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic inline void
3708c2ecf20Sopenharmony_ciat86rf230_async_error(struct at86rf230_local *lp,
3718c2ecf20Sopenharmony_ci		      struct at86rf230_state_change *ctx, int rc)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	dev_err(&lp->spi->dev, "spi_async error %d\n", rc);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
3768c2ecf20Sopenharmony_ci				     at86rf230_async_error_recover);
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci/* Generic function to get some register value in async mode */
3808c2ecf20Sopenharmony_cistatic void
3818c2ecf20Sopenharmony_ciat86rf230_async_read_reg(struct at86rf230_local *lp, u8 reg,
3828c2ecf20Sopenharmony_ci			 struct at86rf230_state_change *ctx,
3838c2ecf20Sopenharmony_ci			 void (*complete)(void *context))
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	int rc;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	u8 *tx_buf = ctx->buf;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	tx_buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
3908c2ecf20Sopenharmony_ci	ctx->msg.complete = complete;
3918c2ecf20Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
3928c2ecf20Sopenharmony_ci	if (rc)
3938c2ecf20Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic void
3978c2ecf20Sopenharmony_ciat86rf230_async_write_reg(struct at86rf230_local *lp, u8 reg, u8 val,
3988c2ecf20Sopenharmony_ci			  struct at86rf230_state_change *ctx,
3998c2ecf20Sopenharmony_ci			  void (*complete)(void *context))
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	int rc;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	ctx->buf[0] = (reg & CMD_REG_MASK) | CMD_REG | CMD_WRITE;
4048c2ecf20Sopenharmony_ci	ctx->buf[1] = val;
4058c2ecf20Sopenharmony_ci	ctx->msg.complete = complete;
4068c2ecf20Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
4078c2ecf20Sopenharmony_ci	if (rc)
4088c2ecf20Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic void
4128c2ecf20Sopenharmony_ciat86rf230_async_state_assert(void *context)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
4158c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
4168c2ecf20Sopenharmony_ci	const u8 *buf = ctx->buf;
4178c2ecf20Sopenharmony_ci	const u8 trx_state = buf[1] & TRX_STATE_MASK;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/* Assert state change */
4208c2ecf20Sopenharmony_ci	if (trx_state != ctx->to_state) {
4218c2ecf20Sopenharmony_ci		/* Special handling if transceiver state is in
4228c2ecf20Sopenharmony_ci		 * STATE_BUSY_RX_AACK and a SHR was detected.
4238c2ecf20Sopenharmony_ci		 */
4248c2ecf20Sopenharmony_ci		if  (trx_state == STATE_BUSY_RX_AACK) {
4258c2ecf20Sopenharmony_ci			/* Undocumented race condition. If we send a state
4268c2ecf20Sopenharmony_ci			 * change to STATE_RX_AACK_ON the transceiver could
4278c2ecf20Sopenharmony_ci			 * change his state automatically to STATE_BUSY_RX_AACK
4288c2ecf20Sopenharmony_ci			 * if a SHR was detected. This is not an error, but we
4298c2ecf20Sopenharmony_ci			 * can't assert this.
4308c2ecf20Sopenharmony_ci			 */
4318c2ecf20Sopenharmony_ci			if (ctx->to_state == STATE_RX_AACK_ON)
4328c2ecf20Sopenharmony_ci				goto done;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci			/* If we change to STATE_TX_ON without forcing and
4358c2ecf20Sopenharmony_ci			 * transceiver state is STATE_BUSY_RX_AACK, we wait
4368c2ecf20Sopenharmony_ci			 * 'tFrame + tPAck' receiving time. In this time the
4378c2ecf20Sopenharmony_ci			 * PDU should be received. If the transceiver is still
4388c2ecf20Sopenharmony_ci			 * in STATE_BUSY_RX_AACK, we run a force state change
4398c2ecf20Sopenharmony_ci			 * to STATE_TX_ON. This is a timeout handling, if the
4408c2ecf20Sopenharmony_ci			 * transceiver stucks in STATE_BUSY_RX_AACK.
4418c2ecf20Sopenharmony_ci			 *
4428c2ecf20Sopenharmony_ci			 * Additional we do several retries to try to get into
4438c2ecf20Sopenharmony_ci			 * TX_ON state without forcing. If the retries are
4448c2ecf20Sopenharmony_ci			 * higher or equal than AT86RF2XX_MAX_TX_RETRIES we
4458c2ecf20Sopenharmony_ci			 * will do a force change.
4468c2ecf20Sopenharmony_ci			 */
4478c2ecf20Sopenharmony_ci			if (ctx->to_state == STATE_TX_ON ||
4488c2ecf20Sopenharmony_ci			    ctx->to_state == STATE_TRX_OFF) {
4498c2ecf20Sopenharmony_ci				u8 state = ctx->to_state;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci				if (lp->tx_retry >= AT86RF2XX_MAX_TX_RETRIES)
4528c2ecf20Sopenharmony_ci					state = STATE_FORCE_TRX_OFF;
4538c2ecf20Sopenharmony_ci				lp->tx_retry++;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci				at86rf230_async_state_change(lp, ctx, state,
4568c2ecf20Sopenharmony_ci							     ctx->complete);
4578c2ecf20Sopenharmony_ci				return;
4588c2ecf20Sopenharmony_ci			}
4598c2ecf20Sopenharmony_ci		}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		dev_warn(&lp->spi->dev, "unexcept state change from 0x%02x to 0x%02x. Actual state: 0x%02x\n",
4628c2ecf20Sopenharmony_ci			 ctx->from_state, ctx->to_state, trx_state);
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cidone:
4668c2ecf20Sopenharmony_ci	if (ctx->complete)
4678c2ecf20Sopenharmony_ci		ctx->complete(context);
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic enum hrtimer_restart at86rf230_async_state_timer(struct hrtimer *timer)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx =
4738c2ecf20Sopenharmony_ci		container_of(timer, struct at86rf230_state_change, timer);
4748c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
4778c2ecf20Sopenharmony_ci				 at86rf230_async_state_assert);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	return HRTIMER_NORESTART;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci/* Do state change timing delay. */
4838c2ecf20Sopenharmony_cistatic void
4848c2ecf20Sopenharmony_ciat86rf230_async_state_delay(void *context)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
4878c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
4888c2ecf20Sopenharmony_ci	struct at86rf2xx_chip_data *c = lp->data;
4898c2ecf20Sopenharmony_ci	bool force = false;
4908c2ecf20Sopenharmony_ci	ktime_t tim;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* The force state changes are will show as normal states in the
4938c2ecf20Sopenharmony_ci	 * state status subregister. We change the to_state to the
4948c2ecf20Sopenharmony_ci	 * corresponding one and remember if it was a force change, this
4958c2ecf20Sopenharmony_ci	 * differs if we do a state change from STATE_BUSY_RX_AACK.
4968c2ecf20Sopenharmony_ci	 */
4978c2ecf20Sopenharmony_ci	switch (ctx->to_state) {
4988c2ecf20Sopenharmony_ci	case STATE_FORCE_TX_ON:
4998c2ecf20Sopenharmony_ci		ctx->to_state = STATE_TX_ON;
5008c2ecf20Sopenharmony_ci		force = true;
5018c2ecf20Sopenharmony_ci		break;
5028c2ecf20Sopenharmony_ci	case STATE_FORCE_TRX_OFF:
5038c2ecf20Sopenharmony_ci		ctx->to_state = STATE_TRX_OFF;
5048c2ecf20Sopenharmony_ci		force = true;
5058c2ecf20Sopenharmony_ci		break;
5068c2ecf20Sopenharmony_ci	default:
5078c2ecf20Sopenharmony_ci		break;
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	switch (ctx->from_state) {
5118c2ecf20Sopenharmony_ci	case STATE_TRX_OFF:
5128c2ecf20Sopenharmony_ci		switch (ctx->to_state) {
5138c2ecf20Sopenharmony_ci		case STATE_RX_AACK_ON:
5148c2ecf20Sopenharmony_ci			tim = c->t_off_to_aack * NSEC_PER_USEC;
5158c2ecf20Sopenharmony_ci			/* state change from TRX_OFF to RX_AACK_ON to do a
5168c2ecf20Sopenharmony_ci			 * calibration, we need to reset the timeout for the
5178c2ecf20Sopenharmony_ci			 * next one.
5188c2ecf20Sopenharmony_ci			 */
5198c2ecf20Sopenharmony_ci			lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
5208c2ecf20Sopenharmony_ci			goto change;
5218c2ecf20Sopenharmony_ci		case STATE_TX_ARET_ON:
5228c2ecf20Sopenharmony_ci		case STATE_TX_ON:
5238c2ecf20Sopenharmony_ci			tim = c->t_off_to_tx_on * NSEC_PER_USEC;
5248c2ecf20Sopenharmony_ci			/* state change from TRX_OFF to TX_ON or ARET_ON to do
5258c2ecf20Sopenharmony_ci			 * a calibration, we need to reset the timeout for the
5268c2ecf20Sopenharmony_ci			 * next one.
5278c2ecf20Sopenharmony_ci			 */
5288c2ecf20Sopenharmony_ci			lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
5298c2ecf20Sopenharmony_ci			goto change;
5308c2ecf20Sopenharmony_ci		default:
5318c2ecf20Sopenharmony_ci			break;
5328c2ecf20Sopenharmony_ci		}
5338c2ecf20Sopenharmony_ci		break;
5348c2ecf20Sopenharmony_ci	case STATE_BUSY_RX_AACK:
5358c2ecf20Sopenharmony_ci		switch (ctx->to_state) {
5368c2ecf20Sopenharmony_ci		case STATE_TRX_OFF:
5378c2ecf20Sopenharmony_ci		case STATE_TX_ON:
5388c2ecf20Sopenharmony_ci			/* Wait for worst case receiving time if we
5398c2ecf20Sopenharmony_ci			 * didn't make a force change from BUSY_RX_AACK
5408c2ecf20Sopenharmony_ci			 * to TX_ON or TRX_OFF.
5418c2ecf20Sopenharmony_ci			 */
5428c2ecf20Sopenharmony_ci			if (!force) {
5438c2ecf20Sopenharmony_ci				tim = (c->t_frame + c->t_p_ack) * NSEC_PER_USEC;
5448c2ecf20Sopenharmony_ci				goto change;
5458c2ecf20Sopenharmony_ci			}
5468c2ecf20Sopenharmony_ci			break;
5478c2ecf20Sopenharmony_ci		default:
5488c2ecf20Sopenharmony_ci			break;
5498c2ecf20Sopenharmony_ci		}
5508c2ecf20Sopenharmony_ci		break;
5518c2ecf20Sopenharmony_ci	/* Default value, means RESET state */
5528c2ecf20Sopenharmony_ci	case STATE_P_ON:
5538c2ecf20Sopenharmony_ci		switch (ctx->to_state) {
5548c2ecf20Sopenharmony_ci		case STATE_TRX_OFF:
5558c2ecf20Sopenharmony_ci			tim = c->t_reset_to_off * NSEC_PER_USEC;
5568c2ecf20Sopenharmony_ci			goto change;
5578c2ecf20Sopenharmony_ci		default:
5588c2ecf20Sopenharmony_ci			break;
5598c2ecf20Sopenharmony_ci		}
5608c2ecf20Sopenharmony_ci		break;
5618c2ecf20Sopenharmony_ci	default:
5628c2ecf20Sopenharmony_ci		break;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	/* Default delay is 1us in the most cases */
5668c2ecf20Sopenharmony_ci	udelay(1);
5678c2ecf20Sopenharmony_ci	at86rf230_async_state_timer(&ctx->timer);
5688c2ecf20Sopenharmony_ci	return;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cichange:
5718c2ecf20Sopenharmony_ci	hrtimer_start(&ctx->timer, tim, HRTIMER_MODE_REL);
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic void
5758c2ecf20Sopenharmony_ciat86rf230_async_state_change_start(void *context)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
5788c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
5798c2ecf20Sopenharmony_ci	u8 *buf = ctx->buf;
5808c2ecf20Sopenharmony_ci	const u8 trx_state = buf[1] & TRX_STATE_MASK;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* Check for "possible" STATE_TRANSITION_IN_PROGRESS */
5838c2ecf20Sopenharmony_ci	if (trx_state == STATE_TRANSITION_IN_PROGRESS) {
5848c2ecf20Sopenharmony_ci		udelay(1);
5858c2ecf20Sopenharmony_ci		at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
5868c2ecf20Sopenharmony_ci					 at86rf230_async_state_change_start);
5878c2ecf20Sopenharmony_ci		return;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	/* Check if we already are in the state which we change in */
5918c2ecf20Sopenharmony_ci	if (trx_state == ctx->to_state) {
5928c2ecf20Sopenharmony_ci		if (ctx->complete)
5938c2ecf20Sopenharmony_ci			ctx->complete(context);
5948c2ecf20Sopenharmony_ci		return;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/* Set current state to the context of state change */
5988c2ecf20Sopenharmony_ci	ctx->from_state = trx_state;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	/* Going into the next step for a state change which do a timing
6018c2ecf20Sopenharmony_ci	 * relevant delay.
6028c2ecf20Sopenharmony_ci	 */
6038c2ecf20Sopenharmony_ci	at86rf230_async_write_reg(lp, RG_TRX_STATE, ctx->to_state, ctx,
6048c2ecf20Sopenharmony_ci				  at86rf230_async_state_delay);
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic void
6088c2ecf20Sopenharmony_ciat86rf230_async_state_change(struct at86rf230_local *lp,
6098c2ecf20Sopenharmony_ci			     struct at86rf230_state_change *ctx,
6108c2ecf20Sopenharmony_ci			     const u8 state, void (*complete)(void *context))
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	/* Initialization for the state change context */
6138c2ecf20Sopenharmony_ci	ctx->to_state = state;
6148c2ecf20Sopenharmony_ci	ctx->complete = complete;
6158c2ecf20Sopenharmony_ci	at86rf230_async_read_reg(lp, RG_TRX_STATUS, ctx,
6168c2ecf20Sopenharmony_ci				 at86rf230_async_state_change_start);
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic void
6208c2ecf20Sopenharmony_ciat86rf230_sync_state_change_complete(void *context)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
6238c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	complete(&lp->state_complete);
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci/* This function do a sync framework above the async state change.
6298c2ecf20Sopenharmony_ci * Some callbacks of the IEEE 802.15.4 driver interface need to be
6308c2ecf20Sopenharmony_ci * handled synchronously.
6318c2ecf20Sopenharmony_ci */
6328c2ecf20Sopenharmony_cistatic int
6338c2ecf20Sopenharmony_ciat86rf230_sync_state_change(struct at86rf230_local *lp, unsigned int state)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	unsigned long rc;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	at86rf230_async_state_change(lp, &lp->state, state,
6388c2ecf20Sopenharmony_ci				     at86rf230_sync_state_change_complete);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	rc = wait_for_completion_timeout(&lp->state_complete,
6418c2ecf20Sopenharmony_ci					 msecs_to_jiffies(100));
6428c2ecf20Sopenharmony_ci	if (!rc) {
6438c2ecf20Sopenharmony_ci		at86rf230_async_error(lp, &lp->state, -ETIMEDOUT);
6448c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	return 0;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cistatic void
6518c2ecf20Sopenharmony_ciat86rf230_tx_complete(void *context)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
6548c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	ieee802154_xmit_complete(lp->hw, lp->tx_skb, false);
6578c2ecf20Sopenharmony_ci	kfree(ctx);
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic void
6618c2ecf20Sopenharmony_ciat86rf230_tx_on(void *context)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
6648c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_RX_AACK_ON,
6678c2ecf20Sopenharmony_ci				     at86rf230_tx_complete);
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_cistatic void
6718c2ecf20Sopenharmony_ciat86rf230_tx_trac_check(void *context)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
6748c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS)) {
6778c2ecf20Sopenharmony_ci		u8 trac = TRAC_MASK(ctx->buf[1]);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		switch (trac) {
6808c2ecf20Sopenharmony_ci		case TRAC_SUCCESS:
6818c2ecf20Sopenharmony_ci			lp->trac.success++;
6828c2ecf20Sopenharmony_ci			break;
6838c2ecf20Sopenharmony_ci		case TRAC_SUCCESS_DATA_PENDING:
6848c2ecf20Sopenharmony_ci			lp->trac.success_data_pending++;
6858c2ecf20Sopenharmony_ci			break;
6868c2ecf20Sopenharmony_ci		case TRAC_CHANNEL_ACCESS_FAILURE:
6878c2ecf20Sopenharmony_ci			lp->trac.channel_access_failure++;
6888c2ecf20Sopenharmony_ci			break;
6898c2ecf20Sopenharmony_ci		case TRAC_NO_ACK:
6908c2ecf20Sopenharmony_ci			lp->trac.no_ack++;
6918c2ecf20Sopenharmony_ci			break;
6928c2ecf20Sopenharmony_ci		case TRAC_INVALID:
6938c2ecf20Sopenharmony_ci			lp->trac.invalid++;
6948c2ecf20Sopenharmony_ci			break;
6958c2ecf20Sopenharmony_ci		default:
6968c2ecf20Sopenharmony_ci			WARN_ONCE(1, "received tx trac status %d\n", trac);
6978c2ecf20Sopenharmony_ci			break;
6988c2ecf20Sopenharmony_ci		}
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_TX_ON, at86rf230_tx_on);
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic void
7058c2ecf20Sopenharmony_ciat86rf230_rx_read_frame_complete(void *context)
7068c2ecf20Sopenharmony_ci{
7078c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
7088c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
7098c2ecf20Sopenharmony_ci	const u8 *buf = ctx->buf;
7108c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7118c2ecf20Sopenharmony_ci	u8 len, lqi;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	len = buf[1];
7148c2ecf20Sopenharmony_ci	if (!ieee802154_is_valid_psdu_len(len)) {
7158c2ecf20Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
7168c2ecf20Sopenharmony_ci		len = IEEE802154_MTU;
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci	lqi = buf[2 + len];
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	skb = dev_alloc_skb(IEEE802154_MTU);
7218c2ecf20Sopenharmony_ci	if (!skb) {
7228c2ecf20Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "failed to allocate sk_buff\n");
7238c2ecf20Sopenharmony_ci		kfree(ctx);
7248c2ecf20Sopenharmony_ci		return;
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	skb_put_data(skb, buf + 2, len);
7288c2ecf20Sopenharmony_ci	ieee802154_rx_irqsafe(lp->hw, skb, lqi);
7298c2ecf20Sopenharmony_ci	kfree(ctx);
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_cistatic void
7338c2ecf20Sopenharmony_ciat86rf230_rx_trac_check(void *context)
7348c2ecf20Sopenharmony_ci{
7358c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
7368c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
7378c2ecf20Sopenharmony_ci	u8 *buf = ctx->buf;
7388c2ecf20Sopenharmony_ci	int rc;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS)) {
7418c2ecf20Sopenharmony_ci		u8 trac = TRAC_MASK(buf[1]);
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci		switch (trac) {
7448c2ecf20Sopenharmony_ci		case TRAC_SUCCESS:
7458c2ecf20Sopenharmony_ci			lp->trac.success++;
7468c2ecf20Sopenharmony_ci			break;
7478c2ecf20Sopenharmony_ci		case TRAC_SUCCESS_WAIT_FOR_ACK:
7488c2ecf20Sopenharmony_ci			lp->trac.success_wait_for_ack++;
7498c2ecf20Sopenharmony_ci			break;
7508c2ecf20Sopenharmony_ci		case TRAC_INVALID:
7518c2ecf20Sopenharmony_ci			lp->trac.invalid++;
7528c2ecf20Sopenharmony_ci			break;
7538c2ecf20Sopenharmony_ci		default:
7548c2ecf20Sopenharmony_ci			WARN_ONCE(1, "received rx trac status %d\n", trac);
7558c2ecf20Sopenharmony_ci			break;
7568c2ecf20Sopenharmony_ci		}
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	buf[0] = CMD_FB;
7608c2ecf20Sopenharmony_ci	ctx->trx.len = AT86RF2XX_MAX_BUF;
7618c2ecf20Sopenharmony_ci	ctx->msg.complete = at86rf230_rx_read_frame_complete;
7628c2ecf20Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
7638c2ecf20Sopenharmony_ci	if (rc) {
7648c2ecf20Sopenharmony_ci		ctx->trx.len = 2;
7658c2ecf20Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
7668c2ecf20Sopenharmony_ci	}
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_cistatic void
7708c2ecf20Sopenharmony_ciat86rf230_irq_trx_end(void *context)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
7738c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (lp->is_tx) {
7768c2ecf20Sopenharmony_ci		lp->is_tx = 0;
7778c2ecf20Sopenharmony_ci		at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
7788c2ecf20Sopenharmony_ci					 at86rf230_tx_trac_check);
7798c2ecf20Sopenharmony_ci	} else {
7808c2ecf20Sopenharmony_ci		at86rf230_async_read_reg(lp, RG_TRX_STATE, ctx,
7818c2ecf20Sopenharmony_ci					 at86rf230_rx_trac_check);
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_cistatic void
7868c2ecf20Sopenharmony_ciat86rf230_irq_status(void *context)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
7898c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
7908c2ecf20Sopenharmony_ci	const u8 *buf = ctx->buf;
7918c2ecf20Sopenharmony_ci	u8 irq = buf[1];
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	enable_irq(lp->spi->irq);
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	if (irq & IRQ_TRX_END) {
7968c2ecf20Sopenharmony_ci		at86rf230_irq_trx_end(ctx);
7978c2ecf20Sopenharmony_ci	} else {
7988c2ecf20Sopenharmony_ci		dev_err(&lp->spi->dev, "not supported irq %02x received\n",
7998c2ecf20Sopenharmony_ci			irq);
8008c2ecf20Sopenharmony_ci		kfree(ctx);
8018c2ecf20Sopenharmony_ci	}
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic void
8058c2ecf20Sopenharmony_ciat86rf230_setup_spi_messages(struct at86rf230_local *lp,
8068c2ecf20Sopenharmony_ci			     struct at86rf230_state_change *state)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	state->lp = lp;
8098c2ecf20Sopenharmony_ci	state->irq = lp->spi->irq;
8108c2ecf20Sopenharmony_ci	spi_message_init(&state->msg);
8118c2ecf20Sopenharmony_ci	state->msg.context = state;
8128c2ecf20Sopenharmony_ci	state->trx.len = 2;
8138c2ecf20Sopenharmony_ci	state->trx.tx_buf = state->buf;
8148c2ecf20Sopenharmony_ci	state->trx.rx_buf = state->buf;
8158c2ecf20Sopenharmony_ci	spi_message_add_tail(&state->trx, &state->msg);
8168c2ecf20Sopenharmony_ci	hrtimer_init(&state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
8178c2ecf20Sopenharmony_ci	state->timer.function = at86rf230_async_state_timer;
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_cistatic irqreturn_t at86rf230_isr(int irq, void *data)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = data;
8238c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx;
8248c2ecf20Sopenharmony_ci	int rc;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	disable_irq_nosync(irq);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
8298c2ecf20Sopenharmony_ci	if (!ctx) {
8308c2ecf20Sopenharmony_ci		enable_irq(irq);
8318c2ecf20Sopenharmony_ci		return IRQ_NONE;
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	at86rf230_setup_spi_messages(lp, ctx);
8358c2ecf20Sopenharmony_ci	/* tell on error handling to free ctx */
8368c2ecf20Sopenharmony_ci	ctx->free = true;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	ctx->buf[0] = (RG_IRQ_STATUS & CMD_REG_MASK) | CMD_REG;
8398c2ecf20Sopenharmony_ci	ctx->msg.complete = at86rf230_irq_status;
8408c2ecf20Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
8418c2ecf20Sopenharmony_ci	if (rc) {
8428c2ecf20Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
8438c2ecf20Sopenharmony_ci		enable_irq(irq);
8448c2ecf20Sopenharmony_ci		return IRQ_NONE;
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cistatic void
8518c2ecf20Sopenharmony_ciat86rf230_write_frame_complete(void *context)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
8548c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	ctx->trx.len = 2;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	if (gpio_is_valid(lp->slp_tr))
8598c2ecf20Sopenharmony_ci		at86rf230_slp_tr_rising_edge(lp);
8608c2ecf20Sopenharmony_ci	else
8618c2ecf20Sopenharmony_ci		at86rf230_async_write_reg(lp, RG_TRX_STATE, STATE_BUSY_TX, ctx,
8628c2ecf20Sopenharmony_ci					  NULL);
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_cistatic void
8668c2ecf20Sopenharmony_ciat86rf230_write_frame(void *context)
8678c2ecf20Sopenharmony_ci{
8688c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
8698c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
8708c2ecf20Sopenharmony_ci	struct sk_buff *skb = lp->tx_skb;
8718c2ecf20Sopenharmony_ci	u8 *buf = ctx->buf;
8728c2ecf20Sopenharmony_ci	int rc;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	lp->is_tx = 1;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	buf[0] = CMD_FB | CMD_WRITE;
8778c2ecf20Sopenharmony_ci	buf[1] = skb->len + 2;
8788c2ecf20Sopenharmony_ci	memcpy(buf + 2, skb->data, skb->len);
8798c2ecf20Sopenharmony_ci	ctx->trx.len = skb->len + 2;
8808c2ecf20Sopenharmony_ci	ctx->msg.complete = at86rf230_write_frame_complete;
8818c2ecf20Sopenharmony_ci	rc = spi_async(lp->spi, &ctx->msg);
8828c2ecf20Sopenharmony_ci	if (rc) {
8838c2ecf20Sopenharmony_ci		ctx->trx.len = 2;
8848c2ecf20Sopenharmony_ci		at86rf230_async_error(lp, ctx, rc);
8858c2ecf20Sopenharmony_ci	}
8868c2ecf20Sopenharmony_ci}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_cistatic void
8898c2ecf20Sopenharmony_ciat86rf230_xmit_tx_on(void *context)
8908c2ecf20Sopenharmony_ci{
8918c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
8928c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
8958c2ecf20Sopenharmony_ci				     at86rf230_write_frame);
8968c2ecf20Sopenharmony_ci}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_cistatic void
8998c2ecf20Sopenharmony_ciat86rf230_xmit_start(void *context)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = context;
9028c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = ctx->lp;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	/* check if we change from off state */
9058c2ecf20Sopenharmony_ci	if (lp->is_tx_from_off)
9068c2ecf20Sopenharmony_ci		at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON,
9078c2ecf20Sopenharmony_ci					     at86rf230_write_frame);
9088c2ecf20Sopenharmony_ci	else
9098c2ecf20Sopenharmony_ci		at86rf230_async_state_change(lp, ctx, STATE_TX_ON,
9108c2ecf20Sopenharmony_ci					     at86rf230_xmit_tx_on);
9118c2ecf20Sopenharmony_ci}
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_cistatic int
9148c2ecf20Sopenharmony_ciat86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
9178c2ecf20Sopenharmony_ci	struct at86rf230_state_change *ctx = &lp->tx;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	lp->tx_skb = skb;
9208c2ecf20Sopenharmony_ci	lp->tx_retry = 0;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	/* After 5 minutes in PLL and the same frequency we run again the
9238c2ecf20Sopenharmony_ci	 * calibration loops which is recommended by at86rf2xx datasheets.
9248c2ecf20Sopenharmony_ci	 *
9258c2ecf20Sopenharmony_ci	 * The calibration is initiate by a state change from TRX_OFF
9268c2ecf20Sopenharmony_ci	 * to TX_ON, the lp->cal_timeout should be reinit by state_delay
9278c2ecf20Sopenharmony_ci	 * function then to start in the next 5 minutes.
9288c2ecf20Sopenharmony_ci	 */
9298c2ecf20Sopenharmony_ci	if (time_is_before_jiffies(lp->cal_timeout)) {
9308c2ecf20Sopenharmony_ci		lp->is_tx_from_off = true;
9318c2ecf20Sopenharmony_ci		at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF,
9328c2ecf20Sopenharmony_ci					     at86rf230_xmit_start);
9338c2ecf20Sopenharmony_ci	} else {
9348c2ecf20Sopenharmony_ci		lp->is_tx_from_off = false;
9358c2ecf20Sopenharmony_ci		at86rf230_xmit_start(ctx);
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	return 0;
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic int
9428c2ecf20Sopenharmony_ciat86rf230_ed(struct ieee802154_hw *hw, u8 *level)
9438c2ecf20Sopenharmony_ci{
9448c2ecf20Sopenharmony_ci	WARN_ON(!level);
9458c2ecf20Sopenharmony_ci	*level = 0xbe;
9468c2ecf20Sopenharmony_ci	return 0;
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_cistatic int
9508c2ecf20Sopenharmony_ciat86rf230_start(struct ieee802154_hw *hw)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	/* reset trac stats on start */
9558c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_IEEE802154_AT86RF230_DEBUGFS))
9568c2ecf20Sopenharmony_ci		memset(&lp->trac, 0, sizeof(struct at86rf230_trac));
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	at86rf230_awake(lp);
9598c2ecf20Sopenharmony_ci	enable_irq(lp->spi->irq);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	return at86rf230_sync_state_change(lp, STATE_RX_AACK_ON);
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_cistatic void
9658c2ecf20Sopenharmony_ciat86rf230_stop(struct ieee802154_hw *hw)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
9688c2ecf20Sopenharmony_ci	u8 csma_seed[2];
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	at86rf230_sync_state_change(lp, STATE_FORCE_TRX_OFF);
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	disable_irq(lp->spi->irq);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	/* It's recommended to set random new csma_seeds before sleep state.
9758c2ecf20Sopenharmony_ci	 * Makes only sense in the stop callback, not doing this inside of
9768c2ecf20Sopenharmony_ci	 * at86rf230_sleep, this is also used when we don't transmit afterwards
9778c2ecf20Sopenharmony_ci	 * when calling start callback again.
9788c2ecf20Sopenharmony_ci	 */
9798c2ecf20Sopenharmony_ci	get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed));
9808c2ecf20Sopenharmony_ci	at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]);
9818c2ecf20Sopenharmony_ci	at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	at86rf230_sleep(lp);
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cistatic int
9878c2ecf20Sopenharmony_ciat86rf23x_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci#define AT86RF2XX_MAX_ED_LEVELS 0xF
9938c2ecf20Sopenharmony_cistatic const s32 at86rf233_ed_levels[AT86RF2XX_MAX_ED_LEVELS + 1] = {
9948c2ecf20Sopenharmony_ci	-9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000, -7800, -7600,
9958c2ecf20Sopenharmony_ci	-7400, -7200, -7000, -6800, -6600, -6400,
9968c2ecf20Sopenharmony_ci};
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic const s32 at86rf231_ed_levels[AT86RF2XX_MAX_ED_LEVELS + 1] = {
9998c2ecf20Sopenharmony_ci	-9100, -8900, -8700, -8500, -8300, -8100, -7900, -7700, -7500, -7300,
10008c2ecf20Sopenharmony_ci	-7100, -6900, -6700, -6500, -6300, -6100,
10018c2ecf20Sopenharmony_ci};
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_cistatic const s32 at86rf212_ed_levels_100[AT86RF2XX_MAX_ED_LEVELS + 1] = {
10048c2ecf20Sopenharmony_ci	-10000, -9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200,
10058c2ecf20Sopenharmony_ci	-8000, -7800, -7600, -7400, -7200, -7000,
10068c2ecf20Sopenharmony_ci};
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_cistatic const s32 at86rf212_ed_levels_98[AT86RF2XX_MAX_ED_LEVELS + 1] = {
10098c2ecf20Sopenharmony_ci	-9800, -9600, -9400, -9200, -9000, -8800, -8600, -8400, -8200, -8000,
10108c2ecf20Sopenharmony_ci	-7800, -7600, -7400, -7200, -7000, -6800,
10118c2ecf20Sopenharmony_ci};
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_cistatic inline int
10148c2ecf20Sopenharmony_ciat86rf212_update_cca_ed_level(struct at86rf230_local *lp, int rssi_base_val)
10158c2ecf20Sopenharmony_ci{
10168c2ecf20Sopenharmony_ci	unsigned int cca_ed_thres;
10178c2ecf20Sopenharmony_ci	int rc;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	rc = at86rf230_read_subreg(lp, SR_CCA_ED_THRES, &cca_ed_thres);
10208c2ecf20Sopenharmony_ci	if (rc < 0)
10218c2ecf20Sopenharmony_ci		return rc;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	switch (rssi_base_val) {
10248c2ecf20Sopenharmony_ci	case -98:
10258c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_98;
10268c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_98);
10278c2ecf20Sopenharmony_ci		lp->hw->phy->cca_ed_level = at86rf212_ed_levels_98[cca_ed_thres];
10288c2ecf20Sopenharmony_ci		break;
10298c2ecf20Sopenharmony_ci	case -100:
10308c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100;
10318c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100);
10328c2ecf20Sopenharmony_ci		lp->hw->phy->cca_ed_level = at86rf212_ed_levels_100[cca_ed_thres];
10338c2ecf20Sopenharmony_ci		break;
10348c2ecf20Sopenharmony_ci	default:
10358c2ecf20Sopenharmony_ci		WARN_ON(1);
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	return 0;
10398c2ecf20Sopenharmony_ci}
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_cistatic int
10428c2ecf20Sopenharmony_ciat86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
10438c2ecf20Sopenharmony_ci{
10448c2ecf20Sopenharmony_ci	int rc;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	if (channel == 0)
10478c2ecf20Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 0);
10488c2ecf20Sopenharmony_ci	else
10498c2ecf20Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 1);
10508c2ecf20Sopenharmony_ci	if (rc < 0)
10518c2ecf20Sopenharmony_ci		return rc;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	if (page == 0) {
10548c2ecf20Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0);
10558c2ecf20Sopenharmony_ci		lp->data->rssi_base_val = -100;
10568c2ecf20Sopenharmony_ci	} else {
10578c2ecf20Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1);
10588c2ecf20Sopenharmony_ci		lp->data->rssi_base_val = -98;
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci	if (rc < 0)
10618c2ecf20Sopenharmony_ci		return rc;
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	rc = at86rf212_update_cca_ed_level(lp, lp->data->rssi_base_val);
10648c2ecf20Sopenharmony_ci	if (rc < 0)
10658c2ecf20Sopenharmony_ci		return rc;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	/* This sets the symbol_duration according frequency on the 212.
10688c2ecf20Sopenharmony_ci	 * TODO move this handling while set channel and page in cfg802154.
10698c2ecf20Sopenharmony_ci	 * We can do that, this timings are according 802.15.4 standard.
10708c2ecf20Sopenharmony_ci	 * If we do that in cfg802154, this is a more generic calculation.
10718c2ecf20Sopenharmony_ci	 *
10728c2ecf20Sopenharmony_ci	 * This should also protected from ifs_timer. Means cancel timer and
10738c2ecf20Sopenharmony_ci	 * init with a new value. For now, this is okay.
10748c2ecf20Sopenharmony_ci	 */
10758c2ecf20Sopenharmony_ci	if (channel == 0) {
10768c2ecf20Sopenharmony_ci		if (page == 0) {
10778c2ecf20Sopenharmony_ci			/* SUB:0 and BPSK:0 -> BPSK-20 */
10788c2ecf20Sopenharmony_ci			lp->hw->phy->symbol_duration = 50;
10798c2ecf20Sopenharmony_ci		} else {
10808c2ecf20Sopenharmony_ci			/* SUB:1 and BPSK:0 -> BPSK-40 */
10818c2ecf20Sopenharmony_ci			lp->hw->phy->symbol_duration = 25;
10828c2ecf20Sopenharmony_ci		}
10838c2ecf20Sopenharmony_ci	} else {
10848c2ecf20Sopenharmony_ci		if (page == 0)
10858c2ecf20Sopenharmony_ci			/* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
10868c2ecf20Sopenharmony_ci			lp->hw->phy->symbol_duration = 40;
10878c2ecf20Sopenharmony_ci		else
10888c2ecf20Sopenharmony_ci			/* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
10898c2ecf20Sopenharmony_ci			lp->hw->phy->symbol_duration = 16;
10908c2ecf20Sopenharmony_ci	}
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	lp->hw->phy->lifs_period = IEEE802154_LIFS_PERIOD *
10938c2ecf20Sopenharmony_ci				   lp->hw->phy->symbol_duration;
10948c2ecf20Sopenharmony_ci	lp->hw->phy->sifs_period = IEEE802154_SIFS_PERIOD *
10958c2ecf20Sopenharmony_ci				   lp->hw->phy->symbol_duration;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
10988c2ecf20Sopenharmony_ci}
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_cistatic int
11018c2ecf20Sopenharmony_ciat86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
11048c2ecf20Sopenharmony_ci	int rc;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	rc = lp->data->set_channel(lp, page, channel);
11078c2ecf20Sopenharmony_ci	/* Wait for PLL */
11088c2ecf20Sopenharmony_ci	usleep_range(lp->data->t_channel_switch,
11098c2ecf20Sopenharmony_ci		     lp->data->t_channel_switch + 10);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT;
11128c2ecf20Sopenharmony_ci	return rc;
11138c2ecf20Sopenharmony_ci}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_cistatic int
11168c2ecf20Sopenharmony_ciat86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
11178c2ecf20Sopenharmony_ci			   struct ieee802154_hw_addr_filt *filt,
11188c2ecf20Sopenharmony_ci			   unsigned long changed)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	if (changed & IEEE802154_AFILT_SADDR_CHANGED) {
11238c2ecf20Sopenharmony_ci		u16 addr = le16_to_cpu(filt->short_addr);
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "%s called for saddr\n", __func__);
11268c2ecf20Sopenharmony_ci		__at86rf230_write(lp, RG_SHORT_ADDR_0, addr);
11278c2ecf20Sopenharmony_ci		__at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	if (changed & IEEE802154_AFILT_PANID_CHANGED) {
11318c2ecf20Sopenharmony_ci		u16 pan = le16_to_cpu(filt->pan_id);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "%s called for pan id\n", __func__);
11348c2ecf20Sopenharmony_ci		__at86rf230_write(lp, RG_PAN_ID_0, pan);
11358c2ecf20Sopenharmony_ci		__at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	if (changed & IEEE802154_AFILT_IEEEADDR_CHANGED) {
11398c2ecf20Sopenharmony_ci		u8 i, addr[8];
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci		memcpy(addr, &filt->ieee_addr, 8);
11428c2ecf20Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "%s called for IEEE addr\n", __func__);
11438c2ecf20Sopenharmony_ci		for (i = 0; i < 8; i++)
11448c2ecf20Sopenharmony_ci			__at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci	if (changed & IEEE802154_AFILT_PANC_CHANGED) {
11488c2ecf20Sopenharmony_ci		dev_vdbg(&lp->spi->dev, "%s called for panc change\n", __func__);
11498c2ecf20Sopenharmony_ci		if (filt->pan_coord)
11508c2ecf20Sopenharmony_ci			at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1);
11518c2ecf20Sopenharmony_ci		else
11528c2ecf20Sopenharmony_ci			at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 0);
11538c2ecf20Sopenharmony_ci	}
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	return 0;
11568c2ecf20Sopenharmony_ci}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci#define AT86RF23X_MAX_TX_POWERS 0xF
11598c2ecf20Sopenharmony_cistatic const s32 at86rf233_powers[AT86RF23X_MAX_TX_POWERS + 1] = {
11608c2ecf20Sopenharmony_ci	400, 370, 340, 300, 250, 200, 100, 0, -100, -200, -300, -400, -600,
11618c2ecf20Sopenharmony_ci	-800, -1200, -1700,
11628c2ecf20Sopenharmony_ci};
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_cistatic const s32 at86rf231_powers[AT86RF23X_MAX_TX_POWERS + 1] = {
11658c2ecf20Sopenharmony_ci	300, 280, 230, 180, 130, 70, 0, -100, -200, -300, -400, -500, -700,
11668c2ecf20Sopenharmony_ci	-900, -1200, -1700,
11678c2ecf20Sopenharmony_ci};
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci#define AT86RF212_MAX_TX_POWERS 0x1F
11708c2ecf20Sopenharmony_cistatic const s32 at86rf212_powers[AT86RF212_MAX_TX_POWERS + 1] = {
11718c2ecf20Sopenharmony_ci	500, 400, 300, 200, 100, 0, -100, -200, -300, -400, -500, -600, -700,
11728c2ecf20Sopenharmony_ci	-800, -900, -1000, -1100, -1200, -1300, -1400, -1500, -1600, -1700,
11738c2ecf20Sopenharmony_ci	-1800, -1900, -2000, -2100, -2200, -2300, -2400, -2500, -2600,
11748c2ecf20Sopenharmony_ci};
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_cistatic int
11778c2ecf20Sopenharmony_ciat86rf23x_set_txpower(struct at86rf230_local *lp, s32 mbm)
11788c2ecf20Sopenharmony_ci{
11798c2ecf20Sopenharmony_ci	u32 i;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) {
11828c2ecf20Sopenharmony_ci		if (lp->hw->phy->supported.tx_powers[i] == mbm)
11838c2ecf20Sopenharmony_ci			return at86rf230_write_subreg(lp, SR_TX_PWR_23X, i);
11848c2ecf20Sopenharmony_ci	}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	return -EINVAL;
11878c2ecf20Sopenharmony_ci}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_cistatic int
11908c2ecf20Sopenharmony_ciat86rf212_set_txpower(struct at86rf230_local *lp, s32 mbm)
11918c2ecf20Sopenharmony_ci{
11928c2ecf20Sopenharmony_ci	u32 i;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	for (i = 0; i < lp->hw->phy->supported.tx_powers_size; i++) {
11958c2ecf20Sopenharmony_ci		if (lp->hw->phy->supported.tx_powers[i] == mbm)
11968c2ecf20Sopenharmony_ci			return at86rf230_write_subreg(lp, SR_TX_PWR_212, i);
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	return -EINVAL;
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cistatic int
12038c2ecf20Sopenharmony_ciat86rf230_set_txpower(struct ieee802154_hw *hw, s32 mbm)
12048c2ecf20Sopenharmony_ci{
12058c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	return lp->data->set_txpower(lp, mbm);
12088c2ecf20Sopenharmony_ci}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_cistatic int
12118c2ecf20Sopenharmony_ciat86rf230_set_lbt(struct ieee802154_hw *hw, bool on)
12128c2ecf20Sopenharmony_ci{
12138c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on);
12168c2ecf20Sopenharmony_ci}
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_cistatic int
12198c2ecf20Sopenharmony_ciat86rf230_set_cca_mode(struct ieee802154_hw *hw,
12208c2ecf20Sopenharmony_ci		       const struct wpan_phy_cca *cca)
12218c2ecf20Sopenharmony_ci{
12228c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
12238c2ecf20Sopenharmony_ci	u8 val;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	/* mapping 802.15.4 to driver spec */
12268c2ecf20Sopenharmony_ci	switch (cca->mode) {
12278c2ecf20Sopenharmony_ci	case NL802154_CCA_ENERGY:
12288c2ecf20Sopenharmony_ci		val = 1;
12298c2ecf20Sopenharmony_ci		break;
12308c2ecf20Sopenharmony_ci	case NL802154_CCA_CARRIER:
12318c2ecf20Sopenharmony_ci		val = 2;
12328c2ecf20Sopenharmony_ci		break;
12338c2ecf20Sopenharmony_ci	case NL802154_CCA_ENERGY_CARRIER:
12348c2ecf20Sopenharmony_ci		switch (cca->opt) {
12358c2ecf20Sopenharmony_ci		case NL802154_CCA_OPT_ENERGY_CARRIER_AND:
12368c2ecf20Sopenharmony_ci			val = 3;
12378c2ecf20Sopenharmony_ci			break;
12388c2ecf20Sopenharmony_ci		case NL802154_CCA_OPT_ENERGY_CARRIER_OR:
12398c2ecf20Sopenharmony_ci			val = 0;
12408c2ecf20Sopenharmony_ci			break;
12418c2ecf20Sopenharmony_ci		default:
12428c2ecf20Sopenharmony_ci			return -EINVAL;
12438c2ecf20Sopenharmony_ci		}
12448c2ecf20Sopenharmony_ci		break;
12458c2ecf20Sopenharmony_ci	default:
12468c2ecf20Sopenharmony_ci		return -EINVAL;
12478c2ecf20Sopenharmony_ci	}
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_CCA_MODE, val);
12508c2ecf20Sopenharmony_ci}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_cistatic int
12538c2ecf20Sopenharmony_ciat86rf230_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
12548c2ecf20Sopenharmony_ci{
12558c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
12568c2ecf20Sopenharmony_ci	u32 i;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) {
12598c2ecf20Sopenharmony_ci		if (hw->phy->supported.cca_ed_levels[i] == mbm)
12608c2ecf20Sopenharmony_ci			return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, i);
12618c2ecf20Sopenharmony_ci	}
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	return -EINVAL;
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_cistatic int
12678c2ecf20Sopenharmony_ciat86rf230_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be,
12688c2ecf20Sopenharmony_ci			  u8 retries)
12698c2ecf20Sopenharmony_ci{
12708c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
12718c2ecf20Sopenharmony_ci	int rc;
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_MIN_BE, min_be);
12748c2ecf20Sopenharmony_ci	if (rc)
12758c2ecf20Sopenharmony_ci		return rc;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_MAX_BE, max_be);
12788c2ecf20Sopenharmony_ci	if (rc)
12798c2ecf20Sopenharmony_ci		return rc;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, retries);
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_cistatic int
12858c2ecf20Sopenharmony_ciat86rf230_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
12908c2ecf20Sopenharmony_ci}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_cistatic int
12938c2ecf20Sopenharmony_ciat86rf230_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
12948c2ecf20Sopenharmony_ci{
12958c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = hw->priv;
12968c2ecf20Sopenharmony_ci	int rc;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	if (on) {
12998c2ecf20Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 1);
13008c2ecf20Sopenharmony_ci		if (rc < 0)
13018c2ecf20Sopenharmony_ci			return rc;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 1);
13048c2ecf20Sopenharmony_ci		if (rc < 0)
13058c2ecf20Sopenharmony_ci			return rc;
13068c2ecf20Sopenharmony_ci	} else {
13078c2ecf20Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_AACK_PROM_MODE, 0);
13088c2ecf20Sopenharmony_ci		if (rc < 0)
13098c2ecf20Sopenharmony_ci			return rc;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci		rc = at86rf230_write_subreg(lp, SR_AACK_DIS_ACK, 0);
13128c2ecf20Sopenharmony_ci		if (rc < 0)
13138c2ecf20Sopenharmony_ci			return rc;
13148c2ecf20Sopenharmony_ci	}
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	return 0;
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_cistatic const struct ieee802154_ops at86rf230_ops = {
13208c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
13218c2ecf20Sopenharmony_ci	.xmit_async = at86rf230_xmit,
13228c2ecf20Sopenharmony_ci	.ed = at86rf230_ed,
13238c2ecf20Sopenharmony_ci	.set_channel = at86rf230_channel,
13248c2ecf20Sopenharmony_ci	.start = at86rf230_start,
13258c2ecf20Sopenharmony_ci	.stop = at86rf230_stop,
13268c2ecf20Sopenharmony_ci	.set_hw_addr_filt = at86rf230_set_hw_addr_filt,
13278c2ecf20Sopenharmony_ci	.set_txpower = at86rf230_set_txpower,
13288c2ecf20Sopenharmony_ci	.set_lbt = at86rf230_set_lbt,
13298c2ecf20Sopenharmony_ci	.set_cca_mode = at86rf230_set_cca_mode,
13308c2ecf20Sopenharmony_ci	.set_cca_ed_level = at86rf230_set_cca_ed_level,
13318c2ecf20Sopenharmony_ci	.set_csma_params = at86rf230_set_csma_params,
13328c2ecf20Sopenharmony_ci	.set_frame_retries = at86rf230_set_frame_retries,
13338c2ecf20Sopenharmony_ci	.set_promiscuous_mode = at86rf230_set_promiscuous_mode,
13348c2ecf20Sopenharmony_ci};
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_cistatic struct at86rf2xx_chip_data at86rf233_data = {
13378c2ecf20Sopenharmony_ci	.t_sleep_cycle = 330,
13388c2ecf20Sopenharmony_ci	.t_channel_switch = 11,
13398c2ecf20Sopenharmony_ci	.t_reset_to_off = 26,
13408c2ecf20Sopenharmony_ci	.t_off_to_aack = 80,
13418c2ecf20Sopenharmony_ci	.t_off_to_tx_on = 80,
13428c2ecf20Sopenharmony_ci	.t_off_to_sleep = 35,
13438c2ecf20Sopenharmony_ci	.t_sleep_to_off = 1000,
13448c2ecf20Sopenharmony_ci	.t_frame = 4096,
13458c2ecf20Sopenharmony_ci	.t_p_ack = 545,
13468c2ecf20Sopenharmony_ci	.rssi_base_val = -94,
13478c2ecf20Sopenharmony_ci	.set_channel = at86rf23x_set_channel,
13488c2ecf20Sopenharmony_ci	.set_txpower = at86rf23x_set_txpower,
13498c2ecf20Sopenharmony_ci};
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_cistatic struct at86rf2xx_chip_data at86rf231_data = {
13528c2ecf20Sopenharmony_ci	.t_sleep_cycle = 330,
13538c2ecf20Sopenharmony_ci	.t_channel_switch = 24,
13548c2ecf20Sopenharmony_ci	.t_reset_to_off = 37,
13558c2ecf20Sopenharmony_ci	.t_off_to_aack = 110,
13568c2ecf20Sopenharmony_ci	.t_off_to_tx_on = 110,
13578c2ecf20Sopenharmony_ci	.t_off_to_sleep = 35,
13588c2ecf20Sopenharmony_ci	.t_sleep_to_off = 1000,
13598c2ecf20Sopenharmony_ci	.t_frame = 4096,
13608c2ecf20Sopenharmony_ci	.t_p_ack = 545,
13618c2ecf20Sopenharmony_ci	.rssi_base_val = -91,
13628c2ecf20Sopenharmony_ci	.set_channel = at86rf23x_set_channel,
13638c2ecf20Sopenharmony_ci	.set_txpower = at86rf23x_set_txpower,
13648c2ecf20Sopenharmony_ci};
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_cistatic struct at86rf2xx_chip_data at86rf212_data = {
13678c2ecf20Sopenharmony_ci	.t_sleep_cycle = 330,
13688c2ecf20Sopenharmony_ci	.t_channel_switch = 11,
13698c2ecf20Sopenharmony_ci	.t_reset_to_off = 26,
13708c2ecf20Sopenharmony_ci	.t_off_to_aack = 200,
13718c2ecf20Sopenharmony_ci	.t_off_to_tx_on = 200,
13728c2ecf20Sopenharmony_ci	.t_off_to_sleep = 35,
13738c2ecf20Sopenharmony_ci	.t_sleep_to_off = 1000,
13748c2ecf20Sopenharmony_ci	.t_frame = 4096,
13758c2ecf20Sopenharmony_ci	.t_p_ack = 545,
13768c2ecf20Sopenharmony_ci	.rssi_base_val = -100,
13778c2ecf20Sopenharmony_ci	.set_channel = at86rf212_set_channel,
13788c2ecf20Sopenharmony_ci	.set_txpower = at86rf212_set_txpower,
13798c2ecf20Sopenharmony_ci};
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_cistatic int at86rf230_hw_init(struct at86rf230_local *lp, u8 xtal_trim)
13828c2ecf20Sopenharmony_ci{
13838c2ecf20Sopenharmony_ci	int rc, irq_type, irq_pol = IRQ_ACTIVE_HIGH;
13848c2ecf20Sopenharmony_ci	unsigned int dvdd;
13858c2ecf20Sopenharmony_ci	u8 csma_seed[2];
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	rc = at86rf230_sync_state_change(lp, STATE_FORCE_TRX_OFF);
13888c2ecf20Sopenharmony_ci	if (rc)
13898c2ecf20Sopenharmony_ci		return rc;
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	irq_type = irq_get_trigger_type(lp->spi->irq);
13928c2ecf20Sopenharmony_ci	if (irq_type == IRQ_TYPE_EDGE_FALLING ||
13938c2ecf20Sopenharmony_ci	    irq_type == IRQ_TYPE_LEVEL_LOW)
13948c2ecf20Sopenharmony_ci		irq_pol = IRQ_ACTIVE_LOW;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_IRQ_POLARITY, irq_pol);
13978c2ecf20Sopenharmony_ci	if (rc)
13988c2ecf20Sopenharmony_ci		return rc;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_RX_SAFE_MODE, 1);
14018c2ecf20Sopenharmony_ci	if (rc)
14028c2ecf20Sopenharmony_ci		return rc;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_IRQ_MASK, IRQ_TRX_END);
14058c2ecf20Sopenharmony_ci	if (rc)
14068c2ecf20Sopenharmony_ci		return rc;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	/* reset values differs in at86rf231 and at86rf233 */
14098c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_IRQ_MASK_MODE, 0);
14108c2ecf20Sopenharmony_ci	if (rc)
14118c2ecf20Sopenharmony_ci		return rc;
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed));
14148c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]);
14158c2ecf20Sopenharmony_ci	if (rc)
14168c2ecf20Sopenharmony_ci		return rc;
14178c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]);
14188c2ecf20Sopenharmony_ci	if (rc)
14198c2ecf20Sopenharmony_ci		return rc;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	/* CLKM changes are applied immediately */
14228c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00);
14238c2ecf20Sopenharmony_ci	if (rc)
14248c2ecf20Sopenharmony_ci		return rc;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	/* Turn CLKM Off */
14278c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_CLKM_CTRL, 0x00);
14288c2ecf20Sopenharmony_ci	if (rc)
14298c2ecf20Sopenharmony_ci		return rc;
14308c2ecf20Sopenharmony_ci	/* Wait the next SLEEP cycle */
14318c2ecf20Sopenharmony_ci	usleep_range(lp->data->t_sleep_cycle,
14328c2ecf20Sopenharmony_ci		     lp->data->t_sleep_cycle + 100);
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	/* xtal_trim value is calculated by:
14358c2ecf20Sopenharmony_ci	 * CL = 0.5 * (CX + CTRIM + CPAR)
14368c2ecf20Sopenharmony_ci	 *
14378c2ecf20Sopenharmony_ci	 * whereas:
14388c2ecf20Sopenharmony_ci	 * CL = capacitor of used crystal
14398c2ecf20Sopenharmony_ci	 * CX = connected capacitors at xtal pins
14408c2ecf20Sopenharmony_ci	 * CPAR = in all at86rf2xx datasheets this is a constant value 3 pF,
14418c2ecf20Sopenharmony_ci	 *	  but this is different on each board setup. You need to fine
14428c2ecf20Sopenharmony_ci	 *	  tuning this value via CTRIM.
14438c2ecf20Sopenharmony_ci	 * CTRIM = variable capacitor setting. Resolution is 0.3 pF range is
14448c2ecf20Sopenharmony_ci	 *	   0 pF upto 4.5 pF.
14458c2ecf20Sopenharmony_ci	 *
14468c2ecf20Sopenharmony_ci	 * Examples:
14478c2ecf20Sopenharmony_ci	 * atben transceiver:
14488c2ecf20Sopenharmony_ci	 *
14498c2ecf20Sopenharmony_ci	 * CL = 8 pF
14508c2ecf20Sopenharmony_ci	 * CX = 12 pF
14518c2ecf20Sopenharmony_ci	 * CPAR = 3 pF (We assume the magic constant from datasheet)
14528c2ecf20Sopenharmony_ci	 * CTRIM = 0.9 pF
14538c2ecf20Sopenharmony_ci	 *
14548c2ecf20Sopenharmony_ci	 * (12+0.9+3)/2 = 7.95 which is nearly at 8 pF
14558c2ecf20Sopenharmony_ci	 *
14568c2ecf20Sopenharmony_ci	 * xtal_trim = 0x3
14578c2ecf20Sopenharmony_ci	 *
14588c2ecf20Sopenharmony_ci	 * openlabs transceiver:
14598c2ecf20Sopenharmony_ci	 *
14608c2ecf20Sopenharmony_ci	 * CL = 16 pF
14618c2ecf20Sopenharmony_ci	 * CX = 22 pF
14628c2ecf20Sopenharmony_ci	 * CPAR = 3 pF (We assume the magic constant from datasheet)
14638c2ecf20Sopenharmony_ci	 * CTRIM = 4.5 pF
14648c2ecf20Sopenharmony_ci	 *
14658c2ecf20Sopenharmony_ci	 * (22+4.5+3)/2 = 14.75 which is the nearest value to 16 pF
14668c2ecf20Sopenharmony_ci	 *
14678c2ecf20Sopenharmony_ci	 * xtal_trim = 0xf
14688c2ecf20Sopenharmony_ci	 */
14698c2ecf20Sopenharmony_ci	rc = at86rf230_write_subreg(lp, SR_XTAL_TRIM, xtal_trim);
14708c2ecf20Sopenharmony_ci	if (rc)
14718c2ecf20Sopenharmony_ci		return rc;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &dvdd);
14748c2ecf20Sopenharmony_ci	if (rc)
14758c2ecf20Sopenharmony_ci		return rc;
14768c2ecf20Sopenharmony_ci	if (!dvdd) {
14778c2ecf20Sopenharmony_ci		dev_err(&lp->spi->dev, "DVDD error\n");
14788c2ecf20Sopenharmony_ci		return -EINVAL;
14798c2ecf20Sopenharmony_ci	}
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	/* Force setting slotted operation bit to 0. Sometimes the atben
14828c2ecf20Sopenharmony_ci	 * sets this bit and I don't know why. We set this always force
14838c2ecf20Sopenharmony_ci	 * to zero while probing.
14848c2ecf20Sopenharmony_ci	 */
14858c2ecf20Sopenharmony_ci	return at86rf230_write_subreg(lp, SR_SLOTTED_OPERATION, 0);
14868c2ecf20Sopenharmony_ci}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_cistatic int
14898c2ecf20Sopenharmony_ciat86rf230_get_pdata(struct spi_device *spi, int *rstn, int *slp_tr,
14908c2ecf20Sopenharmony_ci		    u8 *xtal_trim)
14918c2ecf20Sopenharmony_ci{
14928c2ecf20Sopenharmony_ci	struct at86rf230_platform_data *pdata = spi->dev.platform_data;
14938c2ecf20Sopenharmony_ci	int ret;
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node) {
14968c2ecf20Sopenharmony_ci		if (!pdata)
14978c2ecf20Sopenharmony_ci			return -ENOENT;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci		*rstn = pdata->rstn;
15008c2ecf20Sopenharmony_ci		*slp_tr = pdata->slp_tr;
15018c2ecf20Sopenharmony_ci		*xtal_trim = pdata->xtal_trim;
15028c2ecf20Sopenharmony_ci		return 0;
15038c2ecf20Sopenharmony_ci	}
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	*rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
15068c2ecf20Sopenharmony_ci	*slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0);
15078c2ecf20Sopenharmony_ci	ret = of_property_read_u8(spi->dev.of_node, "xtal-trim", xtal_trim);
15088c2ecf20Sopenharmony_ci	if (ret < 0 && ret != -EINVAL)
15098c2ecf20Sopenharmony_ci		return ret;
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	return 0;
15128c2ecf20Sopenharmony_ci}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_cistatic int
15158c2ecf20Sopenharmony_ciat86rf230_detect_device(struct at86rf230_local *lp)
15168c2ecf20Sopenharmony_ci{
15178c2ecf20Sopenharmony_ci	unsigned int part, version, val;
15188c2ecf20Sopenharmony_ci	u16 man_id = 0;
15198c2ecf20Sopenharmony_ci	const char *chip;
15208c2ecf20Sopenharmony_ci	int rc;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	rc = __at86rf230_read(lp, RG_MAN_ID_0, &val);
15238c2ecf20Sopenharmony_ci	if (rc)
15248c2ecf20Sopenharmony_ci		return rc;
15258c2ecf20Sopenharmony_ci	man_id |= val;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	rc = __at86rf230_read(lp, RG_MAN_ID_1, &val);
15288c2ecf20Sopenharmony_ci	if (rc)
15298c2ecf20Sopenharmony_ci		return rc;
15308c2ecf20Sopenharmony_ci	man_id |= (val << 8);
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	rc = __at86rf230_read(lp, RG_PART_NUM, &part);
15338c2ecf20Sopenharmony_ci	if (rc)
15348c2ecf20Sopenharmony_ci		return rc;
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	rc = __at86rf230_read(lp, RG_VERSION_NUM, &version);
15378c2ecf20Sopenharmony_ci	if (rc)
15388c2ecf20Sopenharmony_ci		return rc;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	if (man_id != 0x001f) {
15418c2ecf20Sopenharmony_ci		dev_err(&lp->spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n",
15428c2ecf20Sopenharmony_ci			man_id >> 8, man_id & 0xFF);
15438c2ecf20Sopenharmony_ci		return -EINVAL;
15448c2ecf20Sopenharmony_ci	}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
15478c2ecf20Sopenharmony_ci			IEEE802154_HW_CSMA_PARAMS |
15488c2ecf20Sopenharmony_ci			IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT |
15498c2ecf20Sopenharmony_ci			IEEE802154_HW_PROMISCUOUS;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	lp->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER |
15528c2ecf20Sopenharmony_ci			     WPAN_PHY_FLAG_CCA_ED_LEVEL |
15538c2ecf20Sopenharmony_ci			     WPAN_PHY_FLAG_CCA_MODE;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	lp->hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) |
15568c2ecf20Sopenharmony_ci		BIT(NL802154_CCA_CARRIER) | BIT(NL802154_CCA_ENERGY_CARRIER);
15578c2ecf20Sopenharmony_ci	lp->hw->phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) |
15588c2ecf20Sopenharmony_ci		BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR);
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	lp->hw->phy->cca.mode = NL802154_CCA_ENERGY;
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	switch (part) {
15638c2ecf20Sopenharmony_ci	case 2:
15648c2ecf20Sopenharmony_ci		chip = "at86rf230";
15658c2ecf20Sopenharmony_ci		rc = -ENOTSUPP;
15668c2ecf20Sopenharmony_ci		goto not_supp;
15678c2ecf20Sopenharmony_ci	case 3:
15688c2ecf20Sopenharmony_ci		chip = "at86rf231";
15698c2ecf20Sopenharmony_ci		lp->data = &at86rf231_data;
15708c2ecf20Sopenharmony_ci		lp->hw->phy->supported.channels[0] = 0x7FFF800;
15718c2ecf20Sopenharmony_ci		lp->hw->phy->current_channel = 11;
15728c2ecf20Sopenharmony_ci		lp->hw->phy->symbol_duration = 16;
15738c2ecf20Sopenharmony_ci		lp->hw->phy->supported.tx_powers = at86rf231_powers;
15748c2ecf20Sopenharmony_ci		lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf231_powers);
15758c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf231_ed_levels;
15768c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf231_ed_levels);
15778c2ecf20Sopenharmony_ci		break;
15788c2ecf20Sopenharmony_ci	case 7:
15798c2ecf20Sopenharmony_ci		chip = "at86rf212";
15808c2ecf20Sopenharmony_ci		lp->data = &at86rf212_data;
15818c2ecf20Sopenharmony_ci		lp->hw->flags |= IEEE802154_HW_LBT;
15828c2ecf20Sopenharmony_ci		lp->hw->phy->supported.channels[0] = 0x00007FF;
15838c2ecf20Sopenharmony_ci		lp->hw->phy->supported.channels[2] = 0x00007FF;
15848c2ecf20Sopenharmony_ci		lp->hw->phy->current_channel = 5;
15858c2ecf20Sopenharmony_ci		lp->hw->phy->symbol_duration = 25;
15868c2ecf20Sopenharmony_ci		lp->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH;
15878c2ecf20Sopenharmony_ci		lp->hw->phy->supported.tx_powers = at86rf212_powers;
15888c2ecf20Sopenharmony_ci		lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers);
15898c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf212_ed_levels_100;
15908c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf212_ed_levels_100);
15918c2ecf20Sopenharmony_ci		break;
15928c2ecf20Sopenharmony_ci	case 11:
15938c2ecf20Sopenharmony_ci		chip = "at86rf233";
15948c2ecf20Sopenharmony_ci		lp->data = &at86rf233_data;
15958c2ecf20Sopenharmony_ci		lp->hw->phy->supported.channels[0] = 0x7FFF800;
15968c2ecf20Sopenharmony_ci		lp->hw->phy->current_channel = 13;
15978c2ecf20Sopenharmony_ci		lp->hw->phy->symbol_duration = 16;
15988c2ecf20Sopenharmony_ci		lp->hw->phy->supported.tx_powers = at86rf233_powers;
15998c2ecf20Sopenharmony_ci		lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf233_powers);
16008c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels = at86rf233_ed_levels;
16018c2ecf20Sopenharmony_ci		lp->hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(at86rf233_ed_levels);
16028c2ecf20Sopenharmony_ci		break;
16038c2ecf20Sopenharmony_ci	default:
16048c2ecf20Sopenharmony_ci		chip = "unknown";
16058c2ecf20Sopenharmony_ci		rc = -ENOTSUPP;
16068c2ecf20Sopenharmony_ci		goto not_supp;
16078c2ecf20Sopenharmony_ci	}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	lp->hw->phy->cca_ed_level = lp->hw->phy->supported.cca_ed_levels[7];
16108c2ecf20Sopenharmony_ci	lp->hw->phy->transmit_power = lp->hw->phy->supported.tx_powers[0];
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_cinot_supp:
16138c2ecf20Sopenharmony_ci	dev_info(&lp->spi->dev, "Detected %s chip version %d\n", chip, version);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	return rc;
16168c2ecf20Sopenharmony_ci}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci#ifdef CONFIG_IEEE802154_AT86RF230_DEBUGFS
16198c2ecf20Sopenharmony_cistatic struct dentry *at86rf230_debugfs_root;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_cistatic int at86rf230_stats_show(struct seq_file *file, void *offset)
16228c2ecf20Sopenharmony_ci{
16238c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = file->private;
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	seq_printf(file, "SUCCESS:\t\t%8llu\n", lp->trac.success);
16268c2ecf20Sopenharmony_ci	seq_printf(file, "SUCCESS_DATA_PENDING:\t%8llu\n",
16278c2ecf20Sopenharmony_ci		   lp->trac.success_data_pending);
16288c2ecf20Sopenharmony_ci	seq_printf(file, "SUCCESS_WAIT_FOR_ACK:\t%8llu\n",
16298c2ecf20Sopenharmony_ci		   lp->trac.success_wait_for_ack);
16308c2ecf20Sopenharmony_ci	seq_printf(file, "CHANNEL_ACCESS_FAILURE:\t%8llu\n",
16318c2ecf20Sopenharmony_ci		   lp->trac.channel_access_failure);
16328c2ecf20Sopenharmony_ci	seq_printf(file, "NO_ACK:\t\t\t%8llu\n", lp->trac.no_ack);
16338c2ecf20Sopenharmony_ci	seq_printf(file, "INVALID:\t\t%8llu\n", lp->trac.invalid);
16348c2ecf20Sopenharmony_ci	return 0;
16358c2ecf20Sopenharmony_ci}
16368c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(at86rf230_stats);
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_cistatic void at86rf230_debugfs_init(struct at86rf230_local *lp)
16398c2ecf20Sopenharmony_ci{
16408c2ecf20Sopenharmony_ci	char debugfs_dir_name[DNAME_INLINE_LEN + 1] = "at86rf230-";
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	strncat(debugfs_dir_name, dev_name(&lp->spi->dev), DNAME_INLINE_LEN);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	at86rf230_debugfs_root = debugfs_create_dir(debugfs_dir_name, NULL);
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	debugfs_create_file("trac_stats", 0444, at86rf230_debugfs_root, lp,
16478c2ecf20Sopenharmony_ci			    &at86rf230_stats_fops);
16488c2ecf20Sopenharmony_ci}
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_cistatic void at86rf230_debugfs_remove(void)
16518c2ecf20Sopenharmony_ci{
16528c2ecf20Sopenharmony_ci	debugfs_remove_recursive(at86rf230_debugfs_root);
16538c2ecf20Sopenharmony_ci}
16548c2ecf20Sopenharmony_ci#else
16558c2ecf20Sopenharmony_cistatic void at86rf230_debugfs_init(struct at86rf230_local *lp) { }
16568c2ecf20Sopenharmony_cistatic void at86rf230_debugfs_remove(void) { }
16578c2ecf20Sopenharmony_ci#endif
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_cistatic int at86rf230_probe(struct spi_device *spi)
16608c2ecf20Sopenharmony_ci{
16618c2ecf20Sopenharmony_ci	struct ieee802154_hw *hw;
16628c2ecf20Sopenharmony_ci	struct at86rf230_local *lp;
16638c2ecf20Sopenharmony_ci	unsigned int status;
16648c2ecf20Sopenharmony_ci	int rc, irq_type, rstn, slp_tr;
16658c2ecf20Sopenharmony_ci	u8 xtal_trim = 0;
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	if (!spi->irq) {
16688c2ecf20Sopenharmony_ci		dev_err(&spi->dev, "no IRQ specified\n");
16698c2ecf20Sopenharmony_ci		return -EINVAL;
16708c2ecf20Sopenharmony_ci	}
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	rc = at86rf230_get_pdata(spi, &rstn, &slp_tr, &xtal_trim);
16738c2ecf20Sopenharmony_ci	if (rc < 0) {
16748c2ecf20Sopenharmony_ci		dev_err(&spi->dev, "failed to parse platform_data: %d\n", rc);
16758c2ecf20Sopenharmony_ci		return rc;
16768c2ecf20Sopenharmony_ci	}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	if (gpio_is_valid(rstn)) {
16798c2ecf20Sopenharmony_ci		rc = devm_gpio_request_one(&spi->dev, rstn,
16808c2ecf20Sopenharmony_ci					   GPIOF_OUT_INIT_HIGH, "rstn");
16818c2ecf20Sopenharmony_ci		if (rc)
16828c2ecf20Sopenharmony_ci			return rc;
16838c2ecf20Sopenharmony_ci	}
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	if (gpio_is_valid(slp_tr)) {
16868c2ecf20Sopenharmony_ci		rc = devm_gpio_request_one(&spi->dev, slp_tr,
16878c2ecf20Sopenharmony_ci					   GPIOF_OUT_INIT_LOW, "slp_tr");
16888c2ecf20Sopenharmony_ci		if (rc)
16898c2ecf20Sopenharmony_ci			return rc;
16908c2ecf20Sopenharmony_ci	}
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	/* Reset */
16938c2ecf20Sopenharmony_ci	if (gpio_is_valid(rstn)) {
16948c2ecf20Sopenharmony_ci		udelay(1);
16958c2ecf20Sopenharmony_ci		gpio_set_value_cansleep(rstn, 0);
16968c2ecf20Sopenharmony_ci		udelay(1);
16978c2ecf20Sopenharmony_ci		gpio_set_value_cansleep(rstn, 1);
16988c2ecf20Sopenharmony_ci		usleep_range(120, 240);
16998c2ecf20Sopenharmony_ci	}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	hw = ieee802154_alloc_hw(sizeof(*lp), &at86rf230_ops);
17028c2ecf20Sopenharmony_ci	if (!hw)
17038c2ecf20Sopenharmony_ci		return -ENOMEM;
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	lp = hw->priv;
17068c2ecf20Sopenharmony_ci	lp->hw = hw;
17078c2ecf20Sopenharmony_ci	lp->spi = spi;
17088c2ecf20Sopenharmony_ci	lp->slp_tr = slp_tr;
17098c2ecf20Sopenharmony_ci	hw->parent = &spi->dev;
17108c2ecf20Sopenharmony_ci	ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config);
17138c2ecf20Sopenharmony_ci	if (IS_ERR(lp->regmap)) {
17148c2ecf20Sopenharmony_ci		rc = PTR_ERR(lp->regmap);
17158c2ecf20Sopenharmony_ci		dev_err(&spi->dev, "Failed to allocate register map: %d\n",
17168c2ecf20Sopenharmony_ci			rc);
17178c2ecf20Sopenharmony_ci		goto free_dev;
17188c2ecf20Sopenharmony_ci	}
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	at86rf230_setup_spi_messages(lp, &lp->state);
17218c2ecf20Sopenharmony_ci	at86rf230_setup_spi_messages(lp, &lp->tx);
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	rc = at86rf230_detect_device(lp);
17248c2ecf20Sopenharmony_ci	if (rc < 0)
17258c2ecf20Sopenharmony_ci		goto free_dev;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	init_completion(&lp->state_complete);
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	spi_set_drvdata(spi, lp);
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	rc = at86rf230_hw_init(lp, xtal_trim);
17328c2ecf20Sopenharmony_ci	if (rc)
17338c2ecf20Sopenharmony_ci		goto free_dev;
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	/* Read irq status register to reset irq line */
17368c2ecf20Sopenharmony_ci	rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status);
17378c2ecf20Sopenharmony_ci	if (rc)
17388c2ecf20Sopenharmony_ci		goto free_dev;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	irq_type = irq_get_trigger_type(spi->irq);
17418c2ecf20Sopenharmony_ci	if (!irq_type)
17428c2ecf20Sopenharmony_ci		irq_type = IRQF_TRIGGER_HIGH;
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	rc = devm_request_irq(&spi->dev, spi->irq, at86rf230_isr,
17458c2ecf20Sopenharmony_ci			      IRQF_SHARED | irq_type, dev_name(&spi->dev), lp);
17468c2ecf20Sopenharmony_ci	if (rc)
17478c2ecf20Sopenharmony_ci		goto free_dev;
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	/* disable_irq by default and wait for starting hardware */
17508c2ecf20Sopenharmony_ci	disable_irq(spi->irq);
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	/* going into sleep by default */
17538c2ecf20Sopenharmony_ci	at86rf230_sleep(lp);
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	at86rf230_debugfs_init(lp);
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	rc = ieee802154_register_hw(lp->hw);
17588c2ecf20Sopenharmony_ci	if (rc)
17598c2ecf20Sopenharmony_ci		goto free_debugfs;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	return rc;
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_cifree_debugfs:
17648c2ecf20Sopenharmony_ci	at86rf230_debugfs_remove();
17658c2ecf20Sopenharmony_cifree_dev:
17668c2ecf20Sopenharmony_ci	ieee802154_free_hw(lp->hw);
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	return rc;
17698c2ecf20Sopenharmony_ci}
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_cistatic int at86rf230_remove(struct spi_device *spi)
17728c2ecf20Sopenharmony_ci{
17738c2ecf20Sopenharmony_ci	struct at86rf230_local *lp = spi_get_drvdata(spi);
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	/* mask all at86rf230 irq's */
17768c2ecf20Sopenharmony_ci	at86rf230_write_subreg(lp, SR_IRQ_MASK, 0);
17778c2ecf20Sopenharmony_ci	ieee802154_unregister_hw(lp->hw);
17788c2ecf20Sopenharmony_ci	ieee802154_free_hw(lp->hw);
17798c2ecf20Sopenharmony_ci	at86rf230_debugfs_remove();
17808c2ecf20Sopenharmony_ci	dev_dbg(&spi->dev, "unregistered at86rf230\n");
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	return 0;
17838c2ecf20Sopenharmony_ci}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_cistatic const struct of_device_id at86rf230_of_match[] = {
17868c2ecf20Sopenharmony_ci	{ .compatible = "atmel,at86rf230", },
17878c2ecf20Sopenharmony_ci	{ .compatible = "atmel,at86rf231", },
17888c2ecf20Sopenharmony_ci	{ .compatible = "atmel,at86rf233", },
17898c2ecf20Sopenharmony_ci	{ .compatible = "atmel,at86rf212", },
17908c2ecf20Sopenharmony_ci	{ },
17918c2ecf20Sopenharmony_ci};
17928c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, at86rf230_of_match);
17938c2ecf20Sopenharmony_ci
17948c2ecf20Sopenharmony_cistatic const struct spi_device_id at86rf230_device_id[] = {
17958c2ecf20Sopenharmony_ci	{ .name = "at86rf230", },
17968c2ecf20Sopenharmony_ci	{ .name = "at86rf231", },
17978c2ecf20Sopenharmony_ci	{ .name = "at86rf233", },
17988c2ecf20Sopenharmony_ci	{ .name = "at86rf212", },
17998c2ecf20Sopenharmony_ci	{ },
18008c2ecf20Sopenharmony_ci};
18018c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, at86rf230_device_id);
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_cistatic struct spi_driver at86rf230_driver = {
18048c2ecf20Sopenharmony_ci	.id_table = at86rf230_device_id,
18058c2ecf20Sopenharmony_ci	.driver = {
18068c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(at86rf230_of_match),
18078c2ecf20Sopenharmony_ci		.name	= "at86rf230",
18088c2ecf20Sopenharmony_ci	},
18098c2ecf20Sopenharmony_ci	.probe      = at86rf230_probe,
18108c2ecf20Sopenharmony_ci	.remove     = at86rf230_remove,
18118c2ecf20Sopenharmony_ci};
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_cimodule_spi_driver(at86rf230_driver);
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AT86RF230 Transceiver Driver");
18168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1817