spi: Updates for v4.19

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.
 -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAltxVvQTHGJyb29uaWVA
 a2VybmVsLm9yZwAKCRAk1otyXVSH0MTxB/9EwdE8WUVn3TPaNAEqFx1ddOmAaC+u
 SRlqSY7OdBMZ8dK6yzV332fVVa52n2kq2AoFClMTo1GWaGVW2Wo836tUt3u38dh5
 WnRlOLfsIxvLYzALJ8somjSeyCUm1zPzK/byj1LYThzss1uGF90isJEndHJVqdP7
 z9XRc3fVcR/7hcTYCJwTmKn6q6Gkb/13rrRUfVOaRqMts6Dk3diSSu7RFJs+I2KD
 JhcWVWylqQ+qtPuUCGBvPcymSNx4nn1ugJdI+eXXrvSuSvhl5Lw4ORUBaeLvhL76
 2ARvvPzf1PXKQeG5Gjy9sk4kt1YVBRGqiPrrLMlo8M1zjbRQxkeiYq3O
 =lnvR
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2018-08-14 12:01:08 -07:00
commit 010b0e708e
31 changed files with 1258 additions and 679 deletions

View 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.

View 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.

View file

@ -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>;
};

View file

@ -199,6 +199,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.

View 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

View 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

View 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;

View file

@ -49,22 +49,26 @@
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;
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
bitbang = spi_master_get_devdata(spi->master);
if (bitbang->set_line_direction) {
int err;
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);
}
/*----------------------------------------------------------------------*/

View 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);
}
/*----------------------------------------------------------------------*/

View file

@ -319,7 +319,7 @@ static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi)
*/
if (cdns_spi_read(xspi, CDNS_SPI_ISR) &
CDNS_SPI_IXR_TXFULL)
usleep_range(10, 20);
udelay(10);
if (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)
ret = clk_prepare_enable(xspi->ref_clk);
if (ret) {
dev_err(dev, "Cannot enable device clock.\n");
clk_disable(xspi->pclk);
clk_disable_unprepare(xspi->pclk);
return ret;
}
return 0;

View file

@ -217,7 +217,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
pdata = &dspi->pdata;
/* program delay transfers if tx_delay is non zero */
if (spicfg->wdelay)
if (spicfg && spicfg->wdelay)
spidat1 |= SPIDAT1_WDEL;
/*

View file

@ -15,11 +15,13 @@
#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"
@ -28,10 +30,90 @@
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);

View 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)
@ -485,6 +486,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
dws->dma_inited = 0;
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),
master);
if (ret < 0) {
@ -505,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);
@ -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);
if (ret) {
dev_err(&master->dev, "problem registering spi master\n");

View 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);

View 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>
@ -38,10 +30,6 @@
#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)
@ -86,11 +75,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
@ -107,21 +101,31 @@
#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 inline int is_double_byte_mode(struct fsl_dspi *dspi)
static u32 dspi_pop_tx(struct fsl_dspi *dspi)
{
unsigned int val;
u32 txdata = 0;
regmap_read(dspi->regmap, SPI_CTAR(0), &val);
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;
}
return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
{
u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
if (dspi->len > 0)
cmd |= SPI_PUSHR_CMD_CONT;
return cmd << 16 | data;
}
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;
u16 cmd = dspi->tx_cmd;
regmap_read(dspi->regmap, SPI_POPR, &val);
d = SPI_POPR_RXDATA(val);
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;
u32 data = dspi_pop_tx(dspi);
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);
}
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;
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
tx_count++;
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);
u32 rxdata = 0;
while ((dspi->rx < dspi->rx_end)
&& (rx_count < DSPI_FIFO_SIZE)) {
if (rx_word && (dspi->rx_end - dspi->rx) == 1)
rx_word = 0;
dspi_data_from_popr(dspi, rx_word);
rx_count++;
}
return rx_count;
}
static int dspi_tcfq_write(struct fsl_dspi *dspi)
{
int tx_word;
u32 dspi_pushr = 0;
tx_word = is_double_byte_mode(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;
}
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;
regmap_read(dspi->regmap, SPI_POPR, &rxdata);
return rxdata;
}
static void dspi_tcfq_read(struct fsl_dspi *dspi)
{
int rx_word = is_double_byte_mode(dspi);
dspi_push_rx(dspi, fifo_read(dspi));
}
if (rx_word && (dspi->rx_end - dspi->rx) == 1)
rx_word = 0;
static void dspi_eoq_write(struct fsl_dspi *dspi)
{
int fifo_size = DSPI_FIFO_SIZE;
dspi_data_from_popr(dspi, rx_word);
/* 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);
}
}
static void dspi_eoq_read(struct fsl_dspi *dspi)
{
int fifo_size = DSPI_FIFO_SIZE;
/* 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 {
@ -943,16 +914,62 @@ static int dspi_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
static const struct regmap_range dspi_volatile_ranges[] = {
regmap_reg_range(SPI_MCR, SPI_TCR),
regmap_reg_range(SPI_SR, SPI_SR),
regmap_reg_range(SPI_PUSHR, SPI_RXFR3),
};
static const struct regmap_access_table dspi_volatile_table = {
.yes_ranges = dspi_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(dspi_volatile_ranges),
};
static const struct regmap_config dspi_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0x88,
.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)
@ -961,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;
@ -980,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) {
@ -1013,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)) {
@ -1020,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));
@ -1029,19 +1053,17 @@ static int dspi_probe(struct platform_device *pdev)
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;
}
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;
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");
@ -1054,6 +1076,21 @@ static int dspi_probe(struct platform_device *pdev)
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_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_clk_put;
}
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
ret = dspi_request_dma(dspi, res->start);
if (ret < 0) {

View 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);
}

View 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;

View 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

View 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 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
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 (spi_imx->count >= sizeof(u32)) {
if (!unaligned) {
spi_imx_buf_tx_swap_u32(spi_imx);
return;
}
bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
if (bytes_per_word == 1)
spi_imx_buf_tx_u8(spi_imx);
else if (bytes_per_word == 2)
if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {
spi_imx_buf_tx_u16(spi_imx);
return;
}
while (unaligned--) {
if (spi_imx->tx_buf) {
val |= *(u8 *)spi_imx->tx_buf << (8 * unaligned);
spi_imx->tx_buf++;
}
spi_imx->count--;
}
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;
/*
* 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)) {
spi_imx->dynamic_burst = 0;
spi_imx->remainder = 0;
spi_imx->read_u32 = 1;
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;

View 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)

View 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);

View 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;

View file

@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/sizes.h>
#include <linux/gpio.h>
@ -681,9 +682,9 @@ static int orion_spi_probe(struct platform_device *pdev)
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) {
u32 cs;
int cs_gpio;
/* Get chip-select number from the "reg" property */
status = of_property_read_u32(np, "reg", &cs);
@ -694,6 +695,44 @@ static int orion_spi_probe(struct platform_device *pdev)
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
* not, the MBus mapping via the 'ranges' property in the 'soc'
@ -740,44 +779,8 @@ static int orion_spi_probe(struct platform_device *pdev)
if (status < 0)
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;
out_rel_master:
spi_unregister_master(master);
out_rel_pm:
pm_runtime_disable(&pdev->dev);
out_rel_axi_clk:

