📄 em104_can.c
字号:
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/arch/regs-mem.h>
#include "trace.h"
#include "sja1000.h"
#include "canbus4linux.h"
MODULE_LICENSE("GPL");
static void em104_sja1000_writereg(void * data, u8 reg, u8 val);
static u8 em104_sja1000_readreg(void * data, u8 reg);
static int em104_sja1000_register_isr(void * data, sja1000_isr chip_isr, struct sja1000_admin * chip_isr_data);
static int em104_sja1000_unregister_isr(void * data);
static int em104_sja1000_open(void * data);
static int em104_sja1000_close(void * data);
struct EM104_SJA1000_CHIP
{
unsigned long addr;
unsigned long data;
char name[MAX_DEVICE_NAME_LENGTH];
int num;
spinlock_t lock;
int open;
sja1000_isr chip_isr;
struct sja1000_admin * chip_isr_data;
};
static struct EM104_SJA1000_CHIP chip[2] = {
[0] = {
addr: (0xE0000000+0x00800000),
data: (0xE0000000+0x00a00000),
name: "can0",
num: -1,
lock: SPIN_LOCK_UNLOCKED,
open: 0
},
[1] = {
addr: (0xE0000000+0x00800000),
data: (0xE0000000+0x00c00000),
name: "can1",
num: -1,
lock: SPIN_LOCK_UNLOCKED,
open: 0
}
};
static struct sja1000_access access[2] = {
[0] = {
pOpenCanDevice: em104_sja1000_open,
pCloseCanDevice: em104_sja1000_close,
pWriteToRegister: em104_sja1000_writereg,
pReadFromRegister: em104_sja1000_readreg,
pRegisterIsr: em104_sja1000_register_isr,
pUnregisterIsr: em104_sja1000_unregister_isr,
bCanChipsetFlags: CANBUS_CFS_CAN_2_0_A | CANBUS_CFS_EXT_FRAME,
chipset_frequency: 16000000,
output_control_register: 0x1b
},
[1] = {
pOpenCanDevice: em104_sja1000_open,
pCloseCanDevice: em104_sja1000_close,
pWriteToRegister: em104_sja1000_writereg,
pReadFromRegister: em104_sja1000_readreg,
pRegisterIsr: em104_sja1000_register_isr,
pUnregisterIsr: em104_sja1000_unregister_isr,
bCanChipsetFlags: CANBUS_CFS_CAN_2_0_A | CANBUS_CFS_EXT_FRAME,
chipset_frequency: 16000000,
output_control_register: 0x1b
}
};
static void em104_sja1000_writereg(void * data, u8 reg, u8 val)
{
struct EM104_SJA1000_CHIP * self = (struct EM104_SJA1000_CHIP *) data;
TRACE("writereg(0x%2.2x,0x%2.2x)", reg, val);
outb(reg, self->addr);
outb(val, self->data);
}
static u8 em104_sja1000_readreg(void * data, u8 reg)
{
u8 val;
struct EM104_SJA1000_CHIP * self = (struct EM104_SJA1000_CHIP *) data;
outb(reg, self->addr);
val = inb(self->data);
TRACE("readreg(0x%2.2x) = 0x%2.2x", reg, val);
return val;
}
static int em104_sja1000_register_isr(void * data, sja1000_isr chip_isr, struct sja1000_admin * chip_isr_data)
{
struct EM104_SJA1000_CHIP * self = (struct EM104_SJA1000_CHIP *) data;
TRACE("register_isr()");
if (!self)
return -EINVAL;
self->chip_isr = chip_isr;
self->chip_isr_data = chip_isr_data;
return 0;
}
static int em104_sja1000_unregister_isr(void * data)
{
struct EM104_SJA1000_CHIP * self = (struct EM104_SJA1000_CHIP *) data;
TRACE("unregister_isr()");
if (!self)
return -EINVAL;
self->chip_isr = 0;
self->chip_isr_data = 0;
return 0;
}
static int em104_sja1000_open(void * data)
{
struct EM104_SJA1000_CHIP * self = (struct EM104_SJA1000_CHIP *) data;
int err;
TRACE("open()");
spin_lock(&self->lock);
do {
if (self->open) {
err = -EBUSY;
break;
}
self->open++;
em104_sja1000_writereg(self, 0x1e, 0x00); // reset, check it!!
} while (0);
spin_unlock(&self->lock);
return 0;
}
static int em104_sja1000_close(void * data)
{
TRACE("close()");
return 0;
}
static irqreturn_t em104_sja1000_isr(int irq, void *dev_id, struct pt_regs *regs)
{
struct EM104_SJA1000_CHIP * self = (struct EM104_SJA1000_CHIP *) dev_id;
static unsigned char vector;
vector = inb(0xE0000000 + 0x02200000);
if((vector&0x10)==0x00)
{
TRACE("can0 isr()");
if (!self)
return IRQ_NONE;
if (self->chip_isr)
self->chip_isr(self,self->chip_isr_data);
}
else if((vector&0x20)==0x00)
{
TRACE("can1 isr()");
if (!self)
return IRQ_NONE;
if (self->chip_isr)
self->chip_isr(self,self->chip_isr_data);
}
return IRQ_HANDLED;
}
int __init em104_sja1000_init(void)
{
unsigned int bswcon = inl((unsigned int)S3C2410_BWSCON);
bswcon = (bswcon & 0xFFFCFFFF) | 0x00000000;
outl(bswcon,(unsigned int)S3C2410_BWSCON);
bswcon = inl((unsigned int)S3C2410_BWSCON);
outb(~0xFF,0xE0000000+0x02600000);
set_irq_type(IRQ_EINT9,IRQT_FALLING);
if(request_irq(IRQ_EINT9, em104_sja1000_isr, SA_SHIRQ, "can isr", &chip[0]))
{
TRACE("request_irq(%d) failed", IRQ_EINT9);
return -ENOMEM;
}
TRACE("registering device %s", chip[0].name);
chip[0].num = sja1000_register_device(chip[0].name, CANBUS4LINUX_VERSION, &chip[0], &access[0], 0, 0);
if (chip[0].num == -1) {
TRACE("can0 sja1000_register_device() failed");
return -ENOMEM;
}
if(request_irq(IRQ_EINT9, em104_sja1000_isr, SA_SHIRQ, "can isr", &chip[1]))
{
TRACE("request_irq(%d) failed", IRQ_EINT9);
return -ENOMEM;
}
TRACE("registering device %s", chip[1].name);
chip[1].num = sja1000_register_device(chip[1].name, CANBUS4LINUX_VERSION, &chip[1], &access[1], 0, 1);
if (chip[1].num == -1) {
TRACE("can1 sja1000_register_device() failed");
return -ENOMEM;
}
return 0;
}
void __exit em104_sja1000_cleanup(void)
{
free_irq(IRQ_EINT9, &chip[0]);
}
module_init(em104_sja1000_init);
module_exit(em104_sja1000_cleanup);
MODULE_AUTHOR("JJJ <jiangjj@embedinfo.com>");
MODULE_DESCRIPTION("CAN driver for EM104 SJA1000");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -