bcm63xx: replace SPI driver with latest upstream version

SVN-Revision: 31130
v19.07.3_mercusys_ac12_duma
Jonas Gorski 12 years ago
parent a2adca6ee9
commit 78fb818f7c

@ -10,8 +10,13 @@ define KernelPackage/bcm63xx-spi
TITLE:=Broadcom BCM63xx SPI driver
DEPENDS:=@TARGET_brcm63xx +kmod-spi-bitbang
KCONFIG:=CONFIG_SPI_BCM63XX
FILES:=$(LINUX_DIR)/drivers/spi/bcm63xx_spi.ko
AUTOLOAD:=$(call AutoLoad,92,bcm63xx_spi)
ifeq ($(strip $(call CompareKernelPatchVer,$(KERNEL_PATCHVER),ge,3.3)),1)
FILES:=$(LINUX_DIR)/drivers/spi/spi-bcm63xx.ko
AUTOLOAD:=$(call AutoLoad,92,spi-bcm63xx)
else
FILES:=$(LINUX_DIR)/drivers/spi/bcm63xx_spi.ko
AUTOLOAD:=$(call AutoLoad,92,bcm63xx_spi)
endif
endef
define KernelPackage/bcm63xx-spi/description

@ -0,0 +1,36 @@
From cbcfe65e357666106c3c6250baf9c5ce33f3e3e3 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:39:53 +0100
Subject: [PATCH 03/63] MIPS: BCM63XX: fix platform_devices id
There is only one watchdog and VoIP DSP platform devices per board, use
-1 as the platform_device id accordingly.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/bcm63xx/dev-dsp.c | 2 +-
arch/mips/bcm63xx/dev-wdt.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
--- a/arch/mips/bcm63xx/dev-dsp.c
+++ b/arch/mips/bcm63xx/dev-dsp.c
@@ -31,7 +31,7 @@ static struct resource voip_dsp_resource
static struct platform_device bcm63xx_voip_dsp_device = {
.name = "bcm63xx-voip-dsp",
- .id = 0,
+ .id = -1,
.num_resources = ARRAY_SIZE(voip_dsp_resources),
.resource = voip_dsp_resources,
};
--- a/arch/mips/bcm63xx/dev-wdt.c
+++ b/arch/mips/bcm63xx/dev-wdt.c
@@ -21,7 +21,7 @@ static struct resource wdt_resources[] =
static struct platform_device bcm63xx_wdt_device = {
.name = "bcm63xx-wdt",
- .id = 0,
+ .id = -1,
.num_resources = ARRAY_SIZE(wdt_resources),
.resource = wdt_resources,
};

