提交 010b0e70 编写于 作者: L Linus Torvalds

Merge tag 'spi-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi updates from Mark Brown:
 "Quite an active release for the SPI subsystem, lots of small updates
  and fixes scattered about with highlights including:

   - 3-wire support in the GPIO driver.

   - support for setting a custom memory name in the memory mapped flash
     drivers.

   - support for extended mode in the Freescale DSPI controller.

   - support for the non-standard integration with the Microsemi Ocelot
     platform in the DesignWare driver.

   - new driver for the SocioNext UniPhier"

* tag 'spi-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (47 commits)
  spi: davinci: fix a NULL pointer dereference
  spi: spi-mem: Constify spi_mem->name
  mtd: m25p80: Call spi_mem_get_name() to let controller set a custom name
  spi: spi-mem: Extend the SPI mem interface to set a custom memory name
  spi: spi-mem: Fix a typo in the documentation of struct spi_mem
  spi: uniphier: remove unnecessary include headers
  spi: spi-gpio: add SPI_3WIRE support
  spi: add flags parameter to txrx_word function pointers
  spi: add SPI controller driver for UniPhier SoC
  spi: add DT bindings for UniPhier SPI controller
  spi: dw: document Microsemi integration
  spi: img-spfi: Set device select bits for SPFI port state
  spi: omap2-mcspi: remove several redundant variables
  spi: dw-mmio: add MSCC Ocelot support
  spi: dw: export dw_spi_set_cs
  spi: spi-fsl-espi: Log fifo counters on error
  spi: imx: Use the longuest possible burst size when in dynamic_burst
  spi: imx: remove unnecessary check in spi_imx_can_dma
  spi: imx: Use correct number of bytes per words
  spi: imx: Use dynamic bursts only when bits_per_word is 8, 16 or 32
  ...
Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface. Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface.
Required properties: Required properties:
- compatible : "snps,dw-apb-ssi" - compatible : "snps,dw-apb-ssi" or "mscc,<soc>-spi", where soc is "ocelot" or
- reg : The register base for the controller. "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. - interrupts : One interrupt, used by the controller.
- #address-cells : <1>, as required by generic SPI binding. - #address-cells : <1>, as required by generic SPI binding.
- #size-cells : <0>, also as required by generic SPI binding. - #size-cells : <0>, also as required by generic SPI binding.
......
...@@ -7,6 +7,7 @@ Required Properties: ...@@ -7,6 +7,7 @@ Required Properties:
- compatible: should be one of the following. - compatible: should be one of the following.
"rockchip,rv1108-spi" for rv1108 SoCs. "rockchip,rv1108-spi" for rv1108 SoCs.
"rockchip,px30-spi", "rockchip,rk3066-spi" for px30 SoCs.
"rockchip,rk3036-spi" for rk3036 SoCS. "rockchip,rk3036-spi" for rk3036 SoCS.
"rockchip,rk3066-spi" for rk3066 SoCs. "rockchip,rk3066-spi" for rk3066 SoCs.
"rockchip,rk3188-spi" for rk3188 SoCs. "rockchip,rk3188-spi" for rk3188 SoCs.
......
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>;
};
...@@ -199,6 +199,9 @@ static int m25p_probe(struct spi_mem *spimem) ...@@ -199,6 +199,9 @@ static int m25p_probe(struct spi_mem *spimem)
if (data && data->name) if (data && data->name)
nor->mtd.name = 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 /* For some (historical?) reason many platforms provide two different
* names in flash_platform_data: "name" and "type". Quite often name is * names in flash_platform_data: "name" and "type". Quite often name is
* set to "m25p80" and then "type" provides a real chip name. * set to "m25p80" and then "type" provides a real chip name.
......
...@@ -688,6 +688,19 @@ config SPI_TXX9 ...@@ -688,6 +688,19 @@ config SPI_TXX9
help help
SPI driver for Toshiba TXx9 MIPS SoCs 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 config SPI_XCOMM
tristate "Analog Devices AD-FMCOMMS1-EBZ SPI-I2C-bridge driver" tristate "Analog Devices AD-FMCOMMS1-EBZ SPI-I2C-bridge driver"
depends on I2C depends on I2C
......
...@@ -101,6 +101,7 @@ spi-thunderx-objs := spi-cavium.o spi-cavium-thunderx.o ...@@ -101,6 +101,7 @@ spi-thunderx-objs := spi-cavium.o spi-cavium-thunderx.o
obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.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_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
obj-$(CONFIG_SPI_XLP) += spi-xlp.o obj-$(CONFIG_SPI_XLP) += spi-xlp.o
......
...@@ -176,7 +176,7 @@ static void ath79_spi_cleanup(struct spi_device *spi) ...@@ -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, 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); struct ath79_spi *sp = ath79_spidev_to_sp(spi);
u32 ioc = sp->ioc_base; u32 ioc = sp->ioc_base;
......
...@@ -49,22 +49,26 @@ ...@@ -49,22 +49,26 @@
struct spi_bitbang_cs { struct spi_bitbang_cs {
unsigned nsecs; /* (clock cycle time)/2 */ unsigned nsecs; /* (clock cycle time)/2 */
u32 (*txrx_word)(struct spi_device *spi, unsigned nsecs, 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 *, unsigned (*txrx_bufs)(struct spi_device *,
u32 (*txrx_word)( u32 (*txrx_word)(
struct spi_device *spi, struct spi_device *spi,
unsigned nsecs, unsigned nsecs,
u32 word, u8 bits), u32 word, u8 bits,
unsigned, struct spi_transfer *); unsigned flags),
unsigned, struct spi_transfer *,
unsigned);
}; };
static unsigned bitbang_txrx_8( static unsigned bitbang_txrx_8(
struct spi_device *spi, struct spi_device *spi,
u32 (*txrx_word)(struct spi_device *spi, u32 (*txrx_word)(struct spi_device *spi,
unsigned nsecs, unsigned nsecs,
u32 word, u8 bits), u32 word, u8 bits,
unsigned flags),
unsigned ns, unsigned ns,
struct spi_transfer *t struct spi_transfer *t,
unsigned flags
) { ) {
unsigned bits = t->bits_per_word; unsigned bits = t->bits_per_word;
unsigned count = t->len; unsigned count = t->len;
...@@ -76,7 +80,7 @@ static unsigned bitbang_txrx_8( ...@@ -76,7 +80,7 @@ static unsigned bitbang_txrx_8(
if (tx) if (tx)
word = *tx++; word = *tx++;
word = txrx_word(spi, ns, word, bits); word = txrx_word(spi, ns, word, bits, flags);
if (rx) if (rx)
*rx++ = word; *rx++ = word;
count -= 1; count -= 1;
...@@ -88,9 +92,11 @@ static unsigned bitbang_txrx_16( ...@@ -88,9 +92,11 @@ static unsigned bitbang_txrx_16(
struct spi_device *spi, struct spi_device *spi,
u32 (*txrx_word)(struct spi_device *spi, u32 (*txrx_word)(struct spi_device *spi,
unsigned nsecs, unsigned nsecs,
u32 word, u8 bits), u32 word, u8 bits,
unsigned flags),
unsigned ns, unsigned ns,
struct spi_transfer *t struct spi_transfer *t,
unsigned flags
) { ) {
unsigned bits = t->bits_per_word; unsigned bits = t->bits_per_word;
unsigned count = t->len; unsigned count = t->len;
...@@ -102,7 +108,7 @@ static unsigned bitbang_txrx_16( ...@@ -102,7 +108,7 @@ static unsigned bitbang_txrx_16(
if (tx) if (tx)
word = *tx++; word = *tx++;
word = txrx_word(spi, ns, word, bits); word = txrx_word(spi, ns, word, bits, flags);
if (rx) if (rx)
*rx++ = word; *rx++ = word;
count -= 2; count -= 2;
...@@ -114,9 +120,11 @@ static unsigned bitbang_txrx_32( ...@@ -114,9 +120,11 @@ static unsigned bitbang_txrx_32(
struct spi_device *spi, struct spi_device *spi,
u32 (*txrx_word)(struct spi_device *spi, u32 (*txrx_word)(struct spi_device *spi,
unsigned nsecs, unsigned nsecs,
u32 word, u8 bits), u32 word, u8 bits,
unsigned flags),
unsigned ns, unsigned ns,
struct spi_transfer *t struct spi_transfer *t,
unsigned flags
) { ) {
unsigned bits = t->bits_per_word; unsigned bits = t->bits_per_word;
unsigned count = t->len; unsigned count = t->len;
...@@ -128,7 +136,7 @@ static unsigned bitbang_txrx_32( ...@@ -128,7 +136,7 @@ static unsigned bitbang_txrx_32(
if (tx) if (tx)
word = *tx++; word = *tx++;
word = txrx_word(spi, ns, word, bits); word = txrx_word(spi, ns, word, bits, flags);
if (rx) if (rx)
*rx++ = word; *rx++ = word;
count -= 4; count -= 4;
...@@ -235,8 +243,24 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) ...@@ -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; struct spi_bitbang_cs *cs = spi->controller_state;
unsigned nsecs = cs->nsecs; 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);
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
......
...@@ -144,9 +144,9 @@ static void butterfly_chipselect(struct spi_device *spi, int value) ...@@ -144,9 +144,9 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
static u32 static u32
butterfly_txrx_word_mode0(struct spi_device *spi, unsigned nsecs, u32 word, 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);
} }
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
......
...@@ -319,7 +319,7 @@ static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi) ...@@ -319,7 +319,7 @@ static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi)
*/ */
if (cdns_spi_read(xspi, CDNS_SPI_ISR) & if (cdns_spi_read(xspi, CDNS_SPI_ISR) &
CDNS_SPI_IXR_TXFULL) CDNS_SPI_IXR_TXFULL)
usleep_range(10, 20); udelay(10);
if (xspi->txbuf) if (xspi->txbuf)
cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++); cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++);
...@@ -739,7 +739,7 @@ static int __maybe_unused cnds_runtime_resume(struct device *dev) ...@@ -739,7 +739,7 @@ static int __maybe_unused cnds_runtime_resume(struct device *dev)
ret = clk_prepare_enable(xspi->ref_clk); ret = clk_prepare_enable(xspi->ref_clk);
if (ret) { if (ret) {
dev_err(dev, "Cannot enable device clock.\n"); dev_err(dev, "Cannot enable device clock.\n");
clk_disable(xspi->pclk); clk_disable_unprepare(xspi->pclk);
return ret; return ret;
} }
return 0; return 0;
......
...@@ -217,7 +217,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) ...@@ -217,7 +217,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
pdata = &dspi->pdata; pdata = &dspi->pdata;
/* program delay transfers if tx_delay is non zero */ /* program delay transfers if tx_delay is non zero */
if (spicfg->wdelay) if (spicfg && spicfg->wdelay)
spidat1 |= SPIDAT1_WDEL; spidat1 |= SPIDAT1_WDEL;
/* /*
......
...@@ -15,11 +15,13 @@ ...@@ -15,11 +15,13 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/regmap.h>
#include "spi-dw.h" #include "spi-dw.h"
...@@ -28,10 +30,90 @@ ...@@ -28,10 +30,90 @@
struct dw_spi_mmio { struct dw_spi_mmio {
struct dw_spi dws; struct dw_spi dws;
struct clk *clk; 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) 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_mmio *dwsmmio;
struct dw_spi *dws; struct dw_spi *dws;
struct resource *mem; struct resource *mem;
...@@ -99,6 +181,13 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) ...@@ -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); ret = dw_spi_add_host(&pdev->dev, dws);
if (ret) if (ret)
goto out; goto out;
...@@ -123,6 +212,7 @@ static int dw_spi_mmio_remove(struct platform_device *pdev) ...@@ -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[] = { static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "snps,dw-apb-ssi", }, { .compatible = "snps,dw-apb-ssi", },
{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_init},
{ /* end of table */} { /* end of table */}
}; };
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
......
...@@ -133,7 +133,7 @@ static inline void dw_spi_debugfs_remove(struct dw_spi *dws) ...@@ -133,7 +133,7 @@ static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
} }
#endif /* CONFIG_DEBUG_FS */ #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 dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct chip_data *chip = spi_get_ctldata(spi); struct chip_data *chip = spi_get_ctldata(spi);
...@@ -145,6 +145,7 @@ static void dw_spi_set_cs(struct spi_device *spi, bool enable) ...@@ -145,6 +145,7 @@ static void dw_spi_set_cs(struct spi_device *spi, bool enable)
if (!enable) if (!enable)
dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select)); 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 */ /* Return the max entries we can fill into tx fifo */
static inline u32 tx_max(struct dw_spi *dws) static inline u32 tx_max(struct dw_spi *dws)
...@@ -485,6 +486,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -485,6 +486,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
dws->dma_inited = 0; dws->dma_inited = 0;
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
spi_controller_set_devdata(master, dws);
ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
master); master);
if (ret < 0) { if (ret < 0) {
...@@ -505,6 +508,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -505,6 +508,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
master->dev.of_node = dev->of_node; master->dev.of_node = dev->of_node;
master->flags = SPI_MASTER_GPIO_SS; master->flags = SPI_MASTER_GPIO_SS;
if (dws->set_cs)
master->set_cs = dws->set_cs;
/* Basic HW init */ /* Basic HW init */
spi_hw_init(dev, dws); spi_hw_init(dev, dws);
...@@ -518,7 +524,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -518,7 +524,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
} }
} }
spi_controller_set_devdata(master, dws);
ret = devm_spi_register_controller(dev, master); ret = devm_spi_register_controller(dev, master);
if (ret) { if (ret) {
dev_err(&master->dev, "problem registering spi master\n"); dev_err(&master->dev, "problem registering spi master\n");
......
...@@ -112,6 +112,7 @@ struct dw_spi { ...@@ -112,6 +112,7 @@ struct dw_spi {
u32 reg_io_width; /* DR I/O width in bytes */ u32 reg_io_width; /* DR I/O width in bytes */
u16 bus_num; u16 bus_num;
u16 num_cs; /* supported slave numbers */ u16 num_cs; /* supported slave numbers */
void (*set_cs)(struct spi_device *spi, bool enable);
/* Current message transfer state info */ /* Current message transfer state info */
size_t len; size_t len;
...@@ -244,6 +245,7 @@ struct dw_spi_chip { ...@@ -244,6 +245,7 @@ struct dw_spi_chip {
void (*cs_control)(u32 command); 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 int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
extern void dw_spi_remove_host(struct dw_spi *dws); extern void dw_spi_remove_host(struct dw_spi *dws);
extern int dw_spi_suspend_host(struct dw_spi *dws); extern int dw_spi_suspend_host(struct dw_spi *dws);
......
此差异已折叠。
...@@ -547,8 +547,11 @@ static void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events) ...@@ -547,8 +547,11 @@ static void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events)
dev_err(espi->dev, dev_err(espi->dev,
"Transfer done but SPIE_DON isn't set!\n"); "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, "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); complete(&espi->done);
} }
......
...@@ -121,7 +121,10 @@ static inline int getmiso(const struct spi_device *spi) ...@@ -121,7 +121,10 @@ static inline int getmiso(const struct spi_device *spi)
{ {
struct spi_gpio *spi_gpio = spi_to_spi_gpio(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) ...@@ -149,27 +152,27 @@ static inline int getmiso(const struct spi_device *spi)
*/ */
static u32 spi_gpio_txrx_word_mode0(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, 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, 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, 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, ...@@ -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, 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); return bitbang_txrx_be_cpha0(spi, nsecs, 0, flags, word, bits);
} }
static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi, 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); return bitbang_txrx_be_cpha1(spi, nsecs, 0, flags, word, bits);
} }
static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi, 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); return bitbang_txrx_be_cpha0(spi, nsecs, 1, flags, word, bits);
} }
static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi, 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); return bitbang_txrx_be_cpha1(spi, nsecs, 1, flags, word, bits);
} }
...@@ -250,6 +253,16 @@ static int spi_gpio_setup(struct spi_device *spi) ...@@ -250,6 +253,16 @@ static int spi_gpio_setup(struct spi_device *spi)
return status; 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) static void spi_gpio_cleanup(struct spi_device *spi)
{ {
spi_bitbang_cleanup(spi); spi_bitbang_cleanup(spi);
...@@ -395,6 +408,7 @@ static int spi_gpio_probe(struct platform_device *pdev) ...@@ -395,6 +408,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
return status; return status;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); 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->flags = master_flags;
master->bus_num = pdev->id; master->bus_num = pdev->id;
/* The master needs to think there is a chipselect even if not connected */ /* 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) ...@@ -407,6 +421,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
spi_gpio->bitbang.master = master; spi_gpio->bitbang.master = master;
spi_gpio->bitbang.chipselect = spi_gpio_chipselect; 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) { 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; spi_gpio->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_word_mode0;
......
...@@ -419,6 +419,9 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg) ...@@ -419,6 +419,9 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
u32 val; u32 val;
val = spfi_readl(spfi, SPFI_PORT_STATE); 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) if (msg->spi->mode & SPI_CPHA)
val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select); val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
else else
......
...@@ -94,8 +94,7 @@ struct spi_imx_data { ...@@ -94,8 +94,7 @@ struct spi_imx_data {
void *rx_buf; void *rx_buf;
const void *tx_buf; const void *tx_buf;
unsigned int txfifo; /* number of words pushed in tx FIFO */ unsigned int txfifo; /* number of words pushed in tx FIFO */
unsigned int dynamic_burst, read_u32; unsigned int dynamic_burst;
unsigned int word_mask;
/* Slave mode */ /* Slave mode */
bool slave_mode; bool slave_mode;
...@@ -140,6 +139,8 @@ static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \ ...@@ -140,6 +139,8 @@ static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \
*(type *)spi_imx->rx_buf = val; \ *(type *)spi_imx->rx_buf = val; \
spi_imx->rx_buf += sizeof(type); \ spi_imx->rx_buf += sizeof(type); \
} \ } \
\
spi_imx->remainder -= sizeof(type); \
} }
#define MXC_SPI_BUF_TX(type) \ #define MXC_SPI_BUF_TX(type) \
...@@ -203,7 +204,12 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin, ...@@ -203,7 +204,12 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
static int spi_imx_bytes_per_word(const int bits_per_word) 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, 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, ...@@ -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); 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--) { for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
if (!(transfer->len % (i * bytes_per_word))) if (!(transfer->len % (i * bytes_per_word)))
break; break;
} }
if (i == 0)
return false;
spi_imx->wml = i; spi_imx->wml = i;
spi_imx->dynamic_burst = 0; spi_imx->dynamic_burst = 0;
...@@ -291,26 +291,39 @@ static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx) ...@@ -291,26 +291,39 @@ static void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx)
else if (bytes_per_word == 2) else if (bytes_per_word == 2)
val = (val << 16) | (val >> 16); val = (val << 16) | (val >> 16);
#endif #endif
val &= spi_imx->word_mask;
*(u32 *)spi_imx->rx_buf = val; *(u32 *)spi_imx->rx_buf = val;
spi_imx->rx_buf += sizeof(u32); spi_imx->rx_buf += sizeof(u32);
} }
spi_imx->remainder -= sizeof(u32);
} }
static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx) 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); unaligned = spi_imx->remainder % 4;
if (spi_imx->read_u32) {
if (!unaligned) {
spi_imx_buf_rx_swap_u32(spi_imx); spi_imx_buf_rx_swap_u32(spi_imx);
return; return;
} }
if (bytes_per_word == 1) if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {
spi_imx_buf_rx_u8(spi_imx);
else if (bytes_per_word == 2)
spi_imx_buf_rx_u16(spi_imx); 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) 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) ...@@ -322,7 +335,6 @@ static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
if (spi_imx->tx_buf) { if (spi_imx->tx_buf) {
val = *(u32 *)spi_imx->tx_buf; val = *(u32 *)spi_imx->tx_buf;
val &= spi_imx->word_mask;
spi_imx->tx_buf += sizeof(u32); spi_imx->tx_buf += sizeof(u32);
} }
...@@ -340,40 +352,30 @@ static void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx) ...@@ -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) static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
{ {
u32 ctrl, val; int unaligned;
unsigned int bytes_per_word; u32 val = 0;
if (spi_imx->count == spi_imx->remainder) { unaligned = spi_imx->count % 4;
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;
}
ctrl |= (val << MX51_ECSPI_CTRL_BL_OFFSET); if (!unaligned) {
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL); spi_imx_buf_tx_swap_u32(spi_imx);
return;
} }
if (spi_imx->count >= sizeof(u32)) { if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {
spi_imx_buf_tx_swap_u32(spi_imx); spi_imx_buf_tx_u16(spi_imx);
return; 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) writel(val, spi_imx->base + MXC_CSPITXDATA);
spi_imx_buf_tx_u8(spi_imx);
else if (bytes_per_word == 2)
spi_imx_buf_tx_u16(spi_imx);
} }
static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx) 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) ...@@ -392,6 +394,8 @@ static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
spi_imx->rx_buf += n_bytes; spi_imx->rx_buf += n_bytes;
spi_imx->slave_burst -= 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) 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) ...@@ -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); 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) 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) { while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) {
if (!spi_imx->count) if (!spi_imx->count)
break; 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; break;
spi_imx->tx(spi_imx); spi_imx->tx(spi_imx);
spi_imx->txfifo++; spi_imx->txfifo++;
...@@ -1102,27 +1146,20 @@ static int spi_imx_setupxfer(struct spi_device *spi, ...@@ -1102,27 +1146,20 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->bits_per_word = t->bits_per_word; spi_imx->bits_per_word = t->bits_per_word;
spi_imx->speed_hz = t->speed_hz; spi_imx->speed_hz = t->speed_hz;
/* Initialize the functions for transfer */ /*
if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode) { * Initialize the functions for transfer. To transfer non byte-aligned
u32 mask; * words, we have to use multiple word-size bursts, we can't use
* dynamic_burst in that case.
spi_imx->dynamic_burst = 0; */
spi_imx->remainder = 0; if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode &&
spi_imx->read_u32 = 1; (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->rx = spi_imx_buf_rx_swap;
spi_imx->tx = spi_imx_buf_tx_swap; spi_imx->tx = spi_imx_buf_tx_swap;
spi_imx->dynamic_burst = 1; 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 { } else {
if (spi_imx->bits_per_word <= 8) { if (spi_imx->bits_per_word <= 8) {
spi_imx->rx = spi_imx_buf_rx_u8; spi_imx->rx = spi_imx_buf_rx_u8;
...@@ -1134,6 +1171,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, ...@@ -1134,6 +1171,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->rx = spi_imx_buf_rx_u32; spi_imx->rx = spi_imx_buf_rx_u32;
spi_imx->tx = spi_imx_buf_tx_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)) 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, ...@@ -1317,6 +1355,7 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
spi_imx->rx_buf = transfer->rx_buf; spi_imx->rx_buf = transfer->rx_buf;
spi_imx->count = transfer->len; spi_imx->count = transfer->len;
spi_imx->txfifo = 0; spi_imx->txfifo = 0;
spi_imx->remainder = 0;
reinit_completion(&spi_imx->xfer_done); reinit_completion(&spi_imx->xfer_done);
...@@ -1354,6 +1393,7 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi, ...@@ -1354,6 +1393,7 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi,
spi_imx->rx_buf = transfer->rx_buf; spi_imx->rx_buf = transfer->rx_buf;
spi_imx->count = transfer->len; spi_imx->count = transfer->len;
spi_imx->txfifo = 0; spi_imx->txfifo = 0;
spi_imx->remainder = 0;
reinit_completion(&spi_imx->xfer_done); reinit_completion(&spi_imx->xfer_done);
spi_imx->slave_aborted = false; spi_imx->slave_aborted = false;
......
...@@ -188,9 +188,10 @@ static void lm70_chipselect(struct spi_device *spi, int value) ...@@ -188,9 +188,10 @@ static void lm70_chipselect(struct spi_device *spi, int value)
/* /*
* Our actual bitbanger routine. * 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) static void spi_lm70llp_attach(struct parport *p)
......
...@@ -310,6 +310,24 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -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); 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 * spi_mem_adjust_op_size() - Adjust the data size of a SPI mem operation to
* match controller limitations * match controller limitations
...@@ -344,6 +362,7 @@ static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv) ...@@ -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) static int spi_mem_probe(struct spi_device *spi)
{ {
struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver);
struct spi_controller *ctlr = spi->controller;
struct spi_mem *mem; struct spi_mem *mem;
mem = devm_kzalloc(&spi->dev, sizeof(*mem), GFP_KERNEL); mem = devm_kzalloc(&spi->dev, sizeof(*mem), GFP_KERNEL);
...@@ -351,6 +370,15 @@ static int spi_mem_probe(struct spi_device *spi) ...@@ -351,6 +370,15 @@ static int spi_mem_probe(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
mem->spi = spi; 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); spi_set_drvdata(spi, mem);
return memdrv->probe(mem); return memdrv->probe(mem);
......
...@@ -398,11 +398,9 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi, ...@@ -398,11 +398,9 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
{ {
struct omap2_mcspi *mcspi; struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_dma *mcspi_dma;
unsigned int count;
mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select]; mcspi_dma = &mcspi->dma_channels[spi->chip_select];
count = xfer->len;
if (mcspi_dma->dma_tx) { if (mcspi_dma->dma_tx) {
struct dma_async_tx_descriptor *tx; struct dma_async_tx_descriptor *tx;
...@@ -582,7 +580,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -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_cs *cs = spi->controller_state;
struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_dma *mcspi_dma;
unsigned int count; unsigned int count;
u32 l;
u8 *rx; u8 *rx;
const u8 *tx; const u8 *tx;
struct dma_slave_config cfg; struct dma_slave_config cfg;
...@@ -595,8 +592,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -595,8 +592,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select]; mcspi_dma = &mcspi->dma_channels[spi->chip_select];
l = mcspi_cached_chconf0(spi);
if (cs->word_len <= 8) { if (cs->word_len <= 8) {
width = DMA_SLAVE_BUSWIDTH_1_BYTE; width = DMA_SLAVE_BUSWIDTH_1_BYTE;
...@@ -676,7 +671,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -676,7 +671,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
static unsigned static unsigned
omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
{ {
struct omap2_mcspi *mcspi;
struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi_cs *cs = spi->controller_state;
unsigned int count, c; unsigned int count, c;
u32 l; u32 l;
...@@ -686,7 +680,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -686,7 +680,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
void __iomem *chstat_reg; void __iomem *chstat_reg;
int word_len; int word_len;
mcspi = spi_master_get_devdata(spi->master);
count = xfer->len; count = xfer->len;
c = count; c = count;
word_len = cs->word_len; word_len = cs->word_len;
...@@ -883,13 +876,11 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, ...@@ -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_cs *cs = spi->controller_state;
struct omap2_mcspi *mcspi; struct omap2_mcspi *mcspi;
struct spi_master *spi_cntrl;
u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0; u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
u8 word_len = spi->bits_per_word; u8 word_len = spi->bits_per_word;
u32 speed_hz = spi->max_speed_hz; u32 speed_hz = spi->max_speed_hz;
mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master);
spi_cntrl = mcspi->master;
if (t != NULL && t->bits_per_word) if (t != NULL && t->bits_per_word)
word_len = t->bits_per_word; word_len = t->bits_per_word;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/gpio.h> #include <linux/gpio.h>
...@@ -681,9 +682,9 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -681,9 +682,9 @@ static int orion_spi_probe(struct platform_device *pdev)
goto out_rel_axi_clk; goto out_rel_axi_clk;
} }
/* Scan all SPI devices of this controller for direct mapped devices */
for_each_available_child_of_node(pdev->dev.of_node, np) { for_each_available_child_of_node(pdev->dev.of_node, np) {
u32 cs; u32 cs;
int cs_gpio;
/* Get chip-select number from the "reg" property */ /* Get chip-select number from the "reg" property */
status = of_property_read_u32(np, "reg", &cs); status = of_property_read_u32(np, "reg", &cs);
...@@ -694,6 +695,44 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -694,6 +695,44 @@ static int orion_spi_probe(struct platform_device *pdev)
continue; continue;
} }
/*
* Initialize the CS GPIO:
* - properly request the actual GPIO signal
* - de-assert the logical signal so that all GPIO CS lines
* are inactive when probing for slaves
* - find an unused physical CS which will be driven for any
* slave which uses a CS GPIO
*/
cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", cs);
if (cs_gpio > 0) {
char *gpio_name;
int cs_flags;
if (spi->unused_hw_gpio == -1) {
dev_info(&pdev->dev,
"Selected unused HW CS#%d for any GPIO CSes\n",
cs);
spi->unused_hw_gpio = cs;
}
gpio_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%s-CS%d", dev_name(&pdev->dev), cs);
if (!gpio_name) {
status = -ENOMEM;
goto out_rel_axi_clk;
}
cs_flags = of_property_read_bool(np, "spi-cs-high") ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
status = devm_gpio_request_one(&pdev->dev, cs_gpio,
cs_flags, gpio_name);
if (status) {
dev_err(&pdev->dev,
"Can't request GPIO for CS %d\n", cs);
goto out_rel_axi_clk;
}
}
/* /*
* Check if an address is configured for this SPI device. If * Check if an address is configured for this SPI device. If
* not, the MBus mapping via the 'ranges' property in the 'soc' * not, the MBus mapping via the 'ranges' property in the 'soc'
...@@ -740,44 +779,8 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -740,44 +779,8 @@ static int orion_spi_probe(struct platform_device *pdev)
if (status < 0) if (status < 0)
goto out_rel_pm; goto out_rel_pm;
if (master->cs_gpios) {
int i;
for (i = 0; i < master->num_chipselect; ++i) {
char *gpio_name;
if (!gpio_is_valid(master->cs_gpios[i])) {
continue;
}
gpio_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%s-CS%d", dev_name(&pdev->dev), i);
if (!gpio_name) {
status = -ENOMEM;
goto out_rel_master;
}
status = devm_gpio_request(&pdev->dev,
master->cs_gpios[i], gpio_name);
if (status) {
dev_err(&pdev->dev,
"Can't request GPIO for CS %d\n",
master->cs_gpios[i]);
goto out_rel_master;
}
if (spi->unused_hw_gpio == -1) {
dev_info(&pdev->dev,
"Selected unused HW CS#%d for any GPIO CSes\n",
i);
spi->unused_hw_gpio = i;
}
}
}
return status; return status;
out_rel_master:
spi_unregister_master(master);
out_rel_pm: out_rel_pm:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
out_rel_axi_clk: out_rel_axi_clk:
......
...@@ -1391,6 +1391,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { ...@@ -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, 0x31c2), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x31c4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x31c4), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x31c6), 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 */ /* APL */
{ PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
......
...@@ -49,6 +49,7 @@ struct sh_msiof_spi_priv { ...@@ -49,6 +49,7 @@ struct sh_msiof_spi_priv {
struct platform_device *pdev; struct platform_device *pdev;
struct sh_msiof_spi_info *info; struct sh_msiof_spi_info *info;
struct completion done; struct completion done;
struct completion done_txdma;
unsigned int tx_fifo_size; unsigned int tx_fifo_size;
unsigned int rx_fifo_size; unsigned int rx_fifo_size;
unsigned int min_div_pow; unsigned int min_div_pow;
...@@ -649,19 +650,21 @@ static int sh_msiof_slave_abort(struct spi_master *master) ...@@ -649,19 +650,21 @@ static int sh_msiof_slave_abort(struct spi_master *master)
p->slave_aborted = true; p->slave_aborted = true;
complete(&p->done); complete(&p->done);
complete(&p->done_txdma);
return 0; return 0;
} }
static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p) static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p,
struct completion *x)
{ {
if (spi_controller_is_slave(p->master)) { if (spi_controller_is_slave(p->master)) {
if (wait_for_completion_interruptible(&p->done) || if (wait_for_completion_interruptible(x) ||
p->slave_aborted) { p->slave_aborted) {
dev_dbg(&p->pdev->dev, "interrupted\n"); dev_dbg(&p->pdev->dev, "interrupted\n");
return -EINTR; return -EINTR;
} }
} else { } else {
if (!wait_for_completion_timeout(&p->done, HZ)) { if (!wait_for_completion_timeout(x, HZ)) {
dev_err(&p->pdev->dev, "timeout\n"); dev_err(&p->pdev->dev, "timeout\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -711,7 +714,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, ...@@ -711,7 +714,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
} }
/* wait for tx fifo to be emptied / rx fifo to be filled */ /* wait for tx fifo to be emptied / rx fifo to be filled */
ret = sh_msiof_wait_for_completion(p); ret = sh_msiof_wait_for_completion(p, &p->done);
if (ret) if (ret)
goto stop_reset; goto stop_reset;
...@@ -740,10 +743,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, ...@@ -740,10 +743,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
static void sh_msiof_dma_complete(void *arg) static void sh_msiof_dma_complete(void *arg)
{ {
struct sh_msiof_spi_priv *p = arg; complete(arg);
sh_msiof_write(p, IER, 0);
complete(&p->done);
} }
static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
...@@ -764,7 +764,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, ...@@ -764,7 +764,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
return -EAGAIN; return -EAGAIN;
desc_rx->callback = sh_msiof_dma_complete; desc_rx->callback = sh_msiof_dma_complete;
desc_rx->callback_param = p; desc_rx->callback_param = &p->done;
cookie = dmaengine_submit(desc_rx); cookie = dmaengine_submit(desc_rx);
if (dma_submit_error(cookie)) if (dma_submit_error(cookie))
return cookie; return cookie;
...@@ -782,13 +782,8 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, ...@@ -782,13 +782,8 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
goto no_dma_tx; goto no_dma_tx;
} }
if (rx) { desc_tx->callback = sh_msiof_dma_complete;
/* No callback */ desc_tx->callback_param = &p->done_txdma;
desc_tx->callback = NULL;
} else {
desc_tx->callback = sh_msiof_dma_complete;
desc_tx->callback_param = p;
}
cookie = dmaengine_submit(desc_tx); cookie = dmaengine_submit(desc_tx);
if (dma_submit_error(cookie)) { if (dma_submit_error(cookie)) {
ret = cookie; ret = cookie;
...@@ -805,6 +800,8 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, ...@@ -805,6 +800,8 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
sh_msiof_write(p, IER, ier_bits); sh_msiof_write(p, IER, ier_bits);
reinit_completion(&p->done); reinit_completion(&p->done);
if (tx)
reinit_completion(&p->done_txdma);
p->slave_aborted = false; p->slave_aborted = false;
/* Now start DMA */ /* Now start DMA */
...@@ -819,17 +816,24 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, ...@@ -819,17 +816,24 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
goto stop_dma; goto stop_dma;
} }
/* wait for tx/rx DMA completion */ if (tx) {
ret = sh_msiof_wait_for_completion(p); /* wait for tx DMA completion */
if (ret) ret = sh_msiof_wait_for_completion(p, &p->done_txdma);
goto stop_reset; if (ret)
goto stop_reset;
}
if (!rx) { if (rx) {
reinit_completion(&p->done); /* wait for rx DMA completion */
sh_msiof_write(p, IER, IER_TEOFE); ret = sh_msiof_wait_for_completion(p, &p->done);
if (ret)
goto stop_reset;
sh_msiof_write(p, IER, 0);
} else {
/* wait for tx fifo to be emptied */ /* wait for tx fifo to be emptied */
ret = sh_msiof_wait_for_completion(p); sh_msiof_write(p, IER, IER_TEOFE);
ret = sh_msiof_wait_for_completion(p, &p->done);
if (ret) if (ret)
goto stop_reset; goto stop_reset;
} }
...@@ -1327,6 +1331,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) ...@@ -1327,6 +1331,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
p->min_div_pow = chipdata->min_div_pow; p->min_div_pow = chipdata->min_div_pow;
init_completion(&p->done); init_completion(&p->done);
init_completion(&p->done_txdma);
p->clk = devm_clk_get(&pdev->dev, NULL); p->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(p->clk)) { if (IS_ERR(p->clk)) {
......
...@@ -80,27 +80,31 @@ static inline u32 getmiso(struct spi_device *dev) ...@@ -80,27 +80,31 @@ static inline u32 getmiso(struct spi_device *dev)
#include "spi-bitbang-txrx.h" #include "spi-bitbang-txrx.h"
static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi, 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, 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, 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, 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) static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
......
// 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");
...@@ -54,7 +54,7 @@ static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi) ...@@ -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, 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); struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
......
/*
* 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_ */
...@@ -124,7 +124,8 @@ struct spi_mem_op { ...@@ -124,7 +124,8 @@ struct spi_mem_op {
/** /**
* struct spi_mem - describes a SPI memory device * struct spi_mem - describes a SPI memory device
* @spi: the underlying SPI 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 * Extra information that describe the SPI memory device and may be needed by
* the controller to properly handle this device should be placed here. * the controller to properly handle this device should be placed here.
...@@ -135,6 +136,7 @@ struct spi_mem_op { ...@@ -135,6 +136,7 @@ struct spi_mem_op {
struct spi_mem { struct spi_mem {
struct spi_device *spi; struct spi_device *spi;
void *drvpriv; void *drvpriv;
const char *name;
}; };
/** /**
...@@ -167,6 +169,13 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem) ...@@ -167,6 +169,13 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
* limitations) * limitations)
* @supports_op: check if an operation is supported by the controller * @supports_op: check if an operation is supported by the controller
* @exec_op: execute a SPI memory operation * @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 * This interface should be implemented by SPI controllers providing an
* high-level interface to execute SPI memory operation, which is usually the * high-level interface to execute SPI memory operation, which is usually the
...@@ -178,6 +187,7 @@ struct spi_controller_mem_ops { ...@@ -178,6 +187,7 @@ struct spi_controller_mem_ops {
const struct spi_mem_op *op); const struct spi_mem_op *op);
int (*exec_op)(struct spi_mem *mem, int (*exec_op)(struct spi_mem *mem,
const struct spi_mem_op *op); const struct spi_mem_op *op);
const char *(*get_name)(struct spi_mem *mem);
}; };
/** /**
...@@ -236,6 +246,8 @@ bool spi_mem_supports_op(struct spi_mem *mem, ...@@ -236,6 +246,8 @@ bool spi_mem_supports_op(struct spi_mem *mem,
int spi_mem_exec_op(struct spi_mem *mem, int spi_mem_exec_op(struct spi_mem *mem,
const struct spi_mem_op *op); 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, int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv,
struct module *owner); struct module *owner);
......
...@@ -8,7 +8,7 @@ struct spi_bitbang { ...@@ -8,7 +8,7 @@ struct spi_bitbang {
struct mutex lock; struct mutex lock;
u8 busy; u8 busy;
u8 use_dma; u8 use_dma;
u8 flags; /* extra spi->mode support */ u16 flags; /* extra spi->mode support */
struct spi_master *master; struct spi_master *master;
...@@ -30,7 +30,8 @@ struct spi_bitbang { ...@@ -30,7 +30,8 @@ struct spi_bitbang {
/* txrx_word[SPI_MODE_*]() just looks like a shift register */ /* txrx_word[SPI_MODE_*]() just looks like a shift register */
u32 (*txrx_word[4])(struct spi_device *spi, u32 (*txrx_word[4])(struct spi_device *spi,
unsigned nsecs, 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 /* you can call these default bitbang->master methods from your custom
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册