]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
Merge branch 'spi-4.19' into spi-next
authorMark Brown <broonie@kernel.org>
Fri, 10 Aug 2018 16:51:52 +0000 (17:51 +0100)
committerMark Brown <broonie@kernel.org>
Fri, 10 Aug 2018 16:51:52 +0000 (17:51 +0100)
27 files changed:
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt
Documentation/devicetree/bindings/spi/spi-rockchip.txt
Documentation/devicetree/bindings/spi/spi-uniphier.txt [new file with mode: 0644]
drivers/mtd/devices/m25p80.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi-ath79.c
drivers/spi/spi-bitbang.c
drivers/spi/spi-butterfly.c
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-dw.c
drivers/spi/spi-dw.h
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-espi.c
drivers/spi/spi-gpio.c
drivers/spi/spi-img-spfi.c
drivers/spi/spi-imx.c
drivers/spi/spi-lm70llp.c
drivers/spi/spi-mem.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-sh-sci.c
drivers/spi/spi-uniphier.c [new file with mode: 0644]
drivers/spi/spi-xtensa-xtfpga.c
include/linux/spi/adi_spi3.h [deleted file]
include/linux/spi/spi-mem.h
include/linux/spi/spi_bitbang.h

index 204b311e04001075eb6ed3b03807087cebea12e2..642d3fb1ef851b4f588f24730df23b70c79aa161 100644 (file)
@@ -1,8 +1,10 @@
 Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface.
 
 Required properties:
-- compatible : "snps,dw-apb-ssi"
-- reg : The register base for the controller.
+- compatible : "snps,dw-apb-ssi" or "mscc,<soc>-spi", where soc is "ocelot" or
+  "jaguar2"
+- reg : The register base for the controller. For "mscc,<soc>-spi", a second
+  register set is required (named ICPU_CFG:SPI_MST)
 - interrupts : One interrupt, used by the controller.
 - #address-cells : <1>, as required by generic SPI binding.
 - #size-cells : <0>, also as required by generic SPI binding.
index 6e3ffacbba320a756933255fe8100c0103e01cc6..a0edac12d8df5457e6b1031b2adf1519c3db7bcf 100644 (file)
@@ -7,6 +7,7 @@ Required Properties:
 
 - compatible: should be one of the following.
     "rockchip,rv1108-spi" for rv1108 SoCs.
+    "rockchip,px30-spi", "rockchip,rk3066-spi" for px30 SoCs.
     "rockchip,rk3036-spi" for rk3036 SoCS.
     "rockchip,rk3066-spi" for rk3066 SoCs.
     "rockchip,rk3188-spi" for rk3188 SoCs.
diff --git a/Documentation/devicetree/bindings/spi/spi-uniphier.txt b/Documentation/devicetree/bindings/spi/spi-uniphier.txt
new file mode 100644 (file)
index 0000000..504a4ec
--- /dev/null
@@ -0,0 +1,22 @@
+Socionext UniPhier SPI controller driver
+
+UniPhier SoCs have SCSSI which supports SPI single channel.
+
+Required properties:
+ - compatible: should be "socionext,uniphier-scssi"
+ - reg: address and length of the spi master registers
+ - #address-cells: must be <1>, see spi-bus.txt
+ - #size-cells: must be <0>, see spi-bus.txt
+ - clocks: A phandle to the clock for the device.
+ - resets: A phandle to the reset control for the device.
+
+Example:
+
+spi0: spi@54006000 {
+       compatible = "socionext,uniphier-scssi";
+       reg = <0x54006000 0x100>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       clocks = <&peri_clk 11>;
+       resets = <&peri_rst 11>;
+};
index e84563d2067f4fe28c1f0ed21defda049323dd36..aac48800821627b6bf44ecef1216412321182be8 100644 (file)
@@ -202,6 +202,9 @@ static int m25p_probe(struct spi_mem *spimem)
        if (data && data->name)
                nor->mtd.name = data->name;
 
+       if (!nor->mtd.name)
+               nor->mtd.name = spi_mem_get_name(spimem);
+
        /* For some (historical?) reason many platforms provide two different
         * names in flash_platform_data: "name" and "type". Quite often name is
         * set to "m25p80" and then "type" provides a real chip name.
index ad5d68e1dab7cc4b79ac782b4e3593dab1c1b5b4..671d078349cc667e32835ded589b145b3bb7d9a2 100644 (file)
@@ -688,6 +688,19 @@ config SPI_TXX9
        help
          SPI driver for Toshiba TXx9 MIPS SoCs
 
+config SPI_UNIPHIER
+       tristate "Socionext UniPhier SPI Controller"
+       depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
+       help
+         This enables a driver for the Socionext UniPhier SoC SCSSI SPI controller.
+
+         UniPhier SoCs have SCSSI and MCSSI SPI controllers.
+         Every UniPhier SoC has SCSSI which supports single channel.
+         Older UniPhier Pro4/Pro5 also has MCSSI which support multiple channels.
+         This driver supports SCSSI only.
+
+         If your SoC supports SCSSI, say Y here.
+
 config SPI_XCOMM
        tristate "Analog Devices AD-FMCOMMS1-EBZ SPI-I2C-bridge driver"
        depends on I2C
index cb1f4378b87c01745837296e0fb4662200110303..a90d55970036536d4bedeccfe533864ddb02622e 100644 (file)
@@ -101,6 +101,7 @@ spi-thunderx-objs                   := spi-cavium.o spi-cavium-thunderx.o
 obj-$(CONFIG_SPI_THUNDERX)             += spi-thunderx.o
 obj-$(CONFIG_SPI_TOPCLIFF_PCH)         += spi-topcliff-pch.o
 obj-$(CONFIG_SPI_TXX9)                 += spi-txx9.o
+obj-$(CONFIG_SPI_UNIPHIER)             += spi-uniphier.o
 obj-$(CONFIG_SPI_XCOMM)                += spi-xcomm.o
 obj-$(CONFIG_SPI_XILINX)               += spi-xilinx.o
 obj-$(CONFIG_SPI_XLP)                  += spi-xlp.o
index 0719bd48489175a3fa7825e3269bf9ac42fa3770..3f6b657394ded800273b45414e920d28341770b1 100644 (file)
@@ -176,7 +176,7 @@ static void ath79_spi_cleanup(struct spi_device *spi)
 }
 
 static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned int nsecs,
-                              u32 word, u8 bits)
+                              u32 word, u8 bits, unsigned flags)
 {
        struct ath79_spi *sp = ath79_spidev_to_sp(spi);
        u32 ioc = sp->ioc_base;
index 3aa9e6e3dac82d63f1abf58e5b7eb4aacbb8f212..f29176000b8df1b0839f5030d8d046fbd07a8ef1 100644 (file)
 struct spi_bitbang_cs {
        unsigned        nsecs;  /* (clock cycle time)/2 */
        u32             (*txrx_word)(struct spi_device *spi, unsigned nsecs,
-                                       u32 word, u8 bits);
+                                       u32 word, u8 bits, unsigned flags);
        unsigned        (*txrx_bufs)(struct spi_device *,
                                        u32 (*txrx_word)(
                                                struct spi_device *spi,
                                                unsigned nsecs,
-                                               u32 word, u8 bits),
-                                       unsigned, struct spi_transfer *);
+                                               u32 word, u8 bits,
+                                               unsigned flags),
+                                       unsigned, struct spi_transfer *,
+                                       unsigned);
 };
 
 static unsigned bitbang_txrx_8(
        struct spi_device       *spi,
        u32                     (*txrx_word)(struct spi_device *spi,
                                        unsigned nsecs,
-                                       u32 word, u8 bits),
+                                       u32 word, u8 bits,
+                                       unsigned flags),
        unsigned                ns,
-       struct spi_transfer     *t
+       struct spi_transfer     *t,
+       unsigned flags
 ) {
        unsigned                bits = t->bits_per_word;
        unsigned                count = t->len;
@@ -76,7 +80,7 @@ static unsigned bitbang_txrx_8(
 
                if (tx)
                        word = *tx++;
-               word = txrx_word(spi, ns, word, bits);
+               word = txrx_word(spi, ns, word, bits, flags);
                if (rx)
                        *rx++ = word;
                count -= 1;
@@ -88,9 +92,11 @@ static unsigned bitbang_txrx_16(
        struct spi_device       *spi,
        u32                     (*txrx_word)(struct spi_device *spi,
                                        unsigned nsecs,
-                                       u32 word, u8 bits),
+                                       u32 word, u8 bits,
+                                       unsigned flags),
        unsigned                ns,
-       struct spi_transfer     *t
+       struct spi_transfer     *t,
+       unsigned flags
 ) {
        unsigned                bits = t->bits_per_word;
        unsigned                count = t->len;
@@ -102,7 +108,7 @@ static unsigned bitbang_txrx_16(
 
                if (tx)
                        word = *tx++;
-               word = txrx_word(spi, ns, word, bits);
+               word = txrx_word(spi, ns, word, bits, flags);
                if (rx)
                        *rx++ = word;
                count -= 2;
@@ -114,9 +120,11 @@ static unsigned bitbang_txrx_32(
        struct spi_device       *spi,
        u32                     (*txrx_word)(struct spi_device *spi,
                                        unsigned nsecs,
-                                       u32 word, u8 bits),
+                                       u32 word, u8 bits,
+                                       unsigned flags),
        unsigned                ns,
-       struct spi_transfer     *t
+       struct spi_transfer     *t,
+       unsigned flags
 ) {
        unsigned                bits = t->bits_per_word;
        unsigned                count = t->len;
@@ -128,7 +136,7 @@ static unsigned bitbang_txrx_32(
 
                if (tx)
                        word = *tx++;
-               word = txrx_word(spi, ns, word, bits);
+               word = txrx_word(spi, ns, word, bits, flags);
                if (rx)
                        *rx++ = word;
                count -= 4;
@@ -235,8 +243,24 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
 {
        struct spi_bitbang_cs   *cs = spi->controller_state;
        unsigned                nsecs = cs->nsecs;
+       struct spi_bitbang      *bitbang;
+
+       bitbang = spi_master_get_devdata(spi->master);
+       if (bitbang->set_line_direction) {
+               int err;
 
-       return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
+               err = bitbang->set_line_direction(spi, !!(t->tx_buf));
+               if (err < 0)
+                       return err;
+       }
+
+       if (spi->mode & SPI_3WIRE) {
+               unsigned flags;
+
+               flags = t->tx_buf ? SPI_MASTER_NO_RX : SPI_MASTER_NO_TX;
+               return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, flags);
+       }
+       return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, 0);
 }
 
 /*----------------------------------------------------------------------*/
index 22a31e4a1a11b84d146e9614acf4624046237e40..1a35102158410d356617835a7dd7ddb3d9f62689 100644 (file)
@@ -144,9 +144,9 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
 
 static u32
 butterfly_txrx_word_mode0(struct spi_device *spi, unsigned nsecs, u32 word,
-                         u8 bits)
+                         u8 bits, unsigned flags)
 {
-       return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
 }
 
 /*----------------------------------------------------------------------*/
index d25cc4037e239d0df386a06253049dd25a79b2b2..e80f60ed6fdf73d4cac750898eec8ef605d30694 100644 (file)
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
 #include <linux/scatterlist.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/of_platform.h>
 #include <linux/property.h>
+#include <linux/regmap.h>
 
 #include "spi-dw.h"
 
 struct dw_spi_mmio {
        struct dw_spi  dws;
        struct clk     *clk;
+       void           *priv;
 };
 
+#define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL      0x24
+#define OCELOT_IF_SI_OWNER_MASK                        GENMASK(5, 4)
+#define OCELOT_IF_SI_OWNER_OFFSET              4
+#define MSCC_IF_SI_OWNER_SISL                  0
+#define MSCC_IF_SI_OWNER_SIBM                  1
+#define MSCC_IF_SI_OWNER_SIMC                  2
+
+#define MSCC_SPI_MST_SW_MODE                   0x14
+#define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE  BIT(13)
+#define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x)      (x << 5)
+
+struct dw_spi_mscc {
+       struct regmap       *syscon;
+       void __iomem        *spi_mst;
+};
+
+/*
+ * The Designware SPI controller (referred to as master in the documentation)
+ * automatically deasserts chip select when the tx fifo is empty. The chip
+ * selects then needs to be either driven as GPIOs or, for the first 4 using the
+ * the SPI boot controller registers. the final chip select is an OR gate
+ * between the Designware SPI controller and the SPI boot controller.
+ */
+static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable)
+{
+       struct dw_spi *dws = spi_master_get_devdata(spi->master);
+       struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
+       struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
+       u32 cs = spi->chip_select;
+
+       if (cs < 4) {
+               u32 sw_mode = MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE;
+
+               if (!enable)
+                       sw_mode |= MSCC_SPI_MST_SW_MODE_SW_SPI_CS(BIT(cs));
+
+               writel(sw_mode, dwsmscc->spi_mst + MSCC_SPI_MST_SW_MODE);
+       }
+
+       dw_spi_set_cs(spi, enable);
+}
+
+static int dw_spi_mscc_init(struct platform_device *pdev,
+                           struct dw_spi_mmio *dwsmmio)
+{
+       struct dw_spi_mscc *dwsmscc;
+       struct resource *res;
+
+       dwsmscc = devm_kzalloc(&pdev->dev, sizeof(*dwsmscc), GFP_KERNEL);
+       if (!dwsmscc)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       dwsmscc->spi_mst = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dwsmscc->spi_mst)) {
+               dev_err(&pdev->dev, "SPI_MST region map failed\n");
+               return PTR_ERR(dwsmscc->spi_mst);
+       }
+
+       dwsmscc->syscon = syscon_regmap_lookup_by_compatible("mscc,ocelot-cpu-syscon");
+       if (IS_ERR(dwsmscc->syscon))
+               return PTR_ERR(dwsmscc->syscon);
+
+       /* Deassert all CS */
+       writel(0, dwsmscc->spi_mst + MSCC_SPI_MST_SW_MODE);
+
+       /* Select the owner of the SI interface */
+       regmap_update_bits(dwsmscc->syscon, MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL,
+                          OCELOT_IF_SI_OWNER_MASK,
+                          MSCC_IF_SI_OWNER_SIMC << OCELOT_IF_SI_OWNER_OFFSET);
+
+       dwsmmio->dws.set_cs = dw_spi_mscc_set_cs;
+       dwsmmio->priv = dwsmscc;
+
+       return 0;
+}
+
 static int dw_spi_mmio_probe(struct platform_device *pdev)
 {
+       int (*init_func)(struct platform_device *pdev,
+                        struct dw_spi_mmio *dwsmmio);
        struct dw_spi_mmio *dwsmmio;
        struct dw_spi *dws;
        struct resource *mem;
@@ -99,6 +181,13 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
                }
        }
 
