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 .
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/spi/spi.h>
# include <linux/interrupt.h>
# include <linux/module.h>
# include <net/wpan-phy.h>
# include <net/mac802154.h>
/* MRF24J40 Short Address Registers */
# define REG_RXMCR 0x00 /* Receive MAC control */
# 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) */
# define REG_TXMCR 0x11 /* Transmit MAC control */
# define REG_PACON0 0x16 /* Power Amplifier Control */
# define REG_PACON1 0x17 /* Power Amplifier Control */
# define REG_PACON2 0x18 /* Power Amplifier Control */
# define REG_TXNCON 0x1B /* Transmit Normal FIFO Control */
# define REG_TXSTAT 0x24 /* TX MAC Status Register */
# define REG_SOFTRST 0x2A /* Soft Reset */
# define REG_TXSTBL 0x2E /* TX Stabilization */
# define REG_INTSTAT 0x31 /* Interrupt Status */
# define REG_INTCON 0x32 /* Interrupt Control */
# define REG_RFCTL 0x36 /* RF Control Mode Register */
# define REG_BBREG1 0x39 /* Baseband Registers */
# define REG_BBREG2 0x3A /* */
# define REG_BBREG6 0x3E /* */
# define REG_CCAEDTH 0x3F /* Energy Detection Threshold */
/* MRF24J40 Long Address Registers */
# define REG_RFCON0 0x200 /* RF Control Registers */
# define REG_RFCON1 0x201
# define REG_RFCON2 0x202
# define REG_RFCON3 0x203
# define REG_RFCON5 0x205
# define REG_RFCON6 0x206
# define REG_RFCON7 0x207
# define REG_RFCON8 0x208
# define REG_RSSI 0x210
# define REG_SLPCON0 0x211 /* Sleep Clock Control Registers */
# define REG_SLPCON1 0x220
# define REG_WAKETIMEL 0x222 /* Wake-up Time Match Value Low */
# define REG_WAKETIMEH 0x223 /* Wake-up Time Match Value High */
# define REG_RX_FIFO 0x300 /* Receive FIFO */
/* 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 */
/* Device Private Data */
struct mrf24j40 {
struct spi_device * spi ;
struct ieee802154_dev * dev ;
struct mutex buffer_mutex ; /* only used to protect buf */
struct completion tx_complete ;
struct work_struct irqwork ;
u8 * buf ; /* 3 bytes. Used for SPI single-register transfers. */
} ;
/* 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)
/* Maximum speed to run the device at. TODO: Get the real max value from
* someone at Microchip since it isn ' t in the datasheet . */
# define MAX_SPI_SPEED_HZ 1000000
# define printdev(X) (&X->spi->dev)
static int write_short_reg ( struct mrf24j40 * devrec , u8 reg , u8 value )
{
int ret ;
struct spi_message msg ;
struct spi_transfer xfer = {
. len = 2 ,
. tx_buf = devrec - > buf ,
. rx_buf = devrec - > buf ,
} ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
mutex_lock ( & devrec - > buffer_mutex ) ;
devrec - > buf [ 0 ] = MRF24J40_WRITESHORT ( reg ) ;
devrec - > buf [ 1 ] = value ;
ret = spi_sync ( devrec - > spi , & msg ) ;
if ( ret )
dev_err ( printdev ( devrec ) ,
" SPI write Failed for short register 0x%hhx \n " , reg ) ;
mutex_unlock ( & devrec - > buffer_mutex ) ;
return ret ;
}
static int read_short_reg ( struct mrf24j40 * devrec , u8 reg , u8 * val )
{
int ret = - 1 ;
struct spi_message msg ;
struct spi_transfer xfer = {
. len = 2 ,
. tx_buf = devrec - > buf ,
. rx_buf = devrec - > buf ,
} ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
mutex_lock ( & devrec - > buffer_mutex ) ;
devrec - > buf [ 0 ] = MRF24J40_READSHORT ( reg ) ;
devrec - > buf [ 1 ] = 0 ;
ret = spi_sync ( devrec - > spi , & msg ) ;
if ( ret )
dev_err ( printdev ( devrec ) ,
" SPI read Failed for short register 0x%hhx \n " , reg ) ;
else
* val = devrec - > buf [ 1 ] ;
mutex_unlock ( & devrec - > buffer_mutex ) ;
return ret ;
}
static int read_long_reg ( struct mrf24j40 * devrec , u16 reg , u8 * value )
{
int ret ;
u16 cmd ;
struct spi_message msg ;
struct spi_transfer xfer = {
. len = 3 ,
. tx_buf = devrec - > buf ,
. rx_buf = devrec - > buf ,
} ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
cmd = MRF24J40_READLONG ( reg ) ;
mutex_lock ( & devrec - > buffer_mutex ) ;
devrec - > buf [ 0 ] = cmd > > 8 & 0xff ;
devrec - > buf [ 1 ] = cmd & 0xff ;
devrec - > buf [ 2 ] = 0 ;
ret = spi_sync ( devrec - > spi , & msg ) ;
if ( ret )
dev_err ( printdev ( devrec ) ,
" SPI read Failed for long register 0x%hx \n " , reg ) ;
else
* value = devrec - > buf [ 2 ] ;
mutex_unlock ( & devrec - > buffer_mutex ) ;
return ret ;
}
static int write_long_reg ( struct mrf24j40 * devrec , u16 reg , u8 val )
{
int ret ;
u16 cmd ;
struct spi_message msg ;
struct spi_transfer xfer = {
. len = 3 ,
. tx_buf = devrec - > buf ,
. rx_buf = devrec - > buf ,
} ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
cmd = MRF24J40_WRITELONG ( reg ) ;
mutex_lock ( & devrec - > buffer_mutex ) ;
devrec - > buf [ 0 ] = cmd > > 8 & 0xff ;
devrec - > buf [ 1 ] = cmd & 0xff ;
devrec - > buf [ 2 ] = val ;
ret = spi_sync ( devrec - > spi , & msg ) ;
if ( ret )
dev_err ( printdev ( devrec ) ,
" SPI write Failed for long register 0x%hx \n " , reg ) ;
mutex_unlock ( & devrec - > buffer_mutex ) ;
return ret ;
}
/* 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 )
{
int ret ;
u16 cmd ;
u8 lengths [ 2 ] ;
struct spi_message msg ;
struct spi_transfer addr_xfer = {
. len = 2 ,
. tx_buf = devrec - > buf ,
} ;
struct spi_transfer lengths_xfer = {
. len = 2 ,
. tx_buf = & lengths , /* TODO: Is DMA really required for SPI? */
} ;
struct spi_transfer data_xfer = {
. len = length ,
. tx_buf = data ,
} ;
/* 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 ;
}
spi_message_init ( & msg ) ;
spi_message_add_tail ( & addr_xfer , & msg ) ;
spi_message_add_tail ( & lengths_xfer , & msg ) ;
spi_message_add_tail ( & data_xfer , & msg ) ;
cmd = MRF24J40_WRITELONG ( reg ) ;
mutex_lock ( & devrec - > buffer_mutex ) ;
devrec - > buf [ 0 ] = cmd > > 8 & 0xff ;
devrec - > buf [ 1 ] = cmd & 0xff ;
lengths [ 0 ] = 0x0 ; /* Header Length. Set to 0 for now. TODO */
lengths [ 1 ] = length ; /* Total length */
ret = spi_sync ( devrec - > spi , & msg ) ;
if ( ret )
dev_err ( printdev ( devrec ) , " SPI write Failed for TX buf \n " ) ;
mutex_unlock ( & devrec - > buffer_mutex ) ;
return ret ;
}
static int mrf24j40_read_rx_buf ( struct mrf24j40 * devrec ,
u8 * data , u8 * len , u8 * lqi )
{
u8 rx_len ;
u8 addr [ 2 ] ;
u8 lqi_rssi [ 2 ] ;
u16 cmd ;
int ret ;
struct spi_message msg ;
struct spi_transfer addr_xfer = {
. len = 2 ,
. tx_buf = & addr ,
} ;
struct spi_transfer data_xfer = {
. len = 0x0 , /* set below */
. rx_buf = data ,
} ;
struct spi_transfer status_xfer = {
. len = 2 ,
. rx_buf = & lqi_rssi ,
} ;
/* Get the length of the data in the RX FIFO. The length in this
* register exclues the 1 - byte length field at the beginning . */
ret = read_long_reg ( devrec , REG_RX_FIFO , & rx_len ) ;
if ( ret )
goto out ;
/* Range check the RX FIFO length, accounting for the one-byte
* length field at the begining . */
if ( rx_len > RX_FIFO_SIZE - 1 ) {
dev_err ( printdev ( devrec ) , " Invalid length read from device. Performing short read. \n " ) ;
rx_len = RX_FIFO_SIZE - 1 ;
}
if ( rx_len > * len ) {
/* Passed in buffer wasn't big enough. Should never happen. */
dev_err ( printdev ( devrec ) , " Buffer not big enough. Performing short read \n " ) ;
rx_len = * len ;
}
/* Set up the commands to read the data. */
cmd = MRF24J40_READLONG ( REG_RX_FIFO + 1 ) ;
addr [ 0 ] = cmd > > 8 & 0xff ;
addr [ 1 ] = cmd & 0xff ;
data_xfer . len = rx_len ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & addr_xfer , & msg ) ;
spi_message_add_tail ( & data_xfer , & msg ) ;
spi_message_add_tail ( & status_xfer , & msg ) ;
ret = spi_sync ( devrec - > spi , & msg ) ;
if ( ret ) {
dev_err ( printdev ( devrec ) , " SPI RX Buffer Read Failed. \n " ) ;
goto out ;
}
* lqi = lqi_rssi [ 0 ] ;
* len = rx_len ;
# ifdef DEBUG
print_hex_dump ( KERN_DEBUG , " mrf24j40 rx: " ,
DUMP_PREFIX_OFFSET , 16 , 1 , data , * len , 0 ) ;
printk ( KERN_DEBUG " mrf24j40 rx: lqi: %02hhx rssi: %02hhx \n " ,
lqi_rssi [ 0 ] , lqi_rssi [ 1 ] ) ;
# endif
out :
return ret ;
}
static int mrf24j40_tx ( struct ieee802154_dev * dev , struct sk_buff * skb )
{
struct mrf24j40 * devrec = dev - > priv ;
u8 val ;
int ret = 0 ;
dev_dbg ( printdev ( devrec ) , " tx packet of %d bytes \n " , skb - > len ) ;
ret = write_tx_buf ( devrec , 0x000 , skb - > data , skb - > len ) ;
if ( ret )
goto err ;
/* Set TXNTRIG bit of TXNCON to send packet */
ret = read_short_reg ( devrec , REG_TXNCON , & val ) ;
if ( ret )
goto err ;
val | = 0x1 ;
val & = ~ 0x4 ;
write_short_reg ( devrec , REG_TXNCON , val ) ;
INIT_COMPLETION ( devrec - > tx_complete ) ;
/* Wait for the device to send the TX complete interrupt. */
ret = wait_for_completion_interruptible_timeout (
& devrec - > tx_complete ,
5 * HZ ) ;
if ( ret = = - ERESTARTSYS )
goto err ;
if ( ret = = 0 ) {
ret = - ETIMEDOUT ;
goto err ;
}
/* Check for send error from the device. */
ret = read_short_reg ( devrec , REG_TXSTAT , & val ) ;
if ( ret )
goto err ;
if ( val & 0x1 ) {
dev_err ( printdev ( devrec ) , " Error Sending. Retry count exceeded \n " ) ;
ret = - ECOMM ; /* TODO: Better error code ? */
} else
dev_dbg ( printdev ( devrec ) , " Packet Sent \n " ) ;
err :
return ret ;
}
static int mrf24j40_ed ( struct ieee802154_dev * dev , u8 * level )
{
/* TODO: */
printk ( KERN_WARNING " mrf24j40: ed not implemented \n " ) ;
* level = 0 ;
return 0 ;
}
static int mrf24j40_start ( struct ieee802154_dev * dev )
{
struct mrf24j40 * devrec = dev - > priv ;
u8 val ;
int ret ;
dev_dbg ( printdev ( devrec ) , " start \n " ) ;
ret = read_short_reg ( devrec , REG_INTCON , & val ) ;
if ( ret )
return ret ;
val & = ~ ( 0x1 | 0x8 ) ; /* Clear TXNIE and RXIE. Enable interrupts */
write_short_reg ( devrec , REG_INTCON , val ) ;
return 0 ;
}
static void mrf24j40_stop ( struct ieee802154_dev * dev )
{
struct mrf24j40 * devrec = dev - > priv ;
u8 val ;
int ret ;
dev_dbg ( printdev ( devrec ) , " stop \n " ) ;
ret = read_short_reg ( devrec , REG_INTCON , & val ) ;
if ( ret )
return ;
val | = 0x1 | 0x8 ; /* Set TXNIE and RXIE. Disable Interrupts */
write_short_reg ( devrec , REG_INTCON , val ) ;
return ;
}
static int mrf24j40_set_channel ( struct ieee802154_dev * dev ,
int page , int channel )
{
struct mrf24j40 * devrec = dev - > priv ;
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 */
val = ( channel - 11 ) < < 4 | 0x03 ;
write_long_reg ( devrec , REG_RFCON0 , val ) ;
/* RF Reset */
ret = read_short_reg ( devrec , REG_RFCTL , & val ) ;
if ( ret )
return ret ;
val | = 0x04 ;
write_short_reg ( devrec , REG_RFCTL , val ) ;
val & = ~ 0x04 ;
write_short_reg ( devrec , REG_RFCTL , val ) ;
udelay ( SET_CHANNEL_DELAY_US ) ; /* per datasheet */
return 0 ;
}
static int mrf24j40_filter ( struct ieee802154_dev * dev ,
struct ieee802154_hw_addr_filt * filt ,
unsigned long changed )
{
struct mrf24j40 * devrec = dev - > priv ;
dev_dbg ( printdev ( devrec ) , " filter \n " ) ;
if ( changed & IEEE802515_AFILT_SADDR_CHANGED ) {
/* Short Addr */
u8 addrh , addrl ;
addrh = filt - > short_addr > > 8 & 0xff ;
addrl = filt - > short_addr & 0xff ;
write_short_reg ( devrec , REG_SADRH , addrh ) ;
write_short_reg ( devrec , REG_SADRL , addrl ) ;
dev_dbg ( printdev ( devrec ) ,
" Set short addr to %04hx \n " , filt - > short_addr ) ;
}
if ( changed & IEEE802515_AFILT_IEEEADDR_CHANGED ) {
/* Device Address */
int i ;
for ( i = 0 ; i < 8 ; i + + )
write_short_reg ( devrec , REG_EADR0 + i ,
filt - > ieee_addr [ i ] ) ;
# ifdef DEBUG
printk ( KERN_DEBUG " Set long addr to: " ) ;
for ( i = 0 ; i < 8 ; i + + )
printk ( " %02hhx " , filt - > ieee_addr [ i ] ) ;
printk ( KERN_DEBUG " \n " ) ;
# endif
}
if ( changed & IEEE802515_AFILT_PANID_CHANGED ) {
/* PAN ID */
u8 panidl , panidh ;
panidh = filt - > pan_id > > 8 & 0xff ;
panidl = filt - > pan_id & 0xff ;
write_short_reg ( devrec , REG_PANIDH , panidh ) ;
write_short_reg ( devrec , REG_PANIDL , panidl ) ;
dev_dbg ( printdev ( devrec ) , " Set PANID to %04hx \n " , filt - > pan_id ) ;
}
if ( changed & IEEE802515_AFILT_PANC_CHANGED ) {
/* Pan Coordinator */
u8 val ;
int ret ;
ret = read_short_reg ( devrec , REG_RXMCR , & val ) ;
if ( ret )
return ret ;
if ( filt - > pan_coord )
val | = 0x8 ;
else
val & = ~ 0x8 ;
write_short_reg ( devrec , REG_RXMCR , val ) ;
/* 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 " ,
filt - > pan_coord ? " on " : " off " ) ;
}
return 0 ;
}
static int mrf24j40_handle_rx ( struct mrf24j40 * devrec )
{
u8 len = RX_FIFO_SIZE ;
u8 lqi = 0 ;
u8 val ;
int ret = 0 ;
struct sk_buff * skb ;
/* Turn off reception of packets off the air. This prevents the
* device from overwriting the buffer while we ' re reading it . */
ret = read_short_reg ( devrec , REG_BBREG1 , & val ) ;
if ( ret )
goto out ;
val | = 4 ; /* SET RXDECINV */
write_short_reg ( devrec , REG_BBREG1 , val ) ;
skb = alloc_skb ( len , GFP_KERNEL ) ;
if ( ! skb ) {
ret = - ENOMEM ;
goto out ;
}
ret = mrf24j40_read_rx_buf ( devrec , skb_put ( skb , len ) , & len , & lqi ) ;
if ( ret < 0 ) {
dev_err ( printdev ( devrec ) , " Failure reading RX FIFO \n " ) ;
kfree_skb ( skb ) ;
ret = - EINVAL ;
goto out ;
}
/* Cut off the checksum */
skb_trim ( skb , len - 2 ) ;
/* TODO: Other drivers call ieee20154_rx_irqsafe() here (eg: cc2040,
* also from a workqueue ) . I think irqsafe is not necessary here .
* Can someone confirm ? */
ieee802154_rx_irqsafe ( devrec - > dev , skb , lqi ) ;
dev_dbg ( printdev ( devrec ) , " RX Handled \n " ) ;
out :
/* Turn back on reception of packets off the air. */
ret = read_short_reg ( devrec , REG_BBREG1 , & val ) ;
if ( ret )
return ret ;
val & = ~ 0x4 ; /* Clear RXDECINV */
write_short_reg ( devrec , REG_BBREG1 , val ) ;
return ret ;
}
static struct ieee802154_ops mrf24j40_ops = {
. owner = THIS_MODULE ,
. xmit = mrf24j40_tx ,
. ed = mrf24j40_ed ,
. start = mrf24j40_start ,
. stop = mrf24j40_stop ,
. set_channel = mrf24j40_set_channel ,
. set_hw_addr_filt = mrf24j40_filter ,
} ;
static irqreturn_t mrf24j40_isr ( int irq , void * data )
{
struct mrf24j40 * devrec = data ;
disable_irq_nosync ( irq ) ;
schedule_work ( & devrec - > irqwork ) ;
return IRQ_HANDLED ;
}
static void mrf24j40_isrwork ( struct work_struct * work )
{
struct mrf24j40 * devrec = container_of ( work , struct mrf24j40 , irqwork ) ;
u8 intstat ;
int ret ;
/* Read the interrupt status */
ret = read_short_reg ( devrec , REG_INTSTAT , & intstat ) ;
if ( ret )
goto out ;
/* Check for TX complete */
if ( intstat & 0x1 )
complete ( & devrec - > tx_complete ) ;
/* Check for Rx */
if ( intstat & 0x8 )
mrf24j40_handle_rx ( devrec ) ;
out :
enable_irq ( devrec - > spi - > irq ) ;
}
2012-12-03 18:24:12 +04:00
static int mrf24j40_probe ( struct spi_device * spi )
2012-09-02 19:44:13 +04:00
{
int ret = - ENOMEM ;
u8 val ;
struct mrf24j40 * devrec ;
printk ( KERN_INFO " mrf24j40: probe(). IRQ: %d \n " , spi - > irq ) ;
devrec = kzalloc ( sizeof ( struct mrf24j40 ) , GFP_KERNEL ) ;
if ( ! devrec )
goto err_devrec ;
devrec - > buf = kzalloc ( 3 , GFP_KERNEL ) ;
if ( ! devrec - > buf )
goto err_buf ;
spi - > mode = SPI_MODE_0 ; /* TODO: Is this appropriate for right here? */
if ( spi - > max_speed_hz > MAX_SPI_SPEED_HZ )
spi - > max_speed_hz = MAX_SPI_SPEED_HZ ;
mutex_init ( & devrec - > buffer_mutex ) ;
init_completion ( & devrec - > tx_complete ) ;
INIT_WORK ( & devrec - > irqwork , mrf24j40_isrwork ) ;
devrec - > spi = spi ;
dev_set_drvdata ( & spi - > dev , devrec ) ;
/* Register with the 802154 subsystem */
devrec - > dev = ieee802154_alloc_device ( 0 , & mrf24j40_ops ) ;
if ( ! devrec - > dev )
goto err_alloc_dev ;
devrec - > dev - > priv = devrec ;
devrec - > dev - > parent = & devrec - > spi - > dev ;
devrec - > dev - > phy - > channels_supported [ 0 ] = CHANNEL_MASK ;
devrec - > dev - > flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK ;
dev_dbg ( printdev ( devrec ) , " registered mrf24j40 \n " ) ;
ret = ieee802154_register_device ( devrec - > dev ) ;
if ( ret )
goto err_register_device ;
/* Initialize the device.
From datasheet section 3.2 : Initialization . */
write_short_reg ( devrec , REG_SOFTRST , 0x07 ) ;
write_short_reg ( devrec , REG_PACON2 , 0x98 ) ;
write_short_reg ( devrec , REG_TXSTBL , 0x95 ) ;
write_long_reg ( devrec , REG_RFCON0 , 0x03 ) ;
write_long_reg ( devrec , REG_RFCON1 , 0x01 ) ;
write_long_reg ( devrec , REG_RFCON2 , 0x80 ) ;
write_long_reg ( devrec , REG_RFCON6 , 0x90 ) ;
write_long_reg ( devrec , REG_RFCON7 , 0x80 ) ;
write_long_reg ( devrec , REG_RFCON8 , 0x10 ) ;
write_long_reg ( devrec , REG_SLPCON1 , 0x21 ) ;
write_short_reg ( devrec , REG_BBREG2 , 0x80 ) ;
write_short_reg ( devrec , REG_CCAEDTH , 0x60 ) ;
write_short_reg ( devrec , REG_BBREG6 , 0x40 ) ;
write_short_reg ( devrec , REG_RFCTL , 0x04 ) ;
write_short_reg ( devrec , REG_RFCTL , 0x0 ) ;
udelay ( 192 ) ;
/* Set RX Mode. RXMCR<1:0>: 0x0 normal, 0x1 promisc, 0x2 error */
ret = read_short_reg ( devrec , REG_RXMCR , & val ) ;
if ( ret )
goto err_read_reg ;
val & = ~ 0x3 ; /* Clear RX mode (normal) */
write_short_reg ( devrec , REG_RXMCR , val ) ;
ret = request_irq ( spi - > irq ,
mrf24j40_isr ,
IRQF_TRIGGER_FALLING ,
dev_name ( & spi - > dev ) ,
devrec ) ;
if ( ret ) {
dev_err ( printdev ( devrec ) , " Unable to get IRQ " ) ;
goto err_irq ;
}
return 0 ;
err_irq :
err_read_reg :
ieee802154_unregister_device ( devrec - > dev ) ;
err_register_device :
ieee802154_free_device ( devrec - > dev ) ;
err_alloc_dev :
kfree ( devrec - > buf ) ;
err_buf :
kfree ( devrec ) ;
err_devrec :
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
{
struct mrf24j40 * devrec = dev_get_drvdata ( & spi - > dev ) ;
dev_dbg ( printdev ( devrec ) , " remove \n " ) ;
free_irq ( spi - > irq , devrec ) ;
2012-10-03 03:01:31 +04:00
flush_work ( & devrec - > irqwork ) ; /* TODO: Is this the right call? */
2012-09-02 19:44:13 +04:00
ieee802154_unregister_device ( devrec - > dev ) ;
ieee802154_free_device ( devrec - > dev ) ;
/* TODO: Will ieee802154_free_device() wait until ->xmit() is
* complete ? */
/* Clean up the SPI stuff. */
dev_set_drvdata ( & spi - > dev , NULL ) ;
kfree ( devrec - > buf ) ;
kfree ( devrec ) ;
return 0 ;
}
static const struct spi_device_id mrf24j40_ids [ ] = {
{ " mrf24j40 " , 0 } ,
{ " mrf24j40ma " , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( spi , mrf24j40_ids ) ;
static struct spi_driver mrf24j40_driver = {
. driver = {
. name = " mrf24j40 " ,
. bus = & spi_bus_type ,
. owner = THIS_MODULE ,
} ,
. 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
} ;
static int __init mrf24j40_init ( void )
{
return spi_register_driver ( & mrf24j40_driver ) ;
}
static void __exit mrf24j40_exit ( void )
{
spi_unregister_driver ( & mrf24j40_driver ) ;
}
module_init ( mrf24j40_init ) ;
module_exit ( mrf24j40_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Alan Ott " ) ;
MODULE_DESCRIPTION ( " MRF24J40 SPI 802.15.4 Controller Driver " ) ;