@ -0,0 +1,93 @@
From db1cc4ee366bf0528fcb8b4afa65dec915d98889 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:39:55 +0100
Subject: [PATCH 04/63] MIPS: BCM63XX: be consistent in clock bits enable naming
Remove the _CLK suffix from the BCM6368 clock bits definitions to be
consistent with what is already present.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/bcm63xx/clk.c | 6 ++--
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 36 ++++++++++----------
2 files changed, 21 insertions(+), 21 deletions(-)
--- a/arch/mips/bcm63xx/clk.c
+++ b/arch/mips/bcm63xx/clk.c
@@ -120,7 +120,7 @@ static void enetsw_set(struct clk *clk,
{
if (!BCMCPU_IS_6368())
return;
- bcm_hwclock_set(CKCTL_6368_ROBOSW_CLK_EN |
+ bcm_hwclock_set(CKCTL_6368_ROBOSW_EN |
CKCTL_6368_SWPKT_USB_EN |
CKCTL_6368_SWPKT_SAR_EN, enable);
if (enable) {
@@ -163,7 +163,7 @@ static void usbh_set(struct clk *clk, in
if (BCMCPU_IS_6348())
bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
else if (BCMCPU_IS_6368())
- bcm_hwclock_set(CKCTL_6368_USBH_CLK_EN, enable);
+ bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
}
static struct clk clk_usbh = {
@@ -199,7 +199,7 @@ static void xtm_set(struct clk *clk, int
if (!BCMCPU_IS_6368())
return;
- bcm_hwclock_set(CKCTL_6368_SAR_CLK_EN |
+ bcm_hwclock_set(CKCTL_6368_SAR_EN |
CKCTL_6368_SWPKT_SAR_EN, enable);
if (enable) {
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -90,29 +90,29 @@
#define CKCTL_6368_PHYMIPS_EN (1 << 6)
#define CKCTL_6368_SWPKT_USB_EN (1 << 7)
#define CKCTL_6368_SWPKT_SAR_EN (1 << 8)
-#define CKCTL_6368_SPI_CLK_EN (1 << 9)
-#define CKCTL_6368_USBD_CLK_EN (1 << 10)
-#define CKCTL_6368_SAR_CLK_EN (1 << 11)
-#define CKCTL_6368_ROBOSW_CLK_EN (1 << 12)
-#define CKCTL_6368_UTOPIA_CLK_EN (1 << 13)
-#define CKCTL_6368_PCM_CLK_EN (1 << 14)
-#define CKCTL_6368_USBH_CLK_EN (1 << 15)
+#define CKCTL_6368_SPI_EN (1 << 9)
+#define CKCTL_6368_USBD_EN (1 << 10)
+#define CKCTL_6368_SAR_EN (1 << 11)
+#define CKCTL_6368_ROBOSW_EN (1 << 12)
+#define CKCTL_6368_UTOPIA_EN (1 << 13)
+#define CKCTL_6368_PCM_EN (1 << 14)
+#define CKCTL_6368_USBH_EN (1 << 15)
#define CKCTL_6368_DISABLE_GLESS_EN (1 << 16)
-#define CKCTL_6368_NAND_CLK_EN (1 << 17)
-#define CKCTL_6368_IPSEC_CLK_EN (1 << 17)
+#define CKCTL_6368_NAND_EN (1 << 17)
+#define CKCTL_6368_IPSEC_EN (1 << 17)
#define CKCTL_6368_ALL_SAFE_EN (CKCTL_6368_SWPKT_USB_EN | \
CKCTL_6368_SWPKT_SAR_EN | \
- CKCTL_6368_SPI_CLK_EN | \
- CKCTL_6368_USBD_CLK_EN | \
- CKCTL_6368_SAR_CLK_EN | \
- CKCTL_6368_ROBOSW_CLK_EN | \
- CKCTL_6368_UTOPIA_CLK_EN | \
- CKCTL_6368_PCM_CLK_EN | \
- CKCTL_6368_USBH_CLK_EN | \
+ CKCTL_6368_SPI_EN | \
+ CKCTL_6368_USBD_EN | \
+ CKCTL_6368_SAR_EN | \
+ CKCTL_6368_ROBOSW_EN | \
+ CKCTL_6368_UTOPIA_EN | \
+ CKCTL_6368_PCM_EN | \
+ CKCTL_6368_USBH_EN | \
CKCTL_6368_DISABLE_GLESS_EN | \
- CKCTL_6368_NAND_CLK_EN | \
- CKCTL_6368_IPSEC_CLK_EN)
+ CKCTL_6368_NAND_EN | \
+ CKCTL_6368_IPSEC_EN)
/* System PLL Control register */
#define PERF_SYS_PLL_CTL_REG 0x8

@ -0,0 +1,68 @@
From 04456614952a9a848192253439b4e361f0321cb5 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:39:51 +0100
Subject: [PATCH 05/63] MIPS: BCM63XX: add IRQ_SPI and CPU specific SPI IRQ values
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
@@ -478,6 +478,7 @@ static inline unsigned long bcm63xx_regs
*/
enum bcm63xx_irq {
IRQ_TIMER = 0,
+ IRQ_SPI,
IRQ_UART0,
IRQ_UART1,
IRQ_DSL,
@@ -509,6 +510,7 @@ enum bcm63xx_irq {
* 6338 irqs
*/
#define BCM_6338_TIMER_IRQ (IRQ_INTERNAL_BASE + 0)
+#define BCM_6338_SPI_IRQ (IRQ_INTERNAL_BASE + 1)
#define BCM_6338_UART0_IRQ (IRQ_INTERNAL_BASE + 2)
#define BCM_6338_UART1_IRQ 0
#define BCM_6338_DSL_IRQ (IRQ_INTERNAL_BASE + 5)
@@ -539,6 +541,7 @@ enum bcm63xx_irq {
* 6345 irqs
*/
#define BCM_6345_TIMER_IRQ (IRQ_INTERNAL_BASE + 0)
+#define BCM_6345_SPI_IRQ 0
#define BCM_6345_UART0_IRQ (IRQ_INTERNAL_BASE + 2)
#define BCM_6345_UART1_IRQ 0
#define BCM_6345_DSL_IRQ (IRQ_INTERNAL_BASE + 3)
@@ -569,6 +572,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_UART1_IRQ 0
#define BCM_6348_DSL_IRQ (IRQ_INTERNAL_BASE + 4)
@@ -599,6 +603,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_UART1_IRQ (IRQ_INTERNAL_BASE + 3)
#define BCM_6358_DSL_IRQ (IRQ_INTERNAL_BASE + 29)
@@ -638,6 +643,7 @@ enum bcm63xx_irq {
#define BCM_6368_HIGH_IRQ_BASE (IRQ_INTERNAL_BASE + 32)
#define BCM_6368_TIMER_IRQ (IRQ_INTERNAL_BASE + 0)
+#define BCM_6368_SPI_IRQ (IRQ_INTERNAL_BASE + 1)
#define BCM_6368_UART0_IRQ (IRQ_INTERNAL_BASE + 2)
#define BCM_6368_UART1_IRQ (IRQ_INTERNAL_BASE + 3)
#define BCM_6368_DSL_IRQ (IRQ_INTERNAL_BASE + 4)
@@ -677,6 +683,7 @@ extern const int *bcm63xx_irqs;
#define __GEN_CPU_IRQ_TABLE(__cpu) \
[IRQ_TIMER] = BCM_## __cpu ##_TIMER_IRQ, \
+ [IRQ_SPI] = BCM_## __cpu ##_SPI_IRQ, \
[IRQ_UART0] = BCM_## __cpu ##_UART0_IRQ, \
[IRQ_UART1] = BCM_## __cpu ##_UART1_IRQ, \
[IRQ_DSL] = BCM_## __cpu ##_DSL_IRQ, \

@ -0,0 +1,21 @@
From bfd78dda2ad5afb4434ebe99c05528614065bdb1 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:39:56 +0100
Subject: [PATCH 06/63] MIPS: BCM63XX: define BCM6358 SPI base address
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
@@ -289,7 +289,7 @@ enum bcm63xx_regs_set {
#define BCM_6358_UART0_BASE (0xfffe0100)
#define BCM_6358_UART1_BASE (0xfffe0120)
#define BCM_6358_GPIO_BASE (0xfffe0080)
-#define BCM_6358_SPI_BASE (0xdeadbeef)
+#define BCM_6358_SPI_BASE (0xfffe0800)
#define BCM_6358_SPI2_BASE (0xfffe0800)
#define BCM_6358_UDC0_BASE (0xfffe0800)
#define BCM_6358_OHCI0_BASE (0xfffe1400)

@ -0,0 +1,26 @@
From 9b990ee00f70bdd6a731dbe264d5acb453a6c5e2 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:39:57 +0100
Subject: [PATCH 07/63] MIPS: BCM63XX: add BCM6368 SPI clock mask
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/bcm63xx/clk.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
--- a/arch/mips/bcm63xx/clk.c
+++ b/arch/mips/bcm63xx/clk.c
@@ -181,9 +181,11 @@ static void spi_set(struct clk *clk, int
mask = CKCTL_6338_SPI_EN;
else if (BCMCPU_IS_6348())
mask = CKCTL_6348_SPI_EN;
- else
- /* BCMCPU_IS_6358 */
+ else if (BCMCPU_IS_6358())
mask = CKCTL_6358_SPI_EN;
+ else
+ /* BCMCPU_IS_6368 */
+ mask = CKCTL_6368_SPI_EN;
bcm_hwclock_set(mask, enable);
}

@ -0,0 +1,26 @@
From 16ba44545156e4e7cc1e812ad93e562ce92fd74c Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:40:00 +0100
Subject: [PATCH 08/63] MIPS: BCM63XX: define SPI register sizes.
There are two distinct sizes for the SPI register depending on the SoC
generation (6338 & 6348 vs 6358 & 6368).
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
@@ -135,6 +135,10 @@ enum bcm63xx_regs_set {
#define RSET_DSL_LMEM_SIZE (64 * 1024 * 4)
#define RSET_DSL_SIZE 4096
#define RSET_WDT_SIZE 12
+#define BCM_6338_RSET_SPI_SIZE 64
+#define BCM_6348_RSET_SPI_SIZE 64
+#define BCM_6358_RSET_SPI_SIZE 1804
+#define BCM_6368_RSET_SPI_SIZE 1804
#define RSET_ENET_SIZE 2048
#define RSET_ENETDMA_SIZE 2048
#define RSET_ENETSW_SIZE 65536

@ -0,0 +1,83 @@
From 32511e7dfab9b9cabe2772e3f5430559294a8d1c Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:40:01 +0100
Subject: [PATCH 09/63] MIPS: BCM63XX: remove SPI2 register
This register was introduced with the support of the BCM6368 CPU in the idea
that its internal layout was different from the other CPUs SPI controller.
The controller is actually the same as the one present on BCM6358 so we can
remove this register and use the usual SPI register instead.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h | 10 +---------
1 files changed, 1 insertions(+), 9 deletions(-)
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
@@ -102,7 +102,6 @@ enum bcm63xx_regs_set {
RSET_UART1,
RSET_GPIO,
RSET_SPI,
- RSET_SPI2,
RSET_UDC0,
RSET_OHCI0,
RSET_OHCI_PRIV,
@@ -166,7 +165,6 @@ enum bcm63xx_regs_set {
#define BCM_6338_UART1_BASE (0xdeadbeef)
#define BCM_6338_GPIO_BASE (0xfffe0400)
#define BCM_6338_SPI_BASE (0xfffe0c00)
-#define BCM_6338_SPI2_BASE (0xdeadbeef)
#define BCM_6338_UDC0_BASE (0xdeadbeef)
#define BCM_6338_USBDMA_BASE (0xfffe2400)
#define BCM_6338_OHCI0_BASE (0xdeadbeef)
@@ -210,7 +208,6 @@ enum bcm63xx_regs_set {
#define BCM_6345_UART1_BASE (0xdeadbeef)
#define BCM_6345_GPIO_BASE (0xfffe0400)
#define BCM_6345_SPI_BASE (0xdeadbeef)
-#define BCM_6345_SPI2_BASE (0xdeadbeef)
#define BCM_6345_UDC0_BASE (0xdeadbeef)
#define BCM_6345_USBDMA_BASE (0xfffe2800)
#define BCM_6345_ENET0_BASE (0xfffe1800)
@@ -253,7 +250,6 @@ enum bcm63xx_regs_set {
#define BCM_6348_UART1_BASE (0xdeadbeef)
#define BCM_6348_GPIO_BASE (0xfffe0400)
#define BCM_6348_SPI_BASE (0xfffe0c00)
-#define BCM_6348_SPI2_BASE (0xdeadbeef)
#define BCM_6348_UDC0_BASE (0xfffe1000)
#define BCM_6348_OHCI0_BASE (0xfffe1b00)
#define BCM_6348_OHCI_PRIV_BASE (0xfffe1c00)
@@ -294,7 +290,6 @@ enum bcm63xx_regs_set {
#define BCM_6358_UART1_BASE (0xfffe0120)
#define BCM_6358_GPIO_BASE (0xfffe0080)
#define BCM_6358_SPI_BASE (0xfffe0800)
-#define BCM_6358_SPI2_BASE (0xfffe0800)
#define BCM_6358_UDC0_BASE (0xfffe0800)
#define BCM_6358_OHCI0_BASE (0xfffe1400)
#define BCM_6358_OHCI_PRIV_BASE (0xdeadbeef)
@@ -335,8 +330,7 @@ enum bcm63xx_regs_set {
#define BCM_6368_UART0_BASE (0xb0000100)
#define BCM_6368_UART1_BASE (0xb0000120)
#define BCM_6368_GPIO_BASE (0xb0000080)
-#define BCM_6368_SPI_BASE (0xdeadbeef)
-#define BCM_6368_SPI2_BASE (0xb0000800)
+#define BCM_6368_SPI_BASE (0xb0000800)
#define BCM_6368_UDC0_BASE (0xdeadbeef)
#define BCM_6368_OHCI0_BASE (0xb0001600)
#define BCM_6368_OHCI_PRIV_BASE (0xdeadbeef)
@@ -383,7 +377,6 @@ extern const unsigned long *bcm63xx_regs
__GEN_RSET_BASE(__cpu, UART1) \
__GEN_RSET_BASE(__cpu, GPIO) \
__GEN_RSET_BASE(__cpu, SPI) \
- __GEN_RSET_BASE(__cpu, SPI2) \
__GEN_RSET_BASE(__cpu, UDC0) \
__GEN_RSET_BASE(__cpu, OHCI0) \
__GEN_RSET_BASE(__cpu, OHCI_PRIV) \
@@ -422,7 +415,6 @@ extern const unsigned long *bcm63xx_regs
[RSET_UART1] = BCM_## __cpu ##_UART1_BASE, \
[RSET_GPIO] = BCM_## __cpu ##_GPIO_BASE, \
[RSET_SPI] = BCM_## __cpu ##_SPI_BASE, \
- [RSET_SPI2] = BCM_## __cpu ##_SPI2_BASE, \
[RSET_UDC0] = BCM_## __cpu ##_UDC0_BASE, \
[RSET_OHCI0] = BCM_## __cpu ##_OHCI0_BASE, \
[RSET_OHCI_PRIV] = BCM_## __cpu ##_OHCI_PRIV_BASE, \

@ -0,0 +1,140 @@
From 81f9e7d6aa1dde65483387ba9e9823ef44f90435 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:40:03 +0100
Subject: [PATCH 10/63] MIPS: BCM63XX: define internal registers offsets of the SPI controller
BCM6338, BCM6348, BCM6358 and BCM6368 basically use the same SPI controller
though the internal registers are shuffled, which still allows a common
driver to drive that IP block.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h | 119 +++++++++++++++++++++
1 files changed, 119 insertions(+), 0 deletions(-)
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -973,4 +973,123 @@
#define M2M_SRCID_REG(x) ((x) * 0x40 + 0x14)
#define M2M_DSTID_REG(x) ((x) * 0x40 + 0x18)
+/*************************************************************************
+ * _REG relative to RSET_SPI
+ *************************************************************************/
+
+/* BCM 6338 SPI core */
+#define SPI_6338_CMD 0x00 /* 16-bits register */
+#define SPI_6338_INT_STATUS 0x02
+#define SPI_6338_INT_MASK_ST 0x03
+#define SPI_6338_INT_MASK 0x04
+#define SPI_6338_ST 0x05
+#define SPI_6338_CLK_CFG 0x06
+#define SPI_6338_FILL_BYTE 0x07
+#define SPI_6338_MSG_TAIL 0x09
+#define SPI_6338_RX_TAIL 0x0b
+#define SPI_6338_MSG_CTL 0x40
+#define SPI_6338_MSG_DATA 0x41
+#define SPI_6338_MSG_DATA_SIZE 0x3f
+#define SPI_6338_RX_DATA 0x80
+#define SPI_6338_RX_DATA_SIZE 0x3f
+
+/* BCM 6348 SPI core */
+#define SPI_6348_CMD 0x00 /* 16-bits register */
+#define SPI_6348_INT_STATUS 0x02
+#define SPI_6348_INT_MASK_ST 0x03
+#define SPI_6348_INT_MASK 0x04
+#define SPI_6348_ST 0x05
+#define SPI_6348_CLK_CFG 0x06
+#define SPI_6348_FILL_BYTE 0x07
+#define SPI_6348_MSG_TAIL 0x09
+#define SPI_6348_RX_TAIL 0x0b
+#define SPI_6348_MSG_CTL 0x40
+#define SPI_6348_MSG_DATA 0x41
+#define SPI_6348_MSG_DATA_SIZE 0x3f
+#define SPI_6348_RX_DATA 0x80
+#define SPI_6348_RX_DATA_SIZE 0x3f
+
+/* BCM 6358 SPI core */
+#define SPI_6358_MSG_CTL 0x00 /* 16-bits register */
+#define SPI_6358_MSG_DATA 0x02
+#define SPI_6358_MSG_DATA_SIZE 0x21e
+#define SPI_6358_RX_DATA 0x400
+#define SPI_6358_RX_DATA_SIZE 0x220
+#define SPI_6358_CMD 0x700 /* 16-bits register */
+#define SPI_6358_INT_STATUS 0x702
+#define SPI_6358_INT_MASK_ST 0x703
+#define SPI_6358_INT_MASK 0x704
+#define SPI_6358_ST 0x705
+#define SPI_6358_CLK_CFG 0x706
+#define SPI_6358_FILL_BYTE 0x707
+#define SPI_6358_MSG_TAIL 0x709
+#define SPI_6358_RX_TAIL 0x70B
+
+/* BCM 6358 SPI core */
+#define SPI_6368_MSG_CTL 0x00 /* 16-bits register */
+#define SPI_6368_MSG_DATA 0x02
+#define SPI_6368_MSG_DATA_SIZE 0x21e
+#define SPI_6368_RX_DATA 0x400
+#define SPI_6368_RX_DATA_SIZE 0x220
+#define SPI_6368_CMD 0x700 /* 16-bits register */
+#define SPI_6368_INT_STATUS 0x702
+#define SPI_6368_INT_MASK_ST 0x703
+#define SPI_6368_INT_MASK 0x704
+#define SPI_6368_ST 0x705
+#define SPI_6368_CLK_CFG 0x706
+#define SPI_6368_FILL_BYTE 0x707
+#define SPI_6368_MSG_TAIL 0x709
+#define SPI_6368_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 0x00
+#define SPI_CMD_SOFT_RESET 0x01
+#define SPI_CMD_HARD_RESET 0x02
+#define SPI_CMD_START_IMMEDIATE 0x03
+#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_MASK 0x07
+#define SPI_SSOFFTIME_MASK 0x38
+#define SPI_SSOFFTIME_SHIFT 3
+#define SPI_BYTE_SWAP 0x80
+
#endif /* BCM63XX_REGS_H_ */

@ -0,0 +1,243 @@
From af84327888c7081662a6b949754fc54d32a50503 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:40:04 +0100
Subject: [PATCH 11/63] MIPS: BCM63XX: add stub to register the SPI platform driver
This patch adds the necessary stub to register the SPI platform driver.
Since the registers are shuffled between the 4 BCM63xx CPUs supported by
this SPI driver we also need to generate the internal register layout and
export this layout for the driver to use it properly.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/bcm63xx/Makefile | 3 +-
arch/mips/bcm63xx/dev-spi.c | 119 ++++++++++++++++++++
.../include/asm/mach-bcm63xx/bcm63xx_dev_spi.h | 89 +++++++++++++++
3 files changed, 210 insertions(+), 1 deletions(-)
create mode 100644 arch/mips/bcm63xx/dev-spi.c
create mode 100644 arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
--- a/arch/mips/bcm63xx/Makefile
+++ b/arch/mips/bcm63xx/Makefile
@@ -1,5 +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-dsp.o dev-enet.o dev-pcmcia.o dev-spi.o dev-uart.o \
+ dev-wdt.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-y += boards/
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-spi.c
@@ -0,0 +1,119 @@
+/*
+ * 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-2011 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_dev_spi.h>
+#include <bcm63xx_regs.h>
+
+#ifdef BCMCPU_RUNTIME_DETECT
+/*
+ * register offsets
+ */
+static const unsigned long bcm6338_regs_spi[] = {
+ __GEN_SPI_REGS_TABLE(6338)
+};
+
+static const unsigned long bcm6348_regs_spi[] = {
+ __GEN_SPI_REGS_TABLE(6348)
+};
+
+static const unsigned long bcm6358_regs_spi[] = {
+ __GEN_SPI_REGS_TABLE(6358)
+};
+
+static const unsigned long bcm6368_regs_spi[] = {
+ __GEN_SPI_REGS_TABLE(6368)
+};
+
+const unsigned long *bcm63xx_regs_spi;
+EXPORT_SYMBOL(bcm63xx_regs_spi);
+
+static __init void bcm63xx_spi_regs_init(void)
+{
+ if (BCMCPU_IS_6338())
+ bcm63xx_regs_spi = bcm6338_regs_spi;
+ if (BCMCPU_IS_6348())
+ bcm63xx_regs_spi = bcm6348_regs_spi;
+ if (BCMCPU_IS_6358())
+ bcm63xx_regs_spi = bcm6358_regs_spi;
+ if (BCMCPU_IS_6368())
+ bcm63xx_regs_spi = bcm6368_regs_spi;
+}
+#else
+static __init void bcm63xx_spi_regs_init(void) { }
+#endif
+
+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 = 8,
+};
+
+static struct platform_device bcm63xx_spi_device = {
+ .name = "bcm63xx-spi",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(spi_resources),
+ .resource = spi_resources,
+ .dev = {
+ .platform_data = &spi_pdata,
+ },
+};
+
+int __init bcm63xx_spi_register(void)
+{
+ struct clk *periph_clk;
+
+ if (BCMCPU_IS_6345())
+ return -ENODEV;
+
+ periph_clk = clk_get(NULL, "periph");
+ if (IS_ERR(periph_clk)) {
+ pr_err("unable to get periph clock\n");
+ return -ENODEV;
+ }
+
+ /* Set bus frequency */
+ spi_pdata.speed_hz = clk_get_rate(periph_clk);
+
+ spi_resources[0].start = bcm63xx_regset_address(RSET_SPI);
+ spi_resources[0].end = spi_resources[0].start;
+ spi_resources[1].start = bcm63xx_get_irq_number(IRQ_SPI);
+
+ if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
+ spi_resources[0].end += BCM_6338_RSET_SPI_SIZE - 1;
+ spi_pdata.fifo_size = SPI_6338_MSG_DATA_SIZE;
+ }
+
+ if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
+ spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
+ spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE;
+ }
+
+ bcm63xx_spi_regs_init();
+
+ return platform_device_register(&bcm63xx_spi_device);
+}
--- /dev/null
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
@@ -0,0 +1,89 @@
+#ifndef BCM63XX_DEV_SPI_H
+#define BCM63XX_DEV_SPI_H
+
+#include <linux/types.h>
+#include <bcm63xx_io.h>
+#include <bcm63xx_regs.h>
+
+int __init bcm63xx_spi_register(void);
+
+struct bcm63xx_spi_pdata {
+ unsigned int fifo_size;
+ int bus_num;
+ int num_chipselect;
+ u32 speed_hz;
+};
+
+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,
+};
+
+#define __GEN_SPI_RSET_BASE(__cpu, __rset) \
+ case SPI_## __rset: \
+ return SPI_## __cpu ##_## __rset;
+
+#define __GEN_SPI_RSET(__cpu) \
+ switch (reg) { \
+ __GEN_SPI_RSET_BASE(__cpu, CMD) \
+ __GEN_SPI_RSET_BASE(__cpu, INT_STATUS) \
+ __GEN_SPI_RSET_BASE(__cpu, INT_MASK_ST) \
+ __GEN_SPI_RSET_BASE(__cpu, INT_MASK) \
+ __GEN_SPI_RSET_BASE(__cpu, ST) \
+ __GEN_SPI_RSET_BASE(__cpu, CLK_CFG) \
+ __GEN_SPI_RSET_BASE(__cpu, FILL_BYTE) \
+ __GEN_SPI_RSET_BASE(__cpu, MSG_TAIL) \
+ __GEN_SPI_RSET_BASE(__cpu, RX_TAIL) \
+ __GEN_SPI_RSET_BASE(__cpu, MSG_CTL) \
+ __GEN_SPI_RSET_BASE(__cpu, MSG_DATA) \
+ __GEN_SPI_RSET_BASE(__cpu, RX_DATA) \
+ }
+
+#define __GEN_SPI_REGS_TABLE(__cpu) \
+ [SPI_CMD] = SPI_## __cpu ##_CMD, \
+ [SPI_INT_STATUS] = SPI_## __cpu ##_INT_STATUS, \
+ [SPI_INT_MASK_ST] = SPI_## __cpu ##_INT_MASK_ST, \
+ [SPI_INT_MASK] = SPI_## __cpu ##_INT_MASK, \
+ [SPI_ST] = SPI_## __cpu ##_ST, \
+ [SPI_CLK_CFG] = SPI_## __cpu ##_CLK_CFG, \
+ [SPI_FILL_BYTE] = SPI_## __cpu ##_FILL_BYTE, \
+ [SPI_MSG_TAIL] = SPI_## __cpu ##_MSG_TAIL, \
+ [SPI_RX_TAIL] = SPI_## __cpu ##_RX_TAIL, \
+ [SPI_MSG_CTL] = SPI_## __cpu ##_MSG_CTL, \
+ [SPI_MSG_DATA] = SPI_## __cpu ##_MSG_DATA, \
+ [SPI_RX_DATA] = SPI_## __cpu ##_RX_DATA,
+
+static inline unsigned long bcm63xx_spireg(enum bcm63xx_regs_spi reg)
+{
+#ifdef BCMCPU_RUNTIME_DETECT
+ extern const unsigned long *bcm63xx_regs_spi;
+
+ return bcm63xx_regs_spi[reg];
+#else
+#ifdef CONFIG_BCM63XX_CPU_6338
+ __GEN_SPI_RSET(6338)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6348
+ __GEN_SPI_RSET(6348)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6358
+ __GEN_SPI_RSET(6358)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6368
+ __GEN_SPI_RSET(6368)
+#endif
+#endif
+ return 0;
+}
+
+#endif /* BCM63XX_DEV_SPI_H */

@ -0,0 +1,29 @@
From fab0cbda27ab2400d6a461bf144007a0d5337527 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 25 Jan 2012 17:40:05 +0100
Subject: [PATCH 12/63] MIPS: BCM63XX: make board setup code register the spi platform device
Signed-off-by: Florian Fainelli <florian@openwrt.org>
---
arch/mips/bcm63xx/boards/board_bcm963xx.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -25,6 +25,7 @@
#include <bcm63xx_dev_enet.h>
#include <bcm63xx_dev_dsp.h>
#include <bcm63xx_dev_pcmcia.h>
+#include <bcm63xx_dev_spi.h>
#include <board_bcm963xx.h>
#define PFX "board_bcm963xx: "
@@ -890,6 +891,8 @@ int __init board_register_devices(void)
}
#endif
+ bcm63xx_spi_register();
+
/* read base address of boot chip select (0) */
val = bcm_mpi_readl(MPI_CSBASE_REG(0));
val &= MPI_CSBASE_BASE_MASK;

@ -0,0 +1,532 @@
From 5f592b818a2c5731bb12137e7cffc3aa6e24ee5a Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Wed, 1 Feb 2012 09:14:09 +0000
Subject: [PATCH 13/63] spi: add Broadcom BCM63xx SPI controller driver
This patch adds support for the SPI controller found on the Broadcom BCM63xx
SoCs.
Signed-off-by: Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
Signed-off-by: Florian Fainelli <florian@openwrt.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
drivers/spi/Kconfig | 6 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-bcm63xx.c | 486 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 493 insertions(+), 0 deletions(-)
create mode 100644 drivers/spi/spi-bcm63xx.c
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -94,6 +94,12 @@ config SPI_AU1550
If you say yes to this option, support will be included for the
PSC SPI controller found on Au1550, Au1200 and Au1300 series.
+config SPI_BCM63XX
+ tristate "Broadcom BCM63xx SPI controller"
+ depends on BCM63XX
+ help
+ Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
+
config SPI_BITBANG
tristate "Utilities for Bitbanging SPI masters"
help
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera.
obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
+obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BFIN) += spi-bfin5xx.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
--- /dev/null
+++ b/drivers/spi/spi-bcm63xx.c
@@ -0,0 +1,486 @@
+/*
+ * Broadcom BCM63xx SPI controller support
+ *
+ * Copyright (C) 2009-2011 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+
+#include <bcm63xx_dev_spi.h>
+
+#define PFX KBUILD_MODNAME
+#define DRV_VER "0.1.2"
+
+struct bcm63xx_spi {
+ spinlock_t lock;
+ int stopping;
+ 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;
+
+ /* data iomem */
+ u8 __iomem *tx_io;
+ const u8 __iomem *rx_io;
+
+ int remaining_bytes;
+
+ struct clk *clk;
+ struct platform_device *pdev;
+};
+
+static inline u8 bcm_spi_readb(struct bcm63xx_spi *bs,
+ unsigned int offset)
+{
+ return bcm_readb(bs->regs + bcm63xx_spireg(offset));
+}
+
+static inline u16 bcm_spi_readw(struct bcm63xx_spi *bs,
+ unsigned int offset)
+{
+ return bcm_readw(bs->regs + bcm63xx_spireg(offset));
+}
+
+static inline void bcm_spi_writeb(struct bcm63xx_spi *bs,
+ u8 value, unsigned int offset)
+{
+ bcm_writeb(value, bs->regs + bcm63xx_spireg(offset));
+}
+
+static inline void bcm_spi_writew(struct bcm63xx_spi *bs,
+ u16 value, unsigned int offset)
+{
+ bcm_writew(value, bs->regs + bcm63xx_spireg(offset));
+}
+
+static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
+ { 20000000, SPI_CLK_20MHZ },
+ { 12500000, SPI_CLK_12_50MHZ },
+ { 6250000, SPI_CLK_6_250MHZ },
+ { 3125000, SPI_CLK_3_125MHZ },
+ { 1563000, SPI_CLK_1_563MHZ },
+ { 781000, SPI_CLK_0_781MHZ },
+ { 391000, SPI_CLK_0_391MHZ }
+};
+
+static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ u8 bits_per_word;
+ u8 clk_cfg, reg;
+ u32 hz;
+ int i;
+
+ 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;
+ }
+
+ /* Find the closest clock configuration */
+ for (i = 0; i < SPI_CLK_MASK; i++) {
+ if (hz <= bcm63xx_spi_freq_table[i][0]) {
+ clk_cfg = bcm63xx_spi_freq_table[i][1];
+ break;
+ }
+ }
+
+ /* No matching configuration found, default to lowest */
+ if (i == SPI_CLK_MASK)
+ clk_cfg = SPI_CLK_0_391MHZ;
+
+ /* clear existing clock configuration bits of the register */
+ reg = bcm_spi_readb(bs, SPI_CLK_CFG);
+ reg &= ~SPI_CLK_MASK;
+ reg |= clk_cfg;
+
+ bcm_spi_writeb(bs, reg, SPI_CLK_CFG);
+ dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n",
+ clk_cfg, hz);
+
+ 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 bcm63xx_spi *bs;
+ int ret;
+
+ bs = spi_master_get_devdata(spi->master);
+
+ if (bs->stopping)
+ return -ESHUTDOWN;
+
+ 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;
+ }
+
+ ret = bcm63xx_spi_setup_transfer(spi, NULL);
+ if (ret < 0) {
+ dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return ret;
+ }
+
+ 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 size;
+
+ /* Fill the Tx FIFO with as many bytes as possible */
+ size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes :
+ bs->fifo_size;
+ memcpy_toio(bs->tx_io, bs->tx_ptr, size);
+ bs->remaining_bytes -= size;
+}
+
+static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ u16 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;
+ init_completion(&bs->done);
+
+ if (t->tx_buf) {
+ bs->remaining_bytes = t->len;
+ bcm63xx_spi_fill_tx_fifo(bs);
+ }
+
+ /* Enable the command done interrupt which
+ * we use to determine completion of a command */
+ bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
+
+ /* Fill in the Message control register */
+ msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
+
+ if (t->rx_buf && t->tx_buf)
+ msg_ctl |= (SPI_FD_RW << SPI_MSG_TYPE_SHIFT);
+ else if (t->rx_buf)
+ msg_ctl |= (SPI_HD_R << SPI_MSG_TYPE_SHIFT);
+ else if (t->tx_buf)
+ msg_ctl |= (SPI_HD_W << SPI_MSG_TYPE_SHIFT);
+
+ bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL);
+
+ /* Issue the transfer */
+ cmd = SPI_CMD_START_IMMEDIATE;
+ cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
+ cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
+ bcm_spi_writew(bs, cmd, SPI_CMD);
+ wait_for_completion(&bs->done);
+
+ /* Disable the CMD_DONE interrupt */
+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
+
+ return t->len - bs->remaining_bytes;
+}
+
+static int bcm63xx_transfer(struct spi_device *spi, struct spi_message *m)
+{
+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ struct spi_transfer *t;
+ int ret = 0;
+
+ if (unlikely(list_empty(&m->transfers)))
+ return -EINVAL;
+
+ if (bs->stopping)
+ return -ESHUTDOWN;
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ ret += bcm63xx_txrx_bufs(spi, t);
+ }
+
+ m->complete(m->context);
+
+ return ret;
+}
+
+/* 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, SPI_INT_STATUS);
+ bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
+
+ /* A tansfer completed */
+ if (intr & SPI_INTR_CMD_DONE) {
+ u8 rx_tail;
+
+ rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
+
+ /* Read out all the data */
+ if (rx_tail)
+ memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
+
+ /* See if there is more data to send */
+ if (bs->remaining_bytes > 0) {
+ bcm63xx_spi_fill_tx_fifo(bs);
+
+ /* Start the transfer */
+ bcm_spi_writew(bs, SPI_HD_W << SPI_MSG_TYPE_SHIFT,
+ SPI_MSG_CTL);
+ cmd = bcm_spi_readw(bs, SPI_CMD);
+ cmd |= SPI_CMD_START_IMMEDIATE;
+ cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
+ bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
+ bcm_spi_writew(bs, cmd, SPI_CMD);
+ } else {
+ complete(&bs->done);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
+{
+ struct resource *r;
+ struct device *dev = &pdev->dev;
+ 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) {
+ dev_err(dev, "no iomem\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "no irq\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ clk = clk_get(dev, "spi");
+ if (IS_ERR(clk)) {
+ dev_err(dev, "no clock for device\n");
+ ret = PTR_ERR(clk);
+ goto out;
+ }
+
+ master = spi_alloc_master(dev, sizeof(*bs));
+ if (!master) {
+ dev_err(dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto out_clk;
+ }
+
+ bs = spi_master_get_devdata(master);
+ init_completion(&bs->done);
+
+ platform_set_drvdata(pdev, master);
+ bs->pdev = pdev;
+
+ if (!devm_request_mem_region(&pdev->dev, r->start,
+ resource_size(r), PFX)) {
+ dev_err(dev, "iomem request failed\n");
+ ret = -ENXIO;
+ goto out_err;
+ }
+
+ bs->regs = devm_ioremap_nocache(&pdev->dev, r->start,
+ resource_size(r));
+ if (!bs->regs) {
+ dev_err(dev, "unable to ioremap regs\n");
+ ret = -ENOMEM;
+ goto out_err;
+ }
+
+ bs->irq = irq;
+ bs->clk = clk;
+ bs->fifo_size = pdata->fifo_size;
+
+ ret = devm_request_irq(&pdev->dev, irq, bcm63xx_spi_interrupt, 0,
+ pdev->name, master);
+ if (ret) {
+ dev_err(dev, "unable to request irq\n");
+ goto out_err;
+ }
+
+ master->bus_num = pdata->bus_num;
+ master->num_chipselect = pdata->num_chipselect;
+ master->setup = bcm63xx_spi_setup;
+ master->transfer = bcm63xx_transfer;
+ bs->speed_hz = pdata->speed_hz;
+ bs->stopping = 0;
+ bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
+ bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA));
+ spin_lock_init(&bs->lock);
+
+ /* Initialize hardware */
+ clk_enable(bs->clk);
+ bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
+
+ /* register and we are done */
+ ret = spi_register_master(master);
+ if (ret) {
+ dev_err(dev, "spi register failed\n");
+ goto out_clk_disable;
+ }
+
+ dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d) v%s\n",
+ r->start, irq, bs->fifo_size, DRV_VER);
+
+ return 0;
+
+out_clk_disable:
+ clk_disable(clk);
+out_err:
+ platform_set_drvdata(pdev, NULL);
+ spi_master_put(master);
+out_clk:
+ clk_put(clk);
+out:
+ return ret;
+}
+
+static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+
+ /* reset spi block */
+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
+ spin_lock(&bs->lock);
+ bs->stopping = 1;
+
+ /* HW shutdown */
+ clk_disable(bs->clk);
+ clk_put(bs->clk);
+
+ spin_unlock(&bs->lock);
+ platform_set_drvdata(pdev, 0);
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bcm63xx_spi_suspend(struct device *dev)
+{
+ struct spi_master *master =
+ platform_get_drvdata(to_platform_device(dev));
+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+
+ clk_disable(bs->clk);
+
+ return 0;
+}
+
+static int bcm63xx_spi_resume(struct device *dev)
+{
+ struct spi_master *master =
+ platform_get_drvdata(to_platform_device(dev));
+ struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+
+ clk_enable(bs->clk);
+
+ return 0;
+}
+
+static const struct dev_pm_ops bcm63xx_spi_pm_ops = {
+ .suspend = bcm63xx_spi_suspend,
+ .resume = bcm63xx_spi_resume,
+};
+
+#define BCM63XX_SPI_PM_OPS (&bcm63xx_spi_pm_ops)
+#else
+#define BCM63XX_SPI_PM_OPS NULL
+#endif
+
+static struct platform_driver bcm63xx_spi_driver = {
+ .driver = {
+ .name = "bcm63xx-spi",
+ .owner = THIS_MODULE,
+ .pm = BCM63XX_SPI_PM_OPS,
+ },
+ .probe = bcm63xx_spi_probe,
+ .remove = __devexit_p(bcm63xx_spi_remove),
+};
+
+module_platform_driver(bcm63xx_spi_driver);
+
+MODULE_ALIAS("platform:bcm63xx_spi");
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
+MODULE_AUTHOR("Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>");
+MODULE_DESCRIPTION("Broadcom BCM63xx SPI Controller driver");
+MODULE_LICENSE("GPL");

@ -9,7 +9,7 @@
#include <asm/addrspace.h>
#include <bcm63xx_board.h>
#include <bcm63xx_cpu.h>
@@ -294,6 +296,16 @@ static struct board_info __initdata boar
@@ -295,6 +297,16 @@ static struct board_info __initdata boar
.active_low = 1,
},
},
@ -26,7 +26,7 @@
};
static struct board_info __initdata board_96348gw = {
@@ -352,6 +364,16 @@ static struct board_info __initdata boar
@@ -353,6 +365,16 @@ static struct board_info __initdata boar
.active_low = 1,
},
},
@ -43,7 +43,7 @@
};
static struct board_info __initdata board_FAST2404 = {
@@ -850,12 +872,23 @@ static struct platform_device bcm63xx_gp
@@ -851,12 +873,23 @@ static struct platform_device bcm63xx_gp
.dev.platform_data = &bcm63xx_led_data,
};
@ -67,7 +67,7 @@
if (board.has_uart0)
bcm63xx_uart_register(0);
@@ -904,5 +937,16 @@ int __init board_register_devices(void)
@@ -907,5 +940,16 @@ int __init board_register_devices(void)
platform_device_register(&bcm63xx_gpio_leds);