+       init_func = device_get_match_data(&pdev->dev);
+       if (init_func) {
+               ret = init_func(pdev, dwsmmio);
+               if (ret)
+                       goto out;
+       }
+
        ret = dw_spi_add_host(&pdev->dev, dws);
        if (ret)
                goto out;
@@ -123,6 +212,7 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
 
 static const struct of_device_id dw_spi_mmio_of_match[] = {
        { .compatible = "snps,dw-apb-ssi", },
+       { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_init},
        { /* end of table */}
 };
 MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
index a087464efdd7592b68f27349b8ee693e247edaa9..ac2eb89ef7a5a0616fe915ec96453ac441f589be 100644 (file)
@@ -133,7 +133,7 @@ static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
 }
 #endif /* CONFIG_DEBUG_FS */
 
-static void dw_spi_set_cs(struct spi_device *spi, bool enable)
+void dw_spi_set_cs(struct spi_device *spi, bool enable)
 {
        struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
        struct chip_data *chip = spi_get_ctldata(spi);
@@ -145,6 +145,7 @@ static void dw_spi_set_cs(struct spi_device *spi, bool enable)
        if (!enable)
                dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
 }
+EXPORT_SYMBOL_GPL(dw_spi_set_cs);
 
 /* Return the max entries we can fill into tx fifo */
 static inline u32 tx_max(struct dw_spi *dws)
@@ -507,6 +508,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
        master->dev.of_node = dev->of_node;
        master->flags = SPI_MASTER_GPIO_SS;
 
+       if (dws->set_cs)
+               master->set_cs = dws->set_cs;
+
        /* Basic HW init */
        spi_hw_init(dev, dws);
 
