2012-06-26 03:24:53 +04:00
/*
* AT86RF230 / RF231 driver
*
* Copyright ( C ) 2009 - 2012 Siemens AG
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Written by :
* Dmitry Eremin - Solenikov < dbaryshkov @ gmail . com >
* Alexander Smirnov < alex . bluesman . smirnov @ gmail . com >
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/gpio.h>
# include <linux/delay.h>
# include <linux/mutex.h>
# include <linux/workqueue.h>
# include <linux/spinlock.h>
# include <linux/spi/spi.h>
# include <linux/spi/at86rf230.h>
# include <linux/skbuff.h>
# include <net/mac802154.h>
# include <net/wpan-phy.h>
struct at86rf230_local {
struct spi_device * spi ;
u8 part ;
u8 vers ;
u8 buf [ 2 ] ;
struct mutex bmux ;
struct work_struct irqwork ;
struct completion tx_complete ;
struct ieee802154_dev * dev ;
spinlock_t lock ;
2013-04-15 02:33:29 +04:00
bool irq_busy ;
2012-06-26 03:24:53 +04:00
bool is_tx ;
2014-02-17 14:34:15 +04:00
bool tx_aret ;
2014-02-17 14:34:12 +04:00
int rssi_base_val ;
2012-06-26 03:24:53 +04:00
} ;
2014-02-26 09:38:29 +04:00
static bool is_rf212 ( struct at86rf230_local * local )
2014-02-17 14:34:06 +04:00
{
return local - > part = = 7 ;
}
2012-06-26 03:24:53 +04:00
# define RG_TRX_STATUS (0x01)
# define SR_TRX_STATUS 0x01, 0x1f, 0
# define SR_RESERVED_01_3 0x01, 0x20, 5
# define SR_CCA_STATUS 0x01, 0x40, 6
# define SR_CCA_DONE 0x01, 0x80, 7
# define RG_TRX_STATE (0x02)
# define SR_TRX_CMD 0x02, 0x1f, 0
# define SR_TRAC_STATUS 0x02, 0xe0, 5
# define RG_TRX_CTRL_0 (0x03)
# define SR_CLKM_CTRL 0x03, 0x07, 0
# define SR_CLKM_SHA_SEL 0x03, 0x08, 3
# define SR_PAD_IO_CLKM 0x03, 0x30, 4
# define SR_PAD_IO 0x03, 0xc0, 6
# define RG_TRX_CTRL_1 (0x04)
# define SR_IRQ_POLARITY 0x04, 0x01, 0
# define SR_IRQ_MASK_MODE 0x04, 0x02, 1
# define SR_SPI_CMD_MODE 0x04, 0x0c, 2
# define SR_RX_BL_CTRL 0x04, 0x10, 4
# define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5
# define SR_IRQ_2_EXT_EN 0x04, 0x40, 6
# define SR_PA_EXT_EN 0x04, 0x80, 7
# define RG_PHY_TX_PWR (0x05)
# define SR_TX_PWR 0x05, 0x0f, 0
# define SR_PA_LT 0x05, 0x30, 4
# define SR_PA_BUF_LT 0x05, 0xc0, 6
# define RG_PHY_RSSI (0x06)
# define SR_RSSI 0x06, 0x1f, 0
# define SR_RND_VALUE 0x06, 0x60, 5
# define SR_RX_CRC_VALID 0x06, 0x80, 7
# define RG_PHY_ED_LEVEL (0x07)
# define SR_ED_LEVEL 0x07, 0xff, 0
# define RG_PHY_CC_CCA (0x08)
# define SR_CHANNEL 0x08, 0x1f, 0
# define SR_CCA_MODE 0x08, 0x60, 5
# define SR_CCA_REQUEST 0x08, 0x80, 7
# define RG_CCA_THRES (0x09)
# define SR_CCA_ED_THRES 0x09, 0x0f, 0
# define SR_RESERVED_09_1 0x09, 0xf0, 4
# define RG_RX_CTRL (0x0a)
# define SR_PDT_THRES 0x0a, 0x0f, 0
# define SR_RESERVED_0a_1 0x0a, 0xf0, 4
# define RG_SFD_VALUE (0x0b)
# define SR_SFD_VALUE 0x0b, 0xff, 0
# define RG_TRX_CTRL_2 (0x0c)
# define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0
2014-02-17 14:34:06 +04:00
# define SR_SUB_MODE 0x0c, 0x04, 2
# define SR_BPSK_QPSK 0x0c, 0x08, 3
2014-02-17 14:34:09 +04:00
# define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4
# define SR_RESERVED_0c_5 0x0c, 0x60, 5
2012-06-26 03:24:53 +04:00
# define SR_RX_SAFE_MODE 0x0c, 0x80, 7
# define RG_ANT_DIV (0x0d)
# define SR_ANT_CTRL 0x0d, 0x03, 0
# define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2
# define SR_ANT_DIV_EN 0x0d, 0x08, 3
# define SR_RESERVED_0d_2 0x0d, 0x70, 4
# define SR_ANT_SEL 0x0d, 0x80, 7
# define RG_IRQ_MASK (0x0e)
# define SR_IRQ_MASK 0x0e, 0xff, 0
# define RG_IRQ_STATUS (0x0f)
# define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0
# define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1
# define SR_IRQ_2_RX_START 0x0f, 0x04, 2
# define SR_IRQ_3_TRX_END 0x0f, 0x08, 3
# define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4
# define SR_IRQ_5_AMI 0x0f, 0x20, 5
# define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6
# define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7
# define RG_VREG_CTRL (0x10)
# define SR_RESERVED_10_6 0x10, 0x03, 0
# define SR_DVDD_OK 0x10, 0x04, 2
# define SR_DVREG_EXT 0x10, 0x08, 3
# define SR_RESERVED_10_3 0x10, 0x30, 4
# define SR_AVDD_OK 0x10, 0x40, 6
# define SR_AVREG_EXT 0x10, 0x80, 7
# define RG_BATMON (0x11)
# define SR_BATMON_VTH 0x11, 0x0f, 0
# define SR_BATMON_HR 0x11, 0x10, 4
# define SR_BATMON_OK 0x11, 0x20, 5
# define SR_RESERVED_11_1 0x11, 0xc0, 6
# define RG_XOSC_CTRL (0x12)
# define SR_XTAL_TRIM 0x12, 0x0f, 0
# define SR_XTAL_MODE 0x12, 0xf0, 4
# define RG_RX_SYN (0x15)
# define SR_RX_PDT_LEVEL 0x15, 0x0f, 0
# define SR_RESERVED_15_2 0x15, 0x70, 4
# define SR_RX_PDT_DIS 0x15, 0x80, 7
# define RG_XAH_CTRL_1 (0x17)
# define SR_RESERVED_17_8 0x17, 0x01, 0
# define SR_AACK_PROM_MODE 0x17, 0x02, 1
# define SR_AACK_ACK_TIME 0x17, 0x04, 2
# define SR_RESERVED_17_5 0x17, 0x08, 3
# define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4
# define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5
2014-02-17 14:34:10 +04:00
# define SR_CSMA_LBT_MODE 0x17, 0x40, 6
2012-06-26 03:24:53 +04:00
# define SR_RESERVED_17_1 0x17, 0x80, 7
# define RG_FTN_CTRL (0x18)
# define SR_RESERVED_18_2 0x18, 0x7f, 0
# define SR_FTN_START 0x18, 0x80, 7
# define RG_PLL_CF (0x1a)
# define SR_RESERVED_1a_2 0x1a, 0x7f, 0
# define SR_PLL_CF_START 0x1a, 0x80, 7
# define RG_PLL_DCU (0x1b)
# define SR_RESERVED_1b_3 0x1b, 0x3f, 0
# define SR_RESERVED_1b_2 0x1b, 0x40, 6
# define SR_PLL_DCU_START 0x1b, 0x80, 7
# define RG_PART_NUM (0x1c)
# define SR_PART_NUM 0x1c, 0xff, 0
# define RG_VERSION_NUM (0x1d)
# define SR_VERSION_NUM 0x1d, 0xff, 0
# define RG_MAN_ID_0 (0x1e)
# define SR_MAN_ID_0 0x1e, 0xff, 0
# define RG_MAN_ID_1 (0x1f)
# define SR_MAN_ID_1 0x1f, 0xff, 0
# define RG_SHORT_ADDR_0 (0x20)
# define SR_SHORT_ADDR_0 0x20, 0xff, 0
# define RG_SHORT_ADDR_1 (0x21)
# define SR_SHORT_ADDR_1 0x21, 0xff, 0
# define RG_PAN_ID_0 (0x22)
# define SR_PAN_ID_0 0x22, 0xff, 0
# define RG_PAN_ID_1 (0x23)
# define SR_PAN_ID_1 0x23, 0xff, 0
# define RG_IEEE_ADDR_0 (0x24)
# define SR_IEEE_ADDR_0 0x24, 0xff, 0
# define RG_IEEE_ADDR_1 (0x25)
# define SR_IEEE_ADDR_1 0x25, 0xff, 0
# define RG_IEEE_ADDR_2 (0x26)
# define SR_IEEE_ADDR_2 0x26, 0xff, 0
# define RG_IEEE_ADDR_3 (0x27)
# define SR_IEEE_ADDR_3 0x27, 0xff, 0
# define RG_IEEE_ADDR_4 (0x28)
# define SR_IEEE_ADDR_4 0x28, 0xff, 0
# define RG_IEEE_ADDR_5 (0x29)
# define SR_IEEE_ADDR_5 0x29, 0xff, 0
# define RG_IEEE_ADDR_6 (0x2a)
# define SR_IEEE_ADDR_6 0x2a, 0xff, 0
# define RG_IEEE_ADDR_7 (0x2b)
# define SR_IEEE_ADDR_7 0x2b, 0xff, 0
# define RG_XAH_CTRL_0 (0x2c)
# define SR_SLOTTED_OPERATION 0x2c, 0x01, 0
# define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1
# define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4
# define RG_CSMA_SEED_0 (0x2d)
# define SR_CSMA_SEED_0 0x2d, 0xff, 0
# define RG_CSMA_SEED_1 (0x2e)
# define SR_CSMA_SEED_1 0x2e, 0x07, 0
# define SR_AACK_I_AM_COORD 0x2e, 0x08, 3
# define SR_AACK_DIS_ACK 0x2e, 0x10, 4
# define SR_AACK_SET_PD 0x2e, 0x20, 5
# define SR_AACK_FVN_MODE 0x2e, 0xc0, 6
# define RG_CSMA_BE (0x2f)
# define SR_MIN_BE 0x2f, 0x0f, 0
# define SR_MAX_BE 0x2f, 0xf0, 4
# define CMD_REG 0x80
# define CMD_REG_MASK 0x3f
# define CMD_WRITE 0x40
# define CMD_FB 0x20
# define IRQ_BAT_LOW (1 << 7)
# define IRQ_TRX_UR (1 << 6)
# define IRQ_AMI (1 << 5)
# define IRQ_CCA_ED (1 << 4)
# define IRQ_TRX_END (1 << 3)
# define IRQ_RX_START (1 << 2)
# define IRQ_PLL_UNL (1 << 1)
# define IRQ_PLL_LOCK (1 << 0)
2013-04-15 02:33:28 +04:00
# define IRQ_ACTIVE_HIGH 0
# define IRQ_ACTIVE_LOW 1
2012-06-26 03:24:53 +04:00
# define STATE_P_ON 0x00 /* BUSY */
# define STATE_BUSY_RX 0x01
# define STATE_BUSY_TX 0x02
# define STATE_FORCE_TRX_OFF 0x03
# define STATE_FORCE_TX_ON 0x04 /* IDLE */
/* 0x05 */ /* INVALID_PARAMETER */
# define STATE_RX_ON 0x06
/* 0x07 */ /* SUCCESS */
# define STATE_TRX_OFF 0x08
# define STATE_TX_ON 0x09
/* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */
# define STATE_SLEEP 0x0F
2014-03-11 04:29:25 +04:00
# define STATE_PREP_DEEP_SLEEP 0x10
2012-06-26 03:24:53 +04:00
# define STATE_BUSY_RX_AACK 0x11
# define STATE_BUSY_TX_ARET 0x12
2013-03-26 16:41:31 +04:00
# define STATE_RX_AACK_ON 0x16
# define STATE_TX_ARET_ON 0x19
2012-06-26 03:24:53 +04:00
# define STATE_RX_ON_NOCLK 0x1C
# define STATE_RX_AACK_ON_NOCLK 0x1D
# define STATE_BUSY_RX_AACK_NOCLK 0x1E
# define STATE_TRANSITION_IN_PROGRESS 0x1F
2014-02-17 14:34:06 +04:00
static int
__at86rf230_detect_device ( struct spi_device * spi , u16 * man_id , u8 * part ,
u8 * version )
{
u8 data [ 4 ] ;
u8 * buf = kmalloc ( 2 , GFP_KERNEL ) ;
int status ;
struct spi_message msg ;
struct spi_transfer xfer = {
. len = 2 ,
. tx_buf = buf ,
. rx_buf = buf ,
} ;
u8 reg ;
if ( ! buf )
return - ENOMEM ;
for ( reg = RG_PART_NUM ; reg < = RG_MAN_ID_1 ; reg + + ) {
buf [ 0 ] = ( reg & CMD_REG_MASK ) | CMD_REG ;
buf [ 1 ] = 0xff ;
dev_vdbg ( & spi - > dev , " buf[0] = %02x \n " , buf [ 0 ] ) ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
status = spi_sync ( spi , & msg ) ;
dev_vdbg ( & spi - > dev , " status = %d \n " , status ) ;
if ( msg . status )
status = msg . status ;
dev_vdbg ( & spi - > dev , " status = %d \n " , status ) ;
dev_vdbg ( & spi - > dev , " buf[0] = %02x \n " , buf [ 0 ] ) ;
dev_vdbg ( & spi - > dev , " buf[1] = %02x \n " , buf [ 1 ] ) ;
if ( status = = 0 )
data [ reg - RG_PART_NUM ] = buf [ 1 ] ;
else
break ;
}
if ( status = = 0 ) {
* part = data [ 0 ] ;
* version = data [ 1 ] ;
* man_id = ( data [ 3 ] < < 8 ) | data [ 2 ] ;
}
kfree ( buf ) ;
return status ;
}
2012-06-26 03:24:53 +04:00
static int
__at86rf230_write ( struct at86rf230_local * lp , u8 addr , u8 data )
{
u8 * buf = lp - > buf ;
int status ;
struct spi_message msg ;
struct spi_transfer xfer = {
. len = 2 ,
. tx_buf = buf ,
} ;
buf [ 0 ] = ( addr & CMD_REG_MASK ) | CMD_REG | CMD_WRITE ;
buf [ 1 ] = data ;
dev_vdbg ( & lp - > spi - > dev , " buf[0] = %02x \n " , buf [ 0 ] ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[1] = %02x \n " , buf [ 1 ] ) ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
status = spi_sync ( lp - > spi , & msg ) ;
dev_vdbg ( & lp - > spi - > dev , " status = %d \n " , status ) ;
if ( msg . status )
status = msg . status ;
dev_vdbg ( & lp - > spi - > dev , " status = %d \n " , status ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[0] = %02x \n " , buf [ 0 ] ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[1] = %02x \n " , buf [ 1 ] ) ;
return status ;
}
static int
__at86rf230_read_subreg ( struct at86rf230_local * lp ,
u8 addr , u8 mask , int shift , u8 * data )
{
u8 * buf = lp - > buf ;
int status ;
struct spi_message msg ;
struct spi_transfer xfer = {
. len = 2 ,
. tx_buf = buf ,
. rx_buf = buf ,
} ;
buf [ 0 ] = ( addr & CMD_REG_MASK ) | CMD_REG ;
buf [ 1 ] = 0xff ;
dev_vdbg ( & lp - > spi - > dev , " buf[0] = %02x \n " , buf [ 0 ] ) ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
status = spi_sync ( lp - > spi , & msg ) ;
dev_vdbg ( & lp - > spi - > dev , " status = %d \n " , status ) ;
if ( msg . status )
status = msg . status ;
dev_vdbg ( & lp - > spi - > dev , " status = %d \n " , status ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[0] = %02x \n " , buf [ 0 ] ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[1] = %02x \n " , buf [ 1 ] ) ;
if ( status = = 0 )
* data = buf [ 1 ] ;
return status ;
}
static int
at86rf230_read_subreg ( struct at86rf230_local * lp ,
u8 addr , u8 mask , int shift , u8 * data )
{
int status ;
mutex_lock ( & lp - > bmux ) ;
status = __at86rf230_read_subreg ( lp , addr , mask , shift , data ) ;
mutex_unlock ( & lp - > bmux ) ;
return status ;
}
static int
at86rf230_write_subreg ( struct at86rf230_local * lp ,
u8 addr , u8 mask , int shift , u8 data )
{
int status ;
u8 val ;
mutex_lock ( & lp - > bmux ) ;
status = __at86rf230_read_subreg ( lp , addr , 0xff , 0 , & val ) ;
if ( status )
goto out ;
val & = ~ mask ;
val | = ( data < < shift ) & mask ;
status = __at86rf230_write ( lp , addr , val ) ;
out :
mutex_unlock ( & lp - > bmux ) ;
return status ;
}
static int
at86rf230_write_fbuf ( struct at86rf230_local * lp , u8 * data , u8 len )
{
u8 * buf = lp - > buf ;
int status ;
struct spi_message msg ;
struct spi_transfer xfer_head = {
. len = 2 ,
. tx_buf = buf ,
} ;
struct spi_transfer xfer_buf = {
. len = len ,
. tx_buf = data ,
} ;
mutex_lock ( & lp - > bmux ) ;
buf [ 0 ] = CMD_WRITE | CMD_FB ;
buf [ 1 ] = len + 2 ; /* 2 bytes for CRC that isn't written */
dev_vdbg ( & lp - > spi - > dev , " buf[0] = %02x \n " , buf [ 0 ] ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[1] = %02x \n " , buf [ 1 ] ) ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer_head , & msg ) ;
spi_message_add_tail ( & xfer_buf , & msg ) ;
status = spi_sync ( lp - > spi , & msg ) ;
dev_vdbg ( & lp - > spi - > dev , " status = %d \n " , status ) ;
if ( msg . status )
status = msg . status ;
dev_vdbg ( & lp - > spi - > dev , " status = %d \n " , status ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[0] = %02x \n " , buf [ 0 ] ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[1] = %02x \n " , buf [ 1 ] ) ;
mutex_unlock ( & lp - > bmux ) ;
return status ;
}
static int
at86rf230_read_fbuf ( struct at86rf230_local * lp , u8 * data , u8 * len , u8 * lqi )
{
u8 * buf = lp - > buf ;
int status ;
struct spi_message msg ;
struct spi_transfer xfer_head = {
. len = 2 ,
. tx_buf = buf ,
. rx_buf = buf ,
} ;
struct spi_transfer xfer_head1 = {
. len = 2 ,
. tx_buf = buf ,
. rx_buf = buf ,
} ;
struct spi_transfer xfer_buf = {
. len = 0 ,
. rx_buf = data ,
} ;
mutex_lock ( & lp - > bmux ) ;
buf [ 0 ] = CMD_FB ;
buf [ 1 ] = 0x00 ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer_head , & msg ) ;
status = spi_sync ( lp - > spi , & msg ) ;
dev_vdbg ( & lp - > spi - > dev , " status = %d \n " , status ) ;
xfer_buf . len = * ( buf + 1 ) + 1 ;
* len = buf [ 1 ] ;
buf [ 0 ] = CMD_FB ;
buf [ 1 ] = 0x00 ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer_head1 , & msg ) ;
spi_message_add_tail ( & xfer_buf , & msg ) ;
status = spi_sync ( lp - > spi , & msg ) ;
if ( msg . status )
status = msg . status ;
dev_vdbg ( & lp - > spi - > dev , " status = %d \n " , status ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[0] = %02x \n " , buf [ 0 ] ) ;
dev_vdbg ( & lp - > spi - > dev , " buf[1] = %02x \n " , buf [ 1 ] ) ;
if ( status ) {
if ( lqi & & ( * len > lp - > buf [ 1 ] ) )
* lqi = data [ lp - > buf [ 1 ] ] ;
}
mutex_unlock ( & lp - > bmux ) ;
return status ;
}
static int
at86rf230_ed ( struct ieee802154_dev * dev , u8 * level )
{
might_sleep ( ) ;
BUG_ON ( ! level ) ;
* level = 0xbe ;
return 0 ;
}
static int
at86rf230_state ( struct ieee802154_dev * dev , int state )
{
struct at86rf230_local * lp = dev - > priv ;
int rc ;
u8 val ;
u8 desired_status ;
might_sleep ( ) ;
if ( state = = STATE_FORCE_TX_ON )
desired_status = STATE_TX_ON ;
else if ( state = = STATE_FORCE_TRX_OFF )
desired_status = STATE_TRX_OFF ;
else
desired_status = state ;
do {
rc = at86rf230_read_subreg ( lp , SR_TRX_STATUS , & val ) ;
if ( rc )
goto err ;
} while ( val = = STATE_TRANSITION_IN_PROGRESS ) ;
if ( val = = desired_status )
return 0 ;
/* state is equal to phy states */
rc = at86rf230_write_subreg ( lp , SR_TRX_CMD , state ) ;
if ( rc )
goto err ;
do {
rc = at86rf230_read_subreg ( lp , SR_TRX_STATUS , & val ) ;
if ( rc )
goto err ;
} while ( val = = STATE_TRANSITION_IN_PROGRESS ) ;
2014-02-17 14:34:15 +04:00
if ( val = = desired_status | |
( desired_status = = STATE_RX_ON & & val = = STATE_BUSY_RX ) | |
( desired_status = = STATE_RX_AACK_ON & & val = = STATE_BUSY_RX_AACK ) )
2012-06-26 03:24:53 +04:00
return 0 ;
pr_err ( " unexpected state change: %d, asked for %d \n " , val , state ) ;
return - EBUSY ;
err :
pr_err ( " error: %d \n " , rc ) ;
return rc ;
}
static int
at86rf230_start ( struct ieee802154_dev * dev )
{
struct at86rf230_local * lp = dev - > priv ;
u8 rc ;
rc = at86rf230_write_subreg ( lp , SR_RX_SAFE_MODE , 1 ) ;
if ( rc )
return rc ;
2014-02-17 14:34:15 +04:00
rc = at86rf230_state ( dev , STATE_FORCE_TX_ON ) ;
if ( rc )
return rc ;
2014-02-17 14:34:07 +04:00
return at86rf230_state ( dev , STATE_RX_AACK_ON ) ;
2012-06-26 03:24:53 +04:00
}
static void
at86rf230_stop ( struct ieee802154_dev * dev )
{
at86rf230_state ( dev , STATE_FORCE_TRX_OFF ) ;
}
2014-02-17 14:34:06 +04:00
static int
at86rf230_set_channel ( struct at86rf230_local * lp , int page , int channel )
{
2014-02-17 14:34:12 +04:00
lp - > rssi_base_val = - 91 ;
2014-02-17 14:34:06 +04:00
return at86rf230_write_subreg ( lp , SR_CHANNEL , channel ) ;
}
static int
at86rf212_set_channel ( struct at86rf230_local * lp , int page , int channel )
{
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-02-17 14:34:12 +04:00
lp - > rssi_base_val = - 100 ;
} else {
2014-02-17 14:34:09 +04:00
rc = at86rf230_write_subreg ( lp , SR_BPSK_QPSK , 1 ) ;
2014-02-17 14:34:12 +04:00
lp - > rssi_base_val = - 98 ;
}
2014-02-17 14:34:09 +04:00
if ( rc < 0 )
return rc ;
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
at86rf230_channel ( struct ieee802154_dev * dev , int page , int channel )
{
struct at86rf230_local * lp = dev - > priv ;
int rc ;
might_sleep ( ) ;
2014-02-17 14:34:06 +04:00
if ( page < 0 | | page > 31 | |
! ( lp - > dev - > phy - > channels_supported [ page ] & BIT ( channel ) ) ) {
2012-06-26 03:24:53 +04:00
WARN_ON ( 1 ) ;
return - EINVAL ;
}
2014-02-17 14:34:06 +04:00
if ( is_rf212 ( lp ) )
rc = at86rf212_set_channel ( lp , page , channel ) ;
else
rc = at86rf230_set_channel ( lp , page , channel ) ;
if ( rc < 0 )
return rc ;
2012-06-26 03:24:53 +04:00
msleep ( 1 ) ; /* Wait for PLL */
dev - > phy - > current_channel = channel ;
2014-02-17 14:34:09 +04:00
dev - > phy - > current_page = page ;
2012-06-26 03:24:53 +04:00
return 0 ;
}
static int
at86rf230_xmit ( struct ieee802154_dev * dev , struct sk_buff * skb )
{
struct at86rf230_local * lp = dev - > priv ;
int rc ;
unsigned long flags ;
2012-07-11 01:22:43 +04:00
spin_lock ( & lp - > lock ) ;
2013-04-15 02:33:29 +04:00
if ( lp - > irq_busy ) {
2012-07-11 01:22:43 +04:00
spin_unlock ( & lp - > lock ) ;
return - EBUSY ;
}
spin_unlock ( & lp - > lock ) ;
2012-06-26 03:24:53 +04:00
might_sleep ( ) ;
rc = at86rf230_state ( dev , STATE_FORCE_TX_ON ) ;
if ( rc )
goto err ;
spin_lock_irqsave ( & lp - > lock , flags ) ;
lp - > is_tx = 1 ;
2013-11-15 02:32:02 +04:00
reinit_completion ( & lp - > tx_complete ) ;
2012-06-26 03:24:53 +04:00
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
rc = at86rf230_write_fbuf ( lp , skb - > data , skb - > len ) ;
if ( rc )
goto err_rx ;
2014-02-17 14:34:15 +04:00
if ( lp - > tx_aret ) {
rc = at86rf230_write_subreg ( lp , SR_TRX_CMD , STATE_TX_ARET_ON ) ;
if ( rc )
goto err_rx ;
}
2012-06-26 03:24:53 +04:00
rc = at86rf230_write_subreg ( lp , SR_TRX_CMD , STATE_BUSY_TX ) ;
if ( rc )
goto err_rx ;
rc = wait_for_completion_interruptible ( & lp - > tx_complete ) ;
if ( rc < 0 )
goto err_rx ;
rc = at86rf230_start ( dev ) ;
return rc ;
err_rx :
at86rf230_start ( dev ) ;
err :
pr_err ( " error: %d \n " , rc ) ;
spin_lock_irqsave ( & lp - > lock , flags ) ;
lp - > is_tx = 0 ;
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
return rc ;
}
static int at86rf230_rx ( struct at86rf230_local * lp )
{
u8 len = 128 , lqi = 0 ;
struct sk_buff * skb ;
skb = alloc_skb ( len , GFP_KERNEL ) ;
if ( ! skb )
return - ENOMEM ;
2012-07-11 01:22:43 +04:00
if ( at86rf230_read_fbuf ( lp , skb_put ( skb , len ) , & len , & lqi ) )
2012-06-26 03:24:53 +04:00
goto err ;
if ( len < 2 )
goto err ;
skb_trim ( skb , len - 2 ) ; /* We do not put CRC into the frame */
ieee802154_rx_irqsafe ( lp - > dev , skb , lqi ) ;
2012-07-02 00:18:32 +04:00
dev_dbg ( & lp - > spi - > dev , " READ_FBUF: %d %x \n " , len , lqi ) ;
2012-06-26 03:24:53 +04:00
return 0 ;
err :
pr_debug ( " received frame is too small \n " ) ;
kfree_skb ( skb ) ;
return - EINVAL ;
}
2013-03-26 16:41:30 +04:00
static int
at86rf230_set_hw_addr_filt ( struct ieee802154_dev * dev ,
struct ieee802154_hw_addr_filt * filt ,
unsigned long changed )
{
struct at86rf230_local * lp = dev - > priv ;
if ( changed & IEEE802515_AFILT_SADDR_CHANGED ) {
dev_vdbg ( & lp - > spi - > dev ,
" at86rf230_set_hw_addr_filt called for saddr \n " ) ;
__at86rf230_write ( lp , RG_SHORT_ADDR_0 , filt - > short_addr ) ;
__at86rf230_write ( lp , RG_SHORT_ADDR_1 , filt - > short_addr > > 8 ) ;
}
if ( changed & IEEE802515_AFILT_PANID_CHANGED ) {
dev_vdbg ( & lp - > spi - > dev ,
" at86rf230_set_hw_addr_filt called for pan id \n " ) ;
__at86rf230_write ( lp , RG_PAN_ID_0 , filt - > pan_id ) ;
__at86rf230_write ( lp , RG_PAN_ID_1 , filt - > pan_id > > 8 ) ;
}
if ( changed & IEEE802515_AFILT_IEEEADDR_CHANGED ) {
dev_vdbg ( & lp - > spi - > dev ,
" at86rf230_set_hw_addr_filt called for IEEE addr \n " ) ;
at86rf230_write_subreg ( lp , SR_IEEE_ADDR_0 , filt - > ieee_addr [ 7 ] ) ;
at86rf230_write_subreg ( lp , SR_IEEE_ADDR_1 , filt - > ieee_addr [ 6 ] ) ;
at86rf230_write_subreg ( lp , SR_IEEE_ADDR_2 , filt - > ieee_addr [ 5 ] ) ;
at86rf230_write_subreg ( lp , SR_IEEE_ADDR_3 , filt - > ieee_addr [ 4 ] ) ;
at86rf230_write_subreg ( lp , SR_IEEE_ADDR_4 , filt - > ieee_addr [ 3 ] ) ;
at86rf230_write_subreg ( lp , SR_IEEE_ADDR_5 , filt - > ieee_addr [ 2 ] ) ;
at86rf230_write_subreg ( lp , SR_IEEE_ADDR_6 , filt - > ieee_addr [ 1 ] ) ;
at86rf230_write_subreg ( lp , SR_IEEE_ADDR_7 , filt - > ieee_addr [ 0 ] ) ;
}
if ( changed & IEEE802515_AFILT_PANC_CHANGED ) {
dev_vdbg ( & lp - > spi - > dev ,
" at86rf230_set_hw_addr_filt called for panc change \n " ) ;
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 ;
}
2014-02-17 14:34:08 +04:00
static int
at86rf212_set_txpower ( struct ieee802154_dev * dev , int db )
{
struct at86rf230_local * lp = dev - > priv ;
/* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five
* bits decrease power in 1 dB steps . 0x60 represents extra PA gain of
* 0 dB .
* thus , supported values for db range from - 26 to 5 , for 31 dB of
* reduction to 0 dB of reduction .
*/
if ( db > 5 | | db < - 26 )
return - EINVAL ;
db = - ( db - 5 ) ;
2014-03-02 02:54:36 +04:00
return __at86rf230_write ( lp , RG_PHY_TX_PWR , 0x60 | db ) ;
2014-02-17 14:34:08 +04:00
}
2014-02-17 14:34:10 +04:00
static int
at86rf212_set_lbt ( struct ieee802154_dev * dev , bool on )
{
struct at86rf230_local * lp = dev - > priv ;
return at86rf230_write_subreg ( lp , SR_CSMA_LBT_MODE , on ) ;
}
2014-02-17 14:34:11 +04:00
static int
at86rf212_set_cca_mode ( struct ieee802154_dev * dev , u8 mode )
{
struct at86rf230_local * lp = dev - > priv ;
return at86rf230_write_subreg ( lp , SR_CCA_MODE , mode ) ;
}
2014-02-17 14:34:12 +04:00
static int
at86rf212_set_cca_ed_level ( struct ieee802154_dev * dev , s32 level )
{
struct at86rf230_local * lp = dev - > priv ;
int desens_steps ;
if ( level < lp - > rssi_base_val | | level > 30 )
return - EINVAL ;
desens_steps = ( level - lp - > rssi_base_val ) * 100 / 207 ;
return at86rf230_write_subreg ( lp , SR_CCA_ED_THRES , desens_steps ) ;
}
2014-02-17 14:34:15 +04:00
static int
at86rf212_set_csma_params ( struct ieee802154_dev * dev , u8 min_be , u8 max_be ,
u8 retries )
{
struct at86rf230_local * lp = dev - > priv ;
int rc ;
if ( min_be > max_be | | max_be > 8 | | retries > 5 )
return - EINVAL ;
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 ;
return at86rf230_write_subreg ( lp , SR_MAX_CSMA_RETRIES , max_be ) ;
}
static int
at86rf212_set_frame_retries ( struct ieee802154_dev * dev , s8 retries )
{
struct at86rf230_local * lp = dev - > priv ;
int rc = 0 ;
if ( retries < - 1 | | retries > 15 )
return - EINVAL ;
lp - > tx_aret = retries > = 0 ;
if ( retries > = 0 )
rc = at86rf230_write_subreg ( lp , SR_MAX_FRAME_RETRIES , retries ) ;
return rc ;
}
2012-06-26 03:24:53 +04:00
static struct ieee802154_ops at86rf230_ops = {
. owner = THIS_MODULE ,
. xmit = at86rf230_xmit ,
. 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 ,
2012-06-26 03:24:53 +04:00
} ;
2014-02-17 14:34:06 +04:00
static struct ieee802154_ops at86rf212_ops = {
. owner = THIS_MODULE ,
. xmit = at86rf230_xmit ,
. ed = at86rf230_ed ,
. set_channel = at86rf230_channel ,
. start = at86rf230_start ,
. stop = at86rf230_stop ,
. set_hw_addr_filt = at86rf230_set_hw_addr_filt ,
2014-02-17 14:34:08 +04:00
. set_txpower = at86rf212_set_txpower ,
2014-02-17 14:34:10 +04:00
. set_lbt = at86rf212_set_lbt ,
2014-02-17 14:34:11 +04:00
. set_cca_mode = at86rf212_set_cca_mode ,
2014-02-17 14:34:12 +04:00
. set_cca_ed_level = at86rf212_set_cca_ed_level ,
2014-02-17 14:34:15 +04:00
. set_csma_params = at86rf212_set_csma_params ,
. set_frame_retries = at86rf212_set_frame_retries ,
2014-02-17 14:34:06 +04:00
} ;
2012-06-26 03:24:53 +04:00
static void at86rf230_irqwork ( struct work_struct * work )
{
struct at86rf230_local * lp =
container_of ( work , struct at86rf230_local , irqwork ) ;
u8 status = 0 , val ;
int rc ;
unsigned long flags ;
rc = at86rf230_read_subreg ( lp , RG_IRQ_STATUS , 0xff , 0 , & val ) ;
status | = val ;
status & = ~ IRQ_PLL_LOCK ; /* ignore */
status & = ~ IRQ_RX_START ; /* ignore */
status & = ~ IRQ_AMI ; /* ignore */
status & = ~ IRQ_TRX_UR ; /* FIXME: possibly handle ???*/
if ( status & IRQ_TRX_END ) {
2012-07-11 01:22:43 +04:00
spin_lock_irqsave ( & lp - > lock , flags ) ;
2012-06-26 03:24:53 +04:00
status & = ~ IRQ_TRX_END ;
if ( lp - > is_tx ) {
lp - > is_tx = 0 ;
2012-07-11 01:22:43 +04:00
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
2012-06-26 03:24:53 +04:00
complete ( & lp - > tx_complete ) ;
} else {
2012-07-11 01:22:43 +04:00
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
2012-06-26 03:24:53 +04:00
at86rf230_rx ( lp ) ;
}
}
2012-07-11 01:22:43 +04:00
spin_lock_irqsave ( & lp - > lock , flags ) ;
2013-04-15 02:33:29 +04:00
lp - > irq_busy = 0 ;
2012-06-26 03:24:53 +04:00
spin_unlock_irqrestore ( & lp - > lock , flags ) ;
2013-04-15 02:33:29 +04:00
}
static void at86rf230_irqwork_level ( struct work_struct * work )
{
struct at86rf230_local * lp =
container_of ( work , struct at86rf230_local , irqwork ) ;
at86rf230_irqwork ( work ) ;
2012-07-11 01:22:43 +04:00
enable_irq ( lp - > spi - > irq ) ;
2012-06-26 03:24:53 +04:00
}
static irqreturn_t at86rf230_isr ( int irq , void * data )
{
struct at86rf230_local * lp = data ;
spin_lock ( & lp - > lock ) ;
2013-04-15 02:33:29 +04:00
lp - > irq_busy = 1 ;
2012-06-26 03:24:53 +04:00
spin_unlock ( & lp - > lock ) ;
schedule_work ( & lp - > irqwork ) ;
return IRQ_HANDLED ;
}
2013-04-15 02:33:29 +04:00
static irqreturn_t at86rf230_isr_level ( int irq , void * data )
{
disable_irq_nosync ( irq ) ;
return at86rf230_isr ( irq , data ) ;
}
2013-04-15 02:33:28 +04:00
static int at86rf230_irq_polarity ( struct at86rf230_local * lp , int pol )
{
return at86rf230_write_subreg ( lp , SR_IRQ_POLARITY , pol ) ;
}
2012-06-26 03:24:53 +04:00
static int at86rf230_hw_init ( struct at86rf230_local * lp )
{
2013-04-15 02:33:28 +04:00
struct at86rf230_platform_data * pdata = lp - > spi - > dev . platform_data ;
int rc , irq_pol ;
2012-06-26 03:24:53 +04:00
u8 status ;
2014-02-17 14:34:15 +04:00
u8 csma_seed [ 2 ] ;
2012-06-26 03:24:53 +04:00
rc = at86rf230_read_subreg ( lp , SR_TRX_STATUS , & status ) ;
if ( rc )
return rc ;
2014-02-17 14:34:13 +04:00
rc = at86rf230_write_subreg ( lp , SR_TRX_CMD , STATE_FORCE_TRX_OFF ) ;
if ( rc )
return rc ;
2012-06-26 03:24:53 +04:00
2013-04-15 02:33:28 +04:00
/* configure irq polarity, defaults to high active */
if ( pdata - > irq_type & ( IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW ) )
irq_pol = IRQ_ACTIVE_LOW ;
else
irq_pol = IRQ_ACTIVE_HIGH ;
rc = at86rf230_irq_polarity ( lp , irq_pol ) ;
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 ;
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 */
msleep ( 100 ) ;
rc = at86rf230_read_subreg ( lp , SR_DVDD_OK , & status ) ;
if ( rc )
return rc ;
if ( ! status ) {
dev_err ( & lp - > spi - > dev , " DVDD error \n " ) ;
return - EINVAL ;
}
rc = at86rf230_read_subreg ( lp , SR_AVDD_OK , & status ) ;
if ( rc )
return rc ;
if ( ! status ) {
dev_err ( & lp - > spi - > dev , " AVDD error \n " ) ;
return - EINVAL ;
}
return 0 ;
}
2012-12-03 18:24:12 +04:00
static int at86rf230_probe ( struct spi_device * spi )
2012-06-26 03:24:53 +04:00
{
2013-04-15 02:33:28 +04:00
struct at86rf230_platform_data * pdata ;
2012-06-26 03:24:53 +04:00
struct ieee802154_dev * dev ;
struct at86rf230_local * lp ;
2014-02-17 14:34:06 +04:00
u16 man_id = 0 ;
u8 part = 0 , version = 0 , status ;
2013-04-15 02:33:29 +04:00
irq_handler_t irq_handler ;
work_func_t irq_worker ;
2014-02-17 14:34:06 +04:00
int rc ;
2012-06-26 03:24:53 +04:00
const char * chip ;
2014-02-17 14:34:06 +04:00
struct ieee802154_ops * ops = NULL ;
2012-06-26 03:24:53 +04:00
if ( ! spi - > irq ) {
dev_err ( & spi - > dev , " no IRQ specified \n " ) ;
return - EINVAL ;
}
2013-04-15 02:33:28 +04:00
pdata = spi - > dev . platform_data ;
if ( ! pdata ) {
dev_err ( & spi - > dev , " no platform_data \n " ) ;
return - EINVAL ;
}
2014-02-17 14:34:06 +04:00
rc = gpio_request ( pdata - > rstn , " rstn " ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
2014-02-17 14:34:06 +04:00
return rc ;
2012-06-26 03:24:53 +04:00
2014-02-17 14:34:06 +04:00
if ( gpio_is_valid ( pdata - > slp_tr ) ) {
rc = gpio_request ( pdata - > slp_tr , " slp_tr " ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
goto err_slp_tr ;
}
2014-02-17 14:34:06 +04:00
rc = gpio_direction_output ( pdata - > rstn , 1 ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
goto err_gpio_dir ;
2014-02-17 14:34:06 +04:00
if ( gpio_is_valid ( pdata - > slp_tr ) ) {
rc = gpio_direction_output ( pdata - > slp_tr , 0 ) ;
2012-06-26 03:24:53 +04:00
if ( rc )
goto err_gpio_dir ;
}
/* Reset */
msleep ( 1 ) ;
2014-02-17 14:34:06 +04:00
gpio_set_value ( pdata - > rstn , 0 ) ;
2012-06-26 03:24:53 +04:00
msleep ( 1 ) ;
2014-02-17 14:34:06 +04:00
gpio_set_value ( pdata - > rstn , 1 ) ;
2012-06-26 03:24:53 +04:00
msleep ( 1 ) ;
2014-02-17 14:34:06 +04:00
rc = __at86rf230_detect_device ( spi , & man_id , & part , & version ) ;
if ( rc < 0 )
2012-06-26 03:24:53 +04:00
goto err_gpio_dir ;
2014-02-17 14:34:06 +04:00
if ( man_id ! = 0x001f ) {
2012-06-26 03:24:53 +04:00
dev_err ( & spi - > dev , " Non-Atmel dev found (MAN_ID %02x %02x) \n " ,
2014-02-17 14:34:06 +04:00
man_id > > 8 , man_id & 0xFF ) ;
2012-06-26 03:24:53 +04:00
rc = - EINVAL ;
goto err_gpio_dir ;
}
2014-02-17 14:34:06 +04:00
switch ( part ) {
2012-06-26 03:24:53 +04:00
case 2 :
chip = " at86rf230 " ;
2014-02-17 14:34:06 +04:00
/* FIXME: should be easy to support; */
2012-06-26 03:24:53 +04:00
break ;
case 3 :
chip = " at86rf231 " ;
2014-02-17 14:34:06 +04:00
ops = & at86rf230_ops ;
break ;
case 7 :
chip = " at86rf212 " ;
if ( version = = 1 )
ops = & at86rf212_ops ;
2012-06-26 03:24:53 +04:00
break ;
2014-03-11 04:29:25 +04:00
case 11 :
chip = " at86rf233 " ;
ops = & at86rf230_ops ;
break ;
2012-06-26 03:24:53 +04:00
default :
chip = " UNKNOWN " ;
break ;
}
2014-02-17 14:34:06 +04:00
dev_info ( & spi - > dev , " Detected %s chip version %d \n " , chip , version ) ;
if ( ! ops ) {
2012-06-26 03:24:53 +04:00
rc = - ENOTSUPP ;
goto err_gpio_dir ;
}
2014-02-17 14:34:06 +04:00
dev = ieee802154_alloc_device ( sizeof ( * lp ) , ops ) ;
if ( ! dev ) {
rc = - ENOMEM ;
goto err_gpio_dir ;
}
lp = dev - > priv ;
lp - > dev = dev ;
lp - > part = part ;
lp - > vers = version ;
lp - > spi = spi ;
dev - > parent = & spi - > dev ;
dev - > extra_tx_headroom = 0 ;
dev - > flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK ;
if ( pdata - > irq_type & ( IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING ) ) {
irq_worker = at86rf230_irqwork ;
irq_handler = at86rf230_isr ;
} else {
irq_worker = at86rf230_irqwork_level ;
irq_handler = at86rf230_isr_level ;
}
mutex_init ( & lp - > bmux ) ;
INIT_WORK ( & lp - > irqwork , irq_worker ) ;
spin_lock_init ( & lp - > lock ) ;
init_completion ( & lp - > tx_complete ) ;
spi_set_drvdata ( spi , lp ) ;
2014-02-17 14:34:09 +04:00
if ( is_rf212 ( lp ) ) {
2014-02-17 14:34:06 +04:00
dev - > phy - > channels_supported [ 0 ] = 0x00007FF ;
2014-02-17 14:34:09 +04:00
dev - > phy - > channels_supported [ 2 ] = 0x00007FF ;
} else {
2014-02-17 14:34:06 +04:00
dev - > phy - > channels_supported [ 0 ] = 0x7FFF800 ;
2014-02-17 14:34:09 +04:00
}
2014-02-17 14:34:06 +04:00
2012-06-26 03:24:53 +04:00
rc = at86rf230_hw_init ( lp ) ;
if ( rc )
2014-02-17 14:34:06 +04:00
goto err_hw_init ;
2012-06-26 03:24:53 +04:00
2013-04-15 02:33:29 +04:00
rc = request_irq ( spi - > irq , irq_handler ,
2013-04-15 02:33:28 +04:00
IRQF_SHARED | pdata - > irq_type ,
2012-06-26 03:24:53 +04:00
dev_name ( & spi - > dev ) , lp ) ;
if ( rc )
2014-02-17 14:34:06 +04:00
goto err_hw_init ;
2012-06-26 03:24:53 +04:00
2013-04-15 02:33:29 +04:00
/* Read irq status register to reset irq line */
rc = at86rf230_read_subreg ( lp , RG_IRQ_STATUS , 0xff , 0 , & status ) ;
if ( rc )
goto err_irq ;
2012-06-26 03:24:53 +04:00
rc = ieee802154_register_device ( lp - > dev ) ;
if ( rc )
goto err_irq ;
return rc ;
err_irq :
free_irq ( spi - > irq , lp ) ;
2014-02-17 14:34:06 +04:00
err_hw_init :
2012-06-26 03:24:53 +04:00
flush_work ( & lp - > irqwork ) ;
2014-02-17 14:34:06 +04:00
spi_set_drvdata ( spi , NULL ) ;
2012-06-26 03:24:53 +04:00
mutex_destroy ( & lp - > bmux ) ;
ieee802154_free_device ( lp - > dev ) ;
2014-02-17 14:34:06 +04:00
err_gpio_dir :
if ( gpio_is_valid ( pdata - > slp_tr ) )
gpio_free ( pdata - > slp_tr ) ;
err_slp_tr :
gpio_free ( pdata - > rstn ) ;
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-02-17 14:34:06 +04:00
struct at86rf230_platform_data * pdata = spi - > dev . platform_data ;
2012-06-26 03:24:53 +04:00
ieee802154_unregister_device ( lp - > dev ) ;
free_irq ( spi - > irq , lp ) ;
flush_work ( & lp - > irqwork ) ;
2014-02-17 14:34:06 +04:00
if ( gpio_is_valid ( pdata - > slp_tr ) )
gpio_free ( pdata - > slp_tr ) ;
gpio_free ( pdata - > rstn ) ;
2012-06-26 03:24:53 +04:00
mutex_destroy ( & lp - > bmux ) ;
ieee802154_free_device ( lp - > dev ) ;
dev_dbg ( & spi - > dev , " unregistered at86rf230 \n " ) ;
return 0 ;
}
static struct spi_driver at86rf230_driver = {
. driver = {
. name = " at86rf230 " ,
. owner = THIS_MODULE ,
} ,
. 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 " ) ;