X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/53463696e258efe91918cfd456764b9c374e7e78..897a534e8b5fe7ef1d6b8eaee3b57eb7d637e1de:/target/linux/brcm63xx/patches-2.6.33/240-spi.patch diff --git a/target/linux/brcm63xx/patches-2.6.33/240-spi.patch b/target/linux/brcm63xx/patches-2.6.33/240-spi.patch deleted file mode 100644 index 86fcc7d76..000000000 --- a/target/linux/brcm63xx/patches-2.6.33/240-spi.patch +++ /dev/null @@ -1,948 +0,0 @@ ---- a/arch/mips/bcm63xx/cpu.c -+++ b/arch/mips/bcm63xx/cpu.c -@@ -55,6 +55,7 @@ static const unsigned long bcm96338_regs - - static const int bcm96338_irqs[] = { - [IRQ_TIMER] = BCM_6338_TIMER_IRQ, -+ [IRQ_SPI] = BCM_6338_SPI_IRQ, - [IRQ_UART0] = BCM_6338_UART0_IRQ, - [IRQ_DSL] = BCM_6338_DSL_IRQ, - [IRQ_ENET0] = BCM_6338_ENET0_IRQ, -@@ -127,6 +128,7 @@ static const unsigned long bcm96348_regs - - static const int bcm96348_irqs[] = { - [IRQ_TIMER] = BCM_6348_TIMER_IRQ, -+ [IRQ_SPI] = BCM_6348_SPI_IRQ, - [IRQ_UART0] = BCM_6348_UART0_IRQ, - [IRQ_DSL] = BCM_6348_DSL_IRQ, - [IRQ_ENET0] = BCM_6348_ENET0_IRQ, -@@ -169,6 +171,7 @@ static const unsigned long bcm96358_regs - - static const int bcm96358_irqs[] = { - [IRQ_TIMER] = BCM_6358_TIMER_IRQ, -+ [IRQ_SPI] = BCM_6358_SPI_IRQ, - [IRQ_UART0] = BCM_6358_UART0_IRQ, - [IRQ_DSL] = BCM_6358_DSL_IRQ, - [IRQ_ENET0] = BCM_6358_ENET0_IRQ, ---- /dev/null -+++ b/arch/mips/bcm63xx/dev-spi.c -@@ -0,0 +1,60 @@ -+/* -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file "COPYING" in the main directory of this archive -+ * for more details. -+ * -+ * Copyright (C) 2009 Florian Fainelli -+ */ -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+static struct resource spi_resources[] = { -+ { -+ .start = -1, /* filled at runtime */ -+ .end = -1, /* filled at runtime */ -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = -1, /* filled at runtime */ -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+static struct bcm63xx_spi_pdata spi_pdata = { -+ .bus_num = 0, -+ .num_chipselect = 4, -+ .speed_hz = 50000000, /* Fclk */ -+}; -+ -+static struct platform_device bcm63xx_spi_device = { -+ .name = "bcm63xx-spi", -+ .id = 0, -+ .num_resources = ARRAY_SIZE(spi_resources), -+ .resource = spi_resources, -+ .dev = { -+ .platform_data = &spi_pdata, -+ }, -+}; -+ -+int __init bcm63xx_spi_register(void) -+{ -+ spi_resources[0].start = bcm63xx_regset_address(RSET_SPI); -+ spi_resources[0].end = spi_resources[0].start; -+ spi_resources[0].end += RSET_SPI_SIZE - 1; -+ spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI); -+ -+ /* Fill in platform data */ -+ if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) -+ spi_pdata.fifo_size = SPI_BCM_6338_SPI_MSG_DATA_SIZE; -+ -+ if (BCMCPU_IS_6358()) -+ spi_pdata.fifo_size = SPI_BCM_6358_SPI_MSG_DATA_SIZE; -+ -+ return platform_device_register(&bcm63xx_spi_device); -+} ---- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h -+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h -@@ -108,6 +108,7 @@ enum bcm63xx_regs_set { - #define RSET_WDT_SIZE 12 - #define RSET_ENET_SIZE 2048 - #define RSET_ENETDMA_SIZE 2048 -+#define RSET_SPI_SIZE 256 - #define RSET_UART_SIZE 24 - #define RSET_UDC_SIZE 256 - #define RSET_OHCI_SIZE 256 -@@ -428,6 +429,7 @@ static inline unsigned long bcm63xx_regs - */ - enum bcm63xx_irq { - IRQ_TIMER = 0, -+ IRQ_SPI, - IRQ_UART0, - IRQ_DSL, - IRQ_UDC0, -@@ -493,6 +495,7 @@ enum bcm63xx_irq { - * 6348 irqs - */ - #define BCM_6348_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) -+#define BCM_6348_SPI_IRQ (IRQ_INTERNAL_BASE + 1) - #define BCM_6348_UART0_IRQ (IRQ_INTERNAL_BASE + 2) - #define BCM_6348_DSL_IRQ (IRQ_INTERNAL_BASE + 4) - #define BCM_6348_UDC0_IRQ (IRQ_INTERNAL_BASE + 6) -@@ -517,6 +520,7 @@ enum bcm63xx_irq { - * 6358 irqs - */ - #define BCM_6358_TIMER_IRQ (IRQ_INTERNAL_BASE + 0) -+#define BCM_6358_SPI_IRQ (IRQ_INTERNAL_BASE + 1) - #define BCM_6358_UART0_IRQ (IRQ_INTERNAL_BASE + 2) - #define BCM_6358_OHCI0_IRQ (IRQ_INTERNAL_BASE + 5) - #define BCM_6358_ENET1_IRQ (IRQ_INTERNAL_BASE + 6) ---- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h -+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h -@@ -769,5 +769,117 @@ - #define DMIPSPLLCFG_N2_SHIFT 29 - #define DMIPSPLLCFG_N2_MASK (0x7 << DMIPSPLLCFG_N2_SHIFT) - -+/************************************************************************* -+ * _REG relative to RSET_SPI -+ *************************************************************************/ -+ -+/* BCM 6338 SPI core */ -+#define SPI_BCM_6338_SPI_CMD 0x00 /* 16-bits register */ -+#define SPI_BCM_6338_SPI_INT_STATUS 0x02 -+#define SPI_BCM_6338_SPI_MASK_INT_ST 0x03 -+#define SPI_BCM_6338_SPI_INT_MASK 0x04 -+#define SPI_BCM_6338_SPI_ST 0x05 -+#define SPI_BCM_6338_SPI_CLK_CFG 0x06 -+#define SPI_BCM_6338_SPI_FILL_BYTE 0x07 -+#define SPI_BCM_6338_SPI_MSG_TAIL 0x09 -+#define SPI_BCM_6338_SPI_RX_TAIL 0x0b -+#define SPI_BCM_6338_SPI_MSG_CTL 0x40 -+#define SPI_BCM_6338_SPI_MSG_DATA 0x41 -+#define SPI_BCM_6338_SPI_MSG_DATA_SIZE 0x3f -+#define SPI_BCM_6338_SPI_RX_DATA 0x80 -+#define SPI_BCM_6338_SPI_RX_DATA_SIZE 0x3f -+ -+/* BCM 6348 SPI core */ -+#define SPI_BCM_6348_SPI_MASK_INT_ST 0x00 -+#define SPI_BCM_6348_SPI_INT_STATUS 0x01 -+#define SPI_BCM_6348_SPI_CMD 0x02 /* 16-bits register */ -+#define SPI_BCM_6348_SPI_FILL_BYTE 0x04 -+#define SPI_BCM_6348_SPI_CLK_CFG 0x05 -+#define SPI_BCM_6348_SPI_ST 0x06 -+#define SPI_BCM_6348_SPI_INT_MASK 0x07 -+#define SPI_BCM_6348_SPI_RX_TAIL 0x08 -+#define SPI_BCM_6348_SPI_MSG_TAIL 0x10 -+#define SPI_BCM_6348_SPI_MSG_DATA 0x40 -+#define SPI_BCM_6348_SPI_MSG_CTL 0x42 -+#define SPI_BCM_6348_SPI_MSG_DATA_SIZE 0x3f -+#define SPI_BCM_6348_SPI_RX_DATA 0x80 -+#define SPI_BCM_6348_SPI_RX_DATA_SIZE 0x3f -+ -+/* BCM 6358 SPI core */ -+#define SPI_BCM_6358_MSG_CTL 0x00 /* 16-bits register */ -+ -+#define SPI_BCM_6358_SPI_MSG_DATA 0x02 -+#define SPI_BCM_6358_SPI_MSG_DATA_SIZE 0x21e -+ -+#define SPI_BCM_6358_SPI_RX_DATA 0x400 -+#define SPI_BCM_6358_SPI_RX_DATA_SIZE 0x220 -+ -+#define SPI_BCM_6358_SPI_CMD 0x700 /* 16-bits register */ -+ -+#define SPI_BCM_6358_SPI_INT_STATUS 0x702 -+#define SPI_BCM_6358_SPI_MASK_INT_ST 0x703 -+ -+#define SPI_BCM_6358_SPI_INT_MASK 0x704 -+ -+#define SPI_BCM_6358_SPI_STATUS 0x705 -+ -+#define SPI_BCM_6358_SPI_CLK_CFG 0x706 -+ -+#define SPI_BCM_6358_SPI_FILL_BYTE 0x707 -+#define SPI_BCM_6358_SPI_MSG_TAIL 0x709 -+#define SPI_BCM_6358_SPI_RX_TAIL 0x70B -+ -+/* Shared SPI definitions */ -+ -+/* Message configuration */ -+#define SPI_FD_RW 0x00 -+#define SPI_HD_W 0x01 -+#define SPI_HD_R 0x02 -+#define SPI_BYTE_CNT_SHIFT 0 -+#define SPI_MSG_TYPE_SHIFT 14 -+ -+/* Command */ -+#define SPI_CMD_NOOP 0x01 -+#define SPI_CMD_SOFT_RESET 0x02 -+#define SPI_CMD_HARD_RESET 0x04 -+#define SPI_CMD_START_IMMEDIATE 0x08 -+#define SPI_CMD_COMMAND_SHIFT 0 -+#define SPI_CMD_COMMAND_MASK 0x000f -+#define SPI_CMD_DEVICE_ID_SHIFT 4 -+#define SPI_CMD_PREPEND_BYTE_CNT_SHIFT 8 -+#define SPI_CMD_ONE_BYTE_SHIFT 11 -+#define SPI_CMD_ONE_WIRE_SHIFT 12 -+#define SPI_DEV_ID_0 0 -+#define SPI_DEV_ID_1 1 -+#define SPI_DEV_ID_2 2 -+#define SPI_DEV_ID_3 3 -+ -+/* Interrupt mask */ -+#define SPI_INTR_CMD_DONE 0x01 -+#define SPI_INTR_RX_OVERFLOW 0x02 -+#define SPI_INTR_TX_UNDERFLOW 0x04 -+#define SPI_INTR_TX_OVERFLOW 0x08 -+#define SPI_INTR_RX_UNDERFLOW 0x10 -+#define SPI_INTR_CLEAR_ALL 0x1f -+ -+/* Status */ -+#define SPI_RX_EMPTY 0x02 -+#define SPI_CMD_BUSY 0x04 -+#define SPI_SERIAL_BUSY 0x08 -+ -+/* Clock configuration */ -+#define SPI_CLK_20MHZ 0x00 -+#define SPI_CLK_0_391MHZ 0x01 -+#define SPI_CLK_0_781MHZ 0x02 /* default */ -+#define SPI_CLK_1_563MHZ 0x03 -+#define SPI_CLK_3_125MHZ 0x04 -+#define SPI_CLK_6_250MHZ 0x05 -+#define SPI_CLK_12_50MHZ 0x06 -+#define SPI_CLK_25MHZ 0x07 -+#define SPI_CLK_MASK 0x07 -+#define SPI_SSOFFTIME_MASK 0x38 -+#define SPI_SSOFFTIME_SHIFT 3 -+#define SPI_BYTE_SWAP 0x80 -+ - #endif /* BCM63XX_REGS_H_ */ - ---- /dev/null -+++ b/drivers/spi/bcm63xx_spi.c -@@ -0,0 +1,628 @@ -+/* -+ * Broadcom BCM63xx SPI controller support -+ * -+ * Copyright (C) 2009 Florian Fainelli -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the -+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#define PFX KBUILD_MODNAME -+#define DRV_VER "0.1.2" -+ -+enum bcm63xx_regs_spi { -+ SPI_CMD, -+ SPI_INT_STATUS, -+ SPI_INT_MASK_ST, -+ SPI_INT_MASK, -+ SPI_ST, -+ SPI_CLK_CFG, -+ SPI_FILL_BYTE, -+ SPI_MSG_TAIL, -+ SPI_RX_TAIL, -+ SPI_MSG_CTL, -+ SPI_MSG_DATA, -+ SPI_RX_DATA, -+}; -+ -+/* -+ * register offsets -+ */ -+static const unsigned long bcm96338_regs_spi[] = { -+ [SPI_CMD] = SPI_BCM_6338_SPI_CMD, -+ [SPI_INT_STATUS] = SPI_BCM_6338_SPI_INT_STATUS, -+ [SPI_INT_MASK_ST] = SPI_BCM_6338_SPI_MASK_INT_ST, -+ [SPI_INT_MASK] = SPI_BCM_6338_SPI_INT_MASK, -+ [SPI_ST] = SPI_BCM_6338_SPI_ST, -+ [SPI_CLK_CFG] = SPI_BCM_6338_SPI_CLK_CFG, -+ [SPI_FILL_BYTE] = SPI_BCM_6338_SPI_FILL_BYTE, -+ [SPI_MSG_TAIL] = SPI_BCM_6338_SPI_MSG_TAIL, -+ [SPI_RX_TAIL] = SPI_BCM_6338_SPI_RX_TAIL, -+ [SPI_MSG_CTL] = SPI_BCM_6338_SPI_MSG_CTL, -+ [SPI_MSG_DATA] = SPI_BCM_6338_SPI_MSG_DATA, -+ [SPI_RX_DATA] = SPI_BCM_6338_SPI_RX_DATA, -+}; -+ -+static const unsigned long bcm96348_regs_spi[] = { -+ [SPI_CMD] = SPI_BCM_6348_SPI_CMD, -+ [SPI_INT_STATUS] = SPI_BCM_6348_SPI_INT_STATUS, -+ [SPI_INT_MASK_ST] = SPI_BCM_6348_SPI_MASK_INT_ST, -+ [SPI_INT_MASK] = SPI_BCM_6348_SPI_INT_MASK, -+ [SPI_ST] = SPI_BCM_6348_SPI_ST, -+ [SPI_CLK_CFG] = SPI_BCM_6348_SPI_CLK_CFG, -+ [SPI_FILL_BYTE] = SPI_BCM_6348_SPI_FILL_BYTE, -+ [SPI_MSG_TAIL] = SPI_BCM_6348_SPI_MSG_TAIL, -+ [SPI_RX_TAIL] = SPI_BCM_6348_SPI_RX_TAIL, -+ [SPI_MSG_CTL] = SPI_BCM_6348_SPI_MSG_CTL, -+ [SPI_MSG_DATA] = SPI_BCM_6348_SPI_MSG_DATA, -+ [SPI_RX_DATA] = SPI_BCM_6348_SPI_RX_DATA, -+}; -+ -+static const unsigned long bcm96358_regs_spi[] = { -+ [SPI_CMD] = SPI_BCM_6358_SPI_CMD, -+ [SPI_INT_STATUS] = SPI_BCM_6358_SPI_INT_STATUS, -+ [SPI_INT_MASK_ST] = SPI_BCM_6358_SPI_MASK_INT_ST, -+ [SPI_INT_MASK] = SPI_BCM_6358_SPI_INT_MASK, -+ [SPI_ST] = SPI_BCM_6358_SPI_STATUS, -+ [SPI_CLK_CFG] = SPI_BCM_6358_SPI_CLK_CFG, -+ [SPI_FILL_BYTE] = SPI_BCM_6358_SPI_FILL_BYTE, -+ [SPI_MSG_TAIL] = SPI_BCM_6358_SPI_MSG_TAIL, -+ [SPI_RX_TAIL] = SPI_BCM_6358_SPI_RX_TAIL, -+ [SPI_MSG_CTL] = SPI_BCM_6358_MSG_CTL, -+ [SPI_MSG_DATA] = SPI_BCM_6358_SPI_MSG_DATA, -+ [SPI_RX_DATA] = SPI_BCM_6358_SPI_RX_DATA, -+}; -+ -+ -+#ifdef BCMCPU_RUNTIME_DETECT -+static const unsigned long *bcm63xx_regs_spi; -+ -+static __init void bcm63xx_spi_regs_init(void) -+{ -+ if (BCMCPU_IS_6338()) -+ bcm63xx_regs_spi = bcm96338_regs_spi; -+ if (BCMCPU_IS_6348()) -+ bcm63xx_regs_spi = bcm96348_regs_spi; -+ if (BCMCPU_IS_6358()) -+ bcm63xx_regs_spi = bcm96358_regs_spi; -+} -+#else -+static __init void bcm63xx_spi_regs_init(void) { } -+#endif -+ -+static inline unsigned long bcm63xx_spireg(enum bcm63xx_regs_spi reg) -+{ -+#ifdef BCMCPU_RUNTIME_DETECT -+ return bcm63xx_regs_spi[reg]; -+#else -+#ifdef CONFIG_BCM63XX_CPU_6338 -+switch (reg) { -+ case SPI_CMD: -+ return SPI_BCM_6338_SPI_CMD; -+ case SPI_INT_STATUS: -+ return SPI_BCM_6338_SPI_INT_STATUS; -+ case SPI_INT_MASK_ST: -+ return SPI_BCM_6338_SPI_MASK_INT_ST; -+ case SPI_INT_MASK: -+ return SPI_BCM_6338_SPI_INT_MASK; -+ case SPI_ST: -+ return SPI_BCM_6338_SPI_ST; -+ case SPI_CLK_CFG: -+ return SPI_BCM_6338_SPI_CLK_CFG; -+ case SPI_FILL_BYTE: -+ return SPI_BCM_6338_SPI_FILL_BYTE; -+ case SPI_MSG_TAIL: -+ return SPI_BCM_6338_SPI_MSG_TAIL; -+ case SPI_RX_TAIL: -+ return SPI_BCM_6338_SPI_RX_TAIL; -+ case SPI_MSG_CTL: -+ return SPI_BCM_6338_SPI_MSG_CTL; -+ case SPI_MSG_DATA: -+ return SPI_BCM_6338_SPI_MSG_DATA; -+ case SPI_RX_DATA: -+ return SPI_BCM_6338_SPI_RX_DATA; -+} -+#endif -+#ifdef CONFIG_BCM63XX_CPU_6348 -+switch (reg) { -+ case SPI_CMD: -+ return SPI_BCM_6348_SPI_CMD; -+ case SPI_INT_MASK_ST: -+ return SPI_BCM_6348_SPI_MASK_INT_ST; -+ case SPI_INT_MASK: -+ return SPI_BCM_6348_SPI_INT_MASK; -+ case SPI_INT_STATUS: -+ return SPI_BCM_6348_SPI_INT_STATUS; -+ case SPI_ST: -+ return SPI_BCM_6348_SPI_ST; -+ case SPI_CLK_CFG: -+ return SPI_BCM_6348_SPI_CLK_CFG; -+ case SPI_FILL_BYTE: -+ return SPI_BCM_6348_SPI_FILL_BYTE; -+ case SPI_MSG_TAIL: -+ return SPI_BCM_6348_SPI_MSG_TAIL; -+ case SPI_RX_TAIL: -+ return SPI_BCM_6348_SPI_RX_TAIL; -+ case SPI_MSG_CTL: -+ return SPI_BCM_6348_SPI_MSG_CTL; -+ case SPI_MSG_DATA: -+ return SPI_BCM_6348_SPI_MSG_DATA; -+ case SPI_RX_DATA: -+ return SPI_BCM_6348_SPI_RX_DATA; -+} -+#endif -+#ifdef CONFIG_BCM63XX_CPU_6358 -+switch (reg) { -+ case SPI_CMD: -+ return SPI_BCM_6358_SPI_CMD; -+ case SPI_INT_STATUS: -+ return SPI_BCM_6358_SPI_INT_STATUS; -+ case SPI_INT_MASK_ST: -+ return SPI_BCM_6358_SPI_MASK_INT_ST; -+ case SPI_INT_MASK: -+ return SPI_BCM_6358_SPI_INT_MASK; -+ case SPI_ST: -+ return SPI_BCM_6358_SPI_STATUS; -+ case SPI_CLK_CFG: -+ return SPI_BCM_6358_SPI_CLK_CFG; -+ case SPI_FILL_BYTE: -+ return SPI_BCM_6358_SPI_FILL_BYTE; -+ case SPI_MSG_TAIL: -+ return SPI_BCM_6358_SPI_MSG_TAIL; -+ case SPI_RX_TAIL: -+ return SPI_BCM_6358_SPI_RX_TAIL; -+ case SPI_MSG_CTL: -+ return SPI_BCM_6358_MSG_CTL; -+ case SPI_MSG_DATA: -+ return SPI_BCM_6358_SPI_MSG_DATA; -+ case SPI_RX_DATA: -+ return SPI_BCM_6358_SPI_RX_DATA; -+} -+#endif -+#endif -+ return 0; -+} -+ -+/* -+ * helpers for the SPI register sets -+ */ -+#define bcm_spi_readb(b,o) bcm_readb((b) + bcm63xx_spireg(o)) -+#define bcm_spi_readw(b,o) bcm_readw((b) + bcm63xx_spireg(o)) -+#define bcm_spi_writeb(v,b,o) bcm_writeb((v), (b) + bcm63xx_spireg(o)) -+#define bcm_spi_writew(v,b,o) bcm_writew((v), (b) + bcm63xx_spireg(o)) -+ -+struct bcm63xx_spi { -+ /* bitbang has to be first */ -+ struct spi_bitbang bitbang; -+ struct completion done; -+ -+ void __iomem *regs; -+ int irq; -+ -+ /* Platform data */ -+ u32 speed_hz; -+ unsigned fifo_size; -+ -+ /* Data buffers */ -+ const unsigned char *tx_ptr; -+ unsigned char *rx_ptr; -+ int remaining_bytes; -+ -+ struct clk *clk; -+ struct resource *ioarea; -+ struct platform_device *pdev; -+}; -+ -+static void bcm63xx_spi_chipselect(struct spi_device *spi, int is_on) -+{ -+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); -+ u16 val; -+ -+ val = bcm_spi_readw(bs->regs, SPI_CMD); -+ if (is_on == BITBANG_CS_INACTIVE) -+ val |= SPI_CMD_NOOP; -+ else if (is_on == BITBANG_CS_ACTIVE) -+ val |= (1 << spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT); -+ -+ bcm_spi_writew(val, bs->regs, SPI_CMD); -+} -+ -+static int bcm63xx_spi_setup_transfer(struct spi_device *spi, -+ struct spi_transfer *t) -+{ -+ u8 bits_per_word; -+ u8 clk_cfg; -+ u32 hz; -+ unsigned int div; -+ -+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); -+ -+ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; -+ hz = (t) ? t->speed_hz : spi->max_speed_hz; -+ if (bits_per_word != 8) { -+ dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", -+ __func__, bits_per_word); -+ return -EINVAL; -+ } -+ -+ if (spi->chip_select > spi->master->num_chipselect) { -+ dev_err(&spi->dev, "%s, unsupported slave %d\n", -+ __func__, spi->chip_select); -+ return -EINVAL; -+ } -+ -+ /* Check clock setting */ -+ div = (bs->speed_hz / hz); -+ switch (div) { -+ case 2: -+ clk_cfg = SPI_CLK_25MHZ; -+ break; -+ case 4: -+ clk_cfg = SPI_CLK_12_50MHZ; -+ break; -+ case 8: -+ clk_cfg = SPI_CLK_6_250MHZ; -+ break; -+ case 16: -+ clk_cfg = SPI_CLK_3_125MHZ; -+ break; -+ case 32: -+ clk_cfg = SPI_CLK_1_563MHZ; -+ break; -+ case 128: -+ clk_cfg = SPI_CLK_0_781MHZ; -+ break; -+ case 64: -+ default: -+ /* Set to slowest mode for compatibility */ -+ clk_cfg = SPI_CLK_0_781MHZ; -+ break; -+ } -+ -+ bcm_spi_writeb(clk_cfg, bs->regs, SPI_CLK_CFG); -+ dev_dbg(&spi->dev, "Setting clock register to %d (hz %d, cmd %02x)\n", -+ div, hz, clk_cfg); -+ -+ return 0; -+} -+ -+/* the spi->mode bits understood by this driver: */ -+#define MODEBITS (SPI_CPOL | SPI_CPHA) -+ -+static int bcm63xx_spi_setup(struct spi_device *spi) -+{ -+ struct spi_bitbang *bitbang; -+ struct bcm63xx_spi *bs; -+ int retval; -+ -+ bs = spi_master_get_devdata(spi->master); -+ bitbang = &bs->bitbang; -+ -+ if (!spi->bits_per_word) -+ spi->bits_per_word = 8; -+ -+ if (spi->mode & ~MODEBITS) { -+ dev_err(&spi->dev, "%s, unsupported mode bits %x\n", -+ __func__, spi->mode & ~MODEBITS); -+ return -EINVAL; -+ } -+ -+ retval = bcm63xx_spi_setup_transfer(spi, NULL); -+ if (retval < 0) { -+ dev_err(&spi->dev, "setup: unsupported mode bits %x\n", -+ spi->mode & ~MODEBITS); -+ return retval; -+ } -+ -+ dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n", -+ __func__, spi->mode & MODEBITS, spi->bits_per_word, 0); -+ -+ return 0; -+} -+ -+/* Fill the TX FIFO with as many bytes as possible */ -+static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs) -+{ -+ u8 tail; -+ -+ /* Fill the Tx FIFO with as many bytes as possible */ -+ tail = bcm_spi_readb(bs->regs, SPI_MSG_TAIL); -+ while ((tail < bs->fifo_size) && (bs->remaining_bytes > 0)) { -+ if (bs->tx_ptr) -+ bcm_spi_writeb(*bs->tx_ptr++, bs->regs, SPI_MSG_DATA); -+ else -+ bcm_spi_writeb(0, bs->regs, SPI_MSG_DATA); -+ bs->remaining_bytes--; -+ tail = bcm_spi_readb(bs->regs, SPI_MSG_TAIL); -+ } -+} -+ -+static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) -+{ -+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); -+ u8 msg_ctl; -+ u16 cmd; -+ -+ dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", -+ t->tx_buf, t->rx_buf, t->len); -+ -+ /* Transmitter is inhibited */ -+ bs->tx_ptr = t->tx_buf; -+ bs->rx_ptr = t->rx_buf; -+ bs->remaining_bytes = t->len; -+ init_completion(&bs->done); -+ -+ bcm63xx_spi_fill_tx_fifo(bs); -+ -+ /* Enable the command done interrupt which -+ * we use to determine completion of a command */ -+ bcm_spi_writeb(SPI_INTR_CMD_DONE, bs->regs, SPI_INT_MASK); -+ -+ /* Fill in the Message control register */ -+ msg_ctl = bcm_spi_readb(bs->regs, SPI_MSG_CTL); -+ msg_ctl |= (t->len << SPI_BYTE_CNT_SHIFT); -+ msg_ctl |= (SPI_FD_RW << SPI_MSG_TYPE_SHIFT); -+ bcm_spi_writeb(msg_ctl, bs->regs, SPI_MSG_CTL); -+ -+ /* Issue the transfer */ -+ cmd = bcm_spi_readw(bs->regs, SPI_CMD); -+ cmd |= SPI_CMD_START_IMMEDIATE; -+ cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT); -+ bcm_spi_writew(cmd, bs->regs, SPI_CMD); -+ -+ wait_for_completion(&bs->done); -+ -+ /* Disable the CMD_DONE interrupt */ -+ bcm_spi_writeb(~(SPI_INTR_CMD_DONE), bs->regs, SPI_INT_MASK); -+ -+ return t->len - bs->remaining_bytes; -+} -+ -+/* This driver supports single master mode only. Hence -+ * CMD_DONE is the only interrupt we care about -+ */ -+static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id) -+{ -+ struct spi_master *master = (struct spi_master *)dev_id; -+ struct bcm63xx_spi *bs = spi_master_get_devdata(master); -+ u8 intr; -+ u16 cmd; -+ -+ /* Read interupts and clear them immediately */ -+ intr = bcm_spi_readb(bs->regs, SPI_INT_STATUS); -+ bcm_spi_writeb(SPI_INTR_CLEAR_ALL, bs->regs, SPI_INT_MASK); -+ -+ /* A tansfer completed */ -+ if (intr & SPI_INTR_CMD_DONE) { -+ u8 rx_empty; -+ -+ rx_empty = bcm_spi_readb(bs->regs, SPI_ST); -+ /* Read out all the data */ -+ while ((rx_empty & SPI_RX_EMPTY) == 0) { -+ u8 data; -+ -+ data = bcm_spi_readb(bs->regs, SPI_RX_DATA); -+ if (bs->rx_ptr) -+ *bs->rx_ptr++ = data; -+ -+ rx_empty = bcm_spi_readb(bs->regs, SPI_RX_EMPTY); -+ } -+ -+ /* See if there is more data to send */ -+ if (bs->remaining_bytes > 0) { -+ bcm63xx_spi_fill_tx_fifo(bs); -+ -+ /* Start the transfer */ -+ cmd = bcm_spi_readw(bs->regs, SPI_CMD); -+ cmd |= SPI_CMD_START_IMMEDIATE; -+ cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT); -+ bcm_spi_writew(cmd, bs->regs, SPI_CMD); -+ } else -+ complete(&bs->done); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+ -+static int __init bcm63xx_spi_probe(struct platform_device *pdev) -+{ -+ struct resource *r; -+ struct bcm63xx_spi_pdata *pdata = pdev->dev.platform_data; -+ int irq; -+ struct spi_master *master; -+ struct clk *clk; -+ struct bcm63xx_spi *bs; -+ int ret; -+ -+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!r) { -+ ret = -ENXIO; -+ goto out; -+ } -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) { -+ ret = -ENXIO; -+ goto out; -+ } -+ -+ bcm63xx_spi_regs_init(); -+ -+ clk = clk_get(&pdev->dev, "spi"); -+ if (IS_ERR(clk)) { -+ dev_err(&pdev->dev, "No clock for device\n"); -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(struct bcm63xx_spi)); -+ if (!master) { -+ ret = -ENOMEM; -+ goto out_free; -+ } -+ -+ bs = spi_master_get_devdata(master); -+ bs->bitbang.master = spi_master_get(master); -+ bs->bitbang.chipselect = bcm63xx_spi_chipselect; -+ bs->bitbang.setup_transfer = bcm63xx_spi_setup_transfer; -+ bs->bitbang.txrx_bufs = bcm63xx_txrx_bufs; -+ bs->bitbang.master->setup = bcm63xx_spi_setup; -+ init_completion(&bs->done); -+ -+ platform_set_drvdata(pdev, master); -+ bs->pdev = pdev; -+ -+ if (!request_mem_region(r->start, -+ r->end - r->start, PFX)) { -+ ret = -ENXIO; -+ goto out_free; -+ } -+ -+ bs->regs = ioremap_nocache(r->start, r->end - r->start); -+ if (!bs->regs) { -+ printk(KERN_ERR PFX " unable to ioremap regs\n"); -+ ret = -ENOMEM; -+ goto out_free; -+ } -+ bs->irq = irq; -+ bs->clk = clk; -+ bs->fifo_size = pdata->fifo_size; -+ -+ ret = request_irq(irq, bcm63xx_spi_interrupt, 0, -+ pdev->name, master); -+ if (ret) { -+ printk(KERN_ERR PFX " unable to request irq\n"); -+ goto out_unmap; -+ } -+ -+ master->bus_num = pdata->bus_num; -+ master->num_chipselect = pdata->num_chipselect; -+ bs->speed_hz = pdata->speed_hz; -+ -+ /* Initialize hardware */ -+ clk_enable(bs->clk); -+ bcm_spi_writeb(SPI_INTR_CLEAR_ALL, bs->regs, SPI_INT_MASK); -+ -+ dev_info(&pdev->dev, " at 0x%08x (irq %d, FIFOs size %d) v%s\n", -+ r->start, irq, bs->fifo_size, DRV_VER); -+ -+ ret = spi_bitbang_start(&bs->bitbang); -+ if (ret) { -+ dev_err(&pdev->dev, "spi_bitbang_start FAILED\n"); -+ goto out_reset_hw; -+ } -+ -+ return ret; -+ -+out_reset_hw: -+ clk_disable(clk); -+ free_irq(irq, master); -+out_unmap: -+ iounmap(bs->regs); -+out_free: -+ clk_put(clk); -+ spi_master_put(master); -+out: -+ return ret; -+} -+ -+static int __exit bcm63xx_spi_remove(struct platform_device *pdev) -+{ -+ struct spi_master *master = platform_get_drvdata(pdev); -+ struct bcm63xx_spi *bs = spi_master_get_devdata(master); -+ -+ spi_bitbang_stop(&bs->bitbang); -+ clk_disable(bs->clk); -+ clk_put(bs->clk); -+ free_irq(bs->irq, master); -+ iounmap(bs->regs); -+ platform_set_drvdata(pdev, 0); -+ spi_master_put(bs->bitbang.master); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int bcm63xx_spi_suspend(struct platform_device *pdev, pm_message_t mesg) -+{ -+ struct spi_master *master = platform_get_drvdata(pdev); -+ struct bcm63xx_spi *bs = spi_master_get_devdata(master); -+ -+ clk_disable(bs->clk); -+ -+ return 0; -+} -+ -+static int bcm63xx_spi_resume(struct platform_device *pdev) -+{ -+ struct bcm63xx_spi *bs = spi_master_get_devdata(master); -+ struct bcm63xx_spi *bs = spi_master_get_devdata(master); -+ -+ clk_enable(bs->clk); -+ -+ return 0; -+} -+#else -+#define bcm63xx_spi_suspend NULL -+#define bcm63xx_spi_resume NULL -+#endif -+ -+static struct platform_driver bcm63xx_spi_driver = { -+ .driver = { -+ .name = "bcm63xx-spi", -+ .owner = THIS_MODULE, -+ }, -+ .probe = bcm63xx_spi_probe, -+ .remove = bcm63xx_spi_remove, -+ .suspend = bcm63xx_spi_suspend, -+ .resume = bcm63xx_spi_resume, -+}; -+ -+ -+static int __init bcm63xx_spi_init(void) -+{ -+ return platform_driver_register(&bcm63xx_spi_driver); -+} -+ -+static void __exit bcm63xx_spi_exit(void) -+{ -+ platform_driver_unregister(&bcm63xx_spi_driver); -+} -+ -+module_init(bcm63xx_spi_init); -+module_exit(bcm63xx_spi_exit); -+ -+MODULE_ALIAS("platform:bcm63xx_spi"); -+MODULE_AUTHOR("Florian Fainelli "); -+MODULE_DESCRIPTION("Broadcom BCM63xx SPI Controller driver"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(DRV_VER); ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -60,6 +60,13 @@ config SPI_ATMEL - This selects a driver for the Atmel SPI Controller, present on - many AT32 (AVR32) and AT91 (ARM) chips. - -+config SPI_BCM63XX -+ tristate "Broadcom BCM63xx SPI controller" -+ depends on BCM63XX -+ select SPI_BITBANG -+ help -+ This is the SPI controller master driver for Broadcom BCM63xx SoC. -+ - config SPI_BFIN - tristate "SPI controller driver for ADI Blackfin5xx" - depends on BLACKFIN ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -43,6 +43,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_BCM63XX) += bcm63xx_spi.o - - # special build for s3c24xx spi driver with fiq support - spi_s3c24xx_hw-y := spi_s3c24xx.o ---- /dev/null -+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h -@@ -0,0 +1,15 @@ -+#ifndef BCM63XX_DEV_SPI_H -+#define BCM63XX_DEV_SPI_H -+ -+#include -+ -+int __init bcm63xx_spi_register(void); -+ -+struct bcm63xx_spi_pdata { -+ unsigned int fifo_size; -+ int bus_num; -+ int num_chipselect; -+ u32 speed_hz; -+}; -+ -+#endif /* BCM63XX_DEV_SPI_H */ ---- a/arch/mips/bcm63xx/Makefile -+++ b/arch/mips/bcm63xx/Makefile -@@ -1,6 +1,6 @@ - obj-y += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \ - dev-dsp.o dev-enet.o dev-pcmcia.o dev-uart.o dev-wdt.o \ -- dev-usb-ohci.o dev-usb-ehci.o dev-usb-udc.o -+ dev-usb-ohci.o dev-usb-ehci.o dev-usb-udc.o dev-spi.o - obj-$(CONFIG_EARLY_PRINTK) += early_printk.o - - obj-y += boards/ ---- a/arch/mips/bcm63xx/boards/board_bcm963xx.c -+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c -@@ -29,6 +29,7 @@ - #include - #include - #include -+#include - #include - - #define PFX "board_bcm963xx: " -@@ -998,6 +999,9 @@ int __init board_register_devices(void) - if (board.has_udc0) - bcm63xx_udc_register(); - -+ if (!BCMCPU_IS_6345()) -+ bcm63xx_spi_register(); -+ - /* Generate MAC address for WLAN and - * register our SPROM */ - #ifdef CONFIG_SSB_PCIHOST