[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