Quite a quiet release for SPI, there are no changes at all to the core
 and not that many changes to drivers.  Highlights of those driver
 changes include:
 
  - SH MSIOF support for GPIO chip selects contributed by Geert
    Uytterhoeven.
  - Full duplex support for a3700 contributed by Maxime Chevallier.
  - Support for DMA transfers on Atmel devices that require a bounce
    buffer contributed by Radu Pirea.
 -----BEGIN PGP SIGNATURE-----
 
 iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAlpvGpcTHGJyb29uaWVA
 a2VybmVsLm9yZwAKCRAk1otyXVSH0EFXB/9A9mzuFpMpurIcyUyq9pwmu2Xss+Fo
 0/YiyrXLMfmH+6lEaCekfNOsHYEbb9KnbaNThxD1QUEt7wQ5G3UAt1vPHzMbRd/w
 C6JRoTnEZHxj7mmIanXzqzNVhp2qhlQWr0BGwte46VyDci7RZEtqHKjxdeIpS+ll
 Ye4zIKXaO4h6Unpv9o9KMOHG6SHyTuA9QP1Pi/6sGYV67uCw4NPnonacCAC1M++L
 gLaVwWw7IBELg0X9gqH9mn6kTV0ppGGSflm3zFjY+f8EZmCiZ4wVMjPYi+ZTfGrS
 tQVTF4kvm/W0bPcqxHv3dd5ShCKIEu7g3xVshFu9M8TivMzW80eZfuF2
 =Kj+5
 -----END PGP SIGNATURE-----

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

Pull spi updates from Mark Brown:
 "Quite a quiet release for SPI, there are no changes at all to the core
  and not that many changes to drivers. Highlights of those driver
  changes include:

   - SH MSIOF support for GPIO chip selects contributed by Geert
     Uytterhoeven.

   - Full duplex support for a3700 contributed by Maxime Chevallier.

   - Support for DMA transfers on Atmel devices that require a bounce
     buffer contributed by Radu Pirea"

* tag 'spi-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (31 commits)
  spi: dw: Remove unused members from struct chip_data
  spi: orion: Fix a resource leak if the optional "axi" clk is deferred
  spi: a3700: Remove endianness swapping for full-duplex transfers
  spi: a3700: Remove endianness swapping functions when accessing FIFOs
  spi: a3700: Add full-duplex support
  spi: a3700: Allow to enable or disable FIFO mode
  spi: a3700: Set frequency limits at startup
  spi: a3700: Clear DATA_OUT when performing a read
  spi: orion: Fix clock resource by adding an optional bus clock
  spi: s3c64xx: add SPDX identifier
  spi: imx: do not access registers while clocks disabled
  spi: atmel: Implements transfers with bounce buffer
  spi: sh-msiof: Fix timeout failures for TX-only DMA transfers
  spi: spi-fsl-dspi: account for const type of of_device_id.data
  spi: bcm53xx: simplify reading SPI data
  spi: sirf: account for const type of of_device_id.data
  spi: pxa2xx: Use gpiod_put() not gpiod_free()
  spi: pxa2xx: avoid redundant gpio_to_desc(desc_to_gpio()) round-trip
  spi: sh-msiof: Document hardware limitations related to chip selects
  spi: sh-msiof: Implement cs-gpios configuration
  ...
This commit is contained in:
Linus Torvalds 2018-01-29 11:30:16 -08:00
Родитель 0bae60fcee 35a8f1a94d
Коммит 8e3264710c
21 изменённых файлов: 378 добавлений и 132 удалений

Просмотреть файл

@ -36,7 +36,21 @@ Required properties:
Optional properties:
- clocks : Must contain a reference to the functional clock.
- num-cs : Total number of chip-selects (default is 1)
- num-cs : Total number of chip selects (default is 1).
Up to 3 native chip selects are supported:
0: MSIOF_SYNC
1: MSIOF_SS1
2: MSIOF_SS2
Hardware limitations related to chip selects:
- Native chip selects are always deasserted in
between transfers that are part of the same
message. Use cs-gpios to work around this.
- All slaves using native chip selects must use the
same spi-cs-high configuration. Use cs-gpios to
work around this.
- When using GPIO chip selects, at least one native
chip select must be left unused, as it will be
driven anyway.
- dmas : Must contain a list of two references to DMA
specifiers, one for transmission, and one for
reception.

Просмотреть файл

@ -27,7 +27,9 @@ The Meson SPICC is generic SPI controller for general purpose Full-Duplex
communications with dedicated 16 words RX/TX PIO FIFOs.
Required properties:
- compatible: should be "amlogic,meson-gx-spicc" on Amlogic GX SoCs.
- compatible: should be:
"amlogic,meson-gx-spicc" on Amlogic GX and compatible SoCs.
"amlogic,meson-axg-spicc" on Amlogic AXG and compatible SoCs
- reg: physical base address and length of the controller registers
- interrupts: The interrupt specifier
- clock-names: Must contain "core"