index 2cde2473b3e94ba4e13c327bd4a063f9ce868cb8..0168b08364d5d1a83f598c870e297b452f15b952 100644 (file)
@@ -112,6 +112,7 @@ struct dw_spi {
        u32                     reg_io_width;   /* DR I/O width in bytes */
        u16                     bus_num;
        u16                     num_cs;         /* supported slave numbers */
+       void (*set_cs)(struct spi_device *spi, bool enable);
 
        /* Current message transfer state info */
        size_t                  len;
@@ -244,6 +245,7 @@ struct dw_spi_chip {
        void (*cs_control)(u32 command);
 };
 
+extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
 extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
 extern void dw_spi_remove_host(struct dw_spi *dws);
 extern int dw_spi_suspend_host(struct dw_spi *dws);
index 1c1070114246dd787808c70f437b1313e3a7cd56..7cb3ab0a35a009f619ced0409f449e308fd51096 100644 (file)
@@ -1,17 +1,9 @@
-/*
- * drivers/spi/spi-fsl-dspi.c
- *
- * Copyright 2013 Freescale Semiconductor, Inc.
- *
- * Freescale DSPI driver
- * This file contains a driver for the Freescale DSPI
- *
- * 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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2013 Freescale Semiconductor, Inc.
+//
+// Freescale DSPI driver
+// This file contains a driver for the Freescale DSPI
 
 #include <linux/clk.h>
 #include <linux/delay.h>
 
 #define DRIVER_NAME "fsl-dspi"
 
-#define TRAN_STATE_RX_VOID             0x01
-#define TRAN_STATE_TX_VOID             0x02
-#define TRAN_STATE_WORD_ODD_NUM        0x04
-
 #define DSPI_FIFO_SIZE                 4
 #define DSPI_DMA_BUFSIZE               (DSPI_FIFO_SIZE * 1024)
 
@@ -50,6 +38,7 @@
 #define SPI_MCR_PCSIS          (0x3F << 16)
 #define SPI_MCR_CLR_TXF        (1 << 11)
 #define SPI_MCR_CLR_RXF        (1 << 10)
+#define SPI_MCR_XSPI           (1 << 3)
 
 #define SPI_TCR                        0x08
 #define SPI_TCR_GET_TCNT(x)    (((x) & 0xffff0000) >> 16)
 #define SPI_RSER_TCFQE         0x80000000
 
 #define SPI_PUSHR              0x34
-#define SPI_PUSHR_CONT         (1 << 31)
-#define SPI_PUSHR_CTAS(x)      (((x) & 0x00000003) << 28)
-#define SPI_PUSHR_EOQ          (1 << 27)
-#define SPI_PUSHR_CTCNT        (1 << 26)
-#define SPI_PUSHR_PCS(x)       (((1 << x) & 0x0000003f) << 16)
+#define SPI_PUSHR_CMD_CONT     (1 << 15)
+#define SPI_PUSHR_CONT         (SPI_PUSHR_CMD_CONT << 16)
+#define SPI_PUSHR_CMD_CTAS(x)  (((x) & 0x0003) << 12)
+#define SPI_PUSHR_CTAS(x)      (SPI_PUSHR_CMD_CTAS(x) << 16)
+#define SPI_PUSHR_CMD_EOQ      (1 << 11)
+#define SPI_PUSHR_EOQ          (SPI_PUSHR_CMD_EOQ << 16)
+#define SPI_PUSHR_CMD_CTCNT    (1 << 10)
+#define SPI_PUSHR_CTCNT                (SPI_PUSHR_CMD_CTCNT << 16)
+#define SPI_PUSHR_CMD_PCS(x)   ((1 << x) & 0x003f)
+#define SPI_PUSHR_PCS(x)       (SPI_PUSHR_CMD_PCS(x) << 16)
 #define SPI_PUSHR_TXDATA(x)    ((x) & 0x0000ffff)
 
 #define SPI_PUSHR_SLAVE        0x34
 #define SPI_RXFR2              0x84
 #define SPI_RXFR3              0x88
 
+#define SPI_CTARE(x)           (0x11c + (((x) & 0x3) * 4))
+#define SPI_CTARE_FMSZE(x)     (((x) & 0x1) << 16)
+#define SPI_CTARE_DTCP(x)      ((x) & 0x7ff)
+
+#define SPI_SREX               0x13c
+
 #define SPI_FRAME_BITS(bits)   SPI_CTAR_FMSZ((bits) - 1)
 #define SPI_FRAME_BITS_MASK    SPI_CTAR_FMSZ(0xf)
 #define SPI_FRAME_BITS_16      SPI_CTAR_FMSZ(0xf)
 #define SPI_FRAME_BITS_8       SPI_CTAR_FMSZ(0x7)
 
+#define SPI_FRAME_EBITS(bits)  SPI_CTARE_FMSZE(((bits) - 1) >> 4)
+#define SPI_FRAME_EBITS_MASK   SPI_CTARE_FMSZE(1)
+
+/* Register offsets for regmap_pushr */
+#define PUSHR_CMD              0x0
+#define PUSHR_TX               0x2
+
 #define SPI_CS_INIT            0x01
 #define SPI_CS_ASSERT          0x02
 #define SPI_CS_DROP            0x04
 
-#define SPI_TCR_TCNT_MAX       0x10000
-
 #define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
 
 struct chip_data {
-       u32 mcr_val;
        u32 ctar_val;
        u16 void_write_data;
 };
@@ -135,6 +139,7 @@ enum dspi_trans_mode {
 struct fsl_dspi_devtype_data {
        enum dspi_trans_mode trans_mode;
        u8 max_clock_factor;
+       bool xspi_mode;
 };
 
 static const struct fsl_dspi_devtype_data vf610_data = {
@@ -145,6 +150,7 @@ static const struct fsl_dspi_devtype_data vf610_data = {
 static const struct fsl_dspi_devtype_data ls1021a_v1_data = {
        .trans_mode = DSPI_TCFQ_MODE,
        .max_clock_factor = 8,
+       .xspi_mode = true,
 };
 
 static const struct fsl_dspi_devtype_data ls2085a_data = {
@@ -179,6 +185,7 @@ struct fsl_dspi {
        struct platform_device  *pdev;
 
        struct regmap           *regmap;
+       struct regmap           *regmap_pushr;
        int                     irq;
        struct clk              *clk;
 
@@ -186,32 +193,62 @@ struct fsl_dspi {
        struct spi_message      *cur_msg;
        struct chip_data        *cur_chip;
        size_t                  len;
-       void                    *tx;
-       void                    *tx_end;
+       const void              *tx;
        void                    *rx;
        void                    *rx_end;
-       char                    dataflags;
-       u8                      cs;
        u16                     void_write_data;
-       u32                     cs_change;
+       u16                     tx_cmd;
+       u8                      bits_per_word;
+       u8                      bytes_per_word;
        const struct fsl_dspi_devtype_data *devtype_data;
 
        wait_queue_head_t       waitq;
        u32                     waitflags;
 
-       u32                     spi_tcnt;
        struct fsl_dspi_dma     *dma;
 };
 
-static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word);
+static u32 dspi_pop_tx(struct fsl_dspi *dspi)
+{
+       u32 txdata = 0;
+
+       if (dspi->tx) {
+               if (dspi->bytes_per_word == 1)
+                       txdata = *(u8 *)dspi->tx;
+               else if (dspi->bytes_per_word == 2)
+                       txdata = *(u16 *)dspi->tx;
+               else  /* dspi->bytes_per_word == 4 */
+                       txdata = *(u32 *)dspi->tx;
+               dspi->tx += dspi->bytes_per_word;
+       }
+       dspi->len -= dspi->bytes_per_word;
+       return txdata;
+}
 
-static inline int is_double_byte_mode(struct fsl_dspi *dspi)
+static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
 {
-       unsigned int val;
+       u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
 
-       regmap_read(dspi->regmap, SPI_CTAR(0), &val);
+       if (dspi->len > 0)
+               cmd |= SPI_PUSHR_CMD_CONT;
+       return cmd << 16 | data;
+}
 
-       return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
+static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
+{
+       if (!dspi->rx)
+               return;
+
+       /* Mask of undefined bits */
+       rxdata &= (1 << dspi->bits_per_word) - 1;
+
+       if (dspi->bytes_per_word == 1)
+               *(u8 *)dspi->rx = rxdata;
+       else if (dspi->bytes_per_word == 2)
+               *(u16 *)dspi->rx = rxdata;
+       else /* dspi->bytes_per_word == 4 */
+               *(u32 *)dspi->rx = rxdata;
+       dspi->rx += dspi->bytes_per_word;
 }
 
 static void dspi_tx_dma_callback(void *arg)
@@ -226,19 +263,11 @@ static void dspi_rx_dma_callback(void *arg)
 {
        struct fsl_dspi *dspi = arg;
        struct fsl_dspi_dma *dma = dspi->dma;
-       int rx_word;
        int i;
-       u16 d;
-
-       rx_word = is_double_byte_mode(dspi);
 
-       if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
-               for (i = 0; i < dma->curr_xfer_len; i++) {
-                       d = dspi->dma->rx_dma_buf[i];
-                       rx_word ? (*(u16 *)dspi->rx = d) :
-                                               (*(u8 *)dspi->rx = d);
-                       dspi->rx += rx_word + 1;
-               }
+       if (dspi->rx) {
+               for (i = 0; i < dma->curr_xfer_len; i++)
+                       dspi_push_rx(dspi, dspi->dma->rx_dma_buf[i]);
        }
 
        complete(&dma->cmd_rx_complete);
@@ -249,16 +278,10 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
        struct fsl_dspi_dma *dma = dspi->dma;
        struct device *dev = &dspi->pdev->dev;
        int time_left;
-       int tx_word;
        int i;
 
-       tx_word = is_double_byte_mode(dspi);
-
-       for (i = 0; i < dma->curr_xfer_len; i++) {
-               dspi->dma->tx_dma_buf[i] = dspi_data_to_pushr(dspi, tx_word);
-               if ((dspi->cs_change) && (!dspi->len))
-                       dspi->dma->tx_dma_buf[i] &= ~SPI_PUSHR_CONT;
-       }
+       for (i = 0; i < dma->curr_xfer_len; i++)
+               dspi->dma->tx_dma_buf[i] = dspi_pop_tx_pushr(dspi);
 
        dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
                                        dma->tx_dma_phys,
@@ -327,18 +350,17 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
 {
        struct fsl_dspi_dma *dma = dspi->dma;
        struct device *dev = &dspi->pdev->dev;
+       struct spi_message *message = dspi->cur_msg;
        int curr_remaining_bytes;
        int bytes_per_buffer;
-       int word = 1;
        int ret = 0;
 
-       if (is_double_byte_mode(dspi))
-               word = 2;
        curr_remaining_bytes = dspi->len;
        bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE;
        while (curr_remaining_bytes) {
                /* Check if current transfer fits the DMA buffer */
-               dma->curr_xfer_len = curr_remaining_bytes / word;
+               dma->curr_xfer_len = curr_remaining_bytes
+                       / dspi->bytes_per_word;
                if (dma->curr_xfer_len > bytes_per_buffer)
                        dma->curr_xfer_len = bytes_per_buffer;
 
@@ -348,7 +370,10 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
                        goto exit;
 
                } else {
-                       curr_remaining_bytes -= dma->curr_xfer_len * word;
+                       const int len =
+                               dma->curr_xfer_len * dspi->bytes_per_word;
+                       curr_remaining_bytes -= len;
+                       message->actual_length += len;
                        if (curr_remaining_bytes < 0)
                                curr_remaining_bytes = 0;
                }
@@ -534,125 +559,91 @@ static void ns_delay_scale(char *psc, char *sc, int delay_ns,
        }
 }
 
-static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word)
+static void fifo_write(struct fsl_dspi *dspi)
 {
-       u16 d16;
-
-       if (!(dspi->dataflags & TRAN_STATE_TX_VOID))
-               d16 = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx;
-       else
-               d16 = dspi->void_write_data;
-
-       dspi->tx += tx_word + 1;
-       dspi->len -= tx_word + 1;
-
-       return  SPI_PUSHR_TXDATA(d16) |
-               SPI_PUSHR_PCS(dspi->cs) |
-               SPI_PUSHR_CTAS(0) |
-               SPI_PUSHR_CONT;
+       regmap_write(dspi->regmap, SPI_PUSHR, dspi_pop_tx_pushr(dspi));
 }
 
-static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word)
+static void cmd_fifo_write(struct fsl_dspi *dspi)
 {
-       u16 d;
-       unsigned int val;
-
-       regmap_read(dspi->regmap, SPI_POPR, &val);
-       d = SPI_POPR_RXDATA(val);
+       u16 cmd = dspi->tx_cmd;
 
-       if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
-               rx_word ? (*(u16 *)dspi->rx = d) : (*(u8 *)dspi->rx = d);
-
-       dspi->rx += rx_word + 1;
+       if (dspi->len > 0)
+               cmd |= SPI_PUSHR_CMD_CONT;
+       regmap_write(dspi->regmap_pushr, PUSHR_CMD, cmd);
 }
 
-static int dspi_eoq_write(struct fsl_dspi *dspi)
+static void tx_fifo_write(struct fsl_dspi *dspi, u16 txdata)
 {
-       int tx_count = 0;
-       int tx_word;
-       u32 dspi_pushr = 0;
+       regmap_write(dspi->regmap_pushr, PUSHR_TX, txdata);
+}
 
-       tx_word = is_double_byte_mode(dspi);
+static void dspi_tcfq_write(struct fsl_dspi *dspi)
+{
+       /* Clear transfer count */
+       dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
 
-       while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) {
-               /* If we are in word mode, only have a single byte to transfer
-                * switch to byte mode temporarily.  Will switch back at the
-                * end of the transfer.
+       if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) {
+               /* Write two TX FIFO entries first, and then the corresponding
+                * CMD FIFO entry.
                 */
-               if (tx_word && (dspi->len == 1)) {
-                       dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
-                       regmap_update_bits(dspi->regmap, SPI_CTAR(0),
-                                       SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
-                       tx_word = 0;
-               }
-
-               dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
-
-               if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) {
-                       /* last transfer in the transfer */
-                       dspi_pushr |= SPI_PUSHR_EOQ;
-                       if ((dspi->cs_change) && (!dspi->len))
-                               dspi_pushr &= ~SPI_PUSHR_CONT;
-               } else if (tx_word && (dspi->len == 1))
-                       dspi_pushr |= SPI_PUSHR_EOQ;
+               u32 data = dspi_pop_tx(dspi);
 
-               regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
-
-               tx_count++;
+               if (dspi->cur_chip->ctar_val & SPI_CTAR_LSBFE(1)) {
+                       /* LSB */
+                       tx_fifo_write(dspi, data & 0xFFFF);
+                       tx_fifo_write(dspi, data >> 16);
+               } else {
+                       /* MSB */
+                       tx_fifo_write(dspi, data >> 16);
+                       tx_fifo_write(dspi, data & 0xFFFF);
+               }
+               cmd_fifo_write(dspi);
+       } else {
+               /* Write one entry to both TX FIFO and CMD FIFO
+                * simultaneously.
+                */
+               fifo_write(dspi);
        }
-
-       return tx_count * (tx_word + 1);
 }
 
-static int dspi_eoq_read(struct fsl_dspi *dspi)
+static u32 fifo_read(struct fsl_dspi *dspi)
 {
-       int rx_count = 0;
-       int rx_word = is_double_byte_mode(dspi);
-
-       while ((dspi->rx < dspi->rx_end)
-                       && (rx_count < DSPI_FIFO_SIZE)) {
-               if (rx_word && (dspi->rx_end - dspi->rx) == 1)
-                       rx_word = 0;
+       u32 rxdata = 0;
 
-               dspi_data_from_popr(dspi, rx_word);
-               rx_count++;
-       }
-
-       return rx_count;
+       regmap_read(dspi->regmap, SPI_POPR, &rxdata);
+       return rxdata;
 }
 
-static int dspi_tcfq_write(struct fsl_dspi *dspi)
+static void dspi_tcfq_read(struct fsl_dspi *dspi)
 {
-       int tx_word;
-       u32 dspi_pushr = 0;
-
-       tx_word = is_double_byte_mode(dspi);
+       dspi_push_rx(dspi, fifo_read(dspi));
+}
 
-       if (tx_word && (dspi->len == 1)) {
-               dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
-               regmap_update_bits(dspi->regmap, SPI_CTAR(0),
-                               SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
-               tx_word = 0;
+static void dspi_eoq_write(struct fsl_dspi *dspi)
+{
+       int fifo_size = DSPI_FIFO_SIZE;
+
+       /* Fill TX FIFO with as many transfers as possible */
+       while (dspi->len && fifo_size--) {
+               /* Request EOQF for last transfer in FIFO */
+               if (dspi->len == dspi->bytes_per_word || fifo_size == 0)
+                       dspi->tx_cmd |= SPI_PUSHR_CMD_EOQ;
+               /* Clear transfer count for first transfer in FIFO */
+               if (fifo_size == (DSPI_FIFO_SIZE - 1))
+                       dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
+               /* Write combined TX FIFO and CMD FIFO entry */
+               fifo_write(dspi);
        }
-
-       dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
-
-       if ((dspi->cs_change) && (!dspi->len))
-               dspi_pushr &= ~SPI_PUSHR_CONT;
-
-       regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
-
-       return tx_word + 1;
 }
 
-static void dspi_tcfq_read(struct fsl_dspi *dspi)
+static void dspi_eoq_read(struct fsl_dspi *dspi)
 {
-       int rx_word = is_double_byte_mode(dspi);
-
-       if (rx_word && (dspi->rx_end - dspi->rx) == 1)
-               rx_word = 0;
+       int fifo_size = DSPI_FIFO_SIZE;
 
-       dspi_data_from_popr(dspi, rx_word);
+       /* Read one FIFO entry at and push to rx buffer */
+       while ((dspi->rx < dspi->rx_end) && fifo_size--)
+               dspi_push_rx(dspi, fifo_read(dspi));
 }
 
 static int dspi_transfer_one_message(struct spi_master *master,
@@ -663,10 +654,6 @@ static int dspi_transfer_one_message(struct spi_master *master,
        struct spi_transfer *transfer;
        int status = 0;
        enum dspi_trans_mode trans_mode;
-       u32 spi_tcr;
-
-       regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
-       dspi->spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
 
        message->actual_length = 0;
 
@@ -674,32 +661,51 @@ static int dspi_transfer_one_message(struct spi_master *master,
                dspi->cur_transfer = transfer;
                dspi->cur_msg = message;
                dspi->cur_chip = spi_get_ctldata(spi);
-               dspi->cs = spi->chip_select;
-               dspi->cs_change = 0;
+               /* Prepare command word for CMD FIFO */
+               dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0) |
+                       SPI_PUSHR_CMD_PCS(spi->chip_select);
                if (list_is_last(&dspi->cur_transfer->transfer_list,
-                                &dspi->cur_msg->transfers) || transfer->cs_change)
-                       dspi->cs_change = 1;
+                                &dspi->cur_msg->transfers)) {
+                       /* Leave PCS activated after last transfer when
+                        * cs_change is set.
+                        */
+                       if (transfer->cs_change)
+                               dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
+               } else {
+                       /* Keep PCS active between transfers in same message
+                        * when cs_change is not set, and de-activate PCS
+                        * between transfers in the same message when
+                        * cs_change is set.
+                        */
+                       if (!transfer->cs_change)
+                               dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
+               }
+
                dspi->void_write_data = dspi->cur_chip->void_write_data;
 
-               dspi->dataflags = 0;
-               dspi->tx = (void *)transfer->tx_buf;
-               dspi->tx_end = dspi->tx + transfer->len;
+               dspi->tx = transfer->tx_buf;
                dspi->rx = transfer->rx_buf;
                dspi->rx_end = dspi->rx + transfer->len;
                dspi->len = transfer->len;
+               /* Validated transfer specific frame size (defaults applied) */
+               dspi->bits_per_word = transfer->bits_per_word;
+               if (transfer->bits_per_word <= 8)
+                       dspi->bytes_per_word = 1;
+               else if (transfer->bits_per_word <= 16)
+                       dspi->bytes_per_word = 2;
+               else
+                       dspi->bytes_per_word = 4;
 
-               if (!dspi->rx)
-                       dspi->dataflags |= TRAN_STATE_RX_VOID;
-
-               if (!dspi->tx)
-                       dspi->dataflags |= TRAN_STATE_TX_VOID;
-
-               regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
                regmap_update_bits(dspi->regmap, SPI_MCR,
-                               SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
-                               SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
+                                  SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
+                                  SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
                regmap_write(dspi->regmap, SPI_CTAR(0),
-                               dspi->cur_chip->ctar_val);
+                            dspi->cur_chip->ctar_val |
+                            SPI_FRAME_BITS(transfer->bits_per_word));
+               if (dspi->devtype_data->xspi_mode)
+                       regmap_write(dspi->regmap, SPI_CTARE(0),
+                                    SPI_FRAME_EBITS(transfer->bits_per_word)
+                                    | SPI_CTARE_DTCP(1));
 
                trans_mode = dspi->devtype_data->trans_mode;
                switch (trans_mode) {
@@ -750,16 +756,9 @@ static int dspi_setup(struct spi_device *spi)
        struct fsl_dspi_platform_data *pdata;
        u32 cs_sck_delay = 0, sck_cs_delay = 0;
        unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
-       unsigned char pasc = 0, asc = 0, fmsz = 0;
+       unsigned char pasc = 0, asc = 0;
        unsigned long clkrate;
 
-       if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
-               fmsz = spi->bits_per_word - 1;
-       } else {
-               pr_err("Invalid wordsize\n");
-               return -ENODEV;
-       }
-
        /* Only alloc on first setup */
        chip = spi_get_ctldata(spi);
        if (chip == NULL) {
@@ -781,9 +780,6 @@ static int dspi_setup(struct spi_device *spi)
                sck_cs_delay = pdata->sck_cs_delay;
        }
 
-       chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
-               SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
-
        chip->void_write_data = 0;
 
        clkrate = clk_get_rate(dspi->clk);
@@ -795,8 +791,7 @@ static int dspi_setup(struct spi_device *spi)
        /* Set After SCK delay scale values */
        ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate);
 
-       chip->ctar_val =  SPI_CTAR_FMSZ(fmsz)
-               | SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
+       chip->ctar_val = SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
                | SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0)
                | SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0)
                | SPI_CTAR_PCSSCK(pcssck)
@@ -827,36 +822,20 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
        struct spi_message *msg = dspi->cur_msg;
        enum dspi_trans_mode trans_mode;
        u32 spi_sr, spi_tcr;
-       u32 spi_tcnt, tcnt_diff;
-       int tx_word;
+       u16 spi_tcnt;
 
        regmap_read(dspi->regmap, SPI_SR, &spi_sr);
        regmap_write(dspi->regmap, SPI_SR, spi_sr);
 
 
        if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)) {
-               tx_word = is_double_byte_mode(dspi);
-
+               /* Get transfer counter (in number of SPI transfers). It was
+                * reset to 0 when transfer(s) were started.
+                */
                regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
                spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
-               /*
-                * The width of SPI Transfer Counter in SPI_TCR is 16bits,
-                * so the max couner is 65535. When the counter reach 65535,
-                * it will wrap around, counter reset to zero.
-                * spi_tcnt my be less than dspi->spi_tcnt, it means the
-                * counter already wrapped around.
-                * SPI Transfer Counter is a counter of transmitted frames.
-                * The size of frame maybe two bytes.
-                */
-               tcnt_diff = ((spi_tcnt + SPI_TCR_TCNT_MAX) - dspi->spi_tcnt)
-                       % SPI_TCR_TCNT_MAX;
-               tcnt_diff *= (tx_word + 1);
-               if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
-                       tcnt_diff--;
-
-               msg->actual_length += tcnt_diff;
-
-               dspi->spi_tcnt = spi_tcnt;
+               /* Update total number of bytes that were transferred */
+               msg->actual_length += spi_tcnt * dspi->bytes_per_word;
 
                trans_mode = dspi->devtype_data->trans_mode;
                switch (trans_mode) {
@@ -873,14 +852,6 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
                }
 
                if (!dspi->len) {
-                       if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) {
-                               regmap_update_bits(dspi->regmap,
-                                                  SPI_CTAR(0),
-                                                  SPI_FRAME_BITS_MASK,
-                                                  SPI_FRAME_BITS(16));
-                               dspi->dataflags &= ~TRAN_STATE_WORD_ODD_NUM;
-                       }
-
                        dspi->waitflags = 1;
                        wake_up_interruptible(&dspi->waitq);
                } else {
@@ -962,9 +933,43 @@ static const struct regmap_config dspi_regmap_config = {
        .volatile_table = &dspi_volatile_table,
 };
 
+static const struct regmap_range dspi_xspi_volatile_ranges[] = {
+       regmap_reg_range(SPI_MCR, SPI_TCR),
+       regmap_reg_range(SPI_SR, SPI_SR),
+       regmap_reg_range(SPI_PUSHR, SPI_RXFR3),
+       regmap_reg_range(SPI_SREX, SPI_SREX),
+};
+
+static const struct regmap_access_table dspi_xspi_volatile_table = {
+       .yes_ranges     = dspi_xspi_volatile_ranges,
+       .n_yes_ranges   = ARRAY_SIZE(dspi_xspi_volatile_ranges),
+};
+
+static const struct regmap_config dspi_xspi_regmap_config[] = {
+       {
+               .reg_bits = 32,
+               .val_bits = 32,
+               .reg_stride = 4,
+               .max_register = 0x13c,
+               .volatile_table = &dspi_xspi_volatile_table,
+       },
+       {
+               .name = "pushr",
+               .reg_bits = 16,
+               .val_bits = 16,
+               .reg_stride = 2,
+               .max_register = 0x2,
+       },
+};
+
 static void dspi_init(struct fsl_dspi *dspi)
 {
+       regmap_write(dspi->regmap, SPI_MCR, SPI_MCR_MASTER | SPI_MCR_PCSIS |
+                    (dspi->devtype_data->xspi_mode ? SPI_MCR_XSPI : 0));
        regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
+       if (dspi->devtype_data->xspi_mode)
+               regmap_write(dspi->regmap, SPI_CTARE(0),
+                            SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1));
 }
 
 static int dspi_probe(struct platform_device *pdev)
