SPI: DUAL/QUAD support

yuhang wang wangyuhang2014 at gmail.com
Thu Jul 4 07:36:48 EDT 2013


Hi Mark,

Thanks for your reply.
I have added the kerneldoc into the patch below to explain the "DUAL"
and "QUAD" modes.
Hope for your suggestions.

Documentation/spi/spi-dual_quad |  102 +++++++++++++++++++++++++++++++++++++++
 drivers/mtd/devices/m25p80.c    |    2 +
 drivers/spi/spi.c               |    2 +
 include/linux/spi/spi.h         |    8 +++
 4 files changed, 114 insertions(+)
 create mode 100644 Documentation/spi/spi-dual_quad

diff --git a/Documentation/spi/spi-dual_quad b/Documentation/spi/spi-dual_quad
new file mode 100644
index 0000000..06a2f9e
--- /dev/null
+++ b/Documentation/spi/spi-dual_quad
@@ -0,0 +1,102 @@
+spi-dual_quad: make spi support DUAL/QUAD
+============================================
+
+Description
+----------------------
+DUAL/QUAD means spi can transfer in 2bits/4bits at the same time.
+These spi controllers provide 8 data lines(4-tx and 4-rx). User can
+choose tranfer mode(SINGLE/DUAL/QUAD) by setting the certain register.
+Though SPI is a serial interface, some spi controllers can support
+transmitting and receiving in DUAL and QUAD modes aimed to improve
+the performance. Also as spi slave lots of flashes do support this attribute,
+such as serial-norflash in spansion company.
+
+Serial-flash such as s25fl129p in spansion company.
+In common way, the flash has two data pins(IO0,IO1) supporting SINGLE/DUAL.
+The flash also can work in QUAD mode, there are still other two
pins(HOLD,W#)which
+in other usage will be regarded as data pins.
+
+The members added below is used to provide the transfer information from slave
+to master. Thus spi controller driver can distinguish the transfer mode(SINGLE
+/DUAL/QUAD) and set the certain controlling register.
+
+
+Members added
+----------------------
+struct spi_device {
++       u8     rx_bitwidth;
++       u8     tx_bitwidth;
+}
+
+struct spi_transfer {
++       u8     bitwidth;
++#define        SPI_BITWIDTH_SINGLE     0x01; /* 1bit transfer */
++#define        SPI_BITWIDTH_DUAL       0x02; /* 2bits transfer */
++#define        SPI_BITWIDTH_QUAD       0x03; /* 4bits transfer */
+}
+
+struct spi_board_info {
++       u8     rx_bitwidth;
++       u8     tx_bitwidth;
+}
+
+
+How to use the added members
+----------------------
+
+DECLARE SLAVE DEVICES
+
+Normally your arch/.../mach-*/board-*.c files would provide a small table
+listing the SPI devices on each board.  Details refered to "spi-summary".
+At the same time, if your slave device support DUAL/QUAD transfer, you can
+set as below:
+
+       static struct spi_board_info spi_board_info[] __initdata = {
+       {
+               .modalias       = "xxxxx",
+               .......
+               .chip_select    = 0,
+               .rx_bitwidth = SPI_BITWIDTH_DUAL,
+               .tx_bitwidth = SPI_BITWIDTH_QUAD,
+       },
+       };
+
+ORGANISE SPI PACKAGE
+
+When your slave is registered by:
+
+       spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+rx_bitwidth and tx_bitwidth members will be delivered into "struct spi_device".
+Thus the flash driver can notice the tranfer mode that user has appointed.
+Flash driver receives the data from the uplayer and organise the spi_transfer
+package as below:
+
+       ......
+       struct spi_transfer t[2];
+       struct spi_message m;
+       spi_message_init(&m);
+       memset(t, 0, (sizeof t));
+       ......
+       t[0].rx_buf = buf;
+       t[0].len = len;
+       t[0].bitwidth = spi->rx_bitwidth/spi->tx_bitwidth;
+       spi_message_add_tail(&t[0], &m);
+       ......
+       spi_sync(spi, &m);
+       ......
+
+finally, spi controller driver will deal with the spi_tranfer package.
+Controller driver will pick the bitwidth member out due to which set
the transfer
+mode register.
+
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 5b6b072..1411678 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -354,6 +354,7 @@ static int m25p80_read(struct mtd_info *mtd,
loff_t from, size_t len,

        t[1].rx_buf = buf;
        t[1].len = len;
+       t[1].bitwidth = flash->spi->rx_bitwidth;
        spi_message_add_tail(&t[1], &m);

        mutex_lock(&flash->lock);
@@ -409,6 +410,7 @@ static int m25p80_write(struct mtd_info *mtd,
loff_t to, size_t len,
        spi_message_add_tail(&t[0], &m);

        t[1].tx_buf = buf;
+       t[1].bitwidth = flash->spi->tx_bitwidth;
        spi_message_add_tail(&t[1], &m);

        mutex_lock(&flash->lock);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 004b10f..cd99022 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -452,6 +452,8 @@ struct spi_device *spi_new_device(struct spi_master *master,
        proxy->irq = chip->irq;
        strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
        proxy->dev.platform_data = (void *) chip->platform_data;
+       proxy->rx_bitwidth = chip->rx_bitwidth;
+       proxy->tx_bitwidth = chip->tx_bitwidth;
        proxy->controller_data = chip->controller_data;
        proxy->controller_state = NULL;

diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 38c2b92..ddcf308 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -93,6 +93,8 @@ struct spi_device {
        void                    *controller_data;
        char                    modalias[SPI_NAME_SIZE];
        int                     cs_gpio;        /* chip select gpio */
+       u8                      rx_bitwidth;
+       u8                      tx_bitwidth;

        /*
         * likely need more hooks for more protocol options affecting how
@@ -511,6 +513,10 @@ struct spi_transfer {
        dma_addr_t      rx_dma;

        unsigned        cs_change:1;
+       u8              bitwidth;
+#define        SPI_BITWIDTH_SINGLE     0x01; /* 1bit transfer */
+#define        SPI_BITWIDTH_DUAL       0x02; /* 2bits transfer */
+#define        SPI_BITWIDTH_QUAD       0x03; /* 4bits transfer */
        u8              bits_per_word;
        u16             delay_usecs;
        u32             speed_hz;
@@ -859,6 +865,8 @@ struct spi_board_info {
         * where the default of SPI_CS_HIGH = 0 is wrong.
         */
        u8              mode;
+       u8              rx_bitwidth;
+       u8              tx_bitwidth;

        /* ... may need additional spi_device chip config data here.
         * avoid stuff protocol drivers can set; but include stuff

--
1.7.9.5

Best regards



More information about the linux-arm-kernel mailing list