Просмотреть файл

@ -18,8 +18,17 @@ Required properties:
The eight register sets following the control registers refer to
chip-select lines 0 through 7 respectively.
- cell-index : Which of multiple SPI controllers is this.
- clocks : pointers to the reference clocks for this device, the first
one is the one used for the clock on the spi bus, the
second one is optional and is the clock used for the
functional part of the controller
Optional properties:
- interrupts : Is currently not used.
- clock-names : names of used clocks, mandatory if the second clock is
used, the name must be "core", and "axi" (the latter
is only for Armada 7K/8K).
Example:
spi@10600 {

Просмотреть файл

@ -2,7 +2,7 @@ Xilinx SPI controller Device Tree Bindings
-------------------------------------------------
Required properties:
- compatible : Should be "xlnx,xps-spi-2.00.a" or "xlnx,xps-spi-2.00.b"
- compatible : Should be "xlnx,xps-spi-2.00.a", "xlnx,xps-spi-2.00.b" or "xlnx,axi-quad-spi-1.00.a"
- reg : Physical base address and size of SPI registers map.
- interrupts : Property with a value describing the interrupt
number.

Просмотреть файл

@ -27,6 +27,8 @@
#define DRIVER_NAME "armada_3700_spi"
#define A3700_SPI_MAX_SPEED_HZ 100000000
#define A3700_SPI_MAX_PRESCALE 30
#define A3700_SPI_TIMEOUT 10
/* SPI Register Offest */
@ -184,12 +186,15 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
return 0;
}
static void a3700_spi_fifo_mode_set(struct a3700_spi *a3700_spi)
static void a3700_spi_fifo_mode_set(struct a3700_spi *a3700_spi, bool enable)
{
u32 val;
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
val |= A3700_SPI_FIFO_MODE;
if (enable)
val |= A3700_SPI_FIFO_MODE;
else
val &= ~A3700_SPI_FIFO_MODE;
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
}
@ -297,7 +302,7 @@ static int a3700_spi_init(struct a3700_spi *a3700_spi)
a3700_spi_deactivate_cs(a3700_spi, i);
/* Enable FIFO mode */
a3700_spi_fifo_mode_set(a3700_spi);
a3700_spi_fifo_mode_set(a3700_spi, true);
/* Set SPI mode */
a3700_spi_mode_set(a3700_spi, master->mode_bits);
@ -416,15 +421,20 @@ static void a3700_spi_transfer_setup(struct spi_device *spi,
struct spi_transfer *xfer)
{
struct a3700_spi *a3700_spi;
unsigned int byte_len;
a3700_spi = spi_master_get_devdata(spi->master);
a3700_spi_clock_set(a3700_spi, xfer->speed_hz);
byte_len = xfer->bits_per_word >> 3;
/* Use 4 bytes long transfers. Each transfer method has its way to deal
* with the remaining bytes for non 4-bytes aligned transfers.
*/
a3700_spi_bytelen_set(a3700_spi, 4);
a3700_spi_fifo_thres_set(a3700_spi, byte_len);
/* Initialize the working buffers */
a3700_spi->tx_buf = xfer->tx_buf;
a3700_spi->rx_buf = xfer->rx_buf;
a3700_spi->buf_len = xfer->len;
}
static void a3700_spi_set_cs(struct spi_device *spi, bool enable)
@ -491,7 +501,7 @@ static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi)
u32 val;
while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) {
val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf);
val = *(u32 *)a3700_spi->tx_buf;
spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
a3700_spi->buf_len -= 4;
a3700_spi->tx_buf += 4;
@ -514,9 +524,8 @@ static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi)
while (!a3700_is_rfifo_empty(a3700_spi) && a3700_spi->buf_len) {
val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG);
if (a3700_spi->buf_len >= 4) {
u32 data = le32_to_cpu(val);
memcpy(a3700_spi->rx_buf, &data, 4);
memcpy(a3700_spi->rx_buf, &val, 4);
a3700_spi->buf_len -= 4;
a3700_spi->rx_buf += 4;
@ -579,27 +588,26 @@ static int a3700_spi_prepare_message(struct spi_master *master,
if (ret)
return ret;
a3700_spi_bytelen_set(a3700_spi, 4);
a3700_spi_mode_set(a3700_spi, spi->mode);
return 0;
}
static int a3700_spi_transfer_one(struct spi_master *master,
static int a3700_spi_transfer_one_fifo(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
int ret = 0, timeout = A3700_SPI_TIMEOUT;
unsigned int nbits = 0;
unsigned int nbits = 0, byte_len;
u32 val;
a3700_spi_transfer_setup(spi, xfer);
/* Make sure we use FIFO mode */
a3700_spi_fifo_mode_set(a3700_spi, true);
a3700_spi->tx_buf = xfer->tx_buf;
a3700_spi->rx_buf = xfer->rx_buf;
a3700_spi->buf_len = xfer->len;
/* Configure FIFO thresholds */
byte_len = xfer->bits_per_word >> 3;
a3700_spi_fifo_thres_set(a3700_spi, byte_len);
if (xfer->tx_buf)
nbits = xfer->tx_nbits;
@ -615,6 +623,11 @@ static int a3700_spi_transfer_one(struct spi_master *master,
a3700_spi_header_set(a3700_spi);
if (xfer->rx_buf) {
/* Clear WFIFO, since it's last 2 bytes are shifted out during
* a read operation
*/
spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, 0);
/* Set read data length */
spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG,
a3700_spi->buf_len);
@ -729,6 +742,63 @@ out:
return ret;
}
static int a3700_spi_transfer_one_full_duplex(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
u32 val;
/* Disable FIFO mode */
a3700_spi_fifo_mode_set(a3700_spi, false);
while (a3700_spi->buf_len) {
/* When we have less than 4 bytes to transfer, switch to 1 byte
* mode. This is reset after each transfer
*/
if (a3700_spi->buf_len < 4)
a3700_spi_bytelen_set(a3700_spi, 1);
if (a3700_spi->byte_len == 1)
val = *a3700_spi->tx_buf;
else
val = *(u32 *)a3700_spi->tx_buf;
spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
/* Wait for all the data to be shifted in / out */
while (!(spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG) &
A3700_SPI_XFER_DONE))
cpu_relax();
val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG);
memcpy(a3700_spi->rx_buf, &val, a3700_spi->byte_len);
a3700_spi->buf_len -= a3700_spi->byte_len;
a3700_spi->tx_buf += a3700_spi->byte_len;
a3700_spi->rx_buf += a3700_spi->byte_len;
}
spi_finalize_current_transfer(master);
return 0;
}
static int a3700_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
a3700_spi_transfer_setup(spi, xfer);
if (xfer->tx_buf && xfer->rx_buf)
return a3700_spi_transfer_one_full_duplex(master, spi, xfer);
return a3700_spi_transfer_one_fifo(master, spi, xfer);
}
static int a3700_spi_unprepare_message(struct spi_master *master,
struct spi_message *message)
{
@ -778,7 +848,6 @@ static int a3700_spi_probe(struct platform_device *pdev)
master->transfer_one = a3700_spi_transfer_one;
master->unprepare_message = a3700_spi_unprepare_message;
master->set_cs = a3700_spi_set_cs;
master->flags = SPI_MASTER_HALF_DUPLEX;
master->mode_bits |= (SPI_RX_DUAL | SPI_TX_DUAL |
SPI_RX_QUAD | SPI_TX_QUAD);
@ -818,6 +887,11 @@ static int a3700_spi_probe(struct platform_device *pdev)
goto error;
}
master->max_speed_hz = min_t(unsigned long, A3700_SPI_MAX_SPEED_HZ,
clk_get_rate(spi->clk));
master->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk),
A3700_SPI_MAX_PRESCALE);
ret = a3700_spi_init(spi);
if (ret)
goto error_clk;