View 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 },

View file

@ -49,6 +49,7 @@ struct sh_msiof_spi_priv {
struct platform_device *pdev;
struct sh_msiof_spi_info *info;
struct completion done;
struct completion done_txdma;
unsigned int tx_fifo_size;
unsigned int rx_fifo_size;
unsigned int min_div_pow;
@ -649,19 +650,21 @@ static int sh_msiof_slave_abort(struct spi_master *master)
p->slave_aborted = true;
complete(&p->done);
complete(&p->done_txdma);
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 (wait_for_completion_interruptible(&p->done) ||
if (wait_for_completion_interruptible(x) ||
p->slave_aborted) {
dev_dbg(&p->pdev->dev, "interrupted\n");
return -EINTR;
}
} else {
if (!wait_for_completion_timeout(&p->done, HZ)) {
if (!wait_for_completion_timeout(x, HZ)) {
dev_err(&p->pdev->dev, "timeout\n");
return -ETIMEDOUT;
}
@ -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 */
ret = sh_msiof_wait_for_completion(p);
ret = sh_msiof_wait_for_completion(p, &p->done);
if (ret)
goto stop_reset;
@ -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)
{
struct sh_msiof_spi_priv *p = arg;
sh_msiof_write(p, IER, 0);
complete(&p->done);
complete(arg);
}
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;
desc_rx->callback = sh_msiof_dma_complete;
desc_rx->callback_param = p;
desc_rx->callback_param = &p->done;
cookie = dmaengine_submit(desc_rx);
if (dma_submit_error(cookie))
return cookie;
@ -782,13 +782,8 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
goto no_dma_tx;
}
if (rx) {
/* No callback */
desc_tx->callback = NULL;
} else {
desc_tx->callback = sh_msiof_dma_complete;
desc_tx->callback_param = p;
}
desc_tx->callback = sh_msiof_dma_complete;
desc_tx->callback_param = &p->done_txdma;
cookie = dmaengine_submit(desc_tx);
if (dma_submit_error(cookie)) {
ret = cookie;
@ -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);
reinit_completion(&p->done);
if (tx)
reinit_completion(&p->done_txdma);
p->slave_aborted = false;
/* Now start DMA */
@ -819,17 +816,24 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
goto stop_dma;
}
/* wait for tx/rx DMA completion */
ret = sh_msiof_wait_for_completion(p);
if (ret)
goto stop_reset;
if (tx) {
/* wait for tx DMA completion */
ret = sh_msiof_wait_for_completion(p, &p->done_txdma);
if (ret)
goto stop_reset;
}
if (!rx) {
reinit_completion(&p->done);
sh_msiof_write(p, IER, IER_TEOFE);
if (rx) {
/* wait for rx DMA completion */
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 */
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)
goto stop_reset;
}
@ -1327,6 +1331,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
p->min_div_pow = chipdata->min_div_pow;
init_completion(&p->done);
init_completion(&p->done_txdma);
p->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(p->clk)) {

View 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)

523
drivers/spi/spi-uniphier.c Normal file
View file

@ -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");

View 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);

View file

@ -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_ */

View file

@ -124,7 +124,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.
@ -135,6 +136,7 @@ struct spi_mem_op {
struct spi_mem {
struct spi_device *spi;
void *drvpriv;
const char *name;
};
/**
@ -167,6 +169,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
@ -178,6 +187,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);
};
/**
@ -236,6 +246,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);

View file

@ -8,7 +8,7 @@ struct spi_bitbang {
struct mutex lock;
u8 busy;
u8 use_dma;
u8 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