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

Pull spi updates from Mark Brown:
 "The main focus of this release from a framework point of view has been
  spi-mem where we've acquired support for a few new hardware features
  which enable better performance on suitable hardware.

  Otherwise mostly thanks to Arnd's cleanup efforts on old platforms
  we've removed several obsolete drivers which just about balance out
  the newer drivers we've added this cycle.

  Summary:

   - Allow drivers to flag if they are unidirectional.

   - Support for DTR mode and hardware acceleration of dummy cycles in
     spi-mem.

   - Support for Allwinder H616, Intel Lightning Mountain, nVidia Tegra
     QuadSPI, Realtek RTL838x and RTL839x.

   - Removal of obsolete EFM32, Txx9 and SIRF Prima and Atlas drivers"

* tag 'spi-v5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (76 commits)
  spi: Skip zero-length transfers in spi_transfer_one_message()
  spi: dw: Avoid stack content exposure
  spi: cadence-quadspi: Use spi_mem_dtr_supports_op()
  spi: spi-mem: add spi_mem_dtr_supports_op()
  spi: atmel-quadspi: Disable the QSPI IP at suspend()
  spi: pxa2xx: Add IDs for the controllers found on Intel Lynxpoint
  spi: pxa2xx: Fix the controller numbering for Wildcat Point
  spi: Change provied to provided in the file spi.h
  spi: mediatek: add set_cs_timing support
  spi: support CS timing for HW & SW mode
  spi: add power control when set_cs_timing
  spi: stm32: make spurious and overrun interrupts visible
  spi: stm32h7: replace private SPI_1HZ_NS with NSEC_PER_SEC
  spi: stm32: defer probe for reset
  spi: stm32: driver uses reset controller only at init
  spi: stm32h7: ensure message are smaller than max size
  spi: stm32: use bitfield macros
  spi: stm32: do not mandate cs_gpio
  spi: stm32: properly handle 0 byte transfer
  spi: clps711xx: remove redundant white-space
  ...