Просмотреть файл

@ -291,6 +291,10 @@ struct atmel_spi {
struct spi_transfer *current_transfer;
int current_remaining_bytes;
int done_status;
dma_addr_t dma_addr_rx_bbuf;
dma_addr_t dma_addr_tx_bbuf;
void *addr_rx_bbuf;
void *addr_tx_bbuf;
struct completion xfer_completion;
@ -436,6 +440,11 @@ static void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock)
spin_unlock_irqrestore(&as->lock, as->flags);
}
static inline bool atmel_spi_is_vmalloc_xfer(struct spi_transfer *xfer)
{
return is_vmalloc_addr(xfer->tx_buf) || is_vmalloc_addr(xfer->rx_buf);
}
static inline bool atmel_spi_use_dma(struct atmel_spi *as,
struct spi_transfer *xfer)
{
@ -448,7 +457,12 @@ static bool atmel_spi_can_dma(struct spi_master *master,
{
struct atmel_spi *as = spi_master_get_devdata(master);
return atmel_spi_use_dma(as, xfer);
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5))
return atmel_spi_use_dma(as, xfer) &&
!atmel_spi_is_vmalloc_xfer(xfer);
else
return atmel_spi_use_dma(as, xfer);
}
static int atmel_spi_dma_slave_config(struct atmel_spi *as,
@ -594,6 +608,11 @@ static void dma_callback(void *data)
struct spi_master *master = data;
struct atmel_spi *as = spi_master_get_devdata(master);
if (is_vmalloc_addr(as->current_transfer->rx_buf) &&
IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
memcpy(as->current_transfer->rx_buf, as->addr_rx_bbuf,
as->current_transfer->len);
}
complete(&as->xfer_completion);
}
@ -744,17 +763,41 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
goto err_exit;
/* Send both scatterlists */
rxdesc = dmaengine_prep_slave_sg(rxchan,
xfer->rx_sg.sgl, xfer->rx_sg.nents,
DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (atmel_spi_is_vmalloc_xfer(xfer) &&
IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
rxdesc = dmaengine_prep_slave_single(rxchan,
as->dma_addr_rx_bbuf,
xfer->len,
DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
} else {
rxdesc = dmaengine_prep_slave_sg(rxchan,
xfer->rx_sg.sgl,
xfer->rx_sg.nents,
DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
}
if (!rxdesc)
goto err_dma;
txdesc = dmaengine_prep_slave_sg(txchan,
xfer->tx_sg.sgl, xfer->tx_sg.nents,
DMA_TO_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (atmel_spi_is_vmalloc_xfer(xfer) &&
IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
memcpy(as->addr_tx_bbuf, xfer->tx_buf, xfer->len);
txdesc = dmaengine_prep_slave_single(txchan,
as->dma_addr_tx_bbuf,
xfer->len, DMA_TO_DEVICE,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
} else {
txdesc = dmaengine_prep_slave_sg(txchan,
xfer->tx_sg.sgl,
xfer->tx_sg.nents,
DMA_TO_DEVICE,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
}
if (!txdesc)
goto err_dma;
@ -1426,27 +1469,7 @@ static void atmel_get_caps(struct atmel_spi *as)
as->caps.is_spi2 = version > 0x121;
as->caps.has_wdrbt = version >= 0x210;
#ifdef CONFIG_SOC_SAM_V4_V5
/*
* Atmel SoCs based on ARM9 (SAM9x) cores should not use spi_map_buf()
* since this later function tries to map buffers with dma_map_sg()
* even if they have not been allocated inside DMA-safe areas.
* On SoCs based on Cortex A5 (SAMA5Dx), it works anyway because for
* those ARM cores, the data cache follows the PIPT model.
* Also the L2 cache controller of SAMA5D2 uses the PIPT model too.
* In case of PIPT caches, there cannot be cache aliases.
* However on ARM9 cores, the data cache follows the VIVT model, hence
* the cache aliases issue can occur when buffers are allocated from
* DMA-unsafe areas, by vmalloc() for instance, where cache coherency is
* not taken into account or at least not handled completely (cache
* lines of aliases are not invalidated).
* This is not a theorical issue: it was reproduced when trying to mount
* a UBI file-system on a at91sam9g35ek board.
*/
as->caps.has_dma_support = false;
#else
as->caps.has_dma_support = version >= 0x212;
#endif
as->caps.has_pdc_support = version < 0x212;
}
@ -1592,6 +1615,30 @@ static int atmel_spi_probe(struct platform_device *pdev)
as->use_pdc = true;
}
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
as->addr_rx_bbuf = dma_alloc_coherent(&pdev->dev,
SPI_MAX_DMA_XFER,
&as->dma_addr_rx_bbuf,
GFP_KERNEL | GFP_DMA);
if (!as->addr_rx_bbuf) {
as->use_dma = false;
} else {
as->addr_tx_bbuf = dma_alloc_coherent(&pdev->dev,
SPI_MAX_DMA_XFER,
&as->dma_addr_tx_bbuf,
GFP_KERNEL | GFP_DMA);
if (!as->addr_tx_bbuf) {
as->use_dma = false;
dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
as->addr_rx_bbuf,
as->dma_addr_rx_bbuf);
}
}
if (!as->use_dma)
dev_info(master->dev.parent,
" can not allocate dma coherent memory\n");
}
if (as->caps.has_dma_support && !as->use_dma)
dev_info(&pdev->dev, "Atmel SPI Controller using PIO only\n");
@ -1664,6 +1711,14 @@ static int atmel_spi_remove(struct platform_device *pdev)
if (as->use_dma) {
atmel_spi_stop_dma(master);
atmel_spi_release_dma(master);
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
as->addr_tx_bbuf,
as->dma_addr_tx_bbuf);
dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
as->addr_rx_bbuf,
as->dma_addr_rx_bbuf);
}
}
spin_lock_irq(&as->lock);

