spi: Updates for v4.16
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:
Коммит
8e3264710c
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче