From: Wolfgang Grandegger <w...@denx.de> Signed-off-by: Wolfgang Grandegger <w...@denx.de> --- drivers/can/Makefile | 3 +- drivers/can/sja1000.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++ include/sja1000.h | 159 +++++++++++++++++++++++++++++++++++ 3 files changed, 384 insertions(+), 1 deletions(-) create mode 100644 drivers/can/sja1000.c create mode 100644 include/sja1000.h
diff --git a/drivers/can/Makefile b/drivers/can/Makefile index 74d2ff5..e2b6bd6 100644 --- a/drivers/can/Makefile +++ b/drivers/can/Makefile @@ -25,7 +25,8 @@ include $(TOPDIR)/config.mk LIB := $(obj)libcan.a -COBJS-$(CONFIG_CAN) += can.o +COBJS-$(CONFIG_CAN) += can.o +COBJS-$(CONFIG_CAN_SJA1000) += sja1000.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/can/sja1000.c b/drivers/can/sja1000.c new file mode 100644 index 0000000..b75f01c --- /dev/null +++ b/drivers/can/sja1000.c @@ -0,0 +1,223 @@ +/* + * (C) Copyright 2007-2009, Wolfgang Grandegger <w...@denx.de> + * + * Derived from Xenomai's RT-Socket-CAN driver for SJA1000: + * + * Copyright (C) 2005,2006 Sebastian Smolorz + * <sebastian.smol...@stud.uni-hannover.de> + * + * Copyright (C) 2005, Sascha Hauer, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + */ + +#include <common.h> +#include <asm/io.h> + +#include <can.h> +#include <sja1000.h> + +#define SJA1000_OCR (SJA_OCR_MODE_NORMAL | SJA_OCR_TX0_PUSHPULL) +#define SJA1000_CDR SJA_CDR_CAN_MODE + +/* + * Basic functions to access registers + */ +#define sja1000_read_reg(dev, reg) \ + in_8 ((volatile u8 *)((dev)->base + (reg))) + +#define sja1000_write_reg(dev, reg, value) \ + out_8 ((volatile u8 *)((dev)->base + (reg)), value) + +/* + * Baudrate table + */ + +static u16 sja1000_btr0btr1[] = { + 0x031c, /* 125K */ + 0x011c, /* 250K */ + 0x001c, /* 500K */ +}; + +int sja1000_init (struct can_dev *dev, unsigned int ibaud) +{ + int i, wait = 1000; + u16 btr0btr1; + + /* Disable the controller's interrupts */ + sja1000_write_reg (dev, SJA_IER, 0x00); + + /* Set reset mode bit */ + sja1000_write_reg (dev, SJA_MOD, SJA_MOD_RM); + + /* Read reset mode bit, multiple tests */ + do { + udelay (100); + if (sja1000_read_reg (dev, SJA_MOD) & SJA_MOD_RM) + break; + } while (--wait); + + sja1000_write_reg (dev, SJA_CDR, SJA1000_CDR); + sja1000_write_reg (dev, SJA_OCR, SJA1000_OCR); + + sja1000_write_reg (dev, SJA_AMR0, 0xFF); + sja1000_write_reg (dev, SJA_AMR1, 0xFF); + sja1000_write_reg (dev, SJA_AMR2, 0xFF); + sja1000_write_reg (dev, SJA_AMR3, 0xFF); + + sja1000_write_reg (dev, SJA_RXERR, 0); + sja1000_write_reg (dev, SJA_TXERR, 0); + + i = sizeof (sja1000_btr0btr1) / sizeof (u16); + if (ibaud >= i) + ibaud = i - 1; + btr0btr1 = sja1000_btr0btr1[ibaud]; + sja1000_write_reg (dev, SJA_BTR0, (btr0btr1 >> 8) & 0xff); + sja1000_write_reg (dev, SJA_BTR1, (btr0btr1 & 0xff)); + + /* Clear error code capture (i.e. read it) */ + sja1000_read_reg (dev, SJA_ECC); + + /* Clear reset mode bit in SJA1000 */ + sja1000_write_reg (dev, SJA_MOD, 0); + + return 0; +} + +int sja1000_xmit (struct can_dev *dev, struct can_msg *msg) +{ + int i; + u8 fir; + + if (msg->dlc > 8) + msg->dlc = 8; + fir = msg->dlc; + + sja1000_write_reg (dev, SJA_ID1, msg->id >> 3); + sja1000_write_reg (dev, SJA_ID2, msg->id << 5); + for (i = 0; i < msg->dlc; i++) + sja1000_write_reg (dev, SJA_DATA_SFF (i), msg->data[i]); + + /* Write frame information register */ + sja1000_write_reg (dev, SJA_FIR, fir); + + /* Push the 'send' button */ + sja1000_write_reg (dev, SJA_CMR, SJA_CMR_TR); + + /* Wait some time */ + for (i = 0; i < CAN_XMIT_TIMEOUT_US; i += 10000) { + if (sja1000_read_reg (dev, SJA_SR) & SJA_SR_TCS) + return 0; + if (ctrlc ()) + break; + udelay (10000); + } + + return -1; +} + +int sja1000_recv (struct can_dev *dev, struct can_msg *msg) +{ + int i; + u8 fir; + + while (!(sja1000_read_reg (dev, SJA_SR) & SJA_SR_RBS)) { + if (ctrlc ()) + return -1; + } + + /* Read out frame information register */ + fir = sja1000_read_reg (dev, SJA_FIR); + + /* Extract data length code */ + msg->dlc = fir & SJA_FIR_DLC_MASK; + + /* If DLC exceeds 8 bytes adjust it to 8 (for the payload size) */ + if (msg->dlc > 8) + msg->dlc = 8; + + if (fir & SJA_FIR_EFF) { + printf ("Extended CAN messages not supported\n"); + return -1; + } else { + msg->id = sja1000_read_reg (dev, SJA_ID1) << 3; + msg->id |= sja1000_read_reg (dev, SJA_ID2) >> 5; + + if (!(fir & SJA_FIR_RTR)) { + for (i = 0; i < msg->dlc; i++) + msg->data[i] = + sja1000_read_reg (dev, SJA_DATA_SFF (i)); + } + } + if (fir & SJA_FIR_RTR) + msg->id |= CAN_RTR_FLAG; + + /* Release Receive Buffer */ + sja1000_write_reg (dev, SJA_CMR, SJA_CMR_RRB); + + return 0; +} + +int sja1000_status (struct can_dev *dev, int level) +{ + printf ("SJA1000 at %#x", dev->base); + if (level > 0) { + int stat = sja1000_read_reg (dev, SJA_SR) & 0xff; + printf (", status 0x%02x", stat); + if (stat & SJA_SR_BS) + puts (" busoff"); + if (stat & SJA_SR_ES) + puts (" error"); + if (stat & SJA_SR_TS) + puts (" txing"); + if (stat & SJA_SR_RS) + puts (" rxing"); + if (stat & SJA_SR_TCS) + puts (" txdone"); + if (stat & SJA_SR_TBS) + puts (" txfree"); + if (stat & SJA_SR_DOS) + puts (" overrun"); + if (stat & SJA_SR_RBS) + puts (" rxfull"); + } + puts ("\n"); + if (level > 1) { + int i; + for (i = 0; i < SJA1000_SIZE; i++) { + if ((i % 0x10) == 0) + printf ("\n%02x:", i); + printf (" %02x", sja1000_read_reg (dev, i)); + } + puts ("\n"); + } + return 0; +} + +void sja1000_register (struct can_dev *dev, unsigned long base) +{ + dev->name = "sja1000"; + dev->base = base; + dev->init = sja1000_init; + dev->xmit = sja1000_xmit; + dev->recv = sja1000_recv; + dev->status = sja1000_status; + + can_register (dev); +} diff --git a/include/sja1000.h b/include/sja1000.h new file mode 100644 index 0000000..56b43bf --- /dev/null +++ b/include/sja1000.h @@ -0,0 +1,159 @@ +/* + * (C) Copyright 2007-2009, Wolfgang Grandegger <w...@denx.de> + * + * Derived from Xenomai's RT-Socket-CAN driver for SJA1000: + * + * Copyright (C) 2005,2006 Sebastian Smolorz + * <sebastian.smol...@stud.uni-hannover.de> + * + * Copyright (C) 2005, Sascha Hauer, Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + */ + +#ifndef __SJA1000_H__ +#define __SJA1000_H__ + +#include <can.h> + +/* PeliCAN mode address map */ + +/* reset and operating mode */ +#define SJA_MOD 0 /* Mode register */ +#define SJA_CMR 1 /* Command register */ +#define SJA_SR 2 /* Status register */ +#define SJA_IR 3 /* Interrupt register */ +#define SJA_IER 4 /* Interrupt enable register */ +#define SJA_BTR0 6 /* Bus timing register 0 */ +#define SJA_BTR1 7 /* Bus timing register 1 */ +#define SJA_OCR 8 /* Output control register */ +#define SJA_ALC 11 /* Arbitration lost capture */ +#define SJA_ECC 12 /* Error code capture register */ +#define SJA_RXERR 14 /* Receive error counter */ +#define SJA_TXERR 15 /* Transmit error counter */ +#define SJA_CDR 31 /* Clock divider register */ + +/* reset mode */ +#define SJA_ACR0 16 /* Acceptance code register 0 */ +#define SJA_ACR1 17 /* Acceptance code register 1 */ +#define SJA_ACR2 18 /* Acceptance code register 2 */ +#define SJA_ACR3 19 /* Acceptance code register 3 */ +#define SJA_AMR0 20 /* Acceptance mask register 0 */ +#define SJA_AMR1 21 /* Acceptance mask register 1 */ +#define SJA_AMR2 22 /* Acceptance mask register 2 */ +#define SJA_AMR3 23 /* Acceptance mask register 3 */ + +/* operating mode */ +#define SJA_FIR 16 /* Frame information register */ +#define SJA_ID1 17 /* Identifier 1 */ +#define SJA_ID2 18 /* Identifier 2 */ +#define SJA_ID3 19 /* Identifier 3 (EFF only) */ +#define SJA_ID4 20 /* Identifier 4 (EFF only) */ + +#define SJA_DATA_SFF(x) (19 + (x)) /* Data registers in case of standard + * frame format; 0 <= x <= 7 */ +#define SJA_DATA_EFF(x) (21 + (x)) /* Data registers in case of extended + * frame format; 0 <= x <= 7 */ +/* Mode register */ +#define SJA_MOD_RM (1<<0) /* Reset Mode */ +#define SJA_MOD_LOM (1<<1) /* Listen Only Mode */ +#define SJA_MOD_STM (1<<2) /* Self Test Mode */ +#define SJA_MOD_AFM (1<<3) /* Acceptance Filter Mode */ +#define SJA_MOD_SM (1<<4) /* Sleep Mode */ + +/* Command register */ +#define SJA_CMR_TR (1<<0) /* Transmission request */ +#define SJA_CMR_AT (1<<1) /* Abort Transmission */ +#define SJA_CMR_RRB (1<<2) /* Release Receive Buffer */ +#define SJA_CMR_CDO (1<<3) /* Clear Data Overrun */ +#define SJA_CMR_SRR (1<<4) /* Self reception request */ + +/* Status register */ +#define SJA_SR_RBS (1<<0) /* Receive Buffer Status */ +#define SJA_SR_DOS (1<<1) /* Data Overrun Status */ +#define SJA_SR_TBS (1<<2) /* Transmit Buffer Status */ +#define SJA_SR_TCS (1<<3) /* Transmission Complete Status */ +#define SJA_SR_RS (1<<4) /* Receive Status */ +#define SJA_SR_TS (1<<5) /* Transmit Status */ +#define SJA_SR_ES (1<<6) /* Error Status */ +#define SJA_SR_BS (1<<7) /* Bus Status */ + +/* Interrupt register */ +#define SJA_IR_RI (1<<0) /* Receive Interrupt */ +#define SJA_IR_TI (1<<1) /* Transmit Interrupt */ +#define SJA_IR_EI (1<<2) /* Error Warning Interrupt */ +#define SJA_IR_DOI (1<<3) /* Data Overrun Interrupt */ +#define SJA_IR_WUI (1<<4) /* Wake-Up Interrupt */ +#define SJA_IR_EPI (1<<5) /* Error Passive Interrupt */ +#define SJA_IR_ALI (1<<6) /* Arbitration Lost Interrupt */ +#define SJA_IR_BEI (1<<7) /* Bus Error Interrupt */ + +/* Interrupt enable register */ +#define SJA_IER_RIE (1<<0) /* Receive Interrupt Enable */ +#define SJA_IER_TIE (1<<1) /* Transmit Interrupt Enable */ +#define SJA_IER_EIE (1<<2) /* Error Warning Interrupt Enable */ +#define SJA_IER_DOIE (1<<3) /* Data Overrun Interrupt Enable */ +#define SJA_IER_WUIE (1<<4) /* Wake-Up Interrupt Enable */ +#define SJA_IER_EPIE (1<<5) /* Error Passive Interrupt Enable */ +#define SJA_IER_ALIE (1<<6) /* Arbitration Lost Interrupt Enable */ +#define SJA_IER_BEIE (1<<7) /* Bus Error Interrupt Enable */ + +/* Output control register */ +#define SJA_OCR_MODE_BIPHASE 0 +#define SJA_OCR_MODE_TEST 1 +#define SJA_OCR_MODE_NORMAL 2 +#define SJA_OCR_MODE_CLOCK 3 +#define SJA_OCR_TX0_INVERT (1<<2) +#define SJA_OCR_TX0_PULLDOWN (1<<3) +#define SJA_OCR_TX0_PULLUP (2<<3) +#define SJA_OCR_TX0_PUSHPULL (3<<3) +#define SJA_OCR_TX1_INVERT (1<<5) +#define SJA_OCR_TX1_PULLDOWN (1<<6) +#define SJA_OCR_TX1_PULLUP (2<<6) +#define SJA_OCR_TX1_PUSHPULL (3<<6) + +/* Error code capture register */ + +/* + * The segmentation field gives information about the location of + * errors on the bus + */ +#define SJA_ECC_SEG_MASK 31 /* Segmentation field mask */ +#define SJA_ECC_DIR (1<<5) /* Transfer direction */ +#define SJA_ECC_ERR_BIT (0<<6) +#define SJA_ECC_ERR_FORM (1<<6) +#define SJA_ECC_ERR_STUFF (2<<6) +#define SJA_ECC_ERR_MASK (3<<6) /* Error code mask */ + +/* Frame information register */ +#define SJA_FIR_DLC_MASK 15 /* Data length code mask */ +#define SJA_FIR_RTR (1<<6) /* Remote transmission request */ +#define SJA_FIR_EFF (1<<7) /* Extended frame format */ + +/* Clock divider register */ +#define SJA_CDR_CLK_OFF (1<<3) /* Clock off (CLKOUT pin) */ +#define SJA_CDR_CBP (1<<6) /* CAN input comparator bypass */ +#define SJA_CDR_CAN_MODE (1<<7) /* CAN mode: 1 = PeliCAN */ + +#define SJA1000_SIZE 0x80 + +void sja1000_register (struct can_dev *dev, unsigned long base); + +#endif /* __SJA1000_H__ */ + -- 1.6.2.5 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot