sja1000芯片can驱动程序

应用层使用socketCan的方法:http://pan.baidu.com/s/1ntsvbb7

功能:对can驱动程序的函数直接调用,而不经过设备驱动功能层、网络设备接口层、网络协议接口层

      像串口驱动程序调用can驱动程序函数时,首先要调用

  

mytscan1_probe&m_ppriv);
mysja1000_set_bittiming&m_ppriv);
mysja1000_open&m_ppriv);    

这些函数,实现结构体的初始化以及相关寄存器的初始化操作。

调用 netdev_tx_t mysja1000_start_xmitstruct can_frame *cf,struct sja1000_priv *priv) 进行数据的发送。

调用 mysja1000_close)函数进行寄存器及中断的关闭操作

样例:

#include "mycan_drive.h"
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/ratelimit.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
#include <linux/nmi.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>

#include <asm/io.h>

#include <asm/serial.h>



static const struct can_bittiming_const mysja1000_bittiming_const = {
    .name = "",
    .tseg1_min = 1,
    .tseg1_max = 16,
    .tseg2_min = 1,
    .tseg2_max = 8,
    .sjw_max = 4,
    .brp_min = 1,
    .brp_max = 64,
    .brp_inc = 1,
};



struct sja1000_priv m_ppriv;


extern struct uart_8250_port canserial_ports[15];



static int can_update_sptconst struct can_bittiming_const *btc,
              int sampl_pt, int tseg, int *tseg1, int *tseg2)
{
    *tseg2 = tseg + 1 - sampl_pt * tseg + 1)) / 1000;
    if *tseg2 < btc->tseg2_min)
        *tseg2 = btc->tseg2_min;
    if *tseg2 > btc->tseg2_max)
        *tseg2 = btc->tseg2_max;
    *tseg1 = tseg - *tseg2;
    if *tseg1 > btc->tseg1_max) {
        *tseg1 = btc->tseg1_max;
        *tseg2 = tseg - *tseg1;
    }
    return 1000 * tseg + 1 - *tseg2) / tseg + 1);
}



static int can_calc_bittimingstruct can_priv *priv, struct can_bittiming *bt,
                  const struct can_bittiming_const *btc)
{

    printk"Enter can_calc_bittiming
");

    long best_error = 1000000000, error = 0;
    int best_tseg = 0, best_brp = 0, brp = 0;
    int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
    int spt_error = 1000, spt = 0, sampl_pt;
    long rate;
    u64 v64;

    bt->bitrate = 1000000;
    /* Use CiA recommended sample points */
    if bt->sample_point) {
        sampl_pt = bt->sample_point;
    } else {
        if bt->bitrate > 800000)
            sampl_pt = 750;
        else if bt->bitrate > 500000)
            sampl_pt = 800;
        else
            sampl_pt = 875;
    }

    /* tseg even = round down, odd = round up */
    for tseg = btc->tseg1_max + btc->tseg2_max) * 2 + 1;
         tseg >= btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
        tsegall = 1 + tseg / 2;
        /* Compute all possible tseg choices tseg=tseg1+tseg2) */
        brp = priv->clock.freq / tsegall * bt->bitrate) + tseg % 2;
        /* chose brp step which is possible in system */
        brp = brp / btc->brp_inc) * btc->brp_inc;
        if brp < btc->brp_min) || brp > btc->brp_max))
            continue;
        rate = priv->clock.freq / brp * tsegall);
        error = bt->bitrate - rate;
        /* tseg brp biterror */
        if error < 0)
            error = -error;
        if error > best_error)
            continue;
        best_error = error;
        if error == 0) {
            spt = can_update_sptbtc, sampl_pt, tseg / 2,
                         &tseg1, &tseg2);
            error = sampl_pt - spt;
            if error < 0)
                error = -error;
            if error > spt_error)
                continue;
            spt_error = error;
        }
        best_tseg = tseg / 2;
        best_brp = brp;
        if error == 0)
            break;
    }

    // if best_error) {
    //     /* Error in one-tenth of a percent */
    //     error = best_error * 1000) / bt->bitrate;
    //     if error > CAN_CALC_MAX_ERROR) {
    //         // netdev_errdev,
    //         //        "bitrate error %ld.%ld%% too high
",
    //         //        error / 10, error % 10);
    //         return -EDOM;
    //     } else {
    //         // netdev_warndev, "bitrate error %ld.%ld%%