@ -1,6 +1,6 @@
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -889,6 +889,7 @@ int __init board_register_devices(void)
@@ -890,6 +890,7 @@ int __init board_register_devices(void)
{
u32 val;
int button_count = 0;
@ -8,7 +8,7 @@
if (board.has_uart0)
bcm63xx_uart_register(0);
@@ -932,7 +933,11 @@ int __init board_register_devices(void)
@@ -935,7 +936,11 @@ int __init board_register_devices(void)
platform_device_register(&mtd_dev);

@ -1,8 +1,8 @@
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -924,6 +924,9 @@ int __init board_register_devices(void)
}
#endif
@@ -927,6 +927,9 @@ int __init board_register_devices(void)
bcm63xx_spi_register();
+ if (board.num_devs)
+ platform_add_devices(board.devs, board.num_devs);

@ -1,6 +1,6 @@
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -927,6 +927,9 @@ int __init board_register_devices(void)
@@ -930,6 +930,9 @@ int __init board_register_devices(void)
if (board.num_devs)
platform_add_devices(board.devs, board.num_devs);

@ -1,8 +1,8 @@
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -28,9 +28,13 @@
#include <bcm63xx_dev_dsp.h>
@@ -29,9 +29,13 @@
#include <bcm63xx_dev_pcmcia.h>
#include <bcm63xx_dev_spi.h>
#include <board_bcm963xx.h>
+#include <bcm_tag.h>
@ -14,7 +14,7 @@
static struct bcm963xx_nvram nvram;
static unsigned int mac_addr_used;
static struct board_info board;
@@ -721,6 +725,29 @@ static int board_get_mac_address(u8 *mac
@@ -722,6 +726,29 @@ static int board_get_mac_address(u8 *mac
return 0;
}
@ -44,7 +44,7 @@
/*
* early init callback, read nvram data from flash and checksum it
*/
@@ -762,6 +789,11 @@ void __init board_prom_init(void)
@@ -763,6 +790,11 @@ void __init board_prom_init(void)
return;
}

