[U-Boot] [RFC 0/5] CAN framework for U-Boot

From: Wolfgang Grandegger wg@denx.de
This patch series adds a simple CAN framework for U-Boot. The main purpose is to do simple RX/TX testing when the device boots up but the interface functions could also be used for more complex tasks. This is just a RFC and a few more features need to be added or issues to be fixed, like using a generic device interface, if it already exists, and board specific device configuration, e.g. via i82527_register(addr, cfg-params). The sources are based on GPL v2+ code to be compatible with future U-Boot licence requirement.
Please comment.
Wolfgang
Wolfgang Grandegger (5): CAN interface library CAN device test command CAN device driver for the SJA1000 CAN device driver for the Intel 82527 CAN interface support for the TQM855L module
Makefile | 1 + board/tqc/tqm8xx/tqm8xx.c | 17 ++ common/Makefile | 1 + common/cmd_can.c | 119 +++++++++++++++ drivers/can/Makefile | 49 ++++++ drivers/can/can.c | 88 +++++++++++ drivers/can/i82527.c | 366 +++++++++++++++++++++++++++++++++++++++++++++ drivers/can/sja1000.c | 223 +++++++++++++++++++++++++++ include/can.h | 70 +++++++++ include/configs/TQM855L.h | 8 +- include/i82527.h | 201 +++++++++++++++++++++++++ include/sja1000.h | 159 ++++++++++++++++++++ 12 files changed, 1301 insertions(+), 1 deletions(-) create mode 100644 common/cmd_can.c create mode 100644 drivers/can/Makefile create mode 100644 drivers/can/can.c create mode 100644 drivers/can/i82527.c create mode 100644 drivers/can/sja1000.c create mode 100644 include/can.h create mode 100644 include/i82527.h create mode 100644 include/sja1000.h

From: Wolfgang Grandegger wg@denx.de
Signed-off-by: Wolfgang Grandegger wg@denx.de --- Makefile | 1 + drivers/can/Makefile | 47 ++++++++++++++++++++++++++ drivers/can/can.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/can.h | 70 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 0 deletions(-) create mode 100644 drivers/can/Makefile create mode 100644 drivers/can/can.c create mode 100644 include/can.h
diff --git a/Makefile b/Makefile index bcb3fe9..dca15e0 100644 --- a/Makefile +++ b/Makefile @@ -203,6 +203,7 @@ LIBS += net/libnet.a LIBS += disk/libdisk.a LIBS += drivers/bios_emulator/libatibiosemu.a LIBS += drivers/block/libblock.a +LIBS += drivers/can/libcan.a LIBS += drivers/dma/libdma.a LIBS += drivers/fpga/libfpga.a LIBS += drivers/gpio/libgpio.a diff --git a/drivers/can/Makefile b/drivers/can/Makefile new file mode 100644 index 0000000..74d2ff5 --- /dev/null +++ b/drivers/can/Makefile @@ -0,0 +1,47 @@ +# +# Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 $(TOPDIR)/config.mk + +LIB := $(obj)libcan.a + +COBJS-$(CONFIG_CAN) += can.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################## diff --git a/drivers/can/can.c b/drivers/can/can.c new file mode 100644 index 0000000..c09bccf --- /dev/null +++ b/drivers/can/can.c @@ -0,0 +1,88 @@ +/* + * (C) Copyright 2007-2009, Wolfgang Grandegger wg@denx.de + * + * 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 + */ + +/* + * CAN device interface library + */ +#include <common.h> +#include <command.h> +#include <can.h> + +static struct can_dev *can_devs; + +static char *baudrates[] = { "125K", "250K", "500K" }; + +int can_register (struct can_dev* can_dev) +{ + struct can_dev* dev; + + can_dev->next = NULL; + if (!can_devs) + can_devs = can_dev; + else { + for (dev = can_devs; dev->next; dev = dev->next) + ; + dev->next = can_dev; + } + + printf ("CAN: %s at %lx registered\n", can_dev->name, can_dev->base); + + return 0; +} + +struct can_dev *can_init (int dev_num, int ibaud) +{ + struct can_dev *dev; + int i; + + if (!can_devs) { + puts ("No CAN devices registered\n"); + return NULL; + } + + /* Advance to selected device */ + for (i = 0, dev = can_devs; dev; i++, dev = dev->next) { + if (i == dev_num) + break; + } + + if (!dev) { + printf ("CAN device %d does not exist\n", dev_num); + return NULL; + } + + printf ("Initializing CAN%d at 0x%08x with baudrate %s\n", + i, dev->base, baudrates[ibaud]); + + dev->init (dev, ibaud); + + return dev; +} + +void can_list (void) +{ + struct can_dev *dev; + int i; + + for (i = 0, dev = can_devs; dev; i++, dev = dev->next) + printf ("CAN%d: %s at 0x%p\n", i, dev->name, dev->base); +} diff --git a/include/can.h b/include/can.h new file mode 100644 index 0000000..5f5c3c1 --- /dev/null +++ b/include/can.h @@ -0,0 +1,70 @@ +/* + * (C) Copyright 2007-2009, Wolfgang Grandegger wg@denx.de + * + * 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 __CAN_H__ +#define __CAN_H__ + +#define CAN_XMIT_TIMEOUT_US 1000000 + +#define CAN_EFF_MASK 0x1FFFFFFF +#define CAN_SFF_MASK 0x000007FF + +#define CAN_EFF_FLAG 0x80000000 +#define CAN_RTR_FLAG 0x40000000 + +struct can_msg { + u32 id; + u8 data[8]; + u8 dlc; + u8 flags; +}; + +struct can_dev { + char *name; + unsigned long base; + int (*init) (struct can_dev *dev, unsigned int ibaud); + int (*xmit) (struct can_dev *dev, struct can_msg *msg); + int (*recv) (struct can_dev *dev, struct can_msg *msg); + int (*status) (struct can_dev *dev, int level); + struct can_dev *next; +}; + +static inline int can_status (struct can_dev *dev, int level) +{ + return dev->status (dev, level); +} + +static inline int can_recv (struct can_dev *dev, struct can_msg *msg) +{ + return dev->recv (dev, msg); +} + +static inline int can_xmit (struct can_dev *dev, struct can_msg *msg) +{ + return dev->xmit (dev, msg); +} + +int can_register (struct can_dev* dev); +struct can_dev *can_init (int dev_nr, int ibaud); +void can_list (void); + +#endif /* __CAN_H__ */

