[PATCH v2 4/5] spi: bcm-mspi: Make BCMA optional to support non-BCMA chips

From: Jonathan Richardson
Date: Wed Apr 08 2015 - 14:03:51 EST


The Broadcom MSPI controller is used on various chips. The driver only
supported BCM53xx chips with BCMA (an AMBA bus variant). It now supports
both BCMA MSPI and non-BCMA MSPI. To do this the following changes were
made:

- A new config for non-BCMA chips has been added.
- Common code between the BCMA and non BCMA version are shared.
- Function pointers to set read/write functions to abstract bcma
and non-bcma versions are provided.
- DT is now mandatory. Hard coded SPI devices are removed and must be
set in DT.
- Remove function was unnecessary and removed.

Signed-off-by: Jonathan Richardson <jonathar@xxxxxxxxxxxx>
---
drivers/spi/Kconfig | 5 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-bcm-mspi.c | 228 ++++++++++++++++++++++++++++++++------------
3 files changed, 171 insertions(+), 63 deletions(-)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 766e08d..23f2357 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -120,6 +120,11 @@ config SPI_BCMA_MSPI
help
Enable support for the Broadcom BCMA MSPI controller.

+config SPI_BCM_MSPI
+ tristate "Broadcom MSPI controller"
+ help
+ Enable support for the Broadcom MSPI controller.
+
config SPI_BCM63XX
tristate "Broadcom BCM63xx SPI controller"
depends on BCM63XX
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 6b58100..36872d2 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
obj-$(CONFIG_SPI_BCMA_MSPI) += spi-bcm-mspi.o
+obj-$(CONFIG_SPI_BCM_MSPI) += spi-bcm-mspi.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
diff --git a/drivers/spi/spi-bcm-mspi.c b/drivers/spi/spi-bcm-mspi.c
index 502227d..32bb1f0 100644
--- a/drivers/spi/spi-bcm-mspi.c
+++ b/drivers/spi/spi-bcm-mspi.c
@@ -11,11 +11,13 @@
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
+#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/bcma/bcma.h>
#include <linux/spi/spi.h>
+#include <linux/of.h>

#include "spi-bcm-mspi.h"

@@ -25,22 +27,17 @@
#define BCM_MSPI_SPE_TIMEOUT_MS 80

struct bcm_mspi {
+#ifdef CONFIG_SPI_BCMA_MSPI
struct bcma_device *core;
- struct spi_master *master;
+#endif

+ void __iomem *base;
+ struct spi_master *master;
size_t read_offset;
-};
-
-static inline u32 bcm_mspi_read(struct bcm_mspi *mspi, u16 offset)
-{
- return bcma_read32(mspi->core, offset);
-}

-static inline void bcm_mspi_write(struct bcm_mspi *mspi, u16 offset,
- u32 value)
-{
- bcma_write32(mspi->core, offset, value);
-}
+ void (*mspi_write)(struct bcm_mspi *mspi, u16 offset, u32 value);
+ u32 (*mspi_read)(struct bcm_mspi *mspi, u16 offset);
+};

