[U-Boot] [RFC 3/5] CAN device driver for the SJA1000
Matthias Fuchs
matthias.fuchs at esd.eu
Mon Nov 2 13:02:20 CET 2009
Hi Wolfgang,
this patch conflicts with my simple SJA header posted some days ago
http://lists.denx.de/pipermail/u-boot/2009-October/063097.html
together with a fix for two of our boards - which has not much
to do with CAN. WD asked me to use a C struct to access the SJA1000.
http://lists.denx.de/pipermail/u-boot/2009-October/062902.html
So where does this bring us? Either we want to use C structs for everything
or decide it from patch to patch :-(
Matthias
On Sunday 01 November 2009 12:33, Wolfgang Grandegger wrote:
> 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__ */
> +
--
-------------------------------------------------------------------------
Dipl.-Ing. Matthias Fuchs
Head of System Design
esd electronic system design gmbh
Vahrenwalder Str. 207 - 30165 Hannover - GERMANY
Phone: +49-511-37298-0 - Fax: +49-511-37298-68
Please visit our homepage http://www.esd.eu
Quality Products - Made in Germany
-------------------------------------------------------------------------
Geschäftsführer: Klaus Detering, Dr. Werner Schulze
Amtsgericht Hannover HRB 51373 - VAT-ID DE 115672832
-------------------------------------------------------------------------
More information about the U-Boot
mailing list