/* * jcan.c -- CAN driver for i82527 * * Copyright (C) 2003 George Cewe * Copyright (C) 2003 Advanced Concepts Inc. * Copyright (C) 2002 Alessandro Rubini * Copyright (C) 2002 System SpA * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * * This driver is a simplified version of "ocan" driver by Alessandro Rubini. * It supports one memory mapped Intel i82527 CAN chip, running under J1939 * protocol (250kBps, extended message id). * */ #define __NO_VERSION__ #include #include #include #include #include #include #include #include #include #ifdef __powerpc__ #include #endif #include "jcan.h" /*============================================================================= * Messaging stuff */ #undef PDEBUG /* undef it, just in case */ #ifdef CAN_DEBUG #ifdef __KERNEL__ /* This one if debugging is on, and kernel space */ #define PDEBUG(fmt, args...) printk(KERN_DEBUG CAN_TEXT fmt,##args) #else /* This one for user space */ #define PDEBUG(fmt, args...) fprintf(stdout, fmt, ##args) #endif #else /* nothing */ #define PDEBUG(fmt, args...) /* nothing */ #endif /* CAN_DEBUG */ #ifdef CAN_DEBUG #define debug 1 #else #define debug 0 #endif // base address and interrupt number #define IO_ADDR 0xffff0000 #define IO_RANGE 0x100 #define IRQ_NUM SIU_IRQ3 #ifndef CAN_MAJOR #define CAN_MAJOR 91 #endif #define CAN_NAME "jcan" #define CAN_TEXT "jcan: " /* * Sysctl constants */ #define DEV_CAN 2658 /* random for /proc/sys/dev/jcan/ */ /* inside /proc/sys/dev/jcan, each backend can use 100 keys */ /* * minor allocation: each device has 1 general entry point, 15 * message-buffer entry points and a few information/error files. * So it will need 5 bits. This accounts for up to eight devices */ #define CAN_DEV_TYPE(minor) ((minor)&0x1f) #define CAN_DEV_TYPE_GENERIC 0 /* 1..15 are the message objects */ #define CAN_DEV_TYPE_ERROR 16 #define CAN_DEV_TYPE_IO1 17 #define CAN_DEV_TYPE_IO2 18 #define CAN_DEV_NUM(minor) ((minor)>>5) /* * Device structures */ #define CAN_BUFSIZE 64 /* 64 pointers for msg packets */ // i82527 related definitions ============================================= #define I527_MSG_OBJS 16 /* 0 is the whole device, 1..15 are objects */ #define I527_FIRST_OBJ 1 /* 82527 address map (referred from base address) & internal bits. See the 82527 data-sheet page 9 and following */ #define I527_MAP_SIZE 0x100 #define I527_CTRL_REG 0x00 #define I527_CCE 0x40 #define I527_EIE 0x08 #define I527_SIE 0x04 #define I527_IE 0x02 #define I527_INIT 0x01 #define I527_STAT_REG 0x01 #define I527_STAT_REG_DEFAULT 0x07 #define I527_CPU_INT_REG 0x02 #define I527_RSTST 0x80 #define I527_DSC 0x40 #define I527_DMC 0x20 #define I527_PWD 0x10 #define I527_SLEEP 0x08 #define I527_MUX 0x04 #define I527_CEN 0x01 /* Reserved 0x03 */ #define I527_HI_SPEED_RD 0x04 #define I527_GMASK_STD 0x06 #define I527_GMASK_XTD 0x08 #define I527_MSG15_MASK 0x0c /* Message 1 0x10 */ #define I527_MSG_OFF 0x10 /* No size definition here */ #define I527_MSG_CTRL 0x00 #define I527_MSGVAL_R 0xff7f /* *********************** */ #define I527_MSGVAL_S 0xffbf /* WARNING!!! */ #define I527_TXIE_R 0xffdf /* These masks must be */ #define I527_TXIE_S 0xffef /* &-ed and *NOT* |-ed */ #define I527_RXIE_R 0xfff7 /* */ #define I527_RXIE_S 0xfffb /* */ #define I527_INTPND_R 0xfffd /* */ #define I527_INTPND_S 0xfffe /* */ #define I527_RMTPND_R 0x7fff /* WARNING!!! */ #define I527_RMTPND_S 0xbfff /* These masks must be */ #define I527_TXRQST_R 0xdfff /* &-ed and *NOT* |-ed */ #define I527_TXRQST_S 0xefff /* */ #define I527_MSGLST_R 0xf7ff /* */ #define I527_MSGLST_S 0xfbff /* */ #define I527_CPUUPD_R 0xf7ff /* WARNING!!! */ #define I527_CPUUPD_S 0xfbff /* These masks must be */ #define I527_NEWDAT_R 0xfdff /* &-ed and *NOT* |-ed */ #define I527_NEWDAT_S 0xfeff /* *********************** */ #define I527_MSG_ARBIT 0x02 #define I527_MSG_CFG 0x06 #define I527_DLC_MASK 0xf0 #define I527_DLC_SHIFT 4 #define I527_DLC_MASK0 0x0f #define I527_DIR 0x08 #define I527_DIR_TX 0x08 #define I527_DIR_RX 0x00 #define I527_XTD 0x04 #define I527_MSG_DATA 0x07 /* 8 bytes */ #define I527_CLKOUT_REG 0x1f #define I527_SL_MASK 0x30 #define I527_SL_SHIFT 4 #define I527_SL_MASK0 0x03 #define I527_CLKDIV_MASK 0x0f #define I527_CLKDIV_SHIFT 0 #define I527_CLKDIV_MASK0 0x0f /* Message 2 0x20 */ #define I527_BUSCFG_REG 0x2f #define I527_COBY 0x40 #define I527_POL 0x20 #define I527_DCT1 0x08 #define I527_DCR1 0x02 #define I527_DCR0 0x01 /* Message 3 0x30 */ #define I527_BITT0_REG 0x3f #define I527_SJW_MASK 0xc0 #define I527_SJW_SHIFT 0x06 #define I527_SJW_MASK0 0x03 #define I527_BRP_MASK 0x3f #define I527_BRP_SHIFT 0 #define I527_BRP_MASK0 0x3f /* Message 4 0x40 */ #define I527_BITT1_REG 0x4f #define I527_SPL_MASK 0x80 #define I527_SPL_SHIFT 7 #define I527_SPL_MASK0 0x01 #define I527_TSEG2_MASK 0x70 #define I527_TSEG2_SHIFT 4 #define I527_TSEG2_MASK0 0x07 #define I527_TSEG1_MASK 0x0f #define I527_TSEG1_SHIFT 0 #define I527_TSEG1_MASK0 0x0f /* Message 5 0x50 */ #define I527_INT_REG 0x5f /* Message 6 0x60 */ /* Reserved 0x6f */ /* Message 7 0x70 */ /* Reserved 0x7f */ /* Message 8 0x80 */ /* Reserved 0x8f */ /* Message 9 0x90 */ #define I527_P1CONF 0x9f /* Message 10 0xa0 */ #define I527_P2CONF 0xaf /* Message 11 0xb0 */ #define I527_P1IN 0xbf /* Message 12 0xc0 */ #define I527_P2IN 0xcf /* Message 13 0xd0 */ #define I527_P1OUT 0xdf /* Message 14 0xe0 */ #define I527_P2OUT 0xef /* Message 15 0xf0 */ #define I527_SER_RST_ADD 0xff typedef struct { __u8 cpuint; __u8 clkout; __u8 bittm0; __u8 bittm1; } CAN_BPS; /* * WARNING: can_times fields must all be __u8, because I sometimes * iniitalize it from arrays of bytes (for example dev->hal->h_defaults) */ typedef struct { __u8 t_dsc; __u8 t_dmc; __u8 t_clkout_div; __u8 t_clkout_slew; __u8 t_sjw; __u8 t_spl; __u8 t_brp; __u8 t_tseg1; __u8 t_tseg2; } CAN_TIMES; /* This is the MSGOBJ structure */ typedef struct { u32 obj_id; /* current id */ struct file *owner; /* someone is waiting for a message */ volatile u16 obj_flags; /* object-specific flags */ u8 regbase; /* register offset */ volatile u8 error; /* error on message */ spinlock_t lock; unsigned long flags; wait_queue_head_t read_q; /* read queue */ struct fasync_struct *async_read_q; /* async read queue */ wait_queue_head_t write_q; /* write queue */ struct fasync_struct *async_write_q; /* async write queue*/ volatile int head; volatile int tail; CAN_MSG **msg; /* allocated using CAN_BUFSIZE */; } CAN_MSGOBJ; /* object flags and error flags, used internally */ #define CAN_OBJFLAG_WRITE 0x01 /* being used to write/read */ #define CAN_OBJFLAG_READ 0x02 /* (same values as MSGFLAG) */ #define CAN_OBJFLAG_REMOTE 0x04 /* remote flag on */ #define CAN_OBJFLAG_HWBUSY 0x40 /* message is being transmitted */ #define CAN_OBJFLAG_BUSY 0x80 /* message is in use */ /* error notification via signals */ typedef struct { struct file *file; int signal; pid_t pid; } CAN_ERROR; #define CAN_NR_ERROR_FILES 4 /* at most 4 processes can get a signal */ typedef struct { u32 base; volatile u32 irq_count; u8 usecount; volatile u8 statusbyte; u8 registered; u8 gotirq; CAN_MSGOBJ *objs[I527_MSG_OBJS]; CAN_ERROR errorinfo[CAN_NR_ERROR_FILES]; wait_queue_head_t error_q; BPS eBps; } CAN_DEV; static kmem_cache_t *gpsCache; // The memory cache for msg packets static CAN_DEV gsDev; // The device data static const CAN_BPS gasBps[BPS_MAX] = { {0x40, 0x31, 0x03, 0x4d} // 100k ,{0x40, 0x31, 0x03, 0x49} // 125k ,{0x40, 0x31, 0x01, 0x49} // 250k ,{0x40, 0x31, 0x00, 0x49} // 500k ,{0x40, 0x31, 0x00, 0x14} // 1M }; static spinlock_t can_lock = SPIN_LOCK_UNLOCKED; ///////////////////////////////////////////////////////////////////////////// static int can_readb(CAN_DEV *dev, u_char reg) { return readb((volatile unsigned char *)(dev->base + reg)); } //--------------------------------------------------------------------------- static int can_writeb(CAN_DEV *dev, u_char reg, unsigned char val) { writeb(val, (volatile unsigned char *)(dev->base + reg)); return 0; } /*=========================================================================== * basic functions use direct methods */ #define i527_read_reg(dev, reg) \ (can_readb((dev), (reg))) #define i527_write_reg(dev, reg, value) \ (can_writeb((dev), (reg), (value))) /* * bit-setting operation and its use */ extern inline int i527_bits(CAN_DEV *dev, int reg, int bits, int value) { int res = i527_read_reg(dev, reg); if (res < 0) return res; res = (res & ~bits) | (bits & value); return i527_write_reg(dev, reg, res); } #define can_enable_irq(dev) i527_bits((dev), I527_CTRL_REG, \ I527_EIE|I527_IE, I527_EIE|I527_IE) #define can_disable_irq(dev) i527_bits((dev), I527_CTRL_REG, \ I527_EIE|I527_IE, 0) #define can_read_msg_dlc(dev, n) \ ((i527_read_msgcfg(dev, n) & I527_DLC_MASK) \ >> I527_DLC_SHIFT) #define can_write_msg_dlc(dev, n, dlc) \ (i527_bits((dev), n * I527_MSG_OFF + I527_MSG_CFG, \ I527_DLC_MASK, (dlc) << I527_DLC_SHIFT)) /* * Enable/disable configuration changes */ /* enable and return previous value */ extern inline int can_enable_cfg(CAN_DEV *dev) { int res = i527_read_reg(dev, I527_CTRL_REG); if (res < 0) return res; if (res & I527_CCE) return I527_CCE; res = i527_write_reg(dev, I527_CTRL_REG, res | I527_CCE); if (res < 0) return res; return 0; } /* disable and return previous value */ extern inline int can_disable_cfg(CAN_DEV *dev) { int res = i527_read_reg(dev, I527_CTRL_REG); if (res < 0) return res; if (!(res & I527_CCE)) return 0; res = i527_write_reg(dev, I527_CTRL_REG, res & ~I527_CCE); if (res < 0) return res; return I527_CCE; } /* restore previous value */ extern inline int can_restore_cfg(CAN_DEV *dev, int prev) { return i527_bits(dev, I527_CTRL_REG, I527_CCE, prev); } /* * higher level functions (can't be in i82527.h, for strange dependencies) */ extern inline int i527_read_msgcfg(CAN_DEV *dev, CAN_MSGOBJ *obj) { return i527_read_reg(dev, obj->regbase + I527_MSG_CFG); } extern inline int i527_write_msgcfg(CAN_DEV *dev, CAN_MSGOBJ *obj, int val) { if (val & ~0xff) return -EINVAL; return i527_write_reg(dev, obj->regbase + I527_MSG_CFG, val); } extern inline u16 i527_read_std_mask(CAN_DEV *dev) { /* errors are ignored, hmm... */ u16 ret = i527_read_reg(dev, I527_GMASK_STD) << 8 | i527_read_reg(dev, I527_GMASK_STD + 1); return ret; } extern inline void i527_write_std_mask(CAN_DEV *dev, u16 val) { /* errors are ignored, hmm... */ i527_write_reg(dev, I527_GMASK_STD, val >> 8); i527_write_reg(dev, I527_GMASK_STD + 1, val & 0xff); } extern inline u32 i527_read_x_mask(CAN_DEV *dev) { /* errors are ignored, hmm... */ u32 ret = i527_read_reg(dev, I527_GMASK_XTD) << 24 | i527_read_reg(dev, I527_GMASK_XTD + 1) << 16 | i527_read_reg(dev, I527_GMASK_XTD + 2) << 8 | i527_read_reg(dev, I527_GMASK_XTD + 3); return ret; } extern inline void i527_write_x_mask(CAN_DEV *dev, u32 val) { /* errors are ignored, hmm... */ i527_write_reg(dev, I527_GMASK_XTD, val >> 24); i527_write_reg(dev, I527_GMASK_XTD + 1, (val >> 16) & 0xff); i527_write_reg(dev, I527_GMASK_XTD + 2, (val >> 8) & 0xff); i527_write_reg(dev, I527_GMASK_XTD + 3, (val >> 0) & 0xff); } extern inline u32 i527_read_15_mask(CAN_DEV *dev) { /* errors are ignored, hmm... */ u32 ret = i527_read_reg(dev, I527_MSG15_MASK) << 24 | i527_read_reg(dev, I527_MSG15_MASK + 1) << 16 | i527_read_reg(dev, I527_MSG15_MASK + 2) << 8 | i527_read_reg(dev, I527_MSG15_MASK + 3); return ret; } extern inline void i527_write_15_mask(CAN_DEV *dev, u32 val) { /* errors are ignored, hmm... */ i527_write_reg(dev, I527_MSG15_MASK, val >> 24); i527_write_reg(dev, I527_MSG15_MASK + 1, (val >> 16) & 0xff); i527_write_reg(dev, I527_MSG15_MASK + 2, (val >> 8) & 0xff); i527_write_reg(dev, I527_MSG15_MASK + 3, (val >> 0) & 0xff); } extern inline u16 i527_read_msgctrl(CAN_DEV *dev, CAN_MSGOBJ *obj) { /* FIXME: this is used little-endian, but doesn't need to be 16b */ /* errors are ignored, hmm... */ u16 ret = i527_read_reg(dev, obj->regbase + I527_MSG_CTRL) | (i527_read_reg(dev, obj->regbase + I527_MSG_CTRL +1 ) << 8); return ret; } extern inline void i527_write_msgctrl(CAN_DEV *dev, CAN_MSGOBJ *obj, u16 val) { /* FIXME: this is used little-endian, but doesn't need to be 16b */ /* errors are ignored, hmm... */ i527_write_reg(dev, obj->regbase + I527_MSG_CTRL, val & 0xff); i527_write_reg(dev, obj->regbase + I527_MSG_CTRL + 1, val >> 8); } /* write a single byte of msgctrl, twice as fast as the function above */ extern inline void i527_msgflag(CAN_DEV *dev, CAN_MSGOBJ *obj, u16 act) { if ((act & 0xff) == 0xff) i527_write_reg(dev, obj->regbase + I527_MSG_CTRL + 1, act >> 8); else i527_write_reg(dev, obj->regbase + I527_MSG_CTRL, act & 0xff); } /* same, but for unallocated objects */ extern inline void i527_msgflag_noobj(CAN_DEV *dev, int msgnum, u16 act) { if ((act & 0xff) == 0xff) i527_write_reg(dev, msgnum*I527_MSG_OFF + I527_MSG_CTRL + 1, act >> 8); else i527_write_reg(dev, msgnum*I527_MSG_OFF + I527_MSG_CTRL, act & 0xff); } /* read a single byte of msgctrl (use the _S flag. Hm....) */ extern inline int i527_check_msgflag(CAN_DEV *dev, CAN_MSGOBJ *obj, u16 act) { u16 reg; if ((act & 0xff) == 0xff) { reg = i527_read_reg(dev, obj->regbase + I527_MSG_CTRL + 1); return !((reg << 8) & ~act); } reg = i527_read_reg(dev, obj->regbase + I527_MSG_CTRL); return !(reg & ~act); } extern inline u32 i527_read_msgarb(CAN_DEV *dev, CAN_MSGOBJ *obj) { int port = obj->regbase + I527_MSG_ARBIT; /* errors are ignored, hmm... */ u32 ret = i527_read_reg(dev, port) << 24 | i527_read_reg(dev, port + 1) << 16 | i527_read_reg(dev, port + 2) << 8 | i527_read_reg(dev, port + 3); return ret; } extern inline void i527_write_msgarb(CAN_DEV *dev, CAN_MSGOBJ *obj, u32 val) { int port = obj->regbase + I527_MSG_ARBIT; i527_write_reg(dev, port, val >> 24); i527_write_reg(dev, port + 1, (val >> 16) & 0xff); i527_write_reg(dev, port + 2, (val >> 8) & 0xff); i527_write_reg(dev, port + 3, (val >> 0) & 0xff); } extern inline void i527_read_msgdata(CAN_DEV *dev, CAN_MSGOBJ *obj, int n, u8 *data) { int i; u8 reg = obj->regbase + I527_MSG_DATA; for (i=0; iregbase + I527_MSG_DATA; if (!n) return; i527_msgflag(dev, obj, I527_CPUUPD_S); /* CPU updating */ for (i=0; i