2019-05-27 09:55:21 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-06-26 03:24:53 +04:00
/*
* AT86RF230 / RF231 driver
*
* Copyright ( C ) 2009 - 2012 Siemens AG
*
* Written by :
* Dmitry Eremin - Solenikov < dbaryshkov @ gmail . com >
* Alexander Smirnov < alex . bluesman . smirnov @ gmail . com >
2014-07-03 02:20:55 +04:00
* Alexander Aring < aar @ pengutronix . de >
2012-06-26 03:24:53 +04:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
2015-03-09 15:56:10 +03:00
# include <linux/hrtimer.h>
2015-03-09 15:56:11 +03:00
# include <linux/jiffies.h>
2012-06-26 03:24:53 +04:00
# include <linux/interrupt.h>
2014-04-24 21:09:05 +04:00
# include <linux/irq.h>
2012-06-26 03:24:53 +04:00
# include <linux/gpio.h>
# include <linux/delay.h>
# include <linux/spi/spi.h>
# include <linux/spi/at86rf230.h>
2014-07-03 02:20:44 +04:00
# include <linux/regmap.h>
2012-06-26 03:24:53 +04:00
# include <linux/skbuff.h>
2014-03-15 12:29:07 +04:00
# include <linux/of_gpio.h>
2014-10-25 11:41:04 +04:00
# include <linux/ieee802154.h>
2015-08-27 22:49:19 +03:00
# include <linux/debugfs.h>
2012-06-26 03:24:53 +04:00
# include <net/mac802154.h>
2014-10-25 11:41:02 +04:00
# include <net/cfg802154.h>
2012-06-26 03:24:53 +04:00
2015-05-17 22:44:57 +03:00
# include "at86rf230.h"
2014-07-03 02:20:46 +04:00
struct at86rf230_local ;
/* at86rf2xx chip depend data.
* All timings are in us .
*/
struct at86rf2xx_chip_data {
2014-07-03 02:20:54 +04:00
u16 t_sleep_cycle ;
2014-07-03 02:20:53 +04:00
u16 t_channel_switch ;
2014-07-03 02:20:52 +04:00
u16 t_reset_to_off ;
2014-07-03 02:20:51 +04:00
u16 t_off_to_aack ;
u16 t_off_to_tx_on ;
2015-06-13 23:15:54 +03:00
u16 t_off_to_sleep ;
u16 t_sleep_to_off ;
2014-07-03 02:20:48 +04:00
u16 t_frame ;
u16 t_p_ack ;
2014-07-03 02:20:46 +04:00
int rssi_base_val ;
2014-10-28 20:21:19 +03:00
int ( * set_channel ) ( struct at86rf230_local * , u8 , u8 ) ;
2015-05-17 22:44:49 +03:00
int ( * set_txpower ) ( struct at86rf230_local * , s32 ) ;
2014-07-03 02:20:46 +04:00
} ;
2015-03-01 23:55:28 +03:00
# define AT86RF2XX_MAX_BUF (127 + 3)
/* tx retries to access the TX_ON state
* if it ' s above then force change will be started .
*
* We assume the max_frame_retries ( 7 ) value of 802.15 .4 here .
*/
# define AT86RF2XX_MAX_TX_RETRIES 7
2015-03-09 15:56:11 +03:00
/* We use the recommended 5 minutes timeout to recalibrate */
# define AT86RF2XX_CAL_LOOP_TIMEOUT (5 * 60 * HZ)
2012-06-26 03:24:53 +04:00
2014-07-03 02:20:48 +04:00
struct at86rf230_state_change {
struct at86rf230_local * lp ;
2015-03-01 23:55:31 +03:00
int irq ;
2012-06-26 03:24:53 +04:00
2015-03-09 15:56:10 +03:00
struct hrtimer timer ;
2014-07-03 02:20:48 +04:00
struct spi_message msg ;
struct spi_transfer trx ;
u8 buf [ AT86RF2XX_MAX_BUF ] ;
void ( * complete ) ( void * context ) ;
u8 from_state ;
u8 to_state ;
2014-10-07 12:38:32 +04:00
2015-09-21 10:37:54 +03:00
bool free ;
2014-07-03 02:20:48 +04:00
} ;
2015-08-27 22:49:19 +03:00
struct at86rf230_trac {
u64 success ;
u64 success_data_pending ;
u64 success_wait_for_ack ;
u64 channel_access_failure ;
u64 no_ack ;
u64 invalid ;
} ;
2014-07-03 02:20:48 +04:00
struct at86rf230_local {
struct spi_device * spi ;
2012-06-26 03:24:53 +04:00
2014-10-25 19:16:34 +04:00
struct ieee802154_hw * hw ;
2014-07-03 02:20:48 +04:00
struct at86rf2xx_chip_data * data ;
2014-07-03 02:20:44 +04:00
struct regmap * regmap ;
2015-04-30 18:45:03 +03:00
int slp_tr ;
2015-06-16 12:07:42 +03:00
bool sleep ;
2012-06-26 03:24:53 +04:00
2014-07-03 02:20:51 +04:00
struct completion state_complete ;
struct at86rf230_state_change state ;
2015-03-09 15:56:11 +03:00
unsigned long cal_timeout ;
2014-07-03 02:20:48 +04:00
bool is_tx ;
2015-04-30 18:45:02 +03:00
bool is_tx_from_off ;
2015-03-01 23:55:28 +03:00
u8 tx_retry ;
2014-07-03 02:20:48 +04:00
struct sk_buff * tx_skb ;
struct at86rf230_state_change tx ;
2015-08-27 22:49:19 +03:00
struct at86rf230_trac trac ;
2012-06-26 03:24:53 +04:00
} ;
2014-07-03 02:20:44 +04:00
# define AT86RF2XX_NUMREGS 0x3F
2014-10-07 12:38:32 +04:00
static void
2014-07-03 02:20:48 +04:00
at86rf230_async_state_change ( struct at86rf230_local * lp ,
struct at86rf230_state_change * ctx ,
2015-09-21 10:37:54 +03:00
const u8 state , void ( * complete ) ( void * context ) ) ;
2014-07-03 02:20:48 +04:00
2015-06-16 12:07:42 +03:00
static inline void
at86rf230_sleep ( struct at86rf230_local * lp )
{
if ( gpio_is_valid ( lp - > slp_tr ) ) {
gpio_set_value ( lp - > slp_tr , 1 ) ;
usleep_range ( lp - > data - > t_off_to_sleep ,
lp - > data - > t_off_to_sleep + 10 ) ;
lp - > sleep = true ;
}
}
static inline void
at86rf230_awake ( struct at86rf230_local * lp )
{
if ( gpio_is_valid ( lp - > slp_tr ) ) {
gpio_set_value ( lp - > slp_tr , 0 ) ;
usleep_range ( lp - > data - > t_sleep_to_off ,
lp - > data - > t_sleep_to_off + 100 ) ;
lp - > sleep = false ;
}
}
2014-07-03 02:20:44 +04:00
static inline int
__at86rf230_write ( struct at86rf230_local * lp ,
unsigned int addr , unsigned int data )
{
2015-06-16 12:07:42 +03:00
bool sleep = lp - > sleep ;
int ret ;
/* awake for register setting if sleep */
if ( sleep )
at86rf230_awake ( lp ) ;
ret = regmap_write ( lp - > regmap , addr , data ) ;
/* sleep again if was sleeping */
if ( sleep )
at86rf230_sleep ( lp ) ;
return ret ;
2014-07-03 02:20:44 +04:00
}
static inline int
__at86rf230_read ( struct at86rf230_local * lp ,
unsigned int addr , unsigned int * data )
{
2015-06-16 12:07:42 +03:00
bool sleep = lp - > sleep ;
int ret ;
/* awake for register setting if sleep */
if ( sleep )
at86rf230_awake ( lp ) ;
ret = regmap_read ( lp - > regmap , addr , data ) ;
/* sleep again if was sleeping */
if ( sleep )
at86rf230_sleep ( lp ) ;
return ret ;
2014-07-03 02:20:44 +04:00
}
static inline int
at86rf230_read_subreg ( struct at86rf230_local * lp ,
unsigned int addr , unsigned int mask ,
unsigned int shift , unsigned int * data )
{
int rc ;
rc = __at86rf230_read ( lp , addr , data ) ;
2015-03-17 12:32:39 +03:00
if ( ! rc )
2014-07-03 02:20:44 +04:00
* data = ( * data & mask ) > > shift ;
return rc ;
}
static inline int
at86rf230_write_subreg ( struct at86rf230_local * lp ,
unsigned int addr , unsigned int mask ,
unsigned int shift , unsigned int data )
{
2015-06-16 12:07:42 +03:00
bool sleep = lp - > sleep ;
int ret ;
/* awake for register setting if sleep */
if ( sleep )
at86rf230_awake ( lp ) ;
ret = regmap_update_bits ( lp - > regmap , addr , mask , data < < shift ) ;
/* sleep again if was sleeping */
if ( sleep )
at86rf230_sleep ( lp ) ;
return ret ;
2014-07-03 02:20:44 +04:00
}
2015-04-30 18:45:03 +03:00
static inline void
at86rf230_slp_tr_rising_edge ( struct at86rf230_local * lp )
{
gpio_set_value ( lp - > slp_tr , 1 ) ;
udelay ( 1 ) ;
gpio_set_value ( lp - > slp_tr , 0 ) ;
}
2014-07-03 02:20:44 +04:00
static bool
at86rf230_reg_writeable ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case RG_TRX_STATE :
case RG_TRX_CTRL_0 :
case RG_TRX_CTRL_1 :
case RG_PHY_TX_PWR :
case RG_PHY_ED_LEVEL :
case RG_PHY_CC_CCA :
case RG_CCA_THRES :
case RG_RX_CTRL :
case RG_SFD_VALUE :
case RG_TRX_CTRL_2 :
case RG_ANT_DIV :
case RG_IRQ_MASK :
case RG_VREG_CTRL :
case RG_BATMON :
case RG_XOSC_CTRL :
case RG_RX_SYN :
case RG_XAH_CTRL_1 :
case RG_FTN_CTRL :
case RG_PLL_CF :
case RG_PLL_DCU :
case RG_SHORT_ADDR_0 :
case RG_SHORT_ADDR_1 :
case RG_PAN_ID_0 :
case RG_PAN_ID_1 :
case RG_IEEE_ADDR_0 :
case RG_IEEE_ADDR_1 :
case RG_IEEE_ADDR_2 :
case RG_IEEE_ADDR_3 :
case RG_IEEE_ADDR_4 :
case RG_IEEE_ADDR_5 :
case RG_IEEE_ADDR_6 :
case RG_IEEE_ADDR_7 :
case RG_XAH_CTRL_0 :
case RG_CSMA_SEED_0 :
case RG_CSMA_SEED_1 :
case RG_CSMA_BE :
return true ;
default :
return false ;
}
}
static bool
at86rf230_reg_readable ( struct device * dev , unsigned int reg )
{
bool rc ;
/* all writeable are also readable */
rc = at86rf230_reg_writeable ( dev , reg ) ;
if ( rc )
return rc ;
/* readonly regs */
switch ( reg ) {
case RG_TRX_STATUS :
case RG_PHY_RSSI :
case RG_IRQ_STATUS :
case RG_PART_NUM :
case RG_VERSION_NUM :
case RG_MAN_ID_1 :
case RG_MAN_ID_0 :
return true ;
default :
return false ;
}
}
static bool
at86rf230_reg_volatile ( struct device * dev , unsigned int reg )
{
/* can be changed during runtime */
switch ( reg ) {
case RG_TRX_STATUS :
case RG_TRX_STATE :
case RG_PHY_RSSI :
case RG_PHY_ED_LEVEL :
case RG_IRQ_STATUS :
case RG_VREG_CTRL :
2015-03-09 15:56:12 +03:00
case RG_PLL_CF :
case RG_PLL_DCU :
2014-07-03 02:20:44 +04:00
return true ;
default :
return false ;
}
}
static bool
at86rf230_reg_precious ( struct device * dev , unsigned int reg )
{
/* don't clear irq line on read */
switch ( reg ) {
case RG_IRQ_STATUS :
return true ;
default :
return false ;
}
}
2015-01-05 12:02:31 +03:00
static const struct regmap_config at86rf230_regmap_spi_config = {
2014-07-03 02:20:44 +04:00
. reg_bits = 8 ,
. val_bits = 8 ,
. write_flag_mask = CMD_REG | CMD_WRITE ,
. read_flag_mask = CMD_REG ,
. cache_type = REGCACHE_RBTREE ,
. max_register = AT86RF2XX_NUMREGS ,
. writeable_reg = at86rf230_reg_writeable ,
. readable_reg = at86rf230_reg_readable ,
. volatile_reg = at86rf230_reg_volatile ,
. precious_reg = at86rf230_reg_precious ,
} ;
2014-07-03 02:20:48 +04:00
static void
2016-02-19 11:59:12 +03:00
at86rf230_async_error_recover_complete ( void * context )
2014-07-03 02:20:48 +04:00
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2015-09-21 10:37:54 +03:00
if ( ctx - > free )
kfree ( ctx ) ;
2016-02-19 11:59:12 +03:00
ieee802154_wake_queue ( lp - > hw ) ;
}
static void
at86rf230_async_error_recover ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
lp - > is_tx = 0 ;
at86rf230_async_state_change ( lp , ctx , STATE_RX_AACK_ON ,
at86rf230_async_error_recover_complete ) ;
2014-07-03 02:20:48 +04:00
}
2014-12-15 12:25:54 +03:00
static inline void
2014-07-03 02:20:48 +04:00
at86rf230_async_error ( struct at86rf230_local * lp ,
struct at86rf230_state_change * ctx , int rc )
{
dev_err ( & lp - > spi - > dev , " spi_async error %d \n " , rc ) ;
at86rf230_async_state_change ( lp , ctx , STATE_FORCE_TRX_OFF ,
2015-09-21 10:37:54 +03:00
at86rf230_async_error_recover ) ;
2014-07-03 02:20:48 +04:00
}
/* Generic function to get some register value in async mode */
2014-10-07 12:38:32 +04:00
static void
2015-09-21 10:37:54 +03:00
at86rf230_async_read_reg ( struct at86rf230_local * lp , u8 reg ,
2014-07-03 02:20:48 +04:00
struct at86rf230_state_change * ctx ,
2015-09-21 10:37:54 +03:00
void ( * complete ) ( void * context ) )
2012-06-26 03:24:53 +04:00
{
2014-10-07 12:38:32 +04:00
int rc ;
2014-07-03 02:20:48 +04:00
u8 * tx_buf = ctx - > buf ;
tx_buf [ 0 ] = ( reg & CMD_REG_MASK ) | CMD_REG ;
ctx - > msg . complete = complete ;
2014-10-07 12:38:32 +04:00
rc = spi_async ( lp - > spi , & ctx - > msg ) ;
2015-09-21 10:37:54 +03:00
if ( rc )
at86rf230_async_error ( lp , ctx , rc ) ;
}
2014-10-07 12:38:32 +04:00
2015-09-21 10:37:54 +03:00
static void
at86rf230_async_write_reg ( struct at86rf230_local * lp , u8 reg , u8 val ,
struct at86rf230_state_change * ctx ,
void ( * complete ) ( void * context ) )
{
int rc ;
ctx - > buf [ 0 ] = ( reg & CMD_REG_MASK ) | CMD_REG | CMD_WRITE ;
ctx - > buf [ 1 ] = val ;
ctx - > msg . complete = complete ;
rc = spi_async ( lp - > spi , & ctx - > msg ) ;
if ( rc )
2014-10-07 12:38:32 +04:00
at86rf230_async_error ( lp , ctx , rc ) ;
2014-07-03 02:20:48 +04:00
}
static void
at86rf230_async_state_assert ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
const u8 * buf = ctx - > buf ;
2015-04-30 18:44:56 +03:00
const u8 trx_state = buf [ 1 ] & TRX_STATE_MASK ;
2014-07-03 02:20:48 +04:00
/* Assert state change */
if ( trx_state ! = ctx - > to_state ) {
/* Special handling if transceiver state is in
* STATE_BUSY_RX_AACK and a SHR was detected .
*/
if ( trx_state = = STATE_BUSY_RX_AACK ) {
/* Undocumented race condition. If we send a state
* change to STATE_RX_AACK_ON the transceiver could
* change his state automatically to STATE_BUSY_RX_AACK
* if a SHR was detected . This is not an error , but we
* can ' t assert this .
*/
if ( ctx - > to_state = = STATE_RX_AACK_ON )
goto done ;
/* If we change to STATE_TX_ON without forcing and
* transceiver state is STATE_BUSY_RX_AACK , we wait
* ' tFrame + tPAck ' receiving time . In this time the
* PDU should be received . If the transceiver is still
* in STATE_BUSY_RX_AACK , we run a force state change
* to STATE_TX_ON . This is a timeout handling , if the
* transceiver stucks in STATE_BUSY_RX_AACK .
2015-03-01 23:55:28 +03:00
*
* Additional we do several retries to try to get into
* TX_ON state without forcing . If the retries are
* higher or equal than AT86RF2XX_MAX_TX_RETRIES we
* will do a force change .
2014-07-03 02:20:48 +04:00
*/
2015-03-09 15:56:11 +03:00
if ( ctx - > to_state = = STATE_TX_ON | |
ctx - > to_state = = STATE_TRX_OFF ) {
u8 state = ctx - > to_state ;
2015-03-01 23:55:28 +03:00
if ( lp - > tx_retry > = AT86RF2XX_MAX_TX_RETRIES )
2015-08-27 22:49:18 +03:00
state = STATE_FORCE_TRX_OFF ;
2015-03-01 23:55:28 +03:00
lp - > tx_retry + + ;
at86rf230_async_state_change ( lp , ctx , state ,
2015-09-21 10:37:54 +03:00
ctx - > complete ) ;
2014-07-03 02:20:48 +04:00
return ;
}
}
dev_warn ( & lp - > spi - > dev , " unexcept state change from 0x%02x to 0x%02x. Actual state: 0x%02x \n " ,
ctx - > from_state , ctx - > to_state , trx_state ) ;
}
done :
if ( ctx - > complete )
ctx - > complete ( context ) ;
}
2015-03-09 15:56:10 +03:00
static enum hrtimer_restart at86rf230_async_state_timer ( struct hrtimer * timer )
{
struct at86rf230_state_change * ctx =
container_of ( timer , struct at86rf230_state_change , timer ) ;
struct at86rf230_local * lp = ctx - > lp ;
at86rf230_async_read_reg ( lp , RG_TRX_STATUS , ctx ,
2015-09-21 10:37:54 +03:00
at86rf230_async_state_assert ) ;
2015-03-09 15:56:10 +03:00
return HRTIMER_NORESTART ;
}
2014-07-03 02:20:48 +04:00
/* Do state change timing delay. */
static void
at86rf230_async_state_delay ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
struct at86rf2xx_chip_data * c = lp - > data ;
bool force = false ;
2015-03-09 15:56:10 +03:00
ktime_t tim ;
2014-07-03 02:20:48 +04:00
/* The force state changes are will show as normal states in the
* state status subregister . We change the to_state to the
* corresponding one and remember if it was a force change , this
* differs if we do a state change from STATE_BUSY_RX_AACK .
*/
switch ( ctx - > to_state ) {
case STATE_FORCE_TX_ON :
ctx - > to_state = STATE_TX_ON ;
force = true ;
break ;
case STATE_FORCE_TRX_OFF :
ctx - > to_state = STATE_TRX_OFF ;
force = true ;
break ;
default :
break ;
}
switch ( ctx - > from_state ) {
2014-07-03 02:20:51 +04:00
case STATE_TRX_OFF :
switch ( ctx - > to_state ) {
case STATE_RX_AACK_ON :
2016-12-25 14:30:41 +03:00
tim = c - > t_off_to_aack * NSEC_PER_USEC ;
2015-04-30 18:44:59 +03:00
/* state change from TRX_OFF to RX_AACK_ON to do a
* calibration , we need to reset the timeout for the
* next one .
*/
lp - > cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT ;
2014-07-03 02:20:51 +04:00
goto change ;
2015-04-30 18:45:00 +03:00
case STATE_TX_ARET_ON :
2014-07-03 02:20:51 +04:00
case STATE_TX_ON :
2016-12-25 14:30:41 +03:00
tim = c - > t_off_to_tx_on * NSEC_PER_USEC ;
2015-04-30 18:45:00 +03:00
/* state change from TRX_OFF to TX_ON or ARET_ON to do
* a calibration , we need to reset the timeout for the
2015-03-09 15:56:11 +03:00
* next one .
*/
lp - > cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT ;
2014-07-03 02:20:51 +04:00
goto change ;
default :
break ;
}
break ;
2014-07-03 02:20:48 +04:00
case STATE_BUSY_RX_AACK :
switch ( ctx - > to_state ) {
2015-03-09 15:56:11 +03:00
case STATE_TRX_OFF :
2014-07-03 02:20:48 +04:00
case STATE_TX_ON :
/* Wait for worst case receiving time if we
* didn ' t make a force change from BUSY_RX_AACK
2015-03-09 15:56:11 +03:00
* to TX_ON or TRX_OFF .
2014-07-03 02:20:48 +04:00
*/
if ( ! force ) {
2016-12-25 14:30:41 +03:00
tim = ( c - > t_frame + c - > t_p_ack ) * NSEC_PER_USEC ;
2014-07-03 02:20:48 +04:00
goto change ;
}
break ;
default :
break ;
}
break ;
2014-07-03 02:20:52 +04:00
/* Default value, means RESET state */
case STATE_P_ON :
switch ( ctx - > to_state ) {
case STATE_TRX_OFF :
2016-12-25 14:30:41 +03:00
tim = c - > t_reset_to_off * NSEC_PER_USEC ;
2014-07-03 02:20:52 +04:00
goto change ;
default :
break ;
}
break ;
2014-07-03 02:20:48 +04:00
default :
break ;
}
/* Default delay is 1us in the most cases */
2015-07-30 13:13:29 +03:00
udelay ( 1 ) ;
at86rf230_async_state_timer ( & ctx - > timer ) ;
return ;
2014-07-03 02:20:48 +04:00
change :
2015-03-09 15:56:10 +03:00
hrtimer_start ( & ctx - > timer , tim , HRTIMER_MODE_REL ) ;
2014-07-03 02:20:48 +04:00
}
static void
at86rf230_async_state_change_start ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
u8 * buf = ctx - > buf ;
2015-04-30 18:44:56 +03:00
const u8 trx_state = buf [ 1 ] & TRX_STATE_MASK ;
2014-07-03 02:20:48 +04:00
/* Check for "possible" STATE_TRANSITION_IN_PROGRESS */
if ( trx_state = = STATE_TRANSITION_IN_PROGRESS ) {
udelay ( 1 ) ;
2014-10-07 12:38:32 +04:00
at86rf230_async_read_reg ( lp , RG_TRX_STATUS , ctx ,
2015-09-21 10:37:54 +03:00
at86rf230_async_state_change_start ) ;
2014-07-03 02:20:48 +04:00
return ;
}
/* Check if we already are in the state which we change in */
if ( trx_state = = ctx - > to_state ) {
if ( ctx - > complete )
ctx - > complete ( context ) ;
return ;
}
/* Set current state to the context of state change */
ctx - > from_state = trx_state ;
/* Going into the next step for a state change which do a timing
* relevant delay .
*/
2015-09-21 10:37:54 +03:00
at86rf230_async_write_reg ( lp , RG_TRX_STATE , ctx - > to_state , ctx ,
at86rf230_async_state_delay ) ;
2012-06-26 03:24:53 +04:00
}
2014-10-07 12:38:32 +04:00
static void
2014-07-03 02:20:48 +04:00
at86rf230_async_state_change ( struct at86rf230_local * lp ,
struct at86rf230_state_change * ctx ,
2015-09-21 10:37:54 +03:00
const u8 state , void ( * complete ) ( void * context ) )
2012-06-26 03:24:53 +04:00
{
2014-07-03 02:20:48 +04:00
/* Initialization for the state change context */
ctx - > to_state = state ;
ctx - > complete = complete ;
2014-10-07 12:38:32 +04:00
at86rf230_async_read_reg ( lp , RG_TRX_STATUS , ctx ,
2015-09-21 10:37:54 +03:00
at86rf230_async_state_change_start ) ;
2014-07-03 02:20:48 +04:00
}
2012-06-26 03:24:53 +04:00
2014-07-03 02:20:51 +04:00
static void
at86rf230_sync_state_change_complete ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
complete ( & lp - > state_complete ) ;
}
/* This function do a sync framework above the async state change.
* Some callbacks of the IEEE 802.15 .4 driver interface need to be
* handled synchronously .
*/
static int
at86rf230_sync_state_change ( struct at86rf230_local * lp , unsigned int state )
{
2015-02-15 01:57:48 +03:00
unsigned long rc ;
2014-07-03 02:20:51 +04:00
2014-10-07 12:38:32 +04:00
at86rf230_async_state_change ( lp , & lp - > state , state ,
2015-09-21 10:37:54 +03:00
at86rf230_sync_state_change_complete ) ;
2014-07-03 02:20:51 +04:00
rc = wait_for_completion_timeout ( & lp - > state_complete ,
msecs_to_jiffies ( 100 ) ) ;
2014-10-07 12:38:26 +04:00
if ( ! rc ) {
at86rf230_async_error ( lp , & lp - > state , - ETIMEDOUT ) ;
2014-07-03 02:20:51 +04:00
return - ETIMEDOUT ;
2014-10-07 12:38:26 +04:00
}
2014-07-03 02:20:51 +04:00
return 0 ;
}
2014-07-03 02:20:48 +04:00
static void
at86rf230_tx_complete ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2015-08-10 22:15:57 +03:00
ieee802154_xmit_complete ( lp - > hw , lp - > tx_skb , false ) ;
2015-09-21 10:37:54 +03:00
kfree ( ctx ) ;
2014-07-03 02:20:48 +04:00
}
static void
at86rf230_tx_on ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2015-03-01 23:55:32 +03:00
at86rf230_async_state_change ( lp , ctx , STATE_RX_AACK_ON ,
2015-09-21 10:37:54 +03:00
at86rf230_tx_complete ) ;
2014-07-03 02:20:48 +04:00
}
static void
at86rf230_tx_trac_check ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2015-08-27 22:49:19 +03:00
if ( IS_ENABLED ( CONFIG_IEEE802154_AT86RF230_DEBUGFS ) ) {
u8 trac = TRAC_MASK ( ctx - > buf [ 1 ] ) ;
switch ( trac ) {
case TRAC_SUCCESS :
lp - > trac . success + + ;
break ;
case TRAC_SUCCESS_DATA_PENDING :
lp - > trac . success_data_pending + + ;
break ;
case TRAC_CHANNEL_ACCESS_FAILURE :
lp - > trac . channel_access_failure + + ;
break ;
case TRAC_NO_ACK :
lp - > trac . no_ack + + ;
break ;
case TRAC_INVALID :
lp - > trac . invalid + + ;
break ;
default :
WARN_ONCE ( 1 , " received tx trac status %d \n " , trac ) ;
break ;
}
}
2015-09-21 10:37:54 +03:00
at86rf230_async_state_change ( lp , ctx , STATE_TX_ON , at86rf230_tx_on ) ;
2014-07-03 02:20:48 +04:00
}
static void
2015-03-01 23:55:30 +03:00
at86rf230_rx_read_frame_complete ( void * context )
2014-07-03 02:20:48 +04:00
{
2015-03-01 23:55:30 +03:00
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2015-03-01 23:55:32 +03:00
const u8 * buf = ctx - > buf ;
2015-03-01 23:55:30 +03:00
struct sk_buff * skb ;
u8 len , lqi ;
2014-07-03 02:20:48 +04:00
2015-03-01 23:55:30 +03:00
len = buf [ 1 ] ;
if ( ! ieee802154_is_valid_psdu_len ( len ) ) {
dev_vdbg ( & lp - > spi - > dev , " corrupted frame received \n " ) ;
len = IEEE802154_MTU ;
}
lqi = buf [ 2 + len ] ;
2014-10-27 19:13:29 +03:00
skb = dev_alloc_skb ( IEEE802154_MTU ) ;
2014-07-03 02:20:48 +04:00
if ( ! skb ) {
dev_vdbg ( & lp - > spi - > dev , " failed to allocate sk_buff \n " ) ;
2015-09-21 10:37:54 +03:00
kfree ( ctx ) ;
2014-07-03 02:20:48 +04:00
return ;
}
networking: introduce and use skb_put_data()
A common pattern with skb_put() is to just want to memcpy()
some data into the new space, introduce skb_put_data() for
this.
An spatch similar to the one for skb_put_zero() converts many
of the places using it:
@@
identifier p, p2;
expression len, skb, data;
type t, t2;
@@
(
-p = skb_put(skb, len);
+p = skb_put_data(skb, data, len);
|
-p = (t)skb_put(skb, len);
+p = skb_put_data(skb, data, len);
)
(
p2 = (t2)p;
-memcpy(p2, data, len);
|
-memcpy(p, data, len);
)
@@
type t, t2;
identifier p, p2;
expression skb, data;
@@
t *p;
...
(
-p = skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
|
-p = (t *)skb_put(skb, sizeof(t));
+p = skb_put_data(skb, data, sizeof(t));
)
(
p2 = (t2)p;
-memcpy(p2, data, sizeof(*p));
|
-memcpy(p, data, sizeof(*p));
)
@@
expression skb, len, data;
@@
-memcpy(skb_put(skb, len), data, len);
+skb_put_data(skb, data, len);
(again, manually post-processed to retain some comments)
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2017-06-16 15:29:20 +03:00
skb_put_data ( skb , buf + 2 , len ) ;
2014-10-27 19:13:42 +03:00
ieee802154_rx_irqsafe ( lp - > hw , skb , lqi ) ;
2015-09-21 10:37:54 +03:00
kfree ( ctx ) ;
2014-07-03 02:20:48 +04:00
}
2012-06-26 03:24:53 +04:00
2014-10-07 12:38:32 +04:00
static void
2015-08-27 22:49:19 +03:00
at86rf230_rx_trac_check ( void * context )
2014-07-03 02:20:48 +04:00
{
2015-03-01 23:55:31 +03:00
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2015-03-01 23:55:32 +03:00
u8 * buf = ctx - > buf ;
2014-10-07 12:38:32 +04:00
int rc ;
2015-08-27 22:49:19 +03:00
if ( IS_ENABLED ( CONFIG_IEEE802154_AT86RF230_DEBUGFS ) ) {
u8 trac = TRAC_MASK ( buf [ 1 ] ) ;
switch ( trac ) {
case TRAC_SUCCESS :
lp - > trac . success + + ;
break ;
case TRAC_SUCCESS_WAIT_FOR_ACK :
lp - > trac . success_wait_for_ack + + ;
break ;
case TRAC_INVALID :
lp - > trac . invalid + + ;
break ;
default :
WARN_ONCE ( 1 , " received rx trac status %d \n " , trac ) ;
break ;
}
}
2012-06-26 03:24:53 +04:00
buf [ 0 ] = CMD_FB ;
2015-03-01 23:55:32 +03:00
ctx - > trx . len = AT86RF2XX_MAX_BUF ;
ctx - > msg . complete = at86rf230_rx_read_frame_complete ;
rc = spi_async ( lp - > spi , & ctx - > msg ) ;
2014-10-07 12:38:32 +04:00
if ( rc ) {
2015-03-01 23:55:33 +03:00
ctx - > trx . len = 2 ;
2015-03-01 23:55:32 +03:00
at86rf230_async_error ( lp , ctx , rc ) ;
2014-10-07 12:38:32 +04:00
}
2014-07-03 02:20:48 +04:00
}
2014-10-07 12:38:32 +04:00
static void
2015-09-21 10:37:54 +03:00
at86rf230_irq_trx_end ( void * context )
2014-07-03 02:20:48 +04:00
{
2015-09-21 10:37:54 +03:00
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2014-07-03 02:20:48 +04:00
if ( lp - > is_tx ) {
lp - > is_tx = 0 ;
2015-09-21 10:37:54 +03:00
at86rf230_async_read_reg ( lp , RG_TRX_STATE , ctx ,
at86rf230_tx_trac_check ) ;
2014-07-03 02:20:48 +04:00
} else {
2015-09-21 10:37:54 +03:00
at86rf230_async_read_reg ( lp , RG_TRX_STATE , ctx ,
at86rf230_rx_trac_check ) ;
2014-07-03 02:20:48 +04:00
}
}
static void
at86rf230_irq_status ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2015-03-01 23:55:32 +03:00
const u8 * buf = ctx - > buf ;
2015-09-21 10:37:54 +03:00
u8 irq = buf [ 1 ] ;
enable_irq ( lp - > spi - > irq ) ;
2014-07-03 02:20:48 +04:00
if ( irq & IRQ_TRX_END ) {
2015-09-21 10:37:54 +03:00
at86rf230_irq_trx_end ( ctx ) ;
2014-07-03 02:20:48 +04:00
} else {
dev_err ( & lp - > spi - > dev , " not supported irq %02x received \n " ,
irq ) ;
2015-09-21 10:37:54 +03:00
kfree ( ctx ) ;
2014-07-03 02:20:48 +04:00
}
}
2015-09-21 10:37:54 +03:00
static void
at86rf230_setup_spi_messages ( struct at86rf230_local * lp ,
struct at86rf230_state_change * state )
{
state - > lp = lp ;
state - > irq = lp - > spi - > irq ;
spi_message_init ( & state - > msg ) ;
state - > msg . context = state ;
state - > trx . len = 2 ;
state - > trx . tx_buf = state - > buf ;
state - > trx . rx_buf = state - > buf ;
spi_message_add_tail ( & state - > trx , & state - > msg ) ;
hrtimer_init ( & state - > timer , CLOCK_MONOTONIC , HRTIMER_MODE_REL ) ;
state - > timer . function = at86rf230_async_state_timer ;
}
2014-07-03 02:20:48 +04:00
static irqreturn_t at86rf230_isr ( int irq , void * data )
{
struct at86rf230_local * lp = data ;
2015-09-21 10:37:54 +03:00
struct at86rf230_state_change * ctx ;
2014-07-03 02:20:48 +04:00
int rc ;
2014-10-07 12:38:29 +04:00
disable_irq_nosync ( irq ) ;
2014-07-03 02:20:48 +04:00
2015-09-21 10:37:54 +03:00
ctx = kzalloc ( sizeof ( * ctx ) , GFP_ATOMIC ) ;
if ( ! ctx ) {
enable_irq ( irq ) ;
return IRQ_NONE ;
}
at86rf230_setup_spi_messages ( lp , ctx ) ;
/* tell on error handling to free ctx */
ctx - > free = true ;
ctx - > buf [ 0 ] = ( RG_IRQ_STATUS & CMD_REG_MASK ) | CMD_REG ;
2014-07-03 02:20:48 +04:00
ctx - > msg . complete = at86rf230_irq_status ;
rc = spi_async ( lp - > spi , & ctx - > msg ) ;
if ( rc ) {
at86rf230_async_error ( lp , ctx , rc ) ;
2015-09-21 10:37:54 +03:00
enable_irq ( irq ) ;
2014-07-03 02:20:48 +04:00
return IRQ_NONE ;
}
return IRQ_HANDLED ;
}
static void
at86rf230_write_frame_complete ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
ctx - > trx . len = 2 ;
2015-04-30 18:45:03 +03:00
2015-09-21 10:37:54 +03:00
if ( gpio_is_valid ( lp - > slp_tr ) )
2015-04-30 18:45:03 +03:00
at86rf230_slp_tr_rising_edge ( lp ) ;
2015-09-21 10:37:54 +03:00
else
at86rf230_async_write_reg ( lp , RG_TRX_STATE , STATE_BUSY_TX , ctx ,
NULL ) ;
2014-07-03 02:20:48 +04:00
}
static void
at86rf230_write_frame ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
struct sk_buff * skb = lp - > tx_skb ;
2015-03-01 23:55:32 +03:00
u8 * buf = ctx - > buf ;
2014-07-03 02:20:48 +04:00
int rc ;
lp - > is_tx = 1 ;
buf [ 0 ] = CMD_FB | CMD_WRITE ;
buf [ 1 ] = skb - > len + 2 ;
memcpy ( buf + 2 , skb - > data , skb - > len ) ;
2015-03-01 23:55:32 +03:00
ctx - > trx . len = skb - > len + 2 ;
ctx - > msg . complete = at86rf230_write_frame_complete ;
rc = spi_async ( lp - > spi , & ctx - > msg ) ;
2015-03-01 23:55:33 +03:00
if ( rc ) {
ctx - > trx . len = 2 ;
2014-07-03 02:20:48 +04:00
at86rf230_async_error ( lp , ctx , rc ) ;
2015-03-01 23:55:33 +03:00
}
2014-07-03 02:20:48 +04:00
}
static void
at86rf230_xmit_tx_on ( void * context )
{
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2012-06-26 03:24:53 +04:00
2014-10-07 12:38:32 +04:00
at86rf230_async_state_change ( lp , ctx , STATE_TX_ARET_ON ,
2015-09-21 10:37:54 +03:00
at86rf230_write_frame ) ;
2014-07-03 02:20:48 +04:00
}
2015-03-09 15:56:11 +03:00
static void
at86rf230_xmit_start ( void * context )
2014-07-03 02:20:48 +04:00
{
2015-03-09 15:56:11 +03:00
struct at86rf230_state_change * ctx = context ;
struct at86rf230_local * lp = ctx - > lp ;
2012-06-26 03:24:53 +04:00
2015-08-10 22:15:57 +03:00
/* check if we change from off state */
2016-02-19 11:59:13 +03:00
if ( lp - > is_tx_from_off )
2015-08-10 22:15:57 +03:00
at86rf230_async_state_change ( lp , ctx , STATE_TX_ARET_ON ,
2015-09-21 10:37:54 +03:00
at86rf230_write_frame ) ;
2016-02-19 11:59:13 +03:00
else
2015-03-09 15:56:11 +03:00
at86rf230_async_state_change ( lp , ctx , STATE_TX_ON ,
2015-09-21 10:37:54 +03:00
at86rf230_xmit_tx_on ) ;
2015-03-09 15:56:11 +03:00
}
static int
at86rf230_xmit ( struct ieee802154_hw * hw , struct sk_buff * skb )
{
struct at86rf230_local * lp = hw - > priv ;
struct at86rf230_state_change * ctx = & lp - > tx ;
2012-06-26 03:24:53 +04:00
2015-03-09 15:56:11 +03:00
lp - > tx_skb = skb ;
2015-03-01 23:55:28 +03:00
lp - > tx_retry = 0 ;
2015-03-09 15:56:11 +03:00
/* After 5 minutes in PLL and the same frequency we run again the
* calibration loops which is recommended by at86rf2xx datasheets .
*
* The calibration is initiate by a state change from TRX_OFF
* to TX_ON , the lp - > cal_timeout should be reinit by state_delay
* function then to start in the next 5 minutes .
*/
2015-04-30 18:45:02 +03:00
if ( time_is_before_jiffies ( lp - > cal_timeout ) ) {
lp - > is_tx_from_off = true ;
2015-03-09 15:56:11 +03:00
at86rf230_async_state_change ( lp , ctx , STATE_TRX_OFF ,
2015-09-21 10:37:54 +03:00
at86rf230_xmit_start ) ;
2015-04-30 18:45:02 +03:00
} else {
2016-02-19 11:59:13 +03:00
lp - > is_tx_from_off = false ;
2015-03-09 15:56:11 +03:00
at86rf230_xmit_start ( ctx ) ;
2015-04-30 18:45:02 +03:00
}
2014-10-07 12:38:32 +04:00
2014-07-03 02:20:48 +04:00
return 0 ;
2012-06-26 03:24:53 +04:00
}
static int
2014-10-25 19:16:34 +04:00
at86rf230_ed ( struct ieee802154_hw * hw , u8 * level )
2012-06-26 03:24:53 +04:00
{
2017-09-22 15:13:53 +03:00
WARN_ON ( ! level ) ;
2012-06-26 03:24:53 +04:00
* level = 0xbe ;
return 0 ;
}
static int
2014-10-25 19:16:34 +04:00
at86rf230_start ( struct ieee802154_hw * hw )
2012-06-26 03:24:53 +04:00
{
2015-06-13 23:15:54 +03:00
struct at86rf230_local * lp = hw - > priv ;
2015-08-27 22:49:19 +03:00
/* reset trac stats on start */
if ( IS_ENABLED ( CONFIG_IEEE802154_AT86RF230_DEBUGFS ) )
memset ( & lp - > trac , 0 , sizeof ( struct at86rf230_trac ) ) ;
2015-06-16 12:07:42 +03:00
at86rf230_awake ( lp ) ;
2015-06-13 23:15:54 +03:00
enable_irq ( lp - > spi - > irq ) ;
2015-06-16 12:07:44 +03:00
return at86rf230_sync_state_change ( lp , STATE_RX_AACK_ON ) ;
2012-06-26 03:24:53 +04:00
}
static void
2014-10-25 19:16:34 +04:00
at86rf230_stop ( struct ieee802154_hw * hw )
2012-06-26 03:24:53 +04:00
{
2015-06-13 23:15:54 +03:00
struct at86rf230_local * lp = hw - > priv ;
2015-06-16 12:07:43 +03:00
u8 csma_seed [ 2 ] ;
2015-06-13 23:15:54 +03:00
2015-06-16 12:07:44 +03:00
at86rf230_sync_state_change ( lp , STATE_FORCE_TRX_OFF ) ;
2015-06-13 23:15:54 +03:00
disable_irq ( lp - > spi - > irq ) ;
2015-06-16 12:07:43 +03:00
/* It's recommended to set random new csma_seeds before sleep state.
* Makes only sense in the stop callback , not doing this inside of
* at86rf230_sleep , this is also used when we don ' t transmit afterwards
* when calling start callback again .
*/
get_random_bytes ( csma_seed , ARRAY_SIZE ( csma_seed ) ) ;
at86rf230_write_subreg ( lp , SR_CSMA_SEED_0 , csma_seed [ 0 ] ) ;
at86rf230_write_subreg ( lp , SR_CSMA_SEED_1 , csma_seed [ 1 ] ) ;
2015-06-16 12:07:42 +03:00
at86rf230_sleep ( lp ) ;
2012-06-26 03:24:53 +04:00
}
2014-02-17 14:34:06 +04:00
static int
2014-10-28 20:21:19 +03:00
at86rf23x_set_channel ( struct at86rf230_local * lp , u8 page , u8 channel )
2014-02-17 14:34:06 +04:00
{
return at86rf230_write_subreg ( lp , SR_CHANNEL , channel ) ;
}
2015-05-17 22:44:50 +03:00
# define AT86RF2XX_MAX_ED_LEVELS 0xF
2016-09-06 10:50:04 +03:00
static const s32 at86rf233_ed_levels [ AT86RF2XX_MAX_ED_LEVELS + 1 ] = {
- 9400 , - 9200 , - 9000 , - 8800 , - 8600 , - 8400 , - 8200 , - 8000 , - 7800 , - 7600 ,
- 7400 , - 7200 , - 7000 , - 6800 , - 6600 , - 6400 ,
} ;
static const s32 at86rf231_ed_levels [ AT86RF2XX_MAX_ED_LEVELS + 1 ] = {
2015-05-17 22:44:50 +03:00
- 9100 , - 8900 , - 8700 , - 8500 , - 8300 , - 8100 , - 7900 , - 7700 , - 7500 , - 7300 ,
- 7100 , - 6900 , - 6700 , - 6500 , - 6300 , - 6100 ,
} ;
static const s32 at86rf212_ed_levels_100 [ AT86RF2XX_MAX_ED_LEVELS + 1 ] = {
- 10000 , - 9800 , - 9600 , - 9400 , - 9200 , - 9000 , - 8800 , - 8600 , - 8400 , - 8200 ,
2015-05-20 10:27:03 +03:00
- 8000 , - 7800 , - 7600 , - 7400 , - 7200 , - 7000 ,
2015-05-17 22:44:50 +03:00
} ;
static const s32 at86rf212_ed_levels_98 [ AT86RF2XX_MAX_ED_LEVELS + 1 ] = {
- 9800 , - 9600 , - 9400 , - 9200 , - 9000 , - 8800 , - 8600 , - 8400 , - 8200 , - 8000 ,
2015-05-20 10:27:03 +03:00
- 7800 , - 7600 , - 7400 , - 7200 , - 7000 , - 6800 ,
2015-05-17 22:44:50 +03:00
} ;
static inline int
at86rf212_update_cca_ed_level ( struct at86rf230_local * lp , int rssi_base_val )
{
unsigned int cca_ed_thres ;
int rc ;
rc = at86rf230_read_subreg ( lp , SR_CCA_ED_THRES , & cca_ed_thres ) ;
if ( rc < 0 )
return rc ;
switch ( rssi_base_val ) {
case - 98 :
lp - > hw - > phy - > supported . cca_ed_levels = at86rf212_ed_levels_98 ;
lp - > hw - > phy - > supported . cca_ed_levels_size = ARRAY_SIZE ( at86rf212_ed_levels_98 ) ;
lp - > hw - > phy - > cca_ed_level = at86rf212_ed_levels_98 [ cca_ed_thres ] ;
break ;
case - 100 :
lp - > hw - > phy - > supported . cca_ed_levels = at86rf212_ed_levels_100 ;
lp - > hw - > phy - > supported . cca_ed_levels_size = ARRAY_SIZE ( at86rf212_ed_levels_100 ) ;
lp - > hw - > phy - > cca_ed_level = at86rf212_ed_levels_100 [ cca_ed_thres ] ;
break ;
default :
WARN_ON ( 1 ) ;
}
return 0 ;
}
2014-02-17 14:34:06 +04:00
static int
2014-10-28 20:21:19 +03:00
at86rf212_set_channel ( struct at86rf230_local * lp , u8 page , u8 channel )
2014-02-17 14:34:06 +04:00
{
int rc ;
if ( channel = = 0 )
rc = at86rf230_write_subreg ( lp , SR_SUB_MODE , 0 ) ;
else
rc = at86rf230_write_subreg ( lp , SR_SUB_MODE , 1 ) ;
if ( rc < 0 )
return rc ;
2014-02-17 14:34:12 +04:00
if ( page = = 0 ) {
2014-02-17 14:34:09 +04:00
rc = at86rf230_write_subreg ( lp , SR_BPSK_QPSK , 0 ) ;
2014-07-03 02:20:46 +04:00
lp - > data - > rssi_base_val = - 100 ;
2014-02-17 14:34:12 +04:00
} else {
2014-02-17 14:34:09 +04:00
rc = at86rf230_write_subreg ( lp , SR_BPSK_QPSK , 1 ) ;
2014-07-03 02:20:46 +04:00
lp - > data - > rssi_base_val = - 98 ;
2014-02-17 14:34:12 +04:00
}
2014-02-17 14:34:09 +04:00
if ( rc < 0 )
return rc ;
2015-05-17 22:44:50 +03:00
rc = at86rf212_update_cca_ed_level ( lp , lp - > data - > rssi_base_val ) ;
if ( rc < 0 )
return rc ;
2014-11-12 21:51:57 +03:00
/* This sets the symbol_duration according frequency on the 212.
* TODO move this handling while set channel and page in cfg802154 .
* We can do that , this timings are according 802.15 .4 standard .
* If we do that in cfg802154 , this is a more generic calculation .
*
* This should also protected from ifs_timer . Means cancel timer and
* init with a new value . For now , this is okay .
*/
if ( channel = = 0 ) {
if ( page = = 0 ) {
/* SUB:0 and BPSK:0 -> BPSK-20 */
lp - > hw - > phy - > symbol_duration = 50 ;
} else {
/* SUB:1 and BPSK:0 -> BPSK-40 */
lp - > hw - > phy - > symbol_duration = 25 ;
}
} else {
if ( page = = 0 )
2014-11-17 10:20:44 +03:00
/* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
2014-11-12 21:51:57 +03:00
lp - > hw - > phy - > symbol_duration = 40 ;
else
2014-11-17 10:20:44 +03:00
/* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
2014-11-12 21:51:57 +03:00
lp - > hw - > phy - > symbol_duration = 16 ;
}
lp - > hw - > phy - > lifs_period = IEEE802154_LIFS_PERIOD *
lp - > hw - > phy - > symbol_duration ;
lp - > hw - > phy - > sifs_period = IEEE802154_SIFS_PERIOD *
lp - > hw - > phy - > symbol_duration ;
2014-02-17 14:34:06 +04:00
return at86rf230_write_subreg ( lp , SR_CHANNEL , channel ) ;
}
2012-06-26 03:24:53 +04:00
static int
2014-10-28 20:21:19 +03:00
at86rf230_channel ( struct ieee802154_hw * hw , u8 page , u8 channel )
2012-06-26 03:24:53 +04:00
{
2014-10-25 19:16:34 +04:00
struct at86rf230_local * lp = hw - > priv ;
2012-06-26 03:24:53 +04:00
int rc ;
2014-07-03 02:20:46 +04:00
rc = lp - > data - > set_channel ( lp , page , channel ) ;
2014-07-03 02:20:53 +04:00
/* Wait for PLL */
usleep_range ( lp - > data - > t_channel_switch ,
lp - > data - > t_channel_switch + 10 ) ;
2015-03-09 15:56:11 +03:00
lp - > cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT ;
2014-11-12 05:36:56 +03:00
return rc ;
2012-06-26 03:24:53 +04:00
}
2013-03-26 16:41:30 +04:00
static int
2014-10-25 19:16:34 +04:00
at86rf230_set_hw_addr_filt ( struct ieee802154_hw * hw ,
2013-03-26 16:41:30 +04:00
struct ieee802154_hw_addr_filt * filt ,
unsigned long changed )
{
2014-10-25 19:16:34 +04:00
struct at86rf230_local * lp = hw - > priv ;
2013-03-26 16:41:30 +04:00
2014-10-25 07:25:09 +04:00
if ( changed & IEEE802154_AFILT_SADDR_CHANGED ) {
2014-03-15 00:23:59 +04:00
u16 addr = le16_to_cpu ( filt - > short_addr ) ;
2017-09-22 15:13:54 +03:00
dev_vdbg ( & lp - > spi - > dev , " %s called for saddr \n " , __func__ ) ;
2014-03-15 00:23:59 +04:00
__at86rf230_write ( lp , RG_SHORT_ADDR_0 , addr ) ;
__at86rf230_write ( lp , RG_SHORT_ADDR_1 , addr > > 8 ) ;
2013-03-26 16:41:30 +04:00
}
2014-10-25 07:25:09 +04:00
if ( changed & IEEE802154_AFILT_PANID_CHANGED ) {
2014-03-15 00:23:59 +04:00
u16 pan = le16_to_cpu ( filt - > pan_id ) ;
2017-09-22 15:13:54 +03:00
dev_vdbg ( & lp - > spi - > dev , " %s called for pan id \n " , __func__ ) ;
2014-03-15 00:23:59 +04:00
__at86rf230_write ( lp , RG_PAN_ID_0 , pan ) ;
__at86rf230_write ( lp , RG_PAN_ID_1 , pan > > 8 ) ;
2013-03-26 16:41:30 +04:00
}
2014-10-25 07:25:09 +04:00
if ( changed & IEEE802154_AFILT_IEEEADDR_CHANGED ) {
2014-03-15 00:23:59 +04:00
u8 i , addr [ 8 ] ;
memcpy ( addr , & filt - > ieee_addr , 8 ) ;
2017-09-22 15:13:54 +03:00
dev_vdbg ( & lp - > spi - > dev , " %s called for IEEE addr \n " , __func__ ) ;
2014-03-15 00:23:59 +04:00
for ( i = 0 ; i < 8 ; i + + )
__at86rf230_write ( lp , RG_IEEE_ADDR_0 + i , addr [ i ] ) ;
2013-03-26 16:41:30 +04:00
}
2014-10-25 07:25:09 +04:00
if ( changed & IEEE802154_AFILT_PANC_CHANGED ) {
2017-09-22 15:13:54 +03:00
dev_vdbg ( & lp - > spi - > dev , " %s called for panc change \n " , __func__ ) ;
2013-03-26 16:41:30 +04:00
if ( filt - > pan_coord )
at86rf230_write_subreg ( lp , SR_AACK_I_AM_COORD , 1 ) ;
else
at86rf230_write_subreg ( lp , SR_AACK_I_AM_COORD , 0 ) ;
}
return 0 ;
}
2015-05-17 22:44:49 +03:00
# define AT86RF23X_MAX_TX_POWERS 0xF
static const s32 at86rf233_powers [ AT86RF23X_MAX_TX_POWERS + 1 ] = {
400 , 370 , 340 , 300 , 250 , 200 , 100 , 0 , - 100 , - 200 , - 300 , - 400 , - 600 ,
- 800 , - 1200 , - 1700 ,
} ;
static const s32 at86rf231_powers [ AT86RF23X_MAX_TX_POWERS + 1 ] = {
300 , 280 , 230 , 180 , 130 , 70 , 0 , - 100 , - 200 , - 300 , - 400 , - 500 , - 700 ,
- 900 , - 1200 , - 1700 ,
} ;
# define AT86RF212_MAX_TX_POWERS 0x1F
static const s32 at86rf212_powers [ AT86RF212_MAX_TX_POWERS + 1 ] = {
500 , 400 , 300 , 200 , 100 , 0 , - 100 , - 200 , - 300 , - 400 , - 500 , - 600 , - 700 ,
- 800 , - 900 , - 1000 , - 1100 , - 1200 , - 1300 , - 1400 , - 1500 , - 1600 , - 1700 ,
- 1800 , - 1900 , - 2000 , - 2100 , - 2200 , - 2300 , - 2400 , - 2500 , - 2600 ,
} ;
2014-02-17 14:34:08 +04:00
static int
2015-05-17 22:44:49 +03:00
at86rf23x_set_txpower ( struct at86rf230_local * lp , s32 mbm )
2014-02-17 14:34:08 +04:00
{
2015-05-17 22:44:49 +03:00
u32 i ;
2014-02-17 14:34:08 +04:00
2015-05-17 22:44:49 +03:00
for ( i = 0 ; i < lp - > hw - > phy - > supported . tx_powers_size ; i + + ) {
if ( lp - > hw - > phy - > supported . tx_powers [ i ] = = mbm )
return at86rf230_write_subreg ( lp , SR_TX_PWR_23X , i ) ;
}
return - EINVAL ;
}
static int
at86rf212_set_txpower ( struct at86rf230_local * lp , s32 mbm )
{
u32 i ;
for ( i = 0 ; i < lp - > hw - > phy - > supported . tx_powers_size ; i + + ) {
if ( lp - > hw - > phy - > supported . tx_powers [ i ] = = mbm )
return at86rf230_write_subreg ( lp , SR_TX_PWR_212 , i ) ;
}
2014-02-17 14:34:08 +04:00
2015-05-17 22:44:49 +03:00
return - EINVAL ;
}
static int
at86rf230_set_txpower ( struct ieee802154_hw * hw , s32 mbm )
{
struct at86rf230_local * lp = hw - > priv ;
2014-02-17 14:34:08 +04:00
2015-05-17 22:44:49 +03:00
return lp - > data - > set_txpower ( lp , mbm ) ;
2014-02-17 14:34:08 +04:00
}
2014-02-17 14:34:10 +04:00
static int
2014-10-25 19:16:34 +04:00
at86rf230_set_lbt ( struct ieee802154_hw * hw , bool on )
2014-02-17 14:34:10 +04:00
{
2014-10-25 19:16:34 +04:00
struct at86rf230_local * lp = hw - > priv ;
2014-02-17 14:34:10 +04:00
return at86rf230_write_subreg ( lp , SR_CSMA_LBT_MODE , on ) ;
}
2014-02-17 14:34:11 +04:00
static int
2014-12-10 17:33:12 +03:00
at86rf230_set_cca_mode ( struct ieee802154_hw * hw ,
const struct wpan_phy_cca * cca )
2014-02-17 14:34:11 +04:00
{
2014-10-25 19:16:34 +04:00
struct at86rf230_local * lp = hw - > priv ;
2014-12-10 17:33:12 +03:00
u8 val ;
2014-02-17 14:34:11 +04:00
2014-12-10 17:33:12 +03:00
/* mapping 802.15.4 to driver spec */
switch ( cca - > mode ) {
case NL802154_CCA_ENERGY :
val = 1 ;
break ;
case NL802154_CCA_CARRIER :
val = 2 ;
break ;
case NL802154_CCA_ENERGY_CARRIER :
switch ( cca - > opt ) {
case NL802154_CCA_OPT_ENERGY_CARRIER_AND :
val = 3 ;
break ;
case NL802154_CCA_OPT_ENERGY_CARRIER_OR :
val = 0 ;
break ;
default :
return - EINVAL ;
}
break ;
default :
return - EINVAL ;
}
return at86rf230_write_subreg ( lp , SR_CCA_MODE , val ) ;
2014-02-17 14:34:11 +04:00
}
2014-02-17 14:34:12 +04:00
static int
2015-05-17 22:44:41 +03:00
at86rf230_set_cca_ed_level ( struct ieee802154_hw * hw , s32 mbm )
2014-02-17 14:34:12 +04:00
{
2014-10-25 19:16:34 +04:00
struct at86rf230_local * lp = hw - > priv ;
2015-05-17 22:44:50 +03:00
u32 i ;
2014-02-17 14:34:12 +04:00
2015-05-17 22:44:50 +03:00
for ( i = 0 ; i < hw - > phy - > supported . cca_ed_levels_size ; i + + ) {
if ( hw - > phy - > supported . cca_ed_levels [ i ] = = mbm )
return at86rf230_write_subreg ( lp , SR_CCA_ED_THRES , i ) ;
}
2014-02-17 14:34:12 +04:00
2015-05-17 22:44:50 +03:00
return - EINVAL ;
2014-02-17 14:34:12 +04:00
}
2014-02-17 14:34:15 +04:00
static int
2014-10-25 19:16:34 +04:00
at86rf230_set_csma_params ( struct ieee802154_hw * hw , u8 min_be , u8 max_be ,
2014-02-17 14:34:15 +04:00
u8 retries )
{
2014-10-25 19:16:34 +04:00
struct at86rf230_local * lp = hw - > priv ;
2014-02-17 14:34:15 +04:00
int rc ;
rc = at86rf230_write_subreg ( lp , SR_MIN_BE , min_be ) ;
if ( rc )
return rc ;
rc = at86rf230_write_subreg ( lp , SR_MAX_BE , max_be ) ;
if ( rc )
return rc ;
2014-04-05 15:49:26 +04:00
return at86rf230_write_subreg ( lp , SR_MAX_CSMA_RETRIES , retries ) ;
2014-02-17 14:34:15 +04:00
}
static int
2014-10-25 19:16:34 +04:00
at86rf230_set_frame_retries ( struct ieee802154_hw * hw , s8 retries )
2014-02-17 14:34:15 +04:00
{
2014-10-25 19:16:34 +04:00
struct at86rf230_local * lp = hw - > priv ;
2014-02-17 14:34:15 +04:00
2015-08-10 22:15:57 +03:00
return at86rf230_write_subreg ( lp , SR_MAX_FRAME_RETRIES , retries ) ;
2014-02-17 14:34:15 +04:00
}
2014-10-29 23:34:33 +03:00
static int
at86rf230_set_promiscuous_mode ( struct ieee802154_hw * hw , const bool on )
{
struct at86rf230_local * lp = hw - > priv ;
int rc ;
if ( on ) {
rc = at86rf230_write_subreg ( lp , SR_AACK_DIS_ACK , 1 ) ;
if ( rc < 0 )
return rc ;
rc = at86rf230_write_subreg ( lp , SR_AACK_PROM_MODE , 1 ) ;
if ( rc < 0 )
return rc ;
} else {
rc = at86rf230_write_subreg ( lp , SR_AACK_PROM_MODE , 0 ) ;
if ( rc < 0 )
return rc ;
rc = at86rf230_write_subreg ( lp , SR_AACK_DIS_ACK , 0 ) ;
if ( rc < 0 )
return rc ;
}
return 0 ;
}
2014-10-28 20:21:18 +03:00
static const struct ieee802154_ops at86rf230_ops = {
2012-06-26 03:24:53 +04:00
. owner = THIS_MODULE ,
2014-10-26 11:37:15 +03:00
. xmit_async = at86rf230_xmit ,
2012-06-26 03:24:53 +04:00
. ed = at86rf230_ed ,
. set_channel = at86rf230_channel ,
. start = at86rf230_start ,
. stop = at86rf230_stop ,
2013-03-26 16:41:30 +04:00
. set_hw_addr_filt = at86rf230_set_hw_addr_filt ,
2014-07-03 02:20:43 +04:00
. set_txpower = at86rf230_set_txpower ,
. set_lbt = at86rf230_set_lbt ,
. set_cca_mode = at86rf230_set_cca_mode ,
. set_cca_ed_level = at86rf230_set_cca_ed_level ,
. set_csma_params = at86rf230_set_csma_params ,
. set_frame_retries = at86rf230_set_frame_retries ,
2014-10-29 23:34:33 +03:00
. set_promiscuous_mode = at86rf230_set_promiscuous_mode ,
2014-02-17 14:34:06 +04:00
} ;
2014-07-03 02:20:46 +04:00
static struct at86rf2xx_chip_data at86rf233_data = {
2014-07-03 02:20:54 +04:00
. t_sleep_cycle = 330 ,
2014-07-03 02:20:53 +04:00
. t_channel_switch = 11 ,
2014-07-03 02:20:52 +04:00
. t_reset_to_off = 26 ,
2014-07-03 02:20:51 +04:00
. t_off_to_aack = 80 ,
. t_off_to_tx_on = 80 ,
2015-06-13 23:15:54 +03:00
. t_off_to_sleep = 35 ,
2016-04-19 16:34:22 +03:00
. t_sleep_to_off = 1000 ,
2014-07-03 02:20:48 +04:00
. t_frame = 4096 ,
. t_p_ack = 545 ,
2016-09-06 10:50:04 +03:00
. rssi_base_val = - 94 ,
2014-07-03 02:20:46 +04:00
. set_channel = at86rf23x_set_channel ,
2015-05-17 22:44:49 +03:00
. set_txpower = at86rf23x_set_txpower ,
2014-07-03 02:20:46 +04:00
} ;
static struct at86rf2xx_chip_data at86rf231_data = {
2014-07-03 02:20:54 +04:00
. t_sleep_cycle = 330 ,
2014-07-03 02:20:53 +04:00
. t_channel_switch = 24 ,
2014-07-03 02:20:52 +04:00
. t_reset_to_off = 37 ,
2014-07-03 02:20:51 +04:00
. t_off_to_aack = 110 ,
. t_off_to_tx_on = 110 ,
2015-06-13 23:15:54 +03:00
. t_off_to_sleep = 35 ,
2016-04-19 16:34:22 +03:00
. t_sleep_to_off = 1000 ,
2014-07-03 02:20:48 +04:00
. t_frame = 4096 ,
. t_p_ack = 545 ,
2014-07-03 02:20:46 +04:00
. rssi_base_val = - 91 ,
. set_channel = at86rf23x_set_channel ,
2015-05-17 22:44:49 +03:00
. set_txpower = at86rf23x_set_txpower ,
2014-07-03 02:20:46 +04:00
} ;
static struct at86rf2xx_chip_data at86rf212_data = {
2014-07-03 02:20:54 +04:00
. t_sleep_cycle = 330 ,
2014-07-03 02:20:53 +04:00
. t_channel_switch = 11 ,
2014-07-03 02:20:52 +04:00
. t_reset_to_off = 26 ,
2014-07-03 02:20:51 +04:00
. t_off_to_aack = 200 ,
. t_off_to_tx_on = 200 ,
2015-06-13 23:15:54 +03:00
. t_off_to_sleep = 35 ,
2016-04-19 16:34:22 +03:00
. t_sleep_to_off = 1000 ,
2014-07-03 02:20:48 +04:00
. t_frame = 4096 ,
. t_p_ack = 545 ,
2014-07-03 02:20:46 +04:00
. rssi_base_val = - 100 ,
. set_channel = at86rf212_set_channel ,
2015-05-17 22:44:49 +03:00
. set_txpower = at86rf212_set_txpower ,
2014-07-03 02:20:46 +04:00
} ;
2015-02-27 11:58:26 +03:00
static int at86rf230_hw_init ( struct at86rf230_local * lp , u8 xtal_trim )
2012-06-26 03:24:53 +04:00
{
2014-07-03 02:20:50 +04:00
int rc , irq_type , irq_pol = IRQ_ACTIVE_HIGH ;
2014-07-03 02:20:44 +04:00
unsigned int dvdd ;
2014-02-17 14:34:15 +04:00
u8 csma_seed [ 2 ] ;
2012-06-26 03:24:53 +04:00
2014-07-03 02:20:52 +04:00
rc = at86rf230_sync_state_change ( lp , STATE_FORCE_TRX_OFF ) ;
2014-02-17 14:34:13 +04:00
if ( rc )
return rc ;
2012-06-26 03:24:53 +04:00
2014-04-24 21:09:05 +04:00
irq_type = irq_get_trigger_type ( lp - > spi - > irq ) ;
2015-02-27 11:58:29 +03:00
if ( irq_type = = IRQ_TYPE_EDGE_FALLING | |
irq_type = = IRQ_TYPE_LEVEL_LOW )
2013-04-15 02:33:28 +04:00
irq_pol = IRQ_ACTIVE_LOW ;
2014-04-24 21:09:18 +04:00
rc = at86rf230_write_subreg ( lp , SR_IRQ_POLARITY , irq_pol ) ;
2013-04-15 02:33:28 +04:00
if ( rc )
return rc ;
2014-07-03 02:20:49 +04:00
rc = at86rf230_write_subreg ( lp , SR_RX_SAFE_MODE , 1 ) ;
if ( rc )
return rc ;
2013-04-15 02:33:29 +04:00
rc = at86rf230_write_subreg ( lp , SR_IRQ_MASK , IRQ_TRX_END ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
return rc ;
2015-02-27 11:58:28 +03:00
/* reset values differs in at86rf231 and at86rf233 */
rc = at86rf230_write_subreg ( lp , SR_IRQ_MASK_MODE , 0 ) ;
if ( rc )
return rc ;
2014-02-17 14:34:15 +04:00
get_random_bytes ( csma_seed , ARRAY_SIZE ( csma_seed ) ) ;
rc = at86rf230_write_subreg ( lp , SR_CSMA_SEED_0 , csma_seed [ 0 ] ) ;
if ( rc )
return rc ;
rc = at86rf230_write_subreg ( lp , SR_CSMA_SEED_1 , csma_seed [ 1 ] ) ;
if ( rc )
return rc ;
2012-06-26 03:24:53 +04:00
/* CLKM changes are applied immediately */
rc = at86rf230_write_subreg ( lp , SR_CLKM_SHA_SEL , 0x00 ) ;
if ( rc )
return rc ;
/* Turn CLKM Off */
rc = at86rf230_write_subreg ( lp , SR_CLKM_CTRL , 0x00 ) ;
if ( rc )
return rc ;
/* Wait the next SLEEP cycle */
2014-07-03 02:20:54 +04:00
usleep_range ( lp - > data - > t_sleep_cycle ,
lp - > data - > t_sleep_cycle + 100 ) ;
2012-06-26 03:24:53 +04:00
2015-02-27 11:58:26 +03:00
/* xtal_trim value is calculated by:
* CL = 0.5 * ( CX + CTRIM + CPAR )
*
* whereas :
* CL = capacitor of used crystal
* CX = connected capacitors at xtal pins
* CPAR = in all at86rf2xx datasheets this is a constant value 3 pF ,
* but this is different on each board setup . You need to fine
* tuning this value via CTRIM .
* CTRIM = variable capacitor setting . Resolution is 0.3 pF range is
* 0 pF upto 4.5 pF .
*
* Examples :
* atben transceiver :
*
* CL = 8 pF
* CX = 12 pF
* CPAR = 3 pF ( We assume the magic constant from datasheet )
* CTRIM = 0.9 pF
*
* ( 12 + 0.9 + 3 ) / 2 = 7.95 which is nearly at 8 pF
*
* xtal_trim = 0x3
*
* openlabs transceiver :
*
* CL = 16 pF
* CX = 22 pF
* CPAR = 3 pF ( We assume the magic constant from datasheet )
* CTRIM = 4.5 pF
*
* ( 22 + 4.5 + 3 ) / 2 = 14.75 which is the nearest value to 16 pF
*
* xtal_trim = 0xf
*/
rc = at86rf230_write_subreg ( lp , SR_XTAL_TRIM , xtal_trim ) ;
if ( rc )
return rc ;
2014-04-24 21:09:17 +04:00
rc = at86rf230_read_subreg ( lp , SR_DVDD_OK , & dvdd ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
return rc ;
2014-04-24 21:09:17 +04:00
if ( ! dvdd ) {
2012-06-26 03:24:53 +04:00
dev_err ( & lp - > spi - > dev , " DVDD error \n " ) ;
return - EINVAL ;
}
2014-11-05 22:51:27 +03:00
/* Force setting slotted operation bit to 0. Sometimes the atben
* sets this bit and I don ' t know why . We set this always force
* to zero while probing .
*/
2014-11-06 10:31:57 +03:00
return at86rf230_write_subreg ( lp , SR_SLOTTED_OPERATION , 0 ) ;
2012-06-26 03:24:53 +04:00
}
2015-02-27 11:58:25 +03:00
static int
2015-02-27 11:58:26 +03:00
at86rf230_get_pdata ( struct spi_device * spi , int * rstn , int * slp_tr ,
u8 * xtal_trim )
2014-03-15 12:29:07 +04:00
{
2015-02-27 11:58:25 +03:00
struct at86rf230_platform_data * pdata = spi - > dev . platform_data ;
2015-02-27 11:58:26 +03:00
int ret ;
2014-03-15 12:29:07 +04:00
2015-02-27 11:58:25 +03:00
if ( ! IS_ENABLED ( CONFIG_OF ) | | ! spi - > dev . of_node ) {
if ( ! pdata )
return - ENOENT ;
2014-03-15 12:29:07 +04:00
2015-02-27 11:58:25 +03:00
* rstn = pdata - > rstn ;
* slp_tr = pdata - > slp_tr ;
2015-02-27 11:58:26 +03:00
* xtal_trim = pdata - > xtal_trim ;
2015-02-27 11:58:25 +03:00
return 0 ;
}
2014-03-15 12:29:07 +04:00
2015-02-27 11:58:25 +03:00
* rstn = of_get_named_gpio ( spi - > dev . of_node , " reset-gpio " , 0 ) ;
* slp_tr = of_get_named_gpio ( spi - > dev . of_node , " sleep-gpio " , 0 ) ;
2015-02-27 11:58:26 +03:00
ret = of_property_read_u8 ( spi - > dev . of_node , " xtal-trim " , xtal_trim ) ;
if ( ret < 0 & & ret ! = - EINVAL )
return ret ;
2014-03-15 12:29:07 +04:00
2015-02-27 11:58:25 +03:00
return 0 ;
2014-03-15 12:29:07 +04:00
}
2014-07-03 02:20:45 +04:00
static int
at86rf230_detect_device ( struct at86rf230_local * lp )
{
unsigned int part , version , val ;
u16 man_id = 0 ;
const char * chip ;
int rc ;
rc = __at86rf230_read ( lp , RG_MAN_ID_0 , & val ) ;
if ( rc )
return rc ;
man_id | = val ;
rc = __at86rf230_read ( lp , RG_MAN_ID_1 , & val ) ;
if ( rc )
return rc ;
man_id | = ( val < < 8 ) ;
rc = __at86rf230_read ( lp , RG_PART_NUM , & part ) ;
if ( rc )
return rc ;
2014-12-18 00:14:42 +03:00
rc = __at86rf230_read ( lp , RG_VERSION_NUM , & version ) ;
2014-07-03 02:20:45 +04:00
if ( rc )
return rc ;
if ( man_id ! = 0x001f ) {
dev_err ( & lp - > spi - > dev , " Non-Atmel dev found (MAN_ID %02x %02x) \n " ,
man_id > > 8 , man_id & 0xFF ) ;
return - EINVAL ;
}
2015-06-06 18:30:48 +03:00
lp - > hw - > flags = IEEE802154_HW_TX_OMIT_CKSUM |
2015-05-17 22:44:46 +03:00
IEEE802154_HW_CSMA_PARAMS |
IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT |
IEEE802154_HW_PROMISCUOUS ;
lp - > hw - > phy - > flags = WPAN_PHY_FLAG_TXPOWER |
WPAN_PHY_FLAG_CCA_ED_LEVEL |
WPAN_PHY_FLAG_CCA_MODE ;
2014-07-03 02:20:45 +04:00
2015-05-17 22:44:48 +03:00
lp - > hw - > phy - > supported . cca_modes = BIT ( NL802154_CCA_ENERGY ) |
BIT ( NL802154_CCA_CARRIER ) | BIT ( NL802154_CCA_ENERGY_CARRIER ) ;
lp - > hw - > phy - > supported . cca_opts = BIT ( NL802154_CCA_OPT_ENERGY_CARRIER_AND ) |
BIT ( NL802154_CCA_OPT_ENERGY_CARRIER_OR ) ;
2014-12-10 17:33:14 +03:00
lp - > hw - > phy - > cca . mode = NL802154_CCA_ENERGY ;
2014-07-03 02:20:45 +04:00
switch ( part ) {
case 2 :
chip = " at86rf230 " ;
rc = - ENOTSUPP ;
2015-05-17 22:44:51 +03:00
goto not_supp ;
2014-07-03 02:20:45 +04:00
case 3 :
chip = " at86rf231 " ;
2014-07-03 02:20:46 +04:00
lp - > data = & at86rf231_data ;
2015-05-17 22:44:42 +03:00
lp - > hw - > phy - > supported . channels [ 0 ] = 0x7FFF800 ;
2014-11-02 06:18:34 +03:00
lp - > hw - > phy - > current_channel = 11 ;
2014-11-12 21:51:57 +03:00
lp - > hw - > phy - > symbol_duration = 16 ;
2015-05-17 22:44:49 +03:00
lp - > hw - > phy - > supported . tx_powers = at86rf231_powers ;
lp - > hw - > phy - > supported . tx_powers_size = ARRAY_SIZE ( at86rf231_powers ) ;
2016-09-06 10:50:04 +03:00
lp - > hw - > phy - > supported . cca_ed_levels = at86rf231_ed_levels ;
lp - > hw - > phy - > supported . cca_ed_levels_size = ARRAY_SIZE ( at86rf231_ed_levels ) ;
2014-07-03 02:20:45 +04:00
break ;
case 7 :
chip = " at86rf212 " ;
2014-12-19 02:36:18 +03:00
lp - > data = & at86rf212_data ;
lp - > hw - > flags | = IEEE802154_HW_LBT ;
2015-05-17 22:44:42 +03:00
lp - > hw - > phy - > supported . channels [ 0 ] = 0x00007FF ;
lp - > hw - > phy - > supported . channels [ 2 ] = 0x00007FF ;
2014-12-19 02:36:18 +03:00
lp - > hw - > phy - > current_channel = 5 ;
lp - > hw - > phy - > symbol_duration = 25 ;
2015-05-17 22:44:48 +03:00
lp - > hw - > phy - > supported . lbt = NL802154_SUPPORTED_BOOL_BOTH ;
2015-05-17 22:44:49 +03:00
lp - > hw - > phy - > supported . tx_powers = at86rf212_powers ;
lp - > hw - > phy - > supported . tx_powers_size = ARRAY_SIZE ( at86rf212_powers ) ;
2015-05-17 22:44:50 +03:00
lp - > hw - > phy - > supported . cca_ed_levels = at86rf212_ed_levels_100 ;
lp - > hw - > phy - > supported . cca_ed_levels_size = ARRAY_SIZE ( at86rf212_ed_levels_100 ) ;
2014-07-03 02:20:45 +04:00
break ;
case 11 :
chip = " at86rf233 " ;
2014-07-03 02:20:46 +04:00
lp - > data = & at86rf233_data ;
2015-05-17 22:44:42 +03:00
lp - > hw - > phy - > supported . channels [ 0 ] = 0x7FFF800 ;
2014-11-02 06:18:34 +03:00
lp - > hw - > phy - > current_channel = 13 ;
2014-11-12 21:51:57 +03:00
lp - > hw - > phy - > symbol_duration = 16 ;
2015-05-17 22:44:49 +03:00
lp - > hw - > phy - > supported . tx_powers = at86rf233_powers ;
lp - > hw - > phy - > supported . tx_powers_size = ARRAY_SIZE ( at86rf233_powers ) ;
2016-09-06 10:50:04 +03:00
lp - > hw - > phy - > supported . cca_ed_levels = at86rf233_ed_levels ;
lp - > hw - > phy - > supported . cca_ed_levels_size = ARRAY_SIZE ( at86rf233_ed_levels ) ;
2014-07-03 02:20:45 +04:00
break ;
default :
2014-12-12 14:45:30 +03:00
chip = " unknown " ;
2014-07-03 02:20:45 +04:00
rc = - ENOTSUPP ;
2015-05-17 22:44:51 +03:00
goto not_supp ;
2014-07-03 02:20:45 +04:00
}
2015-05-17 22:44:51 +03:00
lp - > hw - > phy - > cca_ed_level = lp - > hw - > phy - > supported . cca_ed_levels [ 7 ] ;
2015-05-17 22:44:52 +03:00
lp - > hw - > phy - > transmit_power = lp - > hw - > phy - > supported . tx_powers [ 0 ] ;
2015-05-17 22:44:51 +03:00
not_supp :
2014-07-03 02:20:45 +04:00
dev_info ( & lp - > spi - > dev , " Detected %s chip version %d \n " , chip , version ) ;
return rc ;
}
2015-08-27 22:49:19 +03:00
# ifdef CONFIG_IEEE802154_AT86RF230_DEBUGFS
static struct dentry * at86rf230_debugfs_root ;
static int at86rf230_stats_show ( struct seq_file * file , void * offset )
{
struct at86rf230_local * lp = file - > private ;
2015-09-22 06:41:44 +03:00
seq_printf ( file , " SUCCESS: \t \t %8llu \n " , lp - > trac . success ) ;
seq_printf ( file , " SUCCESS_DATA_PENDING: \t %8llu \n " ,
lp - > trac . success_data_pending ) ;
seq_printf ( file , " SUCCESS_WAIT_FOR_ACK: \t %8llu \n " ,
lp - > trac . success_wait_for_ack ) ;
seq_printf ( file , " CHANNEL_ACCESS_FAILURE: \t %8llu \n " ,
lp - > trac . channel_access_failure ) ;
seq_printf ( file , " NO_ACK: \t \t \t %8llu \n " , lp - > trac . no_ack ) ;
seq_printf ( file , " INVALID: \t \t %8llu \n " , lp - > trac . invalid ) ;
return 0 ;
2015-08-27 22:49:19 +03:00
}
2018-12-10 18:46:03 +03:00
DEFINE_SHOW_ATTRIBUTE ( at86rf230_stats ) ;
2015-08-27 22:49:19 +03:00
static int at86rf230_debugfs_init ( struct at86rf230_local * lp )
{
char debugfs_dir_name [ DNAME_INLINE_LEN + 1 ] = " at86rf230- " ;
struct dentry * stats ;
strncat ( debugfs_dir_name , dev_name ( & lp - > spi - > dev ) , DNAME_INLINE_LEN ) ;
at86rf230_debugfs_root = debugfs_create_dir ( debugfs_dir_name , NULL ) ;
if ( ! at86rf230_debugfs_root )
return - ENOMEM ;
2018-03-24 01:54:39 +03:00
stats = debugfs_create_file ( " trac_stats " , 0444 ,
2015-08-27 22:49:19 +03:00
at86rf230_debugfs_root , lp ,
& at86rf230_stats_fops ) ;
if ( ! stats )
return - ENOMEM ;
return 0 ;
}
static void at86rf230_debugfs_remove ( void )
{
debugfs_remove_recursive ( at86rf230_debugfs_root ) ;
}
# else
static int at86rf230_debugfs_init ( struct at86rf230_local * lp ) { return 0 ; }
static void at86rf230_debugfs_remove ( void ) { }
# endif
2012-12-03 18:24:12 +04:00
static int at86rf230_probe ( struct spi_device * spi )
2012-06-26 03:24:53 +04:00
{
2014-10-25 19:16:34 +04:00
struct ieee802154_hw * hw ;
2012-06-26 03:24:53 +04:00
struct at86rf230_local * lp ;
2014-07-03 02:20:44 +04:00
unsigned int status ;
2015-02-27 11:58:25 +03:00
int rc , irq_type , rstn , slp_tr ;
2015-03-08 00:07:07 +03:00
u8 xtal_trim = 0 ;
2012-06-26 03:24:53 +04:00
if ( ! spi - > irq ) {
dev_err ( & spi - > dev , " no IRQ specified \n " ) ;
return - EINVAL ;
}
2015-02-27 11:58:26 +03:00
rc = at86rf230_get_pdata ( spi , & rstn , & slp_tr , & xtal_trim ) ;
2015-02-27 11:58:25 +03:00
if ( rc < 0 ) {
dev_err ( & spi - > dev , " failed to parse platform_data: %d \n " , rc ) ;
return rc ;
2013-04-15 02:33:28 +04:00
}
2015-02-27 11:58:25 +03:00
if ( gpio_is_valid ( rstn ) ) {
rc = devm_gpio_request_one ( & spi - > dev , rstn ,
2014-04-24 21:09:09 +04:00
GPIOF_OUT_INIT_HIGH , " rstn " ) ;
2014-03-15 12:29:06 +04:00
if ( rc )
return rc ;
}
2012-06-26 03:24:53 +04:00
2015-02-27 11:58:25 +03:00
if ( gpio_is_valid ( slp_tr ) ) {
rc = devm_gpio_request_one ( & spi - > dev , slp_tr ,
2014-04-24 21:09:09 +04:00
GPIOF_OUT_INIT_LOW , " slp_tr " ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
2014-04-24 21:09:09 +04:00
return rc ;
2012-06-26 03:24:53 +04:00
}
/* Reset */
2015-02-27 11:58:25 +03:00
if ( gpio_is_valid ( rstn ) ) {
2014-03-15 12:29:06 +04:00
udelay ( 1 ) ;
2016-12-19 02:25:33 +03:00
gpio_set_value_cansleep ( rstn , 0 ) ;
2014-03-15 12:29:06 +04:00
udelay ( 1 ) ;
2016-12-19 02:25:33 +03:00
gpio_set_value_cansleep ( rstn , 1 ) ;
2014-03-15 12:29:06 +04:00
usleep_range ( 120 , 240 ) ;
}
2012-06-26 03:24:53 +04:00
2014-10-25 19:16:34 +04:00
hw = ieee802154_alloc_hw ( sizeof ( * lp ) , & at86rf230_ops ) ;
if ( ! hw )
2014-07-03 02:20:43 +04:00
return - ENOMEM ;
2014-10-25 19:16:34 +04:00
lp = hw - > priv ;
lp - > hw = hw ;
2014-07-03 02:20:43 +04:00
lp - > spi = spi ;
2015-04-30 18:45:03 +03:00
lp - > slp_tr = slp_tr ;
2014-10-25 19:16:34 +04:00
hw - > parent = & spi - > dev ;
2014-11-05 22:51:26 +03:00
ieee802154_random_extended_addr ( & hw - > phy - > perm_extended_addr ) ;
2014-02-17 14:34:06 +04:00
2014-07-03 02:20:44 +04:00
lp - > regmap = devm_regmap_init_spi ( spi , & at86rf230_regmap_spi_config ) ;
if ( IS_ERR ( lp - > regmap ) ) {
rc = PTR_ERR ( lp - > regmap ) ;
dev_err ( & spi - > dev , " Failed to allocate register map: %d \n " ,
rc ) ;
goto free_dev ;
}
2015-09-21 10:37:54 +03:00
at86rf230_setup_spi_messages ( lp , & lp - > state ) ;
at86rf230_setup_spi_messages ( lp , & lp - > tx ) ;
2014-07-03 02:20:48 +04:00
2014-07-03 02:20:45 +04:00
rc = at86rf230_detect_device ( lp ) ;
if ( rc < 0 )
goto free_dev ;
2014-07-03 02:20:51 +04:00
init_completion ( & lp - > state_complete ) ;
2014-02-17 14:34:06 +04:00
spi_set_drvdata ( spi , lp ) ;
2015-02-27 11:58:26 +03:00
rc = at86rf230_hw_init ( lp , xtal_trim ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
2014-07-03 02:20:48 +04:00
goto free_dev ;
2012-06-26 03:24:53 +04:00
2014-04-24 21:09:15 +04:00
/* Read irq status register to reset irq line */
rc = at86rf230_read_subreg ( lp , RG_IRQ_STATUS , 0xff , 0 , & status ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
2014-07-03 02:20:48 +04:00
goto free_dev ;
2012-06-26 03:24:53 +04:00
2014-07-03 02:20:48 +04:00
irq_type = irq_get_trigger_type ( spi - > irq ) ;
if ( ! irq_type )
2015-06-13 23:15:53 +03:00
irq_type = IRQF_TRIGGER_HIGH ;
2014-07-03 02:20:48 +04:00
rc = devm_request_irq ( & spi - > dev , spi - > irq , at86rf230_isr ,
IRQF_SHARED | irq_type , dev_name ( & spi - > dev ) , lp ) ;
2013-04-15 02:33:29 +04:00
if ( rc )
2014-07-03 02:20:48 +04:00
goto free_dev ;
2013-04-15 02:33:29 +04:00
2015-06-13 23:15:54 +03:00
/* disable_irq by default and wait for starting hardware */
disable_irq ( spi - > irq ) ;
/* going into sleep by default */
2015-06-16 12:07:42 +03:00
at86rf230_sleep ( lp ) ;
2015-06-13 23:15:54 +03:00
2015-08-27 22:49:19 +03:00
rc = at86rf230_debugfs_init ( lp ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
2014-07-03 02:20:48 +04:00
goto free_dev ;
2012-06-26 03:24:53 +04:00
2015-08-27 22:49:19 +03:00
rc = ieee802154_register_hw ( lp - > hw ) ;
if ( rc )
goto free_debugfs ;
2012-06-26 03:24:53 +04:00
return rc ;
2015-08-27 22:49:19 +03:00
free_debugfs :
at86rf230_debugfs_remove ( ) ;
2014-07-03 02:20:43 +04:00
free_dev :
2014-10-25 19:16:34 +04:00
ieee802154_free_hw ( lp - > hw ) ;
2014-02-17 14:34:06 +04:00
2012-06-26 03:24:53 +04:00
return rc ;
}
2012-12-03 18:24:12 +04:00
static int at86rf230_remove ( struct spi_device * spi )
2012-06-26 03:24:53 +04:00
{
struct at86rf230_local * lp = spi_get_drvdata ( spi ) ;
2014-03-31 05:26:51 +04:00
/* mask all at86rf230 irq's */
at86rf230_write_subreg ( lp , SR_IRQ_MASK , 0 ) ;
2014-10-25 19:16:34 +04:00
ieee802154_unregister_hw ( lp - > hw ) ;
ieee802154_free_hw ( lp - > hw ) ;
2015-08-27 22:49:19 +03:00
at86rf230_debugfs_remove ( ) ;
2012-06-26 03:24:53 +04:00
dev_dbg ( & spi - > dev , " unregistered at86rf230 \n " ) ;
2014-04-24 21:09:09 +04:00
2012-06-26 03:24:53 +04:00
return 0 ;
}
2014-04-24 21:09:11 +04:00
static const struct of_device_id at86rf230_of_match [ ] = {
2014-03-15 12:29:07 +04:00
{ . compatible = " atmel,at86rf230 " , } ,
{ . compatible = " atmel,at86rf231 " , } ,
{ . compatible = " atmel,at86rf233 " , } ,
{ . compatible = " atmel,at86rf212 " , } ,
{ } ,
} ;
2014-04-24 21:09:10 +04:00
MODULE_DEVICE_TABLE ( of , at86rf230_of_match ) ;
2014-03-15 12:29:07 +04:00
2014-04-24 21:09:12 +04:00
static const struct spi_device_id at86rf230_device_id [ ] = {
{ . name = " at86rf230 " , } ,
{ . name = " at86rf231 " , } ,
{ . name = " at86rf233 " , } ,
{ . name = " at86rf212 " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( spi , at86rf230_device_id ) ;
2012-06-26 03:24:53 +04:00
static struct spi_driver at86rf230_driver = {
2014-04-24 21:09:12 +04:00
. id_table = at86rf230_device_id ,
2012-06-26 03:24:53 +04:00
. driver = {
2014-03-15 12:29:07 +04:00
. of_match_table = of_match_ptr ( at86rf230_of_match ) ,
2012-06-26 03:24:53 +04:00
. name = " at86rf230 " ,
} ,
. probe = at86rf230_probe ,
2012-12-03 18:24:12 +04:00
. remove = at86rf230_remove ,
2012-06-26 03:24:53 +04:00
} ;
2012-08-26 09:10:10 +04:00
module_spi_driver ( at86rf230_driver ) ;
2012-06-26 03:24:53 +04:00
MODULE_DESCRIPTION ( " AT86RF230 Transceiver Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;