This commit is contained in:
Linus Torvalds
2021-02-22 09:19:08 -08:00
45 changed files with 2518 additions and 2544 deletions
@@ -25,6 +25,7 @@ properties:
- enum:
- allwinner,sun8i-r40-spi
- allwinner,sun50i-h6-spi
- allwinner,sun50i-h616-spi
- const: allwinner,sun8i-h3-spi
reg:
@@ -5,6 +5,7 @@ Required properties:
Generic default - "cdns,qspi-nor".
For TI 66AK2G SoC - "ti,k2g-qspi", "cdns,qspi-nor".
For TI AM654 SoC - "ti,am654-ospi", "cdns,qspi-nor".
For Intel LGM SoC - "intel,lgm-qspi", "cdns,qspi-nor".
- reg : Contains two entries, each of which is a tuple consisting of a
physical address and length. The first entry is the address and
length of the controller register set. The second entry is the
@@ -0,0 +1,117 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/nvidia,tegra210-quad.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Tegra Quad SPI Controller
maintainers:
- Thierry Reding <thierry.reding@gmail.com>
- Jonathan Hunter <jonathanh@nvidia.com>
allOf:
- $ref: "spi-controller.yaml#"
properties:
compatible:
enum:
- nvidia,tegra210-qspi
- nvidia,tegra186-qspi
- nvidia,tegra194-qspi
reg:
maxItems: 1
interrupts:
maxItems: 1
clock-names:
items:
- const: qspi
- const: qspi_out
clocks:
maxItems: 2
resets:
maxItems: 1
dmas:
maxItems: 2
dma-names:
items:
- const: rx
- const: tx
patternProperties:
"@[0-9a-f]+":
type: object
properties:
spi-rx-bus-width:
enum: [1, 2, 4]
spi-tx-bus-width:
enum: [1, 2, 4]
nvidia,tx-clk-tap-delay:
description:
Delays the clock going out to device with this tap value.
Tap value varies based on platform design trace lengths from Tegra
QSPI to corresponding slave device.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 31
nvidia,rx-clk-tap-delay:
description:
Delays the clock coming in from the device with this tap value.
Tap value varies based on platform design trace lengths from Tegra
QSPI to corresponding slave device.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
required:
- reg
required:
- compatible
- reg
- interrupts
- clock-names
- clocks
- resets
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/tegra210-car.h>
#include <dt-bindings/reset/tegra210-car.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
spi@70410000 {
compatible = "nvidia,tegra210-qspi";
reg = <0x70410000 0x1000>;
interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&tegra_car TEGRA210_CLK_QSPI>,
<&tegra_car TEGRA210_CLK_QSPI_PM>;
clock-names = "qspi", "qspi_out";
resets = <&tegra_car 211>;
dmas = <&apbdma 5>, <&apbdma 5>;
dma-names = "rx", "tx";
flash@0 {
compatible = "spi-nor";
reg = <0>;
spi-max-frequency = <104000000>;
spi-tx-bus-width = <2>;
spi-rx-bus-width = <2>;
nvidia,tx-clk-tap-delay = <0>;
nvidia,rx-clk-tap-delay = <0>;
};
};
@@ -0,0 +1,41 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/realtek,rtl-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek RTL838x/RTL839x SPI controller
maintainers:
- Bert Vermeulen <bert@biot.com>
- Birger Koblitz <mail@birger-koblitz.de>
allOf:
- $ref: "spi-controller.yaml#"
properties:
compatible:
oneOf:
- const: realtek,rtl8380-spi
- const: realtek,rtl8382-spi
- const: realtek,rtl8391-spi
- const: realtek,rtl8392-spi
- const: realtek,rtl8393-spi
reg:
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
spi: spi@1200 {
compatible = "realtek,rtl8382-spi";
reg = <0x1200 0x100>;
#address-cells = <1>;
#size-cells = <0>;
};
@@ -47,6 +47,7 @@ properties:
- renesas,msiof-r8a77980 # R-Car V3H
- renesas,msiof-r8a77990 # R-Car E3
- renesas,msiof-r8a77995 # R-Car D3
- renesas,msiof-r8a779a0 # R-Car V3U
- const: renesas,rcar-gen3-msiof # generic R-Car Gen3 and RZ/G2
# compatible device
- items:
@@ -152,8 +152,9 @@ patternProperties:
spi-rx-bus-width:
description:
Bus width to the SPI bus used for read transfers.
If 0 is provided, then no RX will be possible on this device.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8]
enum: [0, 1, 2, 4, 8]
default: 1
spi-rx-delay-us:
@@ -163,8 +164,9 @@ patternProperties:
spi-tx-bus-width:
description:
Bus width to the SPI bus used for write transfers.
If 0 is provided, then no TX will be possible on this device.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8]
enum: [0, 1, 2, 4, 8]
default: 1
spi-tx-delay-us:
@@ -1,42 +0,0 @@
* CSR SiRFprimaII Serial Peripheral Interface
Required properties:
- compatible : Should be "sirf,prima2-spi", "sirf,prima2-usp"
or "sirf,atlas7-usp"
- reg : Offset and length of the register set for the device
- interrupts : Should contain SPI interrupt
- resets: phandle to the reset controller asserting this device in
reset
See ../reset/reset.txt for details.
- dmas : Must contain an entry for each entry in clock-names.
See ../dma/dma.txt for details.
- dma-names : Must include the following entries:
- rx
- tx
- clocks : Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- #address-cells: Number of cells required to define a chip select
address on the SPI bus. Should be set to 1.
- #size-cells: Should be zero.
Optional properties:
- spi-max-frequency: Specifies maximum SPI clock frequency,
Units - Hz. Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
- cs-gpios: should specify GPIOs used for chipselects.
Example:
spi0: spi@b00d0000 {
compatible = "sirf,prima2-spi";
reg = <0xb00d0000 0x10000>;
interrupts = <15>;
dmas = <&dmac1 9>,
<&dmac1 4>;
dma-names = "rx", "tx";
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clks 19>;
resets = <&rstc 26>;
};
+8
View File
@@ -17537,6 +17537,14 @@ M: Laxman Dewangan <ldewangan@nvidia.com>
S: Supported
F: drivers/spi/spi-tegra*
TEGRA QUAD SPI DRIVER
M: Thierry Reding <thierry.reding@gmail.com>
M: Jonathan Hunter <jonathanh@nvidia.com>
M: Sowjanya Komatineni <skomatineni@nvidia.com>
L: linux-tegra@vger.kernel.org
S: Maintained
F: drivers/spi/spi-tegra210-quad.c
TEGRA VIDEO DRIVER
M: Thierry Reding <thierry.reding@gmail.com>
M: Jonathan Hunter <jonathanh@nvidia.com>
+11 -22
View File
@@ -203,7 +203,7 @@ config SPI_CADENCE
config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller"
depends on OF && (ARM || ARM64 || COMPILE_TEST)
depends on OF && (ARM || ARM64 || X86 || COMPILE_TEST)
help
Enable support for the Cadence Quad SPI Flash controller.
@@ -292,13 +292,6 @@ config SPI_DLN2
This driver can also be built as a module. If so, the module
will be called spi-dln2.
config SPI_EFM32
tristate "EFM32 SPI controller"
depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST)
select SPI_BITBANG
help
Driver for the spi controller found on Energy Micro's EFM32 SoCs.
config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller"
depends on ARCH_EP93XX || COMPILE_TEST
@@ -649,7 +642,7 @@ config SPI_RPCIF
tristate "Renesas RPC-IF SPI driver"
depends on RENESAS_RPCIF
help
SPI driver for Renesas R-Car Gen3 RPC-IF.
SPI driver for Renesas R-Car Gen3 or RZ/G2 RPC-IF.
config SPI_RSPI
tristate "Renesas RSPI/QSPI controller"
@@ -750,13 +743,6 @@ config SPI_SIFIVE
help
This exposes the SPI controller IP from SiFive.
config SPI_SIRF
tristate "CSR SiRFprimaII SPI controller"
depends on SIRF_DMA
select SPI_BITBANG
help
SPI driver for CSR SiRFprimaII SoCs
config SPI_SLAVE_MT27XX
tristate "MediaTek SPI slave device"
depends on ARCH_MEDIATEK || COMPILE_TEST
@@ -842,6 +828,15 @@ config SPI_MXS
help
SPI driver for Freescale MXS devices.
config SPI_TEGRA210_QUAD
tristate "NVIDIA Tegra QSPI Controller"
depends on ARCH_TEGRA || COMPILE_TEST
depends on RESET_CONTROLLER
help
QSPI driver for NVIDIA Tegra QSPI Controller interface. This
controller is different from the SPI controller and is available
on Tegra SoCs starting from Tegra210.
config SPI_TEGRA114
tristate "NVIDIA Tegra114 SPI Controller"
depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
@@ -884,12 +879,6 @@ config SPI_TOPCLIFF_PCH
This driver also supports the ML7213/ML7223/ML7831, a companion chip
for the Atom E6xx series and compatible with the Intel EG20T PCH.
config SPI_TXX9
tristate "Toshiba TXx9 SPI controller"
depends on GPIOLIB && (CPU_TX49XX || COMPILE_TEST)
help
SPI driver for Toshiba TXx9 MIPS SoCs
config SPI_UNIPHIER
tristate "Socionext UniPhier SPI Controller"
depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
+2 -3
View File
@@ -42,7 +42,6 @@ spi-dw-$(CONFIG_SPI_DW_DMA) += spi-dw-dma.o
obj-$(CONFIG_SPI_DW_BT1) += spi-dw-bt1.o
obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o
obj-$(CONFIG_SPI_EFM32) += spi-efm32.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
obj-$(CONFIG_SPI_FSI) += spi-fsi.o
@@ -94,6 +93,7 @@ obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o
obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
@@ -105,7 +105,6 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIFIVE) += spi-sifive.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
obj-$(CONFIG_SPI_SLAVE_MT27XX) += spi-slave-mt27xx.o
obj-$(CONFIG_SPI_SPRD) += spi-sprd.o
obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o
@@ -115,6 +114,7 @@ obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
obj-$(CONFIG_SPI_SYNQUACER) += spi-synquacer.o
obj-$(CONFIG_SPI_TEGRA210_QUAD) += spi-tegra210-quad.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
@@ -122,7 +122,6 @@ obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
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
+1
View File
@@ -657,6 +657,7 @@ static int __maybe_unused atmel_qspi_suspend(struct device *dev)
struct spi_controller *ctrl = dev_get_drvdata(dev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
clk_disable_unprepare(aq->qspick);
clk_disable_unprepare(aq->pclk);
+1 -1
View File
@@ -1590,7 +1590,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
if (ret == 0) {
as->use_dma = true;
} else if (ret == -EPROBE_DEFER) {
return ret;
goto out_unmap_regs;
}
} else if (as->caps.has_pdc_support) {
as->use_pdc = true;
+27 -26
View File
@@ -26,7 +26,7 @@
#include <asm/mach-au1x00/au1550_spi.h>
static unsigned usedma = 1;
static unsigned int usedma = 1;
module_param(usedma, uint, 0644);
/*
@@ -43,9 +43,9 @@ struct au1550_spi {
volatile psc_spi_t __iomem *regs;
int irq;
unsigned len;
unsigned tx_count;
unsigned rx_count;
unsigned int len;
unsigned int tx_count;
unsigned int rx_count;
const u8 *tx;
u8 *rx;
@@ -56,14 +56,14 @@ struct au1550_spi {
struct completion master_done;
unsigned usedma;
unsigned int usedma;
u32 dma_tx_id;
u32 dma_rx_id;
u32 dma_tx_ch;
u32 dma_rx_ch;
u8 *dma_rx_tmpbuf;
unsigned dma_rx_tmpbuf_size;
unsigned int dma_rx_tmpbuf_size;
u32 dma_rx_tmpbuf_addr;
struct spi_master *master;
@@ -74,8 +74,7 @@ struct au1550_spi {
/* we use an 8-bit memory device for dma transfers to/from spi fifo */
static dbdev_tab_t au1550_spi_mem_dbdev =
{
static dbdev_tab_t au1550_spi_mem_dbdev = {
.dev_id = DBDMA_MEM_CHAN,
.dev_flags = DEV_FLAGS_ANYUSE|DEV_FLAGS_SYNC,
.dev_tsize = 0,
@@ -99,7 +98,7 @@ static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw);
* BRG valid range is 4..63
* DIV valid range is 0..3
*/
static u32 au1550_spi_baudcfg(struct au1550_spi *hw, unsigned speed_hz)
static u32 au1550_spi_baudcfg(struct au1550_spi *hw, unsigned int speed_hz)
{
u32 mainclk_hz = hw->pdata->mainclk_hz;
u32 div, brg;
@@ -161,7 +160,7 @@ static void au1550_spi_reset_fifos(struct au1550_spi *hw)
static void au1550_spi_chipsel(struct spi_device *spi, int value)
{
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
unsigned cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
u32 cfg, stat;
switch (value) {
@@ -221,7 +220,7 @@ static void au1550_spi_chipsel(struct spi_device *spi, int value)
static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
{
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
unsigned bpw, hz;
unsigned int bpw, hz;
u32 cfg, stat;
if (t) {
@@ -276,7 +275,7 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
* spi master done event irq is not generated unless rx fifo is empty (emptied)
* so we need rx tmp buffer to use for rx dma if user does not provide one
*/
static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned size)
static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned int size)
{
hw->dma_rx_tmpbuf = kmalloc(size, GFP_KERNEL);
if (!hw->dma_rx_tmpbuf)
@@ -399,10 +398,10 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
DMA_FROM_DEVICE);
}
/* unmap buffers if mapped above */
if (t->rx_buf && t->rx_dma == 0 )
if (t->rx_buf && t->rx_dma == 0)
dma_unmap_single(hw->dev, dma_rx_addr, t->len,
DMA_FROM_DEVICE);
if (t->tx_buf && t->tx_dma == 0 )
if (t->tx_buf && t->tx_dma == 0)
dma_unmap_single(hw->dev, dma_tx_addr, t->len,
DMA_TO_DEVICE);
@@ -447,8 +446,8 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
"dma transfer: receive FIFO overflow!\n");
else
dev_err(hw->dev,
"dma transfer: unexpected SPI error "
"(event=0x%x stat=0x%x)!\n", evnt, stat);
"dma transfer: unexpected SPI error (event=0x%x stat=0x%x)!\n",
evnt, stat);
complete(&hw->master_done);
return IRQ_HANDLED;
@@ -493,12 +492,12 @@ static void au1550_spi_tx_word_##size(struct au1550_spi *hw) \
wmb(); /* drain writebuffer */ \
}
AU1550_SPI_RX_WORD(8,0xff)
AU1550_SPI_RX_WORD(16,0xffff)
AU1550_SPI_RX_WORD(32,0xffffff)
AU1550_SPI_TX_WORD(8,0xff)
AU1550_SPI_TX_WORD(16,0xffff)
AU1550_SPI_TX_WORD(32,0xffffff)
AU1550_SPI_RX_WORD(8, 0xff)
AU1550_SPI_RX_WORD(16, 0xffff)
AU1550_SPI_RX_WORD(32, 0xffffff)
AU1550_SPI_TX_WORD(8, 0xff)
AU1550_SPI_TX_WORD(16, 0xffff)
AU1550_SPI_TX_WORD(32, 0xffffff)
static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t)
{
@@ -567,8 +566,8 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
au1550_spi_mask_ack_all(hw);
au1550_spi_reset_fifos(hw);
dev_err(hw->dev,
"pio transfer: unexpected SPI error "
"(event=0x%x stat=0x%x)!\n", evnt, stat);
"pio transfer: unexpected SPI error (event=0x%x stat=0x%x)!\n",
evnt, stat);
complete(&hw->master_done);
return IRQ_HANDLED;
}
@@ -636,12 +635,14 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
return hw->txrx_bufs(spi, t);
}
static irqreturn_t au1550_spi_irq(int irq, void *dev)
{
struct au1550_spi *hw = dev;
return hw->irq_callback(hw);
}
@@ -872,6 +873,7 @@ static int au1550_spi_probe(struct platform_device *pdev)
{
int min_div = (2 << 0) * (2 * (4 + 1));
int max_div = (2 << 3) * (2 * (63 + 1));
master->max_speed_hz = hw->pdata->mainclk_hz / min_div;
master->min_speed_hz =
hw->pdata->mainclk_hz / (max_div + 1) + 1;
@@ -972,8 +974,7 @@ static int __init au1550_spi_init(void)
if (usedma) {
ddma_memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev);
if (!ddma_memid)
printk(KERN_ERR "au1550-spi: cannot add memory"
"dbdma device\n");
printk(KERN_ERR "au1550-spi: cannot add memory dbdma device\n");
}
return platform_driver_register(&au1550_spi_drv);
}
+1 -1
View File
@@ -881,7 +881,7 @@ static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
* when using flex mode we need to send
* the upper address byte to bspi
*/
if (bcm_qspi_bspi_ver_three(qspi) == false) {
if (!bcm_qspi_bspi_ver_three(qspi)) {
addr = from & 0xff000000;
bcm_qspi_write(qspi, BSPI,
BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr);
+5 -3
View File
@@ -386,7 +386,7 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
/* Transfer complete - reset SPI HW */
bcm2835_spi_reset_hw(bs);
/* wake up the framework */
complete(&bs->ctlr->xfer_completion);
spi_finalize_current_transfer(bs->ctlr);
}
return IRQ_HANDLED;
@@ -608,7 +608,7 @@ static void bcm2835_spi_dma_rx_done(void *data)
bcm2835_spi_reset_hw(bs);
/* and mark as completed */;
complete(&ctlr->xfer_completion);
spi_finalize_current_transfer(ctlr);
}
/**
@@ -640,7 +640,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
bcm2835_spi_undo_prologue(bs);
bcm2835_spi_reset_hw(bs);
complete(&ctlr->xfer_completion);
spi_finalize_current_transfer(ctlr);
}
/**
@@ -1307,6 +1307,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(bs->clk),
"could not get clk\n");
ctlr->max_speed_hz = clk_get_rate(bs->clk) / 2;
bs->irq = platform_get_irq(pdev, 0);
if (bs->irq <= 0)
return bs->irq ? bs->irq : -ENODEV;
+1 -1
View File
@@ -254,7 +254,7 @@ static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
/* and if rx_len is 0 then disable interrupts and wake up completion */
if (!bs->rx_len) {
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1]);
complete(&master->xfer_completion);
spi_finalize_current_transfer(master);
}
return IRQ_HANDLED;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -104,7 +104,7 @@ static int spi_clps711x_probe(struct platform_device *pdev)
master->use_gpio_descriptors = true;
master->bus_num = -1;
master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
master->dev.of_node = pdev->dev.of_node;
master->prepare_message = spi_clps711x_prepare_message;
master->transfer_one = spi_clps711x_transfer_one;
+1 -1
View File
@@ -84,7 +84,7 @@ static void dw_spi_bt1_dirmap_copy_from_map(void *to, void __iomem *from, size_t
if (shift) {
chunk = min_t(size_t, 4 - shift, len);
data = readl_relaxed(from - shift);
memcpy(to, &data + shift, chunk);
memcpy(to, (char *)&data + shift, chunk);
from += chunk;
to += chunk;
len -= chunk;
-462
View File
@@ -1,462 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012-2013 Uwe Kleine-Koenig for Pengutronix
*/
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_data/efm32-spi.h>
#include <linux/of.h>
#define DRIVER_NAME "efm32-spi"
#define MASK_VAL(mask, val) ((val << __ffs(mask)) & mask)
#define REG_CTRL 0x00
#define REG_CTRL_SYNC 0x0001
#define REG_CTRL_CLKPOL 0x0100
#define REG_CTRL_CLKPHA 0x0200
#define REG_CTRL_MSBF 0x0400
#define REG_CTRL_TXBIL 0x1000
#define REG_FRAME 0x04
#define REG_FRAME_DATABITS__MASK 0x000f
#define REG_FRAME_DATABITS(n) ((n) - 3)
#define REG_CMD 0x0c
#define REG_CMD_RXEN 0x0001
#define REG_CMD_RXDIS 0x0002
#define REG_CMD_TXEN 0x0004
#define REG_CMD_TXDIS 0x0008
#define REG_CMD_MASTEREN 0x0010
#define REG_STATUS 0x10
#define REG_STATUS_TXENS 0x0002
#define REG_STATUS_TXC 0x0020
#define REG_STATUS_TXBL 0x0040
#define REG_STATUS_RXDATAV 0x0080
#define REG_CLKDIV 0x14
#define REG_RXDATAX 0x18
#define REG_RXDATAX_RXDATA__MASK 0x01ff
#define REG_RXDATAX_PERR 0x4000
#define REG_RXDATAX_FERR 0x8000
#define REG_TXDATA 0x34
#define REG_IF 0x40
#define REG_IF_TXBL 0x0002
#define REG_IF_RXDATAV 0x0004
#define REG_IFS 0x44
#define REG_IFC 0x48
#define REG_IEN 0x4c
#define REG_ROUTE 0x54
#define REG_ROUTE_RXPEN 0x0001
#define REG_ROUTE_TXPEN 0x0002
#define REG_ROUTE_CLKPEN 0x0008
#define REG_ROUTE_LOCATION__MASK 0x0700
#define REG_ROUTE_LOCATION(n) MASK_VAL(REG_ROUTE_LOCATION__MASK, (n))
struct efm32_spi_ddata {
struct spi_bitbang bitbang;
spinlock_t lock;
struct clk *clk;
void __iomem *base;
unsigned int rxirq, txirq;
struct efm32_spi_pdata pdata;
/* irq data */
struct completion done;
const u8 *tx_buf;
u8 *rx_buf;
unsigned tx_len, rx_len;
};
#define ddata_to_dev(ddata) (&(ddata->bitbang.master->dev))
#define efm32_spi_vdbg(ddata, format, arg...) \
dev_vdbg(ddata_to_dev(ddata), format, ##arg)
static void efm32_spi_write32(struct efm32_spi_ddata *ddata,
u32 value, unsigned offset)
{
writel_relaxed(value, ddata->base + offset);
}
static u32 efm32_spi_read32(struct efm32_spi_ddata *ddata, unsigned offset)
{
return readl_relaxed(ddata->base + offset);
}
static int efm32_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
unsigned bpw = t->bits_per_word ?: spi->bits_per_word;
unsigned speed = t->speed_hz ?: spi->max_speed_hz;
unsigned long clkfreq = clk_get_rate(ddata->clk);
u32 clkdiv;
efm32_spi_write32(ddata, REG_CTRL_SYNC | REG_CTRL_MSBF |
(spi->mode & SPI_CPHA ? REG_CTRL_CLKPHA : 0) |
(spi->mode & SPI_CPOL ? REG_CTRL_CLKPOL : 0), REG_CTRL);
efm32_spi_write32(ddata,
REG_FRAME_DATABITS(bpw), REG_FRAME);
if (2 * speed >= clkfreq)
clkdiv = 0;
else
clkdiv = 64 * (DIV_ROUND_UP(2 * clkfreq, speed) - 4);
if (clkdiv > (1U << 21))
return -EINVAL;
efm32_spi_write32(ddata, clkdiv, REG_CLKDIV);
efm32_spi_write32(ddata, REG_CMD_MASTEREN, REG_CMD);
efm32_spi_write32(ddata, REG_CMD_RXEN | REG_CMD_TXEN, REG_CMD);
return 0;
}
static void efm32_spi_tx_u8(struct efm32_spi_ddata *ddata)
{
u8 val = 0;
if (ddata->tx_buf) {
val = *ddata->tx_buf;
ddata->tx_buf++;
}
ddata->tx_len--;
efm32_spi_write32(ddata, val, REG_TXDATA);
efm32_spi_vdbg(ddata, "%s: tx 0x%x\n", __func__, val);
}
static void efm32_spi_rx_u8(struct efm32_spi_ddata *ddata)
{
u32 rxdata = efm32_spi_read32(ddata, REG_RXDATAX);
efm32_spi_vdbg(ddata, "%s: rx 0x%x\n", __func__, rxdata);
if (ddata->rx_buf) {
*ddata->rx_buf = rxdata;
ddata->rx_buf++;
}
ddata->rx_len--;
}
static void efm32_spi_filltx(struct efm32_spi_ddata *ddata)
{
while (ddata->tx_len &&
ddata->tx_len + 2 > ddata->rx_len &&
efm32_spi_read32(ddata, REG_STATUS) & REG_STATUS_TXBL) {
efm32_spi_tx_u8(ddata);
}
}
static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
int ret = -EBUSY;
spin_lock_irq(&ddata->lock);
if (ddata->tx_buf || ddata->rx_buf)
goto out_unlock;
ddata->tx_buf = t->tx_buf;
ddata->rx_buf = t->rx_buf;
ddata->tx_len = ddata->rx_len =
t->len * DIV_ROUND_UP(t->bits_per_word, 8);
efm32_spi_filltx(ddata);
reinit_completion(&ddata->done);
efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN);
spin_unlock_irq(&ddata->lock);
wait_for_completion(&ddata->done);
spin_lock_irq(&ddata->lock);
ret = t->len - max(ddata->tx_len, ddata->rx_len);
efm32_spi_write32(ddata, 0, REG_IEN);
ddata->tx_buf = ddata->rx_buf = NULL;
out_unlock:
spin_unlock_irq(&ddata->lock);
return ret;
}
static irqreturn_t efm32_spi_rxirq(int irq, void *data)
{
struct efm32_spi_ddata *ddata = data;
irqreturn_t ret = IRQ_NONE;
spin_lock(&ddata->lock);
while (ddata->rx_len > 0 &&
efm32_spi_read32(ddata, REG_STATUS) &
REG_STATUS_RXDATAV) {
efm32_spi_rx_u8(ddata);
ret = IRQ_HANDLED;
}
if (!ddata->rx_len) {
u32 ien = efm32_spi_read32(ddata, REG_IEN);
ien &= ~REG_IF_RXDATAV;
efm32_spi_write32(ddata, ien, REG_IEN);
complete(&ddata->done);
}
spin_unlock(&ddata->lock);
return ret;
}
static irqreturn_t efm32_spi_txirq(int irq, void *data)
{
struct efm32_spi_ddata *ddata = data;
efm32_spi_vdbg(ddata,
"%s: txlen = %u, rxlen = %u, if=0x%08x, stat=0x%08x\n",
__func__, ddata->tx_len, ddata->rx_len,
efm32_spi_read32(ddata, REG_IF),
efm32_spi_read32(ddata, REG_STATUS));
spin_lock(&ddata->lock);
efm32_spi_filltx(ddata);
efm32_spi_vdbg(ddata, "%s: txlen = %u, rxlen = %u\n",
__func__, ddata->tx_len, ddata->rx_len);
if (!ddata->tx_len) {
u32 ien = efm32_spi_read32(ddata, REG_IEN);
ien &= ~REG_IF_TXBL;
efm32_spi_write32(ddata, ien, REG_IEN);
efm32_spi_vdbg(ddata, "disable TXBL\n");
}
spin_unlock(&ddata->lock);
return IRQ_HANDLED;
}
static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
{
u32 reg = efm32_spi_read32(ddata, REG_ROUTE);
return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
}
static void efm32_spi_probe_dt(struct platform_device *pdev,
struct spi_master *master, struct efm32_spi_ddata *ddata)
{
struct device_node *np = pdev->dev.of_node;
u32 location;
int ret;
ret = of_property_read_u32(np, "energymicro,location", &location);
if (ret)
/* fall back to wrongly namespaced property */
ret = of_property_read_u32(np, "efm32,location", &location);
if (ret)
/* fall back to old and (wrongly) generic property "location" */
ret = of_property_read_u32(np, "location", &location);
if (!ret) {
dev_dbg(&pdev->dev, "using location %u\n", location);
} else {
/* default to location configured in hardware */
location = efm32_spi_get_configured_location(ddata);
dev_info(&pdev->dev, "fall back to location %u\n", location);
}
ddata->pdata.location = location;
}
static int efm32_spi_probe(struct platform_device *pdev)
{
struct efm32_spi_ddata *ddata;
struct resource *res;
int ret;
struct spi_master *master;
struct device_node *np = pdev->dev.of_node;
if (!np)
return -EINVAL;
master = spi_alloc_master(&pdev->dev, sizeof(*ddata));
if (!master) {
dev_dbg(&pdev->dev,
"failed to allocate spi master controller\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, master);
master->dev.of_node = pdev->dev.of_node;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
master->use_gpio_descriptors = true;
ddata = spi_master_get_devdata(master);
ddata->bitbang.master = master;
ddata->bitbang.setup_transfer = efm32_spi_setup_transfer;
ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
spin_lock_init(&ddata->lock);
init_completion(&ddata->done);
ddata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ddata->clk)) {
ret = PTR_ERR(ddata->clk);
dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
goto err;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
dev_err(&pdev->dev, "failed to determine base address\n");
goto err;
}
if (resource_size(res) < 0x60) {
ret = -EINVAL;
dev_err(&pdev->dev, "memory resource too small\n");
goto err;
}
ddata->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(ddata->base)) {
ret = PTR_ERR(ddata->base);
goto err;
}
ret = platform_get_irq(pdev, 0);
if (ret <= 0)
goto err;
ddata->rxirq = ret;
ret = platform_get_irq(pdev, 1);
if (ret <= 0)
ret = ddata->rxirq + 1;
ddata->txirq = ret;
ret = clk_prepare_enable(ddata->clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret);
goto err;
}
efm32_spi_probe_dt(pdev, master, ddata);
efm32_spi_write32(ddata, 0, REG_IEN);
efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
REG_ROUTE_CLKPEN |
REG_ROUTE_LOCATION(ddata->pdata.location), REG_ROUTE);
ret = request_irq(ddata->rxirq, efm32_spi_rxirq,
0, DRIVER_NAME " rx", ddata);
if (ret) {
dev_err(&pdev->dev, "failed to register rxirq (%d)\n", ret);
goto err_disable_clk;
}
ret = request_irq(ddata->txirq, efm32_spi_txirq,
0, DRIVER_NAME " tx", ddata);
if (ret) {
dev_err(&pdev->dev, "failed to register txirq (%d)\n", ret);
goto err_free_rx_irq;
}
ret = spi_bitbang_start(&ddata->bitbang);
if (ret) {
dev_err(&pdev->dev, "spi_bitbang_start failed (%d)\n", ret);
free_irq(ddata->txirq, ddata);
err_free_rx_irq:
free_irq(ddata->rxirq, ddata);
err_disable_clk:
clk_disable_unprepare(ddata->clk);
err:
spi_master_put(master);
}
return ret;
}
static int efm32_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct efm32_spi_ddata *ddata = spi_master_get_devdata(master);
spi_bitbang_stop(&ddata->bitbang);
efm32_spi_write32(ddata, 0, REG_IEN);
free_irq(ddata->txirq, ddata);
free_irq(ddata->rxirq, ddata);
clk_disable_unprepare(ddata->clk);
spi_master_put(master);
return 0;
}
static const struct of_device_id efm32_spi_dt_ids[] = {
{
.compatible = "energymicro,efm32-spi",
}, {
/* doesn't follow the "vendor,device" scheme, don't use */
.compatible = "efm32,spi",
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, efm32_spi_dt_ids);
static struct platform_driver efm32_spi_driver = {
.probe = efm32_spi_probe,
.remove = efm32_spi_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = efm32_spi_dt_ids,
},
};
module_platform_driver(efm32_spi_driver);
MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
MODULE_DESCRIPTION("EFM32 SPI driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRIVER_NAME);

Some files were not shown because too many files have changed in this diff Show More