From: Wolfgang Grandegger wg@denx.de
Signed-off-by: Wolfgang Grandegger wg@denx.de --- common/Makefile | 1 + common/cmd_can.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 0 deletions(-) create mode 100644 common/cmd_can.c
diff --git a/common/Makefile b/common/Makefile index 3781738..b7f4c22 100644 --- a/common/Makefile +++ b/common/Makefile @@ -72,6 +72,7 @@ COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o +COBJS-$(CONFIG_CMD_CAN) += cmd_can.o COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o COBJS-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o diff --git a/common/cmd_can.c b/common/cmd_can.c new file mode 100644 index 0000000..af7bf34 --- /dev/null +++ b/common/cmd_can.c @@ -0,0 +1,119 @@ +/* + * (C) Copyright 2007-2009, Wolfgang Grandegger wg@denx.de + * + * 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 + */ + +/* + * CAN device test command + */ +#include <common.h> +#include <command.h> +#include <can.h> + +static struct can_dev *can_dev; + +int do_can (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + struct can_msg msg; + char op; + int i; + + op = argv[1][0]; + + if (argc < 2) { + can_list (); + return 0; + } + + if (!can_dev && op != 'i') { + can_dev = can_init (0, 0); + if (!can_dev) + return 1; + } + + if (op == 's') { + unsigned int level = 0; + if (argc > 2) + level = simple_strtoul (argv[2], NULL, 10); + can_status (can_dev, level); + } + + else if (op == 'i') { + unsigned int dev_num = 0, ibaud = 0; + struct can_dev *dev; + + if (argc > 2) + dev_num = simple_strtoul (argv[2], NULL, 10); + if (argc > 3) { + ibaud = simple_strtoul (argv[3], NULL, 10); + if (ibaud > 2) + ibaud = 2; + } + dev = can_init (dev_num, ibaud); + if (!dev) + return 1; + can_dev = dev; + } + + else if (op == 'r') { + while (!can_recv (can_dev, &msg)) { + printf ("<0x%03x>", msg.id & CAN_SFF_MASK); + + printf (" [%d]", msg.dlc); + if (msg.id & CAN_RTR_FLAG) + puts (" rtr"); + else { + for (i = 0; i < msg.dlc; i++) + printf (" %02x", msg.data[i]); + } + puts ("\n"); + } + } else if (op == 'x') { + memset (&msg, 0, sizeof (msg)); + msg.id = 0x123; + if (argc > 2) + msg.id = simple_strtoul (argv[2], NULL, 16); + for (i = 0; argc > (3 + i); i++, msg.dlc++) { + msg.data[i] = simple_strtoul (argv[3 + i], NULL, 16); + } + if (argc == 2) + printf ("Transmitting id %#x dlc %d\n", + msg.id, msg.dlc); + + if (can_xmit (can_dev, &msg)) + puts("FAILED\n"); + else + puts("OK\n"); + } else { + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + return 0; +} + +U_BOOT_CMD( + can, 3, 1, do_can, + "can - CAN bus commands\n", + "can status [level]\n" + "can init [dev] [baud-index]\n" + "can xmit [id] [d0] [d1] ... [d7]\n" + "can recv, abort with CTRL-C\n" +);

From: Wolfgang Grandegger wg@denx.de
Signed-off-by: Wolfgang Grandegger wg@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@denx.de + * + * Derived from Xenomai's RT-Socket-CAN driver for SJA1000: + * + * Copyright (C) 2005,2006 Sebastian Smolorz + * Sebastian.Smolorz@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@denx.de + * + * Derived from Xenomai's RT-Socket-CAN driver for SJA1000: + * + * Copyright (C) 2005,2006 Sebastian Smolorz + * Sebastian.Smolorz@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__ */ +

