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