2019-05-29 16:57:58 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2009-11-13 06:14:52 +00:00
/*
* CAN bus driver for the alone generic ( as possible as ) MSCAN controller .
*
* Copyright ( C ) 2005 - 2006 Andrey Volkov < avolkov @ varma - el . com > ,
* Varma Electronics Oy
* Copyright ( C ) 2008 - 2009 Wolfgang Grandegger < wg @ grandegger . com >
2010-01-07 09:43:06 +00:00
* Copyright ( C ) 2008 - 2009 Pengutronix < kernel @ pengutronix . de >
2009-11-13 06:14:52 +00:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/netdevice.h>
# include <linux/if_arp.h>
# include <linux/if_ether.h>
# include <linux/list.h>
# include <linux/can/dev.h>
# include <linux/can/error.h>
# include <linux/io.h>
# include "mscan.h"
2012-07-16 12:58:31 +02:00
static const struct can_bittiming_const mscan_bittiming_const = {
2009-11-13 06:14:52 +00:00
. name = " mscan " ,
. tseg1_min = 4 ,
. tseg1_max = 16 ,
. tseg2_min = 2 ,
. tseg2_max = 8 ,
. sjw_max = 4 ,
. brp_min = 1 ,
. brp_max = 64 ,
. brp_inc = 1 ,
} ;
struct mscan_state {
u8 mode ;
u8 canrier ;
u8 cantier ;
} ;
static enum can_state state_map [ ] = {
CAN_STATE_ERROR_ACTIVE ,
CAN_STATE_ERROR_WARNING ,
CAN_STATE_ERROR_PASSIVE ,
CAN_STATE_BUS_OFF
} ;
static int mscan_set_mode ( struct net_device * dev , u8 mode )
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
int ret = 0 ;
int i ;
u8 canctl1 ;
if ( mode ! = MSCAN_NORMAL_MODE ) {
if ( priv - > tx_active ) {
/* Abort transfers before going to sleep */ #
out_8 ( & regs - > cantarq , priv - > tx_active ) ;
/* Suppress TX done interrupts */
out_8 ( & regs - > cantier , 0 ) ;
}
canctl1 = in_8 ( & regs - > canctl1 ) ;
2009-11-16 12:57:45 +00:00
if ( ( mode & MSCAN_SLPRQ ) & & ! ( canctl1 & MSCAN_SLPAK ) ) {
2009-11-16 12:57:47 +00:00
setbits8 ( & regs - > canctl0 , MSCAN_SLPRQ ) ;
2009-11-13 06:14:52 +00:00
for ( i = 0 ; i < MSCAN_SET_MODE_RETRIES ; i + + ) {
if ( in_8 ( & regs - > canctl1 ) & MSCAN_SLPAK )
break ;
udelay ( 100 ) ;
}
/*
* The mscan controller will fail to enter sleep mode ,
* while there are irregular activities on bus , like
* somebody keeps retransmitting . This behavior is
* undocumented and seems to differ between mscan built
* in mpc5200b and mpc5200 . We proceed in that case ,
* since otherwise the slprq will be kept set and the
* controller will get stuck . NOTE : INITRQ or CSWAI
* will abort all active transmit actions , if still
* any , at once .
*/
if ( i > = MSCAN_SET_MODE_RETRIES )
2012-02-01 11:02:05 +01:00
netdev_dbg ( dev ,
" device failed to enter sleep mode. "
" We proceed anyhow. \n " ) ;
2009-11-13 06:14:52 +00:00
else
priv - > can . state = CAN_STATE_SLEEPING ;
}
2009-11-16 12:57:45 +00:00
if ( ( mode & MSCAN_INITRQ ) & & ! ( canctl1 & MSCAN_INITAK ) ) {
2009-11-16 12:57:47 +00:00
setbits8 ( & regs - > canctl0 , MSCAN_INITRQ ) ;
2009-11-13 06:14:52 +00:00
for ( i = 0 ; i < MSCAN_SET_MODE_RETRIES ; i + + ) {
if ( in_8 ( & regs - > canctl1 ) & MSCAN_INITAK )
break ;
}
if ( i > = MSCAN_SET_MODE_RETRIES )
ret = - ENODEV ;
}
if ( ! ret )
priv - > can . state = CAN_STATE_STOPPED ;
if ( mode & MSCAN_CSWAI )
2009-11-16 12:57:47 +00:00
setbits8 ( & regs - > canctl0 , MSCAN_CSWAI ) ;
2009-11-13 06:14:52 +00:00
} else {
canctl1 = in_8 ( & regs - > canctl1 ) ;
if ( canctl1 & ( MSCAN_SLPAK | MSCAN_INITAK ) ) {
2009-11-16 12:57:47 +00:00
clrbits8 ( & regs - > canctl0 , MSCAN_SLPRQ | MSCAN_INITRQ ) ;
2009-11-13 06:14:52 +00:00
for ( i = 0 ; i < MSCAN_SET_MODE_RETRIES ; i + + ) {
canctl1 = in_8 ( & regs - > canctl1 ) ;
if ( ! ( canctl1 & ( MSCAN_INITAK | MSCAN_SLPAK ) ) )
break ;
}
if ( i > = MSCAN_SET_MODE_RETRIES )
ret = - ENODEV ;
else
priv - > can . state = CAN_STATE_ERROR_ACTIVE ;
}
}
return ret ;
}
static int mscan_start ( struct net_device * dev )
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
u8 canrflg ;
int err ;
out_8 ( & regs - > canrier , 0 ) ;
INIT_LIST_HEAD ( & priv - > tx_head ) ;
priv - > prev_buf_id = 0 ;
priv - > cur_pri = 0 ;
priv - > tx_active = 0 ;
priv - > shadow_canrier = 0 ;
priv - > flags = 0 ;
2010-01-07 09:43:07 +00:00
if ( priv - > type = = MSCAN_TYPE_MPC5121 ) {
/* Clear pending bus-off condition */
if ( in_8 ( & regs - > canmisc ) & MSCAN_BOHOLD )
out_8 ( & regs - > canmisc , MSCAN_BOHOLD ) ;
}
2009-11-13 06:14:52 +00:00
err = mscan_set_mode ( dev , MSCAN_NORMAL_MODE ) ;
if ( err )
return err ;
canrflg = in_8 ( & regs - > canrflg ) ;
priv - > shadow_statflg = canrflg & MSCAN_STAT_MSK ;
priv - > can . state = state_map [ max ( MSCAN_STATE_RX ( canrflg ) ,
MSCAN_STATE_TX ( canrflg ) ) ] ;
out_8 ( & regs - > cantier , 0 ) ;
/* Enable receive interrupts. */
2010-01-07 09:43:07 +00:00
out_8 ( & regs - > canrier , MSCAN_RX_INTS_ENABLE ) ;
return 0 ;
}
static int mscan_restart ( struct net_device * dev )
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
if ( priv - > type = = MSCAN_TYPE_MPC5121 ) {
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2010-01-07 09:43:07 +00:00
priv - > can . state = CAN_STATE_ERROR_ACTIVE ;
WARN ( ! ( in_8 ( & regs - > canmisc ) & MSCAN_BOHOLD ) ,
2010-10-30 11:08:33 +00:00
" bus-off state expected \n " ) ;
2010-01-07 09:43:07 +00:00
out_8 ( & regs - > canmisc , MSCAN_BOHOLD ) ;
/* Re-enable receive interrupts. */
out_8 ( & regs - > canrier , MSCAN_RX_INTS_ENABLE ) ;
} else {
if ( priv - > can . state < = CAN_STATE_BUS_OFF )
mscan_set_mode ( dev , MSCAN_INIT_MODE ) ;
return mscan_start ( dev ) ;
}
2009-11-13 06:14:52 +00:00
return 0 ;
}
static netdev_tx_t mscan_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
struct can_frame * frame = ( struct can_frame * ) skb - > data ;
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
int i , rtr , buf_id ;
u32 can_id ;
2010-01-12 02:00:46 -08:00
if ( can_dropped_invalid_skb ( dev , skb ) )
2010-01-07 09:43:06 +00:00
return NETDEV_TX_OK ;
2009-11-13 06:14:52 +00:00
out_8 ( & regs - > cantier , 0 ) ;
i = ~ priv - > tx_active & MSCAN_TXE ;
buf_id = ffs ( i ) - 1 ;
switch ( hweight8 ( i ) ) {
case 0 :
netif_stop_queue ( dev ) ;
2012-02-01 11:02:05 +01:00
netdev_err ( dev , " Tx Ring full when queue awake! \n " ) ;
2009-11-13 06:14:52 +00:00
return NETDEV_TX_BUSY ;
case 1 :
/*
* if buf_id < 3 , then current frame will be send out of order ,
* since buffer with lower id have higher priority ( hell . . )
*/
netif_stop_queue ( dev ) ;
2020-09-16 00:35:06 +02:00
fallthrough ;
2009-11-13 06:14:52 +00:00
case 2 :
if ( buf_id < priv - > prev_buf_id ) {
priv - > cur_pri + + ;
if ( priv - > cur_pri = = 0xff ) {
set_bit ( F_TX_WAIT_ALL , & priv - > flags ) ;
netif_stop_queue ( dev ) ;
}
}
set_bit ( F_TX_PROGRESS , & priv - > flags ) ;
break ;
}
priv - > prev_buf_id = buf_id ;
out_8 ( & regs - > cantbsel , i ) ;
rtr = frame - > can_id & CAN_RTR_FLAG ;
2009-11-16 12:57:52 +00:00
/* RTR is always the lowest bit of interest, then IDs follow */
2009-11-13 06:14:52 +00:00
if ( frame - > can_id & CAN_EFF_FLAG ) {
2009-11-16 12:57:52 +00:00
can_id = ( frame - > can_id & CAN_EFF_MASK )
< < ( MSCAN_EFF_RTR_SHIFT + 1 ) ;
2009-11-13 06:14:52 +00:00
if ( rtr )
2009-11-16 12:57:52 +00:00
can_id | = 1 < < MSCAN_EFF_RTR_SHIFT ;
2009-11-13 06:14:52 +00:00
out_be16 ( & regs - > tx . idr3_2 , can_id ) ;
can_id > > = 16 ;
2011-03-30 22:57:33 -03:00
/* EFF_FLAGS are between the IDs :( */
2009-11-16 12:57:52 +00:00
can_id = ( can_id & 0x7 ) | ( ( can_id < < 2 ) & 0xffe0 )
| MSCAN_EFF_FLAGS ;
2009-11-13 06:14:52 +00:00
} else {
2009-11-16 12:57:52 +00:00
can_id = ( frame - > can_id & CAN_SFF_MASK )
< < ( MSCAN_SFF_RTR_SHIFT + 1 ) ;
2009-11-13 06:14:52 +00:00
if ( rtr )
2009-11-16 12:57:52 +00:00
can_id | = 1 < < MSCAN_SFF_RTR_SHIFT ;
2009-11-13 06:14:52 +00:00
}
out_be16 ( & regs - > tx . idr1_0 , can_id ) ;
if ( ! rtr ) {
void __iomem * data = & regs - > tx . dsr1_0 ;
2009-11-16 12:57:45 +00:00
u16 * payload = ( u16 * ) frame - > data ;
2020-11-20 11:04:44 +01:00
for ( i = 0 ; i < frame - > len / 2 ; i + + ) {
2009-11-13 06:14:52 +00:00
out_be16 ( data , * payload + + ) ;
data + = 2 + _MSCAN_RESERVED_DSR_SIZE ;
}
2011-10-07 09:28:14 +00:00
/* write remaining byte if necessary */
2020-11-20 11:04:44 +01:00
if ( frame - > len & 1 )
out_8 ( data , frame - > data [ frame - > len - 1 ] ) ;
2009-11-13 06:14:52 +00:00
}
2020-11-20 11:04:44 +01:00
out_8 ( & regs - > tx . dlr , frame - > len ) ;
2009-11-13 06:14:52 +00:00
out_8 ( & regs - > tx . tbpr , priv - > cur_pri ) ;
/* Start transmission. */
out_8 ( & regs - > cantflg , 1 < < buf_id ) ;
if ( ! test_bit ( F_TX_PROGRESS , & priv - > flags ) )
2016-05-03 16:33:13 +02:00
netif_trans_update ( dev ) ;
2009-11-13 06:14:52 +00:00
list_add_tail ( & priv - > tx_queue [ buf_id ] . list , & priv - > tx_head ) ;
2021-01-11 15:19:27 +01:00
can_put_echo_skb ( skb , dev , buf_id , 0 ) ;
2009-11-13 06:14:52 +00:00
/* Enable interrupt. */
priv - > tx_active | = 1 < < buf_id ;
out_8 ( & regs - > cantier , priv - > tx_active ) ;
return NETDEV_TX_OK ;
}
2014-12-03 17:54:14 +00:00
static enum can_state get_new_state ( struct net_device * dev , u8 canrflg )
2009-11-13 06:14:52 +00:00
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
2014-12-03 17:54:14 +00:00
if ( unlikely ( canrflg & MSCAN_CSCIF ) )
return state_map [ max ( MSCAN_STATE_RX ( canrflg ) ,
MSCAN_STATE_TX ( canrflg ) ) ] ;
return priv - > can . state ;
2009-11-13 06:14:52 +00:00
}
static void mscan_get_rx_frame ( struct net_device * dev , struct can_frame * frame )
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
u32 can_id ;
int i ;
can_id = in_be16 ( & regs - > rx . idr1_0 ) ;
if ( can_id & ( 1 < < 3 ) ) {
frame - > can_id = CAN_EFF_FLAG ;
can_id = ( ( can_id < < 16 ) | in_be16 ( & regs - > rx . idr3_2 ) ) ;
can_id = ( ( can_id & 0xffe00000 ) |
( ( can_id & 0x7ffff ) < < 2 ) ) > > 2 ;
} else {
can_id > > = 4 ;
frame - > can_id = 0 ;
}
frame - > can_id | = can_id > > 1 ;
if ( can_id & 1 )
frame - > can_id | = CAN_RTR_FLAG ;
2009-12-12 04:13:21 +00:00
2020-11-20 11:04:44 +01:00
frame - > len = can_cc_dlc2len ( in_8 ( & regs - > rx . dlr ) & 0xf ) ;
2009-11-13 06:14:52 +00:00
if ( ! ( frame - > can_id & CAN_RTR_FLAG ) ) {
void __iomem * data = & regs - > rx . dsr1_0 ;
2009-11-16 12:57:45 +00:00
u16 * payload = ( u16 * ) frame - > data ;
2020-11-20 11:04:44 +01:00
for ( i = 0 ; i < frame - > len / 2 ; i + + ) {
2009-11-13 06:14:52 +00:00
* payload + + = in_be16 ( data ) ;
data + = 2 + _MSCAN_RESERVED_DSR_SIZE ;
}
2011-10-07 09:28:14 +00:00
/* read remaining byte if necessary */
2020-11-20 11:04:44 +01:00
if ( frame - > len & 1 )
frame - > data [ frame - > len - 1 ] = in_8 ( data ) ;
2009-11-13 06:14:52 +00:00
}
out_8 ( & regs - > canrflg , MSCAN_RXF ) ;
}
static void mscan_get_err_frame ( struct net_device * dev , struct can_frame * frame ,
u8 canrflg )
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
struct net_device_stats * stats = & dev - > stats ;
2014-12-03 17:54:14 +00:00
enum can_state new_state ;
2009-11-13 06:14:52 +00:00
2012-02-01 11:02:05 +01:00
netdev_dbg ( dev , " error interrupt (canrflg=%#x) \n " , canrflg ) ;
2009-11-13 06:14:52 +00:00
frame - > can_id = CAN_ERR_FLAG ;
if ( canrflg & MSCAN_OVRIF ) {
frame - > can_id | = CAN_ERR_CRTL ;
frame - > data [ 1 ] = CAN_ERR_CRTL_RX_OVERFLOW ;
stats - > rx_over_errors + + ;
stats - > rx_errors + + ;
2009-11-16 12:57:45 +00:00
} else {
2009-11-13 06:14:52 +00:00
frame - > data [ 1 ] = 0 ;
2009-11-16 12:57:45 +00:00
}
2009-11-13 06:14:52 +00:00
2014-12-03 17:54:14 +00:00
new_state = get_new_state ( dev , canrflg ) ;
if ( new_state ! = priv - > can . state ) {
can_change_state ( dev , frame ,
state_map [ MSCAN_STATE_TX ( canrflg ) ] ,
state_map [ MSCAN_STATE_RX ( canrflg ) ] ) ;
if ( priv - > can . state = = CAN_STATE_BUS_OFF ) {
2009-11-13 06:14:52 +00:00
/*
* The MSCAN on the MPC5200 does recover from bus - off
* automatically . To avoid that we stop the chip doing
* a light - weight stop ( we are in irq - context ) .
*/
2010-01-07 09:43:07 +00:00
if ( priv - > type ! = MSCAN_TYPE_MPC5121 ) {
out_8 ( & regs - > cantier , 0 ) ;
out_8 ( & regs - > canrier , 0 ) ;
setbits8 ( & regs - > canctl0 ,
MSCAN_SLPRQ | MSCAN_INITRQ ) ;
}
2009-11-13 06:14:52 +00:00
can_bus_off ( dev ) ;
}
}
priv - > shadow_statflg = canrflg & MSCAN_STAT_MSK ;
2020-11-20 11:04:44 +01:00
frame - > len = CAN_ERR_DLC ;
2009-11-13 06:14:52 +00:00
out_8 ( & regs - > canrflg , MSCAN_ERR_IF ) ;
}
static int mscan_rx_poll ( struct napi_struct * napi , int quota )
{
struct mscan_priv * priv = container_of ( napi , struct mscan_priv , napi ) ;
struct net_device * dev = napi - > dev ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
struct net_device_stats * stats = & dev - > stats ;
2019-12-26 19:51:24 +01:00
int work_done = 0 ;
2009-11-13 06:14:52 +00:00
struct sk_buff * skb ;
struct can_frame * frame ;
u8 canrflg ;
2019-12-26 19:51:24 +01:00
while ( work_done < quota ) {
2009-11-16 12:57:49 +00:00
canrflg = in_8 ( & regs - > canrflg ) ;
if ( ! ( canrflg & ( MSCAN_RXF | MSCAN_ERR_IF ) ) )
break ;
2009-11-13 06:14:52 +00:00
skb = alloc_can_skb ( dev , & frame ) ;
if ( ! skb ) {
if ( printk_ratelimit ( ) )
2012-02-01 11:02:05 +01:00
netdev_notice ( dev , " packet dropped \n " ) ;
2009-11-13 06:14:52 +00:00
stats - > rx_dropped + + ;
out_8 ( & regs - > canrflg , canrflg ) ;
continue ;
}
if ( canrflg & MSCAN_RXF )
mscan_get_rx_frame ( dev , frame ) ;
2009-11-16 12:57:45 +00:00
else if ( canrflg & MSCAN_ERR_IF )
2009-11-13 06:14:52 +00:00
mscan_get_err_frame ( dev , frame , canrflg ) ;
stats - > rx_packets + + ;
2020-11-20 11:04:44 +01:00
stats - > rx_bytes + = frame - > len ;
2019-12-26 19:51:24 +01:00
work_done + + ;
2009-11-13 06:14:52 +00:00
netif_receive_skb ( skb ) ;
}
2019-12-26 19:51:24 +01:00
if ( work_done < quota ) {
if ( likely ( napi_complete_done ( & priv - > napi , work_done ) ) ) {
clear_bit ( F_RX_PROGRESS , & priv - > flags ) ;
if ( priv - > can . state < CAN_STATE_BUS_OFF )
out_8 ( & regs - > canrier , priv - > shadow_canrier ) ;
}
2009-11-13 06:14:52 +00:00
}
2019-12-26 19:51:24 +01:00
return work_done ;
2009-11-13 06:14:52 +00:00
}
static irqreturn_t mscan_isr ( int irq , void * dev_id )
{
struct net_device * dev = ( struct net_device * ) dev_id ;
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
struct net_device_stats * stats = & dev - > stats ;
u8 cantier , cantflg , canrflg ;
irqreturn_t ret = IRQ_NONE ;
cantier = in_8 ( & regs - > cantier ) & MSCAN_TXE ;
cantflg = in_8 ( & regs - > cantflg ) & cantier ;
if ( cantier & & cantflg ) {
struct list_head * tmp , * pos ;
list_for_each_safe ( pos , tmp , & priv - > tx_head ) {
struct tx_queue_entry * entry =
list_entry ( pos , struct tx_queue_entry , list ) ;
u8 mask = entry - > mask ;
if ( ! ( cantflg & mask ) )
continue ;
out_8 ( & regs - > cantbsel , mask ) ;
stats - > tx_bytes + = in_8 ( & regs - > tx . dlr ) ;
stats - > tx_packets + + ;
2021-01-11 15:19:28 +01:00
can_get_echo_skb ( dev , entry - > id , NULL ) ;
2009-11-13 06:14:52 +00:00
priv - > tx_active & = ~ mask ;
list_del ( pos ) ;
}
if ( list_empty ( & priv - > tx_head ) ) {
clear_bit ( F_TX_WAIT_ALL , & priv - > flags ) ;
clear_bit ( F_TX_PROGRESS , & priv - > flags ) ;
priv - > cur_pri = 0 ;
2009-11-16 12:57:45 +00:00
} else {
2016-05-03 16:33:13 +02:00
netif_trans_update ( dev ) ;
2009-11-16 12:57:45 +00:00
}
2009-11-13 06:14:52 +00:00
if ( ! test_bit ( F_TX_WAIT_ALL , & priv - > flags ) )
netif_wake_queue ( dev ) ;
out_8 ( & regs - > cantier , priv - > tx_active ) ;
ret = IRQ_HANDLED ;
}
canrflg = in_8 ( & regs - > canrflg ) ;
if ( ( canrflg & ~ MSCAN_STAT_MSK ) & &
! test_and_set_bit ( F_RX_PROGRESS , & priv - > flags ) ) {
if ( canrflg & ~ MSCAN_STAT_MSK ) {
priv - > shadow_canrier = in_8 ( & regs - > canrier ) ;
out_8 ( & regs - > canrier , 0 ) ;
napi_schedule ( & priv - > napi ) ;
ret = IRQ_HANDLED ;
2009-11-16 12:57:45 +00:00
} else {
2009-11-13 06:14:52 +00:00
clear_bit ( F_RX_PROGRESS , & priv - > flags ) ;
2009-11-16 12:57:45 +00:00
}
2009-11-13 06:14:52 +00:00
}
return ret ;
}
static int mscan_do_set_mode ( struct net_device * dev , enum can_mode mode )
{
int ret = 0 ;
switch ( mode ) {
case CAN_MODE_START :
2010-01-07 09:43:07 +00:00
ret = mscan_restart ( dev ) ;
2009-11-13 06:14:52 +00:00
if ( ret )
break ;
if ( netif_queue_stopped ( dev ) )
netif_wake_queue ( dev ) ;
break ;
default :
ret = - EOPNOTSUPP ;
break ;
}
return ret ;
}
static int mscan_do_set_bittiming ( struct net_device * dev )
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
struct can_bittiming * bt = & priv - > can . bittiming ;
u8 btr0 , btr1 ;
btr0 = BTR0_SET_BRP ( bt - > brp ) | BTR0_SET_SJW ( bt - > sjw ) ;
btr1 = ( BTR1_SET_TSEG1 ( bt - > prop_seg + bt - > phase_seg1 ) |
BTR1_SET_TSEG2 ( bt - > phase_seg2 ) |
BTR1_SET_SAM ( priv - > can . ctrlmode & CAN_CTRLMODE_3_SAMPLES ) ) ;
2012-02-01 11:02:05 +01:00
netdev_info ( dev , " setting BTR0=0x%02x BTR1=0x%02x \n " , btr0 , btr1 ) ;
2009-11-13 06:14:52 +00:00
out_8 ( & regs - > canbtr0 , btr0 ) ;
out_8 ( & regs - > canbtr1 , btr1 ) ;
return 0 ;
}
2012-02-01 11:14:13 +01:00
static int mscan_get_berr_counter ( const struct net_device * dev ,
struct can_berr_counter * bec )
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
struct mscan_regs __iomem * regs = priv - > reg_base ;
bec - > txerr = in_8 ( & regs - > cantxerr ) ;
bec - > rxerr = in_8 ( & regs - > canrxerr ) ;
return 0 ;
}
2009-11-13 06:14:52 +00:00
static int mscan_open ( struct net_device * dev )
{
int ret ;
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
2020-07-17 16:01:15 +08:00
ret = clk_prepare_enable ( priv - > clk_ipg ) ;
if ( ret )
goto exit_retcode ;
ret = clk_prepare_enable ( priv - > clk_can ) ;
if ( ret )
goto exit_dis_ipg_clock ;
2013-08-23 13:09:03 +02:00
2009-11-13 06:14:52 +00:00
/* common open */
ret = open_candev ( dev ) ;
if ( ret )
2013-08-23 13:09:03 +02:00
goto exit_dis_can_clock ;
2009-11-13 06:14:52 +00:00
napi_enable ( & priv - > napi ) ;
ret = request_irq ( dev - > irq , mscan_isr , 0 , dev - > name , dev ) ;
if ( ret < 0 ) {
2012-02-01 11:02:05 +01:00
netdev_err ( dev , " failed to attach interrupt \n " ) ;
2009-11-16 12:57:53 +00:00
goto exit_napi_disable ;
2009-11-13 06:14:52 +00:00
}
2011-11-14 14:30:05 -05:00
if ( priv - > can . ctrlmode & CAN_CTRLMODE_LISTENONLY )
2011-11-09 10:50:49 +00:00
setbits8 ( & regs - > canctl1 , MSCAN_LISTEN ) ;
else
clrbits8 ( & regs - > canctl1 , MSCAN_LISTEN ) ;
2009-11-13 06:14:52 +00:00
ret = mscan_start ( dev ) ;
if ( ret )
2009-11-16 12:57:53 +00:00
goto exit_free_irq ;
2009-11-13 06:14:52 +00:00
netif_start_queue ( dev ) ;
return 0 ;
2009-11-16 12:57:53 +00:00
exit_free_irq :
free_irq ( dev - > irq , dev ) ;
exit_napi_disable :
napi_disable ( & priv - > napi ) ;
close_candev ( dev ) ;
2013-08-23 13:09:03 +02:00
exit_dis_can_clock :
2020-07-17 16:01:15 +08:00
clk_disable_unprepare ( priv - > clk_can ) ;
2013-08-23 13:09:03 +02:00
exit_dis_ipg_clock :
2020-07-17 16:01:15 +08:00
clk_disable_unprepare ( priv - > clk_ipg ) ;
2013-08-23 13:09:03 +02:00
exit_retcode :
2009-11-16 12:57:53 +00:00
return ret ;
2009-11-13 06:14:52 +00:00
}
static int mscan_close ( struct net_device * dev )
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
netif_stop_queue ( dev ) ;
napi_disable ( & priv - > napi ) ;
out_8 ( & regs - > cantier , 0 ) ;
out_8 ( & regs - > canrier , 0 ) ;
mscan_set_mode ( dev , MSCAN_INIT_MODE ) ;
close_candev ( dev ) ;
free_irq ( dev - > irq , dev ) ;
2020-07-17 16:01:15 +08:00
clk_disable_unprepare ( priv - > clk_can ) ;
clk_disable_unprepare ( priv - > clk_ipg ) ;
2013-08-23 13:09:03 +02:00
2009-11-13 06:14:52 +00:00
return 0 ;
}
static const struct net_device_ops mscan_netdev_ops = {
2014-03-07 09:23:41 +01:00
. ndo_open = mscan_open ,
. ndo_stop = mscan_close ,
. ndo_start_xmit = mscan_start_xmit ,
. ndo_change_mtu = can_change_mtu ,
2009-11-13 06:14:52 +00:00
} ;
2010-01-07 09:43:07 +00:00
int register_mscandev ( struct net_device * dev , int mscan_clksrc )
2009-11-13 06:14:52 +00:00
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
u8 ctl1 ;
ctl1 = in_8 ( & regs - > canctl1 ) ;
2010-01-07 09:43:07 +00:00
if ( mscan_clksrc )
2009-11-13 06:14:52 +00:00
ctl1 | = MSCAN_CLKSRC ;
else
ctl1 & = ~ MSCAN_CLKSRC ;
2012-02-01 11:14:13 +01:00
if ( priv - > type = = MSCAN_TYPE_MPC5121 ) {
priv - > can . do_get_berr_counter = mscan_get_berr_counter ;
2010-01-07 09:43:07 +00:00
ctl1 | = MSCAN_BORM ; /* bus-off recovery upon request */
2012-02-01 11:14:13 +01:00
}
2010-01-07 09:43:07 +00:00
2009-11-13 06:14:52 +00:00
ctl1 | = MSCAN_CANE ;
out_8 ( & regs - > canctl1 , ctl1 ) ;
udelay ( 100 ) ;
/* acceptance mask/acceptance code (accept everything) */
out_be16 ( & regs - > canidar1_0 , 0 ) ;
out_be16 ( & regs - > canidar3_2 , 0 ) ;
out_be16 ( & regs - > canidar5_4 , 0 ) ;
out_be16 ( & regs - > canidar7_6 , 0 ) ;
out_be16 ( & regs - > canidmr1_0 , 0xffff ) ;
out_be16 ( & regs - > canidmr3_2 , 0xffff ) ;
out_be16 ( & regs - > canidmr5_4 , 0xffff ) ;
out_be16 ( & regs - > canidmr7_6 , 0xffff ) ;
/* Two 32 bit Acceptance Filters */
out_8 ( & regs - > canidac , MSCAN_AF_32BIT ) ;
mscan_set_mode ( dev , MSCAN_INIT_MODE ) ;
return register_candev ( dev ) ;
}
void unregister_mscandev ( struct net_device * dev )
{
struct mscan_priv * priv = netdev_priv ( dev ) ;
2011-08-15 12:45:08 +02:00
struct mscan_regs __iomem * regs = priv - > reg_base ;
2009-11-13 06:14:52 +00:00
mscan_set_mode ( dev , MSCAN_INIT_MODE ) ;
2009-11-16 12:57:47 +00:00
clrbits8 ( & regs - > canctl1 , MSCAN_CANE ) ;
2009-11-13 06:14:52 +00:00
unregister_candev ( dev ) ;
}
struct net_device * alloc_mscandev ( void )
{
struct net_device * dev ;
struct mscan_priv * priv ;
int i ;
dev = alloc_candev ( sizeof ( struct mscan_priv ) , MSCAN_ECHO_SKB_MAX ) ;
if ( ! dev )
return NULL ;
priv = netdev_priv ( dev ) ;
dev - > netdev_ops = & mscan_netdev_ops ;
dev - > flags | = IFF_ECHO ; /* we support local echo */
netif_napi_add ( dev , & priv - > napi , mscan_rx_poll , 8 ) ;
priv - > can . bittiming_const = & mscan_bittiming_const ;
priv - > can . do_set_bittiming = mscan_do_set_bittiming ;
priv - > can . do_set_mode = mscan_do_set_mode ;
2011-11-09 10:50:49 +00:00
priv - > can . ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_LISTENONLY ;
2009-11-13 06:14:52 +00:00
for ( i = 0 ; i < TX_QUEUE_SIZE ; i + + ) {
priv - > tx_queue [ i ] . id = i ;
priv - > tx_queue [ i ] . mask = 1 < < i ;
}
return dev ;
}
MODULE_AUTHOR ( " Andrey Volkov <avolkov@varma-el.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " CAN port driver for a MSCAN based chips " ) ;