spi: rcar: add Renesas QSPI support on RSPI
authorHiep Cao Minh <cm-hiep@jinso.co.jp>
Tue, 3 Sep 2013 04:10:26 +0000 (13:10 +0900)
committerMark Brown <broonie@linaro.org>
Mon, 16 Sep 2013 23:22:50 +0000 (00:22 +0100)
The R8A7790 has QSPI module which is very similar to RSPI.
This patch adds into RSPI module together to supports QSPI module.

Signed-off-by: Hiep Cao Minh <cm-hiep@jinso.co.jp>
Signed-off-by: Mark Brown <broonie@linaro.org>
drivers/spi/Kconfig
drivers/spi/spi-rspi.c
include/linux/spi/rspi.h

index b9c53cc40e1fa487dd3d73cd9c83d713a3334e6a..738facf90597815825ce030f3b315a800ece3649 100644 (file)
@@ -369,7 +369,7 @@ config SPI_PXA2XX_PCI
 
 config SPI_RSPI
        tristate "Renesas RSPI controller"
-       depends on SUPERH && SH_DMAE_BASE
+       depends on (SUPERH || ARCH_SHMOBILE) && SH_DMAE_BASE
        help
          SPI driver for Renesas RSPI blocks.
 
index 8719206a03a00e59a7dea523afe7f6c841745d50..4c8dbac11b4252465b7d5d118529a25e1a1b2693 100644 (file)
 #define RSPI_SPCMD6            0x1c
 #define RSPI_SPCMD7            0x1e
 
+/*qspi only */
+#define QSPI_SPBFCR            0x18
+#define QSPI_SPBDCR            0x1a
+#define QSPI_SPBMUL0           0x1c
+#define QSPI_SPBMUL1           0x20
+#define QSPI_SPBMUL2           0x24
+#define QSPI_SPBMUL3           0x28
+
 /* SPCR */
 #define SPCR_SPRIE             0x80
 #define SPCR_SPE               0x40
 #define SPCMD_LSBF             0x1000
 #define SPCMD_SPB_MASK         0x0f00
 #define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK)
+#define SPCMD_SPB_8BIT         0x0000  /* qspi only */
+#define SPCMD_SPB_16BIT                0x0100
 #define SPCMD_SPB_20BIT                0x0000
 #define SPCMD_SPB_24BIT                0x0100
 #define SPCMD_SPB_32BIT                0x0200
 #define SPCMD_CPOL             0x0002
 #define SPCMD_CPHA             0x0001
 
+/* SPBFCR */
+#define SPBFCR_TXRST           0x80    /* qspi only */
+#define SPBFCR_RXRST           0x40    /* qspi only */
+
 struct rspi_data {
        void __iomem *addr;
        u32 max_speed_hz;
@@ -145,6 +159,7 @@ struct rspi_data {
        spinlock_t lock;
        struct clk *clk;
        unsigned char spsr;
+       const struct spi_ops *ops;
 
        /* for dmaengine */
        struct dma_chan *chan_tx;
@@ -165,6 +180,11 @@ static void rspi_write16(struct rspi_data *rspi, u16 data, u16 offset)
        iowrite16(data, rspi->addr + offset);
 }
 
+static void rspi_write32(struct rspi_data *rspi, u32 data, u16 offset)
+{
+       iowrite32(data, rspi->addr + offset);
+}
+
 static u8 rspi_read8(struct rspi_data *rspi, u16 offset)
 {
        return ioread8(rspi->addr + offset);
@@ -175,17 +195,98 @@ static u16 rspi_read16(struct rspi_data *rspi, u16 offset)
        return ioread16(rspi->addr + offset);
 }
 
-static unsigned char rspi_calc_spbr(struct rspi_data *rspi)
+/* optional functions */
+struct spi_ops {
+       int (*set_config_register)(struct rspi_data *rspi, int access_size);
+};
+
+/*
+ * functions for RSPI
+ */
+static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
 {
-       int tmp;
-       unsigned char spbr;
+       int spbr;
+
+       /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
+       rspi_write8(rspi, 0x00, RSPI_SPPCR);
 
-       tmp = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
-       spbr = clamp(tmp, 0, 255);
+       /* Sets transfer bit rate */
+       spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
+       rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
+
+       /* Sets number of frames to be used: 1 frame */
+       rspi_write8(rspi, 0x00, RSPI_SPDCR);
 
-       return spbr;
+       /* Sets RSPCK, SSL, next-access delay value */
+       rspi_write8(rspi, 0x00, RSPI_SPCKD);
+       rspi_write8(rspi, 0x00, RSPI_SSLND);
+       rspi_write8(rspi, 0x00, RSPI_SPND);
+
+       /* Sets parity, interrupt mask */
+       rspi_write8(rspi, 0x00, RSPI_SPCR2);
+
+       /* Sets SPCMD */
+       rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP,
+                    RSPI_SPCMD0);
+
+       /* Sets RSPI mode */
+       rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
+
+       return 0;
 }
 
