888 lines
22 KiB
Plaintext
888 lines
22 KiB
Plaintext
/*
|
|
* gsc3280_can.c - CAN network driver for GSC3280 SoC CAN controller
|
|
*
|
|
* (C) 2013 by Clive Chen, chenguangyu@china-cpu.com
|
|
* (C) 2016 by Merlin Song, songxingjia@china-cpu.com
|
|
*
|
|
* This software may be distributed under the terms of the GNU General
|
|
* Public License ("GPL") version 2 as distributed in the 'COPYING'
|
|
* file from the main directory of the linux kernel source.
|
|
*
|
|
* Send feedback to <socketcan-users@lists.berlios.de>
|
|
*
|
|
*
|
|
* Your platform definition file should specify something like:
|
|
*
|
|
* static struct at91_can_data ek_can_data = {
|
|
* transceiver_switch = sam9263ek_transceiver_switch,
|
|
* };
|
|
*
|
|
* at91_add_device_can(&ek_can_data);
|
|
*
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/types.h>
|
|
#include <linux/fcntl.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/string.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/if_arp.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/cpu.h>
|
|
#include <asm/cpu.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/can/dev.h>
|
|
#include <linux/can/error.h>
|
|
|
|
#include "gsc3280_can.h"
|
|
|
|
#define DRV_NAME "gsc3280-can"
|
|
#define TX_ECHO_SKB_MAX 1
|
|
|
|
#ifdef CONFIG_GSC3280_CAN_DEBUG
|
|
#define DBG(msg...) do { \
|
|
printk(KERN_INFO msg); \
|
|
} while (0)
|
|
#else
|
|
#define DBG(msg...) do { } while(0)
|
|
#endif
|
|
|
|
/****************gsc3280 can module register enum************************/
|
|
enum gsc3280_reg {
|
|
CAN_MOD = 0x00,
|
|
CAN_CMR = 0x04,
|
|
CAN_SR = 0x08,
|
|
CAN_IR = 0x0C,
|
|
CAN_IER = 0x10,
|
|
CAN_BTR = 0x14,
|
|
CAN_ALC = 0x18,
|
|
CAN_ECC = 0x1C,
|
|
CAN_EWLR = 0x20,
|
|
CAN_RXERR = 0x24,
|
|
CAN_TXERR = 0x28,
|
|
CAN_RMC = 0x2C,
|
|
|
|
CAN_ACR = 0x80,
|
|
CAN_AMR = 0x84,
|
|
|
|
CAN_TXB0 = 0x80,
|
|
CAN_TXB1 = 0x84,
|
|
CAN_TXB2 = 0x88,
|
|
CAN_TXB3 = 0x8C,
|
|
|
|
CAN_RXB0 = 0x80,
|
|
CAN_RXB1 = 0x84,
|
|
CAN_RXB2 = 0x88,
|
|
CAN_RXB3 = 0x8C,
|
|
};
|
|
|
|
enum BLX_devtype {
|
|
BLX_DEVTYPE_GSC3280,
|
|
};
|
|
|
|
struct gsc3280_priv{
|
|
struct can_priv can; /*must be the first member!*/
|
|
struct net_device *dev;
|
|
void __iomem *reg_base;
|
|
|
|
int open_time;
|
|
void (*pre_irq) (const struct gsc3280_priv *priv);
|
|
void (*post_irq) (const struct gsc3280_priv *priv);
|
|
|
|
u32 reg_sr;
|
|
int irq;
|
|
unsigned short *pin_list;
|
|
spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */
|
|
};
|
|
|
|
static inline u32 gsc3280_read(const struct gsc3280_priv *priv, enum gsc3280_reg reg)
|
|
{
|
|
return __raw_readl((priv->reg_base + reg) + 0xa0000000);
|
|
}
|
|
|
|
static inline void gsc3280_write(const struct gsc3280_priv *priv, enum gsc3280_reg reg, u32 value )
|
|
{
|
|
__raw_writel(value, (priv->reg_base + reg + 0xa0000000));
|
|
}
|
|
|
|
static struct can_bittiming_const gsc3280_can_bittiming_const = {
|
|
.name = DRV_NAME,
|
|
.tseg1_min = 1,
|
|
.tseg1_max = 16,
|
|
.tseg2_min = 1,
|
|
.tseg2_max = 8,
|
|
.sjw_max = 4,
|
|
.brp_min = 2,
|
|
.brp_max = 128,
|
|
.brp_inc = 1,
|
|
};
|
|
|
|
/*
|
|
* gsc3280_can_set_reset_mode - gsc3280 can set reset mode routine
|
|
* @dev net device structure
|
|
*/
|
|
static void gsc3280_can_set_reset_mode (struct net_device *dev)
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
int i;
|
|
unsigned char status = gsc3280_read(priv, CAN_MOD) & 0xff;
|
|
|
|
DBG("status is 0x%x, GSC3280_IER 0x%2x,IRQ_OFF 0x%2x\n", status, GSC3280_IER, IRQ_OFF);
|
|
/* disable interrupts */
|
|
gsc3280_write(priv, CAN_IER, IRQ_OFF);
|
|
|
|
for (i = 0; i < 100; i++) {
|
|
/* check reset bit */
|
|
if (status & MOD_RM) {
|
|
priv->can.state = CAN_STATE_STOPPED;
|
|
return ;
|
|
}
|
|
|
|
/* reset chip */
|
|
gsc3280_write(priv, CAN_MOD, MOD_RM);
|
|
udelay(10);
|
|
status = gsc3280_read(priv, CAN_MOD) & 0xff;
|
|
}
|
|
|
|
DBG("setting GSC3280 CAN into reset mode failed!\n");
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_set_normal_mode - gsc3280 can set normal mode routine
|
|
* @dev net device structure
|
|
*/
|
|
static void gsc3280_can_set_normal_mode(struct net_device *dev)
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
int i;
|
|
u32 status = gsc3280_read ( priv, CAN_MOD );
|
|
|
|
/*printk("Enter gsc3280_can_set_normal_mod, reg_base is %x\n", priv->reg_base);*/
|
|
|
|
for ( i = 0; i < 100; i++){
|
|
/* check reset bit */
|
|
if (( status & MOD_RM) == 0) {
|
|
/* enable interrupts */
|
|
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
|
|
|
gsc3280_write(priv, CAN_IER, IRQ_ALL);
|
|
|
|
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
|
|
gsc3280_write(priv, CAN_IER, IRQ_ALL);
|
|
else
|
|
gsc3280_write(priv, CAN_IER, IRQ_ALL & ~IRQ_BEI);
|
|
return;
|
|
}
|
|
|
|
/* set chip to normal mode */
|
|
gsc3280_write (priv, CAN_MOD, 0x00);
|
|
udelay(10);
|
|
status = gsc3280_read ( priv, CAN_MOD);
|
|
DBG("normal_mod status is 0x%x, mode is 0x%x\n", status, mode);
|
|
}
|
|
|
|
DBG("setting GSC3280 CAN into normal mode failed!\n");
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_start - gsc3280 can start routine
|
|
* @dev net device structure
|
|
*/
|
|
static void gsc3280_can_start(struct net_device *dev)
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
|
|
/* leave reset mode */
|
|
if (priv->can.state != CAN_STATE_STOPPED)
|
|
gsc3280_can_set_reset_mode(dev);
|
|
|
|
/* Clear error counters and error code capture */
|
|
gsc3280_write (priv, CAN_TXERR, 0x0 );
|
|
gsc3280_write (priv, CAN_RXERR, 0x0 );
|
|
gsc3280_read(priv, CAN_ECC);
|
|
|
|
/* leave reset mode */
|
|
gsc3280_can_set_normal_mode(dev);
|
|
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_set_bittiming - get can controller bittimg parameters from app
|
|
* @dev: netdevice structure
|
|
*/
|
|
static int gsc3280_can_set_bittiming(struct net_device *dev)
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
struct can_bittiming *bt = &priv->can.bittiming;
|
|
unsigned int btr;
|
|
uint8_t tseg1, tseg2, sjw, brp, sam;
|
|
|
|
//fxtal = priv->can.clock.freq;
|
|
|
|
tseg1 = (bt->prop_seg + bt->phase_seg1 - 1) & 0xf;
|
|
tseg2 = (bt->phase_seg2 - 1) & 0x7;
|
|
sjw = (bt->sjw - 1) & 0x3;
|
|
brp = (bt->brp - 1) & 0x3f ;
|
|
|
|
btr = (tseg2<<12) | (tseg1<<8) | (sjw<<6) | brp;
|
|
|
|
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
|
|
{
|
|
sam = 0x1;
|
|
btr = btr| (sam<<15);
|
|
}
|
|
|
|
gsc3280_write ( priv, CAN_BTR, btr );
|
|
|
|
btr = gsc3280_read ( priv, CAN_BTR);
|
|
DBG("Setting CAN BTR=0x%04x\n",btr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gsc3280_can_get_berr_counter(const struct net_device *dev,
|
|
struct can_berr_counter *bec)
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
|
|
bec->txerr = gsc3280_read(priv, CAN_TXERR);
|
|
bec->rxerr = gsc3280_read(priv, CAN_RXERR);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_start_xmit - can controller transmiter function
|
|
* @dev: netdevice structure
|
|
* @skb: socket buffer structure
|
|
*/
|
|
static int gsc3280_can_start_xmit ( struct sk_buff * skb , struct net_device *dev )
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
struct can_frame *cf = ( struct can_frame *)skb->data;
|
|
|
|
uint8_t fi;
|
|
uint8_t dlc;
|
|
canid_t id;
|
|
|
|
unsigned long flags;
|
|
u32 buf1,buf2;
|
|
|
|
DBG("Enter gsc3280_can_start_xmit\n");
|
|
|
|
if (can_dropped_invalid_skb(dev, skb))
|
|
return NETDEV_TX_OK;
|
|
|
|
netif_stop_queue(dev);
|
|
|
|
fi = dlc = cf->can_dlc;
|
|
id = cf->can_id;
|
|
|
|
DBG(" can_dlc 0x%x \n", cf->can_dlc);
|
|
DBG(" can_id 0x%x \n", cf->can_id);
|
|
|
|
//if(fi & FI_RTR){
|
|
if((id>>24) & FI_RTR)
|
|
{
|
|
fi |= FI_RTR;
|
|
DBG("remote frame |");
|
|
gsc3280_write(priv, CAN_TXB0, fi);
|
|
}else{
|
|
DBG("data frame |");
|
|
}
|
|
|
|
//if( fi & FI_FF )
|
|
if((id>>24) & FI_FF)
|
|
{
|
|
DBG("extend");
|
|
fi |= FI_FF;
|
|
gsc3280_write (priv, CAN_TXB0, fi);
|
|
DBG("id=0x%x, \n", id<<3);
|
|
gsc3280_write (priv, CAN_TXB1, id<<3);
|
|
}else{
|
|
DBG("standard");
|
|
gsc3280_write (priv, CAN_TXB0, fi);
|
|
DBG("id=0x%x, \n",id);
|
|
gsc3280_write (priv, CAN_TXB1, id<<21);
|
|
}
|
|
|
|
DBG ("ID: %x |", id);
|
|
|
|
if (dlc){
|
|
DBG("dlc = %d \n", dlc);
|
|
DBG("DATA:%x %x %x %x %x %x %x %x", cf->data[0], cf->data[1],cf->data[2],cf->data[3],cf->data[4],cf->data[5],cf->data[6],cf->data[7]);
|
|
|
|
buf1= ((cf->data[3]&0xff)<<24) | ((cf->data[2]&0xff)<<16) | ((cf->data[1]&0xff)<<8) | (cf->data[0]);
|
|
DBG("GSC3280_TXB3 data %x \n",buf1);
|
|
buf2= ((cf->data[7]&0xff)<<24) | ((cf->data[6]&0xff)<<16) | ((cf->data[5]&0xff)<<8) | (cf->data[4]);
|
|
DBG("GSC3280_TXB4 data %x \n",buf2);
|
|
|
|
gsc3280_write ( priv, CAN_TXB2, buf1);
|
|
gsc3280_write ( priv, CAN_TXB3, buf2);
|
|
}
|
|
|
|
can_put_echo_skb ( skb, dev, 0 );
|
|
|
|
while (!(gsc3280_read(priv, CAN_SR) & 0x4)); /*tx fifo ok*/
|
|
spin_lock_irqsave(&priv->cmdreg_lock, flags);
|
|
gsc3280_write(priv, CAN_CMR, CMD_TR);
|
|
spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
|
|
while (!(gsc3280_read(priv, CAN_SR) & 0x8)); /*tx fifo ok*/
|
|
|
|
|
|
#if 0
|
|
printk("REG info: \n");
|
|
printk("REG CAN_ALC: 0x%08x \n", gsc3280_read(priv, CAN_ALC));
|
|
printk("REG CAN_ECC: 0x%08x \n", gsc3280_read(priv, CAN_ECC));
|
|
printk("REG CAN_EWLR: 0x%08x \n", gsc3280_read(priv, CAN_EWLR));
|
|
printk("REG CAN_RXERR: 0x%08x \n", gsc3280_read(priv, CAN_RXERR));
|
|
printk("REG CAN_TXERR: 0x%08x \n", gsc3280_read(priv, CAN_TXERR));
|
|
printk("T over \n");
|
|
#endif
|
|
return NETDEV_TX_OK;
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_rx - gsc3280 can receive routine
|
|
* @dev net device structure
|
|
*/
|
|
static void gsc3280_can_rx ( struct net_device *dev )
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
struct net_device_stats *stats = &dev->stats;
|
|
|
|
struct can_frame *cf;
|
|
struct sk_buff *skb;
|
|
|
|
unsigned long flags;
|
|
unsigned char ff;
|
|
unsigned char fi;
|
|
unsigned char id;
|
|
unsigned char dlc;
|
|
|
|
skb = alloc_can_skb(dev, &cf);
|
|
if ( skb == NULL )
|
|
return;
|
|
|
|
/*struct net_device *dev = dev_id;*/
|
|
|
|
DBG("Enter gsc3280_can_rx\n");
|
|
|
|
ff = gsc3280_read ( priv, CAN_RXB0);
|
|
fi = ff & 0xc0;
|
|
dlc = ff & 0x0F;
|
|
|
|
cf->can_dlc = get_can_dlc(dlc);
|
|
|
|
DBG( "rx: ff is 0x%x,fi is 0x%x,dlc is 0x%x\n", ff, fi, dlc );
|
|
if ( fi & FI_FF ){
|
|
/* extended frame format (EFF) */
|
|
DBG("extend ");
|
|
id = (gsc3280_read (priv, CAN_RXB1)) >> 3;
|
|
}else {
|
|
/* standard frame format (SFF) */
|
|
DBG("standard ");
|
|
id = (gsc3280_read (priv, CAN_RXB1)) >> 21;
|
|
}
|
|
cf->can_id = id;
|
|
DBG("ID: %x |", id);
|
|
|
|
if ( fi & FI_RTR ){
|
|
DBG("remote frame |");
|
|
}else{
|
|
DBG("data frame |");
|
|
}
|
|
|
|
if (dlc){
|
|
cf->data[0] = gsc3280_read ( priv, CAN_RXB2);
|
|
cf->data[1] = (gsc3280_read ( priv, CAN_RXB2))>>8;
|
|
cf->data[2] = (gsc3280_read ( priv, CAN_RXB2))>>16;
|
|
cf->data[3] = (gsc3280_read ( priv, CAN_RXB2))>>24;
|
|
cf->data[4] = gsc3280_read ( priv, CAN_RXB3);
|
|
cf->data[5] = (gsc3280_read ( priv, CAN_RXB3))>>8;
|
|
cf->data[6] = (gsc3280_read ( priv, CAN_RXB3))>>16;
|
|
cf->data[7] = (gsc3280_read ( priv, CAN_RXB3))>>24;
|
|
|
|
DBG("DATA: ");
|
|
DBG("%x", gsc3280_read(priv, CAN_RXB3));
|
|
DBG("%x", gsc3280_read(priv, CAN_RXB2));
|
|
}
|
|
|
|
netif_rx (skb);
|
|
stats->rx_packets++;
|
|
stats->rx_bytes += cf->can_dlc;
|
|
|
|
spin_lock_irqsave(&priv->cmdreg_lock, flags);
|
|
gsc3280_write(priv, CAN_CMR, CMD_RRB);
|
|
spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
|
|
#if 0
|
|
printk("REG info: \n");
|
|
printk("REG CAN_ALC: 0x%08x \n", gsc3280_read(priv, CAN_ALC));
|
|
printk("REG CAN_ECC: 0x%08x \n", gsc3280_read(priv, CAN_ECC));
|
|
printk("REG CAN_EWLR: 0x%08x \n", gsc3280_read(priv, CAN_EWLR));
|
|
printk("REG CAN_RXERR: 0x%08x \n", gsc3280_read(priv, CAN_RXERR));
|
|
printk("REG CAN_TXERR: 0x%08x \n", gsc3280_read(priv, CAN_TXERR));
|
|
printk("R over!\n");
|
|
#endif
|
|
}
|
|
|
|
static int gsc3280_can_err ( struct net_device * dev, u8 isrc, u8 status )
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv (dev);
|
|
struct net_device_stats *stats = &dev->stats;
|
|
|
|
struct can_frame *cf;
|
|
struct sk_buff *skb;
|
|
uint8_t ecc, alc;
|
|
|
|
enum can_state state = priv->can.state;
|
|
|
|
DBG("Enter gsc3280_can_err\n");
|
|
|
|
skb = alloc_can_err_skb ( dev, &cf );
|
|
|
|
if ( skb == NULL )
|
|
return -ENOMEM;
|
|
|
|
if ( isrc & IRQ_DOI )
|
|
{
|
|
/* data overrun interrupt */
|
|
DBG("data overflow interrupt\n" );
|
|
cf->can_id |= CAN_ERR_CRTL;
|
|
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
|
stats->rx_over_errors++;
|
|
stats->rx_errors++;
|
|
/* gsc3280 can controllor used read reg clear bit */
|
|
/* read CAN_IR or set reset mode can clear it */
|
|
}
|
|
|
|
if ( isrc & IRQ_EI ) {
|
|
/* error warning interrupt */
|
|
DBG("error warning interrupt\n");
|
|
|
|
if (status & SR_BS) {
|
|
state = CAN_STATE_BUS_OFF;
|
|
cf->can_id |= CAN_ERR_BUSOFF;
|
|
can_bus_off(dev);
|
|
} else if (status & SR_ES) {
|
|
state = CAN_STATE_ERROR_WARNING;
|
|
} else
|
|
state = CAN_STATE_ERROR_ACTIVE;
|
|
}
|
|
|
|
if (isrc & IRQ_BEI) {
|
|
/* bus error interrupt */
|
|
priv->can.can_stats.bus_error++;
|
|
stats->rx_errors++;
|
|
|
|
ecc = gsc3280_read(priv, CAN_ECC);
|
|
|
|
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
|
|
|
switch (ecc & ECC_MASK) {
|
|
case ECC_BIT:
|
|
cf->data[2] |= CAN_ERR_PROT_BIT;
|
|
break;
|
|
case ECC_FORM:
|
|
cf->data[2] |= CAN_ERR_PROT_FORM;
|
|
break;
|
|
case ECC_STUFF:
|
|
cf->data[2] |= CAN_ERR_PROT_STUFF;
|
|
break;
|
|
default:
|
|
cf->data[2] |= CAN_ERR_PROT_UNSPEC;
|
|
cf->data[3] = ecc & ECC_SEG;
|
|
break;
|
|
}
|
|
/* Error occurred during transmission? */
|
|
if ((ecc & ECC_DIR) == 0)
|
|
cf->data[2] |= CAN_ERR_PROT_TX;
|
|
}
|
|
if ( isrc & IRQ_EPI )
|
|
{
|
|
/* error passive interrupt */
|
|
DBG( "error passive interrupt\n");
|
|
if (status & SR_ES)
|
|
state = CAN_STATE_ERROR_PASSIVE;
|
|
else
|
|
state = CAN_STATE_ERROR_ACTIVE;
|
|
}
|
|
if (isrc & IRQ_ALI) {
|
|
/* arbitration lost interrupt */
|
|
DBG("arbitration lost interrupt\n");
|
|
alc = gsc3280_read(priv, CAN_ALC);
|
|
priv->can.can_stats.arbitration_lost++;
|
|
stats->tx_errors++;
|
|
cf->can_id |= CAN_ERR_LOSTARB;
|
|
cf->data[0] = alc & 0x1f;
|
|
}
|
|
|
|
if (state != priv->can.state && (state == CAN_STATE_ERROR_WARNING ||
|
|
state == CAN_STATE_ERROR_PASSIVE)) {
|
|
uint8_t rxerr = gsc3280_read(priv, CAN_RXERR);
|
|
uint8_t txerr = gsc3280_read(priv, CAN_TXERR);
|
|
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;
|
|
}
|
|
cf->data[6] = txerr;
|
|
cf->data[7] = rxerr;
|
|
}
|
|
|
|
priv->can.state = state;
|
|
|
|
netif_rx ( skb );
|
|
|
|
stats->rx_packets++;
|
|
stats->rx_bytes += cf->can_dlc;
|
|
|
|
return 0;
|
|
}
|
|
|
|
irqreturn_t gsc3280_can_interrupt ( int irq, void * dev_id )
|
|
{
|
|
struct net_device *dev = dev_id;
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
struct net_device_stats *stats = &dev->stats;
|
|
|
|
uint8_t status, isrc;
|
|
|
|
/* Shared interrupts and IRQ off? */
|
|
if (gsc3280_read(priv, CAN_IER) == IRQ_OFF)
|
|
return IRQ_NONE;
|
|
|
|
if (priv->pre_irq)
|
|
priv->pre_irq(priv);
|
|
|
|
while ((isrc = gsc3280_read(priv, CAN_IR)))
|
|
{
|
|
status = gsc3280_read( priv, CAN_SR);
|
|
|
|
if(isrc & IRQ_TI ){
|
|
/*trammiter interrupt*/
|
|
DBG("Enter gsc3280_can_interrupt tx\n");
|
|
stats->tx_bytes += gsc3280_read (priv, CAN_TXB0)&0xf;
|
|
stats->tx_packets++;
|
|
|
|
can_get_echo_skb ( dev, 0 );
|
|
netif_wake_queue ( dev );
|
|
}
|
|
if( isrc & IRQ_RI ){
|
|
/*receive interrupt*/
|
|
DBG("Enter gsc3280_can_interrupt rx\n");
|
|
while (status & SR_RBS) {
|
|
gsc3280_can_rx ( dev );
|
|
status = gsc3280_read(priv, CAN_SR);
|
|
}
|
|
}
|
|
if (isrc & IRQ_WUI){
|
|
DBG("wakeup interrupt\n");
|
|
}
|
|
if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
|
|
/* error interrupt */
|
|
if (gsc3280_can_err(dev, isrc, status))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (priv->post_irq)
|
|
priv->post_irq(priv);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_open - gsc3280 can open routine
|
|
* @dev net device structure
|
|
*/
|
|
static int gsc3280_can_open ( struct net_device *dev )
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
int err;
|
|
|
|
DBG(" gsc3280_can_open \n");
|
|
|
|
gsc3280_can_set_reset_mode(dev);
|
|
|
|
err = open_candev(dev);
|
|
if(err)
|
|
goto exit_open;
|
|
|
|
err = request_irq(priv->irq, &gsc3280_can_interrupt, 0, "gsc3280-can-irq" , dev);
|
|
if(err)
|
|
goto exit_err_irq;
|
|
|
|
/*this must set in reset mode*/
|
|
// gsc3280_write(priv, CAN_ACR, 0x100);
|
|
// gsc3280_write(priv, CAN_AMR, 0xffffffff);
|
|
|
|
gsc3280_can_start(dev);
|
|
priv->open_time = jiffies;
|
|
|
|
netif_start_queue (dev);
|
|
|
|
return 0;
|
|
|
|
exit_err_irq:
|
|
close_candev(dev);
|
|
free_irq(priv->irq,dev);
|
|
|
|
exit_open:
|
|
return err;
|
|
}
|
|
|
|
static int gsc3280_can_close ( struct net_device *dev )
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
|
|
DBG("Enter gsc3280_can_close\n");
|
|
|
|
netif_stop_queue (dev);
|
|
gsc3280_can_set_reset_mode(dev);
|
|
|
|
close_candev(dev);
|
|
free_irq(priv->irq,dev);
|
|
|
|
priv->open_time = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gsc3280_can_set_mode(struct net_device *dev, enum can_mode mode)
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
|
|
if (!priv->open_time)
|
|
return -EINVAL;
|
|
|
|
switch (mode) {
|
|
case CAN_MODE_START:
|
|
gsc3280_can_start(dev);
|
|
if (netif_queue_stopped(dev))
|
|
netif_wake_queue(dev);
|
|
break;
|
|
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct net_device *alloc_gsc3280_candev(void)
|
|
{
|
|
struct net_device *dev;
|
|
struct gsc3280_priv *priv;
|
|
|
|
dev = alloc_candev ( sizeof(*priv), TX_ECHO_SKB_MAX);
|
|
|
|
DBG("alloc_gsc3280_candev,dev is 0x%x, dev->dev is 0x%x\n", dev, dev->dev);
|
|
|
|
if ( !dev)
|
|
return NULL;
|
|
|
|
priv = netdev_priv (dev);
|
|
priv->dev = dev;
|
|
priv->can.bittiming_const = &gsc3280_can_bittiming_const;
|
|
priv->can.do_set_bittiming = gsc3280_can_set_bittiming;
|
|
//priv->can.do_set_mode = gsc3280_can_set_mode;
|
|
priv->can.do_set_mode = gsc3280_can_set_reset_mode;
|
|
priv->can.do_get_berr_counter = gsc3280_can_get_berr_counter;
|
|
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
|
|
|
|
spin_lock_init(&priv->cmdreg_lock);
|
|
|
|
return dev;
|
|
}
|
|
|
|
static const struct net_device_ops gsc3280_can_netdev_ops = {
|
|
.ndo_open = gsc3280_can_open,
|
|
.ndo_stop = gsc3280_can_close,
|
|
.ndo_start_xmit = gsc3280_can_start_xmit,
|
|
};
|
|
|
|
static int __devinit gsc3280_can_probe (struct platform_device *pdev)
|
|
{
|
|
struct net_device *dev;
|
|
struct gsc3280_priv *priv;
|
|
struct resource *res_mem, *irq;
|
|
struct clk *clk;
|
|
unsigned long rate;
|
|
unsigned short *pdata;
|
|
int err;
|
|
|
|
//void __iomem *addr;
|
|
|
|
//SYSCTL_CLK_DIV_CAN;
|
|
*(volatile unsigned int *)0xbc04a030 = 0x1; // rate=55.6M/2
|
|
//__raw_writel( 0x1 , 0xbc04a030); // rate=55.6M/2
|
|
//__raw_writel( 0x9 , 0xbc04a030); // rate=55.6M/10
|
|
//__raw_writel( 0x1f , 0xbc04a030); // rate=55.6M/32
|
|
|
|
clk = clk_get ( &pdev->dev , "can" );
|
|
rate = clk_get_rate ( clk );
|
|
|
|
clk_set_rate(clk, rate);
|
|
|
|
if ( IS_ERR(clk)){
|
|
DBG("no clock defined\n");
|
|
err = -ENODEV;
|
|
goto exit;
|
|
}
|
|
|
|
pdata = pdev->dev.platform_data;
|
|
|
|
if(!pdata){
|
|
DBG("No platform data provided!\n");
|
|
err = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
res_mem = platform_get_resource (pdev, IORESOURCE_MEM, 0);
|
|
irq = platform_get_resource (pdev, IORESOURCE_IRQ, 0);
|
|
|
|
DBG("res_mem is 0x%x, irq is %d\n", res_mem->start, irq->start);
|
|
|
|
/* if ( !res_mem || irq<0 || !tx_irq || !rx_irq ){
|
|
err = -ENODEV;
|
|
goto exit;
|
|
}
|
|
*/
|
|
if (!request_mem_region( res_mem->start , resource_size(res_mem), dev_name(&pdev->dev) )){
|
|
printk("request_mem_region is null\n");
|
|
err = -ENOMEM;
|
|
goto exit_release;
|
|
}
|
|
|
|
dev = alloc_gsc3280_candev();
|
|
if (!dev){
|
|
err = -ENOMEM;
|
|
goto exit_iounmap;
|
|
}
|
|
|
|
priv = netdev_priv (dev);
|
|
priv->can.clock.freq = rate;
|
|
priv->can.bittiming_const = &gsc3280_can_bittiming_const;
|
|
priv->can.do_set_bittiming = gsc3280_can_set_bittiming;
|
|
priv->can.do_get_berr_counter = gsc3280_can_get_berr_counter;
|
|
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
|
|
priv->dev = dev;
|
|
priv->reg_base = (void __iomem*) (res_mem->start);
|
|
|
|
/* DBG("priv->reg_base is 0x%x\n", priv->reg_base);*/
|
|
|
|
priv->irq = irq->start;
|
|
priv->pin_list = pdata;
|
|
|
|
DBG("priv_irq is %d\n", priv->irq);
|
|
|
|
dev_set_drvdata(&pdev->dev, dev);
|
|
SET_NETDEV_DEV(dev, &pdev->dev);
|
|
|
|
dev->netdev_ops = &gsc3280_can_netdev_ops;
|
|
dev->flags |= IFF_ECHO;
|
|
|
|
gsc3280_can_set_reset_mode(dev);
|
|
gsc3280_can_set_bittiming(dev);
|
|
|
|
err = register_candev(dev);
|
|
if(err){
|
|
DBG("registering netdev failed\n");
|
|
goto exit_free;
|
|
}
|
|
|
|
DBG("device registered (reg_base=0x%x,irq=%d)\n", priv->reg_base, priv->irq);
|
|
|
|
return 0;
|
|
|
|
exit_free:
|
|
free_candev(dev);
|
|
|
|
exit_iounmap:
|
|
// iounmap(addr);
|
|
|
|
exit_release:
|
|
release_mem_region ( res_mem->start, resource_size(res_mem));
|
|
|
|
exit:
|
|
return err;
|
|
|
|
}
|
|
|
|
static int __devexit gsc3280_can_remove ( struct platform_device *pdev )
|
|
{
|
|
struct net_device *dev = dev_get_drvdata ( &pdev->dev );
|
|
/* struct gsc3280_priv *priv = netdev_priv (dev);*/
|
|
struct resource *res;
|
|
|
|
gsc3280_can_set_reset_mode(dev);
|
|
|
|
unregister_candev(dev);
|
|
|
|
dev_set_drvdata(&pdev->dev, NULL);
|
|
|
|
res = platform_get_resource ( pdev, IORESOURCE_MEM, 0 );
|
|
release_mem_region (res->start, resource_size(res));
|
|
|
|
free_candev(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct platform_device_id gsc3280_can_id_table[] = {
|
|
{
|
|
.name = "gsc3280_can_driver",
|
|
.driver_data = BLX_DEVTYPE_GSC3280,
|
|
},{
|
|
}
|
|
};
|
|
|
|
static struct platform_driver gsc3280_can_driver = {
|
|
.probe = gsc3280_can_probe,
|
|
.remove = __devexit_p ( gsc3280_can_remove ),
|
|
.driver = {
|
|
.name = KBUILD_MODNAME,
|
|
.owner = THIS_MODULE,
|
|
},
|
|
.id_table = gsc3280_can_id_table,
|
|
};
|
|
|
|
static int __init gsc3280_can_module_init (void)
|
|
{
|
|
printk("gsc3280_can_init\n");
|
|
return platform_driver_register (&gsc3280_can_driver);
|
|
}
|
|
|
|
static void __exit gsc3280_can_module_exit (void)
|
|
{
|
|
platform_driver_unregister(&gsc3280_can_driver);
|
|
}
|
|
|
|
module_init(gsc3280_can_module_init);
|
|
module_exit(gsc3280_can_module_exit);
|
|
|
|
MODULE_AUTHOR("Merlin Song <songxingjia@china-cpu.com>");
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION(KBUILD_MODNAME " CAN netdevice driver");
|