[U-Boot] [RFC 3/5] CAN device driver for the SJA1000
Wolfgang Grandegger
wg at grandegger.com
Sun Nov 1 12:33:35 CET 2009
From: Wolfgang Grandegger <wg at denx.de>
Signed-off-by: Wolfgang Grandegger <wg at 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 <wg at denx.de>
+ *
+ * Derived from Xenomai's RT-Socket-CAN driver for SJA1000:
+ *
+ * Copyright (C) 2005,2006 Sebastian Smolorz
+ * <Sebastian.Smolorz at 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 <wg at denx.de>
+ *
+ * Derived from Xenomai's RT-Socket-CAN driver for SJA1000:
+ *
+ * Copyright (C) 2005,2006 Sebastian Smolorz
+ * <Sebastian.Smolorz at 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
More information about the U-Boot
mailing list