From: Wolfgang Grandegger wg@denx.de
Signed-off-by: Wolfgang Grandegger wg@denx.de --- drivers/can/Makefile | 1 + drivers/can/i82527.c | 366 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/i82527.h | 201 +++++++++++++++++++++++++++ 3 files changed, 568 insertions(+), 0 deletions(-) create mode 100644 drivers/can/i82527.c create mode 100644 include/i82527.h
diff --git a/drivers/can/Makefile b/drivers/can/Makefile index e2b6bd6..d550a45 100644 --- a/drivers/can/Makefile +++ b/drivers/can/Makefile @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libcan.a
COBJS-$(CONFIG_CAN) += can.o +COBJS-$(CONFIG_CAN_I82527) += i82527.o COBJS-$(CONFIG_CAN_SJA1000) += sja1000.o
COBJS := $(COBJS-y) diff --git a/drivers/can/i82527.c b/drivers/can/i82527.c new file mode 100644 index 0000000..b3eacd6 --- /dev/null +++ b/drivers/can/i82527.c @@ -0,0 +1,366 @@ +/* + * (C) Copyright 2007-2009, Wolfgang Grandegger wg@denx.de + * + * Derived from OCAN driver: + * + * Copyright (C) 2002 Alessandro Rubini rubini@linux.it + * Copyright (C) 2002 System SpA info.electronics@system-group.it + * + * 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 <i82527.h> + +#define I82527_TX_OBJ 1 +#define I82527_RX_OBJ 15 + +/* + * Basic functions to access registers + */ +#define i82527_read_reg(dev, reg) \ + in_8 ((volatile u8 *)((dev)->base + (reg))) + +#define i82527_write_reg(dev, reg, value) \ + out_8 ((volatile u8 *)((dev)->base + (reg)), value) + +/* + * Higher level functions + */ +static inline int i82527_read_msgcfg (struct can_dev *dev, int iobj) +{ + return i82527_read_reg (dev, (iobj * I82527_MSG_OFF) + I82527_MSG_CFG); +} + +static inline void i82527_write_msgcfg (struct can_dev *dev, int iobj, int val) +{ + i82527_write_reg (dev, (iobj * I82527_MSG_OFF) + I82527_MSG_CFG, val); +} + +static inline void i82527_write_std_mask (struct can_dev *dev, u16 val) +{ + /* errors are ignored, hmm... */ + i82527_write_reg (dev, I82527_GMASK_STD, val >> 8); + i82527_write_reg (dev, I82527_GMASK_STD + 1, val & 0xff); +} + +static inline void i82527_write_x_mask (struct can_dev *dev, u32 val) +{ + /* errors are ignored, hmm... */ + i82527_write_reg (dev, I82527_GMASK_XTD, val >> 24); + i82527_write_reg (dev, I82527_GMASK_XTD + 1, (val >> 16) & 0xff); + i82527_write_reg (dev, I82527_GMASK_XTD + 2, (val >> 8) & 0xff); + i82527_write_reg (dev, I82527_GMASK_XTD + 3, (val >> 0) & 0xff); +} + +static inline void i82527_write_15_mask (struct can_dev *dev, u32 val) +{ + /* errors are ignored, hmm... */ + i82527_write_reg (dev, I82527_MSG15_MASK, val >> 24); + i82527_write_reg (dev, I82527_MSG15_MASK + 1, (val >> 16) & 0xff); + i82527_write_reg (dev, I82527_MSG15_MASK + 2, (val >> 8) & 0xff); + i82527_write_reg (dev, I82527_MSG15_MASK + 3, (val >> 0) & 0xff); +} + +static inline void i82527_write_msgctrl (struct can_dev *dev, int iobj, u16 val) +{ + /* FIXME: this is used little-endian, but doesn't need to be 16b */ + + /* errors are ignored, hmm... */ + i82527_write_reg (dev, (iobj * I82527_MSG_OFF) + + I82527_MSG_CTRL, val & 0xff); + i82527_write_reg (dev, (iobj * I82527_MSG_OFF) + + I82527_MSG_CTRL + 1, val >> 8); +} + +/* write a single byte of msgctrl, twice as fast as the function above */ +static inline void i82527_msgflag (struct can_dev *dev, int iobj, u16 act) +{ + if ((act & 0xff) == 0xff) + i82527_write_reg (dev, (iobj * I82527_MSG_OFF) + + I82527_MSG_CTRL + 1, act >> 8); + else + i82527_write_reg (dev, (iobj * I82527_MSG_OFF) + + I82527_MSG_CTRL, act & 0xff); +} + +static inline u32 i82527_read_msgarb (struct can_dev *dev, int iobj) +{ + int port = (iobj * I82527_MSG_OFF) + I82527_MSG_ARBIT; + + u32 ret = (i82527_read_reg (dev, port) << 24 | + i82527_read_reg (dev, port + 1) << 16 | + i82527_read_reg (dev, port + 2) << 8 | + i82527_read_reg (dev, port + 3)); + return ret; +} + +static inline void i82527_write_msgarb (struct can_dev *dev, int iobj, u32 val) +{ + int port = (iobj * I82527_MSG_OFF) + I82527_MSG_ARBIT; + i82527_write_reg (dev, port, val >> 24); + i82527_write_reg (dev, port + 1, (val >> 16) & 0xff); + i82527_write_reg (dev, port + 2, (val >> 8) & 0xff); + i82527_write_reg (dev, port + 3, (val >> 0) & 0xff); +} + +static inline void i82527_read_msgdata (struct can_dev *dev, int iobj, + int n, u8 * data) +{ + int i; + u8 reg = (iobj * I82527_MSG_OFF) + I82527_MSG_DATA; + + for (i = 0; i < n; i++) + data[i] = i82527_read_reg (dev, reg++); +} + +static inline void i82527_write_msgdata (struct can_dev *dev, int iobj, + int n, u8 * data) +{ + int i; + u8 reg = (iobj * I82527_MSG_OFF) + I82527_MSG_DATA; + + if (!n) + return; + i82527_msgflag (dev, iobj, I82527_CPUUPD_S); /* CPU updating */ + for (i = 0; i < n && i < 8; i++) + i82527_write_reg (dev, reg++, data[i]); + i82527_msgflag (dev, iobj, I82527_CPUUPD_R); +} + +static struct i82527_times i82527_baudrates[] = { + {1, 0, 0, 2, 0, 0, 3, 12, 1}, /* 125K */ + {1, 0, 0, 2, 0, 0, 1, 12, 1}, /* 250K */ + {1, 0, 0, 2, 0, 0, 0, 12, 1} /* 500K */ +}; + +static void i82527_baudrate (struct can_dev *dev, unsigned int ibaud) +{ + struct i82527_times *times; + int i; + + i = sizeof (i82527_baudrates) / sizeof (struct i82527_times); + if (ibaud >= i) + ibaud = i - 1; + times = &i82527_baudrates[ibaud]; + + i = i82527_read_reg (dev, I82527_CPU_INT_REG) & + ~(I82527_DSC | I82527_DMC); + i |= times->t_dsc * I82527_DSC; + i |= times->t_dmc * I82527_DMC; + i82527_write_reg (dev, I82527_CPU_INT_REG, i); + + i = (times->t_clkout_div << I82527_CLKDIV_SHIFT) + | (times->t_clkout_slew << I82527_SL_SHIFT); + i82527_write_reg (dev, I82527_CLKOUT_REG, i); + + i = (times->t_sjw << I82527_SJW_SHIFT) + | (times->t_brp << I82527_BRP_SHIFT); + i82527_write_reg (dev, I82527_BITT0_REG, i); + + i = (times->t_spl << I82527_SPL_SHIFT) + | (times->t_tseg1 << I82527_TSEG1_SHIFT) + | (times->t_tseg2 << I82527_TSEG2_SHIFT); + i82527_write_reg (dev, I82527_BITT1_REG, i); + +} + +int i82527_init (struct can_dev *dev, unsigned int ibaud) +{ + int i; + + i82527_write_reg (dev, I82527_CTRL_REG, I82527_CCE | I82527_INIT); + + i82527_write_reg (dev, I82527_CLKOUT_REG, 3 << I82527_SL_SHIFT); + i82527_write_reg (dev, I82527_STAT_REG, 0x00); + i82527_write_reg (dev, I82527_P1CONF, 0x00); + i82527_write_reg (dev, I82527_P2CONF, 0x00); + + i82527_write_15_mask (dev, 0x0); + i82527_write_std_mask (dev, 0xffff); + i82527_write_x_mask (dev, 0xffffffff); + + /* Turn off all message objects and clear message identifiers */ + for (i = I82527_FIRST_OBJ; i < I82527_MSG_OBJS; i++) { + i82527_write_msgctrl (dev, i, + I82527_MSGVAL_R & I82527_INTPND_R & + I82527_RMTPND_R & I82527_TXRQST_R & + I82527_MSGLST_R & I82527_NEWDAT_R); + i82527_write_msgarb (dev, i, 0); + } + + /* Configure Bus Configuration Register */ + i82527_write_reg (dev, I82527_BUSCFG_REG, + I82527_COBY | I82527_DCT1 | I82527_DCR1); + + /* + * Preconfigure CPU Interface Register. The XTAL of the CAN1 + * contoller is connected to CLKOUT of the CAN0 contoller. + */ + i82527_write_reg (dev, I82527_CPU_INT_REG, + (dev) ? I82527_MUX : (I82527_MUX | I82527_CEN)); + + i82527_baudrate (dev, ibaud); + + /* Inizialization end */ + i82527_write_reg (dev, I82527_STAT_REG, I82527_STAT_REG_DEFAULT); + + /* Start device */ + i82527_write_reg (dev, I82527_CTRL_REG, 0); + + return 0; +} + +void i82527_config_xmit (struct can_dev *dev, struct can_msg *msg, + int iobj, int xmit) +{ + int cfg; + + /* it looks like message 15 fires an interrupt when re-enabled */ + if (iobj != 15) + i82527_msgflag (dev, iobj, I82527_MSGVAL_R); /* being updated */ + + /* set DLC and X flag */ + cfg = (msg->dlc << I82527_DLC_SHIFT); + msg->id <<= I82527_ID_STD_SHIFT; + + i82527_write_msgarb (dev, iobj, msg->id); + + if (xmit) { + if (msg->dlc > 8) + msg->dlc = 8; + + cfg |= I82527_DIR_TX; + + i82527_write_msgcfg (dev, iobj, cfg); + /* write data bytes */ + i82527_write_msgdata (dev, iobj, msg->dlc, msg->data); + + /* set MSGVAL; then clear CPUUpd and set newdat */ + i82527_msgflag (dev, iobj, I82527_MSGVAL_S); + + i82527_msgflag (dev, iobj, I82527_CPUUPD_R & I82527_NEWDAT_S & + I82527_TXRQST_S); + } else { + i82527_write_msgcfg (dev, iobj, cfg); + i82527_msgflag (dev, iobj, I82527_MSGVAL_S); + i82527_msgflag (dev, iobj, I82527_RMTPND_R & I82527_MSGLST_R & + I82527_NEWDAT_R); + } +} + +int i82527_xmit (struct can_dev *dev, struct can_msg *msg) +{ + int i; + + i82527_config_xmit (dev, msg, I82527_TX_OBJ, 1); + + for (i = 0; i < CAN_XMIT_TIMEOUT_US; i += 10000) { + if (i82527_read_reg (dev, I82527_STAT_REG) & I82527_TXOK) + return 0; + if (ctrlc ()) + break; + udelay (10000); + } + + return -1; +} + +int i82527_recv (struct can_dev *dev, struct can_msg *msg) +{ + int cfg, iobj = I82527_RX_OBJ; + + /* Clear status registers (RXOK) */ + i82527_write_reg (dev, I82527_STAT_REG, I82527_STAT_REG_DEFAULT); + + msg->id = 0; + msg->dlc = 0; + i82527_config_xmit (dev, msg, iobj, 0); + + while (!(i82527_read_reg (dev, I82527_STAT_REG) & I82527_RXOK)) { + if (ctrlc ()) + return -1; + } + + if (iobj != 15) + i82527_msgflag (dev, iobj, I82527_NEWDAT_R); + + msg->id = i82527_read_msgarb (dev, iobj) >> I82527_ID_STD_SHIFT; + + cfg = i82527_read_msgcfg (dev, iobj); + + msg->dlc = (cfg & I82527_DLC_MASK) >> I82527_DLC_SHIFT; + + i82527_read_msgdata (dev, iobj, msg->dlc, msg->data); + + i82527_msgflag (dev, iobj, I82527_INTPND_R); + if (iobj == 15) + i82527_msgflag (dev, iobj, I82527_NEWDAT_R & I82527_RMTPND_R); + + return 0; +} + +int i82527_status (struct can_dev *dev, int level) +{ + printf ("i82527 at %#lx", dev->base); + if (level > 0) { + int stat = i82527_read_reg (dev, I82527_STAT_REG) & 0xff; + printf (", status 0x%02x", stat); + if (stat & I82527_BOFF) + puts (" busoff"); + if (stat & I82527_WARN) + puts (" warning"); + if (stat & I82527_WAKE) + puts (" wake"); + if (stat & I82527_RXOK) + puts (" rxok"); + if (stat & I82527_TXOK) + puts (" txok"); + stat &= I82527_LEC_MASK; + if (stat > 0 && stat < 7) + printf (" lec=%d", stat); + } + + puts ("\n"); + if (level > 1) { + int i; + for (i = 0; i < I82527_SIZE; i++) { + if ((i % 0x10) == 0) + printf ("\n%02x:", i); + printf (" %02x", i82527_read_reg (dev, i)); + } + puts ("\n"); + } + return 0; +} + +void i82527_register (struct can_dev *dev, unsigned long base) +{ + dev->name = "i82527"; + dev->base = base; + dev->init = i82527_init; + dev->xmit = i82527_xmit; + dev->recv = i82527_recv; + dev->status = i82527_status; + + can_register (dev); +} diff --git a/include/i82527.h b/include/i82527.h new file mode 100644 index 0000000..8cd70e2 --- /dev/null +++ b/include/i82527.h @@ -0,0 +1,201 @@ +/* + * (C) Copyright 2007-2009, Wolfgang Grandegger wg@denx.de + * + * Derived from OCAN driver: + * + * Copyright (C) 2002 Alessandro Rubini rubini@linux.it + * Copyright (C) 2002 System SpA info.electronics@system-group.it + * + * 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 __I82527_H__ +#define __I82527_H__ + +#include <can.h> + +#define I82527_MSG_OBJS 16 /* 0 is the whole device, 1..15 are objects */ +#define I82527_FIRST_OBJ 1 + +#define I82527_ID_STD_SHIFT 21 +#define I82527_ID_XTD_SHIFT 3 + +/* + * i82527 address map (referred from base address) & internal bits. + * See the 82527 data-sheet page 9 and following +*/ +#define I82527_MAP_SIZE 0x100 + +#define I82527_CTRL_REG 0x00 + #define I82527_CCE 0x40 + #define I82527_EIE 0x08 + #define I82527_SIE 0x04 + #define I82527_IE 0x02 + #define I82527_INIT 0x01 + +#define I82527_STAT_REG 0x01 + #define I82527_BOFF 0x80 + #define I82527_WARN 0x40 + #define I82527_WAKE 0x20 + #define I82527_RXOK 0x10 + #define I82527_TXOK 0x08 + #define I82527_LEC_MASK 0x07 +#define I82527_STAT_REG_DEFAULT I82527_LEC_MASK + +#define I82527_CPU_INT_REG 0x02 + #define I82527_RSTST 0x80 + #define I82527_DSC 0x40 + #define I82527_DMC 0x20 + #define I82527_PWD 0x10 + #define I82527_SLEEP 0x08 + #define I82527_MUX 0x04 + #define I82527_CEN 0x01 + +/* Reserved 0x03 */ + +#define I82527_HI_SPEED_RD 0x04 +#define I82527_GMASK_STD 0x06 +#define I82527_GMASK_XTD 0x08 +#define I82527_MSG15_MASK 0x0c + +/* Message 1 0x10 */ +#define I82527_MSG_OFF 0x10 /* No size definition here */ + #define I82527_MSG_CTRL 0x00 + #define I82527_MSGVAL_R 0xff7f /* *********************** */ + #define I82527_MSGVAL_S 0xffbf /* WARNING!!! */ + #define I82527_TXIE_R 0xffdf /* These masks must be */ + #define I82527_TXIE_S 0xffef /* &-ed and *NOT* |-ed */ + #define I82527_RXIE_R 0xfff7 /* */ + #define I82527_RXIE_S 0xfffb /* */ + #define I82527_INTPND_R 0xfffd /* */ + #define I82527_INTPND_S 0xfffe /* */ + #define I82527_RMTPND_R 0x7fff /* WARNING!!! */ + #define I82527_RMTPND_S 0xbfff /* These masks must be */ + #define I82527_TXRQST_R 0xdfff /* &-ed and *NOT* |-ed */ + #define I82527_TXRQST_S 0xefff /* */ + #define I82527_MSGLST_R 0xf7ff /* */ + #define I82527_MSGLST_S 0xfbff /* */ + #define I82527_CPUUPD_R 0xf7ff /* WARNING!!! */ + #define I82527_CPUUPD_S 0xfbff /* These masks must be */ + #define I82527_NEWDAT_R 0xfdff /* &-ed and *NOT* |-ed */ + #define I82527_NEWDAT_S 0xfeff /* *********************** */ + + #define I82527_MSG_ARBIT 0x02 + #define I82527_MSG_CFG 0x06 + #define I82527_DLC_MASK 0xf0 + #define I82527_DLC_SHIFT 4 + #define I82527_DLC_MASK0 0x0f + #define I82527_DIR 0x08 + #define I82527_DIR_TX 0x08 + #define I82527_DIR_RX 0x00 + #define I82527_XTD 0x04 + #define I82527_XTD_XTD 0x04 + #define I82527_XTD_STD 0x00 + #define I82527_MSG_DATA 0x07 /* 8 bytes */ +#define I82527_CLKOUT_REG 0x1f + #define I82527_SL_MASK 0x30 + #define I82527_SL_SHIFT 4 + #define I82527_SL_MASK0 0x03 + #define I82527_CLKDIV_MASK 0x0f + #define I82527_CLKDIV_SHIFT 0 + #define I82527_CLKDIV_MASK0 0x0f + +/* Message 2 0x20 */ +#define I82527_BUSCFG_REG 0x2f + #define I82527_COBY 0x40 + #define I82527_POL 0x20 + #define I82527_DCT1 0x08 + #define I82527_DCR1 0x02 + #define I82527_DCR0 0x01 + +/* Message 3 0x30 */ +#define I82527_BITT0_REG 0x3f + #define I82527_SJW_MASK 0xc0 + #define I82527_SJW_SHIFT 6 + #define I82527_SJW_MASK0 0x03 + #define I82527_BRP_MASK 0x3f + #define I82527_BRP_SHIFT 0 + #define I82527_BRP_MASK0 0x3f + +/* Message 4 0x40 */ +#define I82527_BITT1_REG 0x4f + #define I82527_SPL_MASK 0x80 + #define I82527_SPL_SHIFT 7 + #define I82527_SPL_MASK0 0x01 + #define I82527_TSEG2_MASK 0x70 + #define I82527_TSEG2_SHIFT 4 + #define I82527_TSEG2_MASK0 0x07 + #define I82527_TSEG1_MASK 0x0f + #define I82527_TSEG1_SHIFT 0 + #define I82527_TSEG1_MASK0 0x0f + +/* Message 5 0x50 */ +#define I82527_INT_REG 0x5f + +/* Message 6 0x60 */ +/* Reserved 0x6f */ + +/* Message 7 0x70 */ +/* Reserved 0x7f */ + +/* Message 8 0x80 */ +/* Reserved 0x8f */ + +/* Message 9 0x90 */ +#define I82527_P1CONF 0x9f + +/* Message 10 0xa0 */ +#define I82527_P2CONF 0xaf + +/* Message 11 0xb0 */ +#define I82527_P1IN 0xbf + +/* Message 12 0xc0 */ +#define I82527_P2IN 0xcf + +/* Message 13 0xd0 */ +#define I82527_P1OUT 0xdf + +/* Message 14 0xe0 */ +#define I82527_P2OUT 0xef + +/* Message 15 0xf0 */ +#define I82527_SER_RST_ADD 0xff + + +#define I82527_SIZE 0x100 + +/* + * Bit timing + */ +struct i82527_times { + 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; +}; + +void i82527_register (struct can_dev *dev, unsigned long base); + +#endif /*__I82527_H__*/

