Hi,
i have connected a MCP2515 CAN bus controller with a MCP2551 tranceiver to a BR-6104-K.
Using the bitbang SPI module the controller can be initialized:
BusyBox v1.19.3 (2012-04-05 12:15:53 CEST) built-in shell (ash)
Enter 'help' for a list of built-in commands.
_______ ________ __
| |.-----.-----.-----.| | | |.----.| |_
| - || _ | -__| || | | || _|| _|
|_______|| __|_____|__|__||________||__| |____|
|__| W I R E L E S S F R E E D O M
ATTITUDE ADJUSTMENT (bleeding edge, r30857) ----------
root@OpenWrt:/# uname -a
Linux OpenWrt 3.1.10 #6 Thu Apr 5 16:39:22 CEST 2012 mips GNU/Linux
root@OpenWrt:/# insmod mcp251x
root@OpenWrt:/# cat /sys/kernel/debug/gpio
GPIOs 0-3, adm5120 gpio0:
gpio-2 (MCP251x CAN INT ) in hi
GPIOs 8-22, adm5120 gpio1:
gpio-17 (spi_gpio.1 ) in lo
gpio-18 (spi_gpio.1 ) out lo
gpio-20 (spi_gpio.1 ) out lo
gpio-21 (spi1.0 ) out hi
root@OpenWrt:/# insmod mcp251x
[ 368.736000] mcp251x spi1.0: probed
root@OpenWrt:/# ip link set can0 type can bitrate 125000 loopback on
root@OpenWrt:/# ifconfig can0 up
[ 402.324000] mcp251x spi1.0: CNF: 0x03 0xb5 0x01
root@OpenWrt:/# ip -details link show can0
10: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN qlen 10
link/can
can <LOOPBACK> state ERROR-ACTIVE restart-ms 0
bitrate 125000 sample-point 0.875
tq 500 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
mcp251x: tseg1 3..16 tseg2 2..8 sjw 1..4 brp 1..64 brp-inc 1
clock 8000000
root@OpenWrt:/# cat /sys/kernel/debug/gpio
GPIOs 0-3, adm5120 gpio0:
gpio-2 (MCP251x CAN INT ) in hi
GPIOs 8-22, adm5120 gpio1:
gpio-17 (spi_gpio.1 ) in lo
gpio-18 (spi_gpio.1 ) out lo
gpio-20 (spi_gpio.1 ) out lo
gpio-21 (spi1.0 ) out hi
root@OpenWrt:/# cat /proc/interrupts
CPU0
2: 0 MIPS cascade [INTC]
7: 33933 MIPS timer
9: 2477 INTC uart-pl010
12: 0 INTC mcp251x
17: 614 INTC eth0, eth1
ERR: 0
root@OpenWrt:/# dmesg | tail -5
[ 368.732000] mcp251x spi1.0: CANSTAT 0x80 CANCTRL 0x07
[ 368.736000] mcp251x spi1.0: probed
[ 402.308000] mcp251x spi1.0: INTC_REG_IRQ_ENABLE = 0x212
[ 402.308000] mcp251x spi1.0: GPIO2 IRQ initialized
[ 402.324000] mcp251x spi1.0: CNF: 0x03 0xb5 0x01
Everything seems to be fine. But the IRQ (/INT from MCP2515) doesn't work. The /INT is pulled down when I
send a message to the controller (expecting a message back thru loopback):
root@OpenWrt:/# cansend can0 123#DEADBEEF
root@OpenWrt:/# cat /proc/interrupts
CPU0
2: 0 MIPS cascade [INTC]
7: 34334 MIPS timer
9: 2845 INTC uart-pl010
12: 0 INTC mcp251x
17: 669 INTC eth0, eth1
ERR: 0
root@OpenWrt:/# cat /sys/kernel/debug/gpio
GPIOs 0-3, adm5120 gpio0:
gpio-2 (MCP251x CAN INT ) in lo
GPIOs 8-22, adm5120 gpio1:
gpio-17 (spi_gpio.1 ) in lo
gpio-18 (spi_gpio.1 ) out lo
gpio-20 (spi_gpio.1 ) out lo
gpio-21 (spi1.0 ) out hi
I have done several tests (setting up the IRQs in the board setup) - with no luck.
To get further I have put the IRQ setup into the driver setup (I know it's ugly and not the right way):
mcp251x.c
static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
{
struct mcp251x_priv *priv = dev_id;
struct spi_device *spi = priv->spi;
struct net_device *net = priv->net;
unsigned long flags;
unsigned int intc_reg_int_level;
mutex_lock(&priv->mcp_lock);
dev_dbg(&spi->dev, " in mcp251x_can_ist ...\n");
// ADM5120 IRQs can only be level, not edge so we are going
// switch level and only use high to low trigger
spin_lock_irqsave(&level_register_lock, flags);
{
intc_reg_int_level = BIT(4) ^ intc_read_reg(INTC_REG_INT_LEVEL);
intc_write_reg(INTC_REG_INT_LEVEL, intc_reg_int_level);
}
spin_unlock_irqrestore(&level_register_lock, flags);
// we only need falling edge
if (BIT(4) & intc_reg_int_level)
return(IRQ_HANDLED);
while (!priv->force_quit) {
...
}
}
...
static int mcp251x_open(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
struct mcp251x_platform_data *pdata = spi->dev.platform_data;
int ret;
unsigned int ire;
unsigned long flags;
ret = open_candev(net);
if (ret) {
dev_err(&spi->dev, "unable to set initial baudrate!\n");
return ret;
}
mutex_lock(&priv->mcp_lock);
if (pdata->transceiver_enable)
pdata->transceiver_enable(1);
priv->force_quit = 0;
priv->tx_skb = NULL;
priv->tx_len = 0;
ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
DEVICE_NAME, priv);
if (ret) {
dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
if (pdata->transceiver_enable)
pdata->transceiver_enable(0);
close_candev(net);
goto open_unlock;
} else {
spin_lock_irqsave(&level_register_lock, flags);
// enable interrupt on GPIO 2
// pp37 ADM5120 manual
ire = intc_read_reg(INTC_REG_IRQ_ENABLE);
ire |= BIT(4) | BIT(9); // II0E | SWIE
intc_write_reg(INTC_REG_IRQ_ENABLE, ire);
dev_dbg(&spi->dev, " INTC_REG_IRQ_ENABLE = 0x%x\n", ire);
// Enable CSX0/INTX0 processing as described on pp131 of ADM5120 manual
SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, BIT(4));
// sets GPIO4 and 2 as active low
// pp41/42 of ADM5120 manual.
intc_write_reg(INTC_REG_INT_LEVEL, BIT(4) | intc_read_reg(INTC_REG_INT_LEVEL));
spin_unlock_irqrestore(&level_register_lock, flags);
dev_dbg(&spi->dev, " GPIO2 IRQ initialized\n");
}
...
}
A simple test with this code http://www.omnima.co.uk/forums/lofivers … p?t72.html works:
root@OpenWrt:/# insmod gpio2
[ 130.380000] INTC_REG_IRQ_ENABLE = 0x212
[ 130.384000] GPIO_RESET: requesting IRQ -> fine
root@OpenWrt:/# [ 133.820000] pressed
[ 134.040000] released
[ 135.196000] pressed
[ 135.412000] released
[ 136.076000] pressed
[ 136.220000] released
root@OpenWrt:/# cat /proc/interrupts
CPU0
2: 0 MIPS cascade [INTC]
7: 28970 MIPS timer
9: 180 INTC uart-pl010
12: 6 INTC gpio_reset
17: 334 INTC eth0, eth1
ERR: 0
Does anybody has a hint ?
Regards bertc3p0
The board setup
nizza ~/projekte/openwrt/trunk_3.1 (svn)-[trunk:30857] % cat build_dir/linux-adm5120_router_le/linux-3.1.10/arch/mips/adm5120/edimax/br-61xx.c
/*
* Edimax BR-61xx support
*
* Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
*/
#include "br-61xx.h"
#include <prom/admboot.h>
#include <linux/spi/spi_gpio.h>
#include <linux/can/platform/mcp251x.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <adm5120_defs.h>
#define BR61XX_GPIO_DEV_MASK 0
#define BR61XX_CONFIG_OFFSET 0x8000
#define BR61XX_CONFIG_SIZE 0x1000
static struct mtd_partition br61xx_partitions[] = {
{
.name = "admboot",
.offset = 0,
.size = 32*1024,
.mask_flags = MTD_WRITEABLE,
} , {
.name = "config",
.offset = MTDPART_OFS_APPEND,
.size = 32*1024,
} , {
.name = "firmware",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
}
};
/* static struct gpio_button br61xx_gpio_buttons[] __initdata = {
{
.desc = "reset_button",
.type = EV_KEY,
.code = BTN_0,
.threshold = 5,
.gpio = ADM5120_GPIO_PIN2,
}
};
*/
static u8 br61xx_vlans[6] __initdata = {
0x41, 0x42, 0x44, 0x48, 0x50, 0x00
};
/* SPI specific part
CS GPIO_21
SCLK GPIO_20
MOSI GPIO_18
MISO GPIO_17
*/
static struct mcp251x_platform_data mcp251x_info = {
.oscillator_frequency = 16000000,
.board_specific_setup = NULL,
.irq_flags = IRQF_TRIGGER_LOW,
.power_enable = NULL,
.transceiver_enable = NULL,
};
static struct spi_gpio_platform_data br61xx_gpio_spi = {
.sck = 20,
.mosi = 18,
.miso = 17,
.num_chipselect = 1, // number of chip selects for spi gpio master
};
static struct platform_device spi_gpio_device = {
.name = "spi_gpio",
.id = 1, // Bus number
.dev.platform_data = &br61xx_gpio_spi,
};
static struct spi_board_info mcp2515_spi_gpio_board_info [] = {
{
.modalias = "mcp2515",
.max_speed_hz = 10000000,
.bus_num = 1,
.chip_select = 0,
.platform_data = &mcp251x_info,
.irq = ADM5120_IRQ_GPIO2,
.mode = SPI_MODE_0,
.controller_data = (void *) 21,
},
};
static struct platform_device *br61xx_devices[] __initdata = {
&spi_gpio_device,
};
static void __init adm5120_mcp251x_init(void) {
printk(KERN_DEBUG "adm5120_mcp251x_init: Entry\n");
if ((gpio_request(ADM5120_GPIO_PIN2, "MCP251x CAN INT") == 0) &&
(gpio_direction_input(ADM5120_GPIO_PIN2) == 0)) {
gpio_export(ADM5120_GPIO_PIN2, 0);
printk(KERN_DEBUG " registered GPIO2 for mcp251x INT\n");
} else {
printk(KERN_ERR "could not obtain gpio for MCP251x CAN bus interrupt\n");
return;
}
}
static void __init br61xx_mac_setup(void)
{
u8 mac_base[6];
int err;
err = admboot_get_mac_base(BR61XX_CONFIG_OFFSET,
BR61XX_CONFIG_SIZE, mac_base);
if ((err) || !is_valid_ether_addr(mac_base))
random_ether_addr(mac_base);
adm5120_setup_eth_macs(mac_base);
}
void __init br61xx_generic_setup(void)
{
adm5120_flash0_data.nr_parts = ARRAY_SIZE(br61xx_partitions);
adm5120_flash0_data.parts = br61xx_partitions;
adm5120_add_device_flash(0);
adm5120_add_device_gpio(BR61XX_GPIO_DEV_MASK);
adm5120_add_device_uart(0);
adm5120_add_device_uart(1);
adm5120_add_device_switch(5, br61xx_vlans);
adm5120_mcp251x_init();
spi_register_board_info(mcp2515_spi_gpio_board_info,ARRAY_SIZE(mcp2515_spi_gpio_board_info));
// adm5120_add_device_gpio_buttons(ARRAY_SIZE(br61xx_gpio_buttons), br61xx_gpio_buttons);
br61xx_mac_setup();
platform_add_devices(br61xx_devices,ARRAY_SIZE(br61xx_devices));
}
(Last edited by bertc3p0 on 5 Apr 2012, 16:18)