sja1000芯片can驱动程序

时间:2023-03-10 06:22:13
sja1000芯片can驱动程序

应用层使用socketCan的方法:http://pan.baidu.com/s/1ntsvbb7#path=%252Floongson1%252Ftools%252Fcan

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

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

  

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

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

调用 netdev_tx_t mysja1000_start_xmit(struct 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 = ,
.tseg1_max = ,
.tseg2_min = ,
.tseg2_max = ,
.sjw_max = ,
.brp_min = ,
.brp_max = ,
.brp_inc = ,
}; struct sja1000_priv m_ppriv; extern struct uart_8250_port canserial_ports[]; static int can_update_spt(const struct can_bittiming_const *btc,
int sampl_pt, int tseg, int *tseg1, int *tseg2)
{
*tseg2 = tseg + - (sampl_pt * (tseg + )) / ;
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 * (tseg + - *tseg2) / (tseg + );
} static int can_calc_bittiming(struct can_priv *priv, struct can_bittiming *bt,
const struct can_bittiming_const *btc)
{ printk("Enter can_calc_bittiming\n"); long best_error = , error = ;
int best_tseg = , best_brp = , brp = ;
int tsegall, tseg = , tseg1 = , tseg2 = ;
int spt_error = , spt = , sampl_pt;
long rate;
u64 v64; bt->bitrate = ;
/* Use CiA recommended sample points */
if (bt->sample_point) {
sampl_pt = bt->sample_point;
} else {
if (bt->bitrate > )
sampl_pt = ;
else if (bt->bitrate > )
sampl_pt = ;
else
sampl_pt = ;
} /* tseg even = round down, odd = round up */
for (tseg = (btc->tseg1_max + btc->tseg2_max) * + ;
tseg >= (btc->tseg1_min + btc->tseg2_min) * ; tseg--) {
tsegall = + tseg / ;
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % ;
/* 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 < )
error = -error;
if (error > best_error)
continue;
best_error = error;
if (error == ) {
spt = can_update_spt(btc, sampl_pt, tseg / ,
&tseg1, &tseg2);
error = sampl_pt - spt;
if (error < )
error = -error;
if (error > spt_error)
continue;
spt_error = error;
}
best_tseg = tseg / ;
best_brp = brp;
if (error == )
break;
} // if (best_error) {
// /* Error in one-tenth of a percent */
// error = (best_error * 1000) / bt->bitrate;
// if (error > CAN_CALC_MAX_ERROR) {
// // netdev_err(dev,
// // "bitrate error %ld.%ld%% too high\n",
// // error / 10, error % 10);
// return -EDOM;
// } else {
// // netdev_warn(dev, "bitrate error %ld.%ld%%\n",
// // error / 10, error % 10);
// }
// } /* real sample point */
bt->sample_point = can_update_spt(btc, sampl_pt, best_tseg,
&tseg1, &tseg2); v64 = (u64)best_brp * 1000000000UL;
do_div(v64, priv->clock.freq);
bt->tq = (u32)v64;
bt->prop_seg = tseg1 / ;
bt->phase_seg1 = tseg1 - bt->prop_seg;
bt->phase_seg2 = tseg2; /* check for sjw user settings */
if (!bt->sjw || !btc->sjw_max)
bt->sjw = ;
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 + )); printk("can_calc_bittiming bitrate:%d\n",bt->bitrate); return ;
} int mysja1000_set_bittiming(struct sja1000_priv *priv)
{ printk("Enter mysja1000_set_bittiming\n");
can_calc_bittiming(&priv->can,&priv->can.bittiming,&mysja1000_bittiming_const); struct can_bittiming *bt = &priv->can.bittiming;
u8 btr0, btr1; btr0 = ((bt->brp - ) & 0x3f) | (((bt->sjw - ) & 0x3) << );
btr1 = ((bt->prop_seg + bt->phase_seg1 - ) & 0xf) |
(((bt->phase_seg2 - ) & 0x7) << );
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
btr1 |= 0x80; // netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); printk("mysja1000_set_bittiming BTR0=0x%02x BTR1=0x%02x\n",btr0,btr1);
priv->write_reg(priv, SJA1000_BTR0, btr0);
priv->write_reg(priv, SJA1000_BTR1, btr1); return ;
} // 对发送接收计数失败的统计
int mysja1000_get_berr_counter(const struct sja1000_priv *priv,
struct can_berr_counter *bec)
{ bec->txerr = priv->read_reg(priv, SJA1000_TXERR);
bec->rxerr = priv->read_reg(priv, SJA1000_RXERR); return ;
} /* Read SJA1000 register */
static u8 mytscan1_read(const struct sja1000_priv *priv, int reg)
{
return inb((unsigned long)priv->reg_base + reg);
} /* Write SJA1000 register */
static void mytscan1_write(const struct sja1000_priv *priv, int reg, u8 val)
{
outb(val, (unsigned long)priv->reg_base + reg);
} void myset_normal_mode(struct sja1000_priv *priv)
{ printk("Enter myset_normal_mode\n ");
unsigned char status = priv->read_reg(priv, SJA1000_MOD);
u8 mod_reg_val = 0x00;
int i; for (i = ; i < ; i++) {
/* check reset bit */
if ((status & MOD_RM) == ) {
priv->can.state = CAN_STATE_ERROR_ACTIVE;
/* enable interrupts */
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
priv->write_reg(priv, SJA1000_IER, IRQ_ALL);
else
priv->write_reg(priv, 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_reg(priv, SJA1000_MOD, mod_reg_val); udelay(); status = priv->read_reg(priv, SJA1000_MOD);
} } void myset_reset_mode(struct sja1000_priv *priv)
{ unsigned char status = priv->read_reg(priv, SJA1000_MOD);
int i; /* disable interrupts */
priv->write_reg(priv, SJA1000_IER, IRQ_OFF); for (i = ; i < ; i++) {
/* check reset bit */
if (status & MOD_RM) {
priv->can.state = CAN_STATE_STOPPED;
return;
} /* reset chip */
priv->write_reg(priv, SJA1000_MOD, MOD_RM);
udelay();
status = priv->read_reg(priv, SJA1000_MOD);
} } // open can /******************************************************************************/ void mysja1000_write_cmdreg(struct 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_reg(priv, SJA1000_CMR, val);
priv->read_reg(priv, 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_init(struct sja1000_priv *priv )
{ printk("Enter the mychipset_init\n"); /* set clock divider and output control register */
#if defined(CONFIG_LS1X_CAN0) || defined(CONFIG_LS1X_CAN1)
mysja1000_write_cmdreg(priv, 0x80);
#else
priv->write_reg(priv, SJA1000_CDR, priv->cdr | CDR_PELICAN);
#endif /* set acceptance filter (accept all) */
priv->write_reg(priv, SJA1000_ACCC0, 0x00);
priv->write_reg(priv, SJA1000_ACCC1, 0x00);
priv->write_reg(priv, SJA1000_ACCC2, 0x00);
priv->write_reg(priv, SJA1000_ACCC3, 0x00); priv->write_reg(priv, SJA1000_ACCM0, 0xFF);
priv->write_reg(priv, SJA1000_ACCM1, 0xFF);
priv->write_reg(priv, SJA1000_ACCM2, 0xFF);
priv->write_reg(priv, SJA1000_ACCM3, 0xFF);
priv->write_reg(priv, SJA1000_OCR, priv->ocr | OCR_MODE_NORMAL);
} void mysja1000_start(struct sja1000_priv *priv)
{ printk("Enter the mysja1000_start\n"); /* leave reset mode */
if (priv->can.state != CAN_STATE_STOPPED)
myset_reset_mode(priv); /* Initialize chip if uninitialized at this stage */
if (!(priv->read_reg(priv, SJA1000_CDR) & CDR_PELICAN))
mychipset_init(priv); /* Clear error counters and error code capture */
priv->write_reg(priv, SJA1000_TXERR, 0x0);
priv->write_reg(priv, SJA1000_RXERR, 0x0);
priv->read_reg(priv, SJA1000_ECC); /* leave reset mode */
myset_normal_mode(priv);
} int mysja1000_set_mode(struct sja1000_priv *priv, enum can_mode mode)
{
switch (mode) {
case CAN_MODE_START:
mysja1000_start(priv);
// if (netif_queue_stopped(dev))
// netif_wake_queue(dev);
break; default:
return -EOPNOTSUPP;
} return ;
} static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg)
{
return ioread8(priv->reg_base + reg);
} static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val)
{
iowrite8(val, priv->reg_base + reg);
} int calc_com_addr(int can_id)
{
int device_addr, sub_addr;
device_addr = can_id & 0x0F;
sub_addr = (can_id & 0x70)>>; return sub_addr+(device_addr-)*;
} void mysja1000_rx(struct 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\n"); /*******************************/
// 进行数据的获取
/* create zero'ed CAN frame buffer */
// skb = alloc_can_skb(dev, &cf); // if (skb == NULL)
// return; fi = priv->read_reg(priv, SJA1000_FI); if (fi & SJA1000_FI_FF) {
printk("mysja1000_rx expand frame\n");
/* extended frame format (EFF) */
dreg = SJA1000_EFF_BUF;
id = (priv->read_reg(priv, SJA1000_ID1) << )
| (priv->read_reg(priv, SJA1000_ID2) << )
| (priv->read_reg(priv, SJA1000_ID3) << )
| (priv->read_reg(priv, SJA1000_ID4) >> );
id |= CAN_EFF_FLAG;
} else {
/* standard frame format (SFF) */
dreg = SJA1000_SFF_BUF;
id = (priv->read_reg(priv, SJA1000_ID1) << )
| (priv->read_reg(priv, SJA1000_ID2) >> );
} // cf->can_dlc = get_can_dlc(fi & 0x0F); length_can = get_can_dlc(fi & 0x0F); int curr_index = calc_com_addr(id); printk("receive from can's com addr:%d\n",curr_index);
struct uart_port *curr_port = &canserial_ports[curr_index].port; if (fi & SJA1000_FI_RTR) {
id |= CAN_RTR_FLAG;
} else {
for (i = ; i < length_can; i++)
{ ch = priv->read_reg(priv, dreg++); uart_insert_char(curr_port, , 0x02, ch, ); curr_port->icount.tx++;
// cf->data[i] = priv->read_reg(priv, dreg++);
// printk("rx data %x\n",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_cmdreg(priv, CMD_RRB); } irqreturn_t mysja1000_interrupt(int irq, void *dev_id)
{ struct sja1000_priv *priv = (struct sja1000_priv*)dev_id; printk("mysja1000_interrupt\n"); // struct net_device_stats *stats = &dev->stats; uint8_t isrc, status;
int n = ; if (priv->pre_irq)
priv->pre_irq(priv); /* Shared interrupts and IRQ off? */
if (priv->read_reg(priv, SJA1000_IER) == IRQ_OFF)
goto out; while ((isrc = priv->read_reg(priv, SJA1000_IR)) &&
(n < SJA1000_MAX_IRQ)) { status = priv->read_reg(priv, SJA1000_SR);
/* check for absent controller due to hw unplug */
// if (status == 0xFF && sja1000_is_absent(priv))
// goto out; // if (isrc & IRQ_WUI)
// netdev_warn(dev, "wakeup interrupt\n"); if (isrc & IRQ_TI) {
/* transmission buffer released */
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT &&
!(status & SR_TCS)) {
// stats->tx_errors++;
// can_free_echo_skb(dev, 0);
} else {
/* transmission complete */
// stats->tx_bytes +=
priv->read_reg(priv, SJA1000_FI) & 0xf;
// stats->tx_packets++;
}
// can_led_event(dev, CAN_LED_EVENT_TX);
}
if (isrc & IRQ_RI) {
/* receive interrupt */
while (status & SR_RBS) {
mysja1000_rx(priv);
status = priv->read_reg(priv, SJA1000_SR);
/* check for absent controller */
// if (status == 0xFF && sja1000_is_absent(priv))
// goto out;
}
}
if (isrc & (IRQ_DOI | IRQ_EI | IRQ_BEI | IRQ_EPI | IRQ_ALI)) {
/* error interrupt */
// if (sja1000_err(dev, isrc, status))
// break;
}
n++;
} out:
if (priv->post_irq)
priv->post_irq(priv); // if (n >= SJA1000_MAX_IRQ)
// netdev_dbg(dev, "%d messages handled in ISR", n); return (n) ? IRQ_HANDLED : IRQ_NONE;
} EXPORT_SYMBOL_GPL(mysja1000_interrupt); int mysja1000_open(struct sja1000_priv *priv)
{ printk("enter mysja1000_open\n"); myset_reset_mode(priv); /***********************open_candev()**********************/
// err = open_candev(dev); 等效
if (!priv->can.bittiming.bitrate) {
printk("bit-timing not yet defined\n");
return -EINVAL;
} printk("priv->can.bittiming.bitrate is %d\n" ,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_err(dev, "incorrect/missing data bit-timing\n");
printk("incorrect/missing data bit-timing\n");
return -EINVAL;
} // mysja1000_set_mode(priv, CAN_MODE_START); /*********************************************/ // 请求中断 待解决
// 第一个参数irq:申请的硬件中断号; // 第二个参数handler:是一个函数指针,向系统登记的中断处理函数,是一个回调函数,当中断发生时,系统调用这个函数,传入的参数包括中断设备 id,寄存器值。 // 第三个参数flags:指定了快速中断或中断共享等中断处理属性。 // 第四个参数devices:指定设备驱动程序的名称。 // 第五个参数dev_id:传入中断处理程序的参数,可以为NULL,在注册共享中断时,此参数不能为NULL,作为共享中断时的中断区别参数。
int err = request_irq(, mysja1000_interrupt, priv->irq_flags,
"canserial8250", (void *)priv); if(!err)
{
printk("request_irq failed\n");
} mysja1000_start(priv); } int mysja1000_close(struct sja1000_priv *priv)
{ printk("mysja1000_close\n");
myset_reset_mode(priv); if (!(priv->flags & SJA1000_CUSTOM_IRQ_HANDLER))
free_irq(, (void *)priv); // close_candev(dev); return ;
} /*
* 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_xmit(struct sk_buff *skb,
// struct sja1000_priv *priv) netdev_tx_t mysja1000_start_xmit(struct 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\n");
printk("the start send data:%s\n",cf->data); // if (can_dropped_invalid_skb(dev, skb))
// return NETDEV_TX_OK; // netif_stop_queue(dev); 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 \n");
fi |= SJA1000_FI_FF;
dreg = SJA1000_EFF_BUF;
priv->write_reg(priv, SJA1000_FI, fi);
priv->write_reg(priv, SJA1000_ID1, (id & 0x1fe00000) >> );
priv->write_reg(priv, SJA1000_ID2, (id & 0x001fe000) >> );
priv->write_reg(priv, SJA1000_ID3, (id & 0x00001fe0) >> );
priv->write_reg(priv, SJA1000_ID4, (id & 0x0000001f) << );
} else {
dreg = SJA1000_SFF_BUF;
priv->write_reg(priv, SJA1000_FI, fi);
priv->write_reg(priv, SJA1000_ID1, (id & 0x000007f8) >> );
priv->write_reg(priv, SJA1000_ID2, (id & 0x00000007) << );
} for (i = ; i < dlc; i++)
{
printk("send data:%d\n", cf->data[i]);
priv->write_reg(priv, dreg++, cf->data[i]);
} // can_put_echo_skb(skb, 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_cmdreg(priv, cmd_reg_val); return NETDEV_TX_OK;
} int sja1000_is_absent(struct sja1000_priv *priv)
{
printk("sja1000_is_absent\n");
return (priv->read_reg(priv, SJA1000_MOD) == 0xFF);
} int myregister_sja1000dev(struct sja1000_priv *priv)
{
int ret; printk("Enter myregister_sja1000dev\n");
// if (!mysja1000_probe_chip(priv))
// return -ENODEV; if (priv->reg_base && sja1000_is_absent(priv)) {
printk("probing failed\n");
return ;
} // dev->flags |= IFF_ECHO; we support local echo
// dev->netdev_ops = &sja1000_netdev_ops; myset_reset_mode(priv);
mychipset_init(priv); // ret = register_candev(dev); // if (!ret)
// devm_can_led_init(dev); // return ret;
} // probe 这一块没什么问题
int mytscan1_probe(struct sja1000_priv *priv)
{ printk("Enter mytscan1_probe\n");
priv->irq_flags = ;
// dev->irq = 14;
priv->reg_base = (void __iomem *)0xbfe50000;
priv->can.clock.freq = ;
priv->ocr = ;
priv->cdr = ; 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_sja1000dev(priv); return ;
}