From: Wolfgang Grandegger wg@denx.de
Signed-off-by: Wolfgang Grandegger wg@denx.de --- board/tqc/tqm8xx/tqm8xx.c | 17 +++++++++++++++++ include/configs/TQM855L.h | 8 +++++++- 2 files changed, 24 insertions(+), 1 deletions(-)
diff --git a/board/tqc/tqm8xx/tqm8xx.c b/board/tqc/tqm8xx/tqm8xx.c index f92c598..f1aab43 100644 --- a/board/tqc/tqm8xx/tqm8xx.c +++ b/board/tqc/tqm8xx/tqm8xx.c @@ -26,6 +26,10 @@ #ifdef CONFIG_PS2MULT #include <ps2mult.h> #endif +#ifdef CONFIG_CAN +#include <can.h> +#include <i82527.h> +#endif
extern flash_info_t flash_info[]; /* FLASH chips info */
@@ -447,6 +451,19 @@ int board_early_init_r (void)
#endif /* CONFIG_PS2MULT */
+#if defined(CONFIG_CAN_DRIVER) && defined(CONFIG_CAN) +static struct can_dev tqm8xx_can[2]; + +#ifdef CONFIG_BOARD_EARLY_INIT_R +int board_early_init_r (void) +{ + i82527_register (&tqm8xx_can[0], CONFIG_SYS_CAN_BASE); + i82527_register( &tqm8xx_can[1], CONFIG_SYS_CAN_BASE + 0x100); + + return (0); +} +#endif +#endif
#ifdef CONFIG_MISC_INIT_R extern void load_sernum_ethaddr(void); diff --git a/include/configs/TQM855L.h b/include/configs/TQM855L.h index 1255928..1603d30 100644 --- a/include/configs/TQM855L.h +++ b/include/configs/TQM855L.h @@ -88,7 +88,13 @@
#define CONFIG_STATUS_LED 1 /* Status LED enabled */
-#undef CONFIG_CAN_DRIVER /* CAN Driver support disabled */ +#define CONFIG_CAN_DRIVER /* CAN Driver support enabled */ +#ifdef CONFIG_CAN_DRIVER +#define CONFIG_CAN +#define CONFIG_CAN_I82527 +#define CONFIG_CMD_CAN +#define CONFIG_BOARD_EARLY_INIT_R +#endif
/* * BOOTP options

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@denx.de
Signed-off-by: Wolfgang Grandegger wg@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@denx.de
- Derived from Xenomai's RT-Socket-CAN driver for SJA1000:
- Copyright (C) 2005,2006 Sebastian Smolorz
<Sebastian.Smolorz@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@denx.de
- Derived from Xenomai's RT-Socket-CAN driver for SJA1000:
- Copyright (C) 2005,2006 Sebastian Smolorz
<Sebastian.Smolorz@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__ */

