Skip to content

Commit

Permalink
Merge tag 'spi-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/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
  ...
  • Loading branch information
torvalds committed Jan 29, 2018
2 parents 0bae60f + 35a8f1a commit 8e32647
Show file tree
Hide file tree
Showing 21 changed files with 378 additions and 132 deletions.
16 changes: 15 additions & 1 deletion Documentation/devicetree/bindings/spi/sh-msiof.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion Documentation/devicetree/bindings/spi/spi-meson.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
9 changes: 9 additions & 0 deletions Documentation/devicetree/bindings/spi/spi-orion.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion Documentation/devicetree/bindings/spi/spi-xilinx.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
110 changes: 92 additions & 18 deletions drivers/spi/spi-armada-3700.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -729,6 +742,63 @@ static int a3700_spi_transfer_one(struct spi_master *master,
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)
{
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 8e32647

Please sign in to comment.