@ -1,7 +1,7 @@
From f4aa3db2fb59983d45a9038daabad76102d32fc4 Mon Sep 17 00:00:00 2001
From 7b510c5754d3c46e1287803f51e8ecb177414438 Mon Sep 17 00:00:00 2001
From: Maxime Bizon <mbizon@freebox.fr>
Date: Fri, 10 Jun 2011 19:14:30 +0200
Subject: [PATCH 20/57] ohci: add driver for bcm63xx integrated controller.
Subject: [PATCH 23/63] ohci: add driver for bcm63xx integrated controller.
---
drivers/usb/host/Kconfig | 9 ++

@ -1,7 +1,7 @@
From 4ce192d5860760140439a3f305bc32f5e2316aa8 Mon Sep 17 00:00:00 2001
From ab96f20ca1c3c8e7e5acd82d1e50823a5d572675 Mon Sep 17 00:00:00 2001
From: Maxime Bizon <mbizon@freebox.fr>
Date: Tue, 24 May 2011 21:47:41 +0200
Subject: [PATCH 21/57] MIPS: BCM63XX: register ohci device.
Subject: [PATCH 24/63] MIPS: BCM63XX: register ohci device.
---
arch/mips/bcm63xx/Kconfig | 9 ++--
@ -48,25 +48,25 @@ Subject: [PATCH 21/57] MIPS: BCM63XX: register ohci device.
source "arch/mips/bcm63xx/boards/Kconfig"
--- a/arch/mips/bcm63xx/Makefile
+++ b/arch/mips/bcm63xx/Makefile
@@ -1,5 +1,6 @@
@@ -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-dsp.o dev-enet.o dev-pcmcia.o dev-uart.o \
dev-dsp.o dev-enet.o dev-pcmcia.o dev-spi.o dev-uart.o \
- dev-wdt.o
+ dev-usb-ohci.o dev-wdt.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
@@ -27,6 +27,7 @@
#include <bcm63xx_dev_enet.h>
@@ -28,6 +28,7 @@
#include <bcm63xx_dev_dsp.h>
#include <bcm63xx_dev_pcmcia.h>
#include <bcm63xx_dev_spi.h>
+#include <bcm63xx_dev_usb_ohci.h>
#include <board_bcm963xx.h>
#include <bcm_tag.h>
@@ -940,6 +941,9 @@ int __init board_register_devices(void)
@@ -941,6 +942,9 @@ int __init board_register_devices(void)
!board_get_mac_address(board.enet1.mac_addr))
bcm63xx_enet_register(1, &board.enet1);

