From: juhosg Date: Tue, 31 Aug 2010 20:13:47 +0000 (+0000) Subject: ar71xx: rewrite SPI drivers for the RB4xx boards X-Git-Url: https://git.archive.openwrt.org/?p=openwrt.git;a=commitdiff_plain;h=d1f333874d4c4ff3f4a27ec3eb08d3f7ca6d8e43;hp=c433567bd3abf153f116b01fec22538a3c9d7fe7 ar71xx: rewrite SPI drivers for the RB4xx boards * add a new SPI controller driver * add SPI driver for the CPLD chip * convert the NAND driver * enable the mikroSD slot * enable more LEDs git-svn-id: svn://svn.openwrt.org/openwrt/trunk@22863 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- diff --git a/target/linux/ar71xx/config-2.6.32 b/target/linux/ar71xx/config-2.6.32 index cb33fac33e..9e4296b9f5 100644 --- a/target/linux/ar71xx/config-2.6.32 +++ b/target/linux/ar71xx/config-2.6.32 @@ -224,6 +224,8 @@ CONFIG_SPI_BITBANG=y CONFIG_SPI_GPIO=y CONFIG_SPI_MASTER=y CONFIG_SPI_PB44=y +# CONFIG_SPI_RB4XX is not set +# CONFIG_SPI_RB4XX_CPLD is not set # CONFIG_SPI_SPIDEV is not set # CONFIG_SPI_VSC7385 is not set CONFIG_SWCONFIG=y diff --git a/target/linux/ar71xx/config-2.6.33 b/target/linux/ar71xx/config-2.6.33 index 2c078d5601..5bc478c463 100644 --- a/target/linux/ar71xx/config-2.6.33 +++ b/target/linux/ar71xx/config-2.6.33 @@ -233,6 +233,8 @@ CONFIG_SPI_BITBANG=y CONFIG_SPI_GPIO=y CONFIG_SPI_MASTER=y CONFIG_SPI_PB44=y +# CONFIG_SPI_RB4XX is not set +# CONFIG_SPI_RB4XX_CPLD is not set # CONFIG_SPI_SPIDEV is not set # CONFIG_SPI_VSC7385 is not set CONFIG_SWCONFIG=y diff --git a/target/linux/ar71xx/config-2.6.34 b/target/linux/ar71xx/config-2.6.34 index 5df6f88dd1..36a8f33020 100644 --- a/target/linux/ar71xx/config-2.6.34 +++ b/target/linux/ar71xx/config-2.6.34 @@ -235,6 +235,8 @@ CONFIG_SPI_BITBANG=y CONFIG_SPI_GPIO=y CONFIG_SPI_MASTER=y CONFIG_SPI_PB44=y +# CONFIG_SPI_RB4XX is not set +# CONFIG_SPI_RB4XX_CPLD is not set # CONFIG_SPI_SPIDEV is not set # CONFIG_SPI_VSC7385 is not set CONFIG_SWCONFIG=y diff --git a/target/linux/ar71xx/config-2.6.35 b/target/linux/ar71xx/config-2.6.35 index 5df6f88dd1..36a8f33020 100644 --- a/target/linux/ar71xx/config-2.6.35 +++ b/target/linux/ar71xx/config-2.6.35 @@ -235,6 +235,8 @@ CONFIG_SPI_BITBANG=y CONFIG_SPI_GPIO=y CONFIG_SPI_MASTER=y CONFIG_SPI_PB44=y +# CONFIG_SPI_RB4XX is not set +# CONFIG_SPI_RB4XX_CPLD is not set # CONFIG_SPI_SPIDEV is not set # CONFIG_SPI_VSC7385 is not set CONFIG_SWCONFIG=y diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb4xx.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb4xx.c index a477cd3ade..8694211d9e 100644 --- a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb4xx.c +++ b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb4xx.c @@ -1,7 +1,7 @@ /* * MikroTik RouterBOARD 4xx series support * - * Copyright (C) 2008 Gabor Juhos + * Copyright (C) 2008-2010 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * * This program is free software; you can redistribute it and/or modify it @@ -15,9 +15,12 @@ #include #include #include +#include +#include #include #include +#include #include "machtype.h" #include "devices.h" @@ -28,6 +31,13 @@ #define RB4XX_GPIO_USER_LED 4 #define RB4XX_GPIO_RESET_SWITCH 7 +#define RB4XX_GPIO_CPLD_BASE 32 +#define RB4XX_GPIO_CPLD_LED1 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED1) +#define RB4XX_GPIO_CPLD_LED2 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED2) +#define RB4XX_GPIO_CPLD_LED3 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED3) +#define RB4XX_GPIO_CPLD_LED4 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED4) +#define RB4XX_GPIO_CPLD_LED5 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED5) + #define RB4XX_BUTTONS_POLL_INTERVAL 20 static struct gpio_led rb4xx_leds_gpio[] __initdata = { @@ -35,6 +45,26 @@ static struct gpio_led rb4xx_leds_gpio[] __initdata = { .name = "rb4xx:yellow:user", .gpio = RB4XX_GPIO_USER_LED, .active_low = 0, + }, { + .name = "rb4xx:green:led1", + .gpio = RB4XX_GPIO_CPLD_LED1, + .active_low = 1, + }, { + .name = "rb4xx:green:led2", + .gpio = RB4XX_GPIO_CPLD_LED2, + .active_low = 1, + }, { + .name = "rb4xx:green:led3", + .gpio = RB4XX_GPIO_CPLD_LED3, + .active_low = 1, + }, { + .name = "rb4xx:green:led4", + .gpio = RB4XX_GPIO_CPLD_LED4, + .active_low = 1, + }, { + .name = "rb4xx:green:led5", + .gpio = RB4XX_GPIO_CPLD_LED5, + .active_low = 0, }, }; @@ -78,84 +108,90 @@ static struct ar71xx_pci_irq rb4xx_pci_irqs[] __initdata = { } }; -#if 0 -/* - * SPI device support is experimental - */ +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition rb4xx_partitions[] = { + { + .name = "routerboot", + .offset = 0, + .size = 0x0b000, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "hard_config", + .offset = 0x0b000, + .size = 0x01000, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "bios", + .offset = 0x0d000, + .size = 0x02000, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "soft_config", + .offset = 0x0f000, + .size = 0x01000, + } +}; +#define rb4xx_num_partitions ARRAY_SIZE(rb4xx_partitions) +#else /* CONFIG_MTD_PARTITIONS */ +#define rb4xx_partitions NULL +#define rb4xx_num_partitions 0 +#endif /* CONFIG_MTD_PARTITIONS */ + static struct flash_platform_data rb4xx_flash_data = { .type = "pm25lv512", + .parts = rb4xx_partitions, + .nr_parts = rb4xx_num_partitions, }; -static struct spi_board_info rb4xx_spi_info[] = { - { - .bus_num = 0, - .chip_select = 0, - .max_speed_hz = 25000000, - .modalias = "m25p80", - .platform_data = &rb4xx_flash_data, - } +static struct rb4xx_cpld_platform_data rb4xx_cpld_data = { + .gpio_base = RB4XX_GPIO_CPLD_BASE, }; -static struct mmc_spi_platform_data rb433_mmc_data = { +static struct mmc_spi_platform_data rb4xx_mmc_data = { .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, }; -static struct spi_board_info rb433_spi_info[] = { +static struct spi_board_info rb4xx_spi_info[] = { { .bus_num = 0, .chip_select = 0, .max_speed_hz = 25000000, .modalias = "m25p80", - .platform_data = &rb433_flash_data, + .platform_data = &rb4xx_flash_data, }, { .bus_num = 0, - .chip_select = 2, + .chip_select = 1, .max_speed_hz = 25000000, - .modalias = "mmc_spi", - .platform_data = &rb433_mmc_data, + .modalias = "spi-rb4xx-cpld", + .platform_data = &rb4xx_cpld_data, } }; -static u32 rb433_spi_get_ioc_base(u8 chip_select, int cs_high, int is_on) -{ - u32 ret; - - if (is_on == AR71XX_SPI_CS_INACTIVE) { - ret = SPI_IOC_CS0 | SPI_IOC_CS1; - } else { - if (cs_high) { - ret = SPI_IOC_CS0 | SPI_IOC_CS1; - } else { - if ((chip_select ^ 2) == 0) - ret = SPI_IOC_CS1 ^ (SPI_IOC_CS0 | SPI_IOC_CS1); - else - ret = SPI_IOC_CS0 ^ (SPI_IOC_CS0 | SPI_IOC_CS1); - } +static struct spi_board_info rb4xx_microsd_info[] = { + { + .bus_num = 0, + .chip_select = 2, + .max_speed_hz = 25000000, + .modalias = "mmc_spi", + .platform_data = &rb4xx_mmc_data, } +}; - return ret; -} -struct ar71xx_spi_platform_data rb433_spi_data = { - .bus_num = 0, - .num_chipselect = 3, - .get_ioc_base = rb433_spi_get_ioc_base, +static struct resource rb4xx_spi_resources[] = { + { + .start = AR71XX_SPI_BASE, + .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1, + .flags = IORESOURCE_MEM, + }, }; -static void rb4xx_add_device_spi(void) -{ - ar71xx_add_device_spi(NULL, rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info)); -} - -static void rb433_add_device_spi(void) -{ - ar71xx_add_device_spi(&rb433_spi_data, rb433_spi_info, - ARRAY_SIZE(rb433_spi_info)); -} -#else -static inline void rb4xx_add_device_spi(void) {} -static inline void rb433_add_device_spi(void) {} -#endif +static struct platform_device rb4xx_spi_device = { + .name = "rb4xx-spi", + .id = -1, + .resource = rb4xx_spi_resources, + .num_resources = ARRAY_SIZE(rb4xx_spi_resources), +}; static void __init rb4xx_generic_setup(void) { @@ -169,13 +205,16 @@ static void __init rb4xx_generic_setup(void) ARRAY_SIZE(rb4xx_gpio_buttons), rb4xx_gpio_buttons); + spi_register_board_info(rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info)); + platform_device_register(&rb4xx_spi_device); platform_device_register(&rb4xx_nand_device); } static void __init rb411_setup(void) { rb4xx_generic_setup(); - rb4xx_add_device_spi(); + spi_register_board_info(rb4xx_microsd_info, + ARRAY_SIZE(rb4xx_microsd_info)); ar71xx_add_device_mdio(0xfffffffc); @@ -207,7 +246,8 @@ MIPS_MACHINE(AR71XX_MACH_RB_411U, "411U", "MikroTik RouterBOARD 411U", static void __init rb433_setup(void) { rb4xx_generic_setup(); - rb433_add_device_spi(); + spi_register_board_info(rb4xx_microsd_info, + ARRAY_SIZE(rb4xx_microsd_info)); ar71xx_add_device_mdio(~RB433_MDIO_PHYMASK); @@ -244,8 +284,6 @@ MIPS_MACHINE(AR71XX_MACH_RB_433U, "433U", "MikroTik RouterBOARD 433UAH", static void __init rb450_generic_setup(int gige) { rb4xx_generic_setup(); - rb4xx_add_device_spi(); - ar71xx_add_device_mdio(~RB450_MDIO_PHYMASK); ar71xx_init_mac(ar71xx_eth0_data.mac_addr, ar71xx_mac_base, 1); @@ -271,6 +309,8 @@ MIPS_MACHINE(AR71XX_MACH_RB_450, "450", "MikroTik RouterBOARD 450", static void __init rb450g_setup(void) { rb450_generic_setup(1); + spi_register_board_info(rb4xx_microsd_info, + ARRAY_SIZE(rb4xx_microsd_info)); } MIPS_MACHINE(AR71XX_MACH_RB_450G, "450G", "MikroTik RouterBOARD 450G", @@ -279,7 +319,6 @@ MIPS_MACHINE(AR71XX_MACH_RB_450G, "450G", "MikroTik RouterBOARD 450G", static void __init rb493_setup(void) { rb4xx_generic_setup(); - rb4xx_add_device_spi(); ar71xx_add_device_mdio(0x3fffff00); diff --git a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/rb4xx_cpld.h b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/rb4xx_cpld.h new file mode 100644 index 0000000000..5b17e94b64 --- /dev/null +++ b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/rb4xx_cpld.h @@ -0,0 +1,48 @@ +/* + * SPI driver definitions for the CPLD chip on the Mikrotik RB4xx boards + * + * Copyright (C) 2010 Gabor Juhos + * + * This file was based on the patches for Linux 2.6.27.39 published by + * MikroTik for their RouterBoard 4xx series devices. + * + * 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. + */ + +#define CPLD_GPIO_nLED1 0 +#define CPLD_GPIO_nLED2 1 +#define CPLD_GPIO_nLED3 2 +#define CPLD_GPIO_nLED4 3 +#define CPLD_GPIO_FAN 4 +#define CPLD_GPIO_ALE 5 +#define CPLD_GPIO_CLE 6 +#define CPLD_GPIO_nCE 7 +#define CPLD_GPIO_nLED5 8 + +#define CPLD_NUM_GPIOS 9 + +#define CPLD_CFG_nLED1 BIT(CPLD_GPIO_nLED1) +#define CPLD_CFG_nLED2 BIT(CPLD_GPIO_nLED2) +#define CPLD_CFG_nLED3 BIT(CPLD_GPIO_nLED3) +#define CPLD_CFG_nLED4 BIT(CPLD_GPIO_nLED4) +#define CPLD_CFG_FAN BIT(CPLD_GPIO_FAN) +#define CPLD_CFG_ALE BIT(CPLD_GPIO_ALE) +#define CPLD_CFG_CLE BIT(CPLD_GPIO_CLE) +#define CPLD_CFG_nCE BIT(CPLD_GPIO_nCE) +#define CPLD_CFG_nLED5 BIT(CPLD_GPIO_nLED5) + +struct rb4xx_cpld_platform_data { + unsigned gpio_base; +}; + +extern int rb4xx_cpld_change_cfg(unsigned mask, unsigned value); +extern int rb4xx_cpld_read(unsigned char *rx_buf, + const unsigned char *verify_buf, + unsigned cnt); +extern int rb4xx_cpld_read_from(unsigned addr, + unsigned char *rx_buf, + const unsigned char *verify_buf, + unsigned cnt); +extern int rb4xx_cpld_write(const unsigned char *buf, unsigned count); diff --git a/target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c b/target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c index a107708a85..59ea17d896 100644 --- a/target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c +++ b/target/linux/ar71xx/files/drivers/mtd/nand/rb4xx_nand.c @@ -1,7 +1,7 @@ /* * NAND flash driver for the MikroTik RouterBoard 4xx series * - * Copyright (C) 2008 Gabor Juhos + * Copyright (C) 2008-2010 Gabor Juhos * Copyright (C) 2008 Imre Kaloz * * This file was based on the driver for Linux 2.6.22 published by @@ -23,49 +23,16 @@ #include #include +#include #define DRV_NAME "rb4xx-nand" -#define DRV_VERSION "0.1.10" +#define DRV_VERSION "0.2.0" #define DRV_DESC "NAND flash driver for RouterBoard 4xx series" -#define USE_FAST_READ 1 -#define USE_FAST_WRITE 1 -#undef RB4XX_NAND_DEBUG - -#ifdef RB4XX_NAND_DEBUG -#define DBG(fmt, arg...) printk(KERN_DEBUG DRV_NAME ": " fmt, ## arg) -#else -#define DBG(fmt, arg...) do {} while (0) -#endif - -#define RB4XX_NAND_GPIO_RDY 5 -#define RB4XX_FLASH_HZ 33333334 -#define RB4XX_NAND_HZ 33333334 - -#define SPI_CTRL_FASTEST 0x40 -#define SPI_CTRL_SAFE 0x43 /* 25 MHz for AHB 200 MHz */ -#define SBIT_IOC_BASE SPI_IOC_CS1 -#define SBIT_IOC_DO_SHIFT 0 -#define SBIT_IOC_DO (1u << SBIT_IOC_DO_SHIFT) -#define SBIT_IOC_DO2_SHIFT 18 -#define SBIT_IOC_DO2 (1u << SBIT_IOC_DO2_SHIFT) - -#define CPLD_CMD_WRITE_MULT 0x08 /* send cmd, n x send data, read data */ -#define CPLD_CMD_WRITE_CFG 0x09 /* send cmd, n x send cfg */ -#define CPLD_CMD_READ_MULT 0x0a /* send cmd, send idle, n x read data */ -#define CPLD_CMD_READ_FAST 0x0b /* send cmd, 4 x idle, n x read data */ - -#define CFG_BIT_nCE 0x80 -#define CFG_BIT_CLE 0x40 -#define CFG_BIT_ALE 0x20 -#define CFG_BIT_FAN 0x10 -#define CFG_BIT_nLED4 0x08 -#define CFG_BIT_nLED3 0x04 -#define CFG_BIT_nLED2 0x02 -#define CFG_BIT_nLED1 0x01 - -#define CFG_BIT_nLEDS \ - (CFG_BIT_nLED1 | CFG_BIT_nLED2 | CFG_BIT_nLED3 | CFG_BIT_nLED4) +#define RB4XX_NAND_GPIO_READY 5 +#define RB4XX_NAND_GPIO_ALE 37 +#define RB4XX_NAND_GPIO_CLE 38 +#define RB4XX_NAND_GPIO_NCE 39 struct rb4xx_nand_info { struct nand_chip chip; @@ -102,318 +69,138 @@ static struct mtd_partition rb4xx_nand_partitions[] = { }, }; -#if USE_FAST_READ -#define SPI_NDATA_BASE 0x00800000 -static unsigned spi_ctrl_fread = SPI_CTRL_SAFE; -static unsigned spi_ctrl_flash = SPI_CTRL_SAFE; -extern unsigned mips_hpt_frequency; -#endif - -static inline unsigned rb4xx_spi_rreg(unsigned r) -{ - return __raw_readl((void * __iomem)(KSEG1ADDR(AR71XX_SPI_BASE) + r)); -} - -static inline void rb4xx_spi_wreg(unsigned r, unsigned v) -{ - __raw_writel(v, (void * __iomem)(KSEG1ADDR(AR71XX_SPI_BASE) + r)); -} - -static inline void do_spi_clk(int bit) -{ - unsigned bval = SBIT_IOC_BASE | (bit & 1); - - rb4xx_spi_wreg(SPI_REG_IOC, bval); - rb4xx_spi_wreg(SPI_REG_IOC, bval | SPI_IOC_CLK); -} - -static void do_spi_byte(uint8_t byte) +static int rb4xx_nand_dev_ready(struct mtd_info *mtd) { - do_spi_clk(byte >> 7); - do_spi_clk(byte >> 6); - do_spi_clk(byte >> 5); - do_spi_clk(byte >> 4); - do_spi_clk(byte >> 3); - do_spi_clk(byte >> 2); - do_spi_clk(byte >> 1); - do_spi_clk(byte); - - DBG("spi_byte sent 0x%02x got 0x%x\n", - byte, rb4xx_spi_rreg(SPI_REG_RDS)); + return gpio_get_value(RB4XX_NAND_GPIO_READY); } -#if USE_FAST_WRITE -static inline void do_spi_clk_fast(int bit1, int bit2) +static void rb4xx_nand_write_cmd(unsigned char cmd) { - unsigned bval = (SBIT_IOC_BASE | - ((bit1 << SBIT_IOC_DO_SHIFT) & SBIT_IOC_DO) | - ((bit2 << SBIT_IOC_DO2_SHIFT) & SBIT_IOC_DO2)); + unsigned char data = cmd; + int err; - rb4xx_spi_wreg(SPI_REG_IOC, bval); - rb4xx_spi_wreg(SPI_REG_IOC, bval | SPI_IOC_CLK); + err = rb4xx_cpld_write(&data, 1); + if (err) + pr_err("rb4xx_nand: write cmd failed, err=%d\n", err); } -static inline void do_spi_byte_fast(uint8_t byte) +static void rb4xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) { - do_spi_clk_fast(byte >> 7, byte >> 6); - do_spi_clk_fast(byte >> 5, byte >> 4); - do_spi_clk_fast(byte >> 3, byte >> 2); - do_spi_clk_fast(byte >> 1, byte >> 0); + if (ctrl & NAND_CTRL_CHANGE) { + gpio_set_value(RB4XX_NAND_GPIO_CLE, (ctrl & NAND_CLE) ? 1 : 0); + gpio_set_value(RB4XX_NAND_GPIO_ALE, (ctrl & NAND_ALE) ? 1 : 0); + gpio_set_value(RB4XX_NAND_GPIO_NCE, (ctrl & NAND_NCE) ? 0 : 1); + } - DBG("spi_byte_fast sent 0x%02x got 0x%x\n", - byte, rb4xx_spi_rreg(SPI_REG_RDS)); -} -#else -static inline void do_spi_byte_fast(uint8_t byte) -{ - do_spi_byte(byte); + if (cmd != NAND_CMD_NONE) + rb4xx_nand_write_cmd(cmd); } -#endif /* USE_FAST_WRITE */ -static int do_spi_cmd(unsigned cmd, unsigned sendCnt, const uint8_t *sendData, - unsigned recvCnt, uint8_t *recvData, - const uint8_t *verifyData, int fastWrite) +static unsigned char rb4xx_nand_read_byte(struct mtd_info *mtd) { - unsigned i; - - DBG("SPI cmd 0x%x send %u recv %u\n", cmd, sendCnt, recvCnt); - - rb4xx_spi_wreg(SPI_REG_FS, SPI_FS_GPIO); - rb4xx_spi_wreg(SPI_REG_CTRL, SPI_CTRL_FASTEST); + unsigned char data = 0; + int err; - do_spi_byte(cmd); -#if 0 - if (cmd == CPLD_CMD_READ_FAST) { - do_spi_byte(0x80); - do_spi_byte(0); - do_spi_byte(0); - } -#endif - for (i = 0; i < sendCnt; ++i) { - if (fastWrite) - do_spi_byte_fast(sendData[i]); - else - do_spi_byte(sendData[i]); - } - - for (i = 0; i < recvCnt; ++i) { - if (fastWrite) - do_spi_byte_fast(0); - else - do_spi_byte(0); - - if (recvData) { - recvData[i] = rb4xx_spi_rreg(SPI_REG_RDS) & 0xff; - } else if (verifyData) { - if (verifyData[i] != (rb4xx_spi_rreg(SPI_REG_RDS) - & 0xff)) - break; - } + err = rb4xx_cpld_read(&data, NULL, 1); + if (err) { + pr_err("rb4xx_nand: read data failed, err=%d\n", err); + data = 0xff; } - rb4xx_spi_wreg(SPI_REG_IOC, SBIT_IOC_BASE | SPI_IOC_CS0); - rb4xx_spi_wreg(SPI_REG_CTRL, spi_ctrl_flash); - rb4xx_spi_wreg(SPI_REG_FS, 0); - - return i == recvCnt; + return data; } -static int got_write = 1; - -static void rb4xx_nand_write_data(const uint8_t *byte, unsigned cnt) +static void rb4xx_nand_write_buf(struct mtd_info *mtd, const unsigned char *buf, + int len) { - do_spi_cmd(CPLD_CMD_WRITE_MULT, cnt, byte, 1, NULL, NULL, 1); - got_write = 1; -} + int err; -static void rb4xx_nand_write_byte(uint8_t byte) -{ - rb4xx_nand_write_data(&byte, 1); + err = rb4xx_cpld_write(buf, len); + if (err) + pr_err("rb4xx_nand: write buf failed, err=%d\n", err); } -#if USE_FAST_READ -static uint8_t *rb4xx_nand_read_getaddr(unsigned cnt) +static void rb4xx_nand_read_buf(struct mtd_info *mtd, unsigned char *buf, + int len) { - static unsigned nboffset = 0x100000; - unsigned addr; - - if (got_write) { - nboffset = (nboffset + 31) & ~31; - if (nboffset >= 0x100000) /* 1MB */ - nboffset = 0; - - got_write = 0; - rb4xx_spi_wreg(SPI_REG_FS, SPI_FS_GPIO); - rb4xx_spi_wreg(SPI_REG_CTRL, spi_ctrl_fread); - rb4xx_spi_wreg(SPI_REG_FS, 0); - } + int err; - addr = KSEG1ADDR(AR71XX_SPI_BASE + SPI_NDATA_BASE) + nboffset; - DBG("rb4xx_nand_read_getaddr 0x%x cnt 0x%x\n", addr, cnt); - - nboffset += cnt; - return (uint8_t *)addr; + err = rb4xx_cpld_read(buf, NULL, len); + if (err) + pr_err("rb4xx_nand: read buf failed, err=%d\n", err); } -static void rb4xx_nand_read_data(uint8_t *buf, unsigned cnt) +static int __init rb4xx_nand_probe(struct platform_device *pdev) { - unsigned size32 = cnt & ~31; - unsigned remain = cnt & 31; + struct rb4xx_nand_info *info; + int ret; - if (size32) { - uint8_t *addr = rb4xx_nand_read_getaddr(size32); - memcpy(buf, (void *)addr, size32); - } + printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n"); - if (remain) { - do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain, - buf + size32, NULL, 0); + ret = gpio_request(RB4XX_NAND_GPIO_READY, "NAND RDY"); + if (ret) { + dev_err(&pdev->dev, "unable to request gpio %d\n", + RB4XX_NAND_GPIO_READY); + goto err; } -} - -static int rb4xx_nand_verify_data(const uint8_t *buf, unsigned cnt) -{ - unsigned size32 = cnt & ~31; - unsigned remain = cnt & 31; - if (size32) { - uint8_t *addr = rb4xx_nand_read_getaddr(size32); - if (memcmp(buf, (void *)addr, size32) != 0) - return 0; + ret = gpio_direction_input(RB4XX_NAND_GPIO_READY); + if (ret) { + dev_err(&pdev->dev, "unable to set input mode on gpio %d\n", + RB4XX_NAND_GPIO_READY); + goto err_free_gpio_ready; } - if (remain) { - return do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, remain, - NULL, buf + size32, 0); + ret = gpio_request(RB4XX_NAND_GPIO_ALE, "NAND ALE"); + if (ret) { + dev_err(&pdev->dev, "unable to request gpio %d\n", + RB4XX_NAND_GPIO_ALE); + goto err_free_gpio_ready; } - return 1; -} -#else /* USE_FAST_READ */ -static void rb4xx_nand_read_data(uint8_t *buf, unsigned cnt) -{ - do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, cnt, buf, NULL, 0); -} -static int rb4xx_nand_verify_data(const uint8_t *buf, unsigned cnt) -{ - return do_spi_cmd(CPLD_CMD_READ_MULT, 1, buf, cnt, NULL, buf, 0); -} -#endif /* USE_FAST_READ */ - -static void rb4xx_nand_write_cfg(uint8_t byte) -{ - do_spi_cmd(CPLD_CMD_WRITE_CFG, 1, &byte, 0, NULL, NULL, 0); - got_write = 1; -} - -static int rb4xx_nand_dev_ready(struct mtd_info *mtd) -{ - return gpio_get_value(RB4XX_NAND_GPIO_RDY); -} - -static void rb4xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - if (ctrl & NAND_CTRL_CHANGE) { - uint8_t cfg = CFG_BIT_nLEDS; - - cfg |= (ctrl & NAND_CLE) ? CFG_BIT_CLE : 0; - cfg |= (ctrl & NAND_ALE) ? CFG_BIT_ALE : 0; - cfg |= (ctrl & NAND_NCE) ? 0 : CFG_BIT_nCE; - - rb4xx_nand_write_cfg(cfg); + ret = gpio_direction_output(RB4XX_NAND_GPIO_ALE, 0); + if (ret) { + dev_err(&pdev->dev, "unable to set output mode on gpio %d\n", + RB4XX_NAND_GPIO_ALE); + goto err_free_gpio_ale; } - if (cmd != NAND_CMD_NONE) - rb4xx_nand_write_byte(cmd); -} - -static uint8_t rb4xx_nand_read_byte(struct mtd_info *mtd) -{ - uint8_t byte = 0; - - rb4xx_nand_read_data(&byte, 1); - return byte; -} - -static void rb4xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - rb4xx_nand_write_data(buf, len); -} - -static void rb4xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, - int len) -{ - rb4xx_nand_read_data(buf, len); -} - -static int rb4xx_nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - if (!rb4xx_nand_verify_data(buf, len)) - return -EFAULT; - - return 0; -} - -static unsigned get_spi_ctrl(unsigned hz_max, const char *name) -{ - unsigned div; - - div = (ar71xx_ahb_freq - 1) / (2 * hz_max); - /* - * CPU has a bug at (div == 0) - first bit read is random - */ - if (div == 0) - ++div; - - if (name) { - unsigned ahb_khz = (ar71xx_ahb_freq + 500) / 1000; - unsigned div_real = 2 * (div + 1); - printk(KERN_INFO "%s SPI clock %u kHz (AHB %u kHz / %u)\n", - name, - ahb_khz / div_real, - ahb_khz, div_real); + ret = gpio_request(RB4XX_NAND_GPIO_CLE, "NAND CLE"); + if (ret) { + dev_err(&pdev->dev, "unable to request gpio %d\n", + RB4XX_NAND_GPIO_CLE); + goto err_free_gpio_ale; } - return SPI_CTRL_FASTEST + div; -} - -static int __init rb4xx_nand_probe(struct platform_device *pdev) -{ - struct rb4xx_nand_info *info; - int ret; - - printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n"); + ret = gpio_direction_output(RB4XX_NAND_GPIO_CLE, 0); + if (ret) { + dev_err(&pdev->dev, "unable to set output mode on gpio %d\n", + RB4XX_NAND_GPIO_CLE); + goto err_free_gpio_cle; + } - ret = gpio_request(RB4XX_NAND_GPIO_RDY, "NAND RDY"); + ret = gpio_request(RB4XX_NAND_GPIO_NCE, "NAND NCE"); if (ret) { - printk(KERN_ERR "rb4xx-nand: gpio request failed\n"); - return ret; + dev_err(&pdev->dev, "unable to request gpio %d\n", + RB4XX_NAND_GPIO_NCE); + goto err_free_gpio_cle; } - ret = gpio_direction_input(RB4XX_NAND_GPIO_RDY); + ret = gpio_direction_output(RB4XX_NAND_GPIO_NCE, 1); if (ret) { - printk(KERN_ERR "rb4xx-nand: unable to set input mode " - "on gpio%d\n", RB4XX_NAND_GPIO_RDY); - goto err_free_gpio; + dev_err(&pdev->dev, "unable to set output mode on gpio %d\n", + RB4XX_NAND_GPIO_ALE); + goto err_free_gpio_nce; } info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { - printk(KERN_ERR "rb4xx-nand: no memory for private data\n"); + dev_err(&pdev->dev, "rb4xx-nand: no memory for private data\n"); ret = -ENOMEM; - goto err_free_gpio; + goto err_free_gpio_nce; } -#if USE_FAST_READ - spi_ctrl_fread = get_spi_ctrl(RB4XX_NAND_HZ, "NAND"); -#endif - spi_ctrl_flash = get_spi_ctrl(RB4XX_FLASH_HZ, "FLASH"); - - rb4xx_nand_write_cfg(CFG_BIT_nLEDS | CFG_BIT_nCE); - info->chip.priv = &info; info->mtd.priv = &info->chip; info->mtd.owner = THIS_MODULE; @@ -423,7 +210,7 @@ static int __init rb4xx_nand_probe(struct platform_device *pdev) info->chip.read_byte = rb4xx_nand_read_byte; info->chip.write_buf = rb4xx_nand_write_buf; info->chip.read_buf = rb4xx_nand_read_buf; - info->chip.verify_buf = rb4xx_nand_verify_buf; +// info->chip.verify_buf = rb4xx_nand_verify_buf; info->chip.chip_delay = 25; info->chip.ecc.mode = NAND_ECC_SOFT; @@ -457,14 +244,21 @@ static int __init rb4xx_nand_probe(struct platform_device *pdev) return 0; -err_release_nand: + err_release_nand: nand_release(&info->mtd); -err_set_drvdata: + err_set_drvdata: platform_set_drvdata(pdev, NULL); -err_free_info: + err_free_info: kfree(info); -err_free_gpio: - gpio_free(RB4XX_NAND_GPIO_RDY); + err_free_gpio_nce: + gpio_free(RB4XX_NAND_GPIO_NCE); + err_free_gpio_cle: + gpio_free(RB4XX_NAND_GPIO_CLE); + err_free_gpio_ale: + gpio_free(RB4XX_NAND_GPIO_ALE); + err_free_gpio_ready: + gpio_free(RB4XX_NAND_GPIO_READY); + err: return ret; } @@ -475,6 +269,10 @@ static int __devexit rb4xx_nand_remove(struct platform_device *pdev) nand_release(&info->mtd); platform_set_drvdata(pdev, NULL); kfree(info); + gpio_free(RB4XX_NAND_GPIO_NCE); + gpio_free(RB4XX_NAND_GPIO_CLE); + gpio_free(RB4XX_NAND_GPIO_ALE); + gpio_free(RB4XX_NAND_GPIO_READY); return 0; } diff --git a/target/linux/ar71xx/files/drivers/spi/rb4xx_spi.c b/target/linux/ar71xx/files/drivers/spi/rb4xx_spi.c new file mode 100644 index 0000000000..731f501547 --- /dev/null +++ b/target/linux/ar71xx/files/drivers/spi/rb4xx_spi.c @@ -0,0 +1,480 @@ +/* + * SPI controller driver for the Mikrotik RB4xx boards + * + * Copyright (C) 2010 Gabor Juhos + * + * This file was based on the patches for Linux 2.6.27.39 published by + * MikroTik for their RouterBoard 4xx series devices. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#define DRV_NAME "rb4xx-spi" +#define DRV_DESC "Mikrotik RB4xx SPI controller driver" +#define DRV_VERSION "0.1.0" + +#define SPI_CTRL_FASTEST 0x40 +#define SPI_FLASH_HZ 33333334 +#define SPI_CPLD_HZ 33333334 + +#define CPLD_CMD_READ_FAST 0x0b + +#undef RB4XX_SPI_DEBUG + +struct rb4xx_spi { + void __iomem *base; + struct spi_master *master; + + unsigned spi_ctrl_flash; + unsigned spi_ctrl_fread; + + spinlock_t lock; + struct list_head queue; + int busy:1; + int cs_wait; +}; + +static unsigned spi_clk_low = SPI_IOC_CS1; + +#ifdef RB4XX_SPI_DEBUG +static inline void do_spi_delay(void) +{ + ndelay(20000); +} +#else +static inline void do_spi_delay(void) { } +#endif + +static inline void do_spi_init(struct spi_device *spi) +{ + unsigned cs = SPI_IOC_CS0 | SPI_IOC_CS1; + + if (!(spi->mode & SPI_CS_HIGH)) + cs ^= (spi->chip_select == 2) ? SPI_IOC_CS1 : SPI_IOC_CS0; + + spi_clk_low = cs; +} + +static inline void do_spi_finish(void __iomem *base) +{ + do_spi_delay(); + __raw_writel(SPI_IOC_CS0 | SPI_IOC_CS1, base + SPI_REG_IOC); +} + +static inline void do_spi_clk(void __iomem *base, int bit) +{ + unsigned bval = spi_clk_low | ((bit & 1) ? SPI_IOC_DO : 0); + + do_spi_delay(); + __raw_writel(bval, base + SPI_REG_IOC); + do_spi_delay(); + __raw_writel(bval | SPI_IOC_CLK, base + SPI_REG_IOC); +} + +static void do_spi_byte(void __iomem *base, unsigned char byte) +{ + do_spi_clk(base, byte >> 7); + do_spi_clk(base, byte >> 6); + do_spi_clk(base, byte >> 5); + do_spi_clk(base, byte >> 4); + do_spi_clk(base, byte >> 3); + do_spi_clk(base, byte >> 2); + do_spi_clk(base, byte >> 1); + do_spi_clk(base, byte); + +#ifdef RB4XX_SPI_DEBUG + printk("spi_byte sent 0x%02x got 0x%02x\n", + (unsigned)byte, + (unsigned char)__raw_readl(base + SPI_REG_RDS)); +#endif +} + +static inline void do_spi_clk_fast(void __iomem *base, unsigned bit1, + unsigned bit2) +{ + unsigned bval = (spi_clk_low | + ((bit1 & 1) ? SPI_IOC_DO : 0) | + ((bit2 & 1) ? SPI_IOC_CS2 : 0)); + do_spi_delay(); + __raw_writel(bval, base + SPI_REG_IOC); + do_spi_delay(); + __raw_writel(bval | SPI_IOC_CLK, base + SPI_REG_IOC); +} + +static void do_spi_byte_fast(void __iomem *base, unsigned char byte) +{ + do_spi_clk_fast(base, byte >> 7, byte >> 6); + do_spi_clk_fast(base, byte >> 5, byte >> 4); + do_spi_clk_fast(base, byte >> 3, byte >> 2); + do_spi_clk_fast(base, byte >> 1, byte >> 0); + +#ifdef RB4XX_SPI_DEBUG + printk("spi_byte_fast sent 0x%02x got 0x%02x\n", + (unsigned)byte, + (unsigned char) __raw_readl(base + SPI_REG_RDS)); +#endif +} + +static int rb4xx_spi_txrx(void __iomem *base, struct spi_transfer *t) +{ + const unsigned char *rxv_ptr = NULL; + const unsigned char *tx_ptr = t->tx_buf; + unsigned char *rx_ptr = t->rx_buf; + unsigned i; + +#ifdef RB4XX_SPI_DEBUG + printk("spi_txrx len %u tx %u rx %u\n", + t->len, + (t->tx_buf ? 1 : 0), + (t->rx_buf ? 1 : 0)); +#endif + + if (t->verify) { + rxv_ptr = tx_ptr; + tx_ptr = NULL; + } + + for (i = 0; i < t->len; ++i) { + unsigned char sdata = tx_ptr ? tx_ptr[i] : 0; + + if (t->fast_write) + do_spi_byte_fast(base, sdata); + else + do_spi_byte(base, sdata); + + if (rx_ptr) { + rx_ptr[i] = __raw_readl(base + SPI_REG_RDS) & 0xff; + } else if (rxv_ptr) { + unsigned char c = __raw_readl(base + SPI_REG_RDS); + if (rxv_ptr[i] != c) + return i; + } + } + + return i; +} + +static int rb4xx_spi_read_fast(struct rb4xx_spi *rbspi, + struct spi_message *m) +{ + struct spi_transfer *t; + const unsigned char *tx_ptr; + unsigned addr; + void __iomem *base = rbspi->base; + + /* check for exactly two transfers */ + if (list_empty(&m->transfers) || + list_is_last(m->transfers.next, &m->transfers) || + !list_is_last(m->transfers.next->next, &m->transfers)) { + return -1; + } + + /* first transfer contains command and address */ + t = list_entry(m->transfers.next, + struct spi_transfer, transfer_list); + + if (t->len != 5 || t->tx_buf == NULL) + return -1; + + tx_ptr = t->tx_buf; + if (tx_ptr[0] != CPLD_CMD_READ_FAST) + return -1; + + addr = tx_ptr[1]; + addr = tx_ptr[2] | (addr << 8); + addr = tx_ptr[3] | (addr << 8); + addr += (unsigned) base; + + m->actual_length += t->len; + + /* second transfer contains data itself */ + t = list_entry(m->transfers.next->next, + struct spi_transfer, transfer_list); + + if (t->tx_buf && !t->verify) + return -1; + + __raw_writel(SPI_FS_GPIO, base + SPI_REG_FS); + __raw_writel(rbspi->spi_ctrl_fread, base + SPI_REG_CTRL); + __raw_writel(0, base + SPI_REG_FS); + + if (t->rx_buf) { + memcpy(t->rx_buf, (const void *)addr, t->len); + } else if (t->tx_buf) { + unsigned char buf[t->len]; + memcpy(buf, (const void *)addr, t->len); + if (memcmp(t->tx_buf, buf, t->len) != 0) + m->status = -EMSGSIZE; + } + m->actual_length += t->len; + + if (rbspi->spi_ctrl_flash != rbspi->spi_ctrl_fread) { + __raw_writel(SPI_FS_GPIO, base + SPI_REG_FS); + __raw_writel(rbspi->spi_ctrl_flash, base + SPI_REG_CTRL); + __raw_writel(0, base + SPI_REG_FS); + } + + return 0; +} + +static int rb4xx_spi_msg(struct rb4xx_spi *rbspi, struct spi_message *m) +{ + struct spi_transfer *t = NULL; + void __iomem *base = rbspi->base; + + m->status = 0; + if (list_empty(&m->transfers)) + return -1; + + if (m->fast_read) + if (rb4xx_spi_read_fast(rbspi, m) == 0) + return -1; + + __raw_writel(SPI_FS_GPIO, base + SPI_REG_FS); + __raw_writel(SPI_CTRL_FASTEST, base + SPI_REG_CTRL); + do_spi_init(m->spi); + + list_for_each_entry (t, &m->transfers, transfer_list) { + int len; + + len = rb4xx_spi_txrx(base, t); + if (len != t->len) { + m->status = -EMSGSIZE; + break; + } + m->actual_length += len; + + if (t->cs_change) { + if (list_is_last(&t->transfer_list, &m->transfers)) { + /* wait for continuation */ + return m->spi->chip_select; + } + do_spi_finish(base); + ndelay(100); + } + } + + do_spi_finish(base); + __raw_writel(rbspi->spi_ctrl_flash, base + SPI_REG_CTRL); + __raw_writel(0, base + SPI_REG_FS); + return -1; +} + +static void rb4xx_spi_process_queue_locked(struct rb4xx_spi *rbspi, + unsigned long *flags) +{ + int cs = rbspi->cs_wait; + + rbspi->busy = 1; + while (!list_empty(&rbspi->queue)) { + struct spi_message *m; + + list_for_each_entry(m, &rbspi->queue, queue) + if (cs < 0 || cs == m->spi->chip_select) + break; + + if (&m->queue == &rbspi->queue) + break; + + list_del_init(&m->queue); + spin_unlock_irqrestore(&rbspi->lock, *flags); + + cs = rb4xx_spi_msg(rbspi, m); + m->complete(m->context); + + spin_lock_irqsave(&rbspi->lock, *flags); + } + + rbspi->cs_wait = cs; + rbspi->busy = 0; + + if (cs >= 0) { + /* TODO: add timer to unlock cs after 1s inactivity */ + } +} + +static int rb4xx_spi_transfer(struct spi_device *spi, + struct spi_message *m) +{ + struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master); + unsigned long flags; + + m->actual_length = 0; + m->status = -EINPROGRESS; + + spin_lock_irqsave(&rbspi->lock, flags); + list_add_tail(&m->queue, &rbspi->queue); + if (rbspi->busy || + (rbspi->cs_wait >= 0 && rbspi->cs_wait != m->spi->chip_select)) { + /* job will be done later */ + spin_unlock_irqrestore(&rbspi->lock, flags); + return 0; + } + + /* process job in current context */ + rb4xx_spi_process_queue_locked(rbspi, &flags); + spin_unlock_irqrestore(&rbspi->lock, flags); + + return 0; +} + +static int rb4xx_spi_setup(struct spi_device *spi) +{ + struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master); + unsigned long flags; + + if (spi->mode & ~(SPI_CS_HIGH)) { + dev_err(&spi->dev, "mode %x not supported\n", + (unsigned) spi->mode); + return -EINVAL; + } + + if (spi->bits_per_word != 8 && spi->bits_per_word != 0) { + dev_err(&spi->dev, "bits_per_word %u not supported\n", + (unsigned) spi->bits_per_word); + return -EINVAL; + } + + spin_lock_irqsave(&rbspi->lock, flags); + if (rbspi->cs_wait == spi->chip_select && !rbspi->busy) { + rbspi->cs_wait = -1; + rb4xx_spi_process_queue_locked(rbspi, &flags); + } + spin_unlock_irqrestore(&rbspi->lock, flags); + + return 0; +} + +static unsigned get_spi_ctrl(unsigned hz_max, const char *name) +{ + unsigned div; + + div = (ar71xx_ahb_freq - 1) / (2 * hz_max); + + /* + * CPU has a bug at (div == 0) - first bit read is random + */ + if (div == 0) + ++div; + + if (name) { + unsigned ahb_khz = (ar71xx_ahb_freq + 500) / 1000; + unsigned div_real = 2 * (div + 1); + pr_debug("rb4xx: %s SPI clock %u kHz (AHB %u kHz / %u)\n", + name, + ahb_khz / div_real, + ahb_khz, div_real); + } + + return SPI_CTRL_FASTEST + div; +} + +static int rb4xx_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct rb4xx_spi *rbspi; + struct resource *r; + int err = 0; + + master = spi_alloc_master(&pdev->dev, sizeof(*rbspi)); + if (master == NULL) { + dev_err(&pdev->dev, "no memory for spi_master\n"); + err = -ENOMEM; + goto err_out; + } + + master->bus_num = 0; + master->num_chipselect = 3; + master->setup = rb4xx_spi_setup; + master->transfer = rb4xx_spi_transfer; + + rbspi = spi_master_get_devdata(master); + platform_set_drvdata(pdev, rbspi); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (r == NULL) { + err = -ENOENT; + goto err_put_master; + } + + rbspi->base = ioremap(r->start, r->end - r->start + 1); + if (!rbspi->base) { + err = -ENXIO; + goto err_put_master; + } + + rbspi->master = master; + rbspi->spi_ctrl_flash = get_spi_ctrl(SPI_FLASH_HZ, "FLASH"); + rbspi->spi_ctrl_fread = get_spi_ctrl(SPI_CPLD_HZ, "CPLD"); + rbspi->cs_wait = -1; + + spin_lock_init(&rbspi->lock); + INIT_LIST_HEAD(&rbspi->queue); + + err = spi_register_master(master); + if (err) { + dev_err(&pdev->dev, "failed to register SPI master\n"); + goto err_iounmap; + } + + return 0; + + err_iounmap: + iounmap(rbspi->base); + err_put_master: + platform_set_drvdata(pdev, NULL); + spi_master_put(master); + err_out: + return err; +} + +static int rb4xx_spi_remove(struct platform_device *pdev) +{ + struct rb4xx_spi *rbspi = platform_get_drvdata(pdev); + + iounmap(rbspi->base); + platform_set_drvdata(pdev, NULL); + spi_master_put(rbspi->master); + + return 0; +} + +static struct platform_driver rb4xx_spi_drv = { + .probe = rb4xx_spi_probe, + .remove = rb4xx_spi_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init rb4xx_spi_init(void) +{ + return platform_driver_register(&rb4xx_spi_drv); +} +subsys_initcall(rb4xx_spi_init); + +static void __exit rb4xx_spi_exit(void) +{ + platform_driver_unregister(&rb4xx_spi_drv); +} + +module_exit(rb4xx_spi_exit); + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); diff --git a/target/linux/ar71xx/files/drivers/spi/spi_rb4xx_cpld.c b/target/linux/ar71xx/files/drivers/spi/spi_rb4xx_cpld.c new file mode 100644 index 0000000000..8b34c1b23d --- /dev/null +++ b/target/linux/ar71xx/files/drivers/spi/spi_rb4xx_cpld.c @@ -0,0 +1,440 @@ +/* + * SPI driver for the CPLD chip on the Mikrotik RB4xx boards + * + * Copyright (C) 2010 Gabor Juhos + * + * This file was based on the patches for Linux 2.6.27.39 published by + * MikroTik for their RouterBoard 4xx series devices. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRV_NAME "spi-rb4xx-cpld" +#define DRV_DESC "RB4xx CPLD driver" +#define DRV_VERSION "0.1.0" + +#define CPLD_CMD_WRITE_NAND 0x08 /* send cmd, n x send data, send indle */ +#define CPLD_CMD_WRITE_CFG 0x09 /* send cmd, n x send cfg */ +#define CPLD_CMD_READ_NAND 0x0a /* send cmd, send idle, n x read data */ +#define CPLD_CMD_READ_FAST 0x0b /* send cmd, 4 x idle, n x read data */ +#define CPLD_CMD_LED5_ON 0x0c /* send cmd */ +#define CPLD_CMD_LED5_OFF 0x0d /* send cmd */ + +struct rb4xx_cpld { + struct spi_device *spi; + struct mutex lock; + struct gpio_chip chip; + unsigned int config; +}; + +static struct rb4xx_cpld *rb4xx_cpld; + +static inline struct rb4xx_cpld *gpio_to_cpld(struct gpio_chip *chip) +{ + return container_of(chip, struct rb4xx_cpld, chip); +} + +static int rb4xx_cpld_write_cmd(struct rb4xx_cpld *cpld, unsigned char cmd) +{ + struct spi_transfer t[1]; + struct spi_message m; + unsigned char tx_buf[1]; + int err; + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + + t[0].tx_buf = tx_buf; + t[0].len = sizeof(tx_buf); + spi_message_add_tail(&t[0], &m); + + tx_buf[0] = cmd; + + err = spi_sync(cpld->spi, &m); + return err; +} + +static int rb4xx_cpld_write_cfg(struct rb4xx_cpld *cpld, unsigned char config) +{ + struct spi_transfer t[1]; + struct spi_message m; + unsigned char cmd[2]; + int err; + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + + t[0].tx_buf = cmd; + t[0].len = sizeof(cmd); + spi_message_add_tail(&t[0], &m); + + cmd[0] = CPLD_CMD_WRITE_CFG; + cmd[1] = config; + + err = spi_sync(cpld->spi, &m); + return err; +} + +static int __rb4xx_cpld_change_cfg(struct rb4xx_cpld *cpld, unsigned mask, + unsigned value) +{ + unsigned int config; + int err; + + config = cpld->config & ~mask; + config |= value; + + if ((cpld->config ^ config) & 0xff) { + err = rb4xx_cpld_write_cfg(cpld, config); + if (err) + return err; + } + + if ((cpld->config ^ config) & CPLD_CFG_nLED5) { + err = rb4xx_cpld_write_cmd(cpld, (value) ? CPLD_CMD_LED5_ON : + CPLD_CMD_LED5_OFF); + if (err) + return err; + } + + cpld->config = config; + return 0; +} + +int rb4xx_cpld_change_cfg(unsigned mask, unsigned value) +{ + int ret; + + if (rb4xx_cpld == NULL) + return -ENODEV; + + mutex_lock(&rb4xx_cpld->lock); + ret = __rb4xx_cpld_change_cfg(rb4xx_cpld, mask, value); + mutex_unlock(&rb4xx_cpld->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(rb4xx_cpld_change_cfg); + +int rb4xx_cpld_read_from(unsigned addr, unsigned char *rx_buf, + const unsigned char *verify_buf, unsigned count) +{ + const unsigned char cmd[5] = { + CPLD_CMD_READ_FAST, + (addr >> 16) & 0xff, + (addr >> 8) & 0xff, + addr & 0xff, + 0 + }; + struct spi_transfer t[2] = { + { + .tx_buf = &cmd, + .len = 5, + }, + { + .tx_buf = verify_buf, + .rx_buf = rx_buf, + .len = count, + .verify = (verify_buf != NULL), + }, + }; + struct spi_message m; + + if (rb4xx_cpld == NULL) + return -ENODEV; + + spi_message_init(&m); + m.fast_read = 1; + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + return spi_sync(rb4xx_cpld->spi, &m); +} +EXPORT_SYMBOL_GPL(rb4xx_cpld_read_from); + +#if 0 +int rb4xx_cpld_read(unsigned char *buf, unsigned char *verify_buf, + unsigned count) +{ + struct spi_transfer t[2]; + struct spi_message m; + unsigned char cmd[2]; + + if (rb4xx_cpld == NULL) + return -ENODEV; + + spi_message_init(&m); + memset(&t, 0, sizeof(t)); + + /* send command */ + t[0].tx_buf = cmd; + t[0].len = sizeof(cmd); + spi_message_add_tail(&t[0], &m); + + cmd[0] = CPLD_CMD_READ_NAND; + cmd[1] = 0; + + /* read data */ + t[1].rx_buf = buf; + t[1].len = count; + spi_message_add_tail(&t[1], &m); + + return spi_sync(rb4xx_cpld->spi, &m); +} +#else +int rb4xx_cpld_read(unsigned char *rx_buf, const unsigned char *verify_buf, + unsigned count) +{ + static const unsigned char cmd[2] = { CPLD_CMD_READ_NAND, 0 }; + struct spi_transfer t[2] = { + { + .tx_buf = &cmd, + .len = 2, + }, { + .tx_buf = verify_buf, + .rx_buf = rx_buf, + .len = count, + .verify = (verify_buf != NULL), + }, + }; + struct spi_message m; + + if (rb4xx_cpld == NULL) + return -ENODEV; + + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + return spi_sync(rb4xx_cpld->spi, &m); +} +#endif +EXPORT_SYMBOL_GPL(rb4xx_cpld_read); + +int rb4xx_cpld_write(const unsigned char *buf, unsigned count) +{ +#if 0 + struct spi_transfer t[3]; + struct spi_message m; + unsigned char cmd[1]; + + if (rb4xx_cpld == NULL) + return -ENODEV; + + memset(&t, 0, sizeof(t)); + spi_message_init(&m); + + /* send command */ + t[0].tx_buf = cmd; + t[0].len = sizeof(cmd); + spi_message_add_tail(&t[0], &m); + + cmd[0] = CPLD_CMD_WRITE_NAND; + + /* write data */ + t[1].tx_buf = buf; + t[1].len = count; + spi_message_add_tail(&t[1], &m); + + /* send idle */ + t[2].len = 1; + spi_message_add_tail(&t[2], &m); + + return spi_sync(rb4xx_cpld->spi, &m); +#else + static const unsigned char cmd = CPLD_CMD_WRITE_NAND; + struct spi_transfer t[3] = { + { + .tx_buf = &cmd, + .len = 1, + }, { + .tx_buf = buf, + .len = count, + .fast_write = 1, + }, { + .len = 1, + .fast_write = 1, + }, + }; + struct spi_message m; + + if (rb4xx_cpld == NULL) + return -ENODEV; + + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + spi_message_add_tail(&t[2], &m); + return spi_sync(rb4xx_cpld->spi, &m); +#endif +} +EXPORT_SYMBOL_GPL(rb4xx_cpld_write); + +static int rb4xx_cpld_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct rb4xx_cpld *cpld = gpio_to_cpld(chip); + int ret; + + mutex_lock(&cpld->lock); + ret = (cpld->config >> offset) & 1; + mutex_unlock(&cpld->lock); + + return ret; +} + +static void rb4xx_cpld_gpio_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct rb4xx_cpld *cpld = gpio_to_cpld(chip); + + mutex_lock(&cpld->lock); + __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset); + mutex_unlock(&cpld->lock); +} + +static int rb4xx_cpld_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + return -EOPNOTSUPP; +} + +static int rb4xx_cpld_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, + int value) +{ + struct rb4xx_cpld *cpld = gpio_to_cpld(chip); + int ret; + + mutex_lock(&cpld->lock); + ret = __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset); + mutex_unlock(&cpld->lock); + + return ret; +} + +static int rb4xx_cpld_gpio_init(struct rb4xx_cpld *cpld, unsigned int base) +{ + int err; + + /* init config */ + cpld->config = CPLD_CFG_nLED1 | CPLD_CFG_nLED2 | CPLD_CFG_nLED3 | + CPLD_CFG_nLED4 | CPLD_CFG_nCE; + rb4xx_cpld_write_cfg(cpld, cpld->config); + + /* setup GPIO chip */ + cpld->chip.label = DRV_NAME; + + cpld->chip.get = rb4xx_cpld_gpio_get; + cpld->chip.set = rb4xx_cpld_gpio_set; + cpld->chip.direction_input = rb4xx_cpld_gpio_direction_input; + cpld->chip.direction_output = rb4xx_cpld_gpio_direction_output; + + cpld->chip.base = base; + cpld->chip.ngpio = CPLD_NUM_GPIOS; + cpld->chip.can_sleep = 1; + cpld->chip.dev = &cpld->spi->dev; + cpld->chip.owner = THIS_MODULE; + + err = gpiochip_add(&cpld->chip); + if (err) + dev_err(&cpld->spi->dev, "adding GPIO chip failed, err=%d\n", + err); + + return err; +} + +static int __devinit rb4xx_cpld_probe(struct spi_device *spi) +{ + struct rb4xx_cpld *cpld; + struct rb4xx_cpld_platform_data *pdata; + int err; + + pdata = spi->dev.platform_data; + if (!pdata) { + dev_dbg(&spi->dev, "no platform data\n"); + return -EINVAL; + } + + cpld = kzalloc(sizeof(*cpld), GFP_KERNEL); + if (!cpld) { + dev_err(&spi->dev, "no memory for private data\n"); + return -ENOMEM; + } + + mutex_init(&cpld->lock); + cpld->spi = spi_dev_get(spi); + dev_set_drvdata(&spi->dev, cpld); + + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + err = spi_setup(spi); + if (err) { + dev_err(&spi->dev, "spi_setup failed, err=%d\n", err); + goto err_drvdata; + } + + err = rb4xx_cpld_gpio_init(cpld, pdata->gpio_base); + if (err) + goto err_drvdata; + + rb4xx_cpld = cpld; + + return 0; + + err_drvdata: + dev_set_drvdata(&spi->dev, NULL); + kfree(cpld); + + return err; +} + +static int __devexit rb4xx_cpld_remove(struct spi_device *spi) +{ + struct rb4xx_cpld *cpld; + + rb4xx_cpld = NULL; + cpld = dev_get_drvdata(&spi->dev); + dev_set_drvdata(&spi->dev, NULL); + kfree(cpld); + + return 0; +} + +static struct spi_driver rb4xx_cpld_driver = { + .driver = { + .name = DRV_NAME, + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = rb4xx_cpld_probe, + .remove = __devexit_p(rb4xx_cpld_remove), +}; + +static int __init rb4xx_cpld_init(void) +{ + return spi_register_driver(&rb4xx_cpld_driver); +} +module_init(rb4xx_cpld_init); + +static void __exit rb4xx_cpld_exit(void) +{ + spi_unregister_driver(&rb4xx_cpld_driver); +} +module_exit(rb4xx_cpld_exit); + +MODULE_DESCRIPTION(DRV_DESC); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("Gabor Juhos "); +MODULE_LICENSE("GPL v2"); diff --git a/target/linux/ar71xx/nand/config-default b/target/linux/ar71xx/nand/config-default index bde9171128..c8ef6168d8 100644 --- a/target/linux/ar71xx/nand/config-default +++ b/target/linux/ar71xx/nand/config-default @@ -2,6 +2,8 @@ CONFIG_IP17XX_PHY=y CONFIG_MTD_NAND=y CONFIG_MTD_NAND_RB4XX=y CONFIG_MTD_NAND_RB750=y +CONFIG_SPI_RB4XX=y +CONFIG_SPI_RB4XX_CPLD=y CONFIG_YAFFS_9BYTE_TAGS=y CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED=y CONFIG_YAFFS_AUTO_YAFFS2=y diff --git a/target/linux/ar71xx/patches-2.6.32/150-drivers-link-spi-before-mtd.patch b/target/linux/ar71xx/patches-2.6.32/150-drivers-link-spi-before-mtd.patch new file mode 100644 index 0000000000..85a803581f --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.32/150-drivers-link-spi-before-mtd.patch @@ -0,0 +1,12 @@ +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -44,8 +44,8 @@ obj-y += macintosh/ + obj-$(CONFIG_IDE) += ide/ + obj-$(CONFIG_SCSI) += scsi/ + obj-$(CONFIG_ATA) += ata/ +-obj-$(CONFIG_MTD) += mtd/ + obj-$(CONFIG_SPI) += spi/ ++obj-$(CONFIG_MTD) += mtd/ + obj-y += net/ + obj-$(CONFIG_ATM) += atm/ + obj-$(CONFIG_FUSION) += message/ diff --git a/target/linux/ar71xx/patches-2.6.32/151-spi-add-various-flags.patch b/target/linux/ar71xx/patches-2.6.32/151-spi-add-various-flags.patch new file mode 100644 index 0000000000..bb9a7d6bd4 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.32/151-spi-add-various-flags.patch @@ -0,0 +1,19 @@ +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -434,6 +434,8 @@ struct spi_transfer { + dma_addr_t rx_dma; + + unsigned cs_change:1; ++ unsigned verify:1; ++ unsigned fast_write:1; + u8 bits_per_word; + u16 delay_usecs; + u32 speed_hz; +@@ -475,6 +477,7 @@ struct spi_message { + struct spi_device *spi; + + unsigned is_dma_mapped:1; ++ unsigned fast_read:1; + + /* REVISIT: we might want a flag affecting the behavior of the + * last transfer ... allowing things like "read 16 bit length L" diff --git a/target/linux/ar71xx/patches-2.6.32/152-rb4xx-spi-driver.patch b/target/linux/ar71xx/patches-2.6.32/152-rb4xx-spi-driver.patch new file mode 100644 index 0000000000..e7a2124b83 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.32/152-rb4xx-spi-driver.patch @@ -0,0 +1,25 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -214,6 +214,12 @@ config SPI_PXA2XX + The driver can be configured to use any SSP port and additional + documentation can be found a Documentation/spi/pxa2xx. + ++config SPI_RB4XX ++ tristate "Mikrotik RB4XX SPI master" ++ depends on SPI_MASTER && AR71XX_MACH_RB4XX ++ help ++ SPI controller driver for the Mikrotik RB4xx series boards. ++ + config SPI_S3C24XX + tristate "Samsung S3C24XX series SPI" + depends on ARCH_S3C2410 && EXPERIMENTAL +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -33,6 +33,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s + obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o + obj-$(CONFIG_SPI_TXX9) += spi_txx9.o + obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o ++obj-$(CONFIG_SPI_RB4XX) += rb4xx_spi.o + obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o + obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o + # ... add above this line ... diff --git a/target/linux/ar71xx/patches-2.6.32/153-spi-rb4xx-cpld-driver.patch b/target/linux/ar71xx/patches-2.6.32/153-spi-rb4xx-cpld-driver.patch new file mode 100644 index 0000000000..494269f118 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.32/153-spi-rb4xx-cpld-driver.patch @@ -0,0 +1,26 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -294,6 +294,13 @@ config SPI_TLE62X0 + sysfs interface, with each line presented as a kind of GPIO + exposing both switch control and diagnostic feedback. + ++config SPI_RB4XX_CPLD ++ tristate "MikroTik RB4XX CPLD driver" ++ depends on AR71XX_MACH_RB4XX ++ help ++ SPI driver for the Xilinx CPLD chip present on the ++ MikroTik RB4xx boards. ++ + # + # Add new SPI protocol masters in alphabetical order above this line + # +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -39,6 +39,7 @@ obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp. + # ... add above this line ... + + # SPI protocol drivers (device/link on bus) ++obj-$(CONFIG_SPI_RB4XX_CPLD) += spi_rb4xx_cpld.o + obj-$(CONFIG_SPI_SPIDEV) += spidev.o + obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o + # ... add above this line ... diff --git a/target/linux/ar71xx/patches-2.6.32/202-spi_vsc7385_driver.patch b/target/linux/ar71xx/patches-2.6.32/202-spi_vsc7385_driver.patch index a4b4595b04..1cc64530a7 100644 --- a/target/linux/ar71xx/patches-2.6.32/202-spi_vsc7385_driver.patch +++ b/target/linux/ar71xx/patches-2.6.32/202-spi_vsc7385_driver.patch @@ -1,8 +1,8 @@ --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig -@@ -296,6 +296,11 @@ config SPI_TLE62X0 - sysfs interface, with each line presented as a kind of GPIO - exposing both switch control and diagnostic feedback. +@@ -309,6 +309,11 @@ config SPI_RB4XX_CPLD + SPI driver for the Xilinx CPLD chip present on the + MikroTik RB4xx boards. +config SPI_VSC7385 + tristate "Vitesse VSC7385 ethernet switch driver" @@ -14,9 +14,9 @@ # --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -40,6 +40,7 @@ obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp. - +@@ -42,6 +42,7 @@ obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp. # SPI protocol drivers (device/link on bus) + obj-$(CONFIG_SPI_RB4XX_CPLD) += spi_rb4xx_cpld.o obj-$(CONFIG_SPI_SPIDEV) += spidev.o +obj-$(CONFIG_SPI_VSC7385) += spi_vsc7385.o obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o diff --git a/target/linux/ar71xx/patches-2.6.33/150-drivers-link-spi-before-mtd.patch b/target/linux/ar71xx/patches-2.6.33/150-drivers-link-spi-before-mtd.patch new file mode 100644 index 0000000000..85a803581f --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.33/150-drivers-link-spi-before-mtd.patch @@ -0,0 +1,12 @@ +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -44,8 +44,8 @@ obj-y += macintosh/ + obj-$(CONFIG_IDE) += ide/ + obj-$(CONFIG_SCSI) += scsi/ + obj-$(CONFIG_ATA) += ata/ +-obj-$(CONFIG_MTD) += mtd/ + obj-$(CONFIG_SPI) += spi/ ++obj-$(CONFIG_MTD) += mtd/ + obj-y += net/ + obj-$(CONFIG_ATM) += atm/ + obj-$(CONFIG_FUSION) += message/ diff --git a/target/linux/ar71xx/patches-2.6.33/151-spi-add-various-flags.patch b/target/linux/ar71xx/patches-2.6.33/151-spi-add-various-flags.patch new file mode 100644 index 0000000000..bb9a7d6bd4 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.33/151-spi-add-various-flags.patch @@ -0,0 +1,19 @@ +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -434,6 +434,8 @@ struct spi_transfer { + dma_addr_t rx_dma; + + unsigned cs_change:1; ++ unsigned verify:1; ++ unsigned fast_write:1; + u8 bits_per_word; + u16 delay_usecs; + u32 speed_hz; +@@ -475,6 +477,7 @@ struct spi_message { + struct spi_device *spi; + + unsigned is_dma_mapped:1; ++ unsigned fast_read:1; + + /* REVISIT: we might want a flag affecting the behavior of the + * last transfer ... allowing things like "read 16 bit length L" diff --git a/target/linux/ar71xx/patches-2.6.33/152-rb4xx-spi-driver.patch b/target/linux/ar71xx/patches-2.6.33/152-rb4xx-spi-driver.patch new file mode 100644 index 0000000000..0eaaace1e2 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.33/152-rb4xx-spi-driver.patch @@ -0,0 +1,25 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -225,6 +225,12 @@ config SPI_PXA2XX + The driver can be configured to use any SSP port and additional + documentation can be found a Documentation/spi/pxa2xx. + ++config SPI_RB4XX ++ tristate "Mikrotik RB4XX SPI master" ++ depends on SPI_MASTER && AR71XX_MACH_RB4XX ++ help ++ SPI controller driver for the Mikrotik RB4xx series boards. ++ + config SPI_S3C24XX + tristate "Samsung S3C24XX series SPI" + depends on ARCH_S3C2410 && EXPERIMENTAL +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -44,6 +44,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci. + obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o + obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o + obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o ++obj-$(CONFIG_SPI_RB4XX) += rb4xx_spi.o + + # special build for s3c24xx spi driver with fiq support + spi_s3c24xx_hw-y := spi_s3c24xx.o diff --git a/target/linux/ar71xx/patches-2.6.33/153-spi-rb4xx-cpld-driver.patch b/target/linux/ar71xx/patches-2.6.33/153-spi-rb4xx-cpld-driver.patch new file mode 100644 index 0000000000..1044eb6278 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.33/153-spi-rb4xx-cpld-driver.patch @@ -0,0 +1,26 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -363,6 +363,13 @@ config SPI_TLE62X0 + sysfs interface, with each line presented as a kind of GPIO + exposing both switch control and diagnostic feedback. + ++config SPI_RB4XX_CPLD ++ tristate "MikroTik RB4XX CPLD driver" ++ depends on AR71XX_MACH_RB4XX ++ help ++ SPI driver for the Xilinx CPLD chip present on the ++ MikroTik RB4xx boards. ++ + # + # Add new SPI protocol masters in alphabetical order above this line + # +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -53,6 +53,7 @@ spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) + # ... add above this line ... + + # SPI protocol drivers (device/link on bus) ++obj-$(CONFIG_SPI_RB4XX_CPLD) += spi_rb4xx_cpld.o + obj-$(CONFIG_SPI_SPIDEV) += spidev.o + obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o + # ... add above this line ... diff --git a/target/linux/ar71xx/patches-2.6.33/202-spi_vsc7385_driver.patch b/target/linux/ar71xx/patches-2.6.33/202-spi_vsc7385_driver.patch index 487785a947..9885b8b3f1 100644 --- a/target/linux/ar71xx/patches-2.6.33/202-spi_vsc7385_driver.patch +++ b/target/linux/ar71xx/patches-2.6.33/202-spi_vsc7385_driver.patch @@ -1,8 +1,8 @@ --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig -@@ -365,6 +365,11 @@ config SPI_TLE62X0 - sysfs interface, with each line presented as a kind of GPIO - exposing both switch control and diagnostic feedback. +@@ -378,6 +378,11 @@ config SPI_RB4XX_CPLD + SPI driver for the Xilinx CPLD chip present on the + MikroTik RB4xx boards. +config SPI_VSC7385 + tristate "Vitesse VSC7385 ethernet switch driver" @@ -14,9 +14,9 @@ # --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -54,6 +54,7 @@ spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) - +@@ -56,6 +56,7 @@ spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) # SPI protocol drivers (device/link on bus) + obj-$(CONFIG_SPI_RB4XX_CPLD) += spi_rb4xx_cpld.o obj-$(CONFIG_SPI_SPIDEV) += spidev.o +obj-$(CONFIG_SPI_VSC7385) += spi_vsc7385.o obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o diff --git a/target/linux/ar71xx/patches-2.6.34/150-drivers-link-spi-before-mtd.patch b/target/linux/ar71xx/patches-2.6.34/150-drivers-link-spi-before-mtd.patch new file mode 100644 index 0000000000..1d9bf9e3b5 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.34/150-drivers-link-spi-before-mtd.patch @@ -0,0 +1,12 @@ +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -46,8 +46,8 @@ obj-y += macintosh/ + obj-$(CONFIG_IDE) += ide/ + obj-$(CONFIG_SCSI) += scsi/ + obj-$(CONFIG_ATA) += ata/ +-obj-$(CONFIG_MTD) += mtd/ + obj-$(CONFIG_SPI) += spi/ ++obj-$(CONFIG_MTD) += mtd/ + obj-y += net/ + obj-$(CONFIG_ATM) += atm/ + obj-$(CONFIG_FUSION) += message/ diff --git a/target/linux/ar71xx/patches-2.6.34/151-spi-add-various-flags.patch b/target/linux/ar71xx/patches-2.6.34/151-spi-add-various-flags.patch new file mode 100644 index 0000000000..b3ce1b0797 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.34/151-spi-add-various-flags.patch @@ -0,0 +1,19 @@ +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -435,6 +435,8 @@ struct spi_transfer { + dma_addr_t rx_dma; + + unsigned cs_change:1; ++ unsigned verify:1; ++ unsigned fast_write:1; + u8 bits_per_word; + u16 delay_usecs; + u32 speed_hz; +@@ -476,6 +478,7 @@ struct spi_message { + struct spi_device *spi; + + unsigned is_dma_mapped:1; ++ unsigned fast_read:1; + + /* REVISIT: we might want a flag affecting the behavior of the + * last transfer ... allowing things like "read 16 bit length L" diff --git a/target/linux/ar71xx/patches-2.6.34/152-rb4xx-spi-driver.patch b/target/linux/ar71xx/patches-2.6.34/152-rb4xx-spi-driver.patch new file mode 100644 index 0000000000..22b803ec67 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.34/152-rb4xx-spi-driver.patch @@ -0,0 +1,25 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -242,6 +242,12 @@ config SPI_PXA2XX + The driver can be configured to use any SSP port and additional + documentation can be found a Documentation/spi/pxa2xx. + ++config SPI_RB4XX ++ tristate "Mikrotik RB4XX SPI master" ++ depends on SPI_MASTER && AR71XX_MACH_RB4XX ++ help ++ SPI controller driver for the Mikrotik RB4xx series boards. ++ + config SPI_S3C24XX + tristate "Samsung S3C24XX series SPI" + depends on ARCH_S3C2410 && EXPERIMENTAL +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -47,6 +47,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci. + obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o + obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o + obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o ++obj-$(CONFIG_SPI_RB4XX) += rb4xx_spi.o + + # special build for s3c24xx spi driver with fiq support + spi_s3c24xx_hw-y := spi_s3c24xx.o diff --git a/target/linux/ar71xx/patches-2.6.34/153-spi-rb4xx-cpld-driver.patch b/target/linux/ar71xx/patches-2.6.34/153-spi-rb4xx-cpld-driver.patch new file mode 100644 index 0000000000..7ef419d085 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.34/153-spi-rb4xx-cpld-driver.patch @@ -0,0 +1,26 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -384,6 +384,13 @@ config SPI_TLE62X0 + sysfs interface, with each line presented as a kind of GPIO + exposing both switch control and diagnostic feedback. + ++config SPI_RB4XX_CPLD ++ tristate "MikroTik RB4XX CPLD driver" ++ depends on AR71XX_MACH_RB4XX ++ help ++ SPI driver for the Xilinx CPLD chip present on the ++ MikroTik RB4xx boards. ++ + # + # Add new SPI protocol masters in alphabetical order above this line + # +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -56,6 +56,7 @@ spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) + # ... add above this line ... + + # SPI protocol drivers (device/link on bus) ++obj-$(CONFIG_SPI_RB4XX_CPLD) += spi_rb4xx_cpld.o + obj-$(CONFIG_SPI_SPIDEV) += spidev.o + obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o + # ... add above this line ... diff --git a/target/linux/ar71xx/patches-2.6.34/202-spi_vsc7385_driver.patch b/target/linux/ar71xx/patches-2.6.34/202-spi_vsc7385_driver.patch index b0bb15fcef..f01e0a2de4 100644 --- a/target/linux/ar71xx/patches-2.6.34/202-spi_vsc7385_driver.patch +++ b/target/linux/ar71xx/patches-2.6.34/202-spi_vsc7385_driver.patch @@ -1,8 +1,8 @@ --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig -@@ -386,6 +386,11 @@ config SPI_TLE62X0 - sysfs interface, with each line presented as a kind of GPIO - exposing both switch control and diagnostic feedback. +@@ -399,6 +399,11 @@ config SPI_RB4XX_CPLD + SPI driver for the Xilinx CPLD chip present on the + MikroTik RB4xx boards. +config SPI_VSC7385 + tristate "Vitesse VSC7385 ethernet switch driver" @@ -14,9 +14,9 @@ # --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -57,6 +57,7 @@ spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) - +@@ -59,6 +59,7 @@ spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) # SPI protocol drivers (device/link on bus) + obj-$(CONFIG_SPI_RB4XX_CPLD) += spi_rb4xx_cpld.o obj-$(CONFIG_SPI_SPIDEV) += spidev.o +obj-$(CONFIG_SPI_VSC7385) += spi_vsc7385.o obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o diff --git a/target/linux/ar71xx/patches-2.6.35/150-drivers-link-spi-before-mtd.patch b/target/linux/ar71xx/patches-2.6.35/150-drivers-link-spi-before-mtd.patch new file mode 100644 index 0000000000..eb922dd431 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.35/150-drivers-link-spi-before-mtd.patch @@ -0,0 +1,12 @@ +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -45,8 +45,8 @@ obj-y += macintosh/ + obj-$(CONFIG_IDE) += ide/ + obj-$(CONFIG_SCSI) += scsi/ + obj-$(CONFIG_ATA) += ata/ +-obj-$(CONFIG_MTD) += mtd/ + obj-$(CONFIG_SPI) += spi/ ++obj-$(CONFIG_MTD) += mtd/ + obj-y += net/ + obj-$(CONFIG_ATM) += atm/ + obj-$(CONFIG_FUSION) += message/ diff --git a/target/linux/ar71xx/patches-2.6.35/151-spi-add-various-flags.patch b/target/linux/ar71xx/patches-2.6.35/151-spi-add-various-flags.patch new file mode 100644 index 0000000000..b3ce1b0797 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.35/151-spi-add-various-flags.patch @@ -0,0 +1,19 @@ +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -435,6 +435,8 @@ struct spi_transfer { + dma_addr_t rx_dma; + + unsigned cs_change:1; ++ unsigned verify:1; ++ unsigned fast_write:1; + u8 bits_per_word; + u16 delay_usecs; + u32 speed_hz; +@@ -476,6 +478,7 @@ struct spi_message { + struct spi_device *spi; + + unsigned is_dma_mapped:1; ++ unsigned fast_read:1; + + /* REVISIT: we might want a flag affecting the behavior of the + * last transfer ... allowing things like "read 16 bit length L" diff --git a/target/linux/ar71xx/patches-2.6.35/152-rb4xx-spi-driver.patch b/target/linux/ar71xx/patches-2.6.35/152-rb4xx-spi-driver.patch new file mode 100644 index 0000000000..1a59b44387 --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.35/152-rb4xx-spi-driver.patch @@ -0,0 +1,25 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -259,6 +259,12 @@ config SPI_PXA2XX + The driver can be configured to use any SSP port and additional + documentation can be found a Documentation/spi/pxa2xx. + ++config SPI_RB4XX ++ tristate "Mikrotik RB4XX SPI master" ++ depends on SPI_MASTER && AR71XX_MACH_RB4XX ++ help ++ SPI controller driver for the Mikrotik RB4xx series boards. ++ + config SPI_S3C24XX + tristate "Samsung S3C24XX series SPI" + depends on ARCH_S3C2410 && EXPERIMENTAL +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -49,6 +49,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci. + obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o + obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o + obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o ++obj-$(CONFIG_SPI_RB4XX) += rb4xx_spi.o + + # special build for s3c24xx spi driver with fiq support + spi_s3c24xx_hw-y := spi_s3c24xx.o diff --git a/target/linux/ar71xx/patches-2.6.35/153-spi-rb4xx-cpld-driver.patch b/target/linux/ar71xx/patches-2.6.35/153-spi-rb4xx-cpld-driver.patch new file mode 100644 index 0000000000..435effdfec --- /dev/null +++ b/target/linux/ar71xx/patches-2.6.35/153-spi-rb4xx-cpld-driver.patch @@ -0,0 +1,26 @@ +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -401,6 +401,13 @@ config SPI_TLE62X0 + sysfs interface, with each line presented as a kind of GPIO + exposing both switch control and diagnostic feedback. + ++config SPI_RB4XX_CPLD ++ tristate "MikroTik RB4XX CPLD driver" ++ depends on AR71XX_MACH_RB4XX ++ help ++ SPI driver for the Xilinx CPLD chip present on the ++ MikroTik RB4xx boards. ++ + # + # Add new SPI protocol masters in alphabetical order above this line + # +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -58,6 +58,7 @@ spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) + # ... add above this line ... + + # SPI protocol drivers (device/link on bus) ++obj-$(CONFIG_SPI_RB4XX_CPLD) += spi_rb4xx_cpld.o + obj-$(CONFIG_SPI_SPIDEV) += spidev.o + obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o + # ... add above this line ... diff --git a/target/linux/ar71xx/patches-2.6.35/202-spi_vsc7385_driver.patch b/target/linux/ar71xx/patches-2.6.35/202-spi_vsc7385_driver.patch index 03db33d2b1..46fe39331a 100644 --- a/target/linux/ar71xx/patches-2.6.35/202-spi_vsc7385_driver.patch +++ b/target/linux/ar71xx/patches-2.6.35/202-spi_vsc7385_driver.patch @@ -1,8 +1,8 @@ --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig -@@ -403,6 +403,11 @@ config SPI_TLE62X0 - sysfs interface, with each line presented as a kind of GPIO - exposing both switch control and diagnostic feedback. +@@ -416,6 +416,11 @@ config SPI_RB4XX_CPLD + SPI driver for the Xilinx CPLD chip present on the + MikroTik RB4xx boards. +config SPI_VSC7385 + tristate "Vitesse VSC7385 ethernet switch driver" @@ -14,9 +14,9 @@ # --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -59,6 +59,7 @@ spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) - +@@ -61,6 +61,7 @@ spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) # SPI protocol drivers (device/link on bus) + obj-$(CONFIG_SPI_RB4XX_CPLD) += spi_rb4xx_cpld.o obj-$(CONFIG_SPI_SPIDEV) += spidev.o +obj-$(CONFIG_SPI_VSC7385) += spi_vsc7385.o obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o diff --git a/target/linux/ar71xx/patches-2.6.35/400-2.6.35-fix-nand_scan_ident-options.patch b/target/linux/ar71xx/patches-2.6.35/400-2.6.35-fix-nand_scan_ident-options.patch index fcd2521a67..dfaad1e0e7 100644 --- a/target/linux/ar71xx/patches-2.6.35/400-2.6.35-fix-nand_scan_ident-options.patch +++ b/target/linux/ar71xx/patches-2.6.35/400-2.6.35-fix-nand_scan_ident-options.patch @@ -1,6 +1,6 @@ --- a/drivers/mtd/nand/rb4xx_nand.c +++ b/drivers/mtd/nand/rb4xx_nand.c -@@ -431,7 +431,7 @@ static int __init rb4xx_nand_probe(struc +@@ -218,7 +218,7 @@ static int __init rb4xx_nand_probe(struc platform_set_drvdata(pdev, info);