2012-09-02 19:44:13 +04:00
/*
* Driver for Microchip MRF24J40 802.15 .4 Wireless - PAN Networking controller
*
* Copyright ( C ) 2012 Alan Ott < alan @ signal11 . us >
* Signal 11 Software
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 .
*/
# include <linux/spi/spi.h>
# include <linux/interrupt.h>
# include <linux/module.h>
2017-03-29 00:45:06 +03:00
# include <linux/of.h>
2015-09-21 12:24:30 +03:00
# include <linux/regmap.h>
2014-10-25 11:41:04 +04:00
# include <linux/ieee802154.h>
2015-09-21 12:24:42 +03:00
# include <linux/irq.h>
2014-10-25 11:41:02 +04:00
# include <net/cfg802154.h>
2012-09-02 19:44:13 +04:00
# include <net/mac802154.h>
/* MRF24J40 Short Address Registers */
2015-09-21 12:24:22 +03:00
# define REG_RXMCR 0x00 /* Receive MAC control */
2015-09-21 12:24:43 +03:00
# define BIT_PROMI BIT(0)
# define BIT_ERRPKT BIT(1)
# define BIT_NOACKRSP BIT(5)
# define BIT_PANCOORD BIT(3)
2015-09-21 12:24:22 +03:00
# define REG_PANIDL 0x01 /* PAN ID (low) */
# define REG_PANIDH 0x02 /* PAN ID (high) */
# define REG_SADRL 0x03 /* Short address (low) */
# define REG_SADRH 0x04 /* Short address (high) */
# define REG_EADR0 0x05 /* Long address (low) (high is EADR7) */
2015-09-21 12:24:29 +03:00
# define REG_EADR1 0x06
# define REG_EADR2 0x07
# define REG_EADR3 0x08
# define REG_EADR4 0x09
# define REG_EADR5 0x0A
# define REG_EADR6 0x0B
# define REG_EADR7 0x0C
# define REG_RXFLUSH 0x0D
# define REG_ORDER 0x10
2015-09-21 12:24:22 +03:00
# define REG_TXMCR 0x11 /* Transmit MAC control */
2015-09-21 12:24:43 +03:00
# define TXMCR_MIN_BE_SHIFT 3
# define TXMCR_MIN_BE_MASK 0x18
# define TXMCR_CSMA_RETRIES_SHIFT 0
# define TXMCR_CSMA_RETRIES_MASK 0x07
2015-09-21 12:24:29 +03:00
# define REG_ACKTMOUT 0x12
# define REG_ESLOTG1 0x13
# define REG_SYMTICKL 0x14
# define REG_SYMTICKH 0x15
2015-09-21 12:24:22 +03:00
# define REG_PACON0 0x16 /* Power Amplifier Control */
# define REG_PACON1 0x17 /* Power Amplifier Control */
# define REG_PACON2 0x18 /* Power Amplifier Control */
2015-09-21 12:24:29 +03:00
# define REG_TXBCON0 0x1A
2015-09-21 12:24:22 +03:00
# define REG_TXNCON 0x1B /* Transmit Normal FIFO Control */
2015-09-21 12:24:43 +03:00
# define BIT_TXNTRIG BIT(0)
2016-04-12 19:53:02 +03:00
# define BIT_TXNSECEN BIT(1)
2015-09-21 12:24:43 +03:00
# define BIT_TXNACKREQ BIT(2)
2015-09-21 12:24:29 +03:00
# define REG_TXG1CON 0x1C
# define REG_TXG2CON 0x1D
# define REG_ESLOTG23 0x1E
# define REG_ESLOTG45 0x1F
# define REG_ESLOTG67 0x20
# define REG_TXPEND 0x21
# define REG_WAKECON 0x22
# define REG_FROMOFFSET 0x23
2015-09-21 12:24:22 +03:00
# define REG_TXSTAT 0x24 /* TX MAC Status Register */
2015-09-21 12:24:29 +03:00
# define REG_TXBCON1 0x25
# define REG_GATECLK 0x26
# define REG_TXTIME 0x27
# define REG_HSYMTMRL 0x28
# define REG_HSYMTMRH 0x29
2015-09-21 12:24:22 +03:00
# define REG_SOFTRST 0x2A /* Soft Reset */
2015-09-21 12:24:29 +03:00
# define REG_SECCON0 0x2C
# define REG_SECCON1 0x2D
2015-09-21 12:24:22 +03:00
# define REG_TXSTBL 0x2E /* TX Stabilization */
2015-09-21 12:24:29 +03:00
# define REG_RXSR 0x30
2015-09-21 12:24:22 +03:00
# define REG_INTSTAT 0x31 /* Interrupt Status */
2015-09-21 12:24:43 +03:00
# define BIT_TXNIF BIT(0)
# define BIT_RXIF BIT(3)
2016-04-12 19:53:01 +03:00
# define BIT_SECIF BIT(4)
# define BIT_SECIGNORE BIT(7)
2015-09-21 12:24:43 +03:00
2015-09-21 12:24:22 +03:00
# define REG_INTCON 0x32 /* Interrupt Control */
2015-09-21 12:24:43 +03:00
# define BIT_TXNIE BIT(0)
# define BIT_RXIE BIT(3)
2016-04-12 19:53:01 +03:00
# define BIT_SECIE BIT(4)
2015-09-21 12:24:43 +03:00
2015-09-21 12:24:22 +03:00
# define REG_GPIO 0x33 /* GPIO */
# define REG_TRISGPIO 0x34 /* GPIO direction */
2015-09-21 12:24:29 +03:00
# define REG_SLPACK 0x35
2015-09-21 12:24:22 +03:00
# define REG_RFCTL 0x36 /* RF Control Mode Register */
2015-09-21 12:24:43 +03:00
# define BIT_RFRST BIT(2)
2015-09-21 12:24:29 +03:00
# define REG_SECCR2 0x37
# define REG_BBREG0 0x38
2015-09-21 12:24:22 +03:00
# define REG_BBREG1 0x39 /* Baseband Registers */
2015-09-21 12:24:43 +03:00
# define BIT_RXDECINV BIT(2)
2015-09-21 12:24:22 +03:00
# define REG_BBREG2 0x3A /* */
2015-09-21 12:24:43 +03:00
# define BBREG2_CCA_MODE_SHIFT 6
# define BBREG2_CCA_MODE_MASK 0xc0
2015-09-21 12:24:29 +03:00
# define REG_BBREG3 0x3B
# define REG_BBREG4 0x3C
2015-09-21 12:24:22 +03:00
# define REG_BBREG6 0x3E /* */
# define REG_CCAEDTH 0x3F /* Energy Detection Threshold */
2012-09-02 19:44:13 +04:00
/* MRF24J40 Long Address Registers */
2015-09-21 12:24:22 +03:00
# define REG_RFCON0 0x200 /* RF Control Registers */
2015-09-21 12:24:43 +03:00
# define RFCON0_CH_SHIFT 4
# define RFCON0_CH_MASK 0xf0
# define RFOPT_RECOMMEND 3
2015-09-21 12:24:22 +03:00
# define REG_RFCON1 0x201
# define REG_RFCON2 0x202
# define REG_RFCON3 0x203
2015-09-21 12:24:43 +03:00
# define TXPWRL_MASK 0xc0
# define TXPWRL_SHIFT 6
# define TXPWRL_30 0x3
# define TXPWRL_20 0x2
# define TXPWRL_10 0x1
# define TXPWRL_0 0x0
# define TXPWRS_MASK 0x38
# define TXPWRS_SHIFT 3
# define TXPWRS_6_3 0x7
# define TXPWRS_4_9 0x6
# define TXPWRS_3_7 0x5
# define TXPWRS_2_8 0x4
# define TXPWRS_1_9 0x3
# define TXPWRS_1_2 0x2
# define TXPWRS_0_5 0x1
# define TXPWRS_0 0x0
2015-09-21 12:24:22 +03:00
# define REG_RFCON5 0x205
# define REG_RFCON6 0x206
# define REG_RFCON7 0x207
# define REG_RFCON8 0x208
2015-09-21 12:24:29 +03:00
# define REG_SLPCAL0 0x209
# define REG_SLPCAL1 0x20A
# define REG_SLPCAL2 0x20B
# define REG_RFSTATE 0x20F
2015-09-21 12:24:22 +03:00
# define REG_RSSI 0x210
# define REG_SLPCON0 0x211 /* Sleep Clock Control Registers */
2015-09-21 12:24:43 +03:00
# define BIT_INTEDGE BIT(1)
2015-09-21 12:24:22 +03:00
# define REG_SLPCON1 0x220
# define REG_WAKETIMEL 0x222 /* Wake-up Time Match Value Low */
# define REG_WAKETIMEH 0x223 /* Wake-up Time Match Value High */
2015-09-21 12:24:29 +03:00
# define REG_REMCNTL 0x224
# define REG_REMCNTH 0x225
# define REG_MAINCNT0 0x226
# define REG_MAINCNT1 0x227
# define REG_MAINCNT2 0x228
# define REG_MAINCNT3 0x229
2015-09-21 12:24:22 +03:00
# define REG_TESTMODE 0x22F /* Test mode */
2015-09-21 12:24:29 +03:00
# define REG_ASSOEAR0 0x230
# define REG_ASSOEAR1 0x231
# define REG_ASSOEAR2 0x232
# define REG_ASSOEAR3 0x233
# define REG_ASSOEAR4 0x234
# define REG_ASSOEAR5 0x235
# define REG_ASSOEAR6 0x236
# define REG_ASSOEAR7 0x237
# define REG_ASSOSAR0 0x238
# define REG_ASSOSAR1 0x239
# define REG_UNONCE0 0x240
# define REG_UNONCE1 0x241
# define REG_UNONCE2 0x242
# define REG_UNONCE3 0x243
# define REG_UNONCE4 0x244
# define REG_UNONCE5 0x245
# define REG_UNONCE6 0x246
# define REG_UNONCE7 0x247
# define REG_UNONCE8 0x248
# define REG_UNONCE9 0x249
# define REG_UNONCE10 0x24A
# define REG_UNONCE11 0x24B
# define REG_UNONCE12 0x24C
2015-09-21 12:24:22 +03:00
# define REG_RX_FIFO 0x300 /* Receive FIFO */
2012-09-02 19:44:13 +04:00
/* Device configuration: Only channels 11-26 on page 0 are supported. */
# define MRF24J40_CHAN_MIN 11
# define MRF24J40_CHAN_MAX 26
# define CHANNEL_MASK (((u32)1 << (MRF24J40_CHAN_MAX + 1)) \
- ( ( u32 ) 1 < < MRF24J40_CHAN_MIN ) )
# define TX_FIFO_SIZE 128 /* From datasheet */
# define RX_FIFO_SIZE 144 /* From datasheet */
# define SET_CHANNEL_DELAY_US 192 /* From datasheet */
2014-10-06 13:39:45 +04:00
enum mrf24j40_modules { MRF24J40 , MRF24J40MA , MRF24J40MC } ;
2012-09-02 19:44:13 +04:00
/* Device Private Data */
struct mrf24j40 {
struct spi_device * spi ;
2014-10-25 19:16:34 +04:00
struct ieee802154_hw * hw ;
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:30 +03:00
struct regmap * regmap_short ;
struct regmap * regmap_long ;
2015-09-21 12:24:34 +03:00
/* for writing txfifo */
struct spi_message tx_msg ;
u8 tx_hdr_buf [ 2 ] ;
struct spi_transfer tx_hdr_trx ;
u8 tx_len_buf [ 2 ] ;
struct spi_transfer tx_len_trx ;
struct spi_transfer tx_buf_trx ;
struct sk_buff * tx_skb ;
/* post transmit message to send frame out */
struct spi_message tx_post_msg ;
u8 tx_post_buf [ 2 ] ;
struct spi_transfer tx_post_trx ;
2015-09-21 12:24:35 +03:00
/* for protect/unprotect/read length rxfifo */
struct spi_message rx_msg ;
u8 rx_buf [ 3 ] ;
struct spi_transfer rx_trx ;
/* receive handling */
struct spi_message rx_buf_msg ;
u8 rx_addr_buf [ 2 ] ;
struct spi_transfer rx_addr_trx ;
u8 rx_lqi_buf [ 2 ] ;
struct spi_transfer rx_lqi_trx ;
u8 rx_fifo_buf [ RX_FIFO_SIZE ] ;
struct spi_transfer rx_fifo_buf_trx ;
2015-09-21 12:24:36 +03:00
/* isr handling for reading intstat */
struct spi_message irq_msg ;
u8 irq_buf [ 2 ] ;
struct spi_transfer irq_trx ;
2012-09-02 19:44:13 +04:00
} ;
2015-09-21 12:24:30 +03:00
/* regmap information for short address register access */
# define MRF24J40_SHORT_WRITE 0x01
# define MRF24J40_SHORT_READ 0x00
# define MRF24J40_SHORT_NUMREGS 0x3F
/* regmap information for long address register access */
# define MRF24J40_LONG_ACCESS 0x80
# define MRF24J40_LONG_NUMREGS 0x38F
2012-09-02 19:44:13 +04:00
/* Read/Write SPI Commands for Short and Long Address registers. */
# define MRF24J40_READSHORT(reg) ((reg) << 1)
# define MRF24J40_WRITESHORT(reg) ((reg) << 1 | 1)
# define MRF24J40_READLONG(reg) (1 << 15 | (reg) << 5)
# define MRF24J40_WRITELONG(reg) (1 << 15 | (reg) << 5 | 1 << 4)
2013-03-18 16:06:42 +04:00
/* The datasheet indicates the theoretical maximum for SCK to be 10MHz */
# define MAX_SPI_SPEED_HZ 10000000
2012-09-02 19:44:13 +04:00
# define printdev(X) (&X->spi->dev)
2015-09-21 12:24:30 +03:00
static bool
mrf24j40_short_reg_writeable ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case REG_RXMCR :
case REG_PANIDL :
case REG_PANIDH :
case REG_SADRL :
case REG_SADRH :
case REG_EADR0 :
case REG_EADR1 :
case REG_EADR2 :
case REG_EADR3 :
case REG_EADR4 :
case REG_EADR5 :
case REG_EADR6 :
case REG_EADR7 :
case REG_RXFLUSH :
case REG_ORDER :
case REG_TXMCR :
case REG_ACKTMOUT :
case REG_ESLOTG1 :
case REG_SYMTICKL :
case REG_SYMTICKH :
case REG_PACON0 :
case REG_PACON1 :
case REG_PACON2 :
case REG_TXBCON0 :
case REG_TXNCON :
case REG_TXG1CON :
case REG_TXG2CON :
case REG_ESLOTG23 :
case REG_ESLOTG45 :
case REG_ESLOTG67 :
case REG_TXPEND :
case REG_WAKECON :
case REG_FROMOFFSET :
case REG_TXBCON1 :
case REG_GATECLK :
case REG_TXTIME :
case REG_HSYMTMRL :
case REG_HSYMTMRH :
case REG_SOFTRST :
case REG_SECCON0 :
case REG_SECCON1 :
case REG_TXSTBL :
case REG_RXSR :
case REG_INTCON :
case REG_TRISGPIO :
case REG_GPIO :
case REG_RFCTL :
2016-02-19 11:59:14 +03:00
case REG_SECCR2 :
2015-09-21 12:24:30 +03:00
case REG_SLPACK :
case REG_BBREG0 :
case REG_BBREG1 :
case REG_BBREG2 :
case REG_BBREG3 :
case REG_BBREG4 :
case REG_BBREG6 :
case REG_CCAEDTH :
return true ;
default :
return false ;
}
}
static bool
mrf24j40_short_reg_readable ( struct device * dev , unsigned int reg )
{
bool rc ;
/* all writeable are also readable */
rc = mrf24j40_short_reg_writeable ( dev , reg ) ;
if ( rc )
return rc ;
/* readonly regs */
switch ( reg ) {
case REG_TXSTAT :
case REG_INTSTAT :
return true ;
default :
return false ;
}
}
static bool
mrf24j40_short_reg_volatile ( struct device * dev , unsigned int reg )
{
/* can be changed during runtime */
switch ( reg ) {
case REG_TXSTAT :
case REG_INTSTAT :
case REG_RXFLUSH :
case REG_TXNCON :
case REG_SOFTRST :
case REG_RFCTL :
case REG_TXBCON0 :
case REG_TXG1CON :
case REG_TXG2CON :
case REG_TXBCON1 :
case REG_SECCON0 :
case REG_RXSR :
case REG_SLPACK :
case REG_SECCR2 :
case REG_BBREG6 :
/* use them in spi_async and regmap so it's volatile */
case REG_BBREG1 :
return true ;
default :
return false ;
}
}
static bool
mrf24j40_short_reg_precious ( struct device * dev , unsigned int reg )
{
/* don't clear irq line on read */
switch ( reg ) {
case REG_INTSTAT :
return true ;
default :
return false ;
}
}
static const struct regmap_config mrf24j40_short_regmap = {
. name = " mrf24j40_short " ,
. reg_bits = 7 ,
. val_bits = 8 ,
. pad_bits = 1 ,
. write_flag_mask = MRF24J40_SHORT_WRITE ,
. read_flag_mask = MRF24J40_SHORT_READ ,
. cache_type = REGCACHE_RBTREE ,
. max_register = MRF24J40_SHORT_NUMREGS ,
. writeable_reg = mrf24j40_short_reg_writeable ,
. readable_reg = mrf24j40_short_reg_readable ,
. volatile_reg = mrf24j40_short_reg_volatile ,
. precious_reg = mrf24j40_short_reg_precious ,
} ;
static bool
mrf24j40_long_reg_writeable ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case REG_RFCON0 :
case REG_RFCON1 :
case REG_RFCON2 :
case REG_RFCON3 :
case REG_RFCON5 :
case REG_RFCON6 :
case REG_RFCON7 :
case REG_RFCON8 :
case REG_SLPCAL2 :
case REG_SLPCON0 :
case REG_SLPCON1 :
case REG_WAKETIMEL :
case REG_WAKETIMEH :
case REG_REMCNTL :
case REG_REMCNTH :
case REG_MAINCNT0 :
case REG_MAINCNT1 :
case REG_MAINCNT2 :
case REG_MAINCNT3 :
case REG_TESTMODE :
case REG_ASSOEAR0 :
case REG_ASSOEAR1 :
case REG_ASSOEAR2 :
case REG_ASSOEAR3 :
case REG_ASSOEAR4 :
case REG_ASSOEAR5 :
case REG_ASSOEAR6 :
case REG_ASSOEAR7 :
case REG_ASSOSAR0 :
case REG_ASSOSAR1 :
case REG_UNONCE0 :
case REG_UNONCE1 :
case REG_UNONCE2 :
case REG_UNONCE3 :
case REG_UNONCE4 :
case REG_UNONCE5 :
case REG_UNONCE6 :
case REG_UNONCE7 :
case REG_UNONCE8 :
case REG_UNONCE9 :
case REG_UNONCE10 :
case REG_UNONCE11 :
case REG_UNONCE12 :
return true ;
default :
return false ;
}
}
static bool
mrf24j40_long_reg_readable ( struct device * dev , unsigned int reg )
{
bool rc ;
/* all writeable are also readable */
rc = mrf24j40_long_reg_writeable ( dev , reg ) ;
if ( rc )
return rc ;
/* readonly regs */
switch ( reg ) {
case REG_SLPCAL0 :
case REG_SLPCAL1 :
case REG_RFSTATE :
case REG_RSSI :
return true ;
default :
return false ;
}
}
static bool
mrf24j40_long_reg_volatile ( struct device * dev , unsigned int reg )
{
/* can be changed during runtime */
switch ( reg ) {
case REG_SLPCAL0 :
case REG_SLPCAL1 :
case REG_SLPCAL2 :
case REG_RFSTATE :
case REG_RSSI :
case REG_MAINCNT3 :
return true ;
default :
return false ;
}
}
static const struct regmap_config mrf24j40_long_regmap = {
. name = " mrf24j40_long " ,
. reg_bits = 11 ,
. val_bits = 8 ,
. pad_bits = 5 ,
. write_flag_mask = MRF24J40_LONG_ACCESS ,
. read_flag_mask = MRF24J40_LONG_ACCESS ,
. cache_type = REGCACHE_RBTREE ,
. max_register = MRF24J40_LONG_NUMREGS ,
. writeable_reg = mrf24j40_long_reg_writeable ,
. readable_reg = mrf24j40_long_reg_readable ,
. volatile_reg = mrf24j40_long_reg_volatile ,
} ;
static int mrf24j40_long_regmap_write ( void * context , const void * data ,
size_t count )
{
struct spi_device * spi = context ;
u8 buf [ 3 ] ;
if ( count > 3 )
return - EINVAL ;
/* regmap supports read/write mask only in frist byte
* long write access need to set the 12 th bit , so we
* make special handling for write .
*/
memcpy ( buf , data , count ) ;
buf [ 1 ] | = ( 1 < < 4 ) ;
return spi_write ( spi , buf , count ) ;
}
static int
mrf24j40_long_regmap_read ( void * context , const void * reg , size_t reg_size ,
void * val , size_t val_size )
{
struct spi_device * spi = context ;
return spi_write_then_read ( spi , reg , reg_size , val , val_size ) ;
}
static const struct regmap_bus mrf24j40_long_regmap_bus = {
. write = mrf24j40_long_regmap_write ,
. read = mrf24j40_long_regmap_read ,
. reg_format_endian_default = REGMAP_ENDIAN_BIG ,
. val_format_endian_default = REGMAP_ENDIAN_BIG ,
} ;
2015-09-21 12:24:34 +03:00
static void write_tx_buf_complete ( void * context )
{
struct mrf24j40 * devrec = context ;
__le16 fc = ieee802154_get_fc_from_skb ( devrec - > tx_skb ) ;
2015-09-21 12:24:43 +03:00
u8 val = BIT_TXNTRIG ;
2015-09-21 12:24:34 +03:00
int ret ;
2016-04-12 19:53:02 +03:00
if ( ieee802154_is_secen ( fc ) )
val | = BIT_TXNSECEN ;
2015-09-21 12:24:34 +03:00
if ( ieee802154_is_ackreq ( fc ) )
2015-09-21 12:24:43 +03:00
val | = BIT_TXNACKREQ ;
2015-09-21 12:24:34 +03:00
devrec - > tx_post_msg . complete = NULL ;
devrec - > tx_post_buf [ 0 ] = MRF24J40_WRITESHORT ( REG_TXNCON ) ;
devrec - > tx_post_buf [ 1 ] = val ;
ret = spi_async ( devrec - > spi , & devrec - > tx_post_msg ) ;
if ( ret )
dev_err ( printdev ( devrec ) , " SPI write Failed for transmit buf \n " ) ;
}
2012-09-02 19:44:13 +04:00
/* This function relies on an undocumented write method. Once a write command
and address is set , as many bytes of data as desired can be clocked into
the device . The datasheet only shows setting one byte at a time . */
static int write_tx_buf ( struct mrf24j40 * devrec , u16 reg ,
const u8 * data , size_t length )
{
u16 cmd ;
2015-09-21 12:24:34 +03:00
int ret ;
2012-09-02 19:44:13 +04:00
/* Range check the length. 2 bytes are used for the length fields.*/
if ( length > TX_FIFO_SIZE - 2 ) {
dev_err ( printdev ( devrec ) , " write_tx_buf() was passed too large a buffer. Performing short write. \n " ) ;
length = TX_FIFO_SIZE - 2 ;
}
cmd = MRF24J40_WRITELONG ( reg ) ;
2015-09-21 12:24:34 +03:00
devrec - > tx_hdr_buf [ 0 ] = cmd > > 8 & 0xff ;
devrec - > tx_hdr_buf [ 1 ] = cmd & 0xff ;
devrec - > tx_len_buf [ 0 ] = 0x0 ; /* Header Length. Set to 0 for now. TODO */
devrec - > tx_len_buf [ 1 ] = length ; /* Total length */
devrec - > tx_buf_trx . tx_buf = data ;
devrec - > tx_buf_trx . len = length ;
ret = spi_async ( devrec - > spi , & devrec - > tx_msg ) ;
2012-09-02 19:44:13 +04:00
if ( ret )
dev_err ( printdev ( devrec ) , " SPI write Failed for TX buf \n " ) ;
return ret ;
}
2015-09-21 12:24:34 +03:00
static int mrf24j40_tx ( struct ieee802154_hw * hw , struct sk_buff * skb )
{
struct mrf24j40 * devrec = hw - > priv ;
dev_dbg ( printdev ( devrec ) , " tx packet of %d bytes \n " , skb - > len ) ;
devrec - > tx_skb = skb ;
return write_tx_buf ( devrec , 0x000 , skb - > data , skb - > len ) ;
}
2014-10-25 19:16:34 +04:00
static int mrf24j40_ed ( struct ieee802154_hw * hw , u8 * level )
2012-09-02 19:44:13 +04:00
{
/* TODO: */
2014-09-24 14:21:32 +04:00
pr_warn ( " mrf24j40: ed not implemented \n " ) ;
2012-09-02 19:44:13 +04:00
* level = 0 ;
return 0 ;
}
2014-10-25 19:16:34 +04:00
static int mrf24j40_start ( struct ieee802154_hw * hw )
2012-09-02 19:44:13 +04:00
{
2014-10-25 19:16:34 +04:00
struct mrf24j40 * devrec = hw - > priv ;
2012-09-02 19:44:13 +04:00
dev_dbg ( printdev ( devrec ) , " start \n " ) ;
2015-09-21 12:24:31 +03:00
/* Clear TXNIE and RXIE. Enable interrupts */
return regmap_update_bits ( devrec - > regmap_short , REG_INTCON ,
2016-04-12 19:53:01 +03:00
BIT_TXNIE | BIT_RXIE | BIT_SECIE , 0 ) ;
2012-09-02 19:44:13 +04:00
}
2014-10-25 19:16:34 +04:00
static void mrf24j40_stop ( struct ieee802154_hw * hw )
2012-09-02 19:44:13 +04:00
{
2014-10-25 19:16:34 +04:00
struct mrf24j40 * devrec = hw - > priv ;
2014-09-24 14:21:30 +04:00
2012-09-02 19:44:13 +04:00
dev_dbg ( printdev ( devrec ) , " stop \n " ) ;
2015-09-21 12:24:31 +03:00
/* Set TXNIE and RXIE. Disable Interrupts */
2015-09-21 12:24:43 +03:00
regmap_update_bits ( devrec - > regmap_short , REG_INTCON ,
BIT_TXNIE | BIT_TXNIE , BIT_TXNIE | BIT_TXNIE ) ;
2012-09-02 19:44:13 +04:00
}
2014-10-28 20:21:19 +03:00
static int mrf24j40_set_channel ( struct ieee802154_hw * hw , u8 page , u8 channel )
2012-09-02 19:44:13 +04:00
{
2014-10-25 19:16:34 +04:00
struct mrf24j40 * devrec = hw - > priv ;
2012-09-02 19:44:13 +04:00
u8 val ;
int ret ;
dev_dbg ( printdev ( devrec ) , " Set Channel %d \n " , channel ) ;
WARN_ON ( page ! = 0 ) ;
WARN_ON ( channel < MRF24J40_CHAN_MIN ) ;
WARN_ON ( channel > MRF24J40_CHAN_MAX ) ;
/* Set Channel TODO */
2015-09-21 12:24:43 +03:00
val = ( channel - 11 ) < < RFCON0_CH_SHIFT | RFOPT_RECOMMEND ;
ret = regmap_update_bits ( devrec - > regmap_long , REG_RFCON0 ,
RFCON0_CH_MASK , val ) ;
2015-09-21 12:24:31 +03:00
if ( ret )
return ret ;
2012-09-02 19:44:13 +04:00
/* RF Reset */
2015-09-21 12:24:43 +03:00
ret = regmap_update_bits ( devrec - > regmap_short , REG_RFCTL , BIT_RFRST ,
BIT_RFRST ) ;
2012-09-02 19:44:13 +04:00
if ( ret )
return ret ;
2015-09-21 12:24:43 +03:00
ret = regmap_update_bits ( devrec - > regmap_short , REG_RFCTL , BIT_RFRST , 0 ) ;
2015-09-21 12:24:31 +03:00
if ( ! ret )
udelay ( SET_CHANNEL_DELAY_US ) ; /* per datasheet */
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:31 +03:00
return ret ;
2012-09-02 19:44:13 +04:00
}
2014-10-25 19:16:34 +04:00
static int mrf24j40_filter ( struct ieee802154_hw * hw ,
2012-09-02 19:44:13 +04:00
struct ieee802154_hw_addr_filt * filt ,
unsigned long changed )
{
2014-10-25 19:16:34 +04:00
struct mrf24j40 * devrec = hw - > priv ;
2012-09-02 19:44:13 +04:00
dev_dbg ( printdev ( devrec ) , " filter \n " ) ;
2014-10-25 07:25:09 +04:00
if ( changed & IEEE802154_AFILT_SADDR_CHANGED ) {
2012-09-02 19:44:13 +04:00
/* Short Addr */
u8 addrh , addrl ;
2014-09-24 14:21:30 +04:00
2014-03-15 00:23:59 +04:00
addrh = le16_to_cpu ( filt - > short_addr ) > > 8 & 0xff ;
addrl = le16_to_cpu ( filt - > short_addr ) & 0xff ;
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:31 +03:00
regmap_write ( devrec - > regmap_short , REG_SADRH , addrh ) ;
regmap_write ( devrec - > regmap_short , REG_SADRL , addrl ) ;
2012-09-02 19:44:13 +04:00
dev_dbg ( printdev ( devrec ) ,
" Set short addr to %04hx \n " , filt - > short_addr ) ;
}
2014-10-25 07:25:09 +04:00
if ( changed & IEEE802154_AFILT_IEEEADDR_CHANGED ) {
2012-09-02 19:44:13 +04:00
/* Device Address */
2014-03-15 00:23:59 +04:00
u8 i , addr [ 8 ] ;
memcpy ( addr , & filt - > ieee_addr , 8 ) ;
2012-09-02 19:44:13 +04:00
for ( i = 0 ; i < 8 ; i + + )
2015-09-21 12:24:31 +03:00
regmap_write ( devrec - > regmap_short , REG_EADR0 + i ,
addr [ i ] ) ;
2012-09-02 19:44:13 +04:00
# ifdef DEBUG
2014-09-24 14:21:32 +04:00
pr_debug ( " Set long addr to: " ) ;
2012-09-02 19:44:13 +04:00
for ( i = 0 ; i < 8 ; i + + )
2014-09-24 14:21:32 +04:00
pr_debug ( " %02hhx " , addr [ 7 - i ] ) ;
pr_debug ( " \n " ) ;
2012-09-02 19:44:13 +04:00
# endif
}
2014-10-25 07:25:09 +04:00
if ( changed & IEEE802154_AFILT_PANID_CHANGED ) {
2012-09-02 19:44:13 +04:00
/* PAN ID */
u8 panidl , panidh ;
2014-09-24 14:21:30 +04:00
2014-03-15 00:23:59 +04:00
panidh = le16_to_cpu ( filt - > pan_id ) > > 8 & 0xff ;
panidl = le16_to_cpu ( filt - > pan_id ) & 0xff ;
2015-09-21 12:24:31 +03:00
regmap_write ( devrec - > regmap_short , REG_PANIDH , panidh ) ;
regmap_write ( devrec - > regmap_short , REG_PANIDL , panidl ) ;
2012-09-02 19:44:13 +04:00
dev_dbg ( printdev ( devrec ) , " Set PANID to %04hx \n " , filt - > pan_id ) ;
}
2014-10-25 07:25:09 +04:00
if ( changed & IEEE802154_AFILT_PANC_CHANGED ) {
2012-09-02 19:44:13 +04:00
/* Pan Coordinator */
u8 val ;
int ret ;
if ( filt - > pan_coord )
2015-09-21 12:24:43 +03:00
val = BIT_PANCOORD ;
2012-09-02 19:44:13 +04:00
else
2015-09-21 12:24:43 +03:00
val = 0 ;
ret = regmap_update_bits ( devrec - > regmap_short , REG_RXMCR ,
BIT_PANCOORD , val ) ;
2015-09-21 12:24:31 +03:00
if ( ret )
return ret ;
2012-09-02 19:44:13 +04:00
/* REG_SLOTTED is maintained as default (unslotted/CSMA-CA).
* REG_ORDER is maintained as default ( no beacon / superframe ) .
*/
dev_dbg ( printdev ( devrec ) , " Set Pan Coord to %s \n " ,
2014-12-12 14:45:33 +03:00
filt - > pan_coord ? " on " : " off " ) ;
2012-09-02 19:44:13 +04:00
}
return 0 ;
}
2015-09-21 12:24:35 +03:00
static void mrf24j40_handle_rx_read_buf_unlock ( struct mrf24j40 * devrec )
2012-09-02 19:44:13 +04:00
{
2015-09-21 12:24:35 +03:00
int ret ;
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:35 +03:00
/* Turn back on reception of packets off the air. */
devrec - > rx_msg . complete = NULL ;
devrec - > rx_buf [ 0 ] = MRF24J40_WRITESHORT ( REG_BBREG1 ) ;
devrec - > rx_buf [ 1 ] = 0x00 ; /* CLR RXDECINV */
ret = spi_async ( devrec - > spi , & devrec - > rx_msg ) ;
2012-09-02 19:44:13 +04:00
if ( ret )
2015-09-21 12:24:35 +03:00
dev_err ( printdev ( devrec ) , " failed to unlock rx buffer \n " ) ;
}
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:35 +03:00
static void mrf24j40_handle_rx_read_buf_complete ( void * context )
{
struct mrf24j40 * devrec = context ;
u8 len = devrec - > rx_buf [ 2 ] ;
u8 rx_local_buf [ RX_FIFO_SIZE ] ;
struct sk_buff * skb ;
memcpy ( rx_local_buf , devrec - > rx_fifo_buf , len ) ;
mrf24j40_handle_rx_read_buf_unlock ( devrec ) ;
skb = dev_alloc_skb ( IEEE802154_MTU ) ;
2012-09-02 19:44:13 +04:00
if ( ! skb ) {
2015-09-21 12:24:35 +03:00
dev_err ( printdev ( devrec ) , " failed to allocate skb \n " ) ;
return ;
2012-09-02 19:44:13 +04:00
}
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 , rx_local_buf , len ) ;
2015-09-21 12:24:35 +03:00
ieee802154_rx_irqsafe ( devrec - > hw , skb , 0 ) ;
# ifdef DEBUG
print_hex_dump ( KERN_DEBUG , " mrf24j40 rx: " , DUMP_PREFIX_OFFSET , 16 , 1 ,
rx_local_buf , len , 0 ) ;
pr_debug ( " mrf24j40 rx: lqi: %02hhx rssi: %02hhx \n " ,
devrec - > rx_lqi_buf [ 0 ] , devrec - > rx_lqi_buf [ 1 ] ) ;
# endif
}
static void mrf24j40_handle_rx_read_buf ( void * context )
{
struct mrf24j40 * devrec = context ;
u16 cmd ;
int ret ;
/* if length is invalid read the full MTU */
if ( ! ieee802154_is_valid_psdu_len ( devrec - > rx_buf [ 2 ] ) )
devrec - > rx_buf [ 2 ] = IEEE802154_MTU ;
cmd = MRF24J40_READLONG ( REG_RX_FIFO + 1 ) ;
devrec - > rx_addr_buf [ 0 ] = cmd > > 8 & 0xff ;
devrec - > rx_addr_buf [ 1 ] = cmd & 0xff ;
devrec - > rx_fifo_buf_trx . len = devrec - > rx_buf [ 2 ] ;
ret = spi_async ( devrec - > spi , & devrec - > rx_buf_msg ) ;
if ( ret ) {
dev_err ( printdev ( devrec ) , " failed to read rx buffer \n " ) ;
mrf24j40_handle_rx_read_buf_unlock ( devrec ) ;
2012-09-02 19:44:13 +04:00
}
2015-09-21 12:24:35 +03:00
}
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:35 +03:00
static void mrf24j40_handle_rx_read_len ( void * context )
{
struct mrf24j40 * devrec = context ;
u16 cmd ;
int ret ;
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:35 +03:00
/* read the length of received frame */
devrec - > rx_msg . complete = mrf24j40_handle_rx_read_buf ;
devrec - > rx_trx . len = 3 ;
cmd = MRF24J40_READLONG ( REG_RX_FIFO ) ;
devrec - > rx_buf [ 0 ] = cmd > > 8 & 0xff ;
devrec - > rx_buf [ 1 ] = cmd & 0xff ;
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:35 +03:00
ret = spi_async ( devrec - > spi , & devrec - > rx_msg ) ;
if ( ret ) {
dev_err ( printdev ( devrec ) , " failed to read rx buffer length \n " ) ;
mrf24j40_handle_rx_read_buf_unlock ( devrec ) ;
}
}
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:35 +03:00
static int mrf24j40_handle_rx ( struct mrf24j40 * devrec )
{
/* Turn off reception of packets off the air. This prevents the
* device from overwriting the buffer while we ' re reading it .
*/
devrec - > rx_msg . complete = mrf24j40_handle_rx_read_len ;
devrec - > rx_trx . len = 2 ;
devrec - > rx_buf [ 0 ] = MRF24J40_WRITESHORT ( REG_BBREG1 ) ;
2015-09-21 12:24:43 +03:00
devrec - > rx_buf [ 1 ] = BIT_RXDECINV ; /* SET RXDECINV */
2015-09-21 12:24:35 +03:00
return spi_async ( devrec - > spi , & devrec - > rx_msg ) ;
2012-09-02 19:44:13 +04:00
}
2015-09-21 12:24:37 +03:00
static int
mrf24j40_csma_params ( struct ieee802154_hw * hw , u8 min_be , u8 max_be ,
u8 retries )
{
struct mrf24j40 * devrec = hw - > priv ;
u8 val ;
/* min_be */
2015-09-21 12:24:43 +03:00
val = min_be < < TXMCR_MIN_BE_SHIFT ;
2015-09-21 12:24:37 +03:00
/* csma backoffs */
2015-09-21 12:24:43 +03:00
val | = retries < < TXMCR_CSMA_RETRIES_SHIFT ;
2015-09-21 12:24:37 +03:00
2015-09-21 12:24:43 +03:00
return regmap_update_bits ( devrec - > regmap_short , REG_TXMCR ,
TXMCR_MIN_BE_MASK | TXMCR_CSMA_RETRIES_MASK ,
val ) ;
2015-09-21 12:24:37 +03:00
}
2015-09-21 12:24:38 +03:00
static int mrf24j40_set_cca_mode ( struct ieee802154_hw * hw ,
const struct wpan_phy_cca * cca )
{
struct mrf24j40 * devrec = hw - > priv ;
u8 val ;
/* mapping 802.15.4 to driver spec */
switch ( cca - > mode ) {
case NL802154_CCA_ENERGY :
val = 2 ;
break ;
case NL802154_CCA_CARRIER :
val = 1 ;
break ;
case NL802154_CCA_ENERGY_CARRIER :
switch ( cca - > opt ) {
case NL802154_CCA_OPT_ENERGY_CARRIER_AND :
val = 3 ;
break ;
default :
return - EINVAL ;
}
break ;
default :
return - EINVAL ;
}
2015-09-21 12:24:43 +03:00
return regmap_update_bits ( devrec - > regmap_short , REG_BBREG2 ,
BBREG2_CCA_MODE_MASK ,
val < < BBREG2_CCA_MODE_SHIFT ) ;
2015-09-21 12:24:38 +03:00
}
2015-09-21 12:24:39 +03:00
/* array for representing ed levels */
static const s32 mrf24j40_ed_levels [ ] = {
- 9000 , - 8900 , - 8800 , - 8700 , - 8600 , - 8500 , - 8400 , - 8300 , - 8200 , - 8100 ,
- 8000 , - 7900 , - 7800 , - 7700 , - 7600 , - 7500 , - 7400 , - 7300 , - 7200 , - 7100 ,
- 7000 , - 6900 , - 6800 , - 6700 , - 6600 , - 6500 , - 6400 , - 6300 , - 6200 , - 6100 ,
- 6000 , - 5900 , - 5800 , - 5700 , - 5600 , - 5500 , - 5400 , - 5300 , - 5200 , - 5100 ,
- 5000 , - 4900 , - 4800 , - 4700 , - 4600 , - 4500 , - 4400 , - 4300 , - 4200 , - 4100 ,
- 4000 , - 3900 , - 3800 , - 3700 , - 3600 , - 3500
} ;
/* map ed levels to register value */
static const s32 mrf24j40_ed_levels_map [ ] [ 2 ] = {
{ - 9000 , 0 } , { - 8900 , 1 } , { - 8800 , 2 } , { - 8700 , 5 } , { - 8600 , 9 } ,
{ - 8500 , 13 } , { - 8400 , 18 } , { - 8300 , 23 } , { - 8200 , 27 } ,
{ - 8100 , 32 } , { - 8000 , 37 } , { - 7900 , 43 } , { - 7800 , 48 } ,
{ - 7700 , 53 } , { - 7600 , 58 } , { - 7500 , 63 } , { - 7400 , 68 } ,
{ - 7300 , 73 } , { - 7200 , 78 } , { - 7100 , 83 } , { - 7000 , 89 } ,
{ - 6900 , 95 } , { - 6800 , 100 } , { - 6700 , 107 } , { - 6600 , 111 } ,
{ - 6500 , 117 } , { - 6400 , 121 } , { - 6300 , 125 } , { - 6200 , 129 } ,
{ - 6100 , 133 } , { - 6000 , 138 } , { - 5900 , 143 } , { - 5800 , 148 } ,
{ - 5700 , 153 } , { - 5600 , 159 } , { - 5500 , 165 } , { - 5400 , 170 } ,
{ - 5300 , 176 } , { - 5200 , 183 } , { - 5100 , 188 } , { - 5000 , 193 } ,
{ - 4900 , 198 } , { - 4800 , 203 } , { - 4700 , 207 } , { - 4600 , 212 } ,
{ - 4500 , 216 } , { - 4400 , 221 } , { - 4300 , 225 } , { - 4200 , 228 } ,
{ - 4100 , 233 } , { - 4000 , 239 } , { - 3900 , 245 } , { - 3800 , 250 } ,
{ - 3700 , 253 } , { - 3600 , 254 } , { - 3500 , 255 } ,
} ;
static int mrf24j40_set_cca_ed_level ( struct ieee802154_hw * hw , s32 mbm )
{
struct mrf24j40 * devrec = hw - > priv ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( mrf24j40_ed_levels_map ) ; i + + ) {
if ( mrf24j40_ed_levels_map [ i ] [ 0 ] = = mbm )
return regmap_write ( devrec - > regmap_short , REG_CCAEDTH ,
mrf24j40_ed_levels_map [ i ] [ 1 ] ) ;
}
return - EINVAL ;
}
2015-09-21 12:24:40 +03:00
static const s32 mrf24j40ma_powers [ ] = {
0 , - 50 , - 120 , - 190 , - 280 , - 370 , - 490 , - 630 , - 1000 , - 1050 , - 1120 , - 1190 ,
- 1280 , - 1370 , - 1490 , - 1630 , - 2000 , - 2050 , - 2120 , - 2190 , - 2280 , - 2370 ,
- 2490 , - 2630 , - 3000 , - 3050 , - 3120 , - 3190 , - 3280 , - 3370 , - 3490 , - 3630 ,
} ;
static int mrf24j40_set_txpower ( struct ieee802154_hw * hw , s32 mbm )
{
struct mrf24j40 * devrec = hw - > priv ;
s32 small_scale ;
u8 val ;
if ( 0 > = mbm & & mbm > - 1000 ) {
2015-09-21 12:24:43 +03:00
val = TXPWRL_0 < < TXPWRL_SHIFT ;
2015-09-21 12:24:40 +03:00
small_scale = mbm ;
} else if ( - 1000 > = mbm & & mbm > - 2000 ) {
2015-09-21 12:24:43 +03:00
val = TXPWRL_10 < < TXPWRL_SHIFT ;
2015-09-21 12:24:40 +03:00
small_scale = mbm + 1000 ;
} else if ( - 2000 > = mbm & & mbm > - 3000 ) {
2015-09-21 12:24:43 +03:00
val = TXPWRL_20 < < TXPWRL_SHIFT ;
2015-09-21 12:24:40 +03:00
small_scale = mbm + 2000 ;
} else if ( - 3000 > = mbm & & mbm > - 4000 ) {
2015-09-21 12:24:43 +03:00
val = TXPWRL_30 < < TXPWRL_SHIFT ;
2015-09-21 12:24:40 +03:00
small_scale = mbm + 3000 ;
} else {
return - EINVAL ;
}
switch ( small_scale ) {
case 0 :
2015-09-21 12:24:43 +03:00
val | = ( TXPWRS_0 < < TXPWRS_SHIFT ) ;
2015-09-21 12:24:40 +03:00
break ;
case - 50 :
2015-09-21 12:24:43 +03:00
val | = ( TXPWRS_0_5 < < TXPWRS_SHIFT ) ;
2015-09-21 12:24:40 +03:00
break ;
case - 120 :
2015-09-21 12:24:43 +03:00
val | = ( TXPWRS_1_2 < < TXPWRS_SHIFT ) ;
2015-09-21 12:24:40 +03:00
break ;
case - 190 :
2015-09-21 12:24:43 +03:00
val | = ( TXPWRS_1_9 < < TXPWRS_SHIFT ) ;
2015-09-21 12:24:40 +03:00
break ;
case - 280 :
2015-09-21 12:24:43 +03:00
val | = ( TXPWRS_2_8 < < TXPWRS_SHIFT ) ;
2015-09-21 12:24:40 +03:00
break ;
case - 370 :
2015-09-21 12:24:43 +03:00
val | = ( TXPWRS_3_7 < < TXPWRS_SHIFT ) ;
2015-09-21 12:24:40 +03:00
break ;
case - 490 :
2015-09-21 12:24:43 +03:00
val | = ( TXPWRS_4_9 < < TXPWRS_SHIFT ) ;
2015-09-21 12:24:40 +03:00
break ;
case - 630 :
2015-09-21 12:24:43 +03:00
val | = ( TXPWRS_6_3 < < TXPWRS_SHIFT ) ;
2015-09-21 12:24:40 +03:00
break ;
default :
return - EINVAL ;
}
2015-09-21 12:24:43 +03:00
return regmap_update_bits ( devrec - > regmap_long , REG_RFCON3 ,
TXPWRL_MASK | TXPWRS_MASK , val ) ;
2015-09-21 12:24:40 +03:00
}
2015-09-21 12:24:41 +03:00
static int mrf24j40_set_promiscuous_mode ( struct ieee802154_hw * hw , bool on )
{
struct mrf24j40 * devrec = hw - > priv ;
int ret ;
if ( on ) {
/* set PROMI, ERRPKT and NOACKRSP */
2015-09-21 12:24:43 +03:00
ret = regmap_update_bits ( devrec - > regmap_short , REG_RXMCR ,
BIT_PROMI | BIT_ERRPKT | BIT_NOACKRSP ,
BIT_PROMI | BIT_ERRPKT | BIT_NOACKRSP ) ;
2015-09-21 12:24:41 +03:00
} else {
/* clear PROMI, ERRPKT and NOACKRSP */
2015-09-21 12:24:43 +03:00
ret = regmap_update_bits ( devrec - > regmap_short , REG_RXMCR ,
BIT_PROMI | BIT_ERRPKT | BIT_NOACKRSP ,
0 ) ;
2015-09-21 12:24:41 +03:00
}
return ret ;
}
2014-10-28 20:21:18 +03:00
static const struct ieee802154_ops mrf24j40_ops = {
2012-09-02 19:44:13 +04:00
. owner = THIS_MODULE ,
2015-09-21 12:24:34 +03:00
. xmit_async = mrf24j40_tx ,
2012-09-02 19:44:13 +04:00
. ed = mrf24j40_ed ,
. start = mrf24j40_start ,
. stop = mrf24j40_stop ,
. set_channel = mrf24j40_set_channel ,
. set_hw_addr_filt = mrf24j40_filter ,
2015-09-21 12:24:37 +03:00
. set_csma_params = mrf24j40_csma_params ,
2015-09-21 12:24:38 +03:00
. set_cca_mode = mrf24j40_set_cca_mode ,
2015-09-21 12:24:39 +03:00
. set_cca_ed_level = mrf24j40_set_cca_ed_level ,
2015-09-21 12:24:40 +03:00
. set_txpower = mrf24j40_set_txpower ,
2015-09-21 12:24:41 +03:00
. set_promiscuous_mode = mrf24j40_set_promiscuous_mode ,
2012-09-02 19:44:13 +04:00
} ;
2015-09-21 12:24:36 +03:00
static void mrf24j40_intstat_complete ( void * context )
2012-09-02 19:44:13 +04:00
{
2015-09-21 12:24:36 +03:00
struct mrf24j40 * devrec = context ;
u8 intstat = devrec - > irq_buf [ 1 ] ;
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:36 +03:00
enable_irq ( devrec - > spi - > irq ) ;
2012-09-02 19:44:13 +04:00
2016-04-12 19:53:01 +03:00
/* Ignore Rx security decryption */
if ( intstat & BIT_SECIF )
regmap_write_async ( devrec - > regmap_short , REG_SECCON0 ,
BIT_SECIGNORE ) ;
2012-09-02 19:44:13 +04:00
/* Check for TX complete */
2015-09-21 12:24:43 +03:00
if ( intstat & BIT_TXNIF )
2015-09-21 12:24:34 +03:00
ieee802154_xmit_complete ( devrec - > hw , devrec - > tx_skb , false ) ;
2012-09-02 19:44:13 +04:00
/* Check for Rx */
2015-09-21 12:24:43 +03:00
if ( intstat & BIT_RXIF )
2012-09-02 19:44:13 +04:00
mrf24j40_handle_rx ( devrec ) ;
2015-09-21 12:24:36 +03:00
}
static irqreturn_t mrf24j40_isr ( int irq , void * data )
{
struct mrf24j40 * devrec = data ;
int ret ;
disable_irq_nosync ( irq ) ;
devrec - > irq_buf [ 0 ] = MRF24J40_READSHORT ( REG_INTSTAT ) ;
2016-07-12 06:02:16 +03:00
devrec - > irq_buf [ 1 ] = 0 ;
2015-09-21 12:24:36 +03:00
/* Read the interrupt status */
ret = spi_async ( devrec - > spi , & devrec - > irq_msg ) ;
if ( ret ) {
enable_irq ( irq ) ;
return IRQ_NONE ;
}
2012-09-02 19:44:13 +04:00
2013-10-06 07:52:23 +04:00
return IRQ_HANDLED ;
2012-09-02 19:44:13 +04:00
}
2014-06-16 07:42:31 +04:00
static int mrf24j40_hw_init ( struct mrf24j40 * devrec )
{
2015-09-21 12:24:42 +03:00
u32 irq_type ;
2014-06-16 07:42:31 +04:00
int ret ;
/* Initialize the device.
From datasheet section 3.2 : Initialization . */
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_short , REG_SOFTRST , 0x07 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_short , REG_PACON2 , 0x98 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_short , REG_TXSTBL , 0x95 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_long , REG_RFCON0 , 0x03 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_long , REG_RFCON1 , 0x01 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_long , REG_RFCON2 , 0x80 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_long , REG_RFCON6 , 0x90 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_long , REG_RFCON7 , 0x80 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_long , REG_RFCON8 , 0x10 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_long , REG_SLPCON1 , 0x21 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_short , REG_BBREG2 , 0x80 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_short , REG_CCAEDTH , 0x60 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_short , REG_BBREG6 , 0x40 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_short , REG_RFCTL , 0x04 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2015-09-21 12:24:31 +03:00
ret = regmap_write ( devrec - > regmap_short , REG_RFCTL , 0x0 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
udelay ( 192 ) ;
/* Set RX Mode. RXMCR<1:0>: 0x0 normal, 0x1 promisc, 0x2 error */
2015-09-21 12:24:31 +03:00
ret = regmap_update_bits ( devrec - > regmap_short , REG_RXMCR , 0x03 , 0x00 ) ;
2014-06-16 07:42:31 +04:00
if ( ret )
goto err_ret ;
2014-10-06 13:39:45 +04:00
if ( spi_get_device_id ( devrec - > spi ) - > driver_data = = MRF24J40MC ) {
/* Enable external amplifier.
* From MRF24J40MC datasheet section 1.3 : Operation .
*/
2015-09-21 12:24:31 +03:00
regmap_update_bits ( devrec - > regmap_long , REG_TESTMODE , 0x07 ,
0x07 ) ;
2014-10-06 13:39:45 +04:00
2015-09-21 12:24:31 +03:00
/* Set GPIO3 as output. */
regmap_update_bits ( devrec - > regmap_short , REG_TRISGPIO , 0x08 ,
0x08 ) ;
2014-10-06 13:39:45 +04:00
2015-09-21 12:24:31 +03:00
/* Set GPIO3 HIGH to enable U5 voltage regulator */
regmap_update_bits ( devrec - > regmap_short , REG_GPIO , 0x08 , 0x08 ) ;
2014-10-06 13:39:45 +04:00
/* Reduce TX pwr to meet FCC requirements.
* From MRF24J40MC datasheet section 3.1 .1
*/
2015-09-21 12:24:31 +03:00
regmap_write ( devrec - > regmap_long , REG_RFCON3 , 0x28 ) ;
2014-10-06 13:39:45 +04:00
}
2015-09-21 12:24:42 +03:00
irq_type = irq_get_trigger_type ( devrec - > spi - > irq ) ;
if ( irq_type = = IRQ_TYPE_EDGE_RISING | |
irq_type = = IRQ_TYPE_EDGE_FALLING )
dev_warn ( & devrec - > spi - > dev ,
" Using edge triggered irq's are not recommended, because it can cause races and result in a non-functional driver! \n " ) ;
switch ( irq_type ) {
case IRQ_TYPE_EDGE_RISING :
case IRQ_TYPE_LEVEL_HIGH :
/* set interrupt polarity to rising */
ret = regmap_update_bits ( devrec - > regmap_long , REG_SLPCON0 ,
2015-09-21 12:24:43 +03:00
BIT_INTEDGE , BIT_INTEDGE ) ;
2015-09-21 12:24:42 +03:00
if ( ret )
goto err_ret ;
break ;
default :
/* default is falling edge */
break ;
}
2014-06-16 07:42:31 +04:00
return 0 ;
err_ret :
return ret ;
}
2015-09-21 12:24:34 +03:00
static void
mrf24j40_setup_tx_spi_messages ( struct mrf24j40 * devrec )
{
spi_message_init ( & devrec - > tx_msg ) ;
devrec - > tx_msg . context = devrec ;
devrec - > tx_msg . complete = write_tx_buf_complete ;
devrec - > tx_hdr_trx . len = 2 ;
devrec - > tx_hdr_trx . tx_buf = devrec - > tx_hdr_buf ;
spi_message_add_tail ( & devrec - > tx_hdr_trx , & devrec - > tx_msg ) ;
devrec - > tx_len_trx . len = 2 ;
devrec - > tx_len_trx . tx_buf = devrec - > tx_len_buf ;
spi_message_add_tail ( & devrec - > tx_len_trx , & devrec - > tx_msg ) ;
spi_message_add_tail ( & devrec - > tx_buf_trx , & devrec - > tx_msg ) ;
spi_message_init ( & devrec - > tx_post_msg ) ;
devrec - > tx_post_msg . context = devrec ;
devrec - > tx_post_trx . len = 2 ;
devrec - > tx_post_trx . tx_buf = devrec - > tx_post_buf ;
spi_message_add_tail ( & devrec - > tx_post_trx , & devrec - > tx_post_msg ) ;
}
2015-09-21 12:24:35 +03:00
static void
mrf24j40_setup_rx_spi_messages ( struct mrf24j40 * devrec )
{
spi_message_init ( & devrec - > rx_msg ) ;
devrec - > rx_msg . context = devrec ;
devrec - > rx_trx . len = 2 ;
devrec - > rx_trx . tx_buf = devrec - > rx_buf ;
devrec - > rx_trx . rx_buf = devrec - > rx_buf ;
spi_message_add_tail ( & devrec - > rx_trx , & devrec - > rx_msg ) ;
spi_message_init ( & devrec - > rx_buf_msg ) ;
devrec - > rx_buf_msg . context = devrec ;
devrec - > rx_buf_msg . complete = mrf24j40_handle_rx_read_buf_complete ;
devrec - > rx_addr_trx . len = 2 ;
devrec - > rx_addr_trx . tx_buf = devrec - > rx_addr_buf ;
spi_message_add_tail ( & devrec - > rx_addr_trx , & devrec - > rx_buf_msg ) ;
devrec - > rx_fifo_buf_trx . rx_buf = devrec - > rx_fifo_buf ;
spi_message_add_tail ( & devrec - > rx_fifo_buf_trx , & devrec - > rx_buf_msg ) ;
devrec - > rx_lqi_trx . len = 2 ;
devrec - > rx_lqi_trx . rx_buf = devrec - > rx_lqi_buf ;
spi_message_add_tail ( & devrec - > rx_lqi_trx , & devrec - > rx_buf_msg ) ;
}
2015-09-21 12:24:36 +03:00
static void
mrf24j40_setup_irq_spi_messages ( struct mrf24j40 * devrec )
{
spi_message_init ( & devrec - > irq_msg ) ;
devrec - > irq_msg . context = devrec ;
devrec - > irq_msg . complete = mrf24j40_intstat_complete ;
devrec - > irq_trx . len = 2 ;
devrec - > irq_trx . tx_buf = devrec - > irq_buf ;
devrec - > irq_trx . rx_buf = devrec - > irq_buf ;
spi_message_add_tail ( & devrec - > irq_trx , & devrec - > irq_msg ) ;
}
2015-09-21 12:24:27 +03:00
static void mrf24j40_phy_setup ( struct mrf24j40 * devrec )
{
2015-09-21 12:24:28 +03:00
ieee802154_random_extended_addr ( & devrec - > hw - > phy - > perm_extended_addr ) ;
2015-09-21 12:24:27 +03:00
devrec - > hw - > phy - > current_channel = 11 ;
2015-09-21 12:24:37 +03:00
/* mrf24j40 supports max_minbe 0 - 3 */
devrec - > hw - > phy - > supported . max_minbe = 3 ;
/* datasheet doesn't say anything about max_be, but we have min_be
* So we assume the max_be default .
*/
devrec - > hw - > phy - > supported . min_maxbe = 5 ;
devrec - > hw - > phy - > supported . max_maxbe = 5 ;
2015-09-21 12:24:38 +03:00
2015-09-24 20:40:33 +03:00
devrec - > hw - > phy - > cca . mode = NL802154_CCA_CARRIER ;
2015-09-21 12:24:38 +03:00
devrec - > hw - > phy - > supported . cca_modes = BIT ( NL802154_CCA_ENERGY ) |
BIT ( NL802154_CCA_CARRIER ) |
BIT ( NL802154_CCA_ENERGY_CARRIER ) ;
devrec - > hw - > phy - > supported . cca_opts = BIT ( NL802154_CCA_OPT_ENERGY_CARRIER_AND ) ;
2015-09-21 12:24:39 +03:00
devrec - > hw - > phy - > cca_ed_level = - 6900 ;
devrec - > hw - > phy - > supported . cca_ed_levels = mrf24j40_ed_levels ;
devrec - > hw - > phy - > supported . cca_ed_levels_size = ARRAY_SIZE ( mrf24j40_ed_levels ) ;
2015-09-21 12:24:40 +03:00
switch ( spi_get_device_id ( devrec - > spi ) - > driver_data ) {
case MRF24J40 :
case MRF24J40MA :
devrec - > hw - > phy - > supported . tx_powers = mrf24j40ma_powers ;
devrec - > hw - > phy - > supported . tx_powers_size = ARRAY_SIZE ( mrf24j40ma_powers ) ;
devrec - > hw - > phy - > flags | = WPAN_PHY_FLAG_TXPOWER ;
break ;
default :
break ;
}
2015-09-21 12:24:27 +03:00
}
2012-12-03 18:24:12 +04:00
static int mrf24j40_probe ( struct spi_device * spi )
2012-09-02 19:44:13 +04:00
{
2015-09-21 12:24:42 +03:00
int ret = - ENOMEM , irq_type ;
2015-09-21 12:24:23 +03:00
struct ieee802154_hw * hw ;
2012-09-02 19:44:13 +04:00
struct mrf24j40 * devrec ;
2014-09-24 14:21:32 +04:00
dev_info ( & spi - > dev , " probe(). IRQ: %d \n " , spi - > irq ) ;
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:23 +03:00
/* Register with the 802154 subsystem */
hw = ieee802154_alloc_hw ( sizeof ( * devrec ) , & mrf24j40_ops ) ;
if ( ! hw )
2014-06-11 08:34:44 +04:00
goto err_ret ;
2015-09-21 12:24:23 +03:00
devrec = hw - > priv ;
devrec - > spi = spi ;
spi_set_drvdata ( spi , devrec ) ;
devrec - > hw = hw ;
devrec - > hw - > parent = & spi - > dev ;
devrec - > hw - > phy - > supported . channels [ 0 ] = CHANNEL_MASK ;
2015-09-21 12:24:37 +03:00
devrec - > hw - > flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
2015-09-21 12:24:41 +03:00
IEEE802154_HW_CSMA_PARAMS |
IEEE802154_HW_PROMISCUOUS ;
2015-09-21 12:24:23 +03:00
2015-09-21 12:24:39 +03:00
devrec - > hw - > phy - > flags = WPAN_PHY_FLAG_CCA_MODE |
WPAN_PHY_FLAG_CCA_ED_LEVEL ;
2015-09-21 12:24:38 +03:00
2015-09-21 12:24:34 +03:00
mrf24j40_setup_tx_spi_messages ( devrec ) ;
2015-09-21 12:24:35 +03:00
mrf24j40_setup_rx_spi_messages ( devrec ) ;
2015-09-21 12:24:36 +03:00
mrf24j40_setup_irq_spi_messages ( devrec ) ;
2015-09-21 12:24:34 +03:00
2015-09-21 12:24:30 +03:00
devrec - > regmap_short = devm_regmap_init_spi ( spi ,
& mrf24j40_short_regmap ) ;
if ( IS_ERR ( devrec - > regmap_short ) ) {
ret = PTR_ERR ( devrec - > regmap_short ) ;
dev_err ( & spi - > dev , " Failed to allocate short register map: %d \n " ,
ret ) ;
goto err_register_device ;
}
devrec - > regmap_long = devm_regmap_init ( & spi - > dev ,
& mrf24j40_long_regmap_bus ,
spi , & mrf24j40_long_regmap ) ;
if ( IS_ERR ( devrec - > regmap_long ) ) {
ret = PTR_ERR ( devrec - > regmap_long ) ;
dev_err ( & spi - > dev , " Failed to allocate long register map: %d \n " ,
ret ) ;
goto err_register_device ;
}
2015-09-21 12:24:25 +03:00
if ( spi - > max_speed_hz > MAX_SPI_SPEED_HZ ) {
dev_warn ( & spi - > dev , " spi clock above possible maximum: %d " ,
MAX_SPI_SPEED_HZ ) ;
return - EINVAL ;
}
2012-09-02 19:44:13 +04:00
2014-06-16 07:42:31 +04:00
ret = mrf24j40_hw_init ( devrec ) ;
2012-09-02 19:44:13 +04:00
if ( ret )
2015-09-21 12:24:24 +03:00
goto err_register_device ;
2012-09-02 19:44:13 +04:00
2015-09-21 12:24:27 +03:00
mrf24j40_phy_setup ( devrec ) ;
2015-09-21 12:24:42 +03:00
/* request IRQF_TRIGGER_LOW as fallback default */
irq_type = irq_get_trigger_type ( spi - > irq ) ;
if ( ! irq_type )
irq_type = IRQF_TRIGGER_LOW ;
2015-09-21 12:24:36 +03:00
ret = devm_request_irq ( & spi - > dev , spi - > irq , mrf24j40_isr ,
2015-09-21 12:24:42 +03:00
irq_type , dev_name ( & spi - > dev ) , devrec ) ;
2012-09-02 19:44:13 +04:00
if ( ret ) {
dev_err ( printdev ( devrec ) , " Unable to get IRQ " ) ;
2015-09-21 12:24:24 +03:00
goto err_register_device ;
2012-09-02 19:44:13 +04:00
}
2015-09-21 12:24:24 +03:00
dev_dbg ( printdev ( devrec ) , " registered mrf24j40 \n " ) ;
ret = ieee802154_register_hw ( devrec - > hw ) ;
if ( ret )
goto err_register_device ;
2012-09-02 19:44:13 +04:00
return 0 ;
err_register_device :
2014-10-25 19:16:34 +04:00
ieee802154_free_hw ( devrec - > hw ) ;
2014-06-11 08:34:44 +04:00
err_ret :
2012-09-02 19:44:13 +04:00
return ret ;
}
2012-12-03 18:24:12 +04:00
static int mrf24j40_remove ( struct spi_device * spi )
2012-09-02 19:44:13 +04:00
{
2013-04-06 00:34:18 +04:00
struct mrf24j40 * devrec = spi_get_drvdata ( spi ) ;
2012-09-02 19:44:13 +04:00
dev_dbg ( printdev ( devrec ) , " remove \n " ) ;
2014-10-25 19:16:34 +04:00
ieee802154_unregister_hw ( devrec - > hw ) ;
ieee802154_free_hw ( devrec - > hw ) ;
2012-09-02 19:44:13 +04:00
/* TODO: Will ieee802154_free_device() wait until ->xmit() is
* complete ? */
return 0 ;
}
2015-09-21 12:24:26 +03:00
static const struct of_device_id mrf24j40_of_match [ ] = {
{ . compatible = " microchip,mrf24j40 " , . data = ( void * ) MRF24J40 } ,
{ . compatible = " microchip,mrf24j40ma " , . data = ( void * ) MRF24J40MA } ,
{ . compatible = " microchip,mrf24j40mc " , . data = ( void * ) MRF24J40MC } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , mrf24j40_of_match ) ;
2012-09-02 19:44:13 +04:00
static const struct spi_device_id mrf24j40_ids [ ] = {
2014-10-06 13:39:45 +04:00
{ " mrf24j40 " , MRF24J40 } ,
{ " mrf24j40ma " , MRF24J40MA } ,
{ " mrf24j40mc " , MRF24J40MC } ,
2012-09-02 19:44:13 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( spi , mrf24j40_ids ) ;
static struct spi_driver mrf24j40_driver = {
. driver = {
2015-09-21 12:24:26 +03:00
. of_match_table = of_match_ptr ( mrf24j40_of_match ) ,
2012-09-02 19:44:13 +04:00
. name = " mrf24j40 " ,
} ,
. id_table = mrf24j40_ids ,
. probe = mrf24j40_probe ,
2012-12-03 18:24:12 +04:00
. remove = mrf24j40_remove ,
2012-09-02 19:44:13 +04:00
} ;
2013-04-09 00:34:44 +04:00
module_spi_driver ( mrf24j40_driver ) ;
2012-09-02 19:44:13 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Alan Ott " ) ;
MODULE_DESCRIPTION ( " MRF24J40 SPI 802.15.4 Controller Driver " ) ;