Matthias Fuchs wrote:
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 :-(
Then it should be changed, of course. This patch is far from being accepted and for the moment it's an implementation detail. I'm especially interested to hear if such a generic CAN interface would serve your purposes as well, as you require access to the SJA1000 somehow.
Wolfgang.

Hi Wolfgang,
of course I can think of situations where some simple CAN mechanism might be helpful (e.g. simple hardware testing).
But do we really need this inside a bootloader? Surely not for a production build. But please keep on hacking!
On Monday 02 November 2009 13:50, Wolfgang Grandegger wrote:
Matthias Fuchs wrote:
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 :-(
Then it should be changed, of course. This patch is far from being accepted and for the moment it's an implementation detail. I'm especially interested to hear if such a generic CAN interface would serve your purposes as well, as you require access to the SJA1000 somehow.
I just need to bit bang around in the OCR register. So no need for a full blown and flash consuming CAN implementation. Of course I could life with your register access style. Especially because it makes the code more common with Socket-CAN files which prevents us from rewriting fully functional code ;-)
Matthias

Matthias Fuchs wrote:
Hi Wolfgang,
of course I can think of situations where some simple CAN mechanism might be helpful (e.g. simple hardware testing).
But do we really need this inside a bootloader? Surely not for a production build. But please keep on hacking!
On Monday 02 November 2009 13:50, Wolfgang Grandegger wrote:
Matthias Fuchs wrote:
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 :-(
Then it should be changed, of course. This patch is far from being accepted and for the moment it's an implementation detail. I'm especially interested to hear if such a generic CAN interface would serve your purposes as well, as you require access to the SJA1000 somehow.
I just need to bit bang around in the OCR register. So no need for a full blown and flash consuming CAN implementation. Of course I could life with your register access style. Especially because it makes the code more common with Socket-CAN files which prevents us from rewriting fully functional code ;-)
Well, I think Wolfgang will tell me to use structs sooner than later.
Wolfgang.

Dear Wolfgang Grandegger,
In message 4AEF3F18.6000103@grandegger.com you wrote:
Well, I think Wolfgang will tell me to use structs sooner than later.
Why should I? You already know it!
Best regards,
Wolfgang Denk

On Sunday 01 November 2009 06:33:34 Wolfgang Grandegger wrote:
- if (op == 's') {
- else if (op == 'i') {
- else if (op == 'r') {
- } else if (op == 'x') {
- } else {
your if style here is inconsistent, but ignoring that, shouldnt this really be a switch() ? although, by only checking the first char, you allow people to encode typos into their commands and not realize it until some point in the future where things get stricter. i.e. people can do `can ilovecandy ...`
unsigned int dev_num = 0, ibaud = 0;
struct can_dev *dev;
if (argc > 2)
dev_num = simple_strtoul (argv[2], NULL, 10);
if (argc > 3) {
ibaud = simple_strtoul (argv[3], NULL, 10);
if (ibaud > 2)
ibaud = 2;
}
dev = can_init (dev_num, ibaud);
if (!dev)
return 1;
can_dev = dev;
if i told CAN to init an unknown device, i would expect to get an error and the command state to remain in said error state until i selected a proper CAN device. otherwise, a script that didnt check the can init status would incorrectly operate on the previously selected can device.
how do other commands work ? am i complaining about common convention here ?
printf ("Usage:\n%s\n", cmdtp->usage);
cmd_usage() ?
- can, 3, 1, do_can,
- "can - CAN bus commands\n",
- "can status [level]\n"
- "can init [dev] [baud-index]\n"
- "can xmit [id] [d0] [d1] ... [d7]\n"
- "can recv, abort with CTRL-C\n"
does the help really display correctly here ? i think the "can status" line will have too many "can"'s ? -mike

Mike Frysinger wrote:
On Sunday 01 November 2009 06:33:34 Wolfgang Grandegger wrote:
- if (op == 's') {
- else if (op == 'i') {
- else if (op == 'r') {
- } else if (op == 'x') {
- } else {
your if style here is inconsistent, but ignoring that, shouldnt this really be a switch() ? although, by only checking the first char, you allow people to encode typos into their commands and not realize it until some point in the future where things get stricter. i.e. people can do `can ilovecandy ...`
Will fix.
unsigned int dev_num = 0, ibaud = 0;
struct can_dev *dev;
if (argc > 2)
dev_num = simple_strtoul (argv[2], NULL, 10);
if (argc > 3) {
ibaud = simple_strtoul (argv[3], NULL, 10);
if (ibaud > 2)
ibaud = 2;
}
dev = can_init (dev_num, ibaud);
if (!dev)
return 1;
can_dev = dev;
if i told CAN to init an unknown device, i would expect to get an error and the command state to remain in said error state until i selected a proper CAN device. otherwise, a script that didnt check the can init status would incorrectly operate on the previously selected can device.
can_init will already print an error message. But that might be changed.
how do other commands work ? am i complaining about common convention here ?
printf ("Usage:\n%s\n", cmdtp->usage);
cmd_usage() ?
OK.
- can, 3, 1, do_can,
- "can - CAN bus commands\n",
- "can status [level]\n"
- "can init [dev] [baud-index]\n"
- "can xmit [id] [d0] [d1] ... [d7]\n"
- "can recv, abort with CTRL-C\n"
does the help really display correctly here ? i think the "can status" line will have too many "can"'s ?
I think the output was OK. But I will check later next week.
Note that this is a RFC trying to discuss the real requirements of a CAN interface in U-Boot. I think it would also be nice to have can_xmit() and can_recv() with a timeout parameter, e.g.:
can_xmit(struct can_dev *dev, int timeout_us);
And maybe also a can_xmit_done() function.
Wolfgang.

On Sunday 01 November 2009 11:24:59 Wolfgang Grandegger wrote:
Note that this is a RFC trying to discuss the real requirements of a CAN interface in U-Boot. I think it would also be nice to have can_xmit() and can_recv() with a timeout parameter, e.g.:
can_xmit(struct can_dev *dev, int timeout_us);
And maybe also a can_xmit_done() function.
i only have a passing familiarity with CAN (havent done real work with it), but i can find someone to look over the current stuff -mike

On Sunday 01 November 2009 06:33:33 Wolfgang Grandegger wrote:
--- a/Makefile +++ b/Makefile @@ -203,6 +203,7 @@ LIBS += net/libnet.a LIBS += disk/libdisk.a LIBS += drivers/bios_emulator/libatibiosemu.a LIBS += drivers/block/libblock.a +LIBS += drivers/can/libcan.a
this isnt an issue specific to CAN, but i wonder if we should switch LIBS to LIBS-y now that the top level Makefile can rely on autoconf.mk settings after the point config.mk is included. it would save time on pointlessly recursing into all the empty dirs and creating empty archives.
--- /dev/null +++ b/drivers/can/Makefile @@ -0,0 +1,47 @@ +include $(TOPDIR)/config.mk
+LIB := $(obj)libcan.a
+COBJS-$(CONFIG_CAN) += can.o
+COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS))
+all: $(LIB)
+$(LIB): $(obj).depend $(OBJS)
- $(AR) $(ARFLAGS) $@ $(OBJS)
+#####################################################
+# defines $(obj).depend target +include $(SRCTREE)/rules.mk
+sinclude $(obj).depend
+####################################################
also not specific to CAN, but i think it's time we start creating .mk files for subdirs to include
--- /dev/null +++ b/drivers/can/can.c
+static char *baudrates[] = { "125K", "250K", "500K" };
so we're restricting ourselves to these three speeds ? i have passing familiarity with CAN, but i didnt think the protocol was restricted to specific speeds.
+int can_register (struct can_dev* can_dev)
no space before the paren, and the * is cuddled on the wrong side of the space. seems like a lot of this code suffers from these two issues.
+{
- struct can_dev* dev;
- can_dev->next = NULL;
- if (!can_devs)
can_devs = can_dev;
- else {
for (dev = can_devs; dev->next; dev = dev->next)
;
dev->next = can_dev;
- }
invert the if logic and i think the code would look "nicer" -- use braces on the first branch instead of the second.
+struct can_dev *can_init (int dev_num, int ibaud) +{
- struct can_dev *dev;
- int i;
- if (!can_devs) {
puts ("No CAN devices registered\n");
return NULL;
- }
- /* Advance to selected device */
- for (i = 0, dev = can_devs; dev; i++, dev = dev->next) {
if (i == dev_num)
break;
- }
- if (!dev) {
printf ("CAN device %d does not exist\n", dev_num);
return NULL;
- }
- printf ("Initializing CAN%d at 0x%08x with baudrate %s\n",
i, dev->base, baudrates[ibaud]);
- dev->init (dev, ibaud);
- return dev;
+}
wonder if we should have a generic device list code base since this looks similar to a lot of other u-boot device lists ...
--- /dev/null +++ b/include/can.h @@ -0,0 +1,70 @@ +/*
- (C) Copyright 2007-2009, Wolfgang Grandegger wg@denx.de
have you really been working on this stuff since 2007 ?
+struct can_dev {
- char *name;
const ? -mike

Mike Frysinger wrote:
On Sunday 01 November 2009 06:33:33 Wolfgang Grandegger wrote:
[snip]
--- /dev/null +++ b/drivers/can/can.c
+static char *baudrates[] = { "125K", "250K", "500K" };
so we're restricting ourselves to these three speeds ? i have passing familiarity with CAN, but i didnt think the protocol was restricted to specific speeds.
Well, this is an RFC and as I wrote in the introduction some features need to be added or extended, especially for CAN device configuration. My idea is to have a more complete default bit-timing table, which board specific code may overwrite using, for example:
sja1000_register(&my_sja1000, &my_config_opts);
This would also allow to set the CAN clock, cdr and ocr registers.
+int can_register (struct can_dev* can_dev)
no space before the paren, and the * is cuddled on the wrong side of the space. seems like a lot of this code suffers from these two issues.
U-Boot coding style requires a space after the function name and before "(". But the "*" is misplaced, of course.
+{
- struct can_dev* dev;
- can_dev->next = NULL;
- if (!can_devs)
can_devs = can_dev;
- else {
for (dev = can_devs; dev->next; dev = dev->next)
;
dev->next = can_dev;
- }
invert the if logic and i think the code would look "nicer" -- use braces on the first branch instead of the second.
OK.
+struct can_dev *can_init (int dev_num, int ibaud) +{
- struct can_dev *dev;
- int i;
- if (!can_devs) {
puts ("No CAN devices registered\n");
return NULL;
- }
- /* Advance to selected device */
- for (i = 0, dev = can_devs; dev; i++, dev = dev->next) {
if (i == dev_num)
break;
- }
- if (!dev) {
printf ("CAN device %d does not exist\n", dev_num);
return NULL;
- }
- printf ("Initializing CAN%d at 0x%08x with baudrate %s\n",
i, dev->base, baudrates[ibaud]);
- dev->init (dev, ibaud);
- return dev;
+}
wonder if we should have a generic device list code base since this looks similar to a lot of other u-boot device lists ...
Do we already have a generic interface?
--- /dev/null +++ b/include/can.h @@ -0,0 +1,70 @@ +/*
- (C) Copyright 2007-2009, Wolfgang Grandegger wg@denx.de
have you really been working on this stuff since 2007 ?
The code was written in 2007. "2007, 2009" is more appropriate.
+struct can_dev {
- char *name;
const ?
OK.
Wolfgang.

On Sunday 01 November 2009 11:16:59 Wolfgang Grandegger wrote:
Mike Frysinger wrote:
On Sunday 01 November 2009 06:33:33 Wolfgang Grandegger wrote:
--- /dev/null +++ b/drivers/can/can.c
+static char *baudrates[] = { "125K", "250K", "500K" };
so we're restricting ourselves to these three speeds ? i have passing familiarity with CAN, but i didnt think the protocol was restricted to specific speeds.
Well, this is an RFC and as I wrote in the introduction some features need to be added or extended, especially for CAN device configuration. My idea is to have a more complete default bit-timing table, which board specific code may overwrite using, for example:
sja1000_register(&my_sja1000, &my_config_opts);
This would also allow to set the CAN clock, cdr and ocr registers.
this makes sense if the device supports a limited number of baud rates. but what if the baud rate is arbitrary (between two limits) ?
+int can_register (struct can_dev* can_dev)
no space before the paren, and the * is cuddled on the wrong side of the space. seems like a lot of this code suffers from these two issues.
U-Boot coding style requires a space after the function name and before "(". But the "*" is misplaced, of course.
it's (thankfully) been changing to Linux kernel style
+struct can_dev *can_init (int dev_num, int ibaud)
wonder if we should have a generic device list code base since this looks similar to a lot of other u-boot device lists ...
Do we already have a generic interface?
i dont think so
--- /dev/null +++ b/include/can.h @@ -0,0 +1,70 @@ +/*
- (C) Copyright 2007-2009, Wolfgang Grandegger wg@denx.de
have you really been working on this stuff since 2007 ?
The code was written in 2007. "2007, 2009" is more appropriate.
the intro made it sound like this was a recent development (i.e. last few days/weeks). if code is actually from 2007, then the range is fine. -mike

Mike Frysinger wrote:
On Sunday 01 November 2009 11:16:59 Wolfgang Grandegger wrote:
Mike Frysinger wrote:
On Sunday 01 November 2009 06:33:33 Wolfgang Grandegger wrote:
--- /dev/null +++ b/drivers/can/can.c
+static char *baudrates[] = { "125K", "250K", "500K" };
so we're restricting ourselves to these three speeds ? i have passing familiarity with CAN, but i didnt think the protocol was restricted to specific speeds.
Well, this is an RFC and as I wrote in the introduction some features need to be added or extended, especially for CAN device configuration. My idea is to have a more complete default bit-timing table, which board specific code may overwrite using, for example:
sja1000_register(&my_sja1000, &my_config_opts);
This would also allow to set the CAN clock, cdr and ocr registers.
this makes sense if the device supports a limited number of baud rates. but what if the baud rate is arbitrary (between two limits) ?
Board specific code can define what ever table it likes, including non-standard bit-rate and bit-timings. Nevertheless, for most CAN controllers the default bit-timing parameters are just fine.
+int can_register (struct can_dev* can_dev)
no space before the paren, and the * is cuddled on the wrong side of the space. seems like a lot of this code suffers from these two issues.
U-Boot coding style requires a space after the function name and before "(". But the "*" is misplaced, of course.
it's (thankfully) been changing to Linux kernel style
I really appreciate that.
+struct can_dev *can_init (int dev_num, int ibaud)
wonder if we should have a generic device list code base since this looks similar to a lot of other u-boot device lists ...
Do we already have a generic interface?
i dont think so
Nor do I.
Wolfgang.
participants (4)
-
Matthias Fuchs
-
Mike Frysinger
-
Wolfgang Denk
-
Wolfgang Grandegger