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>
2014-10-25 11:41:04 +04:00
# include <linux/ieee802154.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 */
# 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 */
2014-10-06 13:39:45 +04:00
# define REG_GPIO 0x33 /* GPIO */
# define REG_TRISGPIO 0x34 /* GPIO direction */
2012-09-02 19:44:13 +04:00
# 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 */
2014-10-06 13:39:45 +04:00
# define REG_TESTMODE 0x22F /* Test mode */
2012-09-02 19:44:13 +04:00
# 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 */
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
struct mutex buffer_mutex ; /* only used to protect buf */
struct completion tx_complete ;
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)
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)
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
2014-12-12 14:45:32 +03:00
* length field at the beginning . */
2012-09-02 19:44:13 +04:00
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: " ,
2014-12-12 14:45:33 +03:00
DUMP_PREFIX_OFFSET , 16 , 1 , data , * len , 0 ) ;
2014-09-24 14:21:32 +04:00
pr_debug ( " mrf24j40 rx: lqi: %02hhx rssi: %02hhx \n " ,
lqi_rssi [ 0 ] , lqi_rssi [ 1 ] ) ;
2012-09-02 19:44:13 +04:00
# endif
out :
return ret ;
}
2014-10-25 19:16:34 +04:00
static int mrf24j40_tx ( struct ieee802154_hw * hw , struct sk_buff * skb )
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 = 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 ;
2013-11-15 02:32:02 +04:00
reinit_completion ( & devrec - > tx_complete ) ;
2013-10-06 07:52:22 +04:00
2012-09-02 19:44:13 +04:00
/* Set TXNTRIG bit of TXNCON to send packet */
ret = read_short_reg ( devrec , REG_TXNCON , & val ) ;
if ( ret )
goto err ;
val | = 0x1 ;
2013-04-05 14:34:51 +04:00
/* Set TXNACKREQ if the ACK bit is set in the packet. */
if ( skb - > data [ 0 ] & IEEE802154_FC_ACK_REQ )
val | = 0x4 ;
2012-09-02 19:44:13 +04:00
write_short_reg ( devrec , REG_TXNCON , val ) ;
/* 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 ) {
2013-03-18 16:06:41 +04:00
dev_warn ( printdev ( devrec ) , " Timeout waiting for TX interrupt \n " ) ;
2012-09-02 19:44:13 +04:00
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 ) {
2013-04-05 14:34:51 +04:00
dev_dbg ( printdev ( devrec ) , " Error Sending. Retry count exceeded \n " ) ;
2012-09-02 19:44:13 +04:00
ret = - ECOMM ; /* TODO: Better error code ? */
} else
dev_dbg ( printdev ( devrec ) , " Packet Sent \n " ) ;
err :
return ret ;
}
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
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 ;
}
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 ;
2012-09-02 19:44:13 +04:00
u8 val ;
int ret ;
2014-09-24 14:21:30 +04:00
2012-09-02 19:44:13 +04:00
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 ) ;
}
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 */
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 ;
}
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
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 ) ;
}
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 + + )
2014-03-15 00:23:59 +04:00
write_short_reg ( devrec , 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 ;
2012-09-02 19:44:13 +04:00
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 ) ;
}
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 ;
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 " ,
2014-12-12 14:45:33 +03:00
filt - > pan_coord ? " on " : " off " ) ;
2012-09-02 19:44:13 +04:00
}
return 0 ;
}
static int mrf24j40_handle_rx ( struct mrf24j40 * devrec )
{
u8 len = RX_FIFO_SIZE ;
u8 lqi = 0 ;
u8 val ;
int ret = 0 ;
2015-06-09 11:52:26 +03:00
int ret2 ;
2012-09-02 19:44:13 +04:00
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 ) ;
2014-10-27 19:13:29 +03:00
skb = dev_alloc_skb ( len ) ;
2012-09-02 19:44:13 +04:00
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 ? */
2014-10-25 19:16:34 +04:00
ieee802154_rx_irqsafe ( devrec - > hw , skb , lqi ) ;
2012-09-02 19:44:13 +04:00
dev_dbg ( printdev ( devrec ) , " RX Handled \n " ) ;
out :
/* Turn back on reception of packets off the air. */
2015-06-09 11:52:26 +03:00
ret2 = read_short_reg ( devrec , REG_BBREG1 , & val ) ;
if ( ret2 )
return ret2 ;
2012-09-02 19:44:13 +04:00
val & = ~ 0x4 ; /* Clear RXDECINV */
write_short_reg ( devrec , REG_BBREG1 , val ) ;
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 ,
2014-10-26 11:37:08 +03:00
. xmit_sync = 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 ,
} ;
static irqreturn_t mrf24j40_isr ( int irq , void * data )
{
struct mrf24j40 * devrec = data ;
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 :
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 )
{
int ret ;
u8 val ;
/* Initialize the device.
From datasheet section 3.2 : Initialization . */
ret = write_short_reg ( devrec , REG_SOFTRST , 0x07 ) ;
if ( ret )
goto err_ret ;
ret = write_short_reg ( devrec , REG_PACON2 , 0x98 ) ;
if ( ret )
goto err_ret ;
ret = write_short_reg ( devrec , REG_TXSTBL , 0x95 ) ;
if ( ret )
goto err_ret ;
ret = write_long_reg ( devrec , REG_RFCON0 , 0x03 ) ;
if ( ret )
goto err_ret ;
ret = write_long_reg ( devrec , REG_RFCON1 , 0x01 ) ;
if ( ret )
goto err_ret ;
ret = write_long_reg ( devrec , REG_RFCON2 , 0x80 ) ;
if ( ret )
goto err_ret ;
ret = write_long_reg ( devrec , REG_RFCON6 , 0x90 ) ;
if ( ret )
goto err_ret ;
ret = write_long_reg ( devrec , REG_RFCON7 , 0x80 ) ;
if ( ret )
goto err_ret ;
ret = write_long_reg ( devrec , REG_RFCON8 , 0x10 ) ;
if ( ret )
goto err_ret ;
ret = write_long_reg ( devrec , REG_SLPCON1 , 0x21 ) ;
if ( ret )
goto err_ret ;
ret = write_short_reg ( devrec , REG_BBREG2 , 0x80 ) ;
if ( ret )
goto err_ret ;
ret = write_short_reg ( devrec , REG_CCAEDTH , 0x60 ) ;
if ( ret )
goto err_ret ;
ret = write_short_reg ( devrec , REG_BBREG6 , 0x40 ) ;
if ( ret )
goto err_ret ;
ret = write_short_reg ( devrec , REG_RFCTL , 0x04 ) ;
if ( ret )
goto err_ret ;
ret = write_short_reg ( devrec , REG_RFCTL , 0x0 ) ;
if ( ret )
goto err_ret ;
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_ret ;
val & = ~ 0x3 ; /* Clear RX mode (normal) */
ret = write_short_reg ( devrec , REG_RXMCR , val ) ;
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 .
*/
read_long_reg ( devrec , REG_TESTMODE , & val ) ;
val | = 0x7 ; /* Configure GPIO 0-2 to control amplifier */
write_long_reg ( devrec , REG_TESTMODE , val ) ;
read_short_reg ( devrec , REG_TRISGPIO , & val ) ;
val | = 0x8 ; /* Set GPIO3 as output. */
write_short_reg ( devrec , REG_TRISGPIO , val ) ;
read_short_reg ( devrec , REG_GPIO , & val ) ;
val | = 0x8 ; /* Set GPIO3 HIGH to enable U5 voltage regulator */
write_short_reg ( devrec , REG_GPIO , val ) ;
/* Reduce TX pwr to meet FCC requirements.
* From MRF24J40MC datasheet section 3.1 .1
*/
write_long_reg ( devrec , REG_RFCON3 , 0x28 ) ;
}
2014-06-16 07:42:31 +04:00
return 0 ;
err_ret :
return ret ;
}
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 ;
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
2014-06-11 08:34:44 +04:00
devrec = devm_kzalloc ( & spi - > dev , sizeof ( struct mrf24j40 ) , GFP_KERNEL ) ;
2012-09-02 19:44:13 +04:00
if ( ! devrec )
2014-06-11 08:34:44 +04:00
goto err_ret ;
devrec - > buf = devm_kzalloc ( & spi - > dev , 3 , GFP_KERNEL ) ;
2012-09-02 19:44:13 +04:00
if ( ! devrec - > buf )
2014-06-11 08:34:44 +04:00
goto err_ret ;
2012-09-02 19:44:13 +04:00
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 ) ;
devrec - > spi = spi ;
2013-04-06 00:34:18 +04:00
spi_set_drvdata ( spi , devrec ) ;
2012-09-02 19:44:13 +04:00
/* Register with the 802154 subsystem */
2014-10-25 19:16:34 +04:00
devrec - > hw = ieee802154_alloc_hw ( 0 , & mrf24j40_ops ) ;
if ( ! devrec - > hw )
2014-06-11 08:34:44 +04:00
goto err_ret ;
2012-09-02 19:44:13 +04:00
2014-10-25 19:16:34 +04:00
devrec - > hw - > priv = devrec ;
devrec - > hw - > parent = & devrec - > spi - > dev ;
2015-05-17 22:44:42 +03:00
devrec - > hw - > phy - > supported . channels [ 0 ] = CHANNEL_MASK ;
2015-06-06 18:30:48 +03:00
devrec - > hw - > flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT ;
2012-09-02 19:44:13 +04:00
dev_dbg ( printdev ( devrec ) , " registered mrf24j40 \n " ) ;
2014-10-25 19:16:34 +04:00
ret = ieee802154_register_hw ( devrec - > hw ) ;
2012-09-02 19:44:13 +04:00
if ( ret )
goto err_register_device ;
2014-06-16 07:42:31 +04:00
ret = mrf24j40_hw_init ( devrec ) ;
2012-09-02 19:44:13 +04:00
if ( ret )
2014-06-16 07:42:31 +04:00
goto err_hw_init ;
2012-09-02 19:44:13 +04:00
2014-06-11 08:34:44 +04:00
ret = devm_request_threaded_irq ( & spi - > dev ,
spi - > irq ,
NULL ,
mrf24j40_isr ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
dev_name ( & spi - > dev ) ,
devrec ) ;
2012-09-02 19:44:13 +04:00
if ( ret ) {
dev_err ( printdev ( devrec ) , " Unable to get IRQ " ) ;
goto err_irq ;
}
return 0 ;
err_irq :
2014-06-16 07:42:31 +04:00
err_hw_init :
2014-10-25 19:16:34 +04:00
ieee802154_unregister_hw ( devrec - > hw ) ;
2012-09-02 19:44:13 +04:00
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 ;
}
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 = {
. name = " mrf24j40 " ,
. 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
} ;
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 " ) ;