@@ -973,6 +978,7 @@ static int dspi_probe(struct platform_device *pdev)
        struct spi_master *master;
        struct fsl_dspi *dspi;
        struct resource *res;
+       const struct regmap_config *regmap_config;
        void __iomem *base;
        struct fsl_dspi_platform_data *pdata;
        int ret = 0, cs_num, bus_num;
@@ -992,8 +998,6 @@ static int dspi_probe(struct platform_device *pdev)
 
        master->cleanup = dspi_cleanup;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
-       master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) |
-                                       SPI_BPW_MASK(16);
 
        pdata = dev_get_platdata(&pdev->dev);
        if (pdata) {
@@ -1025,6 +1029,11 @@ static int dspi_probe(struct platform_device *pdev)
                }
        }
 
+       if (dspi->devtype_data->xspi_mode)
+               master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+       else
+               master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(base)) {
@@ -1032,8 +1041,11 @@ static int dspi_probe(struct platform_device *pdev)
                goto out_master_put;
        }
 
-       dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
-                                               &dspi_regmap_config);
+       if (dspi->devtype_data->xspi_mode)
+               regmap_config = &dspi_xspi_regmap_config[0];
+       else
+               regmap_config = &dspi_regmap_config;
+       dspi->regmap = devm_regmap_init_mmio(&pdev->dev, base, regmap_config);
        if (IS_ERR(dspi->regmap)) {
                dev_err(&pdev->dev, "failed to init regmap: %ld\n",
                                PTR_ERR(dspi->regmap));
@@ -1041,30 +1053,43 @@ static int dspi_probe(struct platform_device *pdev)
                goto out_master_put;
        }
 
+       if (dspi->devtype_data->xspi_mode) {
+               dspi->regmap_pushr = devm_regmap_init_mmio(
+                       &pdev->dev, base + SPI_PUSHR,
+                       &dspi_xspi_regmap_config[1]);
+               if (IS_ERR(dspi->regmap_pushr)) {
+                       dev_err(&pdev->dev,
+                               "failed to init pushr regmap: %ld\n",
+                               PTR_ERR(dspi->regmap_pushr));
+                       ret = PTR_ERR(dspi->regmap_pushr);
+                       goto out_master_put;
+               }
+       }
+
+       dspi->clk = devm_clk_get(&pdev->dev, "dspi");
+       if (IS_ERR(dspi->clk)) {
+               ret = PTR_ERR(dspi->clk);
+               dev_err(&pdev->dev, "unable to get clock\n");
+               goto out_master_put;
+       }
+       ret = clk_prepare_enable(dspi->clk);
+       if (ret)
+               goto out_master_put;
+
        dspi_init(dspi);
        dspi->irq = platform_get_irq(pdev, 0);
        if (dspi->irq < 0) {
                dev_err(&pdev->dev, "can't get platform irq\n");
                ret = dspi->irq;
-               goto out_master_put;
+               goto out_clk_put;
        }
 
        ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt, 0,
                        pdev->name, dspi);
        if (ret < 0) {
                dev_err(&pdev->dev, "Unable to attach DSPI interrupt\n");
-               goto out_master_put;
-       }
-
-       dspi->clk = devm_clk_get(&pdev->dev, "dspi");
-       if (IS_ERR(dspi->clk)) {
-               ret = PTR_ERR(dspi->clk);
-               dev_err(&pdev->dev, "unable to get clock\n");
-               goto out_master_put;
+               goto out_clk_put;
        }
-       ret = clk_prepare_enable(dspi->clk);
-       if (ret)
-               goto out_master_put;
 
        if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
                ret = dspi_request_dma(dspi, res->start);
index 1d332e23f6ede6874e3a7c76329a9ab0ff67a751..1e8ff6256079f1344e5e6a1ceb2192d620bf0d5b 100644 (file)
@@ -547,8 +547,11 @@ static void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events)
                dev_err(espi->dev,
                        "Transfer done but SPIE_DON isn't set!\n");
 
-       if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE)
+       if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE) {
                dev_err(espi->dev, "Transfer done but rx/tx fifo's aren't empty!\n");
+               dev_err(espi->dev, "SPIE_RXCNT = %d, SPIE_TXCNT = %d\n",
+                       SPIE_RXCNT(events), SPIE_TXCNT(events));
+       }
 
        complete(&espi->done);
 }
index 6ae92d4dca19d6201c5f2ddd4e552f4d639bbce2..0626e6e3ea0c05dee66e177aa4d2a0c75b703247 100644 (file)
@@ -121,7 +121,10 @@ static inline int getmiso(const struct spi_device *spi)
 {
        struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
 
-       return !!gpiod_get_value_cansleep(spi_gpio->miso);
+       if (spi->mode & SPI_3WIRE)
+               return !!gpiod_get_value_cansleep(spi_gpio->mosi);
+       else
+               return !!gpiod_get_value_cansleep(spi_gpio->miso);
 }
 
 /*
@@ -149,27 +152,27 @@ static inline int getmiso(const struct spi_device *spi)
  */
 
 static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
-               unsigned nsecs, u32 word, u8 bits)
+               unsigned nsecs, u32 word, u8 bits, unsigned flags)
 {
-       return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
 }
 
 static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi,
-               unsigned nsecs, u32 word, u8 bits)
+               unsigned nsecs, u32 word, u8 bits, unsigned flags)
 {
-       return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
+       return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
 }
 
 static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi,
-               unsigned nsecs, u32 word, u8 bits)
+               unsigned nsecs, u32 word, u8 bits, unsigned flags)
 {
-       return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
+       return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
 }
 
 static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
-               unsigned nsecs, u32 word, u8 bits)
+               unsigned nsecs, u32 word, u8 bits, unsigned flags)
 {
-       return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
+       return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
 }
 
 /*
@@ -183,30 +186,30 @@ static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
  */
 
 static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
-               unsigned nsecs, u32 word, u8 bits)
+               unsigned nsecs, u32 word, u8 bits, unsigned flags)
 {
-       unsigned flags = spi->master->flags;
+       flags = spi->master->flags;
        return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
 }
 
 static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi,
-               unsigned nsecs, u32 word, u8 bits)
+               unsigned nsecs, u32 word, u8 bits, unsigned flags)
 {
-       unsigned flags = spi->master->flags;
+       flags = spi->master->flags;
        return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
 }
 
 static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi,
-               unsigned nsecs, u32 word, u8 bits)
+               unsigned nsecs, u32 word, u8 bits, unsigned flags)
 {
-       unsigned flags = spi->master->flags;
+       flags = spi->master->flags;
        return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
 }
 
 static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi,
-               unsigned nsecs, u32 word, u8 bits)
+               unsigned nsecs, u32 word, u8 bits, unsigned flags)
 {
-       unsigned flags = spi->master->flags;
+       flags = spi->master->flags;
        return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
 }
 
@@ -250,6 +253,16 @@ static int spi_gpio_setup(struct spi_device *spi)
        return status;
 }
 
+static int spi_gpio_set_direction(struct spi_device *spi, bool output)
+{
+       struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+
+       if (output)
+               return gpiod_direction_output(spi_gpio->mosi, 1);
+       else
+               return gpiod_direction_input(spi_gpio->mosi);
+}
+
 static void spi_gpio_cleanup(struct spi_device *spi)
 {
        spi_bitbang_cleanup(spi);
@@ -395,6 +408,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
                return status;
 
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+       master->mode_bits = SPI_3WIRE | SPI_CPHA | SPI_CPOL;
        master->flags = master_flags;
        master->bus_num = pdev->id;
        /* The master needs to think there is a chipselect even if not connected */
@@ -407,6 +421,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
 
        spi_gpio->bitbang.master = master;
        spi_gpio->bitbang.chipselect = spi_gpio_chipselect;
+       spi_gpio->bitbang.set_line_direction = spi_gpio_set_direction;
 
        if ((master_flags & (SPI_MASTER_NO_TX | SPI_MASTER_NO_RX)) == 0) {
                spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
index 7a37090dabbea55308b555d03f19dd56c4c3c15c..e6eb979f1b8a09f038ec012f288dba4219bfe604 100644 (file)
@@ -419,6 +419,9 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
        u32 val;
 
        val = spfi_readl(spfi, SPFI_PORT_STATE);
+       val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK <<
+                SPFI_PORT_STATE_DEV_SEL_SHIFT);
+       val |= msg->spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT;
        if (msg->spi->mode & SPI_CPHA)
                val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
        else
index d3b21faf6b1f812c1f089cf9f8964f732385c69c..08dd3a31a3e5f7d49a40400300f85477ef6a464e 100644 (file)
@@ -94,8 +94,7 @@ struct spi_imx_data {
        void *rx_buf;
        const void *tx_buf;
        unsigned int txfifo; /* number of words pushed in tx FIFO */
-       unsigned int dynamic_burst, read_u32;
-       unsigned int word_mask;
+       unsigned int dynamic_burst;
 
        /* Slave mode */
        bool slave_mode;
@@ -140,6 +139,8 @@ static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx)             \
                *(type *)spi_imx->rx_buf = val;                         \
                spi_imx->rx_buf += sizeof(type);                        \
        }                                                               \
+                                                                       \
+       spi_imx->remainder -= sizeof(type);                             \
 }
 
 #define MXC_SPI_BUF_TX(type)                                           \
@@ -203,7 +204,12 @@ out:
 
 static int spi_imx_bytes_per_word(const int bits_per_word)
 {
-       return DIV_ROUND_UP(bits_per_word, BITS_PER_BYTE);
+       if (bits_per_word <= 8)
+               return 1;
+       else if (bits_per_word <= 16)
+               return 2;
+       else
+               return 4;
 }
 
 static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
@@ -220,17 +226,11 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 
        bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
 
-       if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
-               return false;
-
        for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
                if (!(transfer->len % (i * bytes_per_word)))
                        break;
        }
 
