mirror of
https://github.com/t2linux/kernel.git
synced 2026-04-30 13:48:59 -07:00
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:
@@ -25,6 +25,7 @@ properties:
|
||||
- enum:
|
||||
- allwinner,sun8i-r40-spi
|
||||
- allwinner,sun50i-h6-spi
|
||||
- allwinner,sun50i-h616-spi
|
||||
- const: allwinner,sun8i-h3-spi
|
||||
|
||||
reg:
|
||||
|
||||
+1
@@ -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>;
|
||||
};
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user