2009-07-29 12:20:10 +04:00
/*
* flexcan . c - FLEXCAN CAN controller driver
*
* Copyright ( c ) 2005 - 2006 Varma Electronics Oy
* Copyright ( c ) 2009 Sascha Hauer , Pengutronix
* Copyright ( c ) 2010 Marc Kleine - Budde , Pengutronix
*
* Based on code originally by Andrey Volkov < avolkov @ varma - el . com >
*
* LICENCE :
* 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 version 2.
*
* 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/netdevice.h>
# include <linux/can.h>
# include <linux/can/dev.h>
# include <linux/can/error.h>
2012-12-18 21:50:58 +04:00
# include <linux/can/led.h>
2009-07-29 12:20:10 +04:00
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/if_arp.h>
# include <linux/if_ether.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/module.h>
2011-08-16 21:32:23 +04:00
# include <linux/of.h>
2012-06-28 12:21:35 +04:00
# include <linux/of_device.h>
2009-07-29 12:20:10 +04:00
# include <linux/platform_device.h>
2013-06-11 06:12:57 +04:00
# include <linux/regulator/consumer.h>
2009-07-29 12:20:10 +04:00
# define DRV_NAME "flexcan"
/* 8 for RX fifo and 2 error handling */
# define FLEXCAN_NAPI_WEIGHT (8 + 2)
/* FLEXCAN module configuration register (CANMCR) bits */
# define FLEXCAN_MCR_MDIS BIT(31)
# define FLEXCAN_MCR_FRZ BIT(30)
# define FLEXCAN_MCR_FEN BIT(29)
# define FLEXCAN_MCR_HALT BIT(28)
# define FLEXCAN_MCR_NOT_RDY BIT(27)
# define FLEXCAN_MCR_WAK_MSK BIT(26)
# define FLEXCAN_MCR_SOFTRST BIT(25)
# define FLEXCAN_MCR_FRZ_ACK BIT(24)
# define FLEXCAN_MCR_SUPV BIT(23)
# define FLEXCAN_MCR_SLF_WAK BIT(22)
# define FLEXCAN_MCR_WRN_EN BIT(21)
# define FLEXCAN_MCR_LPM_ACK BIT(20)
# define FLEXCAN_MCR_WAK_SRC BIT(19)
# define FLEXCAN_MCR_DOZE BIT(18)
# define FLEXCAN_MCR_SRX_DIS BIT(17)
# define FLEXCAN_MCR_BCC BIT(16)
# define FLEXCAN_MCR_LPRIO_EN BIT(13)
# define FLEXCAN_MCR_AEN BIT(12)
2013-10-04 12:52:36 +04:00
# define FLEXCAN_MCR_MAXMB(x) ((x) & 0x1f)
2009-07-29 12:20:10 +04:00
# define FLEXCAN_MCR_IDAM_A (0 << 8)
# define FLEXCAN_MCR_IDAM_B (1 << 8)
# define FLEXCAN_MCR_IDAM_C (2 << 8)
# define FLEXCAN_MCR_IDAM_D (3 << 8)
/* FLEXCAN control register (CANCTRL) bits */
# define FLEXCAN_CTRL_PRESDIV(x) (((x) & 0xff) << 24)
# define FLEXCAN_CTRL_RJW(x) (((x) & 0x03) << 22)
# define FLEXCAN_CTRL_PSEG1(x) (((x) & 0x07) << 19)
# define FLEXCAN_CTRL_PSEG2(x) (((x) & 0x07) << 16)
# define FLEXCAN_CTRL_BOFF_MSK BIT(15)
# define FLEXCAN_CTRL_ERR_MSK BIT(14)
# define FLEXCAN_CTRL_CLK_SRC BIT(13)
# define FLEXCAN_CTRL_LPB BIT(12)
# define FLEXCAN_CTRL_TWRN_MSK BIT(11)
# define FLEXCAN_CTRL_RWRN_MSK BIT(10)
# define FLEXCAN_CTRL_SMP BIT(7)
# define FLEXCAN_CTRL_BOFF_REC BIT(6)
# define FLEXCAN_CTRL_TSYN BIT(5)
# define FLEXCAN_CTRL_LBUF BIT(4)
# define FLEXCAN_CTRL_LOM BIT(3)
# define FLEXCAN_CTRL_PROPSEG(x) ((x) & 0x07)
# define FLEXCAN_CTRL_ERR_BUS (FLEXCAN_CTRL_ERR_MSK)
# define FLEXCAN_CTRL_ERR_STATE \
( FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \
FLEXCAN_CTRL_BOFF_MSK )
# define FLEXCAN_CTRL_ERR_ALL \
( FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE )
/* FLEXCAN error and status register (ESR) bits */
# define FLEXCAN_ESR_TWRN_INT BIT(17)
# define FLEXCAN_ESR_RWRN_INT BIT(16)
# define FLEXCAN_ESR_BIT1_ERR BIT(15)
# define FLEXCAN_ESR_BIT0_ERR BIT(14)
# define FLEXCAN_ESR_ACK_ERR BIT(13)
# define FLEXCAN_ESR_CRC_ERR BIT(12)
# define FLEXCAN_ESR_FRM_ERR BIT(11)
# define FLEXCAN_ESR_STF_ERR BIT(10)
# define FLEXCAN_ESR_TX_WRN BIT(9)
# define FLEXCAN_ESR_RX_WRN BIT(8)
# define FLEXCAN_ESR_IDLE BIT(7)
# define FLEXCAN_ESR_TXRX BIT(6)
# define FLEXCAN_EST_FLT_CONF_SHIFT (4)
# define FLEXCAN_ESR_FLT_CONF_MASK (0x3 << FLEXCAN_EST_FLT_CONF_SHIFT)
# define FLEXCAN_ESR_FLT_CONF_ACTIVE (0x0 << FLEXCAN_EST_FLT_CONF_SHIFT)
# define FLEXCAN_ESR_FLT_CONF_PASSIVE (0x1 << FLEXCAN_EST_FLT_CONF_SHIFT)
# define FLEXCAN_ESR_BOFF_INT BIT(2)
# define FLEXCAN_ESR_ERR_INT BIT(1)
# define FLEXCAN_ESR_WAK_INT BIT(0)
# define FLEXCAN_ESR_ERR_BUS \
( FLEXCAN_ESR_BIT1_ERR | FLEXCAN_ESR_BIT0_ERR | \
FLEXCAN_ESR_ACK_ERR | FLEXCAN_ESR_CRC_ERR | \
FLEXCAN_ESR_FRM_ERR | FLEXCAN_ESR_STF_ERR )
# define FLEXCAN_ESR_ERR_STATE \
( FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | FLEXCAN_ESR_BOFF_INT )
# define FLEXCAN_ESR_ERR_ALL \
( FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE )
2011-12-12 19:09:28 +04:00
# define FLEXCAN_ESR_ALL_INT \
( FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \
FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT )
2009-07-29 12:20:10 +04:00
/* FLEXCAN interrupt flag register (IFLAG) bits */
# define FLEXCAN_TX_BUF_ID 8
# define FLEXCAN_IFLAG_BUF(x) BIT(x)
# define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
# define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
# define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
# define FLEXCAN_IFLAG_DEFAULT \
( FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
FLEXCAN_IFLAG_BUF ( FLEXCAN_TX_BUF_ID ) )
/* FLEXCAN message buffers */
# define FLEXCAN_MB_CNT_CODE(x) (((x) & 0xf) << 24)
# define FLEXCAN_MB_CNT_SRR BIT(22)
# define FLEXCAN_MB_CNT_IDE BIT(21)
# define FLEXCAN_MB_CNT_RTR BIT(20)
# define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xf) << 16)
# define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xffff)
# define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
2014-02-28 18:30:18 +04:00
# define FLEXCAN_TIMEOUT_US (50)
2012-10-10 23:10:42 +04:00
/*
* FLEXCAN hardware feature flags
*
* Below is some version info we got :
* SOC Version IP - Version Glitch - [ TR ] WRN_INT
* Filter ? connected ?
* MX25 FlexCAN2 03.00 .00 .00 no no
* MX28 FlexCAN2 03.00 .04 .00 yes yes
* MX35 FlexCAN2 03.00 .00 .00 no no
* MX53 FlexCAN2 03.00 .00 .00 yes no
* MX6s FlexCAN3 10.00 .12 .00 yes yes
*
* Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected .
*/
2012-09-28 07:17:15 +04:00
# define FLEXCAN_HAS_V10_FEATURES BIT(1) /* For core version >= 10 */
2012-10-10 23:10:42 +04:00
# define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* [TR]WRN_INT not connected */
2012-09-28 07:17:15 +04:00
2009-07-29 12:20:10 +04:00
/* Structure of the message buffer */
struct flexcan_mb {
u32 can_ctrl ;
u32 can_id ;
u32 data [ 2 ] ;
} ;
/* Structure of the hardware registers */
struct flexcan_regs {
u32 mcr ; /* 0x00 */
u32 ctrl ; /* 0x04 */
u32 timer ; /* 0x08 */
u32 _reserved1 ; /* 0x0c */
u32 rxgmask ; /* 0x10 */
u32 rx14mask ; /* 0x14 */
u32 rx15mask ; /* 0x18 */
u32 ecr ; /* 0x1c */
u32 esr ; /* 0x20 */
u32 imask2 ; /* 0x24 */
u32 imask1 ; /* 0x28 */
u32 iflag2 ; /* 0x2c */
u32 iflag1 ; /* 0x30 */
2012-06-28 12:21:35 +04:00
u32 crl2 ; /* 0x34 */
u32 esr2 ; /* 0x38 */
u32 imeur ; /* 0x3c */
u32 lrfr ; /* 0x40 */
u32 crcr ; /* 0x44 */
u32 rxfgmask ; /* 0x48 */
u32 rxfir ; /* 0x4c */
u32 _reserved3 [ 12 ] ;
2009-07-29 12:20:10 +04:00
struct flexcan_mb cantxfg [ 64 ] ;
} ;
2012-06-28 12:21:35 +04:00
struct flexcan_devtype_data {
2012-09-28 07:17:15 +04:00
u32 features ; /* hardware controller features */
2012-06-28 12:21:35 +04:00
} ;
2009-07-29 12:20:10 +04:00
struct flexcan_priv {
struct can_priv can ;
struct net_device * dev ;
struct napi_struct napi ;
void __iomem * base ;
u32 reg_esr ;
u32 reg_ctrl_default ;
2012-07-17 18:14:34 +04:00
struct clk * clk_ipg ;
struct clk * clk_per ;
2009-07-29 12:20:10 +04:00
struct flexcan_platform_data * pdata ;
2012-07-13 16:52:48 +04:00
const struct flexcan_devtype_data * devtype_data ;
2013-06-11 06:12:57 +04:00
struct regulator * reg_xceiver ;
2012-06-28 12:21:35 +04:00
} ;
static struct flexcan_devtype_data fsl_p1010_devtype_data = {
2012-09-28 07:17:15 +04:00
. features = FLEXCAN_HAS_BROKEN_ERR_STATE ,
2012-06-28 12:21:35 +04:00
} ;
2012-09-28 07:17:15 +04:00
static struct flexcan_devtype_data fsl_imx28_devtype_data ;
2012-06-28 12:21:35 +04:00
static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
2012-10-10 23:10:42 +04:00
. features = FLEXCAN_HAS_V10_FEATURES ,
2009-07-29 12:20:10 +04:00
} ;
2012-07-16 14:58:31 +04:00
static const struct can_bittiming_const flexcan_bittiming_const = {
2009-07-29 12:20:10 +04:00
. name = DRV_NAME ,
. tseg1_min = 4 ,
. tseg1_max = 16 ,
. tseg2_min = 2 ,
. tseg2_max = 8 ,
. sjw_max = 4 ,
. brp_min = 1 ,
. brp_max = 256 ,
. brp_inc = 1 ,
} ;
2011-08-16 21:32:20 +04:00
/*
2014-01-14 14:44:09 +04:00
* Abstract off the read / write for arm versus ppc . This
* assumes that PPC uses big - endian registers and everything
* else uses little - endian registers , independent of CPU
* endianess .
2011-08-16 21:32:20 +04:00
*/
2014-01-14 14:44:09 +04:00
# if defined(CONFIG_PPC)
2011-08-16 21:32:20 +04:00
static inline u32 flexcan_read ( void __iomem * addr )
{
return in_be32 ( addr ) ;
}
static inline void flexcan_write ( u32 val , void __iomem * addr )
{
out_be32 ( addr , val ) ;
}
# else
static inline u32 flexcan_read ( void __iomem * addr )
{
return readl ( addr ) ;
}
static inline void flexcan_write ( u32 val , void __iomem * addr )
{
writel ( val , addr ) ;
}
# endif
2014-02-28 20:18:27 +04:00
static inline int flexcan_transceiver_enable ( const struct flexcan_priv * priv )
{
if ( ! priv - > reg_xceiver )
return 0 ;
return regulator_enable ( priv - > reg_xceiver ) ;
}
static inline int flexcan_transceiver_disable ( const struct flexcan_priv * priv )
{
if ( ! priv - > reg_xceiver )
return 0 ;
return regulator_disable ( priv - > reg_xceiver ) ;
}
2009-07-29 12:20:10 +04:00
static inline int flexcan_has_and_handle_berr ( const struct flexcan_priv * priv ,
u32 reg_esr )
{
return ( priv - > can . ctrlmode & CAN_CTRLMODE_BERR_REPORTING ) & &
( reg_esr & FLEXCAN_ESR_ERR_BUS ) ;
}
2014-02-28 18:30:18 +04:00
static int flexcan_chip_enable ( struct flexcan_priv * priv )
2009-07-29 12:20:10 +04:00
{
struct flexcan_regs __iomem * regs = priv - > base ;
2014-02-28 18:30:18 +04:00
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10 ;
2009-07-29 12:20:10 +04:00
u32 reg ;
2011-08-16 21:32:20 +04:00
reg = flexcan_read ( & regs - > mcr ) ;
2009-07-29 12:20:10 +04:00
reg & = ~ FLEXCAN_MCR_MDIS ;
2011-08-16 21:32:20 +04:00
flexcan_write ( reg , & regs - > mcr ) ;
2009-07-29 12:20:10 +04:00
2014-02-28 18:30:18 +04:00
while ( timeout - - & & ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_LPM_ACK ) )
usleep_range ( 10 , 20 ) ;
if ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_LPM_ACK )
return - ETIMEDOUT ;
return 0 ;
2009-07-29 12:20:10 +04:00
}
2014-02-28 18:30:18 +04:00
static int flexcan_chip_disable ( struct flexcan_priv * priv )
2009-07-29 12:20:10 +04:00
{
struct flexcan_regs __iomem * regs = priv - > base ;
2014-02-28 18:30:18 +04:00
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10 ;
2009-07-29 12:20:10 +04:00
u32 reg ;
2011-08-16 21:32:20 +04:00
reg = flexcan_read ( & regs - > mcr ) ;
2009-07-29 12:20:10 +04:00
reg | = FLEXCAN_MCR_MDIS ;
2011-08-16 21:32:20 +04:00
flexcan_write ( reg , & regs - > mcr ) ;
2014-02-28 18:30:18 +04:00
while ( timeout - - & & ! ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_LPM_ACK ) )
usleep_range ( 10 , 20 ) ;
if ( ! ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_LPM_ACK ) )
return - ETIMEDOUT ;
return 0 ;
2009-07-29 12:20:10 +04:00
}
2014-02-28 20:08:21 +04:00
static int flexcan_chip_freeze ( struct flexcan_priv * priv )
{
struct flexcan_regs __iomem * regs = priv - > base ;
unsigned int timeout = 1000 * 1000 * 10 / priv - > can . bittiming . bitrate ;
u32 reg ;
reg = flexcan_read ( & regs - > mcr ) ;
reg | = FLEXCAN_MCR_HALT ;
flexcan_write ( reg , & regs - > mcr ) ;
while ( timeout - - & & ! ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_FRZ_ACK ) )
usleep_range ( 100 , 200 ) ;
if ( ! ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_FRZ_ACK ) )
return - ETIMEDOUT ;
return 0 ;
}
static int flexcan_chip_unfreeze ( struct flexcan_priv * priv )
{
struct flexcan_regs __iomem * regs = priv - > base ;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10 ;
u32 reg ;
reg = flexcan_read ( & regs - > mcr ) ;
reg & = ~ FLEXCAN_MCR_HALT ;
flexcan_write ( reg , & regs - > mcr ) ;
while ( timeout - - & & ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_FRZ_ACK ) )
usleep_range ( 10 , 20 ) ;
if ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_FRZ_ACK )
return - ETIMEDOUT ;
return 0 ;
}
2014-02-28 18:16:59 +04:00
static int flexcan_chip_softreset ( struct flexcan_priv * priv )
{
struct flexcan_regs __iomem * regs = priv - > base ;
unsigned int timeout = FLEXCAN_TIMEOUT_US / 10 ;
flexcan_write ( FLEXCAN_MCR_SOFTRST , & regs - > mcr ) ;
while ( timeout - - & & ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_SOFTRST ) )
usleep_range ( 10 , 20 ) ;
if ( flexcan_read ( & regs - > mcr ) & FLEXCAN_MCR_SOFTRST )
return - ETIMEDOUT ;
return 0 ;
}
2009-07-29 12:20:10 +04:00
static int flexcan_get_berr_counter ( const struct net_device * dev ,
struct can_berr_counter * bec )
{
const struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct flexcan_regs __iomem * regs = priv - > base ;
2011-08-16 21:32:20 +04:00
u32 reg = flexcan_read ( & regs - > ecr ) ;
2009-07-29 12:20:10 +04:00
bec - > txerr = ( reg > > 0 ) & 0xff ;
bec - > rxerr = ( reg > > 8 ) & 0xff ;
return 0 ;
}
static int flexcan_start_xmit ( struct sk_buff * skb , struct net_device * dev )
{
const struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct flexcan_regs __iomem * regs = priv - > base ;
struct can_frame * cf = ( struct can_frame * ) skb - > data ;
u32 can_id ;
u32 ctrl = FLEXCAN_MB_CNT_CODE ( 0xc ) | ( cf - > can_dlc < < 16 ) ;
if ( can_dropped_invalid_skb ( dev , skb ) )
return NETDEV_TX_OK ;
netif_stop_queue ( dev ) ;
if ( cf - > can_id & CAN_EFF_FLAG ) {
can_id = cf - > can_id & CAN_EFF_MASK ;
ctrl | = FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR ;
} else {
can_id = ( cf - > can_id & CAN_SFF_MASK ) < < 18 ;
}
if ( cf - > can_id & CAN_RTR_FLAG )
ctrl | = FLEXCAN_MB_CNT_RTR ;
if ( cf - > can_dlc > 0 ) {
u32 data = be32_to_cpup ( ( __be32 * ) & cf - > data [ 0 ] ) ;
2011-08-16 21:32:20 +04:00
flexcan_write ( data , & regs - > cantxfg [ FLEXCAN_TX_BUF_ID ] . data [ 0 ] ) ;
2009-07-29 12:20:10 +04:00
}
if ( cf - > can_dlc > 3 ) {
u32 data = be32_to_cpup ( ( __be32 * ) & cf - > data [ 4 ] ) ;
2011-08-16 21:32:20 +04:00
flexcan_write ( data , & regs - > cantxfg [ FLEXCAN_TX_BUF_ID ] . data [ 1 ] ) ;
2009-07-29 12:20:10 +04:00
}
2011-11-01 02:18:03 +04:00
can_put_echo_skb ( skb , dev , 0 ) ;
2011-08-16 21:32:20 +04:00
flexcan_write ( can_id , & regs - > cantxfg [ FLEXCAN_TX_BUF_ID ] . can_id ) ;
flexcan_write ( ctrl , & regs - > cantxfg [ FLEXCAN_TX_BUF_ID ] . can_ctrl ) ;
2009-07-29 12:20:10 +04:00
return NETDEV_TX_OK ;
}
static void do_bus_err ( struct net_device * dev ,
struct can_frame * cf , u32 reg_esr )
{
struct flexcan_priv * priv = netdev_priv ( dev ) ;
int rx_errors = 0 , tx_errors = 0 ;
cf - > can_id | = CAN_ERR_PROT | CAN_ERR_BUSERROR ;
if ( reg_esr & FLEXCAN_ESR_BIT1_ERR ) {
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " BIT1_ERR irq \n " ) ;
2009-07-29 12:20:10 +04:00
cf - > data [ 2 ] | = CAN_ERR_PROT_BIT1 ;
tx_errors = 1 ;
}
if ( reg_esr & FLEXCAN_ESR_BIT0_ERR ) {
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " BIT0_ERR irq \n " ) ;
2009-07-29 12:20:10 +04:00
cf - > data [ 2 ] | = CAN_ERR_PROT_BIT0 ;
tx_errors = 1 ;
}
if ( reg_esr & FLEXCAN_ESR_ACK_ERR ) {
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " ACK_ERR irq \n " ) ;
2009-07-29 12:20:10 +04:00
cf - > can_id | = CAN_ERR_ACK ;
cf - > data [ 3 ] | = CAN_ERR_PROT_LOC_ACK ;
tx_errors = 1 ;
}
if ( reg_esr & FLEXCAN_ESR_CRC_ERR ) {
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " CRC_ERR irq \n " ) ;
2009-07-29 12:20:10 +04:00
cf - > data [ 2 ] | = CAN_ERR_PROT_BIT ;
cf - > data [ 3 ] | = CAN_ERR_PROT_LOC_CRC_SEQ ;
rx_errors = 1 ;
}
if ( reg_esr & FLEXCAN_ESR_FRM_ERR ) {
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " FRM_ERR irq \n " ) ;
2009-07-29 12:20:10 +04:00
cf - > data [ 2 ] | = CAN_ERR_PROT_FORM ;
rx_errors = 1 ;
}
if ( reg_esr & FLEXCAN_ESR_STF_ERR ) {
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " STF_ERR irq \n " ) ;
2009-07-29 12:20:10 +04:00
cf - > data [ 2 ] | = CAN_ERR_PROT_STUFF ;
rx_errors = 1 ;
}
priv - > can . can_stats . bus_error + + ;
if ( rx_errors )
dev - > stats . rx_errors + + ;
if ( tx_errors )
dev - > stats . tx_errors + + ;
}
static int flexcan_poll_bus_err ( struct net_device * dev , u32 reg_esr )
{
struct sk_buff * skb ;
struct can_frame * cf ;
skb = alloc_can_err_skb ( dev , & cf ) ;
if ( unlikely ( ! skb ) )
return 0 ;
do_bus_err ( dev , cf , reg_esr ) ;
netif_receive_skb ( skb ) ;
dev - > stats . rx_packets + + ;
dev - > stats . rx_bytes + = cf - > can_dlc ;
return 1 ;
}
static void do_state ( struct net_device * dev ,
struct can_frame * cf , enum can_state new_state )
{
struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct can_berr_counter bec ;
flexcan_get_berr_counter ( dev , & bec ) ;
switch ( priv - > can . state ) {
case CAN_STATE_ERROR_ACTIVE :
/*
* from : ERROR_ACTIVE
* to : ERROR_WARNING , ERROR_PASSIVE , BUS_OFF
* = > : there was a warning int
*/
if ( new_state > = CAN_STATE_ERROR_WARNING & &
new_state < = CAN_STATE_BUS_OFF ) {
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " Error Warning IRQ \n " ) ;
2009-07-29 12:20:10 +04:00
priv - > can . can_stats . error_warning + + ;
cf - > can_id | = CAN_ERR_CRTL ;
cf - > data [ 1 ] = ( bec . txerr > bec . rxerr ) ?
CAN_ERR_CRTL_TX_WARNING :
CAN_ERR_CRTL_RX_WARNING ;
}
case CAN_STATE_ERROR_WARNING : /* fallthrough */
/*
* from : ERROR_ACTIVE , ERROR_WARNING
* to : ERROR_PASSIVE , BUS_OFF
* = > : error passive int
*/
if ( new_state > = CAN_STATE_ERROR_PASSIVE & &
new_state < = CAN_STATE_BUS_OFF ) {
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " Error Passive IRQ \n " ) ;
2009-07-29 12:20:10 +04:00
priv - > can . can_stats . error_passive + + ;
cf - > can_id | = CAN_ERR_CRTL ;
cf - > data [ 1 ] = ( bec . txerr > bec . rxerr ) ?
CAN_ERR_CRTL_TX_PASSIVE :
CAN_ERR_CRTL_RX_PASSIVE ;
}
break ;
case CAN_STATE_BUS_OFF :
2012-02-01 14:02:05 +04:00
netdev_err ( dev , " BUG! "
" hardware recovered automatically from BUS_OFF \n " ) ;
2009-07-29 12:20:10 +04:00
break ;
default :
break ;
}
/* process state changes depending on the new state */
switch ( new_state ) {
case CAN_STATE_ERROR_ACTIVE :
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " Error Active \n " ) ;
2009-07-29 12:20:10 +04:00
cf - > can_id | = CAN_ERR_PROT ;
cf - > data [ 2 ] = CAN_ERR_PROT_ACTIVE ;
break ;
case CAN_STATE_BUS_OFF :
cf - > can_id | = CAN_ERR_BUSOFF ;
can_bus_off ( dev ) ;
break ;
default :
break ;
}
}
static int flexcan_poll_state ( struct net_device * dev , u32 reg_esr )
{
struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct sk_buff * skb ;
struct can_frame * cf ;
enum can_state new_state ;
int flt ;
flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK ;
if ( likely ( flt = = FLEXCAN_ESR_FLT_CONF_ACTIVE ) ) {
if ( likely ( ! ( reg_esr & ( FLEXCAN_ESR_TX_WRN |
FLEXCAN_ESR_RX_WRN ) ) ) )
new_state = CAN_STATE_ERROR_ACTIVE ;
else
new_state = CAN_STATE_ERROR_WARNING ;
} else if ( unlikely ( flt = = FLEXCAN_ESR_FLT_CONF_PASSIVE ) )
new_state = CAN_STATE_ERROR_PASSIVE ;
else
new_state = CAN_STATE_BUS_OFF ;
/* state hasn't changed */
if ( likely ( new_state = = priv - > can . state ) )
return 0 ;
skb = alloc_can_err_skb ( dev , & cf ) ;
if ( unlikely ( ! skb ) )
return 0 ;
do_state ( dev , cf , new_state ) ;
priv - > can . state = new_state ;
netif_receive_skb ( skb ) ;
dev - > stats . rx_packets + + ;
dev - > stats . rx_bytes + = cf - > can_dlc ;
return 1 ;
}
static void flexcan_read_fifo ( const struct net_device * dev ,
struct can_frame * cf )
{
const struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct flexcan_regs __iomem * regs = priv - > base ;
struct flexcan_mb __iomem * mb = & regs - > cantxfg [ 0 ] ;
u32 reg_ctrl , reg_id ;
2011-08-16 21:32:20 +04:00
reg_ctrl = flexcan_read ( & mb - > can_ctrl ) ;
reg_id = flexcan_read ( & mb - > can_id ) ;
2009-07-29 12:20:10 +04:00
if ( reg_ctrl & FLEXCAN_MB_CNT_IDE )
cf - > can_id = ( ( reg_id > > 0 ) & CAN_EFF_MASK ) | CAN_EFF_FLAG ;
else
cf - > can_id = ( reg_id > > 18 ) & CAN_SFF_MASK ;
if ( reg_ctrl & FLEXCAN_MB_CNT_RTR )
cf - > can_id | = CAN_RTR_FLAG ;
cf - > can_dlc = get_can_dlc ( ( reg_ctrl > > 16 ) & 0xf ) ;
2011-08-16 21:32:20 +04:00
* ( __be32 * ) ( cf - > data + 0 ) = cpu_to_be32 ( flexcan_read ( & mb - > data [ 0 ] ) ) ;
* ( __be32 * ) ( cf - > data + 4 ) = cpu_to_be32 ( flexcan_read ( & mb - > data [ 1 ] ) ) ;
2009-07-29 12:20:10 +04:00
/* mark as read */
2011-08-16 21:32:20 +04:00
flexcan_write ( FLEXCAN_IFLAG_RX_FIFO_AVAILABLE , & regs - > iflag1 ) ;
flexcan_read ( & regs - > timer ) ;
2009-07-29 12:20:10 +04:00
}
static int flexcan_read_frame ( struct net_device * dev )
{
struct net_device_stats * stats = & dev - > stats ;
struct can_frame * cf ;
struct sk_buff * skb ;
skb = alloc_can_skb ( dev , & cf ) ;
if ( unlikely ( ! skb ) ) {
stats - > rx_dropped + + ;
return 0 ;
}
flexcan_read_fifo ( dev , cf ) ;
netif_receive_skb ( skb ) ;
stats - > rx_packets + + ;
stats - > rx_bytes + = cf - > can_dlc ;
2012-12-18 21:50:58 +04:00
can_led_event ( dev , CAN_LED_EVENT_RX ) ;
2009-07-29 12:20:10 +04:00
return 1 ;
}
static int flexcan_poll ( struct napi_struct * napi , int quota )
{
struct net_device * dev = napi - > dev ;
const struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct flexcan_regs __iomem * regs = priv - > base ;
u32 reg_iflag1 , reg_esr ;
int work_done = 0 ;
/*
* The error bits are cleared on read ,
* use saved value from irq handler .
*/
2011-08-16 21:32:20 +04:00
reg_esr = flexcan_read ( & regs - > esr ) | priv - > reg_esr ;
2009-07-29 12:20:10 +04:00
/* handle state changes */
work_done + = flexcan_poll_state ( dev , reg_esr ) ;
/* handle RX-FIFO */
2011-08-16 21:32:20 +04:00
reg_iflag1 = flexcan_read ( & regs - > iflag1 ) ;
2009-07-29 12:20:10 +04:00
while ( reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE & &
work_done < quota ) {
work_done + = flexcan_read_frame ( dev ) ;
2011-08-16 21:32:20 +04:00
reg_iflag1 = flexcan_read ( & regs - > iflag1 ) ;
2009-07-29 12:20:10 +04:00
}
/* report bus errors */
if ( flexcan_has_and_handle_berr ( priv , reg_esr ) & & work_done < quota )
work_done + = flexcan_poll_bus_err ( dev , reg_esr ) ;
if ( work_done < quota ) {
napi_complete ( napi ) ;
/* enable IRQs */
2011-08-16 21:32:20 +04:00
flexcan_write ( FLEXCAN_IFLAG_DEFAULT , & regs - > imask1 ) ;
flexcan_write ( priv - > reg_ctrl_default , & regs - > ctrl ) ;
2009-07-29 12:20:10 +04:00
}
return work_done ;
}
static irqreturn_t flexcan_irq ( int irq , void * dev_id )
{
struct net_device * dev = dev_id ;
struct net_device_stats * stats = & dev - > stats ;
struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct flexcan_regs __iomem * regs = priv - > base ;
u32 reg_iflag1 , reg_esr ;
2011-08-16 21:32:20 +04:00
reg_iflag1 = flexcan_read ( & regs - > iflag1 ) ;
reg_esr = flexcan_read ( & regs - > esr ) ;
2011-12-12 19:09:28 +04:00
/* ACK all bus error and state change IRQ sources */
if ( reg_esr & FLEXCAN_ESR_ALL_INT )
flexcan_write ( reg_esr & FLEXCAN_ESR_ALL_INT , & regs - > esr ) ;
2009-07-29 12:20:10 +04:00
/*
* schedule NAPI in case of :
* - rx IRQ
* - state change IRQ
* - bus error IRQ and bus error reporting is activated
*/
if ( ( reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE ) | |
( reg_esr & FLEXCAN_ESR_ERR_STATE ) | |
flexcan_has_and_handle_berr ( priv , reg_esr ) ) {
/*
* The error bits are cleared on read ,
* save them for later use .
*/
priv - > reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS ;
2011-08-16 21:32:20 +04:00
flexcan_write ( FLEXCAN_IFLAG_DEFAULT &
~ FLEXCAN_IFLAG_RX_FIFO_AVAILABLE , & regs - > imask1 ) ;
flexcan_write ( priv - > reg_ctrl_default & ~ FLEXCAN_CTRL_ERR_ALL ,
2009-07-29 12:20:10 +04:00
& regs - > ctrl ) ;
napi_schedule ( & priv - > napi ) ;
}
/* FIFO overflow */
if ( reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW ) {
2011-08-16 21:32:20 +04:00
flexcan_write ( FLEXCAN_IFLAG_RX_FIFO_OVERFLOW , & regs - > iflag1 ) ;
2009-07-29 12:20:10 +04:00
dev - > stats . rx_over_errors + + ;
dev - > stats . rx_errors + + ;
}
/* transmission complete interrupt */
if ( reg_iflag1 & ( 1 < < FLEXCAN_TX_BUF_ID ) ) {
2011-11-01 02:18:03 +04:00
stats - > tx_bytes + = can_get_echo_skb ( dev , 0 ) ;
2009-07-29 12:20:10 +04:00
stats - > tx_packets + + ;
2012-12-18 21:50:58 +04:00
can_led_event ( dev , CAN_LED_EVENT_TX ) ;
2011-08-16 21:32:20 +04:00
flexcan_write ( ( 1 < < FLEXCAN_TX_BUF_ID ) , & regs - > iflag1 ) ;
2009-07-29 12:20:10 +04:00
netif_wake_queue ( dev ) ;
}
return IRQ_HANDLED ;
}
static void flexcan_set_bittiming ( struct net_device * dev )
{
const struct flexcan_priv * priv = netdev_priv ( dev ) ;
const struct can_bittiming * bt = & priv - > can . bittiming ;
struct flexcan_regs __iomem * regs = priv - > base ;
u32 reg ;
2011-08-16 21:32:20 +04:00
reg = flexcan_read ( & regs - > ctrl ) ;
2009-07-29 12:20:10 +04:00
reg & = ~ ( FLEXCAN_CTRL_PRESDIV ( 0xff ) |
FLEXCAN_CTRL_RJW ( 0x3 ) |
FLEXCAN_CTRL_PSEG1 ( 0x7 ) |
FLEXCAN_CTRL_PSEG2 ( 0x7 ) |
FLEXCAN_CTRL_PROPSEG ( 0x7 ) |
FLEXCAN_CTRL_LPB |
FLEXCAN_CTRL_SMP |
FLEXCAN_CTRL_LOM ) ;
reg | = FLEXCAN_CTRL_PRESDIV ( bt - > brp - 1 ) |
FLEXCAN_CTRL_PSEG1 ( bt - > phase_seg1 - 1 ) |
FLEXCAN_CTRL_PSEG2 ( bt - > phase_seg2 - 1 ) |
FLEXCAN_CTRL_RJW ( bt - > sjw - 1 ) |
FLEXCAN_CTRL_PROPSEG ( bt - > prop_seg - 1 ) ;
if ( priv - > can . ctrlmode & CAN_CTRLMODE_LOOPBACK )
reg | = FLEXCAN_CTRL_LPB ;
if ( priv - > can . ctrlmode & CAN_CTRLMODE_LISTENONLY )
reg | = FLEXCAN_CTRL_LOM ;
if ( priv - > can . ctrlmode & CAN_CTRLMODE_3_SAMPLES )
reg | = FLEXCAN_CTRL_SMP ;
2012-02-01 14:02:05 +04:00
netdev_info ( dev , " writing ctrl=0x%08x \n " , reg ) ;
2011-08-16 21:32:20 +04:00
flexcan_write ( reg , & regs - > ctrl ) ;
2009-07-29 12:20:10 +04:00
/* print chip status */
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " %s: mcr=0x%08x ctrl=0x%08x \n " , __func__ ,
flexcan_read ( & regs - > mcr ) , flexcan_read ( & regs - > ctrl ) ) ;
2009-07-29 12:20:10 +04:00
}
/*
* flexcan_chip_start
*
* this functions is entered with clocks enabled
*
*/
static int flexcan_chip_start ( struct net_device * dev )
{
struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct flexcan_regs __iomem * regs = priv - > base ;
int err ;
u32 reg_mcr , reg_ctrl ;
/* enable module */
2014-02-28 18:30:18 +04:00
err = flexcan_chip_enable ( priv ) ;
if ( err )
return err ;
2009-07-29 12:20:10 +04:00
/* soft reset */
2014-02-28 18:16:59 +04:00
err = flexcan_chip_softreset ( priv ) ;
if ( err )
2014-02-28 20:08:21 +04:00
goto out_chip_disable ;
2009-07-29 12:20:10 +04:00
flexcan_set_bittiming ( dev ) ;
/*
* MCR
*
* enable freeze
* enable fifo
* halt now
* only supervisor access
* enable warning int
* choose format C
2011-11-01 02:18:03 +04:00
* disable local echo
2009-07-29 12:20:10 +04:00
*
*/
2011-08-16 21:32:20 +04:00
reg_mcr = flexcan_read ( & regs - > mcr ) ;
2013-10-04 12:52:36 +04:00
reg_mcr & = ~ FLEXCAN_MCR_MAXMB ( 0xff ) ;
2009-07-29 12:20:10 +04:00
reg_mcr | = FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
2013-10-04 12:52:36 +04:00
FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_SRX_DIS |
FLEXCAN_MCR_MAXMB ( FLEXCAN_TX_BUF_ID ) ;
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " %s: writing mcr=0x%08x " , __func__ , reg_mcr ) ;
2011-08-16 21:32:20 +04:00
flexcan_write ( reg_mcr , & regs - > mcr ) ;
2009-07-29 12:20:10 +04:00
/*
* CTRL
*
* disable timer sync feature
*
* disable auto busoff recovery
* transmit lowest buffer first
*
* enable tx and rx warning interrupt
* enable bus off interrupt
* ( = = FLEXCAN_CTRL_ERR_STATE )
*/
2011-08-16 21:32:20 +04:00
reg_ctrl = flexcan_read ( & regs - > ctrl ) ;
2009-07-29 12:20:10 +04:00
reg_ctrl & = ~ FLEXCAN_CTRL_TSYN ;
reg_ctrl | = FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF |
2012-09-28 07:17:15 +04:00
FLEXCAN_CTRL_ERR_STATE ;
/*
* enable the " error interrupt " ( FLEXCAN_CTRL_ERR_MSK ) ,
* on most Flexcan cores , too . Otherwise we don ' t get
* any error warning or passive interrupts .
*/
if ( priv - > devtype_data - > features & FLEXCAN_HAS_BROKEN_ERR_STATE | |
priv - > can . ctrlmode & CAN_CTRLMODE_BERR_REPORTING )
reg_ctrl | = FLEXCAN_CTRL_ERR_MSK ;
2009-07-29 12:20:10 +04:00
/* save for later use */
priv - > reg_ctrl_default = reg_ctrl ;
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " %s: writing ctrl=0x%08x " , __func__ , reg_ctrl ) ;
2011-08-16 21:32:20 +04:00
flexcan_write ( reg_ctrl , & regs - > ctrl ) ;
2009-07-29 12:20:10 +04:00
2013-10-04 12:52:36 +04:00
/* Abort any pending TX, mark Mailbox as INACTIVE */
flexcan_write ( FLEXCAN_MB_CNT_CODE ( 0x4 ) ,
& regs - > cantxfg [ FLEXCAN_TX_BUF_ID ] . can_ctrl ) ;
2009-07-29 12:20:10 +04:00
/* acceptance mask/acceptance code (accept everything) */
2011-08-16 21:32:20 +04:00
flexcan_write ( 0x0 , & regs - > rxgmask ) ;
flexcan_write ( 0x0 , & regs - > rx14mask ) ;
flexcan_write ( 0x0 , & regs - > rx15mask ) ;
2009-07-29 12:20:10 +04:00
2012-09-28 07:17:15 +04:00
if ( priv - > devtype_data - > features & FLEXCAN_HAS_V10_FEATURES )
2012-06-28 12:21:35 +04:00
flexcan_write ( 0x0 , & regs - > rxfgmask ) ;
2014-02-28 20:18:27 +04:00
err = flexcan_transceiver_enable ( priv ) ;
if ( err )
2014-02-28 20:08:21 +04:00
goto out_chip_disable ;
2009-07-29 12:20:10 +04:00
/* synchronize with the can bus */
2014-02-28 20:08:21 +04:00
err = flexcan_chip_unfreeze ( priv ) ;
if ( err )
goto out_transceiver_disable ;
2009-07-29 12:20:10 +04:00
priv - > can . state = CAN_STATE_ERROR_ACTIVE ;
/* enable FIFO interrupts */
2011-08-16 21:32:20 +04:00
flexcan_write ( FLEXCAN_IFLAG_DEFAULT , & regs - > imask1 ) ;
2009-07-29 12:20:10 +04:00
/* print chip status */
2012-02-01 14:02:05 +04:00
netdev_dbg ( dev , " %s: reading mcr=0x%08x ctrl=0x%08x \n " , __func__ ,
flexcan_read ( & regs - > mcr ) , flexcan_read ( & regs - > ctrl ) ) ;
2009-07-29 12:20:10 +04:00
return 0 ;
2014-02-28 20:08:21 +04:00
out_transceiver_disable :
flexcan_transceiver_disable ( priv ) ;
out_chip_disable :
2009-07-29 12:20:10 +04:00
flexcan_chip_disable ( priv ) ;
return err ;
}
/*
* flexcan_chip_stop
*
* this functions is entered with clocks enabled
*
*/
static void flexcan_chip_stop ( struct net_device * dev )
{
struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct flexcan_regs __iomem * regs = priv - > base ;
2014-02-28 20:08:21 +04:00
/* freeze + disable module */
flexcan_chip_freeze ( priv ) ;
flexcan_chip_disable ( priv ) ;
2009-07-29 12:20:10 +04:00
2014-02-19 15:00:51 +04:00
/* Disable all interrupts */
flexcan_write ( 0 , & regs - > imask1 ) ;
flexcan_write ( priv - > reg_ctrl_default & ~ FLEXCAN_CTRL_ERR_ALL ,
& regs - > ctrl ) ;
2014-02-28 20:18:27 +04:00
flexcan_transceiver_disable ( priv ) ;
2009-07-29 12:20:10 +04:00
priv - > can . state = CAN_STATE_STOPPED ;
return ;
}
static int flexcan_open ( struct net_device * dev )
{
struct flexcan_priv * priv = netdev_priv ( dev ) ;
int err ;
2013-07-22 19:41:40 +04:00
err = clk_prepare_enable ( priv - > clk_ipg ) ;
if ( err )
return err ;
err = clk_prepare_enable ( priv - > clk_per ) ;
if ( err )
goto out_disable_ipg ;
2009-07-29 12:20:10 +04:00
err = open_candev ( dev ) ;
if ( err )
2013-07-22 19:41:40 +04:00
goto out_disable_per ;
2009-07-29 12:20:10 +04:00
err = request_irq ( dev - > irq , flexcan_irq , IRQF_SHARED , dev - > name , dev ) ;
if ( err )
goto out_close ;
/* start chip and queuing */
err = flexcan_chip_start ( dev ) ;
if ( err )
2014-02-28 17:52:01 +04:00
goto out_free_irq ;
2012-12-18 21:50:58 +04:00
can_led_event ( dev , CAN_LED_EVENT_OPEN ) ;
2009-07-29 12:20:10 +04:00
napi_enable ( & priv - > napi ) ;
netif_start_queue ( dev ) ;
return 0 ;
2014-02-28 17:52:01 +04:00
out_free_irq :
free_irq ( dev - > irq , dev ) ;
2009-07-29 12:20:10 +04:00
out_close :
close_candev ( dev ) ;
2013-07-22 19:41:40 +04:00
out_disable_per :
2012-07-17 18:14:34 +04:00
clk_disable_unprepare ( priv - > clk_per ) ;
2013-07-22 19:41:40 +04:00
out_disable_ipg :
2012-07-17 18:14:34 +04:00
clk_disable_unprepare ( priv - > clk_ipg ) ;
2009-07-29 12:20:10 +04:00
return err ;
}
static int flexcan_close ( struct net_device * dev )
{
struct flexcan_priv * priv = netdev_priv ( dev ) ;
netif_stop_queue ( dev ) ;
napi_disable ( & priv - > napi ) ;
flexcan_chip_stop ( dev ) ;
free_irq ( dev - > irq , dev ) ;
2012-07-17 18:14:34 +04:00
clk_disable_unprepare ( priv - > clk_per ) ;
clk_disable_unprepare ( priv - > clk_ipg ) ;
2009-07-29 12:20:10 +04:00
close_candev ( dev ) ;
2012-12-18 21:50:58 +04:00
can_led_event ( dev , CAN_LED_EVENT_STOP ) ;
2009-07-29 12:20:10 +04:00
return 0 ;
}
static int flexcan_set_mode ( struct net_device * dev , enum can_mode mode )
{
int err ;
switch ( mode ) {
case CAN_MODE_START :
err = flexcan_chip_start ( dev ) ;
if ( err )
return err ;
netif_wake_queue ( dev ) ;
break ;
default :
return - EOPNOTSUPP ;
}
return 0 ;
}
static const struct net_device_ops flexcan_netdev_ops = {
. ndo_open = flexcan_open ,
. ndo_stop = flexcan_close ,
. ndo_start_xmit = flexcan_start_xmit ,
} ;
2012-12-03 18:22:44 +04:00
static int register_flexcandev ( struct net_device * dev )
2009-07-29 12:20:10 +04:00
{
struct flexcan_priv * priv = netdev_priv ( dev ) ;
struct flexcan_regs __iomem * regs = priv - > base ;
u32 reg , err ;
2013-07-22 19:41:40 +04:00
err = clk_prepare_enable ( priv - > clk_ipg ) ;
if ( err )
return err ;
err = clk_prepare_enable ( priv - > clk_per ) ;
if ( err )
goto out_disable_ipg ;
2009-07-29 12:20:10 +04:00
/* select "bus clock", chip must be disabled */
2014-02-28 18:30:18 +04:00
err = flexcan_chip_disable ( priv ) ;
if ( err )
goto out_disable_per ;
2011-08-16 21:32:20 +04:00
reg = flexcan_read ( & regs - > ctrl ) ;
2009-07-29 12:20:10 +04:00
reg | = FLEXCAN_CTRL_CLK_SRC ;
2011-08-16 21:32:20 +04:00
flexcan_write ( reg , & regs - > ctrl ) ;
2009-07-29 12:20:10 +04:00
2014-02-28 18:30:18 +04:00
err = flexcan_chip_enable ( priv ) ;
if ( err )
goto out_chip_disable ;
2009-07-29 12:20:10 +04:00
/* set freeze, halt and activate FIFO, restrict register access */
2011-08-16 21:32:20 +04:00
reg = flexcan_read ( & regs - > mcr ) ;
2009-07-29 12:20:10 +04:00
reg | = FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV ;
2011-08-16 21:32:20 +04:00
flexcan_write ( reg , & regs - > mcr ) ;
2009-07-29 12:20:10 +04:00
/*
* Currently we only support newer versions of this core
* featuring a RX FIFO . Older cores found on some Coldfire
* derivates are not yet supported .
*/
2011-08-16 21:32:20 +04:00
reg = flexcan_read ( & regs - > mcr ) ;
2009-07-29 12:20:10 +04:00
if ( ! ( reg & FLEXCAN_MCR_FEN ) ) {
2012-02-01 14:02:05 +04:00
netdev_err ( dev , " Could not enable RX FIFO, unsupported core \n " ) ;
2009-07-29 12:20:10 +04:00
err = - ENODEV ;
2014-02-28 18:30:18 +04:00
goto out_chip_disable ;
2009-07-29 12:20:10 +04:00
}
err = register_candev ( dev ) ;
/* disable core and turn off clocks */
2014-02-28 18:30:18 +04:00
out_chip_disable :
2009-07-29 12:20:10 +04:00
flexcan_chip_disable ( priv ) ;
2014-02-28 18:30:18 +04:00
out_disable_per :
2012-07-17 18:14:34 +04:00
clk_disable_unprepare ( priv - > clk_per ) ;
2013-07-22 19:41:40 +04:00
out_disable_ipg :
2012-07-17 18:14:34 +04:00
clk_disable_unprepare ( priv - > clk_ipg ) ;
2009-07-29 12:20:10 +04:00
return err ;
}
2012-12-03 18:22:44 +04:00
static void unregister_flexcandev ( struct net_device * dev )
2009-07-29 12:20:10 +04:00
{
unregister_candev ( dev ) ;
}
2012-06-28 12:21:35 +04:00
static const struct of_device_id flexcan_of_match [ ] = {
{ . compatible = " fsl,imx6q-flexcan " , . data = & fsl_imx6q_devtype_data , } ,
2013-10-04 01:51:55 +04:00
{ . compatible = " fsl,imx28-flexcan " , . data = & fsl_imx28_devtype_data , } ,
{ . compatible = " fsl,p1010-flexcan " , . data = & fsl_p1010_devtype_data , } ,
2012-06-28 12:21:35 +04:00
{ /* sentinel */ } ,
} ;
2012-10-04 12:55:35 +04:00
MODULE_DEVICE_TABLE ( of , flexcan_of_match ) ;
2012-06-28 12:21:35 +04:00
static const struct platform_device_id flexcan_id_table [ ] = {
{ . name = " flexcan " , . driver_data = ( kernel_ulong_t ) & fsl_p1010_devtype_data , } ,
{ /* sentinel */ } ,
} ;
2012-10-04 12:55:35 +04:00
MODULE_DEVICE_TABLE ( platform , flexcan_id_table ) ;
2012-06-28 12:21:35 +04:00
2012-12-03 18:22:44 +04:00
static int flexcan_probe ( struct platform_device * pdev )
2009-07-29 12:20:10 +04:00
{
2012-06-28 12:21:35 +04:00
const struct of_device_id * of_id ;
2012-07-13 16:52:48 +04:00
const struct flexcan_devtype_data * devtype_data ;
2009-07-29 12:20:10 +04:00
struct net_device * dev ;
struct flexcan_priv * priv ;
struct resource * mem ;
2012-07-17 18:14:34 +04:00
struct clk * clk_ipg = NULL , * clk_per = NULL ;
2009-07-29 12:20:10 +04:00
void __iomem * base ;
int err , irq ;
2011-08-16 21:32:23 +04:00
u32 clock_freq = 0 ;
2012-06-28 12:21:34 +04:00
if ( pdev - > dev . of_node )
of_property_read_u32 ( pdev - > dev . of_node ,
" clock-frequency " , & clock_freq ) ;
2011-08-16 21:32:23 +04:00
if ( ! clock_freq ) {
2012-07-17 18:14:34 +04:00
clk_ipg = devm_clk_get ( & pdev - > dev , " ipg " ) ;
if ( IS_ERR ( clk_ipg ) ) {
dev_err ( & pdev - > dev , " no ipg clock defined \n " ) ;
2013-07-22 19:41:39 +04:00
return PTR_ERR ( clk_ipg ) ;
2012-07-17 18:14:34 +04:00
}
clk_per = devm_clk_get ( & pdev - > dev , " per " ) ;
if ( IS_ERR ( clk_per ) ) {
dev_err ( & pdev - > dev , " no per clock defined \n " ) ;
2013-07-22 19:41:39 +04:00
return PTR_ERR ( clk_per ) ;
2011-08-16 21:32:23 +04:00
}
2013-11-26 01:15:20 +04:00
clock_freq = clk_get_rate ( clk_per ) ;
2009-07-29 12:20:10 +04:00
}
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
irq = platform_get_irq ( pdev , 0 ) ;
2013-07-22 19:41:39 +04:00
if ( irq < = 0 )
return - ENODEV ;
2009-07-29 12:20:10 +04:00
2013-07-22 19:41:39 +04:00
base = devm_ioremap_resource ( & pdev - > dev , mem ) ;
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2009-07-29 12:20:10 +04:00
2012-06-28 12:21:35 +04:00
of_id = of_match_device ( flexcan_of_match , & pdev - > dev ) ;
if ( of_id ) {
devtype_data = of_id - > data ;
} else if ( pdev - > id_entry - > driver_data ) {
devtype_data = ( struct flexcan_devtype_data * )
pdev - > id_entry - > driver_data ;
} else {
2013-07-22 19:41:39 +04:00
return - ENODEV ;
2012-06-28 12:21:35 +04:00
}
2013-07-22 19:41:39 +04:00
dev = alloc_candev ( sizeof ( struct flexcan_priv ) , 1 ) ;
if ( ! dev )
return - ENOMEM ;
2009-07-29 12:20:10 +04:00
dev - > netdev_ops = & flexcan_netdev_ops ;
dev - > irq = irq ;
2011-11-01 02:18:03 +04:00
dev - > flags | = IFF_ECHO ;
2009-07-29 12:20:10 +04:00
priv = netdev_priv ( dev ) ;
2011-08-16 21:32:23 +04:00
priv - > can . clock . freq = clock_freq ;
2009-07-29 12:20:10 +04:00
priv - > can . bittiming_const = & flexcan_bittiming_const ;
priv - > can . do_set_mode = flexcan_set_mode ;
priv - > can . do_get_berr_counter = flexcan_get_berr_counter ;
priv - > can . ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_BERR_REPORTING ;
priv - > base = base ;
priv - > dev = dev ;
2012-07-17 18:14:34 +04:00
priv - > clk_ipg = clk_ipg ;
priv - > clk_per = clk_per ;
2013-09-10 12:41:30 +04:00
priv - > pdata = dev_get_platdata ( & pdev - > dev ) ;
2012-06-28 12:21:35 +04:00
priv - > devtype_data = devtype_data ;
2009-07-29 12:20:10 +04:00
2013-06-11 06:12:57 +04:00
priv - > reg_xceiver = devm_regulator_get ( & pdev - > dev , " xceiver " ) ;
if ( IS_ERR ( priv - > reg_xceiver ) )
priv - > reg_xceiver = NULL ;
2009-07-29 12:20:10 +04:00
netif_napi_add ( dev , & priv - > napi , flexcan_poll , FLEXCAN_NAPI_WEIGHT ) ;
2013-08-21 14:15:08 +04:00
platform_set_drvdata ( pdev , dev ) ;
2009-07-29 12:20:10 +04:00
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
err = register_flexcandev ( dev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " registering netdev failed \n " ) ;
goto failed_register ;
}
2012-12-18 21:50:58 +04:00
devm_can_led_init ( dev ) ;
2009-07-29 12:20:10 +04:00
dev_info ( & pdev - > dev , " device registered (reg_base=%p, irq=%d) \n " ,
priv - > base , dev - > irq ) ;
return 0 ;
failed_register :
free_candev ( dev ) ;
return err ;
}
2012-12-03 18:22:44 +04:00
static int flexcan_remove ( struct platform_device * pdev )
2009-07-29 12:20:10 +04:00
{
struct net_device * dev = platform_get_drvdata ( pdev ) ;
2014-02-28 23:48:36 +04:00
struct flexcan_priv * priv = netdev_priv ( dev ) ;
2009-07-29 12:20:10 +04:00
unregister_flexcandev ( dev ) ;
2014-02-28 23:48:36 +04:00
netif_napi_del ( & priv - > napi ) ;
2010-10-21 09:07:58 +04:00
free_candev ( dev ) ;
2009-07-29 12:20:10 +04:00
return 0 ;
}
2014-03-05 22:10:44 +04:00
static int __maybe_unused flexcan_suspend ( struct device * device )
2012-05-08 19:12:17 +04:00
{
2013-05-20 22:43:43 +04:00
struct net_device * dev = dev_get_drvdata ( device ) ;
2012-05-08 19:12:17 +04:00
struct flexcan_priv * priv = netdev_priv ( dev ) ;
2014-02-28 18:30:18 +04:00
int err ;
2012-05-08 19:12:17 +04:00
2014-02-28 18:30:18 +04:00
err = flexcan_chip_disable ( priv ) ;
if ( err )
return err ;
2012-05-08 19:12:17 +04:00
if ( netif_running ( dev ) ) {
netif_stop_queue ( dev ) ;
netif_device_detach ( dev ) ;
}
priv - > can . state = CAN_STATE_SLEEPING ;
return 0 ;
}
2014-03-05 22:10:44 +04:00
static int __maybe_unused flexcan_resume ( struct device * device )
2012-05-08 19:12:17 +04:00
{
2013-05-20 22:43:43 +04:00
struct net_device * dev = dev_get_drvdata ( device ) ;
2012-05-08 19:12:17 +04:00
struct flexcan_priv * priv = netdev_priv ( dev ) ;
priv - > can . state = CAN_STATE_ERROR_ACTIVE ;
if ( netif_running ( dev ) ) {
netif_device_attach ( dev ) ;
netif_start_queue ( dev ) ;
}
2014-02-28 18:30:18 +04:00
return flexcan_chip_enable ( priv ) ;
2012-05-08 19:12:17 +04:00
}
2013-05-20 22:43:43 +04:00
static SIMPLE_DEV_PM_OPS ( flexcan_pm_ops , flexcan_suspend , flexcan_resume ) ;
2012-05-08 19:12:17 +04:00
2009-07-29 12:20:10 +04:00
static struct platform_driver flexcan_driver = {
2011-08-16 21:32:22 +04:00
. driver = {
. name = DRV_NAME ,
. owner = THIS_MODULE ,
2013-05-20 22:43:43 +04:00
. pm = & flexcan_pm_ops ,
2011-08-16 21:32:22 +04:00
. of_match_table = flexcan_of_match ,
} ,
2009-07-29 12:20:10 +04:00
. probe = flexcan_probe ,
2012-12-03 18:22:44 +04:00
. remove = flexcan_remove ,
2012-06-28 12:21:35 +04:00
. id_table = flexcan_id_table ,
2009-07-29 12:20:10 +04:00
} ;
2011-11-27 19:42:31 +04:00
module_platform_driver ( flexcan_driver ) ;
2009-07-29 12:20:10 +04:00
MODULE_AUTHOR ( " Sascha Hauer <kernel@pengutronix.de>, "
" Marc Kleine-Budde <kernel@pengutronix.de> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " CAN port driver for flexcan based chip " ) ;