+/*
+ * functions for QSPI
+ */
+static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
+{
+       u16 spcmd;
+       int spbr;
+
+       /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
+       rspi_write8(rspi, 0x00, RSPI_SPPCR);
+
+       /* Sets transfer bit rate */
+       spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
+       rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);
+
+       /* Sets number of frames to be used: 1 frame */
+       rspi_write8(rspi, 0x00, RSPI_SPDCR);
+
+       /* Sets RSPCK, SSL, next-access delay value */
+       rspi_write8(rspi, 0x00, RSPI_SPCKD);
+       rspi_write8(rspi, 0x00, RSPI_SSLND);
+       rspi_write8(rspi, 0x00, RSPI_SPND);
+
+       /* Data Length Setting */
+       if (access_size == 8)
+               spcmd = SPCMD_SPB_8BIT;
+       else if (access_size == 16)
+               spcmd = SPCMD_SPB_16BIT;
+       else if (access_size == 32)
+               spcmd = SPCMD_SPB_32BIT;
+
+       spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SSLKP | SPCMD_SPNDEN;
+
+       /* Resets transfer data length */
+       rspi_write32(rspi, 0, QSPI_SPBMUL0);
+
+       /* Resets transmit and receive buffer */
+       rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
+       /* Sets buffer to allow normal operation */
+       rspi_write8(rspi, 0x00, QSPI_SPBFCR);
+
+       /* Sets SPCMD */
+       rspi_write16(rspi, spcmd, RSPI_SPCMD0);
+
+       /* Enables SPI function in a master mode */
+       rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);
+
+       return 0;
+}
+
+#define set_config_register(spi, n) spi->ops->set_config_register(spi, n)
+
 static void rspi_enable_irq(struct rspi_data *rspi, u8 enable)
 {
        rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR);
@@ -220,35 +321,6 @@ static void rspi_negate_ssl(struct rspi_data *rspi)
        rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
 }
 
-static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
-{
-       /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
-       rspi_write8(rspi, 0x00, RSPI_SPPCR);
-
-       /* Sets transfer bit rate */
-       rspi_write8(rspi, rspi_calc_spbr(rspi), RSPI_SPBR);
-
-       /* Sets number of frames to be used: 1 frame */
-       rspi_write8(rspi, 0x00, RSPI_SPDCR);
-
-       /* Sets RSPCK, SSL, next-access delay value */
-       rspi_write8(rspi, 0x00, RSPI_SPCKD);
-       rspi_write8(rspi, 0x00, RSPI_SSLND);
-       rspi_write8(rspi, 0x00, RSPI_SPND);
-
-       /* Sets parity, interrupt mask */
-       rspi_write8(rspi, 0x00, RSPI_SPCR2);
-
-       /* Sets SPCMD */
-       rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP,
-                    RSPI_SPCMD0);
-
-       /* Sets RSPI mode */
-       rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
-
-       return 0;
-}
-
 static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
                         struct spi_transfer *t)
 {
@@ -616,7 +688,7 @@ static int rspi_setup(struct spi_device *spi)
                spi->bits_per_word = 8;
        rspi->max_speed_hz = spi->max_speed_hz;
 
-       rspi_set_config_register(rspi, 8);
+       set_config_register(rspi, 8);
 
        return 0;
 }
@@ -745,7 +817,16 @@ static int rspi_probe(struct platform_device *pdev)
        struct rspi_data *rspi;
        int ret, irq;
        char clk_name[16];
-
+       struct rspi_plat_data *rspi_pd = pdev->dev.platform_data;
+       const struct spi_ops *ops;
+       const struct platform_device_id *id_entry = pdev->id_entry;
+
+       ops = (struct spi_ops *)id_entry->driver_data;
+       /* ops parameter check */
+       if (!ops->set_config_register) {
+               dev_err(&pdev->dev, "there is no set_config_register\n");
+               return -ENODEV;
+       }
        /* get base addr */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (unlikely(res == NULL)) {
@@ -767,7 +848,7 @@ static int rspi_probe(struct platform_device *pdev)
 
        rspi = spi_master_get_devdata(master);
        platform_set_drvdata(pdev, rspi);
-
+       rspi->ops = ops;
        rspi->master = master;
        rspi->addr = ioremap(res->start, resource_size(res));
        if (rspi->addr == NULL) {
@@ -776,7 +857,7 @@ static int rspi_probe(struct platform_device *pdev)
                goto error1;
        }
 
-       snprintf(clk_name, sizeof(clk_name), "rspi%d", pdev->id);
+       snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
        rspi->clk = clk_get(&pdev->dev, clk_name);
        if (IS_ERR(rspi->clk)) {
                dev_err(&pdev->dev, "cannot get clock\n");
@@ -790,7 +871,10 @@ static int rspi_probe(struct platform_device *pdev)
        INIT_WORK(&rspi->ws, rspi_work);
        init_waitqueue_head(&rspi->wait);
 
-       master->num_chipselect = 2;
+       master->num_chipselect = rspi_pd->num_chipselect;
+       if (!master->num_chipselect)
+               master->num_chipselect = 2; /* default */
+
        master->bus_num = pdev->id;
        master->setup = rspi_setup;
        master->transfer = rspi_transfer;
@@ -832,11 +916,28 @@ error1:
        return ret;
 }
 
+static struct spi_ops rspi_ops = {
+       .set_config_register =          rspi_set_config_register,
+};
+
+static struct spi_ops qspi_ops = {
+       .set_config_register =          qspi_set_config_register,
+};
+
+static struct platform_device_id spi_driver_ids[] = {
+       { "rspi",       (kernel_ulong_t)&rspi_ops },
+       { "qspi",       (kernel_ulong_t)&qspi_ops },
+       {},
+};
+
+MODULE_DEVICE_TABLE(platform, spi_driver_ids);
+
 static struct platform_driver rspi_driver = {
        .probe =        rspi_probe,
        .remove =       rspi_remove,
+       .id_table =     spi_driver_ids,
        .driver         = {
-               .name = "rspi",
+               .name = "renesas_spi",
                .owner  = THIS_MODULE,
        },
 };
index 900f0e328235790d02f7a38147967b1cfc3631d2..a25bd6f65e7f7fd2a7d21bf4e909016aaeeac959 100644 (file)
@@ -26,6 +26,8 @@ struct rspi_plat_data {
        unsigned int dma_rx_id;
 
        unsigned dma_width_16bit:1;     /* DMAC read/write width = 16-bit */
+
+       u16 num_chipselect;
 };
 
 #endif