-       if (i == 0)
-               return false;
-
        spi_imx->wml = i;
        spi_imx->dynamic_burst = 0;
 
@@ -291,26 +291,39 @@ static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx)
                else if (bytes_per_word == 2)
                        val = (val << 16) | (val >> 16);
 #endif
-               val &= spi_imx->word_mask;
                *(u32 *)spi_imx->rx_buf = val;
                spi_imx->rx_buf += sizeof(u32);
        }
+
+       spi_imx->remainder -= sizeof(u32);
 }
 
 static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx)
 {
-       unsigned int bytes_per_word;
+       int unaligned;
+       u32 val;
 
-       bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
-       if (spi_imx->read_u32) {
+       unaligned = spi_imx->remainder % 4;
+
+       if (!unaligned) {
                spi_imx_buf_rx_swap_u32(spi_imx);
                return;
        }
 
-       if (bytes_per_word == 1)
-               spi_imx_buf_rx_u8(spi_imx);
-       else if (bytes_per_word == 2)
+       if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {
                spi_imx_buf_rx_u16(spi_imx);
+               return;
+       }
+
+       val = readl(spi_imx->base + MXC_CSPIRXDATA);
+
+       while (unaligned--) {
+               if (spi_imx->rx_buf) {
+                       *(u8 *)spi_imx->rx_buf = (val >> (8 * unaligned)) & 0xff;
+                       spi_imx->rx_buf++;
+               }
+               spi_imx->remainder--;
+       }
 }
 
 static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
@@ -322,7 +335,6 @@ static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
 
        if (spi_imx->tx_buf) {
                val = *(u32 *)spi_imx->tx_buf;
-               val &= spi_imx->word_mask;
                spi_imx->tx_buf += sizeof(u32);
        }
 
@@ -340,40 +352,30 @@ static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
 
 static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
 {
-       u32 ctrl, val;
-       unsigned int bytes_per_word;
+       int unaligned;
+       u32 val = 0;
 
-       if (spi_imx->count == spi_imx->remainder) {
-               ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
-               ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
-               if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST) {
-                       spi_imx->remainder = spi_imx->count %
-                                            MX51_ECSPI_CTRL_MAX_BURST;
-                       val = MX51_ECSPI_CTRL_MAX_BURST * 8 - 1;
-               } else if (spi_imx->count >= sizeof(u32)) {
-                       spi_imx->remainder = spi_imx->count % sizeof(u32);
-                       val = (spi_imx->count - spi_imx->remainder) * 8 - 1;
-               } else {
-                       spi_imx->remainder = 0;
-                       val = spi_imx->bits_per_word - 1;
-                       spi_imx->read_u32 = 0;
-               }
+       unaligned = spi_imx->count % 4;
 
-               ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET);
-               writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+       if (!unaligned) {
+               spi_imx_buf_tx_swap_u32(spi_imx);
+               return;
        }
 
-       if (spi_imx->count >= sizeof(u32)) {
-               spi_imx_buf_tx_swap_u32(spi_imx);
+       if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {
+               spi_imx_buf_tx_u16(spi_imx);
                return;
        }
 
-       bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+       while (unaligned--) {
+               if (spi_imx->tx_buf) {
+                       val |= *(u8 *)spi_imx->tx_buf << (8 * unaligned);
+                       spi_imx->tx_buf++;
+               }
+               spi_imx->count--;
+       }
 
-       if (bytes_per_word == 1)
-               spi_imx_buf_tx_u8(spi_imx);
-       else if (bytes_per_word == 2)
-               spi_imx_buf_tx_u16(spi_imx);
+       writel(val, spi_imx->base + MXC_CSPITXDATA);
 }
 
 static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
@@ -392,6 +394,8 @@ static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
                spi_imx->rx_buf += n_bytes;
                spi_imx->slave_burst -= n_bytes;
        }
+
+       spi_imx->remainder -= sizeof(u32);
 }
 
 static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
@@ -1001,12 +1005,52 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active)
        gpio_set_value(spi->cs_gpio, dev_is_lowactive ^ active);
 }
 
+static void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits)
+{
+       u32 ctrl;
+
+       ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
+       ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+       ctrl |= ((n_bits - 1) << MX51_ECSPI_CTRL_BL_OFFSET);
+       writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+}
+
 static void spi_imx_push(struct spi_imx_data *spi_imx)
 {
+       unsigned int burst_len, fifo_words;
+
+       if (spi_imx->dynamic_burst)
+               fifo_words = 4;
+       else
+               fifo_words = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+       /*
+        * Reload the FIFO when the remaining bytes to be transferred in the
+        * current burst is 0. This only applies when bits_per_word is a
+        * multiple of 8.
+        */
+       if (!spi_imx->remainder) {
+               if (spi_imx->dynamic_burst) {
+
+                       /* We need to deal unaligned data first */
+                       burst_len = spi_imx->count % MX51_ECSPI_CTRL_MAX_BURST;
+
+                       if (!burst_len)
+                               burst_len = MX51_ECSPI_CTRL_MAX_BURST;
+
+                       spi_imx_set_burst_len(spi_imx, burst_len * 8);
+
+                       spi_imx->remainder = burst_len;
+               } else {
+                       spi_imx->remainder = fifo_words;
+               }
+       }
+
        while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) {
                if (!spi_imx->count)
                        break;
-               if (spi_imx->txfifo && (spi_imx->count == spi_imx->remainder))
+               if (spi_imx->dynamic_burst &&
+                   spi_imx->txfifo >=  DIV_ROUND_UP(spi_imx->remainder,
+                                                    fifo_words))
                        break;
                spi_imx->tx(spi_imx);
                spi_imx->txfifo++;
@@ -1102,27 +1146,20 @@ static int spi_imx_setupxfer(struct spi_device *spi,
        spi_imx->bits_per_word = t->bits_per_word;
        spi_imx->speed_hz  = t->speed_hz;
 
-       /* Initialize the functions for transfer */
-       if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode) {
-               u32 mask;
-
-               spi_imx->dynamic_burst = 0;
-               spi_imx->remainder = 0;
-               spi_imx->read_u32  = 1;
+       /*
+        * Initialize the functions for transfer. To transfer non byte-aligned
+        * words, we have to use multiple word-size bursts, we can't use
+        * dynamic_burst in that case.
+        */
+       if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode &&
+           (spi_imx->bits_per_word == 8 ||
+           spi_imx->bits_per_word == 16 ||
+           spi_imx->bits_per_word == 32)) {
 
-               mask = (1 << spi_imx->bits_per_word) - 1;
                spi_imx->rx = spi_imx_buf_rx_swap;
                spi_imx->tx = spi_imx_buf_tx_swap;
                spi_imx->dynamic_burst = 1;
-               spi_imx->remainder = t->len;
-
-               if (spi_imx->bits_per_word <= 8)
-                       spi_imx->word_mask = mask << 24 | mask << 16
-                                            | mask << 8 | mask;
-               else if (spi_imx->bits_per_word <= 16)
-                       spi_imx->word_mask = mask << 16 | mask;
-               else
-                       spi_imx->word_mask = mask;
+
        } else {
                if (spi_imx->bits_per_word <= 8) {
                        spi_imx->rx = spi_imx_buf_rx_u8;
@@ -1134,6 +1171,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
                        spi_imx->rx = spi_imx_buf_rx_u32;
                        spi_imx->tx = spi_imx_buf_tx_u32;
                }
+               spi_imx->dynamic_burst = 0;
        }
 
        if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t))
@@ -1317,6 +1355,7 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
        spi_imx->rx_buf = transfer->rx_buf;
        spi_imx->count = transfer->len;
        spi_imx->txfifo = 0;
+       spi_imx->remainder = 0;
 
        reinit_completion(&spi_imx->xfer_done);
 
@@ -1354,6 +1393,7 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi,
        spi_imx->rx_buf = transfer->rx_buf;
        spi_imx->count = transfer->len;
        spi_imx->txfifo = 0;
+       spi_imx->remainder = 0;
 
        reinit_completion(&spi_imx->xfer_done);
        spi_imx->slave_aborted = false;
index 61ee0f4269ae668e95a6352bd44d05349f05d43a..4549efd792da682f9557d22855c1cf65656392f5 100644 (file)
@@ -188,9 +188,10 @@ static void lm70_chipselect(struct spi_device *spi, int value)
 /*
  * Our actual bitbanger routine.
  */
-static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
+static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits,
+                    unsigned flags)
 {
-       return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
 }
 
 static void spi_lm70llp_attach(struct parport *p)
index 990770dfa5cf52f0ffd0048fc954827b079d1dde..e43842c7a31a90388b4eeb3be6ab9a420e30d28b 100644 (file)
@@ -310,6 +310,24 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
 }
 EXPORT_SYMBOL_GPL(spi_mem_exec_op);
 
+/**
+ * spi_mem_get_name() - Return the SPI mem device name to be used by the
+ *                     upper layer if necessary
+ * @mem: the SPI memory
+ *
+ * This function allows SPI mem users to retrieve the SPI mem device name.
+ * It is useful if the upper layer needs to expose a custom name for
+ * compatibility reasons.
+ *
+ * Return: a string containing the name of the memory device to be used
+ *        by the SPI mem user
+ */
+const char *spi_mem_get_name(struct spi_mem *mem)
+{
+       return mem->name;
+}
+EXPORT_SYMBOL_GPL(spi_mem_get_name);
+
 /**
  * spi_mem_adjust_op_size() - Adjust the data size of a SPI mem operation to
  *                           match controller limitations
@@ -344,6 +362,7 @@ static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv)
 static int spi_mem_probe(struct spi_device *spi)
 {
        struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
+       struct spi_controller *ctlr = spi->controller;
        struct spi_mem *mem;
 
        mem = devm_kzalloc(&spi->dev, sizeof(*mem), GFP_KERNEL);
@@ -351,6 +370,15 @@ static int spi_mem_probe(struct spi_device *spi)
                return -ENOMEM;
 
        mem->spi = spi;
+
+       if (ctlr->mem_ops && ctlr->mem_ops->get_name)
+               mem->name = ctlr->mem_ops->get_name(mem);
+       else
+               mem->name = dev_name(&spi->dev);
+
+       if (IS_ERR_OR_NULL(mem->name))
+               return PTR_ERR(mem->name);
+
        spi_set_drvdata(spi, mem);
 
        return memdrv->probe(mem);
index 6c628a54e946942c1a32acea6292abf56717be4c..508c61c669e7d701525af13309430d7a4d1e9ce8 100644 (file)
@@ -398,11 +398,9 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
 {
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *mcspi_dma;
-       unsigned int            count;
 
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
-       count = xfer->len;
 
        if (mcspi_dma->dma_tx) {
                struct dma_async_tx_descriptor *tx;
@@ -582,7 +580,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        struct omap2_mcspi_cs   *cs = spi->controller_state;
        struct omap2_mcspi_dma  *mcspi_dma;
        unsigned int            count;
-       u32                     l;
        u8                      *rx;
        const u8                *tx;
        struct dma_slave_config cfg;
@@ -595,8 +592,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
-       l = mcspi_cached_chconf0(spi);
-
 
        if (cs->word_len <= 8) {
                width = DMA_SLAVE_BUSWIDTH_1_BYTE;
@@ -676,7 +671,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 static unsigned
 omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 {
-       struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_cs   *cs = spi->controller_state;
        unsigned int            count, c;
        u32                     l;
@@ -686,7 +680,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
        void __iomem            *chstat_reg;
        int                     word_len;
 
-       mcspi = spi_master_get_devdata(spi->master);
        count = xfer->len;
        c = count;
        word_len = cs->word_len;
@@ -883,13 +876,11 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
 {
        struct omap2_mcspi_cs *cs = spi->controller_state;
        struct omap2_mcspi *mcspi;
-       struct spi_master *spi_cntrl;
        u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
        u8 word_len = spi->bits_per_word;
        u32 speed_hz = spi->max_speed_hz;
 
        mcspi = spi_master_get_devdata(spi->master);
-       spi_cntrl = mcspi->master;
 
        if (t != NULL && t->bits_per_word)
                word_len = t->bits_per_word;
index 0b2d60d30f6934b9745414a3cb0583c5111c94ca..14f4ea59caff7a235faafc7c5cfb91776bcc68a9 100644 (file)
@@ -1391,6 +1391,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
        { PCI_VDEVICE(INTEL, 0x31c2), LPSS_BXT_SSP },
        { PCI_VDEVICE(INTEL, 0x31c4), LPSS_BXT_SSP },
        { PCI_VDEVICE(INTEL, 0x31c6), LPSS_BXT_SSP },
+       /* ICL-LP */
+       { PCI_VDEVICE(INTEL, 0x34aa), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0x34ab), LPSS_CNL_SSP },
+       { PCI_VDEVICE(INTEL, 0x34fb), LPSS_CNL_SSP },
        /* APL */
        { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
        { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
index a9beeeed812cb58668639f92c7caaf38737abffc..393701cfca3c5244a232ef902c4d63ae54fc3a13 100644 (file)
@@ -80,27 +80,31 @@ static inline u32 getmiso(struct spi_device *dev)
 #include "spi-bitbang-txrx.h"
 
 static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
-                                     unsigned nsecs, u32 word, u8 bits)
+                                unsigned nsecs, u32 word, u8 bits,
+                                unsigned flags)
 {
-       return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
 }
 
 static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi,