@ -1,7 +1,7 @@
From 0f7d8ff44dc9e7048c141e6589bb590438cfc656 Mon Sep 17 00:00:00 2001
From db58271d5152aa1d3894fdef13ca04379139d5d9 Mon Sep 17 00:00:00 2001
From: Maxime Bizon <mbizon@freebox.fr>
Date: Fri, 10 Jun 2011 19:15:47 +0200
Subject: [PATCH 22/57] ehci: add driver for bcm63xx integrated controller.
Subject: [PATCH 25/63] ehci: add driver for bcm63xx integrated controller.
---
drivers/usb/host/Kconfig | 10 ++-

@ -1,7 +1,7 @@
From 00fefa81d4919c72470ad68f05bc9e239108ca1b Mon Sep 17 00:00:00 2001
From a2d78246e4cb45b5978fc682aad19c0fff0cd20d Mon Sep 17 00:00:00 2001
From: Maxime Bizon <mbizon@freebox.fr>
Date: Tue, 24 May 2011 21:50:33 +0200
Subject: [PATCH 23/57] MIPS: BCM63XX: register ehci device.
Subject: [PATCH 26/63] MIPS: BCM63XX: register ehci device.
---
arch/mips/bcm63xx/Kconfig | 2 +
@ -33,7 +33,7 @@ Subject: [PATCH 23/57] MIPS: BCM63XX: register ehci device.
+++ 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-dsp.o dev-enet.o dev-pcmcia.o dev-spi.o dev-uart.o \
- dev-usb-ohci.o dev-wdt.o
+ dev-usb-ehci.o dev-usb-ohci.o dev-wdt.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
@ -41,15 +41,15 @@ Subject: [PATCH 23/57] MIPS: BCM63XX: register ehci device.
obj-y += boards/
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -28,6 +28,7 @@
#include <bcm63xx_dev_dsp.h>
@@ -29,6 +29,7 @@
#include <bcm63xx_dev_pcmcia.h>
#include <bcm63xx_dev_spi.h>
#include <bcm63xx_dev_usb_ohci.h>
+#include <bcm63xx_dev_usb_ehci.h>
#include <board_bcm963xx.h>
#include <bcm_tag.h>
@@ -941,6 +942,9 @@ int __init board_register_devices(void)
@@ -942,6 +943,9 @@ int __init board_register_devices(void)
!board_get_mac_address(board.enet1.mac_addr))
bcm63xx_enet_register(1, &board.enet1);

