📄 sja1000p.c
字号:
/* sja1000.c
* Linux CAN-bus device driver.
* Written by Arnaud Westenberg email:arnaud@wanadoo.nl
* This software is released under the GPL-License.
* Version 0.6 18 Sept 2000
* Changed for PeliCan mode SJA1000 by Tomasz Motylewski (BFAD GmbH)
* T.Motylewski@bfad.de
*/
/*
#include <linux/autoconf.h>
#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
#define MODVERSIONS
#endif
#if defined (MODVERSIONS)
#include <linux/modversions.h>
#endif
*/
#include <linux/delay.h>
#include <asm/irq.h>
#include "sysdep.h"
#include "candrv.h"
#include "sja1000p.h"
//struct chip_t *chip_irq = NULL;
//struct candevice_t *device_irq = NULL;
//struct canfifo_t *fifo_irq = NULL;
void (*put_reg)( u8 data, u32 address);
unsigned (*get_reg)( u32 address );
///////////////////////////////////////////////////////////////////////////////
// sja1000p_enable_configuration
int sja1000p_enable_configuration( struct chip_t *pchip )
{
int i=0;
enum sja1000_PeliCAN_MOD flags;
disable_irq( pchip->irq );
flags = pchip->read_register( pchip->vbase_addr + SJAMOD );
while ((!(flags & MOD_RM)) && (i<=10)) {
pchip->write_register( MOD_RM, pchip->vbase_addr + SJAMOD );
// TODO: chinfigurable MOD_AFM (32/16 bit acceptance filter)
// config MOD_LOM (listen only)
udelay(100);
i++;
flags = pchip->read_register( pchip->vbase_addr + SJAMOD );
}
if (i>=10) {
CANMSG("Reset error\n");
enable_irq( pchip->irq );
return -ENODEV;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// sja1000p_disable_configuration
int sja1000p_disable_configuration( struct chip_t *pchip )
{
int i=0;
enum sja1000_PeliCAN_MOD flags;
flags = pchip->read_register( pchip->vbase_addr + SJAMOD );
while ( (flags & MOD_RM) && (i<=10) ) {
pchip->write_register( 0, pchip->vbase_addr + SJAMOD );
// TODO: chinfigurable MOD_AFM (32/16 bit acceptance filter)
// config MOD_LOM (listen only)
udelay(100);
i++;
flags = pchip->read_register( pchip->vbase_addr + SJAMOD );
}
if (i>=10) {
CANMSG("Error leaving reset status\n");
return -ENODEV;
}
enable_irq( pchip->irq );
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// sja1000p_chip_config
int sja1000p_chip_config( struct chip_t *pchip )
{
if (sja1000p_enable_configuration(pchip))
return -ENODEV;
/* Set mode, clock out, comparator */
pchip->write_register( CDR_PELICAN | pchip->sja_cdr_reg, pchip->vbase_addr + SJACDR );
/* Set driver output configuration */
pchip->write_register( pchip->sja_ocr_reg, pchip->vbase_addr + SJAOCR );
if (sja1000p_extended_mask(pchip,0x00000000, 0xffffffff))
return -ENODEV;
if (!baudrate)
baudrate=1000;
if (sja1000p_baud_rate(pchip,1000*baudrate,pchip->clock,0,75,0))
return -ENODEV;
/* Enable hardware interrupts */
pchip->write_register( ENABLE_INTERRUPTS, pchip->vbase_addr + SJAIER );
sja1000p_disable_configuration( pchip );
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// sja1000p_extended_mask
int sja1000p_extended_mask( struct chip_t *pchip,
u32 code,
u32 mask )
{
int i;
if (sja1000p_enable_configuration(pchip))
return -ENODEV;
// LSB to +3, MSB to +0
for(i=SJA_PeliCAN_AC_LEN; --i>=0;) {
pchip->write_register( code & 0xff, pchip->vbase_addr + SJAACR0+i);
pchip->write_register( mask & 0xff, pchip->vbase_addr + SJAAMR0+i);
code >>= 8;
mask >>= 8;
}
DEBUGMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code);
DEBUGMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
sja1000p_disable_configuration(pchip);
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// sja1000p_baud_rate
/* Set communication parameters.
* param rate baud rate in Hz
* param clock frequency of sja1000 clock in Hz (ISA osc is 14318000)
* param sjw synchronization jump width (0-3) prescaled clock cycles
* param sampl_pt sample point in % (0-100) sets (TSEG1+1)/(TSEG1+TSEG2+2) ratio
* param flags fields BTR1_SAM, OCMODE, OCPOL, OCTP, OCTN, CLK_OFF, CBP
*/
int sja1000p_baud_rate( struct chip_t *pchip,
u32 rate,
u32 clock,
u32 sjw,
u32 sampl_pt,
u32 flags )
{
int best_error = 1000000000, error;
int best_tseg=0, best_brp=0, best_rate=0, brp=0;
int tseg=0, tseg1=0, tseg2=0;
if (sja1000p_enable_configuration(pchip))
return -ENODEV;
clock /=2;
/* tseg even = round down, odd = round up */
for (tseg=(0+0+2)*2; tseg<=(MAX_TSEG2+MAX_TSEG1+2)*2+1; tseg++) {
brp = clock/((1+tseg/2)*rate)+tseg%2;
if (brp == 0 || brp > 64)
continue;
error = rate - clock/(brp*(1+tseg/2));
if (error < 0)
error = -error;
if (error <= best_error) {
best_error = error;
best_tseg = tseg/2;
best_brp = brp-1;
best_rate = clock/(brp*(1+tseg/2));
}
}
if (best_error && (rate/best_error < 10)) {
CANMSG("baud rate %d is not possible with %d Hz clock\n",
rate, 2*clock);
CANMSG("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n",
best_rate, best_brp, best_tseg, tseg1, tseg2);
return -EINVAL;
}
tseg2 = best_tseg-(sampl_pt*(best_tseg+1))/100;
if (tseg2 < 0)
tseg2 = 0;
if (tseg2 > MAX_TSEG2)
tseg2 = MAX_TSEG2;
tseg1 = best_tseg-tseg2-2;
if (tseg1>MAX_TSEG1) {
tseg1 = MAX_TSEG1;
tseg2 = best_tseg-tseg1-2;
}
DEBUGMSG("Setting %d bps.\n", best_rate);
DEBUGMSG("brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d, sampl_pt=%d\n",
best_brp, best_tseg, tseg1, tseg2,
(100*(best_tseg-tseg2)/(best_tseg+1)));
pchip->write_register( sjw<<6 | best_brp, pchip->vbase_addr + SJABTR0);
pchip->write_register( ( ( flags & BTR1_SAM) != 0)<<7 | (tseg2<<4)
| tseg1, pchip->vbase_addr + SJABTR1);
sja1000p_disable_configuration(pchip);
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// sja1000p_read
void sja1000p_read( struct chip_t *pchip ) {
int i, flags, len, datastart;
do {
flags = pchip->read_register( pchip->vbase_addr + SJAFRM );
if(flags&FRM_FF) {
( ( struct canmsg_t *)pchip->fifo.prxbuf )[ pchip->fifo.head ].id =
( pchip->read_register( pchip->vbase_addr + SJAID0)<<21) +
( pchip->read_register( pchip->vbase_addr + SJAID1)<<13) +
( pchip->read_register( pchip->vbase_addr + SJAID2)<<5) +
( pchip->read_register( pchip->vbase_addr + SJAID3)>>3);
datastart = SJADATE;
} else {
( ( struct canmsg_t *)pchip->fifo.prxbuf )[pchip->fifo.head].id =
( pchip->read_register( pchip->vbase_addr + SJAID0)<<3) +
( pchip->read_register( pchip->vbase_addr + SJAID1)>>5);
datastart = SJADATS;
}
( ( struct canmsg_t *)pchip->fifo.prxbuf) [pchip->fifo.head].flags =
((flags & FRM_RTR) ? MSG_RTR : 0) |
((flags & FRM_FF) ? MSG_EXT : 0);
len = flags & FRM_DLC_M;
for(i=0; i< len; i++) {
( ( struct canmsg_t *)pchip->fifo.prxbuf)[ pchip->fifo.head ].data[i]=
pchip->read_register( pchip->vbase_addr + datastart+i);
}
( ( struct canmsg_t *)pchip->fifo.prxbuf )[ pchip->fifo.head ].length = len;
pchip->fifo.head++; pchip->fifo.head %= MAX_BUF_LENGTH;
// FIXME: what if pchip->fifo.head == pchip->fifo.tail again ?
pchip->write_register( CMR_RRB, pchip->vbase_addr + SJACMR);
} while ( pchip->read_register( pchip->vbase_addr + SJASR) & SR_RBS);
}
///////////////////////////////////////////////////////////////////////////////
// sja1000p_pre_read_config
int sja1000p_pre_read_config( struct chip_t *pchip )
{
int i;
i = pchip->read_register( pchip->vbase_addr + SJASR );
if (!(i&SR_RBS)) {
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -