856 lines
22 KiB
Plaintext
856 lines
22 KiB
Plaintext
/*
|
|
* GSC3280 SoC CAN controller Controller Driver
|
|
*
|
|
* Copyright (C) 2013 BLX IC Design Corp.,Ltd.
|
|
* Author: Clive Chen, chenguangyu@china-cpu.com
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
*/
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/cpu.h>
|
|
#include <asm/cpu.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/if_arp.h>
|
|
#include <linux/init.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/module.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/string.h>
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/bitops.h>
|
|
|
|
#include <linux/can/dev.h>
|
|
#include <linux/can/error.h>
|
|
|
|
#include "gsc3280_can.h"
|
|
|
|
/****************gsc3280 can module register enum************************/
|
|
enum gsc3280_reg {
|
|
GSC3280_MOD = 0x000,
|
|
GSC3280_CMR = 0x004,
|
|
GSC3280_SR = 0x008,
|
|
GSC3280_IR = 0x00C,
|
|
GSC3280_IER = 0x010,
|
|
GSC3280_BTR = 0x014,
|
|
GSC3280_ALC = 0x018,
|
|
GSC3280_ECC = 0x01C,
|
|
GSC3280_EWLR = 0x020,
|
|
GSC3280_RXERR = 0x024,
|
|
|
|
GSC3280_TXERR = 0x028,
|
|
GSC3280_RMC = 0x02C, /*there is a error in datasheet */
|
|
|
|
GSC3280_ACR = 0x080,
|
|
GSC3280_AMR = 0x084,
|
|
|
|
GSC3280_TXB1 = 0x080,
|
|
GSC3280_TXB2 = 0x084,
|
|
GSC3280_TXB3 = 0x088,
|
|
GSC3280_TXB4 = 0x08C,
|
|
|
|
|
|
GSC3280_RXB1 = 0x080,
|
|
GSC3280_RXB2 = 0x084,
|
|
GSC3280_RXB3 = 0x088,
|
|
GSC3280_RXB4 = 0x08C,
|
|
};
|
|
|
|
enum BLX_devtype {
|
|
BLX_DEVTYPE_GSC3280,
|
|
};
|
|
|
|
/* no need to be used in this file*/
|
|
struct BLX_devtype_data {
|
|
unsigned int rx_first;
|
|
unsigned int rx_split;
|
|
unsigned int rx_last;
|
|
unsigned int tx_shift;
|
|
enum BLX_devtype type;
|
|
};
|
|
|
|
struct gsc3280_priv{
|
|
struct can_priv can; /*must be the first member!*/
|
|
struct net_device *dev;
|
|
void __iomem *reg_base;
|
|
|
|
u32 reg_sr;
|
|
int irq;
|
|
unsigned short *pin_list;
|
|
};
|
|
|
|
|
|
|
|
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));
|
|
}
|
|
|
|
#define DRV_NAME "gsc3280_can"
|
|
|
|
static struct can_bittiming gsc3280_can_bittiming = {
|
|
|
|
.bitrate = 500000, /* Bit-rate in bits/second */
|
|
.sample_point = 2, /* Sample point in one-tenth of a percent */
|
|
.tq = 50, /* Time quanta (TQ) in nanoseconds */
|
|
.prop_seg = 1, /* Propagation segment in TQs */
|
|
.phase_seg1 = 4, /* Phase buffer segment 1 in TQs */
|
|
.phase_seg2 = 5, /* Phase buffer segment 2 in TQs */
|
|
.sjw = 4, /* Synchronisation jump width in TQs */
|
|
.brp = 4, /* Bit-rate prescaler */
|
|
|
|
};
|
|
|
|
/***** according the set of datasheet*****/
|
|
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_print_regs - gsc3280 debug routine
|
|
* @if need debug the can registers, uncomment of content of routine
|
|
*/
|
|
static void gsc3280_print_regs( void )
|
|
{
|
|
/* int i=0;
|
|
unsigned int *cc;
|
|
|
|
cc = (unsigned int *)0xbc100000;
|
|
for ( i = 0; i<10; i++)
|
|
{
|
|
printk("cc: %x, %x\n",cc, *cc);
|
|
cc=cc+1;
|
|
}
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_set_normal_mod - gsc3280 can set normal mode routine
|
|
* @dev net device structure
|
|
* @mode gsc3280 can mode
|
|
*/
|
|
static void gsc3280_can_set_normal_mod (struct net_device *dev, int mode)
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
int i;
|
|
u32 status = gsc3280_read ( priv, GSC3280_MOD );
|
|
|
|
/*printk("Enter gsc3280_can_set_normal_mod, reg_base is %x\n", priv->reg_base);*/
|
|
|
|
for ( i = 0; i < 100; i++){
|
|
if (( status & MOD_RM) == 0 || ( status&( MOD_SM | MOD_STM | MOD_LOM))){
|
|
gsc3280_write(priv, GSC3280_IER, IRQ_ALL);
|
|
|
|
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
|
|
|
return;
|
|
}
|
|
gsc3280_write (priv, GSC3280_MOD, mode);
|
|
udelay(10);
|
|
status = gsc3280_read ( priv, GSC3280_MOD);
|
|
printk(KERN_INFO "normal_mod status is 0x%x, mode is 0x%x\n", status, mode);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_set_reset_mod - gsc3280 can set reset mode routine
|
|
* @dev net device structure
|
|
*/
|
|
static void gsc3280_can_set_reset_mod ( struct net_device *dev )
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
int i;
|
|
unsigned char status = gsc3280_read ( priv, GSC3280_MOD ) & 0xff;
|
|
|
|
printk( "status 1 is 0x%x, GSC3280_IER 0x%2x,IRQ_OFF 0x%2x\n", status, GSC3280_IER, IRQ_OFF);
|
|
|
|
gsc3280_write ( priv, GSC3280_IER, IRQ_OFF);
|
|
|
|
for ( i=0; i<100; i++)
|
|
{
|
|
if ( status & MOD_RM){
|
|
|
|
priv->can.state = CAN_STATE_STOPPED;
|
|
|
|
return;
|
|
}
|
|
gsc3280_write ( priv, GSC3280_MOD, MOD_RM);
|
|
status = gsc3280_read(priv, GSC3280_MOD);
|
|
printk(KERN_INFO "status 2 is 0x%x\n", status);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_start - gsc3280 can start routine
|
|
* @dev net device structure
|
|
* @mode gsc3280 can mode
|
|
*/
|
|
static void gsc3280_can_start (struct net_device *dev, int mode)
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
|
|
gsc3280_write ( priv, GSC3280_TXERR, 0x0 );
|
|
gsc3280_write ( priv, GSC3280_RXERR, 0x0 );
|
|
|
|
gsc3280_can_set_normal_mod(dev, mode);
|
|
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_set_bittimg - 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;
|
|
int fxtal;
|
|
unsigned int btr;
|
|
u8 btr0, btr1;
|
|
|
|
fxtal = priv->can.clock.freq;
|
|
|
|
printk(KERN_INFO "Enter gsc3280_can_set_bittiming\n");
|
|
|
|
/* btr = (bt->sample_point << 15) | ((bt->phase_seg2 - 1) << 12 ) | (bt->phase_seg1 - 1 ) << 8 | (( bt->sjw - 1 ) << 6 ) | ( bt->brp - 1 );*/
|
|
|
|
btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
|
|
btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
|
|
(((bt->phase_seg2 - 1) & 0x7) << 4);
|
|
/* if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) */
|
|
if (bt->bitrate < 250000 )
|
|
btr1 |= 0x80;
|
|
|
|
btr = (btr1<<8) | btr0;
|
|
|
|
printk (KERN_INFO " btr0 is 0x%02x, btr1 is 0x%02x, btr = 0x%x\n", btr0, btr1, btr );
|
|
gsc3280_write ( priv, GSC3280_BTR, btr );
|
|
|
|
/* dev_info(dev->dev.parent, "setting brp=0x%04x\n",btr); */
|
|
|
|
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 ff;
|
|
uint8_t fi;
|
|
uint8_t dlc;
|
|
canid_t id;
|
|
|
|
|
|
printk("Enter gsc3280_can_start_xmit\n");
|
|
|
|
if (can_dropped_invalid_skb(dev, skb))
|
|
return NETDEV_TX_OK;
|
|
|
|
netif_stop_queue(dev);
|
|
|
|
|
|
/*need to be changed ff and canid_id*/
|
|
|
|
|
|
fi = dlc = cf->can_dlc;
|
|
id = cf->can_id;
|
|
ff = cf->can_id & 0xff;
|
|
|
|
printk(KERN_INFO "tx :");
|
|
|
|
if( fi & FI_FF )
|
|
{
|
|
printk (KERN_INFO "extend" );
|
|
ff |= FI_FF;
|
|
gsc3280_write (priv, GSC3280_TXB1, ff);
|
|
gsc3280_write (priv, GSC3280_TXB2, id<<3);
|
|
}else
|
|
{
|
|
printk (KERN_INFO "standard");
|
|
gsc3280_write (priv,GSC3280_TXB1, ff);
|
|
gsc3280_write (priv,GSC3280_TXB2, id<<20);
|
|
}
|
|
|
|
if(fi & FI_RTR){
|
|
ff |= FI_RTR;
|
|
printk("remote frame |");
|
|
}else{
|
|
printk("data frame |");
|
|
}
|
|
|
|
printk (KERN_INFO "ID: %x |", id);
|
|
|
|
if (dlc){
|
|
printk(KERN_INFO "DATA:%x %x", cf->data[0], cf->data[1]);
|
|
gsc3280_write ( priv, GSC3280_TXB3, cf->data[0]);
|
|
gsc3280_write ( priv, GSC3280_TXB4, cf->data[1]);
|
|
}
|
|
|
|
can_put_echo_skb ( skb, dev, 0 );
|
|
|
|
while (!(gsc3280_read(priv, GSC3280_SR) & 0x4)); /*tx fifo ok*/
|
|
gsc3280_write(priv, GSC3280_CMR, CMD_TR);
|
|
|
|
|
|
while (!(gsc3280_read(priv, GSC3280_SR) & 0x8)); /*tx fifo ok*/
|
|
|
|
printk("tok \n");
|
|
|
|
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;
|
|
/*void __iomem *reg = priv->reg_base;*/
|
|
|
|
struct can_frame *cf;
|
|
struct sk_buff *skb;
|
|
|
|
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;*/
|
|
|
|
printk("Enter gsc3280_can_rx\n");
|
|
|
|
ff = gsc3280_read ( priv, GSC3280_RXB1 );
|
|
fi = ff & 0xc0;
|
|
dlc = ff & 0x0F;
|
|
|
|
/* cf->can_id = fi;*/
|
|
cf->can_dlc = get_can_dlc(dlc);
|
|
|
|
printk ( "rx: ff is 0x%x,fi is 0x%x,dlc is 0x%x\n", ff, fi, dlc );
|
|
if ( fi & FI_FF ){
|
|
printk (KERN_INFO "extend ");
|
|
id = (gsc3280_read (priv, GSC3280_RXB2)) >> 3;
|
|
}else {
|
|
printk (KERN_INFO "standard ");
|
|
id = (gsc3280_read (priv, GSC3280_RXB2)) >> 21;
|
|
}
|
|
|
|
if ( fi & FI_RTR ){
|
|
printk("remote frame |");
|
|
}else{
|
|
printk("data frame |");
|
|
}
|
|
|
|
printk(KERN_INFO "ID: %x |", id);
|
|
|
|
if (dlc){
|
|
|
|
cf->data[0] = gsc3280_read ( priv, GSC3280_RXB4);
|
|
cf->data[1] = gsc3280_read ( priv, GSC3280_RXB3);
|
|
|
|
printk(KERN_INFO "DATA: ");
|
|
printk("%x", gsc3280_read(priv, GSC3280_RXB4));
|
|
printk("%x", gsc3280_read(priv, GSC3280_RXB3));
|
|
}
|
|
|
|
netif_rx (skb);
|
|
stats->rx_packets++;
|
|
stats->rx_bytes += cf->can_dlc;
|
|
|
|
gsc3280_write(priv, GSC3280_CMR, CMD_RRB);
|
|
|
|
printk("ok!\n");
|
|
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_err - can controller errors handle funciton
|
|
* @dev: netdevice structure
|
|
* @isrc: error code
|
|
* @status: status info
|
|
*/
|
|
static int gsc3280_can_err ( struct net_device * dev, u16 isrc, u16 status )
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv (dev);
|
|
struct net_device_stats *stats = &dev->stats;
|
|
|
|
struct can_frame *cf;
|
|
struct sk_buff *skb;
|
|
|
|
enum can_state state = priv->can.state;
|
|
|
|
printk("Enter gsc3280_can_err\n");
|
|
|
|
skb = alloc_can_err_skb ( dev, &cf );
|
|
|
|
if ( skb == NULL )
|
|
return -ENOMEM;
|
|
|
|
if ( isrc & IRQ_BEI ){ /* check bus error*/
|
|
dev_dbg(dev->dev.parent, "catched bus error\n" );
|
|
}
|
|
/* if ( isrc & ALI )
|
|
{
|
|
dev_dbg(dev->dev.parent, "lost arbiter, become receiver\n" );
|
|
}
|
|
*/ if ( isrc & IRQ_EPI )
|
|
{
|
|
dev_dbg(dev->dev.parent, "reached error passive state or changed to error activity state\n" );
|
|
state = CAN_STATE_ERROR_PASSIVE;
|
|
}
|
|
if ( isrc & IRQ_DOI )
|
|
{
|
|
dev_dbg(dev->dev.parent, "data overflow,\n" );
|
|
cf->can_id |= CAN_ERR_CRTL;
|
|
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
|
stats->rx_over_errors++;
|
|
stats->rx_errors++;
|
|
}
|
|
if ( (isrc & IRQ_TI) || (isrc & IRQ_RI) )
|
|
{
|
|
dev_dbg(dev->dev.parent, "Error Warning Transmit/Receive Interrupt\n" );
|
|
state = CAN_STATE_ERROR_WARNING;
|
|
}
|
|
|
|
if ( state != priv->can.state && ( state == CAN_STATE_ERROR_WARNING || state == CAN_STATE_ERROR_PASSIVE ))
|
|
{
|
|
cf->can_id |= CAN_ERR_CRTL;
|
|
if ( state == CAN_STATE_ERROR_WARNING ){
|
|
priv->can.can_stats.error_warning++;
|
|
/*inter error frame*/
|
|
}else{
|
|
priv->can.can_stats.error_passive++;
|
|
/* inter error frame*/
|
|
}
|
|
|
|
}
|
|
|
|
if ( status ){
|
|
priv->can.can_stats.bus_error++;
|
|
|
|
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
|
|
|
/*inter serveral states*/
|
|
|
|
}
|
|
|
|
priv->can.state = state;
|
|
|
|
netif_rx ( skb );
|
|
|
|
stats->rx_packets++;
|
|
stats->rx_bytes += cf->can_dlc;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
static int gsc3280_can_suspend (struct platform_device *pdev, pm_message_t mesg)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int gsc3280_can_resume ( struct platform_device *pdev )
|
|
{
|
|
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);
|
|
/* void __iomem *reg = priv->reg_base;*/
|
|
struct net_device_stats *stats = &dev->stats;
|
|
u16 status,status1, isrc;
|
|
|
|
/* unsigned char ff;
|
|
unsigned char fi;
|
|
unsigned char id;
|
|
unsigned char dlc;
|
|
|
|
printk("Enter gsc3280_can_interrupt\n");
|
|
*/
|
|
status = gsc3280_read( priv, GSC3280_IR);
|
|
status1 = gsc3280_read( priv, IRQ_ALL );
|
|
printk( "Enter interrupt status is 0x%x, status1 is 0x%x, irq is 0x%d\n", status,status1, irq);
|
|
/* gsc3280_can_rx ( dev ); */
|
|
|
|
if(status & 0x02 )
|
|
{ /*trammiter interrupt*/
|
|
stats->tx_packets++;
|
|
printk("Enter gsc3280_can_interrupt tx\n");
|
|
stats->tx_bytes += gsc3280_read (priv, GSC3280_TXB1)&0xf;
|
|
|
|
can_get_echo_skb ( dev, 0 );
|
|
netif_wake_queue ( dev );
|
|
|
|
/* gsc3280_can_start_xmit(skb, dev);*/
|
|
}else if(( status & 0x1 ))
|
|
{ /*receive interrupt*/
|
|
|
|
printk("Enter gsc3280_can_interrupt rx\n");
|
|
gsc3280_can_rx ( dev );
|
|
|
|
}else if(( status & ~0x3 ))
|
|
{
|
|
|
|
printk("Enter gsc3280_can_interrupt err\n");
|
|
gsc3280_print_regs();
|
|
gsc3280_can_err ( dev, isrc, status );
|
|
}else
|
|
{
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
|
|
extern void blx_timer_init( int mode, unsigned long count);
|
|
extern void gsc3280_request_timer( int mode, int count, void(*fn)(unsigned long));
|
|
extern void gsc3280_watchdog_init(char wdt_cr, char top);
|
|
|
|
|
|
/*
|
|
* 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;
|
|
int mode;
|
|
/* struct can_frame *cf;*/
|
|
|
|
printk(" gsc3280_can_open \n");
|
|
|
|
|
|
gsc3280_print_regs();
|
|
|
|
gsc3280_can_set_reset_mod(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_rx_irq;
|
|
|
|
mode = 0x8; /*set MOD register to normal mode*/
|
|
|
|
printk("before gsc3280_can_start\n");
|
|
/*this must set in reset mode*/
|
|
gsc3280_write(priv, GSC3280_ACR, 0x100);
|
|
gsc3280_write(priv, GSC3280_AMR, 0xffffffff);
|
|
|
|
|
|
gsc3280_can_start(dev, mode);
|
|
|
|
netif_start_queue (dev);
|
|
|
|
return 0;
|
|
|
|
exit_rx_irq:
|
|
free_irq(priv->irq, dev);
|
|
/*
|
|
exit_tx_irq:
|
|
free_irq(priv->irq,dev);
|
|
|
|
exit_err_irq:
|
|
close_candev(dev);
|
|
*/
|
|
exit_open:
|
|
return err;
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_close - gsc3280 can close routine
|
|
* @dev net device structure
|
|
*/
|
|
static int gsc3280_can_close ( struct net_device *dev )
|
|
{
|
|
struct gsc3280_priv *priv = netdev_priv(dev);
|
|
|
|
printk("Enter gsc3280_can_close\n");
|
|
|
|
netif_stop_queue (dev);
|
|
gsc3280_can_set_reset_mod (dev);
|
|
|
|
close_candev(dev);
|
|
|
|
free_irq(priv->irq,dev);
|
|
/* free_irq(priv->tx_irq,dev);
|
|
free_irq(priv->err_irq,dev);
|
|
*/
|
|
return 0;
|
|
}
|
|
|
|
#define TX_ECHO_SKB_MAX 1
|
|
|
|
struct net_device *alloc_gsc3280_candev(void)
|
|
{
|
|
struct net_device *dev;
|
|
struct gsc3280_priv *priv;
|
|
|
|
dev = alloc_candev ( sizeof(*priv), TX_ECHO_SKB_MAX);
|
|
|
|
/*printk("cc alloc_gsc3280_candev 1,dev is 0x%x, dev->dev is 0x%x\n", dev, dev->dev);*/
|
|
|
|
if ( !dev)
|
|
return NULL;
|
|
|
|
printk("cc alloc_gsc3280_candev 2\n");
|
|
|
|
|
|
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_reset_mod;
|
|
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
|
|
|
|
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;
|
|
|
|
gsc3280_print_regs();
|
|
|
|
clk = clk_get ( &pdev->dev , "can" );
|
|
rate = clk_get_rate ( clk );
|
|
|
|
/*test for 55.6M/2*/
|
|
rate = 27777777;
|
|
clk_set_rate(clk, rate);
|
|
|
|
|
|
if ( IS_ERR(clk)){
|
|
dev_err(&pdev->dev, "no clock defined\n");
|
|
err = -ENODEV;
|
|
goto exit;
|
|
}
|
|
|
|
pdata = pdev->dev.platform_data;
|
|
|
|
printk("Enter can model 2\n");
|
|
|
|
if(!pdata){
|
|
dev_err (&pdev->dev, "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);
|
|
|
|
printk("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 = gsc3280_can_bittiming;
|
|
/* priv->can.do_get_berr_counter = gsc3280_get_berr_counter;*/
|
|
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
|
|
priv->dev = dev;
|
|
priv->reg_base = (void __iomem*) (res_mem->start);
|
|
|
|
|
|
/* printk("priv->reg_base is 0x%x\n", priv->reg_base);*/
|
|
|
|
priv->irq = irq->start;
|
|
priv->pin_list = pdata;
|
|
|
|
printk("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;
|
|
|
|
|
|
/*printk(KERN_INFO " 1before can_reset_mod, %x, %x\n", __raw_readl(0xbc04a008), __raw_readl(0xbc04a0b0));*/
|
|
|
|
__raw_writel(( __raw_readl(0xbc04a008)| 0x4) , 0xbc04a008);
|
|
|
|
/*printk(KERN_INFO " 2before can_reset_mod, %x, %x\n", __raw_readl(0xbc04a008), __raw_readl(0xbc04a0b0));*/
|
|
|
|
gsc3280_can_set_reset_mod (dev);
|
|
|
|
gsc3280_can_set_bittiming (dev);
|
|
|
|
printk(" after can_reset_mod\n");
|
|
|
|
err = register_candev(dev);
|
|
|
|
if(err){
|
|
dev_err(&pdev->dev, "registering netdev failed\n");
|
|
goto exit_free;
|
|
}
|
|
|
|
dev_info(&pdev->dev, "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_put:
|
|
clk_put(clk);*/
|
|
|
|
|
|
exit:
|
|
return err;
|
|
|
|
}
|
|
|
|
/*
|
|
* gsc3280_can_remove - gsc3280 can remove routine
|
|
* @pdev platform device structure
|
|
*/
|
|
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_mod(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));
|
|
|
|
/* peripheral_free_list(priv->pin_list);*/
|
|
|
|
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);
|
|
|