Просмотреть файл

@ -27,8 +27,6 @@ struct bcm53xxspi {
struct bcma_device *core;
struct spi_master *master;
void __iomem *mmio_base;
size_t read_offset;
bool bspi; /* Boot SPI mode with memory mapping */
};
@ -172,8 +170,6 @@ static void bcm53xxspi_buf_write(struct bcm53xxspi *b53spi, u8 *w_buf,
if (!cont)
bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0);
b53spi->read_offset = len;
}
static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf,
@ -182,10 +178,10 @@ static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf,
u32 tmp;
int i;
for (i = 0; i < b53spi->read_offset + len; i++) {
for (i = 0; i < len; i++) {
tmp = B53SPI_CDRAM_CONT | B53SPI_CDRAM_PCS_DISABLE_ALL |
B53SPI_CDRAM_PCS_DSCK;
if (!cont && i == b53spi->read_offset + len - 1)
if (!cont && i == len - 1)
tmp &= ~B53SPI_CDRAM_CONT;
tmp &= ~0x1;
/* Command Register File */
@ -194,8 +190,7 @@ static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf,
/* Set queue pointers */
bcm53xxspi_write(b53spi, B53SPI_MSPI_NEWQP, 0);
bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP,
b53spi->read_offset + len - 1);
bcm53xxspi_write(b53spi, B53SPI_MSPI_ENDQP, len - 1);
if (cont)
bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 1);
@ -214,13 +209,11 @@ static void bcm53xxspi_buf_read(struct bcm53xxspi *b53spi, u8 *r_buf,
bcm53xxspi_write(b53spi, B53SPI_MSPI_WRITE_LOCK, 0);
for (i = 0; i < len; ++i) {
int offset = b53spi->read_offset + i;
u16 reg = B53SPI_MSPI_RXRAM + 4 * (1 + i * 2);
/* Data stored in the transmit register file LSB */
r_buf[i] = (u8)bcm53xxspi_read(b53spi, B53SPI_MSPI_RXRAM + 4 * (1 + offset * 2));
r_buf[i] = (u8)bcm53xxspi_read(b53spi, reg);
}
b53spi->read_offset = 0;
}
static int bcm53xxspi_transfer_one(struct spi_master *master,
@ -238,7 +231,8 @@ static int bcm53xxspi_transfer_one(struct spi_master *master,
left = t->len;
while (left) {
size_t to_write = min_t(size_t, 16, left);
bool cont = left - to_write > 0;
bool cont = !spi_transfer_is_last(master, t) ||
left - to_write > 0;
bcm53xxspi_buf_write(b53spi, buf, to_write, cont);
left -= to_write;
@ -250,9 +244,9 @@ static int bcm53xxspi_transfer_one(struct spi_master *master,
buf = (u8 *)t->rx_buf;
left = t->len;
while (left) {
size_t to_read = min_t(size_t, 16 - b53spi->read_offset,
left);
bool cont = left - to_read > 0;
size_t to_read = min_t(size_t, 16, left);
bool cont = !spi_transfer_is_last(master, t) ||
left - to_read > 0;
bcm53xxspi_buf_read(b53spi, buf, to_read, cont);
left -= to_read;

Просмотреть файл

@ -945,6 +945,8 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_master;
}
init_completion(&dspi->done);
ret = platform_get_irq(pdev, 0);
if (ret == 0)
ret = -EINVAL;
@ -1021,8 +1023,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
dspi->get_rx = davinci_spi_rx_buf_u8;
dspi->get_tx = davinci_spi_tx_buf_u8;
init_completion(&dspi->done);
/* Reset In/OUT SPI module */
iowrite32(0, dspi->base + SPIGCR0);
udelay(100);

Просмотреть файл

@ -30,13 +30,11 @@
/* Slave spi_dev related */
struct chip_data {
u8 cs; /* chip select pin */
u8 tmode; /* TR/TO/RO/EEPROM */
u8 type; /* SPI/SSP/MicroWire */
u8 poll_mode; /* 1 means use poll mode */
u8 enable_dma;
u16 clk_div; /* baud rate divider */
u32 speed_hz; /* baud rate */
void (*cs_control)(u32 command);

Просмотреть файл

@ -903,10 +903,9 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
}
static const struct of_device_id fsl_dspi_dt_ids[] = {
{ .compatible = "fsl,vf610-dspi", .data = (void *)&vf610_data, },
{ .compatible = "fsl,ls1021a-v1.0-dspi",
.data = (void *)&ls1021a_v1_data, },
{ .compatible = "fsl,ls2085a-dspi", .data = (void *)&ls2085a_data, },
{ .compatible = "fsl,vf610-dspi", .data = &vf610_data, },
{ .compatible = "fsl,ls1021a-v1.0-dspi", .data = &ls1021a_v1_data, },
{ .compatible = "fsl,ls2085a-dspi", .data = &ls2085a_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids);
@ -980,7 +979,7 @@ static int dspi_probe(struct platform_device *pdev)
master->dev.of_node = pdev->dev.of_node;
master->cleanup = dspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA;
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);

Просмотреть файл

@ -1622,6 +1622,11 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->devtype_data->intctrl(spi_imx, 0);
master->dev.of_node = pdev->dev.of_node;
ret = spi_bitbang_start(&spi_imx->bitbang);
if (ret) {
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
goto out_clk_put;
}
/* Request GPIO CS lines, if any */
if (!spi_imx->slave_mode && master->cs_gpios) {
@ -1640,12 +1645,6 @@ static int spi_imx_probe(struct platform_device *pdev)
}
}
ret = spi_bitbang_start(&spi_imx->bitbang);
if (ret) {
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
goto out_clk_put;
}
dev_info(&pdev->dev, "probed\n");
clk_disable(spi_imx->clk_ipg);
@ -1668,12 +1667,23 @@ static int spi_imx_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
int ret;
spi_bitbang_stop(&spi_imx->bitbang);
ret = clk_enable(spi_imx->clk_per);
if (ret)
return ret;
ret = clk_enable(spi_imx->clk_ipg);
if (ret) {
clk_disable(spi_imx->clk_per);
return ret;
}
writel(0, spi_imx->base + MXC_CSPICTRL);
clk_unprepare(spi_imx->clk_ipg);
clk_unprepare(spi_imx->clk_per);
clk_disable_unprepare(spi_imx->clk_ipg);
clk_disable_unprepare(spi_imx->clk_per);
spi_imx_sdma_exit(spi_imx);
spi_master_put(master);

Просмотреть файл

@ -198,8 +198,10 @@ static int jcore_spi_probe(struct platform_device *pdev)
/* Register our spi controller */
err = devm_spi_register_master(&pdev->dev, master);
if (err)
if (err) {
clk_disable(clk);
goto exit;
}
return 0;

Просмотреть файл

@ -599,6 +599,7 @@ static int meson_spicc_remove(struct platform_device *pdev)
static const struct of_device_id meson_spicc_of_match[] = {
{ .compatible = "amlogic,meson-gx-spicc", },
{ .compatible = "amlogic,meson-axg-spicc", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, meson_spicc_of_match);

Просмотреть файл

@ -94,6 +94,7 @@ struct orion_spi {
struct spi_master *master;
void __iomem *base;
struct clk *clk;
struct clk *axi_clk;
const struct orion_spi_dev *devdata;
struct orion_direct_acc direct_access[ORION_NUM_CHIPSELECTS];
@ -634,6 +635,16 @@ static int orion_spi_probe(struct platform_device *pdev)
if (status)
goto out;
/* The following clock is only used by some SoCs */
spi->axi_clk = devm_clk_get(&pdev->dev, "axi");
if (IS_ERR(spi->axi_clk) &&
PTR_ERR(spi->axi_clk) == -EPROBE_DEFER) {
status = -EPROBE_DEFER;
goto out_rel_clk;
}
if (!IS_ERR(spi->axi_clk))
clk_prepare_enable(spi->axi_clk);
tclk_hz = clk_get_rate(spi->clk);
/*
@ -658,7 +669,7 @@ static int orion_spi_probe(struct platform_device *pdev)
spi->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(spi->base)) {
status = PTR_ERR(spi->base);
goto out_rel_clk;
goto out_rel_axi_clk;
}
/* Scan all SPI devices of this controller for direct mapped devices */
@ -696,7 +707,7 @@ static int orion_spi_probe(struct platform_device *pdev)
PAGE_SIZE);
if (!spi->direct_access[cs].vaddr) {
status = -ENOMEM;
goto out_rel_clk;
goto out_rel_axi_clk;
}
spi->direct_access[cs].size = PAGE_SIZE;
@ -724,6 +735,8 @@ static int orion_spi_probe(struct platform_device *pdev)
out_rel_pm:
pm_runtime_disable(&pdev->dev);
out_rel_axi_clk:
clk_disable_unprepare(spi->axi_clk);
out_rel_clk:
clk_disable_unprepare(spi->clk);
out:
@ -738,6 +751,7 @@ static int orion_spi_remove(struct platform_device *pdev)
struct orion_spi *spi = spi_master_get_devdata(master);
pm_runtime_get_sync(&pdev->dev);
clk_disable_unprepare(spi->axi_clk);
clk_disable_unprepare(spi->clk);
spi_unregister_master(master);
@ -754,6 +768,7 @@ static int orion_spi_runtime_suspend(struct device *dev)
struct spi_master *master = dev_get_drvdata(dev);
struct orion_spi *spi = spi_master_get_devdata(master);
clk_disable_unprepare(spi->axi_clk);
clk_disable_unprepare(spi->clk);
return 0;
}
@ -763,6 +778,8 @@ static int orion_spi_runtime_resume(struct device *dev)
struct spi_master *master = dev_get_drvdata(dev);
struct orion_spi *spi = spi_master_get_devdata(master);
if (!IS_ERR(spi->axi_clk))
clk_prepare_enable(spi->axi_clk);
return clk_prepare_enable(spi->clk);
}
#endif

Просмотреть файл

@ -1237,7 +1237,7 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
* different chip_info, release previously requested GPIO
*/
if (chip->gpiod_cs) {
gpio_free(desc_to_gpio(chip->gpiod_cs));
gpiod_put(chip->gpiod_cs);
chip->gpiod_cs = NULL;
}
@ -1417,7 +1417,7 @@ static void cleanup(struct spi_device *spi)
if (drv_data->ssp_type != CE4100_SSP && !drv_data->cs_gpiods &&
chip->gpiod_cs)
gpio_free(desc_to_gpio(chip->gpiod_cs));
gpiod_put(chip->gpiod_cs);
kfree(chip);
}

Просмотреть файл

@ -1,17 +1,7 @@
/*
* Copyright (C) 2009 Samsung Electronics Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
*
* 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.
*
* 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.
*/
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (c) 2009 Samsung Electronics Co., Ltd.
// Jaswinder Singh <jassi.brar@samsung.com>
#include <linux/init.h>
#include <linux/module.h>

Просмотреть файл

@ -19,6 +19,7 @@
#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@ -55,9 +56,14 @@ struct sh_msiof_spi_priv {
void *rx_dma_page;
dma_addr_t tx_dma_addr;
dma_addr_t rx_dma_addr;
unsigned short unused_ss;
bool native_cs_inited;
bool native_cs_high;
bool slave_aborted;
};
#define MAX_SS 3 /* Maximum number of native chip selects */
#define TMDR1 0x00 /* Transmit Mode Register 1 */
#define TMDR2 0x04 /* Transmit Mode Register 2 */
#define TMDR3 0x08 /* Transmit Mode Register 3 */
@ -91,6 +97,8 @@ struct sh_msiof_spi_priv {
#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */
/* TMDR1 */
#define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */
#define TMDR1_SYNCCH_MASK 0xc000000 /* Synchronization Signal Channel Select */
#define TMDR1_SYNCCH_SHIFT 26 /* 0=MSIOF_SYNC, 1=MSIOF_SS1, 2=MSIOF_SS2 */
/* TMDR2 and RMDR2 */
#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */
@ -324,7 +332,7 @@ static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p)
return val;
}
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, u32 ss,
u32 cpol, u32 cpha,
u32 tx_hi_z, u32 lsb_first, u32 cs_high)
{
@ -342,10 +350,13 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
tmp |= lsb_first << MDR1_BITLSB_SHIFT;
tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
if (spi_controller_is_slave(p->master))
if (spi_controller_is_slave(p->master)) {
sh_msiof_write(p, TMDR1, tmp | TMDR1_PCON);
else
sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
} else {
sh_msiof_write(p, TMDR1,
tmp | MDR1_TRMD | TMDR1_PCON |
(ss < MAX_SS ? ss : 0) << TMDR1_SYNCCH_SHIFT);
}
if (p->master->flags & SPI_MASTER_MUST_TX) {
/* These bits are reserved if RX needs TX */
tmp &= ~0x0000ffff;
@ -528,8 +539,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
{
struct device_node *np = spi->master->dev.of_node;
struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
pm_runtime_get_sync(&p->pdev->dev);
u32 clr, set, tmp;
if (!np) {
/*
@ -539,19 +549,31 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
spi->cs_gpio = (uintptr_t)spi->controller_data;
}
/* Configure pins before deasserting CS */
sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
!!(spi->mode & SPI_CPHA),
!!(spi->mode & SPI_3WIRE),
!!(spi->mode & SPI_LSB_FIRST),
!!(spi->mode & SPI_CS_HIGH));
if (gpio_is_valid(spi->cs_gpio)) {
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
return 0;
}
if (spi->cs_gpio >= 0)
gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
if (spi_controller_is_slave(p->master))
return 0;
if (p->native_cs_inited &&
(p->native_cs_high == !!(spi->mode & SPI_CS_HIGH)))
return 0;
/* Configure native chip select mode/polarity early */
clr = MDR1_SYNCMD_MASK;
set = MDR1_TRMD | TMDR1_PCON | MDR1_SYNCMD_SPI;
if (spi->mode & SPI_CS_HIGH)
clr |= BIT(MDR1_SYNCAC_SHIFT);
else
set |= BIT(MDR1_SYNCAC_SHIFT);
pm_runtime_get_sync(&p->pdev->dev);
tmp = sh_msiof_read(p, TMDR1) & ~clr;
sh_msiof_write(p, TMDR1, tmp | set);
pm_runtime_put(&p->pdev->dev);
p->native_cs_high = spi->mode & SPI_CS_HIGH;
p->native_cs_inited = true;
return 0;
}
@ -560,13 +582,20 @@ static int sh_msiof_prepare_message(struct spi_master *master,
{
struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
const struct spi_device *spi = msg->spi;
u32 ss, cs_high;
/* Configure pins before asserting CS */
sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
if (gpio_is_valid(spi->cs_gpio)) {
ss = p->unused_ss;
cs_high = p->native_cs_high;
} else {
ss = spi->chip_select;
cs_high = !!(spi->mode & SPI_CS_HIGH);
}
sh_msiof_spi_set_pin_regs(p, ss, !!(spi->mode & SPI_CPOL),
!!(spi->mode & SPI_CPHA),
!!(spi->mode & SPI_3WIRE),
!!(spi->mode & SPI_LSB_FIRST),
!!(spi->mode & SPI_CS_HIGH));
!!(spi->mode & SPI_LSB_FIRST), cs_high);
return 0;
}
@ -784,11 +813,21 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
goto stop_dma;
}
/* wait for tx fifo to be emptied / rx fifo to be filled */
/* wait for tx/rx DMA completion */
ret = sh_msiof_wait_for_completion(p);
if (ret)
goto stop_reset;
if (!rx) {
reinit_completion(&p->done);
sh_msiof_write(p, IER, IER_TEOFE);
/* wait for tx fifo to be emptied */
ret = sh_msiof_wait_for_completion(p);
if (ret)
goto stop_reset;
}
/* clear status bits */
sh_msiof_reset_str(p);
@ -912,9 +951,8 @@ static int sh_msiof_transfer_one(struct spi_master *master,
ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l);
if (ret == -EAGAIN) {
pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
dev_driver_string(&p->pdev->dev),
dev_name(&p->pdev->dev));
dev_warn_once(&p->pdev->dev,
"DMA not available, falling back to PIO\n");
break;
}
if (ret)
@ -1071,6 +1109,45 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
}
#endif
static int sh_msiof_get_cs_gpios(struct sh_msiof_spi_priv *p)
{
struct device *dev = &p->pdev->dev;
unsigned int used_ss_mask = 0;
unsigned int cs_gpios = 0;
unsigned int num_cs, i;
int ret;
ret = gpiod_count(dev, "cs");
if (ret <= 0)
return 0;
num_cs = max_t(unsigned int, ret, p->master->num_chipselect);
for (i = 0; i < num_cs; i++) {
struct gpio_desc *gpiod;
gpiod = devm_gpiod_get_index(dev, "cs", i, GPIOD_ASIS);
if (!IS_ERR(gpiod)) {
cs_gpios++;
continue;
}
if (PTR_ERR(gpiod) != -ENOENT)
return PTR_ERR(gpiod);
if (i >= MAX_SS) {
dev_err(dev, "Invalid native chip select %d\n", i);
return -EINVAL;
}
used_ss_mask |= BIT(i);
}
p->unused_ss = ffz(used_ss_mask);
if (cs_gpios && p->unused_ss >= MAX_SS) {
dev_err(dev, "No unused native chip select available\n");
return -EINVAL;
}
return 0;
}
static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev,
enum dma_transfer_direction dir, unsigned int id, dma_addr_t port_addr)
{
@ -1284,13 +1361,18 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
if (p->info->rx_fifo_override)
p->rx_fifo_size = p->info->rx_fifo_override;
/* Setup GPIO chip selects */
master->num_chipselect = p->info->num_chipselect;
ret = sh_msiof_get_cs_gpios(p);
if (ret)
goto err1;
/* init master code */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
master->flags = chipdata->master_flags;
master->bus_num = pdev->id;
master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = p->info->num_chipselect;
master->setup = sh_msiof_spi_setup;
master->prepare_message = sh_msiof_prepare_message;
master->slave_abort = sh_msiof_slave_abort;

Просмотреть файл

@ -1072,7 +1072,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct sirfsoc_spi *sspi;
struct spi_master *master;
struct resource *mem_res;
struct sirf_spi_comp_data *spi_comp_data;
const struct sirf_spi_comp_data *spi_comp_data;
int irq;
int ret;
const struct of_device_id *match;
@ -1092,7 +1092,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master);
sspi->fifo_full_offset = ilog2(sspi->fifo_size);
spi_comp_data = (struct sirf_spi_comp_data *)match->data;
spi_comp_data = match->data;
sspi->regs = spi_comp_data->regs;
sspi->type = spi_comp_data->type;
sspi->fifo_level_chk_mask = (sspi->fifo_size / 4) - 1;

Просмотреть файл

@ -541,7 +541,7 @@ err_free_master:
static int sun6i_spi_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
pm_runtime_force_suspend(&pdev->dev);
return 0;
}

Просмотреть файл

@ -381,6 +381,7 @@ static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi)
}
static const struct of_device_id xilinx_spi_of_match[] = {
{ .compatible = "xlnx,axi-quad-spi-1.00.a", },
{ .compatible = "xlnx,xps-spi-2.00.a", },
{ .compatible = "xlnx,xps-spi-2.00.b", },
{}

Просмотреть файл

@ -1,10 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2009 Samsung Electronics Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
*
* 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.
*/
#ifndef __SPI_S3C64XX_H