-                                     unsigned nsecs, u32 word, u8 bits)
+                                unsigned nsecs, u32 word, u8 bits,
+                                unsigned flags)
 {
-       return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
+       return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
 }
 
 static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi,
-                                     unsigned nsecs, u32 word, u8 bits)
+                                unsigned nsecs, u32 word, u8 bits,
+                                unsigned flags)
 {
-       return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
+       return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
 }
 
 static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
-                                     unsigned nsecs, u32 word, u8 bits)
+                                unsigned nsecs, u32 word, u8 bits,
+                                unsigned flags)
 {
-       return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
+       return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
 }
 
 static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c
new file mode 100644 (file)
index 0000000..5a6137f
--- /dev/null
@@ -0,0 +1,523 @@
+// SPDX-License-Identifier: GPL-2.0
+// spi-uniphier.c - Socionext UniPhier SPI controller driver
+// Copyright 2012      Panasonic Corporation
+// Copyright 2016-2018 Socionext Inc.
+
+#include <linux/kernel.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#include <asm/unaligned.h>
+
+#define SSI_TIMEOUT_MS         2000
+#define SSI_MAX_CLK_DIVIDER    254
+#define SSI_MIN_CLK_DIVIDER    4
+
+struct uniphier_spi_priv {
+       void __iomem *base;
+       struct clk *clk;
+       struct spi_master *master;
+       struct completion xfer_done;
+
+       int error;
+       unsigned int tx_bytes;
+       unsigned int rx_bytes;
+       const u8 *tx_buf;
+       u8 *rx_buf;
+
+       bool is_save_param;
+       u8 bits_per_word;
+       u16 mode;
+       u32 speed_hz;
+};
+
+#define SSI_CTL                        0x00
+#define   SSI_CTL_EN           BIT(0)
+
+#define SSI_CKS                        0x04
+#define   SSI_CKS_CKRAT_MASK   GENMASK(7, 0)
+#define   SSI_CKS_CKPHS                BIT(14)
+#define   SSI_CKS_CKINIT       BIT(13)
+#define   SSI_CKS_CKDLY                BIT(12)
+
+#define SSI_TXWDS              0x08
+#define   SSI_TXWDS_WDLEN_MASK GENMASK(13, 8)
+#define   SSI_TXWDS_TDTF_MASK  GENMASK(7, 6)
+#define   SSI_TXWDS_DTLEN_MASK GENMASK(5, 0)
+
+#define SSI_RXWDS              0x0c
+#define   SSI_RXWDS_DTLEN_MASK GENMASK(5, 0)
+
+#define SSI_FPS                        0x10
+#define   SSI_FPS_FSPOL                BIT(15)
+#define   SSI_FPS_FSTRT                BIT(14)
+
+#define SSI_SR                 0x14
+#define   SSI_SR_RNE           BIT(0)
+
+#define SSI_IE                 0x18
+#define   SSI_IE_RCIE          BIT(3)
+#define   SSI_IE_RORIE         BIT(0)
+
+#define SSI_IS                 0x1c
+#define   SSI_IS_RXRS          BIT(9)
+#define   SSI_IS_RCID          BIT(3)
+#define   SSI_IS_RORID         BIT(0)
+
+#define SSI_IC                 0x1c
+#define   SSI_IC_TCIC          BIT(4)
+#define   SSI_IC_RCIC          BIT(3)
+#define   SSI_IC_RORIC         BIT(0)
+
+#define SSI_FC                 0x20
+#define   SSI_FC_TXFFL         BIT(12)
+#define   SSI_FC_TXFTH_MASK    GENMASK(11, 8)
+#define   SSI_FC_RXFFL         BIT(4)
+#define   SSI_FC_RXFTH_MASK    GENMASK(3, 0)
+
+#define SSI_TXDR               0x24
+#define SSI_RXDR               0x24
+
+#define SSI_FIFO_DEPTH         8U
+
+static inline unsigned int bytes_per_word(unsigned int bits)
+{
+       return bits <= 8 ? 1 : (bits <= 16 ? 2 : 4);
+}
+
+static inline void uniphier_spi_irq_enable(struct spi_device *spi, u32 mask)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+       u32 val;
+
+       val = readl(priv->base + SSI_IE);
+       val |= mask;
+       writel(val, priv->base + SSI_IE);
+}
+
+static inline void uniphier_spi_irq_disable(struct spi_device *spi, u32 mask)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+       u32 val;
+
+       val = readl(priv->base + SSI_IE);
+       val &= ~mask;
+       writel(val, priv->base + SSI_IE);
+}
+
+static void uniphier_spi_set_mode(struct spi_device *spi)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+       u32 val1, val2;
+
+       /*
+        * clock setting
+        * CKPHS    capture timing. 0:rising edge, 1:falling edge
+        * CKINIT   clock initial level. 0:low, 1:high
+        * CKDLY    clock delay. 0:no delay, 1:delay depending on FSTRT
+        *          (FSTRT=0: 1 clock, FSTRT=1: 0.5 clock)
+        *
+        * frame setting
+        * FSPOL    frame signal porarity. 0: low, 1: high
+        * FSTRT    start frame timing
+        *          0: rising edge of clock, 1: falling edge of clock
+        */
+       switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+       case SPI_MODE_0:
+               /* CKPHS=1, CKINIT=0, CKDLY=1, FSTRT=0 */
+               val1 = SSI_CKS_CKPHS | SSI_CKS_CKDLY;
+               val2 = 0;
+               break;
+       case SPI_MODE_1:
+               /* CKPHS=0, CKINIT=0, CKDLY=0, FSTRT=1 */
+               val1 = 0;
+               val2 = SSI_FPS_FSTRT;
+               break;
+       case SPI_MODE_2:
+               /* CKPHS=0, CKINIT=1, CKDLY=1, FSTRT=1 */
+               val1 = SSI_CKS_CKINIT | SSI_CKS_CKDLY;
+               val2 = SSI_FPS_FSTRT;
+               break;
+       case SPI_MODE_3:
+               /* CKPHS=1, CKINIT=1, CKDLY=0, FSTRT=0 */
+               val1 = SSI_CKS_CKPHS | SSI_CKS_CKINIT;
+               val2 = 0;
+               break;
+       }
+
+       if (!(spi->mode & SPI_CS_HIGH))
+               val2 |= SSI_FPS_FSPOL;
+
+       writel(val1, priv->base + SSI_CKS);
+       writel(val2, priv->base + SSI_FPS);
+
+       val1 = 0;
+       if (spi->mode & SPI_LSB_FIRST)
+               val1 |= FIELD_PREP(SSI_TXWDS_TDTF_MASK, 1);
+       writel(val1, priv->base + SSI_TXWDS);
+       writel(val1, priv->base + SSI_RXWDS);
+}
+
+static void uniphier_spi_set_transfer_size(struct spi_device *spi, int size)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+       u32 val;
+
+       val = readl(priv->base + SSI_TXWDS);
+       val &= ~(SSI_TXWDS_WDLEN_MASK | SSI_TXWDS_DTLEN_MASK);
+       val |= FIELD_PREP(SSI_TXWDS_WDLEN_MASK, size);
+       val |= FIELD_PREP(SSI_TXWDS_DTLEN_MASK, size);
+       writel(val, priv->base + SSI_TXWDS);
+
+       val = readl(priv->base + SSI_RXWDS);
+       val &= ~SSI_RXWDS_DTLEN_MASK;
+       val |= FIELD_PREP(SSI_RXWDS_DTLEN_MASK, size);
+       writel(val, priv->base + SSI_RXWDS);
+}
+
+static void uniphier_spi_set_baudrate(struct spi_device *spi,
+                                     unsigned int speed)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+       u32 val, ckdiv;
+
+       /*
+        * the supported rates are even numbers from 4 to 254. (4,6,8...254)
+        * round up as we look for equal or less speed
+        */
+       ckdiv = DIV_ROUND_UP(clk_get_rate(priv->clk), speed);
+       ckdiv = round_up(ckdiv, 2);
+
+       val = readl(priv->base + SSI_CKS);
+       val &= ~SSI_CKS_CKRAT_MASK;
+       val |= ckdiv & SSI_CKS_CKRAT_MASK;
+       writel(val, priv->base + SSI_CKS);
+}
+
+static void uniphier_spi_setup_transfer(struct spi_device *spi,
+                                      struct spi_transfer *t)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+       u32 val;
+
+       priv->error = 0;
+       priv->tx_buf = t->tx_buf;
+       priv->rx_buf = t->rx_buf;
+       priv->tx_bytes = priv->rx_bytes = t->len;
+
+       if (!priv->is_save_param || priv->mode != spi->mode) {
+               uniphier_spi_set_mode(spi);
+               priv->mode = spi->mode;
+       }
+
+       if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) {
+               uniphier_spi_set_transfer_size(spi, t->bits_per_word);
+               priv->bits_per_word = t->bits_per_word;
+       }
+
+       if (!priv->is_save_param || priv->speed_hz != t->speed_hz) {
+               uniphier_spi_set_baudrate(spi, t->speed_hz);
+               priv->speed_hz = t->speed_hz;
+       }
+
+       if (!priv->is_save_param)
+               priv->is_save_param = true;
+
+       /* reset FIFOs */
+       val = SSI_FC_TXFFL | SSI_FC_RXFFL;
+       writel(val, priv->base + SSI_FC);
+}
+
+static void uniphier_spi_send(struct uniphier_spi_priv *priv)
+{
+       int wsize;
+       u32 val = 0;
+
+       wsize = min(bytes_per_word(priv->bits_per_word), priv->tx_bytes);
+       priv->tx_bytes -= wsize;
+
+       if (priv->tx_buf) {
+               switch (wsize) {
+               case 1:
+                       val = *priv->tx_buf;
+                       break;
+               case 2:
+                       val = get_unaligned_le16(priv->tx_buf);
+                       break;
+               case 4:
+                       val = get_unaligned_le32(priv->tx_buf);
+                       break;
+               }
+
+               priv->tx_buf += wsize;
+       }
+
+       writel(val, priv->base + SSI_TXDR);
+}
+
+static void uniphier_spi_recv(struct uniphier_spi_priv *priv)
+{
+       int rsize;
+       u32 val;
+
+       rsize = min(bytes_per_word(priv->bits_per_word), priv->rx_bytes);
+       priv->rx_bytes -= rsize;
+
+       val = readl(priv->base + SSI_RXDR);
+
+       if (priv->rx_buf) {
+               switch (rsize) {
+               case 1:
+                       *priv->rx_buf = val;
+                       break;
+               case 2:
+                       put_unaligned_le16(val, priv->rx_buf);
+                       break;
+               case 4:
+                       put_unaligned_le32(val, priv->rx_buf);
+                       break;
+               }
+
+               priv->rx_buf += rsize;
+       }
+}
+
+static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv)
+{
+       unsigned int tx_count;
+       u32 val;
+
+       tx_count = DIV_ROUND_UP(priv->tx_bytes,
+                               bytes_per_word(priv->bits_per_word));
+       tx_count = min(tx_count, SSI_FIFO_DEPTH);
+
+       /* set fifo threshold */
+       val = readl(priv->base + SSI_FC);
+       val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK);
+       val |= FIELD_PREP(SSI_FC_TXFTH_MASK, tx_count);
+       val |= FIELD_PREP(SSI_FC_RXFTH_MASK, tx_count);
+       writel(val, priv->base + SSI_FC);
+
+       while (tx_count--)
+               uniphier_spi_send(priv);
+}
+
+static void uniphier_spi_set_cs(struct spi_device *spi, bool enable)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+       u32 val;
+
+       val = readl(priv->base + SSI_FPS);
+
+       if (enable)
+               val |= SSI_FPS_FSPOL;
+       else
+               val &= ~SSI_FPS_FSPOL;
+
+       writel(val, priv->base + SSI_FPS);
+}
+
+static int uniphier_spi_transfer_one(struct spi_master *master,
+                                    struct spi_device *spi,
+                                    struct spi_transfer *t)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+       int status;
+
+       uniphier_spi_setup_transfer(spi, t);
+
+       reinit_completion(&priv->xfer_done);
+
+       uniphier_spi_fill_tx_fifo(priv);
+
+       uniphier_spi_irq_enable(spi, SSI_IE_RCIE | SSI_IE_RORIE);
+
+       status = wait_for_completion_timeout(&priv->xfer_done,
+                                            msecs_to_jiffies(SSI_TIMEOUT_MS));
+
+       uniphier_spi_irq_disable(spi, SSI_IE_RCIE | SSI_IE_RORIE);
+
+       if (status < 0)
+               return status;
+
+       return priv->error;
+}
+
+static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+
+       writel(SSI_CTL_EN, priv->base + SSI_CTL);
+
+       return 0;
+}
+
+static int uniphier_spi_unprepare_transfer_hardware(struct spi_master *master)
+{
+       struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+
+       writel(0, priv->base + SSI_CTL);
+
+       return 0;
+}
+
+static irqreturn_t uniphier_spi_handler(int irq, void *dev_id)
+{
+       struct uniphier_spi_priv *priv = dev_id;
+       u32 val, stat;
+
+       stat = readl(priv->base + SSI_IS);
+       val = SSI_IC_TCIC | SSI_IC_RCIC | SSI_IC_RORIC;
+       writel(val, priv->base + SSI_IC);
+
+       /* rx fifo overrun */
+       if (stat & SSI_IS_RORID) {
+               priv->error = -EIO;
+               goto done;
+       }
+
+       /* rx complete */
+       if ((stat & SSI_IS_RCID) && (stat & SSI_IS_RXRS)) {
+               while ((readl(priv->base + SSI_SR) & SSI_SR_RNE) &&
+                               (priv->rx_bytes - priv->tx_bytes) > 0)
+                       uniphier_spi_recv(priv);
+
+               if ((readl(priv->base + SSI_SR) & SSI_SR_RNE) ||
+                               (priv->rx_bytes != priv->tx_bytes)) {
+                       priv->error = -EIO;
+                       goto done;
+               } else if (priv->rx_bytes == 0)
+                       goto done;
+
+               /* next tx transfer */
+               uniphier_spi_fill_tx_fifo(priv);
+
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+
+done:
+       complete(&priv->xfer_done);
+       return IRQ_HANDLED;
+}
+
+static int uniphier_spi_probe(struct platform_device *pdev)
+{
+       struct uniphier_spi_priv *priv;
+       struct spi_master *master;
+       struct resource *res;
+       unsigned long clk_rate;
+       int irq;
+       int ret;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(*priv));
+       if (!master)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, master);
+
+       priv = spi_master_get_devdata(master);
+       priv->master = master;
+       priv->is_save_param = false;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->base)) {
+               ret = PTR_ERR(priv->base);
+               goto out_master_put;
+       }
+
+       priv->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(&pdev->dev, "failed to get clock\n");
+               ret = PTR_ERR(priv->clk);
+               goto out_master_put;
+       }
+
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               goto out_master_put;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get IRQ\n");
+               ret = irq;
+               goto out_disable_clk;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, uniphier_spi_handler,
+                              0, "uniphier-spi", priv);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request IRQ\n");
+               goto out_disable_clk;
+       }
+
+       init_completion(&priv->xfer_done);
+
+       clk_rate = clk_get_rate(priv->clk);
+
+       master->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER);
+       master->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER);
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+       master->dev.of_node = pdev->dev.of_node;
+       master->bus_num = pdev->id;
+       master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+
+       master->set_cs = uniphier_spi_set_cs;
+       master->transfer_one = uniphier_spi_transfer_one;
+       master->prepare_transfer_hardware
+                               = uniphier_spi_prepare_transfer_hardware;
+       master->unprepare_transfer_hardware
+                               = uniphier_spi_unprepare_transfer_hardware;
+       master->num_chipselect = 1;
+
+       ret = devm_spi_register_master(&pdev->dev, master);
+       if (ret)
+               goto out_disable_clk;
+
+       return 0;
+
+out_disable_clk:
+       clk_disable_unprepare(priv->clk);
+
+out_master_put:
+       spi_master_put(master);
+       return ret;
+}
+
+static int uniphier_spi_remove(struct platform_device *pdev)
+{
+       struct uniphier_spi_priv *priv = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(priv->clk);
+
+       return 0;
+}
+
+static const struct of_device_id uniphier_spi_match[] = {
+       { .compatible = "socionext,uniphier-scssi" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_spi_match);
+
+static struct platform_driver uniphier_spi_driver = {
+       .probe = uniphier_spi_probe,
+       .remove = uniphier_spi_remove,
+       .driver = {
+               .name = "uniphier-spi",
+               .of_match_table = uniphier_spi_match,
+       },
+};
+module_platform_driver(uniphier_spi_driver);
+
+MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
+MODULE_AUTHOR("Keiji Hayashibara <hayashibara.keiji@socionext.com>");
+MODULE_DESCRIPTION("Socionext UniPhier SPI controller driver");
+MODULE_LICENSE("GPL v2");
index be6155cba9de721b4a4ff6983bc6d8bc1e37ed3f..8ce04f829a800245bbbe24899b8d27d7db62476e 100644 (file)
@@ -54,7 +54,7 @@ static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi)
 }
 
 static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