@ -12,7 +12,7 @@ Signed-off-by: Axel Gembe <ago@bastart.eu.org>
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -872,7 +872,7 @@ static struct mtd_partition mtd_partitio
@@ -873,7 +873,7 @@ static struct mtd_partition mtd_partitio
}
};

@ -1,6 +1,6 @@
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -844,6 +844,8 @@ void __init board_prom_init(void)
@@ -845,6 +845,8 @@ void __init board_prom_init(void)
if (BCMCPU_IS_6348())
val |= GPIO_MODE_6348_G3_EXT_MII |
GPIO_MODE_6348_G0_EXT_MII;

@ -1,904 +0,0 @@
--- /dev/null
+++ b/arch/mips/bcm63xx/dev-spi.c
@@ -0,0 +1,99 @@
+/*
+ * 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-2011 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/export.h>
+
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_dev_spi.h>
+#include <bcm63xx_regs.h>
+
+#ifdef BCMCPU_RUNTIME_DETECT
+/*
+ * register offsets
+ */
+static const unsigned long bcm96338_regs_spi[] = {
+ __GEN_SPI_REGS_TABLE(6338)
+};
+
+static const unsigned long bcm96348_regs_spi[] = {
+ __GEN_SPI_REGS_TABLE(6348)
+};
+
+static const unsigned long bcm96358_regs_spi[] = {
+ __GEN_SPI_REGS_TABLE(6358)
+};
+
+const unsigned long *bcm63xx_regs_spi;
+EXPORT_SYMBOL(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 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 = 8,
+ .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);
+
+ if (BCMCPU_IS_6345())
+ return -ENODEV;
+
+ /* 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;
+
+ bcm63xx_spi_regs_init();
+
+ 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
@@ -138,6 +138,7 @@ enum bcm63xx_regs_set {
#define RSET_ENET_SIZE 2048
#define RSET_ENETDMA_SIZE 2048
#define RSET_ENETSW_SIZE 65536
+#define RSET_SPI_SIZE 256
#define RSET_UART_SIZE 24
#define RSET_UDC_SIZE 256
#define RSET_OHCI_SIZE 256
@@ -289,7 +290,7 @@ enum bcm63xx_regs_set {
#define BCM_6358_UART0_BASE (0xfffe0100)
#define BCM_6358_UART1_BASE (0xfffe0120)
#define BCM_6358_GPIO_BASE (0xfffe0080)
-#define BCM_6358_SPI_BASE (0xdeadbeef)
+#define BCM_6358_SPI_BASE (0xfffe0800)
#define BCM_6358_SPI2_BASE (0xfffe0800)
#define BCM_6358_UDC0_BASE (0xfffe0800)
#define BCM_6358_OHCI0_BASE (0xfffe1400)
@@ -478,6 +479,7 @@ static inline unsigned long bcm63xx_regs
*/
enum bcm63xx_irq {
IRQ_TIMER = 0,
+ IRQ_SPI,
IRQ_UART0,
IRQ_UART1,
IRQ_DSL,
@@ -569,6 +571,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_UART1_IRQ 0
#define BCM_6348_DSL_IRQ (IRQ_INTERNAL_BASE + 4)
@@ -599,6 +602,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_UART1_IRQ (IRQ_INTERNAL_BASE + 3)
#define BCM_6358_DSL_IRQ (IRQ_INTERNAL_BASE + 29)
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -976,4 +976,116 @@
#define M2M_SRCID_REG(x) ((x) * 0x40 + 0x14)
#define M2M_DSTID_REG(x) ((x) * 0x40 + 0x18)
+/*************************************************************************
+ * _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_INT_MASK_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_CMD 0x00 /* 16-bits register */
+#define SPI_BCM_6348_SPI_INT_STATUS 0x02
+#define SPI_BCM_6348_SPI_INT_MASK_ST 0x03
+#define SPI_BCM_6348_SPI_INT_MASK 0x04
+#define SPI_BCM_6348_SPI_ST 0x05
+#define SPI_BCM_6348_SPI_CLK_CFG 0x06
+#define SPI_BCM_6348_SPI_FILL_BYTE 0x07
+#define SPI_BCM_6348_SPI_MSG_TAIL 0x09
+#define SPI_BCM_6348_SPI_RX_TAIL 0x0b
+#define SPI_BCM_6348_SPI_MSG_CTL 0x40
+#define SPI_BCM_6348_SPI_MSG_DATA 0x41
+#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_SPI_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_INT_MASK_ST 0x703
+
+#define SPI_BCM_6358_SPI_INT_MASK 0x704
+
+#define SPI_BCM_6358_SPI_ST 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 0x00
+#define SPI_CMD_SOFT_RESET 0x01
+#define SPI_CMD_HARD_RESET 0x02
+#define SPI_CMD_START_IMMEDIATE 0x03
+#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,496 @@
+/*
+ * Broadcom BCM63xx SPI controller support
+ *
+ * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
+ * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
+ *
+ * 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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+
+#include <bcm63xx_dev_spi.h>
+
+#define PFX KBUILD_MODNAME
+#define DRV_VER "0.1.2"
+
+struct bcm63xx_spi {
+ spinlock_t lock;
+ int stopping;
+ 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;
+
+ /* data iomem */
+ u8 __iomem *tx_io;
+ const u8 __iomem *rx_io;
+
+ int remaining_bytes;
+
+ struct clk *clk;
+ struct platform_device *pdev;
+};
+
+static inline u8 bcm_spi_readb(struct bcm63xx_spi *bs,
+ unsigned int offset)
+{
+ return bcm_readw(bs->regs + bcm63xx_spireg(offset));
+}
+
+static inline u16 bcm_spi_readw(struct bcm63xx_spi *bs,
+ unsigned int offset)
+{
+ return bcm_readw(bs->regs + bcm63xx_spireg(offset));
+}
+
+static inline void bcm_spi_writeb(struct bcm63xx_spi *bs,
+ u8 value, unsigned int offset)
+{
+ bcm_writeb(value, bs->regs + bcm63xx_spireg(offset));
+}
+
+static inline void bcm_spi_writew(struct bcm63xx_spi *bs,
+ u16 value, unsigned int offset)
+{
+ bcm_writew(value, bs->regs + bcm63xx_spireg(offset));
+}
+
+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 64:
+ clk_cfg = SPI_CLK_0_781MHZ;
+ break;
+ case 128:
+ default:
+ /* Set to slowest mode for compatibility */
+ clk_cfg = SPI_CLK_0_391MHZ;
+ break;
+ }
+
+ bcm_spi_writeb(bs, clk_cfg, 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 bcm63xx_spi *bs;
+ int ret;
+
+ bs = spi_master_get_devdata(spi->master);
+
+ if (bs->stopping)
+ return -ESHUTDOWN;
+
+ 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;
+ }
+
+ ret = bcm63xx_spi_setup_transfer(spi, NULL);
+ if (ret < 0) {
+ dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return ret;
+ }
+
+ 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 size;
+
+ /* Fill the Tx FIFO with as many bytes as possible */
+ size = bs->remaining_bytes < bs->fifo_size ? bs->remaining_bytes :
+ bs->fifo_size;
+ memcpy_toio(bs->tx_io, bs->tx_ptr, size);
+ bs->remaining_bytes -= size;
+}
+
+static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ u16 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;
+ init_completion(&bs->done);
+
+ if (t->tx_buf) {
+ bs->remaining_bytes = t->len;
+ bcm63xx_spi_fill_tx_fifo(bs);
+ }
+
+ /* Enable the command done interrupt which
+ * we use to determine completion of a command */
+ bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
+
+ /* Fill in the Message control register */
+ msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
+
+ if (t->rx_buf && t->tx_buf)
+ msg_ctl |= (SPI_FD_RW << SPI_MSG_TYPE_SHIFT);
+ else if (t->rx_buf)
+ msg_ctl |= (SPI_HD_R << SPI_MSG_TYPE_SHIFT);
+ else if (t->tx_buf)
+ msg_ctl |= (SPI_HD_W << SPI_MSG_TYPE_SHIFT);
+
+ bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL);
+
+ /* Issue the transfer */
+ cmd = SPI_CMD_START_IMMEDIATE;
+ cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
+ cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
+ bcm_spi_writew(bs, cmd, SPI_CMD);
+ wait_for_completion(&bs->done);
+
+ /* Disable the CMD_DONE interrupt */
+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
+
+ return t->len - bs->remaining_bytes;
+}
+
+static int bcm63xx_transfer(struct spi_device *spi, struct spi_message *m)
+{
+ struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ struct spi_transfer *t;
+ int ret = 0;
+
+ if (unlikely(list_empty(&m->transfers)))
+ return -EINVAL;
+
+ if (bs->stopping)
+ return -ESHUTDOWN;
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ ret += bcm63xx_txrx_bufs(spi, t);
+ }
+
+ m->complete(m->context);
+
+ return ret;
+}
+
+/* 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, SPI_INT_STATUS);
+ bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
+
+ /* A tansfer completed */
+ if (intr & SPI_INTR_CMD_DONE) {
+ u8 rx_tail;
+
+ rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
+
+ /* Read out all the data */
+ if (rx_tail)
+ memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
+
+ /* See if there is more data to send */
+ if (bs->remaining_bytes > 0) {
+ bcm63xx_spi_fill_tx_fifo(bs);
+
+ /* Start the transfer */
+ bcm_spi_writew(bs, SPI_HD_W << SPI_MSG_TYPE_SHIFT,
+ SPI_MSG_CTL);
+ cmd = bcm_spi_readw(bs, SPI_CMD);
+ cmd |= SPI_CMD_START_IMMEDIATE;
+ cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
+ bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
+ bcm_spi_writew(bs, cmd, SPI_CMD);
+ } else {
+ complete(&bs->done);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static int __init bcm63xx_spi_probe(struct platform_device *pdev)
+{
+ struct resource *r;
+ struct device *dev = &pdev->dev;
+ 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) {
+ dev_err(dev, "no iomem\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "no irq\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ clk = clk_get(dev, "spi");
+ if (IS_ERR(clk)) {
+ dev_err(dev, "no clock for device\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ master = spi_alloc_master(dev, sizeof(*bs));
+ if (!master) {
+ dev_err(dev, "out of memory\n");
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ bs = spi_master_get_devdata(master);
+ init_completion(&bs->done);
+
+ platform_set_drvdata(pdev, master);
+ bs->pdev = pdev;
+
+ if (!request_mem_region(r->start, r->end - r->start, PFX)) {
+ dev_err(dev, "iomem request failed\n");
+ ret = -ENXIO;
+ goto out_put_master;
+ }
+
+ bs->regs = ioremap_nocache(r->start, r->end - r->start);
+ if (!bs->regs) {
+ dev_err(dev, "unable to ioremap regs\n");
+ ret = -ENOMEM;
+ goto out_put_master;
+ }
+ 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) {
+ dev_err(dev, "unable to request irq\n");
+ goto out_unmap;
+ }
+
+ master->bus_num = pdata->bus_num;
+ master->num_chipselect = pdata->num_chipselect;
+ master->setup = bcm63xx_spi_setup;
+ master->transfer = bcm63xx_transfer;
+ bs->speed_hz = pdata->speed_hz;
+ bs->stopping = 0;
+ bs->tx_io = (u8*)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
+ bs->rx_io = (const u8*)(bs->regs + bcm63xx_spireg(SPI_RX_DATA));
+ spin_lock_init(&bs->lock);
+
+ /* Initialize hardware */
+ clk_enable(bs->clk);
+ bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
+
+ /* register and we are done */
+ ret = spi_register_master(master);
+ if (ret) {
+ dev_err(dev, "spi register failed\n");
+ goto out_reset_hw;
+ }
+
+ dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d) v%s\n",
+ r->start, irq, bs->fifo_size, DRV_VER);
+
+ return 0;
+
+out_reset_hw:
+ clk_disable(clk);
+ free_irq(irq, master);
+out_unmap:
+ iounmap(bs->regs);
+out_put_master:
+ spi_master_put(master);
+out_free:
+ clk_put(clk);
+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);
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ /* reset spi block */
+ bcm_spi_writeb(bs, 0, SPI_INT_MASK);
+ spin_lock(&bs->lock);
+ bs->stopping = 1;
+
+ /* HW shutdown */
+ clk_disable(bs->clk);
+ clk_put(bs->clk);
+
+ spin_unlock(&bs->lock);
+
+ free_irq(bs->irq, master);
+ iounmap(bs->regs);
+ release_mem_region(r->start, r->end - r->start);
+ platform_set_drvdata(pdev, 0);
+ spi_unregister_master(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 spi_master *master = platform_get_drvdata(pdev);
+ 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 = __exit_p(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 <florian@openwrt.org>");
+MODULE_AUTHOR("Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>");
+MODULE_DESCRIPTION("Broadcom BCM63xx SPI Controller driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VER);
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -74,6 +74,12 @@ 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
+ 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
@@ -14,6 +14,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera.
obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
+obj-$(CONFIG_SPI_BCM63XX) += bcm63xx_spi.o
obj-$(CONFIG_SPI_BFIN) += spi-bfin5xx.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
--- /dev/null
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
@@ -0,0 +1,85 @@
+#ifndef BCM63XX_DEV_SPI_H
+#define BCM63XX_DEV_SPI_H
+
+#include <linux/types.h>
+#include <bcm63xx_io.h>
+#include <bcm63xx_regs.h>
+
+int __init bcm63xx_spi_register(void);
+
+struct bcm63xx_spi_pdata {
+ unsigned int fifo_size;
+ int bus_num;
+ int num_chipselect;
+ u32 speed_hz;
+};
+
+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,
+};
+
+#define __GEN_SPI_RSET_BASE(__cpu, __rset) \
+ case SPI_## __rset: \
+ return SPI_BCM_## __cpu ##_SPI_## __rset;
+
+#define __GEN_SPI_RSET(__cpu) \
+ switch (reg) { \
+ __GEN_SPI_RSET_BASE(__cpu, CMD) \
+ __GEN_SPI_RSET_BASE(__cpu, INT_STATUS) \
+ __GEN_SPI_RSET_BASE(__cpu, INT_MASK_ST) \
+ __GEN_SPI_RSET_BASE(__cpu, INT_MASK) \
+ __GEN_SPI_RSET_BASE(__cpu, ST) \
+ __GEN_SPI_RSET_BASE(__cpu, CLK_CFG) \
+ __GEN_SPI_RSET_BASE(__cpu, FILL_BYTE) \
+ __GEN_SPI_RSET_BASE(__cpu, MSG_TAIL) \
+ __GEN_SPI_RSET_BASE(__cpu, RX_TAIL) \
+ __GEN_SPI_RSET_BASE(__cpu, MSG_CTL) \
+ __GEN_SPI_RSET_BASE(__cpu, MSG_DATA) \
+ __GEN_SPI_RSET_BASE(__cpu, RX_DATA) \
+ }
+
+#define __GEN_SPI_REGS_TABLE(__cpu) \
+ [SPI_CMD] = SPI_BCM_## __cpu ##_SPI_CMD, \
+ [SPI_INT_STATUS] = SPI_BCM_## __cpu ##_SPI_INT_STATUS, \
+ [SPI_INT_MASK_ST] = SPI_BCM_## __cpu ##_SPI_INT_MASK_ST, \
+ [SPI_INT_MASK] = SPI_BCM_## __cpu ##_SPI_INT_MASK, \
+ [SPI_ST] = SPI_BCM_## __cpu ##_SPI_ST, \
+ [SPI_CLK_CFG] = SPI_BCM_## __cpu ##_SPI_CLK_CFG, \
+ [SPI_FILL_BYTE] = SPI_BCM_## __cpu ##_SPI_FILL_BYTE, \
+ [SPI_MSG_TAIL] = SPI_BCM_## __cpu ##_SPI_MSG_TAIL, \
+ [SPI_RX_TAIL] = SPI_BCM_## __cpu ##_SPI_RX_TAIL, \
+ [SPI_MSG_CTL] = SPI_BCM_## __cpu ##_SPI_MSG_CTL, \
+ [SPI_MSG_DATA] = SPI_BCM_## __cpu ##_SPI_MSG_DATA, \
+ [SPI_RX_DATA] = SPI_BCM_## __cpu ##_SPI_RX_DATA,
+
+static inline unsigned long bcm63xx_spireg(enum bcm63xx_regs_spi reg)
+{
+#ifdef BCMCPU_RUNTIME_DETECT
+ extern const unsigned long *bcm63xx_regs_spi;
+ return bcm63xx_regs_spi[reg];
+#else
+#ifdef CONFIG_BCM63XX_CPU_6338
+ __GEN_SPI_RSET(6338)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6348
+ __GEN_SPI_RSET(6348)
+#endif
+#ifdef CONFIG_BCM63XX_CPU_6358
+ __GEN_SPI_RSET(6358)
+#endif
+#endif
+ return 0;
+}
+
+#endif /* BCM63XX_DEV_SPI_H */
--- a/arch/mips/bcm63xx/Makefile
+++ b/arch/mips/bcm63xx/Makefile
@@ -1,5 +1,5 @@
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-dsp.o dev-enet.o dev-pcmcia.o dev-spi.o dev-uart.o \
dev-usb-ehci.o dev-usb-ohci.o dev-wdt.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -29,6 +29,7 @@
#include <bcm63xx_dev_pcmcia.h>
#include <bcm63xx_dev_usb_ohci.h>
#include <bcm63xx_dev_usb_ehci.h>
+#include <bcm63xx_dev_spi.h>
#include <board_bcm963xx.h>
#include <bcm_tag.h>
@@ -972,6 +973,8 @@ int __init board_register_devices(void)
if (board.num_spis)
spi_register_board_info(board.spis, board.num_spis);
+ bcm63xx_spi_register();
+
/* read base address of boot chip select (0) */
val = bcm_mpi_readl(MPI_CSBASE_REG(0));
val &= MPI_CSBASE_BASE_MASK;

@ -50,17 +50,17 @@ Subject: [PATCH 30/63] bcm63xx_enet: split dma registers access.
if (ret)
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
@@ -136,7 +136,9 @@ enum bcm63xx_regs_set {
#define RSET_DSL_SIZE 4096
#define RSET_WDT_SIZE 12
@@ -139,7 +139,9 @@ enum bcm63xx_regs_set {
#define BCM_6358_RSET_SPI_SIZE 1804
#define BCM_6368_RSET_SPI_SIZE 1804
#define RSET_ENET_SIZE 2048
-#define RSET_ENETDMA_SIZE 2048
+#define RSET_ENETDMA_SIZE 256
+#define RSET_ENETDMAC_SIZE(chans) (16 * (chans))
+#define RSET_ENETDMAS_SIZE(chans) (16 * (chans))
#define RSET_ENETSW_SIZE 65536
#define RSET_SPI_SIZE 256
#define RSET_UART_SIZE 24
#define RSET_UDC_SIZE 256
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -41,8 +41,8 @@ static int copybreak __read_mostly = 128

Loading…
Cancel
Save