",
    //         //         error / 10, error % 10);
    //     }
    // }

    /* real sample point */
    bt->sample_point = can_update_sptbtc, sampl_pt, best_tseg,
                      &tseg1, &tseg2);

    v64 = u64)best_brp * 1000000000UL;
    do_divv64, priv->clock.freq);
    bt->tq = u32)v64;
    bt->prop_seg = tseg1 / 2;
    bt->phase_seg1 = tseg1 - bt->prop_seg;
    bt->phase_seg2 = tseg2;

    /* check for sjw user settings */
    if !bt->sjw || !btc->sjw_max)
        bt->sjw = 1;
    else {
        /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
        if bt->sjw > btc->sjw_max)
            bt->sjw = btc->sjw_max;
        /* bt->sjw must not be higher than tseg2 */
        if tseg2 < bt->sjw)
            bt->sjw = tseg2;
    }

    bt->brp = best_brp;
    /* real bit-rate */
    bt->bitrate = priv->clock.freq / bt->brp * tseg1 + tseg2 + 1));

   printk"can_calc_bittiming bitrate:%d
",bt->bitrate);

    return 0;
}




int mysja1000_set_bittimingstruct sja1000_priv *priv)
{
    

    printk"Enter mysja1000_set_bittiming
");
    can_calc_bittiming&priv->can,&priv->can.bittiming,&mysja1000_bittiming_const);



    struct can_bittiming *bt = &priv->can.bittiming;
    u8 btr0, btr1;

    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)
        btr1 |= 0x80;

    // netdev_infodev, "setting BTR0=0x%02x BTR1=0x%02x
", btr0, btr1);

    printk"mysja1000_set_bittiming BTR0=0x%02x BTR1=0x%02x
",btr0,btr1);
    priv->write_regpriv, SJA1000_BTR0, btr0);
    priv->write_regpriv, SJA1000_BTR1, btr1);

    return 0;
}



// 对发送接收计数失败的统计
int mysja1000_get_berr_counterconst struct sja1000_priv *priv,
                struct can_berr_counter *bec)
{
    
    bec->txerr = priv->read_regpriv, SJA1000_TXERR);
    bec->rxerr = priv->read_regpriv, SJA1000_RXERR);

    return 0;
}





/* Read SJA1000 register */
static u8 mytscan1_readconst struct sja1000_priv *priv, int reg)
{
    return inbunsigned long)priv->reg_base + reg);
}

/* Write SJA1000 register */
static void mytscan1_writeconst struct sja1000_priv *priv, int reg, u8 val)
{
    outbval, unsigned long)priv->reg_base + reg);
}

void myset_normal_modestruct sja1000_priv *priv)
{

    printk"Enter myset_normal_mode
 ");
    unsigned char status = priv->read_regpriv, SJA1000_MOD);
    u8 mod_reg_val = 0x00;
    int i;

    for i = 0; i < 100; i++) {
        /* check reset bit */
        if status & MOD_RM) == 0) {
            priv->can.state = CAN_STATE_ERROR_ACTIVE;
            /* enable interrupts */
            if priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
                priv->write_regpriv, SJA1000_IER, IRQ_ALL);
            else
                priv->write_regpriv, SJA1000_IER,
                        IRQ_ALL & ~IRQ_BEI);
            return;
        }

        /* set chip to normal mode */
        if priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
            mod_reg_val |= MOD_LOM;
        if priv->can.ctrlmode & CAN_CTRLMODE_PRESUME_ACK)
            mod_reg_val |= MOD_STM;
        priv->write_regpriv, SJA1000_MOD, mod_reg_val);

        udelay10);

        status = priv->read_regpriv, SJA1000_MOD);
    }

}



void myset_reset_modestruct sja1000_priv *priv)
{

    unsigned char status = priv->read_regpriv, SJA1000_MOD);
    int i;

    /* disable interrupts */
    priv->write_regpriv, SJA1000_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 */
        priv->write_regpriv, SJA1000_MOD, MOD_RM);
        udelay10);
        status = priv->read_regpriv, SJA1000_MOD);
    }

}


// open can  



/******************************************************************************/

void mysja1000_write_cmdregstruct sja1000_priv *priv, u8 val)
{
    unsigned long flags;

    /*
     * The command register needs some locking and time to settle
     * the write_reg) operation - especially on SMP systems.
     */
    spin_lock_irqsave&priv->cmdreg_lock, flags);
    priv->write_regpriv, SJA1000_CMR, val);
    priv->read_regpriv, SJA1000_SR);
    spin_unlock_irqrestore&priv->cmdreg_lock, flags);
}
/*
 * initialize SJA1000 chip:
 *   - reset chip
 *   - set output mode
 *   - set baudrate
 *   - enable interrupts
 *   - start operating mode
 */