static inline unsigned int bcm_mspi_calc_timeout(size_t len)
{
@@ -56,7 +53,7 @@ static int bcm_mspi_wait(struct bcm_mspi *mspi, unsigned int timeout_ms)
/* SPE bit has to be 0 before we read MSPI STATUS */
deadline = jiffies + BCM_MSPI_SPE_TIMEOUT_MS * HZ / 1000;
do {
- tmp = bcm_mspi_read(mspi, MSPI_SPCR2);
+ tmp = mspi->mspi_read(mspi, MSPI_SPCR2);
if (!(tmp & MSPI_SPCR2_SPE))
break;
udelay(5);
@@ -68,9 +65,9 @@ static int bcm_mspi_wait(struct bcm_mspi *mspi, unsigned int timeout_ms)
/* Check status */
deadline = jiffies + timeout_ms * HZ / 1000;
do {
- tmp = bcm_mspi_read(mspi, MSPI_STATUS);
+ tmp = mspi->mspi_read(mspi, MSPI_STATUS);
if (tmp & MSPI_STATUS_SPIF) {
- bcm_mspi_write(mspi, MSPI_STATUS, 0);
+ mspi->mspi_write(mspi, MSPI_STATUS, 0);
return 0;
}

@@ -79,7 +76,7 @@ static int bcm_mspi_wait(struct bcm_mspi *mspi, unsigned int timeout_ms)
} while (!time_after_eq(jiffies, deadline));

spi_timeout:
- bcm_mspi_write(mspi, MSPI_STATUS, 0);
+ mspi->mspi_write(mspi, MSPI_STATUS, 0);

pr_err("Timeout waiting for SPI to be ready!\n");

@@ -94,7 +91,7 @@ static void bcm_mspi_buf_write(struct bcm_mspi *mspi, u8 *w_buf,

for (i = 0; i < len; i++) {
/* Transmit Register File MSB */
- bcm_mspi_write(mspi, MSPI_TXRAM + 4 * (i * 2),
+ mspi->mspi_write(mspi, MSPI_TXRAM + 4 * (i * 2),
(unsigned int)w_buf[i]);
}

@@ -105,28 +102,28 @@ static void bcm_mspi_buf_write(struct bcm_mspi *mspi, u8 *w_buf,
tmp &= ~MSPI_CDRAM_CONT;
tmp &= ~0x1;
/* Command Register File */
- bcm_mspi_write(mspi, MSPI_CDRAM + 4 * i, tmp);
+ mspi->mspi_write(mspi, MSPI_CDRAM + 4 * i, tmp);
}

/* Set queue pointers */
- bcm_mspi_write(mspi, MSPI_NEWQP, 0);
- bcm_mspi_write(mspi, MSPI_ENDQP, len - 1);
+ mspi->mspi_write(mspi, MSPI_NEWQP, 0);
+ mspi->mspi_write(mspi, MSPI_ENDQP, len - 1);

if (cont)
- bcm_mspi_write(mspi, MSPI_WRITE_LOCK, 1);
+ mspi->mspi_write(mspi, MSPI_WRITE_LOCK, 1);

/* Start SPI transfer */
- tmp = bcm_mspi_read(mspi, MSPI_SPCR2);
+ tmp = mspi->mspi_read(mspi, MSPI_SPCR2);
tmp |= MSPI_SPCR2_SPE;
if (cont)
tmp |= MSPI_SPCR2_CONT_AFTER_CMD;
- bcm_mspi_write(mspi, MSPI_SPCR2, tmp);
+ mspi->mspi_write(mspi, MSPI_SPCR2, tmp);

/* Wait for SPI to finish */
bcm_mspi_wait(mspi, bcm_mspi_calc_timeout(len));

if (!cont)
- bcm_mspi_write(mspi, MSPI_WRITE_LOCK, 0);
+ mspi->mspi_write(mspi, MSPI_WRITE_LOCK, 0);

mspi->read_offset = len;
}
@@ -144,34 +141,35 @@ static void bcm_mspi_buf_read(struct bcm_mspi *mspi, u8 *r_buf,
tmp &= ~MSPI_CDRAM_CONT;
tmp &= ~0x1;
/* Command Register File */
- bcm_mspi_write(mspi, MSPI_CDRAM + 4 * i, tmp);
+ mspi->mspi_write(mspi, MSPI_CDRAM + 4 * i, tmp);
}

/* Set queue pointers */
- bcm_mspi_write(mspi, MSPI_NEWQP, 0);
- bcm_mspi_write(mspi, MSPI_ENDQP, mspi->read_offset + len - 1);
+ mspi->mspi_write(mspi, MSPI_NEWQP, 0);
+ mspi->mspi_write(mspi, MSPI_ENDQP,
+ mspi->read_offset + len - 1);

if (cont)
- bcm_mspi_write(mspi, MSPI_WRITE_LOCK, 1);
+ mspi->mspi_write(mspi, MSPI_WRITE_LOCK, 1);

/* Start SPI transfer */
- tmp = bcm_mspi_read(mspi, MSPI_SPCR2);
+ tmp = mspi->mspi_read(mspi, MSPI_SPCR2);
tmp |= MSPI_SPCR2_SPE;
if (cont)
tmp |= MSPI_SPCR2_CONT_AFTER_CMD;
- bcm_mspi_write(mspi, MSPI_SPCR2, tmp);
+ mspi->mspi_write(mspi, MSPI_SPCR2, tmp);

/* Wait for SPI to finish */
bcm_mspi_wait(mspi, bcm_mspi_calc_timeout(len));

if (!cont)
- bcm_mspi_write(mspi, MSPI_WRITE_LOCK, 0);
+ mspi->mspi_write(mspi, MSPI_WRITE_LOCK, 0);

for (i = 0; i < len; ++i) {
int offset = mspi->read_offset + i;

/* Data stored in the transmit register file LSB */
- r_buf[i] = (u8)bcm_mspi_read(mspi,
+ r_buf[i] = (u8)mspi->mspi_read(mspi,
MSPI_RXRAM + 4 * (1 + offset * 2));
}

@@ -216,10 +214,104 @@ static int bcm_mspi_transfer_one(struct spi_master *master,
return 0;
}

-static struct spi_board_info bcm_mspi_info = {
- .modalias = "bcm53xxspiflash",
+/*
+ * Allocate SPI master for both bcma and non bcma bus. The SPI device must be
+ * configured in DT.
+ */
+static struct bcm_mspi *bcm_mspi_init(struct device *dev)
+{
+ struct bcm_mspi *data;
+ struct spi_master *master;
+
+ master = spi_alloc_master(dev, sizeof(*data));
+ if (!master) {
+ dev_err(dev, "error allocating spi_master\n");
+ return 0;
+ }
+
+ data = spi_master_get_devdata(master);
+ data->master = master;
+
+ /* SPI master will always use the SPI device(s) from DT. */
+ master->dev.of_node = dev->of_node;
+ master->transfer_one = bcm_mspi_transfer_one;
+
+ return data;
+}
+
+#ifdef CONFIG_SPI_BCM_MSPI
+
+static const struct of_device_id bcm_mspi_dt[] = {
+ { .compatible = "brcm,mspi" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bcm_mspi_dt);
+
+static inline u32 bcm_mspi_read(struct bcm_mspi *mspi, u16 offset)
+{
+ return readl(mspi->base + offset);
+}
+
+static inline void bcm_mspi_write(struct bcm_mspi *mspi, u16 offset,
+ u32 value)
+{
+ writel(value, mspi->base + offset);
+}
+
+/*
+ * Probe routine for non-bcma devices.
+ */
+static int bcm_mspi_probe(struct platform_device *pdev)
+{
+ struct bcm_mspi *data;
+ struct device *dev = &pdev->dev;
+ int err;
+ struct resource *res;
+
+ dev_info(dev, "BCM MSPI probe\n");
+
+ data = bcm_mspi_init(dev);
+ if (!data)
+ return -ENOMEM;
+
+ /* Map base memory address. */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->base)) {
+ dev_err(&pdev->dev, "unable to map I/O memory\n");
+ err = PTR_ERR(data->base);
+ goto out;
+ }
+
+ data->mspi_read = bcm_mspi_read;
+ data->mspi_write = bcm_mspi_write;
+ platform_set_drvdata(pdev, data);
+
+ err = devm_spi_register_master(dev, data->master);
+ if (err)
+ goto out;
+
+ return 0;
+
+out:
+ spi_master_put(data->master);
+ return err;
+}
+
+static struct platform_driver bcm_mspi_driver = {
+ .driver = {
+ .name = "bcm-mspi",
+ .of_match_table = bcm_mspi_dt,
+ },
+ .probe = bcm_mspi_probe,
};

+module_platform_driver(bcm_mspi_driver);
+
+#endif
+
+#ifdef CONFIG_SPI_BCMA_MSPI
+
static const struct bcma_device_id bcm_mspi_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV,
BCMA_ANY_CLASS),
@@ -227,62 +319,70 @@ static const struct bcma_device_id bcm_mspi_bcma_tbl[] = {
};
MODULE_DEVICE_TABLE(bcma, bcm_mspi_bcma_tbl);

+static const struct of_device_id bcm_bcma_mspi_dt[] = {
+ { .compatible = "brcm,bcma-mspi" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bcm_mspi_dt);
+
+static inline u32 bcm_bcma_mspi_read(struct bcm_mspi *mspi, u16 offset)
+{
+ return bcma_read32(mspi->core, offset);
+}
+
+static inline void bcm_bcma_mspi_write(struct bcm_mspi *mspi, u16 offset,
+ u32 value)
+{
+ bcma_write32(mspi->core, offset, value);
+}
+
+/*
+ * Probe routine for bcma devices.
+ */
static int bcm_mspi_bcma_probe(struct bcma_device *core)
{
struct bcm_mspi *data;
- struct spi_master *master;
int err;

dev_info(&core->dev, "BCM MSPI BCMA probe\n");

if (core->bus->drv_cc.core->id.rev != 42) {
- pr_err("SPI on SoC with unsupported ChipCommon rev\n");
+ dev_err(&core->dev,
+ "SPI on SoC with unsupported ChipCommon rev\n");
return -ENOTSUPP;
}

- master = spi_alloc_master(&core->dev, sizeof(*data));
- if (!master)
+ data = bcm_mspi_init(&core->dev);
+ if (!data)
return -ENOMEM;

- data = spi_master_get_devdata(master);
- data->master = master;
+ data->mspi_read = bcm_bcma_mspi_read;
+ data->mspi_write = bcm_bcma_mspi_write;
data->core = core;

- master->transfer_one = bcm_mspi_transfer_one;
-
bcma_set_drvdata(core, data);

err = devm_spi_register_master(&core->dev, data->master);
if (err) {
- spi_master_put(master);
- bcma_set_drvdata(core, NULL);
- goto out;
+ spi_master_put(data->master);
+ return err;
}

- /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */
- spi_new_device(master, &bcm_mspi_info);
-
-out:
- return err;
-}
-
-static void bcm_mspi_bcma_remove(struct bcma_device *core)
-{
- struct bcm_mspi *mspi = bcma_get_drvdata(core);
-
- spi_unregister_master(mspi->master);
+ return 0;
}

static struct bcma_driver bcm_mspi_bcma_driver = {
.name = KBUILD_MODNAME,
+ .drv = {
+ .of_match_table = bcm_bcma_mspi_dt,
+ },
.id_table = bcm_mspi_bcma_tbl,
.probe = bcm_mspi_bcma_probe,
- .remove = bcm_mspi_bcma_remove,
};

-static int __init bcm_mspi_module_init(void)
+static int __init bcm_mspi_bcma_module_init(void)
{
- int err = 0;
+ int err;

err = bcma_driver_register(&bcm_mspi_bcma_driver);
if (err)
@@ -291,13 +391,15 @@ static int __init bcm_mspi_module_init(void)
return err;
}

-static void __exit bcm_mspi_module_exit(void)
+static void __exit bcm_mspi_bcma_module_exit(void)
{
bcma_driver_unregister(&bcm_mspi_bcma_driver);
}

-module_init(bcm_mspi_module_init);
-module_exit(bcm_mspi_module_exit);
+module_init(bcm_mspi_bcma_module_init);
+module_exit(bcm_mspi_bcma_module_exit);
+
+#endif

MODULE_DESCRIPTION("Broadcom MSPI SPI Controller driver");
MODULE_AUTHOR("RafaÅ MiÅecki <zajec5@xxxxxxxxx>");
--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/