2009-12-10 23:46:28 +00:00
/*
* Blackfin On - Chip CAN Driver
*
* Copyright 2004 - 2009 Analog Devices Inc .
*
* Enter bugs at http : //blackfin.uclinux.org/
*
* Licensed under the GPL - 2 or later .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/bitops.h>
# include <linux/interrupt.h>
# include <linux/errno.h>
# include <linux/netdevice.h>
# include <linux/skbuff.h>
# include <linux/platform_device.h>
# include <linux/can/dev.h>
# include <linux/can/error.h>
# include <asm/portmux.h>
# define DRV_NAME "bfin_can"
# define BFIN_CAN_TIMEOUT 100
2010-03-08 12:13:57 -08:00
# define TX_ECHO_SKB_MAX 1
2009-12-10 23:46:28 +00:00
2015-02-10 17:40:36 +08:00
/* transmit and receive channels */
# define TRANSMIT_CHL 24
# define RECEIVE_STD_CHL 0
# define RECEIVE_EXT_CHL 4
# define RECEIVE_RTR_CHL 8
# define RECEIVE_EXT_RTR_CHL 12
# define MAX_CHL_NUMBER 32
/* All Blackfin system MMRs are padded to 32bits even if the register
* itself is only 16 bits . So use a helper macro to streamline this
*/
# define __BFP(m) u16 m; u16 __pad_##m
/* bfin can registers layout */
struct bfin_can_mask_regs {
__BFP ( aml ) ;
__BFP ( amh ) ;
} ;
struct bfin_can_channel_regs {
/* data[0,2,4,6] -> data{0,1,2,3} while data[1,3,5,7] is padding */
u16 data [ 8 ] ;
__BFP ( dlc ) ;
__BFP ( tsv ) ;
__BFP ( id0 ) ;
__BFP ( id1 ) ;
} ;
struct bfin_can_regs {
/* global control and status registers */
__BFP ( mc1 ) ; /* offset 0x00 */
__BFP ( md1 ) ; /* offset 0x04 */
__BFP ( trs1 ) ; /* offset 0x08 */
__BFP ( trr1 ) ; /* offset 0x0c */
__BFP ( ta1 ) ; /* offset 0x10 */
__BFP ( aa1 ) ; /* offset 0x14 */
__BFP ( rmp1 ) ; /* offset 0x18 */
__BFP ( rml1 ) ; /* offset 0x1c */
__BFP ( mbtif1 ) ; /* offset 0x20 */
__BFP ( mbrif1 ) ; /* offset 0x24 */
__BFP ( mbim1 ) ; /* offset 0x28 */
__BFP ( rfh1 ) ; /* offset 0x2c */
__BFP ( opss1 ) ; /* offset 0x30 */
u32 __pad1 [ 3 ] ;
__BFP ( mc2 ) ; /* offset 0x40 */
__BFP ( md2 ) ; /* offset 0x44 */
__BFP ( trs2 ) ; /* offset 0x48 */
__BFP ( trr2 ) ; /* offset 0x4c */
__BFP ( ta2 ) ; /* offset 0x50 */
__BFP ( aa2 ) ; /* offset 0x54 */
__BFP ( rmp2 ) ; /* offset 0x58 */
__BFP ( rml2 ) ; /* offset 0x5c */
__BFP ( mbtif2 ) ; /* offset 0x60 */
__BFP ( mbrif2 ) ; /* offset 0x64 */
__BFP ( mbim2 ) ; /* offset 0x68 */
__BFP ( rfh2 ) ; /* offset 0x6c */
__BFP ( opss2 ) ; /* offset 0x70 */
u32 __pad2 [ 3 ] ;
__BFP ( clock ) ; /* offset 0x80 */
__BFP ( timing ) ; /* offset 0x84 */
__BFP ( debug ) ; /* offset 0x88 */
__BFP ( status ) ; /* offset 0x8c */
__BFP ( cec ) ; /* offset 0x90 */
__BFP ( gis ) ; /* offset 0x94 */
__BFP ( gim ) ; /* offset 0x98 */
__BFP ( gif ) ; /* offset 0x9c */
__BFP ( control ) ; /* offset 0xa0 */
__BFP ( intr ) ; /* offset 0xa4 */
__BFP ( version ) ; /* offset 0xa8 */
__BFP ( mbtd ) ; /* offset 0xac */
__BFP ( ewr ) ; /* offset 0xb0 */
__BFP ( esr ) ; /* offset 0xb4 */
u32 __pad3 [ 2 ] ;
__BFP ( ucreg ) ; /* offset 0xc0 */
__BFP ( uccnt ) ; /* offset 0xc4 */
__BFP ( ucrc ) ; /* offset 0xc8 */
__BFP ( uccnf ) ; /* offset 0xcc */
u32 __pad4 [ 1 ] ;
__BFP ( version2 ) ; /* offset 0xd4 */
u32 __pad5 [ 10 ] ;
/* channel(mailbox) mask and message registers */
struct bfin_can_mask_regs msk [ MAX_CHL_NUMBER ] ; /* offset 0x100 */
struct bfin_can_channel_regs chl [ MAX_CHL_NUMBER ] ; /* offset 0x200 */
} ;
# undef __BFP
# define SRS 0x0001 /* Software Reset */
# define SER 0x0008 /* Stuff Error */
# define BOIM 0x0008 /* Enable Bus Off Interrupt */
# define CCR 0x0080 /* CAN Configuration Mode Request */
# define CCA 0x0080 /* Configuration Mode Acknowledge */
# define SAM 0x0080 /* Sampling */
# define AME 0x8000 /* Acceptance Mask Enable */
# define RMLIM 0x0080 /* Enable RX Message Lost Interrupt */
# define RMLIS 0x0080 /* RX Message Lost IRQ Status */
# define RTR 0x4000 /* Remote Frame Transmission Request */
# define BOIS 0x0008 /* Bus Off IRQ Status */
# define IDE 0x2000 /* Identifier Extension */
# define EPIS 0x0004 /* Error-Passive Mode IRQ Status */
# define EPIM 0x0004 /* Enable Error-Passive Mode Interrupt */
# define EWTIS 0x0001 /* TX Error Count IRQ Status */
# define EWRIS 0x0002 /* RX Error Count IRQ Status */
# define BEF 0x0040 /* Bit Error Flag */
# define FER 0x0080 /* Form Error Flag */
# define SMR 0x0020 /* Sleep Mode Request */
# define SMACK 0x0008 /* Sleep Mode Acknowledge */
2009-12-10 23:46:28 +00:00
/*
* bfin can private data
*/
struct bfin_can_priv {
struct can_priv can ; /* must be the first member */
struct net_device * dev ;
void __iomem * membase ;
int rx_irq ;
int tx_irq ;
int err_irq ;
unsigned short * pin_list ;
} ;
/*
* bfin can timing parameters
*/
2012-07-16 12:58:31 +02:00
static const struct can_bittiming_const bfin_can_bittiming_const = {
2009-12-10 23:46:28 +00:00
. name = DRV_NAME ,
. tseg1_min = 1 ,
. tseg1_max = 16 ,
. tseg2_min = 1 ,
. tseg2_max = 8 ,
. sjw_max = 4 ,
/*
* Although the BRP field can be set to any value , it is recommended
* that the value be greater than or equal to 4 , as restrictions
* apply to the bit timing configuration when BRP is less than 4.
*/
. brp_min = 4 ,
. brp_max = 1024 ,
. brp_inc = 1 ,
} ;
static int bfin_can_set_bittiming ( struct net_device * dev )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
struct can_bittiming * bt = & priv - > can . bittiming ;
u16 clk , timing ;
clk = bt - > brp - 1 ;
timing = ( ( bt - > sjw - 1 ) < < 8 ) | ( bt - > prop_seg + bt - > phase_seg1 - 1 ) |
( ( bt - > phase_seg2 - 1 ) < < 4 ) ;
/*
* If the SAM bit is set , the input signal is oversampled three times
* at the SCLK rate .
*/
if ( priv - > can . ctrlmode & CAN_CTRLMODE_3_SAMPLES )
timing | = SAM ;
2015-02-10 17:40:34 +08:00
writew ( clk , & reg - > clock ) ;
writew ( timing , & reg - > timing ) ;
2009-12-10 23:46:28 +00:00
2012-02-01 11:02:05 +01:00
netdev_info ( dev , " setting CLOCK=0x%04x TIMING=0x%04x \n " , clk , timing ) ;
2009-12-10 23:46:28 +00:00
return 0 ;
}
static void bfin_can_set_reset_mode ( struct net_device * dev )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
int timeout = BFIN_CAN_TIMEOUT ;
int i ;
/* disable interrupts */
2015-02-10 17:40:34 +08:00
writew ( 0 , & reg - > mbim1 ) ;
writew ( 0 , & reg - > mbim2 ) ;
writew ( 0 , & reg - > gim ) ;
2009-12-10 23:46:28 +00:00
/* reset can and enter configuration mode */
2015-02-10 17:40:34 +08:00
writew ( SRS | CCR , & reg - > control ) ;
writew ( CCR , & reg - > control ) ;
while ( ! ( readw ( & reg - > control ) & CCA ) ) {
2009-12-10 23:46:28 +00:00
udelay ( 10 ) ;
if ( - - timeout = = 0 ) {
2012-02-01 11:02:05 +01:00
netdev_err ( dev , " fail to enter configuration mode \n " ) ;
2009-12-10 23:46:28 +00:00
BUG ( ) ;
}
}
/*
* All mailbox configurations are marked as inactive
* by writing to CAN Mailbox Configuration Registers 1 and 2
* For all bits : 0 - Mailbox disabled , 1 - Mailbox enabled
*/
2015-02-10 17:40:34 +08:00
writew ( 0 , & reg - > mc1 ) ;
writew ( 0 , & reg - > mc2 ) ;
2009-12-10 23:46:28 +00:00
/* Set Mailbox Direction */
2015-02-10 17:40:34 +08:00
writew ( 0xFFFF , & reg - > md1 ) ; /* mailbox 1-16 are RX */
writew ( 0 , & reg - > md2 ) ; /* mailbox 17-32 are TX */
2009-12-10 23:46:28 +00:00
/* RECEIVE_STD_CHL */
for ( i = 0 ; i < 2 ; i + + ) {
2015-02-10 17:40:34 +08:00
writew ( 0 , & reg - > chl [ RECEIVE_STD_CHL + i ] . id0 ) ;
writew ( AME , & reg - > chl [ RECEIVE_STD_CHL + i ] . id1 ) ;
writew ( 0 , & reg - > chl [ RECEIVE_STD_CHL + i ] . dlc ) ;
writew ( 0x1FFF , & reg - > msk [ RECEIVE_STD_CHL + i ] . amh ) ;
writew ( 0xFFFF , & reg - > msk [ RECEIVE_STD_CHL + i ] . aml ) ;
2009-12-10 23:46:28 +00:00
}
/* RECEIVE_EXT_CHL */
for ( i = 0 ; i < 2 ; i + + ) {
2015-02-10 17:40:34 +08:00
writew ( 0 , & reg - > chl [ RECEIVE_EXT_CHL + i ] . id0 ) ;
writew ( AME | IDE , & reg - > chl [ RECEIVE_EXT_CHL + i ] . id1 ) ;
writew ( 0 , & reg - > chl [ RECEIVE_EXT_CHL + i ] . dlc ) ;
writew ( 0x1FFF , & reg - > msk [ RECEIVE_EXT_CHL + i ] . amh ) ;
writew ( 0xFFFF , & reg - > msk [ RECEIVE_EXT_CHL + i ] . aml ) ;
2009-12-10 23:46:28 +00:00
}
2015-02-10 17:40:34 +08:00
writew ( BIT ( TRANSMIT_CHL - 16 ) , & reg - > mc2 ) ;
writew ( BIT ( RECEIVE_STD_CHL ) + BIT ( RECEIVE_EXT_CHL ) , & reg - > mc1 ) ;
2009-12-10 23:46:28 +00:00
priv - > can . state = CAN_STATE_STOPPED ;
}
static void bfin_can_set_normal_mode ( struct net_device * dev )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
int timeout = BFIN_CAN_TIMEOUT ;
/*
* leave configuration mode
*/
2015-02-10 17:40:34 +08:00
writew ( readw ( & reg - > control ) & ~ CCR , & reg - > control ) ;
2009-12-10 23:46:28 +00:00
2015-02-10 17:40:34 +08:00
while ( readw ( & reg - > status ) & CCA ) {
2009-12-10 23:46:28 +00:00
udelay ( 10 ) ;
if ( - - timeout = = 0 ) {
2012-02-01 11:02:05 +01:00
netdev_err ( dev , " fail to leave configuration mode \n " ) ;
2009-12-10 23:46:28 +00:00
BUG ( ) ;
}
}
/*
* clear _All_ tx and rx interrupts
*/
2015-02-10 17:40:34 +08:00
writew ( 0xFFFF , & reg - > mbtif1 ) ;
writew ( 0xFFFF , & reg - > mbtif2 ) ;
writew ( 0xFFFF , & reg - > mbrif1 ) ;
writew ( 0xFFFF , & reg - > mbrif2 ) ;
2009-12-10 23:46:28 +00:00
/*
* clear global interrupt status register
*/
2015-02-10 17:40:34 +08:00
writew ( 0x7FF , & reg - > gis ) ; /* overwrites with '1' */
2009-12-10 23:46:28 +00:00
/*
* Initialize Interrupts
* - set bits in the mailbox interrupt mask register
* - global interrupt mask
*/
2015-02-10 17:40:34 +08:00
writew ( BIT ( RECEIVE_STD_CHL ) + BIT ( RECEIVE_EXT_CHL ) , & reg - > mbim1 ) ;
writew ( BIT ( TRANSMIT_CHL - 16 ) , & reg - > mbim2 ) ;
2009-12-10 23:46:28 +00:00
2015-02-10 17:40:34 +08:00
writew ( EPIM | BOIM | RMLIM , & reg - > gim ) ;
2009-12-10 23:46:28 +00:00
}
static void bfin_can_start ( struct net_device * dev )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
/* enter reset mode */
if ( priv - > can . state ! = CAN_STATE_STOPPED )
bfin_can_set_reset_mode ( dev ) ;
/* leave reset mode */
bfin_can_set_normal_mode ( dev ) ;
}
static int bfin_can_set_mode ( struct net_device * dev , enum can_mode mode )
{
switch ( mode ) {
case CAN_MODE_START :
bfin_can_start ( dev ) ;
if ( netif_queue_stopped ( dev ) )
netif_wake_queue ( dev ) ;
break ;
default :
return - EOPNOTSUPP ;
}
return 0 ;
}
2012-02-01 11:14:13 +01:00
static int bfin_can_get_berr_counter ( const struct net_device * dev ,
struct can_berr_counter * bec )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
2015-02-10 17:40:34 +08:00
u16 cec = readw ( & reg - > cec ) ;
2012-02-01 11:14:13 +01:00
bec - > txerr = cec > > 8 ;
bec - > rxerr = cec ;
return 0 ;
}
2009-12-10 23:46:28 +00:00
static int bfin_can_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
struct can_frame * cf = ( struct can_frame * ) skb - > data ;
u8 dlc = cf - > can_dlc ;
canid_t id = cf - > can_id ;
u8 * data = cf - > data ;
u16 val ;
int i ;
2010-01-12 02:00:46 -08:00
if ( can_dropped_invalid_skb ( dev , skb ) )
return NETDEV_TX_OK ;
2009-12-10 23:46:28 +00:00
netif_stop_queue ( dev ) ;
/* fill id */
if ( id & CAN_EFF_FLAG ) {
2015-02-10 17:40:34 +08:00
writew ( id , & reg - > chl [ TRANSMIT_CHL ] . id0 ) ;
2011-06-24 04:33:01 +00:00
val = ( ( id & 0x1FFF0000 ) > > 16 ) | IDE ;
} else
val = ( id < < 2 ) ;
if ( id & CAN_RTR_FLAG )
val | = RTR ;
2015-02-10 17:40:34 +08:00
writew ( val | AME , & reg - > chl [ TRANSMIT_CHL ] . id1 ) ;
2009-12-10 23:46:28 +00:00
/* fill payload */
for ( i = 0 ; i < 8 ; i + = 2 ) {
val = ( ( 7 - i ) < dlc ? ( data [ 7 - i ] ) : 0 ) +
( ( 6 - i ) < dlc ? ( data [ 6 - i ] < < 8 ) : 0 ) ;
2015-02-10 17:40:34 +08:00
writew ( val , & reg - > chl [ TRANSMIT_CHL ] . data [ i ] ) ;
2009-12-10 23:46:28 +00:00
}
/* fill data length code */
2015-02-10 17:40:34 +08:00
writew ( dlc , & reg - > chl [ TRANSMIT_CHL ] . dlc ) ;
2009-12-10 23:46:28 +00:00
can_put_echo_skb ( skb , dev , 0 ) ;
/* set transmit request */
2015-02-10 17:40:34 +08:00
writew ( BIT ( TRANSMIT_CHL - 16 ) , & reg - > trs2 ) ;
2009-12-10 23:46:28 +00:00
return 0 ;
}
static void bfin_can_rx ( struct net_device * dev , u16 isrc )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct net_device_stats * stats = & dev - > stats ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
struct can_frame * cf ;
struct sk_buff * skb ;
int obj ;
int i ;
u16 val ;
skb = alloc_can_skb ( dev , & cf ) ;
if ( skb = = NULL )
return ;
/* get id */
if ( isrc & BIT ( RECEIVE_EXT_CHL ) ) {
/* extended frame format (EFF) */
2015-02-10 17:40:34 +08:00
cf - > can_id = ( ( readw ( & reg - > chl [ RECEIVE_EXT_CHL ] . id1 )
2009-12-10 23:46:28 +00:00
& 0x1FFF ) < < 16 )
2015-02-10 17:40:34 +08:00
+ readw ( & reg - > chl [ RECEIVE_EXT_CHL ] . id0 ) ;
2009-12-10 23:46:28 +00:00
cf - > can_id | = CAN_EFF_FLAG ;
obj = RECEIVE_EXT_CHL ;
} else {
/* standard frame format (SFF) */
2015-02-10 17:40:34 +08:00
cf - > can_id = ( readw ( & reg - > chl [ RECEIVE_STD_CHL ] . id1 )
2009-12-10 23:46:28 +00:00
& 0x1ffc ) > > 2 ;
obj = RECEIVE_STD_CHL ;
}
2015-02-10 17:40:34 +08:00
if ( readw ( & reg - > chl [ obj ] . id1 ) & RTR )
2009-12-10 23:46:28 +00:00
cf - > can_id | = CAN_RTR_FLAG ;
/* get data length code */
2015-02-10 17:40:34 +08:00
cf - > can_dlc = get_can_dlc ( readw ( & reg - > chl [ obj ] . dlc ) & 0xF ) ;
2009-12-10 23:46:28 +00:00
/* get payload */
for ( i = 0 ; i < 8 ; i + = 2 ) {
2015-02-10 17:40:34 +08:00
val = readw ( & reg - > chl [ obj ] . data [ i ] ) ;
2009-12-10 23:46:28 +00:00
cf - > data [ 7 - i ] = ( 7 - i ) < cf - > can_dlc ? val : 0 ;
cf - > data [ 6 - i ] = ( 6 - i ) < cf - > can_dlc ? ( val > > 8 ) : 0 ;
}
stats - > rx_packets + + ;
stats - > rx_bytes + = cf - > can_dlc ;
2015-07-11 21:16:08 +02:00
netif_rx ( skb ) ;
2009-12-10 23:46:28 +00:00
}
static int bfin_can_err ( struct net_device * dev , u16 isrc , u16 status )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
struct net_device_stats * stats = & dev - > stats ;
struct can_frame * cf ;
struct sk_buff * skb ;
enum can_state state = priv - > can . state ;
skb = alloc_can_err_skb ( dev , & cf ) ;
if ( skb = = NULL )
return - ENOMEM ;
if ( isrc & RMLIS ) {
/* data overrun interrupt */
2012-02-01 11:02:05 +01:00
netdev_dbg ( dev , " data overrun interrupt \n " ) ;
2009-12-10 23:46:28 +00:00
cf - > can_id | = CAN_ERR_CRTL ;
cf - > data [ 1 ] = CAN_ERR_CRTL_RX_OVERFLOW ;
stats - > rx_over_errors + + ;
stats - > rx_errors + + ;
}
if ( isrc & BOIS ) {
2012-02-01 11:02:05 +01:00
netdev_dbg ( dev , " bus-off mode interrupt \n " ) ;
2009-12-10 23:46:28 +00:00
state = CAN_STATE_BUS_OFF ;
cf - > can_id | = CAN_ERR_BUSOFF ;
2015-01-16 14:30:28 +00:00
priv - > can . can_stats . bus_off + + ;
2009-12-10 23:46:28 +00:00
can_bus_off ( dev ) ;
}
if ( isrc & EPIS ) {
/* error passive interrupt */
2012-02-01 11:02:05 +01:00
netdev_dbg ( dev , " error passive interrupt \n " ) ;
2009-12-10 23:46:28 +00:00
state = CAN_STATE_ERROR_PASSIVE ;
}
if ( ( isrc & EWTIS ) | | ( isrc & EWRIS ) ) {
2012-02-01 11:02:05 +01:00
netdev_dbg ( dev , " Error Warning Transmit/Receive Interrupt \n " ) ;
2009-12-10 23:46:28 +00:00
state = CAN_STATE_ERROR_WARNING ;
}
if ( state ! = priv - > can . state & & ( state = = CAN_STATE_ERROR_WARNING | |
state = = CAN_STATE_ERROR_PASSIVE ) ) {
2015-02-10 17:40:34 +08:00
u16 cec = readw ( & reg - > cec ) ;
2009-12-10 23:46:28 +00:00
u8 rxerr = cec ;
u8 txerr = cec > > 8 ;
cf - > can_id | = CAN_ERR_CRTL ;
if ( state = = CAN_STATE_ERROR_WARNING ) {
priv - > can . can_stats . error_warning + + ;
cf - > data [ 1 ] = ( txerr > rxerr ) ?
CAN_ERR_CRTL_TX_WARNING :
CAN_ERR_CRTL_RX_WARNING ;
} else {
priv - > can . can_stats . error_passive + + ;
cf - > data [ 1 ] = ( txerr > rxerr ) ?
CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE ;
}
}
if ( status ) {
priv - > can . can_stats . bus_error + + ;
cf - > can_id | = CAN_ERR_PROT | CAN_ERR_BUSERROR ;
if ( status & BEF )
cf - > data [ 2 ] | = CAN_ERR_PROT_BIT ;
else if ( status & FER )
cf - > data [ 2 ] | = CAN_ERR_PROT_FORM ;
else if ( status & SER )
cf - > data [ 2 ] | = CAN_ERR_PROT_STUFF ;
}
priv - > can . state = state ;
stats - > rx_packets + + ;
stats - > rx_bytes + = cf - > can_dlc ;
2015-07-11 21:16:08 +02:00
netif_rx ( skb ) ;
2009-12-10 23:46:28 +00:00
return 0 ;
}
2012-10-11 23:20:27 +02:00
static irqreturn_t bfin_can_interrupt ( int irq , void * dev_id )
2009-12-10 23:46:28 +00:00
{
struct net_device * dev = dev_id ;
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
struct net_device_stats * stats = & dev - > stats ;
u16 status , isrc ;
2015-02-10 17:40:34 +08:00
if ( ( irq = = priv - > tx_irq ) & & readw ( & reg - > mbtif2 ) ) {
2009-12-10 23:46:28 +00:00
/* transmission complete interrupt */
2015-02-10 17:40:34 +08:00
writew ( 0xFFFF , & reg - > mbtif2 ) ;
2009-12-10 23:46:28 +00:00
stats - > tx_packets + + ;
2015-02-10 17:40:34 +08:00
stats - > tx_bytes + = readw ( & reg - > chl [ TRANSMIT_CHL ] . dlc ) ;
2009-12-10 23:46:28 +00:00
can_get_echo_skb ( dev , 0 ) ;
netif_wake_queue ( dev ) ;
2015-02-10 17:40:34 +08:00
} else if ( ( irq = = priv - > rx_irq ) & & readw ( & reg - > mbrif1 ) ) {
2009-12-10 23:46:28 +00:00
/* receive interrupt */
2015-02-10 17:40:34 +08:00
isrc = readw ( & reg - > mbrif1 ) ;
writew ( 0xFFFF , & reg - > mbrif1 ) ;
2009-12-10 23:46:28 +00:00
bfin_can_rx ( dev , isrc ) ;
2015-02-10 17:40:34 +08:00
} else if ( ( irq = = priv - > err_irq ) & & readw ( & reg - > gis ) ) {
2009-12-10 23:46:28 +00:00
/* error interrupt */
2015-02-10 17:40:34 +08:00
isrc = readw ( & reg - > gis ) ;
status = readw ( & reg - > esr ) ;
writew ( 0x7FF , & reg - > gis ) ;
2009-12-10 23:46:28 +00:00
bfin_can_err ( dev , isrc , status ) ;
} else {
return IRQ_NONE ;
}
return IRQ_HANDLED ;
}
static int bfin_can_open ( struct net_device * dev )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
int err ;
/* set chip into reset mode */
bfin_can_set_reset_mode ( dev ) ;
/* common open */
err = open_candev ( dev ) ;
if ( err )
goto exit_open ;
/* register interrupt handler */
err = request_irq ( priv - > rx_irq , & bfin_can_interrupt , 0 ,
" bfin-can-rx " , dev ) ;
if ( err )
goto exit_rx_irq ;
err = request_irq ( priv - > tx_irq , & bfin_can_interrupt , 0 ,
" bfin-can-tx " , dev ) ;
if ( err )
goto exit_tx_irq ;
err = request_irq ( priv - > err_irq , & bfin_can_interrupt , 0 ,
" bfin-can-err " , dev ) ;
if ( err )
goto exit_err_irq ;
bfin_can_start ( dev ) ;
netif_start_queue ( dev ) ;
return 0 ;
exit_err_irq :
free_irq ( priv - > tx_irq , dev ) ;
exit_tx_irq :
free_irq ( priv - > rx_irq , dev ) ;
exit_rx_irq :
close_candev ( dev ) ;
exit_open :
return err ;
}
static int bfin_can_close ( struct net_device * dev )
{
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
netif_stop_queue ( dev ) ;
bfin_can_set_reset_mode ( dev ) ;
close_candev ( dev ) ;
free_irq ( priv - > rx_irq , dev ) ;
free_irq ( priv - > tx_irq , dev ) ;
free_irq ( priv - > err_irq , dev ) ;
return 0 ;
}
2012-10-11 23:20:27 +02:00
static struct net_device * alloc_bfin_candev ( void )
2009-12-10 23:46:28 +00:00
{
struct net_device * dev ;
struct bfin_can_priv * priv ;
2010-03-08 12:13:57 -08:00
dev = alloc_candev ( sizeof ( * priv ) , TX_ECHO_SKB_MAX ) ;
2009-12-10 23:46:28 +00:00
if ( ! dev )
return NULL ;
priv = netdev_priv ( dev ) ;
priv - > dev = dev ;
priv - > can . bittiming_const = & bfin_can_bittiming_const ;
priv - > can . do_set_bittiming = bfin_can_set_bittiming ;
priv - > can . do_set_mode = bfin_can_set_mode ;
2012-02-01 11:14:13 +01:00
priv - > can . do_get_berr_counter = bfin_can_get_berr_counter ;
2010-01-14 07:08:34 +00:00
priv - > can . ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES ;
2009-12-10 23:46:28 +00:00
return dev ;
}
static const struct net_device_ops bfin_can_netdev_ops = {
. ndo_open = bfin_can_open ,
. ndo_stop = bfin_can_close ,
. ndo_start_xmit = bfin_can_start_xmit ,
2014-03-07 09:23:41 +01:00
. ndo_change_mtu = can_change_mtu ,
2009-12-10 23:46:28 +00:00
} ;
2012-12-03 09:22:44 -05:00
static int bfin_can_probe ( struct platform_device * pdev )
2009-12-10 23:46:28 +00:00
{
int err ;
struct net_device * dev ;
struct bfin_can_priv * priv ;
struct resource * res_mem , * rx_irq , * tx_irq , * err_irq ;
unsigned short * pdata ;
2013-09-10 17:40:42 +09:00
pdata = dev_get_platdata ( & pdev - > dev ) ;
2009-12-10 23:46:28 +00:00
if ( ! pdata ) {
dev_err ( & pdev - > dev , " No platform data provided! \n " ) ;
err = - EINVAL ;
goto exit ;
}
res_mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
rx_irq = platform_get_resource ( pdev , IORESOURCE_IRQ , 0 ) ;
tx_irq = platform_get_resource ( pdev , IORESOURCE_IRQ , 1 ) ;
err_irq = platform_get_resource ( pdev , IORESOURCE_IRQ , 2 ) ;
if ( ! res_mem | | ! rx_irq | | ! tx_irq | | ! err_irq ) {
err = - EINVAL ;
goto exit ;
}
/* request peripheral pins */
err = peripheral_request_list ( pdata , dev_name ( & pdev - > dev ) ) ;
if ( err )
2015-02-10 17:40:35 +08:00
goto exit ;
2009-12-10 23:46:28 +00:00
dev = alloc_bfin_candev ( ) ;
if ( ! dev ) {
err = - ENOMEM ;
goto exit_peri_pin_free ;
}
priv = netdev_priv ( dev ) ;
2015-02-10 17:40:35 +08:00
priv - > membase = devm_ioremap_resource ( & pdev - > dev , res_mem ) ;
if ( IS_ERR ( priv - > membase ) ) {
err = PTR_ERR ( priv - > membase ) ;
goto exit_peri_pin_free ;
}
2009-12-10 23:46:28 +00:00
priv - > rx_irq = rx_irq - > start ;
priv - > tx_irq = tx_irq - > start ;
priv - > err_irq = err_irq - > start ;
priv - > pin_list = pdata ;
priv - > can . clock . freq = get_sclk ( ) ;
2013-05-23 19:47:58 +09:00
platform_set_drvdata ( pdev , dev ) ;
2009-12-10 23:46:28 +00:00
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
dev - > flags | = IFF_ECHO ; /* we support local echo */
dev - > netdev_ops = & bfin_can_netdev_ops ;
bfin_can_set_reset_mode ( dev ) ;
err = register_candev ( dev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " registering failed (err=%d) \n " , err ) ;
goto exit_candev_free ;
}
dev_info ( & pdev - > dev ,
" %s device registered "
" (®_base=%p, rx_irq=%d, tx_irq=%d, err_irq=%d, sclk=%d) \n " ,
2012-06-04 12:44:18 +00:00
DRV_NAME , priv - > membase , priv - > rx_irq ,
2009-12-10 23:46:28 +00:00
priv - > tx_irq , priv - > err_irq , priv - > can . clock . freq ) ;
return 0 ;
exit_candev_free :
free_candev ( dev ) ;
exit_peri_pin_free :
peripheral_free_list ( pdata ) ;
exit :
return err ;
}
2012-12-03 09:22:44 -05:00
static int bfin_can_remove ( struct platform_device * pdev )
2009-12-10 23:46:28 +00:00
{
2013-05-23 19:47:58 +09:00
struct net_device * dev = platform_get_drvdata ( pdev ) ;
2009-12-10 23:46:28 +00:00
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
bfin_can_set_reset_mode ( dev ) ;
unregister_candev ( dev ) ;
peripheral_free_list ( priv - > pin_list ) ;
free_candev ( dev ) ;
return 0 ;
}
# ifdef CONFIG_PM
static int bfin_can_suspend ( struct platform_device * pdev , pm_message_t mesg )
{
2013-05-23 19:47:58 +09:00
struct net_device * dev = platform_get_drvdata ( pdev ) ;
2009-12-10 23:46:28 +00:00
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
int timeout = BFIN_CAN_TIMEOUT ;
if ( netif_running ( dev ) ) {
/* enter sleep mode */
2015-02-10 17:40:34 +08:00
writew ( readw ( & reg - > control ) | SMR , & reg - > control ) ;
while ( ! ( readw ( & reg - > intr ) & SMACK ) ) {
2009-12-10 23:46:28 +00:00
udelay ( 10 ) ;
if ( - - timeout = = 0 ) {
2012-02-01 11:02:05 +01:00
netdev_err ( dev , " fail to enter sleep mode \n " ) ;
2009-12-10 23:46:28 +00:00
BUG ( ) ;
}
}
}
return 0 ;
}
static int bfin_can_resume ( struct platform_device * pdev )
{
2013-05-23 19:47:58 +09:00
struct net_device * dev = platform_get_drvdata ( pdev ) ;
2009-12-10 23:46:28 +00:00
struct bfin_can_priv * priv = netdev_priv ( dev ) ;
struct bfin_can_regs __iomem * reg = priv - > membase ;
if ( netif_running ( dev ) ) {
/* leave sleep mode */
2015-02-10 17:40:34 +08:00
writew ( 0 , & reg - > intr ) ;
2009-12-10 23:46:28 +00:00
}
return 0 ;
}
# else
# define bfin_can_suspend NULL
# define bfin_can_resume NULL
# endif /* CONFIG_PM */
static struct platform_driver bfin_can_driver = {
. probe = bfin_can_probe ,
2012-12-03 09:22:44 -05:00
. remove = bfin_can_remove ,
2009-12-10 23:46:28 +00:00
. suspend = bfin_can_suspend ,
. resume = bfin_can_resume ,
. driver = {
. name = DRV_NAME ,
} ,
} ;
2011-11-27 15:42:31 +00:00
module_platform_driver ( bfin_can_driver ) ;
2009-12-10 23:46:28 +00:00
MODULE_AUTHOR ( " Barry Song <21cnbao@gmail.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Blackfin on-chip CAN netdevice driver " ) ;
2012-10-12 09:45:14 +02:00
MODULE_ALIAS ( " platform: " DRV_NAME ) ;