There has been some requests for CAN-bus support, and I have now succeeded in connecting Jetson to a MCP2515 Can-bus controller over SPI. I use the SPI port available over the expansion connector (normaly used for touch screen interface). The MCP2515 requires a buffer to translate to 3.3V, and I use the GPIO-PU3 for the hardware interrupt. For tests the code uses only 4Mhz, which is the lowest possible clock frequency. It can be increased quite a bit, but this is not what limits the speed.
The main patch to the kernel is a modification to arch/arm/mach-tegra/board-ardbeg.c.
diff --git a/kernel/arch/arm/mach-tegra/board-ardbeg.c b/kernel/arch/arm/mach-tegra/board-ardbeg.c
index 9b997dd..419ce01 100644
--- a/kernel/arch/arm/mach-tegra/board-ardbeg.c
+++ b/kernel/arch/arm/mach-tegra/board-ardbeg.c
@@ -93,6 +93,7 @@
#include "pm.h"
#include "tegra-board-id.h"
#include "tegra-of-dev-auxdata.h"
+#include <linux/can/platform/mcp251x.h>
static struct board_info board_info, display_board_info;
@@ -1114,6 +1115,44 @@ static struct spi_board_info rm31080a_norrin_spi_board[1] = {
},
};
+static struct mcp251x_platform_data mcp251x_info = {
+.oscillator_frequency = 16000000,
+.board_specific_setup = NULL,
+.power_enable = NULL,
+.transceiver_enable = NULL,
+};
+
+static struct spi_board_info mcp251x_spi_board[1] = {
+ {
+ .modalias = "mcp2515",
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 4 * 1000 * 1000,
+ .mode = SPI_MODE_0,
+ .controller_data = &dev_cdata,
+ .platform_data = &mcp251x_info,
+ },
+};
+
+#define TEGRA_GPIO_PU5 165
+#define MCP2515_INT TEGRA_GPIO_PU5
+
+static int __init mcp251x_controller_init(void)
+{
+ int ret;
+ mcp251x_spi_board[0].irq = gpio_to_irq(MCP2515_INT);
+ pr_info("mcp251x_controller_initialisation\n");
+ ret = gpio_request(MCP2515_INT, "MCP251x interrupt");
+ if (ret < 0) {
+ pr_err("gpio_request failed for MCP251x irq\n");
+ return ret;
+ }
+ pr_info("setting mcp251x interrupt pin direction\n");
+ gpio_direction_input(MCP2515_INT);
+ spi_register_board_info(mcp251x_spi_board, ARRAY_SIZE(mcp251x_spi_board));
+ return 0;
+};
+
static int __init ardbeg_touch_init(void)
{
tegra_get_board_info(&board_info);
@@ -1417,7 +1456,8 @@ static void __init tegra_ardbeg_late_init(void)
edp_init();
isomgr_init();
- ardbeg_touch_init();
+ mcp251x_controller_init();
+ ardbeg_touch_init();
if (board_info.board_id == BOARD_E2548 ||
board_info.board_id == BOARD_P2530)
loki_panel_init();
We get an error message saying chip select 0 is already used. This is because the touch controller fails to start up, becuase MCP251x has taken it already. This can be ignored, or you can disable the
touch controller by editing /boot/extlinux/extlinux.conf and setting “touch_id=3@3”
ubuntu@tegra-ubuntu:~$ dmesg | grep "spi"
[ 0.592477] avdd-spi: 3300 mV at 150 mA
[ 4.471441] spi-tegra114 spi-tegra114.0: chipselect 0 already in use
[ 4.479089] spi-tegra114 spi-tegra114.0: can't create new device for rm_ts_spidev
[ 4.521330] mcp251x spi0.0: probed
[ 7.631728] avdd-spi: incomplete constraints, leaving on
For testing, try the following:
sudo ip link set can0 type can bitrate 125000 triple-sampling on
sudo ifconfig can0 up
sudo apt-get install can-utils
cansend can0 5A1#11.22.33.44.55.66.77.88
Note that there does not seem to be any need to change the DTS file, contrary to many earlier advices. The reason seems to be that the DTS changes are only needed when you are going to access the SPI port alone. The MCP251x.c does not need this.
At last, there is a remaining problem:
The chip select is active for around 100us, while the data transfer takes only 30uS (or less using higher clock frequency). This is not fast enough for 1Mb can bus trafic.
Is there any way to speed up the transfers?
It would also be nice if the board-ardbeg.c patch could take its parameters from the dts file, so you did not have to recompile the kernel if the irq line or bitrate changes. That would make it possible to include the patch permanently in the L4T code. Is there anybody capable to do this?