summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2013-03-12 08:56:29 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2013-03-12 08:56:29 +0100
commitd4be58791a6358e85fa1bf139d46f7e80c65eec4 (patch)
tree7802382d7412eb28bc9fb906b617b8f2dcee4719
parent5dcf120a31010d2d64846c259ddeb7187cb41cda (diff)
colibri_t20/30: can: integrate mcp251x and sja1000 support
Integrate CAN support for the Colibri Evaluation Board V3.1a with built-in MCP2515 SPI CAN controller resp. the Colibri Evaluation Board V2.1c with its built-in SJA1000 CAN controller connected to the GMI bus. The following kernel configuration needs to be enabled as well: CONFIG_CAN CONFIG_CAN_RAW CONFIG_CAN_BCM CONFIG_CAN_DEV Plus depending on the Evaluation Board revision: CONFIG_CAN_MCP251X or CONFIG_CAN_SJA1000 CONFIG_CAN_SJA1000_PLATFORM Optional support for 32-bit GMI as well as xPOD CAN on MECS Tellurium for Colibri T20 is provided via commented defines in arch/arm/mach-tegra/board-colibri_t20.h.
-rw-r--r--arch/arm/mach-tegra/board-colibri_t20-pinmux.c19
-rw-r--r--arch/arm/mach-tegra/board-colibri_t20.c186
-rw-r--r--arch/arm/mach-tegra/board-colibri_t20.h7
-rw-r--r--arch/arm/mach-tegra/board-colibri_t30-pinmux.c10
-rw-r--r--arch/arm/mach-tegra/board-colibri_t30.c119
-rw-r--r--drivers/net/can/sja1000/sja1000_platform.c12
6 files changed, 346 insertions, 7 deletions
diff --git a/arch/arm/mach-tegra/board-colibri_t20-pinmux.c b/arch/arm/mach-tegra/board-colibri_t20-pinmux.c
index 1383f7d..5570e8c 100644
--- a/arch/arm/mach-tegra/board-colibri_t20-pinmux.c
+++ b/arch/arm/mach-tegra/board-colibri_t20-pinmux.c
@@ -92,7 +92,7 @@ static __initdata int colibri_t20_gpio_input_pinmux[] = {
#endif
/* SODIMM pin 99 nPWE */
-#if 0
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
TEGRA_GPIO_PZ3, /* gated GMI_WR_N multiplexed LCD_WR_N */
#endif
@@ -138,7 +138,7 @@ static __initdata struct tegra_pingroup_config colibri_t20_pinmux[] = {
{TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
{TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK,TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- /* GPIO N0, N1, N2, N3 and USBC_DET */
+ /* GPIO N0, N1, N2 and N3 */
{TEGRA_PINGROUP_DAP1, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
/* GPIO A2 and A3 */
{TEGRA_PINGROUP_DAP2, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
@@ -293,7 +293,7 @@ static __initdata struct tegra_pingroup_config colibri_t20_pinmux[] = {
#else
{TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
#endif
- /* GPIO K5 multiplexed USB1_VBUS */
+ /* GPIO K5 multiplexed USB1_VBUS (USBC_DET) */
{TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
/* X0, X1, X2, X3, X4, X5, X6 and X7 */
@@ -332,7 +332,7 @@ static __initdata struct tegra_pingroup_config colibri_t20_pinmux[] = {
{TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
};
-#if 0
+#ifdef GMI_32BIT
/* 32-bit wide data and 28-bit wide address bus, more chip selects */
static __initdata struct tegra_pingroup_config colibri_t20_widebus_pinmux[] = {
/* D28, D29, D30 and D31 */
@@ -348,13 +348,16 @@ static __initdata struct tegra_pingroup_config colibri_t20_widebus_pinmux[] = {
{TEGRA_PINGROUP_GME, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
#endif
};
-#endif
+#endif /* GMI_32BIT */
int __init colibri_t20_pinmux_init(void)
{
int i;
tegra_pinmux_config_table(colibri_t20_pinmux, ARRAY_SIZE(colibri_t20_pinmux));
+#ifdef GMI_32BIT
+ tegra_pinmux_config_table(colibri_t20_widebus_pinmux, ARRAY_SIZE(colibri_t20_widebus_pinmux));
+#endif
tegra_drive_pinmux_config_table(colibri_t20_drive_pinmux,
ARRAY_SIZE(colibri_t20_drive_pinmux));
@@ -369,9 +372,15 @@ int __init colibri_t20_pinmux_init(void)
gpio_request(TEGRA_GPIO_PI4, "SODIMM 87 nRESET_OUT");
gpio_direction_output(TEGRA_GPIO_PI4, 1);
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+ /* not tri-stating GMI_WR_N on SODIMM pin 99 nPWE */
+ gpio_request(TEGRA_GPIO_PT5, "GMI_WR_N on 99");
+ gpio_direction_output(TEGRA_GPIO_PT5, 0);
+#else /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
/* tri-stating GMI_WR_N on SODIMM pin 99 nPWE */
gpio_request(TEGRA_GPIO_PT5, "no GMI_WR_N on 99");
gpio_direction_output(TEGRA_GPIO_PT5, 1);
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
/* not tri-stating GMI_WR_N on SODIMM pin 93 RDnWR */
gpio_request(TEGRA_GPIO_PT6, "GMI_WR_N on 93 RDnWR");
diff --git a/arch/arm/mach-tegra/board-colibri_t20.c b/arch/arm/mach-tegra/board-colibri_t20.c
index dcbacc6..2cb679a 100644
--- a/arch/arm/mach-tegra/board-colibri_t20.c
+++ b/arch/arm/mach-tegra/board-colibri_t20.c
@@ -10,6 +10,8 @@
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
+#include <linux/can/platform/mcp251x.h>
+#include <linux/can/platform/sja1000.h>
#include <linux/clk.h>
#include <linux/colibri_usb.h>
#include <linux/debugfs.h>
@@ -27,6 +29,9 @@
#include <linux/reboot.h>
#include <linux/serial_8250.h>
#include <linux/spi/spi.h>
+#if defined(CONFIG_SPI_GPIO) || defined(CONFIG_SPI_GPIO_MODULE)
+#include <linux/spi/spi_gpio.h>
+#endif
#include <linux/tegra_uart.h>
#include <linux/wm97xx.h>
@@ -48,6 +53,18 @@
#include "pm.h"
#include "wakeups-t2.h"
+//from former drivers/mtd/maps/tegra_nor.h
+#define TEGRA_GMI_PHYS 0x70009000
+#define TEGRA_GMI_BASE IO_TO_VIRT(TEGRA_GMI_PHYS)
+#define TEGRA_SNOR_CONFIG_REG (TEGRA_GMI_BASE + 0x00)
+
+//from drivers/mtd/maps/tegra_nor.c
+#define __BITMASK0(len) (BIT(len) - 1)
+#define REG_FIELD(val, start, len) (((val) & __BITMASK0(len)) << (start))
+
+#define TEGRA_SNOR_CONFIG_GO BIT(31)
+#define TEGRA_SNOR_CONFIG_SNOR_CS(val) REG_FIELD((val), 4, 3)
+
/* ADC */
static struct wm97xx_batt_pdata colibri_t20_adc_pdata = {
@@ -126,6 +143,113 @@ static struct platform_device soc_camera = {
};
#endif /* CONFIG_VIDEO_TEGRA */
+/* CAN */
+#if ((defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)) && \
+ (defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)))
+ #error either enable MCP251X or SJA1000 but not both
+#endif
+
+#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)
+/* Colibri EvalBoard V3.1a/MECS Tellurium xPOD CAN module featuring MCP2515 SPI CAN controller */
+
+#ifdef MECS_TELLURIUM_XPOD2
+#define CAN_CS_GPIO TEGRA_GPIO_PB7 /* SSPFRM2 */
+#define CAN_INTERRUPT_GPIO TEGRA_GPIO_PK3 /* active low interrupt (MCP2515 nINT) */
+#define CAN_RESET_GPIO TEGRA_GPIO_PK2 /* active high reset (not MCP2515 nRESET) */
+#else
+#define CAN_INTERRUPT_GPIO TEGRA_GPIO_PA0 /* active low interrupt (MCP2515 nINT) */
+#define CAN_RESET_GPIO TEGRA_GPIO_PK4 /* active high reset (not MCP2515 nRESET) */
+#endif
+
+static int __init colibri_t20_mcp2515_setup(struct spi_device *spi)
+{
+ int gpio_status;
+
+ printk("Colibri EvalBoard V3.1a/MECS Tellurium xPOD CAN Initialisation\n");
+
+ /* configure MCP2515 reset line as output and pull high into reset */
+ gpio_status = gpio_request(CAN_RESET_GPIO, "CAN_RESET_GPIO");
+ if (gpio_status < 0)
+ pr_warning("CAN_RESET_GPIO request GPIO FAILED\n");
+ gpio_status = gpio_direction_output(CAN_RESET_GPIO, 1);
+ if (gpio_status < 0)
+ pr_warning("CAN_RESET_GPIO request GPIO DIRECTION FAILED\n");
+
+ udelay(2);
+
+ /* pull out of reset */
+ gpio_set_value(CAN_RESET_GPIO, 0);
+
+ return 0;
+}
+
+static struct mcp251x_platform_data mcp251x_pdata = {
+ .board_specific_setup = colibri_t20_mcp2515_setup,
+ .oscillator_frequency = 16000000,
+ .power_enable = NULL,
+ .transceiver_enable = NULL
+};
+
+static struct spi_board_info mcp251x_board_info[] = {
+ {
+#ifndef MECS_TELLURIUM_XPOD2
+ .bus_num = 3,
+#else
+ .bus_num = 4,
+#endif
+ .chip_select = 0,
+#ifdef MECS_TELLURIUM_XPOD2
+ .controller_data = (void *) CAN_CS_GPIO,
+#else
+// .controller_data = ,
+#endif
+ .max_speed_hz = 10000000,
+ .modalias = "mcp2515",
+ .platform_data = &mcp251x_pdata,
+ },
+};
+
+static void __init colibri_t20_mcp2515_can_init(void)
+{
+ mcp251x_board_info[0].irq = gpio_to_irq(CAN_INTERRUPT_GPIO);
+ spi_register_board_info(mcp251x_board_info, ARRAY_SIZE(mcp251x_board_info));
+}
+#else /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+#define colibri_t20_mcp2515_can_init() do {} while (0)
+#endif /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+#define CAN_BASE_TEG 0xd0000000 /* GMI_CS4_N */
+static struct resource colibri_can_resource[] = {
+ [0] = {
+ .start = CAN_BASE_TEG, /* address */
+ .end = CAN_BASE_TEG + 0xff, /* data */
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* interrupt assigned during initialisation */
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+ }
+};
+
+static struct sja1000_platform_data colibri_can_platdata = {
+ .osc_freq = 24000000,
+ .ocr = (OCR_MODE_NORMAL | OCR_TX0_PUSHPULL),
+ .cdr = CDR_CLK_OFF | /* Clock off (CLKOUT pin) */
+ CDR_CBP, /* CAN input comparator bypass */
+};
+
+static struct platform_device colibri_can_device = {
+ .name = "sja1000_platform",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(colibri_can_resource),
+ .resource = colibri_can_resource,
+ .dev = {
+ .platform_data = &colibri_can_platdata,
+ }
+};
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
+
/* Clocks */
static struct tegra_clk_init_table colibri_t20_clk_init_table[] __initdata = {
/* name parent rate enabled */
@@ -153,6 +277,7 @@ static struct tegra_clk_init_table colibri_t20_clk_init_table[] __initdata = {
{"vde", "pll_c", 240000000, false},
{"ndflash", "pll_p", 108000000, false},
+ {"nor", "pll_p", 86500000, true},
//[ 2.284308] kernel BUG at drivers/spi/spi-tegra.c:254!
//[ 2.289454] Unable to handle kernel NULL pointer dereference at virtual
@@ -165,10 +290,13 @@ static struct tegra_clk_init_table colibri_t20_clk_init_table[] __initdata = {
/* GPIO */
static struct gpio colibri_t20_gpios[] = {
+#if !defined(IRIS) && !defined(CONFIG_CAN_MCP251X) && \
+ !defined(CONFIG_CAN_MCP251X_MODULE) && \
+ !defined(CONFIG_CAN_SJA1000) && \
+ !defined(CONFIG_CAN_SJA1000_MODULE)
//conflicts with CAN interrupt on Colibri Evaluation Board and MECS Tellurium
//xPOD1 CAN
//conflicts with DAC_PSAVE# on Iris
-#ifndef IRIS
{TEGRA_GPIO_PA0, GPIOF_IN, "SODIMM pin 73"},
#endif
{TEGRA_GPIO_PA2, GPIOF_IN, "SODIMM pin 186"},
@@ -178,10 +306,14 @@ static struct gpio colibri_t20_gpios[] = {
{TEGRA_GPIO_PB2, GPIOF_IN, "SODIMM pin 154"},
//multiplexed VI_D7
{TEGRA_GPIO_PB4, GPIOF_IN, "SODIMM pin 59"},
+#if !defined(CONFIG_SPI_GPIO) && !defined(CONFIG_SPI_GPIO_MODULE)
//conflicts with MECS Tellurium xPOD2 SSPCLK2
{TEGRA_GPIO_PB6, GPIOF_IN, "SODIMM pin 55"},
+#endif
+#ifndef MECS_TELLURIUM_XPOD2
//conflicts with MECS Tellurium xPOD2 SSPFRM2
{TEGRA_GPIO_PB7, GPIOF_IN, "SODIMM pin 63"},
+#endif
#ifndef COLIBRI_T20_VI
{TEGRA_GPIO_PD5, GPIOF_IN, "SODI-98, Iris X16-13"},
{TEGRA_GPIO_PD6, GPIOF_IN, "SODIMM pin 81"},
@@ -192,8 +324,10 @@ static struct gpio colibri_t20_gpios[] = {
{TEGRA_GPIO_PK0, GPIOF_IN, "SODIMM pin 150"},
//multiplexed OWR
{TEGRA_GPIO_PK1, GPIOF_IN, "SODIMM pin 152"},
+#if !defined(CONFIG_CAN_MCP251X) && !defined(CONFIG_CAN_MCP251X_MODULE)
//conflicts with CAN reset on MECS Tellurium xPOD1 CAN
{TEGRA_GPIO_PK4, GPIOF_IN, "SODIMM pin 106"},
+#endif
// {TEGRA_GPIO_PK5, GPIOF_IN, "USBC_DET"},
#ifndef CONFIG_KEYBOARD_GPIO
//conflicts with menu key
@@ -217,10 +351,12 @@ static struct gpio colibri_t20_gpios[] = {
{TEGRA_GPIO_PM4, GPIOF_IN, "SODIMM pin 140"},
{TEGRA_GPIO_PM5, GPIOF_IN, "SODIMM pin 142"},
+#ifndef GMI_32BIT
{TEGRA_GPIO_PN0, GPIOF_IN, "SODIMM pin 174"},
{TEGRA_GPIO_PN1, GPIOF_IN, "SODIMM pin 176"},
{TEGRA_GPIO_PN2, GPIOF_IN, "SODIMM pin 178"},
{TEGRA_GPIO_PN3, GPIOF_IN, "SODIMM pin 180"},
+#endif
{TEGRA_GPIO_PN4, GPIOF_IN, "SODIMM pin 160"},
{TEGRA_GPIO_PN5, GPIOF_IN, "SODIMM pin 158"},
{TEGRA_GPIO_PN6, GPIOF_IN, "SODIMM pin 162"},
@@ -254,7 +390,7 @@ static struct gpio colibri_t20_gpios[] = {
{TEGRA_GPIO_PX7, GPIOF_IN, "104, I X14 ForceOFF#"},
{TEGRA_GPIO_PZ2, GPIOF_IN, "SODIMM pin 156"},
{TEGRA_GPIO_PZ4, GPIOF_IN, "SODIMM pin 164"},
-#ifndef SDHCI_8BIT
+#if !defined(GMI_32BIT) && !defined SDHCI_8BIT
{TEGRA_GPIO_PAA4, GPIOF_IN, "SODIMM pin 166"},
{TEGRA_GPIO_PAA5, GPIOF_IN, "SODIMM pin 168"},
{TEGRA_GPIO_PAA6, GPIOF_IN, "SODIMM pin 170"},
@@ -456,6 +592,7 @@ static struct platform_device colibri_t20_keys_device = {
};
#endif /* CONFIG_KEYBOARD_GPIO */
+#ifndef GMI_32BIT
/* MMC/SD */
static struct tegra_sdhci_platform_data colibri_t20_sdhci_platform_data = {
@@ -477,6 +614,7 @@ int __init colibri_t20_sdhci_init(void)
return 0;
}
+#endif /* !GMI_32BIT */
/* NAND */
@@ -696,11 +834,34 @@ static struct platform_device tegra_rtc_device = {
/* SPI */
+#if defined(CONFIG_SPI_GPIO) || defined(CONFIG_SPI_GPIO_MODULE)
+#ifdef MECS_TELLURIUM_XPOD2
+struct spi_gpio_platform_data xpod2_spi_platform_data = {
+ .sck = TEGRA_GPIO_PB6, /* SSPCLK2 */
+ .mosi = TEGRA_GPIO_PW2, /* SSPTXD2 */
+ .miso = TEGRA_GPIO_PW3, /* SSPRXD2 */
+ .num_chipselect = 1,
+};
+
+static struct platform_device xpod2_spi_device = {
+ .name = "spi_gpio",
+ .id = 4,
+ .dev = {
+ .platform_data = &xpod2_spi_platform_data,
+ }
+};
+#endif /* MECS_TELLURIUM_XPOD2 */
+#endif /* CONFIG_SPI_GPIO | CONFIG_SPI_GPIO_MODULE */
+
#if defined(CONFIG_SPI_TEGRA) && defined(CONFIG_SPI_SPIDEV)
static struct spi_board_info tegra_spi_devices[] __initdata = {
{
.bus_num = 3, /* SPI4: Colibri SSP */
+#if !defined(CONFIG_CAN_MCP251X) && !defined(CONFIG_CAN_MCP251X_MODULE)
.chip_select = 0,
+#else /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */
+ .chip_select = 1,
+#endif /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */
.irq = 0,
.max_speed_hz = 50000000,
.modalias = "spidev",
@@ -884,7 +1045,9 @@ late_initcall(colibri_t20_thermal_debug_init);
static struct platform_device *colibri_t20_uart_devices[] __initdata = {
&tegra_uarta_device, /* Colibri FFUART */
+#ifndef GMI_32BIT
&tegra_uartd_device, /* Colibri BTUART */
+#endif
&tegra_uartb_device, /* Colibri STDUART */
};
@@ -947,7 +1110,9 @@ static void __init colibri_t20_uart_init(void)
colibri_t20_uart_pdata.parent_clk_count = ARRAY_SIZE(uart_parent_clk);
tegra_uarta_device.dev.platform_data = &colibri_t20_uart_pdata;
tegra_uartb_device.dev.platform_data = &colibri_t20_uart_pdata;
+#ifndef GMI_32BIT
tegra_uartd_device.dev.platform_data = &colibri_t20_uart_pdata;
+#endif
/* Register low speed only if it is selected */
if (!is_tegra_debug_uartport_hs())
@@ -1085,8 +1250,12 @@ static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
.hot_plug = true,
.power_off_on_suspend = false,
.remote_wakeup_supported = false,
+#ifdef MECS_TELLURIUM_XPOD2
+ .vbus_gpio = -1,
+#else
.vbus_gpio = USBH_PEN,
.vbus_gpio_inverted = 1,
+#endif
.vbus_reg = NULL,
},
};
@@ -1285,6 +1454,9 @@ static struct platform_device *colibri_t20_devices[] __initdata = {
&tegra_pcm_device,
&colibri_t20_audio_device,
&tegra_spi_device4,
+#ifdef MECS_TELLURIUM_XPOD2
+ &xpod2_spi_device,
+#endif
&tegra_led_pwm_device,
&tegra_pwfm1_device,
#ifndef MECS_TELLURIUM
@@ -1302,6 +1474,13 @@ static void __init colibri_t20_init(void)
{
tegra_clk_init_from_table(colibri_t20_clk_init_table);
colibri_t20_pinmux_init();
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+ writel(TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG);
+ writel(TEGRA_SNOR_CONFIG_GO | TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG);
+ colibri_can_resource[1].start = gpio_to_irq(TEGRA_GPIO_PA0);
+ colibri_can_resource[1].end = gpio_to_irq(TEGRA_GPIO_PA0);
+ platform_device_register(&colibri_can_device);
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
colibri_t20_thermd_alert_init();
colibri_t20_i2c_init();
colibri_t20_uart_init();
@@ -1314,7 +1493,9 @@ static void __init colibri_t20_init(void)
platform_add_devices(colibri_t20_devices,
ARRAY_SIZE(colibri_t20_devices));
tegra_ram_console_debug_init();
+#ifndef GMI_32BIT
colibri_t20_sdhci_init();
+#endif
colibri_t20_regulator_init();
// tegra_das_device.dev.platform_data = &tegra_das_pdata;
@@ -1332,6 +1513,7 @@ static void __init colibri_t20_init(void)
colibri_t20_gpio_init();
colibri_t20_register_spidev();
+ colibri_t20_mcp2515_can_init();
#ifdef CONFIG_VIDEO_TEGRA
t20_get_tegra_vi01_device()->dev.platform_data = &tegra_camera_platform_data;
diff --git a/arch/arm/mach-tegra/board-colibri_t20.h b/arch/arm/mach-tegra/board-colibri_t20.h
index 8dc8d46..70a2f83 100644
--- a/arch/arm/mach-tegra/board-colibri_t20.h
+++ b/arch/arm/mach-tegra/board-colibri_t20.h
@@ -28,6 +28,9 @@
#define TEGRA_FB_VGA
#endif
+/* Uncomment to activate 32-bit GMI address/databus */
+//#define GMI_32BIT
+
/* GPIO */
#define FF_DCD TEGRA_GPIO_PC6 /* SODIMM 31 */
@@ -70,6 +73,10 @@
board */
//#define MECS_TELLURIUM
+/* Uncomment to use the xPOD2 which due to its Colibri T20 incompatible wiring
+ uses GPIO bit banging SPI driver rather than a hardware SPI controller */
+//#define MECS_TELLURIUM_XPOD2
+
/* Uncomment for 8-bit SDHCI on HSMMC controller (requires custom carrier
board) */
//#define SDHCI_8BIT
diff --git a/arch/arm/mach-tegra/board-colibri_t30-pinmux.c b/arch/arm/mach-tegra/board-colibri_t30-pinmux.c
index 87692bf..f02060c 100644
--- a/arch/arm/mach-tegra/board-colibri_t30-pinmux.c
+++ b/arch/arm/mach-tegra/board-colibri_t30-pinmux.c
@@ -275,6 +275,7 @@ static __initdata struct tegra_pingroup_config colibri_t30_pinmux[] = {
DEFAULT_PINMUX(GMI_WAIT, GMI, NORMAL, TRISTATE, OUTPUT),
//GPIO PU6: MMC_CD
DEFAULT_PINMUX(GMI_WP_N, RSVD1, NORMAL, NORMAL, INPUT),
+//gated, multiplexed LCD_CS1_N or LCD_WR_N
DEFAULT_PINMUX(GMI_WR_N, GMI, NORMAL, NORMAL, INPUT),
#endif /* COLIBRI_T30_V10 */
@@ -430,7 +431,11 @@ static __initdata struct tegra_pingroup_config colibri_t30_pinmux[] = {
DEFAULT_PINMUX(LCD_SDOUT, DISPLAYA, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(LCD_VSYNC, DISPLAYA, NORMAL, NORMAL, INPUT),
//multiplexed with SDMMC3_DAT4 gated GMI_WR_N
+#if !defined(CONFIG_CAN_SJA1000) && !defined(CONFIG_CAN_SJA1000_MODULE)
DEFAULT_PINMUX(LCD_WR_N, RSVD, NORMAL, NORMAL, INPUT),
+#else /* CONFIG_CAN_SJA1000 & CONFIG_CAN_SJA1000_MODULE */
+ DEFAULT_PINMUX(LCD_WR_N, RSVD, NORMAL, TRISTATE, INPUT),
+#endif /* CONFIG_CAN_SJA1000 & CONFIG_CAN_SJA1000_MODULE */
//multiplexed GMI_CLK
DEFAULT_PINMUX(OWR, OWR, NORMAL, NORMAL, INPUT),
//GPIO DD2: LAN_VBUS
@@ -502,8 +507,13 @@ static __initdata struct tegra_pingroup_config colibri_t30_pinmux[] = {
#else
DEFAULT_PINMUX(SDMMC3_DAT3, PWM0, NORMAL, NORMAL, INPUT),
#endif
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+//not tri-stating GMI_WR_N on nPWE SODIMM pin 99
+ DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT),
+#else /* CONFIG_CAN_SJA1000) | CONFIG_CAN_SJA1000_MODULE */
//tri-stating GMI_WR_N on nPWE SODIMM pin 99
DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, PULL_UP, TRISTATE, OUTPUT),
+#endif /* CONFIG_CAN_SJA1000) | CONFIG_CAN_SJA1000_MODULE */
//not tri-stating GMI_WR_N on RDnWR SODIMM pin 93
DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT),
//multiplexed ULPI_STP used as SSPFRM
diff --git a/arch/arm/mach-tegra/board-colibri_t30.c b/arch/arm/mach-tegra/board-colibri_t30.c
index 4906a11..ceb5ee5 100644
--- a/arch/arm/mach-tegra/board-colibri_t30.c
+++ b/arch/arm/mach-tegra/board-colibri_t30.c
@@ -10,6 +10,8 @@
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
+#include <linux/can/platform/mcp251x.h>
+#include <linux/can/platform/sja1000.h>
#include <linux/clk.h>
#include <linux/colibri_usb.h>
#include <linux/types.h> /* required by linux/gpio_keys.h */
@@ -46,6 +48,18 @@
#include "gpio-names.h"
#include "pm.h"
+//from former drivers/mtd/maps/tegra_nor.h
+#define TEGRA_GMI_PHYS 0x70009000
+#define TEGRA_GMI_BASE IO_TO_VIRT(TEGRA_GMI_PHYS)
+#define TEGRA_SNOR_CONFIG_REG (TEGRA_GMI_BASE + 0x00)
+
+//from drivers/mtd/maps/tegra_nor.c
+#define __BITMASK0(len) (BIT(len) - 1)
+#define REG_FIELD(val, start, len) (((val) & __BITMASK0(len)) << (start))
+
+#define TEGRA_SNOR_CONFIG_GO BIT(31)
+#define TEGRA_SNOR_CONFIG_SNOR_CS(val) REG_FIELD((val), 4, 3)
+
/* ADC */
//TODO
@@ -129,6 +143,98 @@ static struct platform_device soc_camera = {
};
#endif /* CONFIG_VIDEO_TEGRA */
+/* CAN */
+#if ((defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)) && \
+ (defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)))
+ #error either enable MCP251X or SJA1000 but not both
+#endif
+
+#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)
+/* Colibri EvalBoard V3.1a */
+
+#define CAN_INTERRUPT_GPIO TEGRA_GPIO_PS0 /* active low interrupt (MCP2515 nINT) */
+#define CAN_RESET_GPIO TEGRA_GPIO_PK4 /* active high reset (not MCP2515 nRESET) */
+
+static int __init colibri_t20_mcp2515_setup(struct spi_device *spi)
+{
+ int gpio_status;
+
+ printk("Colibri EvalBoard V3.1a CAN Initialisation\n");
+
+ /* configure MCP2515 reset line as output and pull high into reset */
+ gpio_status = gpio_request(CAN_RESET_GPIO, "CAN_RESET_GPIO");
+ if (gpio_status < 0)
+ pr_warning("CAN_RESET_GPIO request GPIO FAILED\n");
+ gpio_status = gpio_direction_output(CAN_RESET_GPIO, 1);
+ if (gpio_status < 0)
+ pr_warning("CAN_RESET_GPIO request GPIO DIRECTION FAILED\n");
+
+ udelay(2);
+
+ /* pull out of reset */
+ gpio_set_value(CAN_RESET_GPIO, 0);
+
+ return 0;
+}
+
+static struct mcp251x_platform_data mcp251x_pdata = {
+ .board_specific_setup = colibri_t20_mcp2515_setup,
+ .oscillator_frequency = 16000000,
+ .power_enable = NULL,
+ .transceiver_enable = NULL
+};
+
+static struct spi_board_info mcp251x_board_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 10000000,
+ .modalias = "mcp2515",
+ .platform_data = &mcp251x_pdata,
+ },
+};
+
+static void __init colibri_t20_mcp2515_can_init(void)
+{
+ mcp251x_board_info[0].irq = gpio_to_irq(CAN_INTERRUPT_GPIO);
+ spi_register_board_info(mcp251x_board_info, ARRAY_SIZE(mcp251x_board_info));
+}
+#else /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+#define colibri_t20_mcp2515_can_init() do {} while (0)
+#endif /* CONFIG_CAN_MCP251X | CONFIG_CAN_MCP251X_MODULE */
+
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+#define CAN_BASE_TEG 0x48000000 /* GMI_CS4_N */
+static struct resource colibri_can_resource[] = {
+ [0] = {
+ .start = CAN_BASE_TEG, /* address */
+ .end = CAN_BASE_TEG + 0xff, /* data */
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* interrupt assigned during initialisation */
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
+ }
+};
+
+static struct sja1000_platform_data colibri_can_platdata = {
+ .osc_freq = 24000000,
+ .ocr = (OCR_MODE_NORMAL | OCR_TX0_PUSHPULL),
+ .cdr = CDR_CLK_OFF | /* Clock off (CLKOUT pin) */
+ CDR_CBP, /* CAN input comparator bypass */
+};
+
+static struct platform_device colibri_can_device = {
+ .name = "sja1000_platform",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(colibri_can_resource),
+ .resource = colibri_can_resource,
+ .dev = {
+ .platform_data = &colibri_can_platdata,
+ }
+};
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
+
/* Clocks */
static struct tegra_clk_init_table colibri_t30_clk_init_table[] __initdata = {
/* name parent rate enabled */
@@ -151,6 +257,7 @@ static struct tegra_clk_init_table colibri_t30_clk_init_table[] __initdata = {
{"i2s1", "pll_a_out0", 0, false},
{"i2s2", "pll_a_out0", 0, false},
{"i2s3", "pll_a_out0", 0, false},
+ {"nor", "pll_p", 86500000, true},
{"pll_m", NULL, 0, false},
{"pwm", "pll_p", 3187500, false},
{"spdif_out", "pll_a_out0", 0, false},
@@ -465,7 +572,11 @@ static struct platform_device tegra_rtc_device = {
static struct spi_board_info tegra_spi_devices[] __initdata = {
{
.bus_num = 0, /* SPI1: Colibri SSP */
+#if !defined(CONFIG_CAN_MCP251X) && !defined(CONFIG_CAN_MCP251X_MODULE)
.chip_select = 0,
+#else /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */
+ .chip_select = 1,
+#endif /* !CONFIG_CAN_MCP251X & !CONFIG_CAN_MCP251X_MODULE */
.irq = 0,
.max_speed_hz = 50000000,
.modalias = "spidev",
@@ -1213,6 +1324,13 @@ static void __init colibri_t30_init(void)
ARRAY_SIZE(throttle_list));
tegra_clk_init_from_table(colibri_t30_clk_init_table);
colibri_t30_pinmux_init();
+#if defined(CONFIG_CAN_SJA1000) || defined(CONFIG_CAN_SJA1000_MODULE)
+ writel(TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG);
+ writel(TEGRA_SNOR_CONFIG_GO | TEGRA_SNOR_CONFIG_SNOR_CS(4), TEGRA_SNOR_CONFIG_REG);
+ colibri_can_resource[1].start = gpio_to_irq(TEGRA_GPIO_PS0);
+ colibri_can_resource[1].end = gpio_to_irq(TEGRA_GPIO_PS0);
+ platform_device_register(&colibri_can_device);
+#endif /* CONFIG_CAN_SJA1000 | CONFIG_CAN_SJA1000_MODULE */
colibri_t30_thermd_alert_init();
colibri_t30_i2c_init();
colibri_t30_spi_init();
@@ -1234,6 +1352,7 @@ static void __init colibri_t30_init(void)
// colibri_t30_sensors_init();
colibri_t30_emc_init();
colibri_t30_register_spidev();
+ colibri_t20_mcp2515_can_init();
#ifdef CONFIG_VIDEO_TEGRA
t30_get_tegra_vi01_device()->dev.platform_data = &tegra_camera_platform_data;
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c
index d9fadc4..c8428f2 100644
--- a/drivers/net/can/sja1000/sja1000_platform.c
+++ b/drivers/net/can/sja1000/sja1000_platform.c
@@ -38,12 +38,24 @@ MODULE_LICENSE("GPL v2");
static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg)
{
+#if !defined(CONFIG_MACH_COLIBRI_T20) && !defined(CONFIG_MACH_COLIBRI_T30)
return ioread8(priv->reg_base + reg);
+#else
+ u8 value;
+ iowrite8(reg, priv->reg_base);
+ value = ioread8(priv->reg_base + 8);
+ return value;
+#endif
}
static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val)
{
+#if !defined(CONFIG_MACH_COLIBRI_T20) && !defined(CONFIG_MACH_COLIBRI_T30)
iowrite8(val, priv->reg_base + reg);
+#else
+ iowrite8(reg, priv->reg_base);
+ iowrite8(val, priv->reg_base + 8);
+#endif
}
static u8 sp_read_reg16(const struct sja1000_priv *priv, int reg)