void mychipset_initstruct sja1000_priv *priv )
{

    printk"Enter the mychipset_init
");

    /* set clock divider and output control register */
#if definedCONFIG_LS1X_CAN0) || definedCONFIG_LS1X_CAN1)
    mysja1000_write_cmdregpriv, 0x80);
#else
    priv->write_regpriv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
#endif

    /* set acceptance filter accept all) */
    priv->write_regpriv, SJA1000_ACCC0, 0x00);
    priv->write_regpriv, SJA1000_ACCC1, 0x00);
    priv->write_regpriv, SJA1000_ACCC2, 0x00);
    priv->write_regpriv, SJA1000_ACCC3, 0x00);

    priv->write_regpriv, SJA1000_ACCM0, 0xFF);
    priv->write_regpriv, SJA1000_ACCM1, 0xFF);
    priv->write_regpriv, SJA1000_ACCM2, 0xFF);
    priv->write_regpriv, SJA1000_ACCM3, 0xFF);
    priv->write_regpriv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
}







void mysja1000_startstruct sja1000_priv *priv)
{

    
    printk"Enter the mysja1000_start
");


    /* leave reset mode */
    if priv->can.state != CAN_STATE_STOPPED)
        myset_reset_modepriv);

    /* Initialize chip if uninitialized at this stage */
    if !priv->read_regpriv, SJA1000_CDR) & CDR_PELICAN))
        mychipset_initpriv);

    /* Clear error counters and error code capture */
    priv->write_regpriv, SJA1000_TXERR, 0x0);
    priv->write_regpriv, SJA1000_RXERR, 0x0);
    priv->read_regpriv, SJA1000_ECC);

    /* leave reset mode */
    myset_normal_modepriv);
}


int mysja1000_set_modestruct sja1000_priv *priv, enum can_mode mode)
{
    switch mode) {
    case CAN_MODE_START:
        mysja1000_startpriv);
        // if netif_queue_stoppeddev))
        //     netif_wake_queuedev);
        break;

    default:
        return -EOPNOTSUPP;
    }

    return 0;
}



static u8 sp_read_reg8const struct sja1000_priv *priv, int reg)
{
    return ioread8priv->reg_base + reg);
}

static void sp_write_reg8const struct sja1000_priv *priv, int reg, u8 val)
{
    iowrite8val, priv->reg_base + reg);
}








int calc_com_addrint can_id)
{
     int device_addr, sub_addr;
     device_addr = can_id & 0x0F;
     sub_addr = can_id & 0x70)>>4;

     return sub_addr+device_addr-1)*5;
}











void mysja1000_rxstruct sja1000_priv *priv)
{

    // struct net_device_stats *stats = &dev->stats;
    // struct can_frame can_buff;
    char length_can;
    // struct can_frame *cf = &can_buff;
    struct sk_buff skb;
    uint8_t fi;
    uint8_t dreg;
    canid_t id;
    int i;
    unsigned ch;
    printk"Enter the mysja1000_rx
");

/*******************************/
    // 进行数据的获取
    /* create zero'ed CAN frame buffer */
    // skb = alloc_can_skbdev, &cf);

    // if skb == NULL)
    //     return;

    fi = priv->read_regpriv, SJA1000_FI);

    if fi & SJA1000_FI_FF) {
        printk"mysja1000_rx expand frame
");
        /* extended frame format EFF) */
        dreg = SJA1000_EFF_BUF;
        id = priv->read_regpriv, SJA1000_ID1) << 21)
            | priv->read_regpriv, SJA1000_ID2) << 13)
            | priv->read_regpriv, SJA1000_ID3) << 5)
            | priv->read_regpriv, SJA1000_ID4) >> 3);
        id |= CAN_EFF_FLAG;
    } else {
        /* standard frame format SFF) */
        dreg = SJA1000_SFF_BUF;
        id = priv->read_regpriv, SJA1000_ID1) << 3)
            | priv->read_regpriv, SJA1000_ID2) >> 5);
    }

    // cf->can_dlc = get_can_dlcfi & 0x0F);


    length_can = get_can_dlcfi & 0x0F);


    int curr_index =  calc_com_addrid);

    printk"receive from can's com addr:%d
",curr_index);
    struct uart_port *curr_port = &canserial_ports[curr_index].port;

    if fi & SJA1000_FI_RTR) {
        id |= CAN_RTR_FLAG;
    } else {
        for i = 0; i < length_can; i++)
        {

            ch = priv->read_regpriv, dreg++);

            uart_insert_charcurr_port, 0, 0x02, ch, 0);

            curr_port->icount.tx++;
            // cf->data[i] = priv->read_regpriv, dreg++);
            // printk"rx data %x
