diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2013-03-12 08:56:29 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2013-03-12 08:56:29 +0100 |
commit | d4be58791a6358e85fa1bf139d46f7e80c65eec4 (patch) | |
tree | 7802382d7412eb28bc9fb906b617b8f2dcee4719 /arch/arm | |
parent | 5dcf120a31010d2d64846c259ddeb7187cb41cda (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.
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-tegra/board-colibri_t20-pinmux.c | 19 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-colibri_t20.c | 186 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-colibri_t20.h | 7 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-colibri_t30-pinmux.c | 10 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-colibri_t30.c | 119 |
5 files changed, 334 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 1383f7d55459..5570e8c222e4 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 dcbacc68c3e7..2cb679a3e23f 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 8dc8d46c79d0..70a2f835deaf 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 87692bfa31ff..f02060c3d535 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 4906a1180ce6..ceb5ee546947 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; |