-                               u32 v, u8 bits)
+                               u32 v, u8 bits, unsigned flags)
 {
        struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
 
diff --git a/include/linux/spi/adi_spi3.h b/include/linux/spi/adi_spi3.h
deleted file mode 100644 (file)
index c84123a..0000000
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Analog Devices SPI3 controller driver
- *
- * Copyright (c) 2014 Analog Devices Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-#ifndef _ADI_SPI3_H_
-#define _ADI_SPI3_H_
-
-#include <linux/types.h>
-
-/* SPI_CONTROL */
-#define SPI_CTL_EN                  0x00000001    /* Enable */
-#define SPI_CTL_MSTR                0x00000002    /* Master/Slave */
-#define SPI_CTL_PSSE                0x00000004    /* controls modf error in master mode */
-#define SPI_CTL_ODM                 0x00000008    /* Open Drain Mode */
-#define SPI_CTL_CPHA                0x00000010    /* Clock Phase */
-#define SPI_CTL_CPOL                0x00000020    /* Clock Polarity */
-#define SPI_CTL_ASSEL               0x00000040    /* Slave Select Pin Control */
-#define SPI_CTL_SELST               0x00000080    /* Slave Select Polarity in-between transfers */
-#define SPI_CTL_EMISO               0x00000100    /* Enable MISO */
-#define SPI_CTL_SIZE                0x00000600    /* Word Transfer Size */
-#define SPI_CTL_SIZE08              0x00000000    /* SIZE: 8 bits */
-#define SPI_CTL_SIZE16              0x00000200    /* SIZE: 16 bits */
-#define SPI_CTL_SIZE32              0x00000400    /* SIZE: 32 bits */
-#define SPI_CTL_LSBF                0x00001000    /* LSB First */
-#define SPI_CTL_FCEN                0x00002000    /* Flow-Control Enable */
-#define SPI_CTL_FCCH                0x00004000    /* Flow-Control Channel Selection */
-#define SPI_CTL_FCPL                0x00008000    /* Flow-Control Polarity */
-#define SPI_CTL_FCWM                0x00030000    /* Flow-Control Water-Mark */
-#define SPI_CTL_FIFO0               0x00000000    /* FCWM: TFIFO empty or RFIFO Full */
-#define SPI_CTL_FIFO1               0x00010000    /* FCWM: TFIFO 75% or more empty or RFIFO 75% or more full */
-#define SPI_CTL_FIFO2               0x00020000    /* FCWM: TFIFO 50% or more empty or RFIFO 50% or more full */
-#define SPI_CTL_FMODE               0x00040000    /* Fast-mode Enable */
-#define SPI_CTL_MIOM                0x00300000    /* Multiple I/O Mode */
-#define SPI_CTL_MIO_DIS             0x00000000    /* MIOM: Disable */
-#define SPI_CTL_MIO_DUAL            0x00100000    /* MIOM: Enable DIOM (Dual I/O Mode) */
-#define SPI_CTL_MIO_QUAD            0x00200000    /* MIOM: Enable QUAD (Quad SPI Mode) */
-#define SPI_CTL_SOSI                0x00400000    /* Start on MOSI */
-/* SPI_RX_CONTROL */
-#define SPI_RXCTL_REN               0x00000001    /* Receive Channel Enable */
-#define SPI_RXCTL_RTI               0x00000004    /* Receive Transfer Initiate */
-#define SPI_RXCTL_RWCEN             0x00000008    /* Receive Word Counter Enable */
-#define SPI_RXCTL_RDR               0x00000070    /* Receive Data Request */
-#define SPI_RXCTL_RDR_DIS           0x00000000    /* RDR: Disabled */
-#define SPI_RXCTL_RDR_NE            0x00000010    /* RDR: RFIFO not empty */
-#define SPI_RXCTL_RDR_25            0x00000020    /* RDR: RFIFO 25% full */
-#define SPI_RXCTL_RDR_50            0x00000030    /* RDR: RFIFO 50% full */
-#define SPI_RXCTL_RDR_75            0x00000040    /* RDR: RFIFO 75% full */
-#define SPI_RXCTL_RDR_FULL          0x00000050    /* RDR: RFIFO full */
-#define SPI_RXCTL_RDO               0x00000100    /* Receive Data Over-Run */
-#define SPI_RXCTL_RRWM              0x00003000    /* FIFO Regular Water-Mark */
-#define SPI_RXCTL_RWM_0             0x00000000    /* RRWM: RFIFO Empty */
-#define SPI_RXCTL_RWM_25            0x00001000    /* RRWM: RFIFO 25% full */
-#define SPI_RXCTL_RWM_50            0x00002000    /* RRWM: RFIFO 50% full */
-#define SPI_RXCTL_RWM_75            0x00003000    /* RRWM: RFIFO 75% full */
-#define SPI_RXCTL_RUWM              0x00070000    /* FIFO Urgent Water-Mark */
-#define SPI_RXCTL_UWM_DIS           0x00000000    /* RUWM: Disabled */
-#define SPI_RXCTL_UWM_25            0x00010000    /* RUWM: RFIFO 25% full */
-#define SPI_RXCTL_UWM_50            0x00020000    /* RUWM: RFIFO 50% full */
-#define SPI_RXCTL_UWM_75            0x00030000    /* RUWM: RFIFO 75% full */
-#define SPI_RXCTL_UWM_FULL          0x00040000    /* RUWM: RFIFO full */
-/* SPI_TX_CONTROL */
-#define SPI_TXCTL_TEN               0x00000001    /* Transmit Channel Enable */
-#define SPI_TXCTL_TTI               0x00000004    /* Transmit Transfer Initiate */
-#define SPI_TXCTL_TWCEN             0x00000008    /* Transmit Word Counter Enable */
-#define SPI_TXCTL_TDR               0x00000070    /* Transmit Data Request */
-#define SPI_TXCTL_TDR_DIS           0x00000000    /* TDR: Disabled */
-#define SPI_TXCTL_TDR_NF            0x00000010    /* TDR: TFIFO not full */
-#define SPI_TXCTL_TDR_25            0x00000020    /* TDR: TFIFO 25% empty */
-#define SPI_TXCTL_TDR_50            0x00000030    /* TDR: TFIFO 50% empty */
-#define SPI_TXCTL_TDR_75            0x00000040    /* TDR: TFIFO 75% empty */
-#define SPI_TXCTL_TDR_EMPTY         0x00000050    /* TDR: TFIFO empty */
-#define SPI_TXCTL_TDU               0x00000100    /* Transmit Data Under-Run */
-#define SPI_TXCTL_TRWM              0x00003000    /* FIFO Regular Water-Mark */
-#define SPI_TXCTL_RWM_FULL          0x00000000    /* TRWM: TFIFO full */
-#define SPI_TXCTL_RWM_25            0x00001000    /* TRWM: TFIFO 25% empty */
-#define SPI_TXCTL_RWM_50            0x00002000    /* TRWM: TFIFO 50% empty */
-#define SPI_TXCTL_RWM_75            0x00003000    /* TRWM: TFIFO 75% empty */
-#define SPI_TXCTL_TUWM              0x00070000    /* FIFO Urgent Water-Mark */
-#define SPI_TXCTL_UWM_DIS           0x00000000    /* TUWM: Disabled */
-#define SPI_TXCTL_UWM_25            0x00010000    /* TUWM: TFIFO 25% empty */
-#define SPI_TXCTL_UWM_50            0x00020000    /* TUWM: TFIFO 50% empty */
-#define SPI_TXCTL_UWM_75            0x00030000    /* TUWM: TFIFO 75% empty */
-#define SPI_TXCTL_UWM_EMPTY         0x00040000    /* TUWM: TFIFO empty */
-/* SPI_CLOCK */
-#define SPI_CLK_BAUD                0x0000FFFF    /* Baud Rate */
-/* SPI_DELAY */
-#define SPI_DLY_STOP                0x000000FF    /* Transfer delay time in multiples of SCK period */
-#define SPI_DLY_LEADX               0x00000100    /* Extended (1 SCK) LEAD Control */
-#define SPI_DLY_LAGX                0x00000200    /* Extended (1 SCK) LAG control */
-/* SPI_SSEL */
-#define SPI_SLVSEL_SSE1             0x00000002    /* SPISSEL1 Enable */
-#define SPI_SLVSEL_SSE2             0x00000004    /* SPISSEL2 Enable */
-#define SPI_SLVSEL_SSE3             0x00000008    /* SPISSEL3 Enable */
-#define SPI_SLVSEL_SSE4             0x00000010    /* SPISSEL4 Enable */
-#define SPI_SLVSEL_SSE5             0x00000020    /* SPISSEL5 Enable */
-#define SPI_SLVSEL_SSE6             0x00000040    /* SPISSEL6 Enable */
-#define SPI_SLVSEL_SSE7             0x00000080    /* SPISSEL7 Enable */
-#define SPI_SLVSEL_SSEL1            0x00000200    /* SPISSEL1 Value */
-#define SPI_SLVSEL_SSEL2            0x00000400    /* SPISSEL2 Value */
-#define SPI_SLVSEL_SSEL3            0x00000800    /* SPISSEL3 Value */
-#define SPI_SLVSEL_SSEL4            0x00001000    /* SPISSEL4 Value */
-#define SPI_SLVSEL_SSEL5            0x00002000    /* SPISSEL5 Value */
-#define SPI_SLVSEL_SSEL6            0x00004000    /* SPISSEL6 Value */
-#define SPI_SLVSEL_SSEL7            0x00008000    /* SPISSEL7 Value */
-/* SPI_RWC */
-#define SPI_RWC_VALUE               0x0000FFFF    /* Received Word-Count */
-/* SPI_RWCR */
-#define SPI_RWCR_VALUE              0x0000FFFF    /* Received Word-Count Reload */
-/* SPI_TWC */
-#define SPI_TWC_VALUE               0x0000FFFF    /* Transmitted Word-Count */
-/* SPI_TWCR */
-#define SPI_TWCR_VALUE              0x0000FFFF    /* Transmitted Word-Count Reload */
-/* SPI_IMASK */
-#define SPI_IMSK_RUWM               0x00000002    /* Receive Urgent Water-Mark Interrupt Mask */
-#define SPI_IMSK_TUWM               0x00000004    /* Transmit Urgent Water-Mark Interrupt Mask */
-#define SPI_IMSK_ROM                0x00000010    /* Receive Over-Run Error Interrupt Mask */
-#define SPI_IMSK_TUM                0x00000020    /* Transmit Under-Run Error Interrupt Mask */
-#define SPI_IMSK_TCM                0x00000040    /* Transmit Collision Error Interrupt Mask */
-#define SPI_IMSK_MFM                0x00000080    /* Mode Fault Error Interrupt Mask */
-#define SPI_IMSK_RSM                0x00000100    /* Receive Start Interrupt Mask */
-#define SPI_IMSK_TSM                0x00000200    /* Transmit Start Interrupt Mask */
-#define SPI_IMSK_RFM                0x00000400    /* Receive Finish Interrupt Mask */
-#define SPI_IMSK_TFM                0x00000800    /* Transmit Finish Interrupt Mask */
-/* SPI_IMASKCL */
-#define SPI_IMSK_CLR_RUW            0x00000002    /* Receive Urgent Water-Mark Interrupt Mask */
-#define SPI_IMSK_CLR_TUWM           0x00000004    /* Transmit Urgent Water-Mark Interrupt Mask */
-#define SPI_IMSK_CLR_ROM            0x00000010    /* Receive Over-Run Error Interrupt Mask */
-#define SPI_IMSK_CLR_TUM            0x00000020    /* Transmit Under-Run Error Interrupt Mask */
-#define SPI_IMSK_CLR_TCM            0x00000040    /* Transmit Collision Error Interrupt Mask */
-#define SPI_IMSK_CLR_MFM            0x00000080    /* Mode Fault Error Interrupt Mask */
-#define SPI_IMSK_CLR_RSM            0x00000100    /* Receive Start Interrupt Mask */
-#define SPI_IMSK_CLR_TSM            0x00000200    /* Transmit Start Interrupt Mask */
-#define SPI_IMSK_CLR_RFM            0x00000400    /* Receive Finish Interrupt Mask */
-#define SPI_IMSK_CLR_TFM            0x00000800    /* Transmit Finish Interrupt Mask */
-/* SPI_IMASKST */
-#define SPI_IMSK_SET_RUWM           0x00000002    /* Receive Urgent Water-Mark Interrupt Mask */
-#define SPI_IMSK_SET_TUWM           0x00000004    /* Transmit Urgent Water-Mark Interrupt Mask */
-#define SPI_IMSK_SET_ROM            0x00000010    /* Receive Over-Run Error Interrupt Mask */
-#define SPI_IMSK_SET_TUM            0x00000020    /* Transmit Under-Run Error Interrupt Mask */
-#define SPI_IMSK_SET_TCM            0x00000040    /* Transmit Collision Error Interrupt Mask */
-#define SPI_IMSK_SET_MFM            0x00000080    /* Mode Fault Error Interrupt Mask */
-#define SPI_IMSK_SET_RSM            0x00000100    /* Receive Start Interrupt Mask */
-#define SPI_IMSK_SET_TSM            0x00000200    /* Transmit Start Interrupt Mask */
-#define SPI_IMSK_SET_RFM            0x00000400    /* Receive Finish Interrupt Mask */
-#define SPI_IMSK_SET_TFM            0x00000800    /* Transmit Finish Interrupt Mask */
-/* SPI_STATUS */
-#define SPI_STAT_SPIF               0x00000001    /* SPI Finished */
-#define SPI_STAT_RUWM               0x00000002    /* Receive Urgent Water-Mark Breached */
-#define SPI_STAT_TUWM               0x00000004    /* Transmit Urgent Water-Mark Breached */
-#define SPI_STAT_ROE                0x00000010    /* Receive Over-Run Error Indication */
-#define SPI_STAT_TUE                0x00000020    /* Transmit Under-Run Error Indication */
-#define SPI_STAT_TCE                0x00000040    /* Transmit Collision Error Indication */
-#define SPI_STAT_MODF               0x00000080    /* Mode Fault Error Indication */
-#define SPI_STAT_RS                 0x00000100    /* Receive Start Indication */
-#define SPI_STAT_TS                 0x00000200    /* Transmit Start Indication */
-#define SPI_STAT_RF                 0x00000400    /* Receive Finish Indication */
-#define SPI_STAT_TF                 0x00000800    /* Transmit Finish Indication */
-#define SPI_STAT_RFS                0x00007000    /* SPI_RFIFO status */
-#define SPI_STAT_RFIFO_EMPTY        0x00000000    /* RFS: RFIFO Empty */
-#define SPI_STAT_RFIFO_25           0x00001000    /* RFS: RFIFO 25% Full */
-#define SPI_STAT_RFIFO_50           0x00002000    /* RFS: RFIFO 50% Full */
-#define SPI_STAT_RFIFO_75           0x00003000    /* RFS: RFIFO 75% Full */
-#define SPI_STAT_RFIFO_FULL         0x00004000    /* RFS: RFIFO Full */
-#define SPI_STAT_TFS                0x00070000    /* SPI_TFIFO status */
-#define SPI_STAT_TFIFO_FULL         0x00000000    /* TFS: TFIFO full */
-#define SPI_STAT_TFIFO_25           0x00010000    /* TFS: TFIFO 25% empty */
-#define SPI_STAT_TFIFO_50           0x00020000    /* TFS: TFIFO 50% empty */
-#define SPI_STAT_TFIFO_75           0x00030000    /* TFS: TFIFO 75% empty */
-#define SPI_STAT_TFIFO_EMPTY        0x00040000    /* TFS: TFIFO empty */
-#define SPI_STAT_FCS                0x00100000    /* Flow-Control Stall Indication */
-#define SPI_STAT_RFE                0x00400000    /* SPI_RFIFO Empty */
-#define SPI_STAT_TFF                0x00800000    /* SPI_TFIFO Full */
-/* SPI_ILAT */
-#define SPI_ILAT_RUWMI              0x00000002    /* Receive Urgent Water Mark Interrupt */
-#define SPI_ILAT_TUWMI              0x00000004    /* Transmit Urgent Water Mark Interrupt */
-#define SPI_ILAT_ROI                0x00000010    /* Receive Over-Run Error Indication */
-#define SPI_ILAT_TUI                0x00000020    /* Transmit Under-Run Error Indication */
-#define SPI_ILAT_TCI                0x00000040    /* Transmit Collision Error Indication */
-#define SPI_ILAT_MFI                0x00000080    /* Mode Fault Error Indication */
-#define SPI_ILAT_RSI                0x00000100    /* Receive Start Indication */
-#define SPI_ILAT_TSI                0x00000200    /* Transmit Start Indication */
-#define SPI_ILAT_RFI                0x00000400    /* Receive Finish Indication */
-#define SPI_ILAT_TFI                0x00000800    /* Transmit Finish Indication */
-/* SPI_ILATCL */
-#define SPI_ILAT_CLR_RUWMI          0x00000002    /* Receive Urgent Water Mark Interrupt */
-#define SPI_ILAT_CLR_TUWMI          0x00000004    /* Transmit Urgent Water Mark Interrupt */
-#define SPI_ILAT_CLR_ROI            0x00000010    /* Receive Over-Run Error Indication */
-#define SPI_ILAT_CLR_TUI            0x00000020    /* Transmit Under-Run Error Indication */
-#define SPI_ILAT_CLR_TCI            0x00000040    /* Transmit Collision Error Indication */
-#define SPI_ILAT_CLR_MFI            0x00000080    /* Mode Fault Error Indication */
-#define SPI_ILAT_CLR_RSI            0x00000100    /* Receive Start Indication */
-#define SPI_ILAT_CLR_TSI            0x00000200    /* Transmit Start Indication */
-#define SPI_ILAT_CLR_RFI            0x00000400    /* Receive Finish Indication */
-#define SPI_ILAT_CLR_TFI            0x00000800    /* Transmit Finish Indication */
-
-/*
- * adi spi3 registers layout
- */
-struct adi_spi_regs {
-       u32 revid;
-       u32 control;
-       u32 rx_control;
-       u32 tx_control;
-       u32 clock;
-       u32 delay;
-       u32 ssel;
-       u32 rwc;
-       u32 rwcr;
-       u32 twc;
-       u32 twcr;
-       u32 reserved0;
-       u32 emask;
-       u32 emaskcl;
-       u32 emaskst;
-       u32 reserved1;
-       u32 status;
-       u32 elat;
-       u32 elatcl;
-       u32 reserved2;
-       u32 rfifo;
-       u32 reserved3;
-       u32 tfifo;
-};
-
-#define MAX_CTRL_CS          8  /* cs in spi controller */
-
-/* device.platform_data for SSP controller devices */
-struct adi_spi3_master {
-       u16 num_chipselect;
-       u16 pin_req[7];
-};
-
-/* spi_board_info.controller_data for SPI slave devices,
- * copied to spi_device.platform_data ... mostly for dma tuning
- */
-struct adi_spi3_chip {
-       u32 control;
-       u16 cs_chg_udelay; /* Some devices require 16-bit delays */
-       u32 tx_dummy_val; /* tx value for rx only transfer */
-       bool enable_dma;
-};
-
-#endif /* _ADI_SPI3_H_ */
index bb4bd15ae1f637b692df81bfa9b84a99237653f2..62722fb7472d86efd55dfa029f939d7b5b28d941 100644 (file)
@@ -122,7 +122,8 @@ struct spi_mem_op {
 /**
  * struct spi_mem - describes a SPI memory device
  * @spi: the underlying SPI device
- * @drvpriv: spi_mem_drviver private data
+ * @drvpriv: spi_mem_driver private data
+ * @name: name of the SPI memory device
  *
  * Extra information that describe the SPI memory device and may be needed by
  * the controller to properly handle this device should be placed here.
@@ -133,6 +134,7 @@ struct spi_mem_op {
 struct spi_mem {
        struct spi_device *spi;
        void *drvpriv;
+       const char *name;
 };
 
 /**
@@ -165,6 +167,13 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
  *                 limitations)
  * @supports_op: check if an operation is supported by the controller
  * @exec_op: execute a SPI memory operation
+ * @get_name: get a custom name for the SPI mem device from the controller.
+ *           This might be needed if the controller driver has been ported
+ *           to use the SPI mem layer and a custom name is used to keep
+ *           mtdparts compatible.
+ *           Note that if the implementation of this function allocates memory
+ *           dynamically, then it should do so with devm_xxx(), as we don't
+ *           have a ->free_name() function.
  *
  * This interface should be implemented by SPI controllers providing an
  * high-level interface to execute SPI memory operation, which is usually the
@@ -176,6 +185,7 @@ struct spi_controller_mem_ops {
                            const struct spi_mem_op *op);
        int (*exec_op)(struct spi_mem *mem,
                       const struct spi_mem_op *op);
+       const char *(*get_name)(struct spi_mem *mem);
 };
 
 /**
@@ -234,6 +244,8 @@ bool spi_mem_supports_op(struct spi_mem *mem,
 int spi_mem_exec_op(struct spi_mem *mem,
                    const struct spi_mem_op *op);
 
+const char *spi_mem_get_name(struct spi_mem *mem);
+
 int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv,
                                       struct module *owner);
 
index 51d8c060e513ef767125a6268b459df91091b8df..b7e021b274dce572b11a58244ba0376b4c032bbf 100644 (file)
@@ -8,7 +8,7 @@ struct spi_bitbang {
        struct mutex            lock;
        u8                      busy;
        u8                      use_dma;
-       u                     flags;          /* extra spi->mode support */
+       u16                     flags;          /* extra spi->mode support */
 
        struct spi_master       *master;
 
@@ -30,7 +30,8 @@ struct spi_bitbang {
        /* txrx_word[SPI_MODE_*]() just looks like a shift register */
        u32     (*txrx_word[4])(struct spi_device *spi,
                        unsigned nsecs,
-                       u32 word, u8 bits);
+                       u32 word, u8 bits, unsigned flags);
+       int     (*set_line_direction)(struct spi_device *spi, bool output);
 };
 
 /* you can call these default bitbang->master methods from your custom