",data[i]);
        }

    }

    spin_unlock&curr_port->lock);
    tty_flip_buffer_push&curr_port->state->port);
    spin_lock&curr_port->lock);


    /* release receive buffer */
    mysja1000_write_cmdregpriv, CMD_RRB);



}




irqreturn_t mysja1000_interruptint irq, void *dev_id)
{



     struct sja1000_priv *priv = struct sja1000_priv*)dev_id;

     printk"mysja1000_interrupt
");



    // struct net_device_stats *stats = &dev->stats;

    uint8_t isrc, status;
    int n = 0;

    if priv->pre_irq)
        priv->pre_irqpriv);

    /* Shared interrupts and IRQ off? */
    if priv->read_regpriv, SJA1000_IER) == IRQ_OFF)
        goto out;

    while isrc = priv->read_regpriv, SJA1000_IR)) &&
           n < SJA1000_MAX_IRQ)) {

        status = priv->read_regpriv, SJA1000_SR);
        /* check for absent controller due to hw unplug */
        // if status == 0xFF && sja1000_is_absentpriv))
        //     goto out;

        // if isrc & IRQ_WUI)
        //     netdev_warndev, "wakeup interrupt
");

        if isrc & IRQ_TI) {
            /* transmission buffer released */
            if priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT &&
                !status & SR_TCS)) {
                // stats->tx_errors++;
                // can_free_echo_skbdev, 0);
            } else {
                /* transmission complete */
                // stats->tx_bytes +=
                    priv->read_regpriv, SJA1000_FI) & 0xf;
                // stats->tx_packets++;
            }
            // can_led_eventdev, CAN_LED_EVENT_TX);
        }
        if isrc & IRQ_RI) {
            /* receive interrupt */
            while status & SR_RBS) {
                mysja1000_rxpriv);
                status = priv->read_regpriv, SJA1000_SR);
                /* check for absent controller */
                // if status == 0xFF && sja1000_is_absentpriv))
                //     goto out;
            }
        }
        if isrc & IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
            /* error interrupt */
            // if sja1000_errdev, isrc, status))
            //     break;
        }
        n++;
    }


out:
    if priv->post_irq)
        priv->post_irqpriv);

    // if n >= SJA1000_MAX_IRQ)
    //     netdev_dbgdev, "%d messages handled in ISR", n);

    return n) ? IRQ_HANDLED : IRQ_NONE;
}



EXPORT_SYMBOL_GPLmysja1000_interrupt);


int mysja1000_openstruct sja1000_priv *priv)
{


    printk"enter mysja1000_open
");

    myset_reset_modepriv);



/***********************open_candev)**********************/
    // err = open_candevdev); 等效
    if !priv->can.bittiming.bitrate) {
        printk"bit-timing not yet defined
");
        return -EINVAL;
    }

    printk"priv->can.bittiming.bitrate is %d
" ,priv->can.bittiming.bitrate);

    if priv->can.ctrlmode & CAN_CTRLMODE_FD) &&
        !priv->can.data_bittiming.bitrate ||
         priv->can.data_bittiming.bitrate < priv->can.bittiming.bitrate))) {
            // netdev_errdev, "incorrect/missing data bit-timing
");
        printk"incorrect/missing data bit-timing
");
        return -EINVAL;
    }


    // mysja1000_set_modepriv, CAN_MODE_START);
    
/*********************************************/


// 请求中断   待解决
// 第一个参数irq:申请的硬件中断号;

// 第二个参数handler:是一个函数指针,向系统登记的中断处理函数,是一个回调函数,当中断发生时,系统调用这个函数,传入的参数包括中断设备 id,寄存器值。

// 第三个参数flags:指定了快速中断或中断共享等中断处理属性。

// 第四个参数devices:指定设备驱动程序的名称。

// 第五个参数dev_id:传入中断处理程序的参数,可以为NULL,在注册共享中断时,此参数不能为NULL,作为共享中断时的中断区别参数。
    int err = request_irq14, mysja1000_interrupt, priv->irq_flags,
                  "canserial8250", void *)priv);
   
    if!err)
    {
        printk"request_irq failed
");
    }

    mysja1000_startpriv);

}






int mysja1000_closestruct sja1000_priv *priv)
{


    printk"mysja1000_close
");
    myset_reset_modepriv);

    if !priv->flags & SJA1000_CUSTOM_IRQ_HANDLER))
        free_irq14, void *)priv);

    // close_candevdev);


    return 0;
}





/*
 * transmit a CAN message
 * message layout in the sk_buff should be like this:
 * xx xx xx xx     ff     ll   00 11 22 33 44 55 66 77
 * [  can-id ] [flags] [len] [can data up to 8 bytes]
 */
// netdev_tx_t mysja1000_start_xmitstruct sk_buff *skb,
                        // struct sja1000_priv *priv)

netdev_tx_t mysja1000_start_xmitstruct can_frame *cf,
                        struct sja1000_priv *priv)
{

 //  对sk_buff 结构体定义其id、can_dlc、data

    // struct can_frame *cf = struct can_frame *)skb->data;

    uint8_t fi;
    uint8_t dlc;
    canid_t id;
    uint8_t dreg;
    u8 cmd_reg_val = 0x00;
    int i;
    printk"Enter the mysja1000_start_xmit
");
    printk"the start send data:%s
",cf->data);


    // if can_dropped_invalid_skbdev, skb))
    //     return NETDEV_TX_OK;

    // netif_stop_queuedev);

    fi = dlc = cf->can_dlc;
    id = cf->can_id;

    if id & CAN_RTR_FLAG)
        fi |= SJA1000_FI_RTR;

// CAN_EFF_FLAG 扩展帧  用扩展帧对数据进行发送
    if id & CAN_EFF_FLAG) {
        printk"Enter mysja1000_start_xmit expand frame 
");
        fi |= SJA1000_FI_FF;
        dreg = SJA1000_EFF_BUF;
        priv->write_regpriv, SJA1000_FI, fi);
        priv->write_regpriv, SJA1000_ID1, id & 0x1fe00000) >> 21);
        priv->write_regpriv, SJA1000_ID2, id & 0x001fe000) >> 13);
        priv->write_regpriv, SJA1000_ID3, id & 0x00001fe0) >> 5);
        priv->write_regpriv, SJA1000_ID4, id & 0x0000001f) << 3);
    } else {
        dreg = SJA1000_SFF_BUF;
        priv->write_regpriv, SJA1000_FI, fi);
        priv->write_regpriv, SJA1000_ID1, id & 0x000007f8) >> 3);
        priv->write_regpriv, SJA1000_ID2, id & 0x00000007) << 5);
    }

    for i = 0; i < dlc; i++)
    { 
        printk"send data:%d
", cf->data[i]);
        priv->write_regpriv, dreg++, cf->data[i]);
    }

    // can_put_echo_skbskb, dev, 0);

    if priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
        cmd_reg_val |= CMD_AT;

    if priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
        cmd_reg_val |= CMD_SRR;
    else
        cmd_reg_val |= CMD_TR;

    mysja1000_write_cmdregpriv, cmd_reg_val);

    return NETDEV_TX_OK;
}


int sja1000_is_absentstruct sja1000_priv *priv)
{    
    printk"sja1000_is_absent
");
    return priv->read_regpriv, SJA1000_MOD) == 0xFF);
}


int myregister_sja1000devstruct sja1000_priv *priv)
{
    int ret;

    printk"Enter myregister_sja1000dev
");
    // if !mysja1000_probe_chippriv))
    //     return -ENODEV;

    if priv->reg_base && sja1000_is_absentpriv)) {
        printk"probing failed
");
        return 0;
    }


    // dev->flags |= IFF_ECHO;     we support local echo 
    // dev->netdev_ops = &sja1000_netdev_ops;

    myset_reset_modepriv);
    mychipset_initpriv);

    // ret =  register_candevdev);

    // if !ret)
        // devm_can_led_initdev);

    // return ret;
}



// probe 这一块没什么问题
int mytscan1_probestruct sja1000_priv *priv)
{

    printk"Enter mytscan1_probe
");
    priv->irq_flags = 0;
    // dev->irq = 14;
    priv->reg_base = void __iomem *)0xbfe50000;
    priv->can.clock.freq = 41406250;
    priv->ocr = 88;
    priv->cdr = 64;

    priv->read_reg = sp_read_reg8;
    priv->write_reg = sp_write_reg8;



//alloc_sja1000dev
    priv->dev = NULL;
    priv->can.bittiming_const = &mysja1000_bittiming_const;
    priv->can.do_set_bittiming = mysja1000_set_bittiming;
    priv->can.do_set_mode = mysja1000_set_mode;
    priv->can.do_get_berr_counter = mysja1000_get_berr_counter;
    priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
                       CAN_CTRLMODE_LISTENONLY |
                       CAN_CTRLMODE_3_SAMPLES |
                       CAN_CTRLMODE_ONE_SHOT |
                       CAN_CTRLMODE_BERR_REPORTING |
                       CAN_CTRLMODE_PRESUME_ACK;



   myregister_sja1000devpriv);

    return 0;
}

    

Published by

风君子

独自遨游何稽首 揭天掀地慰生平