summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig252
-rw-r--r--drivers/spi/Makefile30
-rw-r--r--drivers/spi/atmel-quadspi.c1144
-rw-r--r--drivers/spi/internals.h8
-rw-r--r--drivers/spi/spi-airoha-snfi.c1148
-rw-r--r--drivers/spi/spi-altera-core.c1
-rw-r--r--drivers/spi/spi-altera-platform.c2
-rw-r--r--drivers/spi/spi-amd-pci.c69
-rw-r--r--drivers/spi/spi-amd.c594
-rw-r--r--drivers/spi/spi-amd.h44
-rw-r--r--drivers/spi/spi-amlogic-spifc-a1.c97
-rw-r--r--drivers/spi/spi-amlogic-spifc-a4.c1222
-rw-r--r--drivers/spi/spi-amlogic-spisg.c888
-rw-r--r--drivers/spi/spi-apple.c531
-rw-r--r--drivers/spi/spi-ar934x.c27
-rw-r--r--drivers/spi/spi-armada-3700.c34
-rw-r--r--drivers/spi/spi-aspeed-smc.c796
-rw-r--r--drivers/spi/spi-at91-usart.c32
-rw-r--r--drivers/spi/spi-ath79.c21
-rw-r--r--drivers/spi/spi-atmel.c193
-rw-r--r--drivers/spi/spi-au1550.c105
-rw-r--r--drivers/spi/spi-axi-spi-engine.c1011
-rw-r--r--drivers/spi/spi-bcm-qspi.c70
-rw-r--r--drivers/spi/spi-bcm2835.c240
-rw-r--r--drivers/spi/spi-bcm2835aux.c117
-rw-r--r--drivers/spi/spi-bcm63xx-hsspi.c90
-rw-r--r--drivers/spi/spi-bcm63xx.c100
-rw-r--r--drivers/spi/spi-bcmbca-hsspi.c85
-rw-r--r--drivers/spi/spi-bitbang-txrx.h16
-rw-r--r--drivers/spi/spi-bitbang.c188
-rw-r--r--drivers/spi/spi-brcmstb-qspi.c2
-rw-r--r--drivers/spi/spi-butterfly.c21
-rw-r--r--drivers/spi/spi-cadence-quadspi.c474
-rw-r--r--drivers/spi/spi-cadence-xspi.c742
-rw-r--r--drivers/spi/spi-cadence.c254
-rw-r--r--drivers/spi/spi-cavium-octeon.c34
-rw-r--r--drivers/spi/spi-cavium-thunderx.c44
-rw-r--r--drivers/spi/spi-cavium.c6
-rw-r--r--drivers/spi/spi-cavium.h2
-rw-r--r--drivers/spi/spi-ch341.c241
-rw-r--r--drivers/spi/spi-clps711x.c42
-rw-r--r--drivers/spi/spi-coldfire-qspi.c81
-rw-r--r--drivers/spi/spi-cs42l43.c451
-rw-r--r--drivers/spi/spi-davinci.c181
-rw-r--r--drivers/spi/spi-dln2.c98
-rw-r--r--drivers/spi/spi-dw-bt1.c41
-rw-r--r--drivers/spi/spi-dw-core.c202
-rw-r--r--drivers/spi/spi-dw-dma.c28
-rw-r--r--drivers/spi/spi-dw-mmio.c62
-rw-r--r--drivers/spi/spi-dw-pci.c19
-rw-r--r--drivers/spi/spi-dw.h14
-rw-r--r--drivers/spi/spi-ep93xx.c257
-rw-r--r--drivers/spi/spi-falcon.c39
-rw-r--r--drivers/spi/spi-fsi.c15
-rw-r--r--drivers/spi/spi-fsl-cpm.c89
-rw-r--r--drivers/spi/spi-fsl-cpm.h5
-rw-r--r--drivers/spi/spi-fsl-dspi.c686
-rw-r--r--drivers/spi/spi-fsl-espi.c80
-rw-r--r--drivers/spi/spi-fsl-lib.c18
-rw-r--r--drivers/spi/spi-fsl-lib.h3
-rw-r--r--drivers/spi/spi-fsl-lpspi.c243
-rw-r--r--drivers/spi/spi-fsl-qspi.c219
-rw-r--r--drivers/spi/spi-fsl-spi.c93
-rw-r--r--drivers/spi/spi-geni-qcom.c217
-rw-r--r--drivers/spi/spi-gpio.c202
-rw-r--r--drivers/spi/spi-gxp.c9
-rw-r--r--drivers/spi/spi-hisi-kunpeng.c92
-rw-r--r--drivers/spi/spi-hisi-sfc-v3xx.c25
-rw-r--r--drivers/spi/spi-img-spfi.c120
-rw-r--r--drivers/spi/spi-imx.c356
-rw-r--r--drivers/spi/spi-ingenic.c23
-rw-r--r--drivers/spi/spi-intel-pci.c18
-rw-r--r--drivers/spi/spi-intel-platform.c10
-rw-r--r--drivers/spi/spi-intel.c179
-rw-r--r--drivers/spi/spi-intel.h4
-rw-r--r--drivers/spi/spi-iproc-qspi.c11
-rw-r--r--drivers/spi/spi-jcore.c44
-rw-r--r--drivers/spi/spi-kspi2.c431
-rw-r--r--drivers/spi/spi-lantiq-ssc.c111
-rw-r--r--drivers/spi/spi-ljca.c297
-rw-r--r--drivers/spi/spi-lm70llp.c27
-rw-r--r--drivers/spi/spi-loongson-core.c280
-rw-r--r--drivers/spi/spi-loongson-pci.c54
-rw-r--r--drivers/spi/spi-loongson-plat.c47
-rw-r--r--drivers/spi/spi-loongson.h49
-rw-r--r--drivers/spi/spi-loopback-test.c29
-rw-r--r--drivers/spi/spi-lp8841-rtc.c65
-rw-r--r--drivers/spi/spi-mem.c161
-rw-r--r--drivers/spi/spi-meson-spicc.c399
-rw-r--r--drivers/spi/spi-meson-spifc.c81
-rw-r--r--drivers/spi/spi-microchip-core-qspi.c273
-rw-r--r--drivers/spi/spi-microchip-core-spi.c429
-rw-r--r--drivers/spi/spi-microchip-core.c606
-rw-r--r--drivers/spi/spi-mpc512x-psc.c56
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c44
-rw-r--r--drivers/spi/spi-mpc52xx.c60
-rw-r--r--drivers/spi/spi-mpfs.c626
-rw-r--r--drivers/spi/spi-mt65xx.c340
-rw-r--r--drivers/spi/spi-mt7621.c145
-rw-r--r--drivers/spi/spi-mtk-nor.c20
-rw-r--r--drivers/spi/spi-mtk-snfi.c80
-rw-r--r--drivers/spi/spi-mux.c6
-rw-r--r--drivers/spi/spi-mxic.c102
-rw-r--r--drivers/spi/spi-mxs.c90
-rw-r--r--drivers/spi/spi-npcm-fiu.c60
-rw-r--r--drivers/spi/spi-npcm-pspi.c72
-rw-r--r--drivers/spi/spi-nxp-fspi.c443
-rw-r--r--drivers/spi/spi-oc-tiny.c36
-rw-r--r--drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c62
-rw-r--r--drivers/spi/spi-offload-trigger-pwm.c172
-rw-r--r--drivers/spi/spi-offload.c465
-rw-r--r--drivers/spi/spi-omap-uwire.c35
-rw-r--r--drivers/spi/spi-omap2-mcspi.c363
-rw-r--r--drivers/spi/spi-orion.c106
-rw-r--r--drivers/spi/spi-pci1xxxx.c702
-rw-r--r--drivers/spi/spi-pic32-sqi.c119
-rw-r--r--drivers/spi/spi-pic32.c172
-rw-r--r--drivers/spi/spi-pl022.c494
-rw-r--r--drivers/spi/spi-ppc4xx.c83
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c38
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c60
-rw-r--r--drivers/spi/spi-pxa2xx-platform.c230
-rw-r--r--drivers/spi/spi-pxa2xx.c466
-rw-r--r--drivers/spi/spi-pxa2xx.h49
-rw-r--r--drivers/spi/spi-qcom-qspi.c86
-rw-r--r--drivers/spi/spi-qpic-snand.c1653
-rw-r--r--drivers/spi/spi-qup.c223
-rw-r--r--drivers/spi/spi-rb4xx.c72
-rw-r--r--drivers/spi/spi-realtek-rtl-snand.c418
-rw-r--r--drivers/spi/spi-realtek-rtl.c2
-rw-r--r--drivers/spi/spi-rockchip-sfc.c293
-rw-r--r--drivers/spi/spi-rockchip.c191
-rw-r--r--drivers/spi/spi-rpc-if.c51
-rw-r--r--drivers/spi/spi-rspi.c30
-rw-r--r--drivers/spi/spi-rzv2h-rspi.c687
-rw-r--r--drivers/spi/spi-rzv2m-csi.c245
-rw-r--r--drivers/spi/spi-s3c64xx.c461
-rw-r--r--drivers/spi/spi-sc18is602.c81
-rw-r--r--drivers/spi/spi-sg2044-nor.c511
-rw-r--r--drivers/spi/spi-sh-hspi.c6
-rw-r--r--drivers/spi/spi-sh-msiof.c470
-rw-r--r--drivers/spi/spi-sh-sci.c30
-rw-r--r--drivers/spi/spi-sh.c36
-rw-r--r--drivers/spi/spi-sifive.c82
-rw-r--r--drivers/spi/spi-slave-mt27xx.c26
-rw-r--r--drivers/spi/spi-slave-system-control.c2
-rw-r--r--drivers/spi/spi-slave-time.c2
-rw-r--r--drivers/spi/spi-sn-f-ospi.c19
-rw-r--r--drivers/spi/spi-sprd-adi.c35
-rw-r--r--drivers/spi/spi-sprd.c10
-rw-r--r--drivers/spi/spi-st-ssc4.c86
-rw-r--r--drivers/spi/spi-stm32-ospi.c1068
-rw-r--r--drivers/spi/spi-stm32-qspi.c47
-rw-r--r--drivers/spi/spi-stm32.c1016
-rw-r--r--drivers/spi/spi-sun4i.c89
-rw-r--r--drivers/spi/spi-sun6i.c216
-rw-r--r--drivers/spi/spi-sunplus-sp7021.c96
-rw-r--r--drivers/spi/spi-synquacer.c84
-rw-r--r--drivers/spi/spi-tegra114.c139
-rw-r--r--drivers/spi/spi-tegra20-sflash.c82
-rw-r--r--drivers/spi/spi-tegra20-slink.c117
-rw-r--r--drivers/spi/spi-tegra210-quad.c525
-rw-r--r--drivers/spi/spi-ti-qspi.c124
-rw-r--r--drivers/spi/spi-tle62x0.c2
-rw-r--r--drivers/spi/spi-topcliff-pch.c228
-rw-r--r--drivers/spi/spi-uniphier.c198
-rw-r--r--drivers/spi/spi-virtio.c431
-rw-r--r--drivers/spi/spi-wpcm-fiu.c30
-rw-r--r--drivers/spi/spi-xcomm.c103
-rw-r--r--drivers/spi/spi-xilinx.c67
-rw-r--r--drivers/spi/spi-xlp.c48
-rw-r--r--drivers/spi/spi-xtensa-xtfpga.c32
-rw-r--r--drivers/spi/spi-zynq-qspi.c66
-rw-r--r--drivers/spi/spi-zynqmp-gqspi.c309
-rw-r--r--drivers/spi/spi.c1246
-rw-r--r--drivers/spi/spidev.c83
176 files changed, 27352 insertions, 9288 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 8962b2557615..5520403896fc 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -55,8 +55,21 @@ config SPI_MEM
This extension is meant to simplify interaction with SPI memories
by providing a high-level interface to send memory-like commands.
+config SPI_OFFLOAD
+ bool
+
comment "SPI Master Controller Drivers"
+config SPI_AIROHA_SNFI
+ tristate "Airoha SPI NAND Flash Interface"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on SPI_MASTER
+ select REGMAP_MMIO
+ help
+ This enables support for SPI-NAND mode on the Airoha NAND
+ Flash Interface found on Airoha ARM SoCs. This controller
+ is implemented as a SPI-MEM controller.
+
config SPI_ALTERA
tristate "Altera SPI Controller platform driver"
select SPI_ALTERA_CORE
@@ -86,6 +99,36 @@ config SPI_AMLOGIC_SPIFC_A1
This enables master mode support for the SPIFC (SPI flash
controller) available in Amlogic A1 (A113L SoC).
+config SPI_AMLOGIC_SPIFC_A4
+ tristate "Amlogic A4 SPI Flash controller"
+ depends on ARCH_MESON || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ This enables SPI mode on the NAND Flash Controller of Amlogic
+ ARM SoCs. It supports SPI Nor Flash and SPI NAND Flash (Could
+ enable Host ECC HW engine). The controller implements the
+ SPI-MEM interface, it doesn't support generic SPI.
+
+config SPI_AMLOGIC_SPISG
+ tristate "Amlogic SPISG controller"
+ depends on COMMON_CLK
+ depends on ARCH_MESON || COMPILE_TEST
+ help
+ This enables master mode support for the SPISG (SPI scatter-gather
+ communication controller), which is available on platforms such as
+ Amlogic A4 SoCs.
+
+config SPI_APPLE
+ tristate "Apple SoC SPI Controller platform driver"
+ depends on ARCH_APPLE || COMPILE_TEST
+ help
+ This enables support for the SPI controller present on
+ many Apple SoCs, including the t8103 (M1), t8112 (M2)
+ and t600x (M1 Pro/Max/Ultra). Multiple SPI controller
+ instances are present on the SoC and each connects usually
+ to a single device like spi-nor (nvram), input device controller
+ or fingerprint sensor.
+
config SPI_AR934X
tristate "Qualcomm Atheros AR934X/QCA95XX SPI controller driver"
depends on ATH79 || COMPILE_TEST
@@ -121,7 +164,7 @@ config SPI_ASPEED_SMC
config SPI_ATMEL
tristate "Atmel SPI Controller"
- depends on ARCH_AT91 || COMPILE_TEST
+ depends on ARCH_MICROCHIP || COMPILE_TEST
depends on OF
help
This selects a driver for the Atmel SPI Controller, present on
@@ -155,6 +198,7 @@ config SPI_AU1550
config SPI_AXI_SPI_ENGINE
tristate "Analog Devices AXI SPI Engine controller"
depends on HAS_IOMEM
+ select SPI_OFFLOAD
help
This enables support for the Analog Devices AXI SPI Engine SPI controller.
It is part of the SPI Engine framework that is used in some Analog Devices
@@ -216,11 +260,11 @@ config SPI_BCMBCA_HSSPI
explicitly.
config SPI_BITBANG
- tristate "Utilities for Bitbanging SPI masters"
+ tristate "Utilities for Bitbanging SPI host controllers"
help
With a few GPIO pins, your system can bitbang the SPI protocol.
Select this to get SPI support through I/O pins (GPIO, parallel
- port, etc). Or, some systems' SPI master controller drivers use
+ port, etc). Or, some systems' SPI host controller drivers use
this code to manage the per-word or per-transfer accesses to the
hardware shift registers.
@@ -246,7 +290,7 @@ config SPI_CADENCE
config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller"
- depends on OF && (ARM || ARM64 || X86 || RISCV || COMPILE_TEST)
+ depends on OF && (ARM || ARM64 || X86 || RISCV || MIPS || COMPILE_TEST)
help
Enable support for the Cadence Quad SPI Flash controller.
@@ -257,7 +301,7 @@ config SPI_CADENCE_QUADSPI
config SPI_CADENCE_XSPI
tristate "Cadence XSPI controller"
- depends on OF && HAS_IOMEM
+ depends on OF && HAS_IOMEM && 64BIT
depends on SPI_MEM
help
Enable support for the Cadence XSPI Flash controller.
@@ -267,6 +311,12 @@ config SPI_CADENCE_XSPI
device with a Cadence XSPI controller and want to access the
Flash as an MTD device.
+config SPI_CH341
+ tristate "CH341 USB2SPI adapter"
+ depends on SPI_MASTER && USB
+ help
+ Enables the SPI controller on the CH341a USB to serial chip
+
config SPI_CLPS711X
tristate "CLPS711X host SPI controller"
depends on ARCH_CLPS711X || COMPILE_TEST
@@ -281,6 +331,14 @@ config SPI_COLDFIRE_QSPI
This enables support for the Coldfire QSPI controller in master
mode.
+config SPI_CS42L43
+ tristate "Cirrus Logic CS42L43 SPI controller"
+ depends on MFD_CS42L43 && PINCTRL_CS42L43
+ select GPIO_SWNODE_UNDEFINED
+ help
+ This enables support for the SPI controller inside the Cirrus Logic
+ CS42L43 audio codec.
+
config SPI_DAVINCI
tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
@@ -377,7 +435,8 @@ config SPI_FSL_LPSPI
config SPI_FSL_QUADSPI
tristate "Freescale QSPI controller"
- depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
+ depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || \
+ ARCH_SPACEMIT || COMPILE_TEST
depends on HAS_IOMEM
help
This enables support for the Quad SPI controller in master mode.
@@ -507,6 +566,18 @@ config SPI_JCORE
This enables support for the SPI master controller in the J-Core
synthesizable, open source SoC.
+config SPI_KSPI2
+ tristate "Support for KEBA SPI master type 2 hardware"
+ depends on HAS_IOMEM
+ depends on KEBA_CP500 || COMPILE_TEST
+ select AUXILIARY_BUS
+ help
+ This driver supports KEBA SPI master type 2 FPGA implementation,
+ as found on CP500 devices for example.
+
+ This driver can also be built as a module. If so, the module
+ will be called spi-kspi2.
+
config SPI_LM70_LLP
tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
depends on PARPORT
@@ -516,6 +587,32 @@ config SPI_LM70_LLP
which interfaces to an LM70 temperature sensor using
a parallel port.
+config SPI_LOONGSON_CORE
+ tristate
+ depends on LOONGARCH || COMPILE_TEST
+
+config SPI_LOONGSON_PCI
+ tristate "Loongson SPI Controller PCI Driver Support"
+ select SPI_LOONGSON_CORE
+ depends on PCI && (LOONGARCH || COMPILE_TEST)
+ help
+ This bus driver supports the Loongson SPI hardware controller in
+ the Loongson platforms and supports to use PCI framework to
+ register SPI device resources.
+ Say Y or M here if you want to use the SPI controller on
+ Loongson platform.
+
+config SPI_LOONGSON_PLATFORM
+ tristate "Loongson SPI Controller Platform Driver Support"
+ select SPI_LOONGSON_CORE
+ depends on OF && (LOONGARCH || COMPILE_TEST)
+ help
+ This bus driver supports the Loongson SPI hardware controller in
+ the Loongson platforms and supports to use DTS framework to
+ register SPI device resources.
+ Say Y or M here if you want to use the SPI controller on
+ Loongson platform.
+
config SPI_LP8841_RTC
tristate "ICP DAS LP-8841 SPI Controller for RTC"
depends on MACH_PXA27X_DT || COMPILE_TEST
@@ -570,10 +667,10 @@ config SPI_FSL_SPI
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select REGMAP_MMIO
- depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || M5441x || COMPILE_TEST
+ depends on ARCH_MXC || ARCH_NXP || M5441x || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
- mode. VF610, LS1021A and ColdFire platforms uses the controller.
+ mode. S32, VF610, LS1021A and ColdFire platforms uses the controller.
config SPI_FSL_ESPI
tristate "Freescale eSPI controller"
@@ -583,6 +680,17 @@ config SPI_FSL_ESPI
From MPC8536, 85xx platform uses the controller, and all P10xx,
P20xx, P30xx,P40xx, P50xx uses this controller.
+config SPI_LJCA
+ tristate "Intel La Jolla Cove Adapter SPI support"
+ depends on USB_LJCA
+ default USB_LJCA
+ help
+ Select this option to enable SPI driver for the Intel
+ La Jolla Cove Adapter (LJCA) board.
+
+ This driver can also be built as a module. If so, the module
+ will be called spi-ljca.
+
config SPI_MESON_SPICC
tristate "Amlogic Meson SPICC controller"
depends on COMMON_CLK
@@ -599,15 +707,6 @@ config SPI_MESON_SPIFC
This enables master mode support for the SPIFC (SPI flash
controller) available in Amlogic Meson SoCs.
-config SPI_MICROCHIP_CORE
- tristate "Microchip FPGA SPI controllers"
- depends on SPI_MASTER
- help
- This enables the SPI driver for Microchip FPGA SPI controllers.
- Say Y or M here if you want to use the "hard" controllers on
- PolarFire SoC.
- If built as a module, it will be called spi-microchip-core.
-
config SPI_MICROCHIP_CORE_QSPI
tristate "Microchip FPGA QSPI controllers"
depends on SPI_MASTER
@@ -617,6 +716,15 @@ config SPI_MICROCHIP_CORE_QSPI
PolarFire SoC.
If built as a module, it will be called spi-microchip-core-qspi.
+config SPI_MICROCHIP_CORE_SPI
+ tristate "Microchip FPGA CoreSPI controller"
+ depends on SPI_MASTER
+ help
+ This enables the SPI driver for Microchip FPGA CoreSPI controller.
+ Say Y or M here if you want to use the "soft" controllers on
+ PolarFire SoC.
+ If built as a module, it will be called spi-microchip-core-spi.
+
config SPI_MT65XX
tristate "MediaTek SPI controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
@@ -650,7 +758,7 @@ config SPI_MTK_SNFI
This enables support for SPI-NAND mode on the MediaTek NAND
Flash Interface found on MediaTek ARM SoCs. This controller
is implemented as a SPI-MEM controller with pipelined ECC
- capcability.
+ capability.
config SPI_WPCM_FIU
tristate "Nuvoton WPCM450 Flash Interface Unit"
@@ -764,6 +872,16 @@ config SPI_PL022
controller. If you have an embedded system with an AMBA(R)
bus and a PL022 controller, say Y or M here.
+config SPI_POLARFIRE_SOC
+ tristate "Microchip FPGA SPI controllers"
+ depends on SPI_MASTER
+ depends on ARCH_MICROCHIP || COMPILE_TEST
+ help
+ This enables the SPI driver for Microchip FPGA SPI controllers.
+ Say Y or M here if you want to use the "hard" controllers on
+ PolarFire SoC.
+ If built as a module, it will be called spi-mpfs.
+
config SPI_PPC4xx
tristate "PPC4xx SPI Controller"
depends on PPC32 && 4xx
@@ -773,16 +891,26 @@ config SPI_PPC4xx
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
- depends on ARCH_PXA || ARCH_MMP || PCI || ACPI || COMPILE_TEST
+ depends on ARCH_PXA || ARCH_MMP || (X86 && (PCI || ACPI)) || COMPILE_TEST
select PXA_SSP if ARCH_PXA || ARCH_MMP
help
This enables using a PXA2xx or Sodaville SSP port as a SPI master
- controller. The driver can be configured to use any SSP port and
- additional documentation can be found a Documentation/spi/pxa2xx.rst.
+ controller. The driver can be configured to use any SSP port.
config SPI_PXA2XX_PCI
def_tristate SPI_PXA2XX && PCI && COMMON_CLK
+config SPI_REALTEK_SNAND
+ tristate "Realtek SPI-NAND Flash Controller"
+ depends on MACH_REALTEK_RTL || COMPILE_TEST
+ select REGMAP
+ help
+ This enables support for the SPI-NAND Flash controller on
+ Realtek SoCs.
+
+ This driver does not support generic SPI. The implementation
+ only supports the spi-mem interface.
+
config SPI_ROCKCHIP
tristate "Rockchip SPI controller driver"
depends on ARCH_ROCKCHIP || COMPILE_TEST
@@ -809,7 +937,8 @@ config SPI_ROCKCHIP_SFC
config SPI_RB4XX
tristate "Mikrotik RB4XX SPI master"
- depends on SPI_MASTER && ATH79
+ depends on SPI_MASTER && (ATH79 || COMPILE_TEST)
+ depends on OF
help
SPI controller driver for the Mikrotik RB4xx series boards.
@@ -825,11 +954,20 @@ config SPI_RSPI
help
SPI driver for Renesas RSPI and QSPI blocks.
+config SPI_RZV2H_RSPI
+ tristate "Renesas RZ/V2H RSPI controller"
+ depends on ARCH_RENESAS || COMPILE_TEST
+ help
+ RSPI driver for the Renesas RZ/V2H Serial Peripheral Interface (RSPI).
+ RSPI supports both SPI host and SPI target roles. This option only
+ enables the SPI host role.
+
config SPI_RZV2M_CSI
tristate "Renesas RZ/V2M CSI controller"
depends on ARCH_RENESAS || COMPILE_TEST
help
- SPI driver for Renesas RZ/V2M Clocked Serial Interface (CSI)
+ SPI driver for Renesas RZ/V2M Clocked Serial Interface (CSI).
+ CSI supports both SPI host and SPI target roles.
config SPI_QCOM_QSPI
tristate "QTI QSPI controller"
@@ -837,6 +975,15 @@ config SPI_QCOM_QSPI
help
QSPI(Quad SPI) driver for Qualcomm QSPI controller.
+config SPI_QPIC_SNAND
+ tristate "QPIC SNAND controller"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on MTD
+ help
+ QPIC_SNAND (QPIC SPI NAND) driver for Qualcomm QPIC controller.
+ QPIC controller supports both parallel nand and serial nand.
+ This config will enable serial nand driver for QPIC controller.
+
config SPI_QUP
tristate "Qualcomm SPI controller with QUP interface"
depends on ARCH_QCOM || COMPILE_TEST
@@ -926,6 +1073,15 @@ config SPI_SN_F_OSPI
for connecting an SPI Flash memory over up to 8-bit wide bus.
It supports indirect access mode only.
+config SPI_SG2044_NOR
+ tristate "SG2044 SPI NOR Controller"
+ depends on ARCH_SOPHGO || COMPILE_TEST
+ help
+ This enables support for the SG2044 SPI NOR controller,
+ which supports Dual/Quad read and write operations while
+ also supporting 3Byte address devices and 4Byte address
+ devices.
+
config SPI_SPRD
tristate "Spreadtrum SPI controller"
depends on ARCH_SPRD || COMPILE_TEST
@@ -950,6 +1106,16 @@ config SPI_STM32
is not available, the driver automatically falls back to
PIO mode.
+config SPI_STM32_OSPI
+ tristate "STMicroelectronics STM32 OCTO SPI controller"
+ depends on ARCH_STM32 || COMPILE_TEST
+ depends on OF
+ depends on SPI_MEM
+ help
+ This enables support for the Octo SPI controller in master mode.
+ This driver does not support generic SPI. The implementation only
+ supports spi-mem interface.
+
config SPI_STM32_QSPI
tristate "STMicroelectronics STM32 QUAD SPI controller"
depends on ARCH_STM32 || COMPILE_TEST
@@ -1026,10 +1192,10 @@ config SPI_TEGRA210_QUAD
config SPI_TEGRA114
tristate "NVIDIA Tegra114 SPI Controller"
- depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
+ depends on ARCH_TEGRA || COMPILE_TEST
depends on RESET_CONTROLLER
help
- SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller
+ SPI controller driver for NVIDIA Tegra114 and later SoCs. This controller
is different than the older SoCs SPI controller and also register interface
get changed with this controller.
@@ -1080,6 +1246,17 @@ config SPI_UNIPHIER
If your SoC supports SCSSI, say Y here.
+config SPI_VIRTIO
+ tristate "Virtio SPI Controller"
+ depends on SPI_MASTER && VIRTIO
+ help
+ If you say yes to this option, support will be included for the virtio
+ SPI controller driver. The hardware can be emulated by any device model
+ software according to the virtio protocol.
+
+ This driver can also be built as a module. If so, the module
+ will be called spi-virtio.
+
config SPI_XCOMM
tristate "Analog Devices AD-FMCOMMS1-EBZ SPI-I2C-bridge driver"
depends on I2C
@@ -1124,6 +1301,7 @@ config SPI_XTENSA_XTFPGA
config SPI_ZYNQ_QSPI
tristate "Xilinx Zynq QSPI controller"
depends on ARCH_ZYNQ || COMPILE_TEST
+ depends on SPI_MEM
help
This enables support for the Zynq Quad SPI controller
in master mode.
@@ -1131,13 +1309,16 @@ config SPI_ZYNQ_QSPI
config SPI_ZYNQMP_GQSPI
tristate "Xilinx ZynqMP GQSPI controller"
- depends on (SPI_MASTER && HAS_DMA) || COMPILE_TEST
+ depends on (SPI_MEM && HAS_DMA) || COMPILE_TEST
help
Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
+ This controller only supports SPI memory interface.
config SPI_AMD
tristate "AMD SPI controller"
- depends on SPI_MASTER || COMPILE_TEST
+ depends on PCI
+ depends on SPI_MASTER || X86 || COMPILE_TEST
+ depends on SPI_MEM
help
Enables SPI controller driver for AMD SoC.
@@ -1220,4 +1401,21 @@ endif # SPI_SLAVE
config SPI_DYNAMIC
def_bool ACPI || OF_DYNAMIC || SPI_SLAVE
+if SPI_OFFLOAD
+
+comment "SPI Offload triggers"
+
+config SPI_OFFLOAD_TRIGGER_ADI_UTIL_SD
+ tristate "SPI offload trigger using ADI sigma-delta utility"
+ help
+ SPI offload trigger from ADI sigma-delta utility FPGA IP block.
+
+config SPI_OFFLOAD_TRIGGER_PWM
+ tristate "SPI offload trigger using PWM"
+ depends on PWM
+ help
+ Generic SPI offload trigger implemented using PWM output.
+
+endif # SPI_OFFLOAD
+
endif # SPI
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 080c2c1b3ec1..863b628ff1ec 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -10,14 +10,19 @@ ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
obj-$(CONFIG_SPI_MASTER) += spi.o
obj-$(CONFIG_SPI_MEM) += spi-mem.o
obj-$(CONFIG_SPI_MUX) += spi-mux.o
+obj-$(CONFIG_SPI_OFFLOAD) += spi-offload.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o
# SPI master controller drivers (bus)
+obj-$(CONFIG_SPI_AIROHA_SNFI) += spi-airoha-snfi.o
obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o
obj-$(CONFIG_SPI_ALTERA_CORE) += spi-altera-core.o
obj-$(CONFIG_SPI_ALTERA_DFL) += spi-altera-dfl.o
obj-$(CONFIG_SPI_AMLOGIC_SPIFC_A1) += spi-amlogic-spifc-a1.o
+obj-$(CONFIG_SPI_AMLOGIC_SPIFC_A4) += spi-amlogic-spifc-a4.o
+obj-$(CONFIG_SPI_AMLOGIC_SPISG) += spi-amlogic-spisg.o
+obj-$(CONFIG_SPI_APPLE) += spi-apple.o
obj-$(CONFIG_SPI_AR934X) += spi-ar934x.o
obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o
obj-$(CONFIG_SPI_ASPEED_SMC) += spi-aspeed-smc.o
@@ -38,8 +43,10 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o
obj-$(CONFIG_SPI_CADENCE_QUADSPI) += spi-cadence-quadspi.o
obj-$(CONFIG_SPI_CADENCE_XSPI) += spi-cadence-xspi.o
+obj-$(CONFIG_SPI_CH341) += spi-ch341.o
obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
+obj-$(CONFIG_SPI_CS42L43) += spi-cs42l43.o
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
obj-$(CONFIG_SPI_DLN2) += spi-dln2.o
obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
@@ -70,12 +77,17 @@ obj-$(CONFIG_SPI_INTEL_PCI) += spi-intel-pci.o
obj-$(CONFIG_SPI_INTEL_PLATFORM) += spi-intel-platform.o
obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o
obj-$(CONFIG_SPI_JCORE) += spi-jcore.o
+obj-$(CONFIG_SPI_KSPI2) += spi-kspi2.o
+obj-$(CONFIG_SPI_LJCA) += spi-ljca.o
obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
+obj-$(CONFIG_SPI_LOONGSON_CORE) += spi-loongson-core.o
+obj-$(CONFIG_SPI_LOONGSON_PCI) += spi-loongson-pci.o
+obj-$(CONFIG_SPI_LOONGSON_PLATFORM) += spi-loongson-plat.o
obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o
obj-$(CONFIG_SPI_MESON_SPICC) += spi-meson-spicc.o
obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
-obj-$(CONFIG_SPI_MICROCHIP_CORE) += spi-microchip-core.o
obj-$(CONFIG_SPI_MICROCHIP_CORE_QSPI) += spi-microchip-core-qspi.o
+obj-$(CONFIG_SPI_MICROCHIP_CORE_SPI) += spi-microchip-core-spi.o
obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o
@@ -85,6 +97,7 @@ obj-$(CONFIG_SPI_MTK_NOR) += spi-mtk-nor.o
obj-$(CONFIG_SPI_MTK_SNFI) += spi-mtk-snfi.o
obj-$(CONFIG_SPI_MXIC) += spi-mxic.o
obj-$(CONFIG_SPI_MXS) += spi-mxs.o
+obj-$(CONFIG_SPI_POLARFIRE_SOC) += spi-mpfs.o
obj-$(CONFIG_SPI_WPCM_FIU) += spi-wpcm-fiu.o
obj-$(CONFIG_SPI_NPCM_FIU) += spi-npcm-fiu.o
obj-$(CONFIG_SPI_NPCM_PSPI) += spi-npcm-pspi.o
@@ -101,18 +114,22 @@ obj-$(CONFIG_SPI_PIC32) += spi-pic32.o
obj-$(CONFIG_SPI_PIC32_SQI) += spi-pic32-sqi.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
-spi-pxa2xx-platform-objs := spi-pxa2xx.o spi-pxa2xx-dma.o
+obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-core.o
+spi-pxa2xx-core-y := spi-pxa2xx.o spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o
obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o
+obj-$(CONFIG_SPI_QPIC_SNAND) += spi-qpic-snand.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o
+obj-$(CONFIG_SPI_REALTEK_SNAND) += spi-realtek-rtl-snand.o
obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
+obj-$(CONFIG_SPI_RZV2H_RSPI) += spi-rzv2h-rspi.o
obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o
obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o
obj-$(CONFIG_SPI_SC18IS602) += spi-sc18is602.o
@@ -123,9 +140,11 @@ obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIFIVE) += spi-sifive.o
obj-$(CONFIG_SPI_SLAVE_MT27XX) += spi-slave-mt27xx.o
obj-$(CONFIG_SPI_SN_F_OSPI) += spi-sn-f-ospi.o
+obj-$(CONFIG_SPI_SG2044_NOR) += spi-sg2044-nor.o
obj-$(CONFIG_SPI_SPRD) += spi-sprd.o
obj-$(CONFIG_SPI_SPRD_ADI) += spi-sprd-adi.o
obj-$(CONFIG_SPI_STM32) += spi-stm32.o
+obj-$(CONFIG_SPI_STM32_OSPI) += spi-stm32-ospi.o
obj-$(CONFIG_SPI_STM32_QSPI) += spi-stm32-qspi.o
obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
@@ -141,14 +160,19 @@ 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_UNIPHIER) += spi-uniphier.o
+obj-$(CONFIG_SPI_VIRTIO) += spi-virtio.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
obj-$(CONFIG_SPI_XLP) += spi-xlp.o
obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
obj-$(CONFIG_SPI_ZYNQ_QSPI) += spi-zynq-qspi.o
obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o
-obj-$(CONFIG_SPI_AMD) += spi-amd.o
+obj-$(CONFIG_SPI_AMD) += spi-amd.o spi-amd-pci.o
# SPI slave protocol handlers
obj-$(CONFIG_SPI_SLAVE_TIME) += spi-slave-time.o
obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL) += spi-slave-system-control.o
+
+# SPI offload triggers
+obj-$(CONFIG_SPI_OFFLOAD_TRIGGER_PWM) += spi-offload-trigger-pwm.o
+obj-$(CONFIG_SPI_OFFLOAD_TRIGGER_ADI_UTIL_SD) += spi-offload-trigger-adi-util-sigma-delta.o
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index 3d1252566134..d7a3d85d00c2 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -11,11 +11,15 @@
* This driver is based on drivers/mtd/spi-nor/fsl-quadspi.c from Freescale.
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -34,6 +38,7 @@
#define QSPI_IDR 0x0018 /* Interrupt Disable Register */
#define QSPI_IMR 0x001c /* Interrupt Mask Register */
#define QSPI_SCR 0x0020 /* Serial Clock Register */
+#define QSPI_SR2 0x0024 /* SAMA7G5 Status Register */
#define QSPI_IAR 0x0030 /* Instruction Address Register */
#define QSPI_ICR 0x0034 /* Instruction Code Register */
@@ -44,16 +49,33 @@
#define QSPI_SMR 0x0040 /* Scrambling Mode Register */
#define QSPI_SKR 0x0044 /* Scrambling Key Register */
+#define QSPI_REFRESH 0x0050 /* Refresh Register */
+#define QSPI_WRACNT 0x0054 /* Write Access Counter Register */
+#define QSPI_DLLCFG 0x0058 /* DLL Configuration Register */
+#define QSPI_PCALCFG 0x005C /* Pad Calibration Configuration Register */
+#define QSPI_PCALBP 0x0060 /* Pad Calibration Bypass Register */
+#define QSPI_TOUT 0x0064 /* Timeout Register */
+
#define QSPI_WPMR 0x00E4 /* Write Protection Mode Register */
#define QSPI_WPSR 0x00E8 /* Write Protection Status Register */
#define QSPI_VERSION 0x00FC /* Version Register */
+#define SAMA7G5_QSPI0_MAX_SPEED_HZ 200000000
+#define SAMA7G5_QSPI1_SDR_MAX_SPEED_HZ 133000000
+#define SAM9X7_QSPI_MAX_SPEED_HZ 100000000
/* Bitfields in QSPI_CR (Control Register) */
#define QSPI_CR_QSPIEN BIT(0)
#define QSPI_CR_QSPIDIS BIT(1)
+#define QSPI_CR_DLLON BIT(2)
+#define QSPI_CR_DLLOFF BIT(3)
+#define QSPI_CR_STPCAL BIT(4)
+#define QSPI_CR_SRFRSH BIT(5)
#define QSPI_CR_SWRST BIT(7)
+#define QSPI_CR_UPDCFG BIT(8)
+#define QSPI_CR_STTFR BIT(9)
+#define QSPI_CR_RTOUT BIT(10)
#define QSPI_CR_LASTXFER BIT(24)
/* Bitfields in QSPI_MR (Mode Register) */
@@ -61,12 +83,14 @@
#define QSPI_MR_LLB BIT(1)
#define QSPI_MR_WDRBT BIT(2)
#define QSPI_MR_SMRM BIT(3)
+#define QSPI_MR_DQSDLYEN BIT(3)
#define QSPI_MR_CSMODE_MASK GENMASK(5, 4)
#define QSPI_MR_CSMODE_NOT_RELOADED (0 << 4)
#define QSPI_MR_CSMODE_LASTXFER (1 << 4)
#define QSPI_MR_CSMODE_SYSTEMATICALLY (2 << 4)
#define QSPI_MR_NBBITS_MASK GENMASK(11, 8)
#define QSPI_MR_NBBITS(n) ((((n) - 8) << 8) & QSPI_MR_NBBITS_MASK)
+#define QSPI_MR_OENSD BIT(15)
#define QSPI_MR_DLYBCT_MASK GENMASK(23, 16)
#define QSPI_MR_DLYBCT(n) (((n) << 16) & QSPI_MR_DLYBCT_MASK)
#define QSPI_MR_DLYCS_MASK GENMASK(31, 24)
@@ -80,6 +104,13 @@
#define QSPI_SR_CSR BIT(8)
#define QSPI_SR_CSS BIT(9)
#define QSPI_SR_INSTRE BIT(10)
+#define QSPI_SR_LWRA BIT(11)
+#define QSPI_SR_QITF BIT(12)
+#define QSPI_SR_QITR BIT(13)
+#define QSPI_SR_CSFA BIT(14)
+#define QSPI_SR_CSRA BIT(15)
+#define QSPI_SR_RFRSHD BIT(16)
+#define QSPI_SR_TOUT BIT(17)
#define QSPI_SR_QSPIENS BIT(24)
#define QSPI_SR_CMD_COMPLETED (QSPI_SR_INSTRE | QSPI_SR_CSR)
@@ -92,9 +123,22 @@
#define QSPI_SCR_DLYBS_MASK GENMASK(23, 16)
#define QSPI_SCR_DLYBS(n) (((n) << 16) & QSPI_SCR_DLYBS_MASK)
+/* Bitfields in QSPI_SR2 (SAMA7G5 Status Register) */
+#define QSPI_SR2_SYNCBSY BIT(0)
+#define QSPI_SR2_QSPIENS BIT(1)
+#define QSPI_SR2_CSS BIT(2)
+#define QSPI_SR2_RBUSY BIT(3)
+#define QSPI_SR2_HIDLE BIT(4)
+#define QSPI_SR2_DLOCK BIT(5)
+#define QSPI_SR2_CALBSY BIT(6)
+
+/* Bitfields in QSPI_IAR (Instruction Address Register) */
+#define QSPI_IAR_ADDR GENMASK(31, 0)
+
/* Bitfields in QSPI_ICR (Read/Write Instruction Code Register) */
#define QSPI_ICR_INST_MASK GENMASK(7, 0)
#define QSPI_ICR_INST(inst) (((inst) << 0) & QSPI_ICR_INST_MASK)
+#define QSPI_ICR_INST_MASK_SAMA7G5 GENMASK(15, 0)
#define QSPI_ICR_OPT_MASK GENMASK(23, 16)
#define QSPI_ICR_OPT(opt) (((opt) << 16) & QSPI_ICR_OPT_MASK)
@@ -107,6 +151,9 @@
#define QSPI_IFR_WIDTH_QUAD_IO (4 << 0)
#define QSPI_IFR_WIDTH_DUAL_CMD (5 << 0)
#define QSPI_IFR_WIDTH_QUAD_CMD (6 << 0)
+#define QSPI_IFR_WIDTH_OCT_OUTPUT (7 << 0)
+#define QSPI_IFR_WIDTH_OCT_IO (8 << 0)
+#define QSPI_IFR_WIDTH_OCT_CMD (9 << 0)
#define QSPI_IFR_INSTEN BIT(4)
#define QSPI_IFR_ADDREN BIT(5)
#define QSPI_IFR_OPTEN BIT(6)
@@ -117,19 +164,60 @@
#define QSPI_IFR_OPTL_4BIT (2 << 8)
#define QSPI_IFR_OPTL_8BIT (3 << 8)
#define QSPI_IFR_ADDRL BIT(10)
+#define QSPI_IFR_ADDRL_SAMA7G5 GENMASK(11, 10)
#define QSPI_IFR_TFRTYP_MEM BIT(12)
#define QSPI_IFR_SAMA5D2_WRITE_TRSFR BIT(13)
#define QSPI_IFR_CRM BIT(14)
+#define QSPI_IFR_DDREN BIT(15)
#define QSPI_IFR_NBDUM_MASK GENMASK(20, 16)
#define QSPI_IFR_NBDUM(n) (((n) << 16) & QSPI_IFR_NBDUM_MASK)
+#define QSPI_IFR_END BIT(22)
+#define QSPI_IFR_SMRM BIT(23)
#define QSPI_IFR_APBTFRTYP_READ BIT(24) /* Defined in SAM9X60 */
+#define QSPI_IFR_DQSEN BIT(25)
+#define QSPI_IFR_DDRCMDEN BIT(26)
+#define QSPI_IFR_HFWBEN BIT(27)
+#define QSPI_IFR_PROTTYP GENMASK(29, 28)
+#define QSPI_IFR_PROTTYP_STD_SPI 0
+#define QSPI_IFR_PROTTYP_TWIN_QUAD 1
+#define QSPI_IFR_PROTTYP_OCTAFLASH 2
+#define QSPI_IFR_PROTTYP_HYPERFLASH 3
/* Bitfields in QSPI_SMR (Scrambling Mode Register) */
#define QSPI_SMR_SCREN BIT(0)
#define QSPI_SMR_RVDIS BIT(1)
+#define QSPI_SMR_SCRKL BIT(2)
+
+/* Bitfields in QSPI_REFRESH (Refresh Register) */
+#define QSPI_REFRESH_DELAY_COUNTER GENMASK(31, 0)
+
+/* Bitfields in QSPI_WRACNT (Write Access Counter Register) */
+#define QSPI_WRACNT_NBWRA GENMASK(31, 0)
+
+/* Bitfields in QSPI_DLLCFG (DLL Configuration Register) */
+#define QSPI_DLLCFG_RANGE BIT(0)
+
+/* Bitfields in QSPI_PCALCFG (DLL Pad Calibration Configuration Register) */
+#define QSPI_PCALCFG_AAON BIT(0)
+#define QSPI_PCALCFG_DAPCAL BIT(1)
+#define QSPI_PCALCFG_DIFFPM BIT(2)
+#define QSPI_PCALCFG_CLKDIV GENMASK(6, 4)
+#define QSPI_PCALCFG_CALCNT GENMASK(16, 8)
+#define QSPI_PCALCFG_CALP GENMASK(27, 24)
+#define QSPI_PCALCFG_CALN GENMASK(31, 28)
+
+/* Bitfields in QSPI_PCALBP (DLL Pad Calibration Bypass Register) */
+#define QSPI_PCALBP_BPEN BIT(0)
+#define QSPI_PCALBP_CALPBP GENMASK(11, 8)
+#define QSPI_PCALBP_CALNBP GENMASK(19, 16)
+
+/* Bitfields in QSPI_TOUT (Timeout Register) */
+#define QSPI_TOUT_TCNTM GENMASK(15, 0)
/* Bitfields in QSPI_WPMR (Write Protection Mode Register) */
#define QSPI_WPMR_WPEN BIT(0)
+#define QSPI_WPMR_WPITEN BIT(1)
+#define QSPI_WPMR_WPCREN BIT(2)
#define QSPI_WPMR_WPKEY_MASK GENMASK(31, 8)
#define QSPI_WPMR_WPKEY(wpkey) (((wpkey) << 8) & QSPI_WPMR_WPKEY_MASK)
@@ -138,23 +226,77 @@
#define QSPI_WPSR_WPVSRC_MASK GENMASK(15, 8)
#define QSPI_WPSR_WPVSRC(src) (((src) << 8) & QSPI_WPSR_WPVSRC)
+#define ATMEL_QSPI_TIMEOUT 1000 /* ms */
+#define ATMEL_QSPI_SYNC_TIMEOUT 300 /* ms */
+#define QSPI_DLLCFG_THRESHOLD_FREQ 90000000U
+#define QSPI_CALIB_TIME 2000 /* 2 us */
+
+/* Use PIO for small transfers. */
+#define ATMEL_QSPI_DMA_MIN_BYTES 16
+/**
+ * struct atmel_qspi_pcal - Pad Calibration Clock Division
+ * @pclk_rate: peripheral clock rate.
+ * @pclk_div: calibration clock division. The clock applied to the calibration
+ * cell is divided by pclk_div + 1.
+ */
+struct atmel_qspi_pcal {
+ u32 pclk_rate;
+ u8 pclk_div;
+};
+
+#define ATMEL_QSPI_PCAL_ARRAY_SIZE 8
+static const struct atmel_qspi_pcal pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE] = {
+ {25000000, 0},
+ {50000000, 1},
+ {75000000, 2},
+ {100000000, 3},
+ {125000000, 4},
+ {150000000, 5},
+ {175000000, 6},
+ {200000000, 7},
+};
+
struct atmel_qspi_caps {
+ u32 max_speed_hz;
bool has_qspick;
+ bool has_gclk;
bool has_ricr;
+ bool octal;
+ bool has_dma;
+ bool has_2xgclk;
+ bool has_padcalib;
+ bool has_dllon;
};
+struct atmel_qspi_ops;
+
struct atmel_qspi {
void __iomem *regs;
void __iomem *mem;
struct clk *pclk;
struct clk *qspick;
+ struct clk *gclk;
struct platform_device *pdev;
const struct atmel_qspi_caps *caps;
+ const struct atmel_qspi_ops *ops;
resource_size_t mmap_size;
u32 pending;
+ u32 irq_mask;
u32 mr;
u32 scr;
+ u32 target_max_speed_hz;
struct completion cmd_completion;
+ struct completion dma_completion;
+ dma_addr_t mmap_phys_base;
+ struct dma_chan *rx_chan;
+ struct dma_chan *tx_chan;
+};
+
+struct atmel_qspi_ops {
+ int (*set_cfg)(struct atmel_qspi *aq, const struct spi_mem_op *op,
+ u32 *offset);
+ int (*transfer)(struct spi_mem *mem, const struct spi_mem_op *op,
+ u32 offset);
};
struct atmel_qspi_mode {
@@ -174,6 +316,19 @@ static const struct atmel_qspi_mode atmel_qspi_modes[] = {
{ 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD },
};
+static const struct atmel_qspi_mode atmel_qspi_sama7g5_modes[] = {
+ { 1, 1, 1, QSPI_IFR_WIDTH_SINGLE_BIT_SPI },
+ { 1, 1, 2, QSPI_IFR_WIDTH_DUAL_OUTPUT },
+ { 1, 1, 4, QSPI_IFR_WIDTH_QUAD_OUTPUT },
+ { 1, 2, 2, QSPI_IFR_WIDTH_DUAL_IO },
+ { 1, 4, 4, QSPI_IFR_WIDTH_QUAD_IO },
+ { 2, 2, 2, QSPI_IFR_WIDTH_DUAL_CMD },
+ { 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD },
+ { 1, 1, 8, QSPI_IFR_WIDTH_OCT_OUTPUT },
+ { 1, 8, 8, QSPI_IFR_WIDTH_OCT_IO },
+ { 8, 8, 8, QSPI_IFR_WIDTH_OCT_CMD },
+};
+
#ifdef VERBOSE_DEBUG
static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
{
@@ -183,7 +338,7 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
case QSPI_MR:
return "MR";
case QSPI_RD:
- return "MR";
+ return "RD";
case QSPI_TD:
return "TD";
case QSPI_SR:
@@ -196,6 +351,8 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
return "IMR";
case QSPI_SCR:
return "SCR";
+ case QSPI_SR2:
+ return "SR2";
case QSPI_IAR:
return "IAR";
case QSPI_ICR:
@@ -208,6 +365,18 @@ static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
return "SMR";
case QSPI_SKR:
return "SKR";
+ case QSPI_REFRESH:
+ return "REFRESH";
+ case QSPI_WRACNT:
+ return "WRACNT";
+ case QSPI_DLLCFG:
+ return "DLLCFG";
+ case QSPI_PCALCFG:
+ return "PCALCFG";
+ case QSPI_PCALBP:
+ return "PCALBP";
+ case QSPI_TOUT:
+ return "TOUT";
case QSPI_WPMR:
return "WPMR";
case QSPI_WPSR:
@@ -249,6 +418,28 @@ static void atmel_qspi_write(u32 value, struct atmel_qspi *aq, u32 offset)
writel_relaxed(value, aq->regs + offset);
}
+static int atmel_qspi_reg_sync(struct atmel_qspi *aq)
+{
+ u32 val;
+ int ret;
+
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_SYNCBSY), 40,
+ ATMEL_QSPI_SYNC_TIMEOUT);
+ return ret;
+}
+
+static int atmel_qspi_update_config(struct atmel_qspi *aq)
+{
+ int ret;
+
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_UPDCFG, aq, QSPI_CR);
+ return atmel_qspi_reg_sync(aq);
+}
+
static inline bool atmel_qspi_is_compatible(const struct spi_mem_op *op,
const struct atmel_qspi_mode *mode)
{
@@ -272,15 +463,34 @@ static int atmel_qspi_find_mode(const struct spi_mem_op *op)
if (atmel_qspi_is_compatible(op, &atmel_qspi_modes[i]))
return i;
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
+}
+
+static int atmel_qspi_sama7g5_find_mode(const struct spi_mem_op *op)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(atmel_qspi_sama7g5_modes); i++)
+ if (atmel_qspi_is_compatible(op, &atmel_qspi_sama7g5_modes[i]))
+ return i;
+
+ return -EOPNOTSUPP;
}
static bool atmel_qspi_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
+ struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->controller);
if (!spi_mem_default_supports_op(mem, op))
return false;
+ if (aq->caps->octal) {
+ if (atmel_qspi_sama7g5_find_mode(op) < 0)
+ return false;
+ else
+ return true;
+ }
+
if (atmel_qspi_find_mode(op) < 0)
return false;
@@ -292,6 +502,25 @@ static bool atmel_qspi_supports_op(struct spi_mem *mem,
return true;
}
+/*
+ * If the QSPI controller is set in regular SPI mode, set it in
+ * Serial Memory Mode (SMM).
+ */
+static int atmel_qspi_set_serial_memory_mode(struct atmel_qspi *aq)
+{
+ int ret = 0;
+
+ if (!(aq->mr & QSPI_MR_SMM)) {
+ aq->mr |= QSPI_MR_SMM;
+ atmel_qspi_write(aq->mr, aq, QSPI_MR);
+
+ if (aq->caps->has_gclk)
+ ret = atmel_qspi_update_config(aq);
+ }
+
+ return ret;
+}
+
static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
const struct spi_mem_op *op, u32 *offset)
{
@@ -371,14 +600,9 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
ifr |= QSPI_IFR_TFRTYP_MEM;
}
- /*
- * If the QSPI controller is set in regular SPI mode, set it in
- * Serial Memory Mode (SMM).
- */
- if (aq->mr != QSPI_MR_SMM) {
- atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR);
- aq->mr = QSPI_MR_SMM;
- }
+ mode = atmel_qspi_set_serial_memory_mode(aq);
+ if (mode < 0)
+ return mode;
/* Clear pending interrupts */
(void)atmel_qspi_read(aq, QSPI_SR);
@@ -404,10 +628,323 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
return 0;
}
+static int atmel_qspi_wait_for_completion(struct atmel_qspi *aq, u32 irq_mask)
+{
+ int err = 0;
+ u32 sr;
+
+ /* Poll INSTRuction End status */
+ sr = atmel_qspi_read(aq, QSPI_SR);
+ if ((sr & irq_mask) == irq_mask)
+ return 0;
+
+ /* Wait for INSTRuction End interrupt */
+ reinit_completion(&aq->cmd_completion);
+ aq->pending = sr & irq_mask;
+ aq->irq_mask = irq_mask;
+ atmel_qspi_write(irq_mask, aq, QSPI_IER);
+ if (!wait_for_completion_timeout(&aq->cmd_completion,
+ msecs_to_jiffies(ATMEL_QSPI_TIMEOUT)))
+ err = -ETIMEDOUT;
+ atmel_qspi_write(irq_mask, aq, QSPI_IDR);
+
+ return err;
+}
+
+static int atmel_qspi_transfer(struct spi_mem *mem,
+ const struct spi_mem_op *op, u32 offset)
+{
+ struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->controller);
+
+ /* Skip to the final steps if there is no data */
+ if (!op->data.nbytes)
+ return atmel_qspi_wait_for_completion(aq,
+ QSPI_SR_CMD_COMPLETED);
+
+ /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */
+ (void)atmel_qspi_read(aq, QSPI_IFR);
+
+ /* Send/Receive data */
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ memcpy_fromio(op->data.buf.in, aq->mem + offset,
+ op->data.nbytes);
+
+ /* Synchronize AHB and APB accesses again */
+ rmb();
+ } else {
+ memcpy_toio(aq->mem + offset, op->data.buf.out,
+ op->data.nbytes);
+
+ /* Synchronize AHB and APB accesses again */
+ wmb();
+ }
+
+ /* Release the chip-select */
+ atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);
+
+ return atmel_qspi_wait_for_completion(aq, QSPI_SR_CMD_COMPLETED);
+}
+
+static int atmel_qspi_sama7g5_set_cfg(struct atmel_qspi *aq,
+ const struct spi_mem_op *op, u32 *offset)
+{
+ u32 iar, icr, ifr;
+ int mode, ret;
+
+ iar = 0;
+ icr = FIELD_PREP(QSPI_ICR_INST_MASK_SAMA7G5, op->cmd.opcode);
+ ifr = QSPI_IFR_INSTEN;
+
+ mode = atmel_qspi_sama7g5_find_mode(op);
+ if (mode < 0)
+ return mode;
+ ifr |= atmel_qspi_sama7g5_modes[mode].config;
+
+ if (op->dummy.buswidth && op->dummy.nbytes) {
+ if (op->addr.dtr && op->dummy.dtr && op->data.dtr)
+ ifr |= QSPI_IFR_NBDUM(op->dummy.nbytes * 8 /
+ (2 * op->dummy.buswidth));
+ else
+ ifr |= QSPI_IFR_NBDUM(op->dummy.nbytes * 8 /
+ op->dummy.buswidth);
+ }
+
+ if (op->addr.buswidth && op->addr.nbytes) {
+ ifr |= FIELD_PREP(QSPI_IFR_ADDRL_SAMA7G5, op->addr.nbytes - 1) |
+ QSPI_IFR_ADDREN;
+ iar = FIELD_PREP(QSPI_IAR_ADDR, op->addr.val);
+ }
+
+ if (op->addr.dtr && op->dummy.dtr && op->data.dtr) {
+ ifr |= QSPI_IFR_DDREN;
+ if (op->cmd.dtr)
+ ifr |= QSPI_IFR_DDRCMDEN;
+
+ ifr |= QSPI_IFR_DQSEN;
+ }
+
+ if (op->cmd.buswidth == 8 || op->addr.buswidth == 8 ||
+ op->data.buswidth == 8)
+ ifr |= FIELD_PREP(QSPI_IFR_PROTTYP, QSPI_IFR_PROTTYP_OCTAFLASH);
+
+ /* offset of the data access in the QSPI memory space */
+ *offset = iar;
+
+ /* Set data enable */
+ if (op->data.nbytes) {
+ ifr |= QSPI_IFR_DATAEN;
+
+ if (op->addr.nbytes)
+ ifr |= QSPI_IFR_TFRTYP_MEM;
+ }
+
+ ret = atmel_qspi_set_serial_memory_mode(aq);
+ if (ret < 0)
+ return ret;
+
+ /* Clear pending interrupts */
+ (void)atmel_qspi_read(aq, QSPI_SR);
+
+ /* Set QSPI Instruction Frame registers */
+ if (op->addr.nbytes && !op->data.nbytes)
+ atmel_qspi_write(iar, aq, QSPI_IAR);
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ atmel_qspi_write(icr, aq, QSPI_RICR);
+ } else {
+ atmel_qspi_write(icr, aq, QSPI_WICR);
+ if (op->data.nbytes)
+ atmel_qspi_write(FIELD_PREP(QSPI_WRACNT_NBWRA,
+ op->data.nbytes),
+ aq, QSPI_WRACNT);
+ }
+
+ atmel_qspi_write(ifr, aq, QSPI_IFR);
+
+ return atmel_qspi_update_config(aq);
+}
+
+static void atmel_qspi_dma_callback(void *param)
+{
+ struct atmel_qspi *aq = param;
+
+ complete(&aq->dma_completion);
+}
+
+static int atmel_qspi_dma_xfer(struct atmel_qspi *aq, struct dma_chan *chan,
+ dma_addr_t dma_dst, dma_addr_t dma_src,
+ unsigned int len)
+{
+ struct dma_async_tx_descriptor *tx;
+ dma_cookie_t cookie;
+ int ret;
+
+ tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!tx) {
+ dev_err(&aq->pdev->dev, "device_prep_dma_memcpy error\n");
+ return -EIO;
+ }
+
+ reinit_completion(&aq->dma_completion);
+ tx->callback = atmel_qspi_dma_callback;
+ tx->callback_param = aq;
+ cookie = tx->tx_submit(tx);
+ ret = dma_submit_error(cookie);
+ if (ret) {
+ dev_err(&aq->pdev->dev, "dma_submit_error %d\n", cookie);
+ return ret;
+ }
+
+ dma_async_issue_pending(chan);
+ ret = wait_for_completion_timeout(&aq->dma_completion,
+ msecs_to_jiffies(20 * ATMEL_QSPI_TIMEOUT));
+ if (ret == 0) {
+ dmaengine_terminate_sync(chan);
+ dev_err(&aq->pdev->dev, "DMA wait_for_completion_timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int atmel_qspi_dma_rx_xfer(struct spi_mem *mem,
+ const struct spi_mem_op *op,
+ struct sg_table *sgt, loff_t loff)
+{
+ struct atmel_qspi *aq =
+ spi_controller_get_devdata(mem->spi->controller);
+ struct scatterlist *sg;
+ dma_addr_t dma_src;
+ unsigned int i, len;
+ int ret;
+
+ dma_src = aq->mmap_phys_base + loff;
+
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ len = sg_dma_len(sg);
+ ret = atmel_qspi_dma_xfer(aq, aq->rx_chan, sg_dma_address(sg),
+ dma_src, len);
+ if (ret)
+ return ret;
+ dma_src += len;
+ }
+
+ return 0;
+}
+
+static int atmel_qspi_dma_tx_xfer(struct spi_mem *mem,
+ const struct spi_mem_op *op,
+ struct sg_table *sgt, loff_t loff)
+{
+ struct atmel_qspi *aq =
+ spi_controller_get_devdata(mem->spi->controller);
+ struct scatterlist *sg;
+ dma_addr_t dma_dst;
+ unsigned int i, len;
+ int ret;
+
+ dma_dst = aq->mmap_phys_base + loff;
+
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ len = sg_dma_len(sg);
+ ret = atmel_qspi_dma_xfer(aq, aq->tx_chan, dma_dst,
+ sg_dma_address(sg), len);
+ if (ret)
+ return ret;
+ dma_dst += len;
+ }
+
+ return 0;
+}
+
+static int atmel_qspi_dma_transfer(struct spi_mem *mem,
+ const struct spi_mem_op *op, loff_t loff)
+{
+ struct sg_table sgt;
+ int ret;
+
+ ret = spi_controller_dma_map_mem_op_data(mem->spi->controller, op,
+ &sgt);
+ if (ret)
+ return ret;
+
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ ret = atmel_qspi_dma_rx_xfer(mem, op, &sgt, loff);
+ else
+ ret = atmel_qspi_dma_tx_xfer(mem, op, &sgt, loff);
+
+ spi_controller_dma_unmap_mem_op_data(mem->spi->controller, op, &sgt);
+
+ return ret;
+}
+
+static int atmel_qspi_sama7g5_transfer(struct spi_mem *mem,
+ const struct spi_mem_op *op, u32 offset)
+{
+ struct atmel_qspi *aq =
+ spi_controller_get_devdata(mem->spi->controller);
+ u32 val;
+ int ret;
+
+ if (!op->data.nbytes) {
+ /* Start the transfer. */
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_STTFR, aq, QSPI_CR);
+
+ return atmel_qspi_wait_for_completion(aq, QSPI_SR_CSRA);
+ }
+
+ /* Send/Receive data. */
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ if (aq->rx_chan && op->addr.nbytes &&
+ op->data.nbytes > ATMEL_QSPI_DMA_MIN_BYTES) {
+ ret = atmel_qspi_dma_transfer(mem, op, offset);
+ if (ret)
+ return ret;
+ } else {
+ memcpy_fromio(op->data.buf.in, aq->mem + offset,
+ op->data.nbytes);
+ }
+
+ if (op->addr.nbytes) {
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_RBUSY), 40,
+ ATMEL_QSPI_SYNC_TIMEOUT);
+ if (ret)
+ return ret;
+ }
+ } else {
+ if (aq->tx_chan && op->addr.nbytes &&
+ op->data.nbytes > ATMEL_QSPI_DMA_MIN_BYTES) {
+ ret = atmel_qspi_dma_transfer(mem, op, offset);
+ if (ret)
+ return ret;
+ } else {
+ memcpy_toio(aq->mem + offset, op->data.buf.out,
+ op->data.nbytes);
+ }
+
+ ret = atmel_qspi_wait_for_completion(aq, QSPI_SR_LWRA);
+ if (ret)
+ return ret;
+ }
+
+ /* Release the chip-select. */
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);
+
+ return atmel_qspi_wait_for_completion(aq, QSPI_SR_CSRA);
+}
+
static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->controller);
- u32 sr, offset;
+ u32 offset;
int err;
/*
@@ -416,49 +953,22 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
* when the flash memories overrun the controller's memory space.
*/
if (op->addr.val + op->data.nbytes > aq->mmap_size)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
+
+ if (op->addr.nbytes > 4)
+ return -EOPNOTSUPP;
err = pm_runtime_resume_and_get(&aq->pdev->dev);
if (err < 0)
return err;
- err = atmel_qspi_set_cfg(aq, op, &offset);
+ err = aq->ops->set_cfg(aq, op, &offset);
if (err)
goto pm_runtime_put;
- /* Skip to the final steps if there is no data */
- if (op->data.nbytes) {
- /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */
- (void)atmel_qspi_read(aq, QSPI_IFR);
-
- /* Send/Receive data */
- if (op->data.dir == SPI_MEM_DATA_IN)
- memcpy_fromio(op->data.buf.in, aq->mem + offset,
- op->data.nbytes);
- else
- memcpy_toio(aq->mem + offset, op->data.buf.out,
- op->data.nbytes);
-
- /* Release the chip-select */
- atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);
- }
-
- /* Poll INSTRuction End status */
- sr = atmel_qspi_read(aq, QSPI_SR);
- if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
- goto pm_runtime_put;
-
- /* Wait for INSTRuction End interrupt */
- reinit_completion(&aq->cmd_completion);
- aq->pending = sr & QSPI_SR_CMD_COMPLETED;
- atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IER);
- if (!wait_for_completion_timeout(&aq->cmd_completion,
- msecs_to_jiffies(1000)))
- err = -ETIMEDOUT;
- atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IDR);
+ err = aq->ops->transfer(mem, op, offset);
pm_runtime_put:
- pm_runtime_mark_last_busy(&aq->pdev->dev);
pm_runtime_put_autosuspend(&aq->pdev->dev);
return err;
}
@@ -474,6 +984,181 @@ static const struct spi_controller_mem_ops atmel_qspi_mem_ops = {
.get_name = atmel_qspi_get_name
};
+static int atmel_qspi_set_pad_calibration(struct atmel_qspi *aq)
+{
+ unsigned long pclk_rate;
+ u32 status, val;
+ int i, ret;
+ u8 pclk_div = 0;
+
+ pclk_rate = clk_get_rate(aq->pclk);
+ if (!pclk_rate)
+ return -EINVAL;
+
+ for (i = 0; i < ATMEL_QSPI_PCAL_ARRAY_SIZE; i++) {
+ if (pclk_rate <= pcal[i].pclk_rate) {
+ pclk_div = pcal[i].pclk_div;
+ break;
+ }
+ }
+
+ /*
+ * Use the biggest divider in case the peripheral clock exceeds
+ * 200MHZ.
+ */
+ if (pclk_rate > pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE - 1].pclk_rate)
+ pclk_div = pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE - 1].pclk_div;
+
+ /* Disable QSPI while configuring the pad calibration. */
+ status = atmel_qspi_read(aq, QSPI_SR2);
+ if (status & QSPI_SR2_QSPIENS) {
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
+ }
+
+ /*
+ * The analog circuitry is not shut down at the end of the calibration
+ * and the start-up time is only required for the first calibration
+ * sequence, thus increasing performance. Set the delay between the Pad
+ * calibration analog circuitry and the calibration request to 2us.
+ */
+ atmel_qspi_write(QSPI_PCALCFG_AAON |
+ FIELD_PREP(QSPI_PCALCFG_CLKDIV, pclk_div) |
+ FIELD_PREP(QSPI_PCALCFG_CALCNT,
+ 2 * (pclk_rate / 1000000)),
+ aq, QSPI_PCALCFG);
+
+ /* DLL On + start calibration. */
+ if (aq->caps->has_dllon)
+ atmel_qspi_write(QSPI_CR_DLLON | QSPI_CR_STPCAL, aq, QSPI_CR);
+ /* If there is no DLL support only start calibration. */
+ else
+ atmel_qspi_write(QSPI_CR_STPCAL, aq, QSPI_CR);
+
+ /*
+ * Check DLL clock lock and synchronization status before updating
+ * configuration.
+ */
+ if (aq->caps->has_dllon)
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ (val & QSPI_SR2_DLOCK) &&
+ !(val & QSPI_SR2_CALBSY), 40,
+ ATMEL_QSPI_TIMEOUT);
+ else
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_CALBSY), 40,
+ ATMEL_QSPI_TIMEOUT);
+
+ /* Refresh analogic blocks every 1 ms.*/
+ atmel_qspi_write(FIELD_PREP(QSPI_REFRESH_DELAY_COUNTER,
+ aq->target_max_speed_hz / 1000),
+ aq, QSPI_REFRESH);
+
+ return ret;
+}
+
+static int atmel_qspi_set_gclk(struct atmel_qspi *aq)
+{
+ u32 status, val;
+ int ret;
+
+ /* Disable DLL before setting GCLK */
+ if (aq->caps->has_dllon) {
+ status = atmel_qspi_read(aq, QSPI_SR2);
+ if (status & QSPI_SR2_DLOCK) {
+ atmel_qspi_write(QSPI_CR_DLLOFF, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_DLOCK), 40,
+ ATMEL_QSPI_TIMEOUT);
+ if (ret)
+ return ret;
+ }
+
+ if (aq->target_max_speed_hz > QSPI_DLLCFG_THRESHOLD_FREQ)
+ atmel_qspi_write(QSPI_DLLCFG_RANGE, aq, QSPI_DLLCFG);
+ else
+ atmel_qspi_write(0, aq, QSPI_DLLCFG);
+ }
+
+ if (aq->caps->has_2xgclk)
+ ret = clk_set_rate(aq->gclk, 2 * aq->target_max_speed_hz);
+ else
+ ret = clk_set_rate(aq->gclk, aq->target_max_speed_hz);
+
+ if (ret) {
+ dev_err(&aq->pdev->dev, "Failed to set generic clock rate.\n");
+ return ret;
+ }
+
+ /* Enable the QSPI generic clock */
+ ret = clk_prepare_enable(aq->gclk);
+ if (ret)
+ dev_err(&aq->pdev->dev, "Failed to enable generic clock.\n");
+
+ return ret;
+}
+
+static int atmel_qspi_sama7g5_init(struct atmel_qspi *aq)
+{
+ u32 val;
+ int ret;
+
+ ret = atmel_qspi_set_gclk(aq);
+ if (ret)
+ return ret;
+
+ /*
+ * Check if the SoC supports pad calibration in Octal SPI mode.
+ * Proceed only if both the capabilities are true.
+ */
+ if (aq->caps->octal && aq->caps->has_padcalib) {
+ ret = atmel_qspi_set_pad_calibration(aq);
+ if (ret)
+ return ret;
+ /* Start DLL on only if the SoC supports the same */
+ } else if (aq->caps->has_dllon) {
+ atmel_qspi_write(QSPI_CR_DLLON, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ (val & QSPI_SR2_DLOCK), 40,
+ ATMEL_QSPI_TIMEOUT);
+ }
+
+ /* Set the QSPI controller by default in Serial Memory Mode */
+ aq->mr |= QSPI_MR_DQSDLYEN;
+ ret = atmel_qspi_set_serial_memory_mode(aq);
+ if (ret < 0)
+ return ret;
+
+ /* Enable the QSPI controller. */
+ atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ val & QSPI_SR2_QSPIENS, 40,
+ ATMEL_QSPI_SYNC_TIMEOUT);
+ if (ret)
+ return ret;
+
+ if (aq->caps->octal) {
+ ret = readl_poll_timeout(aq->regs + QSPI_SR, val,
+ val & QSPI_SR_RFRSHD, 40,
+ ATMEL_QSPI_TIMEOUT);
+ }
+
+ atmel_qspi_write(QSPI_TOUT_TCNTM, aq, QSPI_TOUT);
+ return ret;
+}
+
+static int atmel_qspi_sama7g5_setup(struct spi_device *spi)
+{
+ struct atmel_qspi *aq = spi_controller_get_devdata(spi->controller);
+
+ /* The controller can communicate with a single peripheral device (target). */
+ aq->target_max_speed_hz = spi->max_speed_hz;
+
+ return atmel_qspi_sama7g5_init(aq);
+}
+
static int atmel_qspi_setup(struct spi_device *spi)
{
struct spi_controller *ctrl = spi->controller;
@@ -488,6 +1173,9 @@ static int atmel_qspi_setup(struct spi_device *spi)
if (!spi->max_speed_hz)
return -EINVAL;
+ if (aq->caps->has_gclk)
+ return atmel_qspi_sama7g5_setup(spi);
+
src_rate = clk_get_rate(aq->pclk);
if (!src_rate)
return -EINVAL;
@@ -501,10 +1189,10 @@ static int atmel_qspi_setup(struct spi_device *spi)
if (ret < 0)
return ret;
- aq->scr = QSPI_SCR_SCBR(scbr);
+ aq->scr &= ~QSPI_SCR_SCBR_MASK;
+ aq->scr |= QSPI_SCR_SCBR(scbr);
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
- pm_runtime_mark_last_busy(ctrl->dev.parent);
pm_runtime_put_autosuspend(ctrl->dev.parent);
return 0;
@@ -515,45 +1203,85 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi)
struct spi_controller *ctrl = spi->controller;
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
unsigned long clk_rate;
+ u32 cs_inactive;
u32 cs_setup;
+ u32 cs_hold;
int delay;
int ret;
- delay = spi_delay_to_ns(&spi->cs_setup, NULL);
- if (delay <= 0)
- return delay;
-
clk_rate = clk_get_rate(aq->pclk);
if (!clk_rate)
return -EINVAL;
+ /* hold */
+ delay = spi_delay_to_ns(&spi->cs_hold, NULL);
+ if (aq->mr & QSPI_MR_SMM) {
+ if (delay > 0)
+ dev_warn(&aq->pdev->dev,
+ "Ignoring cs_hold, must be 0 in Serial Memory Mode.\n");
+ cs_hold = 0;
+ } else {
+ delay = spi_delay_to_ns(&spi->cs_hold, NULL);
+ if (delay < 0)
+ return delay;
+
+ cs_hold = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 32000);
+ }
+
+ /* setup */
+ delay = spi_delay_to_ns(&spi->cs_setup, NULL);
+ if (delay < 0)
+ return delay;
+
cs_setup = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)),
1000);
+ /* inactive */
+ delay = spi_delay_to_ns(&spi->cs_inactive, NULL);
+ if (delay < 0)
+ return delay;
+ cs_inactive = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 1000);
+
ret = pm_runtime_resume_and_get(ctrl->dev.parent);
if (ret < 0)
return ret;
+ aq->scr &= ~QSPI_SCR_DLYBS_MASK;
aq->scr |= QSPI_SCR_DLYBS(cs_setup);
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
- pm_runtime_mark_last_busy(ctrl->dev.parent);
+ aq->mr &= ~(QSPI_MR_DLYBCT_MASK | QSPI_MR_DLYCS_MASK);
+ aq->mr |= QSPI_MR_DLYBCT(cs_hold) | QSPI_MR_DLYCS(cs_inactive);
+ atmel_qspi_write(aq->mr, aq, QSPI_MR);
+
pm_runtime_put_autosuspend(ctrl->dev.parent);
return 0;
}
-static void atmel_qspi_init(struct atmel_qspi *aq)
+static int atmel_qspi_init(struct atmel_qspi *aq)
{
+ int ret;
+
+ if (aq->caps->has_gclk) {
+ ret = atmel_qspi_reg_sync(aq);
+ if (ret)
+ return ret;
+ atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
+ return 0;
+ }
+
/* Reset the QSPI controller */
atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
/* Set the QSPI controller by default in Serial Memory Mode */
- atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR);
- aq->mr = QSPI_MR_SMM;
+ ret = atmel_qspi_set_serial_memory_mode(aq);
+ if (ret < 0)
+ return ret;
/* Enable the QSPI controller */
atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
+ return 0;
}
static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
@@ -569,12 +1297,54 @@ static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
return IRQ_NONE;
aq->pending |= pending;
- if ((aq->pending & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
+ if ((aq->pending & aq->irq_mask) == aq->irq_mask)
complete(&aq->cmd_completion);
return IRQ_HANDLED;
}
+static int atmel_qspi_dma_init(struct spi_controller *ctrl)
+{
+ struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+ int ret;
+
+ aq->rx_chan = devm_dma_request_chan(&aq->pdev->dev, "rx");
+ if (IS_ERR(aq->rx_chan)) {
+ ret = dev_err_probe(&aq->pdev->dev, PTR_ERR(aq->rx_chan),
+ "RX DMA channel is not available\n");
+ aq->rx_chan = NULL;
+ return ret;
+ }
+
+ aq->tx_chan = devm_dma_request_chan(&aq->pdev->dev, "tx");
+ if (IS_ERR(aq->tx_chan)) {
+ ret = dev_err_probe(&aq->pdev->dev, PTR_ERR(aq->tx_chan),
+ "TX DMA channel is not available\n");
+ aq->rx_chan = NULL;
+ aq->tx_chan = NULL;
+ return ret;
+ }
+
+ ctrl->dma_rx = aq->rx_chan;
+ ctrl->dma_tx = aq->tx_chan;
+ init_completion(&aq->dma_completion);
+
+ dev_info(&aq->pdev->dev, "Using %s (tx) and %s (rx) for DMA transfers\n",
+ dma_chan_name(aq->tx_chan), dma_chan_name(aq->rx_chan));
+
+ return 0;
+}
+
+static const struct atmel_qspi_ops atmel_qspi_ops = {
+ .set_cfg = atmel_qspi_set_cfg,
+ .transfer = atmel_qspi_transfer,
+};
+
+static const struct atmel_qspi_ops atmel_qspi_sama7g5_ops = {
+ .set_cfg = atmel_qspi_sama7g5_set_cfg,
+ .transfer = atmel_qspi_sama7g5_transfer,
+};
+
static int atmel_qspi_probe(struct platform_device *pdev)
{
struct spi_controller *ctrl;
@@ -586,7 +1356,27 @@ static int atmel_qspi_probe(struct platform_device *pdev)
if (!ctrl)
return -ENOMEM;
+ aq = spi_controller_get_devdata(ctrl);
+
+ aq->caps = of_device_get_match_data(&pdev->dev);
+ if (!aq->caps) {
+ dev_err(&pdev->dev, "Could not retrieve QSPI caps\n");
+ return -EINVAL;
+ }
+
+ init_completion(&aq->cmd_completion);
+ aq->pdev = pdev;
+
ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD;
+ if (aq->caps->octal)
+ ctrl->mode_bits |= SPI_RX_OCTAL | SPI_TX_OCTAL;
+
+ if (aq->caps->has_gclk)
+ aq->ops = &atmel_qspi_sama7g5_ops;
+ else
+ aq->ops = &atmel_qspi_ops;
+
+ ctrl->max_speed_hz = aq->caps->max_speed_hz;
ctrl->setup = atmel_qspi_setup;
ctrl->set_cs_timing = atmel_qspi_set_cs_timing;
ctrl->bus_num = -1;
@@ -595,109 +1385,119 @@ static int atmel_qspi_probe(struct platform_device *pdev)
ctrl->dev.of_node = pdev->dev.of_node;
platform_set_drvdata(pdev, ctrl);
- aq = spi_controller_get_devdata(ctrl);
-
- init_completion(&aq->cmd_completion);
- aq->pdev = pdev;
-
/* Map the registers */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base");
- aq->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(aq->regs)) {
- dev_err(&pdev->dev, "missing registers\n");
- return PTR_ERR(aq->regs);
- }
+ aq->regs = devm_platform_ioremap_resource_byname(pdev, "qspi_base");
+ if (IS_ERR(aq->regs))
+ return dev_err_probe(&pdev->dev, PTR_ERR(aq->regs),
+ "missing registers\n");
/* Map the AHB memory */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mmap");
aq->mem = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(aq->mem)) {
- dev_err(&pdev->dev, "missing AHB memory\n");
- return PTR_ERR(aq->mem);
- }
+ if (IS_ERR(aq->mem))
+ return dev_err_probe(&pdev->dev, PTR_ERR(aq->mem),
+ "missing AHB memory\n");
aq->mmap_size = resource_size(res);
+ aq->mmap_phys_base = (dma_addr_t)res->start;
/* Get the peripheral clock */
- aq->pclk = devm_clk_get(&pdev->dev, "pclk");
+ aq->pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
if (IS_ERR(aq->pclk))
- aq->pclk = devm_clk_get(&pdev->dev, NULL);
-
- if (IS_ERR(aq->pclk)) {
- dev_err(&pdev->dev, "missing peripheral clock\n");
- return PTR_ERR(aq->pclk);
- }
+ aq->pclk = devm_clk_get_enabled(&pdev->dev, NULL);
- /* Enable the peripheral clock */
- err = clk_prepare_enable(aq->pclk);
- if (err) {
- dev_err(&pdev->dev, "failed to enable the peripheral clock\n");
- return err;
- }
-
- aq->caps = of_device_get_match_data(&pdev->dev);
- if (!aq->caps) {
- dev_err(&pdev->dev, "Could not retrieve QSPI caps\n");
- err = -EINVAL;
- goto disable_pclk;
- }
+ if (IS_ERR(aq->pclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(aq->pclk),
+ "missing peripheral clock\n");
if (aq->caps->has_qspick) {
/* Get the QSPI system clock */
- aq->qspick = devm_clk_get(&pdev->dev, "qspick");
+ aq->qspick = devm_clk_get_enabled(&pdev->dev, "qspick");
if (IS_ERR(aq->qspick)) {
dev_err(&pdev->dev, "missing system clock\n");
err = PTR_ERR(aq->qspick);
- goto disable_pclk;
+ return err;
}
- /* Enable the QSPI system clock */
- err = clk_prepare_enable(aq->qspick);
- if (err) {
- dev_err(&pdev->dev,
- "failed to enable the QSPI system clock\n");
- goto disable_pclk;
+ } else if (aq->caps->has_gclk) {
+ /* Get the QSPI generic clock */
+ aq->gclk = devm_clk_get(&pdev->dev, "gclk");
+ if (IS_ERR(aq->gclk)) {
+ dev_err(&pdev->dev, "missing Generic clock\n");
+ err = PTR_ERR(aq->gclk);
+ return err;
}
}
+ if (aq->caps->has_dma) {
+ err = atmel_qspi_dma_init(ctrl);
+ if (err == -EPROBE_DEFER)
+ return err;
+ }
+
/* Request the IRQ */
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- err = irq;
- goto disable_qspick;
- }
+ if (irq < 0)
+ return irq;
+
err = devm_request_irq(&pdev->dev, irq, atmel_qspi_interrupt,
0, dev_name(&pdev->dev), aq);
if (err)
- goto disable_qspick;
+ return err;
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_noresume(&pdev->dev);
+ devm_pm_runtime_set_active_enabled(&pdev->dev);
+ devm_pm_runtime_get_noresume(&pdev->dev);
- atmel_qspi_init(aq);
+ err = atmel_qspi_init(aq);
+ if (err)
+ return err;
err = spi_register_controller(ctrl);
- if (err) {
- pm_runtime_put_noidle(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_dont_use_autosuspend(&pdev->dev);
- goto disable_qspick;
- }
- pm_runtime_mark_last_busy(&pdev->dev);
+ if (err)
+ return err;
+
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
+}
-disable_qspick:
- clk_disable_unprepare(aq->qspick);
-disable_pclk:
- clk_disable_unprepare(aq->pclk);
+static int atmel_qspi_sama7g5_suspend(struct atmel_qspi *aq)
+{
+ int ret;
+ u32 val;
- return err;
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_RBUSY) &&
+ (val & QSPI_SR2_HIDLE), 40,
+ ATMEL_QSPI_SYNC_TIMEOUT);
+ if (ret)
+ return ret;
+
+ atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_QSPIENS), 40,
+ ATMEL_QSPI_SYNC_TIMEOUT);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(aq->gclk);
+
+ if (aq->caps->has_dllon) {
+ atmel_qspi_write(QSPI_CR_DLLOFF, aq, QSPI_CR);
+ ret = readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_DLOCK), 40,
+ ATMEL_QSPI_TIMEOUT);
+ if (ret)
+ return ret;
+ }
+
+ if (aq->caps->has_padcalib)
+ return readl_poll_timeout(aq->regs + QSPI_SR2, val,
+ !(val & QSPI_SR2_CALBSY), 40,
+ ATMEL_QSPI_TIMEOUT);
+ return 0;
}
static void atmel_qspi_remove(struct platform_device *pdev)
@@ -710,9 +1510,14 @@ static void atmel_qspi_remove(struct platform_device *pdev)
ret = pm_runtime_get_sync(&pdev->dev);
if (ret >= 0) {
+ if (aq->caps->has_gclk) {
+ ret = atmel_qspi_sama7g5_suspend(aq);
+ if (ret)
+ dev_warn(&pdev->dev, "Failed to de-init device on remove: %d\n", ret);
+ return;
+ }
+
atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
- clk_disable(aq->qspick);
- clk_disable(aq->pclk);
} else {
/*
* atmel_qspi_runtime_{suspend,resume} just disable and enable
@@ -721,12 +1526,6 @@ static void atmel_qspi_remove(struct platform_device *pdev)
*/
dev_warn(&pdev->dev, "Failed to resume device on remove\n");
}
-
- clk_unprepare(aq->qspick);
- clk_unprepare(aq->pclk);
-
- pm_runtime_disable(&pdev->dev);
- pm_runtime_put_noidle(&pdev->dev);
}
static int __maybe_unused atmel_qspi_suspend(struct device *dev)
@@ -739,6 +1538,12 @@ static int __maybe_unused atmel_qspi_suspend(struct device *dev)
if (ret < 0)
return ret;
+ if (aq->caps->has_gclk) {
+ ret = atmel_qspi_sama7g5_suspend(aq);
+ clk_disable_unprepare(aq->pclk);
+ return ret;
+ }
+
atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
pm_runtime_mark_last_busy(dev);
@@ -756,8 +1561,18 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev)
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
int ret;
- clk_prepare(aq->pclk);
- clk_prepare(aq->qspick);
+ ret = clk_prepare(aq->pclk);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare(aq->qspick);
+ if (ret) {
+ clk_unprepare(aq->pclk);
+ return ret;
+ }
+
+ if (aq->caps->has_gclk)
+ return atmel_qspi_sama7g5_init(aq);
ret = pm_runtime_force_resume(dev);
if (ret < 0)
@@ -767,7 +1582,6 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev)
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -814,6 +1628,50 @@ static const struct atmel_qspi_caps atmel_sam9x60_qspi_caps = {
.has_ricr = true,
};
+static const struct atmel_qspi_caps atmel_sam9x7_ospi_caps = {
+ .max_speed_hz = SAM9X7_QSPI_MAX_SPEED_HZ,
+ .has_gclk = true,
+ .octal = true,
+ .has_dma = true,
+ .has_2xgclk = true,
+ .has_padcalib = false,
+ .has_dllon = false,
+};
+
+static const struct atmel_qspi_caps atmel_sama7d65_ospi_caps = {
+ .max_speed_hz = SAMA7G5_QSPI0_MAX_SPEED_HZ,
+ .has_gclk = true,
+ .octal = true,
+ .has_dma = true,
+ .has_2xgclk = true,
+ .has_padcalib = true,
+ .has_dllon = false,
+};
+
+static const struct atmel_qspi_caps atmel_sama7d65_qspi_caps = {
+ .max_speed_hz = SAMA7G5_QSPI1_SDR_MAX_SPEED_HZ,
+ .has_gclk = true,
+ .has_dma = true,
+ .has_2xgclk = true,
+ .has_dllon = false,
+};
+
+static const struct atmel_qspi_caps atmel_sama7g5_ospi_caps = {
+ .max_speed_hz = SAMA7G5_QSPI0_MAX_SPEED_HZ,
+ .has_gclk = true,
+ .octal = true,
+ .has_dma = true,
+ .has_padcalib = true,
+ .has_dllon = true,
+};
+
+static const struct atmel_qspi_caps atmel_sama7g5_qspi_caps = {
+ .max_speed_hz = SAMA7G5_QSPI1_SDR_MAX_SPEED_HZ,
+ .has_gclk = true,
+ .has_dma = true,
+ .has_dllon = true,
+};
+
static const struct of_device_id atmel_qspi_dt_ids[] = {
{
.compatible = "atmel,sama5d2-qspi",
@@ -823,6 +1681,28 @@ static const struct of_device_id atmel_qspi_dt_ids[] = {
.compatible = "microchip,sam9x60-qspi",
.data = &atmel_sam9x60_qspi_caps,
},
+ {
+ .compatible = "microchip,sama7g5-ospi",
+ .data = &atmel_sama7g5_ospi_caps,
+ },
+ {
+ .compatible = "microchip,sama7g5-qspi",
+ .data = &atmel_sama7g5_qspi_caps,
+ },
+ {
+ .compatible = "microchip,sam9x7-ospi",
+ .data = &atmel_sam9x7_ospi_caps,
+ },
+ {
+ .compatible = "microchip,sama7d65-ospi",
+ .data = &atmel_sama7d65_ospi_caps,
+ },
+ {
+ .compatible = "microchip,sama7d65-qspi",
+ .data = &atmel_sama7d65_qspi_caps,
+ },
+
+
{ /* sentinel */ }
};
@@ -835,7 +1715,7 @@ static struct platform_driver atmel_qspi_driver = {
.pm = pm_ptr(&atmel_qspi_pm_ops),
},
.probe = atmel_qspi_probe,
- .remove_new = atmel_qspi_remove,
+ .remove = atmel_qspi_remove,
};
module_platform_driver(atmel_qspi_driver);
diff --git a/drivers/spi/internals.h b/drivers/spi/internals.h
index 4a28a8395552..1f459b895891 100644
--- a/drivers/spi/internals.h
+++ b/drivers/spi/internals.h
@@ -40,4 +40,12 @@ static inline void spi_unmap_buf(struct spi_controller *ctlr,
}
#endif /* CONFIG_HAS_DMA */
+static inline bool spi_xfer_is_dma_mapped(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ return ctlr->can_dma && ctlr->can_dma(ctlr, spi, xfer) &&
+ (xfer->tx_sg_mapped || xfer->rx_sg_mapped);
+}
+
#endif /* __LINUX_SPI_INTERNALS_H */
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c
new file mode 100644
index 000000000000..70327aebc26b
--- /dev/null
+++ b/drivers/spi/spi-airoha-snfi.c
@@ -0,0 +1,1148 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 AIROHA Inc
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
+ * Author: Ray Liu <ray.liu@airoha.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/limits.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+/* SPI */
+#define REG_SPI_CTRL_BASE 0x1FA10000
+
+#define REG_SPI_CTRL_READ_MODE 0x0000
+#define REG_SPI_CTRL_READ_IDLE_EN 0x0004
+#define REG_SPI_CTRL_SIDLY 0x0008
+#define REG_SPI_CTRL_CSHEXT 0x000c
+#define REG_SPI_CTRL_CSLEXT 0x0010
+
+#define REG_SPI_CTRL_MTX_MODE_TOG 0x0014
+#define SPI_CTRL_MTX_MODE_TOG GENMASK(3, 0)
+
+#define REG_SPI_CTRL_RDCTL_FSM 0x0018
+#define SPI_CTRL_RDCTL_FSM GENMASK(3, 0)
+
+#define REG_SPI_CTRL_MACMUX_SEL 0x001c
+
+#define REG_SPI_CTRL_MANUAL_EN 0x0020
+#define SPI_CTRL_MANUAL_EN BIT(0)
+
+#define REG_SPI_CTRL_OPFIFO_EMPTY 0x0024
+#define SPI_CTRL_OPFIFO_EMPTY BIT(0)
+
+#define REG_SPI_CTRL_OPFIFO_WDATA 0x0028
+#define SPI_CTRL_OPFIFO_LEN GENMASK(8, 0)
+#define SPI_CTRL_OPFIFO_OP GENMASK(13, 9)
+
+#define REG_SPI_CTRL_OPFIFO_FULL 0x002c
+#define SPI_CTRL_OPFIFO_FULL BIT(0)
+
+#define REG_SPI_CTRL_OPFIFO_WR 0x0030
+#define SPI_CTRL_OPFIFO_WR BIT(0)
+
+#define REG_SPI_CTRL_DFIFO_FULL 0x0034
+#define SPI_CTRL_DFIFO_FULL BIT(0)
+
+#define REG_SPI_CTRL_DFIFO_WDATA 0x0038
+#define SPI_CTRL_DFIFO_WDATA GENMASK(7, 0)
+
+#define REG_SPI_CTRL_DFIFO_EMPTY 0x003c
+#define SPI_CTRL_DFIFO_EMPTY BIT(0)
+
+#define REG_SPI_CTRL_DFIFO_RD 0x0040
+#define SPI_CTRL_DFIFO_RD BIT(0)
+
+#define REG_SPI_CTRL_DFIFO_RDATA 0x0044
+#define SPI_CTRL_DFIFO_RDATA GENMASK(7, 0)
+
+#define REG_SPI_CTRL_DUMMY 0x0080
+#define SPI_CTRL_CTRL_DUMMY GENMASK(3, 0)
+
+#define REG_SPI_CTRL_PROBE_SEL 0x0088
+#define REG_SPI_CTRL_INTERRUPT 0x0090
+#define REG_SPI_CTRL_INTERRUPT_EN 0x0094
+#define REG_SPI_CTRL_SI_CK_SEL 0x009c
+#define REG_SPI_CTRL_SW_CFGNANDADDR_VAL 0x010c
+#define REG_SPI_CTRL_SW_CFGNANDADDR_EN 0x0110
+#define REG_SPI_CTRL_SFC_STRAP 0x0114
+
+#define REG_SPI_CTRL_NFI2SPI_EN 0x0130
+#define SPI_CTRL_NFI2SPI_EN BIT(0)
+
+/* NFI2SPI */
+#define REG_SPI_NFI_CNFG 0x0000
+#define SPI_NFI_DMA_MODE BIT(0)
+#define SPI_NFI_READ_MODE BIT(1)
+#define SPI_NFI_DMA_BURST_EN BIT(2)
+#define SPI_NFI_HW_ECC_EN BIT(8)
+#define SPI_NFI_AUTO_FDM_EN BIT(9)
+#define SPI_NFI_OPMODE GENMASK(14, 12)
+
+#define REG_SPI_NFI_PAGEFMT 0x0004
+#define SPI_NFI_PAGE_SIZE GENMASK(1, 0)
+#define SPI_NFI_SPARE_SIZE GENMASK(5, 4)
+
+#define REG_SPI_NFI_CON 0x0008
+#define SPI_NFI_FIFO_FLUSH BIT(0)
+#define SPI_NFI_RST BIT(1)
+#define SPI_NFI_RD_TRIG BIT(8)
+#define SPI_NFI_WR_TRIG BIT(9)
+#define SPI_NFI_SEC_NUM GENMASK(15, 12)
+
+#define REG_SPI_NFI_INTR_EN 0x0010
+#define SPI_NFI_RD_DONE_EN BIT(0)
+#define SPI_NFI_WR_DONE_EN BIT(1)
+#define SPI_NFI_RST_DONE_EN BIT(2)
+#define SPI_NFI_ERASE_DONE_EN BIT(3)
+#define SPI_NFI_BUSY_RETURN_EN BIT(4)
+#define SPI_NFI_ACCESS_LOCK_EN BIT(5)
+#define SPI_NFI_AHB_DONE_EN BIT(6)
+#define SPI_NFI_ALL_IRQ_EN \
+ (SPI_NFI_RD_DONE_EN | SPI_NFI_WR_DONE_EN | \
+ SPI_NFI_RST_DONE_EN | SPI_NFI_ERASE_DONE_EN | \
+ SPI_NFI_BUSY_RETURN_EN | SPI_NFI_ACCESS_LOCK_EN | \
+ SPI_NFI_AHB_DONE_EN)
+
+#define REG_SPI_NFI_INTR 0x0014
+#define SPI_NFI_AHB_DONE BIT(6)
+
+#define REG_SPI_NFI_CMD 0x0020
+
+#define REG_SPI_NFI_ADDR_NOB 0x0030
+#define SPI_NFI_ROW_ADDR_NOB GENMASK(6, 4)
+
+#define REG_SPI_NFI_STA 0x0060
+#define REG_SPI_NFI_FIFOSTA 0x0064
+#define REG_SPI_NFI_STRADDR 0x0080
+#define REG_SPI_NFI_FDM0L 0x00a0
+#define REG_SPI_NFI_FDM0M 0x00a4
+#define REG_SPI_NFI_FDM7L 0x00d8
+#define REG_SPI_NFI_FDM7M 0x00dc
+#define REG_SPI_NFI_FIFODATA0 0x0190
+#define REG_SPI_NFI_FIFODATA1 0x0194
+#define REG_SPI_NFI_FIFODATA2 0x0198
+#define REG_SPI_NFI_FIFODATA3 0x019c
+#define REG_SPI_NFI_MASTERSTA 0x0224
+
+#define REG_SPI_NFI_SECCUS_SIZE 0x022c
+#define SPI_NFI_CUS_SEC_SIZE GENMASK(12, 0)
+#define SPI_NFI_CUS_SEC_SIZE_EN BIT(16)
+
+#define REG_SPI_NFI_RD_CTL2 0x0510
+#define SPI_NFI_DATA_READ_CMD GENMASK(7, 0)
+
+#define REG_SPI_NFI_RD_CTL3 0x0514
+
+#define REG_SPI_NFI_PG_CTL1 0x0524
+#define SPI_NFI_PG_LOAD_CMD GENMASK(15, 8)
+
+#define REG_SPI_NFI_PG_CTL2 0x0528
+#define REG_SPI_NFI_NOR_PROG_ADDR 0x052c
+#define REG_SPI_NFI_NOR_RD_ADDR 0x0534
+
+#define REG_SPI_NFI_SNF_MISC_CTL 0x0538
+#define SPI_NFI_DATA_READ_WR_MODE GENMASK(18, 16)
+
+#define REG_SPI_NFI_SNF_MISC_CTL2 0x053c
+#define SPI_NFI_READ_DATA_BYTE_NUM GENMASK(12, 0)
+#define SPI_NFI_PROG_LOAD_BYTE_NUM GENMASK(28, 16)
+
+#define REG_SPI_NFI_SNF_STA_CTL1 0x0550
+#define SPI_NFI_READ_FROM_CACHE_DONE BIT(25)
+#define SPI_NFI_LOAD_TO_CACHE_DONE BIT(26)
+
+#define REG_SPI_NFI_SNF_STA_CTL2 0x0554
+
+#define REG_SPI_NFI_SNF_NFI_CNFG 0x055c
+#define SPI_NFI_SPI_MODE BIT(0)
+
+/* SPI NAND Protocol OP */
+#define SPI_NAND_OP_GET_FEATURE 0x0f
+#define SPI_NAND_OP_SET_FEATURE 0x1f
+#define SPI_NAND_OP_PAGE_READ 0x13
+#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03
+#define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b
+#define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b
+#define SPI_NAND_OP_READ_FROM_CACHE_DUALIO 0xbb
+#define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b
+#define SPI_NAND_OP_READ_FROM_CACHE_QUADIO 0xeb
+#define SPI_NAND_OP_WRITE_ENABLE 0x06
+#define SPI_NAND_OP_WRITE_DISABLE 0x04
+#define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02
+#define SPI_NAND_OP_PROGRAM_LOAD_QUAD 0x32
+#define SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE 0x84
+#define SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD 0x34
+#define SPI_NAND_OP_PROGRAM_EXECUTE 0x10
+#define SPI_NAND_OP_READ_ID 0x9f
+#define SPI_NAND_OP_BLOCK_ERASE 0xd8
+#define SPI_NAND_OP_RESET 0xff
+#define SPI_NAND_OP_DIE_SELECT 0xc2
+
+/* SNAND FIFO commands */
+#define SNAND_FIFO_TX_BUSWIDTH_SINGLE 0x08
+#define SNAND_FIFO_TX_BUSWIDTH_DUAL 0x09
+#define SNAND_FIFO_TX_BUSWIDTH_QUAD 0x0a
+#define SNAND_FIFO_RX_BUSWIDTH_SINGLE 0x0c
+#define SNAND_FIFO_RX_BUSWIDTH_DUAL 0x0e
+#define SNAND_FIFO_RX_BUSWIDTH_QUAD 0x0f
+
+#define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256)
+#define SPI_MAX_TRANSFER_SIZE 511
+
+enum airoha_snand_mode {
+ SPI_MODE_AUTO,
+ SPI_MODE_MANUAL,
+ SPI_MODE_DMA,
+};
+
+enum airoha_snand_cs {
+ SPI_CHIP_SEL_HIGH,
+ SPI_CHIP_SEL_LOW,
+};
+
+struct airoha_snand_ctrl {
+ struct device *dev;
+ struct regmap *regmap_ctrl;
+ struct regmap *regmap_nfi;
+ struct clk *spi_clk;
+};
+
+static int airoha_snand_set_fifo_op(struct airoha_snand_ctrl *as_ctrl,
+ u8 op_cmd, int op_len)
+{
+ int err;
+ u32 val;
+
+ err = regmap_write(as_ctrl->regmap_ctrl, REG_SPI_CTRL_OPFIFO_WDATA,
+ FIELD_PREP(SPI_CTRL_OPFIFO_LEN, op_len) |
+ FIELD_PREP(SPI_CTRL_OPFIFO_OP, op_cmd));
+ if (err)
+ return err;
+
+ err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_OPFIFO_FULL,
+ val, !(val & SPI_CTRL_OPFIFO_FULL),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+
+ err = regmap_write(as_ctrl->regmap_ctrl, REG_SPI_CTRL_OPFIFO_WR,
+ SPI_CTRL_OPFIFO_WR);
+ if (err)
+ return err;
+
+ return regmap_read_poll_timeout(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_OPFIFO_EMPTY,
+ val, (val & SPI_CTRL_OPFIFO_EMPTY),
+ 0, 250 * USEC_PER_MSEC);
+}
+
+static int airoha_snand_set_cs(struct airoha_snand_ctrl *as_ctrl, u8 cs)
+{
+ return airoha_snand_set_fifo_op(as_ctrl, cs, sizeof(cs));
+}
+
+static int airoha_snand_write_data_to_fifo(struct airoha_snand_ctrl *as_ctrl,
+ const u8 *data, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ int err;
+ u32 val;
+
+ /* 1. Wait until dfifo is not full */
+ err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_FULL, val,
+ !(val & SPI_CTRL_DFIFO_FULL),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+
+ /* 2. Write data to register DFIFO_WDATA */
+ err = regmap_write(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_WDATA,
+ FIELD_PREP(SPI_CTRL_DFIFO_WDATA, data[i]));
+ if (err)
+ return err;
+
+ /* 3. Wait until dfifo is not full */
+ err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_FULL, val,
+ !(val & SPI_CTRL_DFIFO_FULL),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_snand_read_data_from_fifo(struct airoha_snand_ctrl *as_ctrl,
+ u8 *ptr, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ int err;
+ u32 val;
+
+ /* 1. wait until dfifo is not empty */
+ err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_EMPTY, val,
+ !(val & SPI_CTRL_DFIFO_EMPTY),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+
+ /* 2. read from dfifo to register DFIFO_RDATA */
+ err = regmap_read(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_RDATA, &val);
+ if (err)
+ return err;
+
+ ptr[i] = FIELD_GET(SPI_CTRL_DFIFO_RDATA, val);
+ /* 3. enable register DFIFO_RD to read next byte */
+ err = regmap_write(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_DFIFO_RD, SPI_CTRL_DFIFO_RD);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_snand_set_mode(struct airoha_snand_ctrl *as_ctrl,
+ enum airoha_snand_mode mode)
+{
+ int err;
+
+ switch (mode) {
+ case SPI_MODE_MANUAL: {
+ u32 val;
+
+ err = regmap_write(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_NFI2SPI_EN, 0);
+ if (err)
+ return err;
+
+ err = regmap_write(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_READ_IDLE_EN, 0);
+ if (err)
+ return err;
+
+ err = regmap_read_poll_timeout(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_RDCTL_FSM, val,
+ !(val & SPI_CTRL_RDCTL_FSM),
+ 0, 250 * USEC_PER_MSEC);
+ if (err)
+ return err;
+
+ err = regmap_write(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_MTX_MODE_TOG, 9);
+ if (err)
+ return err;
+
+ err = regmap_write(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_MANUAL_EN, SPI_CTRL_MANUAL_EN);
+ if (err)
+ return err;
+ break;
+ }
+ case SPI_MODE_DMA:
+ err = regmap_write(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_NFI2SPI_EN,
+ SPI_CTRL_MANUAL_EN);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_MTX_MODE_TOG, 0x0);
+ if (err < 0)
+ return err;
+
+ err = regmap_write(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_MANUAL_EN, 0x0);
+ if (err < 0)
+ return err;
+ break;
+ case SPI_MODE_AUTO:
+ default:
+ break;
+ }
+
+ return regmap_write(as_ctrl->regmap_ctrl, REG_SPI_CTRL_DUMMY, 0);
+}
+
+static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl,
+ const u8 *data, int len, int buswidth)
+{
+ int i, data_len;
+ u8 cmd;
+
+ switch (buswidth) {
+ case 0:
+ case 1:
+ cmd = SNAND_FIFO_TX_BUSWIDTH_SINGLE;
+ break;
+ case 2:
+ cmd = SNAND_FIFO_TX_BUSWIDTH_DUAL;
+ break;
+ case 4:
+ cmd = SNAND_FIFO_TX_BUSWIDTH_QUAD;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i += data_len) {
+ int err;
+
+ data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
+ err = airoha_snand_set_fifo_op(as_ctrl, cmd, data_len);
+ if (err)
+ return err;
+
+ err = airoha_snand_write_data_to_fifo(as_ctrl, &data[i],
+ data_len);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_snand_read_data(struct airoha_snand_ctrl *as_ctrl,
+ u8 *data, int len, int buswidth)
+{
+ int i, data_len;
+ u8 cmd;
+
+ switch (buswidth) {
+ case 0:
+ case 1:
+ cmd = SNAND_FIFO_RX_BUSWIDTH_SINGLE;
+ break;
+ case 2:
+ cmd = SNAND_FIFO_RX_BUSWIDTH_DUAL;
+ break;
+ case 4:
+ cmd = SNAND_FIFO_RX_BUSWIDTH_QUAD;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < len; i += data_len) {
+ int err;
+
+ data_len = min(len - i, SPI_MAX_TRANSFER_SIZE);
+ err = airoha_snand_set_fifo_op(as_ctrl, cmd, data_len);
+ if (err)
+ return err;
+
+ err = airoha_snand_read_data_from_fifo(as_ctrl, &data[i],
+ data_len);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int airoha_snand_nfi_init(struct airoha_snand_ctrl *as_ctrl)
+{
+ int err;
+
+ /* switch to SNFI mode */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_NFI_CNFG,
+ SPI_NFI_SPI_MODE);
+ if (err)
+ return err;
+
+ /* Enable DMA */
+ return regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR_EN,
+ SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN);
+}
+
+static bool airoha_snand_is_page_ops(const struct spi_mem_op *op)
+{
+ if (op->addr.nbytes != 2)
+ return false;
+
+ if (op->addr.buswidth != 1 && op->addr.buswidth != 2 &&
+ op->addr.buswidth != 4)
+ return false;
+
+ switch (op->data.dir) {
+ case SPI_MEM_DATA_IN:
+ if (op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth > 0xf)
+ return false;
+
+ /* quad in / quad out */
+ if (op->addr.buswidth == 4)
+ return op->data.buswidth == 4;
+
+ if (op->addr.buswidth == 2)
+ return op->data.buswidth == 2;
+
+ /* standard spi */
+ return op->data.buswidth == 4 || op->data.buswidth == 2 ||
+ op->data.buswidth == 1;
+ case SPI_MEM_DATA_OUT:
+ return !op->dummy.nbytes && op->addr.buswidth == 1 &&
+ (op->data.buswidth == 4 || op->data.buswidth == 1);
+ default:
+ return false;
+ }
+}
+
+static bool airoha_snand_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ if (!spi_mem_default_supports_op(mem, op))
+ return false;
+
+ if (op->cmd.buswidth != 1)
+ return false;
+
+ if (airoha_snand_is_page_ops(op))
+ return true;
+
+ return (!op->addr.nbytes || op->addr.buswidth == 1) &&
+ (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
+ (!op->data.nbytes || op->data.buswidth == 1);
+}
+
+static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+ u8 *txrx_buf = spi_get_ctldata(desc->mem->spi);
+
+ if (!txrx_buf)
+ return -EINVAL;
+
+ if (desc->info.offset + desc->info.length > U32_MAX)
+ return -EINVAL;
+
+ /* continuous reading is not supported */
+ if (desc->info.length > SPI_NAND_CACHE_SIZE)
+ return -E2BIG;
+
+ if (!airoha_snand_supports_op(desc->mem, &desc->info.op_tmpl))
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
+{
+ struct spi_device *spi = desc->mem->spi;
+ struct airoha_snand_ctrl *as_ctrl;
+ u8 *txrx_buf = spi_get_ctldata(spi);
+ dma_addr_t dma_addr;
+ u32 val, rd_mode, opcode;
+ size_t bytes;
+ int err;
+
+ as_ctrl = spi_controller_get_devdata(spi->controller);
+
+ /* minimum oob size is 64 */
+ bytes = round_up(offs + len, 64);
+
+ /*
+ * DUALIO and QUADIO opcodes are not supported by the spi controller,
+ * replace them with supported opcodes.
+ */
+ opcode = desc->info.op_tmpl.cmd.opcode;
+ switch (opcode) {
+ case SPI_NAND_OP_READ_FROM_CACHE_SINGLE:
+ case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST:
+ rd_mode = 0;
+ break;
+ case SPI_NAND_OP_READ_FROM_CACHE_DUAL:
+ case SPI_NAND_OP_READ_FROM_CACHE_DUALIO:
+ opcode = SPI_NAND_OP_READ_FROM_CACHE_DUAL;
+ rd_mode = 1;
+ break;
+ case SPI_NAND_OP_READ_FROM_CACHE_QUAD:
+ case SPI_NAND_OP_READ_FROM_CACHE_QUADIO:
+ opcode = SPI_NAND_OP_READ_FROM_CACHE_QUAD;
+ rd_mode = 2;
+ break;
+ default:
+ /* unknown opcode */
+ return -EOPNOTSUPP;
+ }
+
+ err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
+ if (err < 0)
+ return err;
+
+ /* NFI reset */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_FIFO_FLUSH | SPI_NFI_RST);
+ if (err)
+ goto error_dma_mode_off;
+
+ /* NFI configure:
+ * - No AutoFDM (custom sector size (SECCUS) register will be used)
+ * - No SoC's hardware ECC (flash internal ECC will be used)
+ * - Use burst mode (faster, but requires 16 byte alignment for addresses)
+ * - Setup for reading (SPI_NFI_READ_MODE)
+ * - Setup reading command: FIELD_PREP(SPI_NFI_OPMODE, 6)
+ * - Use DMA instead of PIO for data reading
+ */
+ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
+ SPI_NFI_DMA_MODE |
+ SPI_NFI_READ_MODE |
+ SPI_NFI_DMA_BURST_EN |
+ SPI_NFI_HW_ECC_EN |
+ SPI_NFI_AUTO_FDM_EN |
+ SPI_NFI_OPMODE,
+ SPI_NFI_DMA_MODE |
+ SPI_NFI_READ_MODE |
+ SPI_NFI_DMA_BURST_EN |
+ FIELD_PREP(SPI_NFI_OPMODE, 6));
+ if (err)
+ goto error_dma_mode_off;
+
+ /* Set number of sector will be read */
+ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_SEC_NUM,
+ FIELD_PREP(SPI_NFI_SEC_NUM, 1));
+ if (err)
+ goto error_dma_mode_off;
+
+ /* Set custom sector size */
+ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE,
+ SPI_NFI_CUS_SEC_SIZE |
+ SPI_NFI_CUS_SEC_SIZE_EN,
+ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) |
+ SPI_NFI_CUS_SEC_SIZE_EN);
+ if (err)
+ goto error_dma_mode_off;
+
+ dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE,
+ DMA_FROM_DEVICE);
+ err = dma_mapping_error(as_ctrl->dev, dma_addr);
+ if (err)
+ goto error_dma_mode_off;
+
+ /* set dma addr */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
+ dma_addr);
+ if (err)
+ goto error_dma_unmap;
+
+ /*
+ * Setup transfer length
+ * ---------------------
+ * The following rule MUST be met:
+ * transfer_length =
+ * = NFI_SNF_MISC_CTL2.read_data_byte_number =
+ * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size
+ */
+ err = regmap_update_bits(as_ctrl->regmap_nfi,
+ REG_SPI_NFI_SNF_MISC_CTL2,
+ SPI_NFI_READ_DATA_BYTE_NUM,
+ FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, bytes));
+ if (err)
+ goto error_dma_unmap;
+
+ /* set read command */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2,
+ FIELD_PREP(SPI_NFI_DATA_READ_CMD, opcode));
+ if (err)
+ goto error_dma_unmap;
+
+ /* set read mode */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL,
+ FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, rd_mode));
+ if (err)
+ goto error_dma_unmap;
+
+ /* set read addr: zero page offset + descriptor read offset */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3,
+ desc->info.offset);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x0);
+ if (err)
+ goto error_dma_unmap;
+
+ /* trigger dma reading */
+ err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_RD_TRIG);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_RD_TRIG);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_read_poll_timeout(as_ctrl->regmap_nfi,
+ REG_SPI_NFI_SNF_STA_CTL1, val,
+ (val & SPI_NFI_READ_FROM_CACHE_DONE),
+ 0, 1 * USEC_PER_SEC);
+ if (err)
+ goto error_dma_unmap;
+
+ /*
+ * SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end
+ * of dirmap_read operation even if it is already set.
+ */
+ err = regmap_write_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
+ SPI_NFI_READ_FROM_CACHE_DONE,
+ SPI_NFI_READ_FROM_CACHE_DONE);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR,
+ val, (val & SPI_NFI_AHB_DONE), 0,
+ 1 * USEC_PER_SEC);
+ if (err)
+ goto error_dma_unmap;
+
+ /* DMA read need delay for data ready from controller to DRAM */
+ udelay(1);
+
+ dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
+ DMA_FROM_DEVICE);
+ err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
+ if (err < 0)
+ return err;
+
+ memcpy(buf, txrx_buf + offs, len);
+
+ return len;
+
+error_dma_unmap:
+ dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
+ DMA_FROM_DEVICE);
+error_dma_mode_off:
+ airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
+ return err;
+}
+
+static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, const void *buf)
+{
+ struct spi_device *spi = desc->mem->spi;
+ u8 *txrx_buf = spi_get_ctldata(spi);
+ struct airoha_snand_ctrl *as_ctrl;
+ dma_addr_t dma_addr;
+ u32 wr_mode, val, opcode;
+ size_t bytes;
+ int err;
+
+ as_ctrl = spi_controller_get_devdata(spi->controller);
+
+ /* minimum oob size is 64 */
+ bytes = round_up(offs + len, 64);
+
+ opcode = desc->info.op_tmpl.cmd.opcode;
+ switch (opcode) {
+ case SPI_NAND_OP_PROGRAM_LOAD_SINGLE:
+ case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE:
+ wr_mode = 0;
+ break;
+ case SPI_NAND_OP_PROGRAM_LOAD_QUAD:
+ case SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD:
+ wr_mode = 2;
+ break;
+ default:
+ /* unknown opcode */
+ return -EOPNOTSUPP;
+ }
+
+ if (offs > 0)
+ memset(txrx_buf, 0xff, offs);
+ memcpy(txrx_buf + offs, buf, len);
+ if (bytes > offs + len)
+ memset(txrx_buf + offs + len, 0xff, bytes - offs - len);
+
+ err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
+ if (err < 0)
+ return err;
+
+ /* NFI reset */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_FIFO_FLUSH | SPI_NFI_RST);
+ if (err)
+ goto error_dma_mode_off;
+
+ /*
+ * NFI configure:
+ * - No AutoFDM (custom sector size (SECCUS) register will be used)
+ * - No SoC's hardware ECC (flash internal ECC will be used)
+ * - Use burst mode (faster, but requires 16 byte alignment for addresses)
+ * - Setup for writing (SPI_NFI_READ_MODE bit is cleared)
+ * - Setup writing command: FIELD_PREP(SPI_NFI_OPMODE, 3)
+ * - Use DMA instead of PIO for data writing
+ */
+ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
+ SPI_NFI_DMA_MODE |
+ SPI_NFI_READ_MODE |
+ SPI_NFI_DMA_BURST_EN |
+ SPI_NFI_HW_ECC_EN |
+ SPI_NFI_AUTO_FDM_EN |
+ SPI_NFI_OPMODE,
+ SPI_NFI_DMA_MODE |
+ SPI_NFI_DMA_BURST_EN |
+ FIELD_PREP(SPI_NFI_OPMODE, 3));
+ if (err)
+ goto error_dma_mode_off;
+
+ /* Set number of sector will be written */
+ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_SEC_NUM,
+ FIELD_PREP(SPI_NFI_SEC_NUM, 1));
+ if (err)
+ goto error_dma_mode_off;
+
+ /* Set custom sector size */
+ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE,
+ SPI_NFI_CUS_SEC_SIZE |
+ SPI_NFI_CUS_SEC_SIZE_EN,
+ FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) |
+ SPI_NFI_CUS_SEC_SIZE_EN);
+ if (err)
+ goto error_dma_mode_off;
+
+ dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE,
+ DMA_TO_DEVICE);
+ err = dma_mapping_error(as_ctrl->dev, dma_addr);
+ if (err)
+ goto error_dma_mode_off;
+
+ /* set dma addr */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
+ dma_addr);
+ if (err)
+ goto error_dma_unmap;
+
+ /*
+ * Setup transfer length
+ * ---------------------
+ * The following rule MUST be met:
+ * transfer_length =
+ * = NFI_SNF_MISC_CTL2.write_data_byte_number =
+ * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size
+ */
+ err = regmap_update_bits(as_ctrl->regmap_nfi,
+ REG_SPI_NFI_SNF_MISC_CTL2,
+ SPI_NFI_PROG_LOAD_BYTE_NUM,
+ FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, bytes));
+ if (err)
+ goto error_dma_unmap;
+
+ /* set write command */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1,
+ FIELD_PREP(SPI_NFI_PG_LOAD_CMD, opcode));
+ if (err)
+ goto error_dma_unmap;
+
+ /* set write mode */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL,
+ FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode));
+ if (err)
+ goto error_dma_unmap;
+
+ /* set write addr: zero page offset + descriptor write offset */
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2,
+ desc->info.offset);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x80);
+ if (err)
+ goto error_dma_unmap;
+
+ /* trigger dma writing */
+ err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_WR_TRIG);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
+ SPI_NFI_WR_TRIG);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR,
+ val, (val & SPI_NFI_AHB_DONE), 0,
+ 1 * USEC_PER_SEC);
+ if (err)
+ goto error_dma_unmap;
+
+ err = regmap_read_poll_timeout(as_ctrl->regmap_nfi,
+ REG_SPI_NFI_SNF_STA_CTL1, val,
+ (val & SPI_NFI_LOAD_TO_CACHE_DONE),
+ 0, 1 * USEC_PER_SEC);
+ if (err)
+ goto error_dma_unmap;
+
+ /*
+ * SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end
+ * of dirmap_write operation even if it is already set.
+ */
+ err = regmap_write_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1,
+ SPI_NFI_LOAD_TO_CACHE_DONE,
+ SPI_NFI_LOAD_TO_CACHE_DONE);
+ if (err)
+ goto error_dma_unmap;
+
+ dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
+ DMA_TO_DEVICE);
+ err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
+ if (err < 0)
+ return err;
+
+ return len;
+
+error_dma_unmap:
+ dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
+ DMA_TO_DEVICE);
+error_dma_mode_off:
+ airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
+ return err;
+}
+
+static int airoha_snand_exec_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct airoha_snand_ctrl *as_ctrl;
+ int op_len, addr_len, dummy_len;
+ u8 buf[20], *data;
+ int i, err;
+
+ as_ctrl = spi_controller_get_devdata(mem->spi->controller);
+
+ op_len = op->cmd.nbytes;
+ addr_len = op->addr.nbytes;
+ dummy_len = op->dummy.nbytes;
+
+ if (op_len + dummy_len + addr_len > sizeof(buf))
+ return -EIO;
+
+ data = buf;
+ for (i = 0; i < op_len; i++)
+ *data++ = op->cmd.opcode >> (8 * (op_len - i - 1));
+ for (i = 0; i < addr_len; i++)
+ *data++ = op->addr.val >> (8 * (addr_len - i - 1));
+ for (i = 0; i < dummy_len; i++)
+ *data++ = 0xff;
+
+ /* switch to manual mode */
+ err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
+ if (err < 0)
+ return err;
+
+ err = airoha_snand_set_cs(as_ctrl, SPI_CHIP_SEL_LOW);
+ if (err < 0)
+ return err;
+
+ /* opcode */
+ data = buf;
+ err = airoha_snand_write_data(as_ctrl, data, op_len,
+ op->cmd.buswidth);
+ if (err)
+ return err;
+
+ /* addr part */
+ data += op_len;
+ if (addr_len) {
+ err = airoha_snand_write_data(as_ctrl, data, addr_len,
+ op->addr.buswidth);
+ if (err)
+ return err;
+ }
+
+ /* dummy */
+ data += addr_len;
+ if (dummy_len) {
+ err = airoha_snand_write_data(as_ctrl, data, dummy_len,
+ op->dummy.buswidth);
+ if (err)
+ return err;
+ }
+
+ /* data */
+ if (op->data.nbytes) {
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ err = airoha_snand_read_data(as_ctrl, op->data.buf.in,
+ op->data.nbytes,
+ op->data.buswidth);
+ else
+ err = airoha_snand_write_data(as_ctrl, op->data.buf.out,
+ op->data.nbytes,
+ op->data.buswidth);
+ if (err)
+ return err;
+ }
+
+ return airoha_snand_set_cs(as_ctrl, SPI_CHIP_SEL_HIGH);
+}
+
+static const struct spi_controller_mem_ops airoha_snand_mem_ops = {
+ .supports_op = airoha_snand_supports_op,
+ .exec_op = airoha_snand_exec_op,
+ .dirmap_create = airoha_snand_dirmap_create,
+ .dirmap_read = airoha_snand_dirmap_read,
+ .dirmap_write = airoha_snand_dirmap_write,
+};
+
+static const struct spi_controller_mem_ops airoha_snand_nodma_mem_ops = {
+ .supports_op = airoha_snand_supports_op,
+ .exec_op = airoha_snand_exec_op,
+};
+
+static int airoha_snand_setup(struct spi_device *spi)
+{
+ struct airoha_snand_ctrl *as_ctrl;
+ u8 *txrx_buf;
+
+ /* prepare device buffer */
+ as_ctrl = spi_controller_get_devdata(spi->controller);
+ txrx_buf = devm_kzalloc(as_ctrl->dev, SPI_NAND_CACHE_SIZE,
+ GFP_KERNEL);
+ if (!txrx_buf)
+ return -ENOMEM;
+
+ spi_set_ctldata(spi, txrx_buf);
+
+ return 0;
+}
+
+static const struct regmap_config spi_ctrl_regmap_config = {
+ .name = "ctrl",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = REG_SPI_CTRL_NFI2SPI_EN,
+};
+
+static const struct regmap_config spi_nfi_regmap_config = {
+ .name = "nfi",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = REG_SPI_NFI_SNF_NFI_CNFG,
+};
+
+static const struct of_device_id airoha_snand_ids[] = {
+ { .compatible = "airoha,en7581-snand" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, airoha_snand_ids);
+
+static int airoha_snand_probe(struct platform_device *pdev)
+{
+ struct airoha_snand_ctrl *as_ctrl;
+ struct device *dev = &pdev->dev;
+ struct spi_controller *ctrl;
+ bool dma_enable = true;
+ void __iomem *base;
+ u32 sfc_strap;
+ int err;
+
+ ctrl = devm_spi_alloc_host(dev, sizeof(*as_ctrl));
+ if (!ctrl)
+ return -ENOMEM;
+
+ as_ctrl = spi_controller_get_devdata(ctrl);
+ as_ctrl->dev = dev;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ as_ctrl->regmap_ctrl = devm_regmap_init_mmio(dev, base,
+ &spi_ctrl_regmap_config);
+ if (IS_ERR(as_ctrl->regmap_ctrl))
+ return dev_err_probe(dev, PTR_ERR(as_ctrl->regmap_ctrl),
+ "failed to init spi ctrl regmap\n");
+
+ base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ as_ctrl->regmap_nfi = devm_regmap_init_mmio(dev, base,
+ &spi_nfi_regmap_config);
+ if (IS_ERR(as_ctrl->regmap_nfi))
+ return dev_err_probe(dev, PTR_ERR(as_ctrl->regmap_nfi),
+ "failed to init spi nfi regmap\n");
+
+ as_ctrl->spi_clk = devm_clk_get_enabled(dev, "spi");
+ if (IS_ERR(as_ctrl->spi_clk))
+ return dev_err_probe(dev, PTR_ERR(as_ctrl->spi_clk),
+ "unable to get spi clk\n");
+
+ if (device_is_compatible(dev, "airoha,en7523-snand")) {
+ err = regmap_read(as_ctrl->regmap_ctrl,
+ REG_SPI_CTRL_SFC_STRAP, &sfc_strap);
+ if (err)
+ return err;
+
+ if (!(sfc_strap & 0x04)) {
+ dma_enable = false;
+ dev_warn(dev, "Detected booting in RESERVED mode (UART_TXD was short to GND).\n");
+ dev_warn(dev, "This mode is known for incorrect DMA reading of some flashes.\n");
+ dev_warn(dev, "Much slower PIO mode will be used to prevent flash data damage.\n");
+ dev_warn(dev, "Unplug UART cable and power cycle board to get full performance.\n");
+ }
+ }
+
+ err = dma_set_mask(as_ctrl->dev, DMA_BIT_MASK(32));
+ if (err)
+ return err;
+
+ ctrl->num_chipselect = 2;
+ ctrl->mem_ops = dma_enable ? &airoha_snand_mem_ops
+ : &airoha_snand_nodma_mem_ops;
+ ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
+ ctrl->mode_bits = SPI_RX_DUAL;
+ ctrl->setup = airoha_snand_setup;
+ device_set_node(&ctrl->dev, dev_fwnode(dev));
+
+ err = airoha_snand_nfi_init(as_ctrl);
+ if (err)
+ return err;
+
+ return devm_spi_register_controller(dev, ctrl);
+}
+
+static struct platform_driver airoha_snand_driver = {
+ .driver = {
+ .name = "airoha-spi",
+ .of_match_table = airoha_snand_ids,
+ },
+ .probe = airoha_snand_probe,
+};
+module_platform_driver(airoha_snand_driver);
+
+MODULE_DESCRIPTION("Airoha SPI-NAND Flash Controller Driver");
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
+MODULE_AUTHOR("Ray Liu <ray.liu@airoha.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-altera-core.c b/drivers/spi/spi-altera-core.c
index 87e37f48f196..7af097929116 100644
--- a/drivers/spi/spi-altera-core.c
+++ b/drivers/spi/spi-altera-core.c
@@ -219,4 +219,5 @@ void altera_spi_init_host(struct spi_controller *host)
}
EXPORT_SYMBOL_GPL(altera_spi_init_host);
+MODULE_DESCRIPTION("Altera SPI Controller driver core");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-altera-platform.c b/drivers/spi/spi-altera-platform.c
index 72e7a0f21793..e163774fd65b 100644
--- a/drivers/spi/spi-altera-platform.c
+++ b/drivers/spi/spi-altera-platform.c
@@ -30,7 +30,6 @@ static const struct regmap_config spi_altera_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .fast_io = true,
};
static int altera_spi_probe(struct platform_device *pdev)
@@ -169,4 +168,3 @@ module_platform_driver(altera_spi_driver);
MODULE_DESCRIPTION("Altera SPI driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/spi/spi-amd-pci.c b/drivers/spi/spi-amd-pci.c
new file mode 100644
index 000000000000..d48c3a5da303
--- /dev/null
+++ b/drivers/spi/spi-amd-pci.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD SPI controller driver
+ *
+ * Copyright (c) 2025, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Authors: Krishnamoorthi M <krishnamoorthi.m@amd.com>
+ * Akshata MukundShetty <akshata.mukundshetty@amd.com>
+ */
+
+#include <linux/init.h>
+#include <linux/spi/spi.h>
+#include <linux/pci.h>
+
+#include "spi-amd.h"
+
+#define AMD_PCI_DEVICE_ID_LPC_BRIDGE 0x1682
+#define AMD_PCI_LPC_SPI_BASE_ADDR_REG 0xA0
+#define AMD_SPI_BASE_ADDR_MASK ~0xFF
+#define AMD_HID2_PCI_BAR_OFFSET 0x00002000
+#define AMD_HID2_MEM_SIZE 0x200
+
+static struct pci_device_id pci_spi_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_PCI_DEVICE_ID_LPC_BRIDGE) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, pci_spi_ids);
+
+static int amd_spi_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_controller *host;
+ struct amd_spi *amd_spi;
+ u32 io_base_addr;
+
+ /* Allocate storage for host and driver private data */
+ host = devm_spi_alloc_host(dev, sizeof(struct amd_spi));
+ if (!host)
+ return -ENOMEM;
+
+ amd_spi = spi_controller_get_devdata(host);
+
+ pci_read_config_dword(pdev, AMD_PCI_LPC_SPI_BASE_ADDR_REG, &io_base_addr);
+ io_base_addr = (io_base_addr & AMD_SPI_BASE_ADDR_MASK) + AMD_HID2_PCI_BAR_OFFSET;
+ amd_spi->io_remap_addr = devm_ioremap(dev, io_base_addr, AMD_HID2_MEM_SIZE);
+
+ if (!amd_spi->io_remap_addr)
+ return -ENOMEM;
+
+ dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr);
+
+ amd_spi->version = AMD_HID2_SPI;
+ host->bus_num = 2;
+
+ return amd_spi_probe_common(dev, host);
+}
+
+static struct pci_driver amd_spi_pci_driver = {
+ .name = "amd_spi_pci",
+ .id_table = pci_spi_ids,
+ .probe = amd_spi_pci_probe,
+};
+
+module_pci_driver(amd_spi_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD HID2 SPI Controller Driver");
diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c
index fecead757a3c..4d1dce4f4974 100644
--- a/drivers/spi/spi-amd.c
+++ b/drivers/spi/spi-amd.c
@@ -7,12 +7,17 @@
// Author: Sanjay R Mehta <sanju.mehta@amd.com>
#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/init.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/delay.h>
#include <linux/spi/spi.h>
-#include <linux/iopoll.h>
+#include <linux/spi/spi-mem.h>
+
+#include "spi-amd.h"
#define AMD_SPI_CTRL0_REG 0x00
#define AMD_SPI_EXEC_CMD BIT(16)
@@ -32,9 +37,12 @@
#define AMD_SPI_TX_COUNT_REG 0x48
#define AMD_SPI_RX_COUNT_REG 0x4B
#define AMD_SPI_STATUS_REG 0x4C
+#define AMD_SPI_ADDR32CTRL_REG 0x50
#define AMD_SPI_FIFO_SIZE 70
#define AMD_SPI_MEM_SIZE 200
+#define AMD_SPI_MAX_DATA 64
+#define AMD_SPI_HID2_DMA_SIZE 4096
#define AMD_SPI_ENA_REG 0x20
#define AMD_SPI_ALT_SPD_SHIFT 20
@@ -45,18 +53,42 @@
#define AMD_SPI_SPD7_SHIFT 8
#define AMD_SPI_SPD7_MASK GENMASK(13, AMD_SPI_SPD7_SHIFT)
+#define AMD_SPI_HID2_INPUT_RING_BUF0 0X100
+#define AMD_SPI_HID2_OUTPUT_BUF0 0x140
+#define AMD_SPI_HID2_CNTRL 0x150
+#define AMD_SPI_HID2_INT_STATUS 0x154
+#define AMD_SPI_HID2_CMD_START 0x156
+#define AMD_SPI_HID2_INT_MASK 0x158
+#define AMD_SPI_HID2_WRITE_CNTRL0 0x160
+#define AMD_SPI_HID2_WRITE_CNTRL1 0x164
+#define AMD_SPI_HID2_READ_CNTRL0 0x170
+#define AMD_SPI_HID2_READ_CNTRL1 0x174
+#define AMD_SPI_HID2_READ_CNTRL2 0x180
+
#define AMD_SPI_MAX_HZ 100000000
#define AMD_SPI_MIN_HZ 800000
-/**
- * enum amd_spi_versions - SPI controller versions
- * @AMD_SPI_V1: AMDI0061 hardware version
- * @AMD_SPI_V2: AMDI0062 hardware version
- */
-enum amd_spi_versions {
- AMD_SPI_V1 = 1,
- AMD_SPI_V2,
-};
+#define AMD_SPI_IO_SLEEP_US 20
+#define AMD_SPI_IO_TIMEOUT_US 2000000
+
+/* SPI read command opcodes */
+#define AMD_SPI_OP_READ 0x03 /* Read data bytes (low frequency) */
+#define AMD_SPI_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
+#define AMD_SPI_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */
+#define AMD_SPI_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */
+#define AMD_SPI_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */
+#define AMD_SPI_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */
+
+/* SPI read command opcodes - 4B address */
+#define AMD_SPI_OP_READ_FAST_4B 0x0c /* Read data bytes (high frequency) */
+#define AMD_SPI_OP_READ_1_1_2_4B 0x3c /* Read data bytes (Dual Output SPI) */
+#define AMD_SPI_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */
+#define AMD_SPI_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */
+#define AMD_SPI_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */
+
+/* SPINAND write command opcodes */
+#define AMD_SPI_OP_PP 0x02 /* Page program */
+#define AMD_SPI_OP_PP_RANDOM 0x84 /* Page program */
enum amd_spi_speed {
F_66_66MHz,
@@ -83,26 +115,14 @@ struct amd_spi_freq {
u32 spd7_val;
};
-/**
- * struct amd_spi - SPI driver instance
- * @io_remap_addr: Start address of the SPI controller registers
- * @version: SPI controller hardware version
- * @speed_hz: Device frequency
- */
-struct amd_spi {
- void __iomem *io_remap_addr;
- enum amd_spi_versions version;
- unsigned int speed_hz;
-};
-
static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx)
{
- return ioread8((u8 __iomem *)amd_spi->io_remap_addr + idx);
+ return readb((u8 __iomem *)amd_spi->io_remap_addr + idx);
}
static inline void amd_spi_writereg8(struct amd_spi *amd_spi, int idx, u8 val)
{
- iowrite8(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
+ writeb(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
}
static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 clear)
@@ -113,14 +133,34 @@ static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 c
amd_spi_writereg8(amd_spi, idx, tmp);
}
+static inline u16 amd_spi_readreg16(struct amd_spi *amd_spi, int idx)
+{
+ return readw((u8 __iomem *)amd_spi->io_remap_addr + idx);
+}
+
+static inline void amd_spi_writereg16(struct amd_spi *amd_spi, int idx, u16 val)
+{
+ writew(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
+}
+
static inline u32 amd_spi_readreg32(struct amd_spi *amd_spi, int idx)
{
- return ioread32((u8 __iomem *)amd_spi->io_remap_addr + idx);
+ return readl((u8 __iomem *)amd_spi->io_remap_addr + idx);
}
static inline void amd_spi_writereg32(struct amd_spi *amd_spi, int idx, u32 val)
{
- iowrite32(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
+ writel(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
+}
+
+static inline u64 amd_spi_readreg64(struct amd_spi *amd_spi, int idx)
+{
+ return readq((u8 __iomem *)amd_spi->io_remap_addr + idx);
+}
+
+static inline void amd_spi_writereg64(struct amd_spi *amd_spi, int idx, u64 val)
+{
+ writeq(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
}
static inline void amd_spi_setclear_reg32(struct amd_spi *amd_spi, int idx, u32 set, u32 clear)
@@ -154,6 +194,7 @@ static int amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode)
AMD_SPI_OPCODE_MASK);
return 0;
case AMD_SPI_V2:
+ case AMD_HID2_SPI:
amd_spi_writereg8(amd_spi, AMD_SPI_OPCODE_REG, cmd_opcode);
return 0;
default:
@@ -163,12 +204,12 @@ static int amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode)
static inline void amd_spi_set_rx_count(struct amd_spi *amd_spi, u8 rx_count)
{
- amd_spi_setclear_reg8(amd_spi, AMD_SPI_RX_COUNT_REG, rx_count, 0xff);
+ amd_spi_writereg8(amd_spi, AMD_SPI_RX_COUNT_REG, rx_count);
}
static inline void amd_spi_set_tx_count(struct amd_spi *amd_spi, u8 tx_count)
{
- amd_spi_setclear_reg8(amd_spi, AMD_SPI_TX_COUNT_REG, tx_count, 0xff);
+ amd_spi_writereg8(amd_spi, AMD_SPI_TX_COUNT_REG, tx_count);
}
static int amd_spi_busy_wait(struct amd_spi *amd_spi)
@@ -181,6 +222,7 @@ static int amd_spi_busy_wait(struct amd_spi *amd_spi)
reg = AMD_SPI_CTRL0_REG;
break;
case AMD_SPI_V2:
+ case AMD_HID2_SPI:
reg = AMD_SPI_STATUS_REG;
break;
default:
@@ -206,6 +248,7 @@ static int amd_spi_execute_opcode(struct amd_spi *amd_spi)
AMD_SPI_EXEC_CMD);
return 0;
case AMD_SPI_V2:
+ case AMD_HID2_SPI:
/* Trigger the command execution */
amd_spi_setclear_reg8(amd_spi, AMD_SPI_CMD_TRIGGER_REG,
AMD_SPI_TRIGGER_CMD, AMD_SPI_TRIGGER_CMD);
@@ -215,9 +258,9 @@ static int amd_spi_execute_opcode(struct amd_spi *amd_spi)
}
}
-static int amd_spi_master_setup(struct spi_device *spi)
+static int amd_spi_host_setup(struct spi_device *spi)
{
- struct amd_spi *amd_spi = spi_master_get_devdata(spi->master);
+ struct amd_spi *amd_spi = spi_controller_get_devdata(spi->controller);
amd_spi_clear_fifo_ptr(amd_spi);
@@ -236,19 +279,16 @@ static const struct amd_spi_freq amd_spi_freq[] = {
{ AMD_SPI_MIN_HZ, F_800KHz, 0},
};
-static int amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz)
+static void amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz)
{
unsigned int i, spd7_val, alt_spd;
- if (speed_hz < AMD_SPI_MIN_HZ)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(amd_spi_freq); i++)
+ for (i = 0; i < ARRAY_SIZE(amd_spi_freq)-1; i++)
if (speed_hz >= amd_spi_freq[i].speed_hz)
break;
if (amd_spi->speed_hz == amd_spi_freq[i].speed_hz)
- return 0;
+ return;
amd_spi->speed_hz = amd_spi_freq[i].speed_hz;
@@ -267,12 +307,10 @@ static int amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz)
amd_spi_setclear_reg32(amd_spi, AMD_SPI_SPEED_REG, spd7_val,
AMD_SPI_SPD7_MASK);
}
-
- return 0;
}
static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
- struct spi_master *master,
+ struct spi_controller *host,
struct spi_message *message)
{
struct spi_transfer *xfer = NULL;
@@ -347,21 +385,393 @@ fin_msg:
case AMD_SPI_V1:
break;
case AMD_SPI_V2:
+ case AMD_HID2_SPI:
amd_spi_clear_chip(amd_spi, spi_get_chipselect(message->spi, 0));
break;
default:
return -ENODEV;
}
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return message->status;
}
-static int amd_spi_master_transfer(struct spi_master *master,
+static inline bool amd_is_spi_read_cmd_4b(const u16 op)
+{
+ switch (op) {
+ case AMD_SPI_OP_READ_FAST_4B:
+ case AMD_SPI_OP_READ_1_1_2_4B:
+ case AMD_SPI_OP_READ_1_2_2_4B:
+ case AMD_SPI_OP_READ_1_1_4_4B:
+ case AMD_SPI_OP_READ_1_4_4_4B:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool amd_is_spi_read_cmd(const u16 op)
+{
+ switch (op) {
+ case AMD_SPI_OP_READ:
+ case AMD_SPI_OP_READ_FAST:
+ case AMD_SPI_OP_READ_1_1_2:
+ case AMD_SPI_OP_READ_1_2_2:
+ case AMD_SPI_OP_READ_1_1_4:
+ case AMD_SPI_OP_READ_1_4_4:
+ return true;
+ default:
+ return amd_is_spi_read_cmd_4b(op);
+ }
+}
+
+static inline bool amd_is_spi_write_cmd(const u16 op)
+{
+ switch (op) {
+ case AMD_SPI_OP_PP:
+ case AMD_SPI_OP_PP_RANDOM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool amd_spi_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct amd_spi *amd_spi = spi_controller_get_devdata(mem->spi->controller);
+
+ /* bus width is number of IO lines used to transmit */
+ if (op->cmd.buswidth > 1 || op->addr.buswidth > 4)
+ return false;
+
+ /* AMD SPI controllers support quad mode only for read operations */
+ if (amd_is_spi_read_cmd(op->cmd.opcode) || amd_is_spi_write_cmd(op->cmd.opcode)) {
+ if (op->data.buswidth > 4)
+ return false;
+
+ /*
+ * HID2 SPI controller supports DMA read up to 4K bytes and
+ * doesn't support 4-byte address commands.
+ */
+ if (amd_spi->version == AMD_HID2_SPI) {
+ if ((amd_is_spi_read_cmd_4b(op->cmd.opcode) ||
+ amd_is_spi_write_cmd(op->cmd.opcode)) &&
+ op->data.nbytes > AMD_SPI_HID2_DMA_SIZE)
+ return false;
+ } else if (op->data.nbytes > AMD_SPI_MAX_DATA) {
+ return false;
+ }
+ } else if (op->data.buswidth > 1 || op->data.nbytes > AMD_SPI_MAX_DATA) {
+ return false;
+ }
+
+ if (op->max_freq < mem->spi->controller->min_speed_hz)
+ return false;
+
+ return spi_mem_default_supports_op(mem, op);
+}
+
+static int amd_spi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+ struct amd_spi *amd_spi = spi_controller_get_devdata(mem->spi->controller);
+
+ /*
+ * HID2 SPI controller DMA read mode supports reading up to 4k
+ * bytes in single transaction, where as SPI0 and HID2 SPI
+ * controller index mode supports maximum of 64 bytes in a single
+ * transaction.
+ */
+ if (amd_spi->version == AMD_HID2_SPI && (amd_is_spi_read_cmd(op->cmd.opcode) ||
+ amd_is_spi_write_cmd(op->cmd.opcode)))
+ op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_HID2_DMA_SIZE);
+ else
+ op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_MAX_DATA);
+
+ return 0;
+}
+
+static void amd_spi_set_addr(struct amd_spi *amd_spi,
+ const struct spi_mem_op *op)
+{
+ u8 nbytes = op->addr.nbytes;
+ u64 addr_val = op->addr.val;
+ int base_addr, i;
+
+ base_addr = AMD_SPI_FIFO_BASE + nbytes;
+
+ for (i = 0; i < nbytes; i++) {
+ amd_spi_writereg8(amd_spi, base_addr - i - 1, addr_val &
+ GENMASK(7, 0));
+ addr_val >>= 8;
+ }
+}
+
+static void amd_spi_hiddma_write(struct amd_spi *amd_spi, const struct spi_mem_op *op)
+{
+ u16 hid_cmd_start, val;
+ u32 hid_regval;
+
+ /*
+ * Program the HID2 output Buffer0. 4k aligned buf_memory_addr[31:12],
+ * buf_size[2:0].
+ */
+ hid_regval = amd_spi->phy_dma_buf | BIT(0);
+ amd_spi_writereg32(amd_spi, AMD_SPI_HID2_OUTPUT_BUF0, hid_regval);
+
+ /* Program max write length in hid2_write_control1 register */
+ hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_WRITE_CNTRL1);
+ hid_regval = (hid_regval & ~GENMASK(15, 0)) | ((op->data.nbytes) + 3);
+ amd_spi_writereg32(amd_spi, AMD_SPI_HID2_WRITE_CNTRL1, hid_regval);
+
+ /* Set cmd start bit in hid2_cmd_start register to trigger HID basic write operation */
+ hid_cmd_start = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_CMD_START);
+ amd_spi_writereg16(amd_spi, AMD_SPI_HID2_CMD_START, (hid_cmd_start | BIT(2)));
+
+ /* Check interrupt status of HIDDMA basic write operation in hid2_int_status register */
+ readw_poll_timeout(amd_spi->io_remap_addr + AMD_SPI_HID2_INT_STATUS, val,
+ (val & BIT(2)), AMD_SPI_IO_SLEEP_US, AMD_SPI_IO_TIMEOUT_US);
+
+ /* Clear the interrupts by writing to hid2_int_status register */
+ val = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_INT_STATUS);
+ amd_spi_writereg16(amd_spi, AMD_SPI_HID2_INT_STATUS, val);
+}
+
+static void amd_spi_mem_data_out(struct amd_spi *amd_spi,
+ const struct spi_mem_op *op)
+{
+ int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes;
+ u64 *buf_64 = (u64 *)op->data.buf.out;
+ u64 addr_val = op->addr.val;
+ u32 nbytes = op->data.nbytes;
+ u32 left_data = nbytes;
+ u8 *buf;
+ int i;
+
+ /*
+ * Condition for using HID write mode. Only for writing complete page data, use HID write.
+ * Use index mode otherwise.
+ */
+ if (amd_spi->version == AMD_HID2_SPI && amd_is_spi_write_cmd(op->cmd.opcode)) {
+ u64 *dma_buf64 = (u64 *)(amd_spi->dma_virt_addr + op->addr.nbytes + op->cmd.nbytes);
+ u8 *dma_buf = (u8 *)amd_spi->dma_virt_addr;
+
+ /* Copy opcode and address to DMA buffer */
+ *dma_buf = op->cmd.opcode;
+
+ dma_buf = (u8 *)dma_buf64;
+ for (i = 0; i < op->addr.nbytes; i++) {
+ *--dma_buf = addr_val & GENMASK(7, 0);
+ addr_val >>= 8;
+ }
+
+ /* Copy data to DMA buffer */
+ while (left_data >= 8) {
+ *dma_buf64++ = *buf_64++;
+ left_data -= 8;
+ }
+
+ buf = (u8 *)buf_64;
+ dma_buf = (u8 *)dma_buf64;
+ while (left_data--)
+ *dma_buf++ = *buf++;
+
+ amd_spi_hiddma_write(amd_spi, op);
+ } else {
+ amd_spi_set_opcode(amd_spi, op->cmd.opcode);
+ amd_spi_set_addr(amd_spi, op);
+
+ for (i = 0; left_data >= 8; i++, left_data -= 8)
+ amd_spi_writereg64(amd_spi, base_addr + op->dummy.nbytes + (i * 8),
+ *buf_64++);
+
+ buf = (u8 *)buf_64;
+ for (i = 0; i < left_data; i++) {
+ amd_spi_writereg8(amd_spi,
+ base_addr + op->dummy.nbytes + nbytes + i - left_data,
+ buf[i]);
+ }
+
+ amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->data.nbytes);
+ amd_spi_set_rx_count(amd_spi, 0);
+ amd_spi_clear_fifo_ptr(amd_spi);
+ amd_spi_execute_opcode(amd_spi);
+ }
+}
+
+static void amd_spi_hiddma_read(struct amd_spi *amd_spi, const struct spi_mem_op *op)
+{
+ u16 hid_cmd_start, val;
+ u32 hid_regval;
+
+ /* Set the opcode in hid2_read_control0 register */
+ hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL0);
+ hid_regval = (hid_regval & ~GENMASK(7, 0)) | op->cmd.opcode;
+
+ /*
+ * Program the address in the hid2_read_control0 register [8:31]. The address should
+ * be written starting from the 8th bit of the register, requiring an 8-bit shift.
+ * Additionally, to convert a 2-byte spinand address to a 3-byte address, another
+ * 8-bit shift is needed. Therefore, a total shift of 16 bits is required.
+ */
+ hid_regval = (hid_regval & ~GENMASK(31, 8)) | (op->addr.val << 16);
+ amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL0, hid_regval);
+
+ /* Configure dummy clock cycles for fast read, dual, quad I/O commands */
+ hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL2);
+ /* Fast read dummy cycle */
+ hid_regval &= ~GENMASK(4, 0);
+
+ /* Fast read Dual I/O dummy cycle */
+ hid_regval &= ~GENMASK(12, 8);
+
+ /* Fast read Quad I/O dummy cycle */
+ hid_regval = (hid_regval & ~GENMASK(20, 16)) | BIT(17);
+
+ /* Set no of preamble bytecount */
+ hid_regval &= ~GENMASK(27, 24);
+ amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL2, hid_regval);
+
+ /*
+ * Program the HID2 Input Ring Buffer0. 4k aligned buf_memory_addr[31:12],
+ * buf_size[4:0], end_input_ring[5].
+ */
+ hid_regval = amd_spi->phy_dma_buf | BIT(5) | BIT(0);
+ amd_spi_writereg32(amd_spi, AMD_SPI_HID2_INPUT_RING_BUF0, hid_regval);
+
+ /* Program max read length(no of DWs) in hid2_read_control1 register */
+ hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL1);
+ hid_regval = (hid_regval & ~GENMASK(15, 0)) | ((op->data.nbytes / 4) - 1);
+ amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL1, hid_regval);
+
+ /* Set cmd start bit in hid2_cmd_start register to trigger HID basic read operation */
+ hid_cmd_start = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_CMD_START);
+ amd_spi_writereg16(amd_spi, AMD_SPI_HID2_CMD_START, (hid_cmd_start | BIT(3)));
+
+ /* Check interrupt status of HIDDMA basic read operation in hid2_int_status register */
+ readw_poll_timeout(amd_spi->io_remap_addr + AMD_SPI_HID2_INT_STATUS, val,
+ (val & BIT(3)), AMD_SPI_IO_SLEEP_US, AMD_SPI_IO_TIMEOUT_US);
+
+ /* Clear the interrupts by writing to hid2_int_status register */
+ val = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_INT_STATUS);
+ amd_spi_writereg16(amd_spi, AMD_SPI_HID2_INT_STATUS, val);
+}
+
+static void amd_spi_mem_data_in(struct amd_spi *amd_spi,
+ const struct spi_mem_op *op)
+{
+ int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes;
+ u64 *buf_64 = (u64 *)op->data.buf.in;
+ u32 nbytes = op->data.nbytes;
+ u32 left_data = nbytes;
+ u32 data;
+ u8 *buf;
+ int i;
+
+ /*
+ * Condition for using HID read mode. Only for reading complete page data, use HID read.
+ * Use index mode otherwise.
+ */
+ if (amd_spi->version == AMD_HID2_SPI && amd_is_spi_read_cmd(op->cmd.opcode)) {
+ u64 *dma_buf64 = (u64 *)amd_spi->dma_virt_addr;
+ u8 *dma_buf;
+
+ amd_spi_hiddma_read(amd_spi, op);
+
+ /* Copy data from DMA buffer */
+ while (left_data >= 8) {
+ *buf_64++ = *dma_buf64++;
+ left_data -= 8;
+ }
+
+ buf = (u8 *)buf_64;
+ dma_buf = (u8 *)dma_buf64;
+ while (left_data--)
+ *buf++ = *dma_buf++;
+
+ /* Reset HID RX memory logic */
+ data = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_CNTRL);
+ amd_spi_writereg32(amd_spi, AMD_SPI_HID2_CNTRL, data | BIT(5));
+ } else {
+ /* Index mode */
+ amd_spi_set_opcode(amd_spi, op->cmd.opcode);
+ amd_spi_set_addr(amd_spi, op);
+ amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->dummy.nbytes);
+
+ for (i = 0; i < op->dummy.nbytes; i++)
+ amd_spi_writereg8(amd_spi, (base_addr + i), 0xff);
+
+ amd_spi_set_rx_count(amd_spi, op->data.nbytes);
+ amd_spi_clear_fifo_ptr(amd_spi);
+ amd_spi_execute_opcode(amd_spi);
+ amd_spi_busy_wait(amd_spi);
+
+ for (i = 0; left_data >= 8; i++, left_data -= 8)
+ *buf_64++ = amd_spi_readreg64(amd_spi, base_addr + op->dummy.nbytes +
+ (i * 8));
+
+ buf = (u8 *)buf_64;
+ for (i = 0; i < left_data; i++)
+ buf[i] = amd_spi_readreg8(amd_spi, base_addr + op->dummy.nbytes +
+ nbytes + i - left_data);
+ }
+
+}
+
+static void amd_set_spi_addr_mode(struct amd_spi *amd_spi,
+ const struct spi_mem_op *op)
+{
+ u32 val = amd_spi_readreg32(amd_spi, AMD_SPI_ADDR32CTRL_REG);
+
+ if (amd_is_spi_read_cmd_4b(op->cmd.opcode))
+ amd_spi_writereg32(amd_spi, AMD_SPI_ADDR32CTRL_REG, val | BIT(0));
+ else
+ amd_spi_writereg32(amd_spi, AMD_SPI_ADDR32CTRL_REG, val & ~BIT(0));
+}
+
+static int amd_spi_exec_mem_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct amd_spi *amd_spi;
+
+ amd_spi = spi_controller_get_devdata(mem->spi->controller);
+
+ amd_set_spi_freq(amd_spi, op->max_freq);
+
+ if (amd_spi->version == AMD_SPI_V2)
+ amd_set_spi_addr_mode(amd_spi, op);
+
+ switch (op->data.dir) {
+ case SPI_MEM_DATA_IN:
+ amd_spi_mem_data_in(amd_spi, op);
+ break;
+ case SPI_MEM_DATA_OUT:
+ fallthrough;
+ case SPI_MEM_NO_DATA:
+ amd_spi_mem_data_out(amd_spi, op);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static const struct spi_controller_mem_ops amd_spi_mem_ops = {
+ .exec_op = amd_spi_exec_mem_op,
+ .adjust_op_size = amd_spi_adjust_op_size,
+ .supports_op = amd_spi_supports_op,
+};
+
+static const struct spi_controller_mem_caps amd_spi_mem_caps = {
+ .per_op_freq = true,
+};
+
+static int amd_spi_host_transfer(struct spi_controller *host,
struct spi_message *msg)
{
- struct amd_spi *amd_spi = spi_master_get_devdata(master);
+ struct amd_spi *amd_spi = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
amd_spi_select_chip(amd_spi, spi_get_chipselect(spi, 0));
@@ -370,7 +780,7 @@ static int amd_spi_master_transfer(struct spi_master *master,
* Extract spi_transfers from the spi message and
* program the controller.
*/
- return amd_spi_fifo_xfer(amd_spi, master, msg);
+ return amd_spi_fifo_xfer(amd_spi, host, msg);
}
static size_t amd_spi_max_transfer_size(struct spi_device *spi)
@@ -378,19 +788,78 @@ static size_t amd_spi_max_transfer_size(struct spi_device *spi)
return AMD_SPI_FIFO_SIZE;
}
+static int amd_spi_setup_hiddma(struct amd_spi *amd_spi, struct device *dev)
+{
+ u32 hid_regval;
+
+ /* Allocate DMA buffer to use for HID basic read and write operations. For write
+ * operations, the DMA buffer should include the opcode, address bytes and dummy
+ * bytes(if any) in addition to the data bytes. Additionally, the hardware requires
+ * that the buffer address be 4K aligned. So, allocate DMA buffer of size
+ * 2 * AMD_SPI_HID2_DMA_SIZE.
+ */
+ amd_spi->dma_virt_addr = dmam_alloc_coherent(dev, AMD_SPI_HID2_DMA_SIZE * 2,
+ &amd_spi->phy_dma_buf, GFP_KERNEL);
+ if (!amd_spi->dma_virt_addr)
+ return -ENOMEM;
+
+ /*
+ * Enable interrupts and set mask bits in hid2_int_mask register to generate interrupt
+ * properly for HIDDMA basic read and write operations.
+ */
+ hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_INT_MASK);
+ hid_regval = (hid_regval & GENMASK(31, 8)) | BIT(18) | BIT(19);
+ amd_spi_writereg32(amd_spi, AMD_SPI_HID2_INT_MASK, hid_regval);
+
+ /* Configure buffer unit(4k) and write threshold in hid2_control register */
+ hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_CNTRL);
+ amd_spi_writereg32(amd_spi, AMD_SPI_HID2_CNTRL, (hid_regval | GENMASK(13, 12)) & ~BIT(3));
+
+ return 0;
+}
+
+int amd_spi_probe_common(struct device *dev, struct spi_controller *host)
+{
+ struct amd_spi *amd_spi = spi_controller_get_devdata(host);
+ int err;
+
+ /* Initialize the spi_controller fields */
+ host->num_chipselect = 4;
+ host->mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->max_speed_hz = AMD_SPI_MAX_HZ;
+ host->min_speed_hz = AMD_SPI_MIN_HZ;
+ host->setup = amd_spi_host_setup;
+ host->transfer_one_message = amd_spi_host_transfer;
+ host->mem_ops = &amd_spi_mem_ops;
+ host->mem_caps = &amd_spi_mem_caps;
+ host->max_transfer_size = amd_spi_max_transfer_size;
+ host->max_message_size = amd_spi_max_transfer_size;
+
+ /* Register the controller with SPI framework */
+ err = devm_spi_register_controller(dev, host);
+ if (err)
+ return dev_err_probe(dev, err, "error registering SPI controller\n");
+
+ if (amd_spi->version == AMD_HID2_SPI)
+ err = amd_spi_setup_hiddma(amd_spi, dev);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(amd_spi_probe_common);
+
static int amd_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct amd_spi *amd_spi;
- int err;
- /* Allocate storage for spi_master and driver private data */
- master = devm_spi_alloc_master(dev, sizeof(struct amd_spi));
- if (!master)
- return dev_err_probe(dev, -ENOMEM, "Error allocating SPI master\n");
+ /* Allocate storage for host and driver private data */
+ host = devm_spi_alloc_host(dev, sizeof(struct amd_spi));
+ if (!host)
+ return -ENOMEM;
- amd_spi = spi_master_get_devdata(master);
+ amd_spi = spi_controller_get_devdata(host);
amd_spi->io_remap_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(amd_spi->io_remap_addr))
return dev_err_probe(dev, PTR_ERR(amd_spi->io_remap_addr),
@@ -398,32 +867,17 @@ static int amd_spi_probe(struct platform_device *pdev)
dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr);
- amd_spi->version = (enum amd_spi_versions) device_get_match_data(dev);
-
- /* Initialize the spi_master fields */
- master->bus_num = 0;
- master->num_chipselect = 4;
- master->mode_bits = 0;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->max_speed_hz = AMD_SPI_MAX_HZ;
- master->min_speed_hz = AMD_SPI_MIN_HZ;
- master->setup = amd_spi_master_setup;
- master->transfer_one_message = amd_spi_master_transfer;
- master->max_transfer_size = amd_spi_max_transfer_size;
- master->max_message_size = amd_spi_max_transfer_size;
+ amd_spi->version = (uintptr_t)device_get_match_data(dev);
+ host->bus_num = 0;
- /* Register the controller with SPI framework */
- err = devm_spi_register_master(dev, master);
- if (err)
- return dev_err_probe(dev, err, "error registering SPI controller\n");
-
- return 0;
+ return amd_spi_probe_common(dev, host);
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id spi_acpi_match[] = {
{ "AMDI0061", AMD_SPI_V1 },
{ "AMDI0062", AMD_SPI_V2 },
+ { "AMDI0063", AMD_HID2_SPI },
{},
};
MODULE_DEVICE_TABLE(acpi, spi_acpi_match);
diff --git a/drivers/spi/spi-amd.h b/drivers/spi/spi-amd.h
new file mode 100644
index 000000000000..5f39ce7b5587
--- /dev/null
+++ b/drivers/spi/spi-amd.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AMD SPI controller driver common stuff
+ *
+ * Copyright (c) 2025, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Krishnamoorthi M <krishnamoorthi.m@amd.com>
+ */
+
+#ifndef SPI_AMD_H
+#define SPI_AMD_H
+
+/**
+ * enum amd_spi_versions - SPI controller versions
+ * @AMD_SPI_V1: AMDI0061 hardware version
+ * @AMD_SPI_V2: AMDI0062 hardware version
+ * @AMD_HID2_SPI: AMDI0063 hardware version
+ */
+enum amd_spi_versions {
+ AMD_SPI_V1 = 1,
+ AMD_SPI_V2,
+ AMD_HID2_SPI,
+};
+
+/**
+ * struct amd_spi - SPI driver instance
+ * @io_remap_addr: Start address of the SPI controller registers
+ * @phy_dma_buf: Physical address of DMA buffer
+ * @dma_virt_addr: Virtual address of DMA buffer
+ * @version: SPI controller hardware version
+ * @speed_hz: Device frequency
+ */
+struct amd_spi {
+ void __iomem *io_remap_addr;
+ dma_addr_t phy_dma_buf;
+ void *dma_virt_addr;
+ enum amd_spi_versions version;
+ unsigned int speed_hz;
+};
+
+int amd_spi_probe_common(struct device *dev, struct spi_controller *host);
+
+#endif /* SPI_AMD_H */
diff --git a/drivers/spi/spi-amlogic-spifc-a1.c b/drivers/spi/spi-amlogic-spifc-a1.c
index 3c4224c38399..eb503790017b 100644
--- a/drivers/spi/spi-amlogic-spifc-a1.c
+++ b/drivers/spi/spi-amlogic-spifc-a1.c
@@ -72,7 +72,7 @@
#define SPIFC_A1_USER_DBUF_ADDR_REG 0x248
-#define SPIFC_A1_BUFFER_SIZE 512
+#define SPIFC_A1_BUFFER_SIZE 512U
#define SPIFC_A1_MAX_HZ 200000000
#define SPIFC_A1_MIN_HZ 1000000
@@ -107,6 +107,7 @@ struct amlogic_spifc_a1 {
struct clk *clk;
struct device *dev;
void __iomem *base;
+ u32 curr_speed_hz;
};
static int amlogic_spifc_a1_request(struct amlogic_spifc_a1 *spifc, bool read)
@@ -235,66 +236,68 @@ static int amlogic_spifc_a1_write(struct amlogic_spifc_a1 *spifc,
return amlogic_spifc_a1_request(spifc, false);
}
-static int amlogic_spifc_a1_exec_op(struct spi_mem *mem,
- const struct spi_mem_op *op)
+static int amlogic_spifc_a1_set_freq(struct amlogic_spifc_a1 *spifc, u32 freq)
{
- struct amlogic_spifc_a1 *spifc =
- spi_controller_get_devdata(mem->spi->controller);
- size_t off, nbytes = op->data.nbytes;
- u32 cmd_cfg, addr_cfg, dummy_cfg, dmode;
int ret;
- amlogic_spifc_a1_user_init(spifc);
-
- cmd_cfg = SPIFC_A1_USER_CMD(op);
- amlogic_spifc_a1_set_cmd(spifc, cmd_cfg);
+ if (freq == spifc->curr_speed_hz)
+ return 0;
- if (op->addr.nbytes) {
- addr_cfg = SPIFC_A1_USER_ADDR(op);
- amlogic_spifc_a1_set_addr(spifc, op->addr.val, addr_cfg);
- }
+ ret = clk_set_rate(spifc->clk, freq);
+ if (ret)
+ return ret;
- if (op->dummy.nbytes) {
- dummy_cfg = SPIFC_A1_USER_DUMMY(op);
- amlogic_spifc_a1_set_dummy(spifc, dummy_cfg);
- }
+ spifc->curr_speed_hz = freq;
+ return 0;
+}
- if (!op->data.nbytes)
- return amlogic_spifc_a1_request(spifc, false);
+static int amlogic_spifc_a1_exec_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct amlogic_spifc_a1 *spifc =
+ spi_controller_get_devdata(mem->spi->controller);
+ size_t data_size = op->data.nbytes;
+ int ret;
- dmode = ilog2(op->data.buswidth);
- off = 0;
+ ret = amlogic_spifc_a1_set_freq(spifc, op->max_freq);
+ if (ret)
+ return ret;
- do {
- size_t block_size = min_t(size_t, nbytes, SPIFC_A1_BUFFER_SIZE);
+ amlogic_spifc_a1_user_init(spifc);
+ amlogic_spifc_a1_set_cmd(spifc, SPIFC_A1_USER_CMD(op));
- amlogic_spifc_a1_set_cmd(spifc, cmd_cfg);
+ if (op->addr.nbytes)
+ amlogic_spifc_a1_set_addr(spifc, op->addr.val,
+ SPIFC_A1_USER_ADDR(op));
- if (op->addr.nbytes)
- amlogic_spifc_a1_set_addr(spifc, op->addr.val + off,
- addr_cfg);
+ if (op->dummy.nbytes)
+ amlogic_spifc_a1_set_dummy(spifc, SPIFC_A1_USER_DUMMY(op));
- if (op->dummy.nbytes)
- amlogic_spifc_a1_set_dummy(spifc, dummy_cfg);
+ if (data_size) {
+ u32 mode = ilog2(op->data.buswidth);
writel(0, spifc->base + SPIFC_A1_USER_DBUF_ADDR_REG);
if (op->data.dir == SPI_MEM_DATA_IN)
- ret = amlogic_spifc_a1_read(spifc,
- op->data.buf.in + off,
- block_size, dmode);
+ ret = amlogic_spifc_a1_read(spifc, op->data.buf.in,
+ data_size, mode);
else
- ret = amlogic_spifc_a1_write(spifc,
- op->data.buf.out + off,
- block_size, dmode);
-
- nbytes -= block_size;
- off += block_size;
- } while (nbytes != 0 && !ret);
+ ret = amlogic_spifc_a1_write(spifc, op->data.buf.out,
+ data_size, mode);
+ } else {
+ ret = amlogic_spifc_a1_request(spifc, false);
+ }
return ret;
}
+static int amlogic_spifc_a1_adjust_op_size(struct spi_mem *mem,
+ struct spi_mem_op *op)
+{
+ op->data.nbytes = min(op->data.nbytes, SPIFC_A1_BUFFER_SIZE);
+ return 0;
+}
+
static void amlogic_spifc_a1_hw_init(struct amlogic_spifc_a1 *spifc)
{
u32 regv;
@@ -314,6 +317,11 @@ static void amlogic_spifc_a1_hw_init(struct amlogic_spifc_a1 *spifc)
static const struct spi_controller_mem_ops amlogic_spifc_a1_mem_ops = {
.exec_op = amlogic_spifc_a1_exec_op,
+ .adjust_op_size = amlogic_spifc_a1_adjust_op_size,
+};
+
+static const struct spi_controller_mem_caps amlogic_spifc_a1_mem_caps = {
+ .per_op_freq = true,
};
static int amlogic_spifc_a1_probe(struct platform_device *pdev)
@@ -322,7 +330,7 @@ static int amlogic_spifc_a1_probe(struct platform_device *pdev)
struct amlogic_spifc_a1 *spifc;
int ret;
- ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*spifc));
+ ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*spifc));
if (!ctrl)
return -ENOMEM;
@@ -345,13 +353,16 @@ static int amlogic_spifc_a1_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(spifc->dev, 500);
pm_runtime_use_autosuspend(spifc->dev);
- devm_pm_runtime_enable(spifc->dev);
+ ret = devm_pm_runtime_enable(spifc->dev);
+ if (ret)
+ return ret;
ctrl->num_chipselect = 1;
ctrl->dev.of_node = pdev->dev.of_node;
ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
ctrl->auto_runtime_pm = true;
ctrl->mem_ops = &amlogic_spifc_a1_mem_ops;
+ ctrl->mem_caps = &amlogic_spifc_a1_mem_caps;
ctrl->min_speed_hz = SPIFC_A1_MIN_HZ;
ctrl->max_speed_hz = SPIFC_A1_MAX_HZ;
ctrl->mode_bits = (SPI_RX_DUAL | SPI_TX_DUAL |
diff --git a/drivers/spi/spi-amlogic-spifc-a4.c b/drivers/spi/spi-amlogic-spifc-a4.c
new file mode 100644
index 000000000000..35a7c4965e11
--- /dev/null
+++ b/drivers/spi/spi-amlogic-spifc-a4.c
@@ -0,0 +1,1222 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2025 Amlogic, Inc. All rights reserved
+ *
+ * Driver for the SPI Mode of Amlogic Flash Controller
+ * Authors:
+ * Liang Yang <liang.yang@amlogic.com>
+ * Feng Chen <feng.chen@amlogic.com>
+ * Xianwei Zhao <xianwei.zhao@amlogic.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/dma-mapping.h>
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/mtd/spinand.h>
+#include <linux/spi/spi-mem.h>
+
+#define SFC_CMD 0x00
+#define SFC_CFG 0x04
+#define SFC_DADR 0x08
+#define SFC_IADR 0x0c
+#define SFC_BUF 0x10
+#define SFC_INFO 0x14
+#define SFC_DC 0x18
+#define SFC_ADR 0x1c
+#define SFC_DL 0x20
+#define SFC_DH 0x24
+#define SFC_CADR 0x28
+#define SFC_SADR 0x2c
+#define SFC_RX_IDX 0x34
+#define SFC_RX_DAT 0x38
+#define SFC_SPI_CFG 0x40
+
+/* settings in SFC_CMD */
+
+/* 4 bits support 4 chip select, high false, low select but spi support 2*/
+#define CHIP_SELECT_MASK GENMASK(13, 10)
+#define CS_NONE 0xf
+#define CS_0 0xe
+#define CS_1 0xd
+
+#define CLE (0x5 << 14)
+#define ALE (0x6 << 14)
+#define DWR (0x4 << 14)
+#define DRD (0x8 << 14)
+#define DUMMY (0xb << 14)
+#define IDLE (0xc << 14)
+#define IDLE_CYCLE_MASK GENMASK(9, 0)
+#define EXT_CYCLE_MASK GENMASK(9, 0)
+
+#define OP_M2N ((0 << 17) | (2 << 20))
+#define OP_N2M ((1 << 17) | (2 << 20))
+#define OP_STS ((3 << 17) | (2 << 20))
+#define OP_ADL ((0 << 16) | (3 << 20))
+#define OP_ADH ((1 << 16) | (3 << 20))
+#define OP_AIL ((2 << 16) | (3 << 20))
+#define OP_AIH ((3 << 16) | (3 << 20))
+#define OP_ASL ((4 << 16) | (3 << 20))
+#define OP_ASH ((5 << 16) | (3 << 20))
+#define OP_SEED ((8 << 16) | (3 << 20))
+#define SEED_MASK GENMASK(14, 0)
+#define ENABLE_RANDOM BIT(19)
+
+#define CMD_COMMAND(cs_sel, cmd) (CLE | ((cs_sel) << 10) | (cmd))
+#define CMD_ADDR(cs_sel, addr) (ALE | ((cs_sel) << 10) | (addr))
+#define CMD_DUMMY(cs_sel, cyc) (DUMMY | ((cs_sel) << 10) | ((cyc) & EXT_CYCLE_MASK))
+#define CMD_IDLE(cs_sel, cyc) (IDLE | ((cs_sel) << 10) | ((cyc) & IDLE_CYCLE_MASK))
+#define CMD_MEM2NAND(bch, pages) (OP_M2N | ((bch) << 14) | (pages))
+#define CMD_NAND2MEM(bch, pages) (OP_N2M | ((bch) << 14) | (pages))
+#define CMD_DATA_ADDRL(addr) (OP_ADL | ((addr) & 0xffff))
+#define CMD_DATA_ADDRH(addr) (OP_ADH | (((addr) >> 16) & 0xffff))
+#define CMD_INFO_ADDRL(addr) (OP_AIL | ((addr) & 0xffff))
+#define CMD_INFO_ADDRH(addr) (OP_AIH | (((addr) >> 16) & 0xffff))
+#define CMD_SEED(seed) (OP_SEED | ((seed) & SEED_MASK))
+
+#define GET_CMD_SIZE(x) (((x) >> 22) & GENMASK(4, 0))
+
+#define DEFAULT_PULLUP_CYCLE 2
+#define CS_SETUP_CYCLE 1
+#define CS_HOLD_CYCLE 2
+#define DEFAULT_BUS_CYCLE 4
+
+#define RAW_SIZE GENMASK(13, 0)
+#define RAW_SIZE_BW 14
+
+#define DMA_ADDR_ALIGN 8
+
+/* Bit fields in SFC_SPI_CFG */
+#define SPI_MODE_EN BIT(31)
+#define RAW_EXT_SIZE GENMASK(29, 18)
+#define ADDR_LANE GENMASK(17, 16)
+#define CPOL BIT(15)
+#define CPHA BIT(14)
+#define EN_HOLD BIT(13)
+#define EN_WP BIT(12)
+#define TXADJ GENMASK(11, 8)
+#define RXADJ GENMASK(7, 4)
+#define CMD_LANE GENMASK(3, 2)
+#define DATA_LANE GENMASK(1, 0)
+#define LANE_MAX 0x3
+
+/* raw ext size[25:14] + raw size[13:0] */
+#define RAW_MAX_RW_SIZE_MASK GENMASK(25, 0)
+
+/* Ecc fields */
+#define ECC_COMPLETE BIT(31)
+#define ECC_UNCORRECTABLE 0x3f
+#define ECC_ERR_CNT(x) (((x) >> 24) & 0x3f)
+#define ECC_ZERO_CNT(x) (((x) >> 16) & 0x3f)
+
+#define ECC_BCH8_512 1
+#define ECC_BCH8_1K 2
+#define ECC_BCH8_PARITY_BYTES 14
+#define ECC_BCH8_USER_BYTES 2
+#define ECC_BCH8_INFO_BYTES (ECC_BCH8_USER_BYTES + ECC_BCH8_PARITY_BYTES)
+#define ECC_BCH8_STRENGTH 8
+#define ECC_BCH8_DEFAULT_STEP 512
+#define ECC_DEFAULT_BCH_MODE ECC_BCH8_512
+#define ECC_PER_INFO_BYTE 8
+#define ECC_PATTERN 0x5a
+#define ECC_BCH_MAX_SECT_SIZE 63
+/* soft flags for sfc */
+#define SFC_HWECC BIT(0)
+#define SFC_DATA_RANDOM BIT(1)
+#define SFC_DATA_ONLY BIT(2)
+#define SFC_OOB_ONLY BIT(3)
+#define SFC_DATA_OOB BIT(4)
+#define SFC_AUTO_OOB BIT(5)
+#define SFC_RAW_RW BIT(6)
+#define SFC_XFER_MDOE_MASK GENMASK(6, 2)
+
+#define SFC_DATABUF_SIZE 8192
+#define SFC_INFOBUF_SIZE 256
+#define SFC_BUF_SIZE (SFC_DATABUF_SIZE + SFC_INFOBUF_SIZE)
+
+/* !!! PCB and SPI-NAND chip limitations */
+#define SFC_MAX_FREQUENCY (250 * 1000 * 1000)
+#define SFC_MIN_FREQUENCY (4 * 1000 * 1000)
+#define SFC_BUS_DEFAULT_CLK 40000000
+#define SFC_MAX_CS_NUM 2
+
+/* SPI-FLASH R/W operation cmd */
+#define SPIFLASH_RD_OCTALIO 0xcb
+#define SPIFLASH_RD_OCTAL 0x8b
+#define SPIFLASH_RD_QUADIO 0xeb
+#define SPIFLASH_RD_QUAD 0x6b
+#define SPIFLASH_RD_DUALIO 0xbb
+#define SPIFLASH_RD_DUAL 0x3b
+#define SPIFLASH_RD_FAST 0x0b
+#define SPIFLASH_RD 0x03
+#define SPIFLASH_WR_OCTALIO 0xC2
+#define SPIFLASH_WR_OCTAL 0x82
+#define SPIFLASH_WR_QUAD 0x32
+#define SPIFLASH_WR 0x02
+#define SPIFLASH_UP_QUAD 0x34
+#define SPIFLASH_UP 0x84
+
+struct aml_sfc_ecc_cfg {
+ u32 stepsize;
+ u32 nsteps;
+ u32 strength;
+ u32 oobsize;
+ u32 bch;
+};
+
+struct aml_ecc_stats {
+ u32 corrected;
+ u32 bitflips;
+ u32 failed;
+};
+
+struct aml_sfc_caps {
+ struct aml_sfc_ecc_cfg *ecc_caps;
+ u32 num_ecc_caps;
+};
+
+struct aml_sfc {
+ struct device *dev;
+ struct clk *gate_clk;
+ struct clk *core_clk;
+ struct spi_controller *ctrl;
+ struct regmap *regmap_base;
+ const struct aml_sfc_caps *caps;
+ struct nand_ecc_engine ecc_eng;
+ struct aml_ecc_stats ecc_stats;
+ dma_addr_t daddr;
+ dma_addr_t iaddr;
+ u32 info_bytes;
+ u32 bus_rate;
+ u32 flags;
+ u32 rx_adj;
+ u32 cs_sel;
+ u8 *data_buf;
+ __le64 *info_buf;
+ u8 *priv;
+};
+
+#define AML_ECC_DATA(sz, s, b) { .stepsize = (sz), .strength = (s), .bch = (b) }
+
+static struct aml_sfc_ecc_cfg aml_a113l2_ecc_caps[] = {
+ AML_ECC_DATA(512, 8, ECC_BCH8_512),
+ AML_ECC_DATA(1024, 8, ECC_BCH8_1K),
+};
+
+static const struct aml_sfc_caps aml_a113l2_sfc_caps = {
+ .ecc_caps = aml_a113l2_ecc_caps,
+ .num_ecc_caps = ARRAY_SIZE(aml_a113l2_ecc_caps)
+};
+
+static struct aml_sfc *nand_to_aml_sfc(struct nand_device *nand)
+{
+ struct nand_ecc_engine *eng = nand->ecc.engine;
+
+ return container_of(eng, struct aml_sfc, ecc_eng);
+}
+
+static inline void *aml_sfc_to_ecc_ctx(struct aml_sfc *sfc)
+{
+ return sfc->priv;
+}
+
+static int aml_sfc_wait_cmd_finish(struct aml_sfc *sfc, u64 timeout_ms)
+{
+ u32 cmd_size = 0;
+ int ret;
+
+ /*
+ * The SPINAND flash controller employs a two-stage pipeline:
+ * 1) command prefetch; 2) command execution.
+ *
+ * All commands are stored in the FIFO, with one prefetched for execution.
+ *
+ * There are cases where the FIFO is detected as empty, yet a command may
+ * still be in execution and a prefetched command pending execution.
+ *
+ * So, send two idle commands to ensure all previous commands have
+ * been executed.
+ */
+ regmap_write(sfc->regmap_base, SFC_CMD, CMD_IDLE(sfc->cs_sel, 0));
+ regmap_write(sfc->regmap_base, SFC_CMD, CMD_IDLE(sfc->cs_sel, 0));
+
+ /* Wait for the FIFO to empty. */
+ ret = regmap_read_poll_timeout(sfc->regmap_base, SFC_CMD, cmd_size,
+ !GET_CMD_SIZE(cmd_size),
+ 10, timeout_ms * 1000);
+ if (ret)
+ dev_err(sfc->dev, "wait for empty CMD FIFO time out\n");
+
+ return ret;
+}
+
+static int aml_sfc_pre_transfer(struct aml_sfc *sfc, u32 idle_cycle, u32 cs2clk_cycle)
+{
+ int ret;
+
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, CMD_IDLE(CS_NONE, idle_cycle));
+ if (ret)
+ return ret;
+
+ return regmap_write(sfc->regmap_base, SFC_CMD, CMD_IDLE(sfc->cs_sel, cs2clk_cycle));
+}
+
+static int aml_sfc_end_transfer(struct aml_sfc *sfc, u32 clk2cs_cycle)
+{
+ int ret;
+
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, CMD_IDLE(sfc->cs_sel, clk2cs_cycle));
+ if (ret)
+ return ret;
+
+ return aml_sfc_wait_cmd_finish(sfc, 0);
+}
+
+static int aml_sfc_set_bus_width(struct aml_sfc *sfc, u8 buswidth, u32 mask)
+{
+ int i;
+ u32 conf = 0;
+
+ for (i = 0; i <= LANE_MAX; i++) {
+ if (buswidth == 1 << i) {
+ conf = i << __ffs(mask);
+ return regmap_update_bits(sfc->regmap_base, SFC_SPI_CFG,
+ mask, conf);
+ }
+ }
+
+ return 0;
+}
+
+static int aml_sfc_send_cmd(struct aml_sfc *sfc, const struct spi_mem_op *op)
+{
+ int i, ret;
+ u8 val;
+
+ ret = aml_sfc_set_bus_width(sfc, op->cmd.buswidth, CMD_LANE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < op->cmd.nbytes; i++) {
+ val = (op->cmd.opcode >> ((op->cmd.nbytes - i - 1) * 8)) & 0xff;
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, CMD_COMMAND(sfc->cs_sel, val));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int aml_sfc_send_addr(struct aml_sfc *sfc, const struct spi_mem_op *op)
+{
+ int i, ret;
+ u8 val;
+
+ ret = aml_sfc_set_bus_width(sfc, op->addr.buswidth, ADDR_LANE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < op->addr.nbytes; i++) {
+ val = (op->addr.val >> ((op->addr.nbytes - i - 1) * 8)) & 0xff;
+
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, CMD_ADDR(sfc->cs_sel, val));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static bool aml_sfc_is_xio_op(const struct spi_mem_op *op)
+{
+ switch (op->cmd.opcode) {
+ case SPIFLASH_RD_OCTALIO:
+ case SPIFLASH_RD_QUADIO:
+ case SPIFLASH_RD_DUALIO:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static int aml_sfc_send_cmd_addr_dummy(struct aml_sfc *sfc, const struct spi_mem_op *op)
+{
+ u32 dummy_cycle, cmd;
+ int ret;
+
+ ret = aml_sfc_send_cmd(sfc, op);
+ if (ret)
+ return ret;
+
+ ret = aml_sfc_send_addr(sfc, op);
+ if (ret)
+ return ret;
+
+ if (op->dummy.nbytes) {
+ /* Dummy buswidth configuration is not supported */
+ if (aml_sfc_is_xio_op(op))
+ dummy_cycle = op->dummy.nbytes * 8 / op->data.buswidth;
+ else
+ dummy_cycle = op->dummy.nbytes * 8;
+ cmd = CMD_DUMMY(sfc->cs_sel, dummy_cycle - 1);
+ return regmap_write(sfc->regmap_base, SFC_CMD, cmd);
+ }
+
+ return 0;
+}
+
+static bool aml_sfc_is_snand_hwecc_page_op(struct aml_sfc *sfc, const struct spi_mem_op *op)
+{
+ switch (op->cmd.opcode) {
+ /* SPINAND read from cache cmd */
+ case SPIFLASH_RD_QUADIO:
+ case SPIFLASH_RD_QUAD:
+ case SPIFLASH_RD_DUALIO:
+ case SPIFLASH_RD_DUAL:
+ case SPIFLASH_RD_FAST:
+ case SPIFLASH_RD:
+ /* SPINAND write to cache cmd */
+ case SPIFLASH_WR_QUAD:
+ case SPIFLASH_WR:
+ case SPIFLASH_UP_QUAD:
+ case SPIFLASH_UP:
+ if (sfc->flags & SFC_HWECC)
+ return true;
+ else
+ return false;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static int aml_sfc_dma_buffer_setup(struct aml_sfc *sfc, void *databuf,
+ int datalen, void *infobuf, int infolen,
+ enum dma_data_direction dir)
+{
+ u32 cmd = 0;
+ int ret;
+
+ sfc->daddr = dma_map_single(sfc->dev, databuf, datalen, dir);
+ ret = dma_mapping_error(sfc->dev, sfc->daddr);
+ if (ret) {
+ dev_err(sfc->dev, "DMA mapping error\n");
+ goto out_map_data;
+ }
+
+ cmd = CMD_DATA_ADDRL(sfc->daddr);
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, cmd);
+ if (ret)
+ goto out_map_data;
+
+ cmd = CMD_DATA_ADDRH(sfc->daddr);
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, cmd);
+ if (ret)
+ goto out_map_data;
+
+ if (infobuf) {
+ sfc->iaddr = dma_map_single(sfc->dev, infobuf, infolen, dir);
+ ret = dma_mapping_error(sfc->dev, sfc->iaddr);
+ if (ret) {
+ dev_err(sfc->dev, "DMA mapping error\n");
+ dma_unmap_single(sfc->dev, sfc->daddr, datalen, dir);
+ goto out_map_data;
+ }
+
+ sfc->info_bytes = infolen;
+ cmd = CMD_INFO_ADDRL(sfc->iaddr);
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, cmd);
+ if (ret)
+ goto out_map_info;
+
+ cmd = CMD_INFO_ADDRH(sfc->iaddr);
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, cmd);
+ if (ret)
+ goto out_map_info;
+ }
+
+ return 0;
+
+out_map_info:
+ dma_unmap_single(sfc->dev, sfc->iaddr, datalen, dir);
+out_map_data:
+ dma_unmap_single(sfc->dev, sfc->daddr, datalen, dir);
+
+ return ret;
+}
+
+static void aml_sfc_dma_buffer_release(struct aml_sfc *sfc,
+ int datalen, int infolen,
+ enum dma_data_direction dir)
+{
+ dma_unmap_single(sfc->dev, sfc->daddr, datalen, dir);
+ if (infolen) {
+ dma_unmap_single(sfc->dev, sfc->iaddr, infolen, dir);
+ sfc->info_bytes = 0;
+ }
+}
+
+static bool aml_sfc_dma_buffer_is_safe(const void *buffer)
+{
+ if ((uintptr_t)buffer % DMA_ADDR_ALIGN)
+ return false;
+
+ if (virt_addr_valid(buffer))
+ return true;
+
+ return false;
+}
+
+static void *aml_get_dma_safe_input_buf(const struct spi_mem_op *op)
+{
+ if (aml_sfc_dma_buffer_is_safe(op->data.buf.in))
+ return op->data.buf.in;
+
+ return kzalloc(op->data.nbytes, GFP_KERNEL);
+}
+
+static void aml_sfc_put_dma_safe_input_buf(const struct spi_mem_op *op, void *buf)
+{
+ if (WARN_ON(op->data.dir != SPI_MEM_DATA_IN) || WARN_ON(!buf))
+ return;
+
+ if (buf == op->data.buf.in)
+ return;
+
+ memcpy(op->data.buf.in, buf, op->data.nbytes);
+ kfree(buf);
+}
+
+static void *aml_sfc_get_dma_safe_output_buf(const struct spi_mem_op *op)
+{
+ if (aml_sfc_dma_buffer_is_safe(op->data.buf.out))
+ return (void *)op->data.buf.out;
+
+ return kmemdup(op->data.buf.out, op->data.nbytes, GFP_KERNEL);
+}
+
+static void aml_sfc_put_dma_safe_output_buf(const struct spi_mem_op *op, const void *buf)
+{
+ if (WARN_ON(op->data.dir != SPI_MEM_DATA_OUT) || WARN_ON(!buf))
+ return;
+
+ if (buf != op->data.buf.out)
+ kfree(buf);
+}
+
+static u64 aml_sfc_cal_timeout_cycle(struct aml_sfc *sfc, const struct spi_mem_op *op)
+{
+ u64 ms;
+
+ /* For each byte we wait for (8 cycles / buswidth) of the SPI clock. */
+ ms = 8 * MSEC_PER_SEC * op->data.nbytes / op->data.buswidth;
+ do_div(ms, sfc->bus_rate / DEFAULT_BUS_CYCLE);
+
+ /*
+ * Double the value and add a 200 ms tolerance to compensate for
+ * the impact of specific CS hold time, CS setup time sequences,
+ * controller burst gaps, and other related timing variations.
+ */
+ ms += ms + 200;
+
+ if (ms > UINT_MAX)
+ ms = UINT_MAX;
+
+ return ms;
+}
+
+static void aml_sfc_check_ecc_pages_valid(struct aml_sfc *sfc, bool raw)
+{
+ struct aml_sfc_ecc_cfg *ecc_cfg;
+ __le64 *info;
+ int ret;
+
+ info = sfc->info_buf;
+ ecc_cfg = aml_sfc_to_ecc_ctx(sfc);
+ info += raw ? 0 : ecc_cfg->nsteps - 1;
+
+ do {
+ usleep_range(10, 15);
+ /* info is updated by nfc dma engine*/
+ smp_rmb();
+ dma_sync_single_for_cpu(sfc->dev, sfc->iaddr, sfc->info_bytes,
+ DMA_FROM_DEVICE);
+ ret = le64_to_cpu(*info) & ECC_COMPLETE;
+ } while (!ret);
+}
+
+static int aml_sfc_raw_io_op(struct aml_sfc *sfc, const struct spi_mem_op *op)
+{
+ void *buf = NULL;
+ int ret;
+ bool is_datain = false;
+ u32 cmd = 0, conf;
+ u64 timeout_ms;
+
+ if (!op->data.nbytes)
+ goto end_xfer;
+
+ conf = (op->data.nbytes >> RAW_SIZE_BW) << __ffs(RAW_EXT_SIZE);
+ ret = regmap_update_bits(sfc->regmap_base, SFC_SPI_CFG, RAW_EXT_SIZE, conf);
+ if (ret)
+ goto err_out;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ is_datain = true;
+
+ buf = aml_get_dma_safe_input_buf(op);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ cmd |= CMD_NAND2MEM(0, (op->data.nbytes & RAW_SIZE));
+ } else if (op->data.dir == SPI_MEM_DATA_OUT) {
+ is_datain = false;
+
+ buf = aml_sfc_get_dma_safe_output_buf(op);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ cmd |= CMD_MEM2NAND(0, (op->data.nbytes & RAW_SIZE));
+ } else {
+ goto end_xfer;
+ }
+
+ ret = aml_sfc_dma_buffer_setup(sfc, buf, op->data.nbytes,
+ is_datain ? sfc->info_buf : NULL,
+ is_datain ? ECC_PER_INFO_BYTE : 0,
+ is_datain ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+ if (ret)
+ goto err_out;
+
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, cmd);
+ if (ret)
+ goto err_out;
+
+ timeout_ms = aml_sfc_cal_timeout_cycle(sfc, op);
+ ret = aml_sfc_wait_cmd_finish(sfc, timeout_ms);
+ if (ret)
+ goto err_out;
+
+ if (is_datain)
+ aml_sfc_check_ecc_pages_valid(sfc, 1);
+
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ aml_sfc_put_dma_safe_input_buf(op, buf);
+ else if (op->data.dir == SPI_MEM_DATA_OUT)
+ aml_sfc_put_dma_safe_output_buf(op, buf);
+
+ aml_sfc_dma_buffer_release(sfc, op->data.nbytes,
+ is_datain ? ECC_PER_INFO_BYTE : 0,
+ is_datain ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+
+end_xfer:
+ return aml_sfc_end_transfer(sfc, CS_HOLD_CYCLE);
+
+err_out:
+ return ret;
+}
+
+static void aml_sfc_set_user_byte(struct aml_sfc *sfc, __le64 *info_buf, u8 *oob_buf, bool auto_oob)
+{
+ struct aml_sfc_ecc_cfg *ecc_cfg;
+ __le64 *info;
+ int i, count, step_size;
+
+ ecc_cfg = aml_sfc_to_ecc_ctx(sfc);
+
+ step_size = auto_oob ? ECC_BCH8_INFO_BYTES : ECC_BCH8_USER_BYTES;
+
+ for (i = 0, count = 0; i < ecc_cfg->nsteps; i++, count += step_size) {
+ info = &info_buf[i];
+ *info &= cpu_to_le64(~0xffff);
+ *info |= cpu_to_le64((oob_buf[count + 1] << 8) + oob_buf[count]);
+ }
+}
+
+static void aml_sfc_get_user_byte(struct aml_sfc *sfc, __le64 *info_buf, u8 *oob_buf)
+{
+ struct aml_sfc_ecc_cfg *ecc_cfg;
+ __le64 *info;
+ int i, count;
+
+ ecc_cfg = aml_sfc_to_ecc_ctx(sfc);
+
+ for (i = 0, count = 0; i < ecc_cfg->nsteps; i++, count += ECC_BCH8_INFO_BYTES) {
+ info = &info_buf[i];
+ oob_buf[count] = le64_to_cpu(*info);
+ oob_buf[count + 1] = le64_to_cpu(*info) >> 8;
+ }
+}
+
+static int aml_sfc_check_hwecc_status(struct aml_sfc *sfc, __le64 *info_buf)
+{
+ struct aml_sfc_ecc_cfg *ecc_cfg;
+ __le64 *info;
+ u32 i, max_bitflips = 0, per_sector_bitflips = 0;
+
+ ecc_cfg = aml_sfc_to_ecc_ctx(sfc);
+
+ sfc->ecc_stats.failed = 0;
+ sfc->ecc_stats.bitflips = 0;
+ sfc->ecc_stats.corrected = 0;
+
+ for (i = 0, info = info_buf; i < ecc_cfg->nsteps; i++, info++) {
+ if (ECC_ERR_CNT(le64_to_cpu(*info)) != ECC_UNCORRECTABLE) {
+ per_sector_bitflips = ECC_ERR_CNT(le64_to_cpu(*info));
+ max_bitflips = max_t(u32, max_bitflips, per_sector_bitflips);
+ sfc->ecc_stats.corrected += per_sector_bitflips;
+ continue;
+ }
+
+ return -EBADMSG;
+ }
+
+ return max_bitflips;
+}
+
+static int aml_sfc_read_page_hwecc(struct aml_sfc *sfc, const struct spi_mem_op *op)
+{
+ struct aml_sfc_ecc_cfg *ecc_cfg;
+ int ret, data_len, info_len;
+ u32 page_size, cmd = 0;
+ u64 timeout_ms;
+
+ ecc_cfg = aml_sfc_to_ecc_ctx(sfc);
+
+ page_size = ecc_cfg->stepsize * ecc_cfg->nsteps;
+ data_len = page_size + ecc_cfg->oobsize;
+ info_len = ecc_cfg->nsteps * ECC_PER_INFO_BYTE;
+
+ ret = aml_sfc_dma_buffer_setup(sfc, sfc->data_buf, data_len,
+ sfc->info_buf, info_len, DMA_FROM_DEVICE);
+ if (ret)
+ goto err_out;
+
+ cmd |= CMD_NAND2MEM(ecc_cfg->bch, ecc_cfg->nsteps);
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, cmd);
+ if (ret)
+ goto err_out;
+
+ timeout_ms = aml_sfc_cal_timeout_cycle(sfc, op);
+ ret = aml_sfc_wait_cmd_finish(sfc, timeout_ms);
+ if (ret)
+ goto err_out;
+
+ aml_sfc_check_ecc_pages_valid(sfc, 0);
+ aml_sfc_dma_buffer_release(sfc, data_len, info_len, DMA_FROM_DEVICE);
+
+ /* check ecc status here */
+ ret = aml_sfc_check_hwecc_status(sfc, sfc->info_buf);
+ if (ret < 0)
+ sfc->ecc_stats.failed++;
+ else
+ sfc->ecc_stats.bitflips = ret;
+
+ if (sfc->flags & SFC_DATA_ONLY) {
+ memcpy(op->data.buf.in, sfc->data_buf, page_size);
+ } else if (sfc->flags & SFC_OOB_ONLY) {
+ aml_sfc_get_user_byte(sfc, sfc->info_buf, op->data.buf.in);
+ } else if (sfc->flags & SFC_DATA_OOB) {
+ memcpy(op->data.buf.in, sfc->data_buf, page_size);
+ aml_sfc_get_user_byte(sfc, sfc->info_buf, op->data.buf.in + page_size);
+ }
+
+ return aml_sfc_end_transfer(sfc, CS_HOLD_CYCLE);
+
+err_out:
+ return ret;
+}
+
+static int aml_sfc_write_page_hwecc(struct aml_sfc *sfc, const struct spi_mem_op *op)
+{
+ struct aml_sfc_ecc_cfg *ecc_cfg;
+ int ret, data_len, info_len;
+ u32 page_size, cmd = 0;
+ u64 timeout_ms;
+
+ ecc_cfg = aml_sfc_to_ecc_ctx(sfc);
+
+ page_size = ecc_cfg->stepsize * ecc_cfg->nsteps;
+ data_len = page_size + ecc_cfg->oobsize;
+ info_len = ecc_cfg->nsteps * ECC_PER_INFO_BYTE;
+
+ memset(sfc->info_buf, ECC_PATTERN, ecc_cfg->oobsize);
+ memcpy(sfc->data_buf, op->data.buf.out, page_size);
+
+ if (!(sfc->flags & SFC_DATA_ONLY)) {
+ if (sfc->flags & SFC_AUTO_OOB)
+ aml_sfc_set_user_byte(sfc, sfc->info_buf,
+ (u8 *)op->data.buf.out + page_size, 1);
+ else
+ aml_sfc_set_user_byte(sfc, sfc->info_buf,
+ (u8 *)op->data.buf.out + page_size, 0);
+ }
+
+ ret = aml_sfc_dma_buffer_setup(sfc, sfc->data_buf, data_len,
+ sfc->info_buf, info_len, DMA_TO_DEVICE);
+ if (ret)
+ goto err_out;
+
+ cmd |= CMD_MEM2NAND(ecc_cfg->bch, ecc_cfg->nsteps);
+ ret = regmap_write(sfc->regmap_base, SFC_CMD, cmd);
+ if (ret)
+ goto err_out;
+
+ timeout_ms = aml_sfc_cal_timeout_cycle(sfc, op);
+
+ ret = aml_sfc_wait_cmd_finish(sfc, timeout_ms);
+ if (ret)
+ goto err_out;
+
+ aml_sfc_dma_buffer_release(sfc, data_len, info_len, DMA_TO_DEVICE);
+
+ return aml_sfc_end_transfer(sfc, CS_HOLD_CYCLE);
+
+err_out:
+ return ret;
+}
+
+static int aml_sfc_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ struct aml_sfc *sfc;
+ struct spi_device *spi;
+ struct aml_sfc_ecc_cfg *ecc_cfg;
+ int ret;
+
+ sfc = spi_controller_get_devdata(mem->spi->controller);
+ ecc_cfg = aml_sfc_to_ecc_ctx(sfc);
+ spi = mem->spi;
+ sfc->cs_sel = spi->chip_select[0] ? CS_1 : CS_0;
+
+ dev_dbg(sfc->dev, "cmd:0x%02x - addr:%08llX@%d:%u - dummy:%d:%u - data:%d:%u",
+ op->cmd.opcode, op->addr.val, op->addr.buswidth, op->addr.nbytes,
+ op->dummy.buswidth, op->dummy.nbytes, op->data.buswidth, op->data.nbytes);
+
+ ret = aml_sfc_pre_transfer(sfc, DEFAULT_PULLUP_CYCLE, CS_SETUP_CYCLE);
+ if (ret)
+ return ret;
+
+ ret = aml_sfc_send_cmd_addr_dummy(sfc, op);
+ if (ret)
+ return ret;
+
+ ret = aml_sfc_set_bus_width(sfc, op->data.buswidth, DATA_LANE);
+ if (ret)
+ return ret;
+
+ if (aml_sfc_is_snand_hwecc_page_op(sfc, op) &&
+ ecc_cfg && !(sfc->flags & SFC_RAW_RW)) {
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ return aml_sfc_read_page_hwecc(sfc, op);
+ else
+ return aml_sfc_write_page_hwecc(sfc, op);
+ }
+
+ return aml_sfc_raw_io_op(sfc, op);
+}
+
+static int aml_sfc_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+ struct aml_sfc *sfc;
+ struct aml_sfc_ecc_cfg *ecc_cfg;
+
+ sfc = spi_controller_get_devdata(mem->spi->controller);
+ ecc_cfg = aml_sfc_to_ecc_ctx(sfc);
+
+ if (aml_sfc_is_snand_hwecc_page_op(sfc, op) && ecc_cfg) {
+ if (op->data.nbytes > ecc_cfg->stepsize * ECC_BCH_MAX_SECT_SIZE)
+ return -EOPNOTSUPP;
+ } else if (op->data.nbytes & ~RAW_MAX_RW_SIZE_MASK) {
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static const struct spi_controller_mem_ops aml_sfc_mem_ops = {
+ .adjust_op_size = aml_sfc_adjust_op_size,
+ .exec_op = aml_sfc_exec_op,
+};
+
+static int aml_sfc_layout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+
+ if (section >= nand->ecc.ctx.nsteps)
+ return -ERANGE;
+
+ oobregion->offset = ECC_BCH8_USER_BYTES + (section * ECC_BCH8_INFO_BYTES);
+ oobregion->length = ECC_BCH8_PARITY_BYTES;
+
+ return 0;
+}
+
+static int aml_sfc_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+
+ if (section >= nand->ecc.ctx.nsteps)
+ return -ERANGE;
+
+ oobregion->offset = section * ECC_BCH8_INFO_BYTES;
+ oobregion->length = ECC_BCH8_USER_BYTES;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops aml_sfc_ooblayout_ops = {
+ .ecc = aml_sfc_layout_ecc,
+ .free = aml_sfc_ooblayout_free,
+};
+
+static int aml_spi_settings(struct aml_sfc *sfc, struct spi_device *spi)
+{
+ u32 conf = 0;
+
+ if (spi->mode & SPI_CPHA)
+ conf |= CPHA;
+
+ if (spi->mode & SPI_CPOL)
+ conf |= CPOL;
+
+ conf |= FIELD_PREP(RXADJ, sfc->rx_adj);
+ conf |= EN_HOLD | EN_WP;
+ return regmap_update_bits(sfc->regmap_base, SFC_SPI_CFG,
+ CPHA | CPOL | RXADJ |
+ EN_HOLD | EN_WP, conf);
+}
+
+static int aml_set_spi_clk(struct aml_sfc *sfc, struct spi_device *spi)
+{
+ u32 speed_hz;
+ int ret;
+
+ if (spi->max_speed_hz > SFC_MAX_FREQUENCY)
+ speed_hz = SFC_MAX_FREQUENCY;
+ else if (!spi->max_speed_hz)
+ speed_hz = SFC_BUS_DEFAULT_CLK;
+ else if (spi->max_speed_hz < SFC_MIN_FREQUENCY)
+ speed_hz = SFC_MIN_FREQUENCY;
+ else
+ speed_hz = spi->max_speed_hz;
+
+ /* The SPI clock is generated by dividing the bus clock by four by default. */
+ ret = regmap_write(sfc->regmap_base, SFC_CFG, (DEFAULT_BUS_CYCLE - 1));
+ if (ret) {
+ dev_err(sfc->dev, "failed to set bus cycle\n");
+ return ret;
+ }
+
+ return clk_set_rate(sfc->core_clk, speed_hz * DEFAULT_BUS_CYCLE);
+}
+
+static int aml_sfc_setup(struct spi_device *spi)
+{
+ struct aml_sfc *sfc;
+ int ret;
+
+ sfc = spi_controller_get_devdata(spi->controller);
+ ret = aml_spi_settings(sfc, spi);
+ if (ret)
+ return ret;
+
+ ret = aml_set_spi_clk(sfc, spi);
+ if (ret)
+ return ret;
+
+ sfc->bus_rate = clk_get_rate(sfc->core_clk);
+
+ return 0;
+}
+
+static int aml_sfc_ecc_init_ctx(struct nand_device *nand)
+{
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
+ struct aml_sfc *sfc = nand_to_aml_sfc(nand);
+ struct aml_sfc_ecc_cfg *ecc_cfg;
+ const struct aml_sfc_caps *caps = sfc->caps;
+ struct aml_sfc_ecc_cfg *ecc_caps = caps->ecc_caps;
+ int i, ecc_strength, ecc_step_size;
+
+ ecc_step_size = nand->ecc.user_conf.step_size;
+ ecc_strength = nand->ecc.user_conf.strength;
+
+ for (i = 0; i < caps->num_ecc_caps; i++) {
+ if (ecc_caps[i].stepsize == ecc_step_size) {
+ nand->ecc.ctx.conf.step_size = ecc_step_size;
+ nand->ecc.ctx.conf.flags |= BIT(ecc_caps[i].bch);
+ }
+
+ if (ecc_caps[i].strength == ecc_strength)
+ nand->ecc.ctx.conf.strength = ecc_strength;
+ }
+
+ if (!nand->ecc.ctx.conf.step_size) {
+ nand->ecc.ctx.conf.step_size = ECC_BCH8_DEFAULT_STEP;
+ nand->ecc.ctx.conf.flags |= BIT(ECC_DEFAULT_BCH_MODE);
+ }
+
+ if (!nand->ecc.ctx.conf.strength)
+ nand->ecc.ctx.conf.strength = ECC_BCH8_STRENGTH;
+
+ nand->ecc.ctx.nsteps = nand->memorg.pagesize / nand->ecc.ctx.conf.step_size;
+ nand->ecc.ctx.total = nand->ecc.ctx.nsteps * ECC_BCH8_PARITY_BYTES;
+
+ /* Verify the page size and OOB size against the SFC requirements. */
+ if ((nand->memorg.pagesize % nand->ecc.ctx.conf.step_size) ||
+ (nand->memorg.oobsize < (nand->ecc.ctx.total +
+ nand->ecc.ctx.nsteps * ECC_BCH8_USER_BYTES)))
+ return -EOPNOTSUPP;
+
+ nand->ecc.ctx.conf.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST;
+
+ ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
+ if (!ecc_cfg)
+ return -ENOMEM;
+
+ ecc_cfg->stepsize = nand->ecc.ctx.conf.step_size;
+ ecc_cfg->nsteps = nand->ecc.ctx.nsteps;
+ ecc_cfg->strength = nand->ecc.ctx.conf.strength;
+ ecc_cfg->oobsize = nand->memorg.oobsize;
+ ecc_cfg->bch = nand->ecc.ctx.conf.flags & BIT(ECC_DEFAULT_BCH_MODE) ? 1 : 2;
+
+ nand->ecc.ctx.priv = ecc_cfg;
+ sfc->priv = (void *)ecc_cfg;
+ mtd_set_ooblayout(mtd, &aml_sfc_ooblayout_ops);
+
+ sfc->flags |= SFC_HWECC;
+
+ return 0;
+}
+
+static void aml_sfc_ecc_cleanup_ctx(struct nand_device *nand)
+{
+ struct aml_sfc *sfc = nand_to_aml_sfc(nand);
+
+ sfc->flags &= ~(SFC_HWECC);
+ kfree(nand->ecc.ctx.priv);
+ sfc->priv = NULL;
+}
+
+static int aml_sfc_ecc_prepare_io_req(struct nand_device *nand,
+ struct nand_page_io_req *req)
+{
+ struct aml_sfc *sfc = nand_to_aml_sfc(nand);
+ struct spinand_device *spinand = nand_to_spinand(nand);
+
+ sfc->flags &= ~SFC_XFER_MDOE_MASK;
+
+ if (req->datalen && !req->ooblen)
+ sfc->flags |= SFC_DATA_ONLY;
+ else if (!req->datalen && req->ooblen)
+ sfc->flags |= SFC_OOB_ONLY;
+ else if (req->datalen && req->ooblen)
+ sfc->flags |= SFC_DATA_OOB;
+
+ if (req->mode == MTD_OPS_RAW)
+ sfc->flags |= SFC_RAW_RW;
+ else if (req->mode == MTD_OPS_AUTO_OOB)
+ sfc->flags |= SFC_AUTO_OOB;
+
+ memset(spinand->oobbuf, 0xff, nanddev_per_page_oobsize(nand));
+
+ return 0;
+}
+
+static int aml_sfc_ecc_finish_io_req(struct nand_device *nand,
+ struct nand_page_io_req *req)
+{
+ struct aml_sfc *sfc = nand_to_aml_sfc(nand);
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
+
+ if (req->mode == MTD_OPS_RAW || req->type == NAND_PAGE_WRITE)
+ return 0;
+
+ if (sfc->ecc_stats.failed)
+ mtd->ecc_stats.failed++;
+
+ mtd->ecc_stats.corrected += sfc->ecc_stats.corrected;
+
+ return sfc->ecc_stats.failed ? -EBADMSG : sfc->ecc_stats.bitflips;
+}
+
+static const struct spi_controller_mem_caps aml_sfc_mem_caps = {
+ .ecc = true,
+};
+
+static const struct nand_ecc_engine_ops aml_sfc_ecc_engine_ops = {
+ .init_ctx = aml_sfc_ecc_init_ctx,
+ .cleanup_ctx = aml_sfc_ecc_cleanup_ctx,
+ .prepare_io_req = aml_sfc_ecc_prepare_io_req,
+ .finish_io_req = aml_sfc_ecc_finish_io_req,
+};
+
+static int aml_sfc_clk_init(struct aml_sfc *sfc)
+{
+ sfc->gate_clk = devm_clk_get_enabled(sfc->dev, "gate");
+ if (IS_ERR(sfc->gate_clk)) {
+ dev_err(sfc->dev, "unable to enable gate clk\n");
+ return PTR_ERR(sfc->gate_clk);
+ }
+
+ sfc->core_clk = devm_clk_get_enabled(sfc->dev, "core");
+ if (IS_ERR(sfc->core_clk)) {
+ dev_err(sfc->dev, "unable to enable core clk\n");
+ return PTR_ERR(sfc->core_clk);
+ }
+
+ return clk_set_rate(sfc->core_clk, SFC_BUS_DEFAULT_CLK);
+}
+
+static int aml_sfc_disable_clk(struct aml_sfc *sfc)
+{
+ clk_disable_unprepare(sfc->core_clk);
+ clk_disable_unprepare(sfc->gate_clk);
+
+ return 0;
+}
+
+static int aml_sfc_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct spi_controller *ctrl;
+ struct aml_sfc *sfc;
+ void __iomem *reg_base;
+ int ret;
+ u32 val = 0;
+
+ const struct regmap_config core_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SFC_SPI_CFG,
+ };
+
+ ctrl = devm_spi_alloc_host(dev, sizeof(*sfc));
+ if (!ctrl)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, ctrl);
+
+ sfc = spi_controller_get_devdata(ctrl);
+ sfc->dev = dev;
+ sfc->ctrl = ctrl;
+
+ sfc->caps = of_device_get_match_data(dev);
+ if (!sfc->caps)
+ return dev_err_probe(dev, -ENODEV, "failed to get device data\n");
+
+ reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+
+ sfc->regmap_base = devm_regmap_init_mmio(dev, reg_base, &core_config);
+ if (IS_ERR(sfc->regmap_base))
+ return dev_err_probe(dev, PTR_ERR(sfc->regmap_base),
+ "failed to init sfc base regmap\n");
+
+ sfc->data_buf = devm_kzalloc(dev, SFC_BUF_SIZE, GFP_KERNEL);
+ if (!sfc->data_buf)
+ return -ENOMEM;
+ sfc->info_buf = (__le64 *)(sfc->data_buf + SFC_DATABUF_SIZE);
+
+ ret = aml_sfc_clk_init(sfc);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize SFC clock\n");
+
+ /* Enable Amlogic flash controller spi mode */
+ ret = regmap_write(sfc->regmap_base, SFC_SPI_CFG, SPI_MODE_EN);
+ if (ret) {
+ dev_err(dev, "failed to enable SPI mode\n");
+ goto err_out;
+ }
+
+ ret = dma_set_mask(sfc->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(sfc->dev, "failed to set dma mask\n");
+ goto err_out;
+ }
+
+ sfc->ecc_eng.dev = &pdev->dev;
+ sfc->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
+ sfc->ecc_eng.ops = &aml_sfc_ecc_engine_ops;
+ sfc->ecc_eng.priv = sfc;
+
+ ret = nand_ecc_register_on_host_hw_engine(&sfc->ecc_eng);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register Aml host ecc engine.\n");
+ goto err_out;
+ }
+
+ ret = of_property_read_u32(np, "amlogic,rx-adj", &val);
+ if (!ret)
+ sfc->rx_adj = val;
+
+ ctrl->dev.of_node = np;
+ ctrl->mem_ops = &aml_sfc_mem_ops;
+ ctrl->mem_caps = &aml_sfc_mem_caps;
+ ctrl->setup = aml_sfc_setup;
+ ctrl->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD |
+ SPI_RX_DUAL | SPI_TX_OCTAL | SPI_RX_OCTAL;
+ ctrl->max_speed_hz = SFC_MAX_FREQUENCY;
+ ctrl->min_speed_hz = SFC_MIN_FREQUENCY;
+ ctrl->num_chipselect = SFC_MAX_CS_NUM;
+
+ ret = devm_spi_register_controller(dev, ctrl);
+ if (ret)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ aml_sfc_disable_clk(sfc);
+
+ return ret;
+}
+
+static void aml_sfc_remove(struct platform_device *pdev)
+{
+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
+ struct aml_sfc *sfc = spi_controller_get_devdata(ctlr);
+
+ aml_sfc_disable_clk(sfc);
+}
+
+static const struct of_device_id aml_sfc_of_match[] = {
+ {
+ .compatible = "amlogic,a4-spifc",
+ .data = &aml_a113l2_sfc_caps
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, aml_sfc_of_match);
+
+static struct platform_driver aml_sfc_driver = {
+ .driver = {
+ .name = "aml_sfc",
+ .of_match_table = aml_sfc_of_match,
+ },
+ .probe = aml_sfc_probe,
+ .remove = aml_sfc_remove,
+};
+module_platform_driver(aml_sfc_driver);
+
+MODULE_DESCRIPTION("Amlogic SPI Flash Controller driver");
+MODULE_AUTHOR("Feng Chen <feng.chen@amlogic.com>");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/spi/spi-amlogic-spisg.c b/drivers/spi/spi-amlogic-spisg.c
new file mode 100644
index 000000000000..bcd7ec291ad0
--- /dev/null
+++ b/drivers/spi/spi-amlogic-spisg.c
@@ -0,0 +1,888 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Amlogic SPI communication Scatter-Gather Controller
+ *
+ * Copyright (C) 2025 Amlogic, Inc. All rights reserved
+ *
+ * Author: Sunny Luo <sunny.luo@amlogic.com>
+ * Author: Xianwei Zhao <xianwei.zhao@amlogic.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+
+/* Register Map */
+#define SPISG_REG_CFG_READY 0x00
+
+#define SPISG_REG_CFG_SPI 0x04
+#define CFG_BUS64_EN BIT(0)
+#define CFG_SLAVE_EN BIT(1)
+#define CFG_SLAVE_SELECT GENMASK(3, 2)
+#define CFG_SFLASH_WP BIT(4)
+#define CFG_SFLASH_HD BIT(5)
+/* start on vsync rising */
+#define CFG_HW_POS BIT(6)
+/* start on vsync falling */
+#define CFG_HW_NEG BIT(7)
+
+#define SPISG_REG_CFG_START 0x08
+#define CFG_BLOCK_NUM GENMASK(19, 0)
+#define CFG_BLOCK_SIZE GENMASK(22, 20)
+#define CFG_DATA_COMMAND BIT(23)
+#define CFG_OP_MODE GENMASK(25, 24)
+#define CFG_RXD_MODE GENMASK(27, 26)
+#define CFG_TXD_MODE GENMASK(29, 28)
+#define CFG_EOC BIT(30)
+#define CFG_PEND BIT(31)
+
+#define SPISG_REG_CFG_BUS 0x0C
+#define CFG_CLK_DIV GENMASK(7, 0)
+#define CLK_DIV_WIDTH 8
+#define CFG_RX_TUNING GENMASK(11, 8)
+#define CFG_TX_TUNING GENMASK(15, 12)
+#define CFG_CS_SETUP GENMASK(19, 16)
+#define CFG_LANE GENMASK(21, 20)
+#define CFG_HALF_DUPLEX BIT(22)
+#define CFG_B_L_ENDIAN BIT(23)
+#define CFG_DC_MODE BIT(24)
+#define CFG_NULL_CTL BIT(25)
+#define CFG_DUMMY_CTL BIT(26)
+#define CFG_READ_TURN GENMASK(28, 27)
+#define CFG_KEEP_SS BIT(29)
+#define CFG_CPHA BIT(30)
+#define CFG_CPOL BIT(31)
+
+#define SPISG_REG_PIO_TX_DATA_L 0x10
+#define SPISG_REG_PIO_TX_DATA_H 0x14
+#define SPISG_REG_PIO_RX_DATA_L 0x18
+#define SPISG_REG_PIO_RX_DATA_H 0x1C
+#define SPISG_REG_MEM_TX_ADDR_L 0x10
+#define SPISG_REG_MEM_TX_ADDR_H 0x14
+#define SPISG_REG_MEM_RX_ADDR_L 0x18
+#define SPISG_REG_MEM_RX_ADDR_H 0x1C
+#define SPISG_REG_DESC_LIST_L 0x20
+#define SPISG_REG_DESC_LIST_H 0x24
+#define LIST_DESC_PENDING BIT(31)
+#define SPISG_REG_DESC_CURRENT_L 0x28
+#define SPISG_REG_DESC_CURRENT_H 0x2c
+#define SPISG_REG_IRQ_STS 0x30
+#define SPISG_REG_IRQ_ENABLE 0x34
+#define IRQ_RCH_DESC_EOC BIT(0)
+#define IRQ_RCH_DESC_INVALID BIT(1)
+#define IRQ_RCH_DESC_RESP BIT(2)
+#define IRQ_RCH_DATA_RESP BIT(3)
+#define IRQ_WCH_DESC_EOC BIT(4)
+#define IRQ_WCH_DESC_INVALID BIT(5)
+#define IRQ_WCH_DESC_RESP BIT(6)
+#define IRQ_WCH_DATA_RESP BIT(7)
+#define IRQ_DESC_ERR BIT(8)
+#define IRQ_SPI_READY BIT(9)
+#define IRQ_DESC_DONE BIT(10)
+#define IRQ_DESC_CHAIN_DONE BIT(11)
+
+#define SPISG_MAX_REG 0x40
+
+#define SPISG_BLOCK_MAX 0x100000
+
+#define SPISG_OP_MODE_WRITE_CMD 0
+#define SPISG_OP_MODE_READ_STS 1
+#define SPISG_OP_MODE_WRITE 2
+#define SPISG_OP_MODE_READ 3
+
+#define SPISG_DATA_MODE_NONE 0
+#define SPISG_DATA_MODE_PIO 1
+#define SPISG_DATA_MODE_MEM 2
+#define SPISG_DATA_MODE_SG 3
+
+#define SPISG_CLK_DIV_MAX 256
+/* recommended by specification */
+#define SPISG_CLK_DIV_MIN 4
+#define DIV_NUM (SPISG_CLK_DIV_MAX - SPISG_CLK_DIV_MIN + 1)
+
+#define SPISG_PCLK_RATE_MIN 24000000
+
+#define SPISG_SINGLE_SPI 0
+#define SPISG_DUAL_SPI 1
+#define SPISG_QUAD_SPI 2
+
+struct spisg_sg_link {
+#define LINK_ADDR_VALID BIT(0)
+#define LINK_ADDR_EOC BIT(1)
+#define LINK_ADDR_IRQ BIT(2)
+#define LINK_ADDR_ACT GENMASK(5, 3)
+#define LINK_ADDR_RING BIT(6)
+#define LINK_ADDR_LEN GENMASK(31, 8)
+ u32 addr;
+ u32 addr1;
+};
+
+struct spisg_descriptor {
+ u32 cfg_start;
+ u32 cfg_bus;
+ u64 tx_paddr;
+ u64 rx_paddr;
+};
+
+struct spisg_descriptor_extra {
+ struct spisg_sg_link *tx_ccsg;
+ struct spisg_sg_link *rx_ccsg;
+ int tx_ccsg_len;
+ int rx_ccsg_len;
+};
+
+struct spisg_device {
+ struct spi_controller *controller;
+ struct platform_device *pdev;
+ struct regmap *map;
+ struct clk *core;
+ struct clk *pclk;
+ struct clk *sclk;
+ struct clk_div_table *tbl;
+ struct completion completion;
+ u32 status;
+ u32 speed_hz;
+ u32 effective_speed_hz;
+ u32 bytes_per_word;
+ u32 cfg_spi;
+ u32 cfg_start;
+ u32 cfg_bus;
+};
+
+static int spi_delay_to_sclk(u32 slck_speed_hz, struct spi_delay *delay)
+{
+ s32 ns;
+
+ if (!delay)
+ return 0;
+
+ if (delay->unit == SPI_DELAY_UNIT_SCK)
+ return delay->value;
+
+ ns = spi_delay_to_ns(delay, NULL);
+ if (ns < 0)
+ return 0;
+
+ return DIV_ROUND_UP_ULL(slck_speed_hz * ns, NSEC_PER_SEC);
+}
+
+static inline u32 aml_spisg_sem_down_read(struct spisg_device *spisg)
+{
+ u32 ret;
+
+ regmap_read(spisg->map, SPISG_REG_CFG_READY, &ret);
+ if (ret)
+ regmap_write(spisg->map, SPISG_REG_CFG_READY, 0);
+
+ return ret;
+}
+
+static inline void aml_spisg_sem_up_write(struct spisg_device *spisg)
+{
+ regmap_write(spisg->map, SPISG_REG_CFG_READY, 1);
+}
+
+static int aml_spisg_set_speed(struct spisg_device *spisg, uint speed_hz)
+{
+ u32 cfg_bus;
+
+ if (!speed_hz || speed_hz == spisg->speed_hz)
+ return 0;
+
+ spisg->speed_hz = speed_hz;
+ clk_set_rate(spisg->sclk, speed_hz);
+ /* Store the div for the descriptor mode */
+ regmap_read(spisg->map, SPISG_REG_CFG_BUS, &cfg_bus);
+ spisg->cfg_bus &= ~CFG_CLK_DIV;
+ spisg->cfg_bus |= cfg_bus & CFG_CLK_DIV;
+ spisg->effective_speed_hz = clk_get_rate(spisg->sclk);
+ dev_dbg(&spisg->pdev->dev,
+ "desired speed %dHz, effective speed %dHz\n",
+ speed_hz, spisg->effective_speed_hz);
+
+ return 0;
+}
+
+static bool aml_spisg_can_dma(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ return true;
+}
+
+static void aml_spisg_sg_xlate(struct sg_table *sgt, struct spisg_sg_link *ccsg)
+{
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ ccsg->addr = FIELD_PREP(LINK_ADDR_VALID, 1) |
+ FIELD_PREP(LINK_ADDR_RING, 0) |
+ FIELD_PREP(LINK_ADDR_EOC, sg_is_last(sg)) |
+ FIELD_PREP(LINK_ADDR_LEN, sg_dma_len(sg));
+ ccsg->addr1 = (u32)sg_dma_address(sg);
+ ccsg++;
+ }
+}
+
+static int nbits_to_lane[] = {
+ SPISG_SINGLE_SPI,
+ SPISG_SINGLE_SPI,
+ SPISG_DUAL_SPI,
+ -EINVAL,
+ SPISG_QUAD_SPI
+};
+
+static int aml_spisg_setup_transfer(struct spisg_device *spisg,
+ struct spi_transfer *xfer,
+ struct spisg_descriptor *desc,
+ struct spisg_descriptor_extra *exdesc)
+{
+ int block_size, blocks;
+ struct device *dev = &spisg->pdev->dev;
+ struct spisg_sg_link *ccsg;
+ int ccsg_len;
+ dma_addr_t paddr;
+ int ret;
+
+ memset(desc, 0, sizeof(*desc));
+ if (exdesc)
+ memset(exdesc, 0, sizeof(*exdesc));
+ aml_spisg_set_speed(spisg, xfer->speed_hz);
+ xfer->effective_speed_hz = spisg->effective_speed_hz;
+
+ desc->cfg_start = spisg->cfg_start;
+ desc->cfg_bus = spisg->cfg_bus;
+
+ block_size = xfer->bits_per_word >> 3;
+ blocks = xfer->len / block_size;
+
+ desc->cfg_start |= FIELD_PREP(CFG_EOC, 0);
+ desc->cfg_bus |= FIELD_PREP(CFG_KEEP_SS, !xfer->cs_change);
+ desc->cfg_bus |= FIELD_PREP(CFG_NULL_CTL, 0);
+
+ if (xfer->tx_buf || xfer->tx_dma) {
+ desc->cfg_bus |= FIELD_PREP(CFG_LANE, nbits_to_lane[xfer->tx_nbits]);
+ desc->cfg_start |= FIELD_PREP(CFG_OP_MODE, SPISG_OP_MODE_WRITE);
+ }
+ if (xfer->rx_buf || xfer->rx_dma) {
+ desc->cfg_bus |= FIELD_PREP(CFG_LANE, nbits_to_lane[xfer->rx_nbits]);
+ desc->cfg_start |= FIELD_PREP(CFG_OP_MODE, SPISG_OP_MODE_READ);
+ }
+
+ if (FIELD_GET(CFG_OP_MODE, desc->cfg_start) == SPISG_OP_MODE_READ_STS) {
+ desc->cfg_start |= FIELD_PREP(CFG_BLOCK_SIZE, blocks) |
+ FIELD_PREP(CFG_BLOCK_NUM, 1);
+ } else {
+ blocks = min_t(int, blocks, SPISG_BLOCK_MAX);
+ desc->cfg_start |= FIELD_PREP(CFG_BLOCK_SIZE, block_size & 0x7) |
+ FIELD_PREP(CFG_BLOCK_NUM, blocks);
+ }
+
+ if (xfer->tx_sg.nents && xfer->tx_sg.sgl) {
+ ccsg_len = xfer->tx_sg.nents * sizeof(struct spisg_sg_link);
+ ccsg = kzalloc(ccsg_len, GFP_KERNEL | GFP_DMA);
+ if (!ccsg) {
+ dev_err(dev, "alloc tx_ccsg failed\n");
+ return -ENOMEM;
+ }
+
+ aml_spisg_sg_xlate(&xfer->tx_sg, ccsg);
+ paddr = dma_map_single(dev, (void *)ccsg,
+ ccsg_len, DMA_TO_DEVICE);
+ ret = dma_mapping_error(dev, paddr);
+ if (ret) {
+ kfree(ccsg);
+ dev_err(dev, "tx ccsg map failed\n");
+ return ret;
+ }
+
+ desc->tx_paddr = paddr;
+ desc->cfg_start |= FIELD_PREP(CFG_TXD_MODE, SPISG_DATA_MODE_SG);
+ exdesc->tx_ccsg = ccsg;
+ exdesc->tx_ccsg_len = ccsg_len;
+ dma_sync_sgtable_for_device(spisg->controller->cur_tx_dma_dev,
+ &xfer->tx_sg, DMA_TO_DEVICE);
+ } else if (xfer->tx_buf || xfer->tx_dma) {
+ paddr = xfer->tx_dma;
+ if (!paddr) {
+ paddr = dma_map_single(dev, (void *)xfer->tx_buf,
+ xfer->len, DMA_TO_DEVICE);
+ ret = dma_mapping_error(dev, paddr);
+ if (ret) {
+ dev_err(dev, "tx buf map failed\n");
+ return ret;
+ }
+ }
+ desc->tx_paddr = paddr;
+ desc->cfg_start |= FIELD_PREP(CFG_TXD_MODE, SPISG_DATA_MODE_MEM);
+ }
+
+ if (xfer->rx_sg.nents && xfer->rx_sg.sgl) {
+ ccsg_len = xfer->rx_sg.nents * sizeof(struct spisg_sg_link);
+ ccsg = kzalloc(ccsg_len, GFP_KERNEL | GFP_DMA);
+ if (!ccsg) {
+ dev_err(dev, "alloc rx_ccsg failed\n");
+ return -ENOMEM;
+ }
+
+ aml_spisg_sg_xlate(&xfer->rx_sg, ccsg);
+ paddr = dma_map_single(dev, (void *)ccsg,
+ ccsg_len, DMA_TO_DEVICE);
+ ret = dma_mapping_error(dev, paddr);
+ if (ret) {
+ kfree(ccsg);
+ dev_err(dev, "rx ccsg map failed\n");
+ return ret;
+ }
+
+ desc->rx_paddr = paddr;
+ desc->cfg_start |= FIELD_PREP(CFG_RXD_MODE, SPISG_DATA_MODE_SG);
+ exdesc->rx_ccsg = ccsg;
+ exdesc->rx_ccsg_len = ccsg_len;
+ dma_sync_sgtable_for_device(spisg->controller->cur_rx_dma_dev,
+ &xfer->rx_sg, DMA_FROM_DEVICE);
+ } else if (xfer->rx_buf || xfer->rx_dma) {
+ paddr = xfer->rx_dma;
+ if (!paddr) {
+ paddr = dma_map_single(dev, xfer->rx_buf,
+ xfer->len, DMA_FROM_DEVICE);
+ ret = dma_mapping_error(dev, paddr);
+ if (ret) {
+ dev_err(dev, "rx buf map failed\n");
+ return ret;
+ }
+ }
+
+ desc->rx_paddr = paddr;
+ desc->cfg_start |= FIELD_PREP(CFG_RXD_MODE, SPISG_DATA_MODE_MEM);
+ }
+
+ return 0;
+}
+
+static void aml_spisg_cleanup_transfer(struct spisg_device *spisg,
+ struct spi_transfer *xfer,
+ struct spisg_descriptor *desc,
+ struct spisg_descriptor_extra *exdesc)
+{
+ struct device *dev = &spisg->pdev->dev;
+
+ if (desc->tx_paddr) {
+ if (FIELD_GET(CFG_TXD_MODE, desc->cfg_start) == SPISG_DATA_MODE_SG) {
+ dma_unmap_single(dev, (dma_addr_t)desc->tx_paddr,
+ exdesc->tx_ccsg_len, DMA_TO_DEVICE);
+ kfree(exdesc->tx_ccsg);
+ dma_sync_sgtable_for_cpu(spisg->controller->cur_tx_dma_dev,
+ &xfer->tx_sg, DMA_TO_DEVICE);
+ } else if (!xfer->tx_dma) {
+ dma_unmap_single(dev, (dma_addr_t)desc->tx_paddr,
+ xfer->len, DMA_TO_DEVICE);
+ }
+ }
+
+ if (desc->rx_paddr) {
+ if (FIELD_GET(CFG_RXD_MODE, desc->cfg_start) == SPISG_DATA_MODE_SG) {
+ dma_unmap_single(dev, (dma_addr_t)desc->rx_paddr,
+ exdesc->rx_ccsg_len, DMA_TO_DEVICE);
+ kfree(exdesc->rx_ccsg);
+ dma_sync_sgtable_for_cpu(spisg->controller->cur_rx_dma_dev,
+ &xfer->rx_sg, DMA_FROM_DEVICE);
+ } else if (!xfer->rx_dma) {
+ dma_unmap_single(dev, (dma_addr_t)desc->rx_paddr,
+ xfer->len, DMA_FROM_DEVICE);
+ }
+ }
+}
+
+static void aml_spisg_setup_null_desc(struct spisg_device *spisg,
+ struct spisg_descriptor *desc,
+ u32 n_sclk)
+{
+ /* unit is the last xfer sclk */
+ desc->cfg_start = spisg->cfg_start;
+ desc->cfg_bus = spisg->cfg_bus;
+
+ desc->cfg_start |= FIELD_PREP(CFG_OP_MODE, SPISG_OP_MODE_WRITE) |
+ FIELD_PREP(CFG_BLOCK_SIZE, 1) |
+ FIELD_PREP(CFG_BLOCK_NUM, DIV_ROUND_UP(n_sclk, 8));
+
+ desc->cfg_bus |= FIELD_PREP(CFG_NULL_CTL, 1);
+}
+
+static void aml_spisg_pending(struct spisg_device *spisg,
+ dma_addr_t desc_paddr,
+ bool trig,
+ bool irq_en)
+{
+ u32 desc_l, desc_h, cfg_spi, irq_enable;
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ desc_l = (u64)desc_paddr & 0xffffffff;
+ desc_h = (u64)desc_paddr >> 32;
+#else
+ desc_l = desc_paddr & 0xffffffff;
+ desc_h = 0;
+#endif
+
+ cfg_spi = spisg->cfg_spi;
+ if (trig)
+ cfg_spi |= CFG_HW_POS;
+ else
+ desc_h |= LIST_DESC_PENDING;
+
+ irq_enable = IRQ_RCH_DESC_INVALID | IRQ_RCH_DESC_RESP |
+ IRQ_RCH_DATA_RESP | IRQ_WCH_DESC_INVALID |
+ IRQ_WCH_DESC_RESP | IRQ_WCH_DATA_RESP |
+ IRQ_DESC_ERR | IRQ_DESC_CHAIN_DONE;
+ regmap_write(spisg->map, SPISG_REG_IRQ_ENABLE, irq_en ? irq_enable : 0);
+ regmap_write(spisg->map, SPISG_REG_CFG_SPI, cfg_spi);
+ regmap_write(spisg->map, SPISG_REG_DESC_LIST_L, desc_l);
+ regmap_write(spisg->map, SPISG_REG_DESC_LIST_H, desc_h);
+}
+
+static irqreturn_t aml_spisg_irq(int irq, void *data)
+{
+ struct spisg_device *spisg = (void *)data;
+ u32 sts;
+
+ spisg->status = 0;
+ regmap_read(spisg->map, SPISG_REG_IRQ_STS, &sts);
+ regmap_write(spisg->map, SPISG_REG_IRQ_STS, sts);
+ if (sts & (IRQ_RCH_DESC_INVALID |
+ IRQ_RCH_DESC_RESP |
+ IRQ_RCH_DATA_RESP |
+ IRQ_WCH_DESC_INVALID |
+ IRQ_WCH_DESC_RESP |
+ IRQ_WCH_DATA_RESP |
+ IRQ_DESC_ERR))
+ spisg->status = sts;
+ else if (sts & IRQ_DESC_CHAIN_DONE)
+ spisg->status = 0;
+ else
+ return IRQ_NONE;
+
+ complete(&spisg->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int aml_spisg_transfer_one_message(struct spi_controller *ctlr,
+ struct spi_message *msg)
+{
+ struct spisg_device *spisg = spi_controller_get_devdata(ctlr);
+ struct device *dev = &spisg->pdev->dev;
+ unsigned long long ms = 0;
+ struct spi_transfer *xfer;
+ struct spisg_descriptor *descs, *desc;
+ struct spisg_descriptor_extra *exdescs, *exdesc;
+ dma_addr_t descs_paddr;
+ int desc_num = 1, descs_len;
+ u32 cs_hold_in_sclk = 0;
+ int ret = -EIO;
+
+ if (!aml_spisg_sem_down_read(spisg)) {
+ spi_finalize_current_message(ctlr);
+ dev_err(dev, "controller busy\n");
+ return -EBUSY;
+ }
+
+ /* calculate the desc num for all xfer */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list)
+ desc_num++;
+
+ /* alloc descriptor/extra-descriptor table */
+ descs = kcalloc(desc_num, sizeof(*desc) + sizeof(*exdesc),
+ GFP_KERNEL | GFP_DMA);
+ if (!descs) {
+ spi_finalize_current_message(ctlr);
+ aml_spisg_sem_up_write(spisg);
+ return -ENOMEM;
+ }
+ descs_len = sizeof(*desc) * desc_num;
+ exdescs = (struct spisg_descriptor_extra *)(descs + desc_num);
+
+ /* config descriptor for each xfer */
+ desc = descs;
+ exdesc = exdescs;
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ ret = aml_spisg_setup_transfer(spisg, xfer, desc, exdesc);
+ if (ret) {
+ dev_err(dev, "config descriptor failed\n");
+ goto end;
+ }
+
+ /* calculate cs-setup delay with the first xfer speed */
+ if (list_is_first(&xfer->transfer_list, &msg->transfers))
+ desc->cfg_bus |= FIELD_PREP(CFG_CS_SETUP,
+ spi_delay_to_sclk(xfer->effective_speed_hz, &msg->spi->cs_setup));
+
+ /* calculate cs-hold delay with the last xfer speed */
+ if (list_is_last(&xfer->transfer_list, &msg->transfers))
+ cs_hold_in_sclk =
+ spi_delay_to_sclk(xfer->effective_speed_hz, &msg->spi->cs_hold);
+
+ desc++;
+ exdesc++;
+ ms += DIV_ROUND_UP_ULL(8LL * MSEC_PER_SEC * xfer->len,
+ xfer->effective_speed_hz);
+ }
+
+ if (cs_hold_in_sclk)
+ /* additional null-descriptor to achieve the cs-hold delay */
+ aml_spisg_setup_null_desc(spisg, desc, cs_hold_in_sclk);
+ else
+ desc--;
+
+ desc->cfg_bus |= FIELD_PREP(CFG_KEEP_SS, 0);
+ desc->cfg_start |= FIELD_PREP(CFG_EOC, 1);
+
+ /* some tolerances */
+ ms += ms + 20;
+ if (ms > UINT_MAX)
+ ms = UINT_MAX;
+
+ descs_paddr = dma_map_single(dev, (void *)descs,
+ descs_len, DMA_TO_DEVICE);
+ ret = dma_mapping_error(dev, descs_paddr);
+ if (ret) {
+ dev_err(dev, "desc table map failed\n");
+ goto end;
+ }
+
+ reinit_completion(&spisg->completion);
+ aml_spisg_pending(spisg, descs_paddr, false, true);
+ if (wait_for_completion_timeout(&spisg->completion,
+ spi_controller_is_target(spisg->controller) ?
+ MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(ms)))
+ ret = spisg->status ? -EIO : 0;
+ else
+ ret = -ETIMEDOUT;
+
+ dma_unmap_single(dev, descs_paddr, descs_len, DMA_TO_DEVICE);
+end:
+ desc = descs;
+ exdesc = exdescs;
+ list_for_each_entry(xfer, &msg->transfers, transfer_list)
+ aml_spisg_cleanup_transfer(spisg, xfer, desc++, exdesc++);
+ kfree(descs);
+
+ if (!ret)
+ msg->actual_length = msg->frame_length;
+ msg->status = ret;
+ spi_finalize_current_message(ctlr);
+ aml_spisg_sem_up_write(spisg);
+
+ return ret;
+}
+
+static int aml_spisg_prepare_message(struct spi_controller *ctlr,
+ struct spi_message *message)
+{
+ struct spisg_device *spisg = spi_controller_get_devdata(ctlr);
+ struct spi_device *spi = message->spi;
+
+ if (!spi->bits_per_word || spi->bits_per_word % 8) {
+ dev_err(&spisg->pdev->dev, "invalid wordlen %d\n", spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ spisg->bytes_per_word = spi->bits_per_word >> 3;
+
+ spisg->cfg_spi &= ~CFG_SLAVE_SELECT;
+ spisg->cfg_spi |= FIELD_PREP(CFG_SLAVE_SELECT, spi_get_chipselect(spi, 0));
+
+ spisg->cfg_bus &= ~(CFG_CPOL | CFG_CPHA | CFG_B_L_ENDIAN | CFG_HALF_DUPLEX);
+ spisg->cfg_bus |= FIELD_PREP(CFG_CPOL, !!(spi->mode & SPI_CPOL)) |
+ FIELD_PREP(CFG_CPHA, !!(spi->mode & SPI_CPHA)) |
+ FIELD_PREP(CFG_B_L_ENDIAN, !!(spi->mode & SPI_LSB_FIRST)) |
+ FIELD_PREP(CFG_HALF_DUPLEX, !!(spi->mode & SPI_3WIRE));
+
+ return 0;
+}
+
+static int aml_spisg_setup(struct spi_device *spi)
+{
+ if (!spi->controller_state)
+ spi->controller_state = spi_controller_get_devdata(spi->controller);
+
+ return 0;
+}
+
+static void aml_spisg_cleanup(struct spi_device *spi)
+{
+ spi->controller_state = NULL;
+}
+
+static int aml_spisg_target_abort(struct spi_controller *ctlr)
+{
+ struct spisg_device *spisg = spi_controller_get_devdata(ctlr);
+
+ spisg->status = 0;
+ regmap_write(spisg->map, SPISG_REG_DESC_LIST_H, 0);
+ complete(&spisg->completion);
+
+ return 0;
+}
+
+static int aml_spisg_clk_init(struct spisg_device *spisg, void __iomem *base)
+{
+ struct device *dev = &spisg->pdev->dev;
+ struct clk_init_data init;
+ struct clk_divider *div;
+ struct clk_div_table *tbl;
+ char name[32];
+ int ret, i;
+
+ spisg->core = devm_clk_get_enabled(dev, "core");
+ if (IS_ERR_OR_NULL(spisg->core)) {
+ dev_err(dev, "core clock request failed\n");
+ return PTR_ERR(spisg->core);
+ }
+
+ spisg->pclk = devm_clk_get_enabled(dev, "pclk");
+ if (IS_ERR_OR_NULL(spisg->pclk)) {
+ dev_err(dev, "pclk clock request failed\n");
+ return PTR_ERR(spisg->pclk);
+ }
+
+ clk_set_min_rate(spisg->pclk, SPISG_PCLK_RATE_MIN);
+
+ clk_disable_unprepare(spisg->pclk);
+
+ tbl = devm_kcalloc(dev, (DIV_NUM + 1), sizeof(*tbl), GFP_KERNEL);
+ if (!tbl)
+ return -ENOMEM;
+
+ for (i = 0; i < DIV_NUM; i++) {
+ tbl[i].val = i + SPISG_CLK_DIV_MIN - 1;
+ tbl[i].div = i + SPISG_CLK_DIV_MIN;
+ }
+ spisg->tbl = tbl;
+
+ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return -ENOMEM;
+
+ div->flags = CLK_DIVIDER_ROUND_CLOSEST;
+ div->reg = base + SPISG_REG_CFG_BUS;
+ div->shift = __bf_shf(CFG_CLK_DIV);
+ div->width = CLK_DIV_WIDTH;
+ div->table = tbl;
+
+ /* Register value should not be outside of the table */
+ regmap_update_bits(spisg->map, SPISG_REG_CFG_BUS, CFG_CLK_DIV,
+ FIELD_PREP(CFG_CLK_DIV, SPISG_CLK_DIV_MIN - 1));
+
+ /* Register clk-divider */
+ snprintf(name, sizeof(name), "%s_div", dev_name(dev));
+ init.name = name;
+ init.ops = &clk_divider_ops;
+ init.flags = CLK_SET_RATE_PARENT;
+ init.parent_data = &(const struct clk_parent_data) {
+ .fw_name = "pclk",
+ };
+ init.num_parents = 1;
+ div->hw.init = &init;
+ ret = devm_clk_hw_register(dev, &div->hw);
+ if (ret) {
+ dev_err(dev, "clock registration failed\n");
+ return ret;
+ }
+
+ spisg->sclk = devm_clk_hw_get_clk(dev, &div->hw, NULL);
+ if (IS_ERR_OR_NULL(spisg->sclk)) {
+ dev_err(dev, "get clock failed\n");
+ return PTR_ERR(spisg->sclk);
+ }
+
+ clk_prepare_enable(spisg->sclk);
+
+ return 0;
+}
+
+static int aml_spisg_probe(struct platform_device *pdev)
+{
+ struct spi_controller *ctlr;
+ struct spisg_device *spisg;
+ struct device *dev = &pdev->dev;
+ void __iomem *base;
+ int ret, irq;
+
+ const struct regmap_config aml_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SPISG_MAX_REG,
+ };
+
+ if (of_property_read_bool(dev->of_node, "spi-slave"))
+ ctlr = spi_alloc_target(dev, sizeof(*spisg));
+ else
+ ctlr = spi_alloc_host(dev, sizeof(*spisg));
+ if (!ctlr)
+ return -ENOMEM;
+
+ spisg = spi_controller_get_devdata(ctlr);
+ spisg->controller = ctlr;
+
+ spisg->pdev = pdev;
+ platform_set_drvdata(pdev, spisg);
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return dev_err_probe(dev, PTR_ERR(base), "resource ioremap failed\n");
+
+ spisg->map = devm_regmap_init_mmio(dev, base, &aml_regmap_config);
+ if (IS_ERR(spisg->map))
+ return dev_err_probe(dev, PTR_ERR(spisg->map), "regmap init failed\n");
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ goto out_controller;
+ }
+
+ ret = device_reset_optional(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "reset dev failed\n");
+
+ ret = aml_spisg_clk_init(spisg, base);
+ if (ret)
+ return dev_err_probe(dev, ret, "clock init failed\n");
+
+ spisg->cfg_spi = 0;
+ spisg->cfg_start = 0;
+ spisg->cfg_bus = 0;
+
+ spisg->cfg_spi = FIELD_PREP(CFG_SFLASH_WP, 1) |
+ FIELD_PREP(CFG_SFLASH_HD, 1);
+ if (spi_controller_is_target(ctlr)) {
+ spisg->cfg_spi |= FIELD_PREP(CFG_SLAVE_EN, 1);
+ spisg->cfg_bus = FIELD_PREP(CFG_TX_TUNING, 0xf);
+ }
+ /* default pending */
+ spisg->cfg_start = FIELD_PREP(CFG_PEND, 1);
+
+ pm_runtime_set_active(&spisg->pdev->dev);
+ pm_runtime_enable(&spisg->pdev->dev);
+ pm_runtime_resume_and_get(&spisg->pdev->dev);
+
+ ctlr->num_chipselect = 4;
+ ctlr->dev.of_node = pdev->dev.of_node;
+ ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST |
+ SPI_3WIRE | SPI_TX_QUAD | SPI_RX_QUAD;
+ ctlr->max_speed_hz = 1000 * 1000 * 100;
+ ctlr->min_speed_hz = 1000 * 10;
+ ctlr->setup = aml_spisg_setup;
+ ctlr->cleanup = aml_spisg_cleanup;
+ ctlr->prepare_message = aml_spisg_prepare_message;
+ ctlr->transfer_one_message = aml_spisg_transfer_one_message;
+ ctlr->target_abort = aml_spisg_target_abort;
+ ctlr->can_dma = aml_spisg_can_dma;
+ ctlr->max_dma_len = SPISG_BLOCK_MAX;
+ ctlr->auto_runtime_pm = true;
+
+ dma_set_max_seg_size(&pdev->dev, SPISG_BLOCK_MAX);
+
+ ret = devm_request_irq(&pdev->dev, irq, aml_spisg_irq, 0, NULL, spisg);
+ if (ret) {
+ dev_err(&pdev->dev, "irq request failed\n");
+ goto out_clk;
+ }
+
+ ret = devm_spi_register_controller(dev, ctlr);
+ if (ret) {
+ dev_err(&pdev->dev, "spi controller registration failed\n");
+ goto out_clk;
+ }
+
+ init_completion(&spisg->completion);
+
+ pm_runtime_put(&spisg->pdev->dev);
+
+ return 0;
+out_clk:
+ if (spisg->core)
+ clk_disable_unprepare(spisg->core);
+ clk_disable_unprepare(spisg->pclk);
+out_controller:
+ spi_controller_put(ctlr);
+
+ return ret;
+}
+
+static void aml_spisg_remove(struct platform_device *pdev)
+{
+ struct spisg_device *spisg = platform_get_drvdata(pdev);
+
+ if (!pm_runtime_suspended(&pdev->dev)) {
+ pinctrl_pm_select_sleep_state(&spisg->pdev->dev);
+ clk_disable_unprepare(spisg->core);
+ clk_disable_unprepare(spisg->pclk);
+ }
+}
+
+static int spisg_suspend_runtime(struct device *dev)
+{
+ struct spisg_device *spisg = dev_get_drvdata(dev);
+
+ pinctrl_pm_select_sleep_state(&spisg->pdev->dev);
+ clk_disable_unprepare(spisg->sclk);
+ clk_disable_unprepare(spisg->core);
+
+ return 0;
+}
+
+static int spisg_resume_runtime(struct device *dev)
+{
+ struct spisg_device *spisg = dev_get_drvdata(dev);
+
+ clk_prepare_enable(spisg->core);
+ clk_prepare_enable(spisg->sclk);
+ pinctrl_pm_select_default_state(&spisg->pdev->dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops amlogic_spisg_pm_ops = {
+ .runtime_suspend = spisg_suspend_runtime,
+ .runtime_resume = spisg_resume_runtime,
+};
+
+static const struct of_device_id amlogic_spisg_of_match[] = {
+ {
+ .compatible = "amlogic,a4-spisg",
+ },
+
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, amlogic_spisg_of_match);
+
+static struct platform_driver amlogic_spisg_driver = {
+ .probe = aml_spisg_probe,
+ .remove = aml_spisg_remove,
+ .driver = {
+ .name = "amlogic-spisg",
+ .of_match_table = amlogic_spisg_of_match,
+ .pm = &amlogic_spisg_pm_ops,
+ },
+};
+
+module_platform_driver(amlogic_spisg_driver);
+
+MODULE_DESCRIPTION("Amlogic SPI Scatter-Gather Controller driver");
+MODULE_AUTHOR("Sunny Luo <sunny.luo@amlogic.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-apple.c b/drivers/spi/spi-apple.c
new file mode 100644
index 000000000000..2fee7057ecc9
--- /dev/null
+++ b/drivers/spi/spi-apple.c
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Apple SoC SPI device driver
+//
+// Copyright The Asahi Linux Contributors
+//
+// Based on spi-sifive.c, Copyright 2018 SiFive, Inc.
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+
+#define APPLE_SPI_CTRL 0x000
+#define APPLE_SPI_CTRL_RUN BIT(0)
+#define APPLE_SPI_CTRL_TX_RESET BIT(2)
+#define APPLE_SPI_CTRL_RX_RESET BIT(3)
+
+#define APPLE_SPI_CFG 0x004
+#define APPLE_SPI_CFG_CPHA BIT(1)
+#define APPLE_SPI_CFG_CPOL BIT(2)
+#define APPLE_SPI_CFG_MODE GENMASK(6, 5)
+#define APPLE_SPI_CFG_MODE_POLLED 0
+#define APPLE_SPI_CFG_MODE_IRQ 1
+#define APPLE_SPI_CFG_MODE_DMA 2
+#define APPLE_SPI_CFG_IE_RXCOMPLETE BIT(7)
+#define APPLE_SPI_CFG_IE_TXRXTHRESH BIT(8)
+#define APPLE_SPI_CFG_LSB_FIRST BIT(13)
+#define APPLE_SPI_CFG_WORD_SIZE GENMASK(16, 15)
+#define APPLE_SPI_CFG_WORD_SIZE_8B 0
+#define APPLE_SPI_CFG_WORD_SIZE_16B 1
+#define APPLE_SPI_CFG_WORD_SIZE_32B 2
+#define APPLE_SPI_CFG_FIFO_THRESH GENMASK(18, 17)
+#define APPLE_SPI_CFG_FIFO_THRESH_8B 0
+#define APPLE_SPI_CFG_FIFO_THRESH_4B 1
+#define APPLE_SPI_CFG_FIFO_THRESH_1B 2
+#define APPLE_SPI_CFG_IE_TXCOMPLETE BIT(21)
+
+#define APPLE_SPI_STATUS 0x008
+#define APPLE_SPI_STATUS_RXCOMPLETE BIT(0)
+#define APPLE_SPI_STATUS_TXRXTHRESH BIT(1)
+#define APPLE_SPI_STATUS_TXCOMPLETE BIT(2)
+
+#define APPLE_SPI_PIN 0x00c
+#define APPLE_SPI_PIN_KEEP_MOSI BIT(0)
+#define APPLE_SPI_PIN_CS BIT(1)
+
+#define APPLE_SPI_TXDATA 0x010
+#define APPLE_SPI_RXDATA 0x020
+#define APPLE_SPI_CLKDIV 0x030
+#define APPLE_SPI_CLKDIV_MAX 0x7ff
+#define APPLE_SPI_RXCNT 0x034
+#define APPLE_SPI_WORD_DELAY 0x038
+#define APPLE_SPI_TXCNT 0x04c
+
+#define APPLE_SPI_FIFOSTAT 0x10c
+#define APPLE_SPI_FIFOSTAT_TXFULL BIT(4)
+#define APPLE_SPI_FIFOSTAT_LEVEL_TX GENMASK(15, 8)
+#define APPLE_SPI_FIFOSTAT_RXEMPTY BIT(20)
+#define APPLE_SPI_FIFOSTAT_LEVEL_RX GENMASK(31, 24)
+
+#define APPLE_SPI_IE_XFER 0x130
+#define APPLE_SPI_IF_XFER 0x134
+#define APPLE_SPI_XFER_RXCOMPLETE BIT(0)
+#define APPLE_SPI_XFER_TXCOMPLETE BIT(1)
+
+#define APPLE_SPI_IE_FIFO 0x138
+#define APPLE_SPI_IF_FIFO 0x13c
+#define APPLE_SPI_FIFO_RXTHRESH BIT(4)
+#define APPLE_SPI_FIFO_TXTHRESH BIT(5)
+#define APPLE_SPI_FIFO_RXFULL BIT(8)
+#define APPLE_SPI_FIFO_TXEMPTY BIT(9)
+#define APPLE_SPI_FIFO_RXUNDERRUN BIT(16)
+#define APPLE_SPI_FIFO_TXOVERFLOW BIT(17)
+
+#define APPLE_SPI_SHIFTCFG 0x150
+#define APPLE_SPI_SHIFTCFG_CLK_ENABLE BIT(0)
+#define APPLE_SPI_SHIFTCFG_CS_ENABLE BIT(1)
+#define APPLE_SPI_SHIFTCFG_AND_CLK_DATA BIT(8)
+#define APPLE_SPI_SHIFTCFG_CS_AS_DATA BIT(9)
+#define APPLE_SPI_SHIFTCFG_TX_ENABLE BIT(10)
+#define APPLE_SPI_SHIFTCFG_RX_ENABLE BIT(11)
+#define APPLE_SPI_SHIFTCFG_BITS GENMASK(21, 16)
+#define APPLE_SPI_SHIFTCFG_OVERRIDE_CS BIT(24)
+
+#define APPLE_SPI_PINCFG 0x154
+#define APPLE_SPI_PINCFG_KEEP_CLK BIT(0)
+#define APPLE_SPI_PINCFG_KEEP_CS BIT(1)
+#define APPLE_SPI_PINCFG_KEEP_MOSI BIT(2)
+#define APPLE_SPI_PINCFG_CLK_IDLE_VAL BIT(8)
+#define APPLE_SPI_PINCFG_CS_IDLE_VAL BIT(9)
+#define APPLE_SPI_PINCFG_MOSI_IDLE_VAL BIT(10)
+
+#define APPLE_SPI_DELAY_PRE 0x160
+#define APPLE_SPI_DELAY_POST 0x168
+#define APPLE_SPI_DELAY_ENABLE BIT(0)
+#define APPLE_SPI_DELAY_NO_INTERBYTE BIT(1)
+#define APPLE_SPI_DELAY_SET_SCK BIT(4)
+#define APPLE_SPI_DELAY_SET_MOSI BIT(6)
+#define APPLE_SPI_DELAY_SCK_VAL BIT(8)
+#define APPLE_SPI_DELAY_MOSI_VAL BIT(12)
+
+#define APPLE_SPI_FIFO_DEPTH 16
+
+/*
+ * The slowest refclock available is 24MHz, the highest divider is 0x7ff,
+ * the largest word size is 32 bits, the FIFO depth is 16, the maximum
+ * intra-word delay is 0xffff refclocks. So the maximum time a transfer
+ * cycle can take is:
+ *
+ * (0x7ff * 32 + 0xffff) * 16 / 24e6 Hz ~= 87ms
+ *
+ * Double it and round it up to 200ms for good measure.
+ */
+#define APPLE_SPI_TIMEOUT_MS 200
+
+struct apple_spi {
+ void __iomem *regs; /* MMIO register address */
+ struct clk *clk; /* bus clock */
+ struct completion done; /* wake-up from interrupt */
+};
+
+static inline void reg_write(struct apple_spi *spi, int offset, u32 value)
+{
+ writel_relaxed(value, spi->regs + offset);
+}
+
+static inline u32 reg_read(struct apple_spi *spi, int offset)
+{
+ return readl_relaxed(spi->regs + offset);
+}
+
+static inline void reg_mask(struct apple_spi *spi, int offset, u32 clear, u32 set)
+{
+ u32 val = reg_read(spi, offset);
+
+ val &= ~clear;
+ val |= set;
+ reg_write(spi, offset, val);
+}
+
+static void apple_spi_init(struct apple_spi *spi)
+{
+ /* Set CS high (inactive) and disable override and auto-CS */
+ reg_write(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS);
+ reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_OVERRIDE_CS, 0);
+ reg_mask(spi, APPLE_SPI_PINCFG, APPLE_SPI_PINCFG_CS_IDLE_VAL, APPLE_SPI_PINCFG_KEEP_CS);
+
+ /* Reset FIFOs */
+ reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET);
+
+ /* Configure defaults */
+ reg_write(spi, APPLE_SPI_CFG,
+ FIELD_PREP(APPLE_SPI_CFG_FIFO_THRESH, APPLE_SPI_CFG_FIFO_THRESH_8B) |
+ FIELD_PREP(APPLE_SPI_CFG_MODE, APPLE_SPI_CFG_MODE_IRQ) |
+ FIELD_PREP(APPLE_SPI_CFG_WORD_SIZE, APPLE_SPI_CFG_WORD_SIZE_8B));
+
+ /* Disable IRQs */
+ reg_write(spi, APPLE_SPI_IE_FIFO, 0);
+ reg_write(spi, APPLE_SPI_IE_XFER, 0);
+
+ /* Disable delays */
+ reg_write(spi, APPLE_SPI_DELAY_PRE, 0);
+ reg_write(spi, APPLE_SPI_DELAY_POST, 0);
+}
+
+static int apple_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *msg)
+{
+ struct apple_spi *spi = spi_controller_get_devdata(ctlr);
+ struct spi_device *device = msg->spi;
+
+ u32 cfg = ((device->mode & SPI_CPHA ? APPLE_SPI_CFG_CPHA : 0) |
+ (device->mode & SPI_CPOL ? APPLE_SPI_CFG_CPOL : 0) |
+ (device->mode & SPI_LSB_FIRST ? APPLE_SPI_CFG_LSB_FIRST : 0));
+
+ /* Update core config */
+ reg_mask(spi, APPLE_SPI_CFG,
+ APPLE_SPI_CFG_CPHA | APPLE_SPI_CFG_CPOL | APPLE_SPI_CFG_LSB_FIRST, cfg);
+
+ return 0;
+}
+
+static void apple_spi_set_cs(struct spi_device *device, bool is_high)
+{
+ struct apple_spi *spi = spi_controller_get_devdata(device->controller);
+
+ reg_mask(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS, is_high ? APPLE_SPI_PIN_CS : 0);
+}
+
+static bool apple_spi_prep_transfer(struct apple_spi *spi, struct spi_transfer *t)
+{
+ u32 cr, fifo_threshold;
+
+ /* Calculate and program the clock rate */
+ cr = DIV_ROUND_UP(clk_get_rate(spi->clk), t->speed_hz);
+ reg_write(spi, APPLE_SPI_CLKDIV, min_t(u32, cr, APPLE_SPI_CLKDIV_MAX));
+
+ /* Update bits per word */
+ reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_BITS,
+ FIELD_PREP(APPLE_SPI_SHIFTCFG_BITS, t->bits_per_word));
+
+ /* We will want to poll if the time we need to wait is
+ * less than the context switching time.
+ * Let's call that threshold 5us. The operation will take:
+ * bits_per_word * fifo_threshold / hz <= 5 * 10^-6
+ * 200000 * bits_per_word * fifo_threshold <= hz
+ */
+ fifo_threshold = APPLE_SPI_FIFO_DEPTH / 2;
+ return (200000 * t->bits_per_word * fifo_threshold) <= t->speed_hz;
+}
+
+static irqreturn_t apple_spi_irq(int irq, void *dev_id)
+{
+ struct apple_spi *spi = dev_id;
+ u32 fifo = reg_read(spi, APPLE_SPI_IF_FIFO) & reg_read(spi, APPLE_SPI_IE_FIFO);
+ u32 xfer = reg_read(spi, APPLE_SPI_IF_XFER) & reg_read(spi, APPLE_SPI_IE_XFER);
+
+ if (fifo || xfer) {
+ /* Disable interrupts until next transfer */
+ reg_write(spi, APPLE_SPI_IE_XFER, 0);
+ reg_write(spi, APPLE_SPI_IE_FIFO, 0);
+ complete(&spi->done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int apple_spi_wait(struct apple_spi *spi, u32 fifo_bit, u32 xfer_bit, int poll)
+{
+ int ret = 0;
+
+ if (poll) {
+ u32 fifo, xfer;
+ unsigned long timeout = jiffies + APPLE_SPI_TIMEOUT_MS * HZ / 1000;
+
+ do {
+ fifo = reg_read(spi, APPLE_SPI_IF_FIFO);
+ xfer = reg_read(spi, APPLE_SPI_IF_XFER);
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ } while (!((fifo & fifo_bit) || (xfer & xfer_bit)));
+ } else {
+ reinit_completion(&spi->done);
+ reg_write(spi, APPLE_SPI_IE_XFER, xfer_bit);
+ reg_write(spi, APPLE_SPI_IE_FIFO, fifo_bit);
+
+ if (!wait_for_completion_timeout(&spi->done,
+ msecs_to_jiffies(APPLE_SPI_TIMEOUT_MS)))
+ ret = -ETIMEDOUT;
+
+ reg_write(spi, APPLE_SPI_IE_XFER, 0);
+ reg_write(spi, APPLE_SPI_IE_FIFO, 0);
+ }
+
+ return ret;
+}
+
+static void apple_spi_tx(struct apple_spi *spi, const void **tx_ptr, u32 *left,
+ unsigned int bytes_per_word)
+{
+ u32 inuse, words, wrote;
+
+ if (!*tx_ptr)
+ return;
+
+ inuse = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_TX, reg_read(spi, APPLE_SPI_FIFOSTAT));
+ words = wrote = min_t(u32, *left, APPLE_SPI_FIFO_DEPTH - inuse);
+
+ if (!words)
+ return;
+
+ *left -= words;
+
+ switch (bytes_per_word) {
+ case 1: {
+ const u8 *p = *tx_ptr;
+
+ while (words--)
+ reg_write(spi, APPLE_SPI_TXDATA, *p++);
+ break;
+ }
+ case 2: {
+ const u16 *p = *tx_ptr;
+
+ while (words--)
+ reg_write(spi, APPLE_SPI_TXDATA, *p++);
+ break;
+ }
+ case 4: {
+ const u32 *p = *tx_ptr;
+
+ while (words--)
+ reg_write(spi, APPLE_SPI_TXDATA, *p++);
+ break;
+ }
+ default:
+ WARN_ON(1);
+ }
+
+ *tx_ptr = ((u8 *)*tx_ptr) + bytes_per_word * wrote;
+}
+
+static void apple_spi_rx(struct apple_spi *spi, void **rx_ptr, u32 *left,
+ unsigned int bytes_per_word)
+{
+ u32 words, read;
+
+ if (!*rx_ptr)
+ return;
+
+ words = read = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_RX, reg_read(spi, APPLE_SPI_FIFOSTAT));
+ WARN_ON(words > *left);
+
+ if (!words)
+ return;
+
+ *left -= min_t(u32, *left, words);
+
+ switch (bytes_per_word) {
+ case 1: {
+ u8 *p = *rx_ptr;
+
+ while (words--)
+ *p++ = reg_read(spi, APPLE_SPI_RXDATA);
+ break;
+ }
+ case 2: {
+ u16 *p = *rx_ptr;
+
+ while (words--)
+ *p++ = reg_read(spi, APPLE_SPI_RXDATA);
+ break;
+ }
+ case 4: {
+ u32 *p = *rx_ptr;
+
+ while (words--)
+ *p++ = reg_read(spi, APPLE_SPI_RXDATA);
+ break;
+ }
+ default:
+ WARN_ON(1);
+ }
+
+ *rx_ptr = ((u8 *)*rx_ptr) + bytes_per_word * read;
+}
+
+static int apple_spi_transfer_one(struct spi_controller *ctlr, struct spi_device *device,
+ struct spi_transfer *t)
+{
+ struct apple_spi *spi = spi_controller_get_devdata(ctlr);
+ bool poll = apple_spi_prep_transfer(spi, t);
+ const void *tx_ptr = t->tx_buf;
+ void *rx_ptr = t->rx_buf;
+ unsigned int bytes_per_word;
+ u32 words, remaining_tx, remaining_rx;
+ u32 xfer_flags = 0;
+ u32 fifo_flags;
+ int retries = 100;
+ int ret = 0;
+
+ if (t->bits_per_word > 16)
+ bytes_per_word = 4;
+ else if (t->bits_per_word > 8)
+ bytes_per_word = 2;
+ else
+ bytes_per_word = 1;
+
+ words = t->len / bytes_per_word;
+ remaining_tx = tx_ptr ? words : 0;
+ remaining_rx = rx_ptr ? words : 0;
+
+ /* Reset FIFOs */
+ reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET);
+
+ /* Clear IRQ flags */
+ reg_write(spi, APPLE_SPI_IF_XFER, ~0);
+ reg_write(spi, APPLE_SPI_IF_FIFO, ~0);
+
+ /* Determine transfer completion flags we wait for */
+ if (tx_ptr)
+ xfer_flags |= APPLE_SPI_XFER_TXCOMPLETE;
+ if (rx_ptr)
+ xfer_flags |= APPLE_SPI_XFER_RXCOMPLETE;
+
+ /* Set transfer length */
+ reg_write(spi, APPLE_SPI_TXCNT, remaining_tx);
+ reg_write(spi, APPLE_SPI_RXCNT, remaining_rx);
+
+ /* Prime transmit FIFO */
+ apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word);
+
+ /* Start transfer */
+ reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RUN);
+
+ /* TX again since a few words get popped off immediately */
+ apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word);
+
+ while (xfer_flags) {
+ fifo_flags = 0;
+
+ if (remaining_tx)
+ fifo_flags |= APPLE_SPI_FIFO_TXTHRESH;
+ if (remaining_rx)
+ fifo_flags |= APPLE_SPI_FIFO_RXTHRESH;
+
+ /* Wait for anything to happen */
+ ret = apple_spi_wait(spi, fifo_flags, xfer_flags, poll);
+ if (ret) {
+ dev_err(&ctlr->dev, "transfer timed out (remaining %d tx, %d rx)\n",
+ remaining_tx, remaining_rx);
+ goto err;
+ }
+
+ /* Stop waiting on transfer halves once they complete */
+ xfer_flags &= ~reg_read(spi, APPLE_SPI_IF_XFER);
+
+ /* Transmit and receive everything we can */
+ apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word);
+ apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word);
+ }
+
+ /*
+ * Sometimes the transfer completes before the last word is in the RX FIFO.
+ * Normally one retry is all it takes to get the last word out.
+ */
+ while (remaining_rx && retries--)
+ apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word);
+
+ if (remaining_tx)
+ dev_err(&ctlr->dev, "transfer completed with %d words left to transmit\n",
+ remaining_tx);
+ if (remaining_rx)
+ dev_err(&ctlr->dev, "transfer completed with %d words left to receive\n",
+ remaining_rx);
+
+err:
+ fifo_flags = reg_read(spi, APPLE_SPI_IF_FIFO);
+ WARN_ON(fifo_flags & APPLE_SPI_FIFO_TXOVERFLOW);
+ WARN_ON(fifo_flags & APPLE_SPI_FIFO_RXUNDERRUN);
+
+ /* Stop transfer */
+ reg_write(spi, APPLE_SPI_CTRL, 0);
+
+ return ret;
+}
+
+static int apple_spi_probe(struct platform_device *pdev)
+{
+ struct apple_spi *spi;
+ int ret, irq;
+ struct spi_controller *ctlr;
+
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(struct apple_spi));
+ if (!ctlr)
+ return -ENOMEM;
+
+ spi = spi_controller_get_devdata(ctlr);
+ init_completion(&spi->done);
+
+ spi->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(spi->regs))
+ return PTR_ERR(spi->regs);
+
+ spi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(spi->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk),
+ "Unable to find or enable bus clock\n");
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, apple_spi_irq, 0,
+ dev_name(&pdev->dev), spi);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Unable to bind to interrupt\n");
+
+ ctlr->dev.of_node = pdev->dev.of_node;
+ ctlr->bus_num = pdev->id;
+ ctlr->num_chipselect = 1;
+ ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
+ ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ ctlr->prepare_message = apple_spi_prepare_message;
+ ctlr->set_cs = apple_spi_set_cs;
+ ctlr->transfer_one = apple_spi_transfer_one;
+ ctlr->use_gpio_descriptors = true;
+ ctlr->auto_runtime_pm = true;
+
+ pm_runtime_set_active(&pdev->dev);
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret < 0)
+ return ret;
+
+ apple_spi_init(spi);
+
+ ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret, "devm_spi_register_controller failed\n");
+
+ return 0;
+}
+
+static const struct of_device_id apple_spi_of_match[] = {
+ { .compatible = "apple,t8103-spi", },
+ { .compatible = "apple,spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, apple_spi_of_match);
+
+static struct platform_driver apple_spi_driver = {
+ .probe = apple_spi_probe,
+ .driver = {
+ .name = "apple-spi",
+ .of_match_table = apple_spi_of_match,
+ },
+};
+module_platform_driver(apple_spi_driver);
+
+MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
+MODULE_DESCRIPTION("Apple SoC SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-ar934x.c b/drivers/spi/spi-ar934x.c
index 9dcada8c4cb9..86c54fff9d6e 100644
--- a/drivers/spi/spi-ar934x.c
+++ b/drivers/spi/spi-ar934x.c
@@ -14,7 +14,8 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#define DRIVER_NAME "spi-ar934x"
@@ -167,27 +168,21 @@ static int ar934x_spi_probe(struct platform_device *pdev)
struct ar934x_spi *sp;
void __iomem *base;
struct clk *clk;
- int ret;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
- clk = devm_clk_get(&pdev->dev, NULL);
+ clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
return PTR_ERR(clk);
}
- ret = clk_prepare_enable(clk);
- if (ret)
- return ret;
-
ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*sp));
if (!ctlr) {
dev_info(&pdev->dev, "failed to allocate spi controller\n");
- ret = -ENOMEM;
- goto err_clk_disable;
+ return -ENOMEM;
}
/* disable flash mapping and expose spi controller registers */
@@ -211,25 +206,15 @@ static int ar934x_spi_probe(struct platform_device *pdev)
sp->clk_freq = clk_get_rate(clk);
sp->ctlr = ctlr;
- ret = spi_register_controller(ctlr);
- if (!ret)
- return 0;
-
-err_clk_disable:
- clk_disable_unprepare(clk);
- return ret;
+ return spi_register_controller(ctlr);
}
static void ar934x_spi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr;
- struct ar934x_spi *sp;
ctlr = dev_get_drvdata(&pdev->dev);
- sp = spi_controller_get_devdata(ctlr);
-
spi_unregister_controller(ctlr);
- clk_disable_unprepare(sp->clk);
}
static struct platform_driver ar934x_spi_driver = {
@@ -238,7 +223,7 @@ static struct platform_driver ar934x_spi_driver = {
.of_match_table = ar934x_spi_match,
},
.probe = ar934x_spi_probe,
- .remove_new = ar934x_spi_remove,
+ .remove = ar934x_spi_remove,
};
module_platform_driver(ar934x_spi_driver);
diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c
index a7fb7c94e70e..02c1e625742d 100644
--- a/drivers/spi/spi-armada-3700.c
+++ b/drivers/spi/spi-armada-3700.c
@@ -17,8 +17,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/spi/spi.h>
@@ -340,7 +339,7 @@ static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id)
static bool a3700_spi_wait_completion(struct spi_device *spi)
{
struct a3700_spi *a3700_spi;
- unsigned int timeout;
+ unsigned long time_left;
unsigned int ctrl_reg;
unsigned long timeout_jiffies;
@@ -362,12 +361,12 @@ static bool a3700_spi_wait_completion(struct spi_device *spi)
a3700_spi->wait_mask);
timeout_jiffies = msecs_to_jiffies(A3700_SPI_TIMEOUT);
- timeout = wait_for_completion_timeout(&a3700_spi->done,
- timeout_jiffies);
+ time_left = wait_for_completion_timeout(&a3700_spi->done,
+ timeout_jiffies);
a3700_spi->wait_mask = 0;
- if (timeout)
+ if (time_left)
return true;
/* there might be the case that right after we checked the
@@ -866,18 +865,12 @@ static int a3700_spi_probe(struct platform_device *pdev)
init_completion(&spi->done);
- spi->clk = devm_clk_get(dev, NULL);
+ spi->clk = devm_clk_get_prepared(dev, NULL);
if (IS_ERR(spi->clk)) {
dev_err(dev, "could not find clk: %ld\n", PTR_ERR(spi->clk));
goto error;
}
- ret = clk_prepare(spi->clk);
- if (ret) {
- dev_err(dev, "could not prepare clk: %d\n", ret);
- goto error;
- }
-
host->max_speed_hz = min_t(unsigned long, A3700_SPI_MAX_SPEED_HZ,
clk_get_rate(spi->clk));
host->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk),
@@ -889,40 +882,29 @@ static int a3700_spi_probe(struct platform_device *pdev)
dev_name(dev), host);
if (ret) {
dev_err(dev, "could not request IRQ: %d\n", ret);
- goto error_clk;
+ goto error;
}
ret = devm_spi_register_controller(dev, host);
if (ret) {
dev_err(dev, "Failed to register host\n");
- goto error_clk;
+ goto error;
}
return 0;
-error_clk:
- clk_unprepare(spi->clk);
error:
spi_controller_put(host);
out:
return ret;
}
-static void a3700_spi_remove(struct platform_device *pdev)
-{
- struct spi_controller *host = platform_get_drvdata(pdev);
- struct a3700_spi *spi = spi_controller_get_devdata(host);
-
- clk_unprepare(spi->clk);
-}
-
static struct platform_driver a3700_spi_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(a3700_spi_dt_ids),
},
.probe = a3700_spi_probe,
- .remove_new = a3700_spi_remove,
};
module_platform_driver(a3700_spi_driver);
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index e75b0d51f06a..db3e096f2eb0 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -7,6 +7,7 @@
*/
#include <linux/clk.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -67,6 +68,7 @@ struct aspeed_spi_chip {
u32 ahb_window_size;
u32 ctl_val[ASPEED_SPI_MAX];
u32 clk_freq;
+ bool force_user_mode;
};
struct aspeed_spi_data {
@@ -78,10 +80,14 @@ struct aspeed_spi_data {
u32 timing;
u32 hclk_mask;
u32 hdiv_max;
-
- u32 (*segment_start)(struct aspeed_spi *aspi, u32 reg);
- u32 (*segment_end)(struct aspeed_spi *aspi, u32 reg);
- u32 (*segment_reg)(struct aspeed_spi *aspi, u32 start, u32 end);
+ u32 min_window_size;
+
+ phys_addr_t (*segment_start)(struct aspeed_spi *aspi, u32 reg);
+ phys_addr_t (*segment_end)(struct aspeed_spi *aspi, u32 reg);
+ u32 (*segment_reg)(struct aspeed_spi *aspi, phys_addr_t start,
+ phys_addr_t end);
+ int (*adjust_window)(struct aspeed_spi *aspi);
+ u32 (*get_clk_div)(struct aspeed_spi_chip *chip, u32 hz);
int (*calibrate)(struct aspeed_spi_chip *chip, u32 hdiv,
const u8 *golden_buf, u8 *test_buf);
};
@@ -92,9 +98,9 @@ struct aspeed_spi {
const struct aspeed_spi_data *data;
void __iomem *regs;
- void __iomem *ahb_base;
- u32 ahb_base_phy;
+ phys_addr_t ahb_base_phy;
u32 ahb_window_size;
+ u32 num_cs;
struct device *dev;
struct clk *clk;
@@ -239,7 +245,7 @@ static ssize_t aspeed_spi_read_user(struct aspeed_spi_chip *chip,
ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, offset, op->cmd.opcode);
if (ret < 0)
- return ret;
+ goto stop_user;
if (op->dummy.buswidth && op->dummy.nbytes) {
for (i = 0; i < op->dummy.nbytes / op->dummy.buswidth; i++)
@@ -249,22 +255,28 @@ static ssize_t aspeed_spi_read_user(struct aspeed_spi_chip *chip,
aspeed_spi_set_io_mode(chip, io_mode);
aspeed_spi_read_from_ahb(buf, chip->ahb_base, len);
+stop_user:
aspeed_spi_stop_user(chip);
- return 0;
+ return ret;
}
static ssize_t aspeed_spi_write_user(struct aspeed_spi_chip *chip,
const struct spi_mem_op *op)
{
int ret;
+ int io_mode = aspeed_spi_get_io_mode(op);
aspeed_spi_start_user(chip);
ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, op->addr.val, op->cmd.opcode);
if (ret < 0)
- return ret;
+ goto stop_user;
+
+ aspeed_spi_set_io_mode(chip, io_mode);
+
aspeed_spi_write_to_ahb(chip->ahb_base, op->data.buf.out, op->data.nbytes);
+stop_user:
aspeed_spi_stop_user(chip);
- return 0;
+ return ret;
}
/* support for 1-1-1, 1-1-2 or 1-1-4 */
@@ -295,19 +307,12 @@ static const struct aspeed_spi_data ast2400_spi_data;
static int do_aspeed_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->controller);
struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(mem->spi, 0)];
u32 addr_mode, addr_mode_backup;
u32 ctl_val;
int ret = 0;
- dev_dbg(aspi->dev,
- "CE%d %s OP %#x mode:%d.%d.%d.%d naddr:%#x ndummies:%#x len:%#x",
- chip->cs, op->data.dir == SPI_MEM_DATA_IN ? "read" : "write",
- op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
- op->dummy.buswidth, op->data.buswidth,
- op->addr.nbytes, op->dummy.nbytes, op->data.nbytes);
-
addr_mode = readl(aspi->regs + CE_CTRL_REG);
addr_mode_backup = addr_mode;
@@ -374,96 +379,277 @@ static int aspeed_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
static const char *aspeed_spi_get_name(struct spi_mem *mem)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->controller);
struct device *dev = aspi->dev;
return devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
spi_get_chipselect(mem->spi, 0));
}
-struct aspeed_spi_window {
+static int aspeed_spi_set_window(struct aspeed_spi *aspi)
+{
+ struct device *dev = aspi->dev;
+ off_t offset = 0;
+ phys_addr_t start;
+ phys_addr_t end;
+ void __iomem *seg_reg_base = aspi->regs + CE0_SEGMENT_ADDR_REG;
+ void __iomem *seg_reg;
+ u32 seg_val_backup;
+ u32 seg_val;
u32 cs;
- u32 offset;
- u32 size;
-};
+ size_t window_size;
+
+ for (cs = 0; cs < aspi->data->max_cs; cs++) {
+ if (aspi->chips[cs].ahb_base) {
+ devm_iounmap(dev, aspi->chips[cs].ahb_base);
+ aspi->chips[cs].ahb_base = NULL;
+ }
+ }
+
+ for (cs = 0; cs < aspi->data->max_cs; cs++) {
+ seg_reg = seg_reg_base + cs * 4;
+ seg_val_backup = readl(seg_reg);
+
+ start = aspi->ahb_base_phy + offset;
+ window_size = aspi->chips[cs].ahb_window_size;
+ end = start + window_size;
+
+ seg_val = aspi->data->segment_reg(aspi, start, end);
+ writel(seg_val, seg_reg);
+
+ /*
+ * Restore initial value if something goes wrong or the segment
+ * register is written protected.
+ */
+ if (seg_val != readl(seg_reg)) {
+ dev_warn(dev, "CE%d expected window [ 0x%.9llx - 0x%.9llx ] %zdMB\n",
+ cs, (u64)start, (u64)end - 1, window_size >> 20);
+ writel(seg_val_backup, seg_reg);
+ window_size = aspi->data->segment_end(aspi, seg_val_backup) -
+ aspi->data->segment_start(aspi, seg_val_backup);
+ aspi->chips[cs].ahb_window_size = window_size;
+ end = start + window_size;
+ }
-static void aspeed_spi_get_windows(struct aspeed_spi *aspi,
- struct aspeed_spi_window windows[ASPEED_SPI_MAX_NUM_CS])
+ if (window_size != 0)
+ dev_dbg(dev, "CE%d window [ 0x%.9llx - 0x%.9llx ] %zdMB\n",
+ cs, (u64)start, (u64)end - 1, window_size >> 20);
+ else
+ dev_dbg(dev, "CE%d window closed\n", cs);
+
+ offset += window_size;
+ if (offset > aspi->ahb_window_size) {
+ dev_err(dev, "CE%d offset value 0x%llx is too large.\n",
+ cs, (u64)offset);
+ return -ENOSPC;
+ }
+
+ /*
+ * No need to map the address deocding range when
+ * - window size is 0.
+ * - the CS is unused.
+ */
+ if (window_size == 0 || cs >= aspi->num_cs)
+ continue;
+
+ aspi->chips[cs].ahb_base =
+ devm_ioremap(aspi->dev, start, window_size);
+ if (!aspi->chips[cs].ahb_base) {
+ dev_err(aspi->dev,
+ "Fail to remap window [0x%.9llx - 0x%.9llx]\n",
+ (u64)start, (u64)end - 1);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+static const struct aspeed_spi_data ast2500_spi_data;
+static const struct aspeed_spi_data ast2600_spi_data;
+static const struct aspeed_spi_data ast2600_fmc_data;
+
+static int aspeed_spi_chip_set_default_window(struct aspeed_spi *aspi)
{
- const struct aspeed_spi_data *data = aspi->data;
- u32 reg_val;
u32 cs;
- for (cs = 0; cs < aspi->data->max_cs; cs++) {
- reg_val = readl(aspi->regs + CE0_SEGMENT_ADDR_REG + cs * 4);
- windows[cs].cs = cs;
- windows[cs].size = data->segment_end(aspi, reg_val) -
- data->segment_start(aspi, reg_val);
- windows[cs].offset = data->segment_start(aspi, reg_val) - aspi->ahb_base_phy;
- dev_vdbg(aspi->dev, "CE%d offset=0x%.8x size=0x%x\n", cs,
- windows[cs].offset, windows[cs].size);
+ /* No segment registers for the AST2400 SPI controller */
+ if (aspi->data == &ast2400_spi_data) {
+ aspi->chips[0].ahb_base = devm_ioremap(aspi->dev,
+ aspi->ahb_base_phy,
+ aspi->ahb_window_size);
+ aspi->chips[0].ahb_window_size = aspi->ahb_window_size;
+ return 0;
}
+
+ /* Assign the minimum window size to each CS */
+ for (cs = 0; cs < aspi->num_cs; cs++) {
+ aspi->chips[cs].ahb_window_size = aspi->data->min_window_size;
+ dev_dbg(aspi->dev, "CE%d default window [ 0x%.9llx - 0x%.9llx ]",
+ cs, (u64)(aspi->ahb_base_phy + aspi->data->min_window_size * cs),
+ (u64)(aspi->ahb_base_phy + aspi->data->min_window_size * cs - 1));
+ }
+
+ /* Close unused CS */
+ for (cs = aspi->num_cs; cs < aspi->data->max_cs; cs++)
+ aspi->chips[cs].ahb_window_size = 0;
+
+ if (aspi->data->adjust_window)
+ aspi->data->adjust_window(aspi);
+
+ return aspeed_spi_set_window(aspi);
}
/*
- * On the AST2600, some CE windows are closed by default at reset but
- * U-Boot should open all.
+ * As the flash size grows up, we need to trim some decoding
+ * size if needed for the sake of conforming the maximum
+ * decoding size. We trim the decoding size from the rear CS
+ * to avoid affecting the default boot up sequence, usually,
+ * from CS0. Notice, if a CS decoding size is trimmed,
+ * command mode may not work perfectly on that CS, but it only
+ * affect performance and the debug function.
*/
-static int aspeed_spi_chip_set_default_window(struct aspeed_spi_chip *chip)
+static int aspeed_spi_trim_window_size(struct aspeed_spi *aspi)
{
- struct aspeed_spi *aspi = chip->aspi;
- struct aspeed_spi_window windows[ASPEED_SPI_MAX_NUM_CS] = { 0 };
- struct aspeed_spi_window *win = &windows[chip->cs];
+ struct aspeed_spi_chip *chips = aspi->chips;
+ size_t total_sz;
+ int cs = aspi->data->max_cs - 1;
+ u32 i;
+ bool trimmed = false;
+
+ do {
+ total_sz = 0;
+ for (i = 0; i < aspi->data->max_cs; i++)
+ total_sz += chips[i].ahb_window_size;
+
+ if (cs < 0)
+ return -ENOMEM;
+
+ if (chips[cs].ahb_window_size <= aspi->data->min_window_size) {
+ cs--;
+ continue;
+ }
- /* No segment registers for the AST2400 SPI controller */
- if (aspi->data == &ast2400_spi_data) {
- win->offset = 0;
- win->size = aspi->ahb_window_size;
- } else {
- aspeed_spi_get_windows(aspi, windows);
+ if (total_sz > aspi->ahb_window_size) {
+ chips[cs].ahb_window_size -=
+ aspi->data->min_window_size;
+ total_sz -= aspi->data->min_window_size;
+ /*
+ * If the ahb window size is ever trimmed, only user
+ * mode can be adopted to access the whole flash.
+ */
+ chips[cs].force_user_mode = true;
+ trimmed = true;
+ }
+ } while (total_sz > aspi->ahb_window_size);
+
+ if (trimmed) {
+ dev_warn(aspi->dev, "Window size after trimming:\n");
+ for (cs = 0; cs < aspi->data->max_cs; cs++) {
+ dev_warn(aspi->dev, "CE%d: 0x%08x\n",
+ cs, chips[cs].ahb_window_size);
+ }
}
- chip->ahb_base = aspi->ahb_base + win->offset;
- chip->ahb_window_size = win->size;
+ return 0;
+}
+
+static int aspeed_adjust_window_ast2400(struct aspeed_spi *aspi)
+{
+ int ret;
+ int cs;
+ struct aspeed_spi_chip *chips = aspi->chips;
- dev_dbg(aspi->dev, "CE%d default window [ 0x%.8x - 0x%.8x ] %dMB",
- chip->cs, aspi->ahb_base_phy + win->offset,
- aspi->ahb_base_phy + win->offset + win->size - 1,
- win->size >> 20);
+ /* Close unused CS. */
+ for (cs = aspi->num_cs; cs < aspi->data->max_cs; cs++)
+ chips[cs].ahb_window_size = 0;
+
+ ret = aspeed_spi_trim_window_size(aspi);
+ if (ret != 0)
+ return ret;
- return chip->ahb_window_size ? 0 : -1;
+ return 0;
}
-static int aspeed_spi_set_window(struct aspeed_spi *aspi,
- const struct aspeed_spi_window *win)
+/*
+ * For AST2500, the minimum address decoding size for each CS
+ * is 8MB. This address decoding size is mandatory for each
+ * CS no matter whether it will be used. This is a HW limitation.
+ */
+static int aspeed_adjust_window_ast2500(struct aspeed_spi *aspi)
{
- u32 start = aspi->ahb_base_phy + win->offset;
- u32 end = start + win->size;
- void __iomem *seg_reg = aspi->regs + CE0_SEGMENT_ADDR_REG + win->cs * 4;
- u32 seg_val_backup = readl(seg_reg);
- u32 seg_val = aspi->data->segment_reg(aspi, start, end);
+ int ret;
+ int cs, i;
+ u32 cum_size, rem_size;
+ struct aspeed_spi_chip *chips = aspi->chips;
+
+ /* Assign min_window_sz to unused CS. */
+ for (cs = aspi->num_cs; cs < aspi->data->max_cs; cs++) {
+ if (chips[cs].ahb_window_size < aspi->data->min_window_size)
+ chips[cs].ahb_window_size =
+ aspi->data->min_window_size;
+ }
- if (seg_val == seg_val_backup)
- return 0;
+ /*
+ * If command mode or normal mode is used by dirmap read, the start
+ * address of a window should be multiple of its related flash size.
+ * Namely, the total windows size from flash 0 to flash N should
+ * be multiple of the size of flash (N + 1).
+ */
+ for (cs = aspi->num_cs - 1; cs >= 0; cs--) {
+ cum_size = 0;
+ for (i = 0; i < cs; i++)
+ cum_size += chips[i].ahb_window_size;
+
+ rem_size = cum_size % chips[cs].ahb_window_size;
+ if (chips[cs].ahb_window_size != 0 && rem_size != 0)
+ chips[0].ahb_window_size +=
+ chips[cs].ahb_window_size - rem_size;
+ }
+
+ ret = aspeed_spi_trim_window_size(aspi);
+ if (ret != 0)
+ return ret;
- writel(seg_val, seg_reg);
+ /* The total window size of AST2500 SPI1 CS0 and CS1 must be 128MB */
+ if (aspi->data == &ast2500_spi_data)
+ chips[1].ahb_window_size =
+ 0x08000000 - chips[0].ahb_window_size;
+
+ return 0;
+}
+
+static int aspeed_adjust_window_ast2600(struct aspeed_spi *aspi)
+{
+ int ret;
+ int cs, i;
+ u32 cum_size, rem_size;
+ struct aspeed_spi_chip *chips = aspi->chips;
+
+ /* Close unused CS. */
+ for (cs = aspi->num_cs; cs < aspi->data->max_cs; cs++)
+ chips[cs].ahb_window_size = 0;
/*
- * Restore initial value if something goes wrong else we could
- * loose access to the chip.
+ * If command mode or normal mode is used by dirmap read, the start
+ * address of a window should be multiple of its related flash size.
+ * Namely, the total windows size from flash 0 to flash N should
+ * be multiple of the size of flash (N + 1).
*/
- if (seg_val != readl(seg_reg)) {
- dev_err(aspi->dev, "CE%d invalid window [ 0x%.8x - 0x%.8x ] %dMB",
- win->cs, start, end - 1, win->size >> 20);
- writel(seg_val_backup, seg_reg);
- return -EIO;
+ for (cs = aspi->num_cs - 1; cs >= 0; cs--) {
+ cum_size = 0;
+ for (i = 0; i < cs; i++)
+ cum_size += chips[i].ahb_window_size;
+
+ rem_size = cum_size % chips[cs].ahb_window_size;
+ if (chips[cs].ahb_window_size != 0 && rem_size != 0)
+ chips[0].ahb_window_size +=
+ chips[cs].ahb_window_size - rem_size;
}
- if (win->size)
- dev_dbg(aspi->dev, "CE%d new window [ 0x%.8x - 0x%.8x ] %dMB",
- win->cs, start, end - 1, win->size >> 20);
- else
- dev_dbg(aspi->dev, "CE%d window closed", win->cs);
+ ret = aspeed_spi_trim_window_size(aspi);
+ if (ret != 0)
+ return ret;
return 0;
}
@@ -474,78 +660,27 @@ static int aspeed_spi_set_window(struct aspeed_spi *aspi,
* - ioremap each window, not strictly necessary since the overall window
* is correct.
*/
-static const struct aspeed_spi_data ast2500_spi_data;
-static const struct aspeed_spi_data ast2600_spi_data;
-static const struct aspeed_spi_data ast2600_fmc_data;
-
static int aspeed_spi_chip_adjust_window(struct aspeed_spi_chip *chip,
u32 local_offset, u32 size)
{
struct aspeed_spi *aspi = chip->aspi;
- struct aspeed_spi_window windows[ASPEED_SPI_MAX_NUM_CS] = { 0 };
- struct aspeed_spi_window *win = &windows[chip->cs];
int ret;
/* No segment registers for the AST2400 SPI controller */
if (aspi->data == &ast2400_spi_data)
return 0;
- /*
- * Due to an HW issue on the AST2500 SPI controller, the CE0
- * window size should be smaller than the maximum 128MB.
- */
- if (aspi->data == &ast2500_spi_data && chip->cs == 0 && size == SZ_128M) {
- size = 120 << 20;
- dev_info(aspi->dev, "CE%d window resized to %dMB (AST2500 HW quirk)",
- chip->cs, size >> 20);
- }
-
- /*
- * The decoding size of AST2600 SPI controller should set at
- * least 2MB.
- */
- if ((aspi->data == &ast2600_spi_data || aspi->data == &ast2600_fmc_data) &&
- size < SZ_2M) {
- size = SZ_2M;
- dev_info(aspi->dev, "CE%d window resized to %dMB (AST2600 Decoding)",
- chip->cs, size >> 20);
- }
-
- aspeed_spi_get_windows(aspi, windows);
-
/* Adjust this chip window */
- win->offset += local_offset;
- win->size = size;
+ aspi->chips[chip->cs].ahb_window_size = size;
- if (win->offset + win->size > aspi->ahb_window_size) {
- win->size = aspi->ahb_window_size - win->offset;
- dev_warn(aspi->dev, "CE%d window resized to %dMB", chip->cs, win->size >> 20);
- }
+ /* Adjust the overall windows size regarding each platform */
+ if (aspi->data->adjust_window)
+ aspi->data->adjust_window(aspi);
- ret = aspeed_spi_set_window(aspi, win);
+ ret = aspeed_spi_set_window(aspi);
if (ret)
return ret;
- /* Update chip mapping info */
- chip->ahb_base = aspi->ahb_base + win->offset;
- chip->ahb_window_size = win->size;
-
- /*
- * Also adjust next chip window to make sure that it does not
- * overlap with the current window.
- */
- if (chip->cs < aspi->data->max_cs - 1) {
- struct aspeed_spi_window *next = &windows[chip->cs + 1];
-
- /* Change offset and size to keep the same end address */
- if ((next->offset + next->size) > (win->offset + win->size))
- next->size = (next->offset + next->size) - (win->offset + win->size);
- else
- next->size = 0;
- next->offset = win->offset + win->size;
-
- aspeed_spi_set_window(aspi, next);
- }
return 0;
}
@@ -553,7 +688,7 @@ static int aspeed_spi_do_calibration(struct aspeed_spi_chip *chip);
static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller);
struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)];
struct spi_mem_op *op = &desc->info.op_tmpl;
u32 ctl_val;
@@ -620,11 +755,11 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offset, size_t len, void *buf)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->controller);
struct aspeed_spi_chip *chip = &aspi->chips[spi_get_chipselect(desc->mem->spi, 0)];
/* Switch to USER command mode if mapping window is too small */
- if (chip->ahb_window_size < offset + len) {
+ if (chip->ahb_window_size < offset + len || chip->force_user_mode) {
int ret;
ret = aspeed_spi_read_user(chip, &desc->info.op_tmpl, offset, len, buf);
@@ -669,7 +804,7 @@ static void aspeed_spi_chip_enable(struct aspeed_spi *aspi, unsigned int cs, boo
static int aspeed_spi_setup(struct spi_device *spi)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(spi->controller);
const struct aspeed_spi_data *data = aspi->data;
unsigned int cs = spi_get_chipselect(spi, 0);
struct aspeed_spi_chip *chip = &aspi->chips[cs];
@@ -682,11 +817,6 @@ static int aspeed_spi_setup(struct spi_device *spi)
if (data->hastype)
aspeed_spi_chip_set_type(aspi, cs, CONFIG_TYPE_SPI);
- if (aspeed_spi_chip_set_default_window(chip) < 0) {
- dev_warn(aspi->dev, "CE%d window invalid", cs);
- return -EINVAL;
- }
-
aspeed_spi_chip_enable(aspi, cs, true);
chip->ctl_val[ASPEED_SPI_BASE] = CTRL_CE_STOP_ACTIVE | CTRL_IO_MODE_USER;
@@ -697,7 +827,7 @@ static int aspeed_spi_setup(struct spi_device *spi)
static void aspeed_spi_cleanup(struct spi_device *spi)
{
- struct aspeed_spi *aspi = spi_controller_get_devdata(spi->master);
+ struct aspeed_spi *aspi = spi_controller_get_devdata(spi->controller);
unsigned int cs = spi_get_chipselect(spi, 0);
aspeed_spi_chip_enable(aspi, cs, false);
@@ -726,7 +856,7 @@ static int aspeed_spi_probe(struct platform_device *pdev)
if (!data)
return -ENODEV;
- ctlr = devm_spi_alloc_master(dev, sizeof(*aspi));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*aspi));
if (!ctlr)
return -ENOMEM;
@@ -739,16 +869,16 @@ static int aspeed_spi_probe(struct platform_device *pdev)
if (IS_ERR(aspi->regs))
return PTR_ERR(aspi->regs);
- aspi->ahb_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
- if (IS_ERR(aspi->ahb_base)) {
- dev_err(dev, "missing AHB mapping window\n");
- return PTR_ERR(aspi->ahb_base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(dev, "missing AHB memory\n");
+ return -EINVAL;
}
aspi->ahb_window_size = resource_size(res);
aspi->ahb_base_phy = res->start;
- aspi->clk = devm_clk_get(&pdev->dev, NULL);
+ aspi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(aspi->clk)) {
dev_err(dev, "missing clock\n");
return PTR_ERR(aspi->clk);
@@ -760,12 +890,6 @@ static int aspeed_spi_probe(struct platform_device *pdev)
return -EINVAL;
}
- ret = clk_prepare_enable(aspi->clk);
- if (ret) {
- dev_err(dev, "can not enable the clock\n");
- return ret;
- }
-
/* IRQ is for DMA, which the driver doesn't support yet */
ctlr->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | data->mode_bits;
@@ -773,18 +897,21 @@ static int aspeed_spi_probe(struct platform_device *pdev)
ctlr->mem_ops = &aspeed_spi_mem_ops;
ctlr->setup = aspeed_spi_setup;
ctlr->cleanup = aspeed_spi_cleanup;
- ctlr->num_chipselect = data->max_cs;
+ ctlr->num_chipselect = of_get_available_child_count(dev->of_node);
ctlr->dev.of_node = dev->of_node;
- ret = devm_spi_register_controller(dev, ctlr);
+ aspi->num_cs = ctlr->num_chipselect;
+
+ ret = aspeed_spi_chip_set_default_window(aspi);
if (ret) {
- dev_err(&pdev->dev, "spi_register_controller failed\n");
- goto disable_clk;
+ dev_err(&pdev->dev, "fail to set default window\n");
+ return ret;
}
- return 0;
-disable_clk:
- clk_disable_unprepare(aspi->clk);
+ ret = devm_spi_register_controller(dev, ctlr);
+ if (ret)
+ dev_err(&pdev->dev, "spi_register_controller failed\n");
+
return ret;
}
@@ -793,7 +920,6 @@ static void aspeed_spi_remove(struct platform_device *pdev)
struct aspeed_spi *aspi = platform_get_drvdata(pdev);
aspeed_spi_enable(aspi, false);
- clk_disable_unprepare(aspi->clk);
}
/*
@@ -805,17 +931,18 @@ static void aspeed_spi_remove(struct platform_device *pdev)
* The address range is encoded with absolute addresses in the overall
* mapping window.
*/
-static u32 aspeed_spi_segment_start(struct aspeed_spi *aspi, u32 reg)
+static phys_addr_t aspeed_spi_segment_start(struct aspeed_spi *aspi, u32 reg)
{
return ((reg >> 16) & 0xFF) << 23;
}
-static u32 aspeed_spi_segment_end(struct aspeed_spi *aspi, u32 reg)
+static phys_addr_t aspeed_spi_segment_end(struct aspeed_spi *aspi, u32 reg)
{
return ((reg >> 24) & 0xFF) << 23;
}
-static u32 aspeed_spi_segment_reg(struct aspeed_spi *aspi, u32 start, u32 end)
+static u32 aspeed_spi_segment_reg(struct aspeed_spi *aspi,
+ phys_addr_t start, phys_addr_t end)
{
return (((start >> 23) & 0xFF) << 16) | (((end >> 23) & 0xFF) << 24);
}
@@ -827,16 +954,16 @@ static u32 aspeed_spi_segment_reg(struct aspeed_spi *aspi, u32 start, u32 end)
#define AST2600_SEG_ADDR_MASK 0x0ff00000
-static u32 aspeed_spi_segment_ast2600_start(struct aspeed_spi *aspi,
- u32 reg)
+static phys_addr_t aspeed_spi_segment_ast2600_start(struct aspeed_spi *aspi,
+ u32 reg)
{
u32 start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK;
return aspi->ahb_base_phy + start_offset;
}
-static u32 aspeed_spi_segment_ast2600_end(struct aspeed_spi *aspi,
- u32 reg)
+static phys_addr_t aspeed_spi_segment_ast2600_end(struct aspeed_spi *aspi,
+ u32 reg)
{
u32 end_offset = reg & AST2600_SEG_ADDR_MASK;
@@ -848,7 +975,7 @@ static u32 aspeed_spi_segment_ast2600_end(struct aspeed_spi *aspi,
}
static u32 aspeed_spi_segment_ast2600_reg(struct aspeed_spi *aspi,
- u32 start, u32 end)
+ phys_addr_t start, phys_addr_t end)
{
/* disable zero size segments */
if (start == end)
@@ -858,6 +985,41 @@ static u32 aspeed_spi_segment_ast2600_reg(struct aspeed_spi *aspi,
((end - 1) & AST2600_SEG_ADDR_MASK);
}
+/* The Segment Registers of the AST2700 use a 64KB unit. */
+#define AST2700_SEG_ADDR_MASK 0x7fff0000
+
+static phys_addr_t aspeed_spi_segment_ast2700_start(struct aspeed_spi *aspi,
+ u32 reg)
+{
+ u64 start_offset = (reg << 16) & AST2700_SEG_ADDR_MASK;
+
+ if (!start_offset)
+ return aspi->ahb_base_phy;
+
+ return aspi->ahb_base_phy + start_offset;
+}
+
+static phys_addr_t aspeed_spi_segment_ast2700_end(struct aspeed_spi *aspi,
+ u32 reg)
+{
+ u64 end_offset = reg & AST2700_SEG_ADDR_MASK;
+
+ if (!end_offset)
+ return aspi->ahb_base_phy;
+
+ return aspi->ahb_base_phy + end_offset;
+}
+
+static u32 aspeed_spi_segment_ast2700_reg(struct aspeed_spi *aspi,
+ phys_addr_t start, phys_addr_t end)
+{
+ if (start == end)
+ return 0;
+
+ return (u32)(((start & AST2700_SEG_ADDR_MASK) >> 16) |
+ (end & AST2700_SEG_ADDR_MASK));
+}
+
/*
* Read timing compensation sequences
*/
@@ -959,26 +1121,149 @@ static bool aspeed_spi_check_calib_data(const u8 *test_buf, u32 size)
}
static const u32 aspeed_spi_hclk_divs[] = {
- 0xf, /* HCLK */
- 0x7, /* HCLK/2 */
- 0xe, /* HCLK/3 */
- 0x6, /* HCLK/4 */
- 0xd, /* HCLK/5 */
+ /* HCLK, HCLK/2, HCLK/3, HCLK/4, HCLK/5, ..., HCLK/16 */
+ 0xf, 0x7, 0xe, 0x6, 0xd,
+ 0x5, 0xc, 0x4, 0xb, 0x3,
+ 0xa, 0x2, 0x9, 0x1, 0x8,
+ 0x0
};
#define ASPEED_SPI_HCLK_DIV(i) \
(aspeed_spi_hclk_divs[(i) - 1] << CTRL_FREQ_SEL_SHIFT)
+/* Transfer maximum clock frequency to register setting */
+static u32 aspeed_get_clk_div_ast2400(struct aspeed_spi_chip *chip,
+ u32 max_hz)
+{
+ struct device *dev = chip->aspi->dev;
+ u32 hclk_clk = chip->aspi->clk_freq;
+ u32 div_ctl = 0;
+ u32 i;
+ bool found = false;
+
+ /* FMC/SPIR10[11:8] */
+ for (i = 1; i <= ARRAY_SIZE(aspeed_spi_hclk_divs); i++) {
+ if (hclk_clk / i <= max_hz) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ div_ctl = ASPEED_SPI_HCLK_DIV(i);
+ chip->clk_freq = hclk_clk / i;
+ }
+
+ dev_dbg(dev, "found: %s, hclk: %d, max_clk: %d\n",
+ found ? "yes" : "no", hclk_clk, max_hz);
+
+ if (found) {
+ dev_dbg(dev, "h_div: 0x%08x, speed: %d\n",
+ div_ctl, chip->clk_freq);
+ }
+
+ return div_ctl;
+}
+
+static u32 aspeed_get_clk_div_ast2500(struct aspeed_spi_chip *chip,
+ u32 max_hz)
+{
+ struct device *dev = chip->aspi->dev;
+ u32 hclk_clk = chip->aspi->clk_freq;
+ u32 div_ctl = 0;
+ u32 i;
+ bool found = false;
+
+ /* FMC/SPIR10[11:8] */
+ for (i = 1; i <= ARRAY_SIZE(aspeed_spi_hclk_divs); i++) {
+ if (hclk_clk / i <= max_hz) {
+ found = true;
+ chip->clk_freq = hclk_clk / i;
+ break;
+ }
+ }
+
+ if (found) {
+ div_ctl = ASPEED_SPI_HCLK_DIV(i);
+ goto end;
+ }
+
+ for (i = 1; i <= ARRAY_SIZE(aspeed_spi_hclk_divs); i++) {
+ if (hclk_clk / (i * 4) <= max_hz) {
+ found = true;
+ chip->clk_freq = hclk_clk / (i * 4);
+ break;
+ }
+ }
+
+ if (found)
+ div_ctl = BIT(13) | ASPEED_SPI_HCLK_DIV(i);
+
+end:
+ dev_dbg(dev, "found: %s, hclk: %d, max_clk: %d\n",
+ found ? "yes" : "no", hclk_clk, max_hz);
+
+ if (found) {
+ dev_dbg(dev, "h_div: 0x%08x, speed: %d\n",
+ div_ctl, chip->clk_freq);
+ }
+
+ return div_ctl;
+}
+
+static u32 aspeed_get_clk_div_ast2600(struct aspeed_spi_chip *chip,
+ u32 max_hz)
+{
+ struct device *dev = chip->aspi->dev;
+ u32 hclk_clk = chip->aspi->clk_freq;
+ u32 div_ctl = 0;
+ u32 i, j;
+ bool found = false;
+
+ /* FMC/SPIR10[27:24] */
+ for (j = 0; j < 16; j++) {
+ /* FMC/SPIR10[11:8] */
+ for (i = 1; i <= ARRAY_SIZE(aspeed_spi_hclk_divs); i++) {
+ if (j == 0 && i == 1)
+ continue;
+
+ if (hclk_clk / (j * 16 + i) <= max_hz) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ div_ctl = ((j << 24) | ASPEED_SPI_HCLK_DIV(i));
+ chip->clk_freq = hclk_clk / (j * 16 + i);
+ break;
+ }
+ }
+
+ dev_dbg(dev, "found: %s, hclk: %d, max_clk: %d\n",
+ found ? "yes" : "no", hclk_clk, max_hz);
+
+ if (found) {
+ dev_dbg(dev, "h_div: 0x%08x, speed: %d\n",
+ div_ctl, chip->clk_freq);
+ }
+
+ return div_ctl;
+}
+
static int aspeed_spi_do_calibration(struct aspeed_spi_chip *chip)
{
struct aspeed_spi *aspi = chip->aspi;
const struct aspeed_spi_data *data = aspi->data;
u32 ahb_freq = aspi->clk_freq;
u32 max_freq = chip->clk_freq;
+ bool exec_calib = false;
+ u32 best_freq = 0;
u32 ctl_val;
u8 *golden_buf = NULL;
u8 *test_buf = NULL;
- int i, rc, best_div = -1;
+ int i, rc;
+ u32 div_ctl;
dev_dbg(aspi->dev, "calculate timing compensation - AHB freq: %d MHz",
ahb_freq / 1000000);
@@ -999,7 +1284,7 @@ static int aspeed_spi_do_calibration(struct aspeed_spi_chip *chip)
memcpy_fromio(golden_buf, chip->ahb_base, CALIBRATE_BUF_SIZE);
if (!aspeed_spi_check_calib_data(golden_buf, CALIBRATE_BUF_SIZE)) {
dev_info(aspi->dev, "Calibration area too uniform, using low speed");
- goto no_calib;
+ goto end_calib;
}
#if defined(VERBOSE_DEBUG)
@@ -1008,7 +1293,7 @@ static int aspeed_spi_do_calibration(struct aspeed_spi_chip *chip)
#endif
/* Now we iterate the HCLK dividers until we find our breaking point */
- for (i = ARRAY_SIZE(aspeed_spi_hclk_divs); i > data->hdiv_max - 1; i--) {
+ for (i = 5; i > data->hdiv_max - 1; i--) {
u32 tv, freq;
freq = ahb_freq / i;
@@ -1021,22 +1306,33 @@ static int aspeed_spi_do_calibration(struct aspeed_spi_chip *chip)
dev_dbg(aspi->dev, "Trying HCLK/%d [%08x] ...", i, tv);
rc = data->calibrate(chip, i, golden_buf, test_buf);
if (rc == 0)
- best_div = i;
+ best_freq = freq;
+
+ exec_calib = true;
}
- /* Nothing found ? */
- if (best_div < 0) {
- dev_warn(aspi->dev, "No good frequency, using dumb slow");
+end_calib:
+ if (!exec_calib) {
+ /* calibration process is not executed */
+ dev_warn(aspi->dev, "Force to dts configuration %dkHz.\n",
+ max_freq / 1000);
+ div_ctl = data->get_clk_div(chip, max_freq);
+ } else if (best_freq == 0) {
+ /* calibration process is executed, but no good frequency */
+ dev_warn(aspi->dev, "No good frequency, using dumb slow\n");
+ div_ctl = 0;
} else {
- dev_dbg(aspi->dev, "Found good read timings at HCLK/%d", best_div);
+ dev_dbg(aspi->dev, "Found good read timings at %dMHz.\n",
+ best_freq / 1000000);
+ div_ctl = data->get_clk_div(chip, best_freq);
+ }
- /* Record the freq */
- for (i = 0; i < ASPEED_SPI_MAX; i++)
- chip->ctl_val[i] = (chip->ctl_val[i] & data->hclk_mask) |
- ASPEED_SPI_HCLK_DIV(best_div);
+ /* Record the freq */
+ for (i = 0; i < ASPEED_SPI_MAX; i++) {
+ chip->ctl_val[i] = (chip->ctl_val[i] & data->hclk_mask) |
+ div_ctl;
}
-no_calib:
writel(chip->ctl_val[ASPEED_SPI_READ], chip->ctl);
kfree(test_buf);
return 0;
@@ -1044,21 +1340,57 @@ no_calib:
#define TIMING_DELAY_DI BIT(3)
#define TIMING_DELAY_HCYCLE_MAX 5
+#define TIMING_DELAY_INPUT_MAX 16
#define TIMING_REG_AST2600(chip) \
((chip)->aspi->regs + (chip)->aspi->data->timing + \
(chip)->cs * 4)
+/*
+ * This function returns the center point of the longest
+ * continuous "pass" interval within the buffer. The interval
+ * must contains the highest number of consecutive "pass"
+ * results and not span across multiple rows.
+ */
+static u32 aspeed_spi_ast2600_optimized_timing(u32 rows, u32 cols,
+ u8 buf[rows][cols])
+{
+ int r = 0, c = 0;
+ int max = 0;
+ int i, j;
+
+ for (i = 0; i < rows; i++) {
+ for (j = 0; j < cols;) {
+ int k = j;
+
+ while (k < cols && buf[i][k])
+ k++;
+
+ if (k - j > max) {
+ max = k - j;
+ r = i;
+ c = j + (k - j) / 2;
+ }
+
+ j = k + 1;
+ }
+ }
+
+ return max > 4 ? r * cols + c : 0;
+}
+
static int aspeed_spi_ast2600_calibrate(struct aspeed_spi_chip *chip, u32 hdiv,
const u8 *golden_buf, u8 *test_buf)
{
struct aspeed_spi *aspi = chip->aspi;
int hcycle;
+ int delay_ns;
u32 shift = (hdiv - 2) << 3;
- u32 mask = ~(0xfu << shift);
+ u32 mask = ~(0xffu << shift);
u32 fread_timing_val = 0;
+ u8 calib_res[6][17] = {0};
+ u32 calib_point;
for (hcycle = 0; hcycle <= TIMING_DELAY_HCYCLE_MAX; hcycle++) {
- int delay_ns;
bool pass = false;
fread_timing_val &= mask;
@@ -1071,14 +1403,14 @@ static int aspeed_spi_ast2600_calibrate(struct aspeed_spi_chip *chip, u32 hdiv,
" * [%08x] %d HCLK delay, DI delay none : %s",
fread_timing_val, hcycle, pass ? "PASS" : "FAIL");
if (pass)
- return 0;
+ calib_res[hcycle][0] = 1;
/* Add DI input delays */
fread_timing_val &= mask;
fread_timing_val |= (TIMING_DELAY_DI | hcycle) << shift;
- for (delay_ns = 0; delay_ns < 0x10; delay_ns++) {
- fread_timing_val &= ~(0xf << (4 + shift));
+ for (delay_ns = 0; delay_ns < TIMING_DELAY_INPUT_MAX; delay_ns++) {
+ fread_timing_val &= ~(0xfu << (4 + shift));
fread_timing_val |= delay_ns << (4 + shift);
writel(fread_timing_val, TIMING_REG_AST2600(chip));
@@ -1087,18 +1419,28 @@ static int aspeed_spi_ast2600_calibrate(struct aspeed_spi_chip *chip, u32 hdiv,
" * [%08x] %d HCLK delay, DI delay %d.%dns : %s",
fread_timing_val, hcycle, (delay_ns + 1) / 2,
(delay_ns + 1) & 1 ? 5 : 5, pass ? "PASS" : "FAIL");
- /*
- * TODO: This is optimistic. We should look
- * for a working interval and save the middle
- * value in the read timing register.
- */
+
if (pass)
- return 0;
+ calib_res[hcycle][delay_ns + 1] = 1;
}
}
+ calib_point = aspeed_spi_ast2600_optimized_timing(6, 17, calib_res);
/* No good setting for this frequency */
- return -1;
+ if (calib_point == 0)
+ return -1;
+
+ hcycle = calib_point / 17;
+ delay_ns = calib_point % 17;
+
+ fread_timing_val = (TIMING_DELAY_DI | hcycle | (delay_ns << 4)) << shift;
+
+ dev_dbg(aspi->dev, "timing val: %08x, final hcycle: %d, delay_ns: %d\n",
+ fread_timing_val, hcycle, delay_ns);
+
+ writel(fread_timing_val, TIMING_REG_AST2600(chip));
+
+ return 0;
}
/*
@@ -1112,10 +1454,13 @@ static const struct aspeed_spi_data ast2400_fmc_data = {
.timing = CE0_TIMING_COMPENSATION_REG,
.hclk_mask = 0xfffff0ff,
.hdiv_max = 1,
+ .min_window_size = 0x800000,
.calibrate = aspeed_spi_calibrate,
+ .get_clk_div = aspeed_get_clk_div_ast2400,
.segment_start = aspeed_spi_segment_start,
.segment_end = aspeed_spi_segment_end,
.segment_reg = aspeed_spi_segment_reg,
+ .adjust_window = aspeed_adjust_window_ast2400,
};
static const struct aspeed_spi_data ast2400_spi_data = {
@@ -1126,6 +1471,7 @@ static const struct aspeed_spi_data ast2400_spi_data = {
.timing = 0x14,
.hclk_mask = 0xfffff0ff,
.hdiv_max = 1,
+ .get_clk_div = aspeed_get_clk_div_ast2400,
.calibrate = aspeed_spi_calibrate,
/* No segment registers */
};
@@ -1138,10 +1484,13 @@ static const struct aspeed_spi_data ast2500_fmc_data = {
.timing = CE0_TIMING_COMPENSATION_REG,
.hclk_mask = 0xffffd0ff,
.hdiv_max = 1,
+ .min_window_size = 0x800000,
+ .get_clk_div = aspeed_get_clk_div_ast2500,
.calibrate = aspeed_spi_calibrate,
.segment_start = aspeed_spi_segment_start,
.segment_end = aspeed_spi_segment_end,
.segment_reg = aspeed_spi_segment_reg,
+ .adjust_window = aspeed_adjust_window_ast2500,
};
static const struct aspeed_spi_data ast2500_spi_data = {
@@ -1152,10 +1501,13 @@ static const struct aspeed_spi_data ast2500_spi_data = {
.timing = CE0_TIMING_COMPENSATION_REG,
.hclk_mask = 0xffffd0ff,
.hdiv_max = 1,
+ .min_window_size = 0x800000,
+ .get_clk_div = aspeed_get_clk_div_ast2500,
.calibrate = aspeed_spi_calibrate,
.segment_start = aspeed_spi_segment_start,
.segment_end = aspeed_spi_segment_end,
.segment_reg = aspeed_spi_segment_reg,
+ .adjust_window = aspeed_adjust_window_ast2500,
};
static const struct aspeed_spi_data ast2600_fmc_data = {
@@ -1167,10 +1519,13 @@ static const struct aspeed_spi_data ast2600_fmc_data = {
.timing = CE0_TIMING_COMPENSATION_REG,
.hclk_mask = 0xf0fff0ff,
.hdiv_max = 2,
+ .min_window_size = 0x200000,
+ .get_clk_div = aspeed_get_clk_div_ast2600,
.calibrate = aspeed_spi_ast2600_calibrate,
.segment_start = aspeed_spi_segment_ast2600_start,
.segment_end = aspeed_spi_segment_ast2600_end,
.segment_reg = aspeed_spi_segment_ast2600_reg,
+ .adjust_window = aspeed_adjust_window_ast2600,
};
static const struct aspeed_spi_data ast2600_spi_data = {
@@ -1182,10 +1537,47 @@ static const struct aspeed_spi_data ast2600_spi_data = {
.timing = CE0_TIMING_COMPENSATION_REG,
.hclk_mask = 0xf0fff0ff,
.hdiv_max = 2,
+ .min_window_size = 0x200000,
+ .get_clk_div = aspeed_get_clk_div_ast2600,
.calibrate = aspeed_spi_ast2600_calibrate,
.segment_start = aspeed_spi_segment_ast2600_start,
.segment_end = aspeed_spi_segment_ast2600_end,
.segment_reg = aspeed_spi_segment_ast2600_reg,
+ .adjust_window = aspeed_adjust_window_ast2600,
+};
+
+static const struct aspeed_spi_data ast2700_fmc_data = {
+ .max_cs = 3,
+ .hastype = false,
+ .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD,
+ .we0 = 16,
+ .ctl0 = CE0_CTRL_REG,
+ .timing = CE0_TIMING_COMPENSATION_REG,
+ .hclk_mask = 0xf0fff0ff,
+ .hdiv_max = 2,
+ .min_window_size = 0x10000,
+ .get_clk_div = aspeed_get_clk_div_ast2600,
+ .calibrate = aspeed_spi_ast2600_calibrate,
+ .segment_start = aspeed_spi_segment_ast2700_start,
+ .segment_end = aspeed_spi_segment_ast2700_end,
+ .segment_reg = aspeed_spi_segment_ast2700_reg,
+};
+
+static const struct aspeed_spi_data ast2700_spi_data = {
+ .max_cs = 2,
+ .hastype = false,
+ .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD,
+ .we0 = 16,
+ .ctl0 = CE0_CTRL_REG,
+ .timing = CE0_TIMING_COMPENSATION_REG,
+ .hclk_mask = 0xf0fff0ff,
+ .hdiv_max = 2,
+ .min_window_size = 0x10000,
+ .get_clk_div = aspeed_get_clk_div_ast2600,
+ .calibrate = aspeed_spi_ast2600_calibrate,
+ .segment_start = aspeed_spi_segment_ast2700_start,
+ .segment_end = aspeed_spi_segment_ast2700_end,
+ .segment_reg = aspeed_spi_segment_ast2700_reg,
};
static const struct of_device_id aspeed_spi_matches[] = {
@@ -1195,13 +1587,15 @@ static const struct of_device_id aspeed_spi_matches[] = {
{ .compatible = "aspeed,ast2500-spi", .data = &ast2500_spi_data },
{ .compatible = "aspeed,ast2600-fmc", .data = &ast2600_fmc_data },
{ .compatible = "aspeed,ast2600-spi", .data = &ast2600_spi_data },
+ { .compatible = "aspeed,ast2700-fmc", .data = &ast2700_fmc_data },
+ { .compatible = "aspeed,ast2700-spi", .data = &ast2700_spi_data },
{ }
};
MODULE_DEVICE_TABLE(of, aspeed_spi_matches);
static struct platform_driver aspeed_spi_driver = {
.probe = aspeed_spi_probe,
- .remove_new = aspeed_spi_remove,
+ .remove = aspeed_spi_remove,
.driver = {
.name = DEVICE_NAME,
.of_match_table = aspeed_spi_matches,
diff --git a/drivers/spi/spi-at91-usart.c b/drivers/spi/spi-at91-usart.c
index 7854d9790fe9..bbe97ce89a2f 100644
--- a/drivers/spi/spi-at91-usart.c
+++ b/drivers/spi/spi-at91-usart.c
@@ -13,7 +13,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -133,28 +132,14 @@ static int at91_usart_spi_configure_dma(struct spi_controller *ctlr,
dma_cap_set(DMA_SLAVE, mask);
ctlr->dma_tx = dma_request_chan(dev, "tx");
- if (IS_ERR_OR_NULL(ctlr->dma_tx)) {
- if (IS_ERR(ctlr->dma_tx)) {
- err = PTR_ERR(ctlr->dma_tx);
- goto at91_usart_spi_error_clear;
- }
-
- dev_dbg(dev,
- "DMA TX channel not available, SPI unable to use DMA\n");
- err = -EBUSY;
+ if (IS_ERR(ctlr->dma_tx)) {
+ err = PTR_ERR(ctlr->dma_tx);
goto at91_usart_spi_error_clear;
}
ctlr->dma_rx = dma_request_chan(dev, "rx");
- if (IS_ERR_OR_NULL(ctlr->dma_rx)) {
- if (IS_ERR(ctlr->dma_rx)) {
- err = PTR_ERR(ctlr->dma_rx);
- goto at91_usart_spi_error;
- }
-
- dev_dbg(dev,
- "DMA RX channel not available, SPI unable to use DMA\n");
- err = -EBUSY;
+ if (IS_ERR(ctlr->dma_rx)) {
+ err = PTR_ERR(ctlr->dma_rx);
goto at91_usart_spi_error;
}
@@ -486,10 +471,7 @@ static int at91_usart_gpio_setup(struct platform_device *pdev)
cs_gpios = devm_gpiod_get_array_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
- if (IS_ERR(cs_gpios))
- return PTR_ERR(cs_gpios);
-
- return 0;
+ return PTR_ERR_OR_ZERO(cs_gpios);
}
static int at91_usart_spi_probe(struct platform_device *pdev)
@@ -527,7 +509,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
controller->dev.of_node = pdev->dev.parent->of_node;
controller->bits_per_word_mask = SPI_BPW_MASK(8);
controller->setup = at91_usart_spi_setup;
- controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
+ controller->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
controller->transfer_one = at91_usart_spi_transfer_one;
controller->prepare_message = at91_usart_spi_prepare_message;
controller->unprepare_message = at91_usart_spi_unprepare_message;
@@ -668,7 +650,7 @@ static struct platform_driver at91_usart_spi_driver = {
.pm = &at91_usart_spi_pm_ops,
},
.probe = at91_usart_spi_probe,
- .remove_new = at91_usart_spi_remove,
+ .remove = at91_usart_spi_remove,
};
module_platform_driver(at91_usart_spi_driver);
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index d3dd21386f12..9a705a9fddd2 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -146,7 +146,7 @@ static int ath79_exec_mem_op(struct spi_mem *mem,
/* Only use for fast-read op. */
if (op->cmd.opcode != 0x0b || op->data.dir != SPI_MEM_DATA_IN ||
op->addr.nbytes != 3 || op->dummy.nbytes != 1)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
/* disable GPIO mode */
ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
@@ -185,11 +185,11 @@ static int ath79_spi_probe(struct platform_device *pdev)
host->use_gpio_descriptors = true;
host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- host->flags = SPI_MASTER_GPIO_SS;
+ host->flags = SPI_CONTROLLER_GPIO_SS;
host->num_chipselect = 3;
host->mem_ops = &ath79_mem_ops;
- sp->bitbang.master = host;
+ sp->bitbang.ctlr = host;
sp->bitbang.chipselect = ath79_spi_chipselect;
sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
sp->bitbang.flags = SPI_CS_HIGH;
@@ -200,20 +200,16 @@ static int ath79_spi_probe(struct platform_device *pdev)
goto err_put_host;
}
- sp->clk = devm_clk_get(&pdev->dev, "ahb");
+ sp->clk = devm_clk_get_enabled(&pdev->dev, "ahb");
if (IS_ERR(sp->clk)) {
ret = PTR_ERR(sp->clk);
goto err_put_host;
}
- ret = clk_prepare_enable(sp->clk);
- if (ret)
- goto err_put_host;
-
rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
if (!rate) {
ret = -EINVAL;
- goto err_clk_disable;
+ goto err_put_host;
}
sp->rrw_delay = ATH79_SPI_RRW_DELAY_FACTOR / rate;
@@ -229,8 +225,6 @@ static int ath79_spi_probe(struct platform_device *pdev)
err_disable:
ath79_spi_disable(sp);
-err_clk_disable:
- clk_disable_unprepare(sp->clk);
err_put_host:
spi_controller_put(host);
@@ -243,8 +237,7 @@ static void ath79_spi_remove(struct platform_device *pdev)
spi_bitbang_stop(&sp->bitbang);
ath79_spi_disable(sp);
- clk_disable_unprepare(sp->clk);
- spi_controller_put(sp->bitbang.master);
+ spi_controller_put(sp->bitbang.ctlr);
}
static void ath79_spi_shutdown(struct platform_device *pdev)
@@ -260,7 +253,7 @@ MODULE_DEVICE_TABLE(of, ath79_spi_of_match);
static struct platform_driver ath79_spi_driver = {
.probe = ath79_spi_probe,
- .remove_new = ath79_spi_remove,
+ .remove = ath79_spi_remove,
.shutdown = ath79_spi_shutdown,
.driver = {
.name = DRV_NAME,
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 152cd6773403..89977bff76d2 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -22,6 +22,7 @@
#include <linux/gpio/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
+#include <linux/iopoll.h>
#include <trace/events/spi.h>
/* SPI register offsets */
@@ -233,9 +234,6 @@
*/
#define DMA_MIN_BYTES 16
-#define SPI_DMA_MIN_TIMEOUT (msecs_to_jiffies(1000))
-#define SPI_DMA_TIMEOUT_PER_10K (msecs_to_jiffies(4))
-
#define AUTOSUSPEND_TIMEOUT 2000
struct atmel_spi_caps {
@@ -258,6 +256,7 @@ struct atmel_spi {
void __iomem *regs;
int irq;
struct clk *clk;
+ struct clk *gclk;
struct platform_device *pdev;
unsigned long spi_clk;
@@ -279,6 +278,7 @@ struct atmel_spi {
bool keep_cs;
u32 fifo_size;
+ bool last_polarity;
u8 native_cs_free;
u8 native_cs_for_gpio;
};
@@ -292,6 +292,22 @@ struct atmel_spi_device {
#define INVALID_DMA_ADDRESS 0xffffffff
/*
+ * This frequency can be anything supported by the controller, but to avoid
+ * unnecessary delay, the highest possible frequency is chosen.
+ *
+ * This frequency is the highest possible which is not interfering with other
+ * chip select registers (see Note for Serial Clock Bit Rate configuration in
+ * Atmel-11121F-ATARM-SAMA5D3-Series-Datasheet_02-Feb-16, page 1283)
+ */
+#define DUMMY_MSG_FREQUENCY 0x02
+/*
+ * 8 bits is the minimum data the controller is capable of sending.
+ *
+ * This message can be anything as it should not be treated by any SPI device.
+ */
+#define DUMMY_MSG 0xAA
+
+/*
* Version 2 of the SPI controller has
* - CR.LASTXFER
* - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero)
@@ -305,6 +321,43 @@ static bool atmel_spi_is_v2(struct atmel_spi *as)
}
/*
+ * Send a dummy message.
+ *
+ * This is sometimes needed when using a CS GPIO to force clock transition when
+ * switching between devices with different polarities.
+ */
+static void atmel_spi_send_dummy(struct atmel_spi *as, struct spi_device *spi, int chip_select)
+{
+ u32 status;
+ u32 csr;
+
+ /*
+ * Set a clock frequency to allow sending message on SPI bus.
+ * The frequency here can be anything, but is needed for
+ * the controller to send the data.
+ */
+ csr = spi_readl(as, CSR0 + 4 * chip_select);
+ csr = SPI_BFINS(SCBR, DUMMY_MSG_FREQUENCY, csr);
+ spi_writel(as, CSR0 + 4 * chip_select, csr);
+
+ /*
+ * Read all data coming from SPI bus, needed to be able to send
+ * the message.
+ */
+ spi_readl(as, RDR);
+ while (spi_readl(as, SR) & SPI_BIT(RDRF)) {
+ spi_readl(as, RDR);
+ cpu_relax();
+ }
+
+ spi_writel(as, TDR, DUMMY_MSG);
+
+ readl_poll_timeout_atomic(as->regs + SPI_SR, status,
+ (status & SPI_BIT(TXEMPTY)), 1, 1000);
+}
+
+
+/*
* Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
* they assume that spi slave device state will not change on deselect, so
* that automagic deselection is OK. ("NPCSx rises if no data is to be
@@ -320,11 +373,17 @@ static bool atmel_spi_is_v2(struct atmel_spi *as)
* Master on Chip Select 0.") No workaround exists for that ... so for
* nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH,
* and (c) will trigger that first erratum in some cases.
+ *
+ * When changing the clock polarity, the SPI controller waits for the next
+ * transmission to enforce the default clock state. This may be an issue when
+ * using a GPIO as Chip Select: the clock level is applied only when the first
+ * packet is sent, once the CS has already been asserted. The workaround is to
+ * avoid this by sending a first (dummy) message before toggling the CS state.
*/
-
static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
{
struct atmel_spi_device *asd = spi->controller_state;
+ bool new_polarity;
int chip_select;
u32 mr;
@@ -339,20 +398,29 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
* on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS
*/
spi_writel(as, CSR0, asd->csr);
- if (as->caps.has_wdrbt) {
- spi_writel(as, MR,
- SPI_BF(PCS, ~(0x01 << chip_select))
- | SPI_BIT(WDRBT)
- | SPI_BIT(MODFDIS)
- | SPI_BIT(MSTR));
- } else {
- spi_writel(as, MR,
- SPI_BF(PCS, ~(0x01 << chip_select))
- | SPI_BIT(MODFDIS)
- | SPI_BIT(MSTR));
- }
mr = spi_readl(as, MR);
+ mr = SPI_BFINS(PCS, ~(0x01 << chip_select), mr);
+ spi_writel(as, MR, mr);
+
+ /*
+ * Ensures the clock polarity is valid before we actually
+ * assert the CS to avoid spurious clock edges to be
+ * processed by the spi devices.
+ */
+ if (spi_get_csgpiod(spi, 0)) {
+ new_polarity = (asd->csr & SPI_BIT(CPOL)) != 0;
+ if (new_polarity != as->last_polarity) {
+ /*
+ * Need to disable the GPIO before sending the dummy
+ * message because it is already set by the spi core.
+ */
+ gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), 0);
+ atmel_spi_send_dummy(as, spi, chip_select);
+ as->last_polarity = new_polarity;
+ gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), 1);
+ }
+ }
} else {
u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
int i;
@@ -910,8 +978,6 @@ static void atmel_spi_pdc_next_xfer(struct spi_controller *host,
* For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma:
* - The buffer is either valid for CPU access, else NULL
* - If the buffer is valid, so is its DMA address
- *
- * This driver manages the dma address unless message->is_dma_mapped.
*/
static int
atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
@@ -1297,8 +1363,7 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
* DMA map early, for performance (empties dcache ASAP) and
* better fault reporting.
*/
- if ((!host->cur_msg->is_dma_mapped)
- && as->use_pdc) {
+ if (as->use_pdc) {
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
return -ENOMEM;
}
@@ -1336,12 +1401,10 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
}
dma_timeout = msecs_to_jiffies(spi_controller_xfer_timeout(host, xfer));
- ret_timeout = wait_for_completion_interruptible_timeout(&as->xfer_completion,
- dma_timeout);
- if (ret_timeout <= 0) {
- dev_err(&spi->dev, "spi transfer %s\n",
- !ret_timeout ? "timeout" : "canceled");
- as->done_status = ret_timeout < 0 ? ret_timeout : -EIO;
+ ret_timeout = wait_for_completion_timeout(&as->xfer_completion, dma_timeout);
+ if (!ret_timeout) {
+ dev_err(&spi->dev, "spi transfer timeout\n");
+ as->done_status = -EIO;
}
if (as->done_status)
@@ -1379,8 +1442,7 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
}
}
- if (!host->cur_msg->is_dma_mapped
- && as->use_pdc)
+ if (as->use_pdc)
atmel_spi_dma_unmap_xfer(host, xfer);
if (as->use_pdc)
@@ -1419,6 +1481,8 @@ static void atmel_get_caps(struct atmel_spi *as)
static void atmel_spi_init(struct atmel_spi *as)
{
+ u32 mr = 0;
+
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
@@ -1426,12 +1490,17 @@ static void atmel_spi_init(struct atmel_spi *as)
if (as->fifo_size)
spi_writel(as, CR, SPI_BIT(FIFOEN));
- if (as->caps.has_wdrbt) {
- spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS)
- | SPI_BIT(MSTR));
- } else {
- spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
- }
+ /*
+ * If GCLK is selected as the source clock for the bit rate generation
+ * Enable the BRSRCCLK/FDIV/DIV32 bit
+ */
+ if (as->gclk)
+ mr |= SPI_BIT(FDIV);
+
+ if (as->caps.has_wdrbt)
+ mr |= SPI_BIT(WDRBT);
+
+ spi_writel(as, MR, mr | SPI_BIT(MODFDIS) | SPI_BIT(MSTR));
if (as->use_pdc)
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
@@ -1450,10 +1519,6 @@ static int atmel_spi_probe(struct platform_device *pdev)
/* Select default pin state */
pinctrl_pm_select_default_state(&pdev->dev);
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs)
- return -ENXIO;
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -1475,8 +1540,8 @@ static int atmel_spi_probe(struct platform_device *pdev)
host->bus_num = pdev->id;
host->num_chipselect = 4;
host->setup = atmel_spi_setup;
- host->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX |
- SPI_MASTER_GPIO_SS);
+ host->flags = (SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX |
+ SPI_CONTROLLER_GPIO_SS);
host->transfer_one = atmel_spi_one_transfer;
host->set_cs = atmel_spi_set_cs;
host->cleanup = atmel_spi_cleanup;
@@ -1490,7 +1555,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
spin_lock_init(&as->lock);
as->pdev = pdev;
- as->regs = devm_ioremap_resource(&pdev->dev, regs);
+ as->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &regs);
if (IS_ERR(as->regs)) {
ret = PTR_ERR(as->regs);
goto out_unmap_regs;
@@ -1498,6 +1563,11 @@ static int atmel_spi_probe(struct platform_device *pdev)
as->phybase = regs->start;
as->irq = irq;
as->clk = clk;
+ as->gclk = devm_clk_get_optional(&pdev->dev, "spi_gclk");
+ if (IS_ERR(as->gclk)) {
+ ret = PTR_ERR(as->gclk);
+ goto out_unmap_regs;
+ }
init_completion(&as->xfer_completion);
@@ -1558,7 +1628,19 @@ static int atmel_spi_probe(struct platform_device *pdev)
if (ret)
goto out_free_irq;
- as->spi_clk = clk_get_rate(clk);
+ /*
+ * In cases where the peripheral clock is higher,the FLEX_SPI_CSRx.SCBR
+ * exceeds the threshold (SCBR ≤ 255), the GCLK is used as the source clock
+ * for the SPCK (SPI Serial Clock) bit rate generation
+ */
+ if (as->gclk) {
+ ret = clk_prepare_enable(as->gclk);
+ if (ret)
+ goto out_disable_clk;
+ as->spi_clk = clk_get_rate(as->gclk);
+ } else {
+ as->spi_clk = clk_get_rate(clk);
+ }
as->fifo_size = 0;
if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size",
@@ -1593,6 +1675,8 @@ out_free_dma:
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
+ clk_disable_unprepare(as->gclk);
+out_disable_clk:
clk_disable_unprepare(clk);
out_free_irq:
out_unmap_regs:
@@ -1628,6 +1712,8 @@ static void atmel_spi_remove(struct platform_device *pdev)
spin_unlock_irq(&as->lock);
clk_disable_unprepare(as->clk);
+ if (as->gclk)
+ clk_disable_unprepare(as->gclk);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -1639,6 +1725,8 @@ static int atmel_spi_runtime_suspend(struct device *dev)
struct atmel_spi *as = spi_controller_get_devdata(host);
clk_disable_unprepare(as->clk);
+ if (as->gclk)
+ clk_disable_unprepare(as->gclk);
pinctrl_pm_select_sleep_state(dev);
return 0;
@@ -1648,10 +1736,20 @@ static int atmel_spi_runtime_resume(struct device *dev)
{
struct spi_controller *host = dev_get_drvdata(dev);
struct atmel_spi *as = spi_controller_get_devdata(host);
+ int ret;
pinctrl_pm_select_default_state(dev);
- return clk_prepare_enable(as->clk);
+ ret = clk_prepare_enable(as->clk);
+ if (ret)
+ return ret;
+ if (as->gclk) {
+ ret = clk_prepare_enable(as->gclk);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int atmel_spi_suspend(struct device *dev)
@@ -1679,10 +1777,17 @@ static int atmel_spi_resume(struct device *dev)
ret = clk_prepare_enable(as->clk);
if (ret)
return ret;
+ if (as->gclk) {
+ ret = clk_prepare_enable(as->gclk);
+ if (ret)
+ return ret;
+ }
atmel_spi_init(as);
clk_disable_unprepare(as->clk);
+ if (as->gclk)
+ clk_disable_unprepare(as->gclk);
if (!pm_runtime_suspended(dev)) {
ret = atmel_spi_runtime_resume(dev);
@@ -1714,7 +1819,7 @@ static struct platform_driver atmel_spi_driver = {
.of_match_table = atmel_spi_dt_ids,
},
.probe = atmel_spi_probe,
- .remove_new = atmel_spi_remove,
+ .remove = atmel_spi_remove,
};
module_platform_driver(atmel_spi_driver);
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index 0b57e6afce0f..b65798ccc679 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -54,7 +54,7 @@ struct au1550_spi {
int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
irqreturn_t (*irq_callback)(struct au1550_spi *hw);
- struct completion master_done;
+ struct completion host_done;
unsigned int usedma;
u32 dma_tx_id;
@@ -66,7 +66,7 @@ struct au1550_spi {
unsigned int dma_rx_tmpbuf_size;
u32 dma_rx_tmpbuf_addr;
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev;
struct au1550_spi_info *pdata;
struct resource *ioarea;
@@ -159,7 +159,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);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
u32 cfg, stat;
@@ -219,7 +219,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);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
unsigned int bpw, hz;
u32 cfg, stat;
@@ -272,7 +272,7 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
* no reliable way how to recognize that spi transfer is done
* dma complete callbacks are called before real spi transfer is finished
* and if only tx dma channel is set up (and rx fifo overflow event masked)
- * spi master done event irq is not generated unless rx fifo is empty (emptied)
+ * spi host 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 int size)
@@ -303,7 +303,7 @@ static void au1550_spi_dma_rxtmp_free(struct au1550_spi *hw)
static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
{
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
dma_addr_t dma_tx_addr;
dma_addr_t dma_rx_addr;
u32 res;
@@ -314,11 +314,8 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
- dma_tx_addr = t->tx_dma;
- dma_rx_addr = t->rx_dma;
/*
- * check if buffers are already dma mapped, map them otherwise:
* - first map the TX buffer, so cache data gets written to memory
* - then map the RX buffer, so that cache entries (with
* soon-to-be-stale data) get removed
@@ -326,23 +323,17 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
* use temp rx buffer (preallocated or realloc to fit) for rx dma
*/
if (t->tx_buf) {
- if (t->tx_dma == 0) { /* if DMA_ADDR_INVALID, map it */
- dma_tx_addr = dma_map_single(hw->dev,
- (void *)t->tx_buf,
- t->len, DMA_TO_DEVICE);
- if (dma_mapping_error(hw->dev, dma_tx_addr))
- dev_err(hw->dev, "tx dma map error\n");
- }
+ dma_tx_addr = dma_map_single(hw->dev, (void *)t->tx_buf,
+ t->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(hw->dev, dma_tx_addr))
+ dev_err(hw->dev, "tx dma map error\n");
}
if (t->rx_buf) {
- if (t->rx_dma == 0) { /* if DMA_ADDR_INVALID, map it */
- dma_rx_addr = dma_map_single(hw->dev,
- (void *)t->rx_buf,
- t->len, DMA_FROM_DEVICE);
- if (dma_mapping_error(hw->dev, dma_rx_addr))
- dev_err(hw->dev, "rx dma map error\n");
- }
+ dma_rx_addr = dma_map_single(hw->dev, (void *)t->rx_buf,
+ t->len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(hw->dev, dma_rx_addr))
+ dev_err(hw->dev, "rx dma map error\n");
} else {
if (t->len > hw->dma_rx_tmpbuf_size) {
int ret;
@@ -387,7 +378,7 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
hw->regs->psc_spipcr = PSC_SPIPCR_MS;
wmb(); /* drain writebuffer */
- wait_for_completion(&hw->master_done);
+ wait_for_completion(&hw->host_done);
au1xxx_dbdma_stop(hw->dma_tx_ch);
au1xxx_dbdma_stop(hw->dma_rx_ch);
@@ -398,10 +389,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)
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)
dma_unmap_single(hw->dev, dma_tx_addr, t->len,
DMA_TO_DEVICE);
@@ -449,7 +440,7 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
"dma transfer: unexpected SPI error (event=0x%x stat=0x%x)!\n",
evnt, stat);
- complete(&hw->master_done);
+ complete(&hw->host_done);
return IRQ_HANDLED;
}
@@ -458,7 +449,7 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
au1550_spi_mask_ack_all(hw);
hw->rx_count = hw->len;
hw->tx_count = hw->len;
- complete(&hw->master_done);
+ complete(&hw->host_done);
}
return IRQ_HANDLED;
}
@@ -502,7 +493,7 @@ AU1550_SPI_TX_WORD(32, 0xffffff)
static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t)
{
u32 stat, mask;
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
@@ -537,7 +528,7 @@ static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t)
hw->regs->psc_spipcr = PSC_SPIPCR_MS;
wmb(); /* drain writebuffer */
- wait_for_completion(&hw->master_done);
+ wait_for_completion(&hw->host_done);
return min(hw->rx_count, hw->tx_count);
}
@@ -568,7 +559,7 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
dev_err(hw->dev,
"pio transfer: unexpected SPI error (event=0x%x stat=0x%x)!\n",
evnt, stat);
- complete(&hw->master_done);
+ complete(&hw->host_done);
return IRQ_HANDLED;
}
@@ -605,11 +596,11 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
/*
* Restart the SPI transmission in case of a transmit underflow.
* This seems to work despite the notes in the Au1550 data book
- * of Figure 8-4 with flowchart for SPI master operation:
+ * of Figure 8-4 with flowchart for SPI host operation:
*
* """Note 1: An XFR Error Interrupt occurs, unless masked,
* for any of the following events: Tx FIFO Underflow,
- * Rx FIFO Overflow, or Multiple-master Error
+ * Rx FIFO Overflow, or Multiple-host Error
* Note 2: In case of a Tx Underflow Error, all zeroes are
* transmitted."""
*
@@ -627,14 +618,14 @@ static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
if (hw->rx_count >= hw->len) {
/* transfer completed successfully */
au1550_spi_mask_ack_all(hw);
- complete(&hw->master_done);
+ complete(&hw->host_done);
}
return IRQ_HANDLED;
}
static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ struct au1550_spi *hw = spi_controller_get_devdata(spi->controller);
return hw->txrx_bufs(spi, t);
}
@@ -723,24 +714,24 @@ static void au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
static int au1550_spi_probe(struct platform_device *pdev)
{
struct au1550_spi *hw;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *r;
int err = 0;
- master = spi_alloc_master(&pdev->dev, sizeof(struct au1550_spi));
- if (master == NULL) {
- dev_err(&pdev->dev, "No memory for spi_master\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(struct au1550_spi));
+ if (host == NULL) {
+ dev_err(&pdev->dev, "No memory for spi_controller\n");
err = -ENOMEM;
goto err_nomem;
}
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 24);
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 24);
- hw = spi_master_get_devdata(master);
+ hw = spi_controller_get_devdata(host);
- hw->master = master;
+ hw->host = host;
hw->pdata = dev_get_platdata(&pdev->dev);
hw->dev = &pdev->dev;
@@ -798,9 +789,9 @@ static int au1550_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hw);
- init_completion(&hw->master_done);
+ init_completion(&hw->host_done);
- hw->bitbang.master = hw->master;
+ hw->bitbang.ctlr = hw->host;
hw->bitbang.setup_transfer = au1550_spi_setupxfer;
hw->bitbang.chipselect = au1550_spi_chipsel;
hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
@@ -858,8 +849,8 @@ static int au1550_spi_probe(struct platform_device *pdev)
goto err_no_irq;
}
- master->bus_num = pdev->id;
- master->num_chipselect = hw->pdata->num_chipselect;
+ host->bus_num = pdev->id;
+ host->num_chipselect = hw->pdata->num_chipselect;
/*
* precompute valid range for spi freq - from au1550 datasheet:
@@ -874,8 +865,8 @@ 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 =
+ host->max_speed_hz = hw->pdata->mainclk_hz / min_div;
+ host->min_speed_hz =
hw->pdata->mainclk_hz / (max_div + 1) + 1;
}
@@ -883,13 +874,13 @@ static int au1550_spi_probe(struct platform_device *pdev)
err = spi_bitbang_start(&hw->bitbang);
if (err) {
- dev_err(&pdev->dev, "Failed to register SPI master\n");
+ dev_err(&pdev->dev, "Failed to register SPI host\n");
goto err_register;
}
dev_info(&pdev->dev,
- "spi master registered: bus_num=%d num_chipselect=%d\n",
- master->bus_num, master->num_chipselect);
+ "spi host registered: bus_num=%d num_chipselect=%d\n",
+ host->bus_num, host->num_chipselect);
return 0;
@@ -917,7 +908,7 @@ err_ioremap:
err_no_iores:
err_no_pdata:
- spi_master_put(hw->master);
+ spi_controller_put(hw->host);
err_nomem:
return err;
@@ -927,8 +918,8 @@ static void au1550_spi_remove(struct platform_device *pdev)
{
struct au1550_spi *hw = platform_get_drvdata(pdev);
- dev_info(&pdev->dev, "spi master remove: bus_num=%d\n",
- hw->master->bus_num);
+ dev_info(&pdev->dev, "spi host remove: bus_num=%d\n",
+ hw->host->bus_num);
spi_bitbang_stop(&hw->bitbang);
free_irq(hw->irq, hw);
@@ -941,7 +932,7 @@ static void au1550_spi_remove(struct platform_device *pdev)
au1xxx_dbdma_chan_free(hw->dma_tx_ch);
}
- spi_master_put(hw->master);
+ spi_controller_put(hw->host);
}
/* work with hotplug and coldplug */
@@ -949,7 +940,7 @@ MODULE_ALIAS("platform:au1550-spi");
static struct platform_driver au1550_spi_drv = {
.probe = au1550_spi_probe,
- .remove_new = au1550_spi_remove,
+ .remove = au1550_spi_remove,
.driver = {
.name = "au1550-spi",
},
diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c
index 89661f3b0d44..e06f412190fd 100644
--- a/drivers/spi/spi-axi-spi-engine.c
+++ b/drivers/spi/spi-axi-spi-engine.c
@@ -2,23 +2,28 @@
/*
* SPI-Engine SPI controller driver
* Copyright 2015 Analog Devices Inc.
+ * Copyright 2024 BayLibre, SAS
* Author: Lars-Peter Clausen <lars@metafoo.de>
*/
+#include <linux/adi-axi-common.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/module.h>
+#include <linux/overflow.h>
#include <linux/platform_device.h>
+#include <linux/spi/offload/provider.h>
#include <linux/spi/spi.h>
+#include <trace/events/spi.h>
-#define SPI_ENGINE_VERSION_MAJOR(x) ((x >> 16) & 0xff)
-#define SPI_ENGINE_VERSION_MINOR(x) ((x >> 8) & 0xff)
-#define SPI_ENGINE_VERSION_PATCH(x) (x & 0xff)
-
-#define SPI_ENGINE_REG_VERSION 0x00
-
+#define SPI_ENGINE_REG_OFFLOAD_MEM_ADDR_WIDTH 0x10
#define SPI_ENGINE_REG_RESET 0x40
#define SPI_ENGINE_REG_INT_ENABLE 0x80
@@ -26,6 +31,7 @@
#define SPI_ENGINE_REG_INT_SOURCE 0x88
#define SPI_ENGINE_REG_SYNC_ID 0xc0
+#define SPI_ENGINE_REG_OFFLOAD_SYNC_ID 0xc4
#define SPI_ENGINE_REG_CMD_FIFO_ROOM 0xd0
#define SPI_ENGINE_REG_SDO_FIFO_ROOM 0xd4
@@ -36,22 +42,39 @@
#define SPI_ENGINE_REG_SDI_DATA_FIFO 0xe8
#define SPI_ENGINE_REG_SDI_DATA_FIFO_PEEK 0xec
+#define SPI_ENGINE_MAX_NUM_OFFLOADS 32
+
+#define SPI_ENGINE_REG_OFFLOAD_CTRL(x) (0x100 + SPI_ENGINE_MAX_NUM_OFFLOADS * (x))
+#define SPI_ENGINE_REG_OFFLOAD_STATUS(x) (0x104 + SPI_ENGINE_MAX_NUM_OFFLOADS * (x))
+#define SPI_ENGINE_REG_OFFLOAD_RESET(x) (0x108 + SPI_ENGINE_MAX_NUM_OFFLOADS * (x))
+#define SPI_ENGINE_REG_OFFLOAD_CMD_FIFO(x) (0x110 + SPI_ENGINE_MAX_NUM_OFFLOADS * (x))
+#define SPI_ENGINE_REG_OFFLOAD_SDO_FIFO(x) (0x114 + SPI_ENGINE_MAX_NUM_OFFLOADS * (x))
+
+#define SPI_ENGINE_SPI_OFFLOAD_MEM_WIDTH_SDO GENMASK(15, 8)
+#define SPI_ENGINE_SPI_OFFLOAD_MEM_WIDTH_CMD GENMASK(7, 0)
+
#define SPI_ENGINE_INT_CMD_ALMOST_EMPTY BIT(0)
#define SPI_ENGINE_INT_SDO_ALMOST_EMPTY BIT(1)
#define SPI_ENGINE_INT_SDI_ALMOST_FULL BIT(2)
#define SPI_ENGINE_INT_SYNC BIT(3)
+#define SPI_ENGINE_INT_OFFLOAD_SYNC BIT(4)
+
+#define SPI_ENGINE_OFFLOAD_CTRL_ENABLE BIT(0)
#define SPI_ENGINE_CONFIG_CPHA BIT(0)
#define SPI_ENGINE_CONFIG_CPOL BIT(1)
#define SPI_ENGINE_CONFIG_3WIRE BIT(2)
+#define SPI_ENGINE_CONFIG_SDO_IDLE_HIGH BIT(3)
#define SPI_ENGINE_INST_TRANSFER 0x0
#define SPI_ENGINE_INST_ASSERT 0x1
#define SPI_ENGINE_INST_WRITE 0x2
#define SPI_ENGINE_INST_MISC 0x3
+#define SPI_ENGINE_INST_CS_INV 0x4
#define SPI_ENGINE_CMD_REG_CLK_DIV 0x0
#define SPI_ENGINE_CMD_REG_CONFIG 0x1
+#define SPI_ENGINE_CMD_REG_XFER_BITS 0x2
#define SPI_ENGINE_MISC_SYNC 0x0
#define SPI_ENGINE_MISC_SLEEP 0x1
@@ -59,6 +82,9 @@
#define SPI_ENGINE_TRANSFER_WRITE 0x1
#define SPI_ENGINE_TRANSFER_READ 0x2
+/* Arbitrary sync ID for use by host->cur_msg */
+#define AXI_SPI_ENGINE_CUR_MSG_SYNC_ID 0x1
+
#define SPI_ENGINE_CMD(inst, arg1, arg2) \
(((inst) << 12) | ((arg1) << 8) | (arg2))
@@ -72,45 +98,80 @@
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SLEEP, (delay))
#define SPI_ENGINE_CMD_SYNC(id) \
SPI_ENGINE_CMD(SPI_ENGINE_INST_MISC, SPI_ENGINE_MISC_SYNC, (id))
+#define SPI_ENGINE_CMD_CS_INV(flags) \
+ SPI_ENGINE_CMD(SPI_ENGINE_INST_CS_INV, 0, (flags))
+
+/* default sizes - can be changed when SPI Engine firmware is compiled */
+#define SPI_ENGINE_OFFLOAD_CMD_FIFO_SIZE 16
+#define SPI_ENGINE_OFFLOAD_SDO_FIFO_SIZE 16
struct spi_engine_program {
unsigned int length;
- uint16_t instructions[];
+ uint16_t instructions[] __counted_by(length);
};
-struct spi_engine {
- struct clk *clk;
- struct clk *ref_clk;
-
- spinlock_t lock;
-
- void __iomem *base;
-
- struct spi_message *msg;
- struct spi_engine_program *p;
+/**
+ * struct spi_engine_message_state - SPI engine per-message state
+ */
+struct spi_engine_message_state {
+ /** @cmd_length: Number of elements in cmd_buf array. */
unsigned cmd_length;
+ /** @cmd_buf: Array of commands not yet written to CMD FIFO. */
const uint16_t *cmd_buf;
-
+ /** @tx_xfer: Next xfer with tx_buf not yet fully written to TX FIFO. */
struct spi_transfer *tx_xfer;
+ /** @tx_length: Size of tx_buf in bytes. */
unsigned int tx_length;
+ /** @tx_buf: Bytes not yet written to TX FIFO. */
const uint8_t *tx_buf;
-
+ /** @rx_xfer: Next xfer with rx_buf not yet fully written to RX FIFO. */
struct spi_transfer *rx_xfer;
+ /** @rx_length: Size of tx_buf in bytes. */
unsigned int rx_length;
+ /** @rx_buf: Bytes not yet written to the RX FIFO. */
uint8_t *rx_buf;
+};
+
+enum {
+ SPI_ENGINE_OFFLOAD_FLAG_ASSIGNED,
+ SPI_ENGINE_OFFLOAD_FLAG_PREPARED,
+};
+
+struct spi_engine_offload {
+ struct spi_engine *spi_engine;
+ unsigned long flags;
+ unsigned int offload_num;
+ unsigned int spi_mode_config;
+ u8 bits_per_word;
+};
+
+struct spi_engine {
+ struct clk *clk;
+ struct clk *ref_clk;
- unsigned int sync_id;
- unsigned int completed_id;
+ spinlock_t lock;
+ void __iomem *base;
+ struct spi_engine_message_state msg_state;
+ struct completion msg_complete;
unsigned int int_enable;
+ /* shadows hardware CS inversion flag state */
+ u8 cs_inv;
+
+ unsigned int offload_ctrl_mem_size;
+ unsigned int offload_sdo_mem_size;
+ struct spi_offload *offload;
+ u32 offload_caps;
+ bool offload_requires_sync;
};
static void spi_engine_program_add_cmd(struct spi_engine_program *p,
bool dry, uint16_t cmd)
{
- if (!dry)
- p->instructions[p->length] = cmd;
p->length++;
+
+ if (!dry)
+ p->instructions[p->length - 1] = cmd;
}
static unsigned int spi_engine_get_config(struct spi_device *spi)
@@ -123,37 +184,33 @@ static unsigned int spi_engine_get_config(struct spi_device *spi)
config |= SPI_ENGINE_CONFIG_CPHA;
if (spi->mode & SPI_3WIRE)
config |= SPI_ENGINE_CONFIG_3WIRE;
+ if (spi->mode & SPI_MOSI_IDLE_HIGH)
+ config |= SPI_ENGINE_CONFIG_SDO_IDLE_HIGH;
+ if (spi->mode & SPI_MOSI_IDLE_LOW)
+ config &= ~SPI_ENGINE_CONFIG_SDO_IDLE_HIGH;
return config;
}
-static unsigned int spi_engine_get_clk_div(struct spi_engine *spi_engine,
- struct spi_device *spi, struct spi_transfer *xfer)
-{
- unsigned int clk_div;
-
- clk_div = DIV_ROUND_UP(clk_get_rate(spi_engine->ref_clk),
- xfer->speed_hz * 2);
- if (clk_div > 255)
- clk_div = 255;
- else if (clk_div > 0)
- clk_div -= 1;
-
- return clk_div;
-}
-
static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
struct spi_transfer *xfer)
{
- unsigned int len = xfer->len;
+ unsigned int len;
+
+ if (xfer->bits_per_word <= 8)
+ len = xfer->len;
+ else if (xfer->bits_per_word <= 16)
+ len = xfer->len / 2;
+ else
+ len = xfer->len / 4;
while (len) {
unsigned int n = min(len, 256U);
unsigned int flags = 0;
- if (xfer->tx_buf)
+ if (xfer->tx_buf || (xfer->offload_flags & SPI_OFFLOAD_XFER_TX_STREAM))
flags |= SPI_ENGINE_TRANSFER_WRITE;
- if (xfer->rx_buf)
+ if (xfer->rx_buf || (xfer->offload_flags & SPI_OFFLOAD_XFER_RX_STREAM))
flags |= SPI_ENGINE_TRANSFER_READ;
spi_engine_program_add_cmd(p, dry,
@@ -163,22 +220,20 @@ static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
}
static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
- struct spi_engine *spi_engine, unsigned int clk_div,
- struct spi_transfer *xfer)
+ int delay_ns, int inst_ns, u32 sclk_hz)
{
- unsigned int spi_clk = clk_get_rate(spi_engine->ref_clk);
unsigned int t;
- int delay;
- delay = spi_delay_to_ns(&xfer->delay, xfer);
- if (delay < 0)
+ /*
+ * Negative delay indicates error, e.g. from spi_delay_to_ns(). And if
+ * delay is less that the instruction execution time, there is no need
+ * for an extra sleep instruction since the instruction execution time
+ * will already cover the required delay.
+ */
+ if (delay_ns < 0 || delay_ns <= inst_ns)
return;
- delay /= 1000;
- if (delay == 0)
- return;
-
- t = DIV_ROUND_UP(delay * spi_clk, (clk_div + 1) * 2);
+ t = DIV_ROUND_UP_ULL((u64)(delay_ns - inst_ns) * sclk_hz, NSEC_PER_SEC);
while (t) {
unsigned int n = min(t, 256U);
@@ -195,53 +250,155 @@ static void spi_engine_gen_cs(struct spi_engine_program *p, bool dry,
if (assert)
mask ^= BIT(spi_get_chipselect(spi, 0));
- spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_ASSERT(1, mask));
+ spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_ASSERT(0, mask));
}
-static int spi_engine_compile_message(struct spi_engine *spi_engine,
- struct spi_message *msg, bool dry, struct spi_engine_program *p)
+/*
+ * Performs precompile steps on the message.
+ *
+ * The SPI core does most of the message/transfer validation and filling in
+ * fields for us via __spi_validate(). This fixes up anything remaining not
+ * done there.
+ *
+ * NB: This is separate from spi_engine_compile_message() because the latter
+ * is called twice and would otherwise result in double-evaluation.
+ *
+ * Returns 0 on success, -EINVAL on failure.
+ */
+static int spi_engine_precompile_message(struct spi_message *msg)
{
- struct spi_device *spi = msg->spi;
+ unsigned int clk_div, max_hz = msg->spi->controller->max_speed_hz;
struct spi_transfer *xfer;
- int clk_div, new_clk_div;
- bool cs_change = true;
+ u8 min_bits_per_word = U8_MAX;
+ u8 max_bits_per_word = 0;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ /* If we have an offload transfer, we can't rx to buffer */
+ if (msg->offload && xfer->rx_buf)
+ return -EINVAL;
+
+ clk_div = DIV_ROUND_UP(max_hz, xfer->speed_hz);
+ xfer->effective_speed_hz = max_hz / min(clk_div, 256U);
+
+ if (xfer->len) {
+ min_bits_per_word = min(min_bits_per_word, xfer->bits_per_word);
+ max_bits_per_word = max(max_bits_per_word, xfer->bits_per_word);
+ }
+ }
+
+ /*
+ * If all xfers in the message use the same bits_per_word, we can
+ * provide some optimization when using SPI offload.
+ */
+ if (msg->offload) {
+ struct spi_engine_offload *priv = msg->offload->priv;
+
+ if (min_bits_per_word == max_bits_per_word)
+ priv->bits_per_word = min_bits_per_word;
+ else
+ priv->bits_per_word = 0;
+ }
+
+ return 0;
+}
- clk_div = -1;
+static void spi_engine_compile_message(struct spi_message *msg, bool dry,
+ struct spi_engine_program *p)
+{
+ struct spi_device *spi = msg->spi;
+ struct spi_controller *host = spi->controller;
+ struct spi_engine_offload *priv;
+ struct spi_transfer *xfer;
+ int clk_div, new_clk_div, inst_ns;
+ bool keep_cs = false;
+ u8 bits_per_word = 0;
+
+ /*
+ * Take into account instruction execution time for more accurate sleep
+ * times, especially when the delay is small.
+ */
+ inst_ns = DIV_ROUND_UP(NSEC_PER_SEC, host->max_speed_hz);
+
+ clk_div = 1;
+
+ /*
+ * As an optimization, SPI offload sets once this when the offload is
+ * enabled instead of repeating the instruction in each message.
+ */
+ if (msg->offload) {
+ priv = msg->offload->priv;
+ priv->spi_mode_config = spi_engine_get_config(spi);
+
+ /*
+ * If all xfers use the same bits_per_word, it can be optimized
+ * in the same way.
+ */
+ bits_per_word = priv->bits_per_word;
+ } else {
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CONFIG,
+ spi_engine_get_config(spi)));
+ }
- spi_engine_program_add_cmd(p, dry,
- SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CONFIG,
- spi_engine_get_config(spi)));
+ xfer = list_first_entry(&msg->transfers, struct spi_transfer, transfer_list);
+ spi_engine_gen_cs(p, dry, spi, !xfer->cs_off);
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- new_clk_div = spi_engine_get_clk_div(spi_engine, spi, xfer);
+ new_clk_div = host->max_speed_hz / xfer->effective_speed_hz;
if (new_clk_div != clk_div) {
clk_div = new_clk_div;
+ /* actual divider used is register value + 1 */
spi_engine_program_add_cmd(p, dry,
SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CLK_DIV,
- clk_div));
+ clk_div - 1));
}
- if (cs_change)
- spi_engine_gen_cs(p, dry, spi, true);
+ if (bits_per_word != xfer->bits_per_word && xfer->len) {
+ bits_per_word = xfer->bits_per_word;
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_XFER_BITS,
+ bits_per_word));
+ }
spi_engine_gen_xfer(p, dry, xfer);
- spi_engine_gen_sleep(p, dry, spi_engine, clk_div, xfer);
-
- cs_change = xfer->cs_change;
- if (list_is_last(&xfer->transfer_list, &msg->transfers))
- cs_change = !cs_change;
-
- if (cs_change)
- spi_engine_gen_cs(p, dry, spi, false);
+ spi_engine_gen_sleep(p, dry, spi_delay_to_ns(&xfer->delay, xfer),
+ inst_ns, xfer->effective_speed_hz);
+
+ if (xfer->cs_change) {
+ if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
+ keep_cs = true;
+ } else {
+ if (!xfer->cs_off)
+ spi_engine_gen_cs(p, dry, spi, false);
+
+ spi_engine_gen_sleep(p, dry, spi_delay_to_ns(
+ &xfer->cs_change_delay, xfer), inst_ns,
+ xfer->effective_speed_hz);
+
+ if (!list_next_entry(xfer, transfer_list)->cs_off)
+ spi_engine_gen_cs(p, dry, spi, true);
+ }
+ } else if (!list_is_last(&xfer->transfer_list, &msg->transfers) &&
+ xfer->cs_off != list_next_entry(xfer, transfer_list)->cs_off) {
+ spi_engine_gen_cs(p, dry, spi, xfer->cs_off);
+ }
}
- return 0;
+ if (!keep_cs)
+ spi_engine_gen_cs(p, dry, spi, false);
+
+ /*
+ * Restore clockdiv to default so that future gen_sleep commands don't
+ * have to be aware of the current register state.
+ */
+ if (clk_div != 1)
+ spi_engine_program_add_cmd(p, dry,
+ SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CLK_DIV, 0));
}
-static void spi_engine_xfer_next(struct spi_engine *spi_engine,
+static void spi_engine_xfer_next(struct spi_message *msg,
struct spi_transfer **_xfer)
{
- struct spi_message *msg = spi_engine->msg;
struct spi_transfer *xfer = *_xfer;
if (!xfer) {
@@ -256,147 +413,188 @@ static void spi_engine_xfer_next(struct spi_engine *spi_engine,
*_xfer = xfer;
}
-static void spi_engine_tx_next(struct spi_engine *spi_engine)
+static void spi_engine_tx_next(struct spi_message *msg)
{
- struct spi_transfer *xfer = spi_engine->tx_xfer;
+ struct spi_engine_message_state *st = msg->state;
+ struct spi_transfer *xfer = st->tx_xfer;
do {
- spi_engine_xfer_next(spi_engine, &xfer);
+ spi_engine_xfer_next(msg, &xfer);
} while (xfer && !xfer->tx_buf);
- spi_engine->tx_xfer = xfer;
+ st->tx_xfer = xfer;
if (xfer) {
- spi_engine->tx_length = xfer->len;
- spi_engine->tx_buf = xfer->tx_buf;
+ st->tx_length = xfer->len;
+ st->tx_buf = xfer->tx_buf;
} else {
- spi_engine->tx_buf = NULL;
+ st->tx_buf = NULL;
}
}
-static void spi_engine_rx_next(struct spi_engine *spi_engine)
+static void spi_engine_rx_next(struct spi_message *msg)
{
- struct spi_transfer *xfer = spi_engine->rx_xfer;
+ struct spi_engine_message_state *st = msg->state;
+ struct spi_transfer *xfer = st->rx_xfer;
do {
- spi_engine_xfer_next(spi_engine, &xfer);
+ spi_engine_xfer_next(msg, &xfer);
} while (xfer && !xfer->rx_buf);
- spi_engine->rx_xfer = xfer;
+ st->rx_xfer = xfer;
if (xfer) {
- spi_engine->rx_length = xfer->len;
- spi_engine->rx_buf = xfer->rx_buf;
+ st->rx_length = xfer->len;
+ st->rx_buf = xfer->rx_buf;
} else {
- spi_engine->rx_buf = NULL;
+ st->rx_buf = NULL;
}
}
-static bool spi_engine_write_cmd_fifo(struct spi_engine *spi_engine)
+static bool spi_engine_write_cmd_fifo(struct spi_engine *spi_engine,
+ struct spi_message *msg)
{
void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_CMD_FIFO;
+ struct spi_engine_message_state *st = msg->state;
unsigned int n, m, i;
const uint16_t *buf;
n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_CMD_FIFO_ROOM);
- while (n && spi_engine->cmd_length) {
- m = min(n, spi_engine->cmd_length);
- buf = spi_engine->cmd_buf;
+ while (n && st->cmd_length) {
+ m = min(n, st->cmd_length);
+ buf = st->cmd_buf;
for (i = 0; i < m; i++)
writel_relaxed(buf[i], addr);
- spi_engine->cmd_buf += m;
- spi_engine->cmd_length -= m;
+ st->cmd_buf += m;
+ st->cmd_length -= m;
n -= m;
}
- return spi_engine->cmd_length != 0;
+ return st->cmd_length != 0;
}
-static bool spi_engine_write_tx_fifo(struct spi_engine *spi_engine)
+static bool spi_engine_write_tx_fifo(struct spi_engine *spi_engine,
+ struct spi_message *msg)
{
void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDO_DATA_FIFO;
+ struct spi_engine_message_state *st = msg->state;
unsigned int n, m, i;
- const uint8_t *buf;
n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDO_FIFO_ROOM);
- while (n && spi_engine->tx_length) {
- m = min(n, spi_engine->tx_length);
- buf = spi_engine->tx_buf;
- for (i = 0; i < m; i++)
- writel_relaxed(buf[i], addr);
- spi_engine->tx_buf += m;
- spi_engine->tx_length -= m;
+ while (n && st->tx_length) {
+ if (st->tx_xfer->bits_per_word <= 8) {
+ const u8 *buf = st->tx_buf;
+
+ m = min(n, st->tx_length);
+ for (i = 0; i < m; i++)
+ writel_relaxed(buf[i], addr);
+ st->tx_buf += m;
+ st->tx_length -= m;
+ } else if (st->tx_xfer->bits_per_word <= 16) {
+ const u16 *buf = (const u16 *)st->tx_buf;
+
+ m = min(n, st->tx_length / 2);
+ for (i = 0; i < m; i++)
+ writel_relaxed(buf[i], addr);
+ st->tx_buf += m * 2;
+ st->tx_length -= m * 2;
+ } else {
+ const u32 *buf = (const u32 *)st->tx_buf;
+
+ m = min(n, st->tx_length / 4);
+ for (i = 0; i < m; i++)
+ writel_relaxed(buf[i], addr);
+ st->tx_buf += m * 4;
+ st->tx_length -= m * 4;
+ }
n -= m;
- if (spi_engine->tx_length == 0)
- spi_engine_tx_next(spi_engine);
+ if (st->tx_length == 0)
+ spi_engine_tx_next(msg);
}
- return spi_engine->tx_length != 0;
+ return st->tx_length != 0;
}
-static bool spi_engine_read_rx_fifo(struct spi_engine *spi_engine)
+static bool spi_engine_read_rx_fifo(struct spi_engine *spi_engine,
+ struct spi_message *msg)
{
void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDI_DATA_FIFO;
+ struct spi_engine_message_state *st = msg->state;
unsigned int n, m, i;
- uint8_t *buf;
n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDI_FIFO_LEVEL);
- while (n && spi_engine->rx_length) {
- m = min(n, spi_engine->rx_length);
- buf = spi_engine->rx_buf;
- for (i = 0; i < m; i++)
- buf[i] = readl_relaxed(addr);
- spi_engine->rx_buf += m;
- spi_engine->rx_length -= m;
+ while (n && st->rx_length) {
+ if (st->rx_xfer->bits_per_word <= 8) {
+ u8 *buf = st->rx_buf;
+
+ m = min(n, st->rx_length);
+ for (i = 0; i < m; i++)
+ buf[i] = readl_relaxed(addr);
+ st->rx_buf += m;
+ st->rx_length -= m;
+ } else if (st->rx_xfer->bits_per_word <= 16) {
+ u16 *buf = (u16 *)st->rx_buf;
+
+ m = min(n, st->rx_length / 2);
+ for (i = 0; i < m; i++)
+ buf[i] = readl_relaxed(addr);
+ st->rx_buf += m * 2;
+ st->rx_length -= m * 2;
+ } else {
+ u32 *buf = (u32 *)st->rx_buf;
+
+ m = min(n, st->rx_length / 4);
+ for (i = 0; i < m; i++)
+ buf[i] = readl_relaxed(addr);
+ st->rx_buf += m * 4;
+ st->rx_length -= m * 4;
+ }
n -= m;
- if (spi_engine->rx_length == 0)
- spi_engine_rx_next(spi_engine);
+ if (st->rx_length == 0)
+ spi_engine_rx_next(msg);
}
- return spi_engine->rx_length != 0;
+ return st->rx_length != 0;
}
static irqreturn_t spi_engine_irq(int irq, void *devid)
{
- struct spi_master *master = devid;
- struct spi_engine *spi_engine = spi_master_get_devdata(master);
+ struct spi_controller *host = devid;
+ struct spi_message *msg = host->cur_msg;
+ struct spi_engine *spi_engine = spi_controller_get_devdata(host);
unsigned int disable_int = 0;
unsigned int pending;
+ int completed_id = -1;
pending = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
if (pending & SPI_ENGINE_INT_SYNC) {
writel_relaxed(SPI_ENGINE_INT_SYNC,
spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
- spi_engine->completed_id = readl_relaxed(
+ completed_id = readl_relaxed(
spi_engine->base + SPI_ENGINE_REG_SYNC_ID);
}
spin_lock(&spi_engine->lock);
if (pending & SPI_ENGINE_INT_CMD_ALMOST_EMPTY) {
- if (!spi_engine_write_cmd_fifo(spi_engine))
+ if (!spi_engine_write_cmd_fifo(spi_engine, msg))
disable_int |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
}
if (pending & SPI_ENGINE_INT_SDO_ALMOST_EMPTY) {
- if (!spi_engine_write_tx_fifo(spi_engine))
+ if (!spi_engine_write_tx_fifo(spi_engine, msg))
disable_int |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
}
if (pending & (SPI_ENGINE_INT_SDI_ALMOST_FULL | SPI_ENGINE_INT_SYNC)) {
- if (!spi_engine_read_rx_fifo(spi_engine))
+ if (!spi_engine_read_rx_fifo(spi_engine, msg))
disable_int |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
}
- if (pending & SPI_ENGINE_INT_SYNC) {
- if (spi_engine->msg &&
- spi_engine->completed_id == spi_engine->sync_id) {
- struct spi_message *msg = spi_engine->msg;
-
- kfree(spi_engine->p);
+ if (pending & SPI_ENGINE_INT_SYNC && msg) {
+ if (completed_id == AXI_SPI_ENGINE_CUR_MSG_SYNC_ID) {
msg->status = 0;
msg->actual_length = msg->frame_length;
- spi_engine->msg = NULL;
- spi_finalize_current_message(master);
+ complete(&spi_engine->msg_complete);
disable_int |= SPI_ENGINE_INT_SYNC;
}
}
@@ -412,43 +610,250 @@ static irqreturn_t spi_engine_irq(int irq, void *devid)
return IRQ_HANDLED;
}
-static int spi_engine_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
+static int spi_engine_offload_prepare(struct spi_message *msg)
+{
+ struct spi_controller *host = msg->spi->controller;
+ struct spi_engine *spi_engine = spi_controller_get_devdata(host);
+ struct spi_engine_program *p = msg->opt_state;
+ struct spi_engine_offload *priv = msg->offload->priv;
+ struct spi_transfer *xfer;
+ void __iomem *cmd_addr;
+ void __iomem *sdo_addr;
+ size_t tx_word_count = 0;
+ unsigned int i;
+
+ if (p->length > spi_engine->offload_ctrl_mem_size)
+ return -EINVAL;
+
+ /* count total number of tx words in message */
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ /* no support for reading to rx_buf */
+ if (xfer->rx_buf)
+ return -EINVAL;
+
+ if (!xfer->tx_buf)
+ continue;
+
+ if (xfer->bits_per_word <= 8)
+ tx_word_count += xfer->len;
+ else if (xfer->bits_per_word <= 16)
+ tx_word_count += xfer->len / 2;
+ else
+ tx_word_count += xfer->len / 4;
+ }
+
+ if (tx_word_count && !(spi_engine->offload_caps & SPI_OFFLOAD_CAP_TX_STATIC_DATA))
+ return -EINVAL;
+
+ if (tx_word_count > spi_engine->offload_sdo_mem_size)
+ return -EINVAL;
+
+ /*
+ * This protects against calling spi_optimize_message() with an offload
+ * that has already been prepared with a different message.
+ */
+ if (test_and_set_bit_lock(SPI_ENGINE_OFFLOAD_FLAG_PREPARED, &priv->flags))
+ return -EBUSY;
+
+ cmd_addr = spi_engine->base +
+ SPI_ENGINE_REG_OFFLOAD_CMD_FIFO(priv->offload_num);
+ sdo_addr = spi_engine->base +
+ SPI_ENGINE_REG_OFFLOAD_SDO_FIFO(priv->offload_num);
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (!xfer->tx_buf)
+ continue;
+
+ if (xfer->bits_per_word <= 8) {
+ const u8 *buf = xfer->tx_buf;
+
+ for (i = 0; i < xfer->len; i++)
+ writel_relaxed(buf[i], sdo_addr);
+ } else if (xfer->bits_per_word <= 16) {
+ const u16 *buf = xfer->tx_buf;
+
+ for (i = 0; i < xfer->len / 2; i++)
+ writel_relaxed(buf[i], sdo_addr);
+ } else {
+ const u32 *buf = xfer->tx_buf;
+
+ for (i = 0; i < xfer->len / 4; i++)
+ writel_relaxed(buf[i], sdo_addr);
+ }
+ }
+
+ for (i = 0; i < p->length; i++)
+ writel_relaxed(p->instructions[i], cmd_addr);
+
+ return 0;
+}
+
+static void spi_engine_offload_unprepare(struct spi_offload *offload)
+{
+ struct spi_engine_offload *priv = offload->priv;
+ struct spi_engine *spi_engine = priv->spi_engine;
+
+ writel_relaxed(1, spi_engine->base +
+ SPI_ENGINE_REG_OFFLOAD_RESET(priv->offload_num));
+ writel_relaxed(0, spi_engine->base +
+ SPI_ENGINE_REG_OFFLOAD_RESET(priv->offload_num));
+
+ clear_bit_unlock(SPI_ENGINE_OFFLOAD_FLAG_PREPARED, &priv->flags);
+}
+
+static int spi_engine_optimize_message(struct spi_message *msg)
{
+ struct spi_controller *host = msg->spi->controller;
+ struct spi_engine *spi_engine = spi_controller_get_devdata(host);
struct spi_engine_program p_dry, *p;
- struct spi_engine *spi_engine = spi_master_get_devdata(master);
- unsigned int int_enable = 0;
- unsigned long flags;
- size_t size;
+ int ret;
+
+ ret = spi_engine_precompile_message(msg);
+ if (ret)
+ return ret;
p_dry.length = 0;
- spi_engine_compile_message(spi_engine, msg, true, &p_dry);
+ spi_engine_compile_message(msg, true, &p_dry);
- size = sizeof(*p->instructions) * (p_dry.length + 1);
- p = kzalloc(sizeof(*p) + size, GFP_KERNEL);
+ p = kzalloc(struct_size(p, instructions, p_dry.length + 1), GFP_KERNEL);
if (!p)
return -ENOMEM;
- spi_engine_compile_message(spi_engine, msg, false, p);
- spin_lock_irqsave(&spi_engine->lock, flags);
- spi_engine->sync_id = (spi_engine->sync_id + 1) & 0xff;
- spi_engine_program_add_cmd(p, false,
- SPI_ENGINE_CMD_SYNC(spi_engine->sync_id));
+ spi_engine_compile_message(msg, false, p);
+
+ /*
+ * Non-offload needs SYNC for completion interrupt. Older versions of
+ * the IP core also need SYNC for offload to work properly.
+ */
+ if (!msg->offload || spi_engine->offload_requires_sync)
+ spi_engine_program_add_cmd(p, false, SPI_ENGINE_CMD_SYNC(
+ msg->offload ? 0 : AXI_SPI_ENGINE_CUR_MSG_SYNC_ID));
+
+ msg->opt_state = p;
+
+ if (msg->offload) {
+ ret = spi_engine_offload_prepare(msg);
+ if (ret) {
+ msg->opt_state = NULL;
+ kfree(p);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int spi_engine_unoptimize_message(struct spi_message *msg)
+{
+ if (msg->offload)
+ spi_engine_offload_unprepare(msg->offload);
+
+ kfree(msg->opt_state);
+
+ return 0;
+}
+
+static struct spi_offload
+*spi_engine_get_offload(struct spi_device *spi,
+ const struct spi_offload_config *config)
+{
+ struct spi_controller *host = spi->controller;
+ struct spi_engine *spi_engine = spi_controller_get_devdata(host);
+ struct spi_engine_offload *priv;
+
+ if (!spi_engine->offload)
+ return ERR_PTR(-ENODEV);
+
+ if (config->capability_flags & ~spi_engine->offload_caps)
+ return ERR_PTR(-EINVAL);
+
+ priv = spi_engine->offload->priv;
+
+ if (test_and_set_bit_lock(SPI_ENGINE_OFFLOAD_FLAG_ASSIGNED, &priv->flags))
+ return ERR_PTR(-EBUSY);
+
+ return spi_engine->offload;
+}
+
+static void spi_engine_put_offload(struct spi_offload *offload)
+{
+ struct spi_engine_offload *priv = offload->priv;
+
+ clear_bit_unlock(SPI_ENGINE_OFFLOAD_FLAG_ASSIGNED, &priv->flags);
+}
+
+static int spi_engine_setup(struct spi_device *device)
+{
+ struct spi_controller *host = device->controller;
+ struct spi_engine *spi_engine = spi_controller_get_devdata(host);
+ unsigned int reg;
+
+ if (device->mode & SPI_CS_HIGH)
+ spi_engine->cs_inv |= BIT(spi_get_chipselect(device, 0));
+ else
+ spi_engine->cs_inv &= ~BIT(spi_get_chipselect(device, 0));
+
+ writel_relaxed(SPI_ENGINE_CMD_SYNC(0),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+
+ writel_relaxed(SPI_ENGINE_CMD_CS_INV(spi_engine->cs_inv),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+
+ /*
+ * In addition to setting the flags, we have to do a CS assert command
+ * to make the new setting actually take effect.
+ */
+ writel_relaxed(SPI_ENGINE_CMD_ASSERT(0, 0xff),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+
+ writel_relaxed(SPI_ENGINE_CMD_SYNC(1),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+
+ return readl_relaxed_poll_timeout(spi_engine->base + SPI_ENGINE_REG_SYNC_ID,
+ reg, reg == 1, 1, 1000);
+}
+
+static int spi_engine_transfer_one_message(struct spi_controller *host,
+ struct spi_message *msg)
+{
+ struct spi_engine *spi_engine = spi_controller_get_devdata(host);
+ struct spi_engine_message_state *st = &spi_engine->msg_state;
+ struct spi_engine_program *p = msg->opt_state;
+ unsigned int int_enable = 0;
+ unsigned long flags;
+
+ if (msg->offload) {
+ dev_err(&host->dev, "Single transfer offload not supported\n");
+ msg->status = -EOPNOTSUPP;
+ goto out;
+ }
- spi_engine->msg = msg;
- spi_engine->p = p;
+ /* reinitialize message state for this transfer */
+ memset(st, 0, sizeof(*st));
+ st->cmd_buf = p->instructions;
+ st->cmd_length = p->length;
+ msg->state = st;
- spi_engine->cmd_buf = p->instructions;
- spi_engine->cmd_length = p->length;
- if (spi_engine_write_cmd_fifo(spi_engine))
+ reinit_completion(&spi_engine->msg_complete);
+
+ if (trace_spi_transfer_start_enabled()) {
+ struct spi_transfer *xfer;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list)
+ trace_spi_transfer_start(msg, xfer);
+ }
+
+ spin_lock_irqsave(&spi_engine->lock, flags);
+
+ if (spi_engine_write_cmd_fifo(spi_engine, msg))
int_enable |= SPI_ENGINE_INT_CMD_ALMOST_EMPTY;
- spi_engine_tx_next(spi_engine);
- if (spi_engine_write_tx_fifo(spi_engine))
+ spi_engine_tx_next(msg);
+ if (spi_engine_write_tx_fifo(spi_engine, msg))
int_enable |= SPI_ENGINE_INT_SDO_ALMOST_EMPTY;
- spi_engine_rx_next(spi_engine);
- if (spi_engine->rx_length != 0)
+ spi_engine_rx_next(msg);
+ if (st->rx_length != 0)
int_enable |= SPI_ENGINE_INT_SDI_ALMOST_FULL;
int_enable |= SPI_ENGINE_INT_SYNC;
@@ -458,120 +863,245 @@ static int spi_engine_transfer_one_message(struct spi_master *master,
spi_engine->int_enable = int_enable;
spin_unlock_irqrestore(&spi_engine->lock, flags);
+ if (!wait_for_completion_timeout(&spi_engine->msg_complete,
+ msecs_to_jiffies(5000))) {
+ dev_err(&host->dev,
+ "Timeout occurred while waiting for transfer to complete. Hardware is probably broken.\n");
+ msg->status = -ETIMEDOUT;
+ }
+
+ if (trace_spi_transfer_stop_enabled()) {
+ struct spi_transfer *xfer;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list)
+ trace_spi_transfer_stop(msg, xfer);
+ }
+
+out:
+ spi_finalize_current_message(host);
+
+ return msg->status;
+}
+
+static int spi_engine_trigger_enable(struct spi_offload *offload)
+{
+ struct spi_engine_offload *priv = offload->priv;
+ struct spi_engine *spi_engine = priv->spi_engine;
+ unsigned int reg;
+ int ret;
+
+ writel_relaxed(SPI_ENGINE_CMD_SYNC(0),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+
+ writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_CONFIG,
+ priv->spi_mode_config),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+
+ if (priv->bits_per_word)
+ writel_relaxed(SPI_ENGINE_CMD_WRITE(SPI_ENGINE_CMD_REG_XFER_BITS,
+ priv->bits_per_word),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+
+ writel_relaxed(SPI_ENGINE_CMD_SYNC(1),
+ spi_engine->base + SPI_ENGINE_REG_CMD_FIFO);
+
+ ret = readl_relaxed_poll_timeout(spi_engine->base + SPI_ENGINE_REG_SYNC_ID,
+ reg, reg == 1, 1, 1000);
+ if (ret)
+ return ret;
+
+ reg = readl_relaxed(spi_engine->base +
+ SPI_ENGINE_REG_OFFLOAD_CTRL(priv->offload_num));
+ reg |= SPI_ENGINE_OFFLOAD_CTRL_ENABLE;
+ writel_relaxed(reg, spi_engine->base +
+ SPI_ENGINE_REG_OFFLOAD_CTRL(priv->offload_num));
return 0;
}
+static void spi_engine_trigger_disable(struct spi_offload *offload)
+{
+ struct spi_engine_offload *priv = offload->priv;
+ struct spi_engine *spi_engine = priv->spi_engine;
+ unsigned int reg;
+
+ reg = readl_relaxed(spi_engine->base +
+ SPI_ENGINE_REG_OFFLOAD_CTRL(priv->offload_num));
+ reg &= ~SPI_ENGINE_OFFLOAD_CTRL_ENABLE;
+ writel_relaxed(reg, spi_engine->base +
+ SPI_ENGINE_REG_OFFLOAD_CTRL(priv->offload_num));
+}
+
+static struct dma_chan
+*spi_engine_tx_stream_request_dma_chan(struct spi_offload *offload)
+{
+ struct spi_engine_offload *priv = offload->priv;
+ char name[16];
+
+ snprintf(name, sizeof(name), "offload%u-tx", priv->offload_num);
+
+ return dma_request_chan(offload->provider_dev, name);
+}
+
+static struct dma_chan
+*spi_engine_rx_stream_request_dma_chan(struct spi_offload *offload)
+{
+ struct spi_engine_offload *priv = offload->priv;
+ char name[16];
+
+ snprintf(name, sizeof(name), "offload%u-rx", priv->offload_num);
+
+ return dma_request_chan(offload->provider_dev, name);
+}
+
+static const struct spi_offload_ops spi_engine_offload_ops = {
+ .trigger_enable = spi_engine_trigger_enable,
+ .trigger_disable = spi_engine_trigger_disable,
+ .tx_stream_request_dma_chan = spi_engine_tx_stream_request_dma_chan,
+ .rx_stream_request_dma_chan = spi_engine_rx_stream_request_dma_chan,
+};
+
+static void spi_engine_release_hw(void *p)
+{
+ struct spi_engine *spi_engine = p;
+
+ writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
+ writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
+ writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET);
+}
+
static int spi_engine_probe(struct platform_device *pdev)
{
struct spi_engine *spi_engine;
- struct spi_master *master;
+ struct spi_controller *host;
unsigned int version;
- int irq;
- int ret;
+ int irq, ret;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -ENXIO;
+ if (irq < 0)
+ return irq;
- spi_engine = devm_kzalloc(&pdev->dev, sizeof(*spi_engine), GFP_KERNEL);
- if (!spi_engine)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi_engine));
+ if (!host)
return -ENOMEM;
- master = spi_alloc_master(&pdev->dev, 0);
- if (!master)
- return -ENOMEM;
-
- spi_master_set_devdata(master, spi_engine);
+ spi_engine = spi_controller_get_devdata(host);
spin_lock_init(&spi_engine->lock);
+ init_completion(&spi_engine->msg_complete);
+
+ /*
+ * REVISIT: for now, all SPI Engines only have one offload. In the
+ * future, this should be read from a memory mapped register to
+ * determine the number of offloads enabled at HDL compile time. For
+ * now, we can tell if an offload is present if there is a trigger
+ * source wired up to it.
+ */
+ if (device_property_present(&pdev->dev, "trigger-sources")) {
+ struct spi_engine_offload *priv;
+
+ spi_engine->offload =
+ devm_spi_offload_alloc(&pdev->dev,
+ sizeof(struct spi_engine_offload));
+ if (IS_ERR(spi_engine->offload))
+ return PTR_ERR(spi_engine->offload);
+
+ priv = spi_engine->offload->priv;
+ priv->spi_engine = spi_engine;
+ priv->offload_num = 0;
+
+ spi_engine->offload->ops = &spi_engine_offload_ops;
+ spi_engine->offload_caps = SPI_OFFLOAD_CAP_TRIGGER;
+
+ if (device_property_match_string(&pdev->dev, "dma-names", "offload0-rx") >= 0) {
+ spi_engine->offload_caps |= SPI_OFFLOAD_CAP_RX_STREAM_DMA;
+ spi_engine->offload->xfer_flags |= SPI_OFFLOAD_XFER_RX_STREAM;
+ }
- spi_engine->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
- if (IS_ERR(spi_engine->clk)) {
- ret = PTR_ERR(spi_engine->clk);
- goto err_put_master;
- }
-
- spi_engine->ref_clk = devm_clk_get(&pdev->dev, "spi_clk");
- if (IS_ERR(spi_engine->ref_clk)) {
- ret = PTR_ERR(spi_engine->ref_clk);
- goto err_put_master;
+ if (device_property_match_string(&pdev->dev, "dma-names", "offload0-tx") >= 0) {
+ spi_engine->offload_caps |= SPI_OFFLOAD_CAP_TX_STREAM_DMA;
+ spi_engine->offload->xfer_flags |= SPI_OFFLOAD_XFER_TX_STREAM;
+ } else {
+ /*
+ * HDL compile option to enable TX DMA stream also disables
+ * the SDO memory, so can't do both at the same time.
+ */
+ spi_engine->offload_caps |= SPI_OFFLOAD_CAP_TX_STATIC_DATA;
+ }
}
- ret = clk_prepare_enable(spi_engine->clk);
- if (ret)
- goto err_put_master;
+ spi_engine->clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
+ if (IS_ERR(spi_engine->clk))
+ return PTR_ERR(spi_engine->clk);
- ret = clk_prepare_enable(spi_engine->ref_clk);
- if (ret)
- goto err_clk_disable;
+ spi_engine->ref_clk = devm_clk_get_enabled(&pdev->dev, "spi_clk");
+ if (IS_ERR(spi_engine->ref_clk))
+ return PTR_ERR(spi_engine->ref_clk);
spi_engine->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(spi_engine->base)) {
- ret = PTR_ERR(spi_engine->base);
- goto err_ref_clk_disable;
+ if (IS_ERR(spi_engine->base))
+ return PTR_ERR(spi_engine->base);
+
+ version = readl(spi_engine->base + ADI_AXI_REG_VERSION);
+ if (ADI_AXI_PCORE_VER_MAJOR(version) != 1) {
+ dev_err(&pdev->dev, "Unsupported peripheral version %u.%u.%u\n",
+ ADI_AXI_PCORE_VER_MAJOR(version),
+ ADI_AXI_PCORE_VER_MINOR(version),
+ ADI_AXI_PCORE_VER_PATCH(version));
+ return -ENODEV;
}
- version = readl(spi_engine->base + SPI_ENGINE_REG_VERSION);
- if (SPI_ENGINE_VERSION_MAJOR(version) != 1) {
- dev_err(&pdev->dev, "Unsupported peripheral version %u.%u.%c\n",
- SPI_ENGINE_VERSION_MAJOR(version),
- SPI_ENGINE_VERSION_MINOR(version),
- SPI_ENGINE_VERSION_PATCH(version));
- ret = -ENODEV;
- goto err_ref_clk_disable;
+ if (adi_axi_pcore_ver_gteq(version, 1, 1)) {
+ unsigned int sizes = readl(spi_engine->base +
+ SPI_ENGINE_REG_OFFLOAD_MEM_ADDR_WIDTH);
+
+ spi_engine->offload_ctrl_mem_size = 1 <<
+ FIELD_GET(SPI_ENGINE_SPI_OFFLOAD_MEM_WIDTH_CMD, sizes);
+ spi_engine->offload_sdo_mem_size = 1 <<
+ FIELD_GET(SPI_ENGINE_SPI_OFFLOAD_MEM_WIDTH_SDO, sizes);
+ } else {
+ spi_engine->offload_ctrl_mem_size = SPI_ENGINE_OFFLOAD_CMD_FIFO_SIZE;
+ spi_engine->offload_sdo_mem_size = SPI_ENGINE_OFFLOAD_SDO_FIFO_SIZE;
}
+ /* IP v1.5 dropped the requirement for SYNC in offload messages. */
+ spi_engine->offload_requires_sync = !adi_axi_pcore_ver_gteq(version, 1, 5);
+
writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_RESET);
writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
- ret = request_irq(irq, spi_engine_irq, 0, pdev->name, master);
+ ret = devm_add_action_or_reset(&pdev->dev, spi_engine_release_hw,
+ spi_engine);
if (ret)
- goto err_ref_clk_disable;
+ return ret;
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->max_speed_hz = clk_get_rate(spi_engine->ref_clk) / 2;
- master->transfer_one_message = spi_engine_transfer_one_message;
- master->num_chipselect = 8;
-
- ret = spi_register_master(master);
+ ret = devm_request_irq(&pdev->dev, irq, spi_engine_irq, 0, pdev->name,
+ host);
if (ret)
- goto err_free_irq;
-
- platform_set_drvdata(pdev, master);
-
- return 0;
-err_free_irq:
- free_irq(irq, master);
-err_ref_clk_disable:
- clk_disable_unprepare(spi_engine->ref_clk);
-err_clk_disable:
- clk_disable_unprepare(spi_engine->clk);
-err_put_master:
- spi_master_put(master);
- return ret;
-}
-
-static void spi_engine_remove(struct platform_device *pdev)
-{
- struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
- struct spi_engine *spi_engine = spi_master_get_devdata(master);
- int irq = platform_get_irq(pdev, 0);
-
- spi_unregister_master(master);
-
- free_irq(irq, master);
-
- spi_master_put(master);
+ return ret;
+
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ host->max_speed_hz = clk_get_rate(spi_engine->ref_clk) / 2;
+ host->transfer_one_message = spi_engine_transfer_one_message;
+ host->optimize_message = spi_engine_optimize_message;
+ host->unoptimize_message = spi_engine_unoptimize_message;
+ host->get_offload = spi_engine_get_offload;
+ host->put_offload = spi_engine_put_offload;
+ host->num_chipselect = 8;
+
+ if (adi_axi_pcore_ver_gteq(version, 1, 2)) {
+ host->mode_bits |= SPI_CS_HIGH;
+ host->setup = spi_engine_setup;
+ }
+ if (adi_axi_pcore_ver_gteq(version, 1, 3))
+ host->mode_bits |= SPI_MOSI_IDLE_LOW | SPI_MOSI_IDLE_HIGH;
- writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING);
- writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE);
- writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET);
+ if (host->max_speed_hz == 0)
+ return dev_err_probe(&pdev->dev, -EINVAL, "spi_clk rate is 0");
- clk_disable_unprepare(spi_engine->ref_clk);
- clk_disable_unprepare(spi_engine->clk);
+ return devm_spi_register_controller(&pdev->dev, host);
}
static const struct of_device_id spi_engine_match_table[] = {
@@ -582,7 +1112,6 @@ MODULE_DEVICE_TABLE(of, spi_engine_match_table);
static struct platform_driver spi_engine_driver = {
.probe = spi_engine_probe,
- .remove_new = spi_engine_remove,
.driver = {
.name = "spi-engine",
.of_match_table = spi_engine_match_table,
diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
index d91dfbe47aa5..cfdaa5eaec76 100644
--- a/drivers/spi/spi-bcm-qspi.c
+++ b/drivers/spi/spi-bcm-qspi.c
@@ -19,7 +19,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/spi/spi-mem.h>
+#include <linux/mtd/spi-nor.h>
#include <linux/sysfs.h>
#include <linux/types.h>
#include "spi-bcm-qspi.h"
@@ -220,7 +220,7 @@ struct qspi_trans {
struct bcm_qspi {
struct platform_device *pdev;
- struct spi_master *master;
+ struct spi_controller *host;
struct clk *clk;
u32 base_clk;
u32 max_speed_hz;
@@ -732,7 +732,7 @@ static bool bcm_qspi_mspi_transfer_is_last(struct bcm_qspi *qspi,
struct qspi_trans *qt)
{
if (qt->mspi_last_trans &&
- spi_transfer_is_last(qspi->master, qt->trans))
+ spi_transfer_is_last(qspi->host, qt->trans))
return true;
else
return false;
@@ -979,7 +979,7 @@ static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
mspi_cdram |= ((tp.trans->bits_per_word <= 8) ? 0 :
MSPI_CDRAM_BITSE_BIT);
- /* set 3wrire halfduplex mode data from master to slave */
+ /* set 3wrire halfduplex mode data from host to target */
if ((spi->mode & SPI_3WIRE) && tp.trans->tx_buf)
mspi_cdram |= MSPI_CDRAM_OUTP;
@@ -1035,7 +1035,7 @@ done:
static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
const struct spi_mem_op *op)
{
- struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct bcm_qspi *qspi = spi_controller_get_devdata(spi->controller);
u32 addr = 0, len, rdlen, len_words, from = 0;
int ret = 0;
unsigned long timeo = msecs_to_jiffies(100);
@@ -1118,11 +1118,11 @@ static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
return ret;
}
-static int bcm_qspi_transfer_one(struct spi_master *master,
+static int bcm_qspi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *trans)
{
- struct bcm_qspi *qspi = spi_master_get_devdata(master);
+ struct bcm_qspi *qspi = spi_controller_get_devdata(host);
int slots;
unsigned long timeo = msecs_to_jiffies(100);
@@ -1150,8 +1150,8 @@ static int bcm_qspi_transfer_one(struct spi_master *master,
static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
const struct spi_mem_op *op)
{
- struct spi_master *master = spi->master;
- struct bcm_qspi *qspi = spi_master_get_devdata(master);
+ struct spi_controller *host = spi->controller;
+ struct bcm_qspi *qspi = spi_controller_get_devdata(host);
struct spi_transfer t[2];
u8 cmd[6] = { };
int ret, i;
@@ -1171,7 +1171,7 @@ static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
t[0].tx_nbits = op->cmd.buswidth;
/* lets mspi know that this is not last transfer */
qspi->trans_pos.mspi_last_trans = false;
- ret = bcm_qspi_transfer_one(master, spi, &t[0]);
+ ret = bcm_qspi_transfer_one(host, spi, &t[0]);
/* rx */
qspi->trans_pos.mspi_last_trans = true;
@@ -1181,7 +1181,7 @@ static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
t[1].len = op->data.nbytes;
t[1].rx_nbits = op->data.buswidth;
t[1].bits_per_word = spi->bits_per_word;
- ret = bcm_qspi_transfer_one(master, spi, &t[1]);
+ ret = bcm_qspi_transfer_one(host, spi, &t[1]);
}
return ret;
@@ -1191,7 +1191,7 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct spi_device *spi = mem->spi;
- struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct bcm_qspi *qspi = spi_controller_get_devdata(spi->controller);
int ret = 0;
bool mspi_read = false;
u32 addr = 0, len;
@@ -1199,7 +1199,7 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem,
if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 ||
op->data.dir != SPI_MEM_DATA_IN)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
buf = op->data.buf.in;
addr = op->addr.val;
@@ -1221,7 +1221,7 @@ static int bcm_qspi_exec_mem_op(struct spi_mem *mem,
/* non-aligned and very short transfers are handled by MSPI */
if (!IS_ALIGNED((uintptr_t)addr, 4) || !IS_ALIGNED((uintptr_t)buf, 4) ||
- len < 4)
+ len < 4 || op->cmd.opcode == SPINOR_OP_RDSFDP)
mspi_read = true;
if (!has_bspi(qspi) || mspi_read)
@@ -1486,7 +1486,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
const struct bcm_qspi_data *data;
struct device *dev = &pdev->dev;
struct bcm_qspi *qspi;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *res;
int irq, ret = 0, num_ints = 0;
u32 val;
@@ -1504,13 +1504,13 @@ int bcm_qspi_probe(struct platform_device *pdev,
data = of_id->data;
- master = devm_spi_alloc_master(dev, sizeof(struct bcm_qspi));
- if (!master) {
- dev_err(dev, "error allocating spi_master\n");
+ host = devm_spi_alloc_host(dev, sizeof(struct bcm_qspi));
+ if (!host) {
+ dev_err(dev, "error allocating spi_controller\n");
return -ENOMEM;
}
- qspi = spi_master_get_devdata(master);
+ qspi = spi_controller_get_devdata(host);
qspi->clk = devm_clk_get_optional(&pdev->dev, NULL);
if (IS_ERR(qspi->clk))
@@ -1520,23 +1520,23 @@ int bcm_qspi_probe(struct platform_device *pdev,
qspi->trans_pos.trans = NULL;
qspi->trans_pos.byte = 0;
qspi->trans_pos.mspi_last_trans = true;
- qspi->master = master;
+ qspi->host = host;
- master->bus_num = -1;
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD |
+ host->bus_num = -1;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_3WIRE;
- master->setup = bcm_qspi_setup;
- master->transfer_one = bcm_qspi_transfer_one;
- master->mem_ops = &bcm_qspi_mem_ops;
- master->cleanup = bcm_qspi_cleanup;
- master->dev.of_node = dev->of_node;
- master->num_chipselect = NUM_CHIPSELECT;
- master->use_gpio_descriptors = true;
+ host->setup = bcm_qspi_setup;
+ host->transfer_one = bcm_qspi_transfer_one;
+ host->mem_ops = &bcm_qspi_mem_ops;
+ host->cleanup = bcm_qspi_cleanup;
+ host->dev.of_node = dev->of_node;
+ host->num_chipselect = NUM_CHIPSELECT;
+ host->use_gpio_descriptors = true;
qspi->big_endian = of_device_is_big_endian(dev->of_node);
if (!of_property_read_u32(dev->of_node, "num-cs", &val))
- master->num_chipselect = val;
+ host->num_chipselect = val;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hif_mspi");
if (!res)
@@ -1659,9 +1659,9 @@ int bcm_qspi_probe(struct platform_device *pdev,
qspi->xfer_mode.addrlen = -1;
qspi->xfer_mode.hp = -1;
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret < 0) {
- dev_err(dev, "can't register master\n");
+ dev_err(dev, "can't register host\n");
goto qspi_reg_err;
}
@@ -1682,7 +1682,7 @@ void bcm_qspi_remove(struct platform_device *pdev)
{
struct bcm_qspi *qspi = platform_get_drvdata(pdev);
- spi_unregister_master(qspi->master);
+ spi_unregister_controller(qspi->host);
bcm_qspi_hw_uninit(qspi);
clk_disable_unprepare(qspi->clk);
kfree(qspi->dev_ids);
@@ -1700,7 +1700,7 @@ static int __maybe_unused bcm_qspi_suspend(struct device *dev)
qspi->s3_strap_override_ctrl =
bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
- spi_master_suspend(qspi->master);
+ spi_controller_suspend(qspi->host);
clk_disable_unprepare(qspi->clk);
bcm_qspi_hw_uninit(qspi);
@@ -1721,7 +1721,7 @@ static int __maybe_unused bcm_qspi_resume(struct device *dev)
ret = clk_prepare_enable(qspi->clk);
if (!ret)
- spi_master_resume(qspi->master);
+ spi_controller_resume(qspi->host);
return ret;
}
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 3b253da98c05..192cc5ef65fb 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -11,6 +11,7 @@
* spi-atmel.c, Copyright (C) 2006 Atmel Corporation
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
@@ -24,11 +25,12 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
-#include <linux/gpio/machine.h> /* FIXME: using chip internals */
-#include <linux/gpio/driver.h> /* FIXME: using chip internals */
+#include <linux/gpio/machine.h> /* FIXME: using GPIO lookup tables */
#include <linux/of_irq.h>
+#include <linux/overflow.h>
+#include <linux/slab.h>
#include <linux/spi/spi.h>
/* SPI register offsets */
@@ -83,6 +85,7 @@ MODULE_PARM_DESC(polling_limit_us,
* struct bcm2835_spi - BCM2835 SPI controller
* @regs: base address of register map
* @clk: core clock, divided to calculate serial clock
+ * @cs_gpio: chip-select GPIO descriptor
* @clk_hz: core clock cached speed
* @irq: interrupt, signals TX FIFO empty or RX FIFO ¾ full
* @tfr: SPI transfer currently processed
@@ -105,7 +108,7 @@ MODULE_PARM_DESC(polling_limit_us,
* These are counted as well in @count_transfer_polling and
* @count_transfer_irq
* @count_transfer_dma: count how often dma mode is used
- * @slv: SPI slave currently selected
+ * @target: SPI target currently selected
* (used by bcm2835_spi_dma_tx_done() to write @clear_rx_cs)
* @tx_dma_active: whether a TX DMA descriptor is in progress
* @rx_dma_active: whether a RX DMA descriptor is in progress
@@ -117,6 +120,7 @@ MODULE_PARM_DESC(polling_limit_us,
struct bcm2835_spi {
void __iomem *regs;
struct clk *clk;
+ struct gpio_desc *cs_gpio;
unsigned long clk_hz;
int irq;
struct spi_transfer *tfr;
@@ -135,7 +139,7 @@ struct bcm2835_spi {
u64 count_transfer_irq_after_polling;
u64 count_transfer_dma;
- struct bcm2835_spidev *slv;
+ struct bcm2835_spidev *target;
unsigned int tx_dma_active;
unsigned int rx_dma_active;
struct dma_async_tx_descriptor *fill_tx_desc;
@@ -143,14 +147,14 @@ struct bcm2835_spi {
};
/**
- * struct bcm2835_spidev - BCM2835 SPI slave
+ * struct bcm2835_spidev - BCM2835 SPI target
* @prepare_cs: precalculated CS register value for ->prepare_message()
- * (uses slave-specific clock polarity and phase settings)
+ * (uses target-specific clock polarity and phase settings)
* @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers
* (cyclically clears RX FIFO by writing @clear_rx_cs to CS register)
* @clear_rx_addr: bus address of @clear_rx_cs
* @clear_rx_cs: precalculated CS register value to clear RX FIFO
- * (uses slave-specific clock polarity and phase settings)
+ * (uses target-specific clock polarity and phase settings)
*/
struct bcm2835_spidev {
u32 prepare_cs;
@@ -434,7 +438,7 @@ static int bcm2835_spi_transfer_one_irq(struct spi_controller *ctlr,
/**
* bcm2835_spi_transfer_prologue() - transfer first few bytes without DMA
- * @ctlr: SPI master controller
+ * @ctlr: SPI host controller
* @tfr: SPI transfer
* @bs: BCM2835 SPI controller
* @cs: CS register
@@ -596,7 +600,7 @@ out:
/**
* bcm2835_spi_dma_rx_done() - callback for DMA RX channel
- * @data: SPI master controller
+ * @data: SPI host controller
*
* Used for bidirectional and RX-only transfers.
*/
@@ -618,13 +622,13 @@ static void bcm2835_spi_dma_rx_done(void *data)
/* reset fifo and HW */
bcm2835_spi_reset_hw(bs);
- /* and mark as completed */;
+ /* and mark as completed */
spi_finalize_current_transfer(ctlr);
}
/**
* bcm2835_spi_dma_tx_done() - callback for DMA TX channel
- * @data: SPI master controller
+ * @data: SPI host controller
*
* Used for TX-only transfers.
*/
@@ -635,7 +639,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
/* busy-wait for TX FIFO to empty */
while (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE))
- bcm2835_wr(bs, BCM2835_SPI_CS, bs->slv->clear_rx_cs);
+ bcm2835_wr(bs, BCM2835_SPI_CS, bs->target->clear_rx_cs);
bs->tx_dma_active = false;
smp_wmb();
@@ -655,10 +659,10 @@ static void bcm2835_spi_dma_tx_done(void *data)
/**
* bcm2835_spi_prepare_sg() - prepare and submit DMA descriptor for sglist
- * @ctlr: SPI master controller
+ * @ctlr: SPI host controller
* @tfr: SPI transfer
* @bs: BCM2835 SPI controller
- * @slv: BCM2835 SPI slave
+ * @target: BCM2835 SPI target
* @is_tx: whether to submit DMA descriptor for TX or RX sglist
*
* Prepare and submit a DMA descriptor for the TX or RX sglist of @tfr.
@@ -667,7 +671,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
struct spi_transfer *tfr,
struct bcm2835_spi *bs,
- struct bcm2835_spidev *slv,
+ struct bcm2835_spidev *target,
bool is_tx)
{
struct dma_chan *chan;
@@ -707,7 +711,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
} else if (!tfr->rx_buf) {
desc->callback = bcm2835_spi_dma_tx_done;
desc->callback_param = ctlr;
- bs->slv = slv;
+ bs->target = target;
}
/* submit it to DMA-engine */
@@ -718,9 +722,9 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
/**
* bcm2835_spi_transfer_one_dma() - perform SPI transfer using DMA engine
- * @ctlr: SPI master controller
+ * @ctlr: SPI host controller
* @tfr: SPI transfer
- * @slv: BCM2835 SPI slave
+ * @target: BCM2835 SPI target
* @cs: CS register
*
* For *bidirectional* transfers (both tx_buf and rx_buf are non-%NULL), set up
@@ -732,7 +736,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
* clear the RX FIFO by setting the CLEAR_RX bit in the CS register.
*
* The CS register value is precalculated in bcm2835_spi_setup(). Normally
- * this is called only once, on slave registration. A DMA descriptor to write
+ * this is called only once, on target registration. A DMA descriptor to write
* this value is preallocated in bcm2835_dma_init(). All that's left to do
* when performing a TX-only transfer is to submit this descriptor to the RX
* DMA channel. Latency is thereby minimized. The descriptor does not
@@ -765,7 +769,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
*/
static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
struct spi_transfer *tfr,
- struct bcm2835_spidev *slv,
+ struct bcm2835_spidev *target,
u32 cs)
{
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
@@ -783,7 +787,7 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
/* setup tx-DMA */
if (bs->tx_buf) {
- ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, true);
+ ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, target, true);
} else {
cookie = dmaengine_submit(bs->fill_tx_desc);
ret = dma_submit_error(cookie);
@@ -809,9 +813,9 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
* this saves 10us or more.
*/
if (bs->rx_buf) {
- ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, false);
+ ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, target, false);
} else {
- cookie = dmaengine_submit(slv->clear_rx_desc);
+ cookie = dmaengine_submit(target->clear_rx_desc);
ret = dma_submit_error(cookie);
}
if (ret) {
@@ -903,15 +907,15 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
/* get tx/rx dma */
ctlr->dma_tx = dma_request_chan(dev, "tx");
if (IS_ERR(ctlr->dma_tx)) {
- dev_err(dev, "no tx-dma configuration found - not using dma mode\n");
- ret = PTR_ERR(ctlr->dma_tx);
+ ret = dev_err_probe(dev, PTR_ERR(ctlr->dma_tx),
+ "no tx-dma configuration found - not using dma mode\n");
ctlr->dma_tx = NULL;
goto err;
}
ctlr->dma_rx = dma_request_chan(dev, "rx");
if (IS_ERR(ctlr->dma_rx)) {
- dev_err(dev, "no rx-dma configuration found - not using dma mode\n");
- ret = PTR_ERR(ctlr->dma_rx);
+ ret = dev_err_probe(dev, PTR_ERR(ctlr->dma_rx),
+ "no rx-dma configuration found - not using dma mode\n");
ctlr->dma_rx = NULL;
goto err_release;
}
@@ -1050,10 +1054,10 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
struct spi_transfer *tfr)
{
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
- struct bcm2835_spidev *slv = spi_get_ctldata(spi);
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
unsigned long spi_hz, cdiv;
unsigned long hz_per_byte, byte_limit;
- u32 cs = slv->prepare_cs;
+ u32 cs = target->prepare_cs;
/* set clock */
spi_hz = tfr->speed_hz;
@@ -1101,7 +1105,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
* this 1 idle clock cycle pattern but runs the spi clock without gaps
*/
if (ctlr->can_dma && bcm2835_spi_can_dma(ctlr, spi, tfr))
- return bcm2835_spi_transfer_one_dma(ctlr, tfr, slv, cs);
+ return bcm2835_spi_transfer_one_dma(ctlr, tfr, target, cs);
/* run in interrupt-mode */
return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true);
@@ -1112,26 +1116,13 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
{
struct spi_device *spi = msg->spi;
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
- struct bcm2835_spidev *slv = spi_get_ctldata(spi);
- int ret;
-
- if (ctlr->can_dma) {
- /*
- * DMA transfers are limited to 16 bit (0 to 65535 bytes) by
- * the SPI HW due to DLEN. Split up transfers (32-bit FIFO
- * aligned) if the limit is exceeded.
- */
- ret = spi_split_transfers_maxsize(ctlr, msg, 65532,
- GFP_KERNEL | GFP_DMA);
- if (ret)
- return ret;
- }
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
/*
* Set up clock polarity before spi_transfer_one_message() asserts
* chip select to avoid a gratuitous clock signal edge.
*/
- bcm2835_wr(bs, BCM2835_SPI_CS, slv->prepare_cs);
+ bcm2835_wr(bs, BCM2835_SPI_CS, target->prepare_cs);
return 0;
}
@@ -1156,58 +1147,58 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
bcm2835_spi_reset_hw(bs);
}
-static int chip_match_name(struct gpio_chip *chip, void *data)
-{
- return !strcmp(chip->label, data);
-}
-
static void bcm2835_spi_cleanup(struct spi_device *spi)
{
- struct bcm2835_spidev *slv = spi_get_ctldata(spi);
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
struct spi_controller *ctlr = spi->controller;
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
- if (slv->clear_rx_desc)
- dmaengine_desc_free(slv->clear_rx_desc);
+ if (target->clear_rx_desc)
+ dmaengine_desc_free(target->clear_rx_desc);
- if (slv->clear_rx_addr)
+ if (target->clear_rx_addr)
dma_unmap_single(ctlr->dma_rx->device->dev,
- slv->clear_rx_addr,
+ target->clear_rx_addr,
sizeof(u32),
DMA_TO_DEVICE);
- kfree(slv);
+ if (!IS_ERR(bs->cs_gpio))
+ gpiod_put(bs->cs_gpio);
+ spi_set_csgpiod(spi, 0, NULL);
+
+ kfree(target);
}
static int bcm2835_spi_setup_dma(struct spi_controller *ctlr,
struct spi_device *spi,
struct bcm2835_spi *bs,
- struct bcm2835_spidev *slv)
+ struct bcm2835_spidev *target)
{
int ret;
if (!ctlr->dma_rx)
return 0;
- slv->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
- &slv->clear_rx_cs,
- sizeof(u32),
- DMA_TO_DEVICE);
- if (dma_mapping_error(ctlr->dma_rx->device->dev, slv->clear_rx_addr)) {
+ target->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
+ &target->clear_rx_cs,
+ sizeof(u32),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctlr->dma_rx->device->dev, target->clear_rx_addr)) {
dev_err(&spi->dev, "cannot map clear_rx_cs\n");
- slv->clear_rx_addr = 0;
+ target->clear_rx_addr = 0;
return -ENOMEM;
}
- slv->clear_rx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
- slv->clear_rx_addr,
- sizeof(u32), 0,
- DMA_MEM_TO_DEV, 0);
- if (!slv->clear_rx_desc) {
+ target->clear_rx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
+ target->clear_rx_addr,
+ sizeof(u32), 0,
+ DMA_MEM_TO_DEV, 0);
+ if (!target->clear_rx_desc) {
dev_err(&spi->dev, "cannot prepare clear_rx_desc\n");
return -ENOMEM;
}
- ret = dmaengine_desc_set_reuse(slv->clear_rx_desc);
+ ret = dmaengine_desc_set_reuse(target->clear_rx_desc);
if (ret) {
dev_err(&spi->dev, "cannot reuse clear_rx_desc\n");
return ret;
@@ -1216,30 +1207,48 @@ static int bcm2835_spi_setup_dma(struct spi_controller *ctlr,
return 0;
}
+static size_t bcm2835_spi_max_transfer_size(struct spi_device *spi)
+{
+ /*
+ * DMA transfers are limited to 16 bit (0 to 65535 bytes) by
+ * the SPI HW due to DLEN. Split up transfers (32-bit FIFO
+ * aligned) if the limit is exceeded.
+ */
+ if (spi->controller->can_dma)
+ return 65532;
+
+ return SIZE_MAX;
+}
+
static int bcm2835_spi_setup(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
- struct bcm2835_spidev *slv = spi_get_ctldata(spi);
- struct gpio_chip *chip;
- int ret;
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
+ struct gpiod_lookup_table *lookup __free(kfree) = NULL;
+ const char *pinctrl_compats[] = {
+ "brcm,bcm2835-gpio",
+ "brcm,bcm2711-gpio",
+ "brcm,bcm7211-gpio",
+ };
+ int ret, i;
u32 cs;
- if (!slv) {
- slv = kzalloc(ALIGN(sizeof(*slv), dma_get_cache_alignment()),
+ if (!target) {
+ target = kzalloc(ALIGN(sizeof(*target), dma_get_cache_alignment()),
GFP_KERNEL);
- if (!slv)
+ if (!target)
return -ENOMEM;
- spi_set_ctldata(spi, slv);
+ spi_set_ctldata(spi, target);
- ret = bcm2835_spi_setup_dma(ctlr, spi, bs, slv);
+ ret = bcm2835_spi_setup_dma(ctlr, spi, bs, target);
if (ret)
goto err_cleanup;
}
/*
- * Precalculate SPI slave's CS register value for ->prepare_message():
+ * Precalculate SPI target's CS register value for ->prepare_message():
* The driver always uses software-controlled GPIO chip select, hence
* set the hardware-controlled native chip select to an invalid value
* to prevent it from interfering.
@@ -1249,18 +1258,18 @@ static int bcm2835_spi_setup(struct spi_device *spi)
cs |= BCM2835_SPI_CS_CPOL;
if (spi->mode & SPI_CPHA)
cs |= BCM2835_SPI_CS_CPHA;
- slv->prepare_cs = cs;
+ target->prepare_cs = cs;
/*
- * Precalculate SPI slave's CS register value to clear RX FIFO
+ * Precalculate SPI target's CS register value to clear RX FIFO
* in case of a TX-only DMA transfer.
*/
if (ctlr->dma_rx) {
- slv->clear_rx_cs = cs | BCM2835_SPI_CS_TA |
+ target->clear_rx_cs = cs | BCM2835_SPI_CS_TA |
BCM2835_SPI_CS_DMAEN |
BCM2835_SPI_CS_CLEAR_RX;
dma_sync_single_for_device(ctlr->dma_rx->device->dev,
- slv->clear_rx_addr,
+ target->clear_rx_addr,
sizeof(u32),
DMA_TO_DEVICE);
}
@@ -1287,30 +1296,45 @@ static int bcm2835_spi_setup(struct spi_device *spi)
goto err_cleanup;
}
+ for (i = 0; i < ARRAY_SIZE(pinctrl_compats); i++) {
+ if (of_find_compatible_node(NULL, NULL, pinctrl_compats[i]))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(pinctrl_compats))
+ return 0;
+
/*
- * Translate native CS to GPIO
+ * TODO: The code below is a slightly better alternative to the utter
+ * abuse of the GPIO API that I found here before. It creates a
+ * temporary lookup table, assigns it to the SPI device, gets the GPIO
+ * descriptor and then releases the lookup table.
*
- * FIXME: poking around in the gpiolib internals like this is
- * not very good practice. Find a way to locate the real problem
- * and fix it. Why is the GPIO descriptor in spi->cs_gpiod
- * sometimes not assigned correctly? Erroneous device trees?
+ * More on the problem that it addresses:
+ * https://www.spinics.net/lists/linux-gpio/msg36218.html
*/
+ lookup = kzalloc(struct_size(lookup, table, 2), GFP_KERNEL);
+ if (!lookup) {
+ ret = -ENOMEM;
+ goto err_cleanup;
+ }
- /* get the gpio chip for the base */
- chip = gpiochip_find("pinctrl-bcm2835", chip_match_name);
- if (!chip)
- return 0;
+ lookup->dev_id = dev_name(&spi->dev);
+ lookup->table[0] = GPIO_LOOKUP("pinctrl-bcm2835",
+ 8 - (spi_get_chipselect(spi, 0)),
+ "cs", GPIO_LOOKUP_FLAGS_DEFAULT);
- spi_set_csgpiod(spi, 0, gpiochip_request_own_desc(chip,
- 8 - (spi_get_chipselect(spi, 0)),
- DRV_NAME,
- GPIO_LOOKUP_FLAGS_DEFAULT,
- GPIOD_OUT_LOW));
- if (IS_ERR(spi_get_csgpiod(spi, 0))) {
- ret = PTR_ERR(spi_get_csgpiod(spi, 0));
+ gpiod_add_lookup_table(lookup);
+
+ bs->cs_gpio = gpiod_get(&spi->dev, "cs", GPIOD_OUT_LOW);
+ gpiod_remove_lookup_table(lookup);
+ if (IS_ERR(bs->cs_gpio)) {
+ ret = PTR_ERR(bs->cs_gpio);
goto err_cleanup;
}
+ spi_set_csgpiod(spi, 0, bs->cs_gpio);
+
/* and set up the "mode" and level */
dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n",
spi_get_chipselect(spi, 0));
@@ -1328,7 +1352,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
struct bcm2835_spi *bs;
int err;
- ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*bs));
if (!ctlr)
return -ENOMEM;
@@ -1338,6 +1362,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
ctlr->mode_bits = BCM2835_SPI_MODE_BITS;
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->num_chipselect = 3;
+ ctlr->max_transfer_size = bcm2835_spi_max_transfer_size;
ctlr->setup = bcm2835_spi_setup;
ctlr->cleanup = bcm2835_spi_cleanup;
ctlr->transfer_one = bcm2835_spi_transfer_one;
@@ -1352,7 +1377,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
if (IS_ERR(bs->regs))
return PTR_ERR(bs->regs);
- bs->clk = devm_clk_get(&pdev->dev, NULL);
+ bs->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(bs->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(bs->clk),
"could not get clk\n");
@@ -1360,15 +1385,14 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
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;
+ if (bs->irq < 0)
+ return bs->irq;
- clk_prepare_enable(bs->clk);
bs->clk_hz = clk_get_rate(bs->clk);
err = bcm2835_dma_init(ctlr, &pdev->dev, bs);
if (err)
- goto out_clk_disable;
+ return err;
/* initialise the hardware with the default polarities */
bcm2835_wr(bs, BCM2835_SPI_CS,
@@ -1394,8 +1418,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
out_dma_release:
bcm2835_dma_release(ctlr, bs);
-out_clk_disable:
- clk_disable_unprepare(bs->clk);
return err;
}
@@ -1413,8 +1435,6 @@ static void bcm2835_spi_remove(struct platform_device *pdev)
/* Clear FIFOs, and disable the HW block */
bcm2835_wr(bs, BCM2835_SPI_CS,
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
-
- clk_disable_unprepare(bs->clk);
}
static const struct of_device_id bcm2835_spi_match[] = {
@@ -1429,7 +1449,7 @@ static struct platform_driver bcm2835_spi_driver = {
.of_match_table = bcm2835_spi_match,
},
.probe = bcm2835_spi_probe,
- .remove_new = bcm2835_spi_remove,
+ .remove = bcm2835_spi_remove,
.shutdown = bcm2835_spi_remove,
};
module_platform_driver(bcm2835_spi_driver);
diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c
index 288f7b994b36..90698d7d809d 100644
--- a/drivers/spi/spi-bcm2835aux.c
+++ b/drivers/spi/spi-bcm2835aux.c
@@ -20,9 +20,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>
@@ -233,8 +231,8 @@ static void bcm2835aux_spi_transfer_helper(struct bcm2835aux_spi *bs)
static irqreturn_t bcm2835aux_spi_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
/* IRQ may be shared, so return if our interrupts are disabled */
if (!(bcm2835aux_rd(bs, BCM2835_AUX_SPI_CNTL1) &
@@ -253,17 +251,17 @@ 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]);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
}
return IRQ_HANDLED;
}
-static int __bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
+static int __bcm2835aux_spi_transfer_one_irq(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
/* enable interrupts */
bcm2835aux_wr(bs, BCM2835_AUX_SPI_CNTL1, bs->cntl[1] |
@@ -274,11 +272,11 @@ static int __bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
return 1;
}
-static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
+static int bcm2835aux_spi_transfer_one_irq(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
/* update statistics */
bs->count_transfer_irq++;
@@ -296,14 +294,14 @@ static int bcm2835aux_spi_transfer_one_irq(struct spi_master *master,
}
/* now run the interrupt mode */
- return __bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
+ return __bcm2835aux_spi_transfer_one_irq(host, spi, tfr);
}
-static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
+static int bcm2835aux_spi_transfer_one_poll(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
unsigned long timeout;
/* update statistics */
@@ -330,7 +328,7 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
bs->tx_len, bs->rx_len);
/* forward to interrupt handler */
bs->count_transfer_irq_after_poll++;
- return __bcm2835aux_spi_transfer_one_irq(master,
+ return __bcm2835aux_spi_transfer_one_irq(host,
spi, tfr);
}
}
@@ -339,11 +337,11 @@ static int bcm2835aux_spi_transfer_one_poll(struct spi_master *master,
return 0;
}
-static int bcm2835aux_spi_transfer_one(struct spi_master *master,
+static int bcm2835aux_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
unsigned long spi_hz, clk_hz, speed;
unsigned long hz_per_byte, byte_limit;
@@ -394,17 +392,17 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
/* run in polling mode for short transfers */
if (tfr->len < byte_limit)
- return bcm2835aux_spi_transfer_one_poll(master, spi, tfr);
+ return bcm2835aux_spi_transfer_one_poll(host, spi, tfr);
/* run in interrupt mode for all others */
- return bcm2835aux_spi_transfer_one_irq(master, spi, tfr);
+ return bcm2835aux_spi_transfer_one_irq(host, spi, tfr);
}
-static int bcm2835aux_spi_prepare_message(struct spi_master *master,
+static int bcm2835aux_spi_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
struct spi_device *spi = msg->spi;
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
bs->cntl[0] = BCM2835_AUX_SPI_CNTL0_ENABLE |
BCM2835_AUX_SPI_CNTL0_VAR_WIDTH |
@@ -424,20 +422,20 @@ static int bcm2835aux_spi_prepare_message(struct spi_master *master,
return 0;
}
-static int bcm2835aux_spi_unprepare_message(struct spi_master *master,
+static int bcm2835aux_spi_unprepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
bcm2835aux_spi_reset_hw(bs);
return 0;
}
-static void bcm2835aux_spi_handle_err(struct spi_master *master,
+static void bcm2835aux_spi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
bcm2835aux_spi_reset_hw(bs);
}
@@ -475,18 +473,18 @@ static int bcm2835aux_spi_setup(struct spi_device *spi)
static int bcm2835aux_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct bcm2835aux_spi *bs;
unsigned long clk_hz;
int err;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*bs));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
- master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS);
- master->bits_per_word_mask = SPI_BPW_MASK(8);
+ platform_set_drvdata(pdev, host);
+ host->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS);
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
/* even though the driver never officially supported native CS
* allow a single native CS for legacy DT support purposes when
* no cs-gpio is configured.
@@ -498,23 +496,23 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
* * cs_delay_usec: cs is always deasserted one SCK cycle after
* a spi_transfer
*/
- master->num_chipselect = 1;
- master->setup = bcm2835aux_spi_setup;
- master->transfer_one = bcm2835aux_spi_transfer_one;
- master->handle_err = bcm2835aux_spi_handle_err;
- master->prepare_message = bcm2835aux_spi_prepare_message;
- master->unprepare_message = bcm2835aux_spi_unprepare_message;
- master->dev.of_node = pdev->dev.of_node;
- master->use_gpio_descriptors = true;
+ host->num_chipselect = 1;
+ host->setup = bcm2835aux_spi_setup;
+ host->transfer_one = bcm2835aux_spi_transfer_one;
+ host->handle_err = bcm2835aux_spi_handle_err;
+ host->prepare_message = bcm2835aux_spi_prepare_message;
+ host->unprepare_message = bcm2835aux_spi_unprepare_message;
+ host->dev.of_node = pdev->dev.of_node;
+ host->use_gpio_descriptors = true;
- bs = spi_master_get_devdata(master);
+ bs = spi_controller_get_devdata(host);
/* the main area */
bs->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(bs->regs))
return PTR_ERR(bs->regs);
- bs->clk = devm_clk_get(&pdev->dev, NULL);
+ bs->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(bs->clk)) {
err = PTR_ERR(bs->clk);
dev_err(&pdev->dev, "could not get clk: %d\n", err);
@@ -522,22 +520,14 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
}
bs->irq = platform_get_irq(pdev, 0);
- if (bs->irq <= 0)
- return bs->irq ? bs->irq : -ENODEV;
-
- /* this also enables the HW block */
- err = clk_prepare_enable(bs->clk);
- if (err) {
- dev_err(&pdev->dev, "could not prepare clock: %d\n", err);
- return err;
- }
+ if (bs->irq < 0)
+ return bs->irq;
/* just checking if the clock returns a sane value */
clk_hz = clk_get_rate(bs->clk);
if (!clk_hz) {
dev_err(&pdev->dev, "clock returns 0 Hz\n");
- err = -ENODEV;
- goto out_clk_disable;
+ return -ENODEV;
}
/* reset SPI-HW block */
@@ -546,40 +536,33 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev)
err = devm_request_irq(&pdev->dev, bs->irq,
bcm2835aux_spi_interrupt,
IRQF_SHARED,
- dev_name(&pdev->dev), master);
+ dev_name(&pdev->dev), host);
if (err) {
dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
- goto out_clk_disable;
+ return err;
}
- err = spi_register_master(master);
+ err = spi_register_controller(host);
if (err) {
- dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
- goto out_clk_disable;
+ dev_err(&pdev->dev, "could not register SPI host: %d\n", err);
+ return err;
}
bcm2835aux_debugfs_create(bs, dev_name(&pdev->dev));
return 0;
-
-out_clk_disable:
- clk_disable_unprepare(bs->clk);
- return err;
}
static void bcm2835aux_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct bcm2835aux_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct bcm2835aux_spi *bs = spi_controller_get_devdata(host);
bcm2835aux_debugfs_remove(bs);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
bcm2835aux_spi_reset_hw(bs);
-
- /* disable the HW block by releasing the clock */
- clk_disable_unprepare(bs->clk);
}
static const struct of_device_id bcm2835aux_spi_match[] = {
@@ -594,7 +577,7 @@ static struct platform_driver bcm2835aux_spi_driver = {
.of_match_table = bcm2835aux_spi_match,
},
.probe = bcm2835aux_spi_probe,
- .remove_new = bcm2835aux_spi_remove,
+ .remove = bcm2835aux_spi_remove,
};
module_platform_driver(bcm2835aux_spi_driver);
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index 9e218e143263..18261cbd413b 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -149,7 +149,7 @@ static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
return sprintf(buf, "%d\n", bs->wait_mode);
}
@@ -158,7 +158,7 @@ static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr
const char *buf, size_t count)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
u32 val;
if (kstrtou32(buf, 10, &val))
@@ -185,7 +185,7 @@ static ssize_t xfer_mode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
return sprintf(buf, "%d\n", bs->xfer_mode);
}
@@ -194,7 +194,7 @@ static ssize_t xfer_mode_store(struct device *dev, struct device_attribute *attr
const char *buf, size_t count)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(ctrl);
u32 val;
if (kstrtou32(buf, 10, &val))
@@ -262,12 +262,12 @@ static int bcm63xx_hsspi_wait_cmd(struct bcm63xx_hsspi *bs)
return rc;
}
-static bool bcm63xx_prepare_prepend_transfer(struct spi_master *master,
+static bool bcm63xx_prepare_prepend_transfer(struct spi_controller *host,
struct spi_message *msg,
struct spi_transfer *t_prepend)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
bool tx_only = false;
struct spi_transfer *t;
@@ -348,7 +348,7 @@ static bool bcm63xx_prepare_prepend_transfer(struct spi_master *master,
static int bcm63xx_hsspi_do_prepend_txrx(struct spi_device *spi,
struct spi_transfer *t)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
unsigned int chip_select = spi_get_chipselect(spi, 0);
u16 opcode = 0, val;
const u8 *tx = t->tx_buf;
@@ -467,7 +467,7 @@ static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
unsigned int chip_select = spi_get_chipselect(spi, 0);
u16 opcode = 0, val;
int pending = t->len;
@@ -541,7 +541,7 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
static int bcm63xx_hsspi_setup(struct spi_device *spi)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
u32 reg;
reg = __raw_readl(bs->regs +
@@ -579,7 +579,7 @@ static int bcm63xx_hsspi_setup(struct spi_device *spi)
static int bcm63xx_hsspi_do_dummy_cs_txrx(struct spi_device *spi,
struct spi_message *msg)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(spi->controller);
int status = -EINVAL;
int dummy_cs;
bool keep_cs = false;
@@ -653,10 +653,10 @@ static int bcm63xx_hsspi_do_dummy_cs_txrx(struct spi_device *spi,
return status;
}
-static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
+static int bcm63xx_hsspi_transfer_one(struct spi_controller *host,
struct spi_message *msg)
{
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
int status = -EINVAL;
bool prependable = false;
@@ -665,7 +665,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
mutex_lock(&bs->msg_mutex);
if (bs->xfer_mode != HSSPI_XFER_MODE_DUMMYCS)
- prependable = bcm63xx_prepare_prepend_transfer(master, msg, &t_prepend);
+ prependable = bcm63xx_prepare_prepend_transfer(host, msg, &t_prepend);
if (prependable) {
status = bcm63xx_hsspi_do_prepend_txrx(spi, &t_prepend);
@@ -681,7 +681,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
mutex_unlock(&bs->msg_mutex);
msg->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return 0;
}
@@ -723,7 +723,7 @@ static irqreturn_t bcm63xx_hsspi_interrupt(int irq, void *dev_id)
static int bcm63xx_hsspi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct bcm63xx_hsspi *bs;
void __iomem *regs;
struct device *dev = &pdev->dev;
@@ -745,7 +745,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- reset = devm_reset_control_get_optional_exclusive(dev, NULL);
+ reset = devm_reset_control_get_optional_shared(dev, NULL);
if (IS_ERR(reset))
return PTR_ERR(reset);
@@ -779,13 +779,13 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
}
}
- master = spi_alloc_master(&pdev->dev, sizeof(*bs));
- if (!master) {
+ host = spi_alloc_host(&pdev->dev, sizeof(*bs));
+ if (!host) {
ret = -ENOMEM;
goto out_disable_pll_clk;
}
- bs = spi_master_get_devdata(master);
+ bs = spi_controller_get_devdata(host);
bs->pdev = pdev;
bs->clk = clk;
bs->pll_clk = pll_clk;
@@ -796,17 +796,17 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
bs->prepend_buf = devm_kzalloc(dev, HSSPI_BUFFER_LEN, GFP_KERNEL);
if (!bs->prepend_buf) {
ret = -ENOMEM;
- goto out_put_master;
+ goto out_put_host;
}
mutex_init(&bs->bus_mutex);
mutex_init(&bs->msg_mutex);
init_completion(&bs->done);
- master->mem_ops = &bcm63xx_hsspi_mem_ops;
- master->dev.of_node = dev->of_node;
+ host->mem_ops = &bcm63xx_hsspi_mem_ops;
+ host->dev.of_node = dev->of_node;
if (!dev->of_node)
- master->bus_num = HSSPI_BUS_NUM;
+ host->bus_num = HSSPI_BUS_NUM;
of_property_read_u32(dev->of_node, "num-cs", &num_cs);
if (num_cs > 8) {
@@ -814,18 +814,18 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
num_cs);
num_cs = HSSPI_SPI_MAX_CS;
}
- master->num_chipselect = num_cs;
- master->setup = bcm63xx_hsspi_setup;
- master->transfer_one_message = bcm63xx_hsspi_transfer_one;
- master->max_transfer_size = bcm63xx_hsspi_max_message_size;
- master->max_message_size = bcm63xx_hsspi_max_message_size;
+ host->num_chipselect = num_cs;
+ host->setup = bcm63xx_hsspi_setup;
+ host->transfer_one_message = bcm63xx_hsspi_transfer_one;
+ host->max_transfer_size = bcm63xx_hsspi_max_message_size;
+ host->max_message_size = bcm63xx_hsspi_max_message_size;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
SPI_RX_DUAL | SPI_TX_DUAL;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->auto_runtime_pm = true;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->auto_runtime_pm = true;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
/* Initialize the hardware */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
@@ -844,7 +844,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
pdev->name, bs);
if (ret)
- goto out_put_master;
+ goto out_put_host;
}
pm_runtime_enable(&pdev->dev);
@@ -856,7 +856,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
}
/* register and we are done */
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
goto out_sysgroup_disable;
@@ -868,8 +868,8 @@ out_sysgroup_disable:
sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
out_pm_disable:
pm_runtime_disable(&pdev->dev);
-out_put_master:
- spi_master_put(master);
+out_put_host:
+ spi_controller_put(host);
out_disable_pll_clk:
clk_disable_unprepare(pll_clk);
out_disable_clk:
@@ -880,8 +880,8 @@ out_disable_clk:
static void bcm63xx_hsspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
/* reset the hardware and block queue progress */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
@@ -893,10 +893,10 @@ static void bcm63xx_hsspi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int bcm63xx_hsspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
- spi_master_suspend(master);
+ spi_controller_suspend(host);
clk_disable_unprepare(bs->pll_clk);
clk_disable_unprepare(bs->clk);
@@ -905,8 +905,8 @@ static int bcm63xx_hsspi_suspend(struct device *dev)
static int bcm63xx_hsspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(bs->clk);
@@ -921,7 +921,7 @@ static int bcm63xx_hsspi_resume(struct device *dev)
}
}
- spi_master_resume(master);
+ spi_controller_resume(host);
return 0;
}
@@ -944,7 +944,7 @@ static struct platform_driver bcm63xx_hsspi_driver = {
.of_match_table = bcm63xx_hsspi_of_match,
},
.probe = bcm63xx_hsspi_probe,
- .remove_new = bcm63xx_hsspi_remove,
+ .remove = bcm63xx_hsspi_remove,
};
module_platform_driver(bcm63xx_hsspi_driver);
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 07b5b71b2352..4c549f166b0f 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -186,7 +186,7 @@ static const unsigned int bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(spi->controller);
u8 clk_cfg, reg;
int i;
@@ -217,7 +217,7 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
unsigned int num_transfers)
{
- struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(spi->controller);
u16 msg_ctl;
u16 cmd;
unsigned int i, timeout = 0, prepend_len = 0, len = 0;
@@ -247,6 +247,20 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
if (t->rx_buf) {
do_rx = true;
+
+ /*
+ * In certain hardware implementations, there appears to be a
+ * hidden accumulator that tracks the number of bytes written into
+ * the hardware FIFO, and this accumulator overrides the length in
+ * the SPI_MSG_CTL register.
+ *
+ * Therefore, for read-only transfers, we need to write some dummy
+ * value into the FIFO to keep the accumulator tracking the correct
+ * length.
+ */
+ if (!t->tx_buf)
+ memset_io(bs->tx_io + len, 0xFF, t->len);
+
/* prepend is half-duplex write only */
if (t == first)
prepend_len = 0;
@@ -312,10 +326,10 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
return 0;
}
-static int bcm63xx_spi_transfer_one(struct spi_master *master,
+static int bcm63xx_spi_transfer_one(struct spi_controller *host,
struct spi_message *m)
{
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
struct spi_transfer *t, *first = NULL;
struct spi_device *spi = m->spi;
int status = 0;
@@ -385,18 +399,18 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
}
exit:
m->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return 0;
}
-/* This driver supports single master mode only. Hence
+/* This driver supports single host mode only. Hence
* CMD_DONE is the only interrupt we care about
*/
static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = (struct spi_master *)dev_id;
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = (struct spi_controller *)dev_id;
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
u8 intr;
/* Read interupts and clear them immediately */
@@ -413,7 +427,7 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
static size_t bcm63xx_spi_max_length(struct spi_device *spi)
{
- struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(spi->controller);
return bs->fifo_size;
}
@@ -466,12 +480,14 @@ static const struct platform_device_id bcm63xx_spi_dev_match[] = {
{
},
};
+MODULE_DEVICE_TABLE(platform, bcm63xx_spi_dev_match);
static const struct of_device_id bcm63xx_spi_of_match[] = {
{ .compatible = "brcm,bcm6348-spi", .data = &bcm6348_spi_reg_offsets },
{ .compatible = "brcm,bcm6358-spi", .data = &bcm6358_spi_reg_offsets },
{ },
};
+MODULE_DEVICE_TABLE(of, bcm63xx_spi_of_match);
static int bcm63xx_spi_probe(struct platform_device *pdev)
{
@@ -479,7 +495,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
const unsigned long *bcm63xx_spireg;
struct device *dev = &pdev->dev;
int irq, bus_num;
- struct spi_master *master;
+ struct spi_controller *host;
struct clk *clk;
struct bcm63xx_spi *bs;
int ret;
@@ -521,20 +537,20 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
return PTR_ERR(clk);
}
- reset = devm_reset_control_get_optional_exclusive(dev, NULL);
+ reset = devm_reset_control_get_optional_shared(dev, NULL);
if (IS_ERR(reset))
return PTR_ERR(reset);
- master = spi_alloc_master(dev, sizeof(*bs));
- if (!master) {
+ host = spi_alloc_host(dev, sizeof(*bs));
+ if (!host) {
dev_err(dev, "out of memory\n");
return -ENOMEM;
}
- bs = spi_master_get_devdata(master);
+ bs = spi_controller_get_devdata(host);
init_completion(&bs->done);
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
bs->pdev = pdev;
bs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
@@ -549,25 +565,25 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
bs->fifo_size = bs->reg_offsets[SPI_MSG_DATA_SIZE];
ret = devm_request_irq(&pdev->dev, irq, bcm63xx_spi_interrupt, 0,
- pdev->name, master);
+ pdev->name, host);
if (ret) {
dev_err(dev, "unable to request irq\n");
goto out_err;
}
- master->dev.of_node = dev->of_node;
- master->bus_num = bus_num;
- master->num_chipselect = num_cs;
- master->transfer_one_message = bcm63xx_spi_transfer_one;
- master->mode_bits = MODEBITS;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->max_transfer_size = bcm63xx_spi_max_length;
- master->max_message_size = bcm63xx_spi_max_length;
- master->auto_runtime_pm = true;
+ host->dev.of_node = dev->of_node;
+ host->bus_num = bus_num;
+ host->num_chipselect = num_cs;
+ host->transfer_one_message = bcm63xx_spi_transfer_one;
+ host->mode_bits = MODEBITS;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->max_transfer_size = bcm63xx_spi_max_length;
+ host->max_message_size = bcm63xx_spi_max_length;
+ host->auto_runtime_pm = true;
bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT];
bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH];
- bs->tx_io = (u8 *)(bs->regs + bs->reg_offsets[SPI_MSG_DATA]);
- bs->rx_io = (const u8 *)(bs->regs + bs->reg_offsets[SPI_RX_DATA]);
+ bs->tx_io = bs->regs + bs->reg_offsets[SPI_MSG_DATA];
+ bs->rx_io = bs->regs + bs->reg_offsets[SPI_RX_DATA];
/* Initialize hardware */
ret = clk_prepare_enable(bs->clk);
@@ -582,13 +598,15 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
- pm_runtime_enable(&pdev->dev);
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ goto out_clk_disable;
/* register and we are done */
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret) {
dev_err(dev, "spi register failed\n");
- goto out_pm_disable;
+ goto out_clk_disable;
}
dev_info(dev, "at %pr (irq %d, FIFOs size %d)\n",
@@ -596,19 +614,17 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
return 0;
-out_pm_disable:
- pm_runtime_disable(&pdev->dev);
out_clk_disable:
clk_disable_unprepare(clk);
out_err:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static void bcm63xx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
/* reset spi block */
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
@@ -619,10 +635,10 @@ static void bcm63xx_spi_remove(struct platform_device *pdev)
static int bcm63xx_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
- spi_master_suspend(master);
+ spi_controller_suspend(host);
clk_disable_unprepare(bs->clk);
@@ -631,15 +647,15 @@ static int bcm63xx_spi_suspend(struct device *dev)
static int bcm63xx_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcm63xx_spi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(bs->clk);
if (ret)
return ret;
- spi_master_resume(master);
+ spi_controller_resume(host);
return 0;
}
@@ -654,7 +670,7 @@ static struct platform_driver bcm63xx_spi_driver = {
},
.id_table = bcm63xx_spi_dev_match,
.probe = bcm63xx_spi_probe,
- .remove_new = bcm63xx_spi_remove,
+ .remove = bcm63xx_spi_remove,
};
module_platform_driver(bcm63xx_spi_driver);
diff --git a/drivers/spi/spi-bcmbca-hsspi.c b/drivers/spi/spi-bcmbca-hsspi.c
index ca1b4741e9f4..f16298b75236 100644
--- a/drivers/spi/spi-bcmbca-hsspi.c
+++ b/drivers/spi/spi-bcmbca-hsspi.c
@@ -127,7 +127,7 @@ static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(ctrl);
return sprintf(buf, "%d\n", bs->wait_mode);
}
@@ -136,7 +136,7 @@ static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr
const char *buf, size_t count)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(ctrl);
u32 val;
if (kstrtou32(buf, 10, &val))
@@ -250,7 +250,7 @@ static int bcmbca_hsspi_wait_cmd(struct bcmbca_hsspi *bs, unsigned int cs)
static int bcmbca_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t,
struct spi_message *msg)
{
- struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(spi->controller);
unsigned int chip_select = spi_get_chipselect(spi, 0);
u16 opcode = 0, val;
int pending = t->len;
@@ -328,7 +328,7 @@ static int bcmbca_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t,
static int bcmbca_hsspi_setup(struct spi_device *spi)
{
- struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(spi->controller);
u32 reg;
reg = __raw_readl(bs->regs +
@@ -366,10 +366,10 @@ static int bcmbca_hsspi_setup(struct spi_device *spi)
return 0;
}
-static int bcmbca_hsspi_transfer_one(struct spi_master *master,
+static int bcmbca_hsspi_transfer_one(struct spi_controller *host,
struct spi_message *msg)
{
- struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(host);
struct spi_transfer *t;
struct spi_device *spi = msg->spi;
int status = -EINVAL;
@@ -409,7 +409,7 @@ static int bcmbca_hsspi_transfer_one(struct spi_master *master,
bcmbca_hsspi_set_cs(bs, spi_get_chipselect(spi, 0), false);
msg->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return 0;
}
@@ -431,9 +431,8 @@ static irqreturn_t bcmbca_hsspi_interrupt(int irq, void *dev_id)
static int bcmbca_hsspi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct bcmbca_hsspi *bs;
- struct resource *res_mem;
void __iomem *spim_ctrl;
void __iomem *regs;
struct device *dev = &pdev->dev;
@@ -445,17 +444,11 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsspi");
- if (!res_mem)
- return -EINVAL;
- regs = devm_ioremap_resource(dev, res_mem);
+ regs = devm_platform_ioremap_resource_byname(pdev, "hsspi");
if (IS_ERR(regs))
return PTR_ERR(regs);
- res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spim-ctrl");
- if (!res_mem)
- return -EINVAL;
- spim_ctrl = devm_ioremap_resource(dev, res_mem);
+ spim_ctrl = devm_platform_ioremap_resource_byname(pdev, "spim-ctrl");
if (IS_ERR(spim_ctrl))
return PTR_ERR(spim_ctrl);
@@ -487,13 +480,13 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
}
}
- master = spi_alloc_master(&pdev->dev, sizeof(*bs));
- if (!master) {
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*bs));
+ if (!host) {
ret = -ENOMEM;
goto out_disable_pll_clk;
}
- bs = spi_master_get_devdata(master);
+ bs = spi_controller_get_devdata(host);
bs->pdev = pdev;
bs->clk = clk;
bs->pll_clk = pll_clk;
@@ -507,9 +500,9 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
mutex_init(&bs->msg_mutex);
init_completion(&bs->done);
- master->dev.of_node = dev->of_node;
+ host->dev.of_node = dev->of_node;
if (!dev->of_node)
- master->bus_num = HSSPI_BUS_NUM;
+ host->bus_num = HSSPI_BUS_NUM;
of_property_read_u32(dev->of_node, "num-cs", &num_cs);
if (num_cs > 8) {
@@ -517,15 +510,15 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
num_cs);
num_cs = HSSPI_SPI_MAX_CS;
}
- master->num_chipselect = num_cs;
- master->setup = bcmbca_hsspi_setup;
- master->transfer_one_message = bcmbca_hsspi_transfer_one;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
- SPI_RX_DUAL | SPI_TX_DUAL;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->auto_runtime_pm = true;
+ host->num_chipselect = num_cs;
+ host->setup = bcmbca_hsspi_setup;
+ host->transfer_one_message = bcmbca_hsspi_transfer_one;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
+ SPI_RX_DUAL | SPI_TX_DUAL;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->auto_runtime_pm = true;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
/* Initialize the hardware */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
@@ -543,19 +536,21 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, bcmbca_hsspi_interrupt, IRQF_SHARED,
pdev->name, bs);
if (ret)
- goto out_put_master;
+ goto out_disable_pll_clk;
}
- pm_runtime_enable(&pdev->dev);
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ goto out_disable_pll_clk;
ret = sysfs_create_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
if (ret) {
dev_err(&pdev->dev, "couldn't register sysfs group\n");
- goto out_pm_disable;
+ goto out_disable_pll_clk;
}
/* register and we are done */
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
goto out_sysgroup_disable;
@@ -565,10 +560,6 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev)
out_sysgroup_disable:
sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
-out_pm_disable:
- pm_runtime_disable(&pdev->dev);
-out_put_master:
- spi_master_put(master);
out_disable_pll_clk:
clk_disable_unprepare(pll_clk);
out_disable_clk:
@@ -578,8 +569,8 @@ out_disable_clk:
static void bcmbca_hsspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(host);
/* reset the hardware and block queue progress */
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
@@ -591,10 +582,10 @@ static void bcmbca_hsspi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int bcmbca_hsspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(host);
- spi_master_suspend(master);
+ spi_controller_suspend(host);
clk_disable_unprepare(bs->pll_clk);
clk_disable_unprepare(bs->clk);
@@ -603,8 +594,8 @@ static int bcmbca_hsspi_suspend(struct device *dev)
static int bcmbca_hsspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct bcmbca_hsspi *bs = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(bs->clk);
@@ -619,7 +610,7 @@ static int bcmbca_hsspi_resume(struct device *dev)
}
}
- spi_master_resume(master);
+ spi_controller_resume(host);
return 0;
}
@@ -642,7 +633,7 @@ static struct platform_driver bcmbca_hsspi_driver = {
.of_match_table = bcmbca_hsspi_of_match,
},
.probe = bcmbca_hsspi_probe,
- .remove_new = bcmbca_hsspi_remove,
+ .remove = bcmbca_hsspi_remove,
};
module_platform_driver(bcmbca_hsspi_driver);
diff --git a/drivers/spi/spi-bitbang-txrx.h b/drivers/spi/spi-bitbang-txrx.h
index 2dcbe166df63..0cab48b7875b 100644
--- a/drivers/spi/spi-bitbang-txrx.h
+++ b/drivers/spi/spi-bitbang-txrx.h
@@ -57,7 +57,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
for (word <<= (32 - bits); likely(bits); bits--) {
/* setup MSB (to slave) on trailing edge */
- if ((flags & SPI_MASTER_NO_TX) == 0) {
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0) {
if ((word & (1 << 31)) != oldbit) {
setmosi(spi, word & (1 << 31));
oldbit = word & (1 << 31);
@@ -70,7 +70,7 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
/* sample MSB (from slave) on leading edge */
word <<= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= getmiso(spi);
setsck(spi, cpol);
}
@@ -90,7 +90,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
/* setup MSB (to slave) on leading edge */
setsck(spi, !cpol);
- if ((flags & SPI_MASTER_NO_TX) == 0) {
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0) {
if ((word & (1 << 31)) != oldbit) {
setmosi(spi, word & (1 << 31));
oldbit = word & (1 << 31);
@@ -103,7 +103,7 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
/* sample MSB (from slave) on trailing edge */
word <<= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= getmiso(spi);
}
return word;
@@ -122,7 +122,7 @@ bitbang_txrx_le_cpha0(struct spi_device *spi,
for (; likely(bits); bits--) {
/* setup LSB (to slave) on trailing edge */
- if ((flags & SPI_MASTER_NO_TX) == 0) {
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0) {
if ((word & 1) != oldbit) {
setmosi(spi, word & 1);
oldbit = word & 1;
@@ -135,7 +135,7 @@ bitbang_txrx_le_cpha0(struct spi_device *spi,
/* sample LSB (from slave) on leading edge */
word >>= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= getmiso(spi) << rxbit;
setsck(spi, cpol);
}
@@ -156,7 +156,7 @@ bitbang_txrx_le_cpha1(struct spi_device *spi,
/* setup LSB (to slave) on leading edge */
setsck(spi, !cpol);
- if ((flags & SPI_MASTER_NO_TX) == 0) {
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0) {
if ((word & 1) != oldbit) {
setmosi(spi, word & 1);
oldbit = word & 1;
@@ -169,7 +169,7 @@ bitbang_txrx_le_cpha1(struct spi_device *spi,
/* sample LSB (from slave) on trailing edge */
word >>= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= getmiso(spi) << rxbit;
}
return word;
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index 27d0087f8688..ebe18f0b5d23 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * polling/bitbanging SPI master controller driver utilities
+ * Polling/bitbanging SPI host controller controller driver utilities
*/
#include <linux/spinlock.h>
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/time64.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
@@ -37,104 +38,106 @@
* working quickly, or testing for differences that aren't speed related.
*/
+typedef unsigned int (*spi_bb_txrx_bufs_fn)(struct spi_device *, spi_bb_txrx_word_fn,
+ unsigned int, struct spi_transfer *,
+ unsigned int);
+
struct spi_bitbang_cs {
- unsigned nsecs; /* (clock cycle time)/2 */
- u32 (*txrx_word)(struct spi_device *spi, unsigned nsecs,
- u32 word, u8 bits, unsigned flags);
- unsigned (*txrx_bufs)(struct spi_device *,
- u32 (*txrx_word)(
- struct spi_device *spi,
- unsigned nsecs,
- u32 word, u8 bits,
- unsigned flags),
- unsigned, struct spi_transfer *,
- unsigned);
+ unsigned int nsecs; /* (clock cycle time) / 2 */
+ spi_bb_txrx_word_fn txrx_word;
+ spi_bb_txrx_bufs_fn txrx_bufs;
};
-static unsigned bitbang_txrx_8(
- struct spi_device *spi,
- u32 (*txrx_word)(struct spi_device *spi,
- unsigned nsecs,
- u32 word, u8 bits,
- unsigned flags),
- unsigned ns,
+static unsigned int bitbang_txrx_8(struct spi_device *spi,
+ spi_bb_txrx_word_fn txrx_word,
+ unsigned int ns,
struct spi_transfer *t,
- unsigned flags
-)
+ unsigned int flags)
{
- unsigned bits = t->bits_per_word;
- unsigned count = t->len;
+ struct spi_bitbang *bitbang;
+ unsigned int bits = t->bits_per_word;
+ unsigned int count = t->len;
const u8 *tx = t->tx_buf;
u8 *rx = t->rx_buf;
+ bitbang = spi_controller_get_devdata(spi->controller);
while (likely(count > 0)) {
u8 word = 0;
if (tx)
word = *tx++;
+ else
+ word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFF : 0;
word = txrx_word(spi, ns, word, bits, flags);
if (rx)
*rx++ = word;
count -= 1;
}
+ if (bitbang->set_mosi_idle)
+ bitbang->set_mosi_idle(spi);
+
return t->len - count;
}
-static unsigned bitbang_txrx_16(
- struct spi_device *spi,
- u32 (*txrx_word)(struct spi_device *spi,
- unsigned nsecs,
- u32 word, u8 bits,
- unsigned flags),
- unsigned ns,
+static unsigned int bitbang_txrx_16(struct spi_device *spi,
+ spi_bb_txrx_word_fn txrx_word,
+ unsigned int ns,
struct spi_transfer *t,
- unsigned flags
-)
+ unsigned int flags)
{
- unsigned bits = t->bits_per_word;
- unsigned count = t->len;
+ struct spi_bitbang *bitbang;
+ unsigned int bits = t->bits_per_word;
+ unsigned int count = t->len;
const u16 *tx = t->tx_buf;
u16 *rx = t->rx_buf;
+ bitbang = spi_controller_get_devdata(spi->controller);
while (likely(count > 1)) {
u16 word = 0;
if (tx)
word = *tx++;
+ else
+ word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFF : 0;
word = txrx_word(spi, ns, word, bits, flags);
if (rx)
*rx++ = word;
count -= 2;
}
+ if (bitbang->set_mosi_idle)
+ bitbang->set_mosi_idle(spi);
+
return t->len - count;
}
-static unsigned bitbang_txrx_32(
- struct spi_device *spi,
- u32 (*txrx_word)(struct spi_device *spi,
- unsigned nsecs,
- u32 word, u8 bits,
- unsigned flags),
- unsigned ns,
+static unsigned int bitbang_txrx_32(struct spi_device *spi,
+ spi_bb_txrx_word_fn txrx_word,
+ unsigned int ns,
struct spi_transfer *t,
- unsigned flags
-)
+ unsigned int flags)
{
- unsigned bits = t->bits_per_word;
- unsigned count = t->len;
+ struct spi_bitbang *bitbang;
+ unsigned int bits = t->bits_per_word;
+ unsigned int count = t->len;
const u32 *tx = t->tx_buf;
u32 *rx = t->rx_buf;
+ bitbang = spi_controller_get_devdata(spi->controller);
while (likely(count > 3)) {
u32 word = 0;
if (tx)
word = *tx++;
+ else
+ word = spi->mode & SPI_MOSI_IDLE_HIGH ? 0xFFFFFFFF : 0;
word = txrx_word(spi, ns, word, bits, flags);
if (rx)
*rx++ = word;
count -= 4;
}
+ if (bitbang->set_mosi_idle)
+ bitbang->set_mosi_idle(spi);
+
return t->len - count;
}
@@ -168,8 +171,8 @@ int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if (!hz)
hz = spi->max_speed_hz;
if (hz) {
- cs->nsecs = (1000000000/2) / hz;
- if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))
+ cs->nsecs = (NSEC_PER_SEC / 2) / hz;
+ if (cs->nsecs > (MAX_UDELAY_MS * NSEC_PER_MSEC))
return -EINVAL;
}
@@ -187,7 +190,7 @@ int spi_bitbang_setup(struct spi_device *spi)
bool initial_setup = false;
int retval;
- bitbang = spi_master_get_devdata(spi->master);
+ bitbang = spi_controller_get_devdata(spi->controller);
if (!cs) {
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
@@ -210,6 +213,9 @@ int spi_bitbang_setup(struct spi_device *spi)
goto err_free;
}
+ if (bitbang->set_mosi_idle)
+ bitbang->set_mosi_idle(spi);
+
dev_dbg(&spi->dev, "%s, %u nsec/bit\n", __func__, 2 * cs->nsecs);
return 0;
@@ -233,10 +239,10 @@ EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct spi_bitbang_cs *cs = spi->controller_state;
- unsigned nsecs = cs->nsecs;
+ unsigned int nsecs = cs->nsecs;
struct spi_bitbang *bitbang;
- bitbang = spi_master_get_devdata(spi->master);
+ bitbang = spi_controller_get_devdata(spi->controller);
if (bitbang->set_line_direction) {
int err;
@@ -246,9 +252,9 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
}
if (spi->mode & SPI_3WIRE) {
- unsigned flags;
+ unsigned int flags;
- flags = t->tx_buf ? SPI_MASTER_NO_RX : SPI_MASTER_NO_TX;
+ flags = t->tx_buf ? SPI_CONTROLLER_NO_RX : SPI_CONTROLLER_NO_TX;
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, flags);
}
return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, 0);
@@ -268,11 +274,11 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
* transfer-at-a-time ones to leverage dma or fifo hardware.
*/
-static int spi_bitbang_prepare_hardware(struct spi_master *spi)
+static int spi_bitbang_prepare_hardware(struct spi_controller *spi)
{
struct spi_bitbang *bitbang;
- bitbang = spi_master_get_devdata(spi);
+ bitbang = spi_controller_get_devdata(spi);
mutex_lock(&bitbang->lock);
bitbang->busy = 1;
@@ -281,11 +287,11 @@ static int spi_bitbang_prepare_hardware(struct spi_master *spi)
return 0;
}
-static int spi_bitbang_transfer_one(struct spi_master *master,
+static int spi_bitbang_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *transfer)
{
- struct spi_bitbang *bitbang = spi_master_get_devdata(master);
+ struct spi_bitbang *bitbang = spi_controller_get_devdata(ctlr);
int status = 0;
if (bitbang->setup_transfer) {
@@ -303,16 +309,16 @@ static int spi_bitbang_transfer_one(struct spi_master *master,
status = -EREMOTEIO;
out:
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(ctlr);
return status;
}
-static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
+static int spi_bitbang_unprepare_hardware(struct spi_controller *spi)
{
struct spi_bitbang *bitbang;
- bitbang = spi_master_get_devdata(spi);
+ bitbang = spi_controller_get_devdata(spi);
mutex_lock(&bitbang->lock);
bitbang->busy = 0;
@@ -323,7 +329,7 @@ static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
static void spi_bitbang_set_cs(struct spi_device *spi, bool enable)
{
- struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master);
+ struct spi_bitbang *bitbang = spi_controller_get_devdata(spi->controller);
/* SPI core provides CS high / low, but bitbang driver
* expects CS active
@@ -341,50 +347,50 @@ static void spi_bitbang_set_cs(struct spi_device *spi, bool enable)
int spi_bitbang_init(struct spi_bitbang *bitbang)
{
- struct spi_master *master = bitbang->master;
+ struct spi_controller *ctlr = bitbang->ctlr;
bool custom_cs;
- if (!master)
+ if (!ctlr)
return -EINVAL;
/*
* We only need the chipselect callback if we are actually using it.
* If we just use GPIO descriptors, it is surplus. If the
- * SPI_MASTER_GPIO_SS flag is set, we always need to call the
+ * SPI_CONTROLLER_GPIO_SS flag is set, we always need to call the
* driver-specific chipselect routine.
*/
- custom_cs = (!master->use_gpio_descriptors ||
- (master->flags & SPI_MASTER_GPIO_SS));
+ custom_cs = (!ctlr->use_gpio_descriptors ||
+ (ctlr->flags & SPI_CONTROLLER_GPIO_SS));
if (custom_cs && !bitbang->chipselect)
return -EINVAL;
mutex_init(&bitbang->lock);
- if (!master->mode_bits)
- master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
+ if (!ctlr->mode_bits)
+ ctlr->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
- if (master->transfer || master->transfer_one_message)
+ if (ctlr->transfer || ctlr->transfer_one_message)
return -EINVAL;
- master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
- master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
- master->transfer_one = spi_bitbang_transfer_one;
+ ctlr->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
+ ctlr->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
+ ctlr->transfer_one = spi_bitbang_transfer_one;
/*
* When using GPIO descriptors, the ->set_cs() callback doesn't even
- * get called unless SPI_MASTER_GPIO_SS is set.
+ * get called unless SPI_CONTROLLER_GPIO_SS is set.
*/
if (custom_cs)
- master->set_cs = spi_bitbang_set_cs;
+ ctlr->set_cs = spi_bitbang_set_cs;
if (!bitbang->txrx_bufs) {
bitbang->use_dma = 0;
bitbang->txrx_bufs = spi_bitbang_bufs;
- if (!master->setup) {
+ if (!ctlr->setup) {
if (!bitbang->setup_transfer)
bitbang->setup_transfer =
spi_bitbang_setup_transfer;
- master->setup = spi_bitbang_setup;
- master->cleanup = spi_bitbang_cleanup;
+ ctlr->setup = spi_bitbang_setup;
+ ctlr->cleanup = spi_bitbang_cleanup;
}
}
@@ -393,12 +399,12 @@ int spi_bitbang_init(struct spi_bitbang *bitbang)
EXPORT_SYMBOL_GPL(spi_bitbang_init);
/**
- * spi_bitbang_start - start up a polled/bitbanging SPI master driver
+ * spi_bitbang_start - start up a polled/bitbanging SPI host controller driver
* @bitbang: driver handle
*
* Caller should have zero-initialized all parts of the structure, and then
- * provided callbacks for chip selection and I/O loops. If the master has
- * a transfer method, its final step should call spi_bitbang_transfer; or,
+ * provided callbacks for chip selection and I/O loops. If the host controller has
+ * a transfer method, its final step should call spi_bitbang_transfer(); or,
* that's the default if the transfer routine is not initialized. It should
* also set up the bus number and number of chipselects.
*
@@ -406,23 +412,23 @@ EXPORT_SYMBOL_GPL(spi_bitbang_init);
* hardware that basically exposes a shift register) or per-spi_transfer
* (which takes better advantage of hardware like fifos or DMA engines).
*
- * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup,
- * spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi
- * master methods. Those methods are the defaults if the bitbang->txrx_bufs
+ * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup(),
+ * spi_bitbang_cleanup() and spi_bitbang_setup_transfer() to handle those SPI
+ * host controller methods. Those methods are the defaults if the bitbang->txrx_bufs
* routine isn't initialized.
*
- * This routine registers the spi_master, which will process requests in a
+ * This routine registers the spi_controller, which will process requests in a
* dedicated task, keeping IRQs unblocked most of the time. To stop
* processing those requests, call spi_bitbang_stop().
*
- * On success, this routine will take a reference to master. The caller is
- * responsible for calling spi_bitbang_stop() to decrement the reference and
- * spi_master_put() as counterpart of spi_alloc_master() to prevent a memory
+ * On success, this routine will take a reference to the controller. The caller
+ * is responsible for calling spi_bitbang_stop() to decrement the reference and
+ * spi_controller_put() as counterpart of spi_alloc_host() to prevent a memory
* leak.
*/
int spi_bitbang_start(struct spi_bitbang *bitbang)
{
- struct spi_master *master = bitbang->master;
+ struct spi_controller *ctlr = bitbang->ctlr;
int ret;
ret = spi_bitbang_init(bitbang);
@@ -432,9 +438,9 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
/* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices
*/
- ret = spi_register_master(spi_master_get(master));
+ ret = spi_register_controller(spi_controller_get(ctlr));
if (ret)
- spi_master_put(master);
+ spi_controller_put(ctlr);
return ret;
}
@@ -445,9 +451,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_start);
*/
void spi_bitbang_stop(struct spi_bitbang *bitbang)
{
- spi_unregister_master(bitbang->master);
+ spi_unregister_controller(bitbang->ctlr);
}
EXPORT_SYMBOL_GPL(spi_bitbang_stop);
MODULE_LICENSE("GPL");
-
+MODULE_DESCRIPTION("Utilities for Bitbanging SPI host controllers");
diff --git a/drivers/spi/spi-brcmstb-qspi.c b/drivers/spi/spi-brcmstb-qspi.c
index e1b137419f5c..7a33b479c1f7 100644
--- a/drivers/spi/spi-brcmstb-qspi.c
+++ b/drivers/spi/spi-brcmstb-qspi.c
@@ -28,7 +28,7 @@ static void brcmstb_qspi_remove(struct platform_device *pdev)
static struct platform_driver brcmstb_qspi_driver = {
.probe = brcmstb_qspi_probe,
- .remove_new = brcmstb_qspi_remove,
+ .remove = brcmstb_qspi_remove,
.driver = {
.name = "brcmstb_qspi",
.pm = &bcm_qspi_pm_ops,
diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c
index cceae816cebc..84eb454ed443 100644
--- a/drivers/spi/spi-butterfly.c
+++ b/drivers/spi/spi-butterfly.c
@@ -178,7 +178,7 @@ static void butterfly_attach(struct parport *p)
struct pardevice *pd;
int status;
struct butterfly *pp;
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev = p->physport->dev;
struct pardev_cb butterfly_cb;
@@ -189,12 +189,12 @@ static void butterfly_attach(struct parport *p)
* and no way to be selective about what it binds to.
*/
- master = spi_alloc_master(dev, sizeof(*pp));
- if (!master) {
+ host = spi_alloc_host(dev, sizeof(*pp));
+ if (!host) {
status = -ENOMEM;
goto done;
}
- pp = spi_master_get_devdata(master);
+ pp = spi_controller_get_devdata(host);
/*
* SPI and bitbang hookup
@@ -202,10 +202,10 @@ static void butterfly_attach(struct parport *p)
* use default setup(), cleanup(), and transfer() methods; and
* only bother implementing mode 0. Start it later.
*/
- master->bus_num = 42;
- master->num_chipselect = 2;
+ host->bus_num = 42;
+ host->num_chipselect = 2;
- pp->bitbang.master = master;
+ pp->bitbang.ctlr = host;
pp->bitbang.chipselect = butterfly_chipselect;
pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
@@ -263,7 +263,7 @@ static void butterfly_attach(struct parport *p)
pp->info[0].platform_data = &flash;
pp->info[0].chip_select = 1;
pp->info[0].controller_data = pp;
- pp->dataflash = spi_new_device(pp->bitbang.master, &pp->info[0]);
+ pp->dataflash = spi_new_device(pp->bitbang.ctlr, &pp->info[0]);
if (pp->dataflash)
pr_debug("%s: dataflash at %s\n", p->name,
dev_name(&pp->dataflash->dev));
@@ -280,7 +280,7 @@ clean2:
clean1:
parport_unregister_device(pd);
clean0:
- spi_master_put(pp->bitbang.master);
+ spi_controller_put(host);
done:
pr_debug("%s: butterfly probe, fail %d\n", p->name, status);
}
@@ -308,14 +308,13 @@ static void butterfly_detach(struct parport *p)
parport_release(pp->pd);
parport_unregister_device(pp->pd);
- spi_master_put(pp->bitbang.master);
+ spi_controller_put(pp->bitbang.ctlr);
}
static struct parport_driver butterfly_driver = {
.name = "spi_butterfly",
.match_port = butterfly_attach,
.detach = butterfly_detach,
- .devmodel = true,
};
module_parport_driver(butterfly_driver);
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index abf10f92415d..af6d050da1c8 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -32,7 +31,9 @@
#include <linux/timer.h>
#define CQSPI_NAME "cadence-qspi"
-#define CQSPI_MAX_CHIPSELECT 16
+#define CQSPI_MAX_CHIPSELECT 4
+
+static_assert(CQSPI_MAX_CHIPSELECT <= SPI_DEVICE_CS_CNT_MAX);
/* Quirks */
#define CQSPI_NEEDS_WR_DELAY BIT(0)
@@ -41,12 +42,24 @@
#define CQSPI_NO_SUPPORT_WR_COMPLETION BIT(3)
#define CQSPI_SLOW_SRAM BIT(4)
#define CQSPI_NEEDS_APB_AHB_HAZARD_WAR BIT(5)
+#define CQSPI_RD_NO_IRQ BIT(6)
+#define CQSPI_DMA_SET_MASK BIT(7)
+#define CQSPI_SUPPORT_DEVICE_RESET BIT(8)
+#define CQSPI_DISABLE_STIG_MODE BIT(9)
+#define CQSPI_DISABLE_RUNTIME_PM BIT(10)
/* Capabilities */
#define CQSPI_SUPPORTS_OCTAL BIT(0)
+#define CQSPI_SUPPORTS_QUAD BIT(1)
#define CQSPI_OP_WIDTH(part) ((part).nbytes ? ilog2((part).buswidth) : 0)
+enum {
+ CLK_QSPI_APB = 0,
+ CLK_QSPI_AHB,
+ CLK_QSPI_NUM,
+};
+
struct cqspi_st;
struct cqspi_flash_pdata {
@@ -62,8 +75,9 @@ struct cqspi_flash_pdata {
struct cqspi_st {
struct platform_device *pdev;
- struct spi_master *master;
+ struct spi_controller *host;
struct clk *clk;
+ struct clk *clks[CLK_QSPI_NUM];
unsigned int sclk;
void __iomem *iobase;
@@ -92,19 +106,32 @@ struct cqspi_st {
bool wr_completion;
bool slow_sram;
bool apb_ahb_hazard;
+
+ bool is_jh7110; /* Flag for StarFive JH7110 SoC */
+ bool disable_stig_mode;
+ refcount_t refcount;
+ refcount_t inflight_ops;
+
+ const struct cqspi_driver_platdata *ddata;
};
struct cqspi_driver_platdata {
u32 hwcaps_mask;
- u8 quirks;
+ u16 quirks;
int (*indirect_read_dma)(struct cqspi_flash_pdata *f_pdata,
u_char *rxbuf, loff_t from_addr, size_t n_rx);
u32 (*get_dma_status)(struct cqspi_st *cqspi);
+ int (*jh7110_clk_init)(struct platform_device *pdev,
+ struct cqspi_st *cqspi);
};
/* Operation timeout value */
#define CQSPI_TIMEOUT_MS 500
#define CQSPI_READ_TIMEOUT_MS 10
+#define CQSPI_BUSYWAIT_TIMEOUT_US 500
+
+/* Runtime_pm autosuspend delay */
+#define CQSPI_AUTOSUSPEND_TIMEOUT 2000
#define CQSPI_DUMMY_CLKS_PER_BYTE 8
#define CQSPI_DUMMY_BYTES_MAX 4
@@ -125,6 +152,8 @@ struct cqspi_driver_platdata {
#define CQSPI_REG_CONFIG_IDLE_LSB 31
#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
+#define CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK BIT(5)
+#define CQSPI_REG_CONFIG_RESET_CFG_FLD_MASK BIT(6)
#define CQSPI_REG_RD_INSTR 0x04
#define CQSPI_REG_RD_INSTR_OPCODE_LSB 0
@@ -280,20 +309,34 @@ struct cqspi_driver_platdata {
#define CQSPI_REG_VERSAL_DMA_VAL 0x602
-static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr)
+static int cqspi_wait_for_bit(const struct cqspi_driver_platdata *ddata,
+ void __iomem *reg, const u32 mask, bool clr,
+ bool busywait)
{
+ u64 timeout_us = CQSPI_TIMEOUT_MS * USEC_PER_MSEC;
u32 val;
+ if (busywait) {
+ int ret = readl_relaxed_poll_timeout(reg, val,
+ (((clr ? ~val : val) & mask) == mask),
+ 0, CQSPI_BUSYWAIT_TIMEOUT_US);
+
+ if (ret != -ETIMEDOUT)
+ return ret;
+
+ timeout_us -= CQSPI_BUSYWAIT_TIMEOUT_US;
+ }
+
return readl_relaxed_poll_timeout(reg, val,
(((clr ? ~val : val) & mask) == mask),
- 10, CQSPI_TIMEOUT_MS * 1000);
+ 10, timeout_us);
}
static bool cqspi_is_idle(struct cqspi_st *cqspi)
{
u32 reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
- return reg & (1UL << CQSPI_REG_CONFIG_IDLE_LSB);
+ return reg & BIT(CQSPI_REG_CONFIG_IDLE_LSB);
}
static u32 cqspi_get_rd_sram_level(struct cqspi_st *cqspi)
@@ -319,11 +362,8 @@ static u32 cqspi_get_versal_dma_status(struct cqspi_st *cqspi)
static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
{
struct cqspi_st *cqspi = dev;
+ const struct cqspi_driver_platdata *ddata = cqspi->ddata;
unsigned int irq_status;
- struct device *device = &cqspi->pdev->dev;
- const struct cqspi_driver_platdata *ddata;
-
- ddata = of_device_get_match_data(device);
/* Read interrupt status */
irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS);
@@ -419,8 +459,8 @@ static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
writel(reg, reg_base + CQSPI_REG_CMDCTRL);
/* Polling for completion. */
- ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL,
- CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1);
+ ret = cqspi_wait_for_bit(cqspi->ddata, reg_base + CQSPI_REG_CMDCTRL,
+ CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1, true);
if (ret) {
dev_err(&cqspi->pdev->dev,
"Flash command execution timed out.\n");
@@ -477,8 +517,11 @@ static int cqspi_enable_dtr(struct cqspi_flash_pdata *f_pdata,
if (ret)
return ret;
} else {
- reg &= ~CQSPI_REG_CONFIG_DTR_PROTO;
- reg &= ~CQSPI_REG_CONFIG_DUAL_OPCODE;
+ unsigned int mask = CQSPI_REG_CONFIG_DTR_PROTO | CQSPI_REG_CONFIG_DUAL_OPCODE;
+ /* Shortcut if DTR is already disabled. */
+ if ((reg & mask) == 0)
+ return 0;
+ reg &= ~mask;
}
writel(reg, reg_base + CQSPI_REG_CONFIG);
@@ -529,7 +572,7 @@ static int cqspi_command_read(struct cqspi_flash_pdata *f_pdata,
reg |= (dummy_clk & CQSPI_REG_CMDCTRL_DUMMY_MASK)
<< CQSPI_REG_CMDCTRL_DUMMY_LSB;
- reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
+ reg |= BIT(CQSPI_REG_CMDCTRL_RD_EN_LSB);
/* 0 means 1 byte. */
reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
@@ -537,7 +580,7 @@ static int cqspi_command_read(struct cqspi_flash_pdata *f_pdata,
/* setup ADDR BIT field */
if (op->addr.nbytes) {
- reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
+ reg |= BIT(CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
reg |= ((op->addr.nbytes - 1) &
CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
<< CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
@@ -604,7 +647,7 @@ static int cqspi_command_write(struct cqspi_flash_pdata *f_pdata,
reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
if (op->addr.nbytes) {
- reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
+ reg |= BIT(CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
reg |= ((op->addr.nbytes - 1) &
CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
<< CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
@@ -613,7 +656,7 @@ static int cqspi_command_write(struct cqspi_flash_pdata *f_pdata,
}
if (n_tx) {
- reg |= (0x1 << CQSPI_REG_CMDCTRL_WR_EN_LSB);
+ reg |= BIT(CQSPI_REG_CMDCTRL_WR_EN_LSB);
reg |= ((n_tx - 1) & CQSPI_REG_CMDCTRL_WR_BYTES_MASK)
<< CQSPI_REG_CMDCTRL_WR_BYTES_LSB;
data = 0;
@@ -677,6 +720,7 @@ static int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata,
reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
reg |= (op->addr.nbytes - 1);
writel(reg, reg_base + CQSPI_REG_SIZE);
+ readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */
return 0;
}
@@ -685,6 +729,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
const size_t n_rx)
{
struct cqspi_st *cqspi = f_pdata->cqspi;
+ bool use_irq = !(cqspi->ddata && cqspi->ddata->quirks & CQSPI_RD_NO_IRQ);
struct device *dev = &cqspi->pdev->dev;
void __iomem *reg_base = cqspi->iobase;
void __iomem *ahb_base = cqspi->ahb_base;
@@ -694,6 +739,9 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
u8 *rxbuf_end = rxbuf + n_rx;
int ret = 0;
+ if (!refcount_read(&cqspi->refcount))
+ return -ENODEV;
+
writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
@@ -708,17 +756,21 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
* all the read interrupts disabled for max performance.
*/
- if (!cqspi->slow_sram)
+ if (use_irq && cqspi->slow_sram)
+ writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);
+ else if (use_irq)
writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);
else
- writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);
+ writel(0, reg_base + CQSPI_REG_IRQMASK);
reinit_completion(&cqspi->transfer_complete);
writel(CQSPI_REG_INDIRECTRD_START_MASK,
reg_base + CQSPI_REG_INDIRECTRD);
+ readl(reg_base + CQSPI_REG_INDIRECTRD); /* Flush posted write. */
while (remaining > 0) {
- if (!wait_for_completion_timeout(&cqspi->transfer_complete,
+ if (use_irq &&
+ !wait_for_completion_timeout(&cqspi->transfer_complete,
msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS)))
ret = -ETIMEDOUT;
@@ -760,7 +812,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
bytes_to_read = cqspi_get_rd_sram_level(cqspi);
}
- if (remaining > 0) {
+ if (use_irq && remaining > 0) {
reinit_completion(&cqspi->transfer_complete);
if (cqspi->slow_sram)
writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);
@@ -768,8 +820,8 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
}
/* Check indirect done status */
- ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD,
- CQSPI_REG_INDIRECTRD_DONE_MASK, 0);
+ ret = cqspi_wait_for_bit(cqspi->ddata, reg_base + CQSPI_REG_INDIRECTRD,
+ CQSPI_REG_INDIRECTRD_DONE_MASK, 0, true);
if (ret) {
dev_err(dev, "Indirect read completion error (%i)\n", ret);
goto failrd;
@@ -793,6 +845,25 @@ failrd:
return ret;
}
+static void cqspi_device_reset(struct cqspi_st *cqspi)
+{
+ u32 reg;
+
+ reg = readl(cqspi->iobase + CQSPI_REG_CONFIG);
+ reg |= CQSPI_REG_CONFIG_RESET_CFG_FLD_MASK;
+ writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
+ /*
+ * NOTE: Delay timing implementation is derived from
+ * spi_nor_hw_reset()
+ */
+ writel(reg & ~CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK, cqspi->iobase + CQSPI_REG_CONFIG);
+ usleep_range(1, 5);
+ writel(reg | CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK, cqspi->iobase + CQSPI_REG_CONFIG);
+ usleep_range(100, 150);
+ writel(reg & ~CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK, cqspi->iobase + CQSPI_REG_CONFIG);
+ usleep_range(1000, 1200);
+}
+
static void cqspi_controller_enable(struct cqspi_st *cqspi, bool enable)
{
void __iomem *reg_base = cqspi->iobase;
@@ -994,6 +1065,7 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata,
reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
reg |= (op->addr.nbytes - 1);
writel(reg, reg_base + CQSPI_REG_SIZE);
+ readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */
return 0;
}
@@ -1008,6 +1080,9 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata,
unsigned int write_bytes;
int ret;
+ if (!refcount_read(&cqspi->refcount))
+ return -ENODEV;
+
writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);
writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);
@@ -1019,6 +1094,8 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata,
reinit_completion(&cqspi->transfer_complete);
writel(CQSPI_REG_INDIRECTWR_START_MASK,
reg_base + CQSPI_REG_INDIRECTWR);
+ readl(reg_base + CQSPI_REG_INDIRECTWR); /* Flush posted write. */
+
/*
* As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access
* Controller programming sequence, couple of cycles of
@@ -1069,8 +1146,8 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata,
}
/* Check indirect done status */
- ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR,
- CQSPI_REG_INDIRECTWR_DONE_MASK, 0);
+ ret = cqspi_wait_for_bit(cqspi->ddata, reg_base + CQSPI_REG_INDIRECTWR,
+ CQSPI_REG_INDIRECTWR_DONE_MASK, 0, false);
if (ret) {
dev_err(dev, "Indirect write completion error (%i)\n", ret);
goto failwr;
@@ -1115,7 +1192,7 @@ static void cqspi_chipselect(struct cqspi_flash_pdata *f_pdata)
* CS2 to 4b'1011
* CS3 to 4b'0111
*/
- chip_select = 0xF & ~(1 << chip_select);
+ chip_select = 0xF & ~BIT(chip_select);
}
reg &= ~(CQSPI_REG_CONFIG_CHIPSELECT_MASK
@@ -1201,9 +1278,9 @@ static void cqspi_readdata_capture(struct cqspi_st *cqspi,
reg = readl(reg_base + CQSPI_REG_READCAPTURE);
if (bypass)
- reg |= (1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
+ reg |= BIT(CQSPI_REG_READCAPTURE_BYPASS_LSB);
else
- reg &= ~(1 << CQSPI_REG_READCAPTURE_BYPASS_LSB);
+ reg &= ~BIT(CQSPI_REG_READCAPTURE_BYPASS_LSB);
reg &= ~(CQSPI_REG_READCAPTURE_DELAY_MASK
<< CQSPI_REG_READCAPTURE_DELAY_LSB);
@@ -1343,16 +1420,13 @@ static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata,
const struct spi_mem_op *op)
{
struct cqspi_st *cqspi = f_pdata->cqspi;
- struct device *dev = &cqspi->pdev->dev;
- const struct cqspi_driver_platdata *ddata;
+ const struct cqspi_driver_platdata *ddata = cqspi->ddata;
loff_t from = op->addr.val;
size_t len = op->data.nbytes;
u_char *buf = op->data.buf.in;
u64 dma_align = (u64)(uintptr_t)buf;
int ret;
- ddata = of_device_get_match_data(dev);
-
ret = cqspi_read_setup(f_pdata, op);
if (ret)
return ret;
@@ -1369,11 +1443,11 @@ static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata,
static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master);
+ struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller);
struct cqspi_flash_pdata *f_pdata;
f_pdata = &cqspi->f_pdata[spi_get_chipselect(mem->spi, 0)];
- cqspi_configure(f_pdata, mem->spi->max_speed_hz);
+ cqspi_configure(f_pdata, op->max_freq);
if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
/*
@@ -1382,7 +1456,8 @@ static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
* reads, prefer STIG mode for such small reads.
*/
if (!op->addr.nbytes ||
- op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX)
+ (op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX &&
+ !cqspi->disable_stig_mode))
return cqspi_command_read(f_pdata, op);
return cqspi_read(f_pdata, op);
@@ -1397,11 +1472,43 @@ static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
int ret;
+ struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller);
+ struct device *dev = &cqspi->pdev->dev;
+ const struct cqspi_driver_platdata *ddata = of_device_get_match_data(dev);
+
+ if (refcount_read(&cqspi->inflight_ops) == 0)
+ return -ENODEV;
+
+ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret) {
+ dev_err(&mem->spi->dev, "resume failed with %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!refcount_read(&cqspi->refcount))
+ return -EBUSY;
+
+ refcount_inc(&cqspi->inflight_ops);
+
+ if (!refcount_read(&cqspi->refcount)) {
+ if (refcount_read(&cqspi->inflight_ops))
+ refcount_dec(&cqspi->inflight_ops);
+ return -EBUSY;
+ }
ret = cqspi_mem_process(mem, op);
+
+ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
+ pm_runtime_put_autosuspend(dev);
+
if (ret)
dev_err(&mem->spi->dev, "operation failed with %d\n", ret);
+ if (refcount_read(&cqspi->inflight_ops) > 1)
+ refcount_dec(&cqspi->inflight_ops);
+
return ret;
}
@@ -1484,8 +1591,8 @@ static int cqspi_of_get_pdata(struct cqspi_st *cqspi)
cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs");
if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) {
- dev_err(dev, "couldn't determine fifo-depth\n");
- return -ENXIO;
+ /* Zero signals FIFO depth should be runtime detected. */
+ cqspi->fifo_depth = 0;
}
if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) {
@@ -1515,8 +1622,6 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
{
u32 reg;
- cqspi_controller_enable(cqspi, 0);
-
/* Configure the remap address register, no remap */
writel(0, cqspi->iobase + CQSPI_REG_REMAP);
@@ -1550,8 +1655,29 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
reg |= CQSPI_REG_CONFIG_DMA_MASK;
writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
}
+}
- cqspi_controller_enable(cqspi, 1);
+static void cqspi_controller_detect_fifo_depth(struct cqspi_st *cqspi)
+{
+ struct device *dev = &cqspi->pdev->dev;
+ u32 reg, fifo_depth;
+
+ /*
+ * Bits N-1:0 are writable while bits 31:N are read as zero, with 2^N
+ * the FIFO depth.
+ */
+ writel(U32_MAX, cqspi->iobase + CQSPI_REG_SRAMPARTITION);
+ reg = readl(cqspi->iobase + CQSPI_REG_SRAMPARTITION);
+ fifo_depth = reg + 1;
+
+ /* FIFO depth of zero means no value from devicetree was provided. */
+ if (cqspi->fifo_depth == 0) {
+ cqspi->fifo_depth = fifo_depth;
+ dev_dbg(dev, "using FIFO depth of %u\n", fifo_depth);
+ } else if (fifo_depth != cqspi->fifo_depth) {
+ dev_warn(dev, "detected FIFO depth (%u) different from config (%u)\n",
+ fifo_depth, cqspi->fifo_depth);
+ }
}
static int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
@@ -1566,6 +1692,12 @@ static int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
int ret = PTR_ERR(cqspi->rx_chan);
cqspi->rx_chan = NULL;
+ if (ret == -ENODEV) {
+ /* DMA support is not mandatory */
+ dev_info(&cqspi->pdev->dev, "No Rx DMA available\n");
+ return 0;
+ }
+
return dev_err_probe(&cqspi->pdev->dev, ret, "No Rx DMA available\n");
}
init_completion(&cqspi->rx_dma_complete);
@@ -1575,7 +1707,7 @@ static int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
static const char *cqspi_get_name(struct spi_mem *mem)
{
- struct cqspi_st *cqspi = spi_master_get_devdata(mem->spi->master);
+ struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller);
struct device *dev = &cqspi->pdev->dev;
return devm_kasprintf(dev, GFP_KERNEL, "%s.%d", dev_name(dev),
@@ -1590,71 +1722,120 @@ static const struct spi_controller_mem_ops cqspi_mem_ops = {
static const struct spi_controller_mem_caps cqspi_mem_caps = {
.dtr = true,
+ .per_op_freq = true,
};
static int cqspi_setup_flash(struct cqspi_st *cqspi)
{
struct platform_device *pdev = cqspi->pdev;
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
struct cqspi_flash_pdata *f_pdata;
- unsigned int cs;
- int ret;
+ int ret, cs, max_cs = -1;
/* Get flash device data */
- for_each_available_child_of_node(dev->of_node, np) {
+ for_each_available_child_of_node_scoped(dev->of_node, np) {
ret = of_property_read_u32(np, "reg", &cs);
if (ret) {
dev_err(dev, "Couldn't determine chip select.\n");
- of_node_put(np);
return ret;
}
- if (cs >= CQSPI_MAX_CHIPSELECT) {
+ if (cs >= cqspi->num_chipselect) {
dev_err(dev, "Chip select %d out of range.\n", cs);
- of_node_put(np);
return -EINVAL;
}
+ max_cs = max_t(int, cs, max_cs);
+
f_pdata = &cqspi->f_pdata[cs];
f_pdata->cqspi = cqspi;
f_pdata->cs = cs;
ret = cqspi_of_get_flash_pdata(pdev, f_pdata, np);
- if (ret) {
- of_node_put(np);
+ if (ret)
return ret;
- }
}
+ if (max_cs < 0) {
+ dev_err(dev, "No flash device declared\n");
+ return -ENODEV;
+ }
+
+ cqspi->num_chipselect = max_cs + 1;
return 0;
}
+static int cqspi_jh7110_clk_init(struct platform_device *pdev, struct cqspi_st *cqspi)
+{
+ static struct clk_bulk_data qspiclk[] = {
+ { .id = "apb" },
+ { .id = "ahb" },
+ };
+
+ int ret = 0;
+
+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(qspiclk), qspiclk);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to get qspi clocks\n", __func__);
+ return ret;
+ }
+
+ cqspi->clks[CLK_QSPI_APB] = qspiclk[0].clk;
+ cqspi->clks[CLK_QSPI_AHB] = qspiclk[1].clk;
+
+ ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_APB]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_APB\n", __func__);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(cqspi->clks[CLK_QSPI_AHB]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_QSPI_AHB\n", __func__);
+ goto disable_apb_clk;
+ }
+
+ cqspi->is_jh7110 = true;
+
+ return 0;
+
+disable_apb_clk:
+ clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]);
+
+ return ret;
+}
+
+static void cqspi_jh7110_disable_clk(struct platform_device *pdev, struct cqspi_st *cqspi)
+{
+ clk_disable_unprepare(cqspi->clks[CLK_QSPI_AHB]);
+ clk_disable_unprepare(cqspi->clks[CLK_QSPI_APB]);
+}
static int cqspi_probe(struct platform_device *pdev)
{
const struct cqspi_driver_platdata *ddata;
struct reset_control *rstc, *rstc_ocp, *rstc_ref;
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *res_ahb;
struct cqspi_st *cqspi;
int ret;
int irq;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*cqspi));
- if (!master) {
- dev_err(&pdev->dev, "spi_alloc_master failed\n");
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*cqspi));
+ if (!host)
return -ENOMEM;
- }
- master->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL;
- master->mem_ops = &cqspi_mem_ops;
- master->mem_caps = &cqspi_mem_caps;
- master->dev.of_node = pdev->dev.of_node;
- cqspi = spi_master_get_devdata(master);
+ host->mode_bits = SPI_RX_QUAD | SPI_RX_DUAL;
+ host->mem_ops = &cqspi_mem_ops;
+ host->mem_caps = &cqspi_mem_caps;
+ host->dev.of_node = pdev->dev.of_node;
+
+ cqspi = spi_controller_get_devdata(host);
cqspi->pdev = pdev;
- cqspi->master = master;
+ cqspi->host = host;
+ cqspi->is_jh7110 = false;
+ cqspi->ddata = ddata = of_device_get_match_data(dev);
platform_set_drvdata(pdev, cqspi);
/* Obtain configuration from OF. */
@@ -1697,10 +1878,10 @@ static int cqspi_probe(struct platform_device *pdev)
if (irq < 0)
return -ENXIO;
- pm_runtime_enable(dev);
- ret = pm_runtime_resume_and_get(dev);
- if (ret < 0)
- goto probe_pm_failed;
+ ret = pm_runtime_set_active(dev);
+ if (ret)
+ return ret;
+
ret = clk_prepare_enable(cqspi->clk);
if (ret) {
@@ -1741,18 +1922,19 @@ static int cqspi_probe(struct platform_device *pdev)
reset_control_deassert(rstc_ocp);
cqspi->master_ref_clk_hz = clk_get_rate(cqspi->clk);
- master->max_speed_hz = cqspi->master_ref_clk_hz;
+ host->max_speed_hz = cqspi->master_ref_clk_hz;
/* write completion is supported by default */
cqspi->wr_completion = true;
- ddata = of_device_get_match_data(dev);
if (ddata) {
if (ddata->quirks & CQSPI_NEEDS_WR_DELAY)
cqspi->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC,
cqspi->master_ref_clk_hz);
if (ddata->hwcaps_mask & CQSPI_SUPPORTS_OCTAL)
- master->mode_bits |= SPI_RX_OCTAL | SPI_TX_OCTAL;
+ host->mode_bits |= SPI_RX_OCTAL | SPI_TX_OCTAL;
+ if (ddata->hwcaps_mask & CQSPI_SUPPORTS_QUAD)
+ host->mode_bits |= SPI_TX_QUAD;
if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE)) {
cqspi->use_direct_mode = true;
cqspi->use_direct_mode_wr = true;
@@ -1766,14 +1948,24 @@ static int cqspi_probe(struct platform_device *pdev)
if (ddata->quirks & CQSPI_NEEDS_APB_AHB_HAZARD_WAR)
cqspi->apb_ahb_hazard = true;
- if (of_device_is_compatible(pdev->dev.of_node,
- "xlnx,versal-ospi-1.0")) {
+ if (ddata->jh7110_clk_init) {
+ ret = cqspi_jh7110_clk_init(pdev, cqspi);
+ if (ret)
+ goto probe_reset_failed;
+ }
+ if (ddata->quirks & CQSPI_DISABLE_STIG_MODE)
+ cqspi->disable_stig_mode = true;
+
+ if (ddata->quirks & CQSPI_DMA_SET_MASK) {
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
if (ret)
goto probe_reset_failed;
}
}
+ refcount_set(&cqspi->refcount, 1);
+ refcount_set(&cqspi->inflight_ops, 1);
+
ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
pdev->name, cqspi);
if (ret) {
@@ -1782,11 +1974,19 @@ static int cqspi_probe(struct platform_device *pdev)
}
cqspi_wait_idle(cqspi);
+ cqspi_controller_enable(cqspi, 0);
+ cqspi_controller_detect_fifo_depth(cqspi);
cqspi_controller_init(cqspi);
+ cqspi_controller_enable(cqspi, 1);
cqspi->current_cs = -1;
cqspi->sclk = 0;
- master->num_chipselect = cqspi->num_chipselect;
+ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_get_noresume(dev);
+ }
ret = cqspi_setup_flash(cqspi);
if (ret) {
@@ -1794,76 +1994,127 @@ static int cqspi_probe(struct platform_device *pdev)
goto probe_setup_failed;
}
+ host->num_chipselect = cqspi->num_chipselect;
+
+ if (ddata && (ddata->quirks & CQSPI_SUPPORT_DEVICE_RESET))
+ cqspi_device_reset(cqspi);
+
if (cqspi->use_direct_mode) {
ret = cqspi_request_mmap_dma(cqspi);
if (ret == -EPROBE_DEFER)
goto probe_setup_failed;
}
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret) {
dev_err(&pdev->dev, "failed to register SPI ctlr %d\n", ret);
goto probe_setup_failed;
}
+ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ }
+
return 0;
probe_setup_failed:
+ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
+ pm_runtime_disable(dev);
cqspi_controller_enable(cqspi, 0);
probe_reset_failed:
+ if (cqspi->is_jh7110)
+ cqspi_jh7110_disable_clk(pdev, cqspi);
clk_disable_unprepare(cqspi->clk);
probe_clk_failed:
- pm_runtime_put_sync(dev);
-probe_pm_failed:
- pm_runtime_disable(dev);
return ret;
}
static void cqspi_remove(struct platform_device *pdev)
{
+ const struct cqspi_driver_platdata *ddata;
struct cqspi_st *cqspi = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ ddata = of_device_get_match_data(dev);
+
+ refcount_set(&cqspi->refcount, 0);
+
+ if (!refcount_dec_and_test(&cqspi->inflight_ops))
+ cqspi_wait_idle(cqspi);
- spi_unregister_master(cqspi->master);
+ spi_unregister_controller(cqspi->host);
cqspi_controller_enable(cqspi, 0);
if (cqspi->rx_chan)
dma_release_channel(cqspi->rx_chan);
- clk_disable_unprepare(cqspi->clk);
+ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
+ if (pm_runtime_get_sync(&pdev->dev) >= 0)
+ clk_disable(cqspi->clk);
+
+ if (cqspi->is_jh7110)
+ cqspi_jh7110_disable_clk(pdev, cqspi);
- pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
+ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ }
}
-static int cqspi_suspend(struct device *dev)
+static int cqspi_runtime_suspend(struct device *dev)
{
struct cqspi_st *cqspi = dev_get_drvdata(dev);
- struct spi_master *master = dev_get_drvdata(dev);
- int ret;
- ret = spi_master_suspend(master);
cqspi_controller_enable(cqspi, 0);
-
clk_disable_unprepare(cqspi->clk);
-
- return ret;
+ return 0;
}
-static int cqspi_resume(struct device *dev)
+static int cqspi_runtime_resume(struct device *dev)
{
struct cqspi_st *cqspi = dev_get_drvdata(dev);
- struct spi_master *master = dev_get_drvdata(dev);
clk_prepare_enable(cqspi->clk);
cqspi_wait_idle(cqspi);
+ cqspi_controller_enable(cqspi, 0);
cqspi_controller_init(cqspi);
+ cqspi_controller_enable(cqspi, 1);
cqspi->current_cs = -1;
cqspi->sclk = 0;
+ return 0;
+}
+
+static int cqspi_suspend(struct device *dev)
+{
+ struct cqspi_st *cqspi = dev_get_drvdata(dev);
+ int ret;
+
+ ret = spi_controller_suspend(cqspi->host);
+ if (ret)
+ return ret;
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int cqspi_resume(struct device *dev)
+{
+ struct cqspi_st *cqspi = dev_get_drvdata(dev);
+ int ret;
- return spi_master_resume(master);
+ ret = pm_runtime_force_resume(dev);
+ if (ret) {
+ dev_err(dev, "pm_runtime_force_resume failed on resume\n");
+ return ret;
+ }
+
+ return spi_controller_resume(cqspi->host);
}
-static DEFINE_SIMPLE_DEV_PM_OPS(cqspi_dev_pm_ops, cqspi_suspend, cqspi_resume);
+static const struct dev_pm_ops cqspi_dev_pm_ops = {
+ RUNTIME_PM_OPS(cqspi_runtime_suspend, cqspi_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(cqspi_suspend, cqspi_resume)
+};
static const struct cqspi_driver_platdata cdns_qspi = {
.quirks = CQSPI_DISABLE_DAC_MODE,
@@ -1874,7 +2125,7 @@ static const struct cqspi_driver_platdata k2g_qspi = {
};
static const struct cqspi_driver_platdata am654_ospi = {
- .hwcaps_mask = CQSPI_SUPPORTS_OCTAL,
+ .hwcaps_mask = CQSPI_SUPPORTS_OCTAL | CQSPI_SUPPORTS_QUAD,
.quirks = CQSPI_NEEDS_WR_DELAY,
};
@@ -1885,24 +2136,43 @@ static const struct cqspi_driver_platdata intel_lgm_qspi = {
static const struct cqspi_driver_platdata socfpga_qspi = {
.quirks = CQSPI_DISABLE_DAC_MODE
| CQSPI_NO_SUPPORT_WR_COMPLETION
- | CQSPI_SLOW_SRAM,
+ | CQSPI_SLOW_SRAM
+ | CQSPI_DISABLE_STIG_MODE
+ | CQSPI_DISABLE_RUNTIME_PM,
};
static const struct cqspi_driver_platdata versal_ospi = {
.hwcaps_mask = CQSPI_SUPPORTS_OCTAL,
- .quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_SUPPORT_EXTERNAL_DMA,
+ .quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_SUPPORT_EXTERNAL_DMA
+ | CQSPI_DMA_SET_MASK,
+ .indirect_read_dma = cqspi_versal_indirect_read_dma,
+ .get_dma_status = cqspi_get_versal_dma_status,
+};
+
+static const struct cqspi_driver_platdata versal2_ospi = {
+ .hwcaps_mask = CQSPI_SUPPORTS_OCTAL,
+ .quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_SUPPORT_EXTERNAL_DMA
+ | CQSPI_DMA_SET_MASK
+ | CQSPI_SUPPORT_DEVICE_RESET,
.indirect_read_dma = cqspi_versal_indirect_read_dma,
.get_dma_status = cqspi_get_versal_dma_status,
};
static const struct cqspi_driver_platdata jh7110_qspi = {
.quirks = CQSPI_DISABLE_DAC_MODE,
+ .jh7110_clk_init = cqspi_jh7110_clk_init,
};
static const struct cqspi_driver_platdata pensando_cdns_qspi = {
.quirks = CQSPI_NEEDS_APB_AHB_HAZARD_WAR | CQSPI_DISABLE_DAC_MODE,
};
+static const struct cqspi_driver_platdata mobileye_eyeq5_ospi = {
+ .hwcaps_mask = CQSPI_SUPPORTS_OCTAL,
+ .quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_NO_SUPPORT_WR_COMPLETION |
+ CQSPI_RD_NO_IRQ,
+};
+
static const struct of_device_id cqspi_dt_ids[] = {
{
.compatible = "cdns,qspi-nor",
@@ -1936,6 +2206,14 @@ static const struct of_device_id cqspi_dt_ids[] = {
.compatible = "amd,pensando-elba-qspi",
.data = &pensando_cdns_qspi,
},
+ {
+ .compatible = "mobileye,eyeq5-ospi",
+ .data = &mobileye_eyeq5_ospi,
+ },
+ {
+ .compatible = "amd,versal2-ospi",
+ .data = &versal2_ospi,
+ },
{ /* end of table */ }
};
@@ -1943,10 +2221,10 @@ MODULE_DEVICE_TABLE(of, cqspi_dt_ids);
static struct platform_driver cqspi_platform_driver = {
.probe = cqspi_probe,
- .remove_new = cqspi_remove,
+ .remove = cqspi_remove,
.driver = {
.name = CQSPI_NAME,
- .pm = &cqspi_dev_pm_ops,
+ .pm = pm_ptr(&cqspi_dev_pm_ops),
.of_match_table = cqspi_dt_ids,
},
};
diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c
index ce4a3145f065..6dcba0e0ddaa 100644
--- a/drivers/spi/spi-cadence-xspi.c
+++ b/drivers/spi/spi-cadence-xspi.c
@@ -2,6 +2,7 @@
// Cadence XSPI flash controller driver
// Copyright (C) 2020-21 Cadence
+#include <linux/acpi.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -11,7 +12,6 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -20,6 +20,7 @@
#include <linux/bitfield.h>
#include <linux/limits.h>
#include <linux/log2.h>
+#include <linux/bitrev.h>
#define CDNS_XSPI_MAGIC_NUM_VALUE 0x6522
#define CDNS_XSPI_MAX_BANKS 8
@@ -146,6 +147,9 @@
#define CDNS_XSPI_STIG_DONE_FLAG BIT(0)
#define CDNS_XSPI_TRD_STATUS 0x0104
+#define MODE_NO_OF_BYTES GENMASK(25, 24)
+#define MODEBYTES_COUNT 1
+
/* Helper macros for filling command registers */
#define CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_1(op, data_phase) ( \
FIELD_PREP(CDNS_XSPI_CMD_INSTR_TYPE, (data_phase) ? \
@@ -158,9 +162,10 @@
FIELD_PREP(CDNS_XSPI_CMD_P1_R2_ADDR3, ((op)->addr.val >> 24) & 0xFF) | \
FIELD_PREP(CDNS_XSPI_CMD_P1_R2_ADDR4, ((op)->addr.val >> 32) & 0xFF))
-#define CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_3(op) ( \
+#define CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_3(op, modebytes) ( \
FIELD_PREP(CDNS_XSPI_CMD_P1_R3_ADDR5, ((op)->addr.val >> 40) & 0xFF) | \
FIELD_PREP(CDNS_XSPI_CMD_P1_R3_CMD, (op)->cmd.opcode) | \
+ FIELD_PREP(MODE_NO_OF_BYTES, modebytes) | \
FIELD_PREP(CDNS_XSPI_CMD_P1_R3_NUM_ADDR_BYTES, (op)->addr.nbytes))
#define CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_4(op, chipsel) ( \
@@ -174,12 +179,12 @@
#define CDNS_XSPI_CMD_FLD_DSEQ_CMD_2(op) \
FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R2_DCNT_L, (op)->data.nbytes & 0xFFFF)
-#define CDNS_XSPI_CMD_FLD_DSEQ_CMD_3(op) ( \
+#define CDNS_XSPI_CMD_FLD_DSEQ_CMD_3(op, dummybytes) ( \
FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_DCNT_H, \
((op)->data.nbytes >> 16) & 0xffff) | \
FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_NUM_OF_DUMMY, \
(op)->dummy.buswidth != 0 ? \
- (((op)->dummy.nbytes * 8) / (op)->dummy.buswidth) : \
+ (((dummybytes) * 8) / (op)->dummy.buswidth) : \
0))
#define CDNS_XSPI_CMD_FLD_DSEQ_CMD_4(op, chipsel) ( \
@@ -190,6 +195,98 @@
((op)->data.dir == SPI_MEM_DATA_IN) ? \
CDNS_XSPI_STIG_CMD_DIR_READ : CDNS_XSPI_STIG_CMD_DIR_WRITE))
+/* Helper macros for GENERIC and GENERIC-DSEQ instruction type */
+#define CMD_REG_LEN (6*4)
+#define INSTRUCTION_TYPE_GENERIC 96
+#define CDNS_XSPI_CMD_FLD_P1_GENERIC_CMD (\
+ FIELD_PREP(CDNS_XSPI_CMD_INSTR_TYPE, INSTRUCTION_TYPE_GENERIC))
+
+#define GENERIC_NUM_OF_BYTES GENMASK(27, 24)
+#define CDNS_XSPI_CMD_FLD_P3_GENERIC_CMD(len) (\
+ FIELD_PREP(GENERIC_NUM_OF_BYTES, len))
+
+#define GENERIC_BANK_NUM GENMASK(14, 12)
+#define GENERIC_GLUE_CMD BIT(28)
+#define CDNS_XSPI_CMD_FLD_P4_GENERIC_CMD(cs, glue) (\
+ FIELD_PREP(GENERIC_BANK_NUM, cs) | FIELD_PREP(GENERIC_GLUE_CMD, glue))
+
+#define CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_1 (\
+ FIELD_PREP(CDNS_XSPI_CMD_INSTR_TYPE, CDNS_XSPI_STIG_INSTR_TYPE_DATA_SEQ))
+
+#define CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_2(nbytes) (\
+ FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R2_DCNT_L, nbytes & 0xffff))
+
+#define CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_3(nbytes) ( \
+ FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R3_DCNT_H, (nbytes >> 16) & 0xffff))
+
+#define CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_4(dir, chipsel) ( \
+ FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R4_BANK, chipsel) | \
+ FIELD_PREP(CDNS_XSPI_CMD_DSEQ_R4_DIR, dir))
+
+/* Marvell PHY default values */
+#define MARVELL_REGS_DLL_PHY_CTRL 0x00000707
+#define MARVELL_CTB_RFILE_PHY_CTRL 0x00004000
+#define MARVELL_RFILE_PHY_TSEL 0x00000000
+#define MARVELL_RFILE_PHY_DQ_TIMING 0x00000101
+#define MARVELL_RFILE_PHY_DQS_TIMING 0x00700404
+#define MARVELL_RFILE_PHY_GATE_LPBK_CTRL 0x00200030
+#define MARVELL_RFILE_PHY_DLL_MASTER_CTRL 0x00800000
+#define MARVELL_RFILE_PHY_DLL_SLAVE_CTRL 0x0000ff01
+
+/* PHY config registers */
+#define CDNS_XSPI_RF_MINICTRL_REGS_DLL_PHY_CTRL 0x1034
+#define CDNS_XSPI_PHY_CTB_RFILE_PHY_CTRL 0x0080
+#define CDNS_XSPI_PHY_CTB_RFILE_PHY_TSEL 0x0084
+#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DQ_TIMING 0x0000
+#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DQS_TIMING 0x0004
+#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_GATE_LPBK_CTRL 0x0008
+#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DLL_MASTER_CTRL 0x000c
+#define CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DLL_SLAVE_CTRL 0x0010
+#define CDNS_XSPI_DATASLICE_RFILE_PHY_DLL_OBS_REG_0 0x001c
+
+#define CDNS_XSPI_DLL_RST_N BIT(24)
+#define CDNS_XSPI_DLL_LOCK BIT(0)
+
+/* Marvell overlay registers - clock */
+#define MRVL_XSPI_CLK_CTRL_AUX_REG 0x2020
+#define MRVL_XSPI_CLK_ENABLE BIT(0)
+#define MRVL_XSPI_CLK_DIV GENMASK(4, 1)
+#define MRVL_XSPI_IRQ_ENABLE BIT(6)
+#define MRVL_XSPI_CLOCK_IO_HZ 800000000
+#define MRVL_XSPI_CLOCK_DIVIDED(div) ((MRVL_XSPI_CLOCK_IO_HZ) / (div))
+#define MRVL_DEFAULT_CLK 25000000
+
+/* Marvell overlay registers - xfer */
+#define MRVL_XFER_FUNC_CTRL 0x210
+#define MRVL_XFER_FUNC_CTRL_READ_DATA(i) (0x000 + 8 * (i))
+#define MRVL_XFER_SOFT_RESET BIT(11)
+#define MRVL_XFER_CS_N_HOLD GENMASK(9, 6)
+#define MRVL_XFER_RECEIVE_ENABLE BIT(4)
+#define MRVL_XFER_FUNC_ENABLE BIT(3)
+#define MRVL_XFER_CLK_CAPTURE_POL BIT(2)
+#define MRVL_XFER_CLK_DRIVE_POL BIT(1)
+#define MRVL_XFER_FUNC_START BIT(0)
+#define MRVL_XFER_QWORD_COUNT 32
+#define MRVL_XFER_QWORD_BYTECOUNT 8
+
+#define MRVL_XSPI_POLL_TIMEOUT_US 1000
+#define MRVL_XSPI_POLL_DELAY_US 10
+
+/* Macros for calculating data bits in generic command
+ * Up to 10 bytes can be fit into cmd_registers
+ * least significant is placed in cmd_reg[1]
+ * Other bits are inserted after it in cmd_reg[1,2,3] register
+ */
+#define GENERIC_CMD_DATA_REG_3_COUNT(len) (len >= 10 ? 2 : len - 8)
+#define GENERIC_CMD_DATA_REG_2_COUNT(len) (len >= 7 ? 3 : len - 4)
+#define GENERIC_CMD_DATA_REG_1_COUNT(len) (len >= 3 ? 2 : len - 1)
+#define GENERIC_CMD_DATA_3_OFFSET(position) (8*(position))
+#define GENERIC_CMD_DATA_2_OFFSET(position) (8*(position))
+#define GENERIC_CMD_DATA_1_OFFSET(position) (8 + 8*(position))
+#define GENERIC_CMD_DATA_INSERT(data, pos) ((data) << (pos))
+#define GENERIC_CMD_REG_3_NEEDED(len) (len > 7)
+#define GENERIC_CMD_REG_2_NEEDED(len) (len > 3)
+
enum cdns_xspi_stig_instr_type {
CDNS_XSPI_STIG_INSTR_TYPE_0,
CDNS_XSPI_STIG_INSTR_TYPE_1,
@@ -206,6 +303,51 @@ enum cdns_xspi_stig_cmd_dir {
CDNS_XSPI_STIG_CMD_DIR_WRITE,
};
+struct cdns_xspi_driver_data {
+ bool mrvl_hw_overlay;
+ u32 dll_phy_ctrl;
+ u32 ctb_rfile_phy_ctrl;
+ u32 rfile_phy_tsel;
+ u32 rfile_phy_dq_timing;
+ u32 rfile_phy_dqs_timing;
+ u32 rfile_phy_gate_lpbk_ctrl;
+ u32 rfile_phy_dll_master_ctrl;
+ u32 rfile_phy_dll_slave_ctrl;
+};
+
+static struct cdns_xspi_driver_data marvell_driver_data = {
+ .mrvl_hw_overlay = true,
+ .dll_phy_ctrl = MARVELL_REGS_DLL_PHY_CTRL,
+ .ctb_rfile_phy_ctrl = MARVELL_CTB_RFILE_PHY_CTRL,
+ .rfile_phy_tsel = MARVELL_RFILE_PHY_TSEL,
+ .rfile_phy_dq_timing = MARVELL_RFILE_PHY_DQ_TIMING,
+ .rfile_phy_dqs_timing = MARVELL_RFILE_PHY_DQS_TIMING,
+ .rfile_phy_gate_lpbk_ctrl = MARVELL_RFILE_PHY_GATE_LPBK_CTRL,
+ .rfile_phy_dll_master_ctrl = MARVELL_RFILE_PHY_DLL_MASTER_CTRL,
+ .rfile_phy_dll_slave_ctrl = MARVELL_RFILE_PHY_DLL_SLAVE_CTRL,
+};
+
+static struct cdns_xspi_driver_data cdns_driver_data = {
+ .mrvl_hw_overlay = false,
+};
+
+static const int cdns_mrvl_xspi_clk_div_list[] = {
+ 4, //0x0 = Divide by 4. SPI clock is 200 MHz.
+ 6, //0x1 = Divide by 6. SPI clock is 133.33 MHz.
+ 8, //0x2 = Divide by 8. SPI clock is 100 MHz.
+ 10, //0x3 = Divide by 10. SPI clock is 80 MHz.
+ 12, //0x4 = Divide by 12. SPI clock is 66.666 MHz.
+ 16, //0x5 = Divide by 16. SPI clock is 50 MHz.
+ 18, //0x6 = Divide by 18. SPI clock is 44.44 MHz.
+ 20, //0x7 = Divide by 20. SPI clock is 40 MHz.
+ 24, //0x8 = Divide by 24. SPI clock is 33.33 MHz.
+ 32, //0x9 = Divide by 32. SPI clock is 25 MHz.
+ 40, //0xA = Divide by 40. SPI clock is 20 MHz.
+ 50, //0xB = Divide by 50. SPI clock is 16 MHz.
+ 64, //0xC = Divide by 64. SPI clock is 12.5 MHz.
+ 128 //0xD = Divide by 128. SPI clock is 6.25 MHz.
+};
+
struct cdns_xspi_dev {
struct platform_device *pdev;
struct device *dev;
@@ -213,6 +355,7 @@ struct cdns_xspi_dev {
void __iomem *iobase;
void __iomem *auxbase;
void __iomem *sdmabase;
+ void __iomem *xferbase;
int irq;
int cur_cs;
@@ -227,8 +370,102 @@ struct cdns_xspi_dev {
const void *out_buffer;
u8 hw_num_banks;
+
+ const struct cdns_xspi_driver_data *driver_data;
+ void (*sdma_handler)(struct cdns_xspi_dev *cdns_xspi);
+ void (*set_interrupts_handler)(struct cdns_xspi_dev *cdns_xspi, bool enabled);
+
+ bool xfer_in_progress;
+ int current_xfer_qword;
};
+static void cdns_xspi_reset_dll(struct cdns_xspi_dev *cdns_xspi)
+{
+ u32 dll_cntrl = readl(cdns_xspi->iobase +
+ CDNS_XSPI_RF_MINICTRL_REGS_DLL_PHY_CTRL);
+
+ /* Reset DLL */
+ dll_cntrl |= CDNS_XSPI_DLL_RST_N;
+ writel(dll_cntrl, cdns_xspi->iobase +
+ CDNS_XSPI_RF_MINICTRL_REGS_DLL_PHY_CTRL);
+}
+
+static bool cdns_xspi_is_dll_locked(struct cdns_xspi_dev *cdns_xspi)
+{
+ u32 dll_lock;
+
+ return !readl_relaxed_poll_timeout(cdns_xspi->iobase +
+ CDNS_XSPI_INTR_STATUS_REG,
+ dll_lock, ((dll_lock & CDNS_XSPI_DLL_LOCK) == 1), 10, 10000);
+}
+
+/* Static configuration of PHY */
+static bool cdns_xspi_configure_phy(struct cdns_xspi_dev *cdns_xspi)
+{
+ writel(cdns_xspi->driver_data->dll_phy_ctrl,
+ cdns_xspi->iobase + CDNS_XSPI_RF_MINICTRL_REGS_DLL_PHY_CTRL);
+ writel(cdns_xspi->driver_data->ctb_rfile_phy_ctrl,
+ cdns_xspi->auxbase + CDNS_XSPI_PHY_CTB_RFILE_PHY_CTRL);
+ writel(cdns_xspi->driver_data->rfile_phy_tsel,
+ cdns_xspi->auxbase + CDNS_XSPI_PHY_CTB_RFILE_PHY_TSEL);
+ writel(cdns_xspi->driver_data->rfile_phy_dq_timing,
+ cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DQ_TIMING);
+ writel(cdns_xspi->driver_data->rfile_phy_dqs_timing,
+ cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DQS_TIMING);
+ writel(cdns_xspi->driver_data->rfile_phy_gate_lpbk_ctrl,
+ cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_GATE_LPBK_CTRL);
+ writel(cdns_xspi->driver_data->rfile_phy_dll_master_ctrl,
+ cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DLL_MASTER_CTRL);
+ writel(cdns_xspi->driver_data->rfile_phy_dll_slave_ctrl,
+ cdns_xspi->auxbase + CDNS_XSPI_PHY_DATASLICE_RFILE_PHY_DLL_SLAVE_CTRL);
+
+ cdns_xspi_reset_dll(cdns_xspi);
+
+ return cdns_xspi_is_dll_locked(cdns_xspi);
+}
+
+static bool cdns_mrvl_xspi_setup_clock(struct cdns_xspi_dev *cdns_xspi,
+ int requested_clk)
+{
+ int i = 0;
+ int clk_val;
+ u32 clk_reg;
+ bool update_clk = false;
+
+ while (i < (ARRAY_SIZE(cdns_mrvl_xspi_clk_div_list) - 1)) {
+ clk_val = MRVL_XSPI_CLOCK_DIVIDED(
+ cdns_mrvl_xspi_clk_div_list[i]);
+ if (clk_val <= requested_clk)
+ break;
+ i++;
+ }
+
+ dev_dbg(cdns_xspi->dev, "Found clk div: %d, clk val: %d\n",
+ cdns_mrvl_xspi_clk_div_list[i],
+ MRVL_XSPI_CLOCK_DIVIDED(
+ cdns_mrvl_xspi_clk_div_list[i]));
+
+ clk_reg = readl(cdns_xspi->auxbase + MRVL_XSPI_CLK_CTRL_AUX_REG);
+
+ if (FIELD_GET(MRVL_XSPI_CLK_DIV, clk_reg) != i) {
+ clk_reg &= ~MRVL_XSPI_CLK_ENABLE;
+ writel(clk_reg,
+ cdns_xspi->auxbase + MRVL_XSPI_CLK_CTRL_AUX_REG);
+ clk_reg = FIELD_PREP(MRVL_XSPI_CLK_DIV, i);
+ clk_reg &= ~MRVL_XSPI_CLK_DIV;
+ clk_reg |= FIELD_PREP(MRVL_XSPI_CLK_DIV, i);
+ clk_reg |= MRVL_XSPI_CLK_ENABLE;
+ clk_reg |= MRVL_XSPI_IRQ_ENABLE;
+ update_clk = true;
+ }
+
+ if (update_clk)
+ writel(clk_reg,
+ cdns_xspi->auxbase + MRVL_XSPI_CLK_CTRL_AUX_REG);
+
+ return update_clk;
+}
+
static int cdns_xspi_wait_for_controller_idle(struct cdns_xspi_dev *cdns_xspi)
{
u32 ctrl_stat;
@@ -301,6 +538,23 @@ static void cdns_xspi_set_interrupts(struct cdns_xspi_dev *cdns_xspi,
writel(intr_enable, cdns_xspi->iobase + CDNS_XSPI_INTR_ENABLE_REG);
}
+static void marvell_xspi_set_interrupts(struct cdns_xspi_dev *cdns_xspi,
+ bool enabled)
+{
+ u32 intr_enable;
+ u32 irq_status;
+
+ irq_status = readl(cdns_xspi->iobase + CDNS_XSPI_INTR_STATUS_REG);
+ writel(irq_status, cdns_xspi->iobase + CDNS_XSPI_INTR_STATUS_REG);
+
+ intr_enable = readl(cdns_xspi->iobase + CDNS_XSPI_INTR_ENABLE_REG);
+ if (enabled)
+ intr_enable |= CDNS_XSPI_INTR_MASK;
+ else
+ intr_enable &= ~CDNS_XSPI_INTR_MASK;
+ writel(intr_enable, cdns_xspi->iobase + CDNS_XSPI_INTR_ENABLE_REG);
+}
+
static int cdns_xspi_controller_init(struct cdns_xspi_dev *cdns_xspi)
{
u32 ctrl_ver;
@@ -318,7 +572,7 @@ static int cdns_xspi_controller_init(struct cdns_xspi_dev *cdns_xspi)
ctrl_features = readl(cdns_xspi->iobase + CDNS_XSPI_CTRL_FEATURES_REG);
cdns_xspi->hw_num_banks = FIELD_GET(CDNS_XSPI_NUM_BANKS, ctrl_features);
- cdns_xspi_set_interrupts(cdns_xspi, false);
+ cdns_xspi->set_interrupts_handler(cdns_xspi, false);
return 0;
}
@@ -345,6 +599,78 @@ static void cdns_xspi_sdma_handle(struct cdns_xspi_dev *cdns_xspi)
}
}
+static void m_ioreadq(void __iomem *addr, void *buf, int len)
+{
+ if (IS_ALIGNED((long)buf, 8) && len >= 8) {
+ u64 full_ops = len / 8;
+ u64 *buffer = buf;
+
+ len -= full_ops * 8;
+ buf += full_ops * 8;
+
+ do {
+ u64 b = readq(addr);
+ *buffer++ = b;
+ } while (--full_ops);
+ }
+
+
+ while (len) {
+ u64 tmp_buf;
+
+ tmp_buf = readq(addr);
+ memcpy(buf, &tmp_buf, min(len, 8));
+ len = len > 8 ? len - 8 : 0;
+ buf += 8;
+ }
+}
+
+static void m_iowriteq(void __iomem *addr, const void *buf, int len)
+{
+ if (IS_ALIGNED((long)buf, 8) && len >= 8) {
+ u64 full_ops = len / 8;
+ const u64 *buffer = buf;
+
+ len -= full_ops * 8;
+ buf += full_ops * 8;
+
+ do {
+ writeq(*buffer++, addr);
+ } while (--full_ops);
+ }
+
+ while (len) {
+ u64 tmp_buf;
+
+ memcpy(&tmp_buf, buf, min(len, 8));
+ writeq(tmp_buf, addr);
+ len = len > 8 ? len - 8 : 0;
+ buf += 8;
+ }
+}
+
+static void marvell_xspi_sdma_handle(struct cdns_xspi_dev *cdns_xspi)
+{
+ u32 sdma_size, sdma_trd_info;
+ u8 sdma_dir;
+
+ sdma_size = readl(cdns_xspi->iobase + CDNS_XSPI_SDMA_SIZE_REG);
+ sdma_trd_info = readl(cdns_xspi->iobase + CDNS_XSPI_SDMA_TRD_INFO_REG);
+ sdma_dir = FIELD_GET(CDNS_XSPI_SDMA_DIR, sdma_trd_info);
+
+ switch (sdma_dir) {
+ case CDNS_XSPI_SDMA_DIR_READ:
+ m_ioreadq(cdns_xspi->sdmabase,
+ cdns_xspi->in_buffer, sdma_size);
+ break;
+
+ case CDNS_XSPI_SDMA_DIR_WRITE:
+ m_iowriteq(cdns_xspi->sdmabase,
+ cdns_xspi->out_buffer, sdma_size);
+ break;
+ }
+}
+
static int cdns_xspi_send_stig_command(struct cdns_xspi_dev *cdns_xspi,
const struct spi_mem_op *op,
bool data_phase)
@@ -352,6 +678,7 @@ static int cdns_xspi_send_stig_command(struct cdns_xspi_dev *cdns_xspi,
u32 cmd_regs[6];
u32 cmd_status;
int ret;
+ int dummybytes = op->dummy.nbytes;
ret = cdns_xspi_wait_for_controller_idle(cdns_xspi);
if (ret < 0)
@@ -360,13 +687,18 @@ static int cdns_xspi_send_stig_command(struct cdns_xspi_dev *cdns_xspi,
writel(FIELD_PREP(CDNS_XSPI_CTRL_WORK_MODE, CDNS_XSPI_WORK_MODE_STIG),
cdns_xspi->iobase + CDNS_XSPI_CTRL_CONFIG_REG);
- cdns_xspi_set_interrupts(cdns_xspi, true);
+ cdns_xspi->set_interrupts_handler(cdns_xspi, true);
cdns_xspi->sdma_error = false;
memset(cmd_regs, 0, sizeof(cmd_regs));
cmd_regs[1] = CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_1(op, data_phase);
cmd_regs[2] = CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_2(op);
- cmd_regs[3] = CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_3(op);
+ if (dummybytes != 0) {
+ cmd_regs[3] = CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_3(op, 1);
+ dummybytes--;
+ } else {
+ cmd_regs[3] = CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_3(op, 0);
+ }
cmd_regs[4] = CDNS_XSPI_CMD_FLD_P1_INSTR_CMD_4(op,
cdns_xspi->cur_cs);
@@ -376,7 +708,7 @@ static int cdns_xspi_send_stig_command(struct cdns_xspi_dev *cdns_xspi,
cmd_regs[0] = CDNS_XSPI_STIG_DONE_FLAG;
cmd_regs[1] = CDNS_XSPI_CMD_FLD_DSEQ_CMD_1(op);
cmd_regs[2] = CDNS_XSPI_CMD_FLD_DSEQ_CMD_2(op);
- cmd_regs[3] = CDNS_XSPI_CMD_FLD_DSEQ_CMD_3(op);
+ cmd_regs[3] = CDNS_XSPI_CMD_FLD_DSEQ_CMD_3(op, dummybytes);
cmd_regs[4] = CDNS_XSPI_CMD_FLD_DSEQ_CMD_4(op,
cdns_xspi->cur_cs);
@@ -387,14 +719,14 @@ static int cdns_xspi_send_stig_command(struct cdns_xspi_dev *cdns_xspi,
wait_for_completion(&cdns_xspi->sdma_complete);
if (cdns_xspi->sdma_error) {
- cdns_xspi_set_interrupts(cdns_xspi, false);
+ cdns_xspi->set_interrupts_handler(cdns_xspi, false);
return -EIO;
}
- cdns_xspi_sdma_handle(cdns_xspi);
+ cdns_xspi->sdma_handler(cdns_xspi);
}
wait_for_completion(&cdns_xspi->cmd_complete);
- cdns_xspi_set_interrupts(cdns_xspi, false);
+ cdns_xspi->set_interrupts_handler(cdns_xspi, false);
cmd_status = cdns_xspi_check_command_status(cdns_xspi);
if (cmd_status)
@@ -420,18 +752,93 @@ static int cdns_xspi_mem_op_execute(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct cdns_xspi_dev *cdns_xspi =
- spi_master_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
+ int ret = 0;
+
+ ret = cdns_xspi_mem_op(cdns_xspi, mem, op);
+
+ return ret;
+}
+
+static int marvell_xspi_mem_op_execute(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct cdns_xspi_dev *cdns_xspi =
+ spi_controller_get_devdata(mem->spi->controller);
int ret = 0;
+ cdns_mrvl_xspi_setup_clock(cdns_xspi, mem->spi->max_speed_hz);
+
ret = cdns_xspi_mem_op(cdns_xspi, mem, op);
return ret;
}
+#ifdef CONFIG_ACPI
+static bool cdns_xspi_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct spi_device *spi = mem->spi;
+ const union acpi_object *obj;
+ struct acpi_device *adev;
+
+ adev = ACPI_COMPANION(&spi->dev);
+
+ if (!acpi_dev_get_property(adev, "spi-tx-bus-width", ACPI_TYPE_INTEGER,
+ &obj)) {
+ switch (obj->integer.value) {
+ case 1:
+ break;
+ case 2:
+ spi->mode |= SPI_TX_DUAL;
+ break;
+ case 4:
+ spi->mode |= SPI_TX_QUAD;
+ break;
+ case 8:
+ spi->mode |= SPI_TX_OCTAL;
+ break;
+ default:
+ dev_warn(&spi->dev,
+ "spi-tx-bus-width %lld not supported\n",
+ obj->integer.value);
+ break;
+ }
+ }
+
+ if (!acpi_dev_get_property(adev, "spi-rx-bus-width", ACPI_TYPE_INTEGER,
+ &obj)) {
+ switch (obj->integer.value) {
+ case 1:
+ break;
+ case 2:
+ spi->mode |= SPI_RX_DUAL;
+ break;
+ case 4:
+ spi->mode |= SPI_RX_QUAD;
+ break;
+ case 8:
+ spi->mode |= SPI_RX_OCTAL;
+ break;
+ default:
+ dev_warn(&spi->dev,
+ "spi-rx-bus-width %lld not supported\n",
+ obj->integer.value);
+ break;
+ }
+ }
+
+ if (!spi_mem_default_supports_op(mem, op))
+ return false;
+
+ return true;
+}
+#endif
+
static int cdns_xspi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
struct cdns_xspi_dev *cdns_xspi =
- spi_master_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
op->data.nbytes = clamp_val(op->data.nbytes, 0, cdns_xspi->sdmasize);
@@ -439,10 +846,21 @@ static int cdns_xspi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *
}
static const struct spi_controller_mem_ops cadence_xspi_mem_ops = {
+#ifdef CONFIG_ACPI
+ .supports_op = cdns_xspi_supports_op,
+#endif
.exec_op = cdns_xspi_mem_op_execute,
.adjust_op_size = cdns_xspi_adjust_mem_op_size,
};
+static const struct spi_controller_mem_ops marvell_xspi_mem_ops = {
+#ifdef CONFIG_ACPI
+ .supports_op = cdns_xspi_supports_op,
+#endif
+ .exec_op = marvell_xspi_mem_op_execute,
+ .adjust_op_size = cdns_xspi_adjust_mem_op_size,
+};
+
static irqreturn_t cdns_xspi_irq_handler(int this_irq, void *dev)
{
struct cdns_xspi_dev *cdns_xspi = dev;
@@ -486,21 +904,20 @@ static irqreturn_t cdns_xspi_irq_handler(int this_irq, void *dev)
static int cdns_xspi_of_get_plat_data(struct platform_device *pdev)
{
- struct device_node *node_prop = pdev->dev.of_node;
- struct device_node *node_child;
+ struct fwnode_handle *fwnode_child;
unsigned int cs;
- for_each_child_of_node(node_prop, node_child) {
- if (!of_device_is_available(node_child))
+ device_for_each_child_node(&pdev->dev, fwnode_child) {
+ if (!fwnode_device_is_available(fwnode_child))
continue;
- if (of_property_read_u32(node_child, "reg", &cs)) {
+ if (fwnode_property_read_u32(fwnode_child, "reg", &cs)) {
dev_err(&pdev->dev, "Couldn't get memory chip select\n");
- of_node_put(node_child);
+ fwnode_handle_put(fwnode_child);
return -ENXIO;
} else if (cs >= CDNS_XSPI_MAX_BANKS) {
dev_err(&pdev->dev, "reg (cs) parameter value too large\n");
- of_node_put(node_child);
+ fwnode_handle_put(fwnode_child);
return -ENXIO;
}
}
@@ -525,29 +942,243 @@ static void cdns_xspi_print_phy_config(struct cdns_xspi_dev *cdns_xspi)
readl(cdns_xspi->auxbase + CDNS_XSPI_CCP_PHY_DLL_SLAVE_CTRL));
}
+static int cdns_xspi_prepare_generic(int cs, const void *dout, int len, int glue, u32 *cmd_regs)
+{
+ u8 *data = (u8 *)dout;
+ int i;
+ int data_counter = 0;
+
+ memset(cmd_regs, 0x00, CMD_REG_LEN);
+
+ if (GENERIC_CMD_REG_3_NEEDED(len)) {
+ for (i = GENERIC_CMD_DATA_REG_3_COUNT(len); i >= 0 ; i--)
+ cmd_regs[3] |= GENERIC_CMD_DATA_INSERT(data[data_counter++],
+ GENERIC_CMD_DATA_3_OFFSET(i));
+ }
+ if (GENERIC_CMD_REG_2_NEEDED(len)) {
+ for (i = GENERIC_CMD_DATA_REG_2_COUNT(len); i >= 0; i--)
+ cmd_regs[2] |= GENERIC_CMD_DATA_INSERT(data[data_counter++],
+ GENERIC_CMD_DATA_2_OFFSET(i));
+ }
+ for (i = GENERIC_CMD_DATA_REG_1_COUNT(len); i >= 0 ; i--)
+ cmd_regs[1] |= GENERIC_CMD_DATA_INSERT(data[data_counter++],
+ GENERIC_CMD_DATA_1_OFFSET(i));
+
+ cmd_regs[1] |= CDNS_XSPI_CMD_FLD_P1_GENERIC_CMD;
+ cmd_regs[3] |= CDNS_XSPI_CMD_FLD_P3_GENERIC_CMD(len);
+ cmd_regs[4] |= CDNS_XSPI_CMD_FLD_P4_GENERIC_CMD(cs, glue);
+
+ return 0;
+}
+
+static void marvell_xspi_read_single_qword(struct cdns_xspi_dev *cdns_xspi, u8 **buffer)
+{
+ u64 d = readq(cdns_xspi->xferbase +
+ MRVL_XFER_FUNC_CTRL_READ_DATA(cdns_xspi->current_xfer_qword));
+ u8 *ptr = (u8 *)&d;
+ int k;
+
+ for (k = 0; k < 8; k++) {
+ u8 val = bitrev8((ptr[k]));
+ **buffer = val;
+ *buffer = *buffer + 1;
+ }
+
+ cdns_xspi->current_xfer_qword++;
+ cdns_xspi->current_xfer_qword %= MRVL_XFER_QWORD_COUNT;
+}
+
+static void cdns_xspi_finish_read(struct cdns_xspi_dev *cdns_xspi, u8 **buffer, u32 data_count)
+{
+ u64 d = readq(cdns_xspi->xferbase +
+ MRVL_XFER_FUNC_CTRL_READ_DATA(cdns_xspi->current_xfer_qword));
+ u8 *ptr = (u8 *)&d;
+ int k;
+
+ for (k = 0; k < data_count % MRVL_XFER_QWORD_BYTECOUNT; k++) {
+ u8 val = bitrev8((ptr[k]));
+ **buffer = val;
+ *buffer = *buffer + 1;
+ }
+
+ cdns_xspi->current_xfer_qword++;
+ cdns_xspi->current_xfer_qword %= MRVL_XFER_QWORD_COUNT;
+}
+
+static int cdns_xspi_prepare_transfer(int cs, int dir, int len, u32 *cmd_regs)
+{
+ memset(cmd_regs, 0x00, CMD_REG_LEN);
+
+ cmd_regs[1] |= CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_1;
+ cmd_regs[2] |= CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_2(len);
+ cmd_regs[4] |= CDNS_XSPI_CMD_FLD_GENERIC_DSEQ_CMD_4(dir, cs);
+
+ return 0;
+}
+
+static bool cdns_xspi_is_stig_ready(struct cdns_xspi_dev *cdns_xspi, bool sleep)
+{
+ u32 ctrl_stat;
+
+ return !readl_relaxed_poll_timeout
+ (cdns_xspi->iobase + CDNS_XSPI_CTRL_STATUS_REG,
+ ctrl_stat,
+ ((ctrl_stat & BIT(3)) == 0),
+ sleep ? MRVL_XSPI_POLL_DELAY_US : 0,
+ sleep ? MRVL_XSPI_POLL_TIMEOUT_US : 0);
+}
+
+static bool cdns_xspi_is_sdma_ready(struct cdns_xspi_dev *cdns_xspi, bool sleep)
+{
+ u32 ctrl_stat;
+
+ return !readl_relaxed_poll_timeout
+ (cdns_xspi->iobase + CDNS_XSPI_INTR_STATUS_REG,
+ ctrl_stat,
+ (ctrl_stat & CDNS_XSPI_SDMA_TRIGGER),
+ sleep ? MRVL_XSPI_POLL_DELAY_US : 0,
+ sleep ? MRVL_XSPI_POLL_TIMEOUT_US : 0);
+}
+
+static int cdns_xspi_transfer_one_message_b0(struct spi_controller *controller,
+ struct spi_message *m)
+{
+ struct cdns_xspi_dev *cdns_xspi = spi_controller_get_devdata(controller);
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t = NULL;
+
+ const unsigned int max_len = MRVL_XFER_QWORD_BYTECOUNT * MRVL_XFER_QWORD_COUNT;
+ int current_transfer_len;
+ int cs = spi_get_chipselect(spi, 0);
+ int cs_change = 0;
+
+ /* Enable xfer state machine */
+ if (!cdns_xspi->xfer_in_progress) {
+ u32 xfer_control = readl(cdns_xspi->xferbase + MRVL_XFER_FUNC_CTRL);
+
+ cdns_xspi->current_xfer_qword = 0;
+ cdns_xspi->xfer_in_progress = true;
+ xfer_control |= (MRVL_XFER_RECEIVE_ENABLE |
+ MRVL_XFER_CLK_CAPTURE_POL |
+ MRVL_XFER_FUNC_START |
+ MRVL_XFER_SOFT_RESET |
+ FIELD_PREP(MRVL_XFER_CS_N_HOLD, (1 << cs)));
+ xfer_control &= ~(MRVL_XFER_FUNC_ENABLE | MRVL_XFER_CLK_DRIVE_POL);
+ writel(xfer_control, cdns_xspi->xferbase + MRVL_XFER_FUNC_CTRL);
+ }
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ u8 *txd = (u8 *) t->tx_buf;
+ u8 *rxd = (u8 *) t->rx_buf;
+ u8 data[10];
+ u32 cmd_regs[6];
+
+ if (!txd)
+ txd = data;
+
+ cdns_xspi->in_buffer = txd + 1;
+ cdns_xspi->out_buffer = txd + 1;
+
+ while (t->len) {
+
+ current_transfer_len = min(max_len, t->len);
+
+ if (current_transfer_len < 10) {
+ cdns_xspi_prepare_generic(cs, txd, current_transfer_len,
+ false, cmd_regs);
+ cdns_xspi_trigger_command(cdns_xspi, cmd_regs);
+ if (!cdns_xspi_is_stig_ready(cdns_xspi, true))
+ return -EIO;
+ } else {
+ cdns_xspi_prepare_generic(cs, txd, 1, true, cmd_regs);
+ cdns_xspi_trigger_command(cdns_xspi, cmd_regs);
+ cdns_xspi_prepare_transfer(cs, 1, current_transfer_len - 1,
+ cmd_regs);
+ cdns_xspi_trigger_command(cdns_xspi, cmd_regs);
+ if (!cdns_xspi_is_sdma_ready(cdns_xspi, true))
+ return -EIO;
+ cdns_xspi->sdma_handler(cdns_xspi);
+ if (!cdns_xspi_is_stig_ready(cdns_xspi, true))
+ return -EIO;
+
+ cdns_xspi->in_buffer += current_transfer_len;
+ cdns_xspi->out_buffer += current_transfer_len;
+ }
+
+ if (rxd) {
+ int j;
+
+ for (j = 0; j < current_transfer_len / 8; j++)
+ marvell_xspi_read_single_qword(cdns_xspi, &rxd);
+ cdns_xspi_finish_read(cdns_xspi, &rxd, current_transfer_len);
+ } else {
+ cdns_xspi->current_xfer_qword += current_transfer_len /
+ MRVL_XFER_QWORD_BYTECOUNT;
+ if (current_transfer_len % MRVL_XFER_QWORD_BYTECOUNT)
+ cdns_xspi->current_xfer_qword++;
+
+ cdns_xspi->current_xfer_qword %= MRVL_XFER_QWORD_COUNT;
+ }
+ cs_change = t->cs_change;
+ t->len -= current_transfer_len;
+ }
+ spi_transfer_delay_exec(t);
+ }
+
+ if (!cs_change) {
+ u32 xfer_control = readl(cdns_xspi->xferbase + MRVL_XFER_FUNC_CTRL);
+
+ xfer_control &= ~(MRVL_XFER_RECEIVE_ENABLE |
+ MRVL_XFER_SOFT_RESET);
+ writel(xfer_control, cdns_xspi->xferbase + MRVL_XFER_FUNC_CTRL);
+ cdns_xspi->xfer_in_progress = false;
+ }
+
+ m->status = 0;
+ spi_finalize_current_message(controller);
+
+ return 0;
+}
+
static int cdns_xspi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_master *master = NULL;
+ struct spi_controller *host = NULL;
struct cdns_xspi_dev *cdns_xspi = NULL;
struct resource *res;
int ret;
- master = devm_spi_alloc_master(dev, sizeof(*cdns_xspi));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*cdns_xspi));
+ if (!host)
return -ENOMEM;
- master->mode_bits = SPI_3WIRE | SPI_TX_DUAL | SPI_TX_QUAD |
+ host->mode_bits = SPI_3WIRE | SPI_TX_DUAL | SPI_TX_QUAD |
SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_OCTAL | SPI_RX_OCTAL |
SPI_MODE_0 | SPI_MODE_3;
- master->mem_ops = &cadence_xspi_mem_ops;
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = -1;
+ cdns_xspi = spi_controller_get_devdata(host);
+ cdns_xspi->driver_data = of_device_get_match_data(dev);
+ if (!cdns_xspi->driver_data) {
+ cdns_xspi->driver_data = acpi_device_get_match_data(dev);
+ if (!cdns_xspi->driver_data)
+ return -ENODEV;
+ }
+
+ if (cdns_xspi->driver_data->mrvl_hw_overlay) {
+ host->mem_ops = &marvell_xspi_mem_ops;
+ host->transfer_one_message = cdns_xspi_transfer_one_message_b0;
+ cdns_xspi->sdma_handler = &marvell_xspi_sdma_handle;
+ cdns_xspi->set_interrupts_handler = &marvell_xspi_set_interrupts;
+ } else {
+ host->mem_ops = &cadence_xspi_mem_ops;
+ cdns_xspi->sdma_handler = &cdns_xspi_sdma_handle;
+ cdns_xspi->set_interrupts_handler = &cdns_xspi_set_interrupts;
+ }
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = -1;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- cdns_xspi = spi_master_get_devdata(master);
cdns_xspi->pdev = pdev;
cdns_xspi->dev = &pdev->dev;
cdns_xspi->cur_cs = 0;
@@ -562,20 +1193,42 @@ static int cdns_xspi_probe(struct platform_device *pdev)
cdns_xspi->iobase = devm_platform_ioremap_resource_byname(pdev, "io");
if (IS_ERR(cdns_xspi->iobase)) {
- dev_err(dev, "Failed to remap controller base address\n");
- return PTR_ERR(cdns_xspi->iobase);
+ cdns_xspi->iobase = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(cdns_xspi->iobase)) {
+ dev_err(dev, "Failed to remap controller base address\n");
+ return PTR_ERR(cdns_xspi->iobase);
+ }
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sdma");
cdns_xspi->sdmabase = devm_ioremap_resource(dev, res);
- if (IS_ERR(cdns_xspi->sdmabase))
- return PTR_ERR(cdns_xspi->sdmabase);
+ if (IS_ERR(cdns_xspi->sdmabase)) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ cdns_xspi->sdmabase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(cdns_xspi->sdmabase))
+ return PTR_ERR(cdns_xspi->sdmabase);
+ }
cdns_xspi->sdmasize = resource_size(res);
cdns_xspi->auxbase = devm_platform_ioremap_resource_byname(pdev, "aux");
if (IS_ERR(cdns_xspi->auxbase)) {
- dev_err(dev, "Failed to remap AUX address\n");
- return PTR_ERR(cdns_xspi->auxbase);
+ cdns_xspi->auxbase = devm_platform_ioremap_resource(pdev, 2);
+ if (IS_ERR(cdns_xspi->auxbase)) {
+ dev_err(dev, "Failed to remap AUX address\n");
+ return PTR_ERR(cdns_xspi->auxbase);
+ }
+ }
+
+ if (cdns_xspi->driver_data->mrvl_hw_overlay) {
+ cdns_xspi->xferbase = devm_platform_ioremap_resource_byname(pdev, "xfer");
+ if (IS_ERR(cdns_xspi->xferbase)) {
+ cdns_xspi->xferbase = devm_platform_ioremap_resource(pdev, 3);
+ if (IS_ERR(cdns_xspi->xferbase)) {
+ dev_info(dev, "XFER register base not found, set it\n");
+ // For compatibility with older firmware
+ cdns_xspi->xferbase = cdns_xspi->iobase + 0x8000;
+ }
+ }
}
cdns_xspi->irq = platform_get_irq(pdev, 0);
@@ -589,6 +1242,11 @@ static int cdns_xspi_probe(struct platform_device *pdev)
return ret;
}
+ if (cdns_xspi->driver_data->mrvl_hw_overlay) {
+ cdns_mrvl_xspi_setup_clock(cdns_xspi, MRVL_DEFAULT_CLK);
+ cdns_xspi_configure_phy(cdns_xspi);
+ }
+
cdns_xspi_print_phy_config(cdns_xspi);
ret = cdns_xspi_controller_init(cdns_xspi);
@@ -597,15 +1255,15 @@ static int cdns_xspi_probe(struct platform_device *pdev)
return ret;
}
- master->num_chipselect = 1 << cdns_xspi->hw_num_banks;
+ host->num_chipselect = 1 << cdns_xspi->hw_num_banks;
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret) {
- dev_err(dev, "Failed to register SPI master\n");
+ dev_err(dev, "Failed to register SPI host\n");
return ret;
}
- dev_info(dev, "Successfully registered SPI master\n");
+ dev_info(dev, "Successfully registered SPI host\n");
return 0;
}
@@ -613,6 +1271,11 @@ static int cdns_xspi_probe(struct platform_device *pdev)
static const struct of_device_id cdns_xspi_of_match[] = {
{
.compatible = "cdns,xspi-nor",
+ .data = &cdns_driver_data,
+ },
+ {
+ .compatible = "marvell,cn10-xspi-nor",
+ .data = &marvell_driver_data,
},
{ /* end of table */}
};
@@ -620,7 +1283,6 @@ MODULE_DEVICE_TABLE(of, cdns_xspi_of_match);
static struct platform_driver cdns_xspi_platform_driver = {
.probe = cdns_xspi_probe,
- .remove = NULL,
.driver = {
.name = CDNS_XSPI_NAME,
.of_match_table = cdns_xspi_of_match,
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index de8fe3c5becb..47054da630d0 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Cadence SPI controller driver (master and slave mode)
+ * Cadence SPI controller driver (host and target mode)
*
* Copyright (C) 2008 - 2014 Xilinx, Inc.
*
@@ -18,6 +18,7 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/spi/spi.h>
/* Name of this driver */
@@ -59,10 +60,10 @@
CDNS_SPI_CR_BAUD_DIV_4)
/*
- * SPI Configuration Register - Baud rate and slave select
+ * SPI Configuration Register - Baud rate and target select
*
* These are the values used in the calculation of baud rate divisor and
- * setting the slave select.
+ * setting the target select.
*/
#define CDNS_SPI_BAUD_DIV_MAX 7 /* Baud rate divisor maximum */
@@ -108,9 +109,11 @@
* @rxbuf: Pointer to the RX buffer
* @tx_bytes: Number of bytes left to transfer
* @rx_bytes: Number of bytes requested
+ * @n_bytes: Number of bytes per word
* @dev_busy: Device busy flag
* @is_decoded_cs: Flag for decoder property set or not
* @tx_fifo_depth: Depth of the TX FIFO
+ * @rstc: Optional reset control for SPI controller
*/
struct cdns_spi {
void __iomem *regs;
@@ -118,13 +121,22 @@ struct cdns_spi {
struct clk *pclk;
unsigned int clk_rate;
u32 speed_hz;
- const u8 *txbuf;
- u8 *rxbuf;
+ const void *txbuf;
+ void *rxbuf;
int tx_bytes;
int rx_bytes;
+ u8 n_bytes;
u8 dev_busy;
u32 is_decoded_cs;
unsigned int tx_fifo_depth;
+ struct reset_control *rstc;
+};
+
+enum cdns_spi_frame_n_bytes {
+ CDNS_SPI_N_BYTES_NULL = 0,
+ CDNS_SPI_N_BYTES_U8 = 1,
+ CDNS_SPI_N_BYTES_U16 = 2,
+ CDNS_SPI_N_BYTES_U32 = 4
};
/* Macros for the SPI controller read/write */
@@ -141,20 +153,20 @@ static inline void cdns_spi_write(struct cdns_spi *xspi, u32 offset, u32 val)
/**
* cdns_spi_init_hw - Initialize the hardware and configure the SPI controller
* @xspi: Pointer to the cdns_spi structure
- * @is_slave: Flag to indicate slave or master mode
- * * On reset the SPI controller is configured to slave or master mode.
- * In master mode baud rate divisor is set to 4, threshold value for TX FIFO
+ * @is_target: Flag to indicate target or host mode
+ * * On reset the SPI controller is configured to target or host mode.
+ * In host mode baud rate divisor is set to 4, threshold value for TX FIFO
* not full interrupt is set to 1 and size of the word to be transferred as 8 bit.
*
* This function initializes the SPI controller to disable and clear all the
- * interrupts, enable manual slave select and manual start, deselect all the
+ * interrupts, enable manual target select and manual start, deselect all the
* chip select lines, and enable the SPI controller.
*/
-static void cdns_spi_init_hw(struct cdns_spi *xspi, bool is_slave)
+static void cdns_spi_init_hw(struct cdns_spi *xspi, bool is_target)
{
u32 ctrl_reg = 0;
- if (!is_slave)
+ if (!is_target)
ctrl_reg |= CDNS_SPI_CR_DEFAULT;
if (xspi->is_decoded_cs)
@@ -185,10 +197,10 @@ static void cdns_spi_chipselect(struct spi_device *spi, bool is_high)
ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR);
if (is_high) {
- /* Deselect the slave */
+ /* Deselect the target */
ctrl_reg |= CDNS_SPI_CR_SSCTRL;
} else {
- /* Select the slave */
+ /* Select the target */
ctrl_reg &= ~CDNS_SPI_CR_SSCTRL;
if (!(xspi->is_decoded_cs))
ctrl_reg |= ((~(CDNS_SPI_SS0 << spi_get_chipselect(spi, 0))) <<
@@ -227,7 +239,7 @@ static void cdns_spi_config_clock_mode(struct spi_device *spi)
/*
* Just writing the CR register does not seem to apply the clock
* setting changes. This is problematic when changing the clock
- * polarity as it will cause the SPI slave to see spurious clock
+ * polarity as it will cause the SPI target to see spurious clock
* transitions. To workaround the issue toggle the ER register.
*/
cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
@@ -302,6 +314,78 @@ static int cdns_spi_setup_transfer(struct spi_device *spi,
return 0;
}
+static u8 cdns_spi_n_bytes(struct spi_transfer *transfer)
+{
+ if (transfer->bits_per_word <= 8)
+ return CDNS_SPI_N_BYTES_U8;
+ else if (transfer->bits_per_word <= 16)
+ return CDNS_SPI_N_BYTES_U16;
+ else
+ return CDNS_SPI_N_BYTES_U32;
+}
+
+static inline void cdns_spi_reader(struct cdns_spi *xspi)
+{
+ u32 rxw = 0;
+
+ if (xspi->rxbuf && !IS_ALIGNED((uintptr_t)xspi->rxbuf, xspi->n_bytes)) {
+ pr_err("%s: rxbuf address is not aligned for %d bytes\n",
+ __func__, xspi->n_bytes);
+ return;
+ }
+
+ rxw = cdns_spi_read(xspi, CDNS_SPI_RXD);
+ if (xspi->rxbuf) {
+ switch (xspi->n_bytes) {
+ case CDNS_SPI_N_BYTES_U8:
+ *(u8 *)xspi->rxbuf = rxw;
+ break;
+ case CDNS_SPI_N_BYTES_U16:
+ *(u16 *)xspi->rxbuf = rxw;
+ break;
+ case CDNS_SPI_N_BYTES_U32:
+ *(u32 *)xspi->rxbuf = rxw;
+ break;
+ default:
+ pr_err("%s invalid n_bytes %d\n", __func__,
+ xspi->n_bytes);
+ return;
+ }
+ xspi->rxbuf = (u8 *)xspi->rxbuf + xspi->n_bytes;
+ }
+}
+
+static inline void cdns_spi_writer(struct cdns_spi *xspi)
+{
+ u32 txw = 0;
+
+ if (xspi->txbuf && !IS_ALIGNED((uintptr_t)xspi->txbuf, xspi->n_bytes)) {
+ pr_err("%s: txbuf address is not aligned for %d bytes\n",
+ __func__, xspi->n_bytes);
+ return;
+ }
+
+ if (xspi->txbuf) {
+ switch (xspi->n_bytes) {
+ case CDNS_SPI_N_BYTES_U8:
+ txw = *(u8 *)xspi->txbuf;
+ break;
+ case CDNS_SPI_N_BYTES_U16:
+ txw = *(u16 *)xspi->txbuf;
+ break;
+ case CDNS_SPI_N_BYTES_U32:
+ txw = *(u32 *)xspi->txbuf;
+ break;
+ default:
+ pr_err("%s invalid n_bytes %d\n", __func__,
+ xspi->n_bytes);
+ return;
+ }
+ cdns_spi_write(xspi, CDNS_SPI_TXD, txw);
+ xspi->txbuf = (u8 *)xspi->txbuf + xspi->n_bytes;
+ }
+}
+
/**
* cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO
* @xspi: Pointer to the cdns_spi structure
@@ -317,29 +401,15 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
xspi->rx_bytes -= nrx;
while (ntx || nrx) {
- /* When xspi in busy condition, bytes may send failed,
- * then spi control did't work thoroughly, add one byte delay
- */
- if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
- udelay(10);
+ if (nrx) {
+ cdns_spi_reader(xspi);
+ nrx--;
+ }
if (ntx) {
- if (xspi->txbuf)
- cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++);
- else
- cdns_spi_write(xspi, CDNS_SPI_TXD, 0);
-
+ cdns_spi_writer(xspi);
ntx--;
}
-
- if (nrx) {
- u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD);
-
- if (xspi->rxbuf)
- *xspi->rxbuf++ = data;
-
- nrx--;
- }
}
}
@@ -392,6 +462,11 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id)
if (xspi->tx_bytes) {
cdns_spi_process_fifo(xspi, trans_cnt, trans_cnt);
} else {
+ /* Fixed delay due to controller limitation with
+ * RX_NEMPTY incorrect status
+ * Xilinx AR:65885 contains more details
+ */
+ udelay(10);
cdns_spi_process_fifo(xspi, 0, trans_cnt);
cdns_spi_write(xspi, CDNS_SPI_IDR,
CDNS_SPI_IXR_DEFAULT);
@@ -406,7 +481,7 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id)
static int cdns_prepare_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
- if (!spi_controller_is_slave(ctlr))
+ if (!spi_controller_is_target(ctlr))
cdns_spi_config_clock_mode(msg->spi);
return 0;
}
@@ -418,9 +493,9 @@ static int cdns_prepare_message(struct spi_controller *ctlr,
* @transfer: Pointer to the spi_transfer structure which provides
* information about next transfer parameters
*
- * This function in master mode fills the TX FIFO, starts the SPI transfer and
+ * This function in host mode fills the TX FIFO, starts the SPI transfer and
* returns a positive transfer count so that core will wait for completion.
- * This function in slave mode fills the TX FIFO and wait for transfer trigger.
+ * This function in target mode fills the TX FIFO and wait for transfer trigger.
*
* Return: Number of bytes transferred in the last transfer
*/
@@ -435,18 +510,27 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
xspi->tx_bytes = transfer->len;
xspi->rx_bytes = transfer->len;
- if (!spi_controller_is_slave(ctlr)) {
+ if (!spi_controller_is_target(ctlr)) {
cdns_spi_setup_transfer(spi, transfer);
} else {
/* Set TX empty threshold to half of FIFO depth
- * only if TX bytes are more than half FIFO depth.
+ * only if TX bytes are more than FIFO depth.
*/
if (xspi->tx_bytes > xspi->tx_fifo_depth)
cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1);
}
+ /* When xspi in busy condition, bytes may send failed,
+ * then spi control didn't work thoroughly, add one byte delay
+ */
+ if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
+ udelay(10);
+
+ xspi->n_bytes = cdns_spi_n_bytes(transfer);
+ xspi->tx_bytes = DIV_ROUND_UP(xspi->tx_bytes, xspi->n_bytes);
+ xspi->rx_bytes = DIV_ROUND_UP(xspi->rx_bytes, xspi->n_bytes);
+
cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0);
- spi_transfer_delay_exec(transfer);
cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT);
return transfer->len;
@@ -457,7 +541,7 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
* @ctlr: Pointer to the spi_controller structure which provides
* information about the controller.
*
- * This function enables SPI master controller.
+ * This function enables SPI host controller.
*
* Return: 0 always
*/
@@ -475,7 +559,7 @@ static int cdns_prepare_transfer_hardware(struct spi_controller *ctlr)
* @ctlr: Pointer to the spi_controller structure which provides
* information about the controller.
*
- * This function disables the SPI master controller when no slave selected.
+ * This function disables the SPI host controller when no target selected.
* This function flush out if any pending data in FIFO.
*
* Return: 0 always
@@ -486,15 +570,15 @@ static int cdns_unprepare_transfer_hardware(struct spi_controller *ctlr)
u32 ctrl_reg;
unsigned int cnt = xspi->tx_fifo_depth;
- if (spi_controller_is_slave(ctlr)) {
+ if (spi_controller_is_target(ctlr)) {
while (cnt--)
cdns_spi_read(xspi, CDNS_SPI_RXD);
}
- /* Disable the SPI if slave is deselected */
+ /* Disable the SPI if target is deselected */
ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR);
ctrl_reg = (ctrl_reg & CDNS_SPI_CR_SSCTRL) >> CDNS_SPI_SS_SHIFT;
- if (ctrl_reg == CDNS_SPI_NOSS || spi_controller_is_slave(ctlr))
+ if (ctrl_reg == CDNS_SPI_NOSS || spi_controller_is_target(ctlr))
cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
/* Reset to default */
@@ -521,14 +605,14 @@ static void cdns_spi_detect_fifo_depth(struct cdns_spi *xspi)
}
/**
- * cdns_slave_abort - Abort slave transfer
+ * cdns_target_abort - Abort target transfer
* @ctlr: Pointer to the spi_controller structure
*
- * This function abort slave transfer if there any transfer timeout.
+ * This function abort target transfer if there any transfer timeout.
*
* Return: 0 always
*/
-static int cdns_slave_abort(struct spi_controller *ctlr)
+static int cdns_target_abort(struct spi_controller *ctlr)
{
struct cdns_spi *xspi = spi_controller_get_devdata(ctlr);
u32 intr_status;
@@ -555,13 +639,13 @@ static int cdns_spi_probe(struct platform_device *pdev)
struct spi_controller *ctlr;
struct cdns_spi *xspi;
u32 num_cs;
- bool slave;
+ bool target;
- slave = of_property_read_bool(pdev->dev.of_node, "spi-slave");
- if (slave)
- ctlr = spi_alloc_slave(&pdev->dev, sizeof(*xspi));
+ target = of_property_read_bool(pdev->dev.of_node, "spi-slave");
+ if (target)
+ ctlr = spi_alloc_target(&pdev->dev, sizeof(*xspi));
else
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*xspi));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*xspi));
if (!ctlr)
return -ENOMEM;
@@ -576,33 +660,31 @@ static int cdns_spi_probe(struct platform_device *pdev)
goto remove_ctlr;
}
- xspi->pclk = devm_clk_get(&pdev->dev, "pclk");
+ xspi->pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
if (IS_ERR(xspi->pclk)) {
dev_err(&pdev->dev, "pclk clock not found.\n");
ret = PTR_ERR(xspi->pclk);
goto remove_ctlr;
}
- ret = clk_prepare_enable(xspi->pclk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable APB clock.\n");
+ xspi->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, "spi");
+ if (IS_ERR(xspi->rstc)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(xspi->rstc),
+ "Cannot get SPI reset.\n");
goto remove_ctlr;
}
- if (!spi_controller_is_slave(ctlr)) {
- xspi->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
- if (IS_ERR(xspi->ref_clk)) {
- dev_err(&pdev->dev, "ref_clk clock not found.\n");
- ret = PTR_ERR(xspi->ref_clk);
- goto clk_dis_apb;
- }
+ reset_control_assert(xspi->rstc);
+ reset_control_deassert(xspi->rstc);
- ret = clk_prepare_enable(xspi->ref_clk);
- if (ret) {
- dev_err(&pdev->dev, "Unable to enable device clock.\n");
- goto clk_dis_apb;
- }
+ xspi->ref_clk = devm_clk_get_enabled(&pdev->dev, "ref_clk");
+ if (IS_ERR(xspi->ref_clk)) {
+ dev_err(&pdev->dev, "ref_clk clock not found.\n");
+ ret = PTR_ERR(xspi->ref_clk);
+ goto remove_ctlr;
+ }
+ if (!spi_controller_is_target(ctlr)) {
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_get_noresume(&pdev->dev);
@@ -624,11 +706,11 @@ static int cdns_spi_probe(struct platform_device *pdev)
cdns_spi_detect_fifo_depth(xspi);
/* SPI controller initializations */
- cdns_spi_init_hw(xspi, spi_controller_is_slave(ctlr));
+ cdns_spi_init_hw(xspi, spi_controller_is_target(ctlr));
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- ret = -ENXIO;
+ if (irq < 0) {
+ ret = irq;
goto clk_dis_all;
}
@@ -648,7 +730,10 @@ static int cdns_spi_probe(struct platform_device *pdev)
ctlr->mode_bits = SPI_CPOL | SPI_CPHA;
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
- if (!spi_controller_is_slave(ctlr)) {
+ if (of_device_is_compatible(pdev->dev.of_node, "cix,sky1-spi-r1p6"))
+ ctlr->bits_per_word_mask |= SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
+
+ if (!spi_controller_is_target(ctlr)) {
ctlr->mode_bits |= SPI_CS_HIGH;
ctlr->set_cs = cdns_spi_chipselect;
ctlr->auto_runtime_pm = true;
@@ -656,11 +741,10 @@ static int cdns_spi_probe(struct platform_device *pdev)
/* Set to default valid value */
ctlr->max_speed_hz = xspi->clk_rate / 4;
xspi->speed_hz = ctlr->max_speed_hz;
- pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
} else {
ctlr->mode_bits |= SPI_NO_CS;
- ctlr->slave_abort = cdns_slave_abort;
+ ctlr->target_abort = cdns_target_abort;
}
ret = spi_register_controller(ctlr);
if (ret) {
@@ -671,13 +755,10 @@ static int cdns_spi_probe(struct platform_device *pdev)
return ret;
clk_dis_all:
- if (!spi_controller_is_slave(ctlr)) {
- pm_runtime_set_suspended(&pdev->dev);
+ if (!spi_controller_is_target(ctlr)) {
pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(xspi->ref_clk);
+ pm_runtime_set_suspended(&pdev->dev);
}
-clk_dis_apb:
- clk_disable_unprepare(xspi->pclk);
remove_ctlr:
spi_controller_put(ctlr);
return ret;
@@ -690,8 +771,6 @@ remove_ctlr:
* This function is called if a device is physically removed from the system or
* if the driver module is being unloaded. It frees all resources allocated to
* the device.
- *
- * Return: 0 on success and error value on error
*/
static void cdns_spi_remove(struct platform_device *pdev)
{
@@ -700,10 +779,10 @@ static void cdns_spi_remove(struct platform_device *pdev)
cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE);
- clk_disable_unprepare(xspi->ref_clk);
- clk_disable_unprepare(xspi->pclk);
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
+ if (!spi_controller_is_target(ctlr)) {
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ }
spi_unregister_controller(ctlr);
}
@@ -737,7 +816,7 @@ static int __maybe_unused cdns_spi_resume(struct device *dev)
struct spi_controller *ctlr = dev_get_drvdata(dev);
struct cdns_spi *xspi = spi_controller_get_devdata(ctlr);
- cdns_spi_init_hw(xspi, spi_controller_is_slave(ctlr));
+ cdns_spi_init_hw(xspi, spi_controller_is_target(ctlr));
return spi_controller_resume(ctlr);
}
@@ -797,6 +876,7 @@ static const struct dev_pm_ops cdns_spi_dev_pm_ops = {
static const struct of_device_id cdns_spi_of_match[] = {
{ .compatible = "xlnx,zynq-spi-r1p6" },
+ { .compatible = "cix,sky1-spi-r1p6" },
{ .compatible = "cdns,spi-r1p6" },
{ /* end of table */ }
};
@@ -805,7 +885,7 @@ MODULE_DEVICE_TABLE(of, cdns_spi_of_match);
/* cdns_spi_driver - This structure defines the SPI subsystem platform driver */
static struct platform_driver cdns_spi_driver = {
.probe = cdns_spi_probe,
- .remove_new = cdns_spi_remove,
+ .remove = cdns_spi_remove,
.driver = {
.name = CDNS_SPI_NAME,
.of_match_table = cdns_spi_of_match,
diff --git a/drivers/spi/spi-cavium-octeon.c b/drivers/spi/spi-cavium-octeon.c
index 58060be33106..a5ad90d66ec0 100644
--- a/drivers/spi/spi-cavium-octeon.c
+++ b/drivers/spi/spi-cavium-octeon.c
@@ -19,15 +19,15 @@
static int octeon_spi_probe(struct platform_device *pdev)
{
void __iomem *reg_base;
- struct spi_master *master;
+ struct spi_controller *host;
struct octeon_spi *p;
int err = -ENOENT;
- master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(struct octeon_spi));
+ if (!host)
return -ENOMEM;
- p = spi_master_get_devdata(master);
- platform_set_drvdata(pdev, master);
+ p = spi_controller_get_devdata(host);
+ platform_set_drvdata(pdev, host);
reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(reg_base)) {
@@ -43,21 +43,21 @@ static int octeon_spi_probe(struct platform_device *pdev)
p->regs.tx = 0x10;
p->regs.data = 0x80;
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPHA |
+ host->num_chipselect = 4;
+ host->mode_bits = SPI_CPHA |
SPI_CPOL |
SPI_CS_HIGH |
SPI_LSB_FIRST |
SPI_3WIRE;
- master->transfer_one_message = octeon_spi_transfer_one_message;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+ host->transfer_one_message = octeon_spi_transfer_one_message;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
- master->dev.of_node = pdev->dev.of_node;
- err = devm_spi_register_master(&pdev->dev, master);
+ host->dev.of_node = pdev->dev.of_node;
+ err = devm_spi_register_controller(&pdev->dev, host);
if (err) {
- dev_err(&pdev->dev, "register master failed: %d\n", err);
+ dev_err(&pdev->dev, "register host failed: %d\n", err);
goto fail;
}
@@ -65,14 +65,14 @@ static int octeon_spi_probe(struct platform_device *pdev)
return 0;
fail:
- spi_master_put(master);
+ spi_controller_put(host);
return err;
}
static void octeon_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct octeon_spi *p = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct octeon_spi *p = spi_controller_get_devdata(host);
/* Clear the CSENA* and put everything in a known state. */
writeq(0, p->register_base + OCTEON_SPI_CFG(p));
@@ -90,7 +90,7 @@ static struct platform_driver octeon_spi_driver = {
.of_match_table = octeon_spi_match,
},
.probe = octeon_spi_probe,
- .remove_new = octeon_spi_remove,
+ .remove = octeon_spi_remove,
};
module_platform_driver(octeon_spi_driver);
diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c
index 60c0d6934654..367ae7120bb3 100644
--- a/drivers/spi/spi-cavium-thunderx.c
+++ b/drivers/spi/spi-cavium-thunderx.c
@@ -20,21 +20,21 @@ static int thunderx_spi_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct octeon_spi *p;
int ret;
- master = spi_alloc_master(dev, sizeof(struct octeon_spi));
- if (!master)
+ host = spi_alloc_host(dev, sizeof(struct octeon_spi));
+ if (!host)
return -ENOMEM;
- p = spi_master_get_devdata(master);
+ p = spi_controller_get_devdata(host);
ret = pcim_enable_device(pdev);
if (ret)
goto error;
- ret = pci_request_regions(pdev, DRV_NAME);
+ ret = pcim_request_all_regions(pdev, DRV_NAME);
if (ret)
goto error;
@@ -49,56 +49,48 @@ static int thunderx_spi_probe(struct pci_dev *pdev,
p->regs.tx = 0x1010;
p->regs.data = 0x1080;
- p->clk = devm_clk_get(dev, NULL);
+ p->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(p->clk)) {
ret = PTR_ERR(p->clk);
goto error;
}
- ret = clk_prepare_enable(p->clk);
- if (ret)
- goto error;
-
p->sys_freq = clk_get_rate(p->clk);
if (!p->sys_freq)
p->sys_freq = SYS_FREQ_DEFAULT;
dev_info(dev, "Set system clock to %u\n", p->sys_freq);
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->num_chipselect = 4;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
SPI_LSB_FIRST | SPI_3WIRE;
- master->transfer_one_message = octeon_spi_transfer_one_message;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
- master->dev.of_node = pdev->dev.of_node;
+ host->transfer_one_message = octeon_spi_transfer_one_message;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
+ host->dev.of_node = pdev->dev.of_node;
- pci_set_drvdata(pdev, master);
+ pci_set_drvdata(pdev, host);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
goto error;
return 0;
error:
- clk_disable_unprepare(p->clk);
- pci_release_regions(pdev);
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static void thunderx_spi_remove(struct pci_dev *pdev)
{
- struct spi_master *master = pci_get_drvdata(pdev);
+ struct spi_controller *host = pci_get_drvdata(pdev);
struct octeon_spi *p;
- p = spi_master_get_devdata(master);
+ p = spi_controller_get_devdata(host);
if (!p)
return;
- clk_disable_unprepare(p->clk);
- pci_release_regions(pdev);
/* Put everything in a known state. */
writeq(0, p->register_base + OCTEON_SPI_CFG(p));
}
diff --git a/drivers/spi/spi-cavium.c b/drivers/spi/spi-cavium.c
index dfe224defd6e..26b8cd1c76e1 100644
--- a/drivers/spi/spi-cavium.c
+++ b/drivers/spi/spi-cavium.c
@@ -124,10 +124,10 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
return xfer->len;
}
-int octeon_spi_transfer_one_message(struct spi_master *master,
+int octeon_spi_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
- struct octeon_spi *p = spi_master_get_devdata(master);
+ struct octeon_spi *p = spi_controller_get_devdata(ctlr);
unsigned int total_len = 0;
int status = 0;
struct spi_transfer *xfer;
@@ -145,6 +145,6 @@ int octeon_spi_transfer_one_message(struct spi_master *master,
err:
msg->status = status;
msg->actual_length = total_len;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(ctlr);
return status;
}
diff --git a/drivers/spi/spi-cavium.h b/drivers/spi/spi-cavium.h
index 1f3ac463a20b..af53a0c31476 100644
--- a/drivers/spi/spi-cavium.h
+++ b/drivers/spi/spi-cavium.h
@@ -28,7 +28,7 @@ struct octeon_spi {
#define OCTEON_SPI_TX(x) (x->regs.tx)
#define OCTEON_SPI_DAT0(x) (x->regs.data)
-int octeon_spi_transfer_one_message(struct spi_master *master,
+int octeon_spi_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *msg);
/* MPI register descriptions */
diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c
new file mode 100644
index 000000000000..79d2f9ab4ef0
--- /dev/null
+++ b/drivers/spi/spi-ch341.c
@@ -0,0 +1,241 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// QiHeng Electronics ch341a USB-to-SPI adapter driver
+//
+// Copyright (C) 2024 Johannes Thumshirn <jth@kernel.org>
+//
+// Based on ch341a_spi.c from the flashrom project.
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/spi/spi.h>
+
+#define CH341_PACKET_LENGTH 32
+#define CH341_DEFAULT_TIMEOUT 1000
+
+#define CH341A_CMD_UIO_STREAM 0xab
+
+#define CH341A_CMD_UIO_STM_END 0x20
+#define CH341A_CMD_UIO_STM_DIR 0x40
+#define CH341A_CMD_UIO_STM_OUT 0x80
+
+#define CH341A_CMD_I2C_STREAM 0xaa
+#define CH341A_CMD_I2C_STM_SET 0x60
+#define CH341A_CMD_I2C_STM_END 0x00
+
+#define CH341A_CMD_SPI_STREAM 0xa8
+
+#define CH341A_STM_I2C_100K 0x01
+
+struct ch341_spi_dev {
+ struct spi_controller *ctrl;
+ struct usb_device *udev;
+ unsigned int write_pipe;
+ unsigned int read_pipe;
+ int rx_len;
+ void *rx_buf;
+ u8 *tx_buf;
+ struct urb *rx_urb;
+ struct spi_device *spidev;
+};
+
+static void ch341_set_cs(struct spi_device *spi, bool is_high)
+{
+ struct ch341_spi_dev *ch341 =
+ spi_controller_get_devdata(spi->controller);
+ int err;
+
+ memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
+ ch341->tx_buf[0] = CH341A_CMD_UIO_STREAM;
+ ch341->tx_buf[1] = CH341A_CMD_UIO_STM_OUT | (is_high ? 0x36 : 0x37);
+
+ if (is_high) {
+ ch341->tx_buf[2] = CH341A_CMD_UIO_STM_DIR | 0x3f;
+ ch341->tx_buf[3] = CH341A_CMD_UIO_STM_END;
+ } else {
+ ch341->tx_buf[2] = CH341A_CMD_UIO_STM_END;
+ }
+
+ err = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf,
+ (is_high ? 4 : 3), NULL, CH341_DEFAULT_TIMEOUT);
+ if (err)
+ dev_err(&spi->dev,
+ "error sending USB message for setting CS (%d)\n", err);
+}
+
+static int ch341_transfer_one(struct spi_controller *host,
+ struct spi_device *spi,
+ struct spi_transfer *trans)
+{
+ struct ch341_spi_dev *ch341 =
+ spi_controller_get_devdata(spi->controller);
+ int len;
+ int ret;
+
+ len = min(CH341_PACKET_LENGTH, trans->len + 1);
+
+ memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
+
+ ch341->tx_buf[0] = CH341A_CMD_SPI_STREAM;
+
+ memcpy(ch341->tx_buf + 1, trans->tx_buf, len - 1);
+
+ ret = usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, len,
+ NULL, CH341_DEFAULT_TIMEOUT);
+ if (ret)
+ return ret;
+
+ return usb_bulk_msg(ch341->udev, ch341->read_pipe, trans->rx_buf,
+ len - 1, NULL, CH341_DEFAULT_TIMEOUT);
+}
+
+static void ch341_recv(struct urb *urb)
+{
+ struct ch341_spi_dev *ch341 = urb->context;
+ struct usb_device *udev = ch341->udev;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPIPE:
+ case -ESHUTDOWN:
+ dev_dbg(&udev->dev, "rx urb terminated with status: %d\n",
+ urb->status);
+ return;
+ default:
+ dev_dbg(&udev->dev, "rx urb error: %d\n", urb->status);
+ break;
+ }
+}
+
+static int ch341_config_stream(struct ch341_spi_dev *ch341)
+{
+ memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
+ ch341->tx_buf[0] = CH341A_CMD_I2C_STREAM;
+ ch341->tx_buf[1] = CH341A_CMD_I2C_STM_SET | CH341A_STM_I2C_100K;
+ ch341->tx_buf[2] = CH341A_CMD_I2C_STM_END;
+
+ return usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, 3,
+ NULL, CH341_DEFAULT_TIMEOUT);
+}
+
+static int ch341_enable_pins(struct ch341_spi_dev *ch341, bool enable)
+{
+ memset(ch341->tx_buf, 0, CH341_PACKET_LENGTH);
+ ch341->tx_buf[0] = CH341A_CMD_UIO_STREAM;
+ ch341->tx_buf[1] = CH341A_CMD_UIO_STM_OUT | 0x37;
+ ch341->tx_buf[2] = CH341A_CMD_UIO_STM_DIR | (enable ? 0x3f : 0x00);
+ ch341->tx_buf[3] = CH341A_CMD_UIO_STM_END;
+
+ return usb_bulk_msg(ch341->udev, ch341->write_pipe, ch341->tx_buf, 4,
+ NULL, CH341_DEFAULT_TIMEOUT);
+}
+
+static struct spi_board_info chip = {
+ .modalias = "spi-ch341a",
+};
+
+static int ch341_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_endpoint_descriptor *in, *out;
+ struct ch341_spi_dev *ch341;
+ struct spi_controller *ctrl;
+ int ret;
+
+ ret = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL,
+ NULL);
+ if (ret)
+ return ret;
+
+ ctrl = devm_spi_alloc_host(&udev->dev, sizeof(struct ch341_spi_dev));
+ if (!ctrl)
+ return -ENOMEM;
+
+ ch341 = spi_controller_get_devdata(ctrl);
+ ch341->ctrl = ctrl;
+ ch341->udev = udev;
+ ch341->write_pipe = usb_sndbulkpipe(udev, usb_endpoint_num(out));
+ ch341->read_pipe = usb_rcvbulkpipe(udev, usb_endpoint_num(in));
+
+ ch341->rx_len = usb_endpoint_maxp(in);
+ ch341->rx_buf = devm_kzalloc(&udev->dev, ch341->rx_len, GFP_KERNEL);
+ if (!ch341->rx_buf)
+ return -ENOMEM;
+
+ ch341->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ch341->rx_urb)
+ return -ENOMEM;
+
+ ch341->tx_buf =
+ devm_kzalloc(&udev->dev, CH341_PACKET_LENGTH, GFP_KERNEL);
+ if (!ch341->tx_buf)
+ return -ENOMEM;
+
+ usb_fill_bulk_urb(ch341->rx_urb, udev, ch341->read_pipe, ch341->rx_buf,
+ ch341->rx_len, ch341_recv, ch341);
+
+ ret = usb_submit_urb(ch341->rx_urb, GFP_KERNEL);
+ if (ret) {
+ usb_free_urb(ch341->rx_urb);
+ return -ENOMEM;
+ }
+
+ ctrl->bus_num = -1;
+ ctrl->mode_bits = SPI_CPHA;
+ ctrl->transfer_one = ch341_transfer_one;
+ ctrl->set_cs = ch341_set_cs;
+ ctrl->auto_runtime_pm = false;
+
+ usb_set_intfdata(intf, ch341);
+
+ ret = ch341_config_stream(ch341);
+ if (ret)
+ return ret;
+
+ ret = ch341_enable_pins(ch341, true);
+ if (ret)
+ return ret;
+
+ ret = spi_register_controller(ctrl);
+ if (ret)
+ return ret;
+
+ ch341->spidev = spi_new_device(ctrl, &chip);
+ if (!ch341->spidev)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void ch341_disconnect(struct usb_interface *intf)
+{
+ struct ch341_spi_dev *ch341 = usb_get_intfdata(intf);
+
+ spi_unregister_device(ch341->spidev);
+ spi_unregister_controller(ch341->ctrl);
+ ch341_enable_pins(ch341, false);
+ usb_free_urb(ch341->rx_urb);
+}
+
+static const struct usb_device_id ch341_id_table[] = {
+ { USB_DEVICE(0x1a86, 0x5512) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, ch341_id_table);
+
+static struct usb_driver ch341a_usb_driver = {
+ .name = "spi-ch341",
+ .probe = ch341_probe,
+ .disconnect = ch341_disconnect,
+ .id_table = ch341_id_table,
+};
+module_usb_driver(ch341a_usb_driver);
+
+MODULE_AUTHOR("Johannes Thumshirn <jth@kernel.org>");
+MODULE_DESCRIPTION("QiHeng Electronics ch341 USB2SPI");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c
index c005ed26a3e1..5552ccd716fc 100644
--- a/drivers/spi/spi-clps711x.c
+++ b/drivers/spi/spi-clps711x.c
@@ -33,10 +33,10 @@ struct spi_clps711x_data {
int len;
};
-static int spi_clps711x_prepare_message(struct spi_master *master,
+static int spi_clps711x_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ struct spi_clps711x_data *hw = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
/* Setup mode for transfer */
@@ -45,11 +45,11 @@ static int spi_clps711x_prepare_message(struct spi_master *master,
SYSCON3_ADCCKNSEN : 0);
}
-static int spi_clps711x_transfer_one(struct spi_master *master,
+static int spi_clps711x_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ struct spi_clps711x_data *hw = spi_controller_get_devdata(host);
u8 data;
clk_set_rate(hw->spi_clk, xfer->speed_hz ? : spi->max_speed_hz);
@@ -68,8 +68,8 @@ static int spi_clps711x_transfer_one(struct spi_master *master,
static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct spi_clps711x_data *hw = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct spi_clps711x_data *hw = spi_controller_get_devdata(host);
u8 data;
/* Handle RX */
@@ -83,7 +83,7 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN,
hw->syncio);
} else
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return IRQ_HANDLED;
}
@@ -92,26 +92,26 @@ static int spi_clps711x_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct spi_clps711x_data *hw;
- struct spi_master *master;
+ struct spi_controller *host;
int irq, ret;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- master = spi_alloc_master(&pdev->dev, sizeof(*hw));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*hw));
+ if (!host)
return -ENOMEM;
- 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->dev.of_node = pdev->dev.of_node;
- master->prepare_message = spi_clps711x_prepare_message;
- master->transfer_one = spi_clps711x_transfer_one;
+ host->use_gpio_descriptors = true;
+ host->bus_num = -1;
+ host->mode_bits = SPI_CPHA | SPI_CS_HIGH;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
+ host->dev.of_node = pdev->dev.of_node;
+ host->prepare_message = spi_clps711x_prepare_message;
+ host->transfer_one = spi_clps711x_transfer_one;
- hw = spi_master_get_devdata(master);
+ hw = spi_controller_get_devdata(host);
hw->spi_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(hw->spi_clk)) {
@@ -138,16 +138,16 @@ static int spi_clps711x_probe(struct platform_device *pdev)
readl(hw->syncio);
ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0,
- dev_name(&pdev->dev), master);
+ dev_name(&pdev->dev), host);
if (ret)
goto err_out;
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (!ret)
return 0;
err_out:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index b1bd8a6b5bf9..fdf37636cb9f 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -286,7 +286,7 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
static void mcfqspi_set_cs(struct spi_device *spi, bool enable)
{
- struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(spi->controller);
bool cs_high = spi->mode & SPI_CS_HIGH;
if (enable)
@@ -295,11 +295,11 @@ static void mcfqspi_set_cs(struct spi_device *spi, bool enable)
mcfqspi_cs_deselect(mcfqspi, spi_get_chipselect(spi, 0), cs_high);
}
-static int mcfqspi_transfer_one(struct spi_master *master,
+static int mcfqspi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
u16 qmr = MCFQSPI_QMR_MSTR;
qmr |= t->bits_per_word << 10;
@@ -323,7 +323,7 @@ static int mcfqspi_transfer_one(struct spi_master *master,
static int mcfqspi_setup(struct spi_device *spi)
{
- mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
+ mcfqspi_cs_deselect(spi_controller_get_devdata(spi->controller),
spi_get_chipselect(spi, 0), spi->mode & SPI_CS_HIGH);
dev_dbg(&spi->dev,
@@ -337,7 +337,7 @@ static int mcfqspi_setup(struct spi_device *spi)
static int mcfqspi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct mcfqspi *mcfqspi;
struct mcfqspi_platform_data *pdata;
int status;
@@ -353,13 +353,13 @@ static int mcfqspi_probe(struct platform_device *pdev)
return -EINVAL;
}
- master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
- if (master == NULL) {
- dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(*mcfqspi));
+ if (host == NULL) {
+ dev_dbg(&pdev->dev, "spi_alloc_host failed\n");
return -ENOMEM;
}
- mcfqspi = spi_master_get_devdata(master);
+ mcfqspi = spi_controller_get_devdata(host);
mcfqspi->iobase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mcfqspi->iobase)) {
@@ -381,53 +381,50 @@ static int mcfqspi_probe(struct platform_device *pdev)
goto fail0;
}
- mcfqspi->clk = devm_clk_get(&pdev->dev, "qspi_clk");
+ mcfqspi->clk = devm_clk_get_enabled(&pdev->dev, "qspi_clk");
if (IS_ERR(mcfqspi->clk)) {
dev_dbg(&pdev->dev, "clk_get failed\n");
status = PTR_ERR(mcfqspi->clk);
goto fail0;
}
- clk_prepare_enable(mcfqspi->clk);
- master->bus_num = pdata->bus_num;
- master->num_chipselect = pdata->num_chipselect;
+ host->bus_num = pdata->bus_num;
+ host->num_chipselect = pdata->num_chipselect;
mcfqspi->cs_control = pdata->cs_control;
status = mcfqspi_cs_setup(mcfqspi);
if (status) {
dev_dbg(&pdev->dev, "error initializing cs_control\n");
- goto fail1;
+ goto fail0;
}
init_waitqueue_head(&mcfqspi->waitq);
- master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
- master->setup = mcfqspi_setup;
- master->set_cs = mcfqspi_set_cs;
- master->transfer_one = mcfqspi_transfer_one;
- master->auto_runtime_pm = true;
+ host->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
+ host->setup = mcfqspi_setup;
+ host->set_cs = mcfqspi_set_cs;
+ host->transfer_one = mcfqspi_transfer_one;
+ host->auto_runtime_pm = true;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
pm_runtime_enable(&pdev->dev);
- status = devm_spi_register_master(&pdev->dev, master);
+ status = devm_spi_register_controller(&pdev->dev, host);
if (status) {
- dev_dbg(&pdev->dev, "spi_register_master failed\n");
- goto fail2;
+ dev_dbg(&pdev->dev, "devm_spi_register_controller failed\n");
+ goto fail1;
}
dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
return 0;
-fail2:
+fail1:
pm_runtime_disable(&pdev->dev);
mcfqspi_cs_teardown(mcfqspi);
-fail1:
- clk_disable_unprepare(mcfqspi->clk);
fail0:
- spi_master_put(master);
+ spi_controller_put(host);
dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n");
@@ -436,25 +433,24 @@ fail0:
static void mcfqspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
pm_runtime_disable(&pdev->dev);
/* disable the hardware (set the baud rate to 0) */
mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
mcfqspi_cs_teardown(mcfqspi);
- clk_disable_unprepare(mcfqspi->clk);
}
#ifdef CONFIG_PM_SLEEP
static int mcfqspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -465,20 +461,20 @@ static int mcfqspi_suspend(struct device *dev)
static int mcfqspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
clk_enable(mcfqspi->clk);
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif
#ifdef CONFIG_PM
static int mcfqspi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
clk_disable(mcfqspi->clk);
@@ -487,8 +483,8 @@ static int mcfqspi_runtime_suspend(struct device *dev)
static int mcfqspi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mcfqspi *mcfqspi = spi_controller_get_devdata(host);
clk_enable(mcfqspi->clk);
@@ -504,10 +500,9 @@ static const struct dev_pm_ops mcfqspi_pm = {
static struct platform_driver mcfqspi_driver = {
.driver.name = DRIVER_NAME,
- .driver.owner = THIS_MODULE,
.driver.pm = &mcfqspi_pm,
.probe = mcfqspi_probe,
- .remove_new = mcfqspi_remove,
+ .remove = mcfqspi_remove,
};
module_platform_driver(mcfqspi_driver);
diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c
new file mode 100644
index 000000000000..4b6b65f450a8
--- /dev/null
+++ b/drivers/spi/spi-cs42l43.c
@@ -0,0 +1,451 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS42L43 SPI Controller Driver
+//
+// Copyright (C) 2022-2023 Cirrus Logic, Inc. and
+// Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/acpi.h>
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/property.h>
+#include <linux/mfd/cs42l43.h>
+#include <linux/mfd/cs42l43-regs.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
+
+#define CS42L43_FIFO_SIZE 16
+#define CS42L43_SPI_ROOT_HZ 49152000
+#define CS42L43_SPI_MAX_LENGTH 65532
+
+enum cs42l43_spi_cmd {
+ CS42L43_WRITE,
+ CS42L43_READ
+};
+
+struct cs42l43_spi {
+ struct device *dev;
+ struct regmap *regmap;
+ struct spi_controller *ctlr;
+};
+
+static const unsigned int cs42l43_clock_divs[] = {
+ 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
+};
+
+static struct spi_board_info amp_info_template = {
+ .modalias = "cs35l56",
+ .max_speed_hz = 11 * HZ_PER_MHZ,
+ .mode = SPI_MODE_0,
+};
+
+static int cs42l43_spi_tx(struct regmap *regmap, const u8 *buf, unsigned int len)
+{
+ const u8 *end = buf + len;
+ u32 val = 0;
+ int ret;
+
+ while (buf < end) {
+ const u8 *block = min(buf + CS42L43_FIFO_SIZE, end);
+
+ while (buf < block) {
+ const u8 *word = min(buf + sizeof(u32), block);
+ int pad = (buf + sizeof(u32)) - word;
+
+ while (buf < word) {
+ val >>= BITS_PER_BYTE;
+ val |= FIELD_PREP(GENMASK(31, 24), *buf);
+
+ buf++;
+ }
+
+ val >>= pad * BITS_PER_BYTE;
+
+ regmap_write(regmap, CS42L43_TX_DATA, val);
+ }
+
+ regmap_write(regmap, CS42L43_TRAN_CONFIG8, CS42L43_SPI_TX_DONE_MASK);
+
+ ret = regmap_read_poll_timeout(regmap, CS42L43_TRAN_STATUS1,
+ val, (val & CS42L43_SPI_TX_REQUEST_MASK),
+ 1000, 5000);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cs42l43_spi_rx(struct regmap *regmap, u8 *buf, unsigned int len)
+{
+ u8 *end = buf + len;
+ u32 val;
+ int ret;
+
+ while (buf < end) {
+ u8 *block = min(buf + CS42L43_FIFO_SIZE, end);
+
+ ret = regmap_read_poll_timeout(regmap, CS42L43_TRAN_STATUS1,
+ val, (val & CS42L43_SPI_RX_REQUEST_MASK),
+ 1000, 5000);
+ if (ret)
+ return ret;
+
+ while (buf < block) {
+ u8 *word = min(buf + sizeof(u32), block);
+
+ ret = regmap_read(regmap, CS42L43_RX_DATA, &val);
+ if (ret)
+ return ret;
+
+ while (buf < word) {
+ *buf = FIELD_GET(GENMASK(7, 0), val);
+
+ val >>= BITS_PER_BYTE;
+ buf++;
+ }
+ }
+
+ regmap_write(regmap, CS42L43_TRAN_CONFIG8, CS42L43_SPI_RX_DONE_MASK);
+ }
+
+ return 0;
+}
+
+static int cs42l43_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(spi->controller);
+ int i, ret = -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(cs42l43_clock_divs); i++) {
+ if (CS42L43_SPI_ROOT_HZ / cs42l43_clock_divs[i] <= tfr->speed_hz)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cs42l43_clock_divs))
+ return -EINVAL;
+
+ regmap_write(priv->regmap, CS42L43_SPI_CLK_CONFIG1, i);
+
+ if (tfr->tx_buf) {
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG3, CS42L43_WRITE);
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG4, tfr->len - 1);
+ } else if (tfr->rx_buf) {
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG3, CS42L43_READ);
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG5, tfr->len - 1);
+ }
+
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG1, CS42L43_SPI_START_MASK);
+
+ if (tfr->tx_buf)
+ ret = cs42l43_spi_tx(priv->regmap, (const u8 *)tfr->tx_buf, tfr->len);
+ else if (tfr->rx_buf)
+ ret = cs42l43_spi_rx(priv->regmap, (u8 *)tfr->rx_buf, tfr->len);
+
+ return ret;
+}
+
+static void cs42l43_set_cs(struct spi_device *spi, bool is_high)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(spi->controller);
+
+ regmap_write(priv->regmap, CS42L43_SPI_CONFIG2, !is_high);
+}
+
+static int cs42l43_prepare_message(struct spi_controller *ctlr, struct spi_message *msg)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(ctlr);
+ struct spi_device *spi = msg->spi;
+ unsigned int spi_config1 = 0;
+
+ /* select another internal CS, which doesn't exist, so CS 0 is not used */
+ if (spi_get_csgpiod(spi, 0))
+ spi_config1 |= 1 << CS42L43_SPI_SS_SEL_SHIFT;
+ if (spi->mode & SPI_CPOL)
+ spi_config1 |= CS42L43_SPI_CPOL_MASK;
+ if (spi->mode & SPI_CPHA)
+ spi_config1 |= CS42L43_SPI_CPHA_MASK;
+ if (spi->mode & SPI_3WIRE)
+ spi_config1 |= CS42L43_SPI_THREE_WIRE_MASK;
+
+ regmap_write(priv->regmap, CS42L43_SPI_CONFIG1, spi_config1);
+
+ return 0;
+}
+
+static int cs42l43_prepare_transfer_hardware(struct spi_controller *ctlr)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(ctlr);
+ int ret;
+
+ ret = regmap_write(priv->regmap, CS42L43_BLOCK_EN2, CS42L43_SPI_MSTR_EN_MASK);
+ if (ret)
+ dev_err(priv->dev, "Failed to enable SPI controller: %d\n", ret);
+
+ return ret;
+}
+
+static int cs42l43_unprepare_transfer_hardware(struct spi_controller *ctlr)
+{
+ struct cs42l43_spi *priv = spi_controller_get_devdata(ctlr);
+ int ret;
+
+ ret = regmap_write(priv->regmap, CS42L43_BLOCK_EN2, 0);
+ if (ret)
+ dev_err(priv->dev, "Failed to disable SPI controller: %d\n", ret);
+
+ return ret;
+}
+
+static size_t cs42l43_spi_max_length(struct spi_device *spi)
+{
+ return CS42L43_SPI_MAX_LENGTH;
+}
+
+static int cs42l43_get_speaker_id_gpios(struct cs42l43_spi *priv, int *result)
+{
+ struct gpio_descs *descs;
+ u32 spkid;
+ int i, ret;
+
+ descs = gpiod_get_array_optional(priv->dev, "spk-id", GPIOD_IN);
+ if (!descs)
+ return 0;
+ else if (IS_ERR(descs))
+ return PTR_ERR(descs);
+
+ spkid = 0;
+ for (i = 0; i < descs->ndescs; i++) {
+ ret = gpiod_get_value_cansleep(descs->desc[i]);
+ if (ret < 0)
+ goto err;
+
+ spkid |= (ret << i);
+ }
+
+ dev_dbg(priv->dev, "spk-id-gpios = %d\n", spkid);
+ *result = spkid;
+err:
+ gpiod_put_array(descs);
+
+ return ret;
+}
+
+static struct fwnode_handle *cs42l43_find_xu_node(struct fwnode_handle *fwnode)
+{
+ static const u32 func_smart_amp = 0x1;
+ struct fwnode_handle *child_fwnode, *ext_fwnode;
+ u32 function;
+ int ret;
+
+ fwnode_for_each_child_node(fwnode, child_fwnode) {
+ acpi_handle handle = ACPI_HANDLE_FWNODE(child_fwnode);
+
+ ret = acpi_get_local_address(handle, &function);
+ if (ret || function != func_smart_amp)
+ continue;
+
+ ext_fwnode = fwnode_get_named_child_node(child_fwnode,
+ "mipi-sdca-function-expansion-subproperties");
+ if (!ext_fwnode)
+ continue;
+
+ fwnode_handle_put(child_fwnode);
+
+ return ext_fwnode;
+ }
+
+ return NULL;
+}
+
+static struct spi_board_info *cs42l43_create_bridge_amp(struct cs42l43_spi *priv,
+ const char * const name,
+ int cs, int spkid)
+{
+ struct property_entry *props = NULL;
+ struct software_node *swnode;
+ struct spi_board_info *info;
+
+ if (spkid >= 0) {
+ props = devm_kcalloc(priv->dev, 2, sizeof(*props), GFP_KERNEL);
+ if (!props)
+ return NULL;
+
+ *props = PROPERTY_ENTRY_U32("cirrus,speaker-id", spkid);
+ }
+
+ swnode = devm_kmalloc(priv->dev, sizeof(*swnode), GFP_KERNEL);
+ if (!swnode)
+ return NULL;
+
+ *swnode = SOFTWARE_NODE(name, props, NULL);
+
+ info = devm_kmemdup(priv->dev, &amp_info_template,
+ sizeof(amp_info_template), GFP_KERNEL);
+ if (!info)
+ return NULL;
+
+ info->chip_select = cs;
+ info->swnode = swnode;
+
+ return info;
+}
+
+static void cs42l43_release_of_node(void *data)
+{
+ fwnode_handle_put(data);
+}
+
+static int cs42l43_spi_probe(struct platform_device *pdev)
+{
+ struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
+ struct cs42l43_spi *priv;
+ struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev);
+ struct fwnode_handle *xu_fwnode __free(fwnode_handle) = cs42l43_find_xu_node(fwnode);
+ int nsidecars = 0;
+ int spkid = -EINVAL;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*priv->ctlr));
+ if (!priv->ctlr)
+ return -ENOMEM;
+
+ spi_controller_set_devdata(priv->ctlr, priv);
+
+ priv->dev = &pdev->dev;
+ priv->regmap = cs42l43->regmap;
+
+ priv->ctlr->prepare_message = cs42l43_prepare_message;
+ priv->ctlr->prepare_transfer_hardware = cs42l43_prepare_transfer_hardware;
+ priv->ctlr->unprepare_transfer_hardware = cs42l43_unprepare_transfer_hardware;
+ priv->ctlr->transfer_one = cs42l43_transfer_one;
+ priv->ctlr->set_cs = cs42l43_set_cs;
+ priv->ctlr->max_transfer_size = cs42l43_spi_max_length;
+ priv->ctlr->mode_bits = SPI_3WIRE | SPI_MODE_X_MASK;
+ priv->ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ priv->ctlr->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(32);
+ priv->ctlr->min_speed_hz = CS42L43_SPI_ROOT_HZ /
+ cs42l43_clock_divs[ARRAY_SIZE(cs42l43_clock_divs) - 1];
+ priv->ctlr->max_speed_hz = CS42L43_SPI_ROOT_HZ / cs42l43_clock_divs[0];
+ priv->ctlr->use_gpio_descriptors = true;
+ priv->ctlr->auto_runtime_pm = true;
+
+ ret = devm_pm_runtime_enable(priv->dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_idle(priv->dev);
+
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG6, CS42L43_FIFO_SIZE - 1);
+ regmap_write(priv->regmap, CS42L43_TRAN_CONFIG7, CS42L43_FIFO_SIZE - 1);
+
+ // Disable Watchdog timer and enable stall
+ regmap_write(priv->regmap, CS42L43_SPI_CONFIG3, 0);
+ regmap_write(priv->regmap, CS42L43_SPI_CONFIG4, CS42L43_SPI_STALL_ENA_MASK);
+
+ if (is_of_node(fwnode)) {
+ fwnode = fwnode_get_named_child_node(fwnode, "spi");
+ ret = devm_add_action_or_reset(priv->dev, cs42l43_release_of_node, fwnode);
+ if (ret)
+ return ret;
+ }
+
+ fwnode_property_read_u32(xu_fwnode, "01fa-sidecar-instances", &nsidecars);
+
+ if (nsidecars) {
+ struct software_node_ref_args args[] = {
+ SOFTWARE_NODE_REFERENCE(fwnode, 0, GPIO_ACTIVE_LOW),
+ SOFTWARE_NODE_REFERENCE(&swnode_gpio_undefined),
+ };
+ struct property_entry props[] = {
+ PROPERTY_ENTRY_REF_ARRAY("cs-gpios", args),
+ { }
+ };
+
+ ret = fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid);
+ if (!ret) {
+ dev_dbg(priv->dev, "01fa-spk-id-val = %d\n", spkid);
+ } else if (ret != -EINVAL) {
+ return dev_err_probe(priv->dev, ret, "Failed to get spk-id-val\n");
+ } else {
+ ret = cs42l43_get_speaker_id_gpios(priv, &spkid);
+ if (ret < 0)
+ return dev_err_probe(priv->dev, ret,
+ "Failed to get spk-id-gpios\n");
+ }
+
+ ret = device_create_managed_software_node(&priv->ctlr->dev, props, NULL);
+ if (ret)
+ return dev_err_probe(priv->dev, ret, "Failed to add swnode\n");
+ } else {
+ device_set_node(&priv->ctlr->dev, fwnode);
+ }
+
+ ret = devm_spi_register_controller(priv->dev, priv->ctlr);
+ if (ret)
+ return dev_err_probe(priv->dev, ret,
+ "Failed to register SPI controller\n");
+
+ if (nsidecars) {
+ struct spi_board_info *ampl_info;
+ struct spi_board_info *ampr_info;
+
+ ampl_info = cs42l43_create_bridge_amp(priv, "cs35l56-left", 0, spkid);
+ if (!ampl_info)
+ return -ENOMEM;
+
+ ampr_info = cs42l43_create_bridge_amp(priv, "cs35l56-right", 1, spkid);
+ if (!ampr_info)
+ return -ENOMEM;
+
+ if (!spi_new_device(priv->ctlr, ampl_info))
+ return dev_err_probe(priv->dev, -ENODEV,
+ "Failed to create left amp slave\n");
+
+ if (!spi_new_device(priv->ctlr, ampr_info))
+ return dev_err_probe(priv->dev, -ENODEV,
+ "Failed to create right amp slave\n");
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id cs42l43_spi_id_table[] = {
+ { "cs42l43-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, cs42l43_spi_id_table);
+
+static struct platform_driver cs42l43_spi_driver = {
+ .driver = {
+ .name = "cs42l43-spi",
+ },
+ .probe = cs42l43_spi_probe,
+ .id_table = cs42l43_spi_id_table,
+};
+module_platform_driver(cs42l43_spi_driver);
+
+MODULE_IMPORT_NS("GPIO_SWNODE");
+MODULE_DESCRIPTION("CS42L43 SPI Driver");
+MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
+MODULE_AUTHOR("Maciej Strozek <mstrozek@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index b04811c911e2..21a14e800eed 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -9,19 +9,17 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/platform_data/edma.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/slab.h>
-#include <linux/platform_data/spi-davinci.h>
-
#define CS_DEFAULT 0xFF
#define SPIFMT_PHASE_MASK BIT(16)
@@ -99,8 +97,69 @@
#define SPIDEF 0x4c
#define SPIFMT0 0x50
+#define SPI_IO_TYPE_POLL 1
+#define SPI_IO_TYPE_DMA 2
+
#define DMA_MIN_BYTES 16
+enum {
+ SPI_VERSION_1, /* For DM355/DM365/DM6467 */
+ SPI_VERSION_2, /* For DA8xx */
+};
+
+/**
+ * struct davinci_spi_platform_data - Platform data for SPI master device on DaVinci
+ *
+ * @version: version of the SPI IP. Different DaVinci devices have slightly
+ * varying versions of the same IP.
+ * @num_chipselect: number of chipselects supported by this SPI master
+ * @intr_line: interrupt line used to connect the SPI IP to the ARM interrupt
+ * controller withn the SoC. Possible values are 0 and 1.
+ * @prescaler_limit: max clock prescaler value
+ * @cshold_bug: set this to true if the SPI controller on your chip requires
+ * a write to CSHOLD bit in between transfers (like in DM355).
+ * @dma_event_q: DMA event queue to use if SPI_IO_TYPE_DMA is used for any
+ * device on the bus.
+ */
+struct davinci_spi_platform_data {
+ u8 version;
+ u8 num_chipselect;
+ u8 intr_line;
+ u8 prescaler_limit;
+ bool cshold_bug;
+ enum dma_event_q dma_event_q;
+};
+
+/**
+ * struct davinci_spi_config - Per-chip-select configuration for SPI slave devices
+ *
+ * @wdelay: amount of delay between transmissions. Measured in number of
+ * SPI module clocks.
+ * @odd_parity: polarity of parity flag at the end of transmit data stream.
+ * 0 - odd parity, 1 - even parity.
+ * @parity_enable: enable transmission of parity at end of each transmit
+ * data stream.
+ * @io_type: type of IO transfer. Choose between polled, interrupt and DMA.
+ * @timer_disable: disable chip-select timers (setup and hold)
+ * @c2tdelay: chip-select setup time. Measured in number of SPI module clocks.
+ * @t2cdelay: chip-select hold time. Measured in number of SPI module clocks.
+ * @t2edelay: transmit data finished to SPI ENAn pin inactive time. Measured
+ * in number of SPI clocks.
+ * @c2edelay: chip-select active to SPI ENAn signal active time. Measured in
+ * number of SPI clocks.
+ */
+struct davinci_spi_config {
+ u8 wdelay;
+ u8 odd_parity;
+ u8 parity_enable;
+ u8 io_type;
+ u8 timer_disable;
+ u8 c2tdelay;
+ u8 t2cdelay;
+ u8 t2edelay;
+ u8 c2edelay;
+};
+
/* SPI Controller driver's private data. */
struct davinci_spi {
struct spi_bitbang bitbang;
@@ -202,7 +261,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
u8 chip_sel = spi_get_chipselect(spi, 0);
u16 spidat1 = CS_DEFAULT;
- dspi = spi_master_get_devdata(spi->master);
+ dspi = spi_controller_get_devdata(spi->controller);
/* program delay transfers if tx_delay is non zero */
if (spicfg && spicfg->wdelay)
@@ -272,7 +331,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
u32 hz = 0, spifmt = 0;
int prescale;
- dspi = spi_master_get_devdata(spi->master);
+ dspi = spi_controller_get_devdata(spi->controller);
spicfg = spi->controller_data;
if (!spicfg)
spicfg = &davinci_spi_default_cfg;
@@ -380,7 +439,7 @@ static int davinci_spi_of_setup(struct spi_device *spi)
{
struct davinci_spi_config *spicfg = spi->controller_data;
struct device_node *np = spi->dev.of_node;
- struct davinci_spi *dspi = spi_master_get_devdata(spi->master);
+ struct davinci_spi *dspi = spi_controller_get_devdata(spi->controller);
u32 prop;
if (spicfg == NULL && np) {
@@ -412,7 +471,7 @@ static int davinci_spi_setup(struct spi_device *spi)
struct device_node *np = spi->dev.of_node;
bool internal_cs = true;
- dspi = spi_master_get_devdata(spi->master);
+ dspi = spi_controller_get_devdata(spi->controller);
if (!(spi->mode & SPI_NO_CS)) {
if (np && spi_get_csgpiod(spi, 0))
@@ -442,7 +501,7 @@ static void davinci_spi_cleanup(struct spi_device *spi)
kfree(spicfg);
}
-static bool davinci_spi_can_dma(struct spi_master *master,
+static bool davinci_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
@@ -460,7 +519,7 @@ static bool davinci_spi_can_dma(struct spi_master *master,
static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
{
- struct device *sdev = dspi->bitbang.master->dev.parent;
+ struct device *sdev = dspi->bitbang.ctlr->dev.parent;
if (int_status & SPIFLG_TIMEOUT_MASK) {
dev_err(sdev, "SPI Time-out Error\n");
@@ -571,8 +630,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
u32 errors = 0;
struct davinci_spi_config *spicfg;
struct davinci_spi_platform_data *pdata;
+ unsigned long timeout;
- dspi = spi_master_get_devdata(spi->master);
+ dspi = spi_controller_get_devdata(spi->controller);
pdata = &dspi->pdata;
spicfg = (struct davinci_spi_config *)spi->controller_data;
if (!spicfg)
@@ -593,7 +653,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
reinit_completion(&dspi->done);
- if (!davinci_spi_can_dma(spi->master, spi, t)) {
+ if (!davinci_spi_can_dma(spi->controller, spi, t)) {
if (spicfg->io_type != SPI_IO_TYPE_POLL)
set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
/* start the transfer */
@@ -662,7 +722,12 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
/* Wait for the transfer to complete */
if (spicfg->io_type != SPI_IO_TYPE_POLL) {
- if (wait_for_completion_timeout(&dspi->done, HZ) == 0)
+ timeout = DIV_ROUND_UP(t->speed_hz, MSEC_PER_SEC);
+ timeout = DIV_ROUND_UP(t->len * 8, timeout);
+ /* Assume we are at most 2x slower than the nominal bus speed */
+ timeout = 2 * msecs_to_jiffies(timeout);
+
+ if (wait_for_completion_timeout(&dspi->done, timeout) == 0)
errors = SPIFLG_TIMEOUT_MASK;
} else {
while (dspi->rcount > 0 || dspi->wcount > 0) {
@@ -674,7 +739,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
}
clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
- if (davinci_spi_can_dma(spi->master, spi, t))
+ if (davinci_spi_can_dma(spi->controller, spi, t))
clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
@@ -743,7 +808,7 @@ static irqreturn_t davinci_spi_irq(s32 irq, void *data)
static int davinci_spi_request_dma(struct davinci_spi *dspi)
{
- struct device *sdev = dspi->bitbang.master->dev.parent;
+ struct device *sdev = dspi->bitbang.ctlr->dev.parent;
dspi->dma_rx = dma_request_chan(sdev, "rx");
if (IS_ERR(dspi->dma_rx))
@@ -856,22 +921,22 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
*/
static int davinci_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata;
struct resource *r;
int ret = 0;
u32 spipc0;
- master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));
- if (master == NULL) {
+ host = spi_alloc_host(&pdev->dev, sizeof(struct davinci_spi));
+ if (host == NULL) {
ret = -ENOMEM;
goto err;
}
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- dspi = spi_master_get_devdata(master);
+ dspi = spi_controller_get_devdata(host);
if (dev_get_platdata(&pdev->dev)) {
pdata = dev_get_platdata(&pdev->dev);
@@ -880,7 +945,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
/* update dspi pdata with that from the DT */
ret = spi_davinci_get_pdata(pdev, dspi);
if (ret < 0)
- goto free_master;
+ goto free_host;
}
/* pdata in dspi is now updated and point pdata to that */
@@ -892,57 +957,45 @@ static int davinci_spi_probe(struct platform_device *pdev)
GFP_KERNEL);
if (dspi->bytes_per_word == NULL) {
ret = -ENOMEM;
- goto free_master;
+ goto free_host;
}
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- ret = -ENOENT;
- goto free_master;
- }
-
- dspi->pbase = r->start;
-
- dspi->base = devm_ioremap_resource(&pdev->dev, r);
+ dspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(dspi->base)) {
ret = PTR_ERR(dspi->base);
- goto free_master;
+ goto free_host;
}
+ dspi->pbase = r->start;
init_completion(&dspi->done);
ret = platform_get_irq(pdev, 0);
- if (ret == 0)
- ret = -EINVAL;
if (ret < 0)
- goto free_master;
+ goto free_host;
dspi->irq = ret;
ret = devm_request_threaded_irq(&pdev->dev, dspi->irq, davinci_spi_irq,
dummy_thread_fn, 0, dev_name(&pdev->dev), dspi);
if (ret)
- goto free_master;
+ goto free_host;
- dspi->bitbang.master = master;
+ dspi->bitbang.ctlr = host;
- dspi->clk = devm_clk_get(&pdev->dev, NULL);
+ dspi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(dspi->clk)) {
ret = -ENODEV;
- goto free_master;
+ goto free_host;
}
- ret = clk_prepare_enable(dspi->clk);
- if (ret)
- goto free_master;
-
- master->use_gpio_descriptors = true;
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = pdev->id;
- master->num_chipselect = pdata->num_chipselect;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
- master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_GPIO_SS;
- master->setup = davinci_spi_setup;
- master->cleanup = davinci_spi_cleanup;
- master->can_dma = davinci_spi_can_dma;
+
+ host->use_gpio_descriptors = true;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = pdev->id;
+ host->num_chipselect = pdata->num_chipselect;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
+ host->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_GPIO_SS;
+ host->setup = davinci_spi_setup;
+ host->cleanup = davinci_spi_cleanup;
+ host->can_dma = davinci_spi_can_dma;
dspi->bitbang.chipselect = davinci_spi_chipselect;
dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
@@ -957,7 +1010,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
ret = davinci_spi_request_dma(dspi);
if (ret == -EPROBE_DEFER) {
- goto free_clk;
+ goto free_host;
} else if (ret) {
dev_info(&pdev->dev, "DMA is not supported (%d)\n", ret);
dspi->dma_rx = NULL;
@@ -983,7 +1036,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
iowrite32(CS_DEFAULT, dspi->base + SPIDEF);
- /* master mode default */
+ /* host mode default */
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK);
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
@@ -997,14 +1050,15 @@ static int davinci_spi_probe(struct platform_device *pdev)
return ret;
free_dma:
+ /* This bit needs to be cleared to disable dpsi->clk */
+ clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
+
if (dspi->dma_rx) {
dma_release_channel(dspi->dma_rx);
dma_release_channel(dspi->dma_tx);
}
-free_clk:
- clk_disable_unprepare(dspi->clk);
-free_master:
- spi_master_put(master);
+free_host:
+ spi_controller_put(host);
err:
return ret;
}
@@ -1021,21 +1075,22 @@ err:
static void davinci_spi_remove(struct platform_device *pdev)
{
struct davinci_spi *dspi;
- struct spi_master *master;
+ struct spi_controller *host;
- master = platform_get_drvdata(pdev);
- dspi = spi_master_get_devdata(master);
+ host = platform_get_drvdata(pdev);
+ dspi = spi_controller_get_devdata(host);
spi_bitbang_stop(&dspi->bitbang);
- clk_disable_unprepare(dspi->clk);
+ /* This bit needs to be cleared to disable dpsi->clk */
+ clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
if (dspi->dma_rx) {
dma_release_channel(dspi->dma_rx);
dma_release_channel(dspi->dma_tx);
}
- spi_master_put(master);
+ spi_controller_put(host);
}
static struct platform_driver davinci_spi_driver = {
@@ -1044,7 +1099,7 @@ static struct platform_driver davinci_spi_driver = {
.of_match_table = of_match_ptr(davinci_spi_of_match),
},
.probe = davinci_spi_probe,
- .remove_new = davinci_spi_remove,
+ .remove = davinci_spi_remove,
};
module_platform_driver(davinci_spi_driver);
diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c
index 6bd93c47853c..2013bc56ded8 100644
--- a/drivers/spi/spi-dln2.c
+++ b/drivers/spi/spi-dln2.c
@@ -12,7 +12,7 @@
#include <linux/mfd/dln2.h>
#include <linux/spi/spi.h>
#include <linux/pm_runtime.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define DLN2_SPI_MODULE_ID 0x02
#define DLN2_SPI_CMD(cmd) DLN2_CMD(cmd, DLN2_SPI_MODULE_ID)
@@ -79,7 +79,7 @@
struct dln2_spi {
struct platform_device *pdev;
- struct spi_master *master;
+ struct spi_controller *host;
u8 port;
/*
@@ -176,7 +176,7 @@ static int dln2_spi_cs_enable(struct dln2_spi *dln2, u8 cs_mask, bool enable)
static int dln2_spi_cs_enable_all(struct dln2_spi *dln2, bool enable)
{
- u8 cs_mask = GENMASK(dln2->master->num_chipselect - 1, 0);
+ u8 cs_mask = GENMASK(dln2->host->num_chipselect - 1, 0);
return dln2_spi_cs_enable(dln2, cs_mask, enable);
}
@@ -589,11 +589,11 @@ static int dln2_spi_rdwr(struct dln2_spi *dln2, const u8 *tx_data,
return 0;
}
-static int dln2_spi_prepare_message(struct spi_master *master,
+static int dln2_spi_prepare_message(struct spi_controller *host,
struct spi_message *message)
{
int ret;
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
struct spi_device *spi = message->spi;
if (dln2->cs != spi_get_chipselect(spi, 0)) {
@@ -650,11 +650,11 @@ static int dln2_spi_transfer_setup(struct dln2_spi *dln2, u32 speed,
return dln2_spi_enable(dln2, true);
}
-static int dln2_spi_transfer_one(struct spi_master *master,
+static int dln2_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
int status;
u8 attr = 0;
@@ -666,7 +666,7 @@ static int dln2_spi_transfer_one(struct spi_master *master,
return status;
}
- if (!xfer->cs_change && !spi_transfer_is_last(master, xfer))
+ if (!xfer->cs_change && !spi_transfer_is_last(host, xfer))
attr = DLN2_SPI_ATTR_LEAVE_SS_LOW;
status = dln2_spi_rdwr(dln2, xfer->tx_buf, xfer->rx_buf,
@@ -679,29 +679,29 @@ static int dln2_spi_transfer_one(struct spi_master *master,
static int dln2_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct dln2_spi *dln2;
struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*dln2));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*dln2));
+ if (!host)
return -ENOMEM;
- device_set_node(&master->dev, dev_fwnode(dev));
+ device_set_node(&host->dev, dev_fwnode(dev));
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- dln2 = spi_master_get_devdata(master);
+ dln2 = spi_controller_get_devdata(host);
dln2->buf = devm_kmalloc(&pdev->dev, DLN2_SPI_BUF_SIZE, GFP_KERNEL);
if (!dln2->buf) {
ret = -ENOMEM;
- goto exit_free_master;
+ goto exit_free_host;
}
- dln2->master = master;
+ dln2->host = host;
dln2->pdev = pdev;
dln2->port = pdata->port;
/* cs/mode can never be 0xff, so the first transfer will set them */
@@ -712,47 +712,47 @@ static int dln2_spi_probe(struct platform_device *pdev)
ret = dln2_spi_enable(dln2, false);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to disable SPI module\n");
- goto exit_free_master;
+ goto exit_free_host;
}
- ret = dln2_spi_get_cs_num(dln2, &master->num_chipselect);
+ ret = dln2_spi_get_cs_num(dln2, &host->num_chipselect);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to get number of CS pins\n");
- goto exit_free_master;
+ goto exit_free_host;
}
ret = dln2_spi_get_speed_range(dln2,
- &master->min_speed_hz,
- &master->max_speed_hz);
+ &host->min_speed_hz,
+ &host->max_speed_hz);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to read bus min/max freqs\n");
- goto exit_free_master;
+ goto exit_free_host;
}
ret = dln2_spi_get_supported_frame_sizes(dln2,
- &master->bits_per_word_mask);
+ &host->bits_per_word_mask);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to read supported frame sizes\n");
- goto exit_free_master;
+ goto exit_free_host;
}
ret = dln2_spi_cs_enable_all(dln2, true);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable CS pins\n");
- goto exit_free_master;
+ goto exit_free_host;
}
- master->bus_num = -1;
- master->mode_bits = SPI_CPOL | SPI_CPHA;
- master->prepare_message = dln2_spi_prepare_message;
- master->transfer_one = dln2_spi_transfer_one;
- master->auto_runtime_pm = true;
+ host->bus_num = -1;
+ host->mode_bits = SPI_CPOL | SPI_CPHA;
+ host->prepare_message = dln2_spi_prepare_message;
+ host->transfer_one = dln2_spi_transfer_one;
+ host->auto_runtime_pm = true;
/* enable SPI module, we're good to go */
ret = dln2_spi_enable(dln2, true);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable SPI module\n");
- goto exit_free_master;
+ goto exit_free_host;
}
pm_runtime_set_autosuspend_delay(&pdev->dev,
@@ -761,9 +761,9 @@ static int dln2_spi_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register master\n");
+ dev_err(&pdev->dev, "Failed to register host\n");
goto exit_register;
}
@@ -775,16 +775,16 @@ exit_register:
if (dln2_spi_enable(dln2, false) < 0)
dev_err(&pdev->dev, "Failed to disable SPI module\n");
-exit_free_master:
- spi_master_put(master);
+exit_free_host:
+ spi_controller_put(host);
return ret;
}
static void dln2_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
pm_runtime_disable(&pdev->dev);
@@ -796,10 +796,10 @@ static void dln2_spi_remove(struct platform_device *pdev)
static int dln2_spi_suspend(struct device *dev)
{
int ret;
- struct spi_master *master = dev_get_drvdata(dev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret < 0)
return ret;
@@ -824,8 +824,8 @@ static int dln2_spi_suspend(struct device *dev)
static int dln2_spi_resume(struct device *dev)
{
int ret;
- struct spi_master *master = dev_get_drvdata(dev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
if (!pm_runtime_suspended(dev)) {
ret = dln2_spi_cs_enable_all(dln2, true);
@@ -837,23 +837,23 @@ static int dln2_spi_resume(struct device *dev)
return ret;
}
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int dln2_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
return dln2_spi_enable(dln2, false);
}
static int dln2_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_controller_get_devdata(host);
return dln2_spi_enable(dln2, true);
}
@@ -871,11 +871,11 @@ static struct platform_driver spi_dln2_driver = {
.pm = &dln2_spi_pm,
},
.probe = dln2_spi_probe,
- .remove_new = dln2_spi_remove,
+ .remove = dln2_spi_remove,
};
module_platform_driver(spi_dln2_driver);
-MODULE_DESCRIPTION("Driver for the Diolan DLN2 SPI master interface");
+MODULE_DESCRIPTION("Driver for the Diolan DLN2 SPI host interface");
MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:dln2-spi");
diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c
index 5e1c01822967..91642e05ac60 100644
--- a/drivers/spi/spi-dw-bt1.c
+++ b/drivers/spi/spi-dw-bt1.c
@@ -55,13 +55,15 @@ static int dw_spi_bt1_dirmap_create(struct spi_mem_dirmap_desc *desc)
!dwsbt1->dws.mem_ops.supports_op(desc->mem, &desc->info.op_tmpl))
return -EOPNOTSUPP;
+ if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
+ return -EOPNOTSUPP;
+
/*
* Make sure the requested region doesn't go out of the physically
- * mapped flash memory bounds and the operation is read-only.
+ * mapped flash memory bounds.
*/
- if (desc->info.offset + desc->info.length > dwsbt1->map_len ||
- desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
- return -EOPNOTSUPP;
+ if (desc->info.offset + desc->info.length > dwsbt1->map_len)
+ return -EINVAL;
return 0;
}
@@ -269,54 +271,41 @@ static int dw_spi_bt1_probe(struct platform_device *pdev)
dws->paddr = mem->start;
- dwsbt1->clk = devm_clk_get(&pdev->dev, NULL);
+ dwsbt1->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(dwsbt1->clk))
return PTR_ERR(dwsbt1->clk);
- ret = clk_prepare_enable(dwsbt1->clk);
- if (ret)
- return ret;
-
dws->bus_num = pdev->id;
dws->reg_io_width = 4;
dws->max_freq = clk_get_rate(dwsbt1->clk);
- if (!dws->max_freq) {
- ret = -EINVAL;
- goto err_disable_clk;
- }
+ if (!dws->max_freq)
+ return -EINVAL;
init_func = device_get_match_data(&pdev->dev);
ret = init_func(pdev, dwsbt1);
if (ret)
- goto err_disable_clk;
+ return ret;
pm_runtime_enable(&pdev->dev);
- ret = dw_spi_add_host(&pdev->dev, dws);
+ ret = dw_spi_add_controller(&pdev->dev, dws);
if (ret) {
pm_runtime_disable(&pdev->dev);
- goto err_disable_clk;
+ return ret;
}
platform_set_drvdata(pdev, dwsbt1);
return 0;
-
-err_disable_clk:
- clk_disable_unprepare(dwsbt1->clk);
-
- return ret;
}
static void dw_spi_bt1_remove(struct platform_device *pdev)
{
struct dw_spi_bt1 *dwsbt1 = platform_get_drvdata(pdev);
- dw_spi_remove_host(&dwsbt1->dws);
+ dw_spi_remove_controller(&dwsbt1->dws);
pm_runtime_disable(&pdev->dev);
-
- clk_disable_unprepare(dwsbt1->clk);
}
static const struct of_device_id dw_spi_bt1_of_match[] = {
@@ -328,7 +317,7 @@ MODULE_DEVICE_TABLE(of, dw_spi_bt1_of_match);
static struct platform_driver dw_spi_bt1_driver = {
.probe = dw_spi_bt1_probe,
- .remove_new = dw_spi_bt1_remove,
+ .remove = dw_spi_bt1_remove,
.driver = {
.name = "bt1-sys-ssi",
.of_match_table = dw_spi_bt1_of_match,
@@ -339,4 +328,4 @@ module_platform_driver(dw_spi_bt1_driver);
MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SPI_DW_CORE);
+MODULE_IMPORT_NS("SPI_DW_CORE");
diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index a8ba41ad4541..9ebf244294f8 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -6,6 +6,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/bitops.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -18,6 +19,7 @@
#include <linux/string.h>
#include <linux/of.h>
+#include "internals.h"
#include "spi-dw.h"
#ifdef CONFIG_DEBUG_FS
@@ -61,7 +63,7 @@ static void dw_spi_debugfs_init(struct dw_spi *dws)
{
char name[32];
- snprintf(name, 32, "dw_spi%d", dws->master->bus_num);
+ snprintf(name, 32, "dw_spi%d", dws->ctlr->bus_num);
dws->debugfs = debugfs_create_dir(name, NULL);
dws->regset.regs = dw_spi_dbgfs_regs;
@@ -102,7 +104,7 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
else
dw_writel(dws, DW_SPI_SER, 0);
}
-EXPORT_SYMBOL_NS_GPL(dw_spi_set_cs, SPI_DW_CORE);
+EXPORT_SYMBOL_NS_GPL(dw_spi_set_cs, "SPI_DW_CORE");
/* Return the max entries we can fill into tx fifo */
static inline u32 dw_spi_tx_max(struct dw_spi *dws)
@@ -183,37 +185,37 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw)
irq_status = dw_readl(dws, DW_SPI_ISR);
if (irq_status & DW_SPI_INT_RXOI) {
- dev_err(&dws->master->dev, "RX FIFO overflow detected\n");
+ dev_err(&dws->ctlr->dev, "RX FIFO overflow detected\n");
ret = -EIO;
}
if (irq_status & DW_SPI_INT_RXUI) {
- dev_err(&dws->master->dev, "RX FIFO underflow detected\n");
+ dev_err(&dws->ctlr->dev, "RX FIFO underflow detected\n");
ret = -EIO;
}
if (irq_status & DW_SPI_INT_TXOI) {
- dev_err(&dws->master->dev, "TX FIFO overflow detected\n");
+ dev_err(&dws->ctlr->dev, "TX FIFO overflow detected\n");
ret = -EIO;
}
/* Generically handle the erroneous situation */
if (ret) {
dw_spi_reset_chip(dws);
- if (dws->master->cur_msg)
- dws->master->cur_msg->status = ret;
+ if (dws->ctlr->cur_msg)
+ dws->ctlr->cur_msg->status = ret;
}
return ret;
}
-EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, SPI_DW_CORE);
+EXPORT_SYMBOL_NS_GPL(dw_spi_check_status, "SPI_DW_CORE");
static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
{
u16 irq_status = dw_readl(dws, DW_SPI_ISR);
if (dw_spi_check_status(dws, false)) {
- spi_finalize_current_transfer(dws->master);
+ spi_finalize_current_transfer(dws->ctlr);
return IRQ_HANDLED;
}
@@ -227,7 +229,7 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
dw_reader(dws);
if (!dws->rx_len) {
dw_spi_mask_intr(dws, 0xff);
- spi_finalize_current_transfer(dws->master);
+ spi_finalize_current_transfer(dws->ctlr);
} else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
}
@@ -248,14 +250,14 @@ static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
static irqreturn_t dw_spi_irq(int irq, void *dev_id)
{
- struct spi_controller *master = dev_id;
- struct dw_spi *dws = spi_controller_get_devdata(master);
+ struct spi_controller *ctlr = dev_id;
+ struct dw_spi *dws = spi_controller_get_devdata(ctlr);
u16 irq_status = dw_readl(dws, DW_SPI_ISR) & DW_SPI_INT_MASK;
if (!irq_status)
return IRQ_NONE;
- if (!master->cur_msg) {
+ if (!ctlr->cur_msg) {
dw_spi_mask_intr(dws, 0xff);
return IRQ_HANDLED;
}
@@ -330,6 +332,9 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
dw_writel(dws, DW_SPI_CTRLR0, cr0);
+ if (spi_controller_is_target(dws->ctlr))
+ return;
+
if (cfg->tmode == DW_SPI_CTRLR0_TMOD_EPROMREAD ||
cfg->tmode == DW_SPI_CTRLR0_TMOD_RO)
dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
@@ -349,7 +354,7 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
dws->cur_rx_sample_dly = chip->rx_sample_dly;
}
}
-EXPORT_SYMBOL_NS_GPL(dw_spi_update_config, SPI_DW_CORE);
+EXPORT_SYMBOL_NS_GPL(dw_spi_update_config, "SPI_DW_CORE");
static void dw_spi_irq_setup(struct dw_spi *dws)
{
@@ -408,11 +413,11 @@ static int dw_spi_poll_transfer(struct dw_spi *dws,
return 0;
}
-static int dw_spi_transfer_one(struct spi_controller *master,
+static int dw_spi_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *transfer)
{
- struct dw_spi *dws = spi_controller_get_devdata(master);
+ struct dw_spi *dws = spi_controller_get_devdata(ctlr);
struct dw_spi_cfg cfg = {
.tmode = DW_SPI_CTRLR0_TMOD_TR,
.dfs = transfer->bits_per_word,
@@ -421,10 +426,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
int ret;
dws->dma_mapped = 0;
- dws->n_bytes =
- roundup_pow_of_two(DIV_ROUND_UP(transfer->bits_per_word,
- BITS_PER_BYTE));
-
+ dws->n_bytes = spi_bpw_to_bytes(transfer->bits_per_word);
dws->tx = (void *)transfer->tx_buf;
dws->tx_len = transfer->len / dws->n_bytes;
dws->rx = transfer->rx_buf;
@@ -440,8 +442,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
transfer->effective_speed_hz = dws->current_freq;
/* Check if current transfer is a DMA transaction */
- if (master->can_dma && master->can_dma(master, spi, transfer))
- dws->dma_mapped = master->cur_msg_mapped;
+ dws->dma_mapped = spi_xfer_is_dma_mapped(ctlr, spi, transfer);
/* For poll mode just disable all interrupts */
dw_spi_mask_intr(dws, 0xff);
@@ -464,10 +465,9 @@ static int dw_spi_transfer_one(struct spi_controller *master,
return 1;
}
-static void dw_spi_handle_err(struct spi_controller *master,
- struct spi_message *msg)
+static inline void dw_spi_abort(struct spi_controller *ctlr)
{
- struct dw_spi *dws = spi_controller_get_devdata(master);
+ struct dw_spi *dws = spi_controller_get_devdata(ctlr);
if (dws->dma_mapped)
dws->dma_ops->dma_stop(dws);
@@ -475,6 +475,19 @@ static void dw_spi_handle_err(struct spi_controller *master,
dw_spi_reset_chip(dws);
}
+static void dw_spi_handle_err(struct spi_controller *ctlr,
+ struct spi_message *msg)
+{
+ dw_spi_abort(ctlr);
+}
+
+static int dw_spi_target_abort(struct spi_controller *ctlr)
+{
+ dw_spi_abort(ctlr);
+
+ return 0;
+}
+
static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
if (op->data.dir == SPI_MEM_DATA_IN)
@@ -576,7 +589,7 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
while (len) {
entries = readl_relaxed(dws->regs + DW_SPI_TXFLR);
if (!entries) {
- dev_err(&dws->master->dev, "CS de-assertion on Tx\n");
+ dev_err(&dws->ctlr->dev, "CS de-assertion on Tx\n");
return -EIO;
}
room = min(dws->fifo_len - entries, len);
@@ -596,7 +609,7 @@ static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
if (!entries) {
sts = readl_relaxed(dws->regs + DW_SPI_RISR);
if (sts & DW_SPI_INT_RXOI) {
- dev_err(&dws->master->dev, "FIFO overflow on Rx\n");
+ dev_err(&dws->ctlr->dev, "FIFO overflow on Rx\n");
return -EIO;
}
continue;
@@ -637,7 +650,7 @@ static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
spi_delay_exec(&delay, NULL);
if (retry < 0) {
- dev_err(&dws->master->dev, "Mem op hanged up\n");
+ dev_err(&dws->ctlr->dev, "Mem op hanged up\n");
return -EIO;
}
@@ -679,7 +692,7 @@ static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
* operation. Transmit-only mode is suitable for the rest of them.
*/
cfg.dfs = 8;
- cfg.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq);
+ cfg.freq = clamp(op->max_freq, 0U, dws->max_mem_freq);
if (op->data.dir == SPI_MEM_DATA_IN) {
cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD;
cfg.ndf = op->data.nbytes;
@@ -836,6 +849,25 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
DW_SPI_GET_BYTE(dws->ver, 1));
}
+ if (spi_controller_is_target(dws->ctlr)) {
+ /* There is only one CS input signal in target mode */
+ dws->num_cs = 1;
+ } else {
+ /*
+ * Try to detect the number of native chip-selects if the platform
+ * driver didn't set it up. There can be up to 16 lines configured.
+ */
+ if (!dws->num_cs) {
+ u32 ser;
+
+ dw_writel(dws, DW_SPI_SER, 0xffff);
+ ser = dw_readl(dws, DW_SPI_SER);
+ dw_writel(dws, DW_SPI_SER, 0);
+
+ dws->num_cs = hweight16(ser);
+ }
+ }
+
/*
* Try to detect the FIFO depth if not set by interface driver,
* the depth could be from 2 to 256 from HW spec
@@ -882,58 +914,76 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF);
}
-int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
+static const struct spi_controller_mem_caps dw_spi_mem_caps = {
+ .per_op_freq = true,
+};
+
+int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
{
- struct spi_controller *master;
+ struct spi_controller *ctlr;
+ bool target;
int ret;
if (!dws)
return -EINVAL;
- master = spi_alloc_master(dev, 0);
- if (!master)
+ target = device_property_read_bool(dev, "spi-slave");
+ if (target)
+ ctlr = spi_alloc_target(dev, 0);
+ else
+ ctlr = spi_alloc_host(dev, 0);
+
+ if (!ctlr)
return -ENOMEM;
- device_set_node(&master->dev, dev_fwnode(dev));
+ device_set_node(&ctlr->dev, dev_fwnode(dev));
- dws->master = master;
+ dws->ctlr = ctlr;
dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
- spi_controller_set_devdata(master, dws);
+ spi_controller_set_devdata(ctlr, dws);
/* Basic HW init */
dw_spi_hw_init(dev, dws);
ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
- master);
+ ctlr);
if (ret < 0 && ret != -ENOTCONN) {
dev_err(dev, "can not get IRQ\n");
- goto err_free_master;
+ goto err_free_ctlr;
}
dw_spi_init_mem_ops(dws);
- master->use_gpio_descriptors = true;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
+ ctlr->mode_bits = SPI_CPOL | SPI_CPHA;
if (dws->caps & DW_SPI_CAP_DFS32)
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
- else
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
- master->bus_num = dws->bus_num;
- master->num_chipselect = dws->num_cs;
- master->setup = dw_spi_setup;
- master->cleanup = dw_spi_cleanup;
- if (dws->set_cs)
- master->set_cs = dws->set_cs;
+ ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
else
- master->set_cs = dw_spi_set_cs;
- master->transfer_one = dw_spi_transfer_one;
- master->handle_err = dw_spi_handle_err;
- if (dws->mem_ops.exec_op)
- master->mem_ops = &dws->mem_ops;
- master->max_speed_hz = dws->max_freq;
- master->flags = SPI_MASTER_GPIO_SS;
- master->auto_runtime_pm = true;
+ ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+ ctlr->bus_num = dws->bus_num;
+ ctlr->num_chipselect = dws->num_cs;
+ ctlr->setup = dw_spi_setup;
+ ctlr->cleanup = dw_spi_cleanup;
+ ctlr->transfer_one = dw_spi_transfer_one;
+ ctlr->handle_err = dw_spi_handle_err;
+ ctlr->auto_runtime_pm = true;
+
+ if (!target) {
+ ctlr->use_gpio_descriptors = true;
+ ctlr->mode_bits |= SPI_LOOP;
+ if (dws->set_cs)
+ ctlr->set_cs = dws->set_cs;
+ else
+ ctlr->set_cs = dw_spi_set_cs;
+ if (dws->mem_ops.exec_op) {
+ ctlr->mem_ops = &dws->mem_ops;
+ ctlr->mem_caps = &dw_spi_mem_caps;
+ }
+ ctlr->max_speed_hz = dws->max_freq;
+ ctlr->flags = SPI_CONTROLLER_GPIO_SS;
+ } else {
+ ctlr->target_abort = dw_spi_target_abort;
+ }
/* Get default rx sample delay */
device_property_read_u32(dev, "rx-sample-delay-ns",
@@ -946,14 +996,14 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
} else if (ret) {
dev_warn(dev, "DMA init failed\n");
} else {
- master->can_dma = dws->dma_ops->can_dma;
- master->flags |= SPI_CONTROLLER_MUST_TX;
+ ctlr->can_dma = dws->dma_ops->can_dma;
+ ctlr->flags |= SPI_CONTROLLER_MUST_TX;
}
}
- ret = spi_register_controller(master);
+ ret = spi_register_controller(ctlr);
if (ret) {
- dev_err_probe(dev, ret, "problem registering spi master\n");
+ dev_err_probe(dev, ret, "problem registering spi controller\n");
goto err_dma_exit;
}
@@ -965,47 +1015,47 @@ err_dma_exit:
dws->dma_ops->dma_exit(dws);
dw_spi_enable_chip(dws, 0);
err_free_irq:
- free_irq(dws->irq, master);
-err_free_master:
- spi_controller_put(master);
+ free_irq(dws->irq, ctlr);
+err_free_ctlr:
+ spi_controller_put(ctlr);
return ret;
}
-EXPORT_SYMBOL_NS_GPL(dw_spi_add_host, SPI_DW_CORE);
+EXPORT_SYMBOL_NS_GPL(dw_spi_add_controller, "SPI_DW_CORE");
-void dw_spi_remove_host(struct dw_spi *dws)
+void dw_spi_remove_controller(struct dw_spi *dws)
{
dw_spi_debugfs_remove(dws);
- spi_unregister_controller(dws->master);
+ spi_unregister_controller(dws->ctlr);
if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws);
dw_spi_shutdown_chip(dws);
- free_irq(dws->irq, dws->master);
+ free_irq(dws->irq, dws->ctlr);
}
-EXPORT_SYMBOL_NS_GPL(dw_spi_remove_host, SPI_DW_CORE);
+EXPORT_SYMBOL_NS_GPL(dw_spi_remove_controller, "SPI_DW_CORE");
-int dw_spi_suspend_host(struct dw_spi *dws)
+int dw_spi_suspend_controller(struct dw_spi *dws)
{
int ret;
- ret = spi_controller_suspend(dws->master);
+ ret = spi_controller_suspend(dws->ctlr);
if (ret)
return ret;
dw_spi_shutdown_chip(dws);
return 0;
}
-EXPORT_SYMBOL_NS_GPL(dw_spi_suspend_host, SPI_DW_CORE);
+EXPORT_SYMBOL_NS_GPL(dw_spi_suspend_controller, "SPI_DW_CORE");
-int dw_spi_resume_host(struct dw_spi *dws)
+int dw_spi_resume_controller(struct dw_spi *dws)
{
- dw_spi_hw_init(&dws->master->dev, dws);
- return spi_controller_resume(dws->master);
+ dw_spi_hw_init(&dws->ctlr->dev, dws);
+ return spi_controller_resume(dws->ctlr);
}
-EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, SPI_DW_CORE);
+EXPORT_SYMBOL_NS_GPL(dw_spi_resume_controller, "SPI_DW_CORE");
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index df819652901a..65adec7c7524 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -139,8 +139,8 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
if (!dws->txchan)
goto free_rxchan;
- dws->master->dma_rx = dws->rxchan;
- dws->master->dma_tx = dws->txchan;
+ dws->ctlr->dma_rx = dws->rxchan;
+ dws->ctlr->dma_tx = dws->txchan;
init_completion(&dws->dma_completion);
@@ -183,8 +183,8 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
goto free_rxchan;
}
- dws->master->dma_rx = dws->rxchan;
- dws->master->dma_tx = dws->txchan;
+ dws->ctlr->dma_rx = dws->rxchan;
+ dws->ctlr->dma_tx = dws->txchan;
init_completion(&dws->dma_completion);
@@ -242,10 +242,10 @@ static enum dma_slave_buswidth dw_spi_dma_convert_width(u8 n_bytes)
}
}
-static bool dw_spi_can_dma(struct spi_controller *master,
+static bool dw_spi_can_dma(struct spi_controller *ctlr,
struct spi_device *spi, struct spi_transfer *xfer)
{
- struct dw_spi *dws = spi_controller_get_devdata(master);
+ struct dw_spi *dws = spi_controller_get_devdata(ctlr);
enum dma_slave_buswidth dma_bus_width;
if (xfer->len <= dws->fifo_len)
@@ -271,7 +271,7 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
msecs_to_jiffies(ms));
if (ms == 0) {
- dev_err(&dws->master->cur_msg->spi->dev,
+ dev_err(&dws->ctlr->cur_msg->spi->dev,
"DMA transaction timed out\n");
return -ETIMEDOUT;
}
@@ -299,7 +299,7 @@ static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
spi_delay_exec(&delay, xfer);
if (retry < 0) {
- dev_err(&dws->master->dev, "Tx hanged up\n");
+ dev_err(&dws->ctlr->dev, "Tx hanged up\n");
return -EIO;
}
@@ -400,7 +400,7 @@ static int dw_spi_dma_wait_rx_done(struct dw_spi *dws)
spi_delay_exec(&delay, NULL);
if (retry < 0) {
- dev_err(&dws->master->dev, "Rx hanged up\n");
+ dev_err(&dws->ctlr->dev, "Rx hanged up\n");
return -EIO;
}
@@ -577,7 +577,7 @@ static int dw_spi_dma_transfer_one(struct dw_spi *dws,
sg_init_table(&tx_tmp, 1);
sg_init_table(&rx_tmp, 1);
- for (base = 0, len = 0; base < xfer->len; base += len) {
+ for (base = 0; base < xfer->len; base += len) {
/* Fetch next Tx DMA data chunk */
if (!tx_len) {
tx_sg = !tx_sg ? &xfer->tx_sg.sgl[0] : sg_next(tx_sg);
@@ -656,13 +656,13 @@ static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
if (ret)
return ret;
- if (dws->master->cur_msg->status == -EINPROGRESS) {
+ if (dws->ctlr->cur_msg->status == -EINPROGRESS) {
ret = dw_spi_dma_wait_tx_done(dws, xfer);
if (ret)
return ret;
}
- if (xfer->rx_buf && dws->master->cur_msg->status == -EINPROGRESS)
+ if (xfer->rx_buf && dws->ctlr->cur_msg->status == -EINPROGRESS)
ret = dw_spi_dma_wait_rx_done(dws);
return ret;
@@ -693,7 +693,7 @@ void dw_spi_dma_setup_mfld(struct dw_spi *dws)
{
dws->dma_ops = &dw_spi_dma_mfld_ops;
}
-EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_mfld, SPI_DW_CORE);
+EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_mfld, "SPI_DW_CORE");
static const struct dw_spi_dma_ops dw_spi_dma_generic_ops = {
.dma_init = dw_spi_dma_init_generic,
@@ -708,4 +708,4 @@ void dw_spi_dma_setup_generic(struct dw_spi *dws)
{
dws->dma_ops = &dw_spi_dma_generic_ops;
}
-EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_generic, SPI_DW_CORE);
+EXPORT_SYMBOL_NS_GPL(dw_spi_dma_setup_generic, "SPI_DW_CORE");
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index a963bc96c223..33239b4778cb 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -76,7 +76,7 @@ struct dw_spi_mscc {
*/
static void dw_spi_mscc_set_cs(struct spi_device *spi, bool enable)
{
- struct dw_spi *dws = spi_master_get_devdata(spi->master);
+ struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
u32 cs = spi_get_chipselect(spi, 0);
@@ -149,7 +149,7 @@ static int dw_spi_mscc_jaguar2_init(struct platform_device *pdev,
*/
static void dw_spi_sparx5_set_cs(struct spi_device *spi, bool enable)
{
- struct dw_spi *dws = spi_master_get_devdata(spi->master);
+ struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
struct dw_spi_mscc *dwsmscc = dwsmmio->priv;
u8 cs = spi_get_chipselect(spi, 0);
@@ -277,7 +277,7 @@ static void dw_spi_elba_override_cs(struct regmap *syscon, int cs, int enable)
static void dw_spi_elba_set_cs(struct spi_device *spi, bool enable)
{
- struct dw_spi *dws = spi_master_get_devdata(spi->master);
+ struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct dw_spi_mmio *dwsmmio = container_of(dws, struct dw_spi_mmio, dws);
struct regmap *syscon = dwsmmio->priv;
u8 cs;
@@ -320,7 +320,6 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
struct resource *mem;
struct dw_spi *dws;
int ret;
- int num_cs;
dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio),
GFP_KERNEL);
@@ -340,53 +339,45 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
if (dws->irq < 0)
return dws->irq; /* -ENXIO */
- dwsmmio->clk = devm_clk_get(&pdev->dev, NULL);
+ dwsmmio->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(dwsmmio->clk))
return PTR_ERR(dwsmmio->clk);
- ret = clk_prepare_enable(dwsmmio->clk);
- if (ret)
- return ret;
/* Optional clock needed to access the registers */
- dwsmmio->pclk = devm_clk_get_optional(&pdev->dev, "pclk");
- if (IS_ERR(dwsmmio->pclk)) {
- ret = PTR_ERR(dwsmmio->pclk);
- goto out_clk;
- }
- ret = clk_prepare_enable(dwsmmio->pclk);
- if (ret)
- goto out_clk;
+ dwsmmio->pclk = devm_clk_get_optional_enabled(&pdev->dev, "pclk");
+ if (IS_ERR(dwsmmio->pclk))
+ return PTR_ERR(dwsmmio->pclk);
/* find an optional reset controller */
dwsmmio->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, "spi");
- if (IS_ERR(dwsmmio->rstc)) {
- ret = PTR_ERR(dwsmmio->rstc);
- goto out_clk;
- }
- reset_control_deassert(dwsmmio->rstc);
+ if (IS_ERR(dwsmmio->rstc))
+ return PTR_ERR(dwsmmio->rstc);
+
+ ret = reset_control_deassert(dwsmmio->rstc);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to deassert resets\n");
dws->bus_num = pdev->id;
dws->max_freq = clk_get_rate(dwsmmio->clk);
- device_property_read_u32(&pdev->dev, "reg-io-width", &dws->reg_io_width);
-
- num_cs = 4;
-
- device_property_read_u32(&pdev->dev, "num-cs", &num_cs);
+ if (device_property_read_u32(&pdev->dev, "reg-io-width",
+ &dws->reg_io_width))
+ dws->reg_io_width = 4;
- dws->num_cs = num_cs;
+ /* Rely on the auto-detection if no property specified */
+ device_property_read_u32(&pdev->dev, "num-cs", &dws->num_cs);
init_func = device_get_match_data(&pdev->dev);
if (init_func) {
ret = init_func(pdev, dwsmmio);
if (ret)
- goto out;
+ goto out_reset;
}
pm_runtime_enable(&pdev->dev);
- ret = dw_spi_add_host(&pdev->dev, dws);
+ ret = dw_spi_add_controller(&pdev->dev, dws);
if (ret)
goto out;
@@ -395,9 +386,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
out:
pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(dwsmmio->pclk);
-out_clk:
- clk_disable_unprepare(dwsmmio->clk);
+out_reset:
reset_control_assert(dwsmmio->rstc);
return ret;
@@ -407,10 +396,8 @@ static void dw_spi_mmio_remove(struct platform_device *pdev)
{
struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
- dw_spi_remove_host(&dwsmmio->dws);
+ dw_spi_remove_controller(&dwsmmio->dws);
pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(dwsmmio->pclk);
- clk_disable_unprepare(dwsmmio->clk);
reset_control_assert(dwsmmio->rstc);
}
@@ -422,7 +409,6 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init},
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
{ .compatible = "intel,keembay-ssi", .data = dw_spi_intel_init},
- { .compatible = "intel,thunderbay-ssi", .data = dw_spi_intel_init},
{
.compatible = "intel,mountevans-imc-ssi",
.data = dw_spi_mountevans_imc_init,
@@ -444,7 +430,7 @@ MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match);
static struct platform_driver dw_spi_mmio_driver = {
.probe = dw_spi_mmio_probe,
- .remove_new = dw_spi_mmio_remove,
+ .remove = dw_spi_mmio_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = dw_spi_mmio_of_match,
@@ -456,4 +442,4 @@ module_platform_driver(dw_spi_mmio_driver);
MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SPI_DW_CORE);
+MODULE_IMPORT_NS("SPI_DW_CORE");
diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c
index 7c8279d13f31..72d9f5bc87f7 100644
--- a/drivers/spi/spi-dw-pci.c
+++ b/drivers/spi/spi-dw-pci.c
@@ -98,15 +98,14 @@ static int dw_spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *en
dws->paddr = pci_resource_start(pdev, pci_bar);
pci_set_master(pdev);
- ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev));
- if (ret)
- return ret;
-
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
if (ret < 0)
return ret;
- dws->regs = pcim_iomap_table(pdev)[pci_bar];
+ dws->regs = pcim_iomap_region(pdev, pci_bar, pci_name(pdev));
+ if (IS_ERR(dws->regs))
+ return PTR_ERR(dws->regs);
+
dws->irq = pci_irq_vector(pdev, 0);
/*
@@ -128,7 +127,7 @@ static int dw_spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *en
goto err_free_irq_vectors;
}
- ret = dw_spi_add_host(&pdev->dev, dws);
+ ret = dw_spi_add_controller(&pdev->dev, dws);
if (ret)
goto err_free_irq_vectors;
@@ -157,7 +156,7 @@ static void dw_spi_pci_remove(struct pci_dev *pdev)
pm_runtime_forbid(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
- dw_spi_remove_host(dws);
+ dw_spi_remove_controller(dws);
pci_free_irq_vectors(pdev);
}
@@ -166,14 +165,14 @@ static int dw_spi_pci_suspend(struct device *dev)
{
struct dw_spi *dws = dev_get_drvdata(dev);
- return dw_spi_suspend_host(dws);
+ return dw_spi_suspend_controller(dws);
}
static int dw_spi_pci_resume(struct device *dev)
{
struct dw_spi *dws = dev_get_drvdata(dev);
- return dw_spi_resume_host(dws);
+ return dw_spi_resume_controller(dws);
}
#endif
@@ -212,4 +211,4 @@ module_pci_driver(dw_spi_pci_driver);
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
MODULE_LICENSE("GPL v2");
-MODULE_IMPORT_NS(SPI_DW_CORE);
+MODULE_IMPORT_NS("SPI_DW_CORE");
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 3962e6dcf880..9cc79c566a70 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -142,14 +142,14 @@ struct dw_spi_dma_ops {
int (*dma_init)(struct device *dev, struct dw_spi *dws);
void (*dma_exit)(struct dw_spi *dws);
int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer);
- bool (*can_dma)(struct spi_controller *master, struct spi_device *spi,
+ bool (*can_dma)(struct spi_controller *ctlr, struct spi_device *spi,
struct spi_transfer *xfer);
int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer);
void (*dma_stop)(struct dw_spi *dws);
};
struct dw_spi {
- struct spi_controller *master;
+ struct spi_controller *ctlr;
u32 ip; /* Synopsys DW SSI IP-core ID */
u32 ver; /* Synopsys component version */
@@ -164,8 +164,8 @@ struct dw_spi {
u32 max_freq; /* max bus freq supported */
u32 reg_io_width; /* DR I/O width in bytes */
+ u32 num_cs; /* chip select lines */
u16 bus_num;
- u16 num_cs; /* supported slave numbers */
void (*set_cs)(struct spi_device *spi, bool enable);
/* Current message transfer state info */
@@ -288,10 +288,10 @@ extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
extern void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
struct dw_spi_cfg *cfg);
extern int dw_spi_check_status(struct dw_spi *dws, bool raw);
-extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
-extern void dw_spi_remove_host(struct dw_spi *dws);
-extern int dw_spi_suspend_host(struct dw_spi *dws);
-extern int dw_spi_resume_host(struct dw_spi *dws);
+extern int dw_spi_add_controller(struct device *dev, struct dw_spi *dws);
+extern void dw_spi_remove_controller(struct dw_spi *dws);
+extern int dw_spi_suspend_controller(struct dw_spi *dws);
+extern int dw_spi_resume_controller(struct dw_spi *dws);
#ifdef CONFIG_SPI_DW_DMA
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index 1615fd22f9a2..e1d097091925 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -18,18 +18,18 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/property.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/scatterlist.h>
#include <linux/spi/spi.h>
-#include <linux/platform_data/dma-ep93xx.h>
-#include <linux/platform_data/spi-ep93xx.h>
-
#define SSPCR0 0x0000
#define SSPCR0_SPO BIT(6)
#define SSPCR0_SPH BIT(7)
@@ -76,8 +76,6 @@
* frame decreases this level and sending one frame increases it.
* @dma_rx: RX DMA channel
* @dma_tx: TX DMA channel
- * @dma_rx_data: RX parameters passed to the DMA engine
- * @dma_tx_data: TX parameters passed to the DMA engine
* @rx_sgt: sg table for RX transfers
* @tx_sgt: sg table for TX transfers
* @zeropage: dummy page used as RX buffer when only TX buffer is passed in by
@@ -92,8 +90,6 @@ struct ep93xx_spi {
size_t fifo_level;
struct dma_chan *dma_rx;
struct dma_chan *dma_tx;
- struct ep93xx_dma_data dma_rx_data;
- struct ep93xx_dma_data dma_tx_data;
struct sg_table rx_sgt;
struct sg_table tx_sgt;
void *zeropage;
@@ -104,15 +100,15 @@ struct ep93xx_spi {
/**
* ep93xx_spi_calc_divisors() - calculates SPI clock divisors
- * @master: SPI master
+ * @host: SPI host
* @rate: desired SPI output clock rate
* @div_cpsr: pointer to return the cpsr (pre-scaler) divider
* @div_scr: pointer to return the scr divider
*/
-static int ep93xx_spi_calc_divisors(struct spi_master *master,
+static int ep93xx_spi_calc_divisors(struct spi_controller *host,
u32 rate, u8 *div_cpsr, u8 *div_scr)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
int cpsr, scr;
@@ -120,7 +116,7 @@ static int ep93xx_spi_calc_divisors(struct spi_master *master,
* Make sure that max value is between values supported by the
* controller.
*/
- rate = clamp(rate, master->min_speed_hz, master->max_speed_hz);
+ rate = clamp(rate, host->min_speed_hz, host->max_speed_hz);
/*
* Calculate divisors so that we can get speed according the
@@ -143,18 +139,18 @@ static int ep93xx_spi_calc_divisors(struct spi_master *master,
return -EINVAL;
}
-static int ep93xx_spi_chip_setup(struct spi_master *master,
+static int ep93xx_spi_chip_setup(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u8 dss = bits_per_word_to_dss(xfer->bits_per_word);
u8 div_cpsr = 0;
u8 div_scr = 0;
u16 cr0;
int err;
- err = ep93xx_spi_calc_divisors(master, xfer->speed_hz,
+ err = ep93xx_spi_calc_divisors(host, xfer->speed_hz,
&div_cpsr, &div_scr);
if (err)
return err;
@@ -166,9 +162,9 @@ static int ep93xx_spi_chip_setup(struct spi_master *master,
cr0 |= SSPCR0_SPH;
cr0 |= dss;
- dev_dbg(&master->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
+ dev_dbg(&host->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
spi->mode, div_cpsr, div_scr, dss);
- dev_dbg(&master->dev, "setup: cr0 %#x\n", cr0);
+ dev_dbg(&host->dev, "setup: cr0 %#x\n", cr0);
writel(div_cpsr, espi->mmio + SSPCPSR);
writel(cr0, espi->mmio + SSPCR0);
@@ -176,10 +172,10 @@ static int ep93xx_spi_chip_setup(struct spi_master *master,
return 0;
}
-static void ep93xx_do_write(struct spi_master *master)
+static void ep93xx_do_write(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *xfer = master->cur_msg->state;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
+ struct spi_transfer *xfer = host->cur_msg->state;
u32 val = 0;
if (xfer->bits_per_word > 8) {
@@ -194,10 +190,10 @@ static void ep93xx_do_write(struct spi_master *master)
writel(val, espi->mmio + SSPDR);
}
-static void ep93xx_do_read(struct spi_master *master)
+static void ep93xx_do_read(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *xfer = master->cur_msg->state;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
+ struct spi_transfer *xfer = host->cur_msg->state;
u32 val;
val = readl(espi->mmio + SSPDR);
@@ -214,7 +210,7 @@ static void ep93xx_do_read(struct spi_master *master)
/**
* ep93xx_spi_read_write() - perform next RX/TX transfer
- * @master: SPI master
+ * @host: SPI host
*
* This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
* called several times, the whole transfer will be completed. Returns
@@ -223,20 +219,20 @@ static void ep93xx_do_read(struct spi_master *master)
* When this function is finished, RX FIFO should be empty and TX FIFO should be
* full.
*/
-static int ep93xx_spi_read_write(struct spi_master *master)
+static int ep93xx_spi_read_write(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *xfer = master->cur_msg->state;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
+ struct spi_transfer *xfer = host->cur_msg->state;
/* read as long as RX FIFO has frames in it */
while ((readl(espi->mmio + SSPSR) & SSPSR_RNE)) {
- ep93xx_do_read(master);
+ ep93xx_do_read(host);
espi->fifo_level--;
}
/* write as long as TX FIFO has room */
while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < xfer->len) {
- ep93xx_do_write(master);
+ ep93xx_do_write(host);
espi->fifo_level++;
}
@@ -261,7 +257,7 @@ ep93xx_dma_data_to_trans_dir(enum dma_data_direction dir)
/**
* ep93xx_spi_dma_prepare() - prepares a DMA transfer
- * @master: SPI master
+ * @host: SPI host
* @dir: DMA transfer direction
*
* Function configures the DMA, maps the buffer and prepares the DMA
@@ -269,11 +265,11 @@ ep93xx_dma_data_to_trans_dir(enum dma_data_direction dir)
* in case of failure.
*/
static struct dma_async_tx_descriptor *
-ep93xx_spi_dma_prepare(struct spi_master *master,
+ep93xx_spi_dma_prepare(struct spi_controller *host,
enum dma_data_direction dir)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct spi_transfer *xfer = master->cur_msg->state;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
+ struct spi_transfer *xfer = host->cur_msg->state;
struct dma_async_tx_descriptor *txd;
enum dma_slave_buswidth buswidth;
struct dma_slave_config conf;
@@ -348,7 +344,7 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
}
if (WARN_ON(len)) {
- dev_warn(&master->dev, "len = %zu expected 0!\n", len);
+ dev_warn(&host->dev, "len = %zu expected 0!\n", len);
return ERR_PTR(-EINVAL);
}
@@ -367,16 +363,16 @@ ep93xx_spi_dma_prepare(struct spi_master *master,
/**
* ep93xx_spi_dma_finish() - finishes with a DMA transfer
- * @master: SPI master
+ * @host: SPI host
* @dir: DMA transfer direction
*
* Function finishes with the DMA transfer. After this, the DMA buffer is
* unmapped.
*/
-static void ep93xx_spi_dma_finish(struct spi_master *master,
+static void ep93xx_spi_dma_finish(struct spi_controller *host,
enum dma_data_direction dir)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
struct dma_chan *chan;
struct sg_table *sgt;
@@ -393,35 +389,35 @@ static void ep93xx_spi_dma_finish(struct spi_master *master,
static void ep93xx_spi_dma_callback(void *callback_param)
{
- struct spi_master *master = callback_param;
+ struct spi_controller *host = callback_param;
- ep93xx_spi_dma_finish(master, DMA_TO_DEVICE);
- ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);
+ ep93xx_spi_dma_finish(host, DMA_TO_DEVICE);
+ ep93xx_spi_dma_finish(host, DMA_FROM_DEVICE);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
}
-static int ep93xx_spi_dma_transfer(struct spi_master *master)
+static int ep93xx_spi_dma_transfer(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
struct dma_async_tx_descriptor *rxd, *txd;
- rxd = ep93xx_spi_dma_prepare(master, DMA_FROM_DEVICE);
+ rxd = ep93xx_spi_dma_prepare(host, DMA_FROM_DEVICE);
if (IS_ERR(rxd)) {
- dev_err(&master->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));
+ dev_err(&host->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));
return PTR_ERR(rxd);
}
- txd = ep93xx_spi_dma_prepare(master, DMA_TO_DEVICE);
+ txd = ep93xx_spi_dma_prepare(host, DMA_TO_DEVICE);
if (IS_ERR(txd)) {
- ep93xx_spi_dma_finish(master, DMA_FROM_DEVICE);
- dev_err(&master->dev, "DMA TX failed: %ld\n", PTR_ERR(txd));
+ ep93xx_spi_dma_finish(host, DMA_FROM_DEVICE);
+ dev_err(&host->dev, "DMA TX failed: %ld\n", PTR_ERR(txd));
return PTR_ERR(txd);
}
/* We are ready when RX is done */
rxd->callback = ep93xx_spi_dma_callback;
- rxd->callback_param = master;
+ rxd->callback_param = host;
/* Now submit both descriptors and start DMA */
dmaengine_submit(rxd);
@@ -436,8 +432,8 @@ static int ep93xx_spi_dma_transfer(struct spi_master *master)
static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
{
- struct spi_master *master = dev_id;
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u32 val;
/*
@@ -447,15 +443,15 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
if (readl(espi->mmio + SSPIIR) & SSPIIR_RORIS) {
/* clear the overrun interrupt */
writel(0, espi->mmio + SSPICR);
- dev_warn(&master->dev,
+ dev_warn(&host->dev,
"receive overrun, aborting the message\n");
- master->cur_msg->status = -EIO;
+ host->cur_msg->status = -EIO;
} else {
/*
* Interrupt is either RX (RIS) or TX (TIS). For both cases we
* simply execute next data transfer.
*/
- if (ep93xx_spi_read_write(master)) {
+ if (ep93xx_spi_read_write(host)) {
/*
* In normal case, there still is some processing left
* for current transfer. Let's wait for the next
@@ -474,26 +470,26 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
val &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
writel(val, espi->mmio + SSPCR1);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return IRQ_HANDLED;
}
-static int ep93xx_spi_transfer_one(struct spi_master *master,
+static int ep93xx_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u32 val;
int ret;
- ret = ep93xx_spi_chip_setup(master, spi, xfer);
+ ret = ep93xx_spi_chip_setup(host, spi, xfer);
if (ret) {
- dev_err(&master->dev, "failed to setup chip for transfer\n");
+ dev_err(&host->dev, "failed to setup chip for transfer\n");
return ret;
}
- master->cur_msg->state = xfer;
+ host->cur_msg->state = xfer;
espi->rx = 0;
espi->tx = 0;
@@ -503,10 +499,10 @@ static int ep93xx_spi_transfer_one(struct spi_master *master,
* So in these cases we will be using PIO and don't bother for DMA.
*/
if (espi->dma_rx && xfer->len > SPI_FIFO_SIZE)
- return ep93xx_spi_dma_transfer(master);
+ return ep93xx_spi_dma_transfer(host);
/* Using PIO so prime the TX FIFO and enable interrupts */
- ep93xx_spi_read_write(master);
+ ep93xx_spi_read_write(host);
val = readl(espi->mmio + SSPCR1);
val |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
@@ -516,10 +512,10 @@ static int ep93xx_spi_transfer_one(struct spi_master *master,
return 1;
}
-static int ep93xx_spi_prepare_message(struct spi_master *master,
+static int ep93xx_spi_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
unsigned long timeout;
/*
@@ -528,7 +524,7 @@ static int ep93xx_spi_prepare_message(struct spi_master *master,
timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT);
while (readl(espi->mmio + SSPSR) & SSPSR_RNE) {
if (time_after(jiffies, timeout)) {
- dev_warn(&master->dev,
+ dev_warn(&host->dev,
"timeout while flushing RX FIFO\n");
return -ETIMEDOUT;
}
@@ -544,9 +540,9 @@ static int ep93xx_spi_prepare_message(struct spi_master *master,
return 0;
}
-static int ep93xx_spi_prepare_hardware(struct spi_master *master)
+static int ep93xx_spi_prepare_hardware(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u32 val;
int ret;
@@ -561,9 +557,9 @@ static int ep93xx_spi_prepare_hardware(struct spi_master *master)
return 0;
}
-static int ep93xx_spi_unprepare_hardware(struct spi_master *master)
+static int ep93xx_spi_unprepare_hardware(struct spi_controller *host)
{
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
u32 val;
val = readl(espi->mmio + SSPCR1);
@@ -575,46 +571,23 @@ static int ep93xx_spi_unprepare_hardware(struct spi_master *master)
return 0;
}
-static bool ep93xx_spi_dma_filter(struct dma_chan *chan, void *filter_param)
-{
- if (ep93xx_dma_chan_is_m2p(chan))
- return false;
-
- chan->private = filter_param;
- return true;
-}
-
-static int ep93xx_spi_setup_dma(struct ep93xx_spi *espi)
+static int ep93xx_spi_setup_dma(struct device *dev, struct ep93xx_spi *espi)
{
- dma_cap_mask_t mask;
int ret;
espi->zeropage = (void *)get_zeroed_page(GFP_KERNEL);
if (!espi->zeropage)
return -ENOMEM;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- espi->dma_rx_data.port = EP93XX_DMA_SSP;
- espi->dma_rx_data.direction = DMA_DEV_TO_MEM;
- espi->dma_rx_data.name = "ep93xx-spi-rx";
-
- espi->dma_rx = dma_request_channel(mask, ep93xx_spi_dma_filter,
- &espi->dma_rx_data);
- if (!espi->dma_rx) {
- ret = -ENODEV;
+ espi->dma_rx = dma_request_chan(dev, "rx");
+ if (IS_ERR(espi->dma_rx)) {
+ ret = dev_err_probe(dev, PTR_ERR(espi->dma_rx), "rx DMA setup failed");
goto fail_free_page;
}
- espi->dma_tx_data.port = EP93XX_DMA_SSP;
- espi->dma_tx_data.direction = DMA_MEM_TO_DEV;
- espi->dma_tx_data.name = "ep93xx-spi-tx";
-
- espi->dma_tx = dma_request_channel(mask, ep93xx_spi_dma_filter,
- &espi->dma_tx_data);
- if (!espi->dma_tx) {
- ret = -ENODEV;
+ espi->dma_tx = dma_request_chan(dev, "tx");
+ if (IS_ERR(espi->dma_tx)) {
+ ret = dev_err_probe(dev, PTR_ERR(espi->dma_tx), "tx DMA setup failed");
goto fail_release_rx;
}
@@ -646,89 +619,80 @@ static void ep93xx_spi_release_dma(struct ep93xx_spi *espi)
static int ep93xx_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
- struct ep93xx_spi_info *info;
+ struct spi_controller *host;
struct ep93xx_spi *espi;
struct resource *res;
int irq;
int error;
- info = dev_get_platdata(&pdev->dev);
- if (!info) {
- dev_err(&pdev->dev, "missing platform data\n");
- return -EINVAL;
- }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
- return -EBUSY;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "unable to get iomem resource\n");
- return -ENODEV;
- }
+ return irq;
- master = spi_alloc_master(&pdev->dev, sizeof(*espi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*espi));
+ if (!host)
return -ENOMEM;
- master->use_gpio_descriptors = true;
- master->prepare_transfer_hardware = ep93xx_spi_prepare_hardware;
- master->unprepare_transfer_hardware = ep93xx_spi_unprepare_hardware;
- master->prepare_message = ep93xx_spi_prepare_message;
- master->transfer_one = ep93xx_spi_transfer_one;
- master->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+ host->use_gpio_descriptors = true;
+ host->prepare_transfer_hardware = ep93xx_spi_prepare_hardware;
+ host->unprepare_transfer_hardware = ep93xx_spi_unprepare_hardware;
+ host->prepare_message = ep93xx_spi_prepare_message;
+ host->transfer_one = ep93xx_spi_transfer_one;
+ host->bus_num = pdev->id;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
/*
* The SPI core will count the number of GPIO descriptors to figure
* out the number of chip selects available on the platform.
*/
- master->num_chipselect = 0;
+ host->num_chipselect = 0;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- espi = spi_master_get_devdata(master);
+ espi = spi_controller_get_devdata(host);
espi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(espi->clk)) {
dev_err(&pdev->dev, "unable to get spi clock\n");
error = PTR_ERR(espi->clk);
- goto fail_release_master;
+ goto fail_release_host;
}
/*
* Calculate maximum and minimum supported clock rates
* for the controller.
*/
- master->max_speed_hz = clk_get_rate(espi->clk) / 2;
- master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
-
- espi->sspdr_phys = res->start + SSPDR;
+ host->max_speed_hz = clk_get_rate(espi->clk) / 2;
+ host->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
- espi->mmio = devm_ioremap_resource(&pdev->dev, res);
+ espi->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(espi->mmio)) {
error = PTR_ERR(espi->mmio);
- goto fail_release_master;
+ goto fail_release_host;
}
+ espi->sspdr_phys = res->start + SSPDR;
error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt,
- 0, "ep93xx-spi", master);
+ 0, "ep93xx-spi", host);
if (error) {
dev_err(&pdev->dev, "failed to request irq\n");
- goto fail_release_master;
+ goto fail_release_host;
}
- if (info->use_dma && ep93xx_spi_setup_dma(espi))
+ error = ep93xx_spi_setup_dma(&pdev->dev, espi);
+ if (error == -EPROBE_DEFER)
+ goto fail_release_host;
+
+ if (error)
dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n");
/* make sure that the hardware is disabled */
writel(0, espi->mmio + SSPCR1);
- error = devm_spi_register_master(&pdev->dev, master);
+ device_set_node(&host->dev, dev_fwnode(&pdev->dev));
+ error = devm_spi_register_controller(&pdev->dev, host);
if (error) {
- dev_err(&pdev->dev, "failed to register SPI master\n");
+ dev_err(&pdev->dev, "failed to register SPI host\n");
goto fail_free_dma;
}
@@ -739,26 +703,33 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
fail_free_dma:
ep93xx_spi_release_dma(espi);
-fail_release_master:
- spi_master_put(master);
+fail_release_host:
+ spi_controller_put(host);
return error;
}
static void ep93xx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct ep93xx_spi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct ep93xx_spi *espi = spi_controller_get_devdata(host);
ep93xx_spi_release_dma(espi);
}
+static const struct of_device_id ep93xx_spi_of_ids[] = {
+ { .compatible = "cirrus,ep9301-spi" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ep93xx_spi_of_ids);
+
static struct platform_driver ep93xx_spi_driver = {
.driver = {
.name = "ep93xx-spi",
+ .of_match_table = ep93xx_spi_of_ids,
},
.probe = ep93xx_spi_probe,
- .remove_new = ep93xx_spi_remove,
+ .remove = ep93xx_spi_remove,
};
module_platform_driver(ep93xx_spi_driver);
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index 4c103dff0d44..faa893f83dc5 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -91,14 +91,15 @@
struct falcon_sflash {
u32 sfcmd; /* for caching of opcode, direction, ... */
- struct spi_master *master;
+ struct spi_controller *host;
};
-int falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t,
- unsigned long flags)
+static int
+falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t,
+ unsigned long flags)
{
struct device *dev = &spi->dev;
- struct falcon_sflash *priv = spi_master_get_devdata(spi->master);
+ struct falcon_sflash *priv = spi_controller_get_devdata(spi->controller);
const u8 *txp = t->tx_buf;
u8 *rxp = t->rx_buf;
unsigned int bytelen = ((8 * t->len + 7) / 8);
@@ -351,10 +352,10 @@ static int falcon_sflash_setup(struct spi_device *spi)
return 0;
}
-static int falcon_sflash_xfer_one(struct spi_master *master,
+static int falcon_sflash_xfer_one(struct spi_controller *host,
struct spi_message *m)
{
- struct falcon_sflash *priv = spi_master_get_devdata(master);
+ struct falcon_sflash *priv = spi_controller_get_devdata(host);
struct spi_transfer *t;
unsigned long spi_flags;
unsigned long flags;
@@ -382,7 +383,7 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
}
m->status = ret;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return 0;
}
@@ -390,25 +391,25 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
static int falcon_sflash_probe(struct platform_device *pdev)
{
struct falcon_sflash *priv;
- struct spi_master *master;
+ struct spi_controller *host;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*priv));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*priv));
+ if (!host)
return -ENOMEM;
- priv = spi_master_get_devdata(master);
- priv->master = master;
+ priv = spi_controller_get_devdata(host);
+ priv->host = host;
- master->mode_bits = SPI_MODE_3;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->setup = falcon_sflash_setup;
- master->transfer_one_message = falcon_sflash_xfer_one;
- master->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_MODE_3;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->setup = falcon_sflash_setup;
+ host->transfer_one_message = falcon_sflash_xfer_one;
+ host->dev.of_node = pdev->dev.of_node;
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret)
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c
index ba3b17d7c9ec..e01c63d23b64 100644
--- a/drivers/spi/spi-fsi.c
+++ b/drivers/spi/spi-fsi.c
@@ -479,6 +479,19 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,
shift = SPI_FSI_SEQUENCE_SHIFT_IN(next->len);
fsi_spi_sequence_add(&seq, shift);
+ } else if (next->tx_buf) {
+ if ((next->len + transfer->len) > (SPI_FSI_MAX_TX_SIZE + 8)) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ len = next->len;
+ while (len > 8) {
+ fsi_spi_sequence_add(&seq,
+ SPI_FSI_SEQUENCE_SHIFT_OUT(8));
+ len -= 8;
+ }
+ fsi_spi_sequence_add(&seq, SPI_FSI_SEQUENCE_SHIFT_OUT(len));
} else {
next = NULL;
}
@@ -542,7 +555,7 @@ static int fsi_spi_probe(struct device *dev)
if (of_property_read_u32(np, "reg", &base))
continue;
- ctlr = spi_alloc_master(dev, sizeof(*ctx));
+ ctlr = spi_alloc_host(dev, sizeof(*ctx));
if (!ctlr) {
of_node_put(np);
break;
diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c
index 38452089e8f3..23ad1249f121 100644
--- a/drivers/spi/spi-fsl-cpm.c
+++ b/drivers/spi/spi-fsl-cpm.c
@@ -56,12 +56,12 @@ void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi)
QE_CR_PROTOCOL_UNSPECIFIED, 0);
} else {
if (mspi->flags & SPI_CPM1) {
- out_be32(&mspi->pram->rstate, 0);
- out_be16(&mspi->pram->rbptr,
- in_be16(&mspi->pram->rbase));
- out_be32(&mspi->pram->tstate, 0);
- out_be16(&mspi->pram->tbptr,
- in_be16(&mspi->pram->tbase));
+ iowrite32be(0, &mspi->pram->rstate);
+ iowrite16be(ioread16be(&mspi->pram->rbase),
+ &mspi->pram->rbptr);
+ iowrite32be(0, &mspi->pram->tstate);
+ iowrite16be(ioread16be(&mspi->pram->tbase),
+ &mspi->pram->tbptr);
} else {
cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
}
@@ -75,42 +75,36 @@ static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
unsigned int xfer_ofs;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
if (mspi->rx_dma == mspi->dma_dummy_rx)
- out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma);
+ iowrite32be(mspi->rx_dma, &rx_bd->cbd_bufaddr);
else
- out_be32(&rx_bd->cbd_bufaddr, mspi->rx_dma + xfer_ofs);
- out_be16(&rx_bd->cbd_datlen, 0);
- out_be16(&rx_bd->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP);
+ iowrite32be(mspi->rx_dma + xfer_ofs, &rx_bd->cbd_bufaddr);
+ iowrite16be(0, &rx_bd->cbd_datlen);
+ iowrite16be(BD_SC_EMPTY | BD_SC_INTRPT | BD_SC_WRAP, &rx_bd->cbd_sc);
if (mspi->tx_dma == mspi->dma_dummy_tx)
- out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma);
+ iowrite32be(mspi->tx_dma, &tx_bd->cbd_bufaddr);
else
- out_be32(&tx_bd->cbd_bufaddr, mspi->tx_dma + xfer_ofs);
- out_be16(&tx_bd->cbd_datlen, xfer_len);
- out_be16(&tx_bd->cbd_sc, BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP |
- BD_SC_LAST);
+ iowrite32be(mspi->tx_dma + xfer_ofs, &tx_bd->cbd_bufaddr);
+ iowrite16be(xfer_len, &tx_bd->cbd_datlen);
+ iowrite16be(BD_SC_READY | BD_SC_INTRPT | BD_SC_WRAP | BD_SC_LAST,
+ &tx_bd->cbd_sc);
/* start transfer */
mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
}
-int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
- struct spi_transfer *t, bool is_dma_mapped)
+int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t)
{
struct device *dev = mspi->dev;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
- if (is_dma_mapped) {
- mspi->map_tx_dma = 0;
- mspi->map_rx_dma = 0;
- } else {
- mspi->map_tx_dma = 1;
- mspi->map_rx_dma = 1;
- }
+ mspi->map_tx_dma = 1;
+ mspi->map_rx_dma = 1;
if (!t->tx_buf) {
mspi->tx_dma = mspi->dma_dummy_tx;
@@ -123,7 +117,7 @@ int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
}
if (t->bits_per_word == 16 && t->tx_buf) {
const u16 *src = t->tx_buf;
- u16 *dst;
+ __le16 *dst;
int i;
dst = kmalloc(t->len, GFP_KERNEL);
@@ -147,7 +141,7 @@ int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
return -ENOMEM;
}
} else if (t->tx_buf) {
- mspi->tx_dma = t->tx_dma;
+ mspi->tx_dma = 0;
}
if (mspi->map_rx_dma) {
@@ -202,12 +196,12 @@ EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs_complete);
void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
{
u16 len;
- struct fsl_spi_reg *reg_base = mspi->reg_base;
+ struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
- in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
+ ioread16be(&mspi->rx_bd->cbd_datlen), mspi->count);
- len = in_be16(&mspi->rx_bd->cbd_datlen);
+ len = ioread16be(&mspi->rx_bd->cbd_datlen);
if (len > mspi->count) {
WARN_ON(1);
len = mspi->count;
@@ -328,7 +322,7 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
}
if (mspi->flags & SPI_CPM1) {
- void *pram;
+ void __iomem *pram;
pram = devm_platform_ioremap_resource(to_platform_device(dev),
1);
@@ -374,21 +368,21 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
mspi->rx_bd = cpm_muram_addr(bds_ofs + sizeof(*mspi->tx_bd));
/* Initialize parameter ram. */
- out_be16(&mspi->pram->tbase, cpm_muram_offset(mspi->tx_bd));
- out_be16(&mspi->pram->rbase, cpm_muram_offset(mspi->rx_bd));
- out_8(&mspi->pram->tfcr, CPMFCR_EB | CPMFCR_GBL);
- out_8(&mspi->pram->rfcr, CPMFCR_EB | CPMFCR_GBL);
- out_be16(&mspi->pram->mrblr, SPI_MRBLR);
- out_be32(&mspi->pram->rstate, 0);
- out_be32(&mspi->pram->rdp, 0);
- out_be16(&mspi->pram->rbptr, 0);
- out_be16(&mspi->pram->rbc, 0);
- out_be32(&mspi->pram->rxtmp, 0);
- out_be32(&mspi->pram->tstate, 0);
- out_be32(&mspi->pram->tdp, 0);
- out_be16(&mspi->pram->tbptr, 0);
- out_be16(&mspi->pram->tbc, 0);
- out_be32(&mspi->pram->txtmp, 0);
+ iowrite16be(cpm_muram_offset(mspi->tx_bd), &mspi->pram->tbase);
+ iowrite16be(cpm_muram_offset(mspi->rx_bd), &mspi->pram->rbase);
+ iowrite8(CPMFCR_EB | CPMFCR_GBL, &mspi->pram->tfcr);
+ iowrite8(CPMFCR_EB | CPMFCR_GBL, &mspi->pram->rfcr);
+ iowrite16be(SPI_MRBLR, &mspi->pram->mrblr);
+ iowrite32be(0, &mspi->pram->rstate);
+ iowrite32be(0, &mspi->pram->rdp);
+ iowrite16be(0, &mspi->pram->rbptr);
+ iowrite16be(0, &mspi->pram->rbc);
+ iowrite32be(0, &mspi->pram->rxtmp);
+ iowrite32be(0, &mspi->pram->tstate);
+ iowrite32be(0, &mspi->pram->tdp);
+ iowrite16be(0, &mspi->pram->tbptr);
+ iowrite16be(0, &mspi->pram->tbc);
+ iowrite32be(0, &mspi->pram->txtmp);
return 0;
@@ -421,4 +415,5 @@ void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
}
EXPORT_SYMBOL_GPL(fsl_spi_cpm_free);
+MODULE_DESCRIPTION("Freescale SPI controller driver CPM functions");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-fsl-cpm.h b/drivers/spi/spi-fsl-cpm.h
index 160f999708b6..e012abba055f 100644
--- a/drivers/spi/spi-fsl-cpm.h
+++ b/drivers/spi/spi-fsl-cpm.h
@@ -20,7 +20,7 @@
#ifdef CONFIG_FSL_SOC
extern void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi);
extern int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
- struct spi_transfer *t, bool is_dma_mapped);
+ struct spi_transfer *t);
extern void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi);
extern void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events);
extern int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi);
@@ -28,8 +28,7 @@ extern void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi);
#else
static inline void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi) { }
static inline int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
- struct spi_transfer *t,
- bool is_dma_mapped) { return 0; }
+ struct spi_transfer *t) { return 0; }
static inline void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) { }
static inline void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) { }
static inline int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) { return 0; }
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 674cfe05f411..83ea296597e9 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright 2013 Freescale Semiconductor, Inc.
-// Copyright 2020 NXP
+// Copyright 2020-2025 NXP
//
// Freescale DSPI driver
// This file contains a driver for the Freescale DSPI
@@ -13,7 +13,8 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
@@ -22,7 +23,8 @@
#define DRIVER_NAME "fsl-dspi"
#define SPI_MCR 0x00
-#define SPI_MCR_MASTER BIT(31)
+#define SPI_MCR_HOST BIT(31)
+#define SPI_MCR_MTFE BIT(26)
#define SPI_MCR_PCSIS(x) ((x) << 16)
#define SPI_MCR_CLR_TXF BIT(11)
#define SPI_MCR_CLR_RXF BIT(10)
@@ -34,8 +36,9 @@
#define SPI_TCR 0x08
#define SPI_TCR_GET_TCNT(x) (((x) & GENMASK(31, 16)) >> 16)
-#define SPI_CTAR(x) (0x0c + (((x) & GENMASK(1, 0)) * 4))
+#define SPI_CTAR(x) (0x0c + (((x) & GENMASK(2, 0)) * 4))
#define SPI_CTAR_FMSZ(x) (((x) << 27) & GENMASK(30, 27))
+#define SPI_CTAR_DBR BIT(31)
#define SPI_CTAR_CPOL BIT(26)
#define SPI_CTAR_CPHA BIT(25)
#define SPI_CTAR_LSBFE BIT(24)
@@ -61,6 +64,7 @@
#define SPI_SR_TFIWF BIT(18)
#define SPI_SR_RFDF BIT(17)
#define SPI_SR_CMDFFF BIT(16)
+#define SPI_SR_TXRXS BIT(30)
#define SPI_SR_CLEAR (SPI_SR_TCFQF | \
SPI_SR_TFUF | SPI_SR_TFFF | \
SPI_SR_CMDTCF | SPI_SR_SPEF | \
@@ -91,12 +95,14 @@
#define SPI_TXFR1 0x40
#define SPI_TXFR2 0x44
#define SPI_TXFR3 0x48
+#define SPI_TXFR4 0x4C
#define SPI_RXFR0 0x7c
#define SPI_RXFR1 0x80
#define SPI_RXFR2 0x84
#define SPI_RXFR3 0x88
+#define SPI_RXFR4 0x8C
-#define SPI_CTARE(x) (0x11c + (((x) & GENMASK(1, 0)) * 4))
+#define SPI_CTARE(x) (0x11c + (((x) & GENMASK(2, 0)) * 4))
#define SPI_CTARE_FMSZE(x) (((x) & 0x1) << 16)
#define SPI_CTARE_DTCP(x) ((x) & 0x7ff)
@@ -107,6 +113,8 @@
#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
+#define SPI_25MHZ 25000000
+
struct chip_data {
u32 ctar_val;
};
@@ -120,6 +128,7 @@ struct fsl_dspi_devtype_data {
enum dspi_trans_mode trans_mode;
u8 max_clock_factor;
int fifo_size;
+ const struct regmap_config *regmap;
};
enum {
@@ -133,6 +142,102 @@ enum {
LX2160A,
MCF5441X,
VF610,
+ S32G,
+ S32G_TARGET,
+};
+
+static const struct regmap_range dspi_yes_ranges[] = {
+ regmap_reg_range(SPI_MCR, SPI_MCR),
+ regmap_reg_range(SPI_TCR, SPI_CTAR(3)),
+ regmap_reg_range(SPI_SR, SPI_TXFR3),
+ regmap_reg_range(SPI_RXFR0, SPI_RXFR3),
+ regmap_reg_range(SPI_CTARE(0), SPI_CTARE(3)),
+ regmap_reg_range(SPI_SREX, SPI_SREX),
+};
+
+static const struct regmap_range s32g_dspi_yes_ranges[] = {
+ regmap_reg_range(SPI_MCR, SPI_MCR),
+ regmap_reg_range(SPI_TCR, SPI_CTAR(5)),
+ regmap_reg_range(SPI_SR, SPI_TXFR4),
+ regmap_reg_range(SPI_RXFR0, SPI_RXFR4),
+ regmap_reg_range(SPI_CTARE(0), SPI_CTARE(5)),
+ regmap_reg_range(SPI_SREX, SPI_SREX),
+};
+
+static const struct regmap_access_table dspi_access_table = {
+ .yes_ranges = dspi_yes_ranges,
+ .n_yes_ranges = ARRAY_SIZE(dspi_yes_ranges),
+};
+
+static const struct regmap_access_table s32g_dspi_access_table = {
+ .yes_ranges = s32g_dspi_yes_ranges,
+ .n_yes_ranges = ARRAY_SIZE(s32g_dspi_yes_ranges),
+};
+
+static const struct regmap_range dspi_volatile_ranges[] = {
+ regmap_reg_range(SPI_MCR, SPI_TCR),
+ regmap_reg_range(SPI_SR, SPI_SR),
+ regmap_reg_range(SPI_PUSHR, SPI_RXFR4),
+ regmap_reg_range(SPI_SREX, SPI_SREX),
+};
+
+static const struct regmap_access_table dspi_volatile_table = {
+ .yes_ranges = dspi_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(dspi_volatile_ranges),
+};
+
+enum {
+ DSPI_REGMAP,
+ S32G_DSPI_REGMAP,
+ DSPI_XSPI_REGMAP,
+ S32G_DSPI_XSPI_REGMAP,
+ DSPI_PUSHR,
+};
+
+static const struct regmap_config dspi_regmap_config[] = {
+ [DSPI_REGMAP] = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SPI_RXFR3,
+ .volatile_table = &dspi_volatile_table,
+ .rd_table = &dspi_access_table,
+ .wr_table = &dspi_access_table,
+ },
+ [S32G_DSPI_REGMAP] = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SPI_RXFR4,
+ .volatile_table = &dspi_volatile_table,
+ .wr_table = &s32g_dspi_access_table,
+ .rd_table = &s32g_dspi_access_table,
+ },
+ [DSPI_XSPI_REGMAP] = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SPI_SREX,
+ .volatile_table = &dspi_volatile_table,
+ .rd_table = &dspi_access_table,
+ .wr_table = &dspi_access_table,
+ },
+ [S32G_DSPI_XSPI_REGMAP] = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SPI_SREX,
+ .volatile_table = &dspi_volatile_table,
+ .wr_table = &s32g_dspi_access_table,
+ .rd_table = &s32g_dspi_access_table,
+ },
+ [DSPI_PUSHR] = {
+ .name = "pushr",
+ .reg_bits = 16,
+ .val_bits = 16,
+ .reg_stride = 2,
+ .max_register = 0x2,
+ },
};
static const struct fsl_dspi_devtype_data devtype_data[] = {
@@ -140,55 +245,77 @@ static const struct fsl_dspi_devtype_data devtype_data[] = {
.trans_mode = DSPI_DMA_MODE,
.max_clock_factor = 2,
.fifo_size = 4,
+ .regmap = &dspi_regmap_config[DSPI_REGMAP],
},
[LS1021A] = {
/* Has A-011218 DMA erratum */
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
+ .regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS1012A] = {
/* Has A-011218 DMA erratum */
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 16,
+ .regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS1028A] = {
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
+ .regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS1043A] = {
/* Has A-011218 DMA erratum */
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 16,
+ .regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS1046A] = {
/* Has A-011218 DMA erratum */
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 16,
+ .regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS2080A] = {
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
+ .regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS2085A] = {
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
+ .regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LX2160A] = {
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
+ .regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[MCF5441X] = {
.trans_mode = DSPI_DMA_MODE,
.max_clock_factor = 8,
.fifo_size = 16,
+ .regmap = &dspi_regmap_config[DSPI_REGMAP],
+ },
+ [S32G] = {
+ .trans_mode = DSPI_XSPI_MODE,
+ .max_clock_factor = 1,
+ .fifo_size = 5,
+ .regmap = &dspi_regmap_config[S32G_DSPI_XSPI_REGMAP],
+ },
+ [S32G_TARGET] = {
+ .trans_mode = DSPI_DMA_MODE,
+ .max_clock_factor = 1,
+ .fifo_size = 5,
+ .regmap = &dspi_regmap_config[S32G_DSPI_REGMAP],
},
};
@@ -204,6 +331,8 @@ struct fsl_dspi_dma {
dma_addr_t rx_dma_phys;
struct completion cmd_rx_complete;
struct dma_async_tx_descriptor *rx_desc;
+
+ size_t bufsize;
};
struct fsl_dspi {
@@ -223,6 +352,7 @@ struct fsl_dspi {
const void *tx;
void *rx;
u16 tx_cmd;
+ bool mtf_enabled;
const struct fsl_dspi_devtype_data *devtype_data;
struct completion xfer_done;
@@ -245,6 +375,14 @@ struct fsl_dspi {
void (*dev_to_host)(struct fsl_dspi *dspi, u32 rxdata);
};
+static void dspi_setup_accel(struct fsl_dspi *dspi);
+
+static bool is_s32g_dspi(struct fsl_dspi *data)
+{
+ return data->devtype_data == &devtype_data[S32G] ||
+ data->devtype_data == &devtype_data[S32G_TARGET];
+}
+
static void dspi_native_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
{
switch (dspi->oper_word_size) {
@@ -279,25 +417,25 @@ static void dspi_native_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
static void dspi_8on32_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
{
- *txdata = cpu_to_be32(*(u32 *)dspi->tx);
+ *txdata = (__force u32)cpu_to_be32(*(u32 *)dspi->tx);
dspi->tx += sizeof(u32);
}
static void dspi_8on32_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
{
- *(u32 *)dspi->rx = be32_to_cpu(rxdata);
+ *(u32 *)dspi->rx = be32_to_cpu((__force __be32)rxdata);
dspi->rx += sizeof(u32);
}
static void dspi_8on16_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
{
- *txdata = cpu_to_be16(*(u16 *)dspi->tx);
+ *txdata = (__force u32)cpu_to_be16(*(u16 *)dspi->tx);
dspi->tx += sizeof(u16);
}
static void dspi_8on16_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
{
- *(u16 *)dspi->rx = be16_to_cpu(rxdata);
+ *(u16 *)dspi->rx = be16_to_cpu((__force __be16)rxdata);
dspi->rx += sizeof(u16);
}
@@ -334,12 +472,33 @@ static u32 dspi_pop_tx(struct fsl_dspi *dspi)
return txdata;
}
+/* Push one word to the RX buffer from the POPR register (RX FIFO) */
+static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
+{
+ if (!dspi->rx)
+ return;
+ dspi->dev_to_host(dspi, rxdata);
+}
+
+static int dspi_fifo_error(struct fsl_dspi *dspi, u32 spi_sr)
+{
+ if (spi_sr & (SPI_SR_TFUF | SPI_SR_RFOF)) {
+ dev_err_ratelimited(&dspi->pdev->dev, "FIFO errors:%s%s\n",
+ spi_sr & SPI_SR_TFUF ? " TX underflow," : "",
+ spi_sr & SPI_SR_RFOF ? " RX overflow," : "");
+ return -EIO;
+ }
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_DMA_ENGINE)
+
/* Prepare one TX FIFO entry (txdata plus cmd) */
static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
{
u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
- if (spi_controller_is_slave(dspi->ctlr))
+ if (spi_controller_is_target(dspi->ctlr))
return data;
if (dspi->len > 0)
@@ -347,19 +506,37 @@ static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
return cmd << 16 | data;
}
-/* Push one word to the RX buffer from the POPR register (RX FIFO) */
-static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
+static size_t dspi_dma_max_datawords(struct fsl_dspi *dspi)
{
- if (!dspi->rx)
- return;
- dspi->dev_to_host(dspi, rxdata);
+ /*
+ * Transfers look like one of these, so we always use a full DMA word
+ * regardless of SPI word size:
+ *
+ * 31 16 15 0
+ * -----------------------------------------
+ * | CONTROL WORD | 16-bit DATA |
+ * -----------------------------------------
+ * or
+ * -----------------------------------------
+ * | CONTROL WORD | UNUSED | 8-bit DATA |
+ * -----------------------------------------
+ */
+ return dspi->dma->bufsize / DMA_SLAVE_BUSWIDTH_4_BYTES;
+}
+
+static size_t dspi_dma_transfer_size(struct fsl_dspi *dspi)
+{
+ return dspi->words_in_flight * DMA_SLAVE_BUSWIDTH_4_BYTES;
}
static void dspi_tx_dma_callback(void *arg)
{
struct fsl_dspi *dspi = arg;
struct fsl_dspi_dma *dma = dspi->dma;
+ struct device *dev = &dspi->pdev->dev;
+ dma_sync_single_for_cpu(dev, dma->tx_dma_phys,
+ dspi_dma_transfer_size(dspi), DMA_TO_DEVICE);
complete(&dma->cmd_tx_complete);
}
@@ -367,9 +544,13 @@ static void dspi_rx_dma_callback(void *arg)
{
struct fsl_dspi *dspi = arg;
struct fsl_dspi_dma *dma = dspi->dma;
+ struct device *dev = &dspi->pdev->dev;
int i;
if (dspi->rx) {
+ dma_sync_single_for_cpu(dev, dma->rx_dma_phys,
+ dspi_dma_transfer_size(dspi),
+ DMA_FROM_DEVICE);
for (i = 0; i < dspi->words_in_flight; i++)
dspi_push_rx(dspi, dspi->dma->rx_dma_buf[i]);
}
@@ -379,20 +560,22 @@ static void dspi_rx_dma_callback(void *arg)
static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
{
+ size_t size = dspi_dma_transfer_size(dspi);
struct device *dev = &dspi->pdev->dev;
struct fsl_dspi_dma *dma = dspi->dma;
int time_left;
+ u32 spi_sr;
int i;
for (i = 0; i < dspi->words_in_flight; i++)
dspi->dma->tx_dma_buf[i] = dspi_pop_tx_pushr(dspi);
+ dma_sync_single_for_device(dev, dma->tx_dma_phys, size, DMA_TO_DEVICE);
dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
- dma->tx_dma_phys,
- dspi->words_in_flight *
- DMA_SLAVE_BUSWIDTH_4_BYTES,
- DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ dma->tx_dma_phys, size,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK);
if (!dma->tx_desc) {
dev_err(dev, "Not able to get desc for DMA xfer\n");
return -EIO;
@@ -405,12 +588,13 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
return -EINVAL;
}
+ dma_sync_single_for_device(dev, dma->rx_dma_phys, size,
+ DMA_FROM_DEVICE);
dma->rx_desc = dmaengine_prep_slave_single(dma->chan_rx,
- dma->rx_dma_phys,
- dspi->words_in_flight *
- DMA_SLAVE_BUSWIDTH_4_BYTES,
- DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ dma->rx_dma_phys, size,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK);
if (!dma->rx_desc) {
dev_err(dev, "Not able to get desc for DMA xfer\n");
return -EIO;
@@ -429,9 +613,10 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
dma_async_issue_pending(dma->chan_rx);
dma_async_issue_pending(dma->chan_tx);
- if (spi_controller_is_slave(dspi->ctlr)) {
+ if (spi_controller_is_target(dspi->ctlr)) {
wait_for_completion_interruptible(&dspi->dma->cmd_rx_complete);
- return 0;
+ regmap_read(dspi->regmap, SPI_SR, &spi_sr);
+ return dspi_fifo_error(dspi, spi_sr);
}
time_left = wait_for_completion_timeout(&dspi->dma->cmd_tx_complete,
@@ -455,13 +640,10 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
return 0;
}
-static void dspi_setup_accel(struct fsl_dspi *dspi);
-
-static int dspi_dma_xfer(struct fsl_dspi *dspi)
+static void dspi_dma_xfer(struct fsl_dspi *dspi)
{
struct spi_message *message = dspi->cur_msg;
struct device *dev = &dspi->pdev->dev;
- int ret = 0;
/*
* dspi->len gets decremented by dspi_pop_tx_pushr in
@@ -471,26 +653,22 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
/* Figure out operational bits-per-word for this chunk */
dspi_setup_accel(dspi);
- dspi->words_in_flight = dspi->len / dspi->oper_word_size;
- if (dspi->words_in_flight > dspi->devtype_data->fifo_size)
- dspi->words_in_flight = dspi->devtype_data->fifo_size;
+ dspi->words_in_flight = min(dspi->len / dspi->oper_word_size,
+ dspi_dma_max_datawords(dspi));
message->actual_length += dspi->words_in_flight *
dspi->oper_word_size;
- ret = dspi_next_xfer_dma_submit(dspi);
- if (ret) {
+ message->status = dspi_next_xfer_dma_submit(dspi);
+ if (message->status) {
dev_err(dev, "DMA transfer failed\n");
break;
}
}
-
- return ret;
}
static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
{
- int dma_bufsize = dspi->devtype_data->fifo_size * 2;
struct device *dev = &dspi->pdev->dev;
struct dma_slave_config cfg;
struct fsl_dspi_dma *dma;
@@ -501,30 +679,39 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
return -ENOMEM;
dma->chan_rx = dma_request_chan(dev, "rx");
- if (IS_ERR(dma->chan_rx)) {
- dev_err(dev, "rx dma channel not available\n");
- ret = PTR_ERR(dma->chan_rx);
- return ret;
- }
+ if (IS_ERR(dma->chan_rx))
+ return dev_err_probe(dev, PTR_ERR(dma->chan_rx), "rx dma channel not available\n");
dma->chan_tx = dma_request_chan(dev, "tx");
if (IS_ERR(dma->chan_tx)) {
- dev_err(dev, "tx dma channel not available\n");
- ret = PTR_ERR(dma->chan_tx);
+ ret = dev_err_probe(dev, PTR_ERR(dma->chan_tx), "tx dma channel not available\n");
goto err_tx_channel;
}
- dma->tx_dma_buf = dma_alloc_coherent(dma->chan_tx->device->dev,
- dma_bufsize, &dma->tx_dma_phys,
- GFP_KERNEL);
+ if (spi_controller_is_target(dspi->ctlr)) {
+ /*
+ * In target mode we have to be ready to receive the maximum
+ * that can possibly be transferred at once by EDMA without any
+ * FIFO underflows.
+ */
+ dma->bufsize = min(dma_get_max_seg_size(dma->chan_rx->device->dev),
+ dma_get_max_seg_size(dma->chan_tx->device->dev)) *
+ DMA_SLAVE_BUSWIDTH_4_BYTES;
+ } else {
+ dma->bufsize = PAGE_SIZE;
+ }
+
+ dma->tx_dma_buf = dma_alloc_noncoherent(dma->chan_tx->device->dev,
+ dma->bufsize, &dma->tx_dma_phys,
+ DMA_TO_DEVICE, GFP_KERNEL);
if (!dma->tx_dma_buf) {
ret = -ENOMEM;
goto err_tx_dma_buf;
}
- dma->rx_dma_buf = dma_alloc_coherent(dma->chan_rx->device->dev,
- dma_bufsize, &dma->rx_dma_phys,
- GFP_KERNEL);
+ dma->rx_dma_buf = dma_alloc_noncoherent(dma->chan_rx->device->dev,
+ dma->bufsize, &dma->rx_dma_phys,
+ DMA_FROM_DEVICE, GFP_KERNEL);
if (!dma->rx_dma_buf) {
ret = -ENOMEM;
goto err_rx_dma_buf;
@@ -541,16 +728,14 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
cfg.direction = DMA_DEV_TO_MEM;
ret = dmaengine_slave_config(dma->chan_rx, &cfg);
if (ret) {
- dev_err(dev, "can't configure rx dma channel\n");
- ret = -EINVAL;
+ dev_err_probe(dev, ret, "can't configure rx dma channel\n");
goto err_slave_config;
}
cfg.direction = DMA_MEM_TO_DEV;
ret = dmaengine_slave_config(dma->chan_tx, &cfg);
if (ret) {
- dev_err(dev, "can't configure tx dma channel\n");
- ret = -EINVAL;
+ dev_err_probe(dev, ret, "can't configure tx dma channel\n");
goto err_slave_config;
}
@@ -561,11 +746,12 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
return 0;
err_slave_config:
- dma_free_coherent(dma->chan_rx->device->dev,
- dma_bufsize, dma->rx_dma_buf, dma->rx_dma_phys);
+ dma_free_noncoherent(dma->chan_rx->device->dev, dma->bufsize,
+ dma->rx_dma_buf, dma->rx_dma_phys,
+ DMA_FROM_DEVICE);
err_rx_dma_buf:
- dma_free_coherent(dma->chan_tx->device->dev,
- dma_bufsize, dma->tx_dma_buf, dma->tx_dma_phys);
+ dma_free_noncoherent(dma->chan_tx->device->dev, dma->bufsize,
+ dma->tx_dma_buf, dma->tx_dma_phys, DMA_TO_DEVICE);
err_tx_dma_buf:
dma_release_channel(dma->chan_tx);
err_tx_channel:
@@ -579,27 +765,40 @@ err_tx_channel:
static void dspi_release_dma(struct fsl_dspi *dspi)
{
- int dma_bufsize = dspi->devtype_data->fifo_size * 2;
struct fsl_dspi_dma *dma = dspi->dma;
if (!dma)
return;
if (dma->chan_tx) {
- dma_free_coherent(dma->chan_tx->device->dev, dma_bufsize,
- dma->tx_dma_buf, dma->tx_dma_phys);
+ dma_free_noncoherent(dma->chan_tx->device->dev, dma->bufsize,
+ dma->tx_dma_buf, dma->tx_dma_phys,
+ DMA_TO_DEVICE);
dma_release_channel(dma->chan_tx);
}
if (dma->chan_rx) {
- dma_free_coherent(dma->chan_rx->device->dev, dma_bufsize,
- dma->rx_dma_buf, dma->rx_dma_phys);
+ dma_free_noncoherent(dma->chan_rx->device->dev, dma->bufsize,
+ dma->rx_dma_buf, dma->rx_dma_phys,
+ DMA_FROM_DEVICE);
dma_release_channel(dma->chan_rx);
}
}
+#else
+static void dspi_dma_xfer(struct fsl_dspi *dspi)
+{
+ dspi->cur_msg->status = -EINVAL;
+}
+static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
+{
+ dev_err(&dspi->pdev->dev, "DMA support not enabled in kernel\n");
+ return -EINVAL;
+}
+static void dspi_release_dma(struct fsl_dspi *dspi) {}
+#endif
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
- unsigned long clkrate)
+ unsigned long clkrate, bool mtf_enabled)
{
/* Valid baud rate pre-scaler values */
int pbr_tbl[4] = {2, 3, 5, 7};
@@ -616,7 +815,13 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
for (i = 0; i < ARRAY_SIZE(brs); i++)
for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) {
- scale = brs[i] * pbr_tbl[j];
+ if (mtf_enabled) {
+ /* In MTF mode DBR=1 so frequency is doubled */
+ scale = (brs[i] * pbr_tbl[j]) / 2;
+ } else {
+ scale = brs[i] * pbr_tbl[j];
+ }
+
if (scale >= scale_needed) {
if (scale < minscale) {
minscale = scale;
@@ -750,8 +955,12 @@ static void dspi_setup_accel(struct fsl_dspi *dspi)
struct spi_transfer *xfer = dspi->cur_transfer;
bool odd = !!(dspi->len & 1);
- /* No accel for frames not multiple of 8 bits at the moment */
- if (xfer->bits_per_word % 8)
+ /*
+ * No accel for DMA transfers or frames not multiples of 8 bits at the
+ * moment.
+ */
+ if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE ||
+ xfer->bits_per_word % 8)
goto no_accel;
if (!odd && dspi->len <= dspi->devtype_data->fifo_size * 2) {
@@ -760,10 +969,7 @@ static void dspi_setup_accel(struct fsl_dspi *dspi)
dspi->oper_bits_per_word = 8;
} else {
/* Start off with maximum supported by hardware */
- if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
- dspi->oper_bits_per_word = 32;
- else
- dspi->oper_bits_per_word = 16;
+ dspi->oper_bits_per_word = 32;
/*
* And go down only if the buffer can't be sent with
@@ -851,41 +1057,55 @@ static void dspi_fifo_write(struct fsl_dspi *dspi)
dspi->progress, !dspi->irq);
}
-static int dspi_rxtx(struct fsl_dspi *dspi)
+/*
+ * Read the previous transfer from the FIFO and transmit the next one.
+ *
+ * Returns false if the buffer to be transmitted is empty, and true if there is
+ * still data to transmit.
+ */
+static bool dspi_rxtx(struct fsl_dspi *dspi)
{
dspi_fifo_read(dspi);
if (!dspi->len)
/* Success! */
- return 0;
+ return false;
dspi_fifo_write(dspi);
- return -EINPROGRESS;
+ return true;
}
-static int dspi_poll(struct fsl_dspi *dspi)
+static void dspi_poll(struct fsl_dspi *dspi)
{
- int tries = 1000;
+ int tries;
+ int err = 0;
u32 spi_sr;
do {
- regmap_read(dspi->regmap, SPI_SR, &spi_sr);
- regmap_write(dspi->regmap, SPI_SR, spi_sr);
-
- if (spi_sr & SPI_SR_CMDTCF)
+ for (tries = 1000; tries > 0; --tries) {
+ regmap_read(dspi->regmap, SPI_SR, &spi_sr);
+ regmap_write(dspi->regmap, SPI_SR, spi_sr);
+
+ dspi->cur_msg->status = dspi_fifo_error(dspi, spi_sr);
+ if (dspi->cur_msg->status)
+ return;
+ if (spi_sr & SPI_SR_CMDTCF)
+ break;
+ }
+ if (!tries) {
+ err = -ETIMEDOUT;
break;
- } while (--tries);
-
- if (!tries)
- return -ETIMEDOUT;
+ }
+ } while (dspi_rxtx(dspi));
- return dspi_rxtx(dspi);
+ dspi->cur_msg->status = err;
}
static irqreturn_t dspi_interrupt(int irq, void *dev_id)
{
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
+ int status;
u32 spi_sr;
regmap_read(dspi->regmap, SPI_SR, &spi_sr);
@@ -894,8 +1114,19 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
if (!(spi_sr & SPI_SR_CMDTCF))
return IRQ_NONE;
- if (dspi_rxtx(dspi) == 0)
+ status = dspi_fifo_error(dspi, spi_sr);
+ if (status) {
+ if (dspi->cur_msg)
+ WRITE_ONCE(dspi->cur_msg->status, status);
+ complete(&dspi->xfer_done);
+ return IRQ_HANDLED;
+ }
+
+ if (dspi_rxtx(dspi) == false) {
+ if (dspi->cur_msg)
+ WRITE_ONCE(dspi->cur_msg->status, 0);
complete(&dspi->xfer_done);
+ }
return IRQ_HANDLED;
}
@@ -925,10 +1156,20 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
struct spi_device *spi = message->spi;
struct spi_transfer *transfer;
bool cs = false;
- int status = 0;
+ u32 val = 0;
+ bool cs_change = false;
message->actual_length = 0;
+ /* Put DSPI in running mode if halted. */
+ regmap_read(dspi->regmap, SPI_MCR, &val);
+ if (val & SPI_MCR_HALT) {
+ regmap_update_bits(dspi->regmap, SPI_MCR, SPI_MCR_HALT, 0);
+ while (regmap_read(dspi->regmap, SPI_SR, &val) >= 0 &&
+ !(val & SPI_SR_TXRXS))
+ ;
+ }
+
list_for_each_entry(transfer, &message->transfers, transfer_list) {
dspi->cur_transfer = transfer;
dspi->cur_msg = message;
@@ -958,6 +1199,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
}
+ cs_change = transfer->cs_change;
dspi->tx = transfer->tx_buf;
dspi->rx = transfer->rx_buf;
dspi->len = transfer->len;
@@ -967,24 +1209,32 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
+ regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
+
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
dspi->progress, !dspi->irq);
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
- status = dspi_dma_xfer(dspi);
+ dspi_dma_xfer(dspi);
} else {
+ /*
+ * Reinitialize the completion before transferring data
+ * to avoid the case where it might remain in the done
+ * state due to a spurious interrupt from a previous
+ * transfer. This could falsely signal that the current
+ * transfer has completed.
+ */
+ if (dspi->irq)
+ reinit_completion(&dspi->xfer_done);
+
dspi_fifo_write(dspi);
- if (dspi->irq) {
+ if (dspi->irq)
wait_for_completion(&dspi->xfer_done);
- reinit_completion(&dspi->xfer_done);
- } else {
- do {
- status = dspi_poll(dspi);
- } while (status == -EINPROGRESS);
- }
+ else
+ dspi_poll(dspi);
}
- if (status)
+ if (READ_ONCE(message->status))
break;
spi_transfer_delay_exec(transfer);
@@ -993,10 +1243,33 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
dspi_deassert_cs(spi, &cs);
}
- message->status = status;
+ dspi->cur_msg = NULL;
+ if (message->status || !cs_change) {
+ /* Put DSPI in stop mode */
+ regmap_update_bits(dspi->regmap, SPI_MCR,
+ SPI_MCR_HALT, SPI_MCR_HALT);
+ while (regmap_read(dspi->regmap, SPI_SR, &val) >= 0 &&
+ val & SPI_SR_TXRXS)
+ ;
+ }
+
spi_finalize_current_message(ctlr);
- return status;
+ return message->status;
+}
+
+static int dspi_set_mtf(struct fsl_dspi *dspi)
+{
+ if (spi_controller_is_target(dspi->ctlr))
+ return 0;
+
+ if (dspi->mtf_enabled)
+ regmap_update_bits(dspi->regmap, SPI_MCR, SPI_MCR_MTFE,
+ SPI_MCR_MTFE);
+ else
+ regmap_update_bits(dspi->regmap, SPI_MCR, SPI_MCR_MTFE, 0);
+
+ return 0;
}
static int dspi_setup(struct spi_device *spi)
@@ -1008,9 +1281,11 @@ static int dspi_setup(struct spi_device *spi)
u32 cs_sck_delay = 0, sck_cs_delay = 0;
struct fsl_dspi_platform_data *pdata;
unsigned char pasc = 0, asc = 0;
+ struct gpio_desc *gpio_cs;
struct chip_data *chip;
unsigned long clkrate;
bool cs = true;
+ int val;
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
@@ -1023,11 +1298,19 @@ static int dspi_setup(struct spi_device *spi)
pdata = dev_get_platdata(&dspi->pdev->dev);
if (!pdata) {
- of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay",
- &cs_sck_delay);
-
- of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay",
- &sck_cs_delay);
+ val = spi_delay_to_ns(&spi->cs_setup, NULL);
+ cs_sck_delay = val >= 0 ? val : 0;
+ if (!cs_sck_delay)
+ of_property_read_u32(spi->dev.of_node,
+ "fsl,spi-cs-sck-delay",
+ &cs_sck_delay);
+
+ val = spi_delay_to_ns(&spi->cs_hold, NULL);
+ sck_cs_delay = val >= 0 ? val : 0;
+ if (!sck_cs_delay)
+ of_property_read_u32(spi->dev.of_node,
+ "fsl,spi-sck-cs-delay",
+ &sck_cs_delay);
} else {
cs_sck_delay = pdata->cs_sck_delay;
sck_cs_delay = pdata->sck_cs_delay;
@@ -1047,7 +1330,16 @@ static int dspi_setup(struct spi_device *spi)
cs_sck_delay, sck_cs_delay);
clkrate = clk_get_rate(dspi->clk);
- hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
+
+ if (is_s32g_dspi(dspi) && spi->max_speed_hz > SPI_25MHZ)
+ dspi->mtf_enabled = true;
+ else
+ dspi->mtf_enabled = false;
+
+ dspi_set_mtf(dspi);
+
+ hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate,
+ dspi->mtf_enabled);
/* Set PCS to SCK delay scale values */
ns_delay_scale(&pcssck, &cssck, cs_sck_delay, clkrate);
@@ -1061,7 +1353,7 @@ static int dspi_setup(struct spi_device *spi)
if (spi->mode & SPI_CPHA)
chip->ctar_val |= SPI_CTAR_CPHA;
- if (!spi_controller_is_slave(dspi->ctlr)) {
+ if (!spi_controller_is_target(dspi->ctlr)) {
chip->ctar_val |= SPI_CTAR_PCSSCK(pcssck) |
SPI_CTAR_CSSCK(cssck) |
SPI_CTAR_PASC(pasc) |
@@ -1069,11 +1361,17 @@ static int dspi_setup(struct spi_device *spi)
SPI_CTAR_PBR(pbr) |
SPI_CTAR_BR(br);
+ if (dspi->mtf_enabled)
+ chip->ctar_val |= SPI_CTAR_DBR;
+
if (spi->mode & SPI_LSB_FIRST)
chip->ctar_val |= SPI_CTAR_LSBFE;
}
- gpiod_direction_output(spi_get_csgpiod(spi, 0), false);
+ gpio_cs = spi_get_csgpiod(spi, 0);
+ if (gpio_cs)
+ gpiod_direction_output(gpio_cs, false);
+
dspi_deassert_cs(spi, &cs);
spi_set_ctldata(spi, chip);
@@ -1119,11 +1417,49 @@ static const struct of_device_id fsl_dspi_dt_ids[] = {
}, {
.compatible = "fsl,lx2160a-dspi",
.data = &devtype_data[LX2160A],
+ }, {
+ .compatible = "nxp,s32g2-dspi",
+ .data = &devtype_data[S32G],
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids);
+static int dspi_init(struct fsl_dspi *dspi)
+{
+ unsigned int mcr;
+
+ /* Set idle states for all chip select signals to high */
+ mcr = SPI_MCR_PCSIS(GENMASK(dspi->ctlr->max_native_cs - 1, 0));
+
+ if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
+ mcr |= SPI_MCR_XSPI;
+ if (!spi_controller_is_target(dspi->ctlr))
+ mcr |= SPI_MCR_HOST;
+
+ mcr |= SPI_MCR_HALT;
+
+ regmap_write(dspi->regmap, SPI_MCR, mcr);
+ regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
+
+ switch (dspi->devtype_data->trans_mode) {
+ case DSPI_XSPI_MODE:
+ regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_CMDTCFE);
+ break;
+ case DSPI_DMA_MODE:
+ regmap_write(dspi->regmap, SPI_RSER,
+ SPI_RSER_TFFFE | SPI_RSER_TFFFD |
+ SPI_RSER_RFDFE | SPI_RSER_RFDFD);
+ break;
+ default:
+ dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n",
+ dspi->devtype_data->trans_mode);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PM_SLEEP
static int dspi_suspend(struct device *dev)
{
@@ -1150,6 +1486,15 @@ static int dspi_resume(struct device *dev)
if (ret)
return ret;
spi_controller_resume(dspi->ctlr);
+
+ ret = dspi_init(dspi);
+ if (ret) {
+ dev_err(dev, "failed to initialize dspi during resume\n");
+ return ret;
+ }
+
+ dspi_set_mtf(dspi);
+
if (dspi->irq)
enable_irq(dspi->irq);
@@ -1159,94 +1504,13 @@ static int dspi_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
-static const struct regmap_range dspi_volatile_ranges[] = {
- regmap_reg_range(SPI_MCR, SPI_TCR),
- regmap_reg_range(SPI_SR, SPI_SR),
- regmap_reg_range(SPI_PUSHR, SPI_RXFR3),
-};
-
-static const struct regmap_access_table dspi_volatile_table = {
- .yes_ranges = dspi_volatile_ranges,
- .n_yes_ranges = ARRAY_SIZE(dspi_volatile_ranges),
-};
-
-static const struct regmap_config dspi_regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .max_register = 0x88,
- .volatile_table = &dspi_volatile_table,
-};
-
-static const struct regmap_range dspi_xspi_volatile_ranges[] = {
- regmap_reg_range(SPI_MCR, SPI_TCR),
- regmap_reg_range(SPI_SR, SPI_SR),
- regmap_reg_range(SPI_PUSHR, SPI_RXFR3),
- regmap_reg_range(SPI_SREX, SPI_SREX),
-};
-
-static const struct regmap_access_table dspi_xspi_volatile_table = {
- .yes_ranges = dspi_xspi_volatile_ranges,
- .n_yes_ranges = ARRAY_SIZE(dspi_xspi_volatile_ranges),
-};
-
-static const struct regmap_config dspi_xspi_regmap_config[] = {
- {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .max_register = 0x13c,
- .volatile_table = &dspi_xspi_volatile_table,
- },
- {
- .name = "pushr",
- .reg_bits = 16,
- .val_bits = 16,
- .reg_stride = 2,
- .max_register = 0x2,
- },
-};
-
-static int dspi_init(struct fsl_dspi *dspi)
-{
- unsigned int mcr;
-
- /* Set idle states for all chip select signals to high */
- mcr = SPI_MCR_PCSIS(GENMASK(dspi->ctlr->max_native_cs - 1, 0));
-
- if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
- mcr |= SPI_MCR_XSPI;
- if (!spi_controller_is_slave(dspi->ctlr))
- mcr |= SPI_MCR_MASTER;
-
- regmap_write(dspi->regmap, SPI_MCR, mcr);
- regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
-
- switch (dspi->devtype_data->trans_mode) {
- case DSPI_XSPI_MODE:
- regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_CMDTCFE);
- break;
- case DSPI_DMA_MODE:
- regmap_write(dspi->regmap, SPI_RSER,
- SPI_RSER_TFFFE | SPI_RSER_TFFFD |
- SPI_RSER_RFDFE | SPI_RSER_RFDFD);
- break;
- default:
- dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n",
- dspi->devtype_data->trans_mode);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int dspi_slave_abort(struct spi_master *master)
+static int dspi_target_abort(struct spi_controller *host)
{
- struct fsl_dspi *dspi = spi_master_get_devdata(master);
+ struct fsl_dspi *dspi = spi_controller_get_devdata(host);
/*
* Terminate all pending DMA transactions for the SPI working
- * in SLAVE mode.
+ * in TARGET mode.
*/
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
dmaengine_terminate_sync(dspi->dma->chan_rx);
@@ -1264,7 +1528,6 @@ static int dspi_slave_abort(struct spi_master *master)
static int dspi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- const struct regmap_config *regmap_config;
struct fsl_dspi_platform_data *pdata;
struct spi_controller *ctlr;
int ret, cs_num, bus_num = -1;
@@ -1277,7 +1540,10 @@ static int dspi_probe(struct platform_device *pdev)
if (!dspi)
return -ENOMEM;
- ctlr = spi_alloc_master(&pdev->dev, 0);
+ if (of_property_read_bool(np, "spi-slave"))
+ ctlr = spi_alloc_target(&pdev->dev, 0);
+ else
+ ctlr = spi_alloc_host(&pdev->dev, 0);
if (!ctlr)
return -ENOMEM;
@@ -1292,7 +1558,7 @@ static int dspi_probe(struct platform_device *pdev)
ctlr->dev.of_node = pdev->dev.of_node;
ctlr->cleanup = dspi_cleanup;
- ctlr->slave_abort = dspi_slave_abort;
+ ctlr->target_abort = dspi_target_abort;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
ctlr->use_gpio_descriptors = true;
@@ -1316,9 +1582,6 @@ static int dspi_probe(struct platform_device *pdev)
of_property_read_u32(np, "bus-num", &bus_num);
ctlr->bus_num = bus_num;
- if (of_property_read_bool(np, "spi-slave"))
- ctlr->slave = true;
-
dspi->devtype_data = of_device_get_match_data(&pdev->dev);
if (!dspi->devtype_data) {
dev_err(&pdev->dev, "can't get devtype_data\n");
@@ -1336,6 +1599,9 @@ static int dspi_probe(struct platform_device *pdev)
dspi->pushr_tx = 0;
}
+ if (spi_controller_is_target(ctlr) && is_s32g_dspi(dspi))
+ dspi->devtype_data = &devtype_data[S32G_TARGET];
+
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
else
@@ -1347,11 +1613,8 @@ static int dspi_probe(struct platform_device *pdev)
goto out_ctlr_put;
}
- if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
- regmap_config = &dspi_xspi_regmap_config[0];
- else
- regmap_config = &dspi_regmap_config;
- dspi->regmap = devm_regmap_init_mmio(&pdev->dev, base, regmap_config);
+ dspi->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ dspi->devtype_data->regmap);
if (IS_ERR(dspi->regmap)) {
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
PTR_ERR(dspi->regmap));
@@ -1362,7 +1625,7 @@ static int dspi_probe(struct platform_device *pdev)
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE) {
dspi->regmap_pushr = devm_regmap_init_mmio(
&pdev->dev, base + SPI_PUSHR,
- &dspi_xspi_regmap_config[1]);
+ &dspi_regmap_config[DSPI_PUSHR]);
if (IS_ERR(dspi->regmap_pushr)) {
dev_err(&pdev->dev,
"failed to init pushr regmap: %ld\n",
@@ -1372,19 +1635,16 @@ static int dspi_probe(struct platform_device *pdev)
}
}
- dspi->clk = devm_clk_get(&pdev->dev, "dspi");
+ dspi->clk = devm_clk_get_enabled(&pdev->dev, "dspi");
if (IS_ERR(dspi->clk)) {
ret = PTR_ERR(dspi->clk);
dev_err(&pdev->dev, "unable to get clock\n");
goto out_ctlr_put;
}
- ret = clk_prepare_enable(dspi->clk);
- if (ret)
- goto out_ctlr_put;
ret = dspi_init(dspi);
if (ret)
- goto out_clk_put;
+ goto out_ctlr_put;
dspi->irq = platform_get_irq(pdev, 0);
if (dspi->irq <= 0) {
@@ -1400,7 +1660,7 @@ static int dspi_probe(struct platform_device *pdev)
IRQF_SHARED, pdev->name, dspi);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to attach DSPI interrupt\n");
- goto out_clk_put;
+ goto out_ctlr_put;
}
poll_mode:
@@ -1432,8 +1692,6 @@ out_release_dma:
out_free_irq:
if (dspi->irq)
free_irq(dspi->irq, dspi);
-out_clk_put:
- clk_disable_unprepare(dspi->clk);
out_ctlr_put:
spi_controller_put(ctlr);
@@ -1458,7 +1716,6 @@ static void dspi_remove(struct platform_device *pdev)
dspi_release_dma(dspi);
if (dspi->irq)
free_irq(dspi->irq, dspi);
- clk_disable_unprepare(dspi->clk);
}
static void dspi_shutdown(struct platform_device *pdev)
@@ -1469,10 +1726,9 @@ static void dspi_shutdown(struct platform_device *pdev)
static struct platform_driver fsl_dspi_driver = {
.driver.name = DRIVER_NAME,
.driver.of_match_table = fsl_dspi_dt_ids,
- .driver.owner = THIS_MODULE,
.driver.pm = &dspi_pm,
.probe = dspi_probe,
- .remove_new = dspi_remove,
+ .remove = dspi_remove,
.shutdown = dspi_shutdown,
};
module_platform_driver(fsl_dspi_driver);
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index b3d2d3db5850..f2f1d3298e6c 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -148,7 +148,7 @@ static inline void fsl_espi_write_reg8(struct fsl_espi *espi, int offset,
static int fsl_espi_check_message(struct spi_message *m)
{
- struct fsl_espi *espi = spi_master_get_devdata(m->spi->master);
+ struct fsl_espi *espi = spi_controller_get_devdata(m->spi->controller);
struct spi_transfer *t, *first;
if (m->frame_length > SPCOM_TRANLEN_MAX) {
@@ -323,7 +323,7 @@ start:
static void fsl_espi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct fsl_espi *espi = spi_master_get_devdata(spi->master);
+ struct fsl_espi *espi = spi_controller_get_devdata(spi->controller);
int bits_per_word = t ? t->bits_per_word : spi->bits_per_word;
u32 pm, hz = t ? t->speed_hz : spi->max_speed_hz;
struct fsl_espi_cs *cs = spi_get_ctldata(spi);
@@ -351,7 +351,7 @@ static void fsl_espi_setup_transfer(struct spi_device *spi,
static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct fsl_espi *espi = spi_master_get_devdata(spi->master);
+ struct fsl_espi *espi = spi_controller_get_devdata(spi->controller);
unsigned int rx_len = t->len;
u32 mask, spcom;
int ret;
@@ -396,7 +396,7 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
{
- struct fsl_espi *espi = spi_master_get_devdata(m->spi->master);
+ struct fsl_espi *espi = spi_controller_get_devdata(m->spi->controller);
struct spi_device *spi = m->spi;
int ret;
@@ -432,7 +432,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
return ret;
}
-static int fsl_espi_do_one_msg(struct spi_master *master,
+static int fsl_espi_do_one_msg(struct spi_controller *host,
struct spi_message *m)
{
unsigned int rx_nbits = 0, delay_nsecs = 0;
@@ -470,7 +470,7 @@ out:
if (m->status == -EINPROGRESS)
m->status = ret;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return ret;
}
@@ -488,7 +488,7 @@ static int fsl_espi_setup(struct spi_device *spi)
spi_set_ctldata(spi, cs);
}
- espi = spi_master_get_devdata(spi->master);
+ espi = spi_controller_get_devdata(spi->controller);
pm_runtime_get_sync(espi->dev);
@@ -513,7 +513,6 @@ static int fsl_espi_setup(struct spi_device *spi)
fsl_espi_setup_transfer(spi, NULL);
- pm_runtime_mark_last_busy(espi->dev);
pm_runtime_put_autosuspend(espi->dev);
return 0;
@@ -584,8 +583,8 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
#ifdef CONFIG_PM
static int fsl_espi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct fsl_espi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct fsl_espi *espi = spi_controller_get_devdata(host);
u32 regval;
regval = fsl_espi_read_reg(espi, ESPI_SPMODE);
@@ -597,8 +596,8 @@ static int fsl_espi_runtime_suspend(struct device *dev)
static int fsl_espi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct fsl_espi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct fsl_espi *espi = spi_controller_get_devdata(host);
u32 regval;
regval = fsl_espi_read_reg(espi, ESPI_SPMODE);
@@ -616,8 +615,8 @@ static size_t fsl_espi_max_message_size(struct spi_device *spi)
static void fsl_espi_init_regs(struct device *dev, bool initial)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct fsl_espi *espi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct fsl_espi *espi = spi_controller_get_devdata(host);
struct device_node *nc;
u32 csmode, cs, prop;
int ret;
@@ -629,10 +628,10 @@ static void fsl_espi_init_regs(struct device *dev, bool initial)
fsl_espi_write_reg(espi, ESPI_SPIE, 0xffffffff);
/* Init eSPI CS mode register */
- for_each_available_child_of_node(master->dev.of_node, nc) {
+ for_each_available_child_of_node(host->dev.of_node, nc) {
/* get chip select */
ret = of_property_read_u32(nc, "reg", &cs);
- if (ret || cs >= master->num_chipselect)
+ if (ret || cs >= host->num_chipselect)
continue;
csmode = CSMODE_INIT_VAL;
@@ -664,28 +663,28 @@ static void fsl_espi_init_regs(struct device *dev, bool initial)
static int fsl_espi_probe(struct device *dev, struct resource *mem,
unsigned int irq, unsigned int num_cs)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct fsl_espi *espi;
int ret;
- master = spi_alloc_master(dev, sizeof(struct fsl_espi));
- if (!master)
+ host = spi_alloc_host(dev, sizeof(struct fsl_espi));
+ if (!host)
return -ENOMEM;
- dev_set_drvdata(dev, master);
+ dev_set_drvdata(dev, host);
- master->mode_bits = SPI_RX_DUAL | SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
- SPI_LSB_FIRST | SPI_LOOP;
- master->dev.of_node = dev->of_node;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
- master->setup = fsl_espi_setup;
- master->cleanup = fsl_espi_cleanup;
- master->transfer_one_message = fsl_espi_do_one_msg;
- master->auto_runtime_pm = true;
- master->max_message_size = fsl_espi_max_message_size;
- master->num_chipselect = num_cs;
+ host->mode_bits = SPI_RX_DUAL | SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
+ SPI_LSB_FIRST | SPI_LOOP;
+ host->dev.of_node = dev->of_node;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+ host->setup = fsl_espi_setup;
+ host->cleanup = fsl_espi_cleanup;
+ host->transfer_one_message = fsl_espi_do_one_msg;
+ host->auto_runtime_pm = true;
+ host->max_message_size = fsl_espi_max_message_size;
+ host->num_chipselect = num_cs;
- espi = spi_master_get_devdata(master);
+ espi = spi_controller_get_devdata(host);
spin_lock_init(&espi->lock);
espi->dev = dev;
@@ -696,8 +695,8 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
goto err_probe;
}
/* determined by clock divider fields DIV16/PM in register SPMODEx */
- master->min_speed_hz = DIV_ROUND_UP(espi->spibrg, 4 * 16 * 16);
- master->max_speed_hz = DIV_ROUND_UP(espi->spibrg, 4);
+ host->min_speed_hz = DIV_ROUND_UP(espi->spibrg, 4 * 16 * 16);
+ host->max_speed_hz = DIV_ROUND_UP(espi->spibrg, 4);
init_completion(&espi->done);
@@ -720,13 +719,12 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret < 0)
goto err_pm;
dev_info(dev, "irq = %u\n", irq);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -736,7 +734,7 @@ err_pm:
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
err_probe:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
@@ -791,10 +789,10 @@ static void of_fsl_espi_remove(struct platform_device *dev)
#ifdef CONFIG_PM_SLEEP
static int of_fsl_espi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -803,7 +801,7 @@ static int of_fsl_espi_suspend(struct device *dev)
static int of_fsl_espi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
fsl_espi_init_regs(dev, false);
@@ -812,7 +810,7 @@ static int of_fsl_espi_resume(struct device *dev)
if (ret < 0)
return ret;
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
@@ -835,7 +833,7 @@ static struct platform_driver fsl_espi_driver = {
.pm = &espi_pm,
},
.probe = of_fsl_espi_probe,
- .remove_new = of_fsl_espi_remove,
+ .remove = of_fsl_espi_remove,
};
module_platform_driver(fsl_espi_driver);
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 76e1192eb025..bb7a625db5b0 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -18,7 +18,8 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#ifdef CONFIG_FSL_SOC
#include <sysdev/fsl_soc.h>
@@ -81,18 +82,18 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
- struct spi_master *master;
+ struct spi_controller *ctlr;
struct mpc8xxx_spi *mpc8xxx_spi;
- master = dev_get_drvdata(dev);
+ ctlr = dev_get_drvdata(dev);
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
+ ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
| SPI_LSB_FIRST | SPI_LOOP;
- master->dev.of_node = dev->of_node;
+ ctlr->dev.of_node = dev->of_node;
- mpc8xxx_spi = spi_master_get_devdata(master);
+ mpc8xxx_spi = spi_controller_get_devdata(ctlr);
mpc8xxx_spi->dev = dev;
mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
@@ -103,8 +104,8 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
mpc8xxx_spi->rx_shift = 0;
mpc8xxx_spi->tx_shift = 0;
- master->bus_num = pdata->bus_num;
- master->num_chipselect = pdata->max_chipselect;
+ ctlr->bus_num = pdata->bus_num;
+ ctlr->num_chipselect = pdata->max_chipselect;
init_completion(&mpc8xxx_spi->done);
}
@@ -157,4 +158,5 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
}
EXPORT_SYMBOL_GPL(of_mpc8xxx_spi_probe);
+MODULE_DESCRIPTION("Freescale SPI/eSPI controller driver library");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 015a1abb6a84..50a07f984b23 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -103,12 +103,9 @@ extern void mpc8xxx_spi_rx_buf_u32(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
extern struct mpc8xxx_spi_probe_info *to_of_pinfo(
struct fsl_spi_platform_data *pdata);
-extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
- struct spi_transfer *t, unsigned int len);
extern const char *mpc8xxx_spi_strmode(unsigned int flags);
extern void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
unsigned int irq);
-extern int mpc8xxx_spi_remove(struct device *dev);
extern int of_mpc8xxx_spi_probe(struct platform_device *ofdev);
#endif /* __SPI_FSL_LIB_H__ */
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index fb68c72df171..065456aba2ae 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -3,8 +3,9 @@
// Freescale i.MX7ULP LPSPI driver
//
// Copyright 2016 Freescale Semiconductor, Inc.
-// Copyright 2018 NXP Semiconductors
+// Copyright 2018, 2023, 2025 NXP
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
@@ -17,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/dma/imx-dma.h>
@@ -26,6 +26,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/types.h>
+#include <linux/minmax.h>
#define DRIVER_NAME "fsl_lpspi"
@@ -71,9 +72,9 @@
#define DER_TDDE BIT(0)
#define CFGR1_PCSCFG BIT(27)
#define CFGR1_PINCFG (BIT(24)|BIT(25))
-#define CFGR1_PCSPOL BIT(8)
+#define CFGR1_PCSPOL_MASK GENMASK(11, 8)
#define CFGR1_NOSTALL BIT(3)
-#define CFGR1_MASTER BIT(0)
+#define CFGR1_HOST BIT(0)
#define FSR_TXCOUNT (0xFF)
#define RSR_RXEMPTY BIT(1)
#define TCR_CPOL BIT(31)
@@ -83,12 +84,20 @@
#define TCR_RXMSK BIT(19)
#define TCR_TXMSK BIT(18)
+#define SR_CLEAR_MASK GENMASK(13, 8)
+
+struct fsl_lpspi_devtype_data {
+ u8 prescale_max : 3; /* 0 == no limit */
+ bool query_hw_for_num_cs : 1;
+};
+
struct lpspi_config {
u8 bpw;
u8 chip_select;
u8 prescale;
u16 mode;
u32 speed_hz;
+ u32 effective_speed_hz;
};
struct fsl_lpspi_data {
@@ -97,8 +106,7 @@ struct fsl_lpspi_data {
unsigned long base_phys;
struct clk *clk_ipg;
struct clk *clk_per;
- bool is_slave;
- u32 num_cs;
+ bool is_target;
bool is_only_cs1;
bool is_first_byte;
@@ -115,16 +123,37 @@ struct fsl_lpspi_data {
struct lpspi_config config;
struct completion xfer_done;
- bool slave_aborted;
+ bool target_aborted;
/* DMA */
bool usedma;
struct completion dma_rx_completion;
struct completion dma_tx_completion;
+
+ const struct fsl_lpspi_devtype_data *devtype_data;
+};
+
+/*
+ * Devices with ERR051608 have a max TCR_PRESCALE value of 1, otherwise there is
+ * no prescale limit: https://www.nxp.com/docs/en/errata/i.MX93_1P87f.pdf
+ */
+static const struct fsl_lpspi_devtype_data imx93_lpspi_devtype_data = {
+ .prescale_max = 1,
+ .query_hw_for_num_cs = true,
+};
+
+static const struct fsl_lpspi_devtype_data imx7ulp_lpspi_devtype_data = {
+ /* All defaults */
+};
+
+static const struct fsl_lpspi_devtype_data s32g_lpspi_devtype_data = {
+ .query_hw_for_num_cs = true,
};
static const struct of_device_id fsl_lpspi_dt_ids[] = {
- { .compatible = "fsl,imx7ulp-spi", },
+ { .compatible = "fsl,imx7ulp-spi", .data = &imx7ulp_lpspi_devtype_data,},
+ { .compatible = "fsl,imx93-spi", .data = &imx93_lpspi_devtype_data,},
+ { .compatible = "nxp,s32g2-lpspi", .data = &s32g_lpspi_devtype_data,},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_lpspi_dt_ids);
@@ -215,7 +244,6 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
- pm_runtime_mark_last_busy(fsl_lpspi->dev);
pm_runtime_put_autosuspend(fsl_lpspi->dev);
return 0;
@@ -236,7 +264,7 @@ static void fsl_lpspi_write_tx_fifo(struct fsl_lpspi_data *fsl_lpspi)
}
if (txfifo_cnt < fsl_lpspi->txfifosize) {
- if (!fsl_lpspi->is_slave) {
+ if (!fsl_lpspi->is_target) {
temp = readl(fsl_lpspi->base + IMX7ULP_TCR);
temp &= ~TCR_CONTC;
writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
@@ -260,7 +288,7 @@ static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi)
temp |= fsl_lpspi->config.bpw - 1;
temp |= (fsl_lpspi->config.mode & 0x3) << 30;
temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;
- if (!fsl_lpspi->is_slave) {
+ if (!fsl_lpspi->is_target) {
temp |= fsl_lpspi->config.prescale << 27;
/*
* Set TCR_CONT will keep SS asserted after current transfer.
@@ -298,10 +326,13 @@ static void fsl_lpspi_set_watermark(struct fsl_lpspi_data *fsl_lpspi)
static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
{
struct lpspi_config config = fsl_lpspi->config;
- unsigned int perclk_rate, scldiv;
+ unsigned int perclk_rate, div;
+ u8 prescale_max;
u8 prescale;
+ int scldiv;
perclk_rate = clk_get_rate(fsl_lpspi->clk_per);
+ prescale_max = fsl_lpspi->devtype_data->prescale_max ?: 7;
if (!config.speed_hz) {
dev_err(fsl_lpspi->dev,
@@ -310,26 +341,29 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
}
if (config.speed_hz > perclk_rate / 2) {
- dev_err(fsl_lpspi->dev,
- "per-clk should be at least two times of transfer speed");
- return -EINVAL;
+ div = 2;
+ } else {
+ div = DIV_ROUND_UP(perclk_rate, config.speed_hz);
}
- for (prescale = 0; prescale < 8; prescale++) {
- scldiv = perclk_rate / config.speed_hz / (1 << prescale) - 2;
- if (scldiv < 256) {
+ for (prescale = 0; prescale <= prescale_max; prescale++) {
+ scldiv = div / (1 << prescale) - 2;
+ if (scldiv >= 0 && scldiv < 256) {
fsl_lpspi->config.prescale = prescale;
break;
}
}
- if (scldiv >= 256)
+ if (scldiv < 0 || scldiv >= 256)
return -EINVAL;
writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16),
fsl_lpspi->base + IMX7ULP_CCR);
- dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale=%d, scldiv=%d\n",
+ fsl_lpspi->config.effective_speed_hz = perclk_rate / (scldiv + 2) *
+ (1 << prescale);
+
+ dev_dbg(fsl_lpspi->dev, "perclk=%u, speed=%u, prescale=%u, scldiv=%d\n",
perclk_rate, config.speed_hz, prescale, scldiv);
return 0;
@@ -387,7 +421,7 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
u32 temp;
int ret;
- if (!fsl_lpspi->is_slave) {
+ if (!fsl_lpspi->is_target) {
ret = fsl_lpspi_set_bitrate(fsl_lpspi);
if (ret)
return ret;
@@ -395,12 +429,14 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_lpspi)
fsl_lpspi_set_watermark(fsl_lpspi);
- if (!fsl_lpspi->is_slave)
- temp = CFGR1_MASTER;
+ if (!fsl_lpspi->is_target)
+ temp = CFGR1_HOST;
else
temp = CFGR1_PINCFG;
if (fsl_lpspi->config.mode & SPI_CS_HIGH)
- temp |= CFGR1_PCSPOL;
+ temp |= FIELD_PREP(CFGR1_PCSPOL_MASK,
+ BIT(fsl_lpspi->config.chip_select));
+
writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1);
temp = readl(fsl_lpspi->base + IMX7ULP_CR);
@@ -450,10 +486,15 @@ static int fsl_lpspi_setup_transfer(struct spi_controller *controller,
fsl_lpspi->tx = fsl_lpspi_buf_tx_u32;
}
- if (t->len <= fsl_lpspi->txfifosize)
- fsl_lpspi->watermark = t->len;
- else
- fsl_lpspi->watermark = fsl_lpspi->txfifosize;
+ /*
+ * t->len is 'unsigned' and txfifosize and watermrk is 'u8', force
+ * type cast is inevitable. When len > 255, len will be truncated in min_t(),
+ * it caused wrong watermark set. 'unsigned int' is as the designated type
+ * for min_t() to avoid truncation.
+ */
+ fsl_lpspi->watermark = min_t(unsigned int,
+ fsl_lpspi->txfifosize,
+ t->len);
if (fsl_lpspi_can_dma(controller, spi, t))
fsl_lpspi->usedma = true;
@@ -463,12 +504,12 @@ static int fsl_lpspi_setup_transfer(struct spi_controller *controller,
return fsl_lpspi_config(fsl_lpspi);
}
-static int fsl_lpspi_slave_abort(struct spi_controller *controller)
+static int fsl_lpspi_target_abort(struct spi_controller *controller)
{
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
- fsl_lpspi->slave_aborted = true;
+ fsl_lpspi->target_aborted = true;
if (!fsl_lpspi->usedma)
complete(&fsl_lpspi->xfer_done);
else {
@@ -484,9 +525,9 @@ static int fsl_lpspi_wait_for_completion(struct spi_controller *controller)
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
- if (fsl_lpspi->is_slave) {
+ if (fsl_lpspi->is_target) {
if (wait_for_completion_interruptible(&fsl_lpspi->xfer_done) ||
- fsl_lpspi->slave_aborted) {
+ fsl_lpspi->target_aborted) {
dev_dbg(fsl_lpspi->dev, "interrupted\n");
return -EINTR;
}
@@ -509,14 +550,13 @@ static int fsl_lpspi_reset(struct fsl_lpspi_data *fsl_lpspi)
fsl_lpspi_intctrl(fsl_lpspi, 0);
}
- /* W1C for all flags in SR */
- temp = 0x3F << 8;
- writel(temp, fsl_lpspi->base + IMX7ULP_SR);
-
/* Clear FIFO and disable module */
temp = CR_RRF | CR_RTF;
writel(temp, fsl_lpspi->base + IMX7ULP_CR);
+ /* W1C for all flags in SR */
+ writel(SR_CLEAR_MASK, fsl_lpspi->base + IMX7ULP_SR);
+
return 0;
}
@@ -546,7 +586,7 @@ static int fsl_lpspi_calculate_timeout(struct fsl_lpspi_data *fsl_lpspi,
timeout += 1;
/* Double calculated timeout */
- return msecs_to_jiffies(2 * timeout * MSEC_PER_SEC);
+ return secs_to_jiffies(2 * timeout);
}
static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
@@ -555,7 +595,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
{
struct dma_async_tx_descriptor *desc_tx, *desc_rx;
unsigned long transfer_timeout;
- unsigned long timeout;
+ unsigned long time_left;
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
int ret;
@@ -589,16 +629,16 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
reinit_completion(&fsl_lpspi->dma_tx_completion);
dma_async_issue_pending(controller->dma_tx);
- fsl_lpspi->slave_aborted = false;
+ fsl_lpspi->target_aborted = false;
- if (!fsl_lpspi->is_slave) {
+ if (!fsl_lpspi->is_target) {
transfer_timeout = fsl_lpspi_calculate_timeout(fsl_lpspi,
transfer->len);
/* Wait eDMA to finish the data transfer.*/
- timeout = wait_for_completion_timeout(&fsl_lpspi->dma_tx_completion,
- transfer_timeout);
- if (!timeout) {
+ time_left = wait_for_completion_timeout(&fsl_lpspi->dma_tx_completion,
+ transfer_timeout);
+ if (!time_left) {
dev_err(fsl_lpspi->dev, "I/O Error in DMA TX\n");
dmaengine_terminate_all(controller->dma_tx);
dmaengine_terminate_all(controller->dma_rx);
@@ -606,9 +646,9 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
return -ETIMEDOUT;
}
- timeout = wait_for_completion_timeout(&fsl_lpspi->dma_rx_completion,
- transfer_timeout);
- if (!timeout) {
+ time_left = wait_for_completion_timeout(&fsl_lpspi->dma_rx_completion,
+ transfer_timeout);
+ if (!time_left) {
dev_err(fsl_lpspi->dev, "I/O Error in DMA RX\n");
dmaengine_terminate_all(controller->dma_tx);
dmaengine_terminate_all(controller->dma_rx);
@@ -617,7 +657,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
}
} else {
if (wait_for_completion_interruptible(&fsl_lpspi->dma_tx_completion) ||
- fsl_lpspi->slave_aborted) {
+ fsl_lpspi->target_aborted) {
dev_dbg(fsl_lpspi->dev,
"I/O Error in DMA TX interrupted\n");
dmaengine_terminate_all(controller->dma_tx);
@@ -627,7 +667,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
}
if (wait_for_completion_interruptible(&fsl_lpspi->dma_rx_completion) ||
- fsl_lpspi->slave_aborted) {
+ fsl_lpspi->target_aborted) {
dev_dbg(fsl_lpspi->dev,
"I/O Error in DMA RX interrupted\n");
dmaengine_terminate_all(controller->dma_tx);
@@ -702,17 +742,15 @@ static int fsl_lpspi_pio_transfer(struct spi_controller *controller,
fsl_lpspi->remain = t->len;
reinit_completion(&fsl_lpspi->xfer_done);
- fsl_lpspi->slave_aborted = false;
+ fsl_lpspi->target_aborted = false;
fsl_lpspi_write_tx_fifo(fsl_lpspi);
ret = fsl_lpspi_wait_for_completion(controller);
- if (ret)
- return ret;
fsl_lpspi_reset(fsl_lpspi);
- return 0;
+ return ret;
}
static int fsl_lpspi_transfer_one(struct spi_controller *controller,
@@ -728,6 +766,8 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller,
if (ret < 0)
return ret;
+ t->effective_speed_hz = fsl_lpspi->config.effective_speed_hz;
+
fsl_lpspi_set_cmd(fsl_lpspi);
fsl_lpspi->is_first_byte = false;
@@ -760,7 +800,7 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
if (temp_SR & SR_MBF ||
readl(fsl_lpspi->base + IMX7ULP_FSR) & FSR_TXCOUNT) {
writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
- fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE);
+ fsl_lpspi_intctrl(fsl_lpspi, IER_FCIE | (temp_IER & IER_TDIE));
return IRQ_HANDLED;
}
@@ -822,20 +862,26 @@ static int fsl_lpspi_init_rpm(struct fsl_lpspi_data *fsl_lpspi)
static int fsl_lpspi_probe(struct platform_device *pdev)
{
+ const struct fsl_lpspi_devtype_data *devtype_data;
struct fsl_lpspi_data *fsl_lpspi;
struct spi_controller *controller;
struct resource *res;
int ret, irq;
+ u32 num_cs;
u32 temp;
- bool is_slave;
+ bool is_target;
- is_slave = of_property_read_bool((&pdev->dev)->of_node, "spi-slave");
- if (is_slave)
- controller = spi_alloc_slave(&pdev->dev,
- sizeof(struct fsl_lpspi_data));
+ devtype_data = of_device_get_match_data(&pdev->dev);
+ if (!devtype_data)
+ return -ENODEV;
+
+ is_target = of_property_read_bool((&pdev->dev)->of_node, "spi-slave");
+ if (is_target)
+ controller = devm_spi_alloc_target(&pdev->dev,
+ sizeof(struct fsl_lpspi_data));
else
- controller = spi_alloc_master(&pdev->dev,
- sizeof(struct fsl_lpspi_data));
+ controller = devm_spi_alloc_host(&pdev->dev,
+ sizeof(struct fsl_lpspi_data));
if (!controller)
return -ENOMEM;
@@ -844,64 +890,49 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
fsl_lpspi = spi_controller_get_devdata(controller);
fsl_lpspi->dev = &pdev->dev;
- fsl_lpspi->is_slave = is_slave;
+ fsl_lpspi->is_target = is_target;
fsl_lpspi->is_only_cs1 = of_property_read_bool((&pdev->dev)->of_node,
"fsl,spi-only-use-cs1-sel");
- if (of_property_read_u32((&pdev->dev)->of_node, "num-cs",
- &fsl_lpspi->num_cs))
- fsl_lpspi->num_cs = 1;
-
- controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
- controller->transfer_one = fsl_lpspi_transfer_one;
- controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware;
- controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware;
- controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- controller->flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX;
- controller->dev.of_node = pdev->dev.of_node;
- controller->bus_num = pdev->id;
- controller->num_chipselect = fsl_lpspi->num_cs;
- controller->slave_abort = fsl_lpspi_slave_abort;
- if (!fsl_lpspi->is_slave)
- controller->use_gpio_descriptors = true;
+ fsl_lpspi->devtype_data = devtype_data;
init_completion(&fsl_lpspi->xfer_done);
fsl_lpspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(fsl_lpspi->base)) {
ret = PTR_ERR(fsl_lpspi->base);
- goto out_controller_put;
+ return ret;
}
fsl_lpspi->base_phys = res->start;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto out_controller_put;
+ return ret;
}
- ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, 0,
+ ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, IRQF_NO_AUTOEN,
dev_name(&pdev->dev), fsl_lpspi);
if (ret) {
dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret);
- goto out_controller_put;
+ return ret;
}
fsl_lpspi->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(fsl_lpspi->clk_per)) {
ret = PTR_ERR(fsl_lpspi->clk_per);
- goto out_controller_put;
+ return ret;
}
fsl_lpspi->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(fsl_lpspi->clk_ipg)) {
ret = PTR_ERR(fsl_lpspi->clk_ipg);
- goto out_controller_put;
+ return ret;
}
/* enable the clock */
ret = fsl_lpspi_init_rpm(fsl_lpspi);
if (ret)
- goto out_controller_put;
+ return ret;
ret = pm_runtime_get_sync(fsl_lpspi->dev);
if (ret < 0) {
@@ -912,18 +943,34 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
temp = readl(fsl_lpspi->base + IMX7ULP_PARAM);
fsl_lpspi->txfifosize = 1 << (temp & 0x0f);
fsl_lpspi->rxfifosize = 1 << ((temp >> 8) & 0x0f);
+ if (of_property_read_u32((&pdev->dev)->of_node, "num-cs",
+ &num_cs)) {
+ if (devtype_data->query_hw_for_num_cs)
+ num_cs = ((temp >> 16) & 0xf);
+ else
+ num_cs = 1;
+ }
+
+ controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+ controller->transfer_one = fsl_lpspi_transfer_one;
+ controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware;
+ controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware;
+ controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ controller->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
+ controller->dev.of_node = pdev->dev.of_node;
+ controller->bus_num = pdev->id;
+ controller->num_chipselect = num_cs;
+ controller->target_abort = fsl_lpspi_target_abort;
+ if (!fsl_lpspi->is_target)
+ controller->use_gpio_descriptors = true;
ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller);
if (ret == -EPROBE_DEFER)
goto out_pm_get;
- if (ret < 0)
+ if (ret < 0) {
dev_warn(&pdev->dev, "dma setup error %d, use pio\n", ret);
- else
- /*
- * disable LPSPI module IRQ when enable DMA mode successfully,
- * to prevent the unexpected LPSPI module IRQ events.
- */
- disable_irq(irq);
+ enable_irq(irq);
+ }
ret = devm_spi_register_controller(&pdev->dev, controller);
if (ret < 0) {
@@ -931,7 +978,6 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
goto free_dma;
}
- pm_runtime_mark_last_busy(fsl_lpspi->dev);
pm_runtime_put_autosuspend(fsl_lpspi->dev);
return 0;
@@ -942,8 +988,6 @@ out_pm_get:
pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
pm_runtime_put_sync(fsl_lpspi->dev);
pm_runtime_disable(fsl_lpspi->dev);
-out_controller_put:
- spi_controller_put(controller);
return ret;
}
@@ -956,16 +1000,17 @@ static void fsl_lpspi_remove(struct platform_device *pdev)
fsl_lpspi_dma_exit(controller);
+ pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
pm_runtime_disable(fsl_lpspi->dev);
}
-static int __maybe_unused fsl_lpspi_suspend(struct device *dev)
+static int fsl_lpspi_suspend(struct device *dev)
{
pinctrl_pm_select_sleep_state(dev);
return pm_runtime_force_suspend(dev);
}
-static int __maybe_unused fsl_lpspi_resume(struct device *dev)
+static int fsl_lpspi_resume(struct device *dev)
{
int ret;
@@ -983,17 +1028,17 @@ static int __maybe_unused fsl_lpspi_resume(struct device *dev)
static const struct dev_pm_ops fsl_lpspi_pm_ops = {
SET_RUNTIME_PM_OPS(fsl_lpspi_runtime_suspend,
fsl_lpspi_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(fsl_lpspi_suspend, fsl_lpspi_resume)
+ SYSTEM_SLEEP_PM_OPS(fsl_lpspi_suspend, fsl_lpspi_resume)
};
static struct platform_driver fsl_lpspi_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = fsl_lpspi_dt_ids,
- .pm = &fsl_lpspi_pm_ops,
+ .pm = pm_ptr(&fsl_lpspi_pm_ops),
},
.probe = fsl_lpspi_probe,
- .remove_new = fsl_lpspi_remove,
+ .remove = fsl_lpspi_remove,
};
module_platform_driver(fsl_lpspi_driver);
diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
index 8ade61e5ebc0..a223b4bc6e63 100644
--- a/drivers/spi/spi-fsl-qspi.c
+++ b/drivers/spi/spi-fsl-qspi.c
@@ -34,9 +34,9 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
+#include <linux/reset.h>
#include <linux/sizes.h>
#include <linux/spi/spi.h>
@@ -197,11 +197,17 @@
*/
#define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5)
+/*
+ * Do not disable the "qspi" clock when changing its rate.
+ */
+#define QUADSPI_QUIRK_SKIP_CLK_DISABLE BIT(6)
+
struct fsl_qspi_devtype_data {
unsigned int rxfifo;
unsigned int txfifo;
int invalid_mstrid;
unsigned int ahb_buf_size;
+ unsigned int sfa_size;
unsigned int quirks;
bool little_endian;
};
@@ -262,47 +268,63 @@ static const struct fsl_qspi_devtype_data ls2080a_data = {
.little_endian = true,
};
+static const struct fsl_qspi_devtype_data spacemit_k1_data = {
+ .rxfifo = SZ_128,
+ .txfifo = SZ_256,
+ .ahb_buf_size = SZ_512,
+ .sfa_size = SZ_1K,
+ .invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
+ .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_SKIP_CLK_DISABLE,
+ .little_endian = true,
+};
+
struct fsl_qspi {
void __iomem *iobase;
void __iomem *ahb_addr;
- u32 memmap_phy;
- struct clk *clk, *clk_en;
- struct device *dev;
- struct completion c;
const struct fsl_qspi_devtype_data *devtype_data;
struct mutex lock;
+ struct completion c;
+ struct reset_control *resets;
+ struct clk *clk, *clk_en;
struct pm_qos_request pm_qos_req;
+ struct device *dev;
int selected;
+ u32 memmap_phy;
};
-static inline int needs_swap_endian(struct fsl_qspi *q)
+static bool needs_swap_endian(struct fsl_qspi *q)
{
- return q->devtype_data->quirks & QUADSPI_QUIRK_SWAP_ENDIAN;
+ return !!(q->devtype_data->quirks & QUADSPI_QUIRK_SWAP_ENDIAN);
}
-static inline int needs_4x_clock(struct fsl_qspi *q)
+static bool needs_4x_clock(struct fsl_qspi *q)
{
- return q->devtype_data->quirks & QUADSPI_QUIRK_4X_INT_CLK;
+ return !!(q->devtype_data->quirks & QUADSPI_QUIRK_4X_INT_CLK);
}
-static inline int needs_fill_txfifo(struct fsl_qspi *q)
+static bool needs_fill_txfifo(struct fsl_qspi *q)
{
- return q->devtype_data->quirks & QUADSPI_QUIRK_TKT253890;
+ return !!(q->devtype_data->quirks & QUADSPI_QUIRK_TKT253890);
}
-static inline int needs_wakeup_wait_mode(struct fsl_qspi *q)
+static bool needs_wakeup_wait_mode(struct fsl_qspi *q)
{
- return q->devtype_data->quirks & QUADSPI_QUIRK_TKT245618;
+ return !!(q->devtype_data->quirks & QUADSPI_QUIRK_TKT245618);
}
-static inline int needs_amba_base_offset(struct fsl_qspi *q)
+static bool needs_amba_base_offset(struct fsl_qspi *q)
{
return !(q->devtype_data->quirks & QUADSPI_QUIRK_BASE_INTERNAL);
}
-static inline int needs_tdh_setting(struct fsl_qspi *q)
+static bool needs_tdh_setting(struct fsl_qspi *q)
{
- return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING;
+ return !!(q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING);
+}
+
+static bool needs_clk_disable(struct fsl_qspi *q)
+{
+ return !(q->devtype_data->quirks & QUADSPI_QUIRK_SKIP_CLK_DISABLE);
}
/*
@@ -368,7 +390,7 @@ static int fsl_qspi_check_buswidth(struct fsl_qspi *q, u8 width)
static bool fsl_qspi_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master);
+ struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->controller);
int ret;
ret = fsl_qspi_check_buswidth(q, op->cmd.buswidth);
@@ -523,9 +545,10 @@ static void fsl_qspi_invalidate(struct fsl_qspi *q)
qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
}
-static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi)
+static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi,
+ const struct spi_mem_op *op)
{
- unsigned long rate = spi->max_speed_hz;
+ unsigned long rate = op->max_freq;
int ret;
if (q->selected == spi_get_chipselect(spi, 0))
@@ -534,15 +557,18 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi)
if (needs_4x_clock(q))
rate *= 4;
- fsl_qspi_clk_disable_unprep(q);
+ if (needs_clk_disable(q))
+ fsl_qspi_clk_disable_unprep(q);
ret = clk_set_rate(q->clk, rate);
if (ret)
return;
- ret = fsl_qspi_clk_prep_enable(q);
- if (ret)
- return;
+ if (needs_clk_disable(q)) {
+ ret = fsl_qspi_clk_prep_enable(q);
+ if (ret)
+ return;
+ }
q->selected = spi_get_chipselect(spi, 0);
@@ -641,7 +667,7 @@ static int fsl_qspi_readl_poll_tout(struct fsl_qspi *q, void __iomem *base,
static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master);
+ struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->controller);
void __iomem *base = q->iobase;
u32 addr_offset = 0;
int err = 0;
@@ -653,7 +679,7 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
fsl_qspi_readl_poll_tout(q, base + QUADSPI_SR, (QUADSPI_SR_IP_ACC_MASK |
QUADSPI_SR_AHB_ACC_MASK), 10, 1000);
- fsl_qspi_select_mem(q, mem->spi);
+ fsl_qspi_select_mem(q, mem->spi, op);
if (needs_amba_base_offset(q))
addr_offset = q->memmap_phy;
@@ -703,7 +729,7 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
static int fsl_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master);
+ struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->controller);
if (op->data.dir == SPI_MEM_DATA_OUT) {
if (op->data.nbytes > q->devtype_data->txfifo)
@@ -722,6 +748,7 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
{
void __iomem *base = q->iobase;
u32 reg, addr_offset = 0;
+ u32 sfa_size;
int ret;
/* disable and unprepare clock to avoid glitch pass to controller */
@@ -780,17 +807,17 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
* In HW there can be a maximum of four chips on two buses with
* two chip selects on each bus. We use four chip selects in SW
* to differentiate between the four chips.
- * We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD,
- * SFB2AD accordingly.
+ *
+ * By default we write the AHB buffer size to each chip, but
+ * a different size can be specified with devtype_data->sfa_size.
+ * The SFA1AD, SFA2AD, SFB1AD, and SFB2AD registers define the
+ * top (end) of these four regions.
*/
- qspi_writel(q, q->devtype_data->ahb_buf_size + addr_offset,
- base + QUADSPI_SFA1AD);
- qspi_writel(q, q->devtype_data->ahb_buf_size * 2 + addr_offset,
- base + QUADSPI_SFA2AD);
- qspi_writel(q, q->devtype_data->ahb_buf_size * 3 + addr_offset,
- base + QUADSPI_SFB1AD);
- qspi_writel(q, q->devtype_data->ahb_buf_size * 4 + addr_offset,
- base + QUADSPI_SFB2AD);
+ sfa_size = q->devtype_data->sfa_size ? : q->devtype_data->ahb_buf_size;
+ qspi_writel(q, addr_offset + 1 * sfa_size, base + QUADSPI_SFA1AD);
+ qspi_writel(q, addr_offset + 2 * sfa_size, base + QUADSPI_SFA2AD);
+ qspi_writel(q, addr_offset + 3 * sfa_size, base + QUADSPI_SFB1AD);
+ qspi_writel(q, addr_offset + 4 * sfa_size, base + QUADSPI_SFB2AD);
q->selected = -1;
@@ -809,7 +836,7 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
static const char *fsl_qspi_get_name(struct spi_mem *mem)
{
- struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->master);
+ struct fsl_qspi *q = spi_controller_get_devdata(mem->spi->controller);
struct device *dev = &mem->spi->dev;
const char *name;
@@ -840,6 +867,30 @@ static const struct spi_controller_mem_ops fsl_qspi_mem_ops = {
.get_name = fsl_qspi_get_name,
};
+static const struct spi_controller_mem_caps fsl_qspi_mem_caps = {
+ .per_op_freq = true,
+};
+
+static void fsl_qspi_disable(void *data)
+{
+ struct fsl_qspi *q = data;
+
+ /* disable the hardware */
+ qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
+ qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER);
+}
+
+static void fsl_qspi_cleanup(void *data)
+{
+ struct fsl_qspi *q = data;
+
+ reset_control_assert(q->resets);
+
+ fsl_qspi_clk_disable_unprep(q);
+
+ mutex_destroy(&q->lock);
+}
+
static int fsl_qspi_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
@@ -849,7 +900,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
struct fsl_qspi *q;
int ret;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*q));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*q));
if (!ctlr)
return -ENOMEM;
@@ -859,106 +910,86 @@ static int fsl_qspi_probe(struct platform_device *pdev)
q = spi_controller_get_devdata(ctlr);
q->dev = dev;
q->devtype_data = of_device_get_match_data(dev);
- if (!q->devtype_data) {
- ret = -ENODEV;
- goto err_put_ctrl;
- }
+ if (!q->devtype_data)
+ return -ENODEV;
platform_set_drvdata(pdev, q);
/* find the resources */
q->iobase = devm_platform_ioremap_resource_byname(pdev, "QuadSPI");
- if (IS_ERR(q->iobase)) {
- ret = PTR_ERR(q->iobase);
- goto err_put_ctrl;
- }
+ if (IS_ERR(q->iobase))
+ return PTR_ERR(q->iobase);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"QuadSPI-memory");
- if (!res) {
- ret = -EINVAL;
- goto err_put_ctrl;
- }
+ if (!res)
+ return -EINVAL;
q->memmap_phy = res->start;
/* Since there are 4 cs, map size required is 4 times ahb_buf_size */
q->ahb_addr = devm_ioremap(dev, q->memmap_phy,
(q->devtype_data->ahb_buf_size * 4));
- if (!q->ahb_addr) {
- ret = -ENOMEM;
- goto err_put_ctrl;
- }
+ if (!q->ahb_addr)
+ return -ENOMEM;
+
+ q->resets = devm_reset_control_array_get_optional_exclusive(dev);
+ if (IS_ERR(q->resets))
+ return PTR_ERR(q->resets);
/* find the clocks */
q->clk_en = devm_clk_get(dev, "qspi_en");
- if (IS_ERR(q->clk_en)) {
- ret = PTR_ERR(q->clk_en);
- goto err_put_ctrl;
- }
+ if (IS_ERR(q->clk_en))
+ return PTR_ERR(q->clk_en);
q->clk = devm_clk_get(dev, "qspi");
- if (IS_ERR(q->clk)) {
- ret = PTR_ERR(q->clk);
- goto err_put_ctrl;
- }
+ if (IS_ERR(q->clk))
+ return PTR_ERR(q->clk);
+
+ mutex_init(&q->lock);
ret = fsl_qspi_clk_prep_enable(q);
if (ret) {
dev_err(dev, "can not enable the clock\n");
- goto err_put_ctrl;
+ return ret;
}
+ ret = devm_add_action_or_reset(dev, fsl_qspi_cleanup, q);
+ if (ret)
+ return ret;
+
+ ret = reset_control_deassert(q->resets);
+ if (ret)
+ return ret;
+
/* find the irq */
ret = platform_get_irq(pdev, 0);
if (ret < 0)
- goto err_disable_clk;
+ return ret;
ret = devm_request_irq(dev, ret,
fsl_qspi_irq_handler, 0, pdev->name, q);
if (ret) {
dev_err(dev, "failed to request irq: %d\n", ret);
- goto err_disable_clk;
+ return ret;
}
- mutex_init(&q->lock);
-
ctlr->bus_num = -1;
ctlr->num_chipselect = 4;
ctlr->mem_ops = &fsl_qspi_mem_ops;
+ ctlr->mem_caps = &fsl_qspi_mem_caps;
fsl_qspi_default_setup(q);
ctlr->dev.of_node = np;
+ ret = devm_add_action_or_reset(dev, fsl_qspi_disable, q);
+ if (ret)
+ return ret;
+
ret = devm_spi_register_controller(dev, ctlr);
if (ret)
- goto err_destroy_mutex;
+ return ret;
return 0;
-
-err_destroy_mutex:
- mutex_destroy(&q->lock);
-
-err_disable_clk:
- fsl_qspi_clk_disable_unprep(q);
-
-err_put_ctrl:
- spi_controller_put(ctlr);
-
- dev_err(dev, "Freescale QuadSPI probe failed\n");
- return ret;
-}
-
-static void fsl_qspi_remove(struct platform_device *pdev)
-{
- struct fsl_qspi *q = platform_get_drvdata(pdev);
-
- /* disable the hardware */
- qspi_writel(q, QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
- qspi_writel(q, 0x0, q->iobase + QUADSPI_RSER);
-
- fsl_qspi_clk_disable_unprep(q);
-
- mutex_destroy(&q->lock);
}
static int fsl_qspi_suspend(struct device *dev)
@@ -982,6 +1013,7 @@ static const struct of_device_id fsl_qspi_dt_ids[] = {
{ .compatible = "fsl,imx6ul-qspi", .data = &imx6ul_data, },
{ .compatible = "fsl,ls1021a-qspi", .data = &ls1021a_data, },
{ .compatible = "fsl,ls2080a-qspi", .data = &ls2080a_data, },
+ { .compatible = "spacemit,k1-qspi", .data = &spacemit_k1_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
@@ -998,7 +1030,6 @@ static struct platform_driver fsl_qspi_driver = {
.pm = &fsl_qspi_pm_ops,
},
.probe = fsl_qspi_probe,
- .remove_new = fsl_qspi_remove,
};
module_platform_driver(fsl_qspi_driver);
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 106fe60a0a50..2f2082652a1a 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -88,7 +88,7 @@ static int fsl_spi_get_type(struct device *dev)
static void fsl_spi_change_mode(struct spi_device *spi)
{
- struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mspi = spi_controller_get_devdata(spi->controller);
struct spi_mpc8xxx_cs *cs = spi->controller_state;
struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
__be32 __iomem *mode = &reg_base->mode;
@@ -183,7 +183,7 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
u32 hz = 0;
struct spi_mpc8xxx_cs *cs = spi->controller_state;
- mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
if (t) {
bits_per_word = t->bits_per_word;
@@ -249,10 +249,9 @@ static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
return 0;
}
-static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
- bool is_dma_mapped)
+static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
struct fsl_spi_reg __iomem *reg_base;
unsigned int len = t->len;
u8 bits_per_word;
@@ -274,7 +273,7 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
reinit_completion(&mpc8xxx_spi->done);
if (mpc8xxx_spi->flags & SPI_CPM_MODE)
- ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
+ ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t);
else
ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len);
if (ret)
@@ -353,7 +352,7 @@ static int fsl_spi_transfer_one(struct spi_controller *controller,
if (status < 0)
return status;
if (t->len)
- status = fsl_spi_bufs(spi, t, !!t->tx_dma || !!t->rx_dma);
+ status = fsl_spi_bufs(spi, t);
if (status > 0)
return -EMSGSIZE;
@@ -385,7 +384,7 @@ static int fsl_spi_setup(struct spi_device *spi)
spi_set_ctldata(spi, cs);
initial_setup = true;
}
- mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
reg_base = mpc8xxx_spi->reg_base;
@@ -479,7 +478,7 @@ static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
u32 slvsel;
u16 cs = spi_get_chipselect(spi, 0);
@@ -493,8 +492,8 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
static void fsl_spi_grlib_probe(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
int mbits;
u32 capabilities;
@@ -511,8 +510,8 @@ static void fsl_spi_grlib_probe(struct device *dev)
mpc8xxx_spi->native_chipselects = SPCAP_SSSZ(capabilities);
mpc8xxx_spi_write_reg(&reg_base->slvsel, 0xffffffff);
}
- master->num_chipselect = mpc8xxx_spi->native_chipselects;
- master->set_cs = fsl_spi_grlib_cs_control;
+ host->num_chipselect = mpc8xxx_spi->native_chipselects;
+ host->set_cs = fsl_spi_grlib_cs_control;
}
static void fsl_spi_cs_control(struct spi_device *spi, bool on)
@@ -526,35 +525,35 @@ static void fsl_spi_cs_control(struct spi_device *spi, bool on)
iowrite32be(on ? 0 : SPI_BOOT_SEL_BIT, pinfo->immr_spi_cs);
}
-static struct spi_master *fsl_spi_probe(struct device *dev,
+static struct spi_controller *fsl_spi_probe(struct device *dev,
struct resource *mem, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
- struct spi_master *master;
+ struct spi_controller *host;
struct mpc8xxx_spi *mpc8xxx_spi;
struct fsl_spi_reg __iomem *reg_base;
u32 regval;
int ret = 0;
- master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
- if (master == NULL) {
+ host = spi_alloc_host(dev, sizeof(struct mpc8xxx_spi));
+ if (host == NULL) {
ret = -ENOMEM;
goto err;
}
- dev_set_drvdata(dev, master);
+ dev_set_drvdata(dev, host);
mpc8xxx_spi_probe(dev, mem, irq);
- master->setup = fsl_spi_setup;
- master->cleanup = fsl_spi_cleanup;
- master->prepare_message = fsl_spi_prepare_message;
- master->transfer_one = fsl_spi_transfer_one;
- master->unprepare_message = fsl_spi_unprepare_message;
- master->use_gpio_descriptors = true;
- master->set_cs = fsl_spi_cs_control;
+ host->setup = fsl_spi_setup;
+ host->cleanup = fsl_spi_cleanup;
+ host->prepare_message = fsl_spi_prepare_message;
+ host->transfer_one = fsl_spi_transfer_one;
+ host->unprepare_message = fsl_spi_unprepare_message;
+ host->use_gpio_descriptors = true;
+ host->set_cs = fsl_spi_cs_control;
- mpc8xxx_spi = spi_master_get_devdata(master);
+ mpc8xxx_spi = spi_controller_get_devdata(host);
mpc8xxx_spi->max_bits_per_word = 32;
mpc8xxx_spi->type = fsl_spi_get_type(dev);
@@ -572,13 +571,13 @@ static struct spi_master *fsl_spi_probe(struct device *dev,
fsl_spi_grlib_probe(dev);
if (mpc8xxx_spi->flags & SPI_CPM_MODE)
- master->bits_per_word_mask =
+ host->bits_per_word_mask =
(SPI_BPW_RANGE_MASK(4, 8) | SPI_BPW_MASK(16) | SPI_BPW_MASK(32));
else
- master->bits_per_word_mask =
+ host->bits_per_word_mask =
(SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32));
- master->bits_per_word_mask &=
+ host->bits_per_word_mask &=
SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word);
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
@@ -615,19 +614,19 @@ static struct spi_master *fsl_spi_probe(struct device *dev,
mpc8xxx_spi_write_reg(&reg_base->mode, regval);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret < 0)
goto err_probe;
- dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
+ dev_info(dev, "at MMIO %pa (irq = %d), %s mode\n", &mem->start,
mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
- return master;
+ return host;
err_probe:
fsl_spi_cpm_free(mpc8xxx_spi);
err_cpm_init:
- spi_master_put(master);
+ spi_controller_put(host);
err:
return ERR_PTR(ret);
}
@@ -636,7 +635,7 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
struct device_node *np = ofdev->dev.of_node;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource mem;
int irq, type;
int ret;
@@ -689,9 +688,9 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
goto unmap_out;
}
- master = fsl_spi_probe(dev, &mem, irq);
+ host = fsl_spi_probe(dev, &mem, irq);
- return PTR_ERR_OR_ZERO(master);
+ return PTR_ERR_OR_ZERO(host);
unmap_out:
#if IS_ENABLED(CONFIG_FSL_SOC)
@@ -703,8 +702,8 @@ unmap_out:
static void of_fsl_spi_remove(struct platform_device *ofdev)
{
- struct spi_master *master = platform_get_drvdata(ofdev);
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(ofdev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
fsl_spi_cpm_free(mpc8xxx_spi);
}
@@ -715,7 +714,7 @@ static struct platform_driver of_fsl_spi_driver = {
.of_match_table = of_fsl_spi_match,
},
.probe = of_fsl_spi_probe,
- .remove_new = of_fsl_spi_remove,
+ .remove = of_fsl_spi_remove,
};
#ifdef CONFIG_MPC832x_RDB
@@ -730,7 +729,7 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
{
struct resource *mem;
int irq;
- struct spi_master *master;
+ struct spi_controller *host;
if (!dev_get_platdata(&pdev->dev))
return -EINVAL;
@@ -740,17 +739,17 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev)
return -EINVAL;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0)
- return -EINVAL;
+ if (irq < 0)
+ return irq;
- master = fsl_spi_probe(&pdev->dev, mem, irq);
- return PTR_ERR_OR_ZERO(master);
+ host = fsl_spi_probe(&pdev->dev, mem, irq);
+ return PTR_ERR_OR_ZERO(host);
}
static void plat_mpc8xxx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(host);
fsl_spi_cpm_free(mpc8xxx_spi);
}
@@ -758,7 +757,7 @@ static void plat_mpc8xxx_spi_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:mpc8xxx_spi");
static struct platform_driver mpc8xxx_spi_driver = {
.probe = plat_mpc8xxx_spi_probe,
- .remove_new = plat_mpc8xxx_spi_remove,
+ .remove = plat_mpc8xxx_spi_remove,
.driver = {
.name = "mpc8xxx_spi",
},
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 1df9d4844a68..a0d8d3425c6c 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/soc/qcom/geni-se.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>
@@ -52,6 +53,9 @@
#define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10)
#define SPI_CS_CLK_DELAY_SHFT 10
+#define SE_SPI_SLAVE_EN (0x2BC)
+#define SPI_SLAVE_EN BIT(0)
+
/* M_CMD OP codes for SPI */
#define SPI_TX_ONLY 1
#define SPI_RX_ONLY 2
@@ -99,6 +103,16 @@ struct spi_geni_master {
int cur_xfer_mode;
};
+static void spi_slv_setup(struct spi_geni_master *mas)
+{
+ struct geni_se *se = &mas->se;
+
+ writel(SPI_SLAVE_EN, se->base + SE_SPI_SLAVE_EN);
+ writel(GENI_IO_MUX_0_EN, se->base + GENI_OUTPUT_CTRL);
+ writel(START_TRIGGER, se->base + SE_GENI_CFG_SEQ_START);
+ dev_dbg(mas->dev, "spi slave setup done\n");
+}
+
static int get_spi_clk_cfg(unsigned int speed_hz,
struct spi_geni_master *mas,
unsigned int *clk_idx,
@@ -131,27 +145,37 @@ static int get_spi_clk_cfg(unsigned int speed_hz,
return ret;
}
-static void handle_se_timeout(struct spi_master *spi,
- struct spi_message *msg)
+static void handle_se_timeout(struct spi_controller *spi,
+ struct spi_message *msg)
{
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
unsigned long time_left;
struct geni_se *se = &mas->se;
const struct spi_transfer *xfer;
spin_lock_irq(&mas->lock);
- reinit_completion(&mas->cancel_done);
if (mas->cur_xfer_mode == GENI_SE_FIFO)
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
xfer = mas->cur_xfer;
mas->cur_xfer = NULL;
+
+ if (spi->target) {
+ /*
+ * skip CMD Cancel sequnece since spi target
+ * doesn`t support CMD Cancel sequnece
+ */
+ spin_unlock_irq(&mas->lock);
+ goto reset_if_dma;
+ }
+
+ reinit_completion(&mas->cancel_done);
geni_se_cancel_m_cmd(se);
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->cancel_done, HZ);
if (time_left)
- goto unmap_if_dma;
+ goto reset_if_dma;
spin_lock_irq(&mas->lock);
reinit_completion(&mas->abort_done);
@@ -169,7 +193,7 @@ static void handle_se_timeout(struct spi_master *spi,
mas->abort_failed = true;
}
-unmap_if_dma:
+reset_if_dma:
if (mas->cur_xfer_mode == GENI_SE_DMA) {
if (xfer) {
if (xfer->tx_buf) {
@@ -201,17 +225,17 @@ unmap_if_dma:
}
}
-static void handle_gpi_timeout(struct spi_master *spi, struct spi_message *msg)
+static void handle_gpi_timeout(struct spi_controller *spi, struct spi_message *msg)
{
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
dmaengine_terminate_sync(mas->tx);
dmaengine_terminate_sync(mas->rx);
}
-static void spi_geni_handle_err(struct spi_master *spi, struct spi_message *msg)
+static void spi_geni_handle_err(struct spi_controller *spi, struct spi_message *msg)
{
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
switch (mas->cur_xfer_mode) {
case GENI_SE_FIFO:
@@ -262,8 +286,8 @@ static bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas)
static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
{
- struct spi_geni_master *mas = spi_master_get_devdata(slv->master);
- struct spi_master *spi = dev_get_drvdata(mas->dev);
+ struct spi_geni_master *mas = spi_controller_get_devdata(slv->controller);
+ struct spi_controller *spi = dev_get_drvdata(mas->dev);
struct geni_se *se = &mas->se;
unsigned long time_left;
@@ -371,9 +395,9 @@ static int geni_spi_set_clock_and_bw(struct spi_geni_master *mas,
}
static int setup_fifo_params(struct spi_device *spi_slv,
- struct spi_master *spi)
+ struct spi_controller *spi)
{
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
struct geni_se *se = &mas->se;
u32 loopback_cfg = 0, cpol = 0, cpha = 0, demux_output_inv = 0;
u32 demux_sel;
@@ -410,7 +434,7 @@ static int setup_fifo_params(struct spi_device *spi_slv,
static void
spi_gsi_callback_result(void *cb, const struct dmaengine_result *result)
{
- struct spi_master *spi = cb;
+ struct spi_controller *spi = cb;
spi->cur_msg->status = -EIO;
if (result->result != DMA_TRANS_NOERROR) {
@@ -430,7 +454,7 @@ spi_gsi_callback_result(void *cb, const struct dmaengine_result *result)
}
static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas,
- struct spi_device *spi_slv, struct spi_master *spi)
+ struct spi_device *spi_slv, struct spi_controller *spi)
{
unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
struct dma_slave_config config = {};
@@ -536,12 +560,16 @@ static u32 get_xfer_len_in_words(struct spi_transfer *xfer,
static bool geni_can_dma(struct spi_controller *ctlr,
struct spi_device *slv, struct spi_transfer *xfer)
{
- struct spi_geni_master *mas = spi_master_get_devdata(slv->master);
+ struct spi_geni_master *mas = spi_controller_get_devdata(slv->controller);
u32 len, fifo_size;
if (mas->cur_xfer_mode == GENI_GPI_DMA)
return true;
+ /* Set SE DMA mode for SPI target. */
+ if (ctlr->target)
+ return true;
+
len = get_xfer_len_in_words(xfer, mas);
fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / mas->cur_bits_per_word;
@@ -551,10 +579,10 @@ static bool geni_can_dma(struct spi_controller *ctlr,
return false;
}
-static int spi_geni_prepare_message(struct spi_master *spi,
- struct spi_message *spi_msg)
+static int spi_geni_prepare_message(struct spi_controller *spi,
+ struct spi_message *spi_msg)
{
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
int ret;
switch (mas->cur_xfer_mode) {
@@ -576,6 +604,21 @@ static int spi_geni_prepare_message(struct spi_master *spi,
return -EINVAL;
}
+static void spi_geni_release_dma_chan(void *data)
+{
+ struct spi_geni_master *mas = data;
+
+ if (mas->rx) {
+ dma_release_channel(mas->rx);
+ mas->rx = NULL;
+ }
+
+ if (mas->tx) {
+ dma_release_channel(mas->tx);
+ mas->tx = NULL;
+ }
+}
+
static int spi_geni_grab_gpi_chan(struct spi_geni_master *mas)
{
int ret;
@@ -594,6 +637,12 @@ static int spi_geni_grab_gpi_chan(struct spi_geni_master *mas)
goto err_rx;
}
+ ret = devm_add_action_or_reset(mas->dev, spi_geni_release_dma_chan, mas);
+ if (ret) {
+ dev_err(mas->dev, "Unable to add action.\n");
+ return ret;
+ }
+
return 0;
err_rx:
@@ -604,21 +653,9 @@ err_tx:
return ret;
}
-static void spi_geni_release_dma_chan(struct spi_geni_master *mas)
-{
- if (mas->rx) {
- dma_release_channel(mas->rx);
- mas->rx = NULL;
- }
-
- if (mas->tx) {
- dma_release_channel(mas->tx);
- mas->tx = NULL;
- }
-}
-
static int spi_geni_init(struct spi_geni_master *mas)
{
+ struct spi_controller *spi = dev_get_drvdata(mas->dev);
struct geni_se *se = &mas->se;
unsigned int proto, major, minor, ver;
u32 spi_tx_cfg, fifo_disable;
@@ -627,7 +664,20 @@ static int spi_geni_init(struct spi_geni_master *mas)
pm_runtime_get_sync(mas->dev);
proto = geni_se_read_proto(se);
- if (proto != GENI_SE_SPI) {
+
+ if (spi->target) {
+ if (proto != GENI_SE_SPI_SLAVE) {
+ dev_err(mas->dev, "Invalid proto %d\n", proto);
+ goto out_pm;
+ }
+ spi_slv_setup(mas);
+ } else if (proto == GENI_SE_INVALID_PROTO) {
+ ret = geni_load_se_firmware(se, GENI_SE_SPI);
+ if (ret) {
+ dev_err(mas->dev, "spi master firmware load failed ret: %d\n", ret);
+ goto out_pm;
+ }
+ } else if (proto != GENI_SE_SPI) {
dev_err(mas->dev, "Invalid proto %d\n", proto);
goto out_pm;
}
@@ -679,9 +729,11 @@ static int spi_geni_init(struct spi_geni_master *mas)
}
/* We always control CS manually */
- spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG);
- spi_tx_cfg &= ~CS_TOGGLE;
- writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
+ if (!spi->target) {
+ spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG);
+ spi_tx_cfg &= ~CS_TOGGLE;
+ writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG);
+ }
out_pm:
pm_runtime_put(mas->dev);
@@ -786,7 +838,7 @@ static void geni_spi_handle_rx(struct spi_geni_master *mas)
static int setup_se_xfer(struct spi_transfer *xfer,
struct spi_geni_master *mas,
- u16 mode, struct spi_master *spi)
+ u16 mode, struct spi_controller *spi)
{
u32 m_cmd = 0;
u32 len;
@@ -875,11 +927,11 @@ static int setup_se_xfer(struct spi_transfer *xfer,
return ret;
}
-static int spi_geni_transfer_one(struct spi_master *spi,
- struct spi_device *slv,
- struct spi_transfer *xfer)
+static int spi_geni_transfer_one(struct spi_controller *spi,
+ struct spi_device *slv,
+ struct spi_transfer *xfer)
{
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
int ret;
if (spi_geni_is_abort_still_pending(mas))
@@ -901,8 +953,8 @@ static int spi_geni_transfer_one(struct spi_master *spi,
static irqreturn_t geni_spi_isr(int irq, void *data)
{
- struct spi_master *spi = data;
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct spi_controller *spi = data;
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
struct geni_se *se = &mas->se;
u32 m_irq;
@@ -1004,7 +1056,7 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
static int spi_geni_probe(struct platform_device *pdev)
{
int ret, irq;
- struct spi_master *spi;
+ struct spi_controller *spi;
struct spi_geni_master *mas;
void __iomem *base;
struct clk *clk;
@@ -1026,12 +1078,12 @@ static int spi_geni_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- spi = devm_spi_alloc_master(dev, sizeof(*mas));
+ spi = devm_spi_alloc_host(dev, sizeof(*mas));
if (!spi)
return -ENOMEM;
platform_set_drvdata(pdev, spi);
- mas = spi_master_get_devdata(spi);
+ mas = spi_controller_get_devdata(spi);
mas->irq = irq;
mas->dev = dev;
mas->se.dev = dev;
@@ -1070,31 +1122,38 @@ static int spi_geni_probe(struct platform_device *pdev)
init_completion(&mas->tx_reset_done);
init_completion(&mas->rx_reset_done);
spin_lock_init(&mas->lock);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_autosuspend_delay(&pdev->dev, 250);
- pm_runtime_enable(dev);
ret = geni_icc_get(&mas->se, NULL);
if (ret)
- goto spi_geni_probe_runtime_disable;
+ return ret;
+
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 250);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ if (device_property_read_bool(&pdev->dev, "spi-slave"))
+ spi->target = true;
+
/* Set the bus quota to a reasonable value for register access */
mas->se.icc_paths[GENI_TO_CORE].avg_bw = Bps_to_icc(CORE_2X_50_MHZ);
mas->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW;
ret = geni_icc_set_bw(&mas->se);
if (ret)
- goto spi_geni_probe_runtime_disable;
+ return ret;
ret = spi_geni_init(mas);
if (ret)
- goto spi_geni_probe_runtime_disable;
+ return ret;
/*
* check the mode supported and set_cs for fifo mode only
* for dma (gsi) mode, the gsi will set cs based on params passed in
* TRE
*/
- if (mas->cur_xfer_mode == GENI_SE_FIFO)
+ if (!spi->target && mas->cur_xfer_mode == GENI_SE_FIFO)
spi->set_cs = spi_geni_set_cs;
/*
@@ -1103,42 +1162,17 @@ static int spi_geni_probe(struct platform_device *pdev)
if (mas->cur_xfer_mode == GENI_GPI_DMA)
spi->flags = SPI_CONTROLLER_MUST_TX;
- ret = request_irq(mas->irq, geni_spi_isr, 0, dev_name(dev), spi);
- if (ret)
- goto spi_geni_release_dma;
-
- ret = spi_register_master(spi);
+ ret = devm_request_irq(dev, mas->irq, geni_spi_isr, 0, dev_name(dev), spi);
if (ret)
- goto spi_geni_probe_free_irq;
-
- return 0;
-spi_geni_probe_free_irq:
- free_irq(mas->irq, spi);
-spi_geni_release_dma:
- spi_geni_release_dma_chan(mas);
-spi_geni_probe_runtime_disable:
- pm_runtime_disable(dev);
- return ret;
-}
-
-static void spi_geni_remove(struct platform_device *pdev)
-{
- struct spi_master *spi = platform_get_drvdata(pdev);
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
-
- /* Unregister _before_ disabling pm_runtime() so we stop transfers */
- spi_unregister_master(spi);
-
- spi_geni_release_dma_chan(mas);
+ return ret;
- free_irq(mas->irq, spi);
- pm_runtime_disable(&pdev->dev);
+ return devm_spi_register_controller(dev, spi);
}
static int __maybe_unused spi_geni_runtime_suspend(struct device *dev)
{
- struct spi_master *spi = dev_get_drvdata(dev);
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct spi_controller *spi = dev_get_drvdata(dev);
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
int ret;
/* Drop the performance state vote */
@@ -1153,8 +1187,8 @@ static int __maybe_unused spi_geni_runtime_suspend(struct device *dev)
static int __maybe_unused spi_geni_runtime_resume(struct device *dev)
{
- struct spi_master *spi = dev_get_drvdata(dev);
- struct spi_geni_master *mas = spi_master_get_devdata(spi);
+ struct spi_controller *spi = dev_get_drvdata(dev);
+ struct spi_geni_master *mas = spi_controller_get_devdata(spi);
int ret;
ret = geni_icc_enable(&mas->se);
@@ -1170,30 +1204,30 @@ static int __maybe_unused spi_geni_runtime_resume(struct device *dev)
static int __maybe_unused spi_geni_suspend(struct device *dev)
{
- struct spi_master *spi = dev_get_drvdata(dev);
+ struct spi_controller *spi = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(spi);
+ ret = spi_controller_suspend(spi);
if (ret)
return ret;
ret = pm_runtime_force_suspend(dev);
if (ret)
- spi_master_resume(spi);
+ spi_controller_resume(spi);
return ret;
}
static int __maybe_unused spi_geni_resume(struct device *dev)
{
- struct spi_master *spi = dev_get_drvdata(dev);
+ struct spi_controller *spi = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
- ret = spi_master_resume(spi);
+ ret = spi_controller_resume(spi);
if (ret)
pm_runtime_force_suspend(dev);
@@ -1214,7 +1248,6 @@ MODULE_DEVICE_TABLE(of, spi_geni_dt_match);
static struct platform_driver spi_geni_driver = {
.probe = spi_geni_probe,
- .remove_new = spi_geni_remove,
.driver = {
.name = "geni_spi",
.pm = &spi_geni_pm_ops,
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 092afc7679d4..c8dadb532c40 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -1,24 +1,23 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * SPI master driver using generic bitbanged GPIO
+ * SPI host driver using generic bitbanged GPIO
*
* Copyright (C) 2006,2008 David Brownell
* Copyright (C) 2017 Linus Walleij
*/
+#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/property.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/spi/spi_gpio.h>
-
/*
- * This bitbanging SPI master driver should help make systems usable
+ * This bitbanging SPI host driver should help make systems usable
* when a native hardware SPI engine is not available, perhaps because
* its driver isn't yet working or because the I/O pins it requires
* are used for other purposes.
@@ -27,7 +26,7 @@
*
* spi->controller_state ... reserved for bitbang framework code
*
- * spi->master->dev.driver_data ... points to spi_gpio->bitbang
+ * spi->controller->dev.driver_data ... points to spi_gpio->bitbang
*/
struct spi_gpio {
@@ -40,45 +39,17 @@ struct spi_gpio {
/*----------------------------------------------------------------------*/
-/*
- * Because the overhead of going through four GPIO procedure calls
- * per transferred bit can make performance a problem, this code
- * is set up so that you can use it in either of two ways:
- *
- * - The slow generic way: set up platform_data to hold the GPIO
- * numbers used for MISO/MOSI/SCK, and issue procedure calls for
- * each of them. This driver can handle several such busses.
- *
- * - The quicker inlined way: only helps with platform GPIO code
- * that inlines operations for constant GPIOs. This can give
- * you tight (fast!) inner loops, but each such bus needs a
- * new driver. You'll define a new C file, with Makefile and
- * Kconfig support; the C code can be a total of six lines:
- *
- * #define DRIVER_NAME "myboard_spi2"
- * #define SPI_MISO_GPIO 119
- * #define SPI_MOSI_GPIO 120
- * #define SPI_SCK_GPIO 121
- * #define SPI_N_CHIPSEL 4
- * #include "spi-gpio.c"
- */
-
-#ifndef DRIVER_NAME
#define DRIVER_NAME "spi_gpio"
-#define GENERIC_BITBANG /* vs tight inlines */
-
-#endif
-
/*----------------------------------------------------------------------*/
static inline struct spi_gpio *__pure
spi_to_spi_gpio(const struct spi_device *spi)
{
- const struct spi_bitbang *bang;
+ struct spi_bitbang *bang;
struct spi_gpio *spi_gpio;
- bang = spi_master_get_devdata(spi->master);
+ bang = spi_controller_get_devdata(spi->controller);
spi_gpio = container_of(bang, struct spi_gpio, bitbang);
return spi_gpio;
}
@@ -133,7 +104,7 @@ static inline int getmiso(const struct spi_device *spi)
*/
static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
- unsigned nsecs, u32 word, u8 bits, unsigned flags)
+ unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha0(spi, nsecs, 0, flags, word, bits);
@@ -142,7 +113,7 @@ static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
}
static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi,
- unsigned nsecs, u32 word, u8 bits, unsigned flags)
+ unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha1(spi, nsecs, 0, flags, word, bits);
@@ -151,7 +122,7 @@ static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi,
}
static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi,
- unsigned nsecs, u32 word, u8 bits, unsigned flags)
+ unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha0(spi, nsecs, 1, flags, word, bits);
@@ -160,7 +131,7 @@ static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi,
}
static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
- unsigned nsecs, u32 word, u8 bits, unsigned flags)
+ unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha1(spi, nsecs, 1, flags, word, bits);
@@ -170,7 +141,7 @@ static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
/*
* These functions do not call setmosi or getmiso if respective flag
- * (SPI_MASTER_NO_RX or SPI_MASTER_NO_TX) is set, so they are safe to
+ * (SPI_CONTROLLER_NO_RX or SPI_CONTROLLER_NO_TX) is set, so they are safe to
* call when such pin is not present or defined in the controller.
* A separate set of callbacks is defined to get highest possible
* speed in the generic case (when both MISO and MOSI lines are
@@ -179,9 +150,9 @@ static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
*/
static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
- unsigned nsecs, u32 word, u8 bits, unsigned flags)
+ unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
- flags = spi->master->flags;
+ flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha0(spi, nsecs, 0, flags, word, bits);
else
@@ -189,9 +160,9 @@ static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
}
static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi,
- unsigned nsecs, u32 word, u8 bits, unsigned flags)
+ unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
- flags = spi->master->flags;
+ flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha1(spi, nsecs, 0, flags, word, bits);
else
@@ -199,9 +170,9 @@ static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi,
}
static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi,
- unsigned nsecs, u32 word, u8 bits, unsigned flags)
+ unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
- flags = spi->master->flags;
+ flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha0(spi, nsecs, 1, flags, word, bits);
else
@@ -209,9 +180,9 @@ static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi,
}
static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi,
- unsigned nsecs, u32 word, u8 bits, unsigned flags)
+ unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
- flags = spi->master->flags;
+ flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha1(spi, nsecs, 1, flags, word, bits);
else
@@ -237,11 +208,19 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
}
}
+static void spi_gpio_set_mosi_idle(struct spi_device *spi)
+{
+ struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+
+ gpiod_set_value_cansleep(spi_gpio->mosi,
+ !!(spi->mode & SPI_MOSI_IDLE_HIGH));
+}
+
static int spi_gpio_setup(struct spi_device *spi)
{
struct gpio_desc *cs;
- int status = 0;
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
+ int ret;
/*
* The CS GPIOs have already been
@@ -249,15 +228,14 @@ static int spi_gpio_setup(struct spi_device *spi)
*/
if (spi_gpio->cs_gpios) {
cs = spi_gpio->cs_gpios[spi_get_chipselect(spi, 0)];
- if (!spi->controller_state && cs)
- status = gpiod_direction_output(cs,
- !(spi->mode & SPI_CS_HIGH));
+ if (!spi->controller_state && cs) {
+ ret = gpiod_direction_output(cs, !(spi->mode & SPI_CS_HIGH));
+ if (ret)
+ return ret;
+ }
}
- if (!status)
- status = spi_bitbang_setup(spi);
-
- return status;
+ return spi_bitbang_setup(spi);
}
static int spi_gpio_set_direction(struct spi_device *spi, bool output)
@@ -311,7 +289,7 @@ static void spi_gpio_cleanup(struct spi_device *spi)
* On platforms which can do so, configure MISO with a weak pullup unless
* there's an external pullup on that signal. That saves power by avoiding
* floating signals. (A weak pulldown would save power too, but many
- * drivers expect to see all-ones data as the no slave "response".)
+ * drivers expect to see all-ones data as the no target "response".)
*/
static int spi_gpio_request(struct device *dev, struct spi_gpio *spi_gpio)
{
@@ -327,54 +305,29 @@ static int spi_gpio_request(struct device *dev, struct spi_gpio *spi_gpio)
return PTR_ERR_OR_ZERO(spi_gpio->sck);
}
-#ifdef CONFIG_OF
-static const struct of_device_id spi_gpio_dt_ids[] = {
- { .compatible = "spi-gpio" },
- {}
-};
-MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids);
-
-static int spi_gpio_probe_dt(struct platform_device *pdev,
- struct spi_master *master)
-{
- master->dev.of_node = pdev->dev.of_node;
- master->use_gpio_descriptors = true;
-
- return 0;
-}
-#else
-static inline int spi_gpio_probe_dt(struct platform_device *pdev,
- struct spi_master *master)
-{
- return 0;
-}
-#endif
-
static int spi_gpio_probe_pdata(struct platform_device *pdev,
- struct spi_master *master)
+ struct spi_controller *host)
{
struct device *dev = &pdev->dev;
struct spi_gpio_platform_data *pdata = dev_get_platdata(dev);
- struct spi_gpio *spi_gpio = spi_master_get_devdata(master);
+ struct spi_gpio *spi_gpio = spi_controller_get_devdata(host);
int i;
-#ifdef GENERIC_BITBANG
- if (!pdata || !pdata->num_chipselect)
+ if (!pdata)
return -ENODEV;
-#endif
- /*
- * The master needs to think there is a chipselect even if not
- * connected
- */
- master->num_chipselect = pdata->num_chipselect ?: 1;
- spi_gpio->cs_gpios = devm_kcalloc(dev, master->num_chipselect,
+ /* It's just one always-selected device, fine to continue */
+ if (!pdata->num_chipselect)
+ return 0;
+
+ host->num_chipselect = pdata->num_chipselect;
+ spi_gpio->cs_gpios = devm_kcalloc(dev, host->num_chipselect,
sizeof(*spi_gpio->cs_gpios),
GFP_KERNEL);
if (!spi_gpio->cs_gpios)
return -ENOMEM;
- for (i = 0; i < master->num_chipselect; i++) {
+ for (i = 0; i < host->num_chipselect; i++) {
spi_gpio->cs_gpios[i] = devm_gpiod_get_index(dev, "cs", i,
GPIOD_OUT_HIGH);
if (IS_ERR(spi_gpio->cs_gpios[i]))
@@ -387,58 +340,62 @@ static int spi_gpio_probe_pdata(struct platform_device *pdev,
static int spi_gpio_probe(struct platform_device *pdev)
{
int status;
- struct spi_master *master;
+ struct spi_controller *host;
struct spi_gpio *spi_gpio;
struct device *dev = &pdev->dev;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
struct spi_bitbang *bb;
- master = devm_spi_alloc_master(dev, sizeof(*spi_gpio));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*spi_gpio));
+ if (!host)
return -ENOMEM;
- if (pdev->dev.of_node)
- status = spi_gpio_probe_dt(pdev, master);
- else
- status = spi_gpio_probe_pdata(pdev, master);
-
- if (status)
- return status;
+ if (fwnode) {
+ device_set_node(&host->dev, fwnode);
+ host->use_gpio_descriptors = true;
+ } else {
+ status = spi_gpio_probe_pdata(pdev, host);
+ if (status)
+ return status;
+ }
- spi_gpio = spi_master_get_devdata(master);
+ spi_gpio = spi_controller_get_devdata(host);
status = spi_gpio_request(dev, spi_gpio);
if (status)
return status;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- master->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL |
- SPI_CS_HIGH | SPI_LSB_FIRST;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ host->mode_bits = SPI_3WIRE | SPI_3WIRE_HIZ | SPI_CPHA | SPI_CPOL |
+ SPI_CS_HIGH | SPI_LSB_FIRST | SPI_MOSI_IDLE_LOW |
+ SPI_MOSI_IDLE_HIGH;
if (!spi_gpio->mosi) {
/* HW configuration without MOSI pin
*
- * No setting SPI_MASTER_NO_RX here - if there is only
+ * No setting SPI_CONTROLLER_NO_RX here - if there is only
* a MOSI pin connected the host can still do RX by
* changing the direction of the line.
*/
- master->flags = SPI_MASTER_NO_TX;
+ host->flags = SPI_CONTROLLER_NO_TX;
}
- master->bus_num = pdev->id;
- master->setup = spi_gpio_setup;
- master->cleanup = spi_gpio_cleanup;
+ host->bus_num = pdev->id;
+ host->setup = spi_gpio_setup;
+ host->cleanup = spi_gpio_cleanup;
bb = &spi_gpio->bitbang;
- bb->master = master;
+ bb->ctlr = host;
/*
* There is some additional business, apart from driving the CS GPIO
* line, that we need to do on selection. This makes the local
* callback for chipselect always get called.
*/
- master->flags |= SPI_MASTER_GPIO_SS;
+ host->flags |= SPI_CONTROLLER_GPIO_SS;
bb->chipselect = spi_gpio_chipselect;
bb->set_line_direction = spi_gpio_set_direction;
+ bb->set_mosi_idle = spi_gpio_set_mosi_idle;
- if (master->flags & SPI_MASTER_NO_TX) {
+ if (host->flags & SPI_CONTROLLER_NO_TX) {
bb->txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0;
bb->txrx_word[SPI_MODE_1] = spi_gpio_spec_txrx_word_mode1;
bb->txrx_word[SPI_MODE_2] = spi_gpio_spec_txrx_word_mode2;
@@ -455,20 +412,25 @@ static int spi_gpio_probe(struct platform_device *pdev)
if (status)
return status;
- return devm_spi_register_master(&pdev->dev, master);
+ return devm_spi_register_controller(&pdev->dev, host);
}
-MODULE_ALIAS("platform:" DRIVER_NAME);
+static const struct of_device_id spi_gpio_dt_ids[] = {
+ { .compatible = "spi-gpio" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, spi_gpio_dt_ids);
static struct platform_driver spi_gpio_driver = {
.driver = {
.name = DRIVER_NAME,
- .of_match_table = of_match_ptr(spi_gpio_dt_ids),
+ .of_match_table = spi_gpio_dt_ids,
},
.probe = spi_gpio_probe,
};
module_platform_driver(spi_gpio_driver);
-MODULE_DESCRIPTION("SPI master driver using generic bitbanged GPIO ");
+MODULE_DESCRIPTION("SPI host driver using generic bitbanged GPIO ");
MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-gxp.c b/drivers/spi/spi-gxp.c
index 684d63f402f3..3aff5a166c94 100644
--- a/drivers/spi/spi-gxp.c
+++ b/drivers/spi/spi-gxp.c
@@ -3,7 +3,6 @@
#include <linux/iopoll.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
@@ -195,12 +194,12 @@ static ssize_t gxp_spi_write(struct gxp_spi_chip *chip, const struct spi_mem_op
return ret;
}
- return write_len;
+ return 0;
}
static int do_gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct gxp_spi *spifi = spi_controller_get_devdata(mem->spi->master);
+ struct gxp_spi *spifi = spi_controller_get_devdata(mem->spi->controller);
struct gxp_spi_chip *chip = &spifi->chips[spi_get_chipselect(mem->spi, 0)];
int ret;
@@ -236,7 +235,7 @@ static const struct spi_controller_mem_ops gxp_spi_mem_ops = {
static int gxp_spi_setup(struct spi_device *spi)
{
- struct gxp_spi *spifi = spi_controller_get_devdata(spi->master);
+ struct gxp_spi *spifi = spi_controller_get_devdata(spi->controller);
unsigned int cs = spi_get_chipselect(spi, 0);
struct gxp_spi_chip *chip = &spifi->chips[cs];
@@ -258,7 +257,7 @@ static int gxp_spifi_probe(struct platform_device *pdev)
data = of_device_get_match_data(&pdev->dev);
- ctlr = devm_spi_alloc_master(dev, sizeof(*spifi));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*spifi));
if (!ctlr)
return -ENOMEM;
diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c
index 2b4b3d2a22b8..dadf558dd9c0 100644
--- a/drivers/spi/spi-hisi-kunpeng.c
+++ b/drivers/spi/spi-hisi-kunpeng.c
@@ -151,8 +151,6 @@ static const struct debugfs_reg32 hisi_spi_regs[] = {
HISI_SPI_DBGFS_REG("ENR", HISI_SPI_ENR),
HISI_SPI_DBGFS_REG("FIFOC", HISI_SPI_FIFOC),
HISI_SPI_DBGFS_REG("IMR", HISI_SPI_IMR),
- HISI_SPI_DBGFS_REG("DIN", HISI_SPI_DIN),
- HISI_SPI_DBGFS_REG("DOUT", HISI_SPI_DOUT),
HISI_SPI_DBGFS_REG("SR", HISI_SPI_SR),
HISI_SPI_DBGFS_REG("RISR", HISI_SPI_RISR),
HISI_SPI_DBGFS_REG("ISR", HISI_SPI_ISR),
@@ -164,10 +162,10 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs)
{
char name[32];
- struct spi_controller *master;
+ struct spi_controller *host;
- master = container_of(hs->dev, struct spi_controller, dev);
- snprintf(name, 32, "hisi_spi%d", master->bus_num);
+ host = container_of(hs->dev, struct spi_controller, dev);
+ snprintf(name, 32, "hisi_spi%d", host->bus_num);
hs->debugfs = debugfs_create_dir(name, NULL);
if (IS_ERR(hs->debugfs))
return -ENOMEM;
@@ -291,18 +289,18 @@ static void __hisi_calc_div_reg(struct hisi_chip_data *chip)
chip->div_post = (chip->clk_div / chip->div_pre) - 1;
}
-static u32 hisi_calc_effective_speed(struct spi_controller *master,
+static u32 hisi_calc_effective_speed(struct spi_controller *host,
struct hisi_chip_data *chip, u32 speed_hz)
{
u32 effective_speed;
/* Note clock divider doesn't support odd numbers */
- chip->clk_div = DIV_ROUND_UP(master->max_speed_hz, speed_hz) + 1;
+ chip->clk_div = DIV_ROUND_UP(host->max_speed_hz, speed_hz) + 1;
chip->clk_div &= 0xfffe;
if (chip->clk_div > CLK_DIV_MAX)
chip->clk_div = CLK_DIV_MAX;
- effective_speed = master->max_speed_hz / chip->clk_div;
+ effective_speed = host->max_speed_hz / chip->clk_div;
if (chip->speed_hz != effective_speed) {
__hisi_calc_div_reg(chip);
chip->speed_hz = effective_speed;
@@ -336,20 +334,20 @@ static void hisi_spi_hw_init(struct hisi_spi *hs)
static irqreturn_t hisi_spi_irq(int irq, void *dev_id)
{
- struct spi_controller *master = dev_id;
- struct hisi_spi *hs = spi_controller_get_devdata(master);
+ struct spi_controller *host = dev_id;
+ struct hisi_spi *hs = spi_controller_get_devdata(host);
u32 irq_status = readl(hs->regs + HISI_SPI_ISR) & ISR_MASK;
if (!irq_status)
return IRQ_NONE;
- if (!master->cur_msg)
+ if (!host->cur_msg)
return IRQ_HANDLED;
/* Error handling */
if (irq_status & ISR_RXOF) {
dev_err(hs->dev, "interrupt_transfer: fifo overflow\n");
- master->cur_msg->status = -EIO;
+ host->cur_msg->status = -EIO;
goto finalize_transfer;
}
@@ -369,20 +367,20 @@ static irqreturn_t hisi_spi_irq(int irq, void *dev_id)
finalize_transfer:
hisi_spi_disable(hs);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return IRQ_HANDLED;
}
-static int hisi_spi_transfer_one(struct spi_controller *master,
+static int hisi_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi, struct spi_transfer *transfer)
{
- struct hisi_spi *hs = spi_controller_get_devdata(master);
+ struct hisi_spi *hs = spi_controller_get_devdata(host);
struct hisi_chip_data *chip = spi_get_ctldata(spi);
u32 cr = chip->cr;
/* Update per transfer options for speed and bpw */
transfer->effective_speed_hz =
- hisi_calc_effective_speed(master, chip, transfer->speed_hz);
+ hisi_calc_effective_speed(host, chip, transfer->speed_hz);
cr |= FIELD_PREP(CR_DIV_PRE_MASK, chip->div_pre);
cr |= FIELD_PREP(CR_DIV_POST_MASK, chip->div_post);
cr |= FIELD_PREP(CR_BPW_MASK, transfer->bits_per_word - 1);
@@ -409,10 +407,10 @@ static int hisi_spi_transfer_one(struct spi_controller *master,
return 1;
}
-static void hisi_spi_handle_err(struct spi_controller *master,
+static void hisi_spi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
- struct hisi_spi *hs = spi_controller_get_devdata(master);
+ struct hisi_spi *hs = spi_controller_get_devdata(host);
hisi_spi_disable(hs);
@@ -452,7 +450,7 @@ static void hisi_spi_cleanup(struct spi_device *spi)
static int hisi_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_controller *master;
+ struct spi_controller *host;
struct hisi_spi *hs;
int ret, irq;
@@ -460,13 +458,13 @@ static int hisi_spi_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- master = devm_spi_alloc_master(dev, sizeof(*hs));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*hs));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- hs = spi_controller_get_devdata(master);
+ hs = spi_controller_get_devdata(host);
hs->dev = dev;
hs->irq = irq;
@@ -474,42 +472,46 @@ static int hisi_spi_probe(struct platform_device *pdev)
if (IS_ERR(hs->regs))
return PTR_ERR(hs->regs);
- /* Specify maximum SPI clocking speed (master only) by firmware */
+ /* Specify maximum SPI clocking speed (host only) by firmware */
ret = device_property_read_u32(dev, "spi-max-frequency",
- &master->max_speed_hz);
+ &host->max_speed_hz);
if (ret) {
dev_err(dev, "failed to get max SPI clocking speed, ret=%d\n",
ret);
return -EINVAL;
}
+ if (host->max_speed_hz == 0)
+ return dev_err_probe(dev, -EINVAL, "spi-max-frequency can't be 0\n");
+
ret = device_property_read_u16(dev, "num-cs",
- &master->num_chipselect);
+ &host->num_chipselect);
if (ret)
- master->num_chipselect = DEFAULT_NUM_CS;
-
- master->use_gpio_descriptors = true;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
- master->bus_num = pdev->id;
- master->setup = hisi_spi_setup;
- master->cleanup = hisi_spi_cleanup;
- master->transfer_one = hisi_spi_transfer_one;
- master->handle_err = hisi_spi_handle_err;
- master->dev.fwnode = dev->fwnode;
+ host->num_chipselect = DEFAULT_NUM_CS;
+
+ host->use_gpio_descriptors = true;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ host->bus_num = pdev->id;
+ host->setup = hisi_spi_setup;
+ host->cleanup = hisi_spi_cleanup;
+ host->transfer_one = hisi_spi_transfer_one;
+ host->handle_err = hisi_spi_handle_err;
+ host->dev.fwnode = dev->fwnode;
+ host->min_speed_hz = DIV_ROUND_UP(host->max_speed_hz, CLK_DIV_MAX);
hisi_spi_hw_init(hs);
ret = devm_request_irq(dev, hs->irq, hisi_spi_irq, 0, dev_name(dev),
- master);
+ host);
if (ret < 0) {
dev_err(dev, "failed to get IRQ=%d, ret=%d\n", hs->irq, ret);
return ret;
}
- ret = spi_register_controller(master);
+ ret = spi_register_controller(host);
if (ret) {
- dev_err(dev, "failed to register spi master, ret=%d\n", ret);
+ dev_err(dev, "failed to register spi host, ret=%d\n", ret);
return ret;
}
@@ -518,18 +520,18 @@ static int hisi_spi_probe(struct platform_device *pdev)
dev_info(dev, "hw version:0x%x max-freq:%u kHz\n",
readl(hs->regs + HISI_SPI_VERSION),
- master->max_speed_hz / 1000);
+ host->max_speed_hz / 1000);
return 0;
}
static void hisi_spi_remove(struct platform_device *pdev)
{
- struct spi_controller *master = platform_get_drvdata(pdev);
- struct hisi_spi *hs = spi_controller_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct hisi_spi *hs = spi_controller_get_devdata(host);
debugfs_remove_recursive(hs->debugfs);
- spi_unregister_controller(master);
+ spi_unregister_controller(host);
}
static const struct acpi_device_id hisi_spi_acpi_match[] = {
@@ -540,7 +542,7 @@ MODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match);
static struct platform_driver hisi_spi_driver = {
.probe = hisi_spi_probe,
- .remove_new = hisi_spi_remove,
+ .remove = hisi_spi_remove,
.driver = {
.name = "hisi-kunpeng-spi",
.acpi_match_table = hisi_spi_acpi_match,
diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c
index 7cbcb065bb44..b2af2eed197f 100644
--- a/drivers/spi/spi-hisi-sfc-v3xx.c
+++ b/drivers/spi/spi-hisi-sfc-v3xx.c
@@ -40,7 +40,7 @@
/* Common definition of interrupt bit masks */
#define HISI_SFC_V3XX_INT_MASK_ALL (0x1ff) /* all the masks */
#define HISI_SFC_V3XX_INT_MASK_CPLT BIT(0) /* command execution complete */
-#define HISI_SFC_V3XX_INT_MASK_PP_ERR BIT(2) /* page progrom error */
+#define HISI_SFC_V3XX_INT_MASK_PP_ERR BIT(2) /* page program error */
#define HISI_SFC_V3XX_INT_MASK_IACCES BIT(5) /* error visiting inaccessible/
* protected address
*/
@@ -152,7 +152,7 @@ static int hisi_sfc_v3xx_adjust_op_size(struct spi_mem *mem,
uintptr_t addr = (uintptr_t)op->data.buf.in;
int max_byte_count;
- host = spi_controller_get_devdata(spi->master);
+ host = spi_controller_get_devdata(spi->controller);
max_byte_count = host->max_cmd_dword * 4;
@@ -174,7 +174,7 @@ static bool hisi_sfc_v3xx_supports_op(struct spi_mem *mem,
struct spi_device *spi = mem->spi;
struct hisi_sfc_v3xx_host *host;
- host = spi_controller_get_devdata(spi->master);
+ host = spi_controller_get_devdata(spi->controller);
if (op->data.buswidth > 4 || op->dummy.buswidth > 4 ||
op->addr.buswidth > 4 || op->cmd.buswidth > 4)
@@ -363,7 +363,7 @@ static int hisi_sfc_v3xx_exec_op(struct spi_mem *mem,
struct spi_device *spi = mem->spi;
u8 chip_select = spi_get_chipselect(spi, 0);
- host = spi_controller_get_devdata(spi->master);
+ host = spi_controller_get_devdata(spi->controller);
return hisi_sfc_v3xx_generic_exec_op(host, op, chip_select);
}
@@ -377,6 +377,11 @@ static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = {
static irqreturn_t hisi_sfc_v3xx_isr(int irq, void *data)
{
struct hisi_sfc_v3xx_host *host = data;
+ u32 reg;
+
+ reg = readl(host->regbase + HISI_SFC_V3XX_INT_STAT);
+ if (!reg)
+ return IRQ_NONE;
hisi_sfc_v3xx_disable_int(host);
@@ -431,7 +436,7 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
u32 version, glb_config;
int ret;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*host));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*host));
if (!ctlr)
return -ENOMEM;
@@ -448,13 +453,13 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
host->regbase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(host->regbase)) {
ret = PTR_ERR(host->regbase);
- goto err_put_master;
+ goto err_put_host;
}
host->irq = platform_get_irq_optional(pdev, 0);
if (host->irq == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
- goto err_put_master;
+ goto err_put_host;
}
hisi_sfc_v3xx_disable_int(host);
@@ -496,15 +501,15 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
ret = devm_spi_register_controller(dev, ctlr);
if (ret)
- goto err_put_master;
+ goto err_put_host;
dev_info(&pdev->dev, "hw version 0x%x, %s mode.\n",
version, host->irq ? "irq" : "polling");
return 0;
-err_put_master:
- spi_master_put(ctlr);
+err_put_host:
+ spi_controller_put(ctlr);
return ret;
}
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index d775f87770e3..168ccf51f6d4 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -86,7 +86,7 @@
struct img_spfi {
struct device *dev;
- struct spi_master *master;
+ struct spi_controller *host;
spinlock_t lock;
void __iomem *regs;
@@ -221,11 +221,11 @@ static unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf,
return count;
}
-static int img_spfi_start_pio(struct spi_master *master,
+static int img_spfi_start_pio(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ struct img_spfi *spfi = spi_controller_get_devdata(spi->controller);
unsigned int tx_bytes = 0, rx_bytes = 0;
const void *tx_buf = xfer->tx_buf;
void *rx_buf = xfer->rx_buf;
@@ -285,7 +285,7 @@ static void img_spfi_dma_rx_cb(void *data)
spin_lock_irqsave(&spfi->lock, flags);
spfi->rx_dma_busy = false;
if (!spfi->tx_dma_busy)
- spi_finalize_current_transfer(spfi->master);
+ spi_finalize_current_transfer(spfi->host);
spin_unlock_irqrestore(&spfi->lock, flags);
}
@@ -299,15 +299,15 @@ static void img_spfi_dma_tx_cb(void *data)
spin_lock_irqsave(&spfi->lock, flags);
spfi->tx_dma_busy = false;
if (!spfi->rx_dma_busy)
- spi_finalize_current_transfer(spfi->master);
+ spi_finalize_current_transfer(spfi->host);
spin_unlock_irqrestore(&spfi->lock, flags);
}
-static int img_spfi_start_dma(struct spi_master *master,
+static int img_spfi_start_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ struct img_spfi *spfi = spi_controller_get_devdata(spi->controller);
struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL;
struct dma_slave_config rxconf, txconf;
@@ -384,10 +384,10 @@ stop_dma:
return -EIO;
}
-static void img_spfi_handle_err(struct spi_master *master,
+static void img_spfi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
unsigned long flags;
/*
@@ -405,9 +405,9 @@ static void img_spfi_handle_err(struct spi_master *master,
spin_unlock_irqrestore(&spfi->lock, flags);
}
-static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
+static int img_spfi_prepare(struct spi_controller *host, struct spi_message *msg)
{
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
u32 val;
val = spfi_readl(spfi, SPFI_PORT_STATE);
@@ -427,20 +427,20 @@ static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
return 0;
}
-static int img_spfi_unprepare(struct spi_master *master,
+static int img_spfi_unprepare(struct spi_controller *host,
struct spi_message *msg)
{
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
spfi_reset(spfi);
return 0;
}
-static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
+static void img_spfi_config(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ struct img_spfi *spfi = spi_controller_get_devdata(spi->controller);
u32 val, div;
/*
@@ -476,11 +476,11 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
spfi_writel(spfi, val, SPFI_CONTROL);
}
-static int img_spfi_transfer_one(struct spi_master *master,
+static int img_spfi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ struct img_spfi *spfi = spi_controller_get_devdata(spi->controller);
int ret;
if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
@@ -490,16 +490,16 @@ static int img_spfi_transfer_one(struct spi_master *master,
return -EINVAL;
}
- img_spfi_config(master, spi, xfer);
- if (master->can_dma && master->can_dma(master, spi, xfer))
- ret = img_spfi_start_dma(master, spi, xfer);
+ img_spfi_config(host, spi, xfer);
+ if (host->can_dma && host->can_dma(host, spi, xfer))
+ ret = img_spfi_start_dma(host, spi, xfer);
else
- ret = img_spfi_start_pio(master, spi, xfer);
+ ret = img_spfi_start_pio(host, spi, xfer);
return ret;
}
-static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi,
+static bool img_spfi_can_dma(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *xfer)
{
if (xfer->len > SPFI_32BIT_FIFO_SIZE)
@@ -524,20 +524,20 @@ static irqreturn_t img_spfi_irq(int irq, void *dev_id)
static int img_spfi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct img_spfi *spfi;
struct resource *res;
int ret;
u32 max_speed_hz;
- master = spi_alloc_master(&pdev->dev, sizeof(*spfi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*spfi));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- spfi = spi_master_get_devdata(master);
+ spfi = spi_controller_get_devdata(host);
spfi->dev = &pdev->dev;
- spfi->master = master;
+ spfi->host = host;
spin_lock_init(&spfi->lock);
spfi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
@@ -582,15 +582,15 @@ static int img_spfi_probe(struct platform_device *pdev)
*/
spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_ENABLE);
- master->auto_runtime_pm = true;
- master->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL;
+ host->auto_runtime_pm = true;
+ host->bus_num = pdev->id;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL;
if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode"))
- master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD;
- master->dev.of_node = pdev->dev.of_node;
- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8);
- master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
- master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
+ host->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8);
+ host->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
+ host->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
/*
* Maximum speed supported by spfi is limited to the lower value
@@ -601,15 +601,15 @@ static int img_spfi_probe(struct platform_device *pdev)
*/
if (!of_property_read_u32(spfi->dev->of_node, "spfi-max-frequency",
&max_speed_hz)) {
- if (master->max_speed_hz > max_speed_hz)
- master->max_speed_hz = max_speed_hz;
+ if (host->max_speed_hz > max_speed_hz)
+ host->max_speed_hz = max_speed_hz;
}
- master->transfer_one = img_spfi_transfer_one;
- master->prepare_message = img_spfi_prepare;
- master->unprepare_message = img_spfi_unprepare;
- master->handle_err = img_spfi_handle_err;
- master->use_gpio_descriptors = true;
+ host->transfer_one = img_spfi_transfer_one;
+ host->prepare_message = img_spfi_prepare;
+ host->unprepare_message = img_spfi_unprepare;
+ host->handle_err = img_spfi_handle_err;
+ host->use_gpio_descriptors = true;
spfi->tx_ch = dma_request_chan(spfi->dev, "tx");
if (IS_ERR(spfi->tx_ch)) {
@@ -636,15 +636,15 @@ static int img_spfi_probe(struct platform_device *pdev)
spfi->rx_ch = NULL;
dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n");
} else {
- master->dma_tx = spfi->tx_ch;
- master->dma_rx = spfi->rx_ch;
- master->can_dma = img_spfi_can_dma;
+ host->dma_tx = spfi->tx_ch;
+ host->dma_rx = spfi->rx_ch;
+ host->can_dma = img_spfi_can_dma;
}
pm_runtime_set_active(spfi->dev);
pm_runtime_enable(spfi->dev);
- ret = devm_spi_register_master(spfi->dev, master);
+ ret = devm_spi_register_controller(spfi->dev, host);
if (ret)
goto disable_pm;
@@ -660,15 +660,15 @@ disable_pm:
disable_pclk:
clk_disable_unprepare(spfi->sys_clk);
put_spi:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static void img_spfi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
if (spfi->tx_ch)
dma_release_channel(spfi->tx_ch);
@@ -685,8 +685,8 @@ static void img_spfi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int img_spfi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
clk_disable_unprepare(spfi->spfi_clk);
clk_disable_unprepare(spfi->sys_clk);
@@ -696,8 +696,8 @@ static int img_spfi_runtime_suspend(struct device *dev)
static int img_spfi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(spfi->sys_clk);
@@ -716,15 +716,15 @@ static int img_spfi_runtime_resume(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int img_spfi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
- return spi_master_suspend(master);
+ return spi_controller_suspend(host);
}
static int img_spfi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct img_spfi *spfi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct img_spfi *spfi = spi_controller_get_devdata(host);
int ret;
ret = pm_runtime_resume_and_get(dev);
@@ -733,7 +733,7 @@ static int img_spfi_resume(struct device *dev)
spfi_reset(spfi);
pm_runtime_put(dev);
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
@@ -756,7 +756,7 @@ static struct platform_driver img_spfi_driver = {
.of_match_table = of_match_ptr(img_spfi_of_match),
},
.probe = img_spfi_probe,
- .remove_new = img_spfi_remove,
+ .remove = img_spfi_remove,
};
module_platform_driver(img_spfi_driver);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 528ae46c087f..b8b79bb7fec3 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -2,6 +2,8 @@
// Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
// Copyright (C) 2008 Juergen Beisert
+#include <linux/bits.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
@@ -12,7 +14,10 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
+#include <linux/math.h>
+#include <linux/math64.h>
#include <linux/module.h>
+#include <linux/overflow.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -20,7 +25,6 @@
#include <linux/spi/spi.h>
#include <linux/types.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/property.h>
#include <linux/dma/imx-dma.h>
@@ -38,6 +42,7 @@ MODULE_PARM_DESC(polling_limit_us,
"time in us to run a transfer in polling mode\n");
#define MXC_RPM_TIMEOUT 2000 /* 2000ms */
+#define MXC_SPI_DEFAULT_SPEED 500000 /* 500KHz */
#define MXC_CSPIRXDATA 0x00
#define MXC_CSPITXDATA 0x04
@@ -53,7 +58,7 @@ MODULE_PARM_DESC(polling_limit_us,
/* The maximum bytes that a sdma BD can transfer. */
#define MAX_SDMA_BD_BYTES (1 << 15)
#define MX51_ECSPI_CTRL_MAX_BURST 512
-/* The maximum bytes that IMX53_ECSPI can transfer in slave mode.*/
+/* The maximum bytes that IMX53_ECSPI can transfer in target mode.*/
#define MX53_MAX_TRANSFER_BYTES 512
enum spi_imx_devtype {
@@ -71,14 +76,15 @@ struct spi_imx_data;
struct spi_imx_devtype_data {
void (*intctrl)(struct spi_imx_data *spi_imx, int enable);
int (*prepare_message)(struct spi_imx_data *spi_imx, struct spi_message *msg);
- int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi);
+ int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi,
+ struct spi_transfer *t);
void (*trigger)(struct spi_imx_data *spi_imx);
int (*rx_available)(struct spi_imx_data *spi_imx);
void (*reset)(struct spi_imx_data *spi_imx);
void (*setup_wml)(struct spi_imx_data *spi_imx);
void (*disable)(struct spi_imx_data *spi_imx);
bool has_dmamode;
- bool has_slavemode;
+ bool has_targetmode;
unsigned int fifo_size;
bool dynamic_burst;
/*
@@ -114,10 +120,10 @@ struct spi_imx_data {
unsigned int dynamic_burst;
bool rx_only;
- /* Slave mode */
- bool slave_mode;
- bool slave_aborted;
- unsigned int slave_burst;
+ /* Target mode */
+ bool target_mode;
+ bool target_aborted;
+ unsigned int target_burst;
/* DMA */
bool usedma;
@@ -241,7 +247,7 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
if (!controller->dma_rx)
return false;
- if (spi_imx->slave_mode)
+ if (spi_imx->target_mode)
return false;
if (transfer->len < spi_imx->devtype_data->fifo_size)
@@ -301,6 +307,18 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
#define MX51_ECSPI_STAT 0x18
#define MX51_ECSPI_STAT_RR (1 << 3)
+#define MX51_ECSPI_PERIOD 0x1c
+#define MX51_ECSPI_PERIOD_MASK 0x7fff
+/*
+ * As measured on the i.MX6, the SPI host controller inserts a 4 SPI-Clock
+ * (SCLK) delay after each burst if the PERIOD reg is 0x0. This value will be
+ * called MX51_ECSPI_PERIOD_MIN_DELAY_SCK.
+ *
+ * If the PERIOD register is != 0, the controller inserts a delay of
+ * MX51_ECSPI_PERIOD_MIN_DELAY_SCK + register value + 1 SCLK after each burst.
+ */
+#define MX51_ECSPI_PERIOD_MIN_DELAY_SCK 4
+
#define MX51_ECSPI_TESTREG 0x20
#define MX51_ECSPI_TESTREG_LBC BIT(31)
@@ -405,12 +423,19 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
writel(val, spi_imx->base + MXC_CSPITXDATA);
}
-static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
+static void mx53_ecspi_rx_target(struct spi_imx_data *spi_imx)
{
- u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA));
+ u32 val = readl(spi_imx->base + MXC_CSPIRXDATA);
+#ifdef __LITTLE_ENDIAN
+ unsigned int bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+ if (bytes_per_word == 1)
+ swab32s(&val);
+ else if (bytes_per_word == 2)
+ swahw32s(&val);
+#endif
if (spi_imx->rx_buf) {
- int n_bytes = spi_imx->slave_burst % sizeof(val);
+ int n_bytes = spi_imx->target_burst % sizeof(val);
if (!n_bytes)
n_bytes = sizeof(val);
@@ -419,16 +444,19 @@ static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
((u8 *)&val) + sizeof(val) - n_bytes, n_bytes);
spi_imx->rx_buf += n_bytes;
- spi_imx->slave_burst -= n_bytes;
+ spi_imx->target_burst -= n_bytes;
}
spi_imx->remainder -= sizeof(u32);
}
-static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
+static void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx)
{
u32 val = 0;
int n_bytes = spi_imx->count % sizeof(val);
+#ifdef __LITTLE_ENDIAN
+ unsigned int bytes_per_word;
+#endif
if (!n_bytes)
n_bytes = sizeof(val);
@@ -436,12 +464,18 @@ static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
if (spi_imx->tx_buf) {
memcpy(((u8 *)&val) + sizeof(val) - n_bytes,
spi_imx->tx_buf, n_bytes);
- val = cpu_to_be32(val);
spi_imx->tx_buf += n_bytes;
}
spi_imx->count -= n_bytes;
+#ifdef __LITTLE_ENDIAN
+ bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
+ if (bytes_per_word == 1)
+ swab32s(&val);
+ else if (bytes_per_word == 2)
+ swahw32s(&val);
+#endif
writel(val, spi_imx->base + MXC_CSPITXDATA);
}
@@ -503,9 +537,15 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
{
u32 reg;
- reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
- reg |= MX51_ECSPI_CTRL_XCH;
- writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
+ if (spi_imx->usedma) {
+ reg = readl(spi_imx->base + MX51_ECSPI_DMA);
+ reg |= MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN;
+ writel(reg, spi_imx->base + MX51_ECSPI_DMA);
+ } else {
+ reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
+ reg |= MX51_ECSPI_CTRL_XCH;
+ writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
+ }
}
static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
@@ -536,8 +576,8 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
u32 current_cfg = cfg;
int channel = mx51_ecspi_channel(spi);
- /* set Master or Slave mode */
- if (spi_imx->slave_mode)
+ /* set Host or Target mode */
+ if (spi_imx->target_mode)
ctrl &= ~MX51_ECSPI_CTRL_MODE_MASK;
else
ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
@@ -565,11 +605,11 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
writel(testreg, spi_imx->base + MX51_ECSPI_TESTREG);
/*
- * eCSPI burst completion by Chip Select signal in Slave mode
+ * eCSPI burst completion by Chip Select signal in Target mode
* is not functional for imx53 Soc, config SPI burst completed when
* BURST_LENGTH + 1 bits are received
*/
- if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
+ if (spi_imx->target_mode)
cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(channel);
else
cfg |= MX51_ECSPI_CONFIG_SBBCTRL(channel);
@@ -649,25 +689,30 @@ static void mx51_configure_cpha(struct spi_imx_data *spi_imx,
}
static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
- struct spi_device *spi)
+ struct spi_device *spi, struct spi_transfer *t)
{
u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
+ u64 word_delay_sck;
u32 clk;
/* Clear BL field and set the right value */
ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
- if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
- ctrl |= (spi_imx->slave_burst * 8 - 1)
+ if (spi_imx->target_mode)
+ ctrl |= (spi_imx->target_burst * 8 - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
- else
+ else {
ctrl |= (spi_imx->bits_per_word - 1)
<< MX51_ECSPI_CTRL_BL_OFFSET;
+ }
/* set clock speed */
ctrl &= ~(0xf << MX51_ECSPI_CTRL_POSTDIV_OFFSET |
0xf << MX51_ECSPI_CTRL_PREDIV_OFFSET);
- ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk);
- spi_imx->spi_bus_clk = clk;
+
+ if (!spi_imx->target_mode) {
+ ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk);
+ spi_imx->spi_bus_clk = clk;
+ }
mx51_configure_cpha(spi_imx, spi);
@@ -682,6 +727,49 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+ /* calculate word delay in SPI Clock (SCLK) cycles */
+ if (t->word_delay.value == 0) {
+ word_delay_sck = 0;
+ } else if (t->word_delay.unit == SPI_DELAY_UNIT_SCK) {
+ word_delay_sck = t->word_delay.value;
+
+ if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK)
+ word_delay_sck = 0;
+ else if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1)
+ word_delay_sck = 1;
+ else
+ word_delay_sck -= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1;
+ } else {
+ int word_delay_ns;
+
+ word_delay_ns = spi_delay_to_ns(&t->word_delay, t);
+ if (word_delay_ns < 0)
+ return word_delay_ns;
+
+ if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC,
+ MX51_ECSPI_PERIOD_MIN_DELAY_SCK,
+ spi_imx->spi_bus_clk)) {
+ word_delay_sck = 0;
+ } else if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC,
+ MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1,
+ spi_imx->spi_bus_clk)) {
+ word_delay_sck = 1;
+ } else {
+ word_delay_ns -= mul_u64_u32_div(NSEC_PER_SEC,
+ MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1,
+ spi_imx->spi_bus_clk);
+
+ word_delay_sck = DIV_U64_ROUND_UP((u64)word_delay_ns * spi_imx->spi_bus_clk,
+ NSEC_PER_SEC);
+ }
+ }
+
+ if (!FIELD_FIT(MX51_ECSPI_PERIOD_MASK, word_delay_sck))
+ return -EINVAL;
+
+ writel(FIELD_PREP(MX51_ECSPI_PERIOD_MASK, word_delay_sck),
+ spi_imx->base + MX51_ECSPI_PERIOD);
+
return 0;
}
@@ -698,7 +786,6 @@ static void mx51_setup_wml(struct spi_imx_data *spi_imx)
writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |
MX51_ECSPI_DMA_TX_WML(tx_wml) |
MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
- MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
}
@@ -718,7 +805,7 @@ static void mx51_ecspi_reset(struct spi_imx_data *spi_imx)
#define MX31_INTREG_RREN (1 << 3)
#define MX31_CSPICTRL_ENABLE (1 << 0)
-#define MX31_CSPICTRL_MASTER (1 << 1)
+#define MX31_CSPICTRL_HOST (1 << 1)
#define MX31_CSPICTRL_XCH (1 << 2)
#define MX31_CSPICTRL_SMC (1 << 3)
#define MX31_CSPICTRL_POL (1 << 4)
@@ -773,9 +860,9 @@ static int mx31_prepare_message(struct spi_imx_data *spi_imx,
}
static int mx31_prepare_transfer(struct spi_imx_data *spi_imx,
- struct spi_device *spi)
+ struct spi_device *spi, struct spi_transfer *t)
{
- unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
+ unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_HOST;
unsigned int clk;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
@@ -845,7 +932,7 @@ static void mx31_reset(struct spi_imx_data *spi_imx)
#define MX21_CSPICTRL_SSPOL (1 << 8)
#define MX21_CSPICTRL_XCH (1 << 9)
#define MX21_CSPICTRL_ENABLE (1 << 10)
-#define MX21_CSPICTRL_MASTER (1 << 11)
+#define MX21_CSPICTRL_HOST (1 << 11)
#define MX21_CSPICTRL_DR_SHIFT 14
#define MX21_CSPICTRL_CS_SHIFT 19
@@ -877,9 +964,9 @@ static int mx21_prepare_message(struct spi_imx_data *spi_imx,
}
static int mx21_prepare_transfer(struct spi_imx_data *spi_imx,
- struct spi_device *spi)
+ struct spi_device *spi, struct spi_transfer *t)
{
- unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER;
+ unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_HOST;
unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
unsigned int clk;
@@ -921,7 +1008,7 @@ static void mx21_reset(struct spi_imx_data *spi_imx)
#define MX1_CSPICTRL_PHA (1 << 5)
#define MX1_CSPICTRL_XCH (1 << 8)
#define MX1_CSPICTRL_ENABLE (1 << 9)
-#define MX1_CSPICTRL_MASTER (1 << 10)
+#define MX1_CSPICTRL_HOST (1 << 10)
#define MX1_CSPICTRL_DR_SHIFT 13
static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
@@ -952,9 +1039,9 @@ static int mx1_prepare_message(struct spi_imx_data *spi_imx,
}
static int mx1_prepare_transfer(struct spi_imx_data *spi_imx,
- struct spi_device *spi)
+ struct spi_device *spi, struct spi_transfer *t)
{
- unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
+ unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_HOST;
unsigned int clk;
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
@@ -993,7 +1080,7 @@ static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX1_CSPI,
};
@@ -1007,7 +1094,7 @@ static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX21_CSPI,
};
@@ -1022,7 +1109,7 @@ static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX27_CSPI,
};
@@ -1036,7 +1123,7 @@ static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
.fifo_size = 8,
.has_dmamode = false,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX31_CSPI,
};
@@ -1049,9 +1136,9 @@ static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
.rx_available = mx31_rx_available,
.reset = mx31_reset,
.fifo_size = 8,
- .has_dmamode = true,
+ .has_dmamode = false,
.dynamic_burst = false,
- .has_slavemode = false,
+ .has_targetmode = false,
.devtype = IMX35_CSPI,
};
@@ -1066,7 +1153,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.fifo_size = 64,
.has_dmamode = true,
.dynamic_burst = true,
- .has_slavemode = true,
+ .has_targetmode = true,
.disable = mx51_ecspi_disable,
.devtype = IMX51_ECSPI,
};
@@ -1080,7 +1167,7 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
.reset = mx51_ecspi_reset,
.fifo_size = 64,
.has_dmamode = true,
- .has_slavemode = true,
+ .has_targetmode = true,
.disable = mx51_ecspi_disable,
.devtype = IMX53_ECSPI,
};
@@ -1096,7 +1183,7 @@ static struct spi_imx_devtype_data imx6ul_ecspi_devtype_data = {
.fifo_size = 64,
.has_dmamode = true,
.dynamic_burst = true,
- .has_slavemode = true,
+ .has_targetmode = true,
.tx_glitch_fixed = true,
.disable = mx51_ecspi_disable,
.devtype = IMX51_ECSPI,
@@ -1161,7 +1248,7 @@ static void spi_imx_push(struct spi_imx_data *spi_imx)
spi_imx->txfifo++;
}
- if (!spi_imx->slave_mode)
+ if (!spi_imx->target_mode)
spi_imx->devtype_data->trigger(spi_imx);
}
@@ -1247,25 +1334,31 @@ static int spi_imx_setupxfer(struct spi_device *spi,
if (!t)
return 0;
- if (!t->speed_hz) {
- if (!spi->max_speed_hz) {
- dev_err(&spi->dev, "no speed_hz provided!\n");
- return -EINVAL;
+ if (!spi_imx->target_mode) {
+ if (!t->speed_hz) {
+ if (!spi->max_speed_hz) {
+ dev_err(&spi->dev, "no speed_hz provided!\n");
+ return -EINVAL;
+ }
+ dev_dbg(&spi->dev, "using spi->max_speed_hz!\n");
+ spi_imx->spi_bus_clk = spi->max_speed_hz;
+ } else {
+ spi_imx->spi_bus_clk = t->speed_hz;
}
- dev_dbg(&spi->dev, "using spi->max_speed_hz!\n");
- spi_imx->spi_bus_clk = spi->max_speed_hz;
- } else
- spi_imx->spi_bus_clk = t->speed_hz;
+ }
spi_imx->bits_per_word = t->bits_per_word;
+ spi_imx->count = t->len;
/*
* Initialize the functions for transfer. To transfer non byte-aligned
- * words, we have to use multiple word-size bursts, we can't use
- * dynamic_burst in that case.
+ * words, we have to use multiple word-size bursts. To insert word
+ * delay, the burst size has to equal the word size. We can't use
+ * dynamic_burst in these cases.
*/
- if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode &&
+ if (spi_imx->devtype_data->dynamic_burst && !spi_imx->target_mode &&
!(spi->mode & SPI_CS_WORD) &&
+ !(t->word_delay.value) &&
(spi_imx->bits_per_word == 8 ||
spi_imx->bits_per_word == 16 ||
spi_imx->bits_per_word == 32)) {
@@ -1296,13 +1389,13 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->rx_only = ((t->tx_buf == NULL)
|| (t->tx_buf == spi->controller->dummy_tx));
- if (is_imx53_ecspi(spi_imx) && spi_imx->slave_mode) {
- spi_imx->rx = mx53_ecspi_rx_slave;
- spi_imx->tx = mx53_ecspi_tx_slave;
- spi_imx->slave_burst = t->len;
+ if (spi_imx->target_mode) {
+ spi_imx->rx = mx53_ecspi_rx_target;
+ spi_imx->tx = mx53_ecspi_tx_target;
+ spi_imx->target_burst = t->len;
}
- spi_imx->devtype_data->prepare_transfer(spi_imx, spi);
+ spi_imx->devtype_data->prepare_transfer(spi_imx, spi, t);
return 0;
}
@@ -1333,7 +1426,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
controller->dma_tx = dma_request_chan(dev, "tx");
if (IS_ERR(controller->dma_tx)) {
ret = PTR_ERR(controller->dma_tx);
- dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
+ dev_err_probe(dev, ret, "can't get the TX DMA channel!\n");
controller->dma_tx = NULL;
goto err;
}
@@ -1342,7 +1435,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
controller->dma_rx = dma_request_chan(dev, "rx");
if (IS_ERR(controller->dma_rx)) {
ret = PTR_ERR(controller->dma_rx);
- dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
+ dev_err_probe(dev, ret, "can't get the RX DMA channel!\n");
controller->dma_rx = NULL;
goto err;
}
@@ -1385,7 +1478,7 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
timeout += 1;
/* Double calculated timeout */
- return msecs_to_jiffies(2 * timeout * MSEC_PER_SEC);
+ return secs_to_jiffies(2 * timeout);
}
static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
@@ -1393,7 +1486,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
{
struct dma_async_tx_descriptor *desc_tx, *desc_rx;
unsigned long transfer_timeout;
- unsigned long timeout;
+ unsigned long time_left;
struct spi_controller *controller = spi_imx->controller;
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
@@ -1456,21 +1549,23 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
reinit_completion(&spi_imx->dma_tx_completion);
dma_async_issue_pending(controller->dma_tx);
+ spi_imx->devtype_data->trigger(spi_imx);
+
transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
/* Wait SDMA to finish the data transfer.*/
- timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
+ time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
transfer_timeout);
- if (!timeout) {
+ if (!time_left) {
dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
dmaengine_terminate_all(controller->dma_tx);
dmaengine_terminate_all(controller->dma_rx);
return -ETIMEDOUT;
}
- timeout = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
- transfer_timeout);
- if (!timeout) {
+ time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
+ transfer_timeout);
+ if (!time_left) {
dev_err(&controller->dev, "I/O Error in DMA RX\n");
spi_imx->devtype_data->reset(spi_imx);
dmaengine_terminate_all(controller->dma_rx);
@@ -1489,7 +1584,7 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
{
struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
unsigned long transfer_timeout;
- unsigned long timeout;
+ unsigned long time_left;
spi_imx->tx_buf = transfer->tx_buf;
spi_imx->rx_buf = transfer->rx_buf;
@@ -1505,9 +1600,9 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
- timeout = wait_for_completion_timeout(&spi_imx->xfer_done,
- transfer_timeout);
- if (!timeout) {
+ time_left = wait_for_completion_timeout(&spi_imx->xfer_done,
+ transfer_timeout);
+ if (!time_left) {
dev_err(&spi->dev, "I/O Error in PIO\n");
spi_imx->devtype_data->reset(spi_imx);
return -ETIMEDOUT;
@@ -1564,14 +1659,13 @@ static int spi_imx_poll_transfer(struct spi_device *spi,
return 0;
}
-static int spi_imx_pio_transfer_slave(struct spi_device *spi,
- struct spi_transfer *transfer)
+static int spi_imx_pio_transfer_target(struct spi_device *spi,
+ struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
int ret = 0;
- if (is_imx53_ecspi(spi_imx) &&
- transfer->len > MX53_MAX_TRANSFER_BYTES) {
+ if (transfer->len > MX53_MAX_TRANSFER_BYTES) {
dev_err(&spi->dev, "Transaction too big, max size is %d bytes\n",
MX53_MAX_TRANSFER_BYTES);
return -EMSGSIZE;
@@ -1584,22 +1678,22 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi,
spi_imx->remainder = 0;
reinit_completion(&spi_imx->xfer_done);
- spi_imx->slave_aborted = false;
+ spi_imx->target_aborted = false;
spi_imx_push(spi_imx);
spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE | MXC_INT_RDR);
if (wait_for_completion_interruptible(&spi_imx->xfer_done) ||
- spi_imx->slave_aborted) {
+ spi_imx->target_aborted) {
dev_dbg(&spi->dev, "interrupted\n");
ret = -EINTR;
}
- /* ecspi has a HW issue when works in Slave mode,
+ /* ecspi has a HW issue when works in Target mode,
* after 64 words writtern to TXFIFO, even TXFIFO becomes empty,
* ECSPI_TXDATA keeps shift out the last word data,
- * so we have to disable ECSPI when in slave mode after the
+ * so we have to disable ECSPI when in target mode after the
* transfer completes
*/
if (spi_imx->devtype_data->disable)
@@ -1608,22 +1702,43 @@ static int spi_imx_pio_transfer_slave(struct spi_device *spi,
return ret;
}
+static unsigned int spi_imx_transfer_estimate_time_us(struct spi_transfer *transfer)
+{
+ u64 result;
+
+ result = DIV_U64_ROUND_CLOSEST((u64)USEC_PER_SEC * transfer->len * BITS_PER_BYTE,
+ transfer->effective_speed_hz);
+ if (transfer->word_delay.value) {
+ unsigned int word_delay_us;
+ unsigned int words;
+
+ words = DIV_ROUND_UP(transfer->len * BITS_PER_BYTE, transfer->bits_per_word);
+ word_delay_us = DIV_ROUND_CLOSEST(spi_delay_to_ns(&transfer->word_delay, transfer),
+ NSEC_PER_USEC);
+ result += (u64)words * word_delay_us;
+ }
+
+ return min(result, U32_MAX);
+}
+
static int spi_imx_transfer_one(struct spi_controller *controller,
struct spi_device *spi,
struct spi_transfer *transfer)
{
+ int ret;
struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
- unsigned long hz_per_byte, byte_limit;
- spi_imx_setupxfer(spi, transfer);
+ ret = spi_imx_setupxfer(spi, transfer);
+ if (ret < 0)
+ return ret;
transfer->effective_speed_hz = spi_imx->spi_bus_clk;
/* flush rxfifo before transfer */
while (spi_imx->devtype_data->rx_available(spi_imx))
readl(spi_imx->base + MXC_CSPIRXDATA);
- if (spi_imx->slave_mode)
- return spi_imx_pio_transfer_slave(spi, transfer);
+ if (spi_imx->target_mode)
+ return spi_imx_pio_transfer_target(spi, transfer);
/*
* If we decided in spi_imx_can_dma() that we want to do a DMA
@@ -1632,15 +1747,10 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
*/
if (spi_imx->usedma)
return spi_imx_dma_transfer(spi_imx, transfer);
- /*
- * Calculate the estimated time in us the transfer runs. Find
- * the number of Hz per byte per polling limit.
- */
- hz_per_byte = polling_limit_us ? ((8 + 4) * USEC_PER_SEC) / polling_limit_us : 0;
- byte_limit = hz_per_byte ? transfer->effective_speed_hz / hz_per_byte : 1;
/* run in polling mode for short transfers */
- if (transfer->len < byte_limit)
+ if (transfer->len == 1 || (polling_limit_us &&
+ spi_imx_transfer_estimate_time_us(transfer) < polling_limit_us))
return spi_imx_poll_transfer(spi, transfer);
return spi_imx_pio_transfer(spi, transfer);
@@ -1654,10 +1764,6 @@ static int spi_imx_setup(struct spi_device *spi)
return 0;
}
-static void spi_imx_cleanup(struct spi_device *spi)
-{
-}
-
static int
spi_imx_prepare_message(struct spi_controller *controller, struct spi_message *msg)
{
@@ -1672,7 +1778,6 @@ spi_imx_prepare_message(struct spi_controller *controller, struct spi_message *m
ret = spi_imx->devtype_data->prepare_message(spi_imx, msg);
if (ret) {
- pm_runtime_mark_last_busy(spi_imx->dev);
pm_runtime_put_autosuspend(spi_imx->dev);
}
@@ -1684,16 +1789,15 @@ spi_imx_unprepare_message(struct spi_controller *controller, struct spi_message
{
struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
- pm_runtime_mark_last_busy(spi_imx->dev);
pm_runtime_put_autosuspend(spi_imx->dev);
return 0;
}
-static int spi_imx_slave_abort(struct spi_controller *controller)
+static int spi_imx_target_abort(struct spi_controller *controller)
{
struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
- spi_imx->slave_aborted = true;
+ spi_imx->target_aborted = true;
complete(&spi_imx->xfer_done);
return 0;
@@ -1708,17 +1812,17 @@ static int spi_imx_probe(struct platform_device *pdev)
int ret, irq, spi_drctl;
const struct spi_imx_devtype_data *devtype_data =
of_device_get_match_data(&pdev->dev);
- bool slave_mode;
+ bool target_mode;
u32 val;
- slave_mode = devtype_data->has_slavemode &&
- of_property_read_bool(np, "spi-slave");
- if (slave_mode)
- controller = spi_alloc_slave(&pdev->dev,
- sizeof(struct spi_imx_data));
- else
- controller = spi_alloc_master(&pdev->dev,
+ target_mode = devtype_data->has_targetmode &&
+ of_property_read_bool(np, "spi-slave");
+ if (target_mode)
+ controller = spi_alloc_target(&pdev->dev,
sizeof(struct spi_imx_data));
+ else
+ controller = spi_alloc_host(&pdev->dev,
+ sizeof(struct spi_imx_data));
if (!controller)
return -ENOMEM;
@@ -1737,7 +1841,7 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx = spi_controller_get_devdata(controller);
spi_imx->controller = controller;
spi_imx->dev = &pdev->dev;
- spi_imx->slave_mode = slave_mode;
+ spi_imx->target_mode = target_mode;
spi_imx->devtype_data = devtype_data;
@@ -1754,10 +1858,10 @@ static int spi_imx_probe(struct platform_device *pdev)
controller->transfer_one = spi_imx_transfer_one;
controller->setup = spi_imx_setup;
- controller->cleanup = spi_imx_cleanup;
controller->prepare_message = spi_imx_prepare_message;
controller->unprepare_message = spi_imx_unprepare_message;
- controller->slave_abort = spi_imx_slave_abort;
+ controller->target_abort = spi_imx_target_abort;
+ spi_imx->spi_bus_clk = MXC_SPI_DEFAULT_SPEED;
controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS |
SPI_MOSI_IDLE_LOW;
@@ -1779,7 +1883,7 @@ static int spi_imx_probe(struct platform_device *pdev)
if (is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx)) {
controller->max_native_cs = 4;
- controller->flags |= SPI_MASTER_GPIO_SS;
+ controller->flags |= SPI_CONTROLLER_GPIO_SS;
}
spi_imx->spi_drctl = spi_drctl;
@@ -1858,7 +1962,6 @@ static int spi_imx_probe(struct platform_device *pdev)
goto out_register_controller;
}
- pm_runtime_mark_last_busy(spi_imx->dev);
pm_runtime_put_autosuspend(spi_imx->dev);
return ret;
@@ -1868,8 +1971,8 @@ out_register_controller:
spi_imx_sdma_exit(spi_imx);
out_runtime_pm_put:
pm_runtime_dont_use_autosuspend(spi_imx->dev);
- pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(spi_imx->dev);
+ pm_runtime_set_suspended(&pdev->dev);
clk_disable_unprepare(spi_imx->clk_ipg);
out_put_per:
@@ -1901,7 +2004,7 @@ static void spi_imx_remove(struct platform_device *pdev)
spi_imx_sdma_exit(spi_imx);
}
-static int __maybe_unused spi_imx_runtime_resume(struct device *dev)
+static int spi_imx_runtime_resume(struct device *dev)
{
struct spi_controller *controller = dev_get_drvdata(dev);
struct spi_imx_data *spi_imx;
@@ -1922,7 +2025,7 @@ static int __maybe_unused spi_imx_runtime_resume(struct device *dev)
return 0;
}
-static int __maybe_unused spi_imx_runtime_suspend(struct device *dev)
+static int spi_imx_runtime_suspend(struct device *dev)
{
struct spi_controller *controller = dev_get_drvdata(dev);
struct spi_imx_data *spi_imx;
@@ -1935,32 +2038,31 @@ static int __maybe_unused spi_imx_runtime_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused spi_imx_suspend(struct device *dev)
+static int spi_imx_suspend(struct device *dev)
{
pinctrl_pm_select_sleep_state(dev);
return 0;
}
-static int __maybe_unused spi_imx_resume(struct device *dev)
+static int spi_imx_resume(struct device *dev)
{
pinctrl_pm_select_default_state(dev);
return 0;
}
static const struct dev_pm_ops imx_spi_pm = {
- SET_RUNTIME_PM_OPS(spi_imx_runtime_suspend,
- spi_imx_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume)
+ RUNTIME_PM_OPS(spi_imx_runtime_suspend, spi_imx_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume)
};
static struct platform_driver spi_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = spi_imx_dt_ids,
- .pm = &imx_spi_pm,
+ .pm = pm_ptr(&imx_spi_pm),
},
.probe = spi_imx_probe,
- .remove_new = spi_imx_remove,
+ .remove = spi_imx_remove,
};
module_platform_driver(spi_imx_driver);
diff --git a/drivers/spi/spi-ingenic.c b/drivers/spi/spi-ingenic.c
index 7d4b515a160d..318b0768701e 100644
--- a/drivers/spi/spi-ingenic.c
+++ b/drivers/spi/spi-ingenic.c
@@ -12,10 +12,11 @@
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
+#include "internals.h"
#define REG_SSIDR 0x0
#define REG_SSICR0 0x4
@@ -242,11 +243,10 @@ static int spi_ingenic_transfer_one(struct spi_controller *ctlr,
{
struct ingenic_spi *priv = spi_controller_get_devdata(ctlr);
unsigned int bits = xfer->bits_per_word ?: spi->bits_per_word;
- bool can_dma = ctlr->can_dma && ctlr->can_dma(ctlr, spi, xfer);
spi_ingenic_prepare_transfer(priv, spi, xfer);
- if (ctlr->cur_msg_mapped && can_dma)
+ if (spi_xfer_is_dma_mapped(ctlr, spi, xfer))
return spi_ingenic_dma_tx(ctlr, xfer, bits);
if (bits > 16)
@@ -346,14 +346,17 @@ static bool spi_ingenic_can_dma(struct spi_controller *ctlr,
static int spi_ingenic_request_dma(struct spi_controller *ctlr,
struct device *dev)
{
- ctlr->dma_tx = dma_request_slave_channel(dev, "tx");
- if (!ctlr->dma_tx)
- return -ENODEV;
+ struct dma_chan *chan;
- ctlr->dma_rx = dma_request_slave_channel(dev, "rx");
+ chan = dma_request_chan(dev, "tx");
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
+ ctlr->dma_tx = chan;
- if (!ctlr->dma_rx)
- return -ENODEV;
+ chan = dma_request_chan(dev, "rx");
+ if (IS_ERR(chan))
+ return PTR_ERR(chan);
+ ctlr->dma_rx = chan;
ctlr->can_dma = spi_ingenic_can_dma;
@@ -392,7 +395,7 @@ static int spi_ingenic_probe(struct platform_device *pdev)
return -EINVAL;
}
- ctlr = devm_spi_alloc_master(dev, sizeof(*priv));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*priv));
if (!ctlr) {
dev_err(dev, "Unable to allocate SPI controller.\n");
return -ENOMEM;
diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c
index a7381e774b95..b8c572394aac 100644
--- a/drivers/spi/spi-intel-pci.c
+++ b/drivers/spi/spi-intel-pci.c
@@ -44,6 +44,7 @@ static int intel_spi_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct intel_spi_boardinfo *info;
+ void __iomem *base;
int ret;
ret = pcim_enable_device(pdev);
@@ -56,7 +57,12 @@ static int intel_spi_pci_probe(struct pci_dev *pdev,
return -ENOMEM;
info->data = pdev;
- return intel_spi_probe(&pdev->dev, &pdev->resource[0], info);
+
+ base = pcim_iomap_region(pdev, 0, KBUILD_MODNAME);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ return intel_spi_probe(&pdev->dev, base, info);
}
static const struct pci_device_id intel_spi_pci_ids[] = {
@@ -69,12 +75,17 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x38a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
+ { PCI_VDEVICE(INTEL, 0x4d23), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x51a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0x5794), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0x5825), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0x7723), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0x7f24), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x9d24), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x9da4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&cnl_info },
@@ -83,7 +94,9 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0xa2a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info },
- { PCI_VDEVICE(INTEL, 0xae23), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0xa823), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0xe323), (unsigned long)&cnl_info },
+ { PCI_VDEVICE(INTEL, 0xe423), (unsigned long)&cnl_info },
{ },
};
MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
@@ -92,6 +105,7 @@ static struct pci_driver intel_spi_pci_driver = {
.name = "intel-spi",
.id_table = intel_spi_pci_ids,
.probe = intel_spi_pci_probe,
+ .dev_groups = intel_spi_groups,
};
module_pci_driver(intel_spi_pci_driver);
diff --git a/drivers/spi/spi-intel-platform.c b/drivers/spi/spi-intel-platform.c
index 2ef09fa35661..6cbed0b2e063 100644
--- a/drivers/spi/spi-intel-platform.c
+++ b/drivers/spi/spi-intel-platform.c
@@ -14,20 +14,24 @@
static int intel_spi_platform_probe(struct platform_device *pdev)
{
struct intel_spi_boardinfo *info;
- struct resource *mem;
+ void __iomem *base;
info = dev_get_platdata(&pdev->dev);
if (!info)
return -EINVAL;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- return intel_spi_probe(&pdev->dev, mem, info);
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ return intel_spi_probe(&pdev->dev, base, info);
}
static struct platform_driver intel_spi_platform_driver = {
.probe = intel_spi_platform_probe,
.driver = {
.name = "intel-spi",
+ .dev_groups = intel_spi_groups,
},
};
diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c
index bc6d22149e7e..1775ad39e633 100644
--- a/drivers/spi/spi-intel.c
+++ b/drivers/spi/spi-intel.c
@@ -132,6 +132,7 @@
#define FLCOMP_C0DEN_16M 0x05
#define FLCOMP_C0DEN_32M 0x06
#define FLCOMP_C0DEN_64M 0x07
+#define FLCOMP_C0DEN_128M 0x08
#define INTEL_SPI_TIMEOUT 5000 /* ms */
#define INTEL_SPI_FIFO_SZ 64
@@ -143,11 +144,13 @@
* @base: Beginning of MMIO space
* @pregs: Start of protection registers
* @sregs: Start of software sequencer registers
- * @master: Pointer to the SPI controller structure
+ * @host: Pointer to the SPI controller structure
* @nregions: Maximum number of regions
* @pr_num: Maximum number of protected range registers
* @chip0_size: Size of the first flash chip in bytes
* @locked: Is SPI setting locked
+ * @protected: Whether the regions are write protected
+ * @bios_locked: Is BIOS region locked
* @swseq_reg: Use SW sequencer in register reads/writes
* @swseq_erase: Use SW sequencer in erase operation
* @atomic_preopcode: Holds preopcode when atomic sequence is requested
@@ -161,11 +164,13 @@ struct intel_spi {
void __iomem *base;
void __iomem *pregs;
void __iomem *sregs;
- struct spi_controller *master;
+ struct spi_controller *host;
size_t nregions;
size_t pr_num;
size_t chip0_size;
bool locked;
+ bool protected;
+ bool bios_locked;
bool swseq_reg;
bool swseq_erase;
u8 atomic_preopcode;
@@ -185,6 +190,11 @@ struct intel_spi_mem_op {
static bool writeable;
module_param(writeable, bool, 0);
MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)");
+static bool ignore_protection_status;
+module_param(ignore_protection_status, bool, 0);
+MODULE_PARM_DESC(
+ ignore_protection_status,
+ "Do not block SPI flash chip write access even if it is write-protected (default=0)");
static void intel_spi_dump_regs(struct intel_spi *ispi)
{
@@ -711,8 +721,7 @@ static bool intel_spi_cmp_mem_op(const struct intel_spi_mem_op *iop,
{
if (iop->mem_op.cmd.nbytes != op->cmd.nbytes ||
iop->mem_op.cmd.buswidth != op->cmd.buswidth ||
- iop->mem_op.cmd.dtr != op->cmd.dtr ||
- iop->mem_op.cmd.opcode != op->cmd.opcode)
+ iop->mem_op.cmd.dtr != op->cmd.dtr)
return false;
if (iop->mem_op.addr.nbytes != op->addr.nbytes ||
@@ -737,17 +746,18 @@ intel_spi_match_mem_op(struct intel_spi *ispi, const struct spi_mem_op *op)
const struct intel_spi_mem_op *iop;
for (iop = ispi->mem_ops; iop->mem_op.cmd.opcode; iop++) {
- if (intel_spi_cmp_mem_op(iop, op))
- break;
+ if (iop->mem_op.cmd.opcode == op->cmd.opcode &&
+ intel_spi_cmp_mem_op(iop, op))
+ return iop;
}
- return iop->mem_op.cmd.opcode ? iop : NULL;
+ return NULL;
}
static bool intel_spi_supports_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct intel_spi *ispi = spi_master_get_devdata(mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(mem->spi->controller);
const struct intel_spi_mem_op *iop;
iop = intel_spi_match_mem_op(ispi, op);
@@ -778,7 +788,7 @@ static bool intel_spi_supports_mem_op(struct spi_mem *mem,
static int intel_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct intel_spi *ispi = spi_master_get_devdata(mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(mem->spi->controller);
const struct intel_spi_mem_op *iop;
iop = intel_spi_match_mem_op(ispi, op);
@@ -790,7 +800,7 @@ static int intel_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *o
static const char *intel_spi_get_name(struct spi_mem *mem)
{
- const struct intel_spi *ispi = spi_master_get_devdata(mem->spi->master);
+ const struct intel_spi *ispi = spi_controller_get_devdata(mem->spi->controller);
/*
* Return name of the flash controller device to be compatible
@@ -801,7 +811,7 @@ static const char *intel_spi_get_name(struct spi_mem *mem)
static int intel_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
- struct intel_spi *ispi = spi_master_get_devdata(desc->mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller);
const struct intel_spi_mem_op *iop;
iop = intel_spi_match_mem_op(ispi, &desc->info.op_tmpl);
@@ -815,7 +825,7 @@ static int intel_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
static ssize_t intel_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs,
size_t len, void *buf)
{
- struct intel_spi *ispi = spi_master_get_devdata(desc->mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller);
const struct intel_spi_mem_op *iop = desc->priv;
struct spi_mem_op op = desc->info.op_tmpl;
int ret;
@@ -832,7 +842,7 @@ static ssize_t intel_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs,
static ssize_t intel_spi_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs,
size_t len, const void *buf)
{
- struct intel_spi *ispi = spi_master_get_devdata(desc->mem->spi->master);
+ struct intel_spi *ispi = spi_controller_get_devdata(desc->mem->spi->controller);
const struct intel_spi_mem_op *iop = desc->priv;
struct spi_mem_op op = desc->info.op_tmpl;
int ret;
@@ -1109,10 +1119,13 @@ static int intel_spi_init(struct intel_spi *ispi)
return -EINVAL;
}
- /* Try to disable write protection if user asked to do so */
- if (writeable && !intel_spi_set_writeable(ispi)) {
- dev_warn(ispi->dev, "can't disable chip write protection\n");
- writeable = false;
+ ispi->bios_locked = true;
+ /* Try to disable BIOS write protection if user asked to do so */
+ if (writeable) {
+ if (intel_spi_set_writeable(ispi))
+ ispi->bios_locked = false;
+ else
+ dev_warn(ispi->dev, "can't disable chip write protection\n");
}
/* Disable #SMI generation from HW sequencer */
@@ -1241,19 +1254,30 @@ static void intel_spi_fill_partition(struct intel_spi *ispi,
continue;
/*
- * If any of the regions have protection bits set, make the
- * whole partition read-only to be on the safe side.
+ * If any of the regions have protection bits set and
+ * the ignore protection status parameter is not set,
+ * make the whole partition read-only to be on the safe side.
*
* Also if the user did not ask the chip to be writeable
* mask the bit too.
*/
- if (!writeable || intel_spi_is_protected(ispi, base, limit))
+ if (!writeable || (!ignore_protection_status &&
+ intel_spi_is_protected(ispi, base, limit))) {
part->mask_flags |= MTD_WRITEABLE;
+ ispi->protected = true;
+ }
end = (limit << 12) + 4096;
if (end > part->size)
part->size = end;
}
+
+ /*
+ * Regions can refer to the second chip too so in this case we
+ * just make the BIOS partition to occupy the whole chip.
+ */
+ if (ispi->chip0_size && part->size > ispi->chip0_size)
+ part->size = MTDPART_SIZ_FULL;
}
static int intel_spi_read_desc(struct intel_spi *ispi)
@@ -1324,7 +1348,12 @@ static int intel_spi_read_desc(struct intel_spi *ispi)
case FLCOMP_C0DEN_64M:
ispi->chip0_size = SZ_64M;
break;
+ case FLCOMP_C0DEN_128M:
+ ispi->chip0_size = SZ_128M;
+ break;
default:
+ dev_warn(ispi->dev, "unsupported C0DEN: %#lx\n",
+ flcomp & FLCOMP_C0DEN_MASK);
return -EINVAL;
}
@@ -1332,23 +1361,28 @@ static int intel_spi_read_desc(struct intel_spi *ispi)
nc = (buf[1] & FLMAP0_NC_MASK) >> FLMAP0_NC_SHIFT;
if (!nc)
- ispi->master->num_chipselect = 1;
+ ispi->host->num_chipselect = 1;
else if (nc == 1)
- ispi->master->num_chipselect = 2;
+ ispi->host->num_chipselect = 2;
else
return -EINVAL;
dev_dbg(ispi->dev, "%u flash components found\n",
- ispi->master->num_chipselect);
+ ispi->host->num_chipselect);
return 0;
}
static int intel_spi_populate_chip(struct intel_spi *ispi)
{
struct flash_platform_data *pdata;
+ struct mtd_partition *parts;
struct spi_board_info chip;
int ret;
+ ret = intel_spi_read_desc(ispi);
+ if (ret)
+ return ret;
+
pdata = devm_kzalloc(ispi->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
@@ -1365,65 +1399,122 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
snprintf(chip.modalias, 8, "spi-nor");
chip.platform_data = pdata;
- if (!spi_new_device(ispi->master, &chip))
+ if (!spi_new_device(ispi->host, &chip))
return -ENODEV;
- ret = intel_spi_read_desc(ispi);
- if (ret)
- return ret;
-
/* Add the second chip if present */
- if (ispi->master->num_chipselect < 2)
+ if (ispi->host->num_chipselect < 2)
return 0;
- chip.platform_data = NULL;
+ pdata = devm_kzalloc(ispi->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->name = devm_kasprintf(ispi->dev, GFP_KERNEL, "%s-chip1",
+ dev_name(ispi->dev));
+ if (!pdata->name)
+ return -ENOMEM;
+
+ pdata->nr_parts = 1;
+ parts = devm_kcalloc(ispi->dev, pdata->nr_parts, sizeof(*parts),
+ GFP_KERNEL);
+ if (!parts)
+ return -ENOMEM;
+
+ parts[0].size = MTDPART_SIZ_FULL;
+ parts[0].name = "BIOS1";
+ pdata->parts = parts;
+
+ chip.platform_data = pdata;
chip.chip_select = 1;
- if (!spi_new_device(ispi->master, &chip))
+ if (!spi_new_device(ispi->host, &chip))
return -ENODEV;
return 0;
}
+static ssize_t intel_spi_protected_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_spi *ispi = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%d\n", ispi->protected);
+}
+static DEVICE_ATTR_ADMIN_RO(intel_spi_protected);
+
+static ssize_t intel_spi_locked_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_spi *ispi = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%d\n", ispi->locked);
+}
+static DEVICE_ATTR_ADMIN_RO(intel_spi_locked);
+
+static ssize_t intel_spi_bios_locked_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct intel_spi *ispi = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%d\n", ispi->bios_locked);
+}
+static DEVICE_ATTR_ADMIN_RO(intel_spi_bios_locked);
+
+static struct attribute *intel_spi_attrs[] = {
+ &dev_attr_intel_spi_protected.attr,
+ &dev_attr_intel_spi_locked.attr,
+ &dev_attr_intel_spi_bios_locked.attr,
+ NULL
+};
+
+static const struct attribute_group intel_spi_attr_group = {
+ .attrs = intel_spi_attrs,
+};
+
+const struct attribute_group *intel_spi_groups[] = {
+ &intel_spi_attr_group,
+ NULL
+};
+EXPORT_SYMBOL_GPL(intel_spi_groups);
+
/**
* intel_spi_probe() - Probe the Intel SPI flash controller
* @dev: Pointer to the parent device
- * @mem: MMIO resource
+ * @base: iomapped MMIO resource
* @info: Platform specific information
*
* Probes Intel SPI flash controller and creates the flash chip device.
* Returns %0 on success and negative errno in case of failure.
*/
-int intel_spi_probe(struct device *dev, struct resource *mem,
+int intel_spi_probe(struct device *dev, void __iomem *base,
const struct intel_spi_boardinfo *info)
{
- struct spi_controller *master;
+ struct spi_controller *host;
struct intel_spi *ispi;
int ret;
- master = devm_spi_alloc_master(dev, sizeof(*ispi));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*ispi));
+ if (!host)
return -ENOMEM;
- master->mem_ops = &intel_spi_mem_ops;
-
- ispi = spi_master_get_devdata(master);
+ host->mem_ops = &intel_spi_mem_ops;
- ispi->base = devm_ioremap_resource(dev, mem);
- if (IS_ERR(ispi->base))
- return PTR_ERR(ispi->base);
+ ispi = spi_controller_get_devdata(host);
+ ispi->base = base;
ispi->dev = dev;
- ispi->master = master;
+ ispi->host = host;
ispi->info = info;
ret = intel_spi_init(ispi);
if (ret)
return ret;
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
return ret;
+ dev_set_drvdata(dev, ispi);
return intel_spi_populate_chip(ispi);
}
EXPORT_SYMBOL_GPL(intel_spi_probe);
diff --git a/drivers/spi/spi-intel.h b/drivers/spi/spi-intel.h
index a4f0327a46ff..53b292c6ea0c 100644
--- a/drivers/spi/spi-intel.h
+++ b/drivers/spi/spi-intel.h
@@ -11,9 +11,9 @@
#include <linux/platform_data/x86/spi-intel.h>
-struct resource;
+extern const struct attribute_group *intel_spi_groups[];
-int intel_spi_probe(struct device *dev, struct resource *mem,
+int intel_spi_probe(struct device *dev, void __iomem *base,
const struct intel_spi_boardinfo *info);
#endif /* SPI_INTEL_H */
diff --git a/drivers/spi/spi-iproc-qspi.c b/drivers/spi/spi-iproc-qspi.c
index 5980a0dbbccb..392acc4026ab 100644
--- a/drivers/spi/spi-iproc-qspi.c
+++ b/drivers/spi/spi-iproc-qspi.c
@@ -94,7 +94,6 @@ static int bcm_iproc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct bcm_iproc_intc *priv;
struct bcm_qspi_soc_intc *soc_intc;
- struct resource *res;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -104,14 +103,12 @@ static int bcm_iproc_probe(struct platform_device *pdev)
spin_lock_init(&priv->soclock);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr_regs");
- priv->int_reg = devm_ioremap_resource(dev, res);
+ priv->int_reg = devm_platform_ioremap_resource_byname(pdev, "intr_regs");
if (IS_ERR(priv->int_reg))
return PTR_ERR(priv->int_reg);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "intr_status_reg");
- priv->int_status_reg = devm_ioremap_resource(dev, res);
+ priv->int_status_reg = devm_platform_ioremap_resource_byname(pdev,
+ "intr_status_reg");
if (IS_ERR(priv->int_status_reg))
return PTR_ERR(priv->int_status_reg);
@@ -141,7 +138,7 @@ MODULE_DEVICE_TABLE(of, bcm_iproc_of_match);
static struct platform_driver bcm_iproc_driver = {
.probe = bcm_iproc_probe,
- .remove_new = bcm_iproc_remove,
+ .remove = bcm_iproc_remove,
.driver = {
.name = "bcm_iproc",
.pm = &bcm_qspi_pm_ops,
diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c
index c42a3358e8c9..e37ca22e04ba 100644
--- a/drivers/spi/spi-jcore.c
+++ b/drivers/spi/spi-jcore.c
@@ -33,7 +33,7 @@
#define JCORE_SPI_WAIT_RDY_MAX_LOOP 2000000
struct jcore_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base;
unsigned int cs_reg;
unsigned int speed_reg;
@@ -59,7 +59,7 @@ static void jcore_spi_program(struct jcore_spi *hw)
void __iomem *ctrl_reg = hw->base + CTRL_REG;
if (jcore_spi_wait(ctrl_reg))
- dev_err(hw->master->dev.parent,
+ dev_err(hw->host->dev.parent,
"timeout waiting to program ctrl reg.\n");
writel(hw->cs_reg | hw->speed_reg, ctrl_reg);
@@ -67,10 +67,10 @@ static void jcore_spi_program(struct jcore_spi *hw)
static void jcore_spi_chipsel(struct spi_device *spi, bool value)
{
- struct jcore_spi *hw = spi_master_get_devdata(spi->master);
+ struct jcore_spi *hw = spi_controller_get_devdata(spi->controller);
u32 csbit = 1U << (2 * spi_get_chipselect(spi, 0));
- dev_dbg(hw->master->dev.parent, "chipselect %d\n", spi_get_chipselect(spi, 0));
+ dev_dbg(hw->host->dev.parent, "chipselect %d\n", spi_get_chipselect(spi, 0));
if (value)
hw->cs_reg |= csbit;
@@ -90,14 +90,14 @@ static void jcore_spi_baudrate(struct jcore_spi *hw, int speed)
else
hw->speed_reg = ((hw->clock_freq / 2 / speed) - 1) << 27;
jcore_spi_program(hw);
- dev_dbg(hw->master->dev.parent, "speed=%d reg=0x%x\n",
+ dev_dbg(hw->host->dev.parent, "speed=%d reg=0x%x\n",
speed, hw->speed_reg);
}
-static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
+static int jcore_spi_txrx(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *t)
{
- struct jcore_spi *hw = spi_master_get_devdata(master);
+ struct jcore_spi *hw = spi_controller_get_devdata(host);
void __iomem *ctrl_reg = hw->base + CTRL_REG;
void __iomem *data_reg = hw->base + DATA_REG;
@@ -130,7 +130,7 @@ static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
*rx++ = readl(data_reg);
}
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
if (count < len)
return -EREMOTEIO;
@@ -142,26 +142,26 @@ static int jcore_spi_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct jcore_spi *hw;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *res;
u32 clock_freq;
struct clk *clk;
int err = -ENODEV;
- master = spi_alloc_master(&pdev->dev, sizeof(struct jcore_spi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(struct jcore_spi));
+ if (!host)
return err;
- /* Setup the master state. */
- master->num_chipselect = 3;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->transfer_one = jcore_spi_txrx;
- master->set_cs = jcore_spi_chipsel;
- master->dev.of_node = node;
- master->bus_num = pdev->id;
+ /* Setup the host state. */
+ host->num_chipselect = 3;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->transfer_one = jcore_spi_txrx;
+ host->set_cs = jcore_spi_chipsel;
+ host->dev.of_node = node;
+ host->bus_num = pdev->id;
- hw = spi_master_get_devdata(master);
- hw->master = master;
+ hw = spi_controller_get_devdata(host);
+ hw->host = host;
platform_set_drvdata(pdev, hw);
/* Find and map our resources */
@@ -200,7 +200,7 @@ static int jcore_spi_probe(struct platform_device *pdev)
jcore_spi_baudrate(hw, 400000);
/* Register our spi controller */
- err = devm_spi_register_master(&pdev->dev, master);
+ err = devm_spi_register_controller(&pdev->dev, host);
if (err)
goto exit;
@@ -209,7 +209,7 @@ static int jcore_spi_probe(struct platform_device *pdev)
exit_busy:
err = -EBUSY;
exit:
- spi_master_put(master);
+ spi_controller_put(host);
return err;
}
diff --git a/drivers/spi/spi-kspi2.c b/drivers/spi/spi-kspi2.c
new file mode 100644
index 000000000000..ca73ec52ce63
--- /dev/null
+++ b/drivers/spi/spi-kspi2.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) KEBA Industrial Automation Gmbh 2024
+ *
+ * Driver for KEBA SPI host controller type 2 FPGA IP core
+ */
+
+#include <linux/iopoll.h>
+#include <linux/misc/keba.h>
+#include <linux/spi/spi.h>
+
+#define KSPI2 "kspi2"
+
+#define KSPI2_CLK_FREQ_REG 0x03
+#define KSPI2_CLK_FREQ_MASK 0x0f
+#define KSPI2_CLK_FREQ_62_5M 0x0
+#define KSPI2_CLK_FREQ_33_3M 0x1
+#define KSPI2_CLK_FREQ_125M 0x2
+#define KSPI2_CLK_FREQ_50M 0x3
+#define KSPI2_CLK_FREQ_100M 0x4
+
+#define KSPI2_CONTROL_REG 0x04
+#define KSPI2_CONTROL_CLK_DIV_MAX 0x0f
+#define KSPI2_CONTROL_CLK_DIV_MASK 0x0f
+#define KSPI2_CONTROL_CPHA 0x10
+#define KSPI2_CONTROL_CPOL 0x20
+#define KSPI2_CONTROL_CLK_MODE_MASK 0x30
+#define KSPI2_CONTROL_INIT KSPI2_CONTROL_CLK_DIV_MAX
+
+#define KSPI2_STATUS_REG 0x08
+#define KSPI2_STATUS_IN_USE 0x01
+#define KSPI2_STATUS_BUSY 0x02
+
+#define KSPI2_DATA_REG 0x0c
+
+#define KSPI2_CS_NR_REG 0x10
+#define KSPI2_CS_NR_NONE 0xff
+
+#define KSPI2_MODE_BITS (SPI_CPHA | SPI_CPOL)
+#define KSPI2_NUM_CS 255
+
+#define KSPI2_SPEED_HZ_MIN(kspi) (kspi->base_speed_hz / 65536)
+#define KSPI2_SPEED_HZ_MAX(kspi) (kspi->base_speed_hz / 2)
+
+/* timeout is 10 times the time to transfer one byte at slowest clock */
+#define KSPI2_XFER_TIMEOUT_US(kspi) (USEC_PER_SEC / \
+ KSPI2_SPEED_HZ_MIN(kspi) * 8 * 10)
+
+#define KSPI2_INUSE_SLEEP_US (2 * USEC_PER_MSEC)
+#define KSPI2_INUSE_TIMEOUT_US (10 * USEC_PER_SEC)
+
+struct kspi2 {
+ struct keba_spi_auxdev *auxdev;
+ void __iomem *base;
+ struct spi_controller *host;
+
+ u32 base_speed_hz; /* SPI base clock frequency in HZ */
+ u8 control_shadow;
+
+ struct spi_device **device;
+ int device_size;
+};
+
+static int kspi2_inuse_lock(struct kspi2 *kspi)
+{
+ u8 sts;
+ int ret;
+
+ /*
+ * The SPI controller has an IN_USE bit for locking access to the
+ * controller. This enables the use of the SPI controller by other none
+ * Linux processors.
+ *
+ * If the SPI controller is free, then the first read returns
+ * IN_USE == 0. After that the SPI controller is locked and further
+ * reads of IN_USE return 1.
+ *
+ * The SPI controller is unlocked by writing 1 into IN_USE.
+ *
+ * The IN_USE bit acts as a hardware semaphore for the SPI controller.
+ * Poll for semaphore, but sleep while polling to free the CPU.
+ */
+ ret = readb_poll_timeout(kspi->base + KSPI2_STATUS_REG,
+ sts, (sts & KSPI2_STATUS_IN_USE) == 0,
+ KSPI2_INUSE_SLEEP_US, KSPI2_INUSE_TIMEOUT_US);
+ if (ret != 0)
+ dev_warn(&kspi->auxdev->auxdev.dev, "%s err!\n", __func__);
+
+ return ret;
+}
+
+static void kspi2_inuse_unlock(struct kspi2 *kspi)
+{
+ /* unlock the controller by writing 1 into IN_USE */
+ iowrite8(KSPI2_STATUS_IN_USE, kspi->base + KSPI2_STATUS_REG);
+}
+
+static int kspi2_prepare_hardware(struct spi_controller *host)
+{
+ struct kspi2 *kspi = spi_controller_get_devdata(host);
+
+ /* lock hardware semaphore before actual use of controller */
+ return kspi2_inuse_lock(kspi);
+}
+
+static int kspi2_unprepare_hardware(struct spi_controller *host)
+{
+ struct kspi2 *kspi = spi_controller_get_devdata(host);
+
+ /* unlock hardware semaphore after actual use of controller */
+ kspi2_inuse_unlock(kspi);
+
+ return 0;
+}
+
+static u8 kspi2_calc_minimal_divider(struct kspi2 *kspi, u32 max_speed_hz)
+{
+ u8 div;
+
+ /*
+ * Divider values 2, 4, 8, 16, ..., 65536 are possible. They are coded
+ * as 0, 1, 2, 3, ..., 15 in the CONTROL_CLK_DIV bit.
+ */
+ for (div = 0; div < KSPI2_CONTROL_CLK_DIV_MAX; div++) {
+ if ((kspi->base_speed_hz >> (div + 1)) <= max_speed_hz)
+ return div;
+ }
+
+ /* return divider for slowest clock if loop fails to find one */
+ return KSPI2_CONTROL_CLK_DIV_MAX;
+}
+
+static void kspi2_write_control_reg(struct kspi2 *kspi, u8 val, u8 mask)
+{
+ /* write control register only when necessary to improve performance */
+ if (val != (kspi->control_shadow & mask)) {
+ kspi->control_shadow = (kspi->control_shadow & ~mask) | val;
+ iowrite8(kspi->control_shadow, kspi->base + KSPI2_CONTROL_REG);
+ }
+}
+
+static int kspi2_txrx_byte(struct kspi2 *kspi, u8 tx, u8 *rx)
+{
+ u8 sts;
+ int ret;
+
+ /* start transfer by writing TX byte */
+ iowrite8(tx, kspi->base + KSPI2_DATA_REG);
+
+ /* wait till finished (BUSY == 0) */
+ ret = readb_poll_timeout(kspi->base + KSPI2_STATUS_REG,
+ sts, (sts & KSPI2_STATUS_BUSY) == 0,
+ 0, KSPI2_XFER_TIMEOUT_US(kspi));
+ if (ret != 0)
+ return ret;
+
+ /* read RX byte */
+ if (rx)
+ *rx = ioread8(kspi->base + KSPI2_DATA_REG);
+
+ return 0;
+}
+
+static int kspi2_process_transfer(struct kspi2 *kspi, struct spi_transfer *t)
+{
+ u8 tx = 0;
+ u8 rx;
+ int i;
+ int ret;
+
+ for (i = 0; i < t->len; i++) {
+ if (t->tx_buf)
+ tx = ((const u8 *)t->tx_buf)[i];
+
+ ret = kspi2_txrx_byte(kspi, tx, &rx);
+ if (ret)
+ return ret;
+
+ if (t->rx_buf)
+ ((u8 *)t->rx_buf)[i] = rx;
+ }
+
+ return 0;
+}
+
+static int kspi2_setup_transfer(struct kspi2 *kspi,
+ struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ u32 max_speed_hz = spi->max_speed_hz;
+ u8 clk_div;
+
+ /*
+ * spi_device (spi) has default parameters. Some of these can be
+ * overwritten by parameters in spi_transfer (t).
+ */
+ if (t->bits_per_word && ((t->bits_per_word % 8) != 0)) {
+ dev_err(&spi->dev, "Word width %d not supported!\n",
+ t->bits_per_word);
+
+ return -EINVAL;
+ }
+
+ if (t->speed_hz && (t->speed_hz < max_speed_hz))
+ max_speed_hz = t->speed_hz;
+
+ clk_div = kspi2_calc_minimal_divider(kspi, max_speed_hz);
+ kspi2_write_control_reg(kspi, clk_div, KSPI2_CONTROL_CLK_DIV_MASK);
+
+ return 0;
+}
+
+static int kspi2_transfer_one(struct spi_controller *host,
+ struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct kspi2 *kspi = spi_controller_get_devdata(host);
+ int ret;
+
+ ret = kspi2_setup_transfer(kspi, spi, t);
+ if (ret != 0)
+ return ret;
+
+ if (t->len) {
+ ret = kspi2_process_transfer(kspi, t);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void kspi2_set_cs(struct spi_device *spi, bool enable)
+{
+ struct spi_controller *host = spi->controller;
+ struct kspi2 *kspi = spi_controller_get_devdata(host);
+
+ /* controller is using active low chip select signals by design */
+ if (!enable)
+ iowrite8(spi_get_chipselect(spi, 0), kspi->base + KSPI2_CS_NR_REG);
+ else
+ iowrite8(KSPI2_CS_NR_NONE, kspi->base + KSPI2_CS_NR_REG);
+}
+
+static int kspi2_prepare_message(struct spi_controller *host,
+ struct spi_message *msg)
+{
+ struct kspi2 *kspi = spi_controller_get_devdata(host);
+ struct spi_device *spi = msg->spi;
+ u8 mode = 0;
+
+ /* setup SPI clock phase and polarity */
+ if (spi->mode & SPI_CPHA)
+ mode |= KSPI2_CONTROL_CPHA;
+ if (spi->mode & SPI_CPOL)
+ mode |= KSPI2_CONTROL_CPOL;
+ kspi2_write_control_reg(kspi, mode, KSPI2_CONTROL_CLK_MODE_MASK);
+
+ return 0;
+}
+
+static int kspi2_setup(struct spi_device *spi)
+{
+ struct kspi2 *kspi = spi_controller_get_devdata(spi->controller);
+
+ /*
+ * Check only parameters. Actual setup is done in kspi2_prepare_message
+ * and directly before the SPI transfer starts.
+ */
+
+ if (spi->mode & ~KSPI2_MODE_BITS) {
+ dev_err(&spi->dev, "Mode %d not supported!\n", spi->mode);
+
+ return -EINVAL;
+ }
+
+ if ((spi->bits_per_word % 8) != 0) {
+ dev_err(&spi->dev, "Word width %d not supported!\n",
+ spi->bits_per_word);
+
+ return -EINVAL;
+ }
+
+ if ((spi->max_speed_hz == 0) ||
+ (spi->max_speed_hz > KSPI2_SPEED_HZ_MAX(kspi)))
+ spi->max_speed_hz = KSPI2_SPEED_HZ_MAX(kspi);
+
+ if (spi->max_speed_hz < KSPI2_SPEED_HZ_MIN(kspi)) {
+ dev_err(&spi->dev, "Requested speed of %d Hz is too low!\n",
+ spi->max_speed_hz);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void kspi2_unregister_devices(struct kspi2 *kspi)
+{
+ int i;
+
+ for (i = 0; i < kspi->device_size; i++) {
+ struct spi_device *device = kspi->device[i];
+
+ if (device)
+ spi_unregister_device(device);
+ }
+}
+
+static int kspi2_register_devices(struct kspi2 *kspi)
+{
+ struct spi_board_info *info = kspi->auxdev->info;
+ int i;
+
+ /* register all known SPI devices */
+ for (i = 0; i < kspi->auxdev->info_size; i++) {
+ struct spi_device *device = spi_new_device(kspi->host, &info[i]);
+
+ if (!device) {
+ kspi2_unregister_devices(kspi);
+
+ return -ENODEV;
+ }
+ kspi->device[i] = device;
+ }
+
+ return 0;
+}
+
+static void kspi2_init(struct kspi2 *kspi)
+{
+ iowrite8(KSPI2_CONTROL_INIT, kspi->base + KSPI2_CONTROL_REG);
+ kspi->control_shadow = KSPI2_CONTROL_INIT;
+
+ iowrite8(KSPI2_CS_NR_NONE, kspi->base + KSPI2_CS_NR_REG);
+}
+
+static int kspi2_probe(struct auxiliary_device *auxdev,
+ const struct auxiliary_device_id *id)
+{
+ struct device *dev = &auxdev->dev;
+ struct spi_controller *host;
+ struct kspi2 *kspi;
+ u8 clk_reg;
+ int ret;
+
+ host = devm_spi_alloc_host(dev, sizeof(struct kspi2));
+ if (!host)
+ return -ENOMEM;
+ kspi = spi_controller_get_devdata(host);
+ kspi->auxdev = container_of(auxdev, struct keba_spi_auxdev, auxdev);
+ kspi->host = host;
+ kspi->device = devm_kcalloc(dev, kspi->auxdev->info_size,
+ sizeof(*kspi->device), GFP_KERNEL);
+ if (!kspi->device)
+ return -ENOMEM;
+ kspi->device_size = kspi->auxdev->info_size;
+ auxiliary_set_drvdata(auxdev, kspi);
+
+ kspi->base = devm_ioremap_resource(dev, &kspi->auxdev->io);
+ if (IS_ERR(kspi->base))
+ return PTR_ERR(kspi->base);
+
+ /* read the SPI base clock frequency */
+ clk_reg = ioread8(kspi->base + KSPI2_CLK_FREQ_REG);
+ switch (clk_reg & KSPI2_CLK_FREQ_MASK) {
+ case KSPI2_CLK_FREQ_62_5M:
+ kspi->base_speed_hz = 62500000; break;
+ case KSPI2_CLK_FREQ_33_3M:
+ kspi->base_speed_hz = 33333333; break;
+ case KSPI2_CLK_FREQ_125M:
+ kspi->base_speed_hz = 125000000; break;
+ case KSPI2_CLK_FREQ_50M:
+ kspi->base_speed_hz = 50000000; break;
+ case KSPI2_CLK_FREQ_100M:
+ kspi->base_speed_hz = 100000000; break;
+ default:
+ dev_err(dev, "Undefined SPI base clock frequency!\n");
+ return -ENODEV;
+ }
+
+ kspi2_init(kspi);
+
+ host->bus_num = -1;
+ host->num_chipselect = KSPI2_NUM_CS;
+ host->mode_bits = KSPI2_MODE_BITS;
+ host->setup = kspi2_setup;
+ host->prepare_transfer_hardware = kspi2_prepare_hardware;
+ host->unprepare_transfer_hardware = kspi2_unprepare_hardware;
+ host->prepare_message = kspi2_prepare_message;
+ host->set_cs = kspi2_set_cs;
+ host->transfer_one = kspi2_transfer_one;
+ ret = devm_spi_register_controller(dev, host);
+ if (ret) {
+ dev_err(dev, "Failed to register host (%d)!\n", ret);
+ return ret;
+ }
+
+ ret = kspi2_register_devices(kspi);
+ if (ret) {
+ dev_err(dev, "Failed to register devices (%d)!\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void kspi2_remove(struct auxiliary_device *auxdev)
+{
+ struct kspi2 *kspi = auxiliary_get_drvdata(auxdev);
+
+ kspi2_unregister_devices(kspi);
+}
+
+static const struct auxiliary_device_id kspi2_devtype_aux[] = {
+ { .name = "keba.spi" },
+ { },
+};
+MODULE_DEVICE_TABLE(auxiliary, kspi2_devtype_aux);
+
+static struct auxiliary_driver kspi2_driver_aux = {
+ .name = KSPI2,
+ .id_table = kspi2_devtype_aux,
+ .probe = kspi2_probe,
+ .remove = kspi2_remove,
+};
+module_auxiliary_driver(kspi2_driver_aux);
+
+MODULE_AUTHOR("Gerhard Engleder <eg@keba.com>");
+MODULE_DESCRIPTION("KEBA SPI host controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c
index 8d6ecc5d6f70..60849e07f674 100644
--- a/drivers/spi/spi-lantiq-ssc.c
+++ b/drivers/spi/spi-lantiq-ssc.c
@@ -6,7 +6,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -91,7 +92,7 @@
#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */
#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */
#define LTQ_SPI_STAT_ME BIT(7) /* Mode error flag */
-#define LTQ_SPI_STAT_MS BIT(1) /* Master/slave select bit */
+#define LTQ_SPI_STAT_MS BIT(1) /* Host/target select bit */
#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */
#define LTQ_SPI_STAT_ERRORS (LTQ_SPI_STAT_ME | LTQ_SPI_STAT_TE | \
LTQ_SPI_STAT_RE | LTQ_SPI_STAT_AE | \
@@ -109,8 +110,8 @@
#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */
#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */
#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */
-#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */
-#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */
+#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set host select bit */
+#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear host select bit */
#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */
#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */
#define LTQ_SPI_WHBSTATE_CLR_ERRORS (LTQ_SPI_WHBSTATE_CLRRUE | \
@@ -138,7 +139,7 @@
#define LTQ_SPI_FGPO_CLROUTN_S 0
#define LTQ_SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */
-#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */
+#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Receive to-do value */
#define LTQ_SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */
#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */
@@ -162,7 +163,7 @@ struct lantiq_ssc_hwcfg {
};
struct lantiq_ssc_spi {
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev;
void __iomem *regbase;
struct clk *spi_clk;
@@ -366,7 +367,7 @@ static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi)
hw_setup_bits_per_word(spi, spi->bits_per_word);
hw_setup_clock_mode(spi, SPI_MODE_0);
- /* Enable master mode and clear error flags */
+ /* Enable host mode and clear error flags */
lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETMS |
LTQ_SPI_WHBSTATE_CLR_ERRORS,
LTQ_SPI_WHBSTATE);
@@ -386,8 +387,8 @@ static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi)
static int lantiq_ssc_setup(struct spi_device *spidev)
{
- struct spi_master *master = spidev->master;
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = spidev->controller;
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
unsigned int cs = spi_get_chipselect(spidev, 0);
u32 gpocon;
@@ -415,10 +416,10 @@ static int lantiq_ssc_setup(struct spi_device *spidev)
return 0;
}
-static int lantiq_ssc_prepare_message(struct spi_master *master,
+static int lantiq_ssc_prepare_message(struct spi_controller *host,
struct spi_message *message)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
hw_enter_config_mode(spi);
hw_setup_clock_mode(spi, message->spi->mode);
@@ -460,10 +461,10 @@ static void hw_setup_transfer(struct lantiq_ssc_spi *spi,
lantiq_ssc_writel(spi, con, LTQ_SPI_CON);
}
-static int lantiq_ssc_unprepare_message(struct spi_master *master,
+static int lantiq_ssc_unprepare_message(struct spi_controller *host,
struct spi_message *message)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
flush_workqueue(spi->wq);
@@ -692,8 +693,8 @@ static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data)
lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
/* set bad status so it can be retried */
- if (spi->master->cur_msg)
- spi->master->cur_msg->status = -EIO;
+ if (spi->host->cur_msg)
+ spi->host->cur_msg->status = -EIO;
queue_work(spi->wq, &spi->work);
spin_unlock(&spi->lock);
@@ -771,22 +772,22 @@ static void lantiq_ssc_bussy_work(struct work_struct *work)
u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT);
if (!(stat & LTQ_SPI_STAT_BSY)) {
- spi_finalize_current_transfer(spi->master);
+ spi_finalize_current_transfer(spi->host);
return;
}
cond_resched();
} while (!time_after_eq(jiffies, end));
- if (spi->master->cur_msg)
- spi->master->cur_msg->status = -EIO;
- spi_finalize_current_transfer(spi->master);
+ if (spi->host->cur_msg)
+ spi->host->cur_msg->status = -EIO;
+ spi_finalize_current_transfer(spi->host);
}
-static void lantiq_ssc_handle_err(struct spi_master *master,
+static void lantiq_ssc_handle_err(struct spi_controller *host,
struct spi_message *message)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
/* flush FIFOs on timeout */
rx_fifo_flush(spi);
@@ -795,7 +796,7 @@ static void lantiq_ssc_handle_err(struct spi_master *master,
static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(spidev->master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(spidev->controller);
unsigned int cs = spi_get_chipselect(spidev, 0);
u32 fgpo;
@@ -807,11 +808,11 @@ static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable)
lantiq_ssc_writel(spi, fgpo, LTQ_SPI_FPGO);
}
-static int lantiq_ssc_transfer_one(struct spi_master *master,
+static int lantiq_ssc_transfer_one(struct spi_controller *host,
struct spi_device *spidev,
struct spi_transfer *t)
{
- struct lantiq_ssc_spi *spi = spi_master_get_devdata(master);
+ struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
hw_setup_transfer(spi, spidev, t);
@@ -903,7 +904,7 @@ MODULE_DEVICE_TABLE(of, lantiq_ssc_match);
static int lantiq_ssc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct lantiq_ssc_spi *spi;
const struct lantiq_ssc_hwcfg *hwcfg;
u32 id, supports_dma, revision;
@@ -912,33 +913,30 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
hwcfg = of_device_get_match_data(dev);
- master = spi_alloc_master(dev, sizeof(struct lantiq_ssc_spi));
- if (!master)
+ host = spi_alloc_host(dev, sizeof(struct lantiq_ssc_spi));
+ if (!host)
return -ENOMEM;
- spi = spi_master_get_devdata(master);
- spi->master = master;
+ spi = spi_controller_get_devdata(host);
+ spi->host = host;
spi->dev = dev;
spi->hwcfg = hwcfg;
platform_set_drvdata(pdev, spi);
spi->regbase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(spi->regbase)) {
err = PTR_ERR(spi->regbase);
- goto err_master_put;
+ goto err_host_put;
}
err = hwcfg->cfg_irq(pdev, spi);
if (err)
- goto err_master_put;
+ goto err_host_put;
- spi->spi_clk = devm_clk_get(dev, "gate");
+ spi->spi_clk = devm_clk_get_enabled(dev, "gate");
if (IS_ERR(spi->spi_clk)) {
err = PTR_ERR(spi->spi_clk);
- goto err_master_put;
+ goto err_host_put;
}
- err = clk_prepare_enable(spi->spi_clk);
- if (err)
- goto err_master_put;
/*
* Use the old clk_get_fpi() function on Lantiq platform, till it
@@ -951,7 +949,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
#endif
if (IS_ERR(spi->fpi_clk)) {
err = PTR_ERR(spi->fpi_clk);
- goto err_clk_disable;
+ goto err_host_put;
}
num_cs = 8;
@@ -964,19 +962,19 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
spi->bits_per_word = 8;
spi->speed_hz = 0;
- master->dev.of_node = pdev->dev.of_node;
- master->num_chipselect = num_cs;
- master->use_gpio_descriptors = true;
- master->setup = lantiq_ssc_setup;
- master->set_cs = lantiq_ssc_set_cs;
- master->handle_err = lantiq_ssc_handle_err;
- master->prepare_message = lantiq_ssc_prepare_message;
- master->unprepare_message = lantiq_ssc_unprepare_message;
- master->transfer_one = lantiq_ssc_transfer_one;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH |
- SPI_LOOP;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) |
- SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
+ host->dev.of_node = pdev->dev.of_node;
+ host->num_chipselect = num_cs;
+ host->use_gpio_descriptors = true;
+ host->setup = lantiq_ssc_setup;
+ host->set_cs = lantiq_ssc_set_cs;
+ host->handle_err = lantiq_ssc_handle_err;
+ host->prepare_message = lantiq_ssc_prepare_message;
+ host->unprepare_message = lantiq_ssc_unprepare_message;
+ host->transfer_one = lantiq_ssc_transfer_one;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH |
+ SPI_LOOP;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) |
+ SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
spi->wq = alloc_ordered_workqueue(dev_name(dev), WQ_MEM_RECLAIM);
if (!spi->wq) {
@@ -997,9 +995,9 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
"Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n",
revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma);
- err = devm_spi_register_master(dev, master);
+ err = devm_spi_register_controller(dev, host);
if (err) {
- dev_err(dev, "failed to register spi_master\n");
+ dev_err(dev, "failed to register spi host\n");
goto err_wq_destroy;
}
@@ -1009,10 +1007,8 @@ err_wq_destroy:
destroy_workqueue(spi->wq);
err_clk_put:
clk_put(spi->fpi_clk);
-err_clk_disable:
- clk_disable_unprepare(spi->spi_clk);
-err_master_put:
- spi_master_put(master);
+err_host_put:
+ spi_controller_put(host);
return err;
}
@@ -1028,13 +1024,12 @@ static void lantiq_ssc_remove(struct platform_device *pdev)
hw_enter_config_mode(spi);
destroy_workqueue(spi->wq);
- clk_disable_unprepare(spi->spi_clk);
clk_put(spi->fpi_clk);
}
static struct platform_driver lantiq_ssc_driver = {
.probe = lantiq_ssc_probe,
- .remove_new = lantiq_ssc_remove,
+ .remove = lantiq_ssc_remove,
.driver = {
.name = "spi-lantiq-ssc",
.of_match_table = lantiq_ssc_match,
diff --git a/drivers/spi/spi-ljca.c b/drivers/spi/spi-ljca.c
new file mode 100644
index 000000000000..3f412cf8f1cd
--- /dev/null
+++ b/drivers/spi/spi-ljca.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel La Jolla Cove Adapter USB-SPI driver
+ *
+ * Copyright (c) 2023, Intel Corporation.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/usb/ljca.h>
+
+#define LJCA_SPI_BUS_MAX_HZ 48000000
+
+#define LJCA_SPI_BUF_SIZE 60u
+#define LJCA_SPI_MAX_XFER_SIZE \
+ (LJCA_SPI_BUF_SIZE - sizeof(struct ljca_spi_xfer_packet))
+
+#define LJCA_SPI_CLK_MODE_POLARITY BIT(0)
+#define LJCA_SPI_CLK_MODE_PHASE BIT(1)
+
+#define LJCA_SPI_XFER_INDICATOR_ID GENMASK(5, 0)
+#define LJCA_SPI_XFER_INDICATOR_CMPL BIT(6)
+#define LJCA_SPI_XFER_INDICATOR_INDEX BIT(7)
+
+/* SPI commands */
+enum ljca_spi_cmd {
+ LJCA_SPI_INIT = 1,
+ LJCA_SPI_READ,
+ LJCA_SPI_WRITE,
+ LJCA_SPI_WRITEREAD,
+ LJCA_SPI_DEINIT,
+};
+
+enum {
+ LJCA_SPI_BUS_SPEED_24M,
+ LJCA_SPI_BUS_SPEED_12M,
+ LJCA_SPI_BUS_SPEED_8M,
+ LJCA_SPI_BUS_SPEED_6M,
+ LJCA_SPI_BUS_SPEED_4_8M, /*4.8MHz*/
+ LJCA_SPI_BUS_SPEED_MIN = LJCA_SPI_BUS_SPEED_4_8M,
+};
+
+enum {
+ LJCA_SPI_CLOCK_LOW_POLARITY,
+ LJCA_SPI_CLOCK_HIGH_POLARITY,
+};
+
+enum {
+ LJCA_SPI_CLOCK_FIRST_PHASE,
+ LJCA_SPI_CLOCK_SECOND_PHASE,
+};
+
+struct ljca_spi_init_packet {
+ u8 index;
+ u8 speed;
+ u8 mode;
+} __packed;
+
+struct ljca_spi_xfer_packet {
+ u8 indicator;
+ u8 len;
+ u8 data[] __counted_by(len);
+} __packed;
+
+struct ljca_spi_dev {
+ struct ljca_client *ljca;
+ struct spi_controller *controller;
+ struct ljca_spi_info *spi_info;
+ u8 speed;
+ u8 mode;
+
+ u8 obuf[LJCA_SPI_BUF_SIZE];
+ u8 ibuf[LJCA_SPI_BUF_SIZE];
+};
+
+static int ljca_spi_read_write(struct ljca_spi_dev *ljca_spi, const u8 *w_data,
+ u8 *r_data, int len, int id, int complete,
+ int cmd)
+{
+ struct ljca_spi_xfer_packet *w_packet =
+ (struct ljca_spi_xfer_packet *)ljca_spi->obuf;
+ struct ljca_spi_xfer_packet *r_packet =
+ (struct ljca_spi_xfer_packet *)ljca_spi->ibuf;
+ int ret;
+
+ w_packet->indicator = FIELD_PREP(LJCA_SPI_XFER_INDICATOR_ID, id) |
+ FIELD_PREP(LJCA_SPI_XFER_INDICATOR_CMPL, complete) |
+ FIELD_PREP(LJCA_SPI_XFER_INDICATOR_INDEX,
+ ljca_spi->spi_info->id);
+
+ if (cmd == LJCA_SPI_READ) {
+ w_packet->len = sizeof(u16);
+ *(__le16 *)&w_packet->data[0] = cpu_to_le16(len);
+ } else {
+ w_packet->len = len;
+ memcpy(w_packet->data, w_data, len);
+ }
+
+ ret = ljca_transfer(ljca_spi->ljca, cmd, (u8 *)w_packet,
+ struct_size(w_packet, data, w_packet->len),
+ (u8 *)r_packet, LJCA_SPI_BUF_SIZE);
+ if (ret < 0)
+ return ret;
+ else if (ret < sizeof(*r_packet) || r_packet->len <= 0)
+ return -EIO;
+
+ if (r_data)
+ memcpy(r_data, r_packet->data, r_packet->len);
+
+ return 0;
+}
+
+static int ljca_spi_init(struct ljca_spi_dev *ljca_spi, u8 div, u8 mode)
+{
+ struct ljca_spi_init_packet w_packet = {};
+ int ret;
+
+ if (ljca_spi->mode == mode && ljca_spi->speed == div)
+ return 0;
+
+ w_packet.index = ljca_spi->spi_info->id;
+ w_packet.speed = div;
+ w_packet.mode = FIELD_PREP(LJCA_SPI_CLK_MODE_POLARITY,
+ (mode & SPI_CPOL) ? LJCA_SPI_CLOCK_HIGH_POLARITY :
+ LJCA_SPI_CLOCK_LOW_POLARITY) |
+ FIELD_PREP(LJCA_SPI_CLK_MODE_PHASE,
+ (mode & SPI_CPHA) ? LJCA_SPI_CLOCK_SECOND_PHASE :
+ LJCA_SPI_CLOCK_FIRST_PHASE);
+
+ ret = ljca_transfer(ljca_spi->ljca, LJCA_SPI_INIT, (u8 *)&w_packet,
+ sizeof(w_packet), NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ ljca_spi->mode = mode;
+ ljca_spi->speed = div;
+
+ return 0;
+}
+
+static int ljca_spi_deinit(struct ljca_spi_dev *ljca_spi)
+{
+ struct ljca_spi_init_packet w_packet = {};
+ int ret;
+
+ w_packet.index = ljca_spi->spi_info->id;
+
+ ret = ljca_transfer(ljca_spi->ljca, LJCA_SPI_DEINIT, (u8 *)&w_packet,
+ sizeof(w_packet), NULL, 0);
+
+ return ret < 0 ? ret : 0;
+}
+
+static inline int ljca_spi_transfer(struct ljca_spi_dev *ljca_spi,
+ const u8 *tx_data, u8 *rx_data, u16 len)
+{
+ int complete, cur_len;
+ int remaining = len;
+ int cmd, ret, i;
+ int offset = 0;
+
+ if (tx_data && rx_data)
+ cmd = LJCA_SPI_WRITEREAD;
+ else if (tx_data)
+ cmd = LJCA_SPI_WRITE;
+ else if (rx_data)
+ cmd = LJCA_SPI_READ;
+ else
+ return -EINVAL;
+
+ for (i = 0; remaining > 0; i++) {
+ cur_len = min_t(unsigned int, remaining, LJCA_SPI_MAX_XFER_SIZE);
+ complete = (cur_len == remaining);
+
+ ret = ljca_spi_read_write(ljca_spi,
+ tx_data ? tx_data + offset : NULL,
+ rx_data ? rx_data + offset : NULL,
+ cur_len, i, complete, cmd);
+ if (ret)
+ return ret;
+
+ offset += cur_len;
+ remaining -= cur_len;
+ }
+
+ return 0;
+}
+
+static int ljca_spi_transfer_one(struct spi_controller *controller,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ u8 div = DIV_ROUND_UP(controller->max_speed_hz, xfer->speed_hz) / 2 - 1;
+ struct ljca_spi_dev *ljca_spi = spi_controller_get_devdata(controller);
+ int ret;
+
+ div = min_t(u8, LJCA_SPI_BUS_SPEED_MIN, div);
+
+ ret = ljca_spi_init(ljca_spi, div, spi->mode);
+ if (ret) {
+ dev_err(&ljca_spi->ljca->auxdev.dev,
+ "cannot initialize transfer ret %d\n", ret);
+ return ret;
+ }
+
+ ret = ljca_spi_transfer(ljca_spi, xfer->tx_buf, xfer->rx_buf, xfer->len);
+ if (ret)
+ dev_err(&ljca_spi->ljca->auxdev.dev,
+ "transfer failed len: %d\n", xfer->len);
+
+ return ret;
+}
+
+static int ljca_spi_probe(struct auxiliary_device *auxdev,
+ const struct auxiliary_device_id *aux_dev_id)
+{
+ struct ljca_client *ljca = auxiliary_dev_to_ljca_client(auxdev);
+ struct spi_controller *controller;
+ struct ljca_spi_dev *ljca_spi;
+ int ret;
+
+ controller = devm_spi_alloc_host(&auxdev->dev, sizeof(*ljca_spi));
+ if (!controller)
+ return -ENOMEM;
+
+ ljca_spi = spi_controller_get_devdata(controller);
+ ljca_spi->ljca = ljca;
+ ljca_spi->spi_info = dev_get_platdata(&auxdev->dev);
+ ljca_spi->controller = controller;
+
+ controller->bus_num = -1;
+ controller->mode_bits = SPI_CPHA | SPI_CPOL;
+ controller->transfer_one = ljca_spi_transfer_one;
+ controller->auto_runtime_pm = false;
+ controller->max_speed_hz = LJCA_SPI_BUS_MAX_HZ;
+
+ device_set_node(&ljca_spi->controller->dev, dev_fwnode(&auxdev->dev));
+ auxiliary_set_drvdata(auxdev, controller);
+
+ ret = spi_register_controller(controller);
+ if (ret)
+ dev_err(&auxdev->dev, "Failed to register controller\n");
+
+ return ret;
+}
+
+static void ljca_spi_dev_remove(struct auxiliary_device *auxdev)
+{
+ struct spi_controller *controller = auxiliary_get_drvdata(auxdev);
+ struct ljca_spi_dev *ljca_spi = spi_controller_get_devdata(controller);
+
+ spi_unregister_controller(controller);
+ ljca_spi_deinit(ljca_spi);
+}
+
+static int ljca_spi_dev_suspend(struct device *dev)
+{
+ struct spi_controller *controller = dev_get_drvdata(dev);
+
+ return spi_controller_suspend(controller);
+}
+
+static int ljca_spi_dev_resume(struct device *dev)
+{
+ struct spi_controller *controller = dev_get_drvdata(dev);
+
+ return spi_controller_resume(controller);
+}
+
+static const struct dev_pm_ops ljca_spi_pm = {
+ SYSTEM_SLEEP_PM_OPS(ljca_spi_dev_suspend, ljca_spi_dev_resume)
+};
+
+static const struct auxiliary_device_id ljca_spi_id_table[] = {
+ { "usb_ljca.ljca-spi", 0 },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(auxiliary, ljca_spi_id_table);
+
+static struct auxiliary_driver ljca_spi_driver = {
+ .driver.pm = &ljca_spi_pm,
+ .probe = ljca_spi_probe,
+ .remove = ljca_spi_dev_remove,
+ .id_table = ljca_spi_id_table,
+};
+module_auxiliary_driver(ljca_spi_driver);
+
+MODULE_AUTHOR("Wentong Wu");
+MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>");
+MODULE_AUTHOR("Lixu Zhang <lixu.zhang@intel.com>");
+MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-SPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("LJCA");
diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c
index ead0507c63be..e61e89b4119f 100644
--- a/drivers/spi/spi-lm70llp.c
+++ b/drivers/spi/spi-lm70llp.c
@@ -24,15 +24,15 @@
* the SPI/Microwire bus interface. This driver specifically supports an
* NS LM70 LLP Evaluation Board, interfacing to a PC using its parallel
* port to bitbang an SPI-parport bridge. Accordingly, this is an SPI
- * master controller driver. The hwmon/lm70 driver is a "SPI protocol
+ * host controller driver. The hwmon/lm70 driver is a "SPI protocol
* driver", layered on top of this one and usable without the lm70llp.
*
* Datasheet and Schematic:
* The LM70 is a temperature sensor chip from National Semiconductor; its
- * datasheet is available at http://www.national.com/pf/LM/LM70.html
+ * datasheet is available at https://www.ti.com/lit/gpn/lm70
* The schematic for this particular board (the LM70EVAL-LLP) is
* available (on page 4) here:
- * http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
+ * https://download.datasheets.com/pdfs/documentation/nat/kit&board/lm70llpevalmanual.pdf
*
* Also see Documentation/spi/spi-lm70llp.rst. The SPI<->parport code here is
* (heavily) based on spi-butterfly by David Brownell.
@@ -189,7 +189,7 @@ static void spi_lm70llp_attach(struct parport *p)
{
struct pardevice *pd;
struct spi_lm70llp *pp;
- struct spi_master *master;
+ struct spi_controller *host;
int status;
struct pardev_cb lm70llp_cb;
@@ -202,17 +202,17 @@ static void spi_lm70llp_attach(struct parport *p)
* the lm70 driver could verify it, reading the manf ID.
*/
- master = spi_alloc_master(p->physport->dev, sizeof(*pp));
- if (!master) {
+ host = spi_alloc_host(p->physport->dev, sizeof(*pp));
+ if (!host) {
status = -ENOMEM;
goto out_fail;
}
- pp = spi_master_get_devdata(master);
+ pp = spi_controller_get_devdata(host);
/*
* SPI and bitbang hookup.
*/
- pp->bitbang.master = master;
+ pp->bitbang.ctlr = host;
pp->bitbang.chipselect = lm70_chipselect;
pp->bitbang.txrx_word[SPI_MODE_0] = lm70_txrx;
pp->bitbang.flags = SPI_3WIRE;
@@ -228,7 +228,7 @@ static void spi_lm70llp_attach(struct parport *p)
if (!pd) {
status = -ENOMEM;
- goto out_free_master;
+ goto out_free_host;
}
pp->pd = pd;
@@ -264,7 +264,7 @@ static void spi_lm70llp_attach(struct parport *p)
* the board info's (void *)controller_data.
*/
pp->info.controller_data = pp;
- pp->spidev_lm70 = spi_new_device(pp->bitbang.master, &pp->info);
+ pp->spidev_lm70 = spi_new_device(pp->bitbang.ctlr, &pp->info);
if (pp->spidev_lm70)
dev_dbg(&pp->spidev_lm70->dev, "spidev_lm70 at %s\n",
dev_name(&pp->spidev_lm70->dev));
@@ -287,8 +287,8 @@ out_off_and_release:
parport_release(pp->pd);
out_parport_unreg:
parport_unregister_device(pd);
-out_free_master:
- spi_master_put(master);
+out_free_host:
+ spi_controller_put(host);
out_fail:
pr_info("spi_lm70llp probe fail, status %d\n", status);
}
@@ -309,7 +309,7 @@ static void spi_lm70llp_detach(struct parport *p)
parport_release(pp->pd);
parport_unregister_device(pp->pd);
- spi_master_put(pp->bitbang.master);
+ spi_controller_put(pp->bitbang.ctlr);
lm70llp = NULL;
}
@@ -318,7 +318,6 @@ static struct parport_driver spi_lm70llp_drv = {
.name = DRVNAME,
.match_port = spi_lm70llp_attach,
.detach = spi_lm70llp_detach,
- .devmodel = true,
};
module_parport_driver(spi_lm70llp_drv);
diff --git a/drivers/spi/spi-loongson-core.c b/drivers/spi/spi-loongson-core.c
new file mode 100644
index 000000000000..b46f072a0387
--- /dev/null
+++ b/drivers/spi/spi-loongson-core.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Loongson SPI Support
+// Copyright (C) 2023 Loongson Technology Corporation Limited
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "spi-loongson.h"
+
+static inline void loongson_spi_write_reg(struct loongson_spi *spi, unsigned char reg,
+ unsigned char data)
+{
+ writeb(data, spi->base + reg);
+}
+
+static inline char loongson_spi_read_reg(struct loongson_spi *spi, unsigned char reg)
+{
+ return readb(spi->base + reg);
+}
+
+static void loongson_spi_set_cs(struct spi_device *spi, bool en)
+{
+ int cs;
+ unsigned char mask = (BIT(4) | BIT(0)) << spi_get_chipselect(spi, 0);
+ unsigned char val = en ? mask : (BIT(0) << spi_get_chipselect(spi, 0));
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(spi->controller);
+
+ cs = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SFCS_REG) & ~mask;
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SFCS_REG, val | cs);
+}
+
+static void loongson_spi_set_clk(struct loongson_spi *loongson_spi, unsigned int hz)
+{
+ unsigned char val;
+ unsigned int div, div_tmp;
+ static const char rdiv[12] = {0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10, 11};
+
+ div = clamp_val(DIV_ROUND_UP_ULL(loongson_spi->clk_rate, hz), 2, 4096);
+ div_tmp = rdiv[fls(div - 1)];
+ loongson_spi->spcr = (div_tmp & GENMASK(1, 0)) >> 0;
+ loongson_spi->sper = (div_tmp & GENMASK(3, 2)) >> 2;
+ val = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPCR_REG);
+ val &= ~GENMASK(1, 0);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPCR_REG, val |
+ loongson_spi->spcr);
+ val = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPER_REG);
+ val &= ~GENMASK(1, 0);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPER_REG, val |
+ loongson_spi->sper);
+ loongson_spi->hz = hz;
+}
+
+static void loongson_spi_set_mode(struct loongson_spi *loongson_spi,
+ struct spi_device *spi)
+{
+ unsigned char val;
+
+ val = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPCR_REG);
+ val &= ~(LOONGSON_SPI_SPCR_CPOL | LOONGSON_SPI_SPCR_CPHA);
+ if (spi->mode & SPI_CPOL)
+ val |= LOONGSON_SPI_SPCR_CPOL;
+ if (spi->mode & SPI_CPHA)
+ val |= LOONGSON_SPI_SPCR_CPHA;
+
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPCR_REG, val);
+ loongson_spi->mode |= spi->mode;
+}
+
+static int loongson_spi_update_state(struct loongson_spi *loongson_spi,
+ struct spi_device *spi, struct spi_transfer *t)
+{
+ if (t && loongson_spi->hz != t->speed_hz)
+ loongson_spi_set_clk(loongson_spi, t->speed_hz);
+
+ if ((spi->mode ^ loongson_spi->mode) & SPI_MODE_X_MASK)
+ loongson_spi_set_mode(loongson_spi, spi);
+
+ return 0;
+}
+
+static int loongson_spi_setup(struct spi_device *spi)
+{
+ struct loongson_spi *loongson_spi;
+
+ loongson_spi = spi_controller_get_devdata(spi->controller);
+ if (spi->bits_per_word % 8)
+ return -EINVAL;
+
+ if (spi_get_chipselect(spi, 0) >= spi->controller->num_chipselect)
+ return -EINVAL;
+
+ loongson_spi->hz = 0;
+ loongson_spi_set_cs(spi, true);
+
+ return 0;
+}
+
+static int loongson_spi_write_read_8bit(struct spi_device *spi, const u8 **tx_buf,
+ u8 **rx_buf, unsigned int num)
+{
+ int ret;
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(spi->controller);
+
+ if (tx_buf && *tx_buf)
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_FIFO_REG, *((*tx_buf)++));
+ else
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_FIFO_REG, 0);
+
+ ret = readb_poll_timeout(loongson_spi->base + LOONGSON_SPI_SPSR_REG,
+ loongson_spi->spsr, (loongson_spi->spsr &
+ LOONGSON_SPI_SPSR_RFEMPTY) != LOONGSON_SPI_SPSR_RFEMPTY,
+ 1, USEC_PER_MSEC);
+
+ if (rx_buf && *rx_buf)
+ *(*rx_buf)++ = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_FIFO_REG);
+ else
+ loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_FIFO_REG);
+
+ return ret;
+}
+
+static int loongson_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ int ret;
+ unsigned int count;
+ const u8 *tx = xfer->tx_buf;
+ u8 *rx = xfer->rx_buf;
+
+ count = xfer->len;
+ do {
+ ret = loongson_spi_write_read_8bit(spi, &tx, &rx, count);
+ if (ret)
+ break;
+ } while (--count);
+
+ return ret;
+}
+
+static int loongson_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *m)
+{
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(ctlr);
+
+ loongson_spi->para = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_PARA_REG);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_PARA_REG, loongson_spi->para &
+ ~LOONGSON_SPI_PARA_MEM_EN);
+
+ return 0;
+}
+
+static int loongson_spi_transfer_one(struct spi_controller *ctrl, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(spi->controller);
+
+ loongson_spi_update_state(loongson_spi, spi, xfer);
+ if (xfer->len)
+ return loongson_spi_write_read(spi, xfer);
+
+ return 0;
+}
+
+static int loongson_spi_unprepare_message(struct spi_controller *ctrl, struct spi_message *m)
+{
+ struct loongson_spi *loongson_spi = spi_controller_get_devdata(ctrl);
+
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_PARA_REG, loongson_spi->para);
+
+ return 0;
+}
+
+static void loongson_spi_reginit(struct loongson_spi *loongson_spi_dev)
+{
+ unsigned char val;
+
+ val = loongson_spi_read_reg(loongson_spi_dev, LOONGSON_SPI_SPCR_REG);
+ val &= ~LOONGSON_SPI_SPCR_SPE;
+ loongson_spi_write_reg(loongson_spi_dev, LOONGSON_SPI_SPCR_REG, val);
+
+ loongson_spi_write_reg(loongson_spi_dev, LOONGSON_SPI_SPSR_REG,
+ (LOONGSON_SPI_SPSR_SPIF | LOONGSON_SPI_SPSR_WCOL));
+
+ val = loongson_spi_read_reg(loongson_spi_dev, LOONGSON_SPI_SPCR_REG);
+ val |= LOONGSON_SPI_SPCR_SPE;
+ loongson_spi_write_reg(loongson_spi_dev, LOONGSON_SPI_SPCR_REG, val);
+}
+
+int loongson_spi_init_controller(struct device *dev, void __iomem *regs)
+{
+ struct spi_controller *controller;
+ struct loongson_spi *spi;
+ struct clk *clk;
+
+ controller = devm_spi_alloc_host(dev, sizeof(struct loongson_spi));
+ if (controller == NULL)
+ return -ENOMEM;
+
+ controller->mode_bits = SPI_MODE_X_MASK | SPI_CS_HIGH;
+ controller->setup = loongson_spi_setup;
+ controller->prepare_message = loongson_spi_prepare_message;
+ controller->transfer_one = loongson_spi_transfer_one;
+ controller->unprepare_message = loongson_spi_unprepare_message;
+ controller->set_cs = loongson_spi_set_cs;
+ controller->num_chipselect = 4;
+ device_set_node(&controller->dev, dev_fwnode(dev));
+ dev_set_drvdata(dev, controller);
+
+ spi = spi_controller_get_devdata(controller);
+ spi->base = regs;
+ spi->controller = controller;
+
+ clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "unable to get clock\n");
+
+ spi->clk_rate = clk_get_rate(clk);
+ loongson_spi_reginit(spi);
+
+ spi->mode = 0;
+
+ return devm_spi_register_controller(dev, controller);
+}
+EXPORT_SYMBOL_NS_GPL(loongson_spi_init_controller, "SPI_LOONGSON_CORE");
+
+static int __maybe_unused loongson_spi_suspend(struct device *dev)
+{
+ struct loongson_spi *loongson_spi;
+ struct spi_controller *controller;
+
+ controller = dev_get_drvdata(dev);
+ spi_controller_suspend(controller);
+
+ loongson_spi = spi_controller_get_devdata(controller);
+
+ loongson_spi->spcr = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPCR_REG);
+ loongson_spi->sper = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPER_REG);
+ loongson_spi->spsr = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPSR_REG);
+ loongson_spi->para = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_PARA_REG);
+ loongson_spi->sfcs = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SFCS_REG);
+ loongson_spi->timi = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_TIMI_REG);
+
+ return 0;
+}
+
+static int __maybe_unused loongson_spi_resume(struct device *dev)
+{
+ struct loongson_spi *loongson_spi;
+ struct spi_controller *controller;
+
+ controller = dev_get_drvdata(dev);
+ loongson_spi = spi_controller_get_devdata(controller);
+
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPCR_REG, loongson_spi->spcr);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPER_REG, loongson_spi->sper);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPSR_REG, loongson_spi->spsr);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_PARA_REG, loongson_spi->para);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SFCS_REG, loongson_spi->sfcs);
+ loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_TIMI_REG, loongson_spi->timi);
+
+ spi_controller_resume(controller);
+
+ return 0;
+}
+
+const struct dev_pm_ops loongson_spi_dev_pm_ops = {
+ .suspend = loongson_spi_suspend,
+ .resume = loongson_spi_resume,
+};
+EXPORT_SYMBOL_NS_GPL(loongson_spi_dev_pm_ops, "SPI_LOONGSON_CORE");
+
+MODULE_DESCRIPTION("Loongson SPI core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-loongson-pci.c b/drivers/spi/spi-loongson-pci.c
new file mode 100644
index 000000000000..cbcde153260e
--- /dev/null
+++ b/drivers/spi/spi-loongson-pci.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0+
+// PCI interface driver for Loongson SPI Support
+// Copyright (C) 2023 Loongson Technology Corporation Limited
+
+#include <linux/mod_devicetable.h>
+#include <linux/pci.h>
+
+#include "spi-loongson.h"
+
+static int loongson_spi_pci_register(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int ret;
+ void __iomem *reg_base;
+ struct device *dev = &pdev->dev;
+ int pci_bar = 0;
+
+ ret = pcim_enable_device(pdev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "cannot enable pci device\n");
+
+ reg_base = pcim_iomap_region(pdev, pci_bar, pci_name(pdev));
+ ret = PTR_ERR_OR_ZERO(reg_base);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request and remap memory\n");
+
+ ret = loongson_spi_init_controller(dev, reg_base);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize controller\n");
+
+ return 0;
+}
+
+static struct pci_device_id loongson_spi_devices[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a0b) },
+ { PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a1b) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, loongson_spi_devices);
+
+static struct pci_driver loongson_spi_pci_driver = {
+ .name = "loongson-spi-pci",
+ .id_table = loongson_spi_devices,
+ .probe = loongson_spi_pci_register,
+ .driver = {
+ .bus = &pci_bus_type,
+ .pm = &loongson_spi_dev_pm_ops,
+ },
+};
+module_pci_driver(loongson_spi_pci_driver);
+
+MODULE_DESCRIPTION("Loongson spi pci driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SPI_LOONGSON_CORE");
diff --git a/drivers/spi/spi-loongson-plat.c b/drivers/spi/spi-loongson-plat.c
new file mode 100644
index 000000000000..64a7270f9a64
--- /dev/null
+++ b/drivers/spi/spi-loongson-plat.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Platform driver for Loongson SPI Support
+// Copyright (C) 2023 Loongson Technology Corporation Limited
+
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "spi-loongson.h"
+
+static int loongson_spi_platform_probe(struct platform_device *pdev)
+{
+ int ret;
+ void __iomem *reg_base;
+ struct device *dev = &pdev->dev;
+
+ reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+
+ ret = loongson_spi_init_controller(dev, reg_base);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to initialize controller\n");
+
+ return 0;
+}
+
+static const struct of_device_id loongson_spi_id_table[] = {
+ { .compatible = "loongson,ls2k1000-spi" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, loongson_spi_id_table);
+
+static struct platform_driver loongson_spi_plat_driver = {
+ .probe = loongson_spi_platform_probe,
+ .driver = {
+ .name = "loongson-spi",
+ .bus = &platform_bus_type,
+ .pm = &loongson_spi_dev_pm_ops,
+ .of_match_table = loongson_spi_id_table,
+ },
+};
+module_platform_driver(loongson_spi_plat_driver);
+
+MODULE_DESCRIPTION("Loongson spi platform driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SPI_LOONGSON_CORE");
diff --git a/drivers/spi/spi-loongson.h b/drivers/spi/spi-loongson.h
new file mode 100644
index 000000000000..35f95b161842
--- /dev/null
+++ b/drivers/spi/spi-loongson.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Header File for Loongson SPI Driver. */
+/* Copyright (C) 2023 Loongson Technology Corporation Limited */
+
+#ifndef __LINUX_SPI_LOONGSON_H
+#define __LINUX_SPI_LOONGSON_H
+
+#include <linux/bits.h>
+#include <linux/pm.h>
+#include <linux/types.h>
+
+#define LOONGSON_SPI_SPCR_REG 0x00
+#define LOONGSON_SPI_SPSR_REG 0x01
+#define LOONGSON_SPI_FIFO_REG 0x02
+#define LOONGSON_SPI_SPER_REG 0x03
+#define LOONGSON_SPI_PARA_REG 0x04
+#define LOONGSON_SPI_SFCS_REG 0x05
+#define LOONGSON_SPI_TIMI_REG 0x06
+
+/* Bits definition for Loongson SPI register */
+#define LOONGSON_SPI_PARA_MEM_EN BIT(0)
+#define LOONGSON_SPI_SPCR_CPHA BIT(2)
+#define LOONGSON_SPI_SPCR_CPOL BIT(3)
+#define LOONGSON_SPI_SPCR_SPE BIT(6)
+#define LOONGSON_SPI_SPSR_RFEMPTY BIT(0)
+#define LOONGSON_SPI_SPSR_WCOL BIT(6)
+#define LOONGSON_SPI_SPSR_SPIF BIT(7)
+
+struct device;
+struct spi_controller;
+
+struct loongson_spi {
+ struct spi_controller *controller;
+ void __iomem *base;
+ int cs_active;
+ unsigned int hz;
+ unsigned char spcr;
+ unsigned char sper;
+ unsigned char spsr;
+ unsigned char para;
+ unsigned char sfcs;
+ unsigned char timi;
+ unsigned int mode;
+ u64 clk_rate;
+};
+
+int loongson_spi_init_controller(struct device *dev, void __iomem *reg);
+extern const struct dev_pm_ops loongson_spi_dev_pm_ops;
+#endif /* __LINUX_SPI_LOONGSON_H */
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c
index 675a73cf1579..e0b131aa29b6 100644
--- a/drivers/spi/spi-loopback-test.c
+++ b/drivers/spi/spi-loopback-test.c
@@ -14,8 +14,8 @@
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/list_sort.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/printk.h>
#include <linux/vmalloc.h>
#include <linux/spi/spi.h>
@@ -396,7 +396,6 @@ MODULE_DEVICE_TABLE(of, spi_loopback_test_of_match);
static struct spi_driver spi_loopback_test_driver = {
.driver = {
.name = "spi-loopback-test",
- .owner = THIS_MODULE,
.of_match_table = spi_loopback_test_of_match,
},
.probe = spi_loopback_test_probe,
@@ -421,7 +420,7 @@ MODULE_LICENSE("GPL");
static void spi_test_print_hex_dump(char *pre, const void *ptr, size_t len)
{
/* limit the hex_dump */
- if (len < 1024) {
+ if (len <= 1024) {
print_hex_dump(KERN_INFO, pre,
DUMP_PREFIX_OFFSET, 16, 1,
ptr, len, 0);
@@ -447,7 +446,7 @@ static void spi_test_dump_message(struct spi_device *spi,
int i;
u8 b;
- dev_info(&spi->dev, " spi_msg@%pK\n", msg);
+ dev_info(&spi->dev, " spi_msg@%p\n", msg);
if (msg->status)
dev_info(&spi->dev, " status: %i\n",
msg->status);
@@ -457,15 +456,15 @@ static void spi_test_dump_message(struct spi_device *spi,
msg->actual_length);
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- dev_info(&spi->dev, " spi_transfer@%pK\n", xfer);
+ dev_info(&spi->dev, " spi_transfer@%p\n", xfer);
dev_info(&spi->dev, " len: %i\n", xfer->len);
- dev_info(&spi->dev, " tx_buf: %pK\n", xfer->tx_buf);
+ dev_info(&spi->dev, " tx_buf: %p\n", xfer->tx_buf);
if (dump_data && xfer->tx_buf)
spi_test_print_hex_dump(" TX: ",
xfer->tx_buf,
xfer->len);
- dev_info(&spi->dev, " rx_buf: %pK\n", xfer->rx_buf);
+ dev_info(&spi->dev, " rx_buf: %p\n", xfer->rx_buf);
if (dump_data && xfer->rx_buf)
spi_test_print_hex_dump(" RX: ",
xfer->rx_buf,
@@ -495,8 +494,8 @@ struct rx_ranges {
static int rx_ranges_cmp(void *priv, const struct list_head *a,
const struct list_head *b)
{
- struct rx_ranges *rx_a = list_entry(a, struct rx_ranges, list);
- struct rx_ranges *rx_b = list_entry(b, struct rx_ranges, list);
+ const struct rx_ranges *rx_a = list_entry(a, struct rx_ranges, list);
+ const struct rx_ranges *rx_b = list_entry(b, struct rx_ranges, list);
if (rx_a->start > rx_b->start)
return 1;
@@ -559,7 +558,7 @@ static int spi_check_rx_ranges(struct spi_device *spi,
/* if still not found then something has modified too much */
/* we could list the "closest" transfer here... */
dev_err(&spi->dev,
- "loopback strangeness - rx changed outside of allowed range at: %pK\n",
+ "loopback strangeness - rx changed outside of allowed range at: %p\n",
addr);
/* do not return, only set ret,
* so that we list all addresses
@@ -636,8 +635,8 @@ static int spi_test_check_loopback_result(struct spi_device *spi,
} else {
/* first byte received */
txb = ((u8 *)xfer->rx_buf)[0];
- /* first byte may be 0 or xff */
- if (!((txb == 0) || (txb == 0xff))) {
+ /* first byte may be 0 or 0xff */
+ if (txb != 0 && txb != 0xff) {
dev_err(&spi->dev,
"loopback strangeness - we expect 0x00 or 0xff, but not 0x%02x\n",
txb);
@@ -697,7 +696,7 @@ static int spi_test_translate(struct spi_device *spi,
}
dev_err(&spi->dev,
- "PointerRange [%pK:%pK[ not in range [%pK:%pK[ or [%pK:%pK[\n",
+ "PointerRange [%p:%p[ not in range [%p:%p[ or [%p:%p[\n",
*ptr, *ptr + len,
RX(0), RX(SPI_TEST_MAX_SIZE),
TX(0), TX(SPI_TEST_MAX_SIZE));
@@ -1031,8 +1030,8 @@ int spi_test_run_test(struct spi_device *spi, const struct spi_test *test,
#define FOR_EACH_ALIGNMENT(var) \
for (var = 0; \
var < (test->iterate_##var ? \
- (spi->master->dma_alignment ? \
- spi->master->dma_alignment : \
+ (spi->controller->dma_alignment ? \
+ spi->controller->dma_alignment : \
test->iterate_##var) : \
1); \
var++)
diff --git a/drivers/spi/spi-lp8841-rtc.c b/drivers/spi/spi-lp8841-rtc.c
index 2d436541d6c2..382e2a69f7a7 100644
--- a/drivers/spi/spi-lp8841-rtc.c
+++ b/drivers/spi/spi-lp8841-rtc.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * SPI master driver for ICP DAS LP-8841 RTC
+ * SPI host driver for ICP DAS LP-8841 RTC
*
* Copyright (C) 2016 Sergei Ianovich
*
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/spi/spi.h>
#define DRIVER_NAME "spi_lp8841_rtc"
@@ -74,15 +73,15 @@ bitbang_txrx_be_cpha0_lsb(struct spi_lp8841_rtc *data,
/* clock starts at inactive polarity */
for (; likely(bits); bits--) {
- /* setup LSB (to slave) on leading edge */
- if ((flags & SPI_MASTER_NO_TX) == 0)
+ /* setup LSB (to target) on leading edge */
+ if ((flags & SPI_CONTROLLER_NO_TX) == 0)
setmosi(data, (word & 1));
usleep_range(usecs, usecs + 1); /* T(setup) */
- /* sample LSB (from slave) on trailing edge */
+ /* sample LSB (from target) on trailing edge */
word >>= 1;
- if ((flags & SPI_MASTER_NO_RX) == 0)
+ if ((flags & SPI_CONTROLLER_NO_RX) == 0)
word |= (getmiso(data) << 31);
setsck(data, !cpol);
@@ -96,11 +95,11 @@ bitbang_txrx_be_cpha0_lsb(struct spi_lp8841_rtc *data,
}
static int
-spi_lp8841_rtc_transfer_one(struct spi_master *master,
+spi_lp8841_rtc_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct spi_lp8841_rtc *data = spi_master_get_devdata(master);
+ struct spi_lp8841_rtc *data = spi_controller_get_devdata(host);
unsigned count = t->len;
const u8 *tx = t->tx_buf;
u8 *rx = t->rx_buf;
@@ -113,7 +112,7 @@ spi_lp8841_rtc_transfer_one(struct spi_master *master,
while (likely(count > 0)) {
word = *tx++;
bitbang_txrx_be_cpha0_lsb(data, 1, 0,
- SPI_MASTER_NO_RX, word, 8);
+ SPI_CONTROLLER_NO_RX, word, 8);
count--;
}
} else if (rx) {
@@ -121,7 +120,7 @@ spi_lp8841_rtc_transfer_one(struct spi_master *master,
writeb(data->state, data->iomem);
while (likely(count > 0)) {
word = bitbang_txrx_be_cpha0_lsb(data, 1, 0,
- SPI_MASTER_NO_TX, word, 8);
+ SPI_CONTROLLER_NO_TX, word, 8);
*rx++ = word;
count--;
}
@@ -129,7 +128,7 @@ spi_lp8841_rtc_transfer_one(struct spi_master *master,
ret = -EINVAL;
}
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return ret;
}
@@ -137,7 +136,7 @@ spi_lp8841_rtc_transfer_one(struct spi_master *master,
static void
spi_lp8841_rtc_set_cs(struct spi_device *spi, bool enable)
{
- struct spi_lp8841_rtc *data = spi_master_get_devdata(spi->master);
+ struct spi_lp8841_rtc *data = spi_controller_get_devdata(spi->controller);
data->state = 0;
writeb(data->state, data->iomem);
@@ -183,48 +182,48 @@ static int
spi_lp8841_rtc_probe(struct platform_device *pdev)
{
int ret;
- struct spi_master *master;
+ struct spi_controller *host;
struct spi_lp8841_rtc *data;
- master = spi_alloc_master(&pdev->dev, sizeof(*data));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*data));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->mode_bits = SPI_CS_HIGH | SPI_3WIRE | SPI_LSB_FIRST;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->mode_bits = SPI_CS_HIGH | SPI_3WIRE | SPI_LSB_FIRST;
- master->bus_num = pdev->id;
- master->num_chipselect = 1;
- master->setup = spi_lp8841_rtc_setup;
- master->set_cs = spi_lp8841_rtc_set_cs;
- master->transfer_one = spi_lp8841_rtc_transfer_one;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->bus_num = pdev->id;
+ host->num_chipselect = 1;
+ host->setup = spi_lp8841_rtc_setup;
+ host->set_cs = spi_lp8841_rtc_set_cs;
+ host->transfer_one = spi_lp8841_rtc_transfer_one;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
#ifdef CONFIG_OF
- master->dev.of_node = pdev->dev.of_node;
+ host->dev.of_node = pdev->dev.of_node;
#endif
- data = spi_master_get_devdata(master);
+ data = spi_controller_get_devdata(host);
data->iomem = devm_platform_ioremap_resource(pdev, 0);
ret = PTR_ERR_OR_ZERO(data->iomem);
if (ret) {
dev_err(&pdev->dev, "failed to get IO address\n");
- goto err_put_master;
+ goto err_put_host;
}
/* register with the SPI framework */
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&pdev->dev, "cannot register spi master\n");
- goto err_put_master;
+ dev_err(&pdev->dev, "cannot register spi host\n");
+ goto err_put_host;
}
return ret;
-err_put_master:
- spi_master_put(master);
+err_put_host:
+ spi_controller_put(host);
return ret;
}
@@ -240,6 +239,6 @@ static struct platform_driver spi_lp8841_rtc_driver = {
};
module_platform_driver(spi_lp8841_rtc_driver);
-MODULE_DESCRIPTION("SPI master driver for ICP DAS LP-8841 RTC");
+MODULE_DESCRIPTION("SPI host driver for ICP DAS LP-8841 RTC");
MODULE_AUTHOR("Sergei Ianovich");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index edd7430d4c05..c8b2add2640e 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -12,6 +12,9 @@
#include <linux/spi/spi-mem.h>
#include <linux/sched/task_stack.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/spi-mem.h>
+
#include "internals.h"
#define SPI_MEM_MAX_BUSWIDTH 8
@@ -172,6 +175,9 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
if (!spi_mem_controller_is_capable(ctlr, dtr))
return false;
+ if (op->data.swap16 && !spi_mem_controller_is_capable(ctlr, swap16))
+ return false;
+
if (op->cmd.nbytes != 2)
return false;
} else {
@@ -184,6 +190,16 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
return false;
}
+ if (op->max_freq && mem->spi->controller->min_speed_hz &&
+ op->max_freq < mem->spi->controller->min_speed_hz)
+ return false;
+
+ if (op->max_freq &&
+ op->max_freq < mem->spi->max_speed_hz) {
+ if (!spi_mem_controller_is_capable(ctlr, per_op_freq))
+ return false;
+ }
+
return spi_mem_check_buswidth(mem, op);
}
EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
@@ -252,6 +268,9 @@ static bool spi_mem_internal_supports_op(struct spi_mem *mem,
*/
bool spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
+ /* Make sure the operation frequency is correct before going futher */
+ spi_mem_adjust_op_freq(mem, (struct spi_mem_op *)op);
+
if (spi_mem_check_op(op))
return false;
@@ -297,6 +316,49 @@ static void spi_mem_access_end(struct spi_mem *mem)
pm_runtime_put(ctlr->dev.parent);
}
+static void spi_mem_add_op_stats(struct spi_statistics __percpu *pcpu_stats,
+ const struct spi_mem_op *op, int exec_op_ret)
+{
+ struct spi_statistics *stats;
+ u64 len, l2len;
+
+ get_cpu();
+ stats = this_cpu_ptr(pcpu_stats);
+ u64_stats_update_begin(&stats->syncp);
+
+ /*
+ * We do not have the concept of messages or transfers. Let's consider
+ * that one operation is equivalent to one message and one transfer.
+ */
+ u64_stats_inc(&stats->messages);
+ u64_stats_inc(&stats->transfers);
+
+ /* Use the sum of all lengths as bytes count and histogram value. */
+ len = op->cmd.nbytes + op->addr.nbytes;
+ len += op->dummy.nbytes + op->data.nbytes;
+ u64_stats_add(&stats->bytes, len);
+ l2len = min(fls(len), SPI_STATISTICS_HISTO_SIZE) - 1;
+ u64_stats_inc(&stats->transfer_bytes_histo[l2len]);
+
+ /* Only account for data bytes as transferred bytes. */
+ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
+ u64_stats_add(&stats->bytes_tx, op->data.nbytes);
+ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN)
+ u64_stats_add(&stats->bytes_rx, op->data.nbytes);
+
+ /*
+ * A timeout is not an error, following the same behavior as
+ * spi_transfer_one_message().
+ */
+ if (exec_op_ret == -ETIMEDOUT)
+ u64_stats_inc(&stats->timedout);
+ else if (exec_op_ret)
+ u64_stats_inc(&stats->errors);
+
+ u64_stats_update_end(&stats->syncp);
+ put_cpu();
+}
+
/**
* spi_mem_exec_op() - Execute a memory operation
* @mem: the SPI memory
@@ -318,19 +380,35 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
u8 *tmpbuf;
int ret;
+ /* Make sure the operation frequency is correct before going futher */
+ spi_mem_adjust_op_freq(mem, (struct spi_mem_op *)op);
+
+ dev_vdbg(&mem->spi->dev, "[cmd: 0x%02x][%dB addr: %#8llx][%2dB dummy][%4dB data %s] %d%c-%d%c-%d%c-%d%c @ %uHz\n",
+ op->cmd.opcode,
+ op->addr.nbytes, (op->addr.nbytes ? op->addr.val : 0),
+ op->dummy.nbytes,
+ op->data.nbytes, (op->data.nbytes ? (op->data.dir == SPI_MEM_DATA_IN ? " read" : "write") : " "),
+ op->cmd.buswidth, op->cmd.dtr ? 'D' : 'S',
+ op->addr.buswidth, op->addr.dtr ? 'D' : 'S',
+ op->dummy.buswidth, op->dummy.dtr ? 'D' : 'S',
+ op->data.buswidth, op->data.dtr ? 'D' : 'S',
+ op->max_freq ? op->max_freq : mem->spi->max_speed_hz);
+
ret = spi_mem_check_op(op);
if (ret)
return ret;
if (!spi_mem_internal_supports_op(mem, op))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (ctlr->mem_ops && ctlr->mem_ops->exec_op && !spi_get_csgpiod(mem->spi, 0)) {
ret = spi_mem_access_start(mem);
if (ret)
return ret;
+ trace_spi_mem_start_op(mem, op);
ret = ctlr->mem_ops->exec_op(mem, op);
+ trace_spi_mem_stop_op(mem, op);
spi_mem_access_end(mem);
@@ -339,8 +417,12 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
* read path) and expect the core to use the regular SPI
* interface in other cases.
*/
- if (!ret || ret != -ENOTSUPP)
+ if (!ret || (ret != -ENOTSUPP && ret != -EOPNOTSUPP)) {
+ spi_mem_add_op_stats(ctlr->pcpu_statistics, op, ret);
+ spi_mem_add_op_stats(mem->spi->pcpu_statistics, op, ret);
+
return ret;
+ }
}
tmpbufsize = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
@@ -360,6 +442,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].tx_buf = tmpbuf;
xfers[xferpos].len = op->cmd.nbytes;
xfers[xferpos].tx_nbits = op->cmd.buswidth;
+ xfers[xferpos].speed_hz = op->max_freq;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen++;
@@ -374,6 +457,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].tx_buf = tmpbuf + 1;
xfers[xferpos].len = op->addr.nbytes;
xfers[xferpos].tx_nbits = op->addr.buswidth;
+ xfers[xferpos].speed_hz = op->max_freq;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->addr.nbytes;
@@ -385,6 +469,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].len = op->dummy.nbytes;
xfers[xferpos].tx_nbits = op->dummy.buswidth;
xfers[xferpos].dummy_data = 1;
+ xfers[xferpos].speed_hz = op->max_freq;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->dummy.nbytes;
@@ -400,6 +485,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
}
xfers[xferpos].len = op->data.nbytes;
+ xfers[xferpos].speed_hz = op->max_freq;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->data.nbytes;
@@ -478,6 +564,75 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
}
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
+/**
+ * spi_mem_adjust_op_freq() - Adjust the frequency of a SPI mem operation to
+ * match controller, PCB and chip limitations
+ * @mem: the SPI memory
+ * @op: the operation to adjust
+ *
+ * Some chips have per-op frequency limitations and must adapt the maximum
+ * speed. This function allows SPI mem drivers to set @op->max_freq to the
+ * maximum supported value.
+ */
+void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op)
+{
+ if (!op->max_freq || op->max_freq > mem->spi->max_speed_hz)
+ op->max_freq = mem->spi->max_speed_hz;
+}
+EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq);
+
+/**
+ * spi_mem_calc_op_duration() - Derives the theoretical length (in ns) of an
+ * operation. This helps finding the best variant
+ * among a list of possible choices.
+ * @mem: the SPI memory
+ * @op: the operation to benchmark
+ *
+ * Some chips have per-op frequency limitations, PCBs usually have their own
+ * limitations as well, and controllers can support dual, quad or even octal
+ * modes, sometimes in DTR. All these combinations make it impossible to
+ * statically list the best combination for all situations. If we want something
+ * accurate, all these combinations should be rated (eg. with a time estimate)
+ * and the best pick should be taken based on these calculations.
+ *
+ * Returns a ns estimate for the time this op would take, except if no
+ * frequency limit has been set, in this case we return the number of
+ * cycles nevertheless to allow callers to distinguish which operation
+ * would be the fastest at iso-frequency.
+ */
+u64 spi_mem_calc_op_duration(struct spi_mem *mem, struct spi_mem_op *op)
+{
+ u64 ncycles = 0;
+ u64 ps_per_cycles, duration;
+
+ spi_mem_adjust_op_freq(mem, op);
+
+ if (op->max_freq) {
+ ps_per_cycles = 1000000000000ULL;
+ do_div(ps_per_cycles, op->max_freq);
+ } else {
+ /* In this case, the unit is no longer a time unit */
+ ps_per_cycles = 1;
+ }
+
+ ncycles += ((op->cmd.nbytes * 8) / op->cmd.buswidth) / (op->cmd.dtr ? 2 : 1);
+ ncycles += ((op->addr.nbytes * 8) / op->addr.buswidth) / (op->addr.dtr ? 2 : 1);
+
+ /* Dummy bytes are optional for some SPI flash memory operations */
+ if (op->dummy.nbytes)
+ ncycles += ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1);
+
+ ncycles += ((op->data.nbytes * 8) / op->data.buswidth) / (op->data.dtr ? 2 : 1);
+
+ /* Derive the duration in ps */
+ duration = ncycles * ps_per_cycles;
+ /* Convert into ns */
+ do_div(duration, 1000);
+
+ return duration;
+}
+EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration);
+
static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
@@ -559,7 +714,7 @@ spi_mem_dirmap_create(struct spi_mem *mem,
if (ret) {
desc->nodirmap = true;
if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
- ret = -ENOTSUPP;
+ ret = -EOPNOTSUPP;
else
ret = 0;
}
diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c
index 141562c882f1..6b9137307533 100644
--- a/drivers/spi/spi-meson-spicc.c
+++ b/drivers/spi/spi-meson-spicc.c
@@ -15,25 +15,32 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/reset.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/dma-mapping.h>
/*
- * The Meson SPICC controller could support DMA based transfers, but is not
- * implemented by the vendor code, and while having the registers documentation
- * it has never worked on the GXL Hardware.
- * The PIO mode is the only mode implemented, and due to badly designed HW :
- * - all transfers are cutted in 16 words burst because the FIFO hangs on
- * TX underflow, and there is no TX "Half-Empty" interrupt, so we go by
- * FIFO max size chunk only
- * - CS management is dumb, and goes UP between every burst, so is really a
- * "Data Valid" signal than a Chip Select, GPIO link should be used instead
- * to have a CS go down over the full transfer
+ * There are two modes for data transmission: PIO and DMA.
+ * When bits_per_word is 8, 16, 24, or 32, data is transferred using PIO mode.
+ * When bits_per_word is 64, DMA mode is used by default.
+ *
+ * DMA achieves a transfer with one or more SPI bursts, each SPI burst is made
+ * up of one or more DMA bursts. The DMA burst implementation mechanism is,
+ * For TX, when the number of words in TXFIFO is less than the preset
+ * reading threshold, SPICC starts a reading DMA burst, which reads the preset
+ * number of words from TX buffer, then writes them into TXFIFO.
+ * For RX, when the number of words in RXFIFO is greater than the preset
+ * writing threshold, SPICC starts a writing request burst, which reads the
+ * preset number of words from RXFIFO, then write them into RX buffer.
+ * DMA works if the transfer meets the following conditions,
+ * - 64 bits per word
+ * - The transfer length in word must be multiples of the dma_burst_len, and
+ * the dma_burst_len should be one of 8,7...2, otherwise, it will be split
+ * into several SPI bursts by this driver
*/
#define SPICC_MAX_BURST 128
@@ -129,6 +136,23 @@
#define SPICC_DWADDR 0x24 /* Write Address of DMA */
+#define SPICC_LD_CNTL0 0x28
+#define VSYNC_IRQ_SRC_SELECT BIT(0)
+#define DMA_EN_SET_BY_VSYNC BIT(2)
+#define XCH_EN_SET_BY_VSYNC BIT(3)
+#define DMA_READ_COUNTER_EN BIT(4)
+#define DMA_WRITE_COUNTER_EN BIT(5)
+#define DMA_RADDR_LOAD_BY_VSYNC BIT(6)
+#define DMA_WADDR_LOAD_BY_VSYNC BIT(7)
+#define DMA_ADDR_LOAD_FROM_LD_ADDR BIT(8)
+
+#define SPICC_LD_CNTL1 0x2c
+#define DMA_READ_COUNTER GENMASK(15, 0)
+#define DMA_WRITE_COUNTER GENMASK(31, 16)
+#define DMA_BURST_LEN_DEFAULT 8
+#define DMA_BURST_COUNT_MAX 0xffff
+#define SPI_BURST_LEN_MAX (DMA_BURST_LEN_DEFAULT * DMA_BURST_COUNT_MAX)
+
#define SPICC_ENH_CTL0 0x38 /* Enhanced Feature */
#define SPICC_ENH_CLK_CS_DELAY_MASK GENMASK(15, 0)
#define SPICC_ENH_DATARATE_MASK GENMASK(23, 16)
@@ -152,7 +176,7 @@ struct meson_spicc_data {
};
struct meson_spicc_device {
- struct spi_master *master;
+ struct spi_controller *host;
struct platform_device *pdev;
void __iomem *base;
struct clk *core;
@@ -172,6 +196,9 @@ struct meson_spicc_device {
struct pinctrl *pinctrl;
struct pinctrl_state *pins_idle_high;
struct pinctrl_state *pins_idle_low;
+ dma_addr_t tx_dma;
+ dma_addr_t rx_dma;
+ bool using_dma;
};
#define pow2_clk_to_spicc(_div) container_of(_div, struct meson_spicc_device, pow2_div)
@@ -203,6 +230,148 @@ static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0);
}
+static int meson_spicc_dma_map(struct meson_spicc_device *spicc,
+ struct spi_transfer *t)
+{
+ struct device *dev = spicc->host->dev.parent;
+
+ if (!(t->tx_buf && t->rx_buf))
+ return -EINVAL;
+
+ t->tx_dma = dma_map_single(dev, (void *)t->tx_buf, t->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, t->tx_dma))
+ return -ENOMEM;
+
+ t->rx_dma = dma_map_single(dev, t->rx_buf, t->len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, t->rx_dma))
+ return -ENOMEM;
+
+ spicc->tx_dma = t->tx_dma;
+ spicc->rx_dma = t->rx_dma;
+
+ return 0;
+}
+
+static void meson_spicc_dma_unmap(struct meson_spicc_device *spicc,
+ struct spi_transfer *t)
+{
+ struct device *dev = spicc->host->dev.parent;
+
+ if (t->tx_dma)
+ dma_unmap_single(dev, t->tx_dma, t->len, DMA_TO_DEVICE);
+ if (t->rx_dma)
+ dma_unmap_single(dev, t->rx_dma, t->len, DMA_FROM_DEVICE);
+}
+
+/*
+ * According to the remain words length, calculate a suitable spi burst length
+ * and a dma burst length for current spi burst
+ */
+static u32 meson_spicc_calc_dma_len(struct meson_spicc_device *spicc,
+ u32 len, u32 *dma_burst_len)
+{
+ u32 i;
+
+ if (len <= spicc->data->fifo_size) {
+ *dma_burst_len = len;
+ return len;
+ }
+
+ *dma_burst_len = DMA_BURST_LEN_DEFAULT;
+
+ if (len == (SPI_BURST_LEN_MAX + 1))
+ return SPI_BURST_LEN_MAX - DMA_BURST_LEN_DEFAULT;
+
+ if (len >= SPI_BURST_LEN_MAX)
+ return SPI_BURST_LEN_MAX;
+
+ for (i = DMA_BURST_LEN_DEFAULT; i > 1; i--)
+ if ((len % i) == 0) {
+ *dma_burst_len = i;
+ return len;
+ }
+
+ i = len % DMA_BURST_LEN_DEFAULT;
+ len -= i;
+
+ if (i == 1)
+ len -= DMA_BURST_LEN_DEFAULT;
+
+ return len;
+}
+
+static void meson_spicc_setup_dma(struct meson_spicc_device *spicc)
+{
+ unsigned int len;
+ unsigned int dma_burst_len, dma_burst_count;
+ unsigned int count_en = 0;
+ unsigned int txfifo_thres = 0;
+ unsigned int read_req = 0;
+ unsigned int rxfifo_thres = 31;
+ unsigned int write_req = 0;
+ unsigned int ld_ctr1 = 0;
+
+ writel_relaxed(spicc->tx_dma, spicc->base + SPICC_DRADDR);
+ writel_relaxed(spicc->rx_dma, spicc->base + SPICC_DWADDR);
+
+ /* Set the max burst length to support a transmission with length of
+ * no more than 1024 bytes(128 words), which must use the CS management
+ * because of some strict timing requirements
+ */
+ writel_bits_relaxed(SPICC_BURSTLENGTH_MASK, SPICC_BURSTLENGTH_MASK,
+ spicc->base + SPICC_CONREG);
+
+ len = meson_spicc_calc_dma_len(spicc, spicc->xfer_remain,
+ &dma_burst_len);
+ spicc->xfer_remain -= len;
+ dma_burst_count = DIV_ROUND_UP(len, dma_burst_len);
+ dma_burst_len--;
+
+ if (spicc->tx_dma) {
+ spicc->tx_dma += len;
+ count_en |= DMA_READ_COUNTER_EN;
+ txfifo_thres = spicc->data->fifo_size - dma_burst_len;
+ read_req = dma_burst_len;
+ ld_ctr1 |= FIELD_PREP(DMA_READ_COUNTER, dma_burst_count);
+ }
+
+ if (spicc->rx_dma) {
+ spicc->rx_dma += len;
+ count_en |= DMA_WRITE_COUNTER_EN;
+ rxfifo_thres = dma_burst_len;
+ write_req = dma_burst_len;
+ ld_ctr1 |= FIELD_PREP(DMA_WRITE_COUNTER, dma_burst_count);
+ }
+
+ writel_relaxed(count_en, spicc->base + SPICC_LD_CNTL0);
+ writel_relaxed(ld_ctr1, spicc->base + SPICC_LD_CNTL1);
+ writel_relaxed(SPICC_DMA_ENABLE
+ | SPICC_DMA_URGENT
+ | FIELD_PREP(SPICC_TXFIFO_THRESHOLD_MASK, txfifo_thres)
+ | FIELD_PREP(SPICC_READ_BURST_MASK, read_req)
+ | FIELD_PREP(SPICC_RXFIFO_THRESHOLD_MASK, rxfifo_thres)
+ | FIELD_PREP(SPICC_WRITE_BURST_MASK, write_req),
+ spicc->base + SPICC_DMAREG);
+}
+
+static irqreturn_t meson_spicc_dma_irq(struct meson_spicc_device *spicc)
+{
+ if (readl_relaxed(spicc->base + SPICC_DMAREG) & SPICC_DMA_ENABLE)
+ return IRQ_HANDLED;
+
+ if (spicc->xfer_remain) {
+ meson_spicc_setup_dma(spicc);
+ } else {
+ writel_bits_relaxed(SPICC_SMC, 0, spicc->base + SPICC_CONREG);
+ writel_relaxed(0, spicc->base + SPICC_INTREG);
+ writel_relaxed(0, spicc->base + SPICC_DMAREG);
+ meson_spicc_dma_unmap(spicc, spicc->xfer);
+ complete(&spicc->done);
+ }
+
+ return IRQ_HANDLED;
+}
+
static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc)
{
return !!FIELD_GET(SPICC_TF,
@@ -294,6 +463,9 @@ static irqreturn_t meson_spicc_irq(int irq, void *data)
writel_bits_relaxed(SPICC_TC, SPICC_TC, spicc->base + SPICC_STATREG);
+ if (spicc->using_dma)
+ return meson_spicc_dma_irq(spicc);
+
/* Empty RX FIFO */
meson_spicc_rx(spicc);
@@ -400,11 +572,11 @@ static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc)
spicc->base + SPICC_ENH_CTL0);
}
-static int meson_spicc_transfer_one(struct spi_master *master,
+static int meson_spicc_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct meson_spicc_device *spicc = spi_master_get_devdata(master);
+ struct meson_spicc_device *spicc = spi_controller_get_devdata(host);
uint64_t timeout;
/* Store current transfer */
@@ -427,9 +599,6 @@ static int meson_spicc_transfer_one(struct spi_master *master,
meson_spicc_reset_fifo(spicc);
- /* Setup burst */
- meson_spicc_setup_burst(spicc);
-
/* Setup wait for completion */
reinit_completion(&spicc->done);
@@ -443,11 +612,36 @@ static int meson_spicc_transfer_one(struct spi_master *master,
/* Increase it twice and add 200 ms tolerance */
timeout += timeout + 200;
- /* Start burst */
- writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG);
+ if (xfer->bits_per_word == 64) {
+ int ret;
+
+ /* dma_burst_len 1 can't trigger a dma burst */
+ if (xfer->len < 16)
+ return -EINVAL;
+
+ ret = meson_spicc_dma_map(spicc, xfer);
+ if (ret) {
+ meson_spicc_dma_unmap(spicc, xfer);
+ dev_err(host->dev.parent, "dma map failed\n");
+ return ret;
+ }
+
+ spicc->using_dma = true;
+ spicc->xfer_remain = DIV_ROUND_UP(xfer->len, spicc->bytes_per_word);
+ meson_spicc_setup_dma(spicc);
+ writel_relaxed(SPICC_TE_EN, spicc->base + SPICC_INTREG);
+ writel_bits_relaxed(SPICC_SMC, SPICC_SMC, spicc->base + SPICC_CONREG);
+ } else {
+ spicc->using_dma = false;
+ /* Setup burst */
+ meson_spicc_setup_burst(spicc);
- /* Enable interrupts */
- writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG);
+ /* Start burst */
+ writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG);
+
+ /* Enable interrupts */
+ writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG);
+ }
if (!wait_for_completion_timeout(&spicc->done, msecs_to_jiffies(timeout)))
return -ETIMEDOUT;
@@ -455,10 +649,10 @@ static int meson_spicc_transfer_one(struct spi_master *master,
return 0;
}
-static int meson_spicc_prepare_message(struct spi_master *master,
+static int meson_spicc_prepare_message(struct spi_controller *host,
struct spi_message *message)
{
- struct meson_spicc_device *spicc = spi_master_get_devdata(master);
+ struct meson_spicc_device *spicc = spi_controller_get_devdata(host);
struct spi_device *spi = message->spi;
u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK;
@@ -515,14 +709,16 @@ static int meson_spicc_prepare_message(struct spi_master *master,
/* Setup no wait cycles by default */
writel_relaxed(0, spicc->base + SPICC_PERIODREG);
- writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG);
+ writel_bits_relaxed(SPICC_LBC_W1,
+ spi->mode & SPI_LOOP ? SPICC_LBC_W1 : 0,
+ spicc->base + SPICC_TESTREG);
return 0;
}
-static int meson_spicc_unprepare_transfer(struct spi_master *master)
+static int meson_spicc_unprepare_transfer(struct spi_controller *host)
{
- struct meson_spicc_device *spicc = spi_master_get_devdata(master);
+ struct meson_spicc_device *spicc = spi_controller_get_devdata(host);
u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK;
/* Disable all IRQs */
@@ -542,7 +738,15 @@ static int meson_spicc_unprepare_transfer(struct spi_master *master)
static int meson_spicc_setup(struct spi_device *spi)
{
if (!spi->controller_state)
- spi->controller_state = spi_master_get_devdata(spi->master);
+ spi->controller_state = spi_controller_get_devdata(spi->controller);
+
+ /* DMA works at 64 bits, the rest works on PIO */
+ if (spi->bits_per_word != 8 &&
+ spi->bits_per_word != 16 &&
+ spi->bits_per_word != 24 &&
+ spi->bits_per_word != 32 &&
+ spi->bits_per_word != 64)
+ return -EINVAL;
return 0;
}
@@ -586,7 +790,7 @@ static unsigned long meson_spicc_pow2_recalc_rate(struct clk_hw *hw,
struct clk_divider *divider = to_clk_divider(hw);
struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);
- if (!spicc->master->cur_msg)
+ if (!spicc->host->cur_msg)
return 0;
return clk_divider_ops.recalc_rate(hw, parent_rate);
@@ -598,7 +802,7 @@ static int meson_spicc_pow2_determine_rate(struct clk_hw *hw,
struct clk_divider *divider = to_clk_divider(hw);
struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);
- if (!spicc->master->cur_msg)
+ if (!spicc->host->cur_msg)
return -EINVAL;
return clk_divider_ops.determine_rate(hw, req);
@@ -610,7 +814,7 @@ static int meson_spicc_pow2_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_divider *divider = to_clk_divider(hw);
struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);
- if (!spicc->master->cur_msg)
+ if (!spicc->host->cur_msg)
return -EINVAL;
return clk_divider_ops.set_rate(hw, rate, parent_rate);
@@ -645,15 +849,17 @@ static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc)
snprintf(name, sizeof(name), "%s#pow2_fixed_div", dev_name(dev));
init.name = name;
init.ops = &clk_fixed_factor_ops;
- init.flags = 0;
- if (spicc->data->has_pclk)
+ if (spicc->data->has_pclk) {
+ init.flags = CLK_SET_RATE_PARENT;
parent_data[0].hw = __clk_get_hw(spicc->pclk);
- else
+ } else {
+ init.flags = 0;
parent_data[0].hw = __clk_get_hw(spicc->core);
+ }
init.num_parents = 1;
- pow2_fixed_div->mult = 1,
- pow2_fixed_div->div = 4,
+ pow2_fixed_div->mult = 1;
+ pow2_fixed_div->div = 4;
pow2_fixed_div->hw.init = &init;
clk = devm_clk_register(dev, &pow2_fixed_div->hw);
@@ -671,9 +877,9 @@ static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc)
parent_data[0].hw = &pow2_fixed_div->hw;
init.num_parents = 1;
- spicc->pow2_div.shift = 16,
- spicc->pow2_div.width = 3,
- spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO,
+ spicc->pow2_div.shift = 16;
+ spicc->pow2_div.width = 3;
+ spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO;
spicc->pow2_div.reg = spicc->base + SPICC_CONREG;
spicc->pow2_div.hw.init = &init;
@@ -709,15 +915,17 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc)
snprintf(name, sizeof(name), "%s#enh_fixed_div", dev_name(dev));
init.name = name;
init.ops = &clk_fixed_factor_ops;
- init.flags = 0;
- if (spicc->data->has_pclk)
+ if (spicc->data->has_pclk) {
+ init.flags = CLK_SET_RATE_PARENT;
parent_data[0].hw = __clk_get_hw(spicc->pclk);
- else
+ } else {
+ init.flags = 0;
parent_data[0].hw = __clk_get_hw(spicc->core);
+ }
init.num_parents = 1;
- enh_fixed_div->mult = 1,
- enh_fixed_div->div = 2,
+ enh_fixed_div->mult = 1;
+ enh_fixed_div->div = 2;
enh_fixed_div->hw.init = &init;
clk = devm_clk_register(dev, &enh_fixed_div->hw);
@@ -735,8 +943,8 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc)
parent_data[0].hw = &enh_fixed_div->hw;
init.num_parents = 1;
- enh_div->shift = 16,
- enh_div->width = 8,
+ enh_div->shift = 16;
+ enh_div->width = 8;
enh_div->reg = spicc->base + SPICC_ENH_CTL0;
enh_div->hw.init = &init;
@@ -756,8 +964,8 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc)
init.num_parents = 2;
init.flags = CLK_SET_RATE_PARENT;
- mux->mask = 0x1,
- mux->shift = 24,
+ mux->mask = 0x1;
+ mux->shift = 24;
mux->reg = spicc->base + SPICC_ENH_CTL0;
mux->hw.init = &init;
@@ -770,23 +978,23 @@ static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc)
static int meson_spicc_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct meson_spicc_device *spicc;
int ret, irq;
- master = spi_alloc_master(&pdev->dev, sizeof(*spicc));
- if (!master) {
- dev_err(&pdev->dev, "master allocation failed\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(*spicc));
+ if (!host) {
+ dev_err(&pdev->dev, "host allocation failed\n");
return -ENOMEM;
}
- spicc = spi_master_get_devdata(master);
- spicc->master = master;
+ spicc = spi_controller_get_devdata(host);
+ spicc->host = host;
spicc->data = of_device_get_match_data(&pdev->dev);
if (!spicc->data) {
dev_err(&pdev->dev, "failed to get match data\n");
ret = -EINVAL;
- goto out_master;
+ goto out_host;
}
spicc->pdev = pdev;
@@ -798,7 +1006,7 @@ static int meson_spicc_probe(struct platform_device *pdev)
if (IS_ERR(spicc->base)) {
dev_err(&pdev->dev, "io resource mapping failed\n");
ret = PTR_ERR(spicc->base);
- goto out_master;
+ goto out_host;
}
/* Set master mode and enable controller */
@@ -811,101 +1019,79 @@ static int meson_spicc_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto out_master;
+ goto out_host;
}
ret = devm_request_irq(&pdev->dev, irq, meson_spicc_irq,
0, NULL, spicc);
if (ret) {
dev_err(&pdev->dev, "irq request failed\n");
- goto out_master;
+ goto out_host;
}
- spicc->core = devm_clk_get(&pdev->dev, "core");
+ spicc->core = devm_clk_get_enabled(&pdev->dev, "core");
if (IS_ERR(spicc->core)) {
dev_err(&pdev->dev, "core clock request failed\n");
ret = PTR_ERR(spicc->core);
- goto out_master;
+ goto out_host;
}
if (spicc->data->has_pclk) {
- spicc->pclk = devm_clk_get(&pdev->dev, "pclk");
+ spicc->pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
if (IS_ERR(spicc->pclk)) {
dev_err(&pdev->dev, "pclk clock request failed\n");
ret = PTR_ERR(spicc->pclk);
- goto out_master;
+ goto out_host;
}
}
- ret = clk_prepare_enable(spicc->core);
- if (ret) {
- dev_err(&pdev->dev, "core clock enable failed\n");
- goto out_master;
- }
-
- ret = clk_prepare_enable(spicc->pclk);
- if (ret) {
- dev_err(&pdev->dev, "pclk clock enable failed\n");
- goto out_core_clk;
- }
-
spicc->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(spicc->pinctrl)) {
ret = PTR_ERR(spicc->pinctrl);
- goto out_clk;
+ goto out_host;
}
device_reset_optional(&pdev->dev);
- master->num_chipselect = 4;
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_MASK(32) |
- SPI_BPW_MASK(24) |
- SPI_BPW_MASK(16) |
- SPI_BPW_MASK(8);
- master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
- master->min_speed_hz = spicc->data->min_speed_hz;
- master->max_speed_hz = spicc->data->max_speed_hz;
- master->setup = meson_spicc_setup;
- master->cleanup = meson_spicc_cleanup;
- master->prepare_message = meson_spicc_prepare_message;
- master->unprepare_transfer_hardware = meson_spicc_unprepare_transfer;
- master->transfer_one = meson_spicc_transfer_one;
- master->use_gpio_descriptors = true;
+ host->num_chipselect = 4;
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LOOP;
+ host->flags = (SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX);
+ host->min_speed_hz = spicc->data->min_speed_hz;
+ host->max_speed_hz = spicc->data->max_speed_hz;
+ host->setup = meson_spicc_setup;
+ host->cleanup = meson_spicc_cleanup;
+ host->prepare_message = meson_spicc_prepare_message;
+ host->unprepare_transfer_hardware = meson_spicc_unprepare_transfer;
+ host->transfer_one = meson_spicc_transfer_one;
+ host->use_gpio_descriptors = true;
meson_spicc_oen_enable(spicc);
ret = meson_spicc_pow2_clk_init(spicc);
if (ret) {
dev_err(&pdev->dev, "pow2 clock registration failed\n");
- goto out_clk;
+ goto out_host;
}
if (spicc->data->has_enhance_clk_div) {
ret = meson_spicc_enh_clk_init(spicc);
if (ret) {
dev_err(&pdev->dev, "clock registration failed\n");
- goto out_clk;
+ goto out_host;
}
}
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&pdev->dev, "spi master registration failed\n");
- goto out_clk;
+ dev_err(&pdev->dev, "spi registration failed\n");
+ goto out_host;
}
return 0;
-out_clk:
- clk_disable_unprepare(spicc->pclk);
-
-out_core_clk:
- clk_disable_unprepare(spicc->core);
-
-out_master:
- spi_master_put(master);
+out_host:
+ spi_controller_put(host);
return ret;
}
@@ -917,10 +1103,7 @@ static void meson_spicc_remove(struct platform_device *pdev)
/* Disable SPI */
writel(0, spicc->base + SPICC_CONREG);
- clk_disable_unprepare(spicc->core);
- clk_disable_unprepare(spicc->pclk);
-
- spi_master_put(spicc->master);
+ spi_controller_put(spicc->host);
}
static const struct meson_spicc_data meson_spicc_gx_data = {
@@ -965,7 +1148,7 @@ MODULE_DEVICE_TABLE(of, meson_spicc_of_match);
static struct platform_driver meson_spicc_driver = {
.probe = meson_spicc_probe,
- .remove_new = meson_spicc_remove,
+ .remove = meson_spicc_remove,
.driver = {
.name = "meson-spicc",
.of_match_table = of_match_ptr(meson_spicc_of_match),
diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c
index 06626f406f68..ef7efeaeee97 100644
--- a/drivers/spi/spi-meson-spifc.c
+++ b/drivers/spi/spi-meson-spifc.c
@@ -67,13 +67,13 @@
/**
* struct meson_spifc
- * @master: the SPI master
+ * @host: the SPI host
* @regmap: regmap for device registers
* @clk: input clock of the built-in baud rate generator
* @dev: the device structure
*/
struct meson_spifc {
- struct spi_master *master;
+ struct spi_controller *host;
struct regmap *regmap;
struct clk *clk;
struct device *dev;
@@ -237,16 +237,16 @@ static int meson_spifc_txrx(struct meson_spifc *spifc,
/**
* meson_spifc_transfer_one() - perform a single transfer
- * @master: the SPI master
+ * @host: the SPI host
* @spi: the SPI device
* @xfer: the current SPI transfer
* Return: 0 on success, a negative value on error
*/
-static int meson_spifc_transfer_one(struct spi_master *master,
+static int meson_spifc_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct meson_spifc *spifc = spi_master_get_devdata(master);
+ struct meson_spifc *spifc = spi_controller_get_devdata(host);
int len, done = 0, ret = 0;
meson_spifc_setup_speed(spifc, xfer->speed_hz);
@@ -256,7 +256,7 @@ static int meson_spifc_transfer_one(struct spi_master *master,
while (done < xfer->len && !ret) {
len = min_t(int, xfer->len - done, SPIFC_BUFFER_SIZE);
ret = meson_spifc_txrx(spifc, xfer, done, len,
- spi_transfer_is_last(master, xfer),
+ spi_transfer_is_last(host, xfer),
done + len >= xfer->len);
done += len;
}
@@ -284,19 +284,19 @@ static void meson_spifc_hw_init(struct meson_spifc *spifc)
static int meson_spifc_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct meson_spifc *spifc;
void __iomem *base;
unsigned int rate;
int ret = 0;
- master = spi_alloc_master(&pdev->dev, sizeof(struct meson_spifc));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(struct meson_spifc));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- spifc = spi_master_get_devdata(master);
+ spifc = spi_controller_get_devdata(host);
spifc->dev = &pdev->dev;
base = devm_platform_ioremap_resource(pdev, 0);
@@ -312,67 +312,56 @@ static int meson_spifc_probe(struct platform_device *pdev)
goto out_err;
}
- spifc->clk = devm_clk_get(spifc->dev, NULL);
+ spifc->clk = devm_clk_get_enabled(spifc->dev, NULL);
if (IS_ERR(spifc->clk)) {
dev_err(spifc->dev, "missing clock\n");
ret = PTR_ERR(spifc->clk);
goto out_err;
}
- ret = clk_prepare_enable(spifc->clk);
- if (ret) {
- dev_err(spifc->dev, "can't prepare clock\n");
- goto out_err;
- }
-
rate = clk_get_rate(spifc->clk);
- master->num_chipselect = 1;
- master->dev.of_node = pdev->dev.of_node;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->auto_runtime_pm = true;
- master->transfer_one = meson_spifc_transfer_one;
- master->min_speed_hz = rate >> 6;
- master->max_speed_hz = rate >> 1;
+ host->num_chipselect = 1;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->auto_runtime_pm = true;
+ host->transfer_one = meson_spifc_transfer_one;
+ host->min_speed_hz = rate >> 6;
+ host->max_speed_hz = rate >> 1;
meson_spifc_hw_init(spifc);
pm_runtime_set_active(spifc->dev);
pm_runtime_enable(spifc->dev);
- ret = devm_spi_register_master(spifc->dev, master);
+ ret = devm_spi_register_controller(spifc->dev, host);
if (ret) {
- dev_err(spifc->dev, "failed to register spi master\n");
- goto out_clk;
+ dev_err(spifc->dev, "failed to register spi host\n");
+ goto out_pm;
}
return 0;
-out_clk:
- clk_disable_unprepare(spifc->clk);
+out_pm:
pm_runtime_disable(spifc->dev);
out_err:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static void meson_spifc_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct meson_spifc *spifc = spi_master_get_devdata(master);
-
pm_runtime_get_sync(&pdev->dev);
- clk_disable_unprepare(spifc->clk);
pm_runtime_disable(&pdev->dev);
}
#ifdef CONFIG_PM_SLEEP
static int meson_spifc_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct meson_spifc *spifc = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct meson_spifc *spifc = spi_controller_get_devdata(host);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -384,8 +373,8 @@ static int meson_spifc_suspend(struct device *dev)
static int meson_spifc_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct meson_spifc *spifc = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct meson_spifc *spifc = spi_controller_get_devdata(host);
int ret;
if (!pm_runtime_suspended(dev)) {
@@ -396,7 +385,7 @@ static int meson_spifc_resume(struct device *dev)
meson_spifc_hw_init(spifc);
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret)
clk_disable_unprepare(spifc->clk);
@@ -407,8 +396,8 @@ static int meson_spifc_resume(struct device *dev)
#ifdef CONFIG_PM
static int meson_spifc_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct meson_spifc *spifc = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct meson_spifc *spifc = spi_controller_get_devdata(host);
clk_disable_unprepare(spifc->clk);
@@ -417,8 +406,8 @@ static int meson_spifc_runtime_suspend(struct device *dev)
static int meson_spifc_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct meson_spifc *spifc = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct meson_spifc *spifc = spi_controller_get_devdata(host);
return clk_prepare_enable(spifc->clk);
}
@@ -440,7 +429,7 @@ MODULE_DEVICE_TABLE(of, meson_spifc_dt_match);
static struct platform_driver meson_spifc_driver = {
.probe = meson_spifc_probe,
- .remove_new = meson_spifc_remove,
+ .remove = meson_spifc_remove,
.driver = {
.name = "meson-spifc",
.of_match_table = of_match_ptr(meson_spifc_dt_match),
diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c
index 4f76ddf97b10..aafe6cbf2aea 100644
--- a/drivers/spi/spi-microchip-core-qspi.c
+++ b/drivers/spi/spi-microchip-core-qspi.c
@@ -194,7 +194,7 @@ static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi)
}
}
-static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word)
+static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi)
{
u32 control, data;
@@ -222,6 +222,87 @@ static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word)
}
}
+static inline void mchp_coreqspi_write_read_op(struct mchp_coreqspi *qspi)
+{
+ u32 control, data;
+
+ qspi->rx_len = qspi->tx_len;
+
+ control = readl_relaxed(qspi->regs + REG_CONTROL);
+ control |= CONTROL_FLAGSX4;
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ while (qspi->tx_len >= 4) {
+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL)
+ ;
+
+ data = qspi->txbuf ? *((u32 *)qspi->txbuf) : 0xaa;
+ if (qspi->txbuf)
+ qspi->txbuf += 4;
+ qspi->tx_len -= 4;
+ writel_relaxed(data, qspi->regs + REG_X4_TX_DATA);
+
+ /*
+ * The rx FIFO is twice the size of the tx FIFO, so there is
+ * no requirement to block transmission if receive data is not
+ * ready, and it is fine to let the tx FIFO completely fill
+ * without reading anything from the rx FIFO. Once the tx FIFO
+ * has been filled and becomes non-full due to a transmission
+ * occurring there will always be something to receive.
+ * IOW, this is safe as TX_FIFO_SIZE + 4 < 2 * TX_FIFO_SIZE
+ */
+ if (qspi->rx_len >= 4) {
+ if (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXAVAILABLE) {
+ data = readl_relaxed(qspi->regs + REG_X4_RX_DATA);
+ *(u32 *)qspi->rxbuf = data;
+ qspi->rxbuf += 4;
+ qspi->rx_len -= 4;
+ }
+ }
+ }
+
+ /*
+ * Since transmission is not being blocked by clearing the rx FIFO,
+ * loop here until all received data "leaked" by the loop above has
+ * been dealt with.
+ */
+ while (qspi->rx_len >= 4) {
+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY)
+ ;
+ data = readl_relaxed(qspi->regs + REG_X4_RX_DATA);
+ *(u32 *)qspi->rxbuf = data;
+ qspi->rxbuf += 4;
+ qspi->rx_len -= 4;
+ }
+
+ /*
+ * Since rx_len and tx_len must be < 4 bytes at this point, there's no
+ * concern about overflowing the rx or tx FIFOs any longer. It's
+ * therefore safe to loop over the remainder of the transmit data before
+ * handling the remaining receive data.
+ */
+ if (!qspi->tx_len)
+ return;
+
+ control &= ~CONTROL_FLAGSX4;
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ while (qspi->tx_len--) {
+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL)
+ ;
+ data = qspi->txbuf ? *qspi->txbuf : 0xaa;
+ qspi->txbuf++;
+ writel_relaxed(data, qspi->regs + REG_TX_DATA);
+ }
+
+ while (qspi->rx_len--) {
+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY)
+ ;
+ data = readl_relaxed(qspi->regs + REG_RX_DATA);
+ *qspi->rxbuf++ = (data & 0xFF);
+ }
+}
+
static void mchp_coreqspi_enable_ints(struct mchp_coreqspi *qspi)
{
u32 mask = IEN_TXDONE |
@@ -265,7 +346,8 @@ static irqreturn_t mchp_coreqspi_isr(int irq, void *dev_id)
return ret;
}
-static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi)
+static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi,
+ u32 max_freq)
{
unsigned long clk_hz;
u32 control, baud_rate_val = 0;
@@ -274,15 +356,16 @@ static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_devi
if (!clk_hz)
return -EINVAL;
- baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * spi->max_speed_hz);
+ baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * max_freq);
if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER) {
dev_err(&spi->dev,
"could not configure the clock for spi clock %d Hz & system clock %ld Hz\n",
- spi->max_speed_hz, clk_hz);
+ max_freq, clk_hz);
return -EINVAL;
}
control = readl_relaxed(qspi->regs + REG_CONTROL);
+ control &= ~CONTROL_CLKRATE_MASK;
control |= baud_rate_val << CONTROL_CLKRATE_SHIFT;
writel_relaxed(control, qspi->regs + REG_CONTROL);
control = readl_relaxed(qspi->regs + REG_CONTROL);
@@ -299,7 +382,7 @@ static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_devi
static int mchp_coreqspi_setup_op(struct spi_device *spi_dev)
{
- struct spi_controller *ctlr = spi_dev->master;
+ struct spi_controller *ctlr = spi_dev->controller;
struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
u32 control = readl_relaxed(qspi->regs + REG_CONTROL);
@@ -365,40 +448,32 @@ static inline void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, const str
writel_relaxed(frames, qspi->regs + REG_FRAMES);
}
-static int mchp_qspi_wait_for_ready(struct spi_mem *mem)
+static int mchp_coreqspi_wait_for_ready(struct mchp_coreqspi *qspi)
{
- struct mchp_coreqspi *qspi = spi_controller_get_devdata
- (mem->spi->master);
u32 status;
- int ret;
- ret = readl_poll_timeout(qspi->regs + REG_STATUS, status,
+ return readl_poll_timeout(qspi->regs + REG_STATUS, status,
(status & STATUS_READY), 0,
TIMEOUT_MS);
- if (ret) {
- dev_err(&mem->spi->dev,
- "Timeout waiting on QSPI ready.\n");
- return -ETIMEDOUT;
- }
-
- return ret;
}
static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata
- (mem->spi->master);
+ (mem->spi->controller);
u32 address = op->addr.val;
u8 opcode = op->cmd.opcode;
u8 opaddr[5];
int err, i;
mutex_lock(&qspi->op_lock);
- err = mchp_qspi_wait_for_ready(mem);
- if (err)
+ err = mchp_coreqspi_wait_for_ready(qspi);
+ if (err) {
+ dev_err(&mem->spi->dev, "Timeout waiting on QSPI ready.\n");
goto error;
+ }
- err = mchp_coreqspi_setup_clock(qspi, mem->spi);
+ err = mchp_coreqspi_setup_clock(qspi, mem->spi, op->max_freq);
if (err)
goto error;
@@ -413,7 +488,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
qspi->rxbuf = NULL;
qspi->tx_len = op->cmd.nbytes;
qspi->rx_len = 0;
- mchp_coreqspi_write_op(qspi, false);
+ mchp_coreqspi_write_op(qspi);
}
qspi->txbuf = &opaddr[0];
@@ -424,7 +499,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
qspi->rxbuf = NULL;
qspi->tx_len = op->addr.nbytes;
qspi->rx_len = 0;
- mchp_coreqspi_write_op(qspi, false);
+ mchp_coreqspi_write_op(qspi);
}
if (op->data.nbytes) {
@@ -433,7 +508,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
qspi->rxbuf = NULL;
qspi->rx_len = 0;
qspi->tx_len = op->data.nbytes;
- mchp_coreqspi_write_op(qspi, true);
+ mchp_coreqspi_write_op(qspi);
} else {
qspi->txbuf = NULL;
qspi->rxbuf = (u8 *)op->data.buf.in;
@@ -497,6 +572,113 @@ static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = {
.exec_op = mchp_coreqspi_exec_op,
};
+static const struct spi_controller_mem_caps mchp_coreqspi_mem_caps = {
+ .per_op_freq = true,
+};
+
+static int mchp_coreqspi_unprepare_message(struct spi_controller *ctlr, struct spi_message *m)
+{
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
+
+ /*
+ * This delay is required for the driver to function correctly,
+ * but no explanation has been determined for why it is required.
+ */
+ udelay(750);
+
+ mutex_unlock(&qspi->op_lock);
+
+ return 0;
+}
+
+static int mchp_coreqspi_prepare_message(struct spi_controller *ctlr, struct spi_message *m)
+{
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
+ struct spi_transfer *t = NULL;
+ u32 control, frames;
+ u32 total_bytes = 0, cmd_bytes = 0, idle_cycles = 0;
+ int ret;
+ bool quad = false, dual = false;
+
+ mutex_lock(&qspi->op_lock);
+ ret = mchp_coreqspi_wait_for_ready(qspi);
+ if (ret) {
+ mutex_unlock(&qspi->op_lock);
+ dev_err(&ctlr->dev, "Timeout waiting on QSPI ready.\n");
+ return ret;
+ }
+
+ ret = mchp_coreqspi_setup_clock(qspi, m->spi, m->spi->max_speed_hz);
+ if (ret) {
+ mutex_unlock(&qspi->op_lock);
+ return ret;
+ }
+
+ control = readl_relaxed(qspi->regs + REG_CONTROL);
+ control &= ~(CONTROL_MODE12_MASK | CONTROL_MODE0);
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ reinit_completion(&qspi->data_completion);
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ total_bytes += t->len;
+ if (!cmd_bytes && !(t->tx_buf && t->rx_buf))
+ cmd_bytes = t->len;
+ if (!t->rx_buf)
+ cmd_bytes = total_bytes;
+ if (t->tx_nbits == SPI_NBITS_QUAD || t->rx_nbits == SPI_NBITS_QUAD)
+ quad = true;
+ else if (t->tx_nbits == SPI_NBITS_DUAL || t->rx_nbits == SPI_NBITS_DUAL)
+ dual = true;
+ }
+
+ control = readl_relaxed(qspi->regs + REG_CONTROL);
+ if (quad) {
+ control |= (CONTROL_MODE0 | CONTROL_MODE12_EX_RW);
+ } else if (dual) {
+ control &= ~CONTROL_MODE0;
+ control |= CONTROL_MODE12_FULL;
+ } else {
+ control &= ~(CONTROL_MODE12_MASK | CONTROL_MODE0);
+ }
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ frames = total_bytes & BYTESUPPER_MASK;
+ writel_relaxed(frames, qspi->regs + REG_FRAMESUP);
+ frames = total_bytes & BYTESLOWER_MASK;
+ frames |= cmd_bytes << FRAMES_CMDBYTES_SHIFT;
+ frames |= idle_cycles << FRAMES_IDLE_SHIFT;
+ control = readl_relaxed(qspi->regs + REG_CONTROL);
+ if (control & CONTROL_MODE12_MASK)
+ frames |= (1 << FRAMES_SHIFT);
+
+ frames |= FRAMES_FLAGWORD;
+ writel_relaxed(frames, qspi->regs + REG_FRAMES);
+
+ return 0;
+};
+
+static int mchp_coreqspi_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
+
+ qspi->tx_len = t->len;
+
+ if (t->tx_buf)
+ qspi->txbuf = (u8 *)t->tx_buf;
+
+ if (!t->rx_buf) {
+ mchp_coreqspi_write_op(qspi);
+ } else {
+ qspi->rxbuf = (u8 *)t->rx_buf;
+ qspi->rx_len = t->len;
+ mchp_coreqspi_write_read_op(qspi);
+ }
+
+ return 0;
+}
+
static int mchp_coreqspi_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
@@ -505,10 +687,9 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
int ret;
- ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*qspi));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*qspi));
if (!ctlr)
- return dev_err_probe(&pdev->dev, -ENOMEM,
- "unable to allocate master for QSPI controller\n");
+ return -ENOMEM;
qspi = spi_controller_get_devdata(ctlr);
platform_set_drvdata(pdev, qspi);
@@ -518,52 +699,45 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(qspi->regs),
"failed to map registers\n");
- qspi->clk = devm_clk_get(&pdev->dev, NULL);
+ qspi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(qspi->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(qspi->clk),
"could not get clock\n");
- ret = clk_prepare_enable(qspi->clk);
- if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "failed to enable clock\n");
-
init_completion(&qspi->data_completion);
mutex_init(&qspi->op_lock);
qspi->irq = platform_get_irq(pdev, 0);
- if (qspi->irq < 0) {
- ret = qspi->irq;
- goto out;
- }
+ if (qspi->irq < 0)
+ return qspi->irq;
ret = devm_request_irq(&pdev->dev, qspi->irq, mchp_coreqspi_isr,
IRQF_SHARED, pdev->name, qspi);
if (ret) {
dev_err(&pdev->dev, "request_irq failed %d\n", ret);
- goto out;
+ return ret;
}
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->mem_ops = &mchp_coreqspi_mem_ops;
+ ctlr->mem_caps = &mchp_coreqspi_mem_caps;
ctlr->setup = mchp_coreqspi_setup_op;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_TX_DUAL | SPI_TX_QUAD;
ctlr->dev.of_node = np;
+ ctlr->min_speed_hz = clk_get_rate(qspi->clk) / 30;
+ ctlr->prepare_message = mchp_coreqspi_prepare_message;
+ ctlr->unprepare_message = mchp_coreqspi_unprepare_message;
+ ctlr->transfer_one = mchp_coreqspi_transfer_one;
+ ctlr->num_chipselect = 2;
+ ctlr->use_gpio_descriptors = true;
ret = devm_spi_register_controller(&pdev->dev, ctlr);
- if (ret) {
- dev_err_probe(&pdev->dev, ret,
- "spi_register_controller failed\n");
- goto out;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "spi_register_controller failed\n");
return 0;
-
-out:
- clk_disable_unprepare(qspi->clk);
-
- return ret;
}
static void mchp_coreqspi_remove(struct platform_device *pdev)
@@ -574,7 +748,6 @@ static void mchp_coreqspi_remove(struct platform_device *pdev)
mchp_coreqspi_disable_ints(qspi);
control &= ~CONTROL_ENABLE;
writel_relaxed(control, qspi->regs + REG_CONTROL);
- clk_disable_unprepare(qspi->clk);
}
static const struct of_device_id mchp_coreqspi_of_match[] = {
@@ -589,7 +762,7 @@ static struct platform_driver mchp_coreqspi_driver = {
.name = "microchip,coreqspi",
.of_match_table = mchp_coreqspi_of_match,
},
- .remove_new = mchp_coreqspi_remove,
+ .remove = mchp_coreqspi_remove,
};
module_platform_driver(mchp_coreqspi_driver);
diff --git a/drivers/spi/spi-microchip-core-spi.c b/drivers/spi/spi-microchip-core-spi.c
new file mode 100644
index 000000000000..98bf0e6cd00e
--- /dev/null
+++ b/drivers/spi/spi-microchip-core-spi.c
@@ -0,0 +1,429 @@
+// SPDX-License-Identifier: (GPL-2.0)
+//
+// Microchip CoreSPI controller driver
+//
+// Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries
+//
+// Author: Prajna Rajendra Kumar <prajna.rajendrakumar@microchip.com>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#define MCHP_CORESPI_MAX_CS (8)
+#define MCHP_CORESPI_DEFAULT_FIFO_DEPTH (4)
+#define MCHP_CORESPI_DEFAULT_MOTOROLA_MODE (3)
+
+#define MCHP_CORESPI_CONTROL_ENABLE BIT(0)
+#define MCHP_CORESPI_CONTROL_MASTER BIT(1)
+#define MCHP_CORESPI_CONTROL_TX_DATA_INT BIT(3)
+#define MCHP_CORESPI_CONTROL_RX_OVER_INT BIT(4)
+#define MCHP_CORESPI_CONTROL_TX_UNDER_INT BIT(5)
+#define MCHP_CORESPI_CONTROL_FRAMEURUN BIT(6)
+#define MCHP_CORESPI_CONTROL_OENOFF BIT(7)
+
+#define MCHP_CORESPI_STATUS_ACTIVE BIT(7)
+#define MCHP_CORESPI_STATUS_SSEL BIT(6)
+#define MCHP_CORESPI_STATUS_TXFIFO_UNDERFLOW BIT(5)
+#define MCHP_CORESPI_STATUS_RXFIFO_FULL BIT(4)
+#define MCHP_CORESPI_STATUS_TXFIFO_FULL BIT(3)
+#define MCHP_CORESPI_STATUS_RXFIFO_EMPTY BIT(2)
+#define MCHP_CORESPI_STATUS_DONE BIT(1)
+#define MCHP_CORESPI_STATUS_FIRSTFRAME BIT(0)
+
+#define MCHP_CORESPI_INT_TXDONE BIT(0)
+#define MCHP_CORESPI_INT_RX_CHANNEL_OVERFLOW BIT(2)
+#define MCHP_CORESPI_INT_TX_CHANNEL_UNDERRUN BIT(3)
+#define MCHP_CORESPI_INT_CMDINT BIT(4)
+#define MCHP_CORESPI_INT_SSEND BIT(5)
+#define MCHP_CORESPI_INT_DATA_RX BIT(6)
+#define MCHP_CORESPI_INT_TXRFM BIT(7)
+
+#define MCHP_CORESPI_CONTROL2_INTEN_TXRFMT BIT(7)
+#define MCHP_CORESPI_CONTROL2_INTEN_DATA_RX BIT(6)
+#define MCHP_CORESPI_CONTROL2_INTEN_SSEND BIT(5)
+#define MCHP_CORESPI_CONTROL2_INTEN_CMD BIT(4)
+
+#define INT_ENABLE_MASK (MCHP_CORESPI_CONTROL_TX_DATA_INT | MCHP_CORESPI_CONTROL_RX_OVER_INT | \
+ MCHP_CORESPI_CONTROL_TX_UNDER_INT)
+
+#define MCHP_CORESPI_REG_CONTROL (0x00)
+#define MCHP_CORESPI_REG_INTCLEAR (0x04)
+#define MCHP_CORESPI_REG_RXDATA (0x08)
+#define MCHP_CORESPI_REG_TXDATA (0x0c)
+#define MCHP_CORESPI_REG_INTMASK (0X10)
+#define MCHP_CORESPI_REG_INTRAW (0X14)
+#define MCHP_CORESPI_REG_CONTROL2 (0x18)
+#define MCHP_CORESPI_REG_COMMAND (0x1c)
+#define MCHP_CORESPI_REG_STAT (0x20)
+#define MCHP_CORESPI_REG_SSEL (0x24)
+#define MCHP_CORESPI_REG_TXDATA_LAST (0X28)
+#define MCHP_CORESPI_REG_CLK_DIV (0x2c)
+
+struct mchp_corespi {
+ void __iomem *regs;
+ struct clk *clk;
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ u32 clk_gen;
+ int irq;
+ unsigned int tx_len;
+ unsigned int rx_len;
+ u32 fifo_depth;
+};
+
+static inline void mchp_corespi_disable(struct mchp_corespi *spi)
+{
+ u8 control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL);
+
+ control &= ~MCHP_CORESPI_CONTROL_ENABLE;
+
+ writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL);
+}
+
+static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi, u32 fifo_max)
+{
+ for (int i = 0; i < fifo_max; i++) {
+ u32 data;
+
+ while (readb(spi->regs + MCHP_CORESPI_REG_STAT) &
+ MCHP_CORESPI_STATUS_RXFIFO_EMPTY)
+ ;
+
+ /* On TX-only transfers always perform a dummy read */
+ data = readb(spi->regs + MCHP_CORESPI_REG_RXDATA);
+ if (spi->rx_buf)
+ *spi->rx_buf++ = data;
+
+ spi->rx_len--;
+ }
+}
+
+static void mchp_corespi_enable_ints(struct mchp_corespi *spi)
+{
+ u8 control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL);
+
+ control |= INT_ENABLE_MASK;
+ writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL);
+}
+
+static void mchp_corespi_disable_ints(struct mchp_corespi *spi)
+{
+ u8 control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL);
+
+ control &= ~INT_ENABLE_MASK;
+ writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL);
+}
+
+static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi, u32 fifo_max)
+{
+ for (int i = 0; i < fifo_max; i++) {
+ if (readb(spi->regs + MCHP_CORESPI_REG_STAT) &
+ MCHP_CORESPI_STATUS_TXFIFO_FULL)
+ break;
+
+ /* On RX-only transfers always perform a dummy write */
+ if (spi->tx_buf)
+ writeb(*spi->tx_buf++, spi->regs + MCHP_CORESPI_REG_TXDATA);
+ else
+ writeb(0xaa, spi->regs + MCHP_CORESPI_REG_TXDATA);
+
+ spi->tx_len--;
+ }
+}
+
+static void mchp_corespi_set_cs(struct spi_device *spi, bool disable)
+{
+ struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller);
+ u32 reg;
+
+ reg = readb(corespi->regs + MCHP_CORESPI_REG_SSEL);
+ reg &= ~BIT(spi_get_chipselect(spi, 0));
+ reg |= !disable << spi_get_chipselect(spi, 0);
+
+ writeb(reg, corespi->regs + MCHP_CORESPI_REG_SSEL);
+}
+
+static int mchp_corespi_setup(struct spi_device *spi)
+{
+ if (spi_get_csgpiod(spi, 0))
+ return 0;
+
+ if (spi->mode & (SPI_CS_HIGH)) {
+ dev_err(&spi->dev, "unable to support active-high CS in Motorola mode\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (spi->mode & SPI_MODE_X_MASK & ~spi->controller->mode_bits) {
+ dev_err(&spi->dev, "incompatible CPOL/CPHA, must match controller's Motorola mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi *spi)
+{
+ u8 control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL);
+
+ /* Master mode changes require core to be disabled.*/
+ control = (control & ~MCHP_CORESPI_CONTROL_ENABLE) | MCHP_CORESPI_CONTROL_MASTER;
+
+ writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL);
+
+ mchp_corespi_enable_ints(spi);
+
+ control = readb(spi->regs + MCHP_CORESPI_REG_CONTROL);
+ control |= MCHP_CORESPI_CONTROL_ENABLE;
+
+ writeb(control, spi->regs + MCHP_CORESPI_REG_CONTROL);
+}
+
+static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id)
+{
+ struct spi_controller *host = dev_id;
+ struct mchp_corespi *spi = spi_controller_get_devdata(host);
+ u8 intfield = readb(spi->regs + MCHP_CORESPI_REG_INTMASK) & 0xff;
+ bool finalise = false;
+
+ /* Interrupt line may be shared and not for us at all */
+ if (intfield == 0)
+ return IRQ_NONE;
+
+ if (intfield & MCHP_CORESPI_INT_TXDONE)
+ writeb(MCHP_CORESPI_INT_TXDONE, spi->regs + MCHP_CORESPI_REG_INTCLEAR);
+
+ if (intfield & MCHP_CORESPI_INT_RX_CHANNEL_OVERFLOW) {
+ writeb(MCHP_CORESPI_INT_RX_CHANNEL_OVERFLOW,
+ spi->regs + MCHP_CORESPI_REG_INTCLEAR);
+ finalise = true;
+ dev_err(&host->dev,
+ "RX OVERFLOW: rxlen: %u, txlen: %u\n",
+ spi->rx_len, spi->tx_len);
+ }
+
+ if (intfield & MCHP_CORESPI_INT_TX_CHANNEL_UNDERRUN) {
+ writeb(MCHP_CORESPI_INT_TX_CHANNEL_UNDERRUN,
+ spi->regs + MCHP_CORESPI_REG_INTCLEAR);
+ finalise = true;
+ dev_err(&host->dev,
+ "TX UNDERFLOW: rxlen: %u, txlen: %u\n",
+ spi->rx_len, spi->tx_len);
+ }
+
+ if (finalise)
+ spi_finalize_current_transfer(host);
+
+ return IRQ_HANDLED;
+}
+
+static int mchp_corespi_set_clk_div(struct mchp_corespi *spi,
+ unsigned long target_hz)
+{
+ unsigned long pclk_hz, spi_hz;
+ u32 clk_div;
+
+ /* Get peripheral clock rate */
+ pclk_hz = clk_get_rate(spi->clk);
+ if (!pclk_hz)
+ return -EINVAL;
+
+ /*
+ * Calculate clock rate generated by SPI master
+ * Formula: SPICLK = PCLK / (2 * (CLK_DIV + 1))
+ */
+ clk_div = DIV_ROUND_UP(pclk_hz, 2 * target_hz) - 1;
+
+ if (clk_div > 0xFF)
+ return -EINVAL;
+
+ spi_hz = pclk_hz / (2 * (clk_div + 1));
+
+ if (spi_hz > target_hz)
+ return -EINVAL;
+
+ writeb(clk_div, spi->regs + MCHP_CORESPI_REG_CLK_DIV);
+
+ return 0;
+}
+
+static int mchp_corespi_transfer_one(struct spi_controller *host,
+ struct spi_device *spi_dev,
+ struct spi_transfer *xfer)
+{
+ struct mchp_corespi *spi = spi_controller_get_devdata(host);
+ int ret;
+
+ ret = mchp_corespi_set_clk_div(spi, (unsigned long)xfer->speed_hz);
+ if (ret) {
+ dev_err(&host->dev, "failed to set clock divider for target %u Hz\n",
+ xfer->speed_hz);
+ return ret;
+ }
+
+ spi->tx_buf = xfer->tx_buf;
+ spi->rx_buf = xfer->rx_buf;
+ spi->tx_len = xfer->len;
+ spi->rx_len = xfer->len;
+
+ while (spi->tx_len) {
+ unsigned int fifo_max = min(spi->tx_len, spi->fifo_depth);
+
+ mchp_corespi_write_fifo(spi, fifo_max);
+ mchp_corespi_read_fifo(spi, fifo_max);
+ }
+
+ spi_finalize_current_transfer(host);
+ return 1;
+}
+
+static int mchp_corespi_probe(struct platform_device *pdev)
+{
+ const char *protocol = "motorola";
+ struct device *dev = &pdev->dev;
+ struct spi_controller *host;
+ struct mchp_corespi *spi;
+ struct resource *res;
+ u32 num_cs, mode, frame_size;
+ bool assert_ssel;
+ int ret = 0;
+
+ host = devm_spi_alloc_host(dev, sizeof(*spi));
+ if (!host)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, host);
+
+ if (of_property_read_u32(dev->of_node, "num-cs", &num_cs))
+ num_cs = MCHP_CORESPI_MAX_CS;
+
+ /*
+ * Protocol: CFG_MODE
+ * CoreSPI can be configured for Motorola, TI or NSC.
+ * The current driver supports only Motorola mode.
+ */
+ ret = of_property_read_string(dev->of_node, "microchip,protocol-configuration",
+ &protocol);
+ if (ret && ret != -EINVAL)
+ return dev_err_probe(dev, ret, "Error reading protocol-configuration\n");
+ if (strcmp(protocol, "motorola") != 0)
+ return dev_err_probe(dev, -EINVAL,
+ "CoreSPI: protocol '%s' not supported by this driver\n",
+ protocol);
+
+ /*
+ * Motorola mode (0-3): CFG_MOT_MODE
+ * Mode is fixed in the IP configurator.
+ */
+ ret = of_property_read_u32(dev->of_node, "microchip,motorola-mode", &mode);
+ if (ret)
+ mode = MCHP_CORESPI_DEFAULT_MOTOROLA_MODE;
+ else if (mode > 3)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid 'microchip,motorola-mode' value %u\n", mode);
+
+ /*
+ * Frame size: CFG_FRAME_SIZE
+ * The hardware allows frame sizes <= APB data width.
+ * However, this driver currently only supports 8-bit frames.
+ */
+ ret = of_property_read_u32(dev->of_node, "microchip,frame-size", &frame_size);
+ if (!ret && frame_size != 8)
+ return dev_err_probe(dev, -EINVAL,
+ "CoreSPI: frame size %u not supported by this driver\n",
+ frame_size);
+
+ /*
+ * SSEL: CFG_MOT_SSEL
+ * CoreSPI deasserts SSEL when the TX FIFO empties.
+ * To prevent CS deassertion when TX FIFO drains, the ssel-active property
+ * keeps CS asserted for the full SPI transfer.
+ */
+ assert_ssel = of_property_read_bool(dev->of_node, "microchip,ssel-active");
+ if (!assert_ssel)
+ return dev_err_probe(dev, -EINVAL,
+ "hardware must enable 'microchip,ssel-active' to keep CS asserted for the SPI transfer\n");
+
+ spi = spi_controller_get_devdata(host);
+
+ host->num_chipselect = num_cs;
+ host->mode_bits = mode;
+ host->setup = mchp_corespi_setup;
+ host->use_gpio_descriptors = true;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ host->transfer_one = mchp_corespi_transfer_one;
+ host->set_cs = mchp_corespi_set_cs;
+ host->dev.of_node = dev->of_node;
+
+ ret = of_property_read_u32(dev->of_node, "fifo-depth", &spi->fifo_depth);
+ if (ret)
+ spi->fifo_depth = MCHP_CORESPI_DEFAULT_FIFO_DEPTH;
+
+ spi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(spi->regs))
+ return PTR_ERR(spi->regs);
+
+ spi->irq = platform_get_irq(pdev, 0);
+ if (spi->irq < 0)
+ return spi->irq;
+
+ ret = devm_request_irq(dev, spi->irq, mchp_corespi_interrupt, IRQF_SHARED,
+ dev_name(dev), host);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not request irq\n");
+
+ spi->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(spi->clk))
+ return dev_err_probe(dev, PTR_ERR(spi->clk), "could not get clk\n");
+
+ mchp_corespi_init(host, spi);
+
+ ret = devm_spi_register_controller(dev, host);
+ if (ret) {
+ mchp_corespi_disable(spi);
+ return dev_err_probe(dev, ret, "unable to register host for CoreSPI controller\n");
+ }
+
+ return 0;
+}
+
+static void mchp_corespi_remove(struct platform_device *pdev)
+{
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct mchp_corespi *spi = spi_controller_get_devdata(host);
+
+ mchp_corespi_disable_ints(spi);
+ mchp_corespi_disable(spi);
+}
+
+/*
+ * Platform driver data structure
+ */
+
+#if defined(CONFIG_OF)
+static const struct of_device_id mchp_corespi_dt_ids[] = {
+ { .compatible = "microchip,corespi-rtl-v5" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mchp_corespi_dt_ids);
+#endif
+
+static struct platform_driver mchp_corespi_driver = {
+ .probe = mchp_corespi_probe,
+ .driver = {
+ .name = "microchip-corespi",
+ .of_match_table = of_match_ptr(mchp_corespi_dt_ids),
+ },
+ .remove = mchp_corespi_remove,
+};
+module_platform_driver(mchp_corespi_driver);
+MODULE_DESCRIPTION("Microchip CoreSPI controller driver");
+MODULE_AUTHOR("Prajna Rajendra Kumar <prajna.rajendrakumar@microchip.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c
deleted file mode 100644
index b59e8a0c5b97..000000000000
--- a/drivers/spi/spi-microchip-core.c
+++ /dev/null
@@ -1,606 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0)
-/*
- * Microchip CoreSPI SPI controller driver
- *
- * Copyright (c) 2018-2022 Microchip Technology Inc. and its subsidiaries
- *
- * Author: Daire McNamara <daire.mcnamara@microchip.com>
- * Author: Conor Dooley <conor.dooley@microchip.com>
- *
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-
-#define MAX_LEN (0xffff)
-#define MAX_CS (8)
-#define DEFAULT_FRAMESIZE (8)
-#define FIFO_DEPTH (32)
-#define CLK_GEN_MODE1_MAX (255)
-#define CLK_GEN_MODE0_MAX (15)
-#define CLK_GEN_MIN (0)
-#define MODE_X_MASK_SHIFT (24)
-
-#define CONTROL_ENABLE BIT(0)
-#define CONTROL_MASTER BIT(1)
-#define CONTROL_RX_DATA_INT BIT(4)
-#define CONTROL_TX_DATA_INT BIT(5)
-#define CONTROL_RX_OVER_INT BIT(6)
-#define CONTROL_TX_UNDER_INT BIT(7)
-#define CONTROL_SPO BIT(24)
-#define CONTROL_SPH BIT(25)
-#define CONTROL_SPS BIT(26)
-#define CONTROL_FRAMEURUN BIT(27)
-#define CONTROL_CLKMODE BIT(28)
-#define CONTROL_BIGFIFO BIT(29)
-#define CONTROL_OENOFF BIT(30)
-#define CONTROL_RESET BIT(31)
-
-#define CONTROL_MODE_MASK GENMASK(3, 2)
-#define MOTOROLA_MODE (0)
-#define CONTROL_FRAMECNT_MASK GENMASK(23, 8)
-#define CONTROL_FRAMECNT_SHIFT (8)
-
-#define STATUS_ACTIVE BIT(14)
-#define STATUS_SSEL BIT(13)
-#define STATUS_FRAMESTART BIT(12)
-#define STATUS_TXFIFO_EMPTY_NEXT_READ BIT(11)
-#define STATUS_TXFIFO_EMPTY BIT(10)
-#define STATUS_TXFIFO_FULL_NEXT_WRITE BIT(9)
-#define STATUS_TXFIFO_FULL BIT(8)
-#define STATUS_RXFIFO_EMPTY_NEXT_READ BIT(7)
-#define STATUS_RXFIFO_EMPTY BIT(6)
-#define STATUS_RXFIFO_FULL_NEXT_WRITE BIT(5)
-#define STATUS_RXFIFO_FULL BIT(4)
-#define STATUS_TX_UNDERRUN BIT(3)
-#define STATUS_RX_OVERFLOW BIT(2)
-#define STATUS_RXDAT_RXED BIT(1)
-#define STATUS_TXDAT_SENT BIT(0)
-
-#define INT_TXDONE BIT(0)
-#define INT_RXRDY BIT(1)
-#define INT_RX_CHANNEL_OVERFLOW BIT(2)
-#define INT_TX_CHANNEL_UNDERRUN BIT(3)
-
-#define INT_ENABLE_MASK (CONTROL_RX_DATA_INT | CONTROL_TX_DATA_INT | \
- CONTROL_RX_OVER_INT | CONTROL_TX_UNDER_INT)
-
-#define REG_CONTROL (0x00)
-#define REG_FRAME_SIZE (0x04)
-#define REG_STATUS (0x08)
-#define REG_INT_CLEAR (0x0c)
-#define REG_RX_DATA (0x10)
-#define REG_TX_DATA (0x14)
-#define REG_CLK_GEN (0x18)
-#define REG_SLAVE_SELECT (0x1c)
-#define SSEL_MASK GENMASK(7, 0)
-#define SSEL_DIRECT BIT(8)
-#define SSELOUT_SHIFT 9
-#define SSELOUT BIT(SSELOUT_SHIFT)
-#define REG_MIS (0x20)
-#define REG_RIS (0x24)
-#define REG_CONTROL2 (0x28)
-#define REG_COMMAND (0x2c)
-#define REG_PKTSIZE (0x30)
-#define REG_CMD_SIZE (0x34)
-#define REG_HWSTATUS (0x38)
-#define REG_STAT8 (0x3c)
-#define REG_CTRL2 (0x48)
-#define REG_FRAMESUP (0x50)
-
-struct mchp_corespi {
- void __iomem *regs;
- struct clk *clk;
- const u8 *tx_buf;
- u8 *rx_buf;
- u32 clk_gen; /* divider for spi output clock generated by the controller */
- u32 clk_mode;
- int irq;
- int tx_len;
- int rx_len;
- int pending;
-};
-
-static inline u32 mchp_corespi_read(struct mchp_corespi *spi, unsigned int reg)
-{
- return readl(spi->regs + reg);
-}
-
-static inline void mchp_corespi_write(struct mchp_corespi *spi, unsigned int reg, u32 val)
-{
- writel(val, spi->regs + reg);
-}
-
-static inline void mchp_corespi_disable(struct mchp_corespi *spi)
-{
- u32 control = mchp_corespi_read(spi, REG_CONTROL);
-
- control &= ~CONTROL_ENABLE;
-
- mchp_corespi_write(spi, REG_CONTROL, control);
-}
-
-static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi)
-{
- u8 data;
- int fifo_max, i = 0;
-
- fifo_max = min(spi->rx_len, FIFO_DEPTH);
-
- while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)) {
- data = mchp_corespi_read(spi, REG_RX_DATA);
-
- if (spi->rx_buf)
- *spi->rx_buf++ = data;
- i++;
- }
- spi->rx_len -= i;
- spi->pending -= i;
-}
-
-static void mchp_corespi_enable_ints(struct mchp_corespi *spi)
-{
- u32 control, mask = INT_ENABLE_MASK;
-
- mchp_corespi_disable(spi);
-
- control = mchp_corespi_read(spi, REG_CONTROL);
-
- control |= mask;
- mchp_corespi_write(spi, REG_CONTROL, control);
-
- control |= CONTROL_ENABLE;
- mchp_corespi_write(spi, REG_CONTROL, control);
-}
-
-static void mchp_corespi_disable_ints(struct mchp_corespi *spi)
-{
- u32 control, mask = INT_ENABLE_MASK;
-
- mchp_corespi_disable(spi);
-
- control = mchp_corespi_read(spi, REG_CONTROL);
- control &= ~mask;
- mchp_corespi_write(spi, REG_CONTROL, control);
-
- control |= CONTROL_ENABLE;
- mchp_corespi_write(spi, REG_CONTROL, control);
-}
-
-static inline void mchp_corespi_set_xfer_size(struct mchp_corespi *spi, int len)
-{
- u32 control;
- u16 lenpart;
-
- /*
- * Disable the SPI controller. Writes to transfer length have
- * no effect when the controller is enabled.
- */
- mchp_corespi_disable(spi);
-
- /*
- * The lower 16 bits of the frame count are stored in the control reg
- * for legacy reasons, but the upper 16 written to a different register:
- * FRAMESUP. While both the upper and lower bits can be *READ* from the
- * FRAMESUP register, writing to the lower 16 bits is a NOP
- */
- lenpart = len & 0xffff;
-
- control = mchp_corespi_read(spi, REG_CONTROL);
- control &= ~CONTROL_FRAMECNT_MASK;
- control |= lenpart << CONTROL_FRAMECNT_SHIFT;
- mchp_corespi_write(spi, REG_CONTROL, control);
-
- lenpart = len & 0xffff0000;
- mchp_corespi_write(spi, REG_FRAMESUP, lenpart);
-
- control |= CONTROL_ENABLE;
- mchp_corespi_write(spi, REG_CONTROL, control);
-}
-
-static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi)
-{
- u8 byte;
- int fifo_max, i = 0;
-
- fifo_max = min(spi->tx_len, FIFO_DEPTH);
- mchp_corespi_set_xfer_size(spi, fifo_max);
-
- while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) {
- byte = spi->tx_buf ? *spi->tx_buf++ : 0xaa;
- mchp_corespi_write(spi, REG_TX_DATA, byte);
- i++;
- }
-
- spi->tx_len -= i;
- spi->pending += i;
-}
-
-static inline void mchp_corespi_set_framesize(struct mchp_corespi *spi, int bt)
-{
- u32 control;
-
- /*
- * Disable the SPI controller. Writes to the frame size have
- * no effect when the controller is enabled.
- */
- mchp_corespi_disable(spi);
-
- mchp_corespi_write(spi, REG_FRAME_SIZE, bt);
-
- control = mchp_corespi_read(spi, REG_CONTROL);
- control |= CONTROL_ENABLE;
- mchp_corespi_write(spi, REG_CONTROL, control);
-}
-
-static void mchp_corespi_set_cs(struct spi_device *spi, bool disable)
-{
- u32 reg;
- struct mchp_corespi *corespi = spi_master_get_devdata(spi->master);
-
- reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT);
- reg &= ~BIT(spi_get_chipselect(spi, 0));
- reg |= !disable << spi_get_chipselect(spi, 0);
-
- mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg);
-}
-
-static int mchp_corespi_setup(struct spi_device *spi)
-{
- struct mchp_corespi *corespi = spi_master_get_devdata(spi->master);
- u32 reg;
-
- /*
- * Active high slaves need to be specifically set to their inactive
- * states during probe by adding them to the "control group" & thus
- * driving their select line low.
- */
- if (spi->mode & SPI_CS_HIGH) {
- reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT);
- reg |= BIT(spi_get_chipselect(spi, 0));
- mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg);
- }
- return 0;
-}
-
-static void mchp_corespi_init(struct spi_master *master, struct mchp_corespi *spi)
-{
- unsigned long clk_hz;
- u32 control = mchp_corespi_read(spi, REG_CONTROL);
-
- control |= CONTROL_MASTER;
-
- control &= ~CONTROL_MODE_MASK;
- control |= MOTOROLA_MODE;
-
- mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE);
-
- /* max. possible spi clock rate is the apb clock rate */
- clk_hz = clk_get_rate(spi->clk);
- master->max_speed_hz = clk_hz;
-
- /*
- * The controller must be configured so that it doesn't remove Chip
- * Select until the entire message has been transferred, even if at
- * some points TX FIFO becomes empty.
- *
- * BIGFIFO mode is also enabled, which sets the fifo depth to 32 frames
- * for the 8 bit transfers that this driver uses.
- */
- control = mchp_corespi_read(spi, REG_CONTROL);
- control |= CONTROL_SPS | CONTROL_BIGFIFO;
-
- mchp_corespi_write(spi, REG_CONTROL, control);
-
- mchp_corespi_enable_ints(spi);
-
- /*
- * It is required to enable direct mode, otherwise control over the chip
- * select is relinquished to the hardware. SSELOUT is enabled too so we
- * can deal with active high slaves.
- */
- mchp_corespi_write(spi, REG_SLAVE_SELECT, SSELOUT | SSEL_DIRECT);
-
- control = mchp_corespi_read(spi, REG_CONTROL);
-
- control &= ~CONTROL_RESET;
- control |= CONTROL_ENABLE;
-
- mchp_corespi_write(spi, REG_CONTROL, control);
-}
-
-static inline void mchp_corespi_set_clk_gen(struct mchp_corespi *spi)
-{
- u32 control;
-
- mchp_corespi_disable(spi);
-
- control = mchp_corespi_read(spi, REG_CONTROL);
- if (spi->clk_mode)
- control |= CONTROL_CLKMODE;
- else
- control &= ~CONTROL_CLKMODE;
-
- mchp_corespi_write(spi, REG_CLK_GEN, spi->clk_gen);
- mchp_corespi_write(spi, REG_CONTROL, control);
- mchp_corespi_write(spi, REG_CONTROL, control | CONTROL_ENABLE);
-}
-
-static inline void mchp_corespi_set_mode(struct mchp_corespi *spi, unsigned int mode)
-{
- u32 control, mode_val;
-
- switch (mode & SPI_MODE_X_MASK) {
- case SPI_MODE_0:
- mode_val = 0;
- break;
- case SPI_MODE_1:
- mode_val = CONTROL_SPH;
- break;
- case SPI_MODE_2:
- mode_val = CONTROL_SPO;
- break;
- case SPI_MODE_3:
- mode_val = CONTROL_SPH | CONTROL_SPO;
- break;
- }
-
- /*
- * Disable the SPI controller. Writes to the frame size have
- * no effect when the controller is enabled.
- */
- mchp_corespi_disable(spi);
-
- control = mchp_corespi_read(spi, REG_CONTROL);
- control &= ~(SPI_MODE_X_MASK << MODE_X_MASK_SHIFT);
- control |= mode_val;
-
- mchp_corespi_write(spi, REG_CONTROL, control);
-
- control |= CONTROL_ENABLE;
- mchp_corespi_write(spi, REG_CONTROL, control);
-}
-
-static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id)
-{
- struct spi_master *master = dev_id;
- struct mchp_corespi *spi = spi_master_get_devdata(master);
- u32 intfield = mchp_corespi_read(spi, REG_MIS) & 0xf;
- bool finalise = false;
-
- /* Interrupt line may be shared and not for us at all */
- if (intfield == 0)
- return IRQ_NONE;
-
- if (intfield & INT_TXDONE) {
- mchp_corespi_write(spi, REG_INT_CLEAR, INT_TXDONE);
-
- if (spi->rx_len)
- mchp_corespi_read_fifo(spi);
-
- if (spi->tx_len)
- mchp_corespi_write_fifo(spi);
-
- if (!spi->rx_len)
- finalise = true;
- }
-
- if (intfield & INT_RXRDY)
- mchp_corespi_write(spi, REG_INT_CLEAR, INT_RXRDY);
-
- if (intfield & INT_RX_CHANNEL_OVERFLOW) {
- mchp_corespi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW);
- finalise = true;
- dev_err(&master->dev,
- "%s: RX OVERFLOW: rxlen: %d, txlen: %d\n", __func__,
- spi->rx_len, spi->tx_len);
- }
-
- if (intfield & INT_TX_CHANNEL_UNDERRUN) {
- mchp_corespi_write(spi, REG_INT_CLEAR, INT_TX_CHANNEL_UNDERRUN);
- finalise = true;
- dev_err(&master->dev,
- "%s: TX UNDERFLOW: rxlen: %d, txlen: %d\n", __func__,
- spi->rx_len, spi->tx_len);
- }
-
- if (finalise)
- spi_finalize_current_transfer(master);
-
- return IRQ_HANDLED;
-}
-
-static int mchp_corespi_calculate_clkgen(struct mchp_corespi *spi,
- unsigned long target_hz)
-{
- unsigned long clk_hz, spi_hz, clk_gen;
-
- clk_hz = clk_get_rate(spi->clk);
- if (!clk_hz)
- return -EINVAL;
- spi_hz = min(target_hz, clk_hz);
-
- /*
- * There are two possible clock modes for the controller generated
- * clock's division ratio:
- * CLK_MODE = 0: 1 / (2^(CLK_GEN + 1)) where CLK_GEN = 0 to 15.
- * CLK_MODE = 1: 1 / (2 * CLK_GEN + 1) where CLK_GEN = 0 to 255.
- * First try mode 1, fall back to 0 and if we have tried both modes and
- * we /still/ can't get a good setting, we then throw the toys out of
- * the pram and give up
- * clk_gen is the register name for the clock divider on MPFS.
- */
- clk_gen = DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1;
- if (clk_gen > CLK_GEN_MODE1_MAX || clk_gen <= CLK_GEN_MIN) {
- clk_gen = DIV_ROUND_UP(clk_hz, spi_hz);
- clk_gen = fls(clk_gen) - 1;
-
- if (clk_gen > CLK_GEN_MODE0_MAX)
- return -EINVAL;
-
- spi->clk_mode = 0;
- } else {
- spi->clk_mode = 1;
- }
-
- spi->clk_gen = clk_gen;
- return 0;
-}
-
-static int mchp_corespi_transfer_one(struct spi_master *master,
- struct spi_device *spi_dev,
- struct spi_transfer *xfer)
-{
- struct mchp_corespi *spi = spi_master_get_devdata(master);
- int ret;
-
- ret = mchp_corespi_calculate_clkgen(spi, (unsigned long)xfer->speed_hz);
- if (ret) {
- dev_err(&master->dev, "failed to set clk_gen for target %u Hz\n", xfer->speed_hz);
- return ret;
- }
-
- mchp_corespi_set_clk_gen(spi);
-
- spi->tx_buf = xfer->tx_buf;
- spi->rx_buf = xfer->rx_buf;
- spi->tx_len = xfer->len;
- spi->rx_len = xfer->len;
- spi->pending = 0;
-
- mchp_corespi_set_xfer_size(spi, (spi->tx_len > FIFO_DEPTH)
- ? FIFO_DEPTH : spi->tx_len);
-
- if (spi->tx_len)
- mchp_corespi_write_fifo(spi);
- return 1;
-}
-
-static int mchp_corespi_prepare_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct spi_device *spi_dev = msg->spi;
- struct mchp_corespi *spi = spi_master_get_devdata(master);
-
- mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE);
- mchp_corespi_set_mode(spi, spi_dev->mode);
-
- return 0;
-}
-
-static int mchp_corespi_probe(struct platform_device *pdev)
-{
- struct spi_master *master;
- struct mchp_corespi *spi;
- struct resource *res;
- u32 num_cs;
- int ret = 0;
-
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*spi));
- if (!master)
- return dev_err_probe(&pdev->dev, -ENOMEM,
- "unable to allocate master for SPI controller\n");
-
- platform_set_drvdata(pdev, master);
-
- if (of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs))
- num_cs = MAX_CS;
-
- master->num_chipselect = num_cs;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->setup = mchp_corespi_setup;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->transfer_one = mchp_corespi_transfer_one;
- master->prepare_message = mchp_corespi_prepare_message;
- master->set_cs = mchp_corespi_set_cs;
- master->dev.of_node = pdev->dev.of_node;
-
- spi = spi_master_get_devdata(master);
-
- spi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
- if (IS_ERR(spi->regs))
- return PTR_ERR(spi->regs);
-
- spi->irq = platform_get_irq(pdev, 0);
- if (spi->irq <= 0)
- return dev_err_probe(&pdev->dev, -ENXIO,
- "invalid IRQ %d for SPI controller\n",
- spi->irq);
-
- ret = devm_request_irq(&pdev->dev, spi->irq, mchp_corespi_interrupt,
- IRQF_SHARED, dev_name(&pdev->dev), master);
- if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "could not request irq\n");
-
- spi->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(spi->clk))
- return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk),
- "could not get clk\n");
-
- ret = clk_prepare_enable(spi->clk);
- if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "failed to enable clock\n");
-
- mchp_corespi_init(master, spi);
-
- ret = devm_spi_register_master(&pdev->dev, master);
- if (ret) {
- mchp_corespi_disable(spi);
- clk_disable_unprepare(spi->clk);
- return dev_err_probe(&pdev->dev, ret,
- "unable to register master for SPI controller\n");
- }
-
- dev_info(&pdev->dev, "Registered SPI controller %d\n", master->bus_num);
-
- return 0;
-}
-
-static void mchp_corespi_remove(struct platform_device *pdev)
-{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct mchp_corespi *spi = spi_master_get_devdata(master);
-
- mchp_corespi_disable_ints(spi);
- clk_disable_unprepare(spi->clk);
- mchp_corespi_disable(spi);
-}
-
-#define MICROCHIP_SPI_PM_OPS (NULL)
-
-/*
- * Platform driver data structure
- */
-
-#if defined(CONFIG_OF)
-static const struct of_device_id mchp_corespi_dt_ids[] = {
- { .compatible = "microchip,mpfs-spi" },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mchp_corespi_dt_ids);
-#endif
-
-static struct platform_driver mchp_corespi_driver = {
- .probe = mchp_corespi_probe,
- .driver = {
- .name = "microchip-corespi",
- .pm = MICROCHIP_SPI_PM_OPS,
- .of_match_table = of_match_ptr(mchp_corespi_dt_ids),
- },
- .remove_new = mchp_corespi_remove,
-};
-module_platform_driver(mchp_corespi_driver);
-MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver");
-MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
-MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 99aeef28a477..3c1638ba5bee 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -53,7 +53,7 @@ struct mpc512x_psc_spi {
int type;
void __iomem *psc;
struct mpc512x_psc_fifo __iomem *fifo;
- unsigned int irq;
+ int irq;
u8 bits_per_word;
u32 mclk_rate;
@@ -85,7 +85,7 @@ static int mpc512x_psc_spi_transfer_setup(struct spi_device *spi,
static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
{
struct mpc512x_psc_spi_cs *cs = spi->controller_state;
- struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+ struct mpc512x_psc_spi *mps = spi_controller_get_devdata(spi->controller);
u32 sicr;
u32 ccr;
int speed;
@@ -143,7 +143,7 @@ static void mpc512x_psc_spi_deactivate_cs(struct spi_device *spi)
static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
struct spi_transfer *t)
{
- struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
+ struct mpc512x_psc_spi *mps = spi_controller_get_devdata(spi->controller);
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
size_t tx_len = t->len;
size_t rx_len = t->len;
@@ -280,7 +280,7 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
return 0;
}
-static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
+static int mpc512x_psc_spi_msg_xfer(struct spi_controller *host,
struct spi_message *m)
{
struct spi_device *spi;
@@ -320,15 +320,15 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
mpc512x_psc_spi_transfer_setup(spi, NULL);
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return status;
}
-static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
+static int mpc512x_psc_spi_prep_xfer_hw(struct spi_controller *host)
{
- struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
+ struct mpc512x_psc_spi *mps = spi_controller_get_devdata(host);
- dev_dbg(&master->dev, "%s()\n", __func__);
+ dev_dbg(&host->dev, "%s()\n", __func__);
/* Zero MR2 */
in_8(psc_addr(mps, mr2));
@@ -340,12 +340,12 @@ static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
return 0;
}
-static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master)
+static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_controller *host)
{
- struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
+ struct mpc512x_psc_spi *mps = spi_controller_get_devdata(host);
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
- dev_dbg(&master->dev, "%s()\n", __func__);
+ dev_dbg(&host->dev, "%s()\n", __func__);
/* disable transmitter/receiver and fifo interrupt */
out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
@@ -380,7 +380,7 @@ static void mpc512x_psc_spi_cleanup(struct spi_device *spi)
kfree(spi->controller_state);
}
-static int mpc512x_psc_spi_port_config(struct spi_master *master,
+static int mpc512x_psc_spi_port_config(struct spi_controller *host,
struct mpc512x_psc_spi *mps)
{
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
@@ -408,7 +408,7 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master,
sicr = 0x01000000 | /* SIM = 0001 -- 8 bit */
0x00800000 | /* GenClk = 1 -- internal clk */
0x00008000 | /* SPI = 1 */
- 0x00004000 | /* MSTR = 1 -- SPI master */
+ 0x00004000 | /* MSTR = 1 -- SPI host */
0x00000800; /* UseEOF = 1 -- SS low until EOF */
out_be32(psc_addr(mps, sicr), sicr);
@@ -459,28 +459,28 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mpc512x_psc_spi *mps;
- struct spi_master *master;
+ struct spi_controller *host;
int ret;
void *tempp;
struct clk *clk;
- master = devm_spi_alloc_master(dev, sizeof(*mps));
- if (master == NULL)
+ host = devm_spi_alloc_host(dev, sizeof(*mps));
+ if (host == NULL)
return -ENOMEM;
- dev_set_drvdata(dev, master);
- mps = spi_master_get_devdata(master);
+ dev_set_drvdata(dev, host);
+ mps = spi_controller_get_devdata(host);
mps->type = (int)device_get_match_data(dev);
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
- master->setup = mpc512x_psc_spi_setup;
- master->prepare_transfer_hardware = mpc512x_psc_spi_prep_xfer_hw;
- master->transfer_one_message = mpc512x_psc_spi_msg_xfer;
- master->unprepare_transfer_hardware = mpc512x_psc_spi_unprep_xfer_hw;
- master->use_gpio_descriptors = true;
- master->cleanup = mpc512x_psc_spi_cleanup;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ host->setup = mpc512x_psc_spi_setup;
+ host->prepare_transfer_hardware = mpc512x_psc_spi_prep_xfer_hw;
+ host->transfer_one_message = mpc512x_psc_spi_msg_xfer;
+ host->unprepare_transfer_hardware = mpc512x_psc_spi_unprep_xfer_hw;
+ host->use_gpio_descriptors = true;
+ host->cleanup = mpc512x_psc_spi_cleanup;
- device_set_node(&master->dev, dev_fwnode(dev));
+ device_set_node(&host->dev, dev_fwnode(dev));
tempp = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(tempp))
@@ -509,11 +509,11 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
- ret = mpc512x_psc_spi_port_config(master, mps);
+ ret = mpc512x_psc_spi_port_config(host, mps);
if (ret < 0)
return ret;
- return devm_spi_register_master(dev, master);
+ return devm_spi_register_controller(dev, host);
}
static const struct of_device_id mpc512x_psc_spi_of_match[] = {
diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c
index 9a1a080fb688..3bbeb8d5bfb8 100644
--- a/drivers/spi/spi-mpc52xx-psc.c
+++ b/drivers/spi/spi-mpc52xx-psc.c
@@ -29,7 +29,7 @@ struct mpc52xx_psc_spi {
/* driver internal data */
struct mpc52xx_psc __iomem *psc;
struct mpc52xx_psc_fifo __iomem *fifo;
- unsigned int irq;
+ int irq;
u8 bits_per_word;
struct completion done;
@@ -60,7 +60,7 @@ static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi,
static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
{
struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
- struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+ struct mpc52xx_psc_spi *mps = spi_controller_get_devdata(spi->controller);
struct mpc52xx_psc __iomem *psc = mps->psc;
u32 sicr;
u16 ccr;
@@ -104,10 +104,10 @@ static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
struct spi_transfer *t)
{
- struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+ struct mpc52xx_psc_spi *mps = spi_controller_get_devdata(spi->controller);
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo;
- unsigned rb = 0; /* number of bytes receieved */
+ unsigned rb = 0; /* number of bytes received */
unsigned sb = 0; /* number of bytes sent */
unsigned char *rx_buf = (unsigned char *)t->rx_buf;
unsigned char *tx_buf = (unsigned char *)t->tx_buf;
@@ -175,8 +175,8 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
return 0;
}
-int mpc52xx_psc_spi_transfer_one_message(struct spi_controller *ctlr,
- struct spi_message *m)
+static int mpc52xx_psc_spi_transfer_one_message(struct spi_controller *ctlr,
+ struct spi_message *m)
{
struct spi_device *spi;
struct spi_transfer *t = NULL;
@@ -263,7 +263,7 @@ static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
out_8(&fifo->rfcntl, 0);
out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
- /* Configure 8bit codec mode as a SPI master and use EOF flags */
+ /* Configure 8bit codec mode as a SPI host and use EOF flags */
/* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
out_be32(&psc->sicr, 0x0180C800);
out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */
@@ -295,37 +295,37 @@ static int mpc52xx_psc_spi_of_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mpc52xx_psc_spi *mps;
- struct spi_master *master;
+ struct spi_controller *host;
u32 bus_num;
int ret;
- master = devm_spi_alloc_master(dev, sizeof(*mps));
- if (master == NULL)
+ host = devm_spi_alloc_host(dev, sizeof(*mps));
+ if (host == NULL)
return -ENOMEM;
- dev_set_drvdata(dev, master);
- mps = spi_master_get_devdata(master);
+ dev_set_drvdata(dev, host);
+ mps = spi_controller_get_devdata(host);
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
ret = device_property_read_u32(dev, "cell-index", &bus_num);
if (ret || bus_num > 5)
return dev_err_probe(dev, ret ? : -EINVAL, "Invalid cell-index property\n");
- master->bus_num = bus_num + 1;
+ host->bus_num = bus_num + 1;
- master->num_chipselect = 255;
- master->setup = mpc52xx_psc_spi_setup;
- master->transfer_one_message = mpc52xx_psc_spi_transfer_one_message;
- master->cleanup = mpc52xx_psc_spi_cleanup;
+ host->num_chipselect = 255;
+ host->setup = mpc52xx_psc_spi_setup;
+ host->transfer_one_message = mpc52xx_psc_spi_transfer_one_message;
+ host->cleanup = mpc52xx_psc_spi_cleanup;
- device_set_node(&master->dev, dev_fwnode(dev));
+ device_set_node(&host->dev, dev_fwnode(dev));
mps->psc = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(mps->psc))
return dev_err_probe(dev, PTR_ERR(mps->psc), "could not ioremap I/O port range\n");
- /* On the 5200, fifo regs are immediately ajacent to the psc regs */
+ /* On the 5200, fifo regs are immediately adjacent to the psc regs */
mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc);
mps->irq = platform_get_irq(pdev, 0);
@@ -337,13 +337,13 @@ static int mpc52xx_psc_spi_of_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = mpc52xx_psc_spi_port_config(master->bus_num, mps);
+ ret = mpc52xx_psc_spi_port_config(host->bus_num, mps);
if (ret < 0)
return dev_err_probe(dev, ret, "can't configure PSC! Is it capable of SPI?\n");
init_completion(&mps->done);
- return devm_spi_register_master(dev, master);
+ return devm_spi_register_controller(dev, host);
}
static const struct of_device_id mpc52xx_psc_spi_of_match[] = {
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index ab7df5f64342..6d4dde15ac54 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/platform_device.h>
#include <asm/time.h>
#include <asm/mpc52xx.h>
@@ -62,7 +63,7 @@ MODULE_LICENSE("GPL");
/* Driver internal data */
struct mpc52xx_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *regs;
int irq0; /* MODF irq */
int irq1; /* SPIF irq */
@@ -152,7 +153,7 @@ mpc52xx_spi_fsmstate_idle(int irq, struct mpc52xx_spi *ms, u8 status, u8 data)
u8 ctrl1;
if (status && irq)
- dev_err(&ms->master->dev, "spurious irq, status=0x%.2x\n",
+ dev_err(&ms->host->dev, "spurious irq, status=0x%.2x\n",
status);
/* Check if there is another transfer waiting. */
@@ -235,7 +236,7 @@ static int mpc52xx_spi_fsmstate_transfer(int irq, struct mpc52xx_spi *ms,
return FSM_CONTINUE;
} else if (status & SPI_STATUS_MODF) {
ms->modf_count++;
- dev_err(&ms->master->dev, "mode fault\n");
+ dev_err(&ms->host->dev, "mode fault\n");
mpc52xx_spi_chipsel(ms, 0);
ms->message->status = -EIO;
if (ms->message->complete)
@@ -280,7 +281,7 @@ static int
mpc52xx_spi_fsmstate_wait(int irq, struct mpc52xx_spi *ms, u8 status, u8 data)
{
if (status && irq)
- dev_err(&ms->master->dev, "spurious irq, status=0x%.2x\n",
+ dev_err(&ms->host->dev, "spurious irq, status=0x%.2x\n",
status);
if (((int)mftb()) - ms->timestamp < 0)
@@ -361,12 +362,12 @@ static void mpc52xx_spi_wq(struct work_struct *work)
}
/*
- * spi_master ops
+ * spi_controller ops
*/
static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
- struct mpc52xx_spi *ms = spi_master_get_devdata(spi->master);
+ struct mpc52xx_spi *ms = spi_controller_get_devdata(spi->controller);
unsigned long flags;
m->actual_length = 0;
@@ -385,7 +386,7 @@ static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
*/
static int mpc52xx_spi_probe(struct platform_device *op)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct mpc52xx_spi *ms;
struct gpio_desc *gpio_cs;
void __iomem *regs;
@@ -406,7 +407,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
out_8(regs + SPI_PORTDATA, 0x8); /* Deassert /SS signal */
/* Clear the status register and re-read it to check for a MODF
- * failure. This driver cannot currently handle multiple masters
+ * failure. This driver cannot currently handle multiple hosts
* on the SPI bus. This fault will also occur if the SPI signals
* are not connected to any pins (port_config setting) */
in_8(regs + SPI_STATUS);
@@ -419,22 +420,22 @@ static int mpc52xx_spi_probe(struct platform_device *op)
goto err_init;
}
- dev_dbg(&op->dev, "allocating spi_master struct\n");
- master = spi_alloc_master(&op->dev, sizeof(*ms));
- if (!master) {
+ dev_dbg(&op->dev, "allocating spi_controller struct\n");
+ host = spi_alloc_host(&op->dev, sizeof(*ms));
+ if (!host) {
rc = -ENOMEM;
goto err_alloc;
}
- master->transfer = mpc52xx_spi_transfer;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->dev.of_node = op->dev.of_node;
+ host->transfer = mpc52xx_spi_transfer;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->dev.of_node = op->dev.of_node;
- platform_set_drvdata(op, master);
+ platform_set_drvdata(op, host);
- ms = spi_master_get_devdata(master);
- ms->master = master;
+ ms = spi_controller_get_devdata(host);
+ ms->host = host;
ms->regs = regs;
ms->irq0 = irq_of_parse_and_map(op->dev.of_node, 0);
ms->irq1 = irq_of_parse_and_map(op->dev.of_node, 1);
@@ -442,7 +443,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
ms->ipb_freq = mpc5xxx_get_bus_frequency(&op->dev);
ms->gpio_cs_count = gpiod_count(&op->dev, NULL);
if (ms->gpio_cs_count > 0) {
- master->num_chipselect = ms->gpio_cs_count;
+ host->num_chipselect = ms->gpio_cs_count;
ms->gpio_cs = kmalloc_array(ms->gpio_cs_count,
sizeof(*ms->gpio_cs),
GFP_KERNEL);
@@ -489,24 +490,24 @@ static int mpc52xx_spi_probe(struct platform_device *op)
if (!ms->irq0)
dev_info(&op->dev, "using polled mode\n");
- dev_dbg(&op->dev, "registering spi_master struct\n");
- rc = spi_register_master(master);
+ dev_dbg(&op->dev, "registering spi_controller struct\n");
+ rc = spi_register_controller(host);
if (rc)
goto err_register;
- dev_info(&ms->master->dev, "registered MPC5200 SPI bus\n");
+ dev_info(&ms->host->dev, "registered MPC5200 SPI bus\n");
return rc;
err_register:
- dev_err(&ms->master->dev, "initialization failed\n");
+ dev_err(&ms->host->dev, "initialization failed\n");
err_gpio:
while (i-- > 0)
gpiod_put(ms->gpio_cs[i]);
kfree(ms->gpio_cs);
err_alloc_gpio:
- spi_master_put(master);
+ spi_controller_put(host);
err_alloc:
err_init:
iounmap(regs);
@@ -515,10 +516,11 @@ static int mpc52xx_spi_probe(struct platform_device *op)
static void mpc52xx_spi_remove(struct platform_device *op)
{
- struct spi_master *master = spi_master_get(platform_get_drvdata(op));
- struct mpc52xx_spi *ms = spi_master_get_devdata(master);
+ struct spi_controller *host = spi_controller_get(platform_get_drvdata(op));
+ struct mpc52xx_spi *ms = spi_controller_get_devdata(host);
int i;
+ cancel_work_sync(&ms->work);
free_irq(ms->irq0, ms);
free_irq(ms->irq1, ms);
@@ -526,9 +528,9 @@ static void mpc52xx_spi_remove(struct platform_device *op)
gpiod_put(ms->gpio_cs[i]);
kfree(ms->gpio_cs);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
iounmap(ms->regs);
- spi_master_put(master);
+ spi_controller_put(host);
}
static const struct of_device_id mpc52xx_spi_match[] = {
@@ -543,6 +545,6 @@ static struct platform_driver mpc52xx_spi_of_driver = {
.of_match_table = mpc52xx_spi_match,
},
.probe = mpc52xx_spi_probe,
- .remove_new = mpc52xx_spi_remove,
+ .remove = mpc52xx_spi_remove,
};
module_platform_driver(mpc52xx_spi_of_driver);
diff --git a/drivers/spi/spi-mpfs.c b/drivers/spi/spi-mpfs.c
new file mode 100644
index 000000000000..9a14d1732a15
--- /dev/null
+++ b/drivers/spi/spi-mpfs.c
@@ -0,0 +1,626 @@
+// SPDX-License-Identifier: (GPL-2.0)
+/*
+ * Microchip CoreSPI SPI controller driver
+ *
+ * Copyright (c) 2018-2022 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Daire McNamara <daire.mcnamara@microchip.com>
+ * Author: Conor Dooley <conor.dooley@microchip.com>
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+
+#define MAX_LEN (0xffff)
+#define MAX_CS (1)
+#define DEFAULT_FRAMESIZE (8)
+#define FIFO_DEPTH (32)
+#define CLK_GEN_MODE1_MAX (255)
+#define CLK_GEN_MODE0_MAX (15)
+#define CLK_GEN_MIN (0)
+#define MODE_X_MASK_SHIFT (24)
+
+#define CONTROL_ENABLE BIT(0)
+#define CONTROL_MASTER BIT(1)
+#define CONTROL_RX_DATA_INT BIT(4)
+#define CONTROL_TX_DATA_INT BIT(5)
+#define CONTROL_RX_OVER_INT BIT(6)
+#define CONTROL_TX_UNDER_INT BIT(7)
+#define CONTROL_SPO BIT(24)
+#define CONTROL_SPH BIT(25)
+#define CONTROL_SPS BIT(26)
+#define CONTROL_FRAMEURUN BIT(27)
+#define CONTROL_CLKMODE BIT(28)
+#define CONTROL_BIGFIFO BIT(29)
+#define CONTROL_OENOFF BIT(30)
+#define CONTROL_RESET BIT(31)
+
+#define CONTROL_MODE_MASK GENMASK(3, 2)
+#define MOTOROLA_MODE (0)
+#define CONTROL_FRAMECNT_MASK GENMASK(23, 8)
+#define CONTROL_FRAMECNT_SHIFT (8)
+
+#define STATUS_ACTIVE BIT(14)
+#define STATUS_SSEL BIT(13)
+#define STATUS_FRAMESTART BIT(12)
+#define STATUS_TXFIFO_EMPTY_NEXT_READ BIT(11)
+#define STATUS_TXFIFO_EMPTY BIT(10)
+#define STATUS_TXFIFO_FULL_NEXT_WRITE BIT(9)
+#define STATUS_TXFIFO_FULL BIT(8)
+#define STATUS_RXFIFO_EMPTY_NEXT_READ BIT(7)
+#define STATUS_RXFIFO_EMPTY BIT(6)
+#define STATUS_RXFIFO_FULL_NEXT_WRITE BIT(5)
+#define STATUS_RXFIFO_FULL BIT(4)
+#define STATUS_TX_UNDERRUN BIT(3)
+#define STATUS_RX_OVERFLOW BIT(2)
+#define STATUS_RXDAT_RXED BIT(1)
+#define STATUS_TXDAT_SENT BIT(0)
+
+#define INT_TXDONE BIT(0)
+#define INT_RXRDY BIT(1)
+#define INT_RX_CHANNEL_OVERFLOW BIT(2)
+#define INT_TX_CHANNEL_UNDERRUN BIT(3)
+
+#define INT_ENABLE_MASK (CONTROL_RX_OVER_INT | CONTROL_TX_UNDER_INT)
+
+#define REG_CONTROL (0x00)
+#define REG_FRAME_SIZE (0x04)
+#define FRAME_SIZE_MASK GENMASK(5, 0)
+#define REG_STATUS (0x08)
+#define REG_INT_CLEAR (0x0c)
+#define REG_RX_DATA (0x10)
+#define REG_TX_DATA (0x14)
+#define REG_CLK_GEN (0x18)
+#define REG_SLAVE_SELECT (0x1c)
+#define SSEL_MASK GENMASK(7, 0)
+#define SSEL_DIRECT BIT(8)
+#define SSELOUT_SHIFT 9
+#define SSELOUT BIT(SSELOUT_SHIFT)
+#define REG_MIS (0x20)
+#define REG_RIS (0x24)
+#define REG_CONTROL2 (0x28)
+#define REG_COMMAND (0x2c)
+#define COMMAND_CLRFRAMECNT BIT(4)
+#define COMMAND_TXFIFORST BIT(3)
+#define COMMAND_RXFIFORST BIT(2)
+#define REG_PKTSIZE (0x30)
+#define REG_CMD_SIZE (0x34)
+#define REG_HWSTATUS (0x38)
+#define REG_STAT8 (0x3c)
+#define REG_CTRL2 (0x48)
+#define REG_FRAMESUP (0x50)
+
+struct mpfs_spi {
+ void __iomem *regs;
+ struct clk *clk;
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ u32 clk_gen; /* divider for spi output clock generated by the controller */
+ u32 clk_mode;
+ u32 pending_slave_select;
+ int irq;
+ int tx_len;
+ int rx_len;
+ int n_bytes;
+};
+
+static inline u32 mpfs_spi_read(struct mpfs_spi *spi, unsigned int reg)
+{
+ return readl(spi->regs + reg);
+}
+
+static inline void mpfs_spi_write(struct mpfs_spi *spi, unsigned int reg, u32 val)
+{
+ writel(val, spi->regs + reg);
+}
+
+static inline void mpfs_spi_disable(struct mpfs_spi *spi)
+{
+ u32 control = mpfs_spi_read(spi, REG_CONTROL);
+
+ control &= ~CONTROL_ENABLE;
+
+ mpfs_spi_write(spi, REG_CONTROL, control);
+}
+
+static inline void mpfs_spi_read_fifo(struct mpfs_spi *spi, int fifo_max)
+{
+ for (int i = 0; i < fifo_max; i++) {
+ u32 data;
+
+ while (mpfs_spi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)
+ ;
+
+ data = mpfs_spi_read(spi, REG_RX_DATA);
+
+ spi->rx_len -= spi->n_bytes;
+
+ if (!spi->rx_buf)
+ continue;
+
+ if (spi->n_bytes == 4)
+ *((u32 *)spi->rx_buf) = data;
+ else if (spi->n_bytes == 2)
+ *((u16 *)spi->rx_buf) = data;
+ else
+ *spi->rx_buf = data;
+
+ spi->rx_buf += spi->n_bytes;
+ }
+}
+
+static void mpfs_spi_enable_ints(struct mpfs_spi *spi)
+{
+ u32 control = mpfs_spi_read(spi, REG_CONTROL);
+
+ control |= INT_ENABLE_MASK;
+ mpfs_spi_write(spi, REG_CONTROL, control);
+}
+
+static void mpfs_spi_disable_ints(struct mpfs_spi *spi)
+{
+ u32 control = mpfs_spi_read(spi, REG_CONTROL);
+
+ control &= ~INT_ENABLE_MASK;
+ mpfs_spi_write(spi, REG_CONTROL, control);
+}
+
+static inline void mpfs_spi_set_xfer_size(struct mpfs_spi *spi, int len)
+{
+ u32 control;
+ u32 lenpart;
+ u32 frames = mpfs_spi_read(spi, REG_FRAMESUP);
+
+ /*
+ * Writing to FRAMECNT in REG_CONTROL will reset the frame count, taking
+ * a shortcut requires an explicit clear.
+ */
+ if (frames == len) {
+ mpfs_spi_write(spi, REG_COMMAND, COMMAND_CLRFRAMECNT);
+ return;
+ }
+
+ /*
+ * The lower 16 bits of the frame count are stored in the control reg
+ * for legacy reasons, but the upper 16 written to a different register:
+ * FRAMESUP. While both the upper and lower bits can be *READ* from the
+ * FRAMESUP register, writing to the lower 16 bits is (supposedly) a NOP.
+ *
+ * The driver used to disable the controller while modifying the frame
+ * count, and mask off the lower 16 bits of len while writing to
+ * FRAMES_UP. When the driver was changed to disable the controller as
+ * infrequently as possible, it was discovered that the logic of
+ * lenpart = len & 0xffff_0000
+ * write(REG_FRAMESUP, lenpart)
+ * would actually write zeros into the lower 16 bits on an mpfs250t-es,
+ * despite documentation stating these bits were read-only.
+ * Writing len unmasked into FRAMES_UP ensures those bits aren't zeroed
+ * on an mpfs250t-es and will be a NOP for the lower 16 bits on hardware
+ * that matches the documentation.
+ */
+ lenpart = len & 0xffff;
+ control = mpfs_spi_read(spi, REG_CONTROL);
+ control &= ~CONTROL_FRAMECNT_MASK;
+ control |= lenpart << CONTROL_FRAMECNT_SHIFT;
+ mpfs_spi_write(spi, REG_CONTROL, control);
+ mpfs_spi_write(spi, REG_FRAMESUP, len);
+}
+
+static inline void mpfs_spi_write_fifo(struct mpfs_spi *spi, int fifo_max)
+{
+ int i = 0;
+
+ mpfs_spi_set_xfer_size(spi, fifo_max);
+
+ while ((i < fifo_max) && !(mpfs_spi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) {
+ u32 word;
+
+ if (spi->n_bytes == 4)
+ word = spi->tx_buf ? *((u32 *)spi->tx_buf) : 0xaa;
+ else if (spi->n_bytes == 2)
+ word = spi->tx_buf ? *((u16 *)spi->tx_buf) : 0xaa;
+ else
+ word = spi->tx_buf ? *spi->tx_buf : 0xaa;
+
+ mpfs_spi_write(spi, REG_TX_DATA, word);
+ if (spi->tx_buf)
+ spi->tx_buf += spi->n_bytes;
+ i++;
+ }
+
+ spi->tx_len -= i * spi->n_bytes;
+}
+
+static inline void mpfs_spi_set_framesize(struct mpfs_spi *spi, int bt)
+{
+ u32 frame_size = mpfs_spi_read(spi, REG_FRAME_SIZE);
+ u32 control;
+
+ if ((frame_size & FRAME_SIZE_MASK) == bt)
+ return;
+
+ /*
+ * Disable the SPI controller. Writes to the frame size have
+ * no effect when the controller is enabled.
+ */
+ control = mpfs_spi_read(spi, REG_CONTROL);
+ control &= ~CONTROL_ENABLE;
+ mpfs_spi_write(spi, REG_CONTROL, control);
+
+ mpfs_spi_write(spi, REG_FRAME_SIZE, bt);
+
+ control |= CONTROL_ENABLE;
+ mpfs_spi_write(spi, REG_CONTROL, control);
+}
+
+static void mpfs_spi_set_cs(struct spi_device *spi, bool disable)
+{
+ u32 reg;
+ struct mpfs_spi *mspi = spi_controller_get_devdata(spi->controller);
+
+ reg = mpfs_spi_read(mspi, REG_SLAVE_SELECT);
+ reg &= ~BIT(spi_get_chipselect(spi, 0));
+ reg |= !disable << spi_get_chipselect(spi, 0);
+ mspi->pending_slave_select = reg;
+
+ /*
+ * Only deassert chip select immediately. Writing to some registers
+ * requires the controller to be disabled, which results in the
+ * output pins being tristated and can cause the SCLK and MOSI lines
+ * to transition. Therefore asserting the chip select is deferred
+ * until just before writing to the TX FIFO, to ensure the device
+ * doesn't see any spurious clock transitions whilst CS is enabled.
+ */
+ if (((spi->mode & SPI_CS_HIGH) == 0) == disable)
+ mpfs_spi_write(mspi, REG_SLAVE_SELECT, reg);
+}
+
+static int mpfs_spi_setup(struct spi_device *spi)
+{
+ struct mpfs_spi *mspi = spi_controller_get_devdata(spi->controller);
+ u32 reg;
+
+ if (spi_is_csgpiod(spi))
+ return 0;
+
+ /*
+ * Active high targets need to be specifically set to their inactive
+ * states during probe by adding them to the "control group" & thus
+ * driving their select line low.
+ */
+ if (spi->mode & SPI_CS_HIGH) {
+ reg = mpfs_spi_read(mspi, REG_SLAVE_SELECT);
+ reg |= BIT(spi_get_chipselect(spi, 0));
+ mspi->pending_slave_select = reg;
+ mpfs_spi_write(mspi, REG_SLAVE_SELECT, reg);
+ }
+ return 0;
+}
+
+static void mpfs_spi_init(struct spi_controller *host, struct mpfs_spi *spi)
+{
+ unsigned long clk_hz;
+ u32 control = mpfs_spi_read(spi, REG_CONTROL);
+
+ control &= ~CONTROL_ENABLE;
+ mpfs_spi_write(spi, REG_CONTROL, control);
+
+ control |= CONTROL_MASTER;
+ control &= ~CONTROL_MODE_MASK;
+ control |= MOTOROLA_MODE;
+
+ /*
+ * The controller must be configured so that it doesn't remove Chip
+ * Select until the entire message has been transferred, even if at
+ * some points TX FIFO becomes empty.
+ *
+ * BIGFIFO mode is also enabled, which sets the fifo depth to 32 frames
+ * for the 8 bit transfers that this driver uses.
+ */
+ control |= CONTROL_SPS | CONTROL_BIGFIFO;
+
+ mpfs_spi_write(spi, REG_CONTROL, control);
+
+ mpfs_spi_set_framesize(spi, DEFAULT_FRAMESIZE);
+
+ /* max. possible spi clock rate is the apb clock rate */
+ clk_hz = clk_get_rate(spi->clk);
+ host->max_speed_hz = clk_hz;
+
+ mpfs_spi_enable_ints(spi);
+
+ /*
+ * It is required to enable direct mode, otherwise control over the chip
+ * select is relinquished to the hardware. SSELOUT is enabled too so we
+ * can deal with active high targets.
+ */
+ spi->pending_slave_select = SSELOUT | SSEL_DIRECT;
+ mpfs_spi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
+
+ control = mpfs_spi_read(spi, REG_CONTROL);
+
+ control &= ~CONTROL_RESET;
+ control |= CONTROL_ENABLE;
+
+ mpfs_spi_write(spi, REG_CONTROL, control);
+}
+
+static inline void mpfs_spi_set_clk_gen(struct mpfs_spi *spi)
+{
+ u32 control;
+
+ control = mpfs_spi_read(spi, REG_CONTROL);
+ if (spi->clk_mode)
+ control |= CONTROL_CLKMODE;
+ else
+ control &= ~CONTROL_CLKMODE;
+
+ mpfs_spi_write(spi, REG_CLK_GEN, spi->clk_gen);
+ mpfs_spi_write(spi, REG_CONTROL, control);
+}
+
+static inline void mpfs_spi_set_mode(struct mpfs_spi *spi, unsigned int mode)
+{
+ u32 mode_val;
+ u32 control = mpfs_spi_read(spi, REG_CONTROL);
+
+ switch (mode & SPI_MODE_X_MASK) {
+ case SPI_MODE_0:
+ mode_val = 0;
+ break;
+ case SPI_MODE_1:
+ mode_val = CONTROL_SPH;
+ break;
+ case SPI_MODE_2:
+ mode_val = CONTROL_SPO;
+ break;
+ case SPI_MODE_3:
+ mode_val = CONTROL_SPH | CONTROL_SPO;
+ break;
+ }
+
+ /*
+ * Disable the SPI controller. Writes to the frame protocol have
+ * no effect when the controller is enabled.
+ */
+
+ control &= ~CONTROL_ENABLE;
+ mpfs_spi_write(spi, REG_CONTROL, control);
+
+ control &= ~(SPI_MODE_X_MASK << MODE_X_MASK_SHIFT);
+ control |= mode_val;
+
+ mpfs_spi_write(spi, REG_CONTROL, control);
+
+ control |= CONTROL_ENABLE;
+ mpfs_spi_write(spi, REG_CONTROL, control);
+}
+
+static irqreturn_t mpfs_spi_interrupt(int irq, void *dev_id)
+{
+ struct spi_controller *host = dev_id;
+ struct mpfs_spi *spi = spi_controller_get_devdata(host);
+ u32 intfield = mpfs_spi_read(spi, REG_MIS) & 0xf;
+ bool finalise = false;
+
+ /* Interrupt line may be shared and not for us at all */
+ if (intfield == 0)
+ return IRQ_NONE;
+
+ if (intfield & INT_RX_CHANNEL_OVERFLOW) {
+ mpfs_spi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW);
+ finalise = true;
+ dev_err(&host->dev,
+ "%s: RX OVERFLOW: rxlen: %d, txlen: %d\n", __func__,
+ spi->rx_len, spi->tx_len);
+ }
+
+ if (intfield & INT_TX_CHANNEL_UNDERRUN) {
+ mpfs_spi_write(spi, REG_INT_CLEAR, INT_TX_CHANNEL_UNDERRUN);
+ finalise = true;
+ dev_err(&host->dev,
+ "%s: TX UNDERFLOW: rxlen: %d, txlen: %d\n", __func__,
+ spi->rx_len, spi->tx_len);
+ }
+
+ if (finalise)
+ spi_finalize_current_transfer(host);
+
+ return IRQ_HANDLED;
+}
+
+static int mpfs_spi_calculate_clkgen(struct mpfs_spi *spi,
+ unsigned long target_hz)
+{
+ unsigned long clk_hz, spi_hz, clk_gen;
+
+ clk_hz = clk_get_rate(spi->clk);
+ if (!clk_hz)
+ return -EINVAL;
+ spi_hz = min(target_hz, clk_hz);
+
+ /*
+ * There are two possible clock modes for the controller generated
+ * clock's division ratio:
+ * CLK_MODE = 0: 1 / (2^(CLK_GEN + 1)) where CLK_GEN = 0 to 15.
+ * CLK_MODE = 1: 1 / (2 * CLK_GEN + 1) where CLK_GEN = 0 to 255.
+ * First try mode 1, fall back to 0 and if we have tried both modes and
+ * we /still/ can't get a good setting, we then throw the toys out of
+ * the pram and give up
+ * clk_gen is the register name for the clock divider on MPFS.
+ */
+ clk_gen = DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1;
+ if (clk_gen > CLK_GEN_MODE1_MAX || clk_gen <= CLK_GEN_MIN) {
+ clk_gen = DIV_ROUND_UP(clk_hz, spi_hz);
+ clk_gen = fls(clk_gen) - 1;
+
+ if (clk_gen > CLK_GEN_MODE0_MAX)
+ return -EINVAL;
+
+ spi->clk_mode = 0;
+ } else {
+ spi->clk_mode = 1;
+ }
+
+ spi->clk_gen = clk_gen;
+ return 0;
+}
+
+static int mpfs_spi_transfer_one(struct spi_controller *host,
+ struct spi_device *spi_dev,
+ struct spi_transfer *xfer)
+{
+ struct mpfs_spi *spi = spi_controller_get_devdata(host);
+ int ret;
+
+ ret = mpfs_spi_calculate_clkgen(spi, (unsigned long)xfer->speed_hz);
+ if (ret) {
+ dev_err(&host->dev, "failed to set clk_gen for target %u Hz\n", xfer->speed_hz);
+ return ret;
+ }
+
+ mpfs_spi_set_clk_gen(spi);
+
+ spi->tx_buf = xfer->tx_buf;
+ spi->rx_buf = xfer->rx_buf;
+ spi->tx_len = xfer->len;
+ spi->rx_len = xfer->len;
+ spi->n_bytes = roundup_pow_of_two(DIV_ROUND_UP(xfer->bits_per_word, BITS_PER_BYTE));
+
+ mpfs_spi_set_framesize(spi, xfer->bits_per_word);
+
+ mpfs_spi_write(spi, REG_COMMAND, COMMAND_RXFIFORST | COMMAND_TXFIFORST);
+
+ mpfs_spi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
+
+ while (spi->tx_len) {
+ int fifo_max = DIV_ROUND_UP(min(spi->tx_len, FIFO_DEPTH), spi->n_bytes);
+
+ mpfs_spi_write_fifo(spi, fifo_max);
+ mpfs_spi_read_fifo(spi, fifo_max);
+ }
+
+ spi_finalize_current_transfer(host);
+ return 1;
+}
+
+static int mpfs_spi_prepare_message(struct spi_controller *host,
+ struct spi_message *msg)
+{
+ struct spi_device *spi_dev = msg->spi;
+ struct mpfs_spi *spi = spi_controller_get_devdata(host);
+
+ mpfs_spi_set_mode(spi, spi_dev->mode);
+
+ return 0;
+}
+
+static int mpfs_spi_probe(struct platform_device *pdev)
+{
+ struct spi_controller *host;
+ struct mpfs_spi *spi;
+ struct resource *res;
+ u32 num_cs;
+ int ret = 0;
+
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi));
+ if (!host)
+ return dev_err_probe(&pdev->dev, -ENOMEM,
+ "unable to allocate host for SPI controller\n");
+
+ platform_set_drvdata(pdev, host);
+
+ if (of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs))
+ num_cs = MAX_CS;
+
+ host->num_chipselect = num_cs;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->use_gpio_descriptors = true;
+ host->setup = mpfs_spi_setup;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ host->transfer_one = mpfs_spi_transfer_one;
+ host->prepare_message = mpfs_spi_prepare_message;
+ host->set_cs = mpfs_spi_set_cs;
+ host->dev.of_node = pdev->dev.of_node;
+
+ spi = spi_controller_get_devdata(host);
+
+ spi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(spi->regs))
+ return PTR_ERR(spi->regs);
+
+ spi->irq = platform_get_irq(pdev, 0);
+ if (spi->irq < 0)
+ return spi->irq;
+
+ ret = devm_request_irq(&pdev->dev, spi->irq, mpfs_spi_interrupt,
+ IRQF_SHARED, dev_name(&pdev->dev), host);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "could not request irq\n");
+
+ spi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(spi->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk),
+ "could not get clk\n");
+
+ mpfs_spi_init(host, spi);
+
+ ret = devm_spi_register_controller(&pdev->dev, host);
+ if (ret) {
+ mpfs_spi_disable(spi);
+ return dev_err_probe(&pdev->dev, ret,
+ "unable to register host for SPI controller\n");
+ }
+
+ dev_info(&pdev->dev, "Registered SPI controller %d\n", host->bus_num);
+
+ return 0;
+}
+
+static void mpfs_spi_remove(struct platform_device *pdev)
+{
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct mpfs_spi *spi = spi_controller_get_devdata(host);
+
+ mpfs_spi_disable_ints(spi);
+ mpfs_spi_disable(spi);
+}
+
+#define MICROCHIP_SPI_PM_OPS (NULL)
+
+/*
+ * Platform driver data structure
+ */
+
+#if defined(CONFIG_OF)
+static const struct of_device_id mpfs_spi_dt_ids[] = {
+ { .compatible = "microchip,mpfs-spi" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mpfs_spi_dt_ids);
+#endif
+
+static struct platform_driver mpfs_spi_driver = {
+ .probe = mpfs_spi_probe,
+ .driver = {
+ .name = "microchip-spi",
+ .pm = MICROCHIP_SPI_PM_OPS,
+ .of_match_table = of_match_ptr(mpfs_spi_dt_ids),
+ },
+ .remove = mpfs_spi_remove,
+};
+module_platform_driver(mpfs_spi_driver);
+MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver");
+MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
+MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 39272ad6641b..4b40985af1ea 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -13,12 +13,14 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/gpio/consumer.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/platform_data/spi-mt65xx.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#include <linux/dma-mapping.h>
+#include <linux/pm_qos.h>
#define SPI_CFG0_REG 0x0000
#define SPI_CFG1_REG 0x0004
@@ -135,7 +137,7 @@ struct mtk_spi_compatible {
* @pad_num: Number of pad_sel entries
* @pad_sel: Groups of pins to select
* @parent_clk: Parent of sel_clk
- * @sel_clk: SPI master mux clock
+ * @sel_clk: SPI host mux clock
* @spi_clk: Peripheral clock
* @spi_hclk: AHB bus clock
* @cur_transfer: Currently processed SPI transfer
@@ -146,6 +148,7 @@ struct mtk_spi_compatible {
* @tx_sgl_len: Size of TX DMA transfer
* @rx_sgl_len: Size of RX DMA transfer
* @dev_comp: Device data structure
+ * @qos_request: QoS request
* @spi_clk_hz: Current SPI clock in Hz
* @spimem_done: SPI-MEM operation completion
* @use_spimem: Enables SPI-MEM
@@ -165,6 +168,7 @@ struct mtk_spi {
struct scatterlist *tx_sgl, *rx_sgl;
u32 tx_sgl_len, rx_sgl_len;
const struct mtk_spi_compatible *dev_comp;
+ struct pm_qos_request qos_request;
u32 spi_clk_hz;
struct completion spimem_done;
bool use_spimem;
@@ -216,6 +220,14 @@ static const struct mtk_spi_compatible mt6893_compat = {
.no_need_unprepare = true,
};
+static const struct mtk_spi_compatible mt6991_compat = {
+ .need_pad_sel = true,
+ .must_tx = true,
+ .enhance_timing = true,
+ .dma_ext = true,
+ .ipm_design = true,
+};
+
/*
* A piece of default chip info unless the platform
* supplies it.
@@ -241,6 +253,9 @@ static const struct of_device_id mtk_spi_of_match[] = {
{ .compatible = "mediatek,mt6765-spi",
.data = (void *)&mt6765_compat,
},
+ { .compatible = "mediatek,mt6991-spi",
+ .data = (void *)&mt6991_compat,
+ },
{ .compatible = "mediatek,mt7622-spi",
.data = (void *)&mt7622_compat,
},
@@ -282,7 +297,7 @@ static void mtk_spi_reset(struct mtk_spi *mdata)
static int mtk_spi_set_hw_cs_timing(struct spi_device *spi)
{
- struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(spi->controller);
struct spi_delay *cs_setup = &spi->cs_setup;
struct spi_delay *cs_hold = &spi->cs_hold;
struct spi_delay *cs_inactive = &spi->cs_inactive;
@@ -347,14 +362,15 @@ static int mtk_spi_set_hw_cs_timing(struct spi_device *spi)
return 0;
}
-static int mtk_spi_hw_init(struct spi_master *master,
+static int mtk_spi_hw_init(struct spi_controller *host,
struct spi_device *spi)
{
u16 cpha, cpol;
u32 reg_val;
struct mtk_chip_config *chip_config = spi->controller_data;
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
+ cpu_latency_qos_update_request(&mdata->qos_request, 500);
cpha = spi->mode & SPI_CPHA ? 1 : 0;
cpol = spi->mode & SPI_CPOL ? 1 : 0;
@@ -452,16 +468,25 @@ static int mtk_spi_hw_init(struct spi_master *master,
return 0;
}
-static int mtk_spi_prepare_message(struct spi_master *master,
+static int mtk_spi_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- return mtk_spi_hw_init(master, msg->spi);
+ return mtk_spi_hw_init(host, msg->spi);
+}
+
+static int mtk_spi_unprepare_message(struct spi_controller *host,
+ struct spi_message *message)
+{
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
+
+ cpu_latency_qos_update_request(&mdata->qos_request, PM_QOS_DEFAULT_VALUE);
+ return 0;
}
static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
{
u32 reg_val;
- struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(spi->controller);
if (spi->mode & SPI_CS_HIGH)
enable = !enable;
@@ -478,11 +503,11 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
}
}
-static void mtk_spi_prepare_transfer(struct spi_master *master,
+static void mtk_spi_prepare_transfer(struct spi_controller *host,
u32 speed_hz)
{
u32 div, sck_time, reg_val;
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
if (speed_hz < mdata->spi_clk_hz / 2)
div = DIV_ROUND_UP(mdata->spi_clk_hz, speed_hz);
@@ -511,10 +536,10 @@ static void mtk_spi_prepare_transfer(struct spi_master *master,
}
}
-static void mtk_spi_setup_packet(struct spi_master *master)
+static void mtk_spi_setup_packet(struct spi_controller *host)
{
u32 packet_size, packet_loop, reg_val;
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
if (mdata->dev_comp->ipm_design)
packet_size = min_t(u32,
@@ -538,10 +563,26 @@ static void mtk_spi_setup_packet(struct spi_master *master)
writel(reg_val, mdata->base + SPI_CFG1_REG);
}
-static void mtk_spi_enable_transfer(struct spi_master *master)
+inline u32 mtk_spi_set_nbit(u32 nbit)
+{
+ switch (nbit) {
+ default:
+ pr_warn_once("unknown nbit mode %u. Falling back to single mode\n",
+ nbit);
+ fallthrough;
+ case SPI_NBITS_SINGLE:
+ return 0x0;
+ case SPI_NBITS_DUAL:
+ return 0x1;
+ case SPI_NBITS_QUAD:
+ return 0x2;
+ }
+}
+
+static void mtk_spi_enable_transfer(struct spi_controller *host)
{
u32 cmd;
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
cmd = readl(mdata->base + SPI_CMD_REG);
if (mdata->state == MTK_SPI_IDLE)
@@ -566,10 +607,10 @@ static int mtk_spi_get_mult_delta(struct mtk_spi *mdata, u32 xfer_len)
return mult_delta;
}
-static void mtk_spi_update_mdata_len(struct spi_master *master)
+static void mtk_spi_update_mdata_len(struct spi_controller *host)
{
int mult_delta;
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
if (mdata->tx_sgl_len && mdata->rx_sgl_len) {
if (mdata->tx_sgl_len > mdata->rx_sgl_len) {
@@ -594,10 +635,10 @@ static void mtk_spi_update_mdata_len(struct spi_master *master)
}
}
-static void mtk_spi_setup_dma_addr(struct spi_master *master,
+static void mtk_spi_setup_dma_addr(struct spi_controller *host,
struct spi_transfer *xfer)
{
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
if (mdata->tx_sgl) {
writel((u32)(xfer->tx_dma & MTK_SPI_32BITS_MASK),
@@ -620,19 +661,19 @@ static void mtk_spi_setup_dma_addr(struct spi_master *master,
}
}
-static int mtk_spi_fifo_transfer(struct spi_master *master,
+static int mtk_spi_fifo_transfer(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
int cnt, remainder;
u32 reg_val;
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
mdata->cur_transfer = xfer;
mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len);
mdata->num_xfered = 0;
- mtk_spi_prepare_transfer(master, xfer->speed_hz);
- mtk_spi_setup_packet(master);
+ mtk_spi_prepare_transfer(host, xfer->speed_hz);
+ mtk_spi_setup_packet(host);
if (xfer->tx_buf) {
cnt = xfer->len / 4;
@@ -645,17 +686,17 @@ static int mtk_spi_fifo_transfer(struct spi_master *master,
}
}
- mtk_spi_enable_transfer(master);
+ mtk_spi_enable_transfer(host);
return 1;
}
-static int mtk_spi_dma_transfer(struct spi_master *master,
+static int mtk_spi_dma_transfer(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
int cmd;
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
mdata->tx_sgl = NULL;
mdata->rx_sgl = NULL;
@@ -664,7 +705,7 @@ static int mtk_spi_dma_transfer(struct spi_master *master,
mdata->cur_transfer = xfer;
mdata->num_xfered = 0;
- mtk_spi_prepare_transfer(master, xfer->speed_hz);
+ mtk_spi_prepare_transfer(host, xfer->speed_hz);
cmd = readl(mdata->base + SPI_CMD_REG);
if (xfer->tx_buf)
@@ -687,38 +728,44 @@ static int mtk_spi_dma_transfer(struct spi_master *master,
mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
}
- mtk_spi_update_mdata_len(master);
- mtk_spi_setup_packet(master);
- mtk_spi_setup_dma_addr(master, xfer);
- mtk_spi_enable_transfer(master);
+ mtk_spi_update_mdata_len(host);
+ mtk_spi_setup_packet(host);
+ mtk_spi_setup_dma_addr(host, xfer);
+ mtk_spi_enable_transfer(host);
return 1;
}
-static int mtk_spi_transfer_one(struct spi_master *master,
+static int mtk_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(spi->controller);
u32 reg_val = 0;
/* prepare xfer direction and duplex mode */
if (mdata->dev_comp->ipm_design) {
- if (!xfer->tx_buf || !xfer->rx_buf) {
+ if (xfer->tx_buf && xfer->rx_buf) {
+ reg_val &= ~SPI_CFG3_IPM_HALF_DUPLEX_EN;
+ } else if (xfer->tx_buf) {
+ reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_EN;
+ reg_val &= ~SPI_CFG3_IPM_HALF_DUPLEX_DIR;
+ reg_val |= mtk_spi_set_nbit(xfer->tx_nbits);
+ } else {
reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_EN;
- if (xfer->rx_buf)
- reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_DIR;
+ reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_DIR;
+ reg_val |= mtk_spi_set_nbit(xfer->rx_nbits);
}
writel(reg_val, mdata->base + SPI_CFG3_IPM_REG);
}
- if (master->can_dma(master, spi, xfer))
- return mtk_spi_dma_transfer(master, spi, xfer);
+ if (host->can_dma(host, spi, xfer))
+ return mtk_spi_dma_transfer(host, spi, xfer);
else
- return mtk_spi_fifo_transfer(master, spi, xfer);
+ return mtk_spi_fifo_transfer(host, spi, xfer);
}
-static bool mtk_spi_can_dma(struct spi_master *master,
+static bool mtk_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
@@ -730,7 +777,7 @@ static bool mtk_spi_can_dma(struct spi_master *master,
static int mtk_spi_setup(struct spi_device *spi)
{
- struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(spi->controller);
if (!spi->controller_data)
spi->controller_data = (void *)&mtk_default_chip_info;
@@ -742,85 +789,73 @@ static int mtk_spi_setup(struct spi_device *spi)
return 0;
}
-static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
+static irqreturn_t mtk_spi_interrupt_thread(int irq, void *dev_id)
{
u32 cmd, reg_val, cnt, remainder, len;
- struct spi_master *master = dev_id;
- struct mtk_spi *mdata = spi_master_get_devdata(master);
- struct spi_transfer *trans = mdata->cur_transfer;
-
- reg_val = readl(mdata->base + SPI_STATUS0_REG);
- if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
- mdata->state = MTK_SPI_PAUSED;
- else
- mdata->state = MTK_SPI_IDLE;
-
- /* SPI-MEM ops */
- if (mdata->use_spimem) {
- complete(&mdata->spimem_done);
- return IRQ_HANDLED;
- }
+ struct spi_controller *host = dev_id;
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
+ struct spi_transfer *xfer = mdata->cur_transfer;
- if (!master->can_dma(master, NULL, trans)) {
- if (trans->rx_buf) {
+ if (!host->can_dma(host, NULL, xfer)) {
+ if (xfer->rx_buf) {
cnt = mdata->xfer_len / 4;
ioread32_rep(mdata->base + SPI_RX_DATA_REG,
- trans->rx_buf + mdata->num_xfered, cnt);
+ xfer->rx_buf + mdata->num_xfered, cnt);
remainder = mdata->xfer_len % 4;
if (remainder > 0) {
reg_val = readl(mdata->base + SPI_RX_DATA_REG);
- memcpy(trans->rx_buf +
- mdata->num_xfered +
- (cnt * 4),
+ memcpy(xfer->rx_buf + (cnt * 4) + mdata->num_xfered,
&reg_val,
remainder);
}
}
mdata->num_xfered += mdata->xfer_len;
- if (mdata->num_xfered == trans->len) {
- spi_finalize_current_transfer(master);
+ if (mdata->num_xfered == xfer->len) {
+ spi_finalize_current_transfer(host);
return IRQ_HANDLED;
}
- len = trans->len - mdata->num_xfered;
+ len = xfer->len - mdata->num_xfered;
mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len);
- mtk_spi_setup_packet(master);
+ mtk_spi_setup_packet(host);
- cnt = mdata->xfer_len / 4;
- iowrite32_rep(mdata->base + SPI_TX_DATA_REG,
- trans->tx_buf + mdata->num_xfered, cnt);
+ if (xfer->tx_buf) {
+ cnt = mdata->xfer_len / 4;
+ iowrite32_rep(mdata->base + SPI_TX_DATA_REG,
+ xfer->tx_buf + mdata->num_xfered, cnt);
- remainder = mdata->xfer_len % 4;
- if (remainder > 0) {
- reg_val = 0;
- memcpy(&reg_val,
- trans->tx_buf + (cnt * 4) + mdata->num_xfered,
- remainder);
- writel(reg_val, mdata->base + SPI_TX_DATA_REG);
+ remainder = mdata->xfer_len % 4;
+ if (remainder > 0) {
+ reg_val = 0;
+ memcpy(&reg_val,
+ xfer->tx_buf + (cnt * 4) + mdata->num_xfered,
+ remainder);
+ writel(reg_val, mdata->base + SPI_TX_DATA_REG);
+ }
}
- mtk_spi_enable_transfer(master);
+ mtk_spi_enable_transfer(host);
return IRQ_HANDLED;
}
if (mdata->tx_sgl)
- trans->tx_dma += mdata->xfer_len;
+ xfer->tx_dma += mdata->xfer_len;
if (mdata->rx_sgl)
- trans->rx_dma += mdata->xfer_len;
+ xfer->rx_dma += mdata->xfer_len;
if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) {
mdata->tx_sgl = sg_next(mdata->tx_sgl);
if (mdata->tx_sgl) {
- trans->tx_dma = sg_dma_address(mdata->tx_sgl);
+ xfer->tx_dma = sg_dma_address(mdata->tx_sgl);
mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
}
}
if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) {
mdata->rx_sgl = sg_next(mdata->rx_sgl);
if (mdata->rx_sgl) {
- trans->rx_dma = sg_dma_address(mdata->rx_sgl);
+ xfer->rx_dma = sg_dma_address(mdata->rx_sgl);
mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
}
}
@@ -832,18 +867,39 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
cmd &= ~SPI_CMD_RX_DMA;
writel(cmd, mdata->base + SPI_CMD_REG);
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return IRQ_HANDLED;
}
- mtk_spi_update_mdata_len(master);
- mtk_spi_setup_packet(master);
- mtk_spi_setup_dma_addr(master, trans);
- mtk_spi_enable_transfer(master);
+ mtk_spi_update_mdata_len(host);
+ mtk_spi_setup_packet(host);
+ mtk_spi_setup_dma_addr(host, xfer);
+ mtk_spi_enable_transfer(host);
return IRQ_HANDLED;
}
+static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
+{
+ struct spi_controller *host = dev_id;
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
+ u32 reg_val;
+
+ reg_val = readl(mdata->base + SPI_STATUS0_REG);
+ if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
+ mdata->state = MTK_SPI_PAUSED;
+ else
+ mdata->state = MTK_SPI_IDLE;
+
+ /* SPI-MEM ops */
+ if (mdata->use_spimem) {
+ complete(&mdata->spimem_done);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_WAKE_THREAD;
+}
+
static int mtk_spi_mem_adjust_op_size(struct spi_mem *mem,
struct spi_mem_op *op)
{
@@ -884,10 +940,10 @@ static bool mtk_spi_mem_supports_op(struct spi_mem *mem,
return true;
}
-static void mtk_spi_mem_setup_dma_xfer(struct spi_master *master,
+static void mtk_spi_mem_setup_dma_xfer(struct spi_controller *host,
const struct spi_mem_op *op)
{
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
writel((u32)(mdata->tx_dma & MTK_SPI_32BITS_MASK),
mdata->base + SPI_TX_SRC_REG);
@@ -911,7 +967,7 @@ static void mtk_spi_mem_setup_dma_xfer(struct spi_master *master,
static int mtk_spi_transfer_wait(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct mtk_spi *mdata = spi_master_get_devdata(mem->spi->master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(mem->spi->controller);
/*
* For each byte we wait for 8 cycles of the SPI clock.
* Since speed is defined in Hz and we want milliseconds,
@@ -941,7 +997,7 @@ static int mtk_spi_transfer_wait(struct spi_mem *mem,
static int mtk_spi_mem_exec_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct mtk_spi *mdata = spi_master_get_devdata(mem->spi->master);
+ struct mtk_spi *mdata = spi_controller_get_devdata(mem->spi->controller);
u32 reg_val, nio, tx_size;
char *tx_tmp_buf, *rx_tmp_buf;
int ret = 0;
@@ -950,8 +1006,8 @@ static int mtk_spi_mem_exec_op(struct spi_mem *mem,
reinit_completion(&mdata->spimem_done);
mtk_spi_reset(mdata);
- mtk_spi_hw_init(mem->spi->master, mem->spi);
- mtk_spi_prepare_transfer(mem->spi->master, mem->spi->max_speed_hz);
+ mtk_spi_hw_init(mem->spi->controller, mem->spi);
+ mtk_spi_prepare_transfer(mem->spi->controller, op->max_freq);
reg_val = readl(mdata->base + SPI_CFG3_IPM_REG);
/* opcode byte len */
@@ -971,7 +1027,7 @@ static int mtk_spi_mem_exec_op(struct spi_mem *mem,
} else {
reg_val &= ~SPI_CFG3_IPM_NODATA_FLAG;
mdata->xfer_len = op->data.nbytes;
- mtk_spi_setup_packet(mem->spi->master);
+ mtk_spi_setup_packet(mem->spi->controller);
}
if (op->addr.nbytes || op->dummy.nbytes) {
@@ -1069,9 +1125,9 @@ static int mtk_spi_mem_exec_op(struct spi_mem *mem,
reg_val |= SPI_CMD_RX_DMA;
writel(reg_val, mdata->base + SPI_CMD_REG);
- mtk_spi_mem_setup_dma_xfer(mem->spi->master, op);
+ mtk_spi_mem_setup_dma_xfer(mem->spi->controller, op);
- mtk_spi_enable_transfer(mem->spi->master);
+ mtk_spi_enable_transfer(mem->spi->controller);
/* Wait for the interrupt. */
ret = mtk_spi_transfer_wait(mem, op);
@@ -1112,44 +1168,50 @@ static const struct spi_controller_mem_ops mtk_spi_mem_ops = {
.exec_op = mtk_spi_mem_exec_op,
};
+static const struct spi_controller_mem_caps mtk_spi_mem_caps = {
+ .per_op_freq = true,
+};
+
static int mtk_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct mtk_spi *mdata;
int i, irq, ret, addr_bits;
- master = devm_spi_alloc_master(dev, sizeof(*mdata));
- if (!master)
- return dev_err_probe(dev, -ENOMEM, "failed to alloc spi master\n");
+ host = devm_spi_alloc_host(dev, sizeof(*mdata));
+ if (!host)
+ return -ENOMEM;
- master->auto_runtime_pm = true;
- master->dev.of_node = dev->of_node;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ host->auto_runtime_pm = true;
+ host->dev.of_node = dev->of_node;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
- master->set_cs = mtk_spi_set_cs;
- master->prepare_message = mtk_spi_prepare_message;
- master->transfer_one = mtk_spi_transfer_one;
- master->can_dma = mtk_spi_can_dma;
- master->setup = mtk_spi_setup;
- master->set_cs_timing = mtk_spi_set_hw_cs_timing;
- master->use_gpio_descriptors = true;
+ host->set_cs = mtk_spi_set_cs;
+ host->prepare_message = mtk_spi_prepare_message;
+ host->unprepare_message = mtk_spi_unprepare_message;
+ host->transfer_one = mtk_spi_transfer_one;
+ host->can_dma = mtk_spi_can_dma;
+ host->setup = mtk_spi_setup;
+ host->set_cs_timing = mtk_spi_set_hw_cs_timing;
+ host->use_gpio_descriptors = true;
- mdata = spi_master_get_devdata(master);
+ mdata = spi_controller_get_devdata(host);
mdata->dev_comp = device_get_match_data(dev);
if (mdata->dev_comp->enhance_timing)
- master->mode_bits |= SPI_CS_HIGH;
+ host->mode_bits |= SPI_CS_HIGH;
if (mdata->dev_comp->must_tx)
- master->flags = SPI_MASTER_MUST_TX;
+ host->flags = SPI_CONTROLLER_MUST_TX;
if (mdata->dev_comp->ipm_design)
- master->mode_bits |= SPI_LOOP | SPI_RX_DUAL | SPI_TX_DUAL |
- SPI_RX_QUAD | SPI_TX_QUAD;
+ host->mode_bits |= SPI_LOOP | SPI_RX_DUAL | SPI_TX_DUAL |
+ SPI_RX_QUAD | SPI_TX_QUAD;
if (mdata->dev_comp->ipm_design) {
mdata->dev = dev;
- master->mem_ops = &mtk_spi_mem_ops;
+ host->mem_ops = &mtk_spi_mem_ops;
+ host->mem_caps = &mtk_spi_mem_caps;
init_completion(&mdata->spimem_done);
}
@@ -1176,7 +1238,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
}
}
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
mdata->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(mdata->base))
return PTR_ERR(mdata->base);
@@ -1234,13 +1296,15 @@ static int mtk_spi_probe(struct platform_device *pdev)
clk_disable_unprepare(mdata->spi_hclk);
}
+ cpu_latency_qos_add_request(&mdata->qos_request, PM_QOS_DEFAULT_VALUE);
+
if (mdata->dev_comp->need_pad_sel) {
- if (mdata->pad_num != master->num_chipselect)
+ if (mdata->pad_num != host->num_chipselect)
return dev_err_probe(dev, -EINVAL,
"pad_num does not match num_chipselect(%d != %d)\n",
- mdata->pad_num, master->num_chipselect);
+ mdata->pad_num, host->num_chipselect);
- if (!master->cs_gpiods && master->num_chipselect > 1)
+ if (!host->cs_gpiods && host->num_chipselect > 1)
return dev_err_probe(dev, -EINVAL,
"cs_gpios not specified and num_chipselect > 1\n");
}
@@ -1254,17 +1318,18 @@ static int mtk_spi_probe(struct platform_device *pdev)
dev_notice(dev, "SPI dma_set_mask(%d) failed, ret:%d\n",
addr_bits, ret);
- ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
- IRQF_TRIGGER_NONE, dev_name(dev), master);
+ ret = devm_request_threaded_irq(dev, irq, mtk_spi_interrupt,
+ mtk_spi_interrupt_thread,
+ IRQF_TRIGGER_NONE, dev_name(dev), host);
if (ret)
return dev_err_probe(dev, ret, "failed to register irq\n");
pm_runtime_enable(dev);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret) {
pm_runtime_disable(dev);
- return dev_err_probe(dev, ret, "failed to register master\n");
+ return dev_err_probe(dev, ret, "failed to register host\n");
}
return 0;
@@ -1272,10 +1337,11 @@ static int mtk_spi_probe(struct platform_device *pdev)
static void mtk_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
int ret;
+ cpu_latency_qos_remove_request(&mdata->qos_request);
if (mdata->use_spimem && !completion_done(&mdata->spimem_done))
complete(&mdata->spimem_done);
@@ -1304,10 +1370,10 @@ static void mtk_spi_remove(struct platform_device *pdev)
static int mtk_spi_suspend(struct device *dev)
{
int ret;
- struct spi_master *master = dev_get_drvdata(dev);
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -1316,14 +1382,18 @@ static int mtk_spi_suspend(struct device *dev)
clk_disable_unprepare(mdata->spi_hclk);
}
+ pinctrl_pm_select_sleep_state(dev);
+
return 0;
}
static int mtk_spi_resume(struct device *dev)
{
int ret;
- struct spi_master *master = dev_get_drvdata(dev);
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
+
+ pinctrl_pm_select_default_state(dev);
if (!pm_runtime_suspended(dev)) {
ret = clk_prepare_enable(mdata->spi_clk);
@@ -1340,7 +1410,7 @@ static int mtk_spi_resume(struct device *dev)
}
}
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret < 0) {
clk_disable_unprepare(mdata->spi_clk);
clk_disable_unprepare(mdata->spi_hclk);
@@ -1353,8 +1423,8 @@ static int mtk_spi_resume(struct device *dev)
#ifdef CONFIG_PM
static int mtk_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
if (mdata->dev_comp->no_need_unprepare) {
clk_disable(mdata->spi_clk);
@@ -1369,8 +1439,8 @@ static int mtk_spi_runtime_suspend(struct device *dev)
static int mtk_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mtk_spi *mdata = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mtk_spi *mdata = spi_controller_get_devdata(host);
int ret;
if (mdata->dev_comp->no_need_unprepare) {
@@ -1417,7 +1487,7 @@ static struct platform_driver mtk_spi_driver = {
.of_match_table = mtk_spi_of_match,
},
.probe = mtk_spi_probe,
- .remove_new = mtk_spi_remove,
+ .remove = mtk_spi_remove,
};
module_platform_driver(mtk_spi_driver);
diff --git a/drivers/spi/spi-mt7621.c b/drivers/spi/spi-mt7621.c
index 3e9d396b33bd..3770b8e096a4 100644
--- a/drivers/spi/spi-mt7621.c
+++ b/drivers/spi/spi-mt7621.c
@@ -14,7 +14,9 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
@@ -50,8 +52,10 @@
#define MT7621_CPOL BIT(4)
#define MT7621_LSB_FIRST BIT(3)
+#define MT7621_NATIVE_CS_COUNT 2
+
struct mt7621_spi {
- struct spi_controller *master;
+ struct spi_controller *host;
void __iomem *base;
unsigned int sys_freq;
unsigned int speed;
@@ -60,7 +64,7 @@ struct mt7621_spi {
static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi)
{
- return spi_controller_get_devdata(spi->master);
+ return spi_controller_get_devdata(spi->controller);
}
static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg)
@@ -73,26 +77,27 @@ static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val)
iowrite32(val, rs->base + reg);
}
-static void mt7621_spi_set_cs(struct spi_device *spi, int enable)
+static void mt7621_spi_set_native_cs(struct spi_device *spi, bool enable)
{
struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
int cs = spi_get_chipselect(spi, 0);
+ bool active = spi->mode & SPI_CS_HIGH ? enable : !enable;
u32 polar = 0;
- u32 master;
+ u32 host;
/*
* Select SPI device 7, enable "more buffer mode" and disable
* full-duplex (only half-duplex really works on this chip
* reliably)
*/
- master = mt7621_spi_read(rs, MT7621_SPI_MASTER);
- master |= MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE;
- master &= ~MASTER_FULL_DUPLEX;
- mt7621_spi_write(rs, MT7621_SPI_MASTER, master);
+ host = mt7621_spi_read(rs, MT7621_SPI_MASTER);
+ host |= MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE;
+ host &= ~MASTER_FULL_DUPLEX;
+ mt7621_spi_write(rs, MT7621_SPI_MASTER, host);
rs->pending_write = 0;
- if (enable)
+ if (active)
polar = BIT(cs);
mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
}
@@ -152,6 +157,23 @@ static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs)
return -ETIMEDOUT;
}
+static int mt7621_spi_prepare_message(struct spi_controller *host,
+ struct spi_message *m)
+{
+ struct mt7621_spi *rs = spi_controller_get_devdata(host);
+ struct spi_device *spi = m->spi;
+ unsigned int speed = spi->max_speed_hz;
+ struct spi_transfer *t = NULL;
+
+ mt7621_spi_wait_till_ready(rs);
+
+ list_for_each_entry(t, &m->transfers, transfer_list)
+ if (t->speed_hz < speed)
+ speed = t->speed_hz;
+
+ return mt7621_spi_prepare(spi, speed);
+}
+
static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs,
int rx_len, u8 *buf)
{
@@ -241,59 +263,30 @@ static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs,
}
rs->pending_write = len;
+ mt7621_spi_flush(rs);
}
-static int mt7621_spi_transfer_one_message(struct spi_controller *master,
- struct spi_message *m)
+static int mt7621_spi_transfer_one(struct spi_controller *host,
+ struct spi_device *spi,
+ struct spi_transfer *t)
{
- struct mt7621_spi *rs = spi_controller_get_devdata(master);
- struct spi_device *spi = m->spi;
- unsigned int speed = spi->max_speed_hz;
- struct spi_transfer *t = NULL;
- int status = 0;
-
- mt7621_spi_wait_till_ready(rs);
-
- list_for_each_entry(t, &m->transfers, transfer_list)
- if (t->speed_hz < speed)
- speed = t->speed_hz;
-
- if (mt7621_spi_prepare(spi, speed)) {
- status = -EIO;
- goto msg_done;
+ struct mt7621_spi *rs = spi_controller_get_devdata(host);
+
+ if ((t->rx_buf) && (t->tx_buf)) {
+ /*
+ * This controller will shift some extra data out
+ * of spi_opcode if (mosi_bit_cnt > 0) &&
+ * (cmd_bit_cnt == 0). So the claimed full-duplex
+ * support is broken since we have no way to read
+ * the MISO value during that bit.
+ */
+ return -EIO;
+ } else if (t->rx_buf) {
+ mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf);
+ } else if (t->tx_buf) {
+ mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf);
}
- /* Assert CS */
- mt7621_spi_set_cs(spi, 1);
-
- m->actual_length = 0;
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if ((t->rx_buf) && (t->tx_buf)) {
- /*
- * This controller will shift some extra data out
- * of spi_opcode if (mosi_bit_cnt > 0) &&
- * (cmd_bit_cnt == 0). So the claimed full-duplex
- * support is broken since we have no way to read
- * the MISO value during that bit.
- */
- status = -EIO;
- goto msg_done;
- } else if (t->rx_buf) {
- mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf);
- } else if (t->tx_buf) {
- mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf);
- }
- m->actual_length += t->len;
- }
-
- /* Flush data and deassert CS */
- mt7621_spi_flush(rs);
- mt7621_spi_set_cs(spi, 0);
-
-msg_done:
- m->status = status;
- spi_finalize_current_message(master);
-
return 0;
}
@@ -323,7 +316,7 @@ MODULE_DEVICE_TABLE(of, mt7621_spi_match);
static int mt7621_spi_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
- struct spi_controller *master;
+ struct spi_controller *host;
struct mt7621_spi *rs;
void __iomem *base;
struct clk *clk;
@@ -342,25 +335,29 @@ static int mt7621_spi_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
"unable to get SYS clock\n");
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*rs));
- if (!master) {
- dev_info(&pdev->dev, "master allocation failed\n");
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*rs));
+ if (!host) {
+ dev_info(&pdev->dev, "host allocation failed\n");
return -ENOMEM;
}
- master->mode_bits = SPI_LSB_FIRST;
- master->flags = SPI_CONTROLLER_HALF_DUPLEX;
- master->setup = mt7621_spi_setup;
- master->transfer_one_message = mt7621_spi_transfer_one_message;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->dev.of_node = pdev->dev.of_node;
- master->num_chipselect = 2;
-
- dev_set_drvdata(&pdev->dev, master);
-
- rs = spi_controller_get_devdata(master);
+ host->mode_bits = SPI_LSB_FIRST;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->setup = mt7621_spi_setup;
+ host->prepare_message = mt7621_spi_prepare_message;
+ host->set_cs = mt7621_spi_set_native_cs;
+ host->transfer_one = mt7621_spi_transfer_one;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->dev.of_node = pdev->dev.of_node;
+ host->max_native_cs = MT7621_NATIVE_CS_COUNT;
+ host->num_chipselect = MT7621_NATIVE_CS_COUNT;
+ host->use_gpio_descriptors = true;
+
+ dev_set_drvdata(&pdev->dev, host);
+
+ rs = spi_controller_get_devdata(host);
rs->base = base;
- rs->master = master;
+ rs->host = host;
rs->sys_freq = clk_get_rate(clk);
rs->pending_write = 0;
dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
@@ -371,7 +368,7 @@ static int mt7621_spi_probe(struct platform_device *pdev)
return ret;
}
- return devm_spi_register_controller(&pdev->dev, master);
+ return devm_spi_register_controller(&pdev->dev, host);
}
MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index baa7a5353987..5cc4632e13d7 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -13,7 +13,8 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
@@ -274,7 +275,7 @@ static void mtk_nor_adj_prg_size(struct spi_mem_op *op)
static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master);
+ struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->controller);
if (!op->data.nbytes)
return 0;
@@ -597,7 +598,7 @@ static int mtk_nor_spi_mem_prg(struct mtk_nor *sp, const struct spi_mem_op *op)
static int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master);
+ struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->controller);
int ret;
if ((op->data.nbytes == 0) ||
@@ -638,7 +639,7 @@ static int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
static int mtk_nor_setup(struct spi_device *spi)
{
- struct mtk_nor *sp = spi_controller_get_devdata(spi->master);
+ struct mtk_nor *sp = spi_controller_get_devdata(spi->controller);
if (spi->max_speed_hz && (spi->max_speed_hz < sp->spi_freq)) {
dev_err(&spi->dev, "spi clock should be %u Hz.\n",
@@ -650,10 +651,10 @@ static int mtk_nor_setup(struct spi_device *spi)
return 0;
}
-static int mtk_nor_transfer_one_message(struct spi_controller *master,
+static int mtk_nor_transfer_one_message(struct spi_controller *host,
struct spi_message *m)
{
- struct mtk_nor *sp = spi_controller_get_devdata(master);
+ struct mtk_nor *sp = spi_controller_get_devdata(host);
struct spi_transfer *t = NULL;
unsigned long trx_len = 0;
int stat = 0;
@@ -695,7 +696,7 @@ static int mtk_nor_transfer_one_message(struct spi_controller *master,
m->actual_length = trx_len;
msg_done:
m->status = stat;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return 0;
}
@@ -843,7 +844,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
return ret;
}
- ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*sp));
if (!ctlr) {
dev_err(&pdev->dev, "failed to allocate spi controller\n");
return -ENOMEM;
@@ -917,7 +918,6 @@ static int mtk_nor_probe(struct platform_device *pdev)
if (ret < 0)
goto err_probe;
- pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
dev_info(&pdev->dev, "spi frequency: %d Hz\n", sp->spi_freq);
@@ -997,7 +997,7 @@ static struct platform_driver mtk_nor_driver = {
.pm = &mtk_nor_pm_ops,
},
.probe = mtk_nor_probe,
- .remove_new = mtk_nor_remove,
+ .remove = mtk_nor_remove,
};
module_platform_driver(mtk_nor_driver);
diff --git a/drivers/spi/spi-mtk-snfi.c b/drivers/spi/spi-mtk-snfi.c
index bed8317cd205..ae38c244e258 100644
--- a/drivers/spi/spi-mtk-snfi.c
+++ b/drivers/spi/spi-mtk-snfi.c
@@ -76,7 +76,8 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/mtd/nand-ecc-mtk.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
@@ -775,7 +776,7 @@ static int mtk_snand_ecc_finish_io_req(struct nand_device *nand,
return snf->ecc_stats.failed ? -EBADMSG : snf->ecc_stats.bitflips;
}
-static struct nand_ecc_engine_ops mtk_snfi_ecc_engine_ops = {
+static const struct nand_ecc_engine_ops mtk_snfi_ecc_engine_ops = {
.init_ctx = mtk_snand_ecc_init_ctx,
.cleanup_ctx = mtk_snand_ecc_cleanup_ctx,
.prepare_io_req = mtk_snand_ecc_prepare_io_req,
@@ -1138,7 +1139,6 @@ static int mtk_snand_write_page_cache(struct mtk_snand *snf,
// Prepare for custom write interrupt
nfi_write32(snf, NFI_INTR_EN, NFI_IRQ_INTR_EN | NFI_IRQ_CUS_PG);
reinit_completion(&snf->op_done);
- ;
// Trigger NFI into custom mode
nfi_write16(snf, NFI_CMD, NFI_CMD_DUMMY_WRITE);
@@ -1186,7 +1186,7 @@ cleanup:
/**
* mtk_snand_is_page_ops() - check if the op is a controller supported page op.
- * @op spi-mem op to check
+ * @op: spi-mem op to check
*
* Check whether op can be executed with read_from_cache or program_load
* mode in the controller.
@@ -1254,7 +1254,7 @@ static bool mtk_snand_supports_op(struct spi_mem *mem,
static int mtk_snand_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct mtk_snand *ms = spi_controller_get_devdata(mem->spi->master);
+ struct mtk_snand *ms = spi_controller_get_devdata(mem->spi->controller);
// page ops transfer size must be exactly ((sector_size + spare_size) *
// nsectors). Limit the op size if the caller requests more than that.
// exec_op will read more than needed and discard the leftover if the
@@ -1281,11 +1281,8 @@ static int mtk_snand_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
static int mtk_snand_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct mtk_snand *ms = spi_controller_get_devdata(mem->spi->master);
+ struct mtk_snand *ms = spi_controller_get_devdata(mem->spi->controller);
- dev_dbg(ms->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode,
- op->addr.val, op->addr.buswidth, op->addr.nbytes,
- op->data.buswidth, op->data.nbytes);
if (mtk_snand_is_page_ops(op)) {
if (op->data.dir == SPI_MEM_DATA_IN)
return mtk_snand_read_page_cache(ms, op);
@@ -1331,42 +1328,6 @@ static const struct of_device_id mtk_snand_ids[] = {
MODULE_DEVICE_TABLE(of, mtk_snand_ids);
-static int mtk_snand_enable_clk(struct mtk_snand *ms)
-{
- int ret;
-
- ret = clk_prepare_enable(ms->nfi_clk);
- if (ret) {
- dev_err(ms->dev, "unable to enable nfi clk\n");
- return ret;
- }
- ret = clk_prepare_enable(ms->pad_clk);
- if (ret) {
- dev_err(ms->dev, "unable to enable pad clk\n");
- goto err1;
- }
- ret = clk_prepare_enable(ms->nfi_hclk);
- if (ret) {
- dev_err(ms->dev, "unable to enable nfi hclk\n");
- goto err2;
- }
-
- return 0;
-
-err2:
- clk_disable_unprepare(ms->pad_clk);
-err1:
- clk_disable_unprepare(ms->nfi_clk);
- return ret;
-}
-
-static void mtk_snand_disable_clk(struct mtk_snand *ms)
-{
- clk_disable_unprepare(ms->nfi_hclk);
- clk_disable_unprepare(ms->pad_clk);
- clk_disable_unprepare(ms->nfi_clk);
-}
-
static int mtk_snand_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -1381,7 +1342,7 @@ static int mtk_snand_probe(struct platform_device *pdev)
if (!dev_id)
return -EINVAL;
- ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*ms));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*ms));
if (!ctlr)
return -ENOMEM;
platform_set_drvdata(pdev, ctlr);
@@ -1405,49 +1366,45 @@ static int mtk_snand_probe(struct platform_device *pdev)
ms->dev = &pdev->dev;
- ms->nfi_clk = devm_clk_get(&pdev->dev, "nfi_clk");
+ ms->nfi_clk = devm_clk_get_enabled(&pdev->dev, "nfi_clk");
if (IS_ERR(ms->nfi_clk)) {
ret = PTR_ERR(ms->nfi_clk);
dev_err(&pdev->dev, "unable to get nfi_clk, err = %d\n", ret);
goto release_ecc;
}
- ms->pad_clk = devm_clk_get(&pdev->dev, "pad_clk");
+ ms->pad_clk = devm_clk_get_enabled(&pdev->dev, "pad_clk");
if (IS_ERR(ms->pad_clk)) {
ret = PTR_ERR(ms->pad_clk);
dev_err(&pdev->dev, "unable to get pad_clk, err = %d\n", ret);
goto release_ecc;
}
- ms->nfi_hclk = devm_clk_get_optional(&pdev->dev, "nfi_hclk");
+ ms->nfi_hclk = devm_clk_get_optional_enabled(&pdev->dev, "nfi_hclk");
if (IS_ERR(ms->nfi_hclk)) {
ret = PTR_ERR(ms->nfi_hclk);
dev_err(&pdev->dev, "unable to get nfi_hclk, err = %d\n", ret);
goto release_ecc;
}
- ret = mtk_snand_enable_clk(ms);
- if (ret)
- goto release_ecc;
-
init_completion(&ms->op_done);
ms->irq = platform_get_irq(pdev, 0);
if (ms->irq < 0) {
ret = ms->irq;
- goto disable_clk;
+ goto release_ecc;
}
ret = devm_request_irq(ms->dev, ms->irq, mtk_snand_irq, 0x0,
"mtk-snand", ms);
if (ret) {
dev_err(ms->dev, "failed to request snfi irq\n");
- goto disable_clk;
+ goto release_ecc;
}
ret = dma_set_mask(ms->dev, DMA_BIT_MASK(32));
if (ret) {
dev_err(ms->dev, "failed to set dma mask\n");
- goto disable_clk;
+ goto release_ecc;
}
// switch to SNFI mode
@@ -1471,7 +1428,7 @@ static int mtk_snand_probe(struct platform_device *pdev)
ret = mtk_snand_setup_pagefmt(ms, SZ_2K, SZ_64);
if (ret) {
dev_err(ms->dev, "failed to set initial page format\n");
- goto disable_clk;
+ goto release_ecc;
}
// setup ECC engine
@@ -1483,7 +1440,7 @@ static int mtk_snand_probe(struct platform_device *pdev)
ret = nand_ecc_register_on_host_hw_engine(&ms->ecc_eng);
if (ret) {
dev_err(&pdev->dev, "failed to register ecc engine.\n");
- goto disable_clk;
+ goto release_ecc;
}
ctlr->num_chipselect = 1;
@@ -1495,12 +1452,10 @@ static int mtk_snand_probe(struct platform_device *pdev)
ret = spi_register_controller(ctlr);
if (ret) {
dev_err(&pdev->dev, "spi_register_controller failed.\n");
- goto disable_clk;
+ goto release_ecc;
}
return 0;
-disable_clk:
- mtk_snand_disable_clk(ms);
release_ecc:
mtk_ecc_release(ms->ecc);
return ret;
@@ -1512,14 +1467,13 @@ static void mtk_snand_remove(struct platform_device *pdev)
struct mtk_snand *ms = spi_controller_get_devdata(ctlr);
spi_unregister_controller(ctlr);
- mtk_snand_disable_clk(ms);
mtk_ecc_release(ms->ecc);
kfree(ms->buf);
}
static struct platform_driver mtk_snand_driver = {
.probe = mtk_snand_probe,
- .remove_new = mtk_snand_remove,
+ .remove = mtk_snand_remove,
.driver = {
.name = "mtk-snand",
.of_match_table = mtk_snand_ids,
diff --git a/drivers/spi/spi-mux.c b/drivers/spi/spi-mux.c
index fa8c1f740c70..0eb35c4e3987 100644
--- a/drivers/spi/spi-mux.c
+++ b/drivers/spi/spi-mux.c
@@ -68,7 +68,7 @@ static int spi_mux_select(struct spi_device *spi)
priv->current_cs = spi_get_chipselect(spi, 0);
- return 0;
+ return spi_setup(priv->spi);
}
static int spi_mux_setup(struct spi_device *spi)
@@ -129,7 +129,7 @@ static int spi_mux_probe(struct spi_device *spi)
struct spi_mux_priv *priv;
int ret;
- ctlr = spi_alloc_master(&spi->dev, sizeof(*priv));
+ ctlr = spi_alloc_host(&spi->dev, sizeof(*priv));
if (!ctlr)
return -ENOMEM;
@@ -156,12 +156,14 @@ static int spi_mux_probe(struct spi_device *spi)
/* supported modes are the same as our parent's */
ctlr->mode_bits = spi->controller->mode_bits;
ctlr->flags = spi->controller->flags;
+ ctlr->bits_per_word_mask = spi->controller->bits_per_word_mask;
ctlr->transfer_one_message = spi_mux_transfer_one_message;
ctlr->setup = spi_mux_setup;
ctlr->num_chipselect = mux_control_states(priv->mux);
ctlr->bus_num = -1;
ctlr->dev.of_node = spi->dev.of_node;
ctlr->must_async = true;
+ ctlr->defer_optimize_message = true;
ret = devm_spi_register_controller(&spi->dev, ctlr);
if (ret)
diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 00617fd4b2c3..eeaea6a5e310 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -294,7 +294,8 @@ static void mxic_spi_hw_init(struct mxic_spi *mxic)
mxic->regs + HC_CFG);
}
-static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
+static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags,
+ bool swap16)
{
int nio = 1;
@@ -305,6 +306,11 @@ static u32 mxic_spi_prep_hc_cfg(struct spi_device *spi, u32 flags)
else if (spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL))
nio = 2;
+ if (swap16)
+ flags &= ~HC_CFG_DATA_PASS;
+ else
+ flags |= HC_CFG_DATA_PASS;
+
return flags | HC_CFG_NIO(nio) |
HC_CFG_TYPE(spi_get_chipselect(spi, 0), HC_CFG_TYPE_SPI_NOR) |
HC_CFG_SLV_ACT(spi_get_chipselect(spi, 0)) | HC_CFG_IDLE_SIO_LVL(1);
@@ -390,14 +396,15 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf,
static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
- struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
+ struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
int ret;
u32 sts;
if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
return -EINVAL;
- writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
+ writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16),
+ mxic->regs + HC_CFG);
writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
mxic->regs + LRD_CFG);
@@ -434,14 +441,15 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len,
const void *buf)
{
- struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
+ struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
u32 sts;
int ret;
if (WARN_ON(offs + desc->info.offset + len > U32_MAX))
return -EINVAL;
- writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0), mxic->regs + HC_CFG);
+ writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.swap16),
+ mxic->regs + HC_CFG);
writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len),
mxic->regs + LWR_CFG);
@@ -493,10 +501,10 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
- struct mxic_spi *mxic = spi_master_get_devdata(desc->mem->spi->master);
+ struct mxic_spi *mxic = spi_controller_get_devdata(desc->mem->spi->controller);
if (!mxic->linear.map)
- return -EINVAL;
+ return -EOPNOTSUPP;
if (desc->info.offset + desc->info.length > U32_MAX)
return -EINVAL;
@@ -510,15 +518,15 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
static int mxic_spi_mem_exec_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master);
+ struct mxic_spi *mxic = spi_controller_get_devdata(mem->spi->controller);
int i, ret;
u8 addr[8], cmd[2];
- ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz);
+ ret = mxic_spi_set_freq(mxic, op->max_freq);
if (ret)
return ret;
- writel(mxic_spi_prep_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN),
+ writel(mxic_spi_prep_hc_cfg(mem->spi, HC_CFG_MAN_CS_EN, op->data.swap16),
mxic->regs + HC_CFG);
writel(HC_EN_BIT, mxic->regs + HC_EN);
@@ -573,11 +581,13 @@ static const struct spi_controller_mem_ops mxic_spi_mem_ops = {
static const struct spi_controller_mem_caps mxic_spi_mem_caps = {
.dtr = true,
.ecc = true,
+ .swap16 = true,
+ .per_op_freq = true,
};
static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
{
- struct mxic_spi *mxic = spi_master_get_devdata(spi->master);
+ struct mxic_spi *mxic = spi_controller_get_devdata(spi->controller);
if (!lvl) {
writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_EN,
@@ -592,11 +602,11 @@ static void mxic_spi_set_cs(struct spi_device *spi, bool lvl)
}
}
-static int mxic_spi_transfer_one(struct spi_master *master,
+static int mxic_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct mxic_spi *mxic = spi_master_get_devdata(master);
+ struct mxic_spi *mxic = spi_controller_get_devdata(host);
unsigned int busw = OP_BUSW_1;
int ret;
@@ -632,7 +642,7 @@ static int mxic_spi_transfer_one(struct spi_master *master,
if (ret)
return ret;
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return 0;
}
@@ -640,7 +650,7 @@ static int mxic_spi_transfer_one(struct spi_master *master,
/* ECC wrapper */
static int mxic_spi_mem_ecc_init_ctx(struct nand_device *nand)
{
- struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+ const struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
struct mxic_spi *mxic = nand->ecc.engine->priv;
mxic->ecc.use_pipelined_conf = true;
@@ -650,7 +660,7 @@ static int mxic_spi_mem_ecc_init_ctx(struct nand_device *nand)
static void mxic_spi_mem_ecc_cleanup_ctx(struct nand_device *nand)
{
- struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+ const struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
struct mxic_spi *mxic = nand->ecc.engine->priv;
mxic->ecc.use_pipelined_conf = false;
@@ -661,7 +671,7 @@ static void mxic_spi_mem_ecc_cleanup_ctx(struct nand_device *nand)
static int mxic_spi_mem_ecc_prepare_io_req(struct nand_device *nand,
struct nand_page_io_req *req)
{
- struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+ const struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
return ops->prepare_io_req(nand, req);
}
@@ -669,12 +679,12 @@ static int mxic_spi_mem_ecc_prepare_io_req(struct nand_device *nand,
static int mxic_spi_mem_ecc_finish_io_req(struct nand_device *nand,
struct nand_page_io_req *req)
{
- struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
+ const struct nand_ecc_engine_ops *ops = mxic_ecc_get_pipelined_ops();
return ops->finish_io_req(nand, req);
}
-static struct nand_ecc_engine_ops mxic_spi_mem_ecc_engine_pipelined_ops = {
+static const struct nand_ecc_engine_ops mxic_spi_mem_ecc_engine_pipelined_ops = {
.init_ctx = mxic_spi_mem_ecc_init_ctx,
.cleanup_ctx = mxic_spi_mem_ecc_cleanup_ctx,
.prepare_io_req = mxic_spi_mem_ecc_prepare_io_req,
@@ -713,8 +723,8 @@ static int mxic_spi_mem_ecc_probe(struct platform_device *pdev,
static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mxic_spi *mxic = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mxic_spi *mxic = spi_controller_get_devdata(host);
mxic_spi_clk_disable(mxic);
clk_disable_unprepare(mxic->ps_clk);
@@ -724,8 +734,8 @@ static int __maybe_unused mxic_spi_runtime_suspend(struct device *dev)
static int __maybe_unused mxic_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mxic_spi *mxic = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mxic_spi *mxic = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(mxic->ps_clk);
@@ -744,21 +754,21 @@ static const struct dev_pm_ops mxic_spi_dev_pm_ops = {
static int mxic_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *res;
struct mxic_spi *mxic;
int ret;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(struct mxic_spi));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(struct mxic_spi));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- mxic = spi_master_get_devdata(master);
+ mxic = spi_controller_get_devdata(host);
mxic->dev = &pdev->dev;
- master->dev.of_node = pdev->dev.of_node;
+ host->dev.of_node = pdev->dev.of_node;
mxic->ps_clk = devm_clk_get(&pdev->dev, "ps_clk");
if (IS_ERR(mxic->ps_clk))
@@ -786,19 +796,19 @@ static int mxic_spi_probe(struct platform_device *pdev)
}
pm_runtime_enable(&pdev->dev);
- master->auto_runtime_pm = true;
+ host->auto_runtime_pm = true;
- master->num_chipselect = 1;
- master->mem_ops = &mxic_spi_mem_ops;
- master->mem_caps = &mxic_spi_mem_caps;
+ host->num_chipselect = 1;
+ host->mem_ops = &mxic_spi_mem_ops;
+ host->mem_caps = &mxic_spi_mem_caps;
- master->set_cs = mxic_spi_set_cs;
- master->transfer_one = mxic_spi_transfer_one;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->mode_bits = SPI_CPOL | SPI_CPHA |
- SPI_RX_DUAL | SPI_TX_DUAL |
- SPI_RX_QUAD | SPI_TX_QUAD |
- SPI_RX_OCTAL | SPI_TX_OCTAL;
+ host->set_cs = mxic_spi_set_cs;
+ host->transfer_one = mxic_spi_transfer_one;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->mode_bits = SPI_CPOL | SPI_CPHA |
+ SPI_RX_DUAL | SPI_TX_DUAL |
+ SPI_RX_QUAD | SPI_TX_QUAD |
+ SPI_RX_OCTAL | SPI_TX_OCTAL;
mxic_spi_hw_init(mxic);
@@ -808,9 +818,9 @@ static int mxic_spi_probe(struct platform_device *pdev)
return ret;
}
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret) {
- dev_err(&pdev->dev, "spi_register_master failed\n");
+ dev_err(&pdev->dev, "spi_register_controller failed\n");
pm_runtime_disable(&pdev->dev);
mxic_spi_mem_ecc_remove(mxic);
}
@@ -820,12 +830,12 @@ static int mxic_spi_probe(struct platform_device *pdev)
static void mxic_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct mxic_spi *mxic = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct mxic_spi *mxic = spi_controller_get_devdata(host);
pm_runtime_disable(&pdev->dev);
mxic_spi_mem_ecc_remove(mxic);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
}
static const struct of_device_id mxic_spi_of_ids[] = {
@@ -836,7 +846,7 @@ MODULE_DEVICE_TABLE(of, mxic_spi_of_ids);
static struct platform_driver mxic_spi_driver = {
.probe = mxic_spi_probe,
- .remove_new = mxic_spi_remove,
+ .remove = mxic_spi_remove,
.driver = {
.name = "mxic-spi",
.of_match_table = mxic_spi_of_ids,
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 963a53dd680b..0ebcbdb1b1f7 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
//
-// Freescale MXS SPI master driver
+// Freescale MXS SPI host driver
//
// Copyright 2012 DENX Software Engineering, GmbH.
// Copyright 2012 Freescale Semiconductor, Inc.
@@ -39,6 +39,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/mxs-spi.h>
#include <trace/events/spi.h>
+#include <linux/dma/mxs-dma.h>
#define DRIVER_NAME "mxs-spi"
@@ -63,7 +64,7 @@ struct mxs_spi {
static int mxs_spi_setup_transfer(struct spi_device *dev,
const struct spi_transfer *t)
{
- struct mxs_spi *spi = spi_master_get_devdata(dev->master);
+ struct mxs_spi *spi = spi_controller_get_devdata(dev->controller);
struct mxs_ssp *ssp = &spi->ssp;
const unsigned int hz = min(dev->max_speed_hz, t->speed_hz);
@@ -252,7 +253,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
desc = dmaengine_prep_slave_sg(ssp->dmach,
&dma_xfer[sg_count].sg, 1,
(flags & TXRX_WRITE) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ DMA_PREP_INTERRUPT | MXS_DMA_CTRL_WAIT4END);
if (!desc) {
dev_err(ssp->dev,
@@ -357,10 +358,10 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi,
return -ETIMEDOUT;
}
-static int mxs_spi_transfer_one(struct spi_master *master,
+static int mxs_spi_transfer_one(struct spi_controller *host,
struct spi_message *m)
{
- struct mxs_spi *spi = spi_master_get_devdata(master);
+ struct mxs_spi *spi = spi_controller_get_devdata(host);
struct mxs_ssp *ssp = &spi->ssp;
struct spi_transfer *t;
unsigned int flag;
@@ -380,12 +381,14 @@ static int mxs_spi_transfer_one(struct spi_master *master,
if (status)
break;
+ t->effective_speed_hz = ssp->clk_rate;
+
/* De-assert on last transfer, inverted by cs_change flag */
flag = (&t->transfer_list == m->transfers.prev) ^ t->cs_change ?
TXRX_DEASSERT_CS : 0;
/*
- * Small blocks can be transfered via PIO.
+ * Small blocks can be transferred via PIO.
* Measured by empiric means:
*
* dd if=/dev/mtdblock0 of=/dev/null bs=1024k count=1
@@ -432,15 +435,15 @@ static int mxs_spi_transfer_one(struct spi_master *master,
}
m->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return status;
}
static int mxs_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mxs_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mxs_spi *spi = spi_controller_get_devdata(host);
struct mxs_ssp *ssp = &spi->ssp;
int ret;
@@ -460,8 +463,8 @@ static int mxs_spi_runtime_suspend(struct device *dev)
static int mxs_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct mxs_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct mxs_spi *spi = spi_controller_get_devdata(host);
struct mxs_ssp *ssp = &spi->ssp;
int ret;
@@ -476,12 +479,12 @@ static int mxs_spi_runtime_resume(struct device *dev)
return ret;
}
-static int __maybe_unused mxs_spi_suspend(struct device *dev)
+static int mxs_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -491,9 +494,9 @@ static int __maybe_unused mxs_spi_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mxs_spi_resume(struct device *dev)
+static int mxs_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
if (!pm_runtime_suspended(dev))
@@ -503,7 +506,7 @@ static int __maybe_unused mxs_spi_resume(struct device *dev)
if (ret)
return ret;
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret < 0 && !pm_runtime_suspended(dev))
mxs_spi_runtime_suspend(dev);
@@ -511,9 +514,8 @@ static int __maybe_unused mxs_spi_resume(struct device *dev)
}
static const struct dev_pm_ops mxs_spi_pm = {
- SET_RUNTIME_PM_OPS(mxs_spi_runtime_suspend,
- mxs_spi_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(mxs_spi_suspend, mxs_spi_resume)
+ RUNTIME_PM_OPS(mxs_spi_runtime_suspend, mxs_spi_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(mxs_spi_suspend, mxs_spi_resume)
};
static const struct of_device_id mxs_spi_dt_ids[] = {
@@ -528,7 +530,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
const struct of_device_id *of_id =
of_match_device(mxs_spi_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
- struct spi_master *master;
+ struct spi_controller *host;
struct mxs_spi *spi;
struct mxs_ssp *ssp;
struct clk *clk;
@@ -561,21 +563,21 @@ static int mxs_spi_probe(struct platform_device *pdev)
if (ret)
clk_freq = clk_freq_default;
- master = spi_alloc_master(&pdev->dev, sizeof(*spi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*spi));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- master->transfer_one_message = mxs_spi_transfer_one;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->mode_bits = SPI_CPOL | SPI_CPHA;
- master->num_chipselect = 3;
- master->dev.of_node = np;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->auto_runtime_pm = true;
+ host->transfer_one_message = mxs_spi_transfer_one;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->mode_bits = SPI_CPOL | SPI_CPHA;
+ host->num_chipselect = 3;
+ host->dev.of_node = np;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->auto_runtime_pm = true;
- spi = spi_master_get_devdata(master);
+ spi = spi_controller_get_devdata(host);
ssp = &spi->ssp;
ssp->dev = &pdev->dev;
ssp->clk = clk;
@@ -587,13 +589,13 @@ static int mxs_spi_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq_err, mxs_ssp_irq_handler, 0,
dev_name(&pdev->dev), ssp);
if (ret)
- goto out_master_free;
+ goto out_host_free;
ssp->dmach = dma_request_chan(&pdev->dev, "rx-tx");
if (IS_ERR(ssp->dmach)) {
dev_err(ssp->dev, "Failed to request DMA\n");
ret = PTR_ERR(ssp->dmach);
- goto out_master_free;
+ goto out_host_free;
}
pm_runtime_enable(ssp->dev);
@@ -617,9 +619,9 @@ static int mxs_spi_probe(struct platform_device *pdev)
if (ret)
goto out_pm_runtime_put;
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret);
+ dev_err(&pdev->dev, "Cannot register SPI host, %d\n", ret);
goto out_pm_runtime_put;
}
@@ -633,19 +635,19 @@ out_pm_runtime_disable:
pm_runtime_disable(ssp->dev);
out_dma_release:
dma_release_channel(ssp->dmach);
-out_master_free:
- spi_master_put(master);
+out_host_free:
+ spi_controller_put(host);
return ret;
}
static void mxs_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct mxs_spi *spi;
struct mxs_ssp *ssp;
- master = platform_get_drvdata(pdev);
- spi = spi_master_get_devdata(master);
+ host = platform_get_drvdata(pdev);
+ spi = spi_controller_get_devdata(host);
ssp = &spi->ssp;
pm_runtime_disable(&pdev->dev);
@@ -657,17 +659,17 @@ static void mxs_spi_remove(struct platform_device *pdev)
static struct platform_driver mxs_spi_driver = {
.probe = mxs_spi_probe,
- .remove_new = mxs_spi_remove,
+ .remove = mxs_spi_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = mxs_spi_dt_ids,
- .pm = &mxs_spi_pm,
+ .pm = pm_ptr(&mxs_spi_pm),
},
};
module_platform_driver(mxs_spi_driver);
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
-MODULE_DESCRIPTION("MXS SPI master driver");
+MODULE_DESCRIPTION("MXS SPI host driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mxs-spi");
diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c
index eb353561509a..cccd17f24775 100644
--- a/drivers/spi/spi-npcm-fiu.c
+++ b/drivers/spi/spi-npcm-fiu.c
@@ -12,7 +12,8 @@
#include <linux/io.h>
#include <linux/vmalloc.h>
#include <linux/regmap.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/minmax.h>
#include <linux/spi/spi-mem.h>
#include <linux/mfd/syscon.h>
@@ -287,7 +288,7 @@ static ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(desc->mem->spi->master);
+ spi_controller_get_devdata(desc->mem->spi->controller);
struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
void __iomem *src = (void __iomem *)(chip->flash_region_mapped_ptr +
offs);
@@ -314,7 +315,7 @@ static ssize_t npcm_fiu_direct_write(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, const void *buf)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(desc->mem->spi->master);
+ spi_controller_get_devdata(desc->mem->spi->controller);
struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
void __iomem *dst = (void __iomem *)(chip->flash_region_mapped_ptr +
offs);
@@ -335,7 +336,7 @@ static int npcm_fiu_uma_read(struct spi_mem *mem,
bool is_address_size, u8 *data, u32 data_size)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
u32 uma_cfg = BIT(10);
u32 data_reg[4];
int ret;
@@ -353,8 +354,9 @@ static int npcm_fiu_uma_read(struct spi_mem *mem,
uma_cfg |= ilog2(op->cmd.buswidth);
uma_cfg |= ilog2(op->addr.buswidth)
<< NPCM_FIU_UMA_CFG_ADBPCK_SHIFT;
- uma_cfg |= ilog2(op->dummy.buswidth)
- << NPCM_FIU_UMA_CFG_DBPCK_SHIFT;
+ if (op->dummy.nbytes)
+ uma_cfg |= ilog2(op->dummy.buswidth)
+ << NPCM_FIU_UMA_CFG_DBPCK_SHIFT;
uma_cfg |= ilog2(op->data.buswidth)
<< NPCM_FIU_UMA_CFG_RDBPCK_SHIFT;
uma_cfg |= op->dummy.nbytes << NPCM_FIU_UMA_CFG_DBSIZ_SHIFT;
@@ -390,7 +392,7 @@ static int npcm_fiu_uma_write(struct spi_mem *mem,
bool is_address_size, u8 *data, u32 data_size)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
u32 uma_cfg = BIT(10);
u32 data_reg[4] = {0};
u32 val;
@@ -439,7 +441,7 @@ static int npcm_fiu_manualwrite(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
u8 *data = (u8 *)op->data.buf.out;
u32 num_data_chunks;
u32 remain_data;
@@ -497,10 +499,7 @@ static int npcm_fiu_read(struct spi_mem *mem, const struct spi_mem_op *op)
do {
addr = ((u32)op->addr.val + i);
- if (currlen < 16)
- readlen = currlen;
- else
- readlen = 16;
+ readlen = min_t(int, currlen, 16);
buf_ptr = data + i;
ret = npcm_fiu_uma_read(mem, op, addr, true, buf_ptr,
@@ -544,18 +543,13 @@ static void npcm_fiux_set_direct_rd(struct npcm_fiu_spi *fiu)
static int npcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(mem->spi->master);
+ spi_controller_get_devdata(mem->spi->controller);
struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(mem->spi, 0)];
int ret = 0;
u8 *buf;
- dev_dbg(fiu->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
- op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
- op->dummy.buswidth, op->data.buswidth, op->addr.val,
- op->data.nbytes);
-
if (fiu->spix_mode || op->addr.nbytes > 4)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (fiu->clkrate != chip->clkrate) {
ret = clk_set_rate(fiu->clk, chip->clkrate);
@@ -604,7 +598,7 @@ static int npcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
struct npcm_fiu_spi *fiu =
- spi_controller_get_devdata(desc->mem->spi->master);
+ spi_controller_get_devdata(desc->mem->spi->controller);
struct npcm_fiu_chip *chip = &fiu->chip[spi_get_chipselect(desc->mem->spi, 0)];
struct regmap *gcr_regmap;
@@ -665,7 +659,7 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
static int npcm_fiu_setup(struct spi_device *spi)
{
- struct spi_controller *ctrl = spi->master;
+ struct spi_controller *ctrl = spi->controller;
struct npcm_fiu_spi *fiu = spi_controller_get_devdata(ctrl);
struct npcm_fiu_chip *chip;
@@ -699,9 +693,9 @@ static int npcm_fiu_probe(struct platform_device *pdev)
struct spi_controller *ctrl;
struct npcm_fiu_spi *fiu;
void __iomem *regbase;
- int id, ret;
+ int id;
- ctrl = devm_spi_alloc_master(dev, sizeof(*fiu));
+ ctrl = devm_spi_alloc_host(dev, sizeof(*fiu));
if (!ctrl)
return -ENOMEM;
@@ -737,7 +731,7 @@ static int npcm_fiu_probe(struct platform_device *pdev)
fiu->res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"memory");
- fiu->clk = devm_clk_get(dev, NULL);
+ fiu->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(fiu->clk))
return PTR_ERR(fiu->clk);
@@ -745,7 +739,6 @@ static int npcm_fiu_probe(struct platform_device *pdev)
"nuvoton,spix-mode");
platform_set_drvdata(pdev, fiu);
- clk_prepare_enable(fiu->clk);
ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD
| SPI_TX_DUAL | SPI_TX_QUAD;
@@ -755,30 +748,23 @@ static int npcm_fiu_probe(struct platform_device *pdev)
ctrl->num_chipselect = fiu->info->max_cs;
ctrl->dev.of_node = dev->of_node;
- ret = devm_spi_register_master(dev, ctrl);
- if (ret)
- clk_disable_unprepare(fiu->clk);
-
- return ret;
+ return devm_spi_register_controller(dev, ctrl);
}
static void npcm_fiu_remove(struct platform_device *pdev)
{
- struct npcm_fiu_spi *fiu = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(fiu->clk);
}
MODULE_DEVICE_TABLE(of, npcm_fiu_dt_ids);
static struct platform_driver npcm_fiu_driver = {
.driver = {
- .name = "NPCM-FIU",
- .bus = &platform_bus_type,
+ .name = "NPCM-FIU",
+ .bus = &platform_bus_type,
.of_match_table = npcm_fiu_dt_ids,
},
- .probe = npcm_fiu_probe,
- .remove_new = npcm_fiu_remove,
+ .probe = npcm_fiu_probe,
+ .remove = npcm_fiu_remove,
};
module_platform_driver(npcm_fiu_driver);
diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c
index 64585c2a25c5..98b6479b961c 100644
--- a/drivers/spi/spi-npcm-pspi.c
+++ b/drivers/spi/spi-npcm-pspi.c
@@ -12,7 +12,7 @@
#include <linux/spi/spi.h>
#include <linux/reset.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
@@ -20,7 +20,7 @@
struct npcm_pspi {
struct completion xfer_done;
struct reset_control *reset;
- struct spi_master *master;
+ struct spi_controller *host;
unsigned int tx_bytes;
unsigned int rx_bytes;
void __iomem *base;
@@ -101,7 +101,7 @@ static inline void npcm_pspi_disable(struct npcm_pspi *priv)
static void npcm_pspi_set_mode(struct spi_device *spi)
{
- struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
+ struct npcm_pspi *priv = spi_controller_get_devdata(spi->controller);
u16 regtemp;
u16 mode_val;
@@ -159,7 +159,7 @@ static void npcm_pspi_set_baudrate(struct npcm_pspi *priv, unsigned int speed)
static void npcm_pspi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
+ struct npcm_pspi *priv = spi_controller_get_devdata(spi->controller);
priv->tx_buf = t->tx_buf;
priv->rx_buf = t->rx_buf;
@@ -245,11 +245,11 @@ static void npcm_pspi_recv(struct npcm_pspi *priv)
}
}
-static int npcm_pspi_transfer_one(struct spi_master *master,
+static int npcm_pspi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct npcm_pspi *priv = spi_master_get_devdata(master);
+ struct npcm_pspi *priv = spi_controller_get_devdata(host);
int status;
npcm_pspi_setup_transfer(spi, t);
@@ -266,18 +266,18 @@ static int npcm_pspi_transfer_one(struct spi_master *master,
return 0;
}
-static int npcm_pspi_prepare_transfer_hardware(struct spi_master *master)
+static int npcm_pspi_prepare_transfer_hardware(struct spi_controller *host)
{
- struct npcm_pspi *priv = spi_master_get_devdata(master);
+ struct npcm_pspi *priv = spi_controller_get_devdata(host);
npcm_pspi_irq_enable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
return 0;
}
-static int npcm_pspi_unprepare_transfer_hardware(struct spi_master *master)
+static int npcm_pspi_unprepare_transfer_hardware(struct spi_controller *host)
{
- struct npcm_pspi *priv = spi_master_get_devdata(master);
+ struct npcm_pspi *priv = spi_controller_get_devdata(host);
npcm_pspi_irq_disable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
@@ -340,37 +340,37 @@ static irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
static int npcm_pspi_probe(struct platform_device *pdev)
{
struct npcm_pspi *priv;
- struct spi_master *master;
+ struct spi_controller *host;
unsigned long clk_hz;
int irq;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*priv));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*priv));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- priv = spi_master_get_devdata(master);
- priv->master = master;
+ priv = spi_controller_get_devdata(host);
+ priv->host = host;
priv->is_save_param = false;
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base)) {
ret = PTR_ERR(priv->base);
- goto out_master_put;
+ goto out_host_put;
}
priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(priv->clk);
- goto out_master_put;
+ goto out_host_put;
}
ret = clk_prepare_enable(priv->clk);
if (ret)
- goto out_master_put;
+ goto out_host_put;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -398,42 +398,42 @@ static int npcm_pspi_probe(struct platform_device *pdev)
clk_hz = clk_get_rate(priv->clk);
- master->max_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MIN_CLK_DIVIDER);
- master->min_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MAX_CLK_DIVIDER);
- master->mode_bits = SPI_CPHA | SPI_CPOL;
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = -1;
- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
- master->transfer_one = npcm_pspi_transfer_one;
- master->prepare_transfer_hardware =
+ host->max_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MIN_CLK_DIVIDER);
+ host->min_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MAX_CLK_DIVIDER);
+ host->mode_bits = SPI_CPHA | SPI_CPOL;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = -1;
+ host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ host->transfer_one = npcm_pspi_transfer_one;
+ host->prepare_transfer_hardware =
npcm_pspi_prepare_transfer_hardware;
- master->unprepare_transfer_hardware =
+ host->unprepare_transfer_hardware =
npcm_pspi_unprepare_transfer_hardware;
- master->use_gpio_descriptors = true;
+ host->use_gpio_descriptors = true;
/* set to default clock rate */
npcm_pspi_set_baudrate(priv, NPCM_PSPI_DEFAULT_CLK);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret)
goto out_disable_clk;
- pr_info("NPCM Peripheral SPI %d probed\n", master->bus_num);
+ pr_info("NPCM Peripheral SPI %d probed\n", host->bus_num);
return 0;
out_disable_clk:
clk_disable_unprepare(priv->clk);
-out_master_put:
- spi_master_put(master);
+out_host_put:
+ spi_controller_put(host);
return ret;
}
static void npcm_pspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct npcm_pspi *priv = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct npcm_pspi *priv = spi_controller_get_devdata(host);
npcm_pspi_reset_hw(priv);
clk_disable_unprepare(priv->clk);
@@ -452,7 +452,7 @@ static struct platform_driver npcm_pspi_driver = {
.of_match_table = npcm_pspi_match,
},
.probe = npcm_pspi_probe,
- .remove_new = npcm_pspi_remove,
+ .remove = npcm_pspi_remove,
};
module_platform_driver(npcm_pspi_driver);
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 544017655787..50a7e4916a60 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -47,8 +47,9 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
@@ -58,12 +59,8 @@
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
-/*
- * The driver only uses one single LUT entry, that is updated on
- * each call of exec_op(). Index 0 is preset at boot with a basic
- * read operation, so let's use the last entry (31).
- */
-#define SEQID_LUT 31
+/* runtime pm timeout */
+#define FSPI_RPM_TIMEOUT 50 /* 50ms */
/* Registers used by the driver */
#define FSPI_MCR0 0x00
@@ -264,9 +261,6 @@
#define FSPI_TFDR 0x180
#define FSPI_LUT_BASE 0x200
-#define FSPI_LUT_OFFSET (SEQID_LUT * 4 * 4)
-#define FSPI_LUT_REG(idx) \
- (FSPI_LUT_BASE + FSPI_LUT_OFFSET + (idx) * 4)
/* register map end */
@@ -336,12 +330,15 @@
/* Access flash memory using IP bus only */
#define FSPI_QUIRK_USE_IP_ONLY BIT(0)
+/* Disable DTR */
+#define FSPI_QUIRK_DISABLE_DTR BIT(1)
struct nxp_fspi_devtype_data {
unsigned int rxfifo;
unsigned int txfifo;
unsigned int ahb_buf_size;
unsigned int quirks;
+ unsigned int lut_num;
bool little_endian;
};
@@ -349,7 +346,8 @@ static struct nxp_fspi_devtype_data lx2160a_data = {
.rxfifo = SZ_512, /* (64 * 64 bits) */
.txfifo = SZ_1K, /* (128 * 64 bits) */
.ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
- .quirks = 0,
+ .quirks = FSPI_QUIRK_DISABLE_DTR,
+ .lut_num = 32,
.little_endian = true, /* little-endian */
};
@@ -358,6 +356,7 @@ static struct nxp_fspi_devtype_data imx8mm_data = {
.txfifo = SZ_1K, /* (128 * 64 bits) */
.ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
.quirks = 0,
+ .lut_num = 32,
.little_endian = true, /* little-endian */
};
@@ -366,6 +365,7 @@ static struct nxp_fspi_devtype_data imx8qxp_data = {
.txfifo = SZ_1K, /* (128 * 64 bits) */
.ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
.quirks = 0,
+ .lut_num = 32,
.little_endian = true, /* little-endian */
};
@@ -374,6 +374,16 @@ static struct nxp_fspi_devtype_data imx8dxl_data = {
.txfifo = SZ_1K, /* (128 * 64 bits) */
.ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
.quirks = FSPI_QUIRK_USE_IP_ONLY,
+ .lut_num = 32,
+ .little_endian = true, /* little-endian */
+};
+
+static struct nxp_fspi_devtype_data imx8ulp_data = {
+ .rxfifo = SZ_512, /* (64 * 64 bits) */
+ .txfifo = SZ_1K, /* (128 * 64 bits) */
+ .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */
+ .quirks = 0,
+ .lut_num = 16,
.little_endian = true, /* little-endian */
};
@@ -391,6 +401,13 @@ struct nxp_fspi {
struct mutex lock;
struct pm_qos_request pm_qos_req;
int selected;
+#define FSPI_NEED_INIT BIT(0)
+#define FSPI_DTR_MODE BIT(1)
+ int flags;
+ /* save the previous operation clock rate */
+ unsigned long pre_op_rate;
+ /* the max clock rate fspi output to device */
+ unsigned long max_rate;
};
static inline int needs_ip_only(struct nxp_fspi *f)
@@ -452,7 +469,7 @@ static int nxp_fspi_check_buswidth(struct nxp_fspi *f, u8 width)
static bool nxp_fspi_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master);
+ struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->controller);
int ret;
ret = nxp_fspi_check_buswidth(f, op->cmd.buswidth);
@@ -521,7 +538,7 @@ static int fspi_readl_poll_tout(struct nxp_fspi *f, void __iomem *base,
}
/*
- * If the slave device content being changed by Write/Erase, need to
+ * If the target device content being changed by Write/Erase, need to
* invalidate the AHB buffer. This can be achieved by doing the reset
* of controller after setting MCR0[SWRESET] bit.
*/
@@ -545,14 +562,25 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
void __iomem *base = f->iobase;
u32 lutval[4] = {};
int lutidx = 1, i;
+ u32 lut_offset = (f->devtype_data->lut_num - 1) * 4 * 4;
+ u32 target_lut_reg;
/* cmd */
- lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth),
- op->cmd.opcode);
+ if (op->cmd.dtr) {
+ lutval[0] |= LUT_DEF(0, LUT_CMD_DDR, LUT_PAD(op->cmd.buswidth),
+ op->cmd.opcode >> 8);
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_CMD_DDR,
+ LUT_PAD(op->cmd.buswidth),
+ op->cmd.opcode & 0xFF);
+ lutidx++;
+ } else {
+ lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth),
+ op->cmd.opcode);
+ }
/* addr bytes */
if (op->addr.nbytes) {
- lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_ADDR,
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, op->addr.dtr ? LUT_ADDR_DDR : LUT_ADDR,
LUT_PAD(op->addr.buswidth),
op->addr.nbytes * 8);
lutidx++;
@@ -560,7 +588,7 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
/* dummy bytes, if needed */
if (op->dummy.nbytes) {
- lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_DUMMY,
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, op->dummy.dtr ? LUT_DUMMY_DDR : LUT_DUMMY,
/*
* Due to FlexSPI controller limitation number of PAD for dummy
* buswidth needs to be programmed as equal to data buswidth.
@@ -575,7 +603,8 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
if (op->data.nbytes) {
lutval[lutidx / 2] |= LUT_DEF(lutidx,
op->data.dir == SPI_MEM_DATA_IN ?
- LUT_NXP_READ : LUT_NXP_WRITE,
+ (op->data.dtr ? LUT_READ_DDR : LUT_NXP_READ) :
+ (op->data.dtr ? LUT_WRITE_DDR : LUT_NXP_WRITE),
LUT_PAD(op->data.buswidth),
0);
lutidx++;
@@ -589,10 +618,12 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f,
fspi_writel(f, FSPI_LCKER_UNLOCK, f->iobase + FSPI_LCKCR);
/* fill LUT */
- for (i = 0; i < ARRAY_SIZE(lutval); i++)
- fspi_writel(f, lutval[i], base + FSPI_LUT_REG(i));
+ for (i = 0; i < ARRAY_SIZE(lutval); i++) {
+ target_lut_reg = FSPI_LUT_BASE + lut_offset + i * 4;
+ fspi_writel(f, lutval[i], base + target_lut_reg);
+ }
- dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x], size: 0x%08x\n",
+ dev_dbg(f->dev, "CMD[%02x] lutval[0:%08x 1:%08x 2:%08x 3:%08x], size: 0x%08x\n",
op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], op->data.nbytes);
/* lock LUT */
@@ -620,15 +651,52 @@ static int nxp_fspi_clk_prep_enable(struct nxp_fspi *f)
return 0;
}
-static int nxp_fspi_clk_disable_unprep(struct nxp_fspi *f)
+static void nxp_fspi_clk_disable_unprep(struct nxp_fspi *f)
{
if (is_acpi_node(dev_fwnode(f->dev)))
- return 0;
+ return;
clk_disable_unprepare(f->clk);
clk_disable_unprepare(f->clk_en);
- return 0;
+ return;
+}
+
+/*
+ * Sample Clock source selection for Flash Reading
+ * Four modes defined by fspi:
+ * mode 0: Dummy Read strobe generated by FlexSPI Controller
+ * and loopback internally
+ * mode 1: Dummy Read strobe generated by FlexSPI Controller
+ * and loopback from DQS pad
+ * mode 2: Reserved
+ * mode 3: Flash provided Read strobe and input from DQS pad
+ *
+ * fspi default use mode 0 after reset
+ */
+static void nxp_fspi_select_rx_sample_clk_source(struct nxp_fspi *f,
+ bool op_is_dtr)
+{
+ u32 reg;
+
+ /*
+ * For 8D-8D-8D mode, need to use mode 3 (Flash provided Read
+ * strobe and input from DQS pad), otherwise read operaton may
+ * meet issue.
+ * This mode require flash device connect the DQS pad on board.
+ * For other modes, still use mode 0, keep align with before.
+ * spi_nor_suspend will disable 8D-8D-8D mode, also need to
+ * change the mode back to mode 0.
+ */
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ if (op_is_dtr) {
+ reg |= FSPI_MCR0_RXCLKSRC(3);
+ f->max_rate = 166000000;
+ } else { /*select mode 0 */
+ reg &= ~FSPI_MCR0_RXCLKSRC(3);
+ f->max_rate = 66000000;
+ }
+ fspi_writel(f, reg, f->iobase + FSPI_MCR0);
}
static void nxp_fspi_dll_calibration(struct nxp_fspi *f)
@@ -658,11 +726,28 @@ static void nxp_fspi_dll_calibration(struct nxp_fspi *f)
0, POLL_TOUT, true);
if (ret)
dev_warn(f->dev, "DLL lock failed, please fix it!\n");
+
+ /*
+ * For ERR050272, DLL lock status bit is not accurate,
+ * wait for 4us more as a workaround.
+ */
+ udelay(4);
+}
+
+/*
+ * Config the DLL register to default value, enable the target clock delay
+ * line delay cell override mode, and use 1 fixed delay cell in DLL delay
+ * chain, this is the suggested setting when clock rate < 100MHz.
+ */
+static void nxp_fspi_dll_override(struct nxp_fspi *f)
+{
+ fspi_writel(f, FSPI_DLLACR_OVRDEN, f->iobase + FSPI_DLLACR);
+ fspi_writel(f, FSPI_DLLBCR_OVRDEN, f->iobase + FSPI_DLLBCR);
}
/*
* In FlexSPI controller, flash access is based on value of FSPI_FLSHXXCR0
- * register and start base address of the slave device.
+ * register and start base address of the target device.
*
* (Higher address)
* -------- <-- FLSHB2CR0
@@ -681,15 +766,15 @@ static void nxp_fspi_dll_calibration(struct nxp_fspi *f)
*
*
* Start base address defines the starting address range for given CS and
- * FSPI_FLSHXXCR0 defines the size of the slave device connected at given CS.
+ * FSPI_FLSHXXCR0 defines the size of the target device connected at given CS.
*
* But, different targets are having different combinations of number of CS,
* some targets only have single CS or two CS covering controller's full
* memory mapped space area.
* Thus, implementation is being done as independent of the size and number
- * of the connected slave device.
+ * of the connected target device.
* Assign controller memory mapped space size as the size to the connected
- * slave device.
+ * target device.
* Mark FLSHxxCR0 as zero initially and then assign value only to the selected
* chip-select Flash configuration register.
*
@@ -698,17 +783,27 @@ static void nxp_fspi_dll_calibration(struct nxp_fspi *f)
* Value for rest of the CS FLSHxxCR0 register would be zero.
*
*/
-static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi)
+static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
+ const struct spi_mem_op *op)
{
- unsigned long rate = spi->max_speed_hz;
+ /* flexspi only support one DTR mode: 8D-8D-8D */
+ bool op_is_dtr = op->cmd.dtr && op->addr.dtr && op->dummy.dtr && op->data.dtr;
+ unsigned long rate = op->max_freq;
int ret;
uint64_t size_kb;
/*
- * Return, if previously selected slave device is same as current
- * requested slave device.
+ * Return when following condition all meet,
+ * 1, if previously selected target device is same as current
+ * requested target device.
+ * 2, the DTR or STR mode do not change.
+ * 3, previous operation max rate equals current one.
+ *
+ * For other case, need to re-config.
*/
- if (f->selected == spi_get_chipselect(spi, 0))
+ if ((f->selected == spi_get_chipselect(spi, 0)) &&
+ (!!(f->flags & FSPI_DTR_MODE) == op_is_dtr) &&
+ (f->pre_op_rate == op->max_freq))
return;
/* Reset FLSHxxCR0 registers */
@@ -723,7 +818,20 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi)
fspi_writel(f, size_kb, f->iobase + FSPI_FLSHA1CR0 +
4 * spi_get_chipselect(spi, 0));
- dev_dbg(f->dev, "Slave device [CS:%x] selected\n", spi_get_chipselect(spi, 0));
+ dev_dbg(f->dev, "Target device [CS:%x] selected\n", spi_get_chipselect(spi, 0));
+
+ nxp_fspi_select_rx_sample_clk_source(f, op_is_dtr);
+ rate = min(f->max_rate, op->max_freq);
+
+ if (op_is_dtr) {
+ f->flags |= FSPI_DTR_MODE;
+ /* For DTR mode, flexspi will default div 2 and output to device.
+ * so here to config the root clock to 2 * device rate.
+ */
+ rate = rate * 2;
+ } else {
+ f->flags &= ~FSPI_DTR_MODE;
+ }
nxp_fspi_clk_disable_unprep(f);
@@ -741,6 +849,10 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi)
*/
if (rate > 100000000)
nxp_fspi_dll_calibration(f);
+ else
+ nxp_fspi_dll_override(f);
+
+ f->pre_op_rate = op->max_freq;
f->selected = spi_get_chipselect(spi, 0);
}
@@ -757,10 +869,9 @@ static int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op)
iounmap(f->ahb_addr);
f->memmap_start = start;
- f->memmap_len = len > NXP_FSPI_MIN_IOMAP ?
- len : NXP_FSPI_MIN_IOMAP;
+ f->memmap_len = max_t(u32, len, NXP_FSPI_MIN_IOMAP);
- f->ahb_addr = ioremap_wc(f->memmap_phy + f->memmap_start,
+ f->ahb_addr = ioremap(f->memmap_phy + f->memmap_start,
f->memmap_len);
if (!f->ahb_addr) {
@@ -806,14 +917,15 @@ static void nxp_fspi_fill_txfifo(struct nxp_fspi *f,
if (i < op->data.nbytes) {
u32 data = 0;
int j;
+ int remaining = op->data.nbytes - i;
/* Wait for TXFIFO empty */
ret = fspi_readl_poll_tout(f, f->iobase + FSPI_INTR,
FSPI_INTR_IPTXWE, 0,
POLL_TOUT, true);
WARN_ON(ret);
- for (j = 0; j < ALIGN(op->data.nbytes - i, 4); j += 4) {
- memcpy(&data, buf + i + j, 4);
+ for (j = 0; j < ALIGN(remaining, 4); j += 4) {
+ memcpy(&data, buf + i + j, min_t(int, 4, remaining - j));
fspi_writel(f, data, base + FSPI_TFDR + j);
}
fspi_writel(f, FSPI_INTR_IPTXWE, base + FSPI_INTR);
@@ -876,7 +988,7 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op)
void __iomem *base = f->iobase;
int seqnum = 0;
int err = 0;
- u32 reg;
+ u32 reg, seqid_lut;
reg = fspi_readl(f, base + FSPI_IPRXFCR);
/* invalid RXFIFO first */
@@ -892,8 +1004,9 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op)
* the LUT at each exec_op() call. And also specify the DATA
* length, since it's has not been specified in the LUT.
*/
+ seqid_lut = f->devtype_data->lut_num - 1;
fspi_writel(f, op->data.nbytes |
- (SEQID_LUT << FSPI_IPCR1_SEQID_SHIFT) |
+ (seqid_lut << FSPI_IPCR1_SEQID_SHIFT) |
(seqnum << FSPI_IPCR1_SEQNUM_SHIFT),
base + FSPI_IPCR1);
@@ -913,17 +1026,23 @@ static int nxp_fspi_do_op(struct nxp_fspi *f, const struct spi_mem_op *op)
static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master);
+ struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->controller);
int err = 0;
- mutex_lock(&f->lock);
+ guard(mutex)(&f->lock);
+
+ err = pm_runtime_get_sync(f->dev);
+ if (err < 0) {
+ dev_err(f->dev, "Failed to enable clock %d\n", __LINE__);
+ return err;
+ }
/* Wait for controller being ready. */
err = fspi_readl_poll_tout(f, f->iobase + FSPI_STS0,
FSPI_STS0_ARB_IDLE, 1, POLL_TOUT, true);
WARN_ON(err);
- nxp_fspi_select_mem(f, mem->spi);
+ nxp_fspi_select_mem(f, mem->spi, op);
nxp_fspi_prepare_lut(f, op);
/*
@@ -946,14 +1065,14 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
/* Invalidate the data in the AHB buffer. */
nxp_fspi_invalid(f);
- mutex_unlock(&f->lock);
+ pm_runtime_put_autosuspend(f->dev);
return err;
}
static int nxp_fspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master);
+ struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->controller);
if (op->data.dir == SPI_MEM_DATA_OUT) {
if (op->data.nbytes > f->devtype_data->txfifo)
@@ -1017,7 +1136,7 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
{
void __iomem *base = f->iobase;
int ret, i;
- u32 reg;
+ u32 reg, seqid_lut;
/* disable and unprepare clock to avoid glitch pass to controller */
nxp_fspi_clk_disable_unprep(f);
@@ -1049,13 +1168,7 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
/* Disable the module */
fspi_writel(f, FSPI_MCR0_MDIS, base + FSPI_MCR0);
- /*
- * Config the DLL register to default value, enable the slave clock delay
- * line delay cell override mode, and use 1 fixed delay cell in DLL delay
- * chain, this is the suggested setting when clock rate < 100MHz.
- */
- fspi_writel(f, FSPI_DLLACR_OVRDEN, base + FSPI_DLLACR);
- fspi_writel(f, FSPI_DLLBCR_OVRDEN, base + FSPI_DLLBCR);
+ nxp_fspi_dll_override(f);
/* enable module */
fspi_writel(f, FSPI_MCR0_AHB_TIMEOUT(0xFF) |
@@ -1063,7 +1176,7 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
base + FSPI_MCR0);
/*
- * Disable same device enable bit and configure all slave devices
+ * Disable same device enable bit and configure all target devices
* independently.
*/
reg = fspi_readl(f, f->iobase + FSPI_MCR2);
@@ -1085,11 +1198,24 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
fspi_writel(f, FSPI_AHBCR_PREF_EN | FSPI_AHBCR_RDADDROPT,
base + FSPI_AHBCR);
+ /* Reset the FLSHxCR1 registers. */
+ reg = FSPI_FLSHXCR1_TCSH(0x3) | FSPI_FLSHXCR1_TCSS(0x3);
+ fspi_writel(f, reg, base + FSPI_FLSHA1CR1);
+ fspi_writel(f, reg, base + FSPI_FLSHA2CR1);
+ fspi_writel(f, reg, base + FSPI_FLSHB1CR1);
+ fspi_writel(f, reg, base + FSPI_FLSHB2CR1);
+
+ /*
+ * The driver only uses one single LUT entry, that is updated on
+ * each call of exec_op(). Index 0 is preset at boot with a basic
+ * read operation, so let's use the last entry.
+ */
+ seqid_lut = f->devtype_data->lut_num - 1;
/* AHB Read - Set lut sequence ID for all CS. */
- fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA1CR2);
- fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA2CR2);
- fspi_writel(f, SEQID_LUT, base + FSPI_FLSHB1CR2);
- fspi_writel(f, SEQID_LUT, base + FSPI_FLSHB2CR2);
+ fspi_writel(f, seqid_lut, base + FSPI_FLSHA1CR2);
+ fspi_writel(f, seqid_lut, base + FSPI_FLSHA2CR2);
+ fspi_writel(f, seqid_lut, base + FSPI_FLSHB1CR2);
+ fspi_writel(f, seqid_lut, base + FSPI_FLSHB2CR2);
f->selected = -1;
@@ -1101,7 +1227,7 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
static const char *nxp_fspi_get_name(struct spi_mem *mem)
{
- struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->master);
+ struct nxp_fspi *f = spi_controller_get_devdata(mem->spi->controller);
struct device *dev = &mem->spi->dev;
const char *name;
@@ -1128,17 +1254,46 @@ static const struct spi_controller_mem_ops nxp_fspi_mem_ops = {
.get_name = nxp_fspi_get_name,
};
+static const struct spi_controller_mem_caps nxp_fspi_mem_caps = {
+ .dtr = true,
+ .swap16 = false,
+ .per_op_freq = true,
+};
+
+static const struct spi_controller_mem_caps nxp_fspi_mem_caps_disable_dtr = {
+ .dtr = false,
+ .per_op_freq = true,
+};
+
+static void nxp_fspi_cleanup(void *data)
+{
+ struct nxp_fspi *f = data;
+
+ /* enable clock first since there is register access */
+ pm_runtime_get_sync(f->dev);
+
+ /* disable the hardware */
+ fspi_writel(f, FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
+
+ pm_runtime_disable(f->dev);
+ pm_runtime_put_noidle(f->dev);
+ nxp_fspi_clk_disable_unprep(f);
+
+ if (f->ahb_addr)
+ iounmap(f->ahb_addr);
+}
+
static int nxp_fspi_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
struct resource *res;
struct nxp_fspi *f;
- int ret;
+ int ret, irq;
u32 reg;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*f));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*f));
if (!ctlr)
return -ENOMEM;
@@ -1148,144 +1303,152 @@ static int nxp_fspi_probe(struct platform_device *pdev)
f = spi_controller_get_devdata(ctlr);
f->dev = dev;
f->devtype_data = (struct nxp_fspi_devtype_data *)device_get_match_data(dev);
- if (!f->devtype_data) {
- ret = -ENODEV;
- goto err_put_ctrl;
- }
+ if (!f->devtype_data)
+ return -ENODEV;
platform_set_drvdata(pdev, f);
/* find the resources - configuration register address space */
- if (is_acpi_node(dev_fwnode(f->dev)))
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (is_acpi_node(fwnode))
+ f->iobase = devm_platform_ioremap_resource(pdev, 0);
else
- res = platform_get_resource_byname(pdev,
- IORESOURCE_MEM, "fspi_base");
-
- f->iobase = devm_ioremap_resource(dev, res);
- if (IS_ERR(f->iobase)) {
- ret = PTR_ERR(f->iobase);
- goto err_put_ctrl;
- }
+ f->iobase = devm_platform_ioremap_resource_byname(pdev, "fspi_base");
+ if (IS_ERR(f->iobase))
+ return PTR_ERR(f->iobase);
/* find the resources - controller memory mapped space */
- if (is_acpi_node(dev_fwnode(f->dev)))
+ if (is_acpi_node(fwnode))
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
else
res = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "fspi_mmap");
-
- if (!res) {
- ret = -ENODEV;
- goto err_put_ctrl;
- }
+ if (!res)
+ return -ENODEV;
/* assign memory mapped starting address and mapped size. */
f->memmap_phy = res->start;
f->memmap_phy_size = resource_size(res);
/* find the clocks */
- if (dev_of_node(&pdev->dev)) {
+ if (is_of_node(fwnode)) {
f->clk_en = devm_clk_get(dev, "fspi_en");
- if (IS_ERR(f->clk_en)) {
- ret = PTR_ERR(f->clk_en);
- goto err_put_ctrl;
- }
+ if (IS_ERR(f->clk_en))
+ return PTR_ERR(f->clk_en);
f->clk = devm_clk_get(dev, "fspi");
- if (IS_ERR(f->clk)) {
- ret = PTR_ERR(f->clk);
- goto err_put_ctrl;
- }
-
- ret = nxp_fspi_clk_prep_enable(f);
- if (ret) {
- dev_err(dev, "can not enable the clock\n");
- goto err_put_ctrl;
- }
+ if (IS_ERR(f->clk))
+ return PTR_ERR(f->clk);
}
+ /* find the irq */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get irq source");
+
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, FSPI_RPM_TIMEOUT);
+ pm_runtime_use_autosuspend(dev);
+
+ /* enable clock */
+ ret = pm_runtime_get_sync(f->dev);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to enable clock");
+
/* Clear potential interrupts */
reg = fspi_readl(f, f->iobase + FSPI_INTR);
if (reg)
fspi_writel(f, reg, f->iobase + FSPI_INTR);
- /* find the irq */
- ret = platform_get_irq(pdev, 0);
+ nxp_fspi_default_setup(f);
+
+ ret = pm_runtime_put_sync(dev);
if (ret < 0)
- goto err_disable_clk;
+ return dev_err_probe(dev, ret, "Failed to disable clock");
- ret = devm_request_irq(dev, ret,
+ ret = devm_request_irq(dev, irq,
nxp_fspi_irq_handler, 0, pdev->name, f);
- if (ret) {
- dev_err(dev, "failed to request irq: %d\n", ret);
- goto err_disable_clk;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request irq\n");
- mutex_init(&f->lock);
+ ret = devm_mutex_init(dev, &f->lock);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to initialize lock\n");
ctlr->bus_num = -1;
ctlr->num_chipselect = NXP_FSPI_MAX_CHIPSELECT;
ctlr->mem_ops = &nxp_fspi_mem_ops;
- nxp_fspi_default_setup(f);
+ if (f->devtype_data->quirks & FSPI_QUIRK_DISABLE_DTR)
+ ctlr->mem_caps = &nxp_fspi_mem_caps_disable_dtr;
+ else
+ ctlr->mem_caps = &nxp_fspi_mem_caps;
- ctlr->dev.of_node = np;
+ device_set_node(&ctlr->dev, fwnode);
- ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ ret = devm_add_action_or_reset(dev, nxp_fspi_cleanup, f);
if (ret)
- goto err_destroy_mutex;
+ return ret;
- return 0;
+ return devm_spi_register_controller(&pdev->dev, ctlr);
+}
-err_destroy_mutex:
- mutex_destroy(&f->lock);
+static int nxp_fspi_runtime_suspend(struct device *dev)
+{
+ struct nxp_fspi *f = dev_get_drvdata(dev);
-err_disable_clk:
nxp_fspi_clk_disable_unprep(f);
-err_put_ctrl:
- spi_controller_put(ctlr);
-
- dev_err(dev, "NXP FSPI probe failed\n");
- return ret;
+ return 0;
}
-static void nxp_fspi_remove(struct platform_device *pdev)
+static int nxp_fspi_runtime_resume(struct device *dev)
{
- struct nxp_fspi *f = platform_get_drvdata(pdev);
-
- /* disable the hardware */
- fspi_writel(f, FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
+ struct nxp_fspi *f = dev_get_drvdata(dev);
+ int ret;
- nxp_fspi_clk_disable_unprep(f);
+ ret = nxp_fspi_clk_prep_enable(f);
+ if (ret)
+ return ret;
- mutex_destroy(&f->lock);
+ if (f->flags & FSPI_NEED_INIT) {
+ nxp_fspi_default_setup(f);
+ ret = pinctrl_pm_select_default_state(dev);
+ if (ret)
+ dev_err(dev, "select flexspi default pinctrl failed!\n");
+ f->flags &= ~FSPI_NEED_INIT;
+ }
- if (f->ahb_addr)
- iounmap(f->ahb_addr);
+ return ret;
}
static int nxp_fspi_suspend(struct device *dev)
{
- return 0;
-}
-
-static int nxp_fspi_resume(struct device *dev)
-{
struct nxp_fspi *f = dev_get_drvdata(dev);
+ int ret;
- nxp_fspi_default_setup(f);
+ ret = pinctrl_pm_select_sleep_state(dev);
+ if (ret) {
+ dev_err(dev, "select flexspi sleep pinctrl failed!\n");
+ return ret;
+ }
- return 0;
+ f->flags |= FSPI_NEED_INIT;
+
+ return pm_runtime_force_suspend(dev);
}
+static const struct dev_pm_ops nxp_fspi_pm_ops = {
+ RUNTIME_PM_OPS(nxp_fspi_runtime_suspend, nxp_fspi_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(nxp_fspi_suspend, pm_runtime_force_resume)
+};
+
static const struct of_device_id nxp_fspi_dt_ids[] = {
{ .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, },
{ .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, },
{ .compatible = "nxp,imx8mp-fspi", .data = (void *)&imx8mm_data, },
{ .compatible = "nxp,imx8qxp-fspi", .data = (void *)&imx8qxp_data, },
{ .compatible = "nxp,imx8dxl-fspi", .data = (void *)&imx8dxl_data, },
+ { .compatible = "nxp,imx8ulp-fspi", .data = (void *)&imx8ulp_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids);
@@ -1298,20 +1461,14 @@ static const struct acpi_device_id nxp_fspi_acpi_ids[] = {
MODULE_DEVICE_TABLE(acpi, nxp_fspi_acpi_ids);
#endif
-static const struct dev_pm_ops nxp_fspi_pm_ops = {
- .suspend = nxp_fspi_suspend,
- .resume = nxp_fspi_resume,
-};
-
static struct platform_driver nxp_fspi_driver = {
.driver = {
.name = "nxp-fspi",
.of_match_table = nxp_fspi_dt_ids,
.acpi_match_table = ACPI_PTR(nxp_fspi_acpi_ids),
- .pm = &nxp_fspi_pm_ops,
+ .pm = pm_ptr(&nxp_fspi_pm_ops),
},
.probe = nxp_fspi_probe,
- .remove_new = nxp_fspi_remove,
};
module_platform_driver(nxp_fspi_driver);
diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c
index 3af499838e84..cba229920357 100644
--- a/drivers/spi/spi-oc-tiny.c
+++ b/drivers/spi/spi-oc-tiny.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * OpenCores tiny SPI master driver
+ * OpenCores tiny SPI host driver
*
* https://opencores.org/project,tiny_spi
*
@@ -53,7 +53,7 @@ struct tiny_spi {
static inline struct tiny_spi *tiny_spi_to_hw(struct spi_device *sdev)
{
- return spi_master_get_devdata(sdev->master);
+ return spi_controller_get_devdata(sdev->controller);
}
static unsigned int tiny_spi_baud(struct spi_device *spi, unsigned int hz)
@@ -184,8 +184,6 @@ static irqreturn_t tiny_spi_irq(int irq, void *dev)
}
#ifdef CONFIG_OF
-#include <linux/of_gpio.h>
-
static int tiny_spi_of_probe(struct platform_device *pdev)
{
struct tiny_spi *hw = platform_get_drvdata(pdev);
@@ -194,7 +192,7 @@ static int tiny_spi_of_probe(struct platform_device *pdev)
if (!np)
return 0;
- hw->bitbang.master->dev.of_node = pdev->dev.of_node;
+ hw->bitbang.ctlr->dev.of_node = pdev->dev.of_node;
if (!of_property_read_u32(np, "clock-frequency", &val))
hw->freq = val;
if (!of_property_read_u32(np, "baud-width", &val))
@@ -212,24 +210,24 @@ static int tiny_spi_probe(struct platform_device *pdev)
{
struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
struct tiny_spi *hw;
- struct spi_master *master;
+ struct spi_controller *host;
int err = -ENODEV;
- master = spi_alloc_master(&pdev->dev, sizeof(struct tiny_spi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(struct tiny_spi));
+ if (!host)
return err;
- /* setup the master state. */
- master->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->setup = tiny_spi_setup;
- master->use_gpio_descriptors = true;
+ /* setup the host state. */
+ host->bus_num = pdev->id;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->setup = tiny_spi_setup;
+ host->use_gpio_descriptors = true;
- hw = spi_master_get_devdata(master);
+ hw = spi_controller_get_devdata(host);
platform_set_drvdata(pdev, hw);
/* setup the state for the bitbang driver */
- hw->bitbang.master = master;
+ hw->bitbang.ctlr = host;
hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;
@@ -267,17 +265,17 @@ static int tiny_spi_probe(struct platform_device *pdev)
return 0;
exit:
- spi_master_put(master);
+ spi_controller_put(host);
return err;
}
static void tiny_spi_remove(struct platform_device *pdev)
{
struct tiny_spi *hw = platform_get_drvdata(pdev);
- struct spi_master *master = hw->bitbang.master;
+ struct spi_controller *host = hw->bitbang.ctlr;
spi_bitbang_stop(&hw->bitbang);
- spi_master_put(master);
+ spi_controller_put(host);
}
#ifdef CONFIG_OF
@@ -290,7 +288,7 @@ MODULE_DEVICE_TABLE(of, tiny_spi_match);
static struct platform_driver tiny_spi_driver = {
.probe = tiny_spi_probe,
- .remove_new = tiny_spi_remove,
+ .remove = tiny_spi_remove,
.driver = {
.name = DRV_NAME,
.pm = NULL,
diff --git a/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c b/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c
new file mode 100644
index 000000000000..8468c773713a
--- /dev/null
+++ b/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Analog Devices Inc.
+ * Copyright (C) 2025 BayLibre, SAS
+ */
+
+#include <linux/clk.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/spi/offload/provider.h>
+#include <linux/spi/offload/types.h>
+#include <linux/types.h>
+
+static bool adi_util_sigma_delta_match(struct spi_offload_trigger *trigger,
+ enum spi_offload_trigger_type type,
+ u64 *args, u32 nargs)
+{
+ return type == SPI_OFFLOAD_TRIGGER_DATA_READY && nargs == 0;
+}
+
+static const struct spi_offload_trigger_ops adi_util_sigma_delta_ops = {
+ .match = adi_util_sigma_delta_match,
+};
+
+static int adi_util_sigma_delta_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_offload_trigger_info info = {
+ .fwnode = dev_fwnode(dev),
+ .ops = &adi_util_sigma_delta_ops,
+ };
+ struct clk *clk;
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "Failed to get clock\n");
+
+ return devm_spi_offload_trigger_register(dev, &info);
+}
+
+static const struct of_device_id adi_util_sigma_delta_of_match_table[] = {
+ { .compatible = "adi,util-sigma-delta-spi", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adi_util_sigma_delta_of_match_table);
+
+static struct platform_driver adi_util_sigma_delta_driver = {
+ .probe = adi_util_sigma_delta_probe,
+ .driver = {
+ .name = "adi-util-sigma-delta-spi",
+ .of_match_table = adi_util_sigma_delta_of_match_table,
+ },
+};
+module_platform_driver(adi_util_sigma_delta_driver);
+
+MODULE_AUTHOR("David Lechner <dlechner@baylibre.com>");
+MODULE_DESCRIPTION("ADI Sigma-Delta SPI offload trigger utility driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-offload-trigger-pwm.c b/drivers/spi/spi-offload-trigger-pwm.c
new file mode 100644
index 000000000000..3e8c19227edb
--- /dev/null
+++ b/drivers/spi/spi-offload-trigger-pwm.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 Analog Devices Inc.
+ * Copyright (C) 2024 BayLibre, SAS
+ *
+ * Generic PWM trigger for SPI offload.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/math.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/pwm.h>
+#include <linux/spi/offload/provider.h>
+#include <linux/spi/offload/types.h>
+#include <linux/time.h>
+#include <linux/types.h>
+
+struct spi_offload_trigger_pwm_state {
+ struct device *dev;
+ struct pwm_device *pwm;
+};
+
+static bool spi_offload_trigger_pwm_match(struct spi_offload_trigger *trigger,
+ enum spi_offload_trigger_type type,
+ u64 *args, u32 nargs)
+{
+ if (nargs)
+ return false;
+
+ return type == SPI_OFFLOAD_TRIGGER_PERIODIC;
+}
+
+static int spi_offload_trigger_pwm_validate(struct spi_offload_trigger *trigger,
+ struct spi_offload_trigger_config *config)
+{
+ struct spi_offload_trigger_pwm_state *st = spi_offload_trigger_get_priv(trigger);
+ struct spi_offload_trigger_periodic *periodic = &config->periodic;
+ struct pwm_waveform wf = { };
+ int ret;
+
+ if (config->type != SPI_OFFLOAD_TRIGGER_PERIODIC)
+ return -EINVAL;
+
+ if (!periodic->frequency_hz)
+ return -EINVAL;
+
+ wf.period_length_ns = DIV_ROUND_UP_ULL(NSEC_PER_SEC, periodic->frequency_hz);
+ /* REVISIT: 50% duty-cycle for now - may add config parameter later */
+ wf.duty_length_ns = wf.period_length_ns / 2;
+ wf.duty_offset_ns = periodic->offset_ns;
+
+ ret = pwm_round_waveform_might_sleep(st->pwm, &wf);
+ if (ret < 0)
+ return ret;
+
+ periodic->frequency_hz = DIV_ROUND_UP_ULL(NSEC_PER_SEC, wf.period_length_ns);
+ periodic->offset_ns = wf.duty_offset_ns;
+
+ return 0;
+}
+
+static int spi_offload_trigger_pwm_enable(struct spi_offload_trigger *trigger,
+ struct spi_offload_trigger_config *config)
+{
+ struct spi_offload_trigger_pwm_state *st = spi_offload_trigger_get_priv(trigger);
+ struct spi_offload_trigger_periodic *periodic = &config->periodic;
+ struct pwm_waveform wf = { };
+
+ if (config->type != SPI_OFFLOAD_TRIGGER_PERIODIC)
+ return -EINVAL;
+
+ if (!periodic->frequency_hz)
+ return -EINVAL;
+
+ wf.period_length_ns = DIV_ROUND_UP_ULL(NSEC_PER_SEC, periodic->frequency_hz);
+ /* REVISIT: 50% duty-cycle for now - may add config parameter later */
+ wf.duty_length_ns = wf.period_length_ns / 2;
+ wf.duty_offset_ns = periodic->offset_ns;
+
+ return pwm_set_waveform_might_sleep(st->pwm, &wf, false);
+}
+
+static void spi_offload_trigger_pwm_disable(struct spi_offload_trigger *trigger)
+{
+ struct spi_offload_trigger_pwm_state *st = spi_offload_trigger_get_priv(trigger);
+ struct pwm_waveform wf;
+ int ret;
+
+ ret = pwm_get_waveform_might_sleep(st->pwm, &wf);
+ if (ret < 0) {
+ dev_err(st->dev, "failed to get waveform: %d\n", ret);
+ return;
+ }
+
+ wf.duty_length_ns = 0;
+
+ ret = pwm_set_waveform_might_sleep(st->pwm, &wf, false);
+ if (ret < 0)
+ dev_err(st->dev, "failed to disable PWM: %d\n", ret);
+}
+
+static const struct spi_offload_trigger_ops spi_offload_trigger_pwm_ops = {
+ .match = spi_offload_trigger_pwm_match,
+ .validate = spi_offload_trigger_pwm_validate,
+ .enable = spi_offload_trigger_pwm_enable,
+ .disable = spi_offload_trigger_pwm_disable,
+};
+
+static void spi_offload_trigger_pwm_release(void *data)
+{
+ pwm_disable(data);
+}
+
+static int spi_offload_trigger_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_offload_trigger_info info = {
+ .fwnode = dev_fwnode(dev),
+ .ops = &spi_offload_trigger_pwm_ops,
+ };
+ struct spi_offload_trigger_pwm_state *st;
+ struct pwm_state state;
+ int ret;
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ info.priv = st;
+ st->dev = dev;
+
+ st->pwm = devm_pwm_get(dev, NULL);
+ if (IS_ERR(st->pwm))
+ return dev_err_probe(dev, PTR_ERR(st->pwm), "failed to get PWM\n");
+
+ /* init with duty_cycle = 0, output enabled to ensure trigger off */
+ pwm_init_state(st->pwm, &state);
+ state.enabled = true;
+
+ ret = pwm_apply_might_sleep(st->pwm, &state);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to apply PWM state\n");
+
+ ret = devm_add_action_or_reset(dev, spi_offload_trigger_pwm_release, st->pwm);
+ if (ret)
+ return ret;
+
+ return devm_spi_offload_trigger_register(dev, &info);
+}
+
+static const struct of_device_id spi_offload_trigger_pwm_of_match_table[] = {
+ { .compatible = "pwm-trigger" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, spi_offload_trigger_pwm_of_match_table);
+
+static struct platform_driver spi_offload_trigger_pwm_driver = {
+ .driver = {
+ .name = "pwm-trigger",
+ .of_match_table = spi_offload_trigger_pwm_of_match_table,
+ },
+ .probe = spi_offload_trigger_pwm_probe,
+};
+module_platform_driver(spi_offload_trigger_pwm_driver);
+
+MODULE_AUTHOR("David Lechner <dlechner@baylibre.com>");
+MODULE_DESCRIPTION("Generic PWM trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-offload.c b/drivers/spi/spi-offload.c
new file mode 100644
index 000000000000..d336f4d228d5
--- /dev/null
+++ b/drivers/spi/spi-offload.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 Analog Devices Inc.
+ * Copyright (C) 2024 BayLibre, SAS
+ */
+
+/*
+ * SPI Offloading support.
+ *
+ * Some SPI controllers support offloading of SPI transfers. Essentially, this
+ * is the ability for a SPI controller to perform SPI transfers with minimal
+ * or even no CPU intervention, e.g. via a specialized SPI controller with a
+ * hardware trigger or via a conventional SPI controller using a non-Linux MCU
+ * processor core to offload the work.
+ */
+
+#define DEFAULT_SYMBOL_NAMESPACE "SPI_OFFLOAD"
+
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/export.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/property.h>
+#include <linux/spi/offload/consumer.h>
+#include <linux/spi/offload/provider.h>
+#include <linux/spi/offload/types.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+
+struct spi_controller_and_offload {
+ struct spi_controller *controller;
+ struct spi_offload *offload;
+};
+
+struct spi_offload_trigger {
+ struct list_head list;
+ struct kref ref;
+ struct fwnode_handle *fwnode;
+ /* synchronizes calling ops and driver registration */
+ struct mutex lock;
+ /*
+ * If the provider goes away while the consumer still has a reference,
+ * ops and priv will be set to NULL and all calls will fail with -ENODEV.
+ */
+ const struct spi_offload_trigger_ops *ops;
+ void *priv;
+};
+
+static LIST_HEAD(spi_offload_triggers);
+static DEFINE_MUTEX(spi_offload_triggers_lock);
+
+/**
+ * devm_spi_offload_alloc() - Allocate offload instance
+ * @dev: Device for devm purposes and assigned to &struct spi_offload.provider_dev
+ * @priv_size: Size of private data to allocate
+ *
+ * Offload providers should use this to allocate offload instances.
+ *
+ * Return: Pointer to new offload instance or error on failure.
+ */
+struct spi_offload *devm_spi_offload_alloc(struct device *dev,
+ size_t priv_size)
+{
+ struct spi_offload *offload;
+ void *priv;
+
+ offload = devm_kzalloc(dev, sizeof(*offload), GFP_KERNEL);
+ if (!offload)
+ return ERR_PTR(-ENOMEM);
+
+ priv = devm_kzalloc(dev, priv_size, GFP_KERNEL);
+ if (!priv)
+ return ERR_PTR(-ENOMEM);
+
+ offload->provider_dev = dev;
+ offload->priv = priv;
+
+ return offload;
+}
+EXPORT_SYMBOL_GPL(devm_spi_offload_alloc);
+
+static void spi_offload_put(void *data)
+{
+ struct spi_controller_and_offload *resource = data;
+
+ resource->controller->put_offload(resource->offload);
+ kfree(resource);
+}
+
+/**
+ * devm_spi_offload_get() - Get an offload instance
+ * @dev: Device for devm purposes
+ * @spi: SPI device to use for the transfers
+ * @config: Offload configuration
+ *
+ * Peripheral drivers call this function to get an offload instance that meets
+ * the requirements specified in @config. If no suitable offload instance is
+ * available, -ENODEV is returned.
+ *
+ * Return: Offload instance or error on failure.
+ */
+struct spi_offload *devm_spi_offload_get(struct device *dev,
+ struct spi_device *spi,
+ const struct spi_offload_config *config)
+{
+ struct spi_controller_and_offload *resource;
+ struct spi_offload *offload;
+ int ret;
+
+ if (!spi || !config)
+ return ERR_PTR(-EINVAL);
+
+ if (!spi->controller->get_offload)
+ return ERR_PTR(-ENODEV);
+
+ resource = kzalloc(sizeof(*resource), GFP_KERNEL);
+ if (!resource)
+ return ERR_PTR(-ENOMEM);
+
+ offload = spi->controller->get_offload(spi, config);
+ if (IS_ERR(offload)) {
+ kfree(resource);
+ return offload;
+ }
+
+ resource->controller = spi->controller;
+ resource->offload = offload;
+
+ ret = devm_add_action_or_reset(dev, spi_offload_put, resource);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return offload;
+}
+EXPORT_SYMBOL_GPL(devm_spi_offload_get);
+
+static void spi_offload_trigger_free(struct kref *ref)
+{
+ struct spi_offload_trigger *trigger =
+ container_of(ref, struct spi_offload_trigger, ref);
+
+ mutex_destroy(&trigger->lock);
+ fwnode_handle_put(trigger->fwnode);
+ kfree(trigger);
+}
+
+static void spi_offload_trigger_put(void *data)
+{
+ struct spi_offload_trigger *trigger = data;
+
+ scoped_guard(mutex, &trigger->lock)
+ if (trigger->ops && trigger->ops->release)
+ trigger->ops->release(trigger);
+
+ kref_put(&trigger->ref, spi_offload_trigger_free);
+}
+
+static struct spi_offload_trigger
+*spi_offload_trigger_get(enum spi_offload_trigger_type type,
+ struct fwnode_reference_args *args)
+{
+ struct spi_offload_trigger *trigger;
+ bool match = false;
+ int ret;
+
+ guard(mutex)(&spi_offload_triggers_lock);
+
+ list_for_each_entry(trigger, &spi_offload_triggers, list) {
+ if (trigger->fwnode != args->fwnode)
+ continue;
+
+ match = trigger->ops->match(trigger, type, args->args, args->nargs);
+ if (match)
+ break;
+ }
+
+ if (!match)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ guard(mutex)(&trigger->lock);
+
+ if (trigger->ops->request) {
+ ret = trigger->ops->request(trigger, type, args->args, args->nargs);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
+ kref_get(&trigger->ref);
+
+ return trigger;
+}
+
+/**
+ * devm_spi_offload_trigger_get() - Get an offload trigger instance
+ * @dev: Device for devm purposes.
+ * @offload: Offload instance connected to a trigger.
+ * @type: Trigger type to get.
+ *
+ * Return: Offload trigger instance or error on failure.
+ */
+struct spi_offload_trigger
+*devm_spi_offload_trigger_get(struct device *dev,
+ struct spi_offload *offload,
+ enum spi_offload_trigger_type type)
+{
+ struct spi_offload_trigger *trigger;
+ struct fwnode_reference_args args;
+ int ret;
+
+ ret = fwnode_property_get_reference_args(dev_fwnode(offload->provider_dev),
+ "trigger-sources",
+ "#trigger-source-cells", 0, 0,
+ &args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ trigger = spi_offload_trigger_get(type, &args);
+ fwnode_handle_put(args.fwnode);
+ if (IS_ERR(trigger))
+ return trigger;
+
+ ret = devm_add_action_or_reset(dev, spi_offload_trigger_put, trigger);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return trigger;
+}
+EXPORT_SYMBOL_GPL(devm_spi_offload_trigger_get);
+
+/**
+ * spi_offload_trigger_validate - Validate the requested trigger
+ * @trigger: Offload trigger instance
+ * @config: Trigger config to validate
+ *
+ * On success, @config may be modifed to reflect what the hardware can do.
+ * For example, the frequency of a periodic trigger may be adjusted to the
+ * nearest supported value.
+ *
+ * Callers will likely need to do additional validation of the modified trigger
+ * parameters.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int spi_offload_trigger_validate(struct spi_offload_trigger *trigger,
+ struct spi_offload_trigger_config *config)
+{
+ guard(mutex)(&trigger->lock);
+
+ if (!trigger->ops)
+ return -ENODEV;
+
+ if (!trigger->ops->validate)
+ return -EOPNOTSUPP;
+
+ return trigger->ops->validate(trigger, config);
+}
+EXPORT_SYMBOL_GPL(spi_offload_trigger_validate);
+
+/**
+ * spi_offload_trigger_enable - enables trigger for offload
+ * @offload: Offload instance
+ * @trigger: Offload trigger instance
+ * @config: Trigger config to validate
+ *
+ * There must be a prepared offload instance with the specified ID (i.e.
+ * spi_optimize_message() was called with the same offload assigned to the
+ * message). This will also reserve the bus for exclusive use by the offload
+ * instance until the trigger is disabled. Any other attempts to send a
+ * transfer or lock the bus will fail with -EBUSY during this time.
+ *
+ * Calls must be balanced with spi_offload_trigger_disable().
+ *
+ * Context: can sleep
+ * Return: 0 on success, else a negative error code.
+ */
+int spi_offload_trigger_enable(struct spi_offload *offload,
+ struct spi_offload_trigger *trigger,
+ struct spi_offload_trigger_config *config)
+{
+ int ret;
+
+ guard(mutex)(&trigger->lock);
+
+ if (!trigger->ops)
+ return -ENODEV;
+
+ if (offload->ops && offload->ops->trigger_enable) {
+ ret = offload->ops->trigger_enable(offload);
+ if (ret)
+ return ret;
+ }
+
+ if (trigger->ops->enable) {
+ ret = trigger->ops->enable(trigger, config);
+ if (ret) {
+ if (offload->ops && offload->ops->trigger_disable)
+ offload->ops->trigger_disable(offload);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_offload_trigger_enable);
+
+/**
+ * spi_offload_trigger_disable - disables hardware trigger for offload
+ * @offload: Offload instance
+ * @trigger: Offload trigger instance
+ *
+ * Disables the hardware trigger for the offload instance with the specified ID
+ * and releases the bus for use by other clients.
+ *
+ * Context: can sleep
+ */
+void spi_offload_trigger_disable(struct spi_offload *offload,
+ struct spi_offload_trigger *trigger)
+{
+ if (offload->ops && offload->ops->trigger_disable)
+ offload->ops->trigger_disable(offload);
+
+ guard(mutex)(&trigger->lock);
+
+ if (!trigger->ops)
+ return;
+
+ if (trigger->ops->disable)
+ trigger->ops->disable(trigger);
+}
+EXPORT_SYMBOL_GPL(spi_offload_trigger_disable);
+
+static void spi_offload_release_dma_chan(void *chan)
+{
+ dma_release_channel(chan);
+}
+
+/**
+ * devm_spi_offload_tx_stream_request_dma_chan - Get the DMA channel info for the TX stream
+ * @dev: Device for devm purposes.
+ * @offload: Offload instance
+ *
+ * This is the DMA channel that will provide data to transfers that use the
+ * %SPI_OFFLOAD_XFER_TX_STREAM offload flag.
+ *
+ * Return: Pointer to DMA channel info, or negative error code
+ */
+struct dma_chan
+*devm_spi_offload_tx_stream_request_dma_chan(struct device *dev,
+ struct spi_offload *offload)
+{
+ struct dma_chan *chan;
+ int ret;
+
+ if (!offload->ops || !offload->ops->tx_stream_request_dma_chan)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ chan = offload->ops->tx_stream_request_dma_chan(offload);
+ if (IS_ERR(chan))
+ return chan;
+
+ ret = devm_add_action_or_reset(dev, spi_offload_release_dma_chan, chan);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(devm_spi_offload_tx_stream_request_dma_chan);
+
+/**
+ * devm_spi_offload_rx_stream_request_dma_chan - Get the DMA channel info for the RX stream
+ * @dev: Device for devm purposes.
+ * @offload: Offload instance
+ *
+ * This is the DMA channel that will receive data from transfers that use the
+ * %SPI_OFFLOAD_XFER_RX_STREAM offload flag.
+ *
+ * Return: Pointer to DMA channel info, or negative error code
+ */
+struct dma_chan
+*devm_spi_offload_rx_stream_request_dma_chan(struct device *dev,
+ struct spi_offload *offload)
+{
+ struct dma_chan *chan;
+ int ret;
+
+ if (!offload->ops || !offload->ops->rx_stream_request_dma_chan)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ chan = offload->ops->rx_stream_request_dma_chan(offload);
+ if (IS_ERR(chan))
+ return chan;
+
+ ret = devm_add_action_or_reset(dev, spi_offload_release_dma_chan, chan);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(devm_spi_offload_rx_stream_request_dma_chan);
+
+/* Triggers providers */
+
+static void spi_offload_trigger_unregister(void *data)
+{
+ struct spi_offload_trigger *trigger = data;
+
+ scoped_guard(mutex, &spi_offload_triggers_lock)
+ list_del(&trigger->list);
+
+ scoped_guard(mutex, &trigger->lock) {
+ trigger->priv = NULL;
+ trigger->ops = NULL;
+ }
+
+ kref_put(&trigger->ref, spi_offload_trigger_free);
+}
+
+/**
+ * devm_spi_offload_trigger_register() - Allocate and register an offload trigger
+ * @dev: Device for devm purposes.
+ * @info: Provider-specific trigger info.
+ *
+ * Return: 0 on success, else a negative error code.
+ */
+int devm_spi_offload_trigger_register(struct device *dev,
+ struct spi_offload_trigger_info *info)
+{
+ struct spi_offload_trigger *trigger;
+
+ if (!info->fwnode || !info->ops || !info->ops->match)
+ return -EINVAL;
+
+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+ if (!trigger)
+ return -ENOMEM;
+
+ kref_init(&trigger->ref);
+ mutex_init(&trigger->lock);
+ trigger->fwnode = fwnode_handle_get(info->fwnode);
+ trigger->ops = info->ops;
+ trigger->priv = info->priv;
+
+ scoped_guard(mutex, &spi_offload_triggers_lock)
+ list_add_tail(&trigger->list, &spi_offload_triggers);
+
+ return devm_add_action_or_reset(dev, spi_offload_trigger_unregister, trigger);
+}
+EXPORT_SYMBOL_GPL(devm_spi_offload_trigger_register);
+
+/**
+ * spi_offload_trigger_get_priv() - Get the private data for the trigger
+ *
+ * @trigger: Offload trigger instance.
+ *
+ * Return: Private data for the trigger.
+ */
+void *spi_offload_trigger_get_priv(struct spi_offload_trigger *trigger)
+{
+ return trigger->priv;
+}
+EXPORT_SYMBOL_GPL(spi_offload_trigger_get_priv);
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index 902d2e0c1f2f..b9a91dbfeaef 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -315,7 +315,7 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
int div2;
int status;
- uwire = spi_master_get_devdata(spi->master);
+ uwire = spi_controller_get_devdata(spi->controller);
/* mode 0..3, clock inverted separately;
* standard nCS signaling;
@@ -448,25 +448,25 @@ static void uwire_off(struct uwire_spi *uwire)
{
uwire_write_reg(UWIRE_SR3, 0);
clk_disable_unprepare(uwire->ck);
- spi_master_put(uwire->bitbang.master);
+ spi_controller_put(uwire->bitbang.ctlr);
}
static int uwire_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct uwire_spi *uwire;
int status;
- master = spi_alloc_master(&pdev->dev, sizeof(*uwire));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*uwire));
+ if (!host)
return -ENODEV;
- uwire = spi_master_get_devdata(master);
+ uwire = spi_controller_get_devdata(host);
uwire_base = devm_ioremap(&pdev->dev, UWIRE_BASE_PHYS, UWIRE_IO_SIZE);
if (!uwire_base) {
dev_dbg(&pdev->dev, "can't ioremap UWIRE\n");
- spi_master_put(master);
+ spi_controller_put(host);
return -ENOMEM;
}
@@ -476,7 +476,7 @@ static int uwire_probe(struct platform_device *pdev)
if (IS_ERR(uwire->ck)) {
status = PTR_ERR(uwire->ck);
dev_dbg(&pdev->dev, "no functional clock?\n");
- spi_master_put(master);
+ spi_controller_put(host);
return status;
}
clk_prepare_enable(uwire->ck);
@@ -484,16 +484,16 @@ static int uwire_probe(struct platform_device *pdev)
uwire_write_reg(UWIRE_SR3, 1);
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
- master->flags = SPI_MASTER_HALF_DUPLEX;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
- master->bus_num = 2; /* "official" */
- master->num_chipselect = 4;
- master->setup = uwire_setup;
- master->cleanup = uwire_cleanup;
+ host->bus_num = 2; /* "official" */
+ host->num_chipselect = 4;
+ host->setup = uwire_setup;
+ host->cleanup = uwire_cleanup;
- uwire->bitbang.master = master;
+ uwire->bitbang.ctlr = host;
uwire->bitbang.chipselect = uwire_chipselect;
uwire->bitbang.setup_transfer = uwire_setup_transfer;
uwire->bitbang.txrx_bufs = uwire_txrx;
@@ -523,7 +523,7 @@ static struct platform_driver uwire_driver = {
.name = "omap_uwire",
},
.probe = uwire_probe,
- .remove_new = uwire_remove,
+ .remove = uwire_remove,
// suspend ... unuse ck
// resume ... use ck
};
@@ -541,5 +541,6 @@ static void __exit omap_uwire_exit(void)
subsys_initcall(omap_uwire_init);
module_exit(omap_uwire_exit);
+MODULE_DESCRIPTION("MicroWire interface driver for OMAP");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 8331e247bf5c..69c2e9d9be3c 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -27,6 +27,8 @@
#include <linux/spi/spi.h>
+#include "internals.h"
+
#include <linux/platform_data/spi-omap2-mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
@@ -117,7 +119,7 @@ struct omap2_mcspi_regs {
struct omap2_mcspi {
struct completion txdone;
- struct spi_master *master;
+ struct spi_controller *ctlr;
/* Virtual base address of the controller */
void __iomem *base;
unsigned long phys;
@@ -125,10 +127,14 @@ struct omap2_mcspi {
struct omap2_mcspi_dma *dma_channels;
struct device *dev;
struct omap2_mcspi_regs ctx;
+ struct clk *ref_clk;
int fifo_depth;
- bool slave_aborted;
+ bool target_aborted;
unsigned int pin_dir:1;
size_t max_xfer_len;
+ u32 ref_clk_hz;
+ bool use_multi_mode;
+ bool last_msg_kept_cs;
};
struct omap2_mcspi_cs {
@@ -141,17 +147,17 @@ struct omap2_mcspi_cs {
u32 chconf0, chctrl0;
};
-static inline void mcspi_write_reg(struct spi_master *master,
+static inline void mcspi_write_reg(struct spi_controller *ctlr,
int idx, u32 val)
{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
writel_relaxed(val, mcspi->base + idx);
}
-static inline u32 mcspi_read_reg(struct spi_master *master, int idx)
+static inline u32 mcspi_read_reg(struct spi_controller *ctlr, int idx)
{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
return readl_relaxed(mcspi->base + idx);
}
@@ -235,7 +241,7 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
u32 l;
/* The controller handles the inverted chip selects
@@ -254,36 +260,45 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
l = mcspi_cached_chconf0(spi);
- if (enable)
+ /* Only enable chip select manually if single mode is used */
+ if (mcspi->use_multi_mode) {
l &= ~OMAP2_MCSPI_CHCONF_FORCE;
- else
- l |= OMAP2_MCSPI_CHCONF_FORCE;
+ } else {
+ if (enable)
+ l &= ~OMAP2_MCSPI_CHCONF_FORCE;
+ else
+ l |= OMAP2_MCSPI_CHCONF_FORCE;
+ }
mcspi_write_chconf0(spi, l);
- pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
}
}
-static void omap2_mcspi_set_mode(struct spi_master *master)
+static void omap2_mcspi_set_mode(struct spi_controller *ctlr)
{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
u32 l;
/*
- * Choose master or slave mode
+ * Choose host or target mode
*/
- l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
+ l = mcspi_read_reg(ctlr, OMAP2_MCSPI_MODULCTRL);
l &= ~(OMAP2_MCSPI_MODULCTRL_STEST);
- if (spi_controller_is_slave(master)) {
+ if (spi_controller_is_target(ctlr)) {
l |= (OMAP2_MCSPI_MODULCTRL_MS);
} else {
l &= ~(OMAP2_MCSPI_MODULCTRL_MS);
- l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
+
+ /* Enable single mode if needed */
+ if (mcspi->use_multi_mode)
+ l &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
+ else
+ l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
}
- mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
+ mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, l);
ctx->modulctrl = l;
}
@@ -291,14 +306,14 @@ static void omap2_mcspi_set_mode(struct spi_master *master)
static void omap2_mcspi_set_fifo(const struct spi_device *spi,
struct spi_transfer *t, int enable)
{
- struct spi_master *master = spi->master;
+ struct spi_controller *ctlr = spi->controller;
struct omap2_mcspi_cs *cs = spi->controller_state;
struct omap2_mcspi *mcspi;
unsigned int wcnt;
int max_fifo_depth, bytes_per_word;
u32 chconf, xferlevel;
- mcspi = spi_master_get_devdata(master);
+ mcspi = spi_controller_get_devdata(ctlr);
chconf = mcspi_cached_chconf0(spi);
if (enable) {
@@ -326,7 +341,7 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
xferlevel |= bytes_per_word - 1;
}
- mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);
+ mcspi_write_reg(ctlr, OMAP2_MCSPI_XFERLEVEL, xferlevel);
mcspi_write_chconf0(spi, chconf);
mcspi->fifo_depth = max_fifo_depth;
@@ -364,9 +379,9 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
static int mcspi_wait_for_completion(struct omap2_mcspi *mcspi,
struct completion *x)
{
- if (spi_controller_is_slave(mcspi->master)) {
+ if (spi_controller_is_target(mcspi->ctlr)) {
if (wait_for_completion_interruptible(x) ||
- mcspi->slave_aborted)
+ mcspi->target_aborted)
return -EINTR;
} else {
wait_for_completion(x);
@@ -378,7 +393,7 @@ static int mcspi_wait_for_completion(struct omap2_mcspi *mcspi,
static void omap2_mcspi_rx_callback(void *data)
{
struct spi_device *spi = data;
- struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
/* We must disable the DMA RX request */
@@ -390,7 +405,7 @@ static void omap2_mcspi_rx_callback(void *data)
static void omap2_mcspi_tx_callback(void *data)
{
struct spi_device *spi = data;
- struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
/* We must disable the DMA TX request */
@@ -407,7 +422,7 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
struct omap2_mcspi_dma *mcspi_dma;
struct dma_async_tx_descriptor *tx;
- mcspi = spi_master_get_devdata(spi->master);
+ mcspi = spi_controller_get_devdata(spi->controller);
mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
@@ -445,13 +460,13 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
struct dma_async_tx_descriptor *tx;
- mcspi = spi_master_get_devdata(spi->master);
+ mcspi = spi_controller_get_devdata(spi->controller);
mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
count = xfer->len;
/*
* In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM
- * it mentions reducing DMA transfer length by one element in master
+ * it mentions reducing DMA transfer length by one element in host
* normal mode.
*/
if (mcspi->fifo_depth == 0)
@@ -514,7 +529,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
omap2_mcspi_set_dma_req(spi, 1, 1);
ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_rx_completion);
- if (ret || mcspi->slave_aborted) {
+ if (ret || mcspi->target_aborted) {
dmaengine_terminate_sync(mcspi_dma->dma_rx);
omap2_mcspi_set_dma_req(spi, 1, 0);
return 0;
@@ -590,7 +605,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
void __iomem *irqstat_reg;
int wait_res;
- mcspi = spi_master_get_devdata(spi->master);
+ mcspi = spi_controller_get_devdata(spi->controller);
mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
if (cs->word_len <= 8) {
@@ -617,14 +632,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
- mcspi->slave_aborted = false;
+ mcspi->target_aborted = false;
reinit_completion(&mcspi_dma->dma_tx_completion);
reinit_completion(&mcspi_dma->dma_rx_completion);
reinit_completion(&mcspi->txdone);
if (tx) {
- /* Enable EOW IRQ to know end of tx in slave mode */
- if (spi_controller_is_slave(spi->master))
- mcspi_write_reg(spi->master,
+ /* Enable EOW IRQ to know end of tx in target mode */
+ if (spi_controller_is_target(spi->controller))
+ mcspi_write_reg(spi->controller,
OMAP2_MCSPI_IRQENABLE,
OMAP2_MCSPI_IRQSTATUS_EOW);
omap2_mcspi_tx_dma(spi, xfer, cfg);
@@ -637,15 +652,15 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
int ret;
ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_tx_completion);
- if (ret || mcspi->slave_aborted) {
+ if (ret || mcspi->target_aborted) {
dmaengine_terminate_sync(mcspi_dma->dma_tx);
omap2_mcspi_set_dma_req(spi, 0, 0);
return 0;
}
- if (spi_controller_is_slave(mcspi->master)) {
+ if (spi_controller_is_target(mcspi->ctlr)) {
ret = mcspi_wait_for_completion(mcspi, &mcspi->txdone);
- if (ret || mcspi->slave_aborted)
+ if (ret || mcspi->target_aborted)
return 0;
}
@@ -656,7 +671,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
OMAP2_MCSPI_IRQSTATUS_EOW) < 0)
dev_err(&spi->dev, "EOW timed out\n");
- mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS,
+ mcspi_write_reg(mcspi->ctlr, OMAP2_MCSPI_IRQSTATUS,
OMAP2_MCSPI_IRQSTATUS_EOW);
}
@@ -880,12 +895,12 @@ out:
return count - c;
}
-static u32 omap2_mcspi_calc_divisor(u32 speed_hz)
+static u32 omap2_mcspi_calc_divisor(u32 speed_hz, u32 ref_clk_hz)
{
u32 div;
for (div = 0; div < 15; div++)
- if (speed_hz >= (OMAP2_MCSPI_MAX_FREQ >> div))
+ if (speed_hz >= (ref_clk_hz >> div))
return div;
return 15;
@@ -897,11 +912,11 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
{
struct omap2_mcspi_cs *cs = spi->controller_state;
struct omap2_mcspi *mcspi;
- u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
+ u32 ref_clk_hz, l = 0, clkd = 0, div, extclk = 0, clkg = 0;
u8 word_len = spi->bits_per_word;
u32 speed_hz = spi->max_speed_hz;
- mcspi = spi_master_get_devdata(spi->master);
+ mcspi = spi_controller_get_devdata(spi->controller);
if (t != NULL && t->bits_per_word)
word_len = t->bits_per_word;
@@ -911,14 +926,15 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
if (t && t->speed_hz)
speed_hz = t->speed_hz;
- speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
- if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) {
- clkd = omap2_mcspi_calc_divisor(speed_hz);
- speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd;
+ ref_clk_hz = mcspi->ref_clk_hz;
+ speed_hz = min_t(u32, speed_hz, ref_clk_hz);
+ if (speed_hz < (ref_clk_hz / OMAP2_MCSPI_MAX_DIVIDER)) {
+ clkd = omap2_mcspi_calc_divisor(speed_hz, ref_clk_hz);
+ speed_hz = ref_clk_hz >> clkd;
clkg = 0;
} else {
- div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz;
- speed_hz = OMAP2_MCSPI_MAX_FREQ / div;
+ div = (ref_clk_hz + speed_hz - 1) / speed_hz;
+ speed_hz = ref_clk_hz / div;
clkd = (div - 1) & 0xf;
extclk = (div - 1) >> 4;
clkg = OMAP2_MCSPI_CHCONF_CLKG;
@@ -926,7 +942,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
l = mcspi_cached_chconf0(spi);
- /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
+ /* standard 4-wire host mode: SCK, MOSI/out, MISO/in, nCS
* REVISIT: this controller could support SPI_3WIRE mode.
*/
if (mcspi->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) {
@@ -972,6 +988,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
else
l &= ~OMAP2_MCSPI_CHCONF_PHA;
+ mcspi_write_chconf0(spi, l | OMAP2_MCSPI_CHCONF_FORCE);
mcspi_write_chconf0(spi, l);
cs->mode = spi->mode;
@@ -1017,13 +1034,13 @@ no_dma:
return ret;
}
-static void omap2_mcspi_release_dma(struct spi_master *master)
+static void omap2_mcspi_release_dma(struct spi_controller *ctlr)
{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
struct omap2_mcspi_dma *mcspi_dma;
int i;
- for (i = 0; i < master->num_chipselect; i++) {
+ for (i = 0; i < ctlr->num_chipselect; i++) {
mcspi_dma = &mcspi->dma_channels[i];
if (mcspi_dma->dma_rx) {
@@ -1054,7 +1071,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
{
bool initial_setup = false;
int ret;
- struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
struct omap2_mcspi_cs *cs = spi->controller_state;
@@ -1085,7 +1102,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
if (ret && initial_setup)
omap2_mcspi_cleanup(spi);
- pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
return ret;
@@ -1096,24 +1112,24 @@ static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data)
struct omap2_mcspi *mcspi = data;
u32 irqstat;
- irqstat = mcspi_read_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS);
+ irqstat = mcspi_read_reg(mcspi->ctlr, OMAP2_MCSPI_IRQSTATUS);
if (!irqstat)
return IRQ_NONE;
- /* Disable IRQ and wakeup slave xfer task */
- mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQENABLE, 0);
+ /* Disable IRQ and wakeup target xfer task */
+ mcspi_write_reg(mcspi->ctlr, OMAP2_MCSPI_IRQENABLE, 0);
if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW)
complete(&mcspi->txdone);
return IRQ_HANDLED;
}
-static int omap2_mcspi_slave_abort(struct spi_master *master)
+static int omap2_mcspi_target_abort(struct spi_controller *ctlr)
{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
struct omap2_mcspi_dma *mcspi_dma = mcspi->dma_channels;
- mcspi->slave_aborted = true;
+ mcspi->target_aborted = true;
complete(&mcspi_dma->dma_rx_completion);
complete(&mcspi_dma->dma_tx_completion);
complete(&mcspi->txdone);
@@ -1121,7 +1137,7 @@ static int omap2_mcspi_slave_abort(struct spi_master *master)
return 0;
}
-static int omap2_mcspi_transfer_one(struct spi_master *master,
+static int omap2_mcspi_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *t)
{
@@ -1129,7 +1145,7 @@ static int omap2_mcspi_transfer_one(struct spi_master *master,
/* We only enable one channel at a time -- the one whose message is
* -- although this controller would gladly
* arbitrate among multiple channels. This corresponds to "single
- * channel" master mode. As a side effect, we need to manage the
+ * channel" host mode. As a side effect, we need to manage the
* chipselect with the FORCE bit ... CS != channel enable.
*/
@@ -1141,13 +1157,13 @@ static int omap2_mcspi_transfer_one(struct spi_master *master,
int status = 0;
u32 chconf;
- mcspi = spi_master_get_devdata(master);
+ mcspi = spi_controller_get_devdata(ctlr);
mcspi_dma = mcspi->dma_channels + spi_get_chipselect(spi, 0);
cs = spi->controller_state;
cd = spi->controller_data;
/*
- * The slave driver could have changed spi->mode in which case
+ * The target driver could have changed spi->mode in which case
* it will be different from cs->mode (the current hardware setup).
* If so, set par_override (even though its not a parity issue) so
* omap2_mcspi_setup_transfer will be called to configure the hardware
@@ -1172,13 +1188,6 @@ static int omap2_mcspi_transfer_one(struct spi_master *master,
t->bits_per_word == spi->bits_per_word)
par_override = 0;
}
- if (cd && cd->cs_per_word) {
- chconf = mcspi->ctx.modulctrl;
- chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
- mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
- mcspi->ctx.modulctrl =
- mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
- }
chconf = mcspi_cached_chconf0(spi);
chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
@@ -1201,8 +1210,7 @@ static int omap2_mcspi_transfer_one(struct spi_master *master,
unsigned count;
if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
- master->cur_msg_mapped &&
- master->can_dma(master, spi, t))
+ spi_xfer_is_dma_mapped(ctlr, spi, t))
omap2_mcspi_set_fifo(spi, t, 1);
omap2_mcspi_set_enable(spi, 1);
@@ -1213,8 +1221,7 @@ static int omap2_mcspi_transfer_one(struct spi_master *master,
+ OMAP2_MCSPI_TX0);
if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
- master->cur_msg_mapped &&
- master->can_dma(master, spi, t))
+ spi_xfer_is_dma_mapped(ctlr, spi, t))
count = omap2_mcspi_txrx_dma(spi, t);
else
count = omap2_mcspi_txrx_pio(spi, t);
@@ -1237,14 +1244,6 @@ out:
status = omap2_mcspi_setup_transfer(spi, NULL);
}
- if (cd && cd->cs_per_word) {
- chconf = mcspi->ctx.modulctrl;
- chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
- mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
- mcspi->ctx.modulctrl =
- mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
- }
-
omap2_mcspi_set_enable(spi, 0);
if (spi_get_csgpiod(spi, 0))
@@ -1256,21 +1255,70 @@ out:
return status;
}
-static int omap2_mcspi_prepare_message(struct spi_master *master,
+static int omap2_mcspi_prepare_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
struct omap2_mcspi_cs *cs;
+ struct spi_transfer *tr;
+ u8 bits_per_word;
+
+ /*
+ * The conditions are strict, it is mandatory to check each transfer of the list to see if
+ * multi-mode is applicable.
+ */
+ mcspi->use_multi_mode = true;
+
+ if (mcspi->last_msg_kept_cs)
+ mcspi->use_multi_mode = false;
+
+ list_for_each_entry(tr, &msg->transfers, transfer_list) {
+ if (!tr->bits_per_word)
+ bits_per_word = msg->spi->bits_per_word;
+ else
+ bits_per_word = tr->bits_per_word;
+
+ /*
+ * Check if this transfer contains only one word;
+ */
+ if (bits_per_word < 8 && tr->len == 1) {
+ /* multi-mode is applicable, only one word (1..7 bits) */
+ } else if (bits_per_word >= 8 && tr->len == bits_per_word / 8) {
+ /* multi-mode is applicable, only one word (8..32 bits) */
+ } else {
+ /* multi-mode is not applicable: more than one word in the transfer */
+ mcspi->use_multi_mode = false;
+ }
- /* Only a single channel can have the FORCE bit enabled
+ if (list_is_last(&tr->transfer_list, &msg->transfers)) {
+ /* Check if transfer asks to keep the CS status after the whole message */
+ if (tr->cs_change) {
+ mcspi->use_multi_mode = false;
+ mcspi->last_msg_kept_cs = true;
+ } else {
+ mcspi->last_msg_kept_cs = false;
+ }
+ } else {
+ /* Check if transfer asks to change the CS status after the transfer */
+ if (!tr->cs_change)
+ mcspi->use_multi_mode = false;
+ }
+ }
+
+ omap2_mcspi_set_mode(ctlr);
+
+ /* In single mode only a single channel can have the FORCE bit enabled
* in its chconf0 register.
* Scan all channels and disable them except the current one.
* A FORCE can remain from a last transfer having cs_change enabled
+ *
+ * In multi mode all FORCE bits must be disabled.
*/
list_for_each_entry(cs, &ctx->cs, node) {
- if (msg->spi->controller_state == cs)
+ if (msg->spi->controller_state == cs && !mcspi->use_multi_mode) {
continue;
+ }
if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) {
cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
@@ -1283,29 +1331,29 @@ static int omap2_mcspi_prepare_message(struct spi_master *master,
return 0;
}
-static bool omap2_mcspi_can_dma(struct spi_master *master,
+static bool omap2_mcspi_can_dma(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
struct omap2_mcspi_dma *mcspi_dma =
&mcspi->dma_channels[spi_get_chipselect(spi, 0)];
if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx)
return false;
- if (spi_controller_is_slave(master))
+ if (spi_controller_is_target(ctlr))
return true;
- master->dma_rx = mcspi_dma->dma_rx;
- master->dma_tx = mcspi_dma->dma_tx;
+ ctlr->dma_rx = mcspi_dma->dma_rx;
+ ctlr->dma_tx = mcspi_dma->dma_tx;
return (xfer->len >= DMA_MIN_BYTES);
}
static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi)
{
- struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
struct omap2_mcspi_dma *mcspi_dma =
&mcspi->dma_channels[spi_get_chipselect(spi, 0)];
@@ -1317,7 +1365,7 @@ static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi)
static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
{
- struct spi_master *master = mcspi->master;
+ struct spi_controller *ctlr = mcspi->ctlr;
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
int ret = 0;
@@ -1325,12 +1373,11 @@ static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
if (ret < 0)
return ret;
- mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
+ mcspi_write_reg(ctlr, OMAP2_MCSPI_WAKEUPENABLE,
OMAP2_MCSPI_WAKEUPENABLE_WKEN);
ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
- omap2_mcspi_set_mode(master);
- pm_runtime_mark_last_busy(mcspi->dev);
+ omap2_mcspi_set_mode(ctlr);
pm_runtime_put_autosuspend(mcspi->dev);
return 0;
}
@@ -1353,8 +1400,8 @@ static int omap_mcspi_runtime_suspend(struct device *dev)
*/
static int omap_mcspi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
struct omap2_mcspi_cs *cs;
int error;
@@ -1364,8 +1411,8 @@ static int omap_mcspi_runtime_resume(struct device *dev)
dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error);
/* McSPI: context restore */
- mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl);
- mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable);
+ mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl);
+ mcspi_write_reg(ctlr, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable);
list_for_each_entry(cs, &ctx->cs, node) {
/*
@@ -1420,7 +1467,7 @@ MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
static int omap2_mcspi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *ctlr;
const struct omap2_mcspi_platform_config *pdata;
struct omap2_mcspi *mcspi;
struct resource *r;
@@ -1430,32 +1477,30 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
const struct of_device_id *match;
if (of_property_read_bool(node, "spi-slave"))
- master = spi_alloc_slave(&pdev->dev, sizeof(*mcspi));
+ ctlr = spi_alloc_target(&pdev->dev, sizeof(*mcspi));
else
- master = spi_alloc_master(&pdev->dev, sizeof(*mcspi));
- if (!master)
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*mcspi));
+ if (!ctlr)
return -ENOMEM;
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
- master->setup = omap2_mcspi_setup;
- master->auto_runtime_pm = true;
- master->prepare_message = omap2_mcspi_prepare_message;
- master->can_dma = omap2_mcspi_can_dma;
- master->transfer_one = omap2_mcspi_transfer_one;
- master->set_cs = omap2_mcspi_set_cs;
- master->cleanup = omap2_mcspi_cleanup;
- master->slave_abort = omap2_mcspi_slave_abort;
- master->dev.of_node = node;
- master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
- master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
- master->use_gpio_descriptors = true;
-
- platform_set_drvdata(pdev, master);
-
- mcspi = spi_master_get_devdata(master);
- mcspi->master = master;
+ ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ ctlr->setup = omap2_mcspi_setup;
+ ctlr->auto_runtime_pm = true;
+ ctlr->prepare_message = omap2_mcspi_prepare_message;
+ ctlr->can_dma = omap2_mcspi_can_dma;
+ ctlr->transfer_one = omap2_mcspi_transfer_one;
+ ctlr->set_cs = omap2_mcspi_set_cs;
+ ctlr->cleanup = omap2_mcspi_cleanup;
+ ctlr->target_abort = omap2_mcspi_target_abort;
+ ctlr->dev.of_node = node;
+ ctlr->use_gpio_descriptors = true;
+
+ platform_set_drvdata(pdev, ctlr);
+
+ mcspi = spi_controller_get_devdata(ctlr);
+ mcspi->ctlr = ctlr;
match = of_match_device(omap_mcspi_of_match, &pdev->dev);
if (match) {
@@ -1463,24 +1508,24 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
pdata = match->data;
of_property_read_u32(node, "ti,spi-num-cs", &num_cs);
- master->num_chipselect = num_cs;
+ ctlr->num_chipselect = num_cs;
if (of_property_read_bool(node, "ti,pindir-d0-out-d1-in"))
mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
} else {
pdata = dev_get_platdata(&pdev->dev);
- master->num_chipselect = pdata->num_cs;
+ ctlr->num_chipselect = pdata->num_cs;
mcspi->pin_dir = pdata->pin_dir;
}
regs_offset = pdata->regs_offset;
if (pdata->max_xfer_len) {
mcspi->max_xfer_len = pdata->max_xfer_len;
- master->max_transfer_size = omap2_mcspi_max_xfer_size;
+ ctlr->max_transfer_size = omap2_mcspi_max_xfer_size;
}
mcspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(mcspi->base)) {
status = PTR_ERR(mcspi->base);
- goto free_master;
+ goto free_ctlr;
}
mcspi->phys = r->start + regs_offset;
mcspi->base += regs_offset;
@@ -1489,37 +1534,48 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&mcspi->ctx.cs);
- mcspi->dma_channels = devm_kcalloc(&pdev->dev, master->num_chipselect,
+ mcspi->dma_channels = devm_kcalloc(&pdev->dev, ctlr->num_chipselect,
sizeof(struct omap2_mcspi_dma),
GFP_KERNEL);
if (mcspi->dma_channels == NULL) {
status = -ENOMEM;
- goto free_master;
+ goto free_ctlr;
}
- for (i = 0; i < master->num_chipselect; i++) {
+ for (i = 0; i < ctlr->num_chipselect; i++) {
sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);
sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
status = omap2_mcspi_request_dma(mcspi,
&mcspi->dma_channels[i]);
if (status == -EPROBE_DEFER)
- goto free_master;
+ goto free_ctlr;
}
status = platform_get_irq(pdev, 0);
- if (status < 0) {
- dev_err_probe(&pdev->dev, status, "no irq resource found\n");
- goto free_master;
- }
+ if (status < 0)
+ goto free_ctlr;
init_completion(&mcspi->txdone);
status = devm_request_irq(&pdev->dev, status,
omap2_mcspi_irq_handler, 0, pdev->name,
mcspi);
if (status) {
dev_err(&pdev->dev, "Cannot request IRQ");
- goto free_master;
+ goto free_ctlr;
+ }
+
+ mcspi->ref_clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
+ if (IS_ERR(mcspi->ref_clk)) {
+ status = PTR_ERR(mcspi->ref_clk);
+ dev_err_probe(&pdev->dev, status, "Failed to get ref_clk");
+ goto free_ctlr;
}
+ if (mcspi->ref_clk)
+ mcspi->ref_clk_hz = clk_get_rate(mcspi->ref_clk);
+ else
+ mcspi->ref_clk_hz = OMAP2_MCSPI_MAX_FREQ;
+ ctlr->max_speed_hz = mcspi->ref_clk_hz;
+ ctlr->min_speed_hz = mcspi->ref_clk_hz >> 15;
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
@@ -1529,7 +1585,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
if (status < 0)
goto disable_pm;
- status = devm_spi_register_controller(&pdev->dev, master);
+ status = devm_spi_register_controller(&pdev->dev, ctlr);
if (status < 0)
goto disable_pm;
@@ -1539,18 +1595,18 @@ disable_pm:
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
-free_master:
- omap2_mcspi_release_dma(master);
- spi_master_put(master);
+free_ctlr:
+ omap2_mcspi_release_dma(ctlr);
+ spi_controller_put(ctlr);
return status;
}
static void omap2_mcspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
- omap2_mcspi_release_dma(master);
+ omap2_mcspi_release_dma(ctlr);
pm_runtime_dont_use_autosuspend(mcspi->dev);
pm_runtime_put_sync(mcspi->dev);
@@ -1562,8 +1618,8 @@ MODULE_ALIAS("platform:omap2_mcspi");
static int __maybe_unused omap2_mcspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
int error;
error = pinctrl_pm_select_sleep_state(dev);
@@ -1571,9 +1627,9 @@ static int __maybe_unused omap2_mcspi_suspend(struct device *dev)
dev_warn(mcspi->dev, "%s: failed to set pins: %i\n",
__func__, error);
- error = spi_master_suspend(master);
+ error = spi_controller_suspend(ctlr);
if (error)
- dev_warn(mcspi->dev, "%s: master suspend failed: %i\n",
+ dev_warn(mcspi->dev, "%s: controller suspend failed: %i\n",
__func__, error);
return pm_runtime_force_suspend(dev);
@@ -1581,13 +1637,13 @@ static int __maybe_unused omap2_mcspi_suspend(struct device *dev)
static int __maybe_unused omap2_mcspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct spi_controller *ctlr = dev_get_drvdata(dev);
+ struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
int error;
- error = spi_master_resume(master);
+ error = spi_controller_resume(ctlr);
if (error)
- dev_warn(mcspi->dev, "%s: master resume failed: %i\n",
+ dev_warn(mcspi->dev, "%s: controller resume failed: %i\n",
__func__, error);
return pm_runtime_force_resume(dev);
@@ -1607,8 +1663,9 @@ static struct platform_driver omap2_mcspi_driver = {
.of_match_table = omap_mcspi_of_match,
},
.probe = omap2_mcspi_probe,
- .remove_new = omap2_mcspi_remove,
+ .remove = omap2_mcspi_remove,
};
module_platform_driver(omap2_mcspi_driver);
+MODULE_DESCRIPTION("OMAP2 McSPI controller driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index ad9e83e34297..43bd9f21137f 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -16,10 +16,9 @@
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/sizes.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define DRIVER_NAME "orion_spi"
@@ -91,7 +90,7 @@ struct orion_child_options {
};
struct orion_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base;
struct clk *clk;
struct clk *axi_clk;
@@ -142,7 +141,7 @@ static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
struct orion_spi *orion_spi;
const struct orion_spi_dev *devdata;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
devdata = orion_spi->devdata;
tclk_hz = clk_get_rate(orion_spi->clk);
@@ -236,7 +235,7 @@ orion_spi_mode_set(struct spi_device *spi)
u32 reg;
struct orion_spi *orion_spi;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
reg &= ~ORION_SPI_MODE_MASK;
@@ -258,7 +257,7 @@ orion_spi_50mhz_ac_timing_erratum(struct spi_device *spi, unsigned int speed)
u32 reg;
struct orion_spi *orion_spi;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
/*
* Erratum description: (Erratum NO. FE-9144572) The device
@@ -298,7 +297,7 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
unsigned int bits_per_word = spi->bits_per_word;
int rc;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
if ((t != NULL) && t->speed_hz)
speed = t->speed_hz;
@@ -331,7 +330,7 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable)
void __iomem *ctrl_reg;
u32 val;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
ctrl_reg = spi_reg(orion_spi, ORION_SPI_IF_CTRL_REG);
val = readl(ctrl_reg);
@@ -389,7 +388,7 @@ orion_spi_write_read_8bit(struct spi_device *spi,
cs_single_byte = spi->mode & SPI_CS_WORD;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
if (cs_single_byte)
orion_spi_set_cs(spi, 0);
@@ -440,7 +439,7 @@ orion_spi_write_read_16bit(struct spi_device *spi,
return -1;
}
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
tx_reg = spi_reg(orion_spi, ORION_SPI_DATA_OUT_REG);
rx_reg = spi_reg(orion_spi, ORION_SPI_DATA_IN_REG);
int_reg = spi_reg(orion_spi, ORION_SPI_INT_CAUSE_REG);
@@ -476,7 +475,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
word_len = spi->bits_per_word;
count = xfer->len;
- orion_spi = spi_master_get_devdata(spi->master);
+ orion_spi = spi_controller_get_devdata(spi->controller);
/*
* Use SPI direct write mode if base address is available
@@ -529,7 +528,7 @@ out:
return xfer->len - count;
}
-static int orion_spi_transfer_one(struct spi_master *master,
+static int orion_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
@@ -549,7 +548,7 @@ static int orion_spi_setup(struct spi_device *spi)
{
int ret;
#ifdef CONFIG_PM
- struct orion_spi *orion_spi = spi_master_get_devdata(spi->master);
+ struct orion_spi *orion_spi = spi_controller_get_devdata(spi->controller);
struct device *dev = orion_spi->dev;
orion_spi_runtime_resume(dev);
@@ -645,65 +644,61 @@ MODULE_DEVICE_TABLE(of, orion_spi_of_match_table);
static int orion_spi_probe(struct platform_device *pdev)
{
const struct orion_spi_dev *devdata;
- struct spi_master *master;
+ struct spi_controller *host;
struct orion_spi *spi;
struct resource *r;
unsigned long tclk_hz;
int status = 0;
struct device_node *np;
- master = spi_alloc_master(&pdev->dev, sizeof(*spi));
- if (master == NULL) {
- dev_dbg(&pdev->dev, "master allocation failed\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(*spi));
+ if (host == NULL) {
+ dev_dbg(&pdev->dev, "host allocation failed\n");
return -ENOMEM;
}
if (pdev->id != -1)
- master->bus_num = pdev->id;
+ host->bus_num = pdev->id;
if (pdev->dev.of_node) {
u32 cell_index;
if (!of_property_read_u32(pdev->dev.of_node, "cell-index",
&cell_index))
- master->bus_num = cell_index;
+ host->bus_num = cell_index;
}
/* we support all 4 SPI modes and LSB first option */
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST | SPI_CS_WORD;
- master->set_cs = orion_spi_set_cs;
- master->transfer_one = orion_spi_transfer_one;
- master->num_chipselect = ORION_NUM_CHIPSELECTS;
- master->setup = orion_spi_setup;
- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
- master->auto_runtime_pm = true;
- master->use_gpio_descriptors = true;
- master->flags = SPI_MASTER_GPIO_SS;
-
- platform_set_drvdata(pdev, master);
-
- spi = spi_master_get_devdata(master);
- spi->master = master;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST | SPI_CS_WORD;
+ host->set_cs = orion_spi_set_cs;
+ host->transfer_one = orion_spi_transfer_one;
+ host->num_chipselect = ORION_NUM_CHIPSELECTS;
+ host->setup = orion_spi_setup;
+ host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ host->auto_runtime_pm = true;
+ host->use_gpio_descriptors = true;
+ host->flags = SPI_CONTROLLER_GPIO_SS;
+
+ platform_set_drvdata(pdev, host);
+
+ spi = spi_controller_get_devdata(host);
+ spi->host = host;
spi->dev = &pdev->dev;
devdata = device_get_match_data(&pdev->dev);
devdata = devdata ? devdata : &orion_spi_dev_data;
spi->devdata = devdata;
- spi->clk = devm_clk_get(&pdev->dev, NULL);
+ spi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(spi->clk)) {
status = PTR_ERR(spi->clk);
goto out;
}
- status = clk_prepare_enable(spi->clk);
- if (status)
- goto out;
-
/* The following clock is only used by some SoCs */
spi->axi_clk = devm_clk_get(&pdev->dev, "axi");
if (PTR_ERR(spi->axi_clk) == -EPROBE_DEFER) {
status = -EPROBE_DEFER;
- goto out_rel_clk;
+ goto out;
}
if (!IS_ERR(spi->axi_clk))
clk_prepare_enable(spi->axi_clk);
@@ -719,14 +714,14 @@ static int orion_spi_probe(struct platform_device *pdev)
*/
if (of_device_is_compatible(pdev->dev.of_node,
"marvell,armada-370-spi"))
- master->max_speed_hz = min(devdata->max_hz,
+ host->max_speed_hz = min(devdata->max_hz,
DIV_ROUND_UP(tclk_hz, devdata->min_divisor));
else if (devdata->min_divisor)
- master->max_speed_hz =
+ host->max_speed_hz =
DIV_ROUND_UP(tclk_hz, devdata->min_divisor);
else
- master->max_speed_hz = devdata->max_hz;
- master->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor);
+ host->max_speed_hz = devdata->max_hz;
+ host->min_speed_hz = DIV_ROUND_UP(tclk_hz, devdata->max_divisor);
spi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(spi->base)) {
@@ -785,8 +780,8 @@ static int orion_spi_probe(struct platform_device *pdev)
if (status < 0)
goto out_rel_pm;
- master->dev.of_node = pdev->dev.of_node;
- status = spi_register_master(master);
+ host->dev.of_node = pdev->dev.of_node;
+ status = spi_register_controller(host);
if (status < 0)
goto out_rel_pm;
@@ -796,24 +791,21 @@ 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:
- spi_master_put(master);
+ spi_controller_put(host);
return status;
}
static void orion_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct orion_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct orion_spi *spi = spi_controller_get_devdata(host);
pm_runtime_get_sync(&pdev->dev);
clk_disable_unprepare(spi->axi_clk);
- clk_disable_unprepare(spi->clk);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
pm_runtime_disable(&pdev->dev);
}
@@ -822,8 +814,8 @@ MODULE_ALIAS("platform:" DRIVER_NAME);
#ifdef CONFIG_PM
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);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct orion_spi *spi = spi_controller_get_devdata(host);
clk_disable_unprepare(spi->axi_clk);
clk_disable_unprepare(spi->clk);
@@ -832,8 +824,8 @@ static int orion_spi_runtime_suspend(struct device *dev)
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);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct orion_spi *spi = spi_controller_get_devdata(host);
if (!IS_ERR(spi->axi_clk))
clk_prepare_enable(spi->axi_clk);
@@ -854,7 +846,7 @@ static struct platform_driver orion_spi_driver = {
.of_match_table = of_match_ptr(orion_spi_of_match_table),
},
.probe = orion_spi_probe,
- .remove_new = orion_spi_remove,
+ .remove = orion_spi_remove,
};
module_platform_driver(orion_spi_driver);
diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c
index 4445d82409d6..8577a19705de 100644
--- a/drivers/spi/spi-pci1xxxx.c
+++ b/drivers/spi/spi-pci1xxxx.c
@@ -5,16 +5,25 @@
// Kumaravel Thiagarajan <Kumaravel.Thiagarajan@microchip.com>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/pci_regs.h>
#include <linux/pci.h>
+#include <linux/spinlock.h>
#include <linux/spi/spi.h>
-#include <linux/delay.h>
+#include "internals.h"
#define DRV_NAME "spi-pci1xxxx"
#define SYS_FREQ_DEFAULT (62500000)
#define PCI1XXXX_SPI_MAX_CLOCK_HZ (30000000)
+#define PCI1XXXX_SPI_CLK_25MHZ (25000000)
#define PCI1XXXX_SPI_CLK_20MHZ (20000000)
#define PCI1XXXX_SPI_CLK_15MHZ (15000000)
#define PCI1XXXX_SPI_CLK_12MHZ (12000000)
@@ -32,8 +41,68 @@
#define SPI_MST_CTL_MODE_SEL (BIT(2))
#define SPI_MST_CTL_GO (BIT(0))
+#define SPI_PERI_ADDR_BASE (0x160000)
+#define SPI_SYSTEM_ADDR_BASE (0x2000)
#define SPI_MST1_ADDR_BASE (0x800)
+#define DEV_REV_REG (SPI_SYSTEM_ADDR_BASE + 0x00)
+#define SPI_SYSLOCK_REG (SPI_SYSTEM_ADDR_BASE + 0xA0)
+#define SPI_CONFIG_PERI_ENABLE_REG (SPI_SYSTEM_ADDR_BASE + 0x108)
+
+#define SPI_PERI_ENBLE_PF_MASK (GENMASK(17, 16))
+#define DEV_REV_MASK (GENMASK(7, 0))
+
+#define SPI_SYSLOCK BIT(4)
+#define SPI0 (0)
+#define SPI1 (1)
+
+/* DMA Related Registers */
+#define SPI_DMA_ADDR_BASE (0x1000)
+#define SPI_DMA_GLOBAL_WR_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x0C)
+#define SPI_DMA_WR_DOORBELL_REG (SPI_DMA_ADDR_BASE + 0x10)
+#define SPI_DMA_GLOBAL_RD_ENGINE_EN (SPI_DMA_ADDR_BASE + 0x2C)
+#define SPI_DMA_RD_DOORBELL_REG (SPI_DMA_ADDR_BASE + 0x30)
+#define SPI_DMA_INTR_WR_STS (SPI_DMA_ADDR_BASE + 0x4C)
+#define SPI_DMA_WR_INT_MASK (SPI_DMA_ADDR_BASE + 0x54)
+#define SPI_DMA_INTR_WR_CLR (SPI_DMA_ADDR_BASE + 0x58)
+#define SPI_DMA_ERR_WR_STS (SPI_DMA_ADDR_BASE + 0x5C)
+#define SPI_DMA_INTR_IMWR_WDONE_LOW (SPI_DMA_ADDR_BASE + 0x60)
+#define SPI_DMA_INTR_IMWR_WDONE_HIGH (SPI_DMA_ADDR_BASE + 0x64)
+#define SPI_DMA_INTR_IMWR_WABORT_LOW (SPI_DMA_ADDR_BASE + 0x68)
+#define SPI_DMA_INTR_IMWR_WABORT_HIGH (SPI_DMA_ADDR_BASE + 0x6C)
+#define SPI_DMA_INTR_WR_IMWR_DATA (SPI_DMA_ADDR_BASE + 0x70)
+#define SPI_DMA_INTR_RD_STS (SPI_DMA_ADDR_BASE + 0xA0)
+#define SPI_DMA_RD_INT_MASK (SPI_DMA_ADDR_BASE + 0xA8)
+#define SPI_DMA_INTR_RD_CLR (SPI_DMA_ADDR_BASE + 0xAC)
+#define SPI_DMA_ERR_RD_STS (SPI_DMA_ADDR_BASE + 0xB8)
+#define SPI_DMA_INTR_IMWR_RDONE_LOW (SPI_DMA_ADDR_BASE + 0xCC)
+#define SPI_DMA_INTR_IMWR_RDONE_HIGH (SPI_DMA_ADDR_BASE + 0xD0)
+#define SPI_DMA_INTR_IMWR_RABORT_LOW (SPI_DMA_ADDR_BASE + 0xD4)
+#define SPI_DMA_INTR_IMWR_RABORT_HIGH (SPI_DMA_ADDR_BASE + 0xD8)
+#define SPI_DMA_INTR_RD_IMWR_DATA (SPI_DMA_ADDR_BASE + 0xDC)
+
+#define SPI_DMA_CH0_WR_BASE (SPI_DMA_ADDR_BASE + 0x200)
+#define SPI_DMA_CH0_RD_BASE (SPI_DMA_ADDR_BASE + 0x300)
+#define SPI_DMA_CH1_WR_BASE (SPI_DMA_ADDR_BASE + 0x400)
+#define SPI_DMA_CH1_RD_BASE (SPI_DMA_ADDR_BASE + 0x500)
+
+#define SPI_DMA_CH_CTL1_OFFSET (0x00)
+#define SPI_DMA_CH_XFER_LEN_OFFSET (0x08)
+#define SPI_DMA_CH_SAR_LO_OFFSET (0x0C)
+#define SPI_DMA_CH_SAR_HI_OFFSET (0x10)
+#define SPI_DMA_CH_DAR_LO_OFFSET (0x14)
+#define SPI_DMA_CH_DAR_HI_OFFSET (0x18)
+
+#define SPI_DMA_CH0_DONE_INT BIT(0)
+#define SPI_DMA_CH1_DONE_INT BIT(1)
+#define SPI_DMA_CH0_ABORT_INT BIT(16)
+#define SPI_DMA_CH1_ABORT_INT BIT(17)
+#define SPI_DMA_DONE_INT_MASK(x) (1 << (x))
+#define SPI_DMA_ABORT_INT_MASK(x) (1 << (16 + (x)))
+#define DMA_CH_CONTROL_LIE BIT(3)
+#define DMA_CH_CONTROL_RIE BIT(4)
+#define DMA_INTR_EN (DMA_CH_CONTROL_RIE | DMA_CH_CONTROL_LIE)
+
/* x refers to SPI Host Controller HW instance id in the below macros - 0 or 1 */
#define SPI_MST_CMD_BUF_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x00)
@@ -50,6 +119,9 @@
#define SPI_MAX_DATA_LEN 320
#define PCI1XXXX_SPI_TIMEOUT (msecs_to_jiffies(100))
+#define SYSLOCK_RETRY_CNT (1000)
+#define SPI_DMA_ENGINE_EN (0x1)
+#define SPI_DMA_ENGINE_DIS (0x0)
#define SPI_INTR BIT(8)
#define SPI_FORCE_CE BIT(4)
@@ -60,13 +132,26 @@
#define SPI_SUSPEND_CONFIG 0x101
#define SPI_RESUME_CONFIG 0x203
+#define NUM_VEC_PER_INST 3
+
struct pci1xxxx_spi_internal {
u8 hw_inst;
+ u8 clkdiv;
+ int irq[NUM_VEC_PER_INST];
+ int mode;
bool spi_xfer_in_progress;
- int irq;
+ atomic_t dma_completion_count;
+ void *rx_buf;
+ bool dma_aborted_rd;
+ u32 bytes_recvd;
+ u32 tx_sgl_len;
+ u32 rx_sgl_len;
+ struct scatterlist *tx_sgl, *rx_sgl;
+ bool dma_aborted_wr;
struct completion spi_xfer_done;
- struct spi_master *spi_host;
+ struct spi_controller *spi_host;
struct pci1xxxx_spi *parent;
+ struct spi_transfer *xfer;
struct {
unsigned int dev_sel : 3;
unsigned int msi_vector_sel : 1;
@@ -76,8 +161,15 @@ struct pci1xxxx_spi_internal {
struct pci1xxxx_spi {
struct pci_dev *dev;
u8 total_hw_instances;
+ u8 dev_rev;
void __iomem *reg_base;
- struct pci1xxxx_spi_internal *spi_int[];
+ void __iomem *dma_offset_bar;
+ /* lock to safely access the DMA RD registers in isr */
+ spinlock_t dma_rd_reg_lock;
+ /* lock to safely access the DMA RD registers in isr */
+ spinlock_t dma_wr_reg_lock;
+ bool can_dma;
+ struct pci1xxxx_spi_internal *spi_int[] __counted_by(total_hw_instances);
};
static const struct pci_device_id pci1xxxx_spi_pci_id_table[] = {
@@ -106,6 +198,172 @@ static const struct pci_device_id pci1xxxx_spi_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, pci1xxxx_spi_pci_id_table);
+static irqreturn_t pci1xxxx_spi_isr_dma_rd(int irq, void *dev);
+static irqreturn_t pci1xxxx_spi_isr_dma_wr(int irq, void *dev);
+
+static int pci1xxxx_set_sys_lock(struct pci1xxxx_spi *par)
+{
+ writel(SPI_SYSLOCK, par->reg_base + SPI_SYSLOCK_REG);
+ return readl(par->reg_base + SPI_SYSLOCK_REG);
+}
+
+static int pci1xxxx_acquire_sys_lock(struct pci1xxxx_spi *par)
+{
+ u32 regval;
+
+ return readx_poll_timeout(pci1xxxx_set_sys_lock, par, regval,
+ (regval & SPI_SYSLOCK), 100,
+ SYSLOCK_RETRY_CNT * 100);
+}
+
+static void pci1xxxx_release_sys_lock(struct pci1xxxx_spi *par)
+{
+ writel(0x0, par->reg_base + SPI_SYSLOCK_REG);
+}
+
+static int pci1xxxx_check_spi_can_dma(struct pci1xxxx_spi *spi_bus, int hw_inst, int num_vector)
+{
+ struct pci_dev *pdev = spi_bus->dev;
+ u32 pf_num;
+ u32 regval;
+ int ret;
+
+ if (num_vector != hw_inst * NUM_VEC_PER_INST)
+ return -EOPNOTSUPP;
+
+ /*
+ * DEV REV Registers is a system register, HW Syslock bit
+ * should be acquired before accessing the register
+ */
+ ret = pci1xxxx_acquire_sys_lock(spi_bus);
+ if (ret) {
+ dev_err(&pdev->dev, "Error failed to acquire syslock\n");
+ return ret;
+ }
+
+ regval = readl(spi_bus->reg_base + DEV_REV_REG);
+ spi_bus->dev_rev = regval & DEV_REV_MASK;
+ if (spi_bus->dev_rev >= 0xC0) {
+ regval = readl(spi_bus->reg_base +
+ SPI_CONFIG_PERI_ENABLE_REG);
+ pf_num = regval & SPI_PERI_ENBLE_PF_MASK;
+ }
+
+ pci1xxxx_release_sys_lock(spi_bus);
+
+ /*
+ * DMA is supported only from C0 and SPI can use DMA only if
+ * it is mapped to PF0
+ */
+ if (spi_bus->dev_rev < 0xC0 || pf_num)
+ return -EOPNOTSUPP;
+
+ spi_bus->dma_offset_bar = pcim_iomap(pdev, 2, pci_resource_len(pdev, 2));
+ if (!spi_bus->dma_offset_bar) {
+ dev_warn(&pdev->dev, "Error failed to map dma bar, will operate in PIO mode\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
+ dev_warn(&pdev->dev, "Error failed to set DMA mask, will operate in PIO mode\n");
+ pcim_iounmap(pdev, spi_bus->dma_offset_bar);
+ spi_bus->dma_offset_bar = NULL;
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static void pci1xxxx_spi_dma_config(struct pci1xxxx_spi *spi_bus)
+{
+ struct pci1xxxx_spi_internal *spi_sub_ptr;
+ u8 iter, irq_index;
+ struct msi_msg msi;
+ u32 regval;
+ u16 data;
+
+ irq_index = spi_bus->total_hw_instances;
+ for (iter = 0; iter < spi_bus->total_hw_instances; iter++) {
+ spi_sub_ptr = spi_bus->spi_int[iter];
+ get_cached_msi_msg(spi_sub_ptr->irq[1], &msi);
+ if (iter == 0) {
+ writel(msi.address_hi, spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_IMWR_WDONE_HIGH);
+ writel(msi.address_hi, spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_IMWR_WABORT_HIGH);
+ writel(msi.address_hi, spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_IMWR_RDONE_HIGH);
+ writel(msi.address_hi, spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_IMWR_RABORT_HIGH);
+ writel(msi.address_lo, spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_IMWR_WDONE_LOW);
+ writel(msi.address_lo, spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_IMWR_WABORT_LOW);
+ writel(msi.address_lo, spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_IMWR_RDONE_LOW);
+ writel(msi.address_lo, spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_IMWR_RABORT_LOW);
+ writel(0, spi_bus->dma_offset_bar + SPI_DMA_INTR_WR_IMWR_DATA);
+ writel(0, spi_bus->dma_offset_bar + SPI_DMA_INTR_RD_IMWR_DATA);
+ }
+ regval = readl(spi_bus->dma_offset_bar + SPI_DMA_INTR_WR_IMWR_DATA);
+ data = msi.data + irq_index;
+ writel((regval | (data << (iter * 16))), spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_WR_IMWR_DATA);
+ regval = readl(spi_bus->dma_offset_bar + SPI_DMA_INTR_WR_IMWR_DATA);
+ irq_index++;
+
+ data = msi.data + irq_index;
+ regval = readl(spi_bus->dma_offset_bar + SPI_DMA_INTR_RD_IMWR_DATA);
+ writel(regval | (data << (iter * 16)), spi_bus->dma_offset_bar +
+ SPI_DMA_INTR_RD_IMWR_DATA);
+ regval = readl(spi_bus->dma_offset_bar + SPI_DMA_INTR_RD_IMWR_DATA);
+ irq_index++;
+ }
+}
+
+static int pci1xxxx_spi_dma_init(struct pci1xxxx_spi *spi_bus, int hw_inst, int num_vector)
+{
+ struct pci1xxxx_spi_internal *spi_sub_ptr;
+ u8 iter, irq_index;
+ int ret;
+
+ irq_index = hw_inst;
+ ret = pci1xxxx_check_spi_can_dma(spi_bus, hw_inst, num_vector);
+ if (ret)
+ return ret;
+
+ spin_lock_init(&spi_bus->dma_rd_reg_lock);
+ spin_lock_init(&spi_bus->dma_wr_reg_lock);
+ writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN);
+ writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN);
+
+ for (iter = 0; iter < hw_inst; iter++) {
+ spi_sub_ptr = spi_bus->spi_int[iter];
+ spi_sub_ptr->irq[1] = pci_irq_vector(spi_bus->dev, irq_index);
+ ret = devm_request_irq(&spi_bus->dev->dev, spi_sub_ptr->irq[1],
+ pci1xxxx_spi_isr_dma_wr, PCI1XXXX_IRQ_FLAGS,
+ pci_name(spi_bus->dev), spi_sub_ptr);
+ if (ret < 0)
+ return ret;
+
+ irq_index++;
+
+ spi_sub_ptr->irq[2] = pci_irq_vector(spi_bus->dev, irq_index);
+ ret = devm_request_irq(&spi_bus->dev->dev, spi_sub_ptr->irq[2],
+ pci1xxxx_spi_isr_dma_rd, PCI1XXXX_IRQ_FLAGS,
+ pci_name(spi_bus->dev), spi_sub_ptr);
+ if (ret < 0)
+ return ret;
+
+ irq_index++;
+ }
+ pci1xxxx_spi_dma_config(spi_bus);
+ dma_set_max_seg_size(&spi_bus->dev->dev, PCI1XXXX_SPI_BUFFER_SIZE);
+ spi_bus->can_dma = true;
+ return 0;
+}
+
static void pci1xxxx_spi_set_cs(struct spi_device *spi, bool enable)
{
struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi->controller);
@@ -124,12 +382,14 @@ static void pci1xxxx_spi_set_cs(struct spi_device *spi, bool enable)
writel(regval, par->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
}
-static u8 pci1xxxx_get_clock_div(u32 hz)
+static u8 pci1xxxx_get_clock_div(struct pci1xxxx_spi *par, u32 hz)
{
u8 val = 0;
if (hz >= PCI1XXXX_SPI_MAX_CLOCK_HZ)
val = 2;
+ else if (par->dev_rev >= 0xC0 && hz >= PCI1XXXX_SPI_CLK_25MHZ)
+ val = 1;
else if ((hz < PCI1XXXX_SPI_MAX_CLOCK_HZ) && (hz >= PCI1XXXX_SPI_CLK_20MHZ))
val = 3;
else if ((hz < PCI1XXXX_SPI_CLK_20MHZ) && (hz >= PCI1XXXX_SPI_CLK_15MHZ))
@@ -146,12 +406,80 @@ static u8 pci1xxxx_get_clock_div(u32 hz)
return val;
}
-static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
- struct spi_device *spi, struct spi_transfer *xfer)
+static void pci1xxxx_spi_setup_dma_to_io(struct pci1xxxx_spi_internal *p,
+ dma_addr_t dma_addr, u32 len)
+{
+ void __iomem *base;
+
+ if (!p->hw_inst)
+ base = p->parent->dma_offset_bar + SPI_DMA_CH0_RD_BASE;
+ else
+ base = p->parent->dma_offset_bar + SPI_DMA_CH1_RD_BASE;
+
+ writel(DMA_INTR_EN, base + SPI_DMA_CH_CTL1_OFFSET);
+ writel(len, base + SPI_DMA_CH_XFER_LEN_OFFSET);
+ writel(lower_32_bits(dma_addr), base + SPI_DMA_CH_SAR_LO_OFFSET);
+ writel(upper_32_bits(dma_addr), base + SPI_DMA_CH_SAR_HI_OFFSET);
+ /* Updated SPI Command Registers */
+ writel(lower_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_CMD_BUF_OFFSET(p->hw_inst)),
+ base + SPI_DMA_CH_DAR_LO_OFFSET);
+ writel(upper_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_CMD_BUF_OFFSET(p->hw_inst)),
+ base + SPI_DMA_CH_DAR_HI_OFFSET);
+}
+
+static void pci1xxxx_spi_setup_dma_from_io(struct pci1xxxx_spi_internal *p,
+ dma_addr_t dma_addr, u32 len)
+{
+ void *base;
+
+ if (!p->hw_inst)
+ base = p->parent->dma_offset_bar + SPI_DMA_CH0_WR_BASE;
+ else
+ base = p->parent->dma_offset_bar + SPI_DMA_CH1_WR_BASE;
+
+ writel(DMA_INTR_EN, base + SPI_DMA_CH_CTL1_OFFSET);
+ writel(len, base + SPI_DMA_CH_XFER_LEN_OFFSET);
+ writel(lower_32_bits(dma_addr), base + SPI_DMA_CH_DAR_LO_OFFSET);
+ writel(upper_32_bits(dma_addr), base + SPI_DMA_CH_DAR_HI_OFFSET);
+ writel(lower_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_RSP_BUF_OFFSET(p->hw_inst)),
+ base + SPI_DMA_CH_SAR_LO_OFFSET);
+ writel(upper_32_bits(SPI_PERI_ADDR_BASE + SPI_MST_RSP_BUF_OFFSET(p->hw_inst)),
+ base + SPI_DMA_CH_SAR_HI_OFFSET);
+}
+
+static void pci1xxxx_spi_setup(struct pci1xxxx_spi *par, u8 hw_inst, u32 mode,
+ u8 clkdiv, u32 len)
+{
+ u32 regval;
+
+ regval = readl(par->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst));
+ regval &= ~(SPI_MST_CTL_MODE_SEL | SPI_MST_CTL_CMD_LEN_MASK |
+ SPI_MST_CTL_SPEED_MASK);
+
+ if (mode == SPI_MODE_3)
+ regval |= SPI_MST_CTL_MODE_SEL;
+
+ regval |= FIELD_PREP(SPI_MST_CTL_CMD_LEN_MASK, len);
+ regval |= FIELD_PREP(SPI_MST_CTL_SPEED_MASK, clkdiv);
+ writel(regval, par->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst));
+}
+
+static void pci1xxxx_start_spi_xfer(struct pci1xxxx_spi_internal *p)
+{
+ u32 regval;
+
+ atomic_set(&p->dma_completion_count, 0);
+ regval = readl(p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+ regval |= SPI_MST_CTL_GO;
+ writel(regval, p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+}
+
+static int pci1xxxx_spi_transfer_with_io(struct spi_controller *spi_ctlr,
+ struct spi_device *spi, struct spi_transfer *xfer)
{
struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi_ctlr);
- int mode, len, loop_iter, transfer_len;
struct pci1xxxx_spi *par = p->parent;
+ int len, loop_iter, transfer_len;
unsigned long bytes_transfered;
unsigned long bytes_recvd;
unsigned long loop_count;
@@ -161,8 +489,8 @@ static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
u8 clkdiv;
p->spi_xfer_in_progress = true;
- mode = spi->mode;
- clkdiv = pci1xxxx_get_clock_div(xfer->speed_hz);
+ p->bytes_recvd = 0;
+ clkdiv = pci1xxxx_get_clock_div(par, xfer->speed_hz);
tx_buf = xfer->tx_buf;
rx_buf = xfer->rx_buf;
transfer_len = xfer->len;
@@ -186,26 +514,8 @@ static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
memcpy_toio(par->reg_base + SPI_MST_CMD_BUF_OFFSET(p->hw_inst),
&tx_buf[bytes_transfered], len);
bytes_transfered += len;
- regval = readl(par->reg_base +
- SPI_MST_CTL_REG_OFFSET(p->hw_inst));
- regval &= ~(SPI_MST_CTL_MODE_SEL | SPI_MST_CTL_CMD_LEN_MASK |
- SPI_MST_CTL_SPEED_MASK);
-
- if (mode == SPI_MODE_3)
- regval |= SPI_MST_CTL_MODE_SEL;
- else
- regval &= ~SPI_MST_CTL_MODE_SEL;
-
- regval |= (clkdiv << 5);
- regval &= ~SPI_MST_CTL_CMD_LEN_MASK;
- regval |= (len << 8);
- writel(regval, par->reg_base +
- SPI_MST_CTL_REG_OFFSET(p->hw_inst));
- regval = readl(par->reg_base +
- SPI_MST_CTL_REG_OFFSET(p->hw_inst));
- regval |= SPI_MST_CTL_GO;
- writel(regval, par->reg_base +
- SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+ pci1xxxx_spi_setup(par, p->hw_inst, spi->mode, clkdiv, len);
+ pci1xxxx_start_spi_xfer(p);
/* Wait for DMA_TERM interrupt */
result = wait_for_completion_timeout(&p->spi_xfer_done,
@@ -225,7 +535,109 @@ static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
return 0;
}
-static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev)
+static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi_ctlr);
+ struct pci1xxxx_spi *par = p->parent;
+ dma_addr_t tx_dma_addr = 0;
+ int ret = 0;
+ u32 regval;
+
+ p->spi_xfer_in_progress = true;
+ p->tx_sgl = xfer->tx_sg.sgl;
+ p->rx_sgl = xfer->rx_sg.sgl;
+ p->rx_buf = xfer->rx_buf;
+ atomic_set(&p->dma_completion_count, 1);
+ regval = readl(par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+ writel(regval, par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+
+ if (!xfer->tx_buf || !p->tx_sgl) {
+ ret = -EINVAL;
+ goto error;
+ }
+ p->xfer = xfer;
+ p->mode = spi->mode;
+ p->clkdiv = pci1xxxx_get_clock_div(par, xfer->speed_hz);
+ p->bytes_recvd = 0;
+ p->rx_buf = xfer->rx_buf;
+ regval = readl(par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+ writel(regval, par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+
+ tx_dma_addr = sg_dma_address(p->tx_sgl);
+ p->tx_sgl_len = sg_dma_len(p->tx_sgl);
+ pci1xxxx_spi_setup(par, p->hw_inst, p->mode, p->clkdiv, p->tx_sgl_len);
+ pci1xxxx_spi_setup_dma_to_io(p, (tx_dma_addr), p->tx_sgl_len);
+ writel(p->hw_inst, par->dma_offset_bar + SPI_DMA_RD_DOORBELL_REG);
+
+ reinit_completion(&p->spi_xfer_done);
+ /* Wait for DMA_TERM interrupt */
+ ret = wait_for_completion_timeout(&p->spi_xfer_done, PCI1XXXX_SPI_TIMEOUT);
+ if (!ret) {
+ ret = -ETIMEDOUT;
+ if (p->dma_aborted_rd) {
+ writel(SPI_DMA_ENGINE_DIS,
+ par->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN);
+ /*
+ * DMA ENGINE reset takes time if any TLP
+ * completeion in progress, should wait
+ * till DMA Engine reset is completed.
+ */
+ ret = readl_poll_timeout(par->dma_offset_bar +
+ SPI_DMA_GLOBAL_RD_ENGINE_EN, regval,
+ (regval == 0x0), 0, USEC_PER_MSEC);
+ if (ret) {
+ ret = -ECANCELED;
+ goto error;
+ }
+ writel(SPI_DMA_ENGINE_EN,
+ par->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN);
+ p->dma_aborted_rd = false;
+ ret = -ECANCELED;
+ }
+ if (p->dma_aborted_wr) {
+ writel(SPI_DMA_ENGINE_DIS,
+ par->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN);
+
+ /*
+ * DMA ENGINE reset takes time if any TLP
+ * completeion in progress, should wait
+ * till DMA Engine reset is completed.
+ */
+ ret = readl_poll_timeout(par->dma_offset_bar +
+ SPI_DMA_GLOBAL_WR_ENGINE_EN, regval,
+ (regval == 0x0), 0, USEC_PER_MSEC);
+ if (ret) {
+ ret = -ECANCELED;
+ goto error;
+ }
+
+ writel(SPI_DMA_ENGINE_EN,
+ par->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN);
+ p->dma_aborted_wr = false;
+ ret = -ECANCELED;
+ }
+ goto error;
+ }
+ ret = 0;
+
+error:
+ p->spi_xfer_in_progress = false;
+
+ return ret;
+}
+
+static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
+ struct spi_device *spi, struct spi_transfer *xfer)
+{
+ if (spi_xfer_is_dma_mapped(spi_ctlr, spi, xfer))
+ return pci1xxxx_spi_transfer_with_dma(spi_ctlr, spi, xfer);
+ else
+ return pci1xxxx_spi_transfer_with_io(spi_ctlr, spi, xfer);
+}
+
+static irqreturn_t pci1xxxx_spi_isr_io(int irq, void *dev)
{
struct pci1xxxx_spi_internal *p = dev;
irqreturn_t spi_int_fired = IRQ_NONE;
@@ -235,22 +647,164 @@ static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev)
regval = readl(p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
if (regval & SPI_INTR) {
/* Clear xfer_done */
- complete(&p->spi_xfer_done);
+ if (p->parent->can_dma && p->rx_buf)
+ writel(p->hw_inst, p->parent->dma_offset_bar +
+ SPI_DMA_WR_DOORBELL_REG);
+ else
+ complete(&p->parent->spi_int[p->hw_inst]->spi_xfer_done);
spi_int_fired = IRQ_HANDLED;
}
-
writel(regval, p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+ return spi_int_fired;
+}
+
+static void pci1xxxx_spi_setup_next_dma_to_io_transfer(struct pci1xxxx_spi_internal *p)
+{
+ dma_addr_t tx_dma_addr = 0;
+ u32 prev_len;
+
+ p->tx_sgl = sg_next(p->tx_sgl);
+ if (p->tx_sgl) {
+ tx_dma_addr = sg_dma_address(p->tx_sgl);
+ prev_len = p->tx_sgl_len;
+ p->tx_sgl_len = sg_dma_len(p->tx_sgl);
+ pci1xxxx_spi_setup_dma_to_io(p, tx_dma_addr, p->tx_sgl_len);
+ writel(p->hw_inst, p->parent->dma_offset_bar + SPI_DMA_RD_DOORBELL_REG);
+ if (prev_len != p->tx_sgl_len)
+ pci1xxxx_spi_setup(p->parent,
+ p->hw_inst, p->mode, p->clkdiv, p->tx_sgl_len);
+ }
+}
+
+static void pci1xxxx_spi_setup_next_dma_from_io_transfer(struct pci1xxxx_spi_internal *p)
+{
+ dma_addr_t rx_dma_addr = 0;
+
+ if (p->rx_sgl) {
+ rx_dma_addr = sg_dma_address(p->rx_sgl);
+ p->rx_sgl_len = sg_dma_len(p->rx_sgl);
+ pci1xxxx_spi_setup_dma_from_io(p, rx_dma_addr, p->rx_sgl_len);
+ writel(p->hw_inst, p->parent->dma_offset_bar + SPI_DMA_WR_DOORBELL_REG);
+ }
+}
+
+static irqreturn_t pci1xxxx_spi_isr_dma_rd(int irq, void *dev)
+{
+ struct pci1xxxx_spi_internal *p = dev;
+ irqreturn_t spi_int_fired = IRQ_NONE;
+ unsigned long flags;
+ u32 regval;
+
+ /* Clear the DMA RD INT and start spi xfer*/
+ regval = readl(p->parent->dma_offset_bar + SPI_DMA_INTR_RD_STS);
+ if (regval) {
+ if (regval & SPI_DMA_DONE_INT_MASK(p->hw_inst)) {
+ /* Start the SPI transfer only if both DMA read and write are completed */
+ if (atomic_inc_return(&p->dma_completion_count) == 2)
+ pci1xxxx_start_spi_xfer(p);
+ spi_int_fired = IRQ_HANDLED;
+ }
+ if (regval & SPI_DMA_ABORT_INT_MASK(p->hw_inst)) {
+ p->dma_aborted_rd = true;
+ spi_int_fired = IRQ_HANDLED;
+ }
+ spin_lock_irqsave(&p->parent->dma_rd_reg_lock, flags);
+ writel((SPI_DMA_DONE_INT_MASK(p->hw_inst) | SPI_DMA_ABORT_INT_MASK(p->hw_inst)),
+ p->parent->dma_offset_bar + SPI_DMA_INTR_RD_CLR);
+ spin_unlock_irqrestore(&p->parent->dma_rd_reg_lock, flags);
+ }
+ return spi_int_fired;
+}
+
+static irqreturn_t pci1xxxx_spi_isr_dma_wr(int irq, void *dev)
+{
+ struct pci1xxxx_spi_internal *p = dev;
+ irqreturn_t spi_int_fired = IRQ_NONE;
+ unsigned long flags;
+ u32 regval;
+
+ /* Clear the DMA WR INT */
+ regval = readl(p->parent->dma_offset_bar + SPI_DMA_INTR_WR_STS);
+ if (regval) {
+ if (regval & SPI_DMA_DONE_INT_MASK(p->hw_inst)) {
+ spi_int_fired = IRQ_HANDLED;
+ if (sg_is_last(p->rx_sgl)) {
+ complete(&p->spi_xfer_done);
+ } else {
+ p->rx_sgl = sg_next(p->rx_sgl);
+ if (atomic_inc_return(&p->dma_completion_count) == 2)
+ pci1xxxx_start_spi_xfer(p);
+ }
+ }
+ if (regval & SPI_DMA_ABORT_INT_MASK(p->hw_inst)) {
+ p->dma_aborted_wr = true;
+ spi_int_fired = IRQ_HANDLED;
+ }
+ spin_lock_irqsave(&p->parent->dma_wr_reg_lock, flags);
+ writel((SPI_DMA_DONE_INT_MASK(p->hw_inst) | SPI_DMA_ABORT_INT_MASK(p->hw_inst)),
+ p->parent->dma_offset_bar + SPI_DMA_INTR_WR_CLR);
+ spin_unlock_irqrestore(&p->parent->dma_wr_reg_lock, flags);
+ }
+ return spi_int_fired;
+}
+
+static irqreturn_t pci1xxxx_spi_isr_dma(int irq, void *dev)
+{
+ struct pci1xxxx_spi_internal *p = dev;
+ irqreturn_t spi_int_fired = IRQ_NONE;
+ u32 regval;
+
+ /* Clear the SPI GO_BIT Interrupt */
+ regval = readl(p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+ if (regval & SPI_INTR) {
+ pci1xxxx_spi_setup_next_dma_from_io_transfer(p);
+ pci1xxxx_spi_setup_next_dma_to_io_transfer(p);
+ spi_int_fired = IRQ_HANDLED;
+ writel(regval, p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+ }
return spi_int_fired;
}
+static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev)
+{
+ struct pci1xxxx_spi_internal *p = dev;
+
+ if (p->spi_host->can_dma(p->spi_host, NULL, p->xfer))
+ return pci1xxxx_spi_isr_dma(irq, dev);
+ else
+ return pci1xxxx_spi_isr_io(irq, dev);
+}
+
+static irqreturn_t pci1xxxx_spi_shared_isr(int irq, void *dev)
+{
+ struct pci1xxxx_spi *par = dev;
+ u8 i = 0;
+
+ for (i = 0; i < par->total_hw_instances; i++)
+ pci1xxxx_spi_isr(irq, par->spi_int[i]);
+
+ return IRQ_HANDLED;
+}
+
+static bool pci1xxxx_spi_can_dma(struct spi_controller *host,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(host);
+ struct pci1xxxx_spi *par = p->parent;
+
+ return par->can_dma;
+}
+
static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
u8 hw_inst_cnt, iter, start, only_sec_inst;
struct pci1xxxx_spi_internal *spi_sub_ptr;
struct device *dev = &pdev->dev;
struct pci1xxxx_spi *spi_bus;
- struct spi_master *spi_host;
+ struct spi_controller *spi_host;
+ int num_vector = 0;
u32 regval;
int ret;
@@ -275,8 +829,10 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
spi_bus->spi_int[iter] = devm_kzalloc(&pdev->dev,
sizeof(struct pci1xxxx_spi_internal),
GFP_KERNEL);
+ if (!spi_bus->spi_int[iter])
+ return -ENOMEM;
spi_sub_ptr = spi_bus->spi_int[iter];
- spi_sub_ptr->spi_host = devm_spi_alloc_master(dev, sizeof(struct spi_master));
+ spi_sub_ptr->spi_host = devm_spi_alloc_host(dev, sizeof(struct spi_controller));
if (!spi_sub_ptr->spi_host)
return -ENOMEM;
@@ -288,21 +844,19 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
if (ret)
return -ENOMEM;
- ret = pci_request_regions(pdev, DRV_NAME);
+ ret = pcim_request_all_regions(pdev, DRV_NAME);
if (ret)
return -ENOMEM;
spi_bus->reg_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
- if (!spi_bus->reg_base) {
- ret = -EINVAL;
- goto error;
- }
+ if (!spi_bus->reg_base)
+ return -EINVAL;
- ret = pci_alloc_irq_vectors(pdev, hw_inst_cnt, hw_inst_cnt,
- PCI_IRQ_ALL_TYPES);
- if (ret < 0) {
+ num_vector = pci_alloc_irq_vectors(pdev, 1, hw_inst_cnt * NUM_VEC_PER_INST,
+ PCI_IRQ_INTX | PCI_IRQ_MSI);
+ if (num_vector < 0) {
dev_err(&pdev->dev, "Error allocating MSI vectors\n");
- goto error;
+ return num_vector;
}
init_completion(&spi_sub_ptr->spi_xfer_done);
@@ -312,16 +866,21 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
regval &= ~SPI_INTR;
writel(regval, spi_bus->reg_base +
SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
- spi_sub_ptr->irq = pci_irq_vector(pdev, 0);
+ spi_sub_ptr->irq[0] = pci_irq_vector(pdev, 0);
- ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
- pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
- pci_name(pdev), spi_sub_ptr);
+ if (num_vector >= hw_inst_cnt)
+ ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq[0],
+ pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
+ pci_name(pdev), spi_sub_ptr);
+ else
+ ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq[0],
+ pci1xxxx_spi_shared_isr,
+ PCI1XXXX_IRQ_FLAGS | IRQF_SHARED,
+ pci_name(pdev), spi_bus);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to request irq : %d",
- spi_sub_ptr->irq);
- ret = -ENODEV;
- goto error;
+ spi_sub_ptr->irq[0]);
+ return -ENODEV;
}
/* This register is only applicable for 1st instance */
@@ -344,15 +903,16 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
regval &= ~SPI_INTR;
writel(regval, spi_bus->reg_base +
SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
- spi_sub_ptr->irq = pci_irq_vector(pdev, iter);
- ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
- pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
- pci_name(pdev), spi_sub_ptr);
- if (ret < 0) {
- dev_err(&pdev->dev, "Unable to request irq : %d",
- spi_sub_ptr->irq);
- ret = -ENODEV;
- goto error;
+ if (num_vector >= hw_inst_cnt) {
+ spi_sub_ptr->irq[0] = pci_irq_vector(pdev, iter);
+ ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq[0],
+ pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
+ pci_name(pdev), spi_sub_ptr);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to request irq : %d",
+ spi_sub_ptr->irq[0]);
+ return -ENODEV;
+ }
}
}
@@ -360,24 +920,26 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
spi_host->num_chipselect = SPI_CHIP_SEL_COUNT;
spi_host->mode_bits = SPI_MODE_0 | SPI_MODE_3 | SPI_RX_DUAL |
SPI_TX_DUAL | SPI_LOOP;
+ spi_host->can_dma = pci1xxxx_spi_can_dma;
spi_host->transfer_one = pci1xxxx_spi_transfer_one;
+
spi_host->set_cs = pci1xxxx_spi_set_cs;
spi_host->bits_per_word_mask = SPI_BPW_MASK(8);
spi_host->max_speed_hz = PCI1XXXX_SPI_MAX_CLOCK_HZ;
spi_host->min_speed_hz = PCI1XXXX_SPI_MIN_CLOCK_HZ;
- spi_host->flags = SPI_MASTER_MUST_TX;
- spi_master_set_devdata(spi_host, spi_sub_ptr);
- ret = devm_spi_register_master(dev, spi_host);
+ spi_host->flags = SPI_CONTROLLER_MUST_TX;
+ spi_controller_set_devdata(spi_host, spi_sub_ptr);
+ ret = devm_spi_register_controller(dev, spi_host);
if (ret)
- goto error;
+ return ret;
}
+ ret = pci1xxxx_spi_dma_init(spi_bus, hw_inst_cnt, num_vector);
+ if (ret && ret != -EOPNOTSUPP)
+ return ret;
+
pci_set_drvdata(pdev, spi_bus);
return 0;
-
-error:
- pci_release_regions(pdev);
- return ret;
}
static void store_restore_config(struct pci1xxxx_spi *spi_ptr,
@@ -415,7 +977,7 @@ static int pci1xxxx_spi_resume(struct device *dev)
for (iter = 0; iter < spi_ptr->total_hw_instances; iter++) {
spi_sub_ptr = spi_ptr->spi_int[iter];
- spi_master_resume(spi_sub_ptr->spi_host);
+ spi_controller_resume(spi_sub_ptr->spi_host);
writel(regval, spi_ptr->reg_base +
SPI_MST_EVENT_MASK_REG_OFFSET(iter));
@@ -441,7 +1003,7 @@ static int pci1xxxx_spi_suspend(struct device *dev)
/* Store existing config before suspend */
store_restore_config(spi_ptr, spi_sub_ptr, iter, 1);
- spi_master_suspend(spi_sub_ptr->spi_host);
+ spi_controller_suspend(spi_sub_ptr->spi_host);
writel(reg1, spi_ptr->reg_base +
SPI_MST_EVENT_MASK_REG_OFFSET(iter));
}
diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c
index 51dfb49523f3..fa0c1ee84532 100644
--- a/drivers/spi/spi-pic32-sqi.c
+++ b/drivers/spi/spi-pic32-sqi.c
@@ -139,7 +139,7 @@ struct pic32_sqi {
void __iomem *regs;
struct clk *sys_clk;
struct clk *base_clk; /* drives spi clock */
- struct spi_master *master;
+ struct spi_controller *host;
int irq;
struct completion xfer_done;
struct ring_desc *ring;
@@ -226,7 +226,7 @@ static irqreturn_t pic32_sqi_isr(int irq, void *dev_id)
if (status & PESQI_PKTCOMP) {
/* mask all interrupts */
enable = 0;
- /* complete trasaction */
+ /* complete transaction */
complete(&sqi->xfer_done);
}
@@ -316,9 +316,9 @@ static int pic32_sqi_one_transfer(struct pic32_sqi *sqi,
return 0;
}
-static int pic32_sqi_prepare_hardware(struct spi_master *master)
+static int pic32_sqi_prepare_hardware(struct spi_controller *host)
{
- struct pic32_sqi *sqi = spi_master_get_devdata(master);
+ struct pic32_sqi *sqi = spi_controller_get_devdata(host);
/* enable spi interface */
pic32_setbits(sqi->regs + PESQI_CONF_REG, PESQI_EN);
@@ -328,7 +328,7 @@ static int pic32_sqi_prepare_hardware(struct spi_master *master)
return 0;
}
-static bool pic32_sqi_can_dma(struct spi_master *master,
+static bool pic32_sqi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *x)
{
@@ -336,7 +336,7 @@ static bool pic32_sqi_can_dma(struct spi_master *master,
return true;
}
-static int pic32_sqi_one_message(struct spi_master *master,
+static int pic32_sqi_one_message(struct spi_controller *host,
struct spi_message *msg)
{
struct spi_device *spi = msg->spi;
@@ -344,10 +344,10 @@ static int pic32_sqi_one_message(struct spi_master *master,
struct spi_transfer *xfer;
struct pic32_sqi *sqi;
int ret = 0, mode;
- unsigned long timeout;
+ unsigned long time_left;
u32 val;
- sqi = spi_master_get_devdata(master);
+ sqi = spi_controller_get_devdata(host);
reinit_completion(&sqi->xfer_done);
msg->actual_length = 0;
@@ -410,9 +410,9 @@ static int pic32_sqi_one_message(struct spi_master *master,
writel(val, sqi->regs + PESQI_BD_CTRL_REG);
/* wait for xfer completion */
- timeout = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ);
- if (timeout == 0) {
- dev_err(&sqi->master->dev, "wait timedout/interrupted\n");
+ time_left = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ);
+ if (time_left == 0) {
+ dev_err(&sqi->host->dev, "wait timedout/interrupted\n");
ret = -ETIMEDOUT;
msg->status = ret;
} else {
@@ -434,14 +434,14 @@ xfer_out:
/* release ring descr */
ring_desc_put(sqi, rdesc);
}
- spi_finalize_current_message(spi->master);
+ spi_finalize_current_message(spi->controller);
return ret;
}
-static int pic32_sqi_unprepare_hardware(struct spi_master *master)
+static int pic32_sqi_unprepare_hardware(struct spi_controller *host)
{
- struct pic32_sqi *sqi = spi_master_get_devdata(master);
+ struct pic32_sqi *sqi = spi_controller_get_devdata(host);
/* disable clk */
pic32_clrbits(sqi->regs + PESQI_CLK_CTRL_REG, PESQI_CLK_EN);
@@ -458,18 +458,18 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi)
int i;
/* allocate coherent DMAable memory for hardware buffer descriptors. */
- sqi->bd = dma_alloc_coherent(&sqi->master->dev,
+ sqi->bd = dma_alloc_coherent(&sqi->host->dev,
sizeof(*bd) * PESQI_BD_COUNT,
&sqi->bd_dma, GFP_KERNEL);
if (!sqi->bd) {
- dev_err(&sqi->master->dev, "failed allocating dma buffer\n");
+ dev_err(&sqi->host->dev, "failed allocating dma buffer\n");
return -ENOMEM;
}
/* allocate software ring descriptors */
sqi->ring = kcalloc(PESQI_BD_COUNT, sizeof(*rdesc), GFP_KERNEL);
if (!sqi->ring) {
- dma_free_coherent(&sqi->master->dev,
+ dma_free_coherent(&sqi->host->dev,
sizeof(*bd) * PESQI_BD_COUNT,
sqi->bd, sqi->bd_dma);
return -ENOMEM;
@@ -498,7 +498,7 @@ static int ring_desc_ring_alloc(struct pic32_sqi *sqi)
static void ring_desc_ring_free(struct pic32_sqi *sqi)
{
- dma_free_coherent(&sqi->master->dev,
+ dma_free_coherent(&sqi->host->dev,
sizeof(struct buf_desc) * PESQI_BD_COUNT,
sqi->bd, sqi->bd_dma);
kfree(sqi->ring);
@@ -568,56 +568,43 @@ static void pic32_sqi_hw_init(struct pic32_sqi *sqi)
static int pic32_sqi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct pic32_sqi *sqi;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*sqi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*sqi));
+ if (!host)
return -ENOMEM;
- sqi = spi_master_get_devdata(master);
- sqi->master = master;
+ sqi = spi_controller_get_devdata(host);
+ sqi->host = host;
sqi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sqi->regs)) {
ret = PTR_ERR(sqi->regs);
- goto err_free_master;
+ goto err_free_host;
}
/* irq */
sqi->irq = platform_get_irq(pdev, 0);
if (sqi->irq < 0) {
ret = sqi->irq;
- goto err_free_master;
+ goto err_free_host;
}
/* clocks */
- sqi->sys_clk = devm_clk_get(&pdev->dev, "reg_ck");
+ sqi->sys_clk = devm_clk_get_enabled(&pdev->dev, "reg_ck");
if (IS_ERR(sqi->sys_clk)) {
ret = PTR_ERR(sqi->sys_clk);
dev_err(&pdev->dev, "no sys_clk ?\n");
- goto err_free_master;
+ goto err_free_host;
}
- sqi->base_clk = devm_clk_get(&pdev->dev, "spi_ck");
+ sqi->base_clk = devm_clk_get_enabled(&pdev->dev, "spi_ck");
if (IS_ERR(sqi->base_clk)) {
ret = PTR_ERR(sqi->base_clk);
dev_err(&pdev->dev, "no base clk ?\n");
- goto err_free_master;
- }
-
- ret = clk_prepare_enable(sqi->sys_clk);
- if (ret) {
- dev_err(&pdev->dev, "sys clk enable failed\n");
- goto err_free_master;
- }
-
- ret = clk_prepare_enable(sqi->base_clk);
- if (ret) {
- dev_err(&pdev->dev, "base clk enable failed\n");
- clk_disable_unprepare(sqi->sys_clk);
- goto err_free_master;
+ goto err_free_host;
}
init_completion(&sqi->xfer_done);
@@ -629,7 +616,7 @@ static int pic32_sqi_probe(struct platform_device *pdev)
ret = ring_desc_ring_alloc(sqi);
if (ret) {
dev_err(&pdev->dev, "ring alloc failed\n");
- goto err_disable_clk;
+ goto err_free_host;
}
/* install irq handlers */
@@ -640,24 +627,24 @@ static int pic32_sqi_probe(struct platform_device *pdev)
goto err_free_ring;
}
- /* register master */
- master->num_chipselect = 2;
- master->max_speed_hz = clk_get_rate(sqi->base_clk);
- master->dma_alignment = 32;
- master->max_dma_len = PESQI_BD_BUF_LEN_MAX;
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL |
+ /* register host */
+ host->num_chipselect = 2;
+ host->max_speed_hz = clk_get_rate(sqi->base_clk);
+ host->dma_alignment = 32;
+ host->max_dma_len = PESQI_BD_BUF_LEN_MAX;
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL |
SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->can_dma = pic32_sqi_can_dma;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
- master->transfer_one_message = pic32_sqi_one_message;
- master->prepare_transfer_hardware = pic32_sqi_prepare_hardware;
- master->unprepare_transfer_hardware = pic32_sqi_unprepare_hardware;
-
- ret = devm_spi_register_master(&pdev->dev, master);
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->can_dma = pic32_sqi_can_dma;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
+ host->transfer_one_message = pic32_sqi_one_message;
+ host->prepare_transfer_hardware = pic32_sqi_prepare_hardware;
+ host->unprepare_transfer_hardware = pic32_sqi_unprepare_hardware;
+
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&master->dev, "failed registering spi master\n");
+ dev_err(&host->dev, "failed registering spi host\n");
free_irq(sqi->irq, sqi);
goto err_free_ring;
}
@@ -669,12 +656,8 @@ static int pic32_sqi_probe(struct platform_device *pdev)
err_free_ring:
ring_desc_ring_free(sqi);
-err_disable_clk:
- clk_disable_unprepare(sqi->base_clk);
- clk_disable_unprepare(sqi->sys_clk);
-
-err_free_master:
- spi_master_put(master);
+err_free_host:
+ spi_controller_put(host);
return ret;
}
@@ -685,10 +668,6 @@ static void pic32_sqi_remove(struct platform_device *pdev)
/* release resources */
free_irq(sqi->irq, sqi);
ring_desc_ring_free(sqi);
-
- /* disable clk */
- clk_disable_unprepare(sqi->base_clk);
- clk_disable_unprepare(sqi->sys_clk);
}
static const struct of_device_id pic32_sqi_of_ids[] = {
@@ -703,7 +682,7 @@ static struct platform_driver pic32_sqi_driver = {
.of_match_table = of_match_ptr(pic32_sqi_of_ids),
},
.probe = pic32_sqi_probe,
- .remove_new = pic32_sqi_remove,
+ .remove = pic32_sqi_remove,
};
module_platform_driver(pic32_sqi_driver);
diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c
index f2af5e653f3d..369850d14313 100644
--- a/drivers/spi/spi-pic32.c
+++ b/drivers/spi/spi-pic32.c
@@ -11,13 +11,13 @@
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
@@ -100,7 +100,7 @@ struct pic32_spi {
int tx_irq;
u32 fifo_n_byte; /* FIFO depth in bytes */
struct clk *clk;
- struct spi_master *master;
+ struct spi_controller *host;
/* Current controller setting */
u32 speed_hz; /* spi-clk rate */
u32 mode;
@@ -224,9 +224,9 @@ static void pic32_err_stop(struct pic32_spi *pic32s, const char *msg)
disable_irq_nosync(pic32s->tx_irq);
/* Show err message and abort xfer with err */
- dev_err(&pic32s->master->dev, "%s\n", msg);
- if (pic32s->master->cur_msg)
- pic32s->master->cur_msg->status = -EIO;
+ dev_err(&pic32s->host->dev, "%s\n", msg);
+ if (pic32s->host->cur_msg)
+ pic32s->host->cur_msg->status = -EIO;
complete(&pic32s->xfer_done);
}
@@ -250,7 +250,7 @@ static irqreturn_t pic32_spi_fault_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
- if (!pic32s->master->cur_msg) {
+ if (!pic32s->host->cur_msg) {
pic32_err_stop(pic32s, "err_irq: no mesg");
return IRQ_NONE;
}
@@ -300,16 +300,16 @@ static void pic32_spi_dma_rx_notify(void *data)
static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
struct spi_transfer *xfer)
{
- struct spi_master *master = pic32s->master;
+ struct spi_controller *host = pic32s->host;
struct dma_async_tx_descriptor *desc_rx;
struct dma_async_tx_descriptor *desc_tx;
dma_cookie_t cookie;
int ret;
- if (!master->dma_rx || !master->dma_tx)
+ if (!host->dma_rx || !host->dma_tx)
return -ENODEV;
- desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
+ desc_rx = dmaengine_prep_slave_sg(host->dma_rx,
xfer->rx_sg.sgl,
xfer->rx_sg.nents,
DMA_DEV_TO_MEM,
@@ -319,7 +319,7 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
goto err_dma;
}
- desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
+ desc_tx = dmaengine_prep_slave_sg(host->dma_tx,
xfer->tx_sg.sgl,
xfer->tx_sg.nents,
DMA_MEM_TO_DEV,
@@ -343,13 +343,13 @@ static int pic32_spi_dma_transfer(struct pic32_spi *pic32s,
if (ret)
goto err_dma_tx;
- dma_async_issue_pending(master->dma_rx);
- dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(host->dma_rx);
+ dma_async_issue_pending(host->dma_tx);
return 0;
err_dma_tx:
- dmaengine_terminate_all(master->dma_rx);
+ dmaengine_terminate_all(host->dma_rx);
err_dma:
return ret;
}
@@ -357,7 +357,7 @@ err_dma:
static int pic32_spi_dma_config(struct pic32_spi *pic32s, u32 dma_width)
{
int buf_offset = offsetof(struct pic32_spi_regs, buf);
- struct spi_master *master = pic32s->master;
+ struct spi_controller *host = pic32s->host;
struct dma_slave_config cfg;
int ret;
@@ -371,16 +371,16 @@ static int pic32_spi_dma_config(struct pic32_spi *pic32s, u32 dma_width)
cfg.dst_addr_width = dma_width;
/* tx channel */
cfg.direction = DMA_MEM_TO_DEV;
- ret = dmaengine_slave_config(master->dma_tx, &cfg);
+ ret = dmaengine_slave_config(host->dma_tx, &cfg);
if (ret) {
- dev_err(&master->dev, "tx channel setup failed\n");
+ dev_err(&host->dev, "tx channel setup failed\n");
return ret;
}
/* rx channel */
cfg.direction = DMA_DEV_TO_MEM;
- ret = dmaengine_slave_config(master->dma_rx, &cfg);
+ ret = dmaengine_slave_config(host->dma_rx, &cfg);
if (ret)
- dev_err(&master->dev, "rx channel setup failed\n");
+ dev_err(&host->dev, "rx channel setup failed\n");
return ret;
}
@@ -430,19 +430,19 @@ static int pic32_spi_set_word_size(struct pic32_spi *pic32s, u8 bits_per_word)
return 0;
}
-static int pic32_spi_prepare_hardware(struct spi_master *master)
+static int pic32_spi_prepare_hardware(struct spi_controller *host)
{
- struct pic32_spi *pic32s = spi_master_get_devdata(master);
+ struct pic32_spi *pic32s = spi_controller_get_devdata(host);
pic32_spi_enable(pic32s);
return 0;
}
-static int pic32_spi_prepare_message(struct spi_master *master,
+static int pic32_spi_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct pic32_spi *pic32s = spi_master_get_devdata(master);
+ struct pic32_spi *pic32s = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
u32 val;
@@ -481,27 +481,27 @@ static int pic32_spi_prepare_message(struct spi_master *master,
return 0;
}
-static bool pic32_spi_can_dma(struct spi_master *master,
+static bool pic32_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct pic32_spi *pic32s = spi_master_get_devdata(master);
+ struct pic32_spi *pic32s = spi_controller_get_devdata(host);
/* skip using DMA on small size transfer to avoid overhead.*/
return (xfer->len >= PIC32_DMA_LEN_MIN) &&
test_bit(PIC32F_DMA_PREP, &pic32s->flags);
}
-static int pic32_spi_one_transfer(struct spi_master *master,
+static int pic32_spi_one_transfer(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *transfer)
{
struct pic32_spi *pic32s;
bool dma_issued = false;
- unsigned long timeout;
+ unsigned long time_left;
int ret;
- pic32s = spi_master_get_devdata(master);
+ pic32s = spi_controller_get_devdata(host);
/* handle transfer specific word size change */
if (transfer->bits_per_word &&
@@ -545,12 +545,12 @@ static int pic32_spi_one_transfer(struct spi_master *master,
}
/* wait for completion */
- timeout = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ);
- if (timeout == 0) {
+ time_left = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ);
+ if (time_left == 0) {
dev_err(&spi->dev, "wait error/timedout\n");
if (dma_issued) {
- dmaengine_terminate_all(master->dma_rx);
- dmaengine_terminate_all(master->dma_tx);
+ dmaengine_terminate_all(host->dma_rx);
+ dmaengine_terminate_all(host->dma_tx);
}
ret = -ETIMEDOUT;
} else {
@@ -560,16 +560,16 @@ static int pic32_spi_one_transfer(struct spi_master *master,
return ret;
}
-static int pic32_spi_unprepare_message(struct spi_master *master,
+static int pic32_spi_unprepare_message(struct spi_controller *host,
struct spi_message *msg)
{
/* nothing to do */
return 0;
}
-static int pic32_spi_unprepare_hardware(struct spi_master *master)
+static int pic32_spi_unprepare_hardware(struct spi_controller *host)
{
- struct pic32_spi *pic32s = spi_master_get_devdata(master);
+ struct pic32_spi *pic32s = spi_controller_get_devdata(host);
pic32_spi_disable(pic32s);
@@ -605,28 +605,28 @@ static void pic32_spi_cleanup(struct spi_device *spi)
static int pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
{
- struct spi_master *master = pic32s->master;
+ struct spi_controller *host = pic32s->host;
int ret = 0;
- master->dma_rx = dma_request_chan(dev, "spi-rx");
- if (IS_ERR(master->dma_rx)) {
- if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER)
+ host->dma_rx = dma_request_chan(dev, "spi-rx");
+ if (IS_ERR(host->dma_rx)) {
+ if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER)
ret = -EPROBE_DEFER;
else
dev_warn(dev, "RX channel not found.\n");
- master->dma_rx = NULL;
+ host->dma_rx = NULL;
goto out_err;
}
- master->dma_tx = dma_request_chan(dev, "spi-tx");
- if (IS_ERR(master->dma_tx)) {
- if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER)
+ host->dma_tx = dma_request_chan(dev, "spi-tx");
+ if (IS_ERR(host->dma_tx)) {
+ if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER)
ret = -EPROBE_DEFER;
else
dev_warn(dev, "TX channel not found.\n");
- master->dma_tx = NULL;
+ host->dma_tx = NULL;
goto out_err;
}
@@ -639,14 +639,14 @@ static int pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
return 0;
out_err:
- if (master->dma_rx) {
- dma_release_channel(master->dma_rx);
- master->dma_rx = NULL;
+ if (host->dma_rx) {
+ dma_release_channel(host->dma_rx);
+ host->dma_rx = NULL;
}
- if (master->dma_tx) {
- dma_release_channel(master->dma_tx);
- master->dma_tx = NULL;
+ if (host->dma_tx) {
+ dma_release_channel(host->dma_tx);
+ host->dma_tx = NULL;
}
return ret;
@@ -658,11 +658,11 @@ static void pic32_spi_dma_unprep(struct pic32_spi *pic32s)
return;
clear_bit(PIC32F_DMA_PREP, &pic32s->flags);
- if (pic32s->master->dma_rx)
- dma_release_channel(pic32s->master->dma_rx);
+ if (pic32s->host->dma_rx)
+ dma_release_channel(pic32s->host->dma_rx);
- if (pic32s->master->dma_tx)
- dma_release_channel(pic32s->master->dma_tx);
+ if (pic32s->host->dma_tx)
+ dma_release_channel(pic32s->host->dma_tx);
}
static void pic32_spi_hw_init(struct pic32_spi *pic32s)
@@ -680,7 +680,7 @@ static void pic32_spi_hw_init(struct pic32_spi *pic32s)
/* disable framing mode */
ctrl &= ~CTRL_FRMEN;
- /* enable master mode while disabled */
+ /* enable host mode while disabled */
ctrl |= CTRL_MSTEN;
/* set tx fifo threshold interrupt */
@@ -730,17 +730,13 @@ static int pic32_spi_hw_probe(struct platform_device *pdev,
return pic32s->tx_irq;
/* get clock */
- pic32s->clk = devm_clk_get(&pdev->dev, "mck0");
+ pic32s->clk = devm_clk_get_enabled(&pdev->dev, "mck0");
if (IS_ERR(pic32s->clk)) {
dev_err(&pdev->dev, "clk not found\n");
ret = PTR_ERR(pic32s->clk);
goto err_unmap_mem;
}
- ret = clk_prepare_enable(pic32s->clk);
- if (ret)
- goto err_unmap_mem;
-
pic32_spi_hw_init(pic32s);
return 0;
@@ -752,36 +748,36 @@ err_unmap_mem:
static int pic32_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct pic32_spi *pic32s;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*pic32s));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*pic32s));
+ if (!host)
return -ENOMEM;
- pic32s = spi_master_get_devdata(master);
- pic32s->master = master;
+ pic32s = spi_controller_get_devdata(host);
+ pic32s->host = host;
ret = pic32_spi_hw_probe(pdev, pic32s);
if (ret)
- goto err_master;
-
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH;
- master->num_chipselect = 1; /* single chip-select */
- master->max_speed_hz = clk_get_rate(pic32s->clk);
- master->setup = pic32_spi_setup;
- master->cleanup = pic32_spi_cleanup;
- master->flags = SPI_MASTER_MUST_TX | SPI_MASTER_MUST_RX;
- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
+ goto err_host;
+
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_MODE_3 | SPI_MODE_0 | SPI_CS_HIGH;
+ host->num_chipselect = 1; /* single chip-select */
+ host->max_speed_hz = clk_get_rate(pic32s->clk);
+ host->setup = pic32_spi_setup;
+ host->cleanup = pic32_spi_cleanup;
+ host->flags = SPI_CONTROLLER_MUST_TX | SPI_CONTROLLER_MUST_RX;
+ host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
SPI_BPW_MASK(32);
- master->transfer_one = pic32_spi_one_transfer;
- master->prepare_message = pic32_spi_prepare_message;
- master->unprepare_message = pic32_spi_unprepare_message;
- master->prepare_transfer_hardware = pic32_spi_prepare_hardware;
- master->unprepare_transfer_hardware = pic32_spi_unprepare_hardware;
- master->use_gpio_descriptors = true;
+ host->transfer_one = pic32_spi_one_transfer;
+ host->prepare_message = pic32_spi_prepare_message;
+ host->unprepare_message = pic32_spi_unprepare_message;
+ host->prepare_transfer_hardware = pic32_spi_prepare_hardware;
+ host->unprepare_transfer_hardware = pic32_spi_unprepare_hardware;
+ host->use_gpio_descriptors = true;
/* optional DMA support */
ret = pic32_spi_dma_prep(pic32s, &pdev->dev);
@@ -789,7 +785,7 @@ static int pic32_spi_probe(struct platform_device *pdev)
goto err_bailout;
if (test_bit(PIC32F_DMA_PREP, &pic32s->flags))
- master->can_dma = pic32_spi_can_dma;
+ host->can_dma = pic32_spi_can_dma;
init_completion(&pic32s->xfer_done);
pic32s->mode = -1;
@@ -824,10 +820,10 @@ static int pic32_spi_probe(struct platform_device *pdev)
goto err_bailout;
}
- /* register master */
- ret = devm_spi_register_master(&pdev->dev, master);
+ /* register host */
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&master->dev, "failed registering spi master\n");
+ dev_err(&host->dev, "failed registering spi host\n");
goto err_bailout;
}
@@ -837,9 +833,8 @@ static int pic32_spi_probe(struct platform_device *pdev)
err_bailout:
pic32_spi_dma_unprep(pic32s);
- clk_disable_unprepare(pic32s->clk);
-err_master:
- spi_master_put(master);
+err_host:
+ spi_controller_put(host);
return ret;
}
@@ -849,7 +844,6 @@ static void pic32_spi_remove(struct platform_device *pdev)
pic32s = platform_get_drvdata(pdev);
pic32_spi_disable(pic32s);
- clk_disable_unprepare(pic32s->clk);
pic32_spi_dma_unprep(pic32s);
}
@@ -865,7 +859,7 @@ static struct platform_driver pic32_spi_driver = {
.of_match_table = of_match_ptr(pic32_spi_of_match),
},
.probe = pic32_spi_probe,
- .remove_new = pic32_spi_remove,
+ .remove = pic32_spi_remove,
};
module_platform_driver(pic32_spi_driver);
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 1af75eff26b6..9e56e8774614 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -33,6 +33,7 @@
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/minmax.h>
/*
* This macro is used to define some register default values.
@@ -336,16 +337,10 @@ struct vendor_data {
* @phybase: the physical memory where the SSP device resides
* @virtbase: the virtual memory where the SSP is mapped
* @clk: outgoing clock "SPICLK" for the SPI bus
- * @master: SPI framework hookup
- * @master_info: controller-specific data from machine setup
- * @pump_transfers: Tasklet used in Interrupt Transfer mode
- * @cur_msg: Pointer to current spi_message being processed
+ * @host: SPI framework hookup
+ * @host_info: controller-specific data from machine setup
* @cur_transfer: Pointer to current spi_transfer
* @cur_chip: pointer to current clients chip(assigned from controller_state)
- * @next_msg_cs_active: the next message in the queue has been examined
- * and it was found that it uses the same chip select as the previous
- * message, so we left it active after the previous transfer, and it's
- * active already.
* @tx: current position in TX buffer to be read
* @tx_end: end position in TX buffer to be read
* @rx: current position in RX buffer to be written
@@ -362,7 +357,6 @@ struct vendor_data {
* @dummypage: a dummy page used for driving data on the bus with DMA
* @dma_running: indicates whether DMA is in operation
* @cur_cs: current chip select index
- * @cur_gpiod: current chip select GPIO descriptor
*/
struct pl022 {
struct amba_device *adev;
@@ -370,14 +364,10 @@ struct pl022 {
resource_size_t phybase;
void __iomem *virtbase;
struct clk *clk;
- struct spi_master *master;
- struct pl022_ssp_controller *master_info;
- /* Message per-transfer pump */
- struct tasklet_struct pump_transfers;
- struct spi_message *cur_msg;
+ struct spi_controller *host;
+ struct pl022_ssp_controller *host_info;
struct spi_transfer *cur_transfer;
struct chip_data *cur_chip;
- bool next_msg_cs_active;
void *tx;
void *tx_end;
void *rx;
@@ -397,7 +387,6 @@ struct pl022 {
bool dma_running;
#endif
int cur_cs;
- struct gpio_desc *cur_gpiod;
};
/**
@@ -431,99 +420,29 @@ struct chip_data {
/**
* internal_cs_control - Control chip select signals via SSP_CSR.
* @pl022: SSP driver private data structure
- * @command: select/delect the chip
+ * @enable: select/delect the chip
*
* Used on controller with internal chip select control via SSP_CSR register
* (vendor extension). Each of the 5 LSB in the register controls one chip
* select signal.
*/
-static void internal_cs_control(struct pl022 *pl022, u32 command)
+static void internal_cs_control(struct pl022 *pl022, bool enable)
{
u32 tmp;
tmp = readw(SSP_CSR(pl022->virtbase));
- if (command == SSP_CHIP_SELECT)
+ if (enable)
tmp &= ~BIT(pl022->cur_cs);
else
tmp |= BIT(pl022->cur_cs);
writew(tmp, SSP_CSR(pl022->virtbase));
}
-static void pl022_cs_control(struct pl022 *pl022, u32 command)
+static void pl022_cs_control(struct spi_device *spi, bool enable)
{
+ struct pl022 *pl022 = spi_controller_get_devdata(spi->controller);
if (pl022->vendor->internal_cs_ctrl)
- internal_cs_control(pl022, command);
- else if (pl022->cur_gpiod)
- /*
- * This needs to be inverted since with GPIOLIB in
- * control, the inversion will be handled by
- * GPIOLIB's active low handling. The "command"
- * passed into this function will be SSP_CHIP_SELECT
- * which is enum:ed to 0, so we need the inverse
- * (1) to activate chip select.
- */
- gpiod_set_value(pl022->cur_gpiod, !command);
-}
-
-/**
- * giveback - current spi_message is over, schedule next message and call
- * callback of this message. Assumes that caller already
- * set message->status; dma and pio irqs are blocked
- * @pl022: SSP driver private data structure
- */
-static void giveback(struct pl022 *pl022)
-{
- struct spi_transfer *last_transfer;
- pl022->next_msg_cs_active = false;
-
- last_transfer = list_last_entry(&pl022->cur_msg->transfers,
- struct spi_transfer, transfer_list);
-
- /* Delay if requested before any change in chip select */
- /*
- * FIXME: This runs in interrupt context.
- * Is this really smart?
- */
- spi_transfer_delay_exec(last_transfer);
-
- if (!last_transfer->cs_change) {
- struct spi_message *next_msg;
-
- /*
- * cs_change was not set. We can keep the chip select
- * enabled if there is message in the queue and it is
- * for the same spi device.
- *
- * We cannot postpone this until pump_messages, because
- * after calling msg->complete (below) the driver that
- * sent the current message could be unloaded, which
- * could invalidate the cs_control() callback...
- */
- /* get a pointer to the next message, if any */
- next_msg = spi_get_next_queued_message(pl022->master);
-
- /*
- * see if the next and current messages point
- * to the same spi device.
- */
- if (next_msg && next_msg->spi != pl022->cur_msg->spi)
- next_msg = NULL;
- if (!next_msg || pl022->cur_msg->state == STATE_ERROR)
- pl022_cs_control(pl022, SSP_CHIP_DESELECT);
- else
- pl022->next_msg_cs_active = true;
-
- }
-
- pl022->cur_msg = NULL;
- pl022->cur_transfer = NULL;
- pl022->cur_chip = NULL;
-
- /* disable the SPI/SSP operation */
- writew((readw(SSP_CR1(pl022->virtbase)) &
- (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
-
- spi_finalize_current_message(pl022->master);
+ internal_cs_control(pl022, enable);
}
/**
@@ -757,30 +676,6 @@ static void readwriter(struct pl022 *pl022)
*/
}
-/**
- * next_transfer - Move to the Next transfer in the current spi message
- * @pl022: SSP driver private data structure
- *
- * This function moves though the linked list of spi transfers in the
- * current spi message and returns with the state of current spi
- * message i.e whether its last transfer is done(STATE_DONE) or
- * Next transfer is ready(STATE_RUNNING)
- */
-static void *next_transfer(struct pl022 *pl022)
-{
- struct spi_message *msg = pl022->cur_msg;
- struct spi_transfer *trans = pl022->cur_transfer;
-
- /* Move to next transfer */
- if (trans->transfer_list.next != &msg->transfers) {
- pl022->cur_transfer =
- list_entry(trans->transfer_list.next,
- struct spi_transfer, transfer_list);
- return STATE_RUNNING;
- }
- return STATE_DONE;
-}
-
/*
* This DMA functionality is only compiled in if we have
* access to the generic DMA devices/DMA engine.
@@ -800,7 +695,6 @@ static void unmap_free_dma_scatter(struct pl022 *pl022)
static void dma_callback(void *data)
{
struct pl022 *pl022 = data;
- struct spi_message *msg = pl022->cur_msg;
BUG_ON(!pl022->sgt_rx.sgl);
@@ -845,13 +739,7 @@ static void dma_callback(void *data)
unmap_free_dma_scatter(pl022);
- /* Update total bytes transferred */
- msg->actual_length += pl022->cur_transfer->len;
- /* Move to next transfer */
- msg->state = next_transfer(pl022);
- if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change)
- pl022_cs_control(pl022, SSP_CHIP_DESELECT);
- tasklet_schedule(&pl022->pump_transfers);
+ spi_finalize_current_transfer(pl022->host);
}
static void setup_dma_scatter(struct pl022 *pl022,
@@ -873,10 +761,9 @@ static void setup_dma_scatter(struct pl022 *pl022,
* we just feed in this, else we stuff in as much
* as we can.
*/
- if (bytesleft < (PAGE_SIZE - offset_in_page(bufp)))
- mapbytes = bytesleft;
- else
- mapbytes = PAGE_SIZE - offset_in_page(bufp);
+ mapbytes = min_t(int, bytesleft,
+ PAGE_SIZE - offset_in_page(bufp));
+
sg_set_page(sg, virt_to_page(bufp),
mapbytes, offset_in_page(bufp));
bufp += mapbytes;
@@ -888,10 +775,7 @@ static void setup_dma_scatter(struct pl022 *pl022,
} else {
/* Map the dummy buffer on every page */
for_each_sg(sgtab->sgl, sg, sgtab->nents, i) {
- if (bytesleft < PAGE_SIZE)
- mapbytes = bytesleft;
- else
- mapbytes = PAGE_SIZE;
+ mapbytes = min_t(int, bytesleft, PAGE_SIZE);
sg_set_page(sg, virt_to_page(pl022->dummypage),
mapbytes, 0);
bytesleft -= mapbytes;
@@ -1012,7 +896,7 @@ static int configure_dma(struct pl022 *pl022)
break;
}
- /* SPI pecularity: we need to read and write the same width */
+ /* SPI peculiarity: we need to read and write the same width */
if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
rx_conf.src_addr_width = tx_conf.dst_addr_width;
if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
@@ -1110,16 +994,16 @@ static int pl022_dma_probe(struct pl022 *pl022)
* of them.
*/
pl022->dma_rx_channel = dma_request_channel(mask,
- pl022->master_info->dma_filter,
- pl022->master_info->dma_rx_param);
+ pl022->host_info->dma_filter,
+ pl022->host_info->dma_rx_param);
if (!pl022->dma_rx_channel) {
dev_dbg(&pl022->adev->dev, "no RX DMA channel!\n");
goto err_no_rxchan;
}
pl022->dma_tx_channel = dma_request_channel(mask,
- pl022->master_info->dma_filter,
- pl022->master_info->dma_tx_param);
+ pl022->host_info->dma_filter,
+ pl022->host_info->dma_tx_param);
if (!pl022->dma_tx_channel) {
dev_dbg(&pl022->adev->dev, "no TX DMA channel!\n");
goto err_no_txchan;
@@ -1189,6 +1073,9 @@ err_no_rxchan:
static void terminate_dma(struct pl022 *pl022)
{
+ if (!pl022->dma_running)
+ return;
+
struct dma_chan *rxchan = pl022->dma_rx_channel;
struct dma_chan *txchan = pl022->dma_tx_channel;
@@ -1200,8 +1087,7 @@ static void terminate_dma(struct pl022 *pl022)
static void pl022_dma_remove(struct pl022 *pl022)
{
- if (pl022->dma_running)
- terminate_dma(pl022);
+ terminate_dma(pl022);
if (pl022->dma_tx_channel)
dma_release_channel(pl022->dma_tx_channel);
if (pl022->dma_rx_channel)
@@ -1225,6 +1111,10 @@ static inline int pl022_dma_probe(struct pl022 *pl022)
return 0;
}
+static inline void terminate_dma(struct pl022 *pl022)
+{
+}
+
static inline void pl022_dma_remove(struct pl022 *pl022)
{
}
@@ -1246,16 +1136,7 @@ static inline void pl022_dma_remove(struct pl022 *pl022)
static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
{
struct pl022 *pl022 = dev_id;
- struct spi_message *msg = pl022->cur_msg;
u16 irq_status = 0;
-
- if (unlikely(!msg)) {
- dev_err(&pl022->adev->dev,
- "bad message state in interrupt handler");
- /* Never fail */
- return IRQ_HANDLED;
- }
-
/* Read the Interrupt Status Register */
irq_status = readw(SSP_MIS(pl022->virtbase));
@@ -1287,10 +1168,8 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
writew((readw(SSP_CR1(pl022->virtbase)) &
(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
- msg->state = STATE_ERROR;
-
- /* Schedule message queue handler */
- tasklet_schedule(&pl022->pump_transfers);
+ pl022->cur_transfer->error |= SPI_TRANS_FAIL_IO;
+ spi_finalize_current_transfer(pl022->host);
return IRQ_HANDLED;
}
@@ -1318,13 +1197,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
"number of bytes on a 16bit bus?)\n",
(u32) (pl022->rx - pl022->rx_end));
}
- /* Update total bytes transferred */
- msg->actual_length += pl022->cur_transfer->len;
- /* Move to next transfer */
- msg->state = next_transfer(pl022);
- if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change)
- pl022_cs_control(pl022, SSP_CHIP_DESELECT);
- tasklet_schedule(&pl022->pump_transfers);
+ spi_finalize_current_transfer(pl022->host);
return IRQ_HANDLED;
}
@@ -1361,98 +1234,20 @@ static int set_up_next_transfer(struct pl022 *pl022,
return 0;
}
-/**
- * pump_transfers - Tasklet function which schedules next transfer
- * when running in interrupt or DMA transfer mode.
- * @data: SSP driver private data structure
- *
- */
-static void pump_transfers(unsigned long data)
+static int do_interrupt_dma_transfer(struct pl022 *pl022)
{
- struct pl022 *pl022 = (struct pl022 *) data;
- struct spi_message *message = NULL;
- struct spi_transfer *transfer = NULL;
- struct spi_transfer *previous = NULL;
-
- /* Get current state information */
- message = pl022->cur_msg;
- transfer = pl022->cur_transfer;
-
- /* Handle for abort */
- if (message->state == STATE_ERROR) {
- message->status = -EIO;
- giveback(pl022);
- return;
- }
-
- /* Handle end of message */
- if (message->state == STATE_DONE) {
- message->status = 0;
- giveback(pl022);
- return;
- }
-
- /* Delay if requested at end of transfer before CS change */
- if (message->state == STATE_RUNNING) {
- previous = list_entry(transfer->transfer_list.prev,
- struct spi_transfer,
- transfer_list);
- /*
- * FIXME: This runs in interrupt context.
- * Is this really smart?
- */
- spi_transfer_delay_exec(previous);
-
- /* Reselect chip select only if cs_change was requested */
- if (previous->cs_change)
- pl022_cs_control(pl022, SSP_CHIP_SELECT);
- } else {
- /* STATE_START */
- message->state = STATE_RUNNING;
- }
-
- if (set_up_next_transfer(pl022, transfer)) {
- message->state = STATE_ERROR;
- message->status = -EIO;
- giveback(pl022);
- return;
- }
- /* Flush the FIFOs and let's go! */
- flush(pl022);
-
- if (pl022->cur_chip->enable_dma) {
- if (configure_dma(pl022)) {
- dev_dbg(&pl022->adev->dev,
- "configuration of DMA failed, fall back to interrupt mode\n");
- goto err_config_dma;
- }
- return;
- }
-
-err_config_dma:
- /* enable all interrupts except RX */
- writew(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM, SSP_IMSC(pl022->virtbase));
-}
+ int ret;
-static void do_interrupt_dma_transfer(struct pl022 *pl022)
-{
/*
* Default is to enable all interrupts except RX -
* this will be enabled once TX is complete
*/
u32 irqflags = (u32)(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM);
- /* Enable target chip, if not already active */
- if (!pl022->next_msg_cs_active)
- pl022_cs_control(pl022, SSP_CHIP_SELECT);
+ ret = set_up_next_transfer(pl022, pl022->cur_transfer);
+ if (ret)
+ return ret;
- if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
- /* Error path */
- pl022->cur_msg->state = STATE_ERROR;
- pl022->cur_msg->status = -EIO;
- giveback(pl022);
- return;
- }
/* If we're using DMA, set up DMA here */
if (pl022->cur_chip->enable_dma) {
/* Configure DMA transfer */
@@ -1469,6 +1264,7 @@ err_config_dma:
writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
SSP_CR1(pl022->virtbase));
writew(irqflags, SSP_IMSC(pl022->virtbase));
+ return 1;
}
static void print_current_status(struct pl022 *pl022)
@@ -1495,116 +1291,70 @@ static void print_current_status(struct pl022 *pl022)
}
-static void do_polling_transfer(struct pl022 *pl022)
+static int do_polling_transfer(struct pl022 *pl022)
{
- struct spi_message *message = NULL;
- struct spi_transfer *transfer = NULL;
- struct spi_transfer *previous = NULL;
+ int ret;
unsigned long time, timeout;
- message = pl022->cur_msg;
-
- while (message->state != STATE_DONE) {
- /* Handle for abort */
- if (message->state == STATE_ERROR)
- break;
- transfer = pl022->cur_transfer;
-
- /* Delay if requested at end of transfer */
- if (message->state == STATE_RUNNING) {
- previous =
- list_entry(transfer->transfer_list.prev,
- struct spi_transfer, transfer_list);
- spi_transfer_delay_exec(previous);
- if (previous->cs_change)
- pl022_cs_control(pl022, SSP_CHIP_SELECT);
- } else {
- /* STATE_START */
- message->state = STATE_RUNNING;
- if (!pl022->next_msg_cs_active)
- pl022_cs_control(pl022, SSP_CHIP_SELECT);
- }
-
- /* Configuration Changing Per Transfer */
- if (set_up_next_transfer(pl022, transfer)) {
- /* Error path */
- message->state = STATE_ERROR;
- break;
- }
- /* Flush FIFOs and enable SSP */
- flush(pl022);
- writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
- SSP_CR1(pl022->virtbase));
-
- dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n");
-
- timeout = jiffies + msecs_to_jiffies(SPI_POLLING_TIMEOUT);
- while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) {
- time = jiffies;
- readwriter(pl022);
- if (time_after(time, timeout)) {
- dev_warn(&pl022->adev->dev,
- "%s: timeout!\n", __func__);
- message->state = STATE_TIMEOUT;
- print_current_status(pl022);
- goto out;
- }
- cpu_relax();
+ /* Configuration Changing Per Transfer */
+ ret = set_up_next_transfer(pl022, pl022->cur_transfer);
+ if (ret)
+ return ret;
+ /* Flush FIFOs and enable SSP */
+ flush(pl022);
+ writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
+ SSP_CR1(pl022->virtbase));
+
+ dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n");
+
+ timeout = jiffies + msecs_to_jiffies(SPI_POLLING_TIMEOUT);
+ while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) {
+ time = jiffies;
+ readwriter(pl022);
+ if (time_after(time, timeout)) {
+ dev_warn(&pl022->adev->dev,
+ "%s: timeout!\n", __func__);
+ print_current_status(pl022);
+ return -ETIMEDOUT;
}
-
- /* Update total byte transferred */
- message->actual_length += pl022->cur_transfer->len;
- /* Move to next transfer */
- message->state = next_transfer(pl022);
- if (message->state != STATE_DONE
- && pl022->cur_transfer->cs_change)
- pl022_cs_control(pl022, SSP_CHIP_DESELECT);
+ cpu_relax();
}
-out:
- /* Handle end of message */
- if (message->state == STATE_DONE)
- message->status = 0;
- else if (message->state == STATE_TIMEOUT)
- message->status = -EAGAIN;
- else
- message->status = -EIO;
- giveback(pl022);
- return;
+ return 0;
}
-static int pl022_transfer_one_message(struct spi_master *master,
- struct spi_message *msg)
+static int pl022_transfer_one(struct spi_controller *host, struct spi_device *spi,
+ struct spi_transfer *transfer)
{
- struct pl022 *pl022 = spi_master_get_devdata(master);
-
- /* Initial message state */
- pl022->cur_msg = msg;
- msg->state = STATE_START;
+ struct pl022 *pl022 = spi_controller_get_devdata(host);
- pl022->cur_transfer = list_entry(msg->transfers.next,
- struct spi_transfer, transfer_list);
+ pl022->cur_transfer = transfer;
/* Setup the SPI using the per chip configuration */
- pl022->cur_chip = spi_get_ctldata(msg->spi);
- pl022->cur_cs = spi_get_chipselect(msg->spi, 0);
- /* This is always available but may be set to -ENOENT */
- pl022->cur_gpiod = spi_get_csgpiod(msg->spi, 0);
+ pl022->cur_chip = spi_get_ctldata(spi);
+ pl022->cur_cs = spi_get_chipselect(spi, 0);
restore_state(pl022);
flush(pl022);
if (pl022->cur_chip->xfer_type == POLLING_TRANSFER)
- do_polling_transfer(pl022);
+ return do_polling_transfer(pl022);
else
- do_interrupt_dma_transfer(pl022);
+ return do_interrupt_dma_transfer(pl022);
+}
- return 0;
+static void pl022_handle_err(struct spi_controller *ctlr, struct spi_message *message)
+{
+ struct pl022 *pl022 = spi_controller_get_devdata(ctlr);
+
+ terminate_dma(pl022);
+ writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
+ writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
}
-static int pl022_unprepare_transfer_hardware(struct spi_master *master)
+static int pl022_unprepare_transfer_hardware(struct spi_controller *host)
{
- struct pl022 *pl022 = spi_master_get_devdata(master);
+ struct pl022 *pl022 = spi_controller_get_devdata(host);
/* nothing more to do - disable spi/ssp and power off */
writew((readw(SSP_CR1(pl022->virtbase)) &
@@ -1826,10 +1576,10 @@ static const struct pl022_config_chip pl022_default_chip_info = {
};
/**
- * pl022_setup - setup function registered to SPI master framework
+ * pl022_setup - setup function registered to SPI host framework
* @spi: spi device which is requesting setup
*
- * This function is registered to the SPI framework for this SPI master
+ * This function is registered to the SPI framework for this SPI host
* controller. If it is the first time when setup is called by this device,
* this function will initialize the runtime state for this chip and save
* the same in the device structure. Else it will update the runtime info
@@ -1844,7 +1594,7 @@ static int pl022_setup(struct spi_device *spi)
struct chip_data *chip;
struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0};
int status = 0;
- struct pl022 *pl022 = spi_master_get_devdata(spi->master);
+ struct pl022 *pl022 = spi_controller_get_devdata(spi->controller);
unsigned int bits = spi->bits_per_word;
u32 tmp;
struct device_node *np = spi->dev.of_node;
@@ -1964,7 +1714,7 @@ static int pl022_setup(struct spi_device *spi)
chip->dmacr = 0;
chip->cpsr = 0;
if ((chip_info->com_mode == DMA_TRANSFER)
- && ((pl022->master_info)->enable_dma)) {
+ && ((pl022->host_info)->enable_dma)) {
chip->enable_dma = true;
dev_dbg(&spi->dev, "DMA mode set in controller state\n");
SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
@@ -2061,10 +1811,10 @@ static int pl022_setup(struct spi_device *spi)
}
/**
- * pl022_cleanup - cleanup function registered to SPI master framework
+ * pl022_cleanup - cleanup function registered to SPI host framework
* @spi: spi device which is requesting cleanup
*
- * This function is registered to the SPI framework for this SPI master
+ * This function is registered to the SPI framework for this SPI host
* controller. It will free the runtime state of chip.
*/
static void pl022_cleanup(struct spi_device *spi)
@@ -2103,7 +1853,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
struct device *dev = &adev->dev;
struct pl022_ssp_controller *platform_info =
dev_get_platdata(&adev->dev);
- struct spi_master *master;
+ struct spi_controller *host;
struct pl022 *pl022 = NULL; /*Data for this driver */
int status = 0;
@@ -2117,16 +1867,16 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
return -ENODEV;
}
- /* Allocate master with space for data */
- master = spi_alloc_master(dev, sizeof(struct pl022));
- if (master == NULL) {
- dev_err(&adev->dev, "probe - cannot alloc SPI master\n");
+ /* Allocate host with space for data */
+ host = spi_alloc_host(dev, sizeof(struct pl022));
+ if (host == NULL) {
+ dev_err(&adev->dev, "probe - cannot alloc SPI host\n");
return -ENOMEM;
}
- pl022 = spi_master_get_devdata(master);
- pl022->master = master;
- pl022->master_info = platform_info;
+ pl022 = spi_controller_get_devdata(host);
+ pl022->host = host;
+ pl022->host_info = platform_info;
pl022->adev = adev;
pl022->vendor = id->data;
@@ -2134,25 +1884,27 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
* Bus Number Which has been Assigned to this SSP controller
* on this board
*/
- master->bus_num = platform_info->bus_id;
- master->cleanup = pl022_cleanup;
- master->setup = pl022_setup;
- master->auto_runtime_pm = true;
- master->transfer_one_message = pl022_transfer_one_message;
- master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
- master->rt = platform_info->rt;
- master->dev.of_node = dev->of_node;
- master->use_gpio_descriptors = true;
+ host->bus_num = platform_info->bus_id;
+ host->cleanup = pl022_cleanup;
+ host->setup = pl022_setup;
+ host->auto_runtime_pm = true;
+ host->transfer_one = pl022_transfer_one;
+ host->set_cs = pl022_cs_control;
+ host->handle_err = pl022_handle_err;
+ host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware;
+ host->rt = platform_info->rt;
+ host->dev.of_node = dev->of_node;
+ host->use_gpio_descriptors = true;
/*
* Supports mode 0-3, loopback, and active low CS. Transfers are
* always MS bit first on the original pl022.
*/
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
if (pl022->vendor->extended_cr)
- master->mode_bits |= SPI_LSB_FIRST;
+ host->mode_bits |= SPI_LSB_FIRST;
- dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num);
+ dev_dbg(&adev->dev, "BUSNO: %d\n", host->bus_num);
status = amba_request_regions(adev, NULL);
if (status)
@@ -2168,23 +1920,13 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
dev_info(&adev->dev, "mapped registers from %pa to %p\n",
&adev->res.start, pl022->virtbase);
- pl022->clk = devm_clk_get(&adev->dev, NULL);
+ pl022->clk = devm_clk_get_enabled(&adev->dev, NULL);
if (IS_ERR(pl022->clk)) {
status = PTR_ERR(pl022->clk);
dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n");
goto err_no_clk;
}
- status = clk_prepare_enable(pl022->clk);
- if (status) {
- dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
- goto err_no_clk_en;
- }
-
- /* Initialize transfer pump */
- tasklet_init(&pl022->pump_transfers, pump_transfers,
- (unsigned long)pl022);
-
/* Disable SSP */
writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)),
SSP_CR1(pl022->virtbase));
@@ -2215,10 +1957,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
/* Register with the SPI framework */
amba_set_drvdata(adev, pl022);
- status = devm_spi_register_master(&adev->dev, master);
+ status = devm_spi_register_controller(&adev->dev, host);
if (status != 0) {
dev_err_probe(&adev->dev, status,
- "problem registering spi master\n");
+ "problem registering spi host\n");
goto err_spi_register;
}
dev_dbg(dev, "probe succeeded\n");
@@ -2240,13 +1982,11 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
if (platform_info->enable_dma)
pl022_dma_remove(pl022);
err_no_irq:
- clk_disable_unprepare(pl022->clk);
- err_no_clk_en:
err_no_clk:
err_no_ioremap:
amba_release_regions(adev);
err_no_ioregion:
- spi_master_put(master);
+ spi_controller_put(host);
return status;
}
@@ -2265,12 +2005,10 @@ pl022_remove(struct amba_device *adev)
pm_runtime_get_noresume(&adev->dev);
load_ssp_default_config(pl022);
- if (pl022->master_info->enable_dma)
+ if (pl022->host_info->enable_dma)
pl022_dma_remove(pl022);
- clk_disable_unprepare(pl022->clk);
amba_release_regions(adev);
- tasklet_disable(&pl022->pump_transfers);
}
#ifdef CONFIG_PM_SLEEP
@@ -2279,13 +2017,13 @@ static int pl022_suspend(struct device *dev)
struct pl022 *pl022 = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(pl022->master);
+ ret = spi_controller_suspend(pl022->host);
if (ret)
return ret;
ret = pm_runtime_force_suspend(dev);
if (ret) {
- spi_master_resume(pl022->master);
+ spi_controller_resume(pl022->host);
return ret;
}
@@ -2305,7 +2043,7 @@ static int pl022_resume(struct device *dev)
dev_err(dev, "problem resuming\n");
/* Start the queue running */
- ret = spi_master_resume(pl022->master);
+ ret = spi_controller_resume(pl022->host);
if (!ret)
dev_dbg(dev, "resumed\n");
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index d725e915025d..688cabcfbc52 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -20,21 +20,21 @@
* during SPI transfers by setting max_speed_hz via the device tree.
*/
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/errno.h>
#include <linux/wait.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-#include <linux/io.h>
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
@@ -126,7 +126,7 @@ struct ppc4xx_spi {
unsigned char *rx;
struct spi_ppc4xx_regs __iomem *regs; /* pointer to the registers */
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev;
};
@@ -143,7 +143,7 @@ static int spi_ppc4xx_txrx(struct spi_device *spi, struct spi_transfer *t)
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len);
- hw = spi_master_get_devdata(spi->master);
+ hw = spi_controller_get_devdata(spi->controller);
hw->tx = t->tx_buf;
hw->rx = t->rx_buf;
@@ -161,15 +161,13 @@ static int spi_ppc4xx_txrx(struct spi_device *spi, struct spi_transfer *t)
static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
{
- struct ppc4xx_spi *hw = spi_master_get_devdata(spi->master);
+ struct ppc4xx_spi *hw = spi_controller_get_devdata(spi->controller);
struct spi_ppc4xx_cs *cs = spi->controller_state;
int scr;
u8 cdm = 0;
u32 speed;
- u8 bits_per_word;
/* Start with the generic configuration for this device. */
- bits_per_word = spi->bits_per_word;
speed = spi->max_speed_hz;
/*
@@ -177,9 +175,6 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
* the transfer to overwrite the generic configuration with zeros.
*/
if (t) {
- if (t->bits_per_word)
- bits_per_word = t->bits_per_word;
-
if (t->speed_hz)
speed = min(t->speed_hz, spi->max_speed_hz);
}
@@ -340,7 +335,7 @@ static void spi_ppc4xx_enable(struct ppc4xx_spi *hw)
static int spi_ppc4xx_of_probe(struct platform_device *op)
{
struct ppc4xx_spi *hw;
- struct spi_master *master;
+ struct spi_controller *host;
struct spi_bitbang *bbp;
struct resource resource;
struct device_node *np = op->dev.of_node;
@@ -349,35 +344,35 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
int ret;
const unsigned int *clk;
- master = spi_alloc_master(dev, sizeof(*hw));
- if (master == NULL)
+ host = spi_alloc_host(dev, sizeof(*hw));
+ if (host == NULL)
return -ENOMEM;
- master->dev.of_node = np;
- platform_set_drvdata(op, master);
- hw = spi_master_get_devdata(master);
- hw->master = master;
+ host->dev.of_node = np;
+ platform_set_drvdata(op, host);
+ hw = spi_controller_get_devdata(host);
+ hw->host = host;
hw->dev = dev;
init_completion(&hw->done);
/* Setup the state for the bitbang driver */
bbp = &hw->bitbang;
- bbp->master = hw->master;
+ bbp->ctlr = hw->host;
bbp->setup_transfer = spi_ppc4xx_setupxfer;
bbp->txrx_bufs = spi_ppc4xx_txrx;
bbp->use_dma = 0;
- bbp->master->setup = spi_ppc4xx_setup;
- bbp->master->cleanup = spi_ppc4xx_cleanup;
- bbp->master->bits_per_word_mask = SPI_BPW_MASK(8);
- bbp->master->use_gpio_descriptors = true;
+ bbp->ctlr->setup = spi_ppc4xx_setup;
+ bbp->ctlr->cleanup = spi_ppc4xx_cleanup;
+ bbp->ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
+ bbp->ctlr->use_gpio_descriptors = true;
/*
* The SPI core will count the number of GPIO descriptors to figure
* out the number of chip selects available on the platform.
*/
- bbp->master->num_chipselect = 0;
+ bbp->ctlr->num_chipselect = 0;
/* the spi->mode bits understood by this driver: */
- bbp->master->mode_bits =
+ bbp->ctlr->mode_bits =
SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST;
/* Get the clock for the OPB */
@@ -385,7 +380,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
if (opbnp == NULL) {
dev_err(dev, "OPB: cannot find node\n");
ret = -ENODEV;
- goto free_master;
+ goto free_host;
}
/* Get the clock (Hz) for the OPB */
clk = of_get_property(opbnp, "clock-frequency", NULL);
@@ -393,7 +388,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
dev_err(dev, "OPB: no clock-frequency property set\n");
of_node_put(opbnp);
ret = -ENODEV;
- goto free_master;
+ goto free_host;
}
hw->opb_freq = *clk;
hw->opb_freq >>= 2;
@@ -402,7 +397,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
ret = of_address_to_resource(np, 0, &resource);
if (ret) {
dev_err(dev, "error while parsing device node resource\n");
- goto free_master;
+ goto free_host;
}
hw->mapbase = resource.start;
hw->mapsize = resource_size(&resource);
@@ -411,16 +406,20 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {
dev_err(dev, "too small to map registers\n");
ret = -EINVAL;
- goto free_master;
+ goto free_host;
}
/* Request IRQ */
- hw->irqnum = irq_of_parse_and_map(np, 0);
+ ret = platform_get_irq(op, 0);
+ if (ret < 0)
+ goto free_host;
+ hw->irqnum = ret;
+
ret = request_irq(hw->irqnum, spi_ppc4xx_int,
0, "spi_ppc4xx_of", (void *)hw);
if (ret) {
dev_err(dev, "unable to allocate interrupt\n");
- goto free_master;
+ goto free_host;
}
if (!request_mem_region(hw->mapbase, hw->mapsize, DRIVER_NAME)) {
@@ -443,7 +442,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
dev->dma_mask = 0;
ret = spi_bitbang_start(bbp);
if (ret) {
- dev_err(dev, "failed to register SPI master\n");
+ dev_err(dev, "failed to register SPI host\n");
goto unmap_regs;
}
@@ -457,8 +456,8 @@ map_io_error:
release_mem_region(hw->mapbase, hw->mapsize);
request_mem_error:
free_irq(hw->irqnum, hw);
-free_master:
- spi_master_put(master);
+free_host:
+ spi_controller_put(host);
dev_err(dev, "initialization failed\n");
return ret;
@@ -466,14 +465,14 @@ free_master:
static void spi_ppc4xx_of_remove(struct platform_device *op)
{
- struct spi_master *master = platform_get_drvdata(op);
- struct ppc4xx_spi *hw = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(op);
+ struct ppc4xx_spi *hw = spi_controller_get_devdata(host);
spi_bitbang_stop(&hw->bitbang);
release_mem_region(hw->mapbase, hw->mapsize);
free_irq(hw->irqnum, hw);
iounmap(hw->regs);
- spi_master_put(master);
+ spi_controller_put(host);
}
static const struct of_device_id spi_ppc4xx_of_match[] = {
@@ -485,7 +484,7 @@ MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
static struct platform_driver spi_ppc4xx_of_driver = {
.probe = spi_ppc4xx_of_probe,
- .remove_new = spi_ppc4xx_of_remove,
+ .remove = spi_ppc4xx_of_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = spi_ppc4xx_of_match,
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index be563f0dd03a..08cb6e96ac94 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -6,17 +6,22 @@
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*/
-#include <linux/device.h>
+#include <linux/atomic.h>
+#include <linux/dev_printk.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
+#include <linux/errno.h>
+#include <linux/irqreturn.h>
#include <linux/scatterlist.h>
-#include <linux/sizes.h>
+#include <linux/string.h>
+#include <linux/types.h>
-#include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/spi.h>
#include "spi-pxa2xx.h"
+struct device;
+
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
bool error)
{
@@ -63,8 +68,6 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
enum dma_transfer_direction dir,
struct spi_transfer *xfer)
{
- struct chip_data *chip =
- spi_get_ctldata(drv_data->controller->cur_msg->spi);
enum dma_slave_buswidth width;
struct dma_slave_config cfg;
struct dma_chan *chan;
@@ -89,14 +92,14 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
if (dir == DMA_MEM_TO_DEV) {
cfg.dst_addr = drv_data->ssp->phys_base + SSDR;
cfg.dst_addr_width = width;
- cfg.dst_maxburst = chip->dma_burst_size;
+ cfg.dst_maxburst = drv_data->controller_info->dma_burst_size;
sgt = &xfer->tx_sg;
chan = drv_data->controller->dma_tx;
} else {
cfg.src_addr = drv_data->ssp->phys_base + SSDR;
cfg.src_addr_width = width;
- cfg.src_maxburst = chip->dma_burst_size;
+ cfg.src_maxburst = drv_data->controller_info->dma_burst_size;
sgt = &xfer->rx_sg;
chan = drv_data->controller->dma_rx;
@@ -220,24 +223,3 @@ void pxa2xx_spi_dma_release(struct driver_data *drv_data)
controller->dma_tx = NULL;
}
}
-
-int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
- struct spi_device *spi,
- u8 bits_per_word, u32 *burst_code,
- u32 *threshold)
-{
- struct pxa2xx_spi_chip *chip_info = spi->controller_data;
- struct driver_data *drv_data = spi_controller_get_devdata(spi->controller);
- u32 dma_burst_size = drv_data->controller_info->dma_burst_size;
-
- /*
- * If the DMA burst size is given in chip_info we use that,
- * otherwise we use the default. Also we use the default FIFO
- * thresholds for now.
- */
- *burst_code = chip_info ? chip_info->dma_burst_size : dma_burst_size;
- *threshold = SSCR1_RxTresh(RX_THRESH_DFLT)
- | SSCR1_TxTresh(TX_THRESH_DFLT);
-
- return 0;
-}
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index 861b21c63504..cae77ac18520 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -6,15 +6,21 @@
* Copyright (C) 2016, 2021 Intel Corporation
*/
#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/platform_device.h>
-
-#include <linux/spi/pxa2xx_spi.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/sprintf.h>
+#include <linux/string.h>
+#include <linux/types.h>
#include <linux/dmaengine.h>
#include <linux/platform_data/dma-dw.h>
+#include "spi-pxa2xx.h"
+
#define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0935
#define PCI_DEVICE_ID_INTEL_BYT 0x0f0e
#define PCI_DEVICE_ID_INTEL_MRFLD 0x1194
@@ -259,29 +265,27 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
const struct pxa_spi_info *info;
- struct platform_device_info pi;
int ret;
- struct platform_device *pdev;
- struct pxa2xx_spi_controller spi_pdata;
+ struct pxa2xx_spi_controller *pdata;
struct ssp_device *ssp;
ret = pcim_enable_device(dev);
if (ret)
return ret;
- ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI");
- if (ret)
- return ret;
-
- memset(&spi_pdata, 0, sizeof(spi_pdata));
+ pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
- ssp = &spi_pdata.ssp;
+ ssp = &pdata->ssp;
ssp->dev = &dev->dev;
ssp->phys_base = pci_resource_start(dev, 0);
- ssp->mmio_base = pcim_iomap_table(dev)[0];
+ ssp->mmio_base = pcim_iomap_region(dev, 0, "PXA2xx SPI");
+ if (IS_ERR(ssp->mmio_base))
+ return PTR_ERR(ssp->mmio_base);
info = (struct pxa_spi_info *)ent->driver_data;
- ret = info->setup(dev, &spi_pdata);
+ ret = info->setup(dev, pdata);
if (ret)
return ret;
@@ -292,28 +296,24 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
return ret;
ssp->irq = pci_irq_vector(dev, 0);
- memset(&pi, 0, sizeof(pi));
- pi.fwnode = dev_fwnode(&dev->dev);
- pi.parent = &dev->dev;
- pi.name = "pxa2xx-spi";
- pi.id = ssp->port_id;
- pi.data = &spi_pdata;
- pi.size_data = sizeof(spi_pdata);
-
- pdev = platform_device_register_full(&pi);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
+ ret = pxa2xx_spi_probe(&dev->dev, ssp, pdata);
+ if (ret)
+ return ret;
- pci_set_drvdata(dev, pdev);
+ pm_runtime_set_autosuspend_delay(&dev->dev, 50);
+ pm_runtime_use_autosuspend(&dev->dev);
+ pm_runtime_put_autosuspend(&dev->dev);
+ pm_runtime_allow(&dev->dev);
return 0;
}
static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
{
- struct platform_device *pdev = pci_get_drvdata(dev);
+ pm_runtime_forbid(&dev->dev);
+ pm_runtime_get_noresume(&dev->dev);
- platform_device_unregister(pdev);
+ pxa2xx_spi_remove(&dev->dev);
}
static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
@@ -335,6 +335,9 @@ MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices);
static struct pci_driver pxa2xx_spi_pci_driver = {
.name = "pxa2xx_spi_pci",
.id_table = pxa2xx_spi_pci_devices,
+ .driver = {
+ .pm = pm_ptr(&pxa2xx_spi_pm_ops),
+ },
.probe = pxa2xx_spi_pci_probe,
.remove = pxa2xx_spi_pci_remove,
};
@@ -343,4 +346,5 @@ module_pci_driver(pxa2xx_spi_pci_driver);
MODULE_DESCRIPTION("CE4100/LPSS PCI-SPI glue code for PXA's driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("SPI_PXA2xx");
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
diff --git a/drivers/spi/spi-pxa2xx-platform.c b/drivers/spi/spi-pxa2xx-platform.c
new file mode 100644
index 000000000000..45e159e75a52
--- /dev/null
+++ b/drivers/spi/spi-pxa2xx-platform.c
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/acpi.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/types.h>
+
+#include "spi-pxa2xx.h"
+
+static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
+{
+ return param == chan->device->dev;
+}
+
+static int
+pxa2xx_spi_init_ssp(struct platform_device *pdev, struct ssp_device *ssp, enum pxa_ssp_type type)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int status;
+ u64 uid;
+
+ ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(ssp->mmio_base))
+ return PTR_ERR(ssp->mmio_base);
+
+ ssp->phys_base = res->start;
+
+ ssp->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(ssp->clk))
+ return PTR_ERR(ssp->clk);
+
+ ssp->irq = platform_get_irq(pdev, 0);
+ if (ssp->irq < 0)
+ return ssp->irq;
+
+ ssp->type = type;
+ ssp->dev = dev;
+
+ status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid);
+ if (status)
+ ssp->port_id = -1;
+ else
+ ssp->port_id = uid;
+
+ return 0;
+}
+
+static void pxa2xx_spi_ssp_release(void *ssp)
+{
+ pxa_ssp_free(ssp);
+}
+
+static struct ssp_device *pxa2xx_spi_ssp_request(struct platform_device *pdev)
+{
+ struct ssp_device *ssp;
+ int status;
+
+ ssp = pxa_ssp_request(pdev->id, pdev->name);
+ if (!ssp)
+ return NULL;
+
+ status = devm_add_action_or_reset(&pdev->dev, pxa2xx_spi_ssp_release, ssp);
+ if (status)
+ return ERR_PTR(status);
+
+ return ssp;
+}
+
+static struct pxa2xx_spi_controller *
+pxa2xx_spi_init_pdata(struct platform_device *pdev)
+{
+ struct pxa2xx_spi_controller *pdata;
+ struct device *dev = &pdev->dev;
+ struct device *parent = dev->parent;
+ const void *match = device_get_match_data(dev);
+ enum pxa_ssp_type type = SSP_UNDEFINED;
+ struct ssp_device *ssp;
+ bool is_lpss_priv;
+ u32 num_cs = 1;
+ int status;
+
+ ssp = pxa2xx_spi_ssp_request(pdev);
+ if (IS_ERR(ssp))
+ return ERR_CAST(ssp);
+ if (ssp) {
+ type = ssp->type;
+ } else if (match) {
+ type = (enum pxa_ssp_type)(uintptr_t)match;
+ } else {
+ u32 value;
+
+ status = device_property_read_u32(dev, "intel,spi-pxa2xx-type", &value);
+ if (status)
+ return ERR_PTR(status);
+
+ type = (enum pxa_ssp_type)value;
+ }
+
+ /* Validate the SSP type correctness */
+ if (!(type > SSP_UNDEFINED && type < SSP_MAX))
+ return ERR_PTR(-EINVAL);
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ /* Platforms with iDMA 64-bit */
+ is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv");
+ if (is_lpss_priv) {
+ pdata->tx_param = parent;
+ pdata->rx_param = parent;
+ pdata->dma_filter = pxa2xx_spi_idma_filter;
+ }
+
+ /* Read number of chip select pins, if provided */
+ device_property_read_u32(dev, "num-cs", &num_cs);
+
+ pdata->num_chipselect = num_cs;
+ pdata->is_target = device_property_read_bool(dev, "spi-slave");
+ pdata->enable_dma = true;
+ pdata->dma_burst_size = 1;
+
+ /* If SSP has been already enumerated, use it */
+ if (ssp)
+ return pdata;
+
+ status = pxa2xx_spi_init_ssp(pdev, &pdata->ssp, type);
+ if (status)
+ return ERR_PTR(status);
+
+ return pdata;
+}
+
+static int pxa2xx_spi_platform_probe(struct platform_device *pdev)
+{
+ struct pxa2xx_spi_controller *platform_info;
+ struct device *dev = &pdev->dev;
+ struct ssp_device *ssp;
+ int ret;
+
+ platform_info = dev_get_platdata(dev);
+ if (!platform_info) {
+ platform_info = pxa2xx_spi_init_pdata(pdev);
+ if (IS_ERR(platform_info))
+ return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n");
+ }
+
+ ssp = pxa2xx_spi_ssp_request(pdev);
+ if (IS_ERR(ssp))
+ return PTR_ERR(ssp);
+ if (!ssp)
+ ssp = &platform_info->ssp;
+
+ pm_runtime_set_autosuspend_delay(dev, 50);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ ret = pxa2xx_spi_probe(dev, ssp, platform_info);
+ if (ret)
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static void pxa2xx_spi_platform_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ pm_runtime_get_sync(dev);
+
+ pxa2xx_spi_remove(dev);
+
+ pm_runtime_put_noidle(dev);
+ pm_runtime_disable(dev);
+}
+
+static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
+ { "80860F0E" },
+ { "8086228E" },
+ { "INT33C0" },
+ { "INT33C1" },
+ { "INT3430" },
+ { "INT3431" },
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
+
+static const struct of_device_id pxa2xx_spi_of_match[] = {
+ { .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match);
+
+static struct platform_driver driver = {
+ .driver = {
+ .name = "pxa2xx-spi",
+ .pm = pm_ptr(&pxa2xx_spi_pm_ops),
+ .acpi_match_table = pxa2xx_spi_acpi_match,
+ .of_match_table = pxa2xx_spi_of_match,
+ },
+ .probe = pxa2xx_spi_platform_probe,
+ .remove = pxa2xx_spi_platform_remove,
+};
+
+static int __init pxa2xx_spi_init(void)
+{
+ return platform_driver_register(&driver);
+}
+subsys_initcall(pxa2xx_spi_init);
+
+static void __exit pxa2xx_spi_exit(void)
+{
+ platform_driver_unregister(&driver);
+}
+module_exit(pxa2xx_spi_exit);
+
+MODULE_AUTHOR("Stephen Street");
+MODULE_DESCRIPTION("PXA2xx SSP SPI Controller platform driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SPI_PXA2xx");
+MODULE_ALIAS("platform:pxa2xx-spi");
+MODULE_SOFTDEP("pre: dw_dmac");
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 1bab18a0f262..ec7117a94d5f 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -4,37 +4,31 @@
* Copyright (C) 2013, 2021 Intel Corporation
*/
-#include <linux/acpi.h>
+#include <linux/atomic.h>
#include <linux/bitops.h>
+#include <linux/bug.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/err.h>
-#include <linux/errno.h>
#include <linux/gpio/consumer.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/ioport.h>
-#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/slab.h>
+#include <linux/types.h>
-#include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/spi.h>
+#include "internals.h"
#include "spi-pxa2xx.h"
-MODULE_AUTHOR("Stephen Street");
-MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pxa2xx-spi");
-
#define TIMOUT_DFLT 1000
/*
@@ -64,6 +58,14 @@ MODULE_ALIAS("platform:pxa2xx-spi");
| CE4100_SSCR1_RFT | CE4100_SSCR1_TFT | SSCR1_MWDS \
| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
+struct chip_data {
+ u32 cr1;
+ u32 dds_rate;
+ u32 threshold;
+ u16 lpss_rx_threshold;
+ u16 lpss_tx_threshold;
+};
+
#define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
#define LPSS_CS_CONTROL_SW_MODE BIT(0)
#define LPSS_CS_CONTROL_CS_HIGH BIT(1)
@@ -71,8 +73,9 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define LPSS_CAPS_CS_EN_MASK (0xf << LPSS_CAPS_CS_EN_SHIFT)
#define LPSS_PRIV_CLOCK_GATE 0x38
-#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3
-#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3
+#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3
+#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3
+#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_OFF 0x0
struct lpss_config {
/* LPSS offset from drv_data->ioaddr */
@@ -89,7 +92,6 @@ struct lpss_config {
/* Chip select control */
unsigned cs_sel_shift;
unsigned cs_sel_mask;
- unsigned cs_num;
/* Quirks */
unsigned cs_clk_stays_gated : 1;
};
@@ -127,7 +129,6 @@ static const struct lpss_config lpss_platforms[] = {
.tx_threshold_hi = 224,
.cs_sel_shift = 2,
.cs_sel_mask = 1 << 2,
- .cs_num = 2,
},
{ /* LPSS_SPT_SSP */
.offset = 0x200,
@@ -321,6 +322,20 @@ static void __lpss_ssp_write_priv(struct driver_data *drv_data,
writel(value, drv_data->lpss_base + offset);
}
+static bool __lpss_ssp_update_priv(struct driver_data *drv_data, unsigned int offset,
+ u32 mask, u32 value)
+{
+ u32 new, curr;
+
+ curr = __lpss_ssp_read_priv(drv_data, offset);
+ new = (curr & ~mask) | (value & mask);
+ if (new == curr)
+ return false;
+
+ __lpss_ssp_write_priv(drv_data, offset, new);
+ return true;
+}
+
/*
* lpss_ssp_setup - perform LPSS SSP specific setup
* @drv_data: pointer to the driver private data
@@ -337,21 +352,16 @@ static void lpss_ssp_setup(struct driver_data *drv_data)
drv_data->lpss_base = drv_data->ssp->mmio_base + config->offset;
/* Enable software chip select control */
- value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
- value &= ~(LPSS_CS_CONTROL_SW_MODE | LPSS_CS_CONTROL_CS_HIGH);
- value |= LPSS_CS_CONTROL_SW_MODE | LPSS_CS_CONTROL_CS_HIGH;
- __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
+ value = LPSS_CS_CONTROL_SW_MODE | LPSS_CS_CONTROL_CS_HIGH;
+ __lpss_ssp_update_priv(drv_data, config->reg_cs_ctrl, value, value);
/* Enable multiblock DMA transfers */
if (drv_data->controller_info->enable_dma) {
- __lpss_ssp_write_priv(drv_data, config->reg_ssp, 1);
+ __lpss_ssp_update_priv(drv_data, config->reg_ssp, BIT(0), BIT(0));
if (config->reg_general >= 0) {
- value = __lpss_ssp_read_priv(drv_data,
- config->reg_general);
- value |= LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE;
- __lpss_ssp_write_priv(drv_data,
- config->reg_general, value);
+ value = LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE;
+ __lpss_ssp_update_priv(drv_data, config->reg_general, value, value);
}
}
}
@@ -361,30 +371,19 @@ static void lpss_ssp_select_cs(struct spi_device *spi,
{
struct driver_data *drv_data =
spi_controller_get_devdata(spi->controller);
- u32 value, cs;
+ u32 cs;
- if (!config->cs_sel_mask)
+ cs = spi_get_chipselect(spi, 0) << config->cs_sel_shift;
+ if (!__lpss_ssp_update_priv(drv_data, config->reg_cs_ctrl, config->cs_sel_mask, cs))
return;
- value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
-
- cs = spi_get_chipselect(spi, 0);
- cs <<= config->cs_sel_shift;
- if (cs != (value & config->cs_sel_mask)) {
- /*
- * When switching another chip select output active the
- * output must be selected first and wait 2 ssp_clk cycles
- * before changing state to active. Otherwise a short
- * glitch will occur on the previous chip select since
- * output select is latched but state control is not.
- */
- value &= ~config->cs_sel_mask;
- value |= cs;
- __lpss_ssp_write_priv(drv_data,
- config->reg_cs_ctrl, value);
- ndelay(1000000000 /
- (drv_data->controller->max_speed_hz / 2));
- }
+ /*
+ * When switching another chip select output active the output must be
+ * selected first and wait 2 ssp_clk cycles before changing state to
+ * active. Otherwise a short glitch will occur on the previous chip
+ * select since output select is latched but state control is not.
+ */
+ ndelay(1000000000 / (drv_data->controller->max_speed_hz / 2));
}
static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)
@@ -392,34 +391,27 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)
struct driver_data *drv_data =
spi_controller_get_devdata(spi->controller);
const struct lpss_config *config;
- u32 value;
+ u32 mask;
config = lpss_get_config(drv_data);
if (enable)
lpss_ssp_select_cs(spi, config);
- value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
- if (enable)
- value &= ~LPSS_CS_CONTROL_CS_HIGH;
- else
- value |= LPSS_CS_CONTROL_CS_HIGH;
- __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
+ mask = LPSS_CS_CONTROL_CS_HIGH;
+ __lpss_ssp_update_priv(drv_data, config->reg_cs_ctrl, mask, enable ? 0 : mask);
if (config->cs_clk_stays_gated) {
- u32 clkgate;
-
/*
* Changing CS alone when dynamic clock gating is on won't
* actually flip CS at that time. This ruins SPI transfers
* that specify delays, or have no data. Toggle the clock mode
* to force on briefly to poke the CS pin to move.
*/
- clkgate = __lpss_ssp_read_priv(drv_data, LPSS_PRIV_CLOCK_GATE);
- value = (clkgate & ~LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK) |
- LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON;
-
- __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, value);
- __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, clkgate);
+ mask = LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK;
+ if (__lpss_ssp_update_priv(drv_data, LPSS_PRIV_CLOCK_GATE, mask,
+ LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON))
+ __lpss_ssp_update_priv(drv_data, LPSS_PRIV_CLOCK_GATE, mask,
+ LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_OFF);
}
}
@@ -932,11 +924,11 @@ static bool pxa2xx_spi_can_dma(struct spi_controller *controller,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct chip_data *chip = spi_get_ctldata(spi);
+ struct driver_data *drv_data = spi_controller_get_devdata(controller);
- return chip->enable_dma &&
+ return drv_data->controller_info->enable_dma &&
xfer->len <= MAX_DMA_LEN &&
- xfer->len >= chip->dma_burst_size;
+ xfer->len >= drv_data->controller_info->dma_burst_size;
}
static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
@@ -944,11 +936,9 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
struct spi_transfer *transfer)
{
struct driver_data *drv_data = spi_controller_get_devdata(controller);
- struct spi_message *message = controller->cur_msg;
struct chip_data *chip = spi_get_ctldata(spi);
- u32 dma_thresh = chip->dma_threshold;
- u32 dma_burst = chip->dma_burst_size;
u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data);
+ u32 dma_thresh;
u32 clk_div;
u8 bits;
u32 speed;
@@ -958,17 +948,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
int dma_mapped;
/* Check if we can DMA this transfer */
- if (transfer->len > MAX_DMA_LEN && chip->enable_dma) {
-
- /* Reject already-mapped transfers; PIO won't always work */
- if (message->is_dma_mapped
- || transfer->rx_dma || transfer->tx_dma) {
- dev_err(&spi->dev,
- "Mapped transfer length of %u is greater than %d\n",
- transfer->len, MAX_DMA_LEN);
- return -EINVAL;
- }
-
+ if (transfer->len > MAX_DMA_LEN && drv_data->controller_info->enable_dma) {
/* Warn ... we force this to PIO mode */
dev_warn_ratelimited(&spi->dev,
"DMA disabled for transfer length %u greater than %d\n",
@@ -1004,24 +984,10 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
drv_data->read = drv_data->rx ? u32_reader : null_reader;
drv_data->write = drv_data->tx ? u32_writer : null_writer;
}
- /*
- * If bits per word is changed in DMA mode, then must check
- * the thresholds and burst also.
- */
- if (chip->enable_dma) {
- if (pxa2xx_spi_set_dma_burst_and_threshold(chip,
- spi,
- bits, &dma_burst,
- &dma_thresh))
- dev_warn_ratelimited(&spi->dev,
- "DMA burst size reduced to match bits_per_word\n");
- }
- dma_mapped = controller->can_dma &&
- controller->can_dma(controller, spi, transfer) &&
- controller->cur_msg_mapped;
+ dma_thresh = SSCR1_RxTresh(RX_THRESH_DFLT) | SSCR1_TxTresh(TX_THRESH_DFLT);
+ dma_mapped = spi_xfer_is_dma_mapped(controller, spi, transfer);
if (dma_mapped) {
-
/* Ensure we have the correct interrupt handler */
drv_data->transfer_handler = pxa2xx_spi_dma_transfer;
@@ -1079,7 +1045,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
pxa_ssp_disable(drv_data->ssp);
if (!pxa25x_ssp_comp(drv_data))
- pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
+ pxa2xx_spi_write(drv_data, SSTO, TIMOUT_DFLT);
/* First set CR1 without interrupt and service enables */
pxa2xx_spi_update(drv_data, SSCR1, change_mask, cr1);
@@ -1102,7 +1068,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
}
}
- if (spi_controller_is_slave(controller)) {
+ if (spi_controller_is_target(controller)) {
while (drv_data->write(drv_data))
;
if (drv_data->gpiod_ready) {
@@ -1121,7 +1087,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
return 1;
}
-static int pxa2xx_spi_slave_abort(struct spi_controller *controller)
+static int pxa2xx_spi_target_abort(struct spi_controller *controller)
{
struct driver_data *drv_data = spi_controller_get_devdata(controller);
@@ -1163,7 +1129,6 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_controller *controller)
static int setup(struct spi_device *spi)
{
- struct pxa2xx_spi_chip *chip_info;
struct chip_data *chip;
const struct lpss_config *config;
struct driver_data *drv_data =
@@ -1199,7 +1164,7 @@ static int setup(struct spi_device *spi)
break;
default:
tx_hi_thres = 0;
- if (spi_controller_is_slave(drv_data->controller)) {
+ if (spi_controller_is_target(drv_data->controller)) {
tx_thres = 1;
rx_thres = 2;
} else {
@@ -1209,46 +1174,23 @@ static int setup(struct spi_device *spi)
break;
}
+ if (drv_data->ssp_type == CE4100_SSP) {
+ if (spi_get_chipselect(spi, 0) > 4) {
+ dev_err(&spi->dev, "failed setup: cs number must not be > 4.\n");
+ return -EINVAL;
+ }
+ }
+
/* Only allocate on the first setup */
chip = spi_get_ctldata(spi);
if (!chip) {
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip)
return -ENOMEM;
-
- if (drv_data->ssp_type == CE4100_SSP) {
- if (spi_get_chipselect(spi, 0) > 4) {
- dev_err(&spi->dev,
- "failed setup: cs number must not be > 4.\n");
- kfree(chip);
- return -EINVAL;
- }
- }
- chip->enable_dma = drv_data->controller_info->enable_dma;
- chip->timeout = TIMOUT_DFLT;
- }
-
- /*
- * Protocol drivers may change the chip settings, so...
- * if chip_info exists, use it.
- */
- chip_info = spi->controller_data;
-
- /* chip_info isn't always needed */
- if (chip_info) {
- if (chip_info->timeout)
- chip->timeout = chip_info->timeout;
- if (chip_info->tx_threshold)
- tx_thres = chip_info->tx_threshold;
- if (chip_info->tx_hi_threshold)
- tx_hi_thres = chip_info->tx_hi_threshold;
- if (chip_info->rx_threshold)
- rx_thres = chip_info->rx_threshold;
- chip->dma_threshold = 0;
}
chip->cr1 = 0;
- if (spi_controller_is_slave(drv_data->controller)) {
+ if (spi_controller_is_target(drv_data->controller)) {
chip->cr1 |= SSCR1_SCFR;
chip->cr1 |= SSCR1_SCLKDIR;
chip->cr1 |= SSCR1_SFRMDIR;
@@ -1266,25 +1208,6 @@ static int setup(struct spi_device *spi)
chip->lpss_tx_threshold = tx_thres;
}
- /*
- * Set DMA burst and threshold outside of chip_info path so that if
- * chip_info goes away after setting chip->enable_dma, the burst and
- * threshold can still respond to changes in bits_per_word.
- */
- if (chip->enable_dma) {
- /* Set up legal burst and threshold for DMA */
- if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi,
- spi->bits_per_word,
- &chip->dma_burst_size,
- &chip->dma_threshold)) {
- dev_warn(&spi->dev,
- "in setup: DMA burst size reduced to match bits_per_word\n");
- }
- dev_dbg(&spi->dev,
- "in setup: DMA burst size set to %u\n",
- chip->dma_burst_size);
- }
-
switch (drv_data->ssp_type) {
case QUARK_X1000_SSP:
chip->threshold = (QUARK_X1000_SSCR1_RxTresh(rx_thres)
@@ -1321,110 +1244,24 @@ static void cleanup(struct spi_device *spi)
kfree(chip);
}
-static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
-{
- return param == chan->device->dev;
-}
-
-static struct pxa2xx_spi_controller *
-pxa2xx_spi_init_pdata(struct platform_device *pdev)
-{
- struct pxa2xx_spi_controller *pdata;
- struct device *dev = &pdev->dev;
- struct device *parent = dev->parent;
- struct ssp_device *ssp;
- struct resource *res;
- enum pxa_ssp_type type = SSP_UNDEFINED;
- const void *match;
- bool is_lpss_priv;
- int status;
- u64 uid;
-
- is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv");
-
- match = device_get_match_data(dev);
- if (match)
- type = (enum pxa_ssp_type)match;
- else if (is_lpss_priv) {
- u32 value;
-
- status = device_property_read_u32(dev, "intel,spi-pxa2xx-type", &value);
- if (status)
- return ERR_PTR(status);
-
- type = (enum pxa_ssp_type)value;
- }
-
- /* Validate the SSP type correctness */
- if (!(type > SSP_UNDEFINED && type < SSP_MAX))
- return ERR_PTR(-EINVAL);
-
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return ERR_PTR(-ENOMEM);
-
- ssp = &pdata->ssp;
-
- ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
- if (IS_ERR(ssp->mmio_base))
- return ERR_CAST(ssp->mmio_base);
-
- ssp->phys_base = res->start;
-
- /* Platforms with iDMA 64-bit */
- if (is_lpss_priv) {
- pdata->tx_param = parent;
- pdata->rx_param = parent;
- pdata->dma_filter = pxa2xx_spi_idma_filter;
- }
-
- ssp->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(ssp->clk))
- return ERR_CAST(ssp->clk);
-
- ssp->irq = platform_get_irq(pdev, 0);
- if (ssp->irq < 0)
- return ERR_PTR(ssp->irq);
-
- ssp->type = type;
- ssp->dev = dev;
-
- status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid);
- if (status)
- ssp->port_id = -1;
- else
- ssp->port_id = uid;
-
- pdata->is_slave = device_property_read_bool(dev, "spi-slave");
- pdata->num_chipselect = 1;
- pdata->enable_dma = true;
- pdata->dma_burst_size = 1;
-
- return pdata;
-}
-
static int pxa2xx_spi_fw_translate_cs(struct spi_controller *controller,
unsigned int cs)
{
struct driver_data *drv_data = spi_controller_get_devdata(controller);
- if (has_acpi_companion(drv_data->ssp->dev)) {
- switch (drv_data->ssp_type) {
- /*
- * For Atoms the ACPI DeviceSelection used by the Windows
- * driver starts from 1 instead of 0 so translate it here
- * to match what Linux expects.
- */
- case LPSS_BYT_SSP:
- case LPSS_BSW_SSP:
- return cs - 1;
+ switch (drv_data->ssp_type) {
+ /*
+ * For some of Intel Atoms the ACPI DeviceSelection used by the Windows
+ * driver starts from 1 instead of 0 so translate it here to match what
+ * Linux expects.
+ */
+ case LPSS_BYT_SSP:
+ case LPSS_BSW_SSP:
+ return cs - 1;
- default:
- break;
- }
+ default:
+ return cs;
}
-
- return cs;
}
static size_t pxa2xx_spi_max_dma_transfer_size(struct spi_device *spi)
@@ -1432,45 +1269,22 @@ static size_t pxa2xx_spi_max_dma_transfer_size(struct spi_device *spi)
return MAX_DMA_LEN;
}
-static int pxa2xx_spi_probe(struct platform_device *pdev)
+int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
+ struct pxa2xx_spi_controller *platform_info)
{
- struct device *dev = &pdev->dev;
- struct pxa2xx_spi_controller *platform_info;
struct spi_controller *controller;
struct driver_data *drv_data;
- struct ssp_device *ssp;
const struct lpss_config *config;
int status;
u32 tmp;
- platform_info = dev_get_platdata(dev);
- if (!platform_info) {
- platform_info = pxa2xx_spi_init_pdata(pdev);
- if (IS_ERR(platform_info)) {
- dev_err(&pdev->dev, "missing platform data\n");
- return PTR_ERR(platform_info);
- }
- }
-
- ssp = pxa_ssp_request(pdev->id, pdev->name);
- if (!ssp)
- ssp = &platform_info->ssp;
-
- if (!ssp->mmio_base) {
- dev_err(&pdev->dev, "failed to get SSP\n");
- return -ENODEV;
- }
-
- if (platform_info->is_slave)
- controller = devm_spi_alloc_slave(dev, sizeof(*drv_data));
+ if (platform_info->is_target)
+ controller = devm_spi_alloc_target(dev, sizeof(*drv_data));
else
- controller = devm_spi_alloc_master(dev, sizeof(*drv_data));
+ controller = devm_spi_alloc_host(dev, sizeof(*drv_data));
+ if (!controller)
+ return -ENOMEM;
- if (!controller) {
- dev_err(&pdev->dev, "cannot alloc spi_controller\n");
- status = -ENOMEM;
- goto out_error_controller_alloc;
- }
drv_data = spi_controller_get_devdata(controller);
drv_data->controller = controller;
drv_data->controller_info = platform_info;
@@ -1487,7 +1301,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
controller->setup = setup;
controller->set_cs = pxa2xx_spi_set_cs;
controller->transfer_one = pxa2xx_spi_transfer_one;
- controller->slave_abort = pxa2xx_spi_slave_abort;
+ controller->target_abort = pxa2xx_spi_target_abort;
controller->handle_err = pxa2xx_spi_handle_err;
controller->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
controller->fw_translate_cs = pxa2xx_spi_fw_translate_cs;
@@ -1521,10 +1335,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
drv_data);
- if (status < 0) {
- dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
- goto out_error_controller_alloc;
- }
+ if (status < 0)
+ return dev_err_probe(dev, status, "cannot get IRQ %d\n", ssp->irq);
/* Setup DMA if requested */
if (platform_info->enable_dma) {
@@ -1537,6 +1349,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
controller->max_dma_len = MAX_DMA_LEN;
controller->max_transfer_size =
pxa2xx_spi_max_dma_transfer_size;
+
+ dev_dbg(dev, "DMA burst size set to %u\n", platform_info->dma_burst_size);
}
}
@@ -1579,7 +1393,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
break;
default:
- if (spi_controller_is_slave(controller)) {
+ if (spi_controller_is_target(controller)) {
tmp = SSCR1_SCFR |
SSCR1_SCLKDIR |
SSCR1_SFRMDIR |
@@ -1592,7 +1406,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
}
pxa2xx_spi_write(drv_data, SSCR1, tmp);
tmp = SSCR0_Motorola | SSCR0_DataSize(8);
- if (!spi_controller_is_slave(controller))
+ if (!spi_controller_is_target(controller))
tmp |= SSCR0_SCR(2);
pxa2xx_spi_write(drv_data, SSCR0, tmp);
break;
@@ -1613,14 +1427,12 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
tmp &= LPSS_CAPS_CS_EN_MASK;
tmp >>= LPSS_CAPS_CS_EN_SHIFT;
platform_info->num_chipselect = ffz(tmp);
- } else if (config->cs_num) {
- platform_info->num_chipselect = config->cs_num;
}
}
controller->num_chipselect = platform_info->num_chipselect;
controller->use_gpio_descriptors = true;
- if (platform_info->is_slave) {
+ if (platform_info->is_target) {
drv_data->gpiod_ready = devm_gpiod_get_optional(dev,
"ready", GPIOD_OUT_LOW);
if (IS_ERR(drv_data->gpiod_ready)) {
@@ -1629,24 +1441,16 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
}
}
- pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
-
/* Register with the SPI framework */
- platform_set_drvdata(pdev, drv_data);
+ dev_set_drvdata(dev, drv_data);
status = spi_register_controller(controller);
if (status) {
- dev_err(&pdev->dev, "problem registering SPI controller\n");
- goto out_error_pm_runtime_enabled;
+ dev_err_probe(dev, status, "problem registering SPI controller\n");
+ goto out_error_clock_enabled;
}
return status;
-out_error_pm_runtime_enabled:
- pm_runtime_disable(&pdev->dev);
-
out_error_clock_enabled:
clk_disable_unprepare(ssp->clk);
@@ -1654,18 +1458,15 @@ out_error_dma_irq_alloc:
pxa2xx_spi_dma_release(drv_data);
free_irq(ssp->irq, drv_data);
-out_error_controller_alloc:
- pxa_ssp_free(ssp);
return status;
}
+EXPORT_SYMBOL_NS_GPL(pxa2xx_spi_probe, "SPI_PXA2xx");
-static void pxa2xx_spi_remove(struct platform_device *pdev)
+void pxa2xx_spi_remove(struct device *dev)
{
- struct driver_data *drv_data = platform_get_drvdata(pdev);
+ struct driver_data *drv_data = dev_get_drvdata(dev);
struct ssp_device *ssp = drv_data->ssp;
- pm_runtime_get_sync(&pdev->dev);
-
spi_unregister_controller(drv_data->controller);
/* Disable the SSP at the peripheral and SOC level */
@@ -1676,15 +1477,10 @@ static void pxa2xx_spi_remove(struct platform_device *pdev)
if (drv_data->controller_info->enable_dma)
pxa2xx_spi_dma_release(drv_data);
- pm_runtime_put_noidle(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
/* Release IRQ */
free_irq(ssp->irq, drv_data);
-
- /* Release SSP */
- pxa_ssp_free(ssp);
}
+EXPORT_SYMBOL_NS_GPL(pxa2xx_spi_remove, "SPI_PXA2xx");
static int pxa2xx_spi_suspend(struct device *dev)
{
@@ -1736,51 +1532,11 @@ static int pxa2xx_spi_runtime_resume(struct device *dev)
return clk_prepare_enable(drv_data->ssp->clk);
}
-static const struct dev_pm_ops pxa2xx_spi_pm_ops = {
+EXPORT_NS_GPL_DEV_PM_OPS(pxa2xx_spi_pm_ops, SPI_PXA2xx) = {
SYSTEM_SLEEP_PM_OPS(pxa2xx_spi_suspend, pxa2xx_spi_resume)
RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend, pxa2xx_spi_runtime_resume, NULL)
};
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
- { "80860F0E", LPSS_BYT_SSP },
- { "8086228E", LPSS_BSW_SSP },
- { "INT33C0", LPSS_LPT_SSP },
- { "INT33C1", LPSS_LPT_SSP },
- { "INT3430", LPSS_LPT_SSP },
- { "INT3431", LPSS_LPT_SSP },
- {}
-};
-MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
-#endif
-
-static const struct of_device_id pxa2xx_spi_of_match[] __maybe_unused = {
- { .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP },
- {}
-};
-MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match);
-
-static struct platform_driver driver = {
- .driver = {
- .name = "pxa2xx-spi",
- .pm = pm_ptr(&pxa2xx_spi_pm_ops),
- .acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match),
- .of_match_table = of_match_ptr(pxa2xx_spi_of_match),
- },
- .probe = pxa2xx_spi_probe,
- .remove_new = pxa2xx_spi_remove,
-};
-
-static int __init pxa2xx_spi_init(void)
-{
- return platform_driver_register(&driver);
-}
-subsys_initcall(pxa2xx_spi_init);
-
-static void __exit pxa2xx_spi_exit(void)
-{
- platform_driver_unregister(&driver);
-}
-module_exit(pxa2xx_spi_exit);
-
-MODULE_SOFTDEP("pre: dw_dmac");
+MODULE_AUTHOR("Stephen Street");
+MODULE_DESCRIPTION("PXA2xx SSP SPI Controller core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index 45cdbbc71c4b..447be0369384 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -7,15 +7,35 @@
#ifndef SPI_PXA2XX_H
#define SPI_PXA2XX_H
-#include <linux/interrupt.h>
-#include <linux/io.h>
+#include <linux/dmaengine.h>
+#include <linux/irqreturn.h>
#include <linux/types.h>
#include <linux/sizes.h>
#include <linux/pxa2xx_ssp.h>
+struct device;
struct gpio_desc;
-struct pxa2xx_spi_controller;
+
+/*
+ * The platform data for SSP controller devices
+ * (resides in device.platform_data).
+ */
+struct pxa2xx_spi_controller {
+ u8 num_chipselect;
+ u8 enable_dma;
+ u8 dma_burst_size;
+ bool is_target;
+
+ /* DMA engine specific config */
+ dma_filter_fn dma_filter;
+ void *tx_param;
+ void *rx_param;
+
+ /* For non-PXA arches */
+ struct ssp_device ssp;
+};
+
struct spi_controller;
struct spi_device;
struct spi_transfer;
@@ -56,18 +76,6 @@ struct driver_data {
struct gpio_desc *gpiod_ready;
};
-struct chip_data {
- u32 cr1;
- u32 dds_rate;
- u32 timeout;
- u8 enable_dma;
- u32 dma_burst_size;
- u32 dma_threshold;
- u32 threshold;
- u16 lpss_rx_threshold;
- u16 lpss_tx_threshold;
-};
-
static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg)
{
return pxa_ssp_read_reg(drv_data->ssp, reg);
@@ -123,10 +131,11 @@ extern void pxa2xx_spi_dma_start(struct driver_data *drv_data);
extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data);
extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data);
extern void pxa2xx_spi_dma_release(struct driver_data *drv_data);
-extern int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
- struct spi_device *spi,
- u8 bits_per_word,
- u32 *burst_code,
- u32 *threshold);
+
+int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
+ struct pxa2xx_spi_controller *platform_info);
+void pxa2xx_spi_remove(struct device *dev);
+
+extern const struct dev_pm_ops pxa2xx_spi_pm_ops;
#endif /* SPI_PXA2XX_H */
diff --git a/drivers/spi/spi-qcom-qspi.c b/drivers/spi/spi-qcom-qspi.c
index 1954c39b3d08..3aeddada58e1 100644
--- a/drivers/spi/spi-qcom-qspi.c
+++ b/drivers/spi/spi-qcom-qspi.c
@@ -9,7 +9,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/pm_opp.h>
@@ -247,11 +247,11 @@ static void qcom_qspi_pio_xfer(struct qcom_qspi *ctrl)
qcom_qspi_pio_xfer_ctrl(ctrl);
}
-static void qcom_qspi_handle_err(struct spi_master *master,
+static void qcom_qspi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
u32 int_status;
- struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
unsigned long flags;
int i;
@@ -411,11 +411,11 @@ static bool qcom_qspi_can_dma(struct spi_controller *ctlr,
return xfer->len > QSPI_MAX_BYTES_FIFO;
}
-static int qcom_qspi_transfer_one(struct spi_master *master,
+static int qcom_qspi_transfer_one(struct spi_controller *host,
struct spi_device *slv,
struct spi_transfer *xfer)
{
- struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
int ret;
unsigned long speed_hz;
unsigned long flags;
@@ -443,7 +443,7 @@ static int qcom_qspi_transfer_one(struct spi_master *master,
ctrl->xfer.tx_buf = xfer->tx_buf;
}
ctrl->xfer.is_last = list_is_last(&xfer->transfer_list,
- &master->cur_msg->transfers);
+ &host->cur_msg->transfers);
ctrl->xfer.rem_bytes = xfer->len;
if (xfer->rx_sg.nents || xfer->tx_sg.nents) {
@@ -481,7 +481,7 @@ exit:
return 1;
}
-static int qcom_qspi_prepare_message(struct spi_master *master,
+static int qcom_qspi_prepare_message(struct spi_controller *host,
struct spi_message *message)
{
u32 mstr_cfg;
@@ -490,7 +490,7 @@ static int qcom_qspi_prepare_message(struct spi_master *master,
int tx_data_delay = 1;
unsigned long flags;
- ctrl = spi_master_get_devdata(master);
+ ctrl = spi_controller_get_devdata(host);
spin_lock_irqsave(&ctrl->lock, flags);
mstr_cfg = readl(ctrl->base + MSTR_CONFIG);
@@ -694,18 +694,18 @@ static int qcom_qspi_probe(struct platform_device *pdev)
{
int ret;
struct device *dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct qcom_qspi *ctrl;
dev = &pdev->dev;
- master = devm_spi_alloc_master(dev, sizeof(*ctrl));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(*ctrl));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- ctrl = spi_master_get_devdata(master);
+ ctrl = spi_controller_get_devdata(host);
spin_lock_init(&ctrl->lock);
ctrl->dev = dev;
@@ -758,23 +758,23 @@ static int qcom_qspi_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(dev, ret, "could not set DMA mask\n");
- master->max_speed_hz = 300000000;
- master->max_dma_len = 65536; /* as per HPG */
- master->dma_alignment = QSPI_ALIGN_REQ;
- master->num_chipselect = QSPI_NUM_CS;
- master->bus_num = -1;
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_MODE_0 |
- SPI_TX_DUAL | SPI_RX_DUAL |
- SPI_TX_QUAD | SPI_RX_QUAD;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->prepare_message = qcom_qspi_prepare_message;
- master->transfer_one = qcom_qspi_transfer_one;
- master->handle_err = qcom_qspi_handle_err;
- if (of_property_read_bool(pdev->dev.of_node, "iommus"))
- master->can_dma = qcom_qspi_can_dma;
- master->auto_runtime_pm = true;
- master->mem_ops = &qcom_qspi_mem_ops;
+ host->max_speed_hz = 300000000;
+ host->max_dma_len = 65536; /* as per HPG */
+ host->dma_alignment = QSPI_ALIGN_REQ;
+ host->num_chipselect = QSPI_NUM_CS;
+ host->bus_num = -1;
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_MODE_0 |
+ SPI_TX_DUAL | SPI_RX_DUAL |
+ SPI_TX_QUAD | SPI_RX_QUAD;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->prepare_message = qcom_qspi_prepare_message;
+ host->transfer_one = qcom_qspi_transfer_one;
+ host->handle_err = qcom_qspi_handle_err;
+ if (of_property_present(pdev->dev.of_node, "iommus"))
+ host->can_dma = qcom_qspi_can_dma;
+ host->auto_runtime_pm = true;
+ host->mem_ops = &qcom_qspi_mem_ops;
ret = devm_pm_opp_set_clkname(&pdev->dev, "core");
if (ret)
@@ -794,7 +794,7 @@ static int qcom_qspi_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(dev, 250);
pm_runtime_enable(dev);
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (!ret)
return 0;
@@ -805,18 +805,18 @@ static int qcom_qspi_probe(struct platform_device *pdev)
static void qcom_qspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_controller *host = platform_get_drvdata(pdev);
/* Unregister _before_ disabling pm_runtime() so we stop transfers */
- spi_unregister_master(master);
+ spi_unregister_controller(host);
pm_runtime_disable(&pdev->dev);
}
static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
int ret;
/* Drop the performance state vote */
@@ -837,8 +837,8 @@ static int __maybe_unused qcom_qspi_runtime_suspend(struct device *dev)
static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct qcom_qspi *ctrl = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct qcom_qspi *ctrl = spi_controller_get_devdata(host);
int ret;
pinctrl_pm_select_default_state(dev);
@@ -859,30 +859,30 @@ static int __maybe_unused qcom_qspi_runtime_resume(struct device *dev)
static int __maybe_unused qcom_qspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
ret = pm_runtime_force_suspend(dev);
if (ret)
- spi_master_resume(master);
+ spi_controller_resume(host);
return ret;
}
static int __maybe_unused qcom_qspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret)
pm_runtime_force_suspend(dev);
@@ -908,7 +908,7 @@ static struct platform_driver qcom_qspi_driver = {
.of_match_table = qcom_qspi_dt_match,
},
.probe = qcom_qspi_probe,
- .remove_new = qcom_qspi_remove,
+ .remove = qcom_qspi_remove,
};
module_platform_driver(qcom_qspi_driver);
diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c
new file mode 100644
index 000000000000..7681a91d67d5
--- /dev/null
+++ b/drivers/spi/spi-qpic-snand.c
@@ -0,0 +1,1653 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * Authors:
+ * Md Sadre Alam <quic_mdalam@quicinc.com>
+ * Sricharan R <quic_srichara@quicinc.com>
+ * Varadarajan Narayanan <quic_varada@quicinc.com>
+ */
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma/qcom_adm.h>
+#include <linux/dma/qcom_bam_dma.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mtd/nand-qpic-common.h>
+#include <linux/mtd/spinand.h>
+#include <linux/bitfield.h>
+
+#define NAND_FLASH_SPI_CFG 0xc0
+#define NAND_NUM_ADDR_CYCLES 0xc4
+#define NAND_BUSY_CHECK_WAIT_CNT 0xc8
+#define NAND_FLASH_FEATURES 0xf64
+
+/* QSPI NAND config reg bits */
+#define LOAD_CLK_CNTR_INIT_EN BIT(28)
+#define CLK_CNTR_INIT_VAL_VEC 0x924
+#define CLK_CNTR_INIT_VAL_VEC_MASK GENMASK(27, 16)
+#define FEA_STATUS_DEV_ADDR 0xc0
+#define FEA_STATUS_DEV_ADDR_MASK GENMASK(15, 8)
+#define SPI_CFG BIT(0)
+#define SPI_NUM_ADDR 0xDA4DB
+#define SPI_WAIT_CNT 0x10
+#define QPIC_QSPI_NUM_CS 1
+#define SPI_TRANSFER_MODE_x1 BIT(29)
+#define SPI_TRANSFER_MODE_x4 (3 << 29)
+#define SPI_WP BIT(28)
+#define SPI_HOLD BIT(27)
+#define QPIC_SET_FEATURE BIT(31)
+
+#define SPINAND_RESET 0xff
+#define SPINAND_READID 0x9f
+#define SPINAND_GET_FEATURE 0x0f
+#define SPINAND_SET_FEATURE 0x1f
+#define SPINAND_READ 0x13
+#define SPINAND_ERASE 0xd8
+#define SPINAND_WRITE_EN 0x06
+#define SPINAND_PROGRAM_EXECUTE 0x10
+#define SPINAND_PROGRAM_LOAD 0x84
+
+#define ACC_FEATURE 0xe
+#define BAD_BLOCK_MARKER_SIZE 0x2
+#define OOB_BUF_SIZE 128
+#define ecceng_to_qspi(eng) container_of(eng, struct qpic_spi_nand, ecc_eng)
+
+struct snandc_read_status {
+ __le32 snandc_flash;
+ __le32 snandc_buffer;
+ __le32 snandc_erased_cw;
+};
+
+/*
+ * ECC state struct
+ * @corrected: ECC corrected
+ * @bitflips: Max bit flip
+ * @failed: ECC failed
+ */
+struct qcom_ecc_stats {
+ u32 corrected;
+ u32 bitflips;
+ u32 failed;
+};
+
+struct qpic_ecc {
+ int ecc_bytes_hw;
+ int spare_bytes;
+ int bbm_size;
+ int ecc_mode;
+ int bytes;
+ int steps;
+ int step_size;
+ int strength;
+ int cw_size;
+ int cw_data;
+ u32 cfg0;
+ u32 cfg1;
+ u32 cfg0_raw;
+ u32 cfg1_raw;
+ u32 ecc_buf_cfg;
+ u32 ecc_bch_cfg;
+ bool bch_enabled;
+};
+
+struct qpic_spi_nand {
+ struct qcom_nand_controller *snandc;
+ struct spi_controller *ctlr;
+ struct mtd_info *mtd;
+ struct clk *iomacro_clk;
+ struct qpic_ecc *ecc;
+ struct qcom_ecc_stats ecc_stats;
+ struct nand_ecc_engine ecc_eng;
+ u8 *data_buf;
+ u8 *oob_buf;
+ __le32 addr1;
+ __le32 addr2;
+ __le32 cmd;
+ u32 num_cw;
+ bool oob_rw;
+ bool page_rw;
+ bool raw_rw;
+};
+
+static void qcom_spi_set_read_loc_first(struct qcom_nand_controller *snandc,
+ int reg, int cw_offset, int read_size,
+ int is_last_read_loc)
+{
+ __le32 locreg_val;
+ u32 val = FIELD_PREP(READ_LOCATION_OFFSET_MASK, cw_offset) |
+ FIELD_PREP(READ_LOCATION_SIZE_MASK, read_size) |
+ FIELD_PREP(READ_LOCATION_LAST_MASK, is_last_read_loc);
+
+ locreg_val = cpu_to_le32(val);
+
+ if (reg == NAND_READ_LOCATION_0)
+ snandc->regs->read_location0 = locreg_val;
+ else if (reg == NAND_READ_LOCATION_1)
+ snandc->regs->read_location1 = locreg_val;
+ else if (reg == NAND_READ_LOCATION_2)
+ snandc->regs->read_location2 = locreg_val;
+ else if (reg == NAND_READ_LOCATION_3)
+ snandc->regs->read_location3 = locreg_val;
+}
+
+static void qcom_spi_set_read_loc_last(struct qcom_nand_controller *snandc,
+ int reg, int cw_offset, int read_size,
+ int is_last_read_loc)
+{
+ __le32 locreg_val;
+ u32 val = FIELD_PREP(READ_LOCATION_OFFSET_MASK, cw_offset) |
+ FIELD_PREP(READ_LOCATION_SIZE_MASK, read_size) |
+ FIELD_PREP(READ_LOCATION_LAST_MASK, is_last_read_loc);
+
+ locreg_val = cpu_to_le32(val);
+
+ if (reg == NAND_READ_LOCATION_LAST_CW_0)
+ snandc->regs->read_location_last0 = locreg_val;
+ else if (reg == NAND_READ_LOCATION_LAST_CW_1)
+ snandc->regs->read_location_last1 = locreg_val;
+ else if (reg == NAND_READ_LOCATION_LAST_CW_2)
+ snandc->regs->read_location_last2 = locreg_val;
+ else if (reg == NAND_READ_LOCATION_LAST_CW_3)
+ snandc->regs->read_location_last3 = locreg_val;
+}
+
+static struct qcom_nand_controller *nand_to_qcom_snand(struct nand_device *nand)
+{
+ struct nand_ecc_engine *eng = nand->ecc.engine;
+ struct qpic_spi_nand *qspi = ecceng_to_qspi(eng);
+
+ return qspi->snandc;
+}
+
+static int qcom_spi_init(struct qcom_nand_controller *snandc)
+{
+ u32 snand_cfg_val = 0x0;
+ int ret;
+
+ snand_cfg_val = FIELD_PREP(CLK_CNTR_INIT_VAL_VEC_MASK, CLK_CNTR_INIT_VAL_VEC) |
+ FIELD_PREP(LOAD_CLK_CNTR_INIT_EN, 0) |
+ FIELD_PREP(FEA_STATUS_DEV_ADDR_MASK, FEA_STATUS_DEV_ADDR) |
+ FIELD_PREP(SPI_CFG, 0);
+
+ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
+ snandc->regs->num_addr_cycle = cpu_to_le32(SPI_NUM_ADDR);
+ snandc->regs->busy_wait_cnt = cpu_to_le32(SPI_WAIT_CNT);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
+
+ snand_cfg_val &= ~LOAD_CLK_CNTR_INIT_EN;
+ snandc->regs->spi_cfg = cpu_to_le32(snand_cfg_val);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->spi_cfg, NAND_FLASH_SPI_CFG, 1, 0);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->num_addr_cycle, NAND_NUM_ADDR_CYCLES, 1, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->busy_wait_cnt, NAND_BUSY_CHECK_WAIT_CNT, 1,
+ NAND_BAM_NEXT_SGL);
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failure in submitting spi init descriptor\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int qcom_spi_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
+ struct qpic_ecc *qecc = snandc->qspi->ecc;
+
+ switch (section) {
+ case 0:
+ oobregion->offset = 0;
+ oobregion->length = qecc->bytes * (qecc->steps - 1) +
+ qecc->bbm_size;
+ return 0;
+ case 1:
+ oobregion->offset = qecc->bytes * (qecc->steps - 1) +
+ qecc->bbm_size +
+ qecc->steps * 4;
+ oobregion->length = mtd->oobsize - oobregion->offset;
+ return 0;
+ }
+
+ return -ERANGE;
+}
+
+static int qcom_spi_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct nand_device *nand = mtd_to_nanddev(mtd);
+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
+ struct qpic_ecc *qecc = snandc->qspi->ecc;
+
+ if (section)
+ return -ERANGE;
+
+ oobregion->length = qecc->steps * 4;
+ oobregion->offset = ((qecc->steps - 1) * qecc->bytes) + qecc->bbm_size;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops qcom_spi_ooblayout = {
+ .ecc = qcom_spi_ooblayout_ecc,
+ .free = qcom_spi_ooblayout_free,
+};
+
+static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
+{
+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
+ struct nand_ecc_props *reqs = &nand->ecc.requirements;
+ struct nand_ecc_props *user = &nand->ecc.user_conf;
+ struct nand_ecc_props *conf = &nand->ecc.ctx.conf;
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
+ int cwperpage, bad_block_byte, ret;
+ struct qpic_ecc *ecc_cfg;
+
+ cwperpage = mtd->writesize / NANDC_STEP_SIZE;
+ snandc->qspi->num_cw = cwperpage;
+
+ ecc_cfg = kzalloc(sizeof(*ecc_cfg), GFP_KERNEL);
+ if (!ecc_cfg)
+ return -ENOMEM;
+
+ if (user->step_size && user->strength) {
+ ecc_cfg->step_size = user->step_size;
+ ecc_cfg->strength = user->strength;
+ } else if (reqs->step_size && reqs->strength) {
+ ecc_cfg->step_size = reqs->step_size;
+ ecc_cfg->strength = reqs->strength;
+ } else {
+ /* use defaults */
+ ecc_cfg->step_size = NANDC_STEP_SIZE;
+ ecc_cfg->strength = 4;
+ }
+
+ if (ecc_cfg->step_size != NANDC_STEP_SIZE) {
+ dev_err(snandc->dev,
+ "only %u bytes ECC step size is supported\n",
+ NANDC_STEP_SIZE);
+ ret = -EOPNOTSUPP;
+ goto err_free_ecc_cfg;
+ }
+
+ switch (ecc_cfg->strength) {
+ case 4:
+ ecc_cfg->ecc_mode = ECC_MODE_4BIT;
+ ecc_cfg->ecc_bytes_hw = 7;
+ ecc_cfg->spare_bytes = 4;
+ break;
+
+ case 8:
+ ecc_cfg->ecc_mode = ECC_MODE_8BIT;
+ ecc_cfg->ecc_bytes_hw = 13;
+ ecc_cfg->spare_bytes = 2;
+ break;
+
+ default:
+ dev_err(snandc->dev,
+ "only 4 or 8 bits ECC strength is supported\n");
+ ret = -EOPNOTSUPP;
+ goto err_free_ecc_cfg;
+ }
+
+ snandc->qspi->oob_buf = kmalloc(mtd->writesize + mtd->oobsize,
+ GFP_KERNEL);
+ if (!snandc->qspi->oob_buf) {
+ ret = -ENOMEM;
+ goto err_free_ecc_cfg;
+ }
+
+ memset(snandc->qspi->oob_buf, 0xff, mtd->writesize + mtd->oobsize);
+
+ nand->ecc.ctx.priv = ecc_cfg;
+ snandc->qspi->mtd = mtd;
+
+ ecc_cfg->bbm_size = 1;
+ ecc_cfg->bch_enabled = true;
+ ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
+
+ ecc_cfg->steps = cwperpage;
+ ecc_cfg->cw_data = 516;
+ ecc_cfg->cw_size = ecc_cfg->cw_data + ecc_cfg->bytes;
+ bad_block_byte = mtd->writesize - ecc_cfg->cw_size * (cwperpage - 1) + 1;
+
+ mtd_set_ooblayout(mtd, &qcom_spi_ooblayout);
+
+ /*
+ * Free the temporary BAM transaction allocated initially by
+ * qcom_nandc_alloc(), and allocate a new one based on the
+ * updated max_cwperpage value.
+ */
+ qcom_free_bam_transaction(snandc);
+
+ snandc->max_cwperpage = cwperpage;
+
+ snandc->bam_txn = qcom_alloc_bam_transaction(snandc);
+ if (!snandc->bam_txn) {
+ dev_err(snandc->dev, "failed to allocate BAM transaction\n");
+ ret = -ENOMEM;
+ goto err_free_ecc_cfg;
+ }
+
+ ecc_cfg->cfg0 = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
+ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_data) |
+ FIELD_PREP(DISABLE_STATUS_AFTER_WRITE, 1) |
+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_RS, ecc_cfg->ecc_bytes_hw) |
+ FIELD_PREP(STATUS_BFR_READ, 0) |
+ FIELD_PREP(SET_RD_MODE_AFTER_STATUS, 1) |
+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, ecc_cfg->spare_bytes);
+
+ ecc_cfg->cfg1 = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, bad_block_byte) |
+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 0) |
+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
+ FIELD_PREP(WIDE_FLASH, 0) |
+ FIELD_PREP(ENABLE_BCH_ECC, ecc_cfg->bch_enabled);
+
+ ecc_cfg->cfg0_raw = FIELD_PREP(CW_PER_PAGE_MASK, (cwperpage - 1)) |
+ FIELD_PREP(NUM_ADDR_CYCLES_MASK, 3) |
+ FIELD_PREP(UD_SIZE_BYTES_MASK, ecc_cfg->cw_size) |
+ FIELD_PREP(SPARE_SIZE_BYTES_MASK, 0);
+
+ ecc_cfg->cfg1_raw = FIELD_PREP(NAND_RECOVERY_CYCLES_MASK, 0) |
+ FIELD_PREP(CS_ACTIVE_BSY, 0) |
+ FIELD_PREP(BAD_BLOCK_BYTE_NUM_MASK, 17) |
+ FIELD_PREP(BAD_BLOCK_IN_SPARE_AREA, 1) |
+ FIELD_PREP(WR_RD_BSY_GAP_MASK, 20) |
+ FIELD_PREP(WIDE_FLASH, 0) |
+ FIELD_PREP(DEV0_CFG1_ECC_DISABLE, 1);
+
+ ecc_cfg->ecc_bch_cfg = FIELD_PREP(ECC_CFG_ECC_DISABLE, !ecc_cfg->bch_enabled) |
+ FIELD_PREP(ECC_SW_RESET, 0) |
+ FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
+ FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
+ FIELD_PREP(ECC_MODE_MASK, ecc_cfg->ecc_mode) |
+ FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
+
+ ecc_cfg->ecc_buf_cfg = FIELD_PREP(NUM_STEPS_MASK, 0x203);
+
+ conf->step_size = ecc_cfg->step_size;
+ conf->strength = ecc_cfg->strength;
+
+ snandc->regs->clrflashstatus = cpu_to_le32(FS_READY_BSY_N);
+ snandc->regs->clrreadstatus = cpu_to_le32(0xc0);
+ snandc->regs->erased_cw_detect_cfg_clr = cpu_to_le32(CLR_ERASED_PAGE_DET);
+ snandc->regs->erased_cw_detect_cfg_set = cpu_to_le32(SET_ERASED_PAGE_DET);
+
+ dev_dbg(snandc->dev, "ECC strength: %u bits per %u bytes\n",
+ ecc_cfg->strength, ecc_cfg->step_size);
+
+ return 0;
+
+err_free_ecc_cfg:
+ kfree(ecc_cfg);
+ return ret;
+}
+
+static void qcom_spi_ecc_cleanup_ctx_pipelined(struct nand_device *nand)
+{
+ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
+
+ kfree(ecc_cfg);
+}
+
+static int qcom_spi_ecc_prepare_io_req_pipelined(struct nand_device *nand,
+ struct nand_page_io_req *req)
+{
+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
+ struct qpic_ecc *ecc_cfg = nand_to_ecc_ctx(nand);
+
+ snandc->qspi->ecc = ecc_cfg;
+ snandc->qspi->raw_rw = false;
+ snandc->qspi->oob_rw = false;
+ snandc->qspi->page_rw = false;
+
+ if (req->datalen)
+ snandc->qspi->page_rw = true;
+
+ if (req->ooblen)
+ snandc->qspi->oob_rw = true;
+
+ if (req->mode == MTD_OPS_RAW)
+ snandc->qspi->raw_rw = true;
+
+ return 0;
+}
+
+static int qcom_spi_ecc_finish_io_req_pipelined(struct nand_device *nand,
+ struct nand_page_io_req *req)
+{
+ struct qcom_nand_controller *snandc = nand_to_qcom_snand(nand);
+ struct mtd_info *mtd = nanddev_to_mtd(nand);
+
+ if (req->mode == MTD_OPS_RAW || req->type != NAND_PAGE_READ)
+ return 0;
+
+ if (snandc->qspi->ecc_stats.failed)
+ mtd->ecc_stats.failed += snandc->qspi->ecc_stats.failed;
+ else
+ mtd->ecc_stats.corrected += snandc->qspi->ecc_stats.corrected;
+
+ if (snandc->qspi->ecc_stats.failed)
+ return -EBADMSG;
+ else
+ return snandc->qspi->ecc_stats.bitflips;
+}
+
+static const struct nand_ecc_engine_ops qcom_spi_ecc_engine_ops_pipelined = {
+ .init_ctx = qcom_spi_ecc_init_ctx_pipelined,
+ .cleanup_ctx = qcom_spi_ecc_cleanup_ctx_pipelined,
+ .prepare_io_req = qcom_spi_ecc_prepare_io_req_pipelined,
+ .finish_io_req = qcom_spi_ecc_finish_io_req_pipelined,
+};
+
+/* helper to configure location register values */
+static void qcom_spi_set_read_loc(struct qcom_nand_controller *snandc, int cw, int reg,
+ int cw_offset, int read_size, int is_last_read_loc)
+{
+ int reg_base = NAND_READ_LOCATION_0;
+ int num_cw = snandc->qspi->num_cw;
+
+ if (cw == (num_cw - 1))
+ reg_base = NAND_READ_LOCATION_LAST_CW_0;
+
+ reg_base += reg * 4;
+
+ if (cw == (num_cw - 1))
+ return qcom_spi_set_read_loc_last(snandc, reg_base, cw_offset,
+ read_size, is_last_read_loc);
+ else
+ return qcom_spi_set_read_loc_first(snandc, reg_base, cw_offset,
+ read_size, is_last_read_loc);
+}
+
+static void
+qcom_spi_config_cw_read(struct qcom_nand_controller *snandc, bool use_ecc, int cw)
+{
+ __le32 *reg = &snandc->regs->read_location0;
+ int num_cw = snandc->qspi->num_cw;
+
+ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_0, 4, NAND_BAM_NEXT_SGL);
+ if (cw == (num_cw - 1)) {
+ reg = &snandc->regs->read_location_last0;
+ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4,
+ NAND_BAM_NEXT_SGL);
+ }
+
+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+ if (use_ecc) {
+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 2, 0);
+ qcom_read_reg_dma(snandc, NAND_ERASED_CW_DETECT_STATUS, 1,
+ NAND_BAM_NEXT_SGL);
+ } else {
+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1,
+ NAND_BAM_NEXT_SGL);
+ }
+}
+
+static int qcom_spi_block_erase(struct qcom_nand_controller *snandc)
+{
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ int ret;
+
+ snandc->buf_count = 0;
+ snandc->buf_start = 0;
+ qcom_clear_read_regs(snandc);
+ qcom_clear_bam_transaction(snandc);
+
+ snandc->regs->cmd = snandc->qspi->cmd;
+ snandc->regs->addr0 = snandc->qspi->addr1;
+ snandc->regs->addr1 = snandc->qspi->addr2;
+ snandc->regs->cfg0 = cpu_to_le32((ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) |
+ FIELD_PREP(CW_PER_PAGE_MASK, 0));
+ snandc->regs->cfg1 = cpu_to_le32(ecc_cfg->cfg1_raw);
+ snandc->regs->exec = cpu_to_le32(1);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 2, NAND_BAM_NEXT_SGL);
+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failure to erase block\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void qcom_spi_config_single_cw_page_read(struct qcom_nand_controller *snandc,
+ bool use_ecc, int cw)
+{
+ __le32 *reg = &snandc->regs->read_location0;
+ int num_cw = snandc->qspi->num_cw;
+
+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
+ NAND_ERASED_CW_DETECT_CFG, 1,
+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
+
+ if (cw == (num_cw - 1)) {
+ reg = &snandc->regs->read_location_last0;
+ qcom_write_reg_dma(snandc, reg, NAND_READ_LOCATION_LAST_CW_0, 4, NAND_BAM_NEXT_SGL);
+ }
+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, 0);
+}
+
+static int qcom_spi_check_raw_flash_errors(struct qcom_nand_controller *snandc, int cw_cnt)
+{
+ int i;
+
+ qcom_nandc_dev_to_mem(snandc, true);
+
+ for (i = 0; i < cw_cnt; i++) {
+ u32 flash = le32_to_cpu(snandc->reg_read_buf[i]);
+
+ if (flash & (FS_OP_ERR | FS_MPU_ERR))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ struct mtd_info *mtd = snandc->qspi->mtd;
+ int size, ret = 0;
+ int col, bbpos;
+ u32 cfg0, cfg1, ecc_bch_cfg;
+ u32 num_cw = snandc->qspi->num_cw;
+
+ qcom_clear_bam_transaction(snandc);
+ qcom_clear_read_regs(snandc);
+
+ size = ecc_cfg->cw_size;
+ col = ecc_cfg->cw_size * (num_cw - 1);
+
+ memset(snandc->data_buffer, 0xff, size);
+ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
+ snandc->regs->addr1 = snandc->qspi->addr2;
+
+ cfg0 = (ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) |
+ FIELD_PREP(CW_PER_PAGE_MASK, 0);
+ cfg1 = ecc_cfg->cfg1_raw;
+ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
+
+ snandc->regs->cmd = snandc->qspi->cmd;
+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
+ snandc->regs->exec = cpu_to_le32(1);
+
+ qcom_spi_set_read_loc(snandc, num_cw - 1, 0, 0, ecc_cfg->cw_size, 1);
+
+ qcom_spi_config_single_cw_page_read(snandc, false, num_cw - 1);
+
+ qcom_read_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, size, 0);
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failed to read last cw\n");
+ return ret;
+ }
+
+ ret = qcom_spi_check_raw_flash_errors(snandc, 1);
+ if (ret)
+ return ret;
+
+ bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
+
+ /*
+ * TODO: The SPINAND code expects two bad block marker bytes
+ * at the beginning of the OOB area, but the OOB layout used by
+ * the driver has only one. Duplicate that for now in order to
+ * avoid certain blocks to be marked as bad.
+ *
+ * This can be removed once single-byte bad block marker support
+ * gets implemented in the SPINAND code.
+ */
+ snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos];
+
+ memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes);
+
+ return ret;
+}
+
+static int qcom_spi_check_error(struct qcom_nand_controller *snandc)
+{
+ struct snandc_read_status *buf;
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ int i, num_cw = snandc->qspi->num_cw;
+ bool flash_op_err = false, erased;
+ unsigned int max_bitflips = 0;
+ unsigned int uncorrectable_cws = 0;
+
+ snandc->qspi->ecc_stats.failed = 0;
+ snandc->qspi->ecc_stats.corrected = 0;
+
+ qcom_nandc_dev_to_mem(snandc, true);
+ buf = (struct snandc_read_status *)snandc->reg_read_buf;
+
+ for (i = 0; i < num_cw; i++, buf++) {
+ u32 flash, buffer, erased_cw;
+
+ flash = le32_to_cpu(buf->snandc_flash);
+ buffer = le32_to_cpu(buf->snandc_buffer);
+ erased_cw = le32_to_cpu(buf->snandc_erased_cw);
+
+ if ((flash & FS_OP_ERR) && (buffer & BS_UNCORRECTABLE_BIT)) {
+ if (ecc_cfg->bch_enabled)
+ erased = (erased_cw & ERASED_CW) == ERASED_CW;
+ else
+ erased = false;
+
+ if (!erased)
+ uncorrectable_cws |= BIT(i);
+
+ } else if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
+ flash_op_err = true;
+ } else {
+ unsigned int stat;
+
+ stat = buffer & BS_CORRECTABLE_ERR_MSK;
+
+ /*
+ * The exact number of the corrected bits is
+ * unknown because the hardware only reports the
+ * number of the corrected bytes.
+ *
+ * Since we have no better solution at the moment,
+ * report that value as the number of bit errors
+ * despite that it is inaccurate in most cases.
+ */
+ if (stat && stat != ecc_cfg->strength)
+ dev_warn_once(snandc->dev,
+ "Warning: due to hw limitation, the reported number of the corrected bits may be inaccurate\n");
+
+ snandc->qspi->ecc_stats.corrected += stat;
+ max_bitflips = max(max_bitflips, stat);
+ }
+ }
+
+ if (flash_op_err)
+ return -EIO;
+
+ if (!uncorrectable_cws)
+ snandc->qspi->ecc_stats.bitflips = max_bitflips;
+ else
+ snandc->qspi->ecc_stats.failed++;
+
+ return 0;
+}
+
+static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_buf,
+ u8 *oob_buf, int cw)
+{
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ struct mtd_info *mtd = snandc->qspi->mtd;
+ int data_size1, data_size2, oob_size1, oob_size2;
+ int ret, reg_off = FLASH_BUF_ACC, read_loc = 0;
+ int raw_cw = cw;
+ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
+ int col;
+
+ snandc->buf_count = 0;
+ snandc->buf_start = 0;
+ qcom_clear_read_regs(snandc);
+ qcom_clear_bam_transaction(snandc);
+ raw_cw = num_cw - 1;
+
+ cfg0 = (ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) |
+ FIELD_PREP(CW_PER_PAGE_MASK, 0);
+ cfg1 = ecc_cfg->cfg1_raw;
+ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
+
+ col = ecc_cfg->cw_size * cw;
+
+ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
+ snandc->regs->addr1 = snandc->qspi->addr2;
+ snandc->regs->cmd = snandc->qspi->cmd;
+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
+ snandc->regs->exec = cpu_to_le32(1);
+
+ qcom_spi_set_read_loc(snandc, raw_cw, 0, 0, ecc_cfg->cw_size, 1);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
+ NAND_ERASED_CW_DETECT_CFG, 1,
+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
+
+ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
+ oob_size1 = ecc_cfg->bbm_size;
+
+ if (cw == (num_cw - 1)) {
+ data_size2 = NANDC_STEP_SIZE - data_size1 -
+ ((num_cw - 1) * 4);
+ oob_size2 = (num_cw * 4) + ecc_cfg->ecc_bytes_hw +
+ ecc_cfg->spare_bytes;
+ } else {
+ data_size2 = ecc_cfg->cw_data - data_size1;
+ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
+ }
+
+ qcom_spi_set_read_loc(snandc, cw, 0, read_loc, data_size1, 0);
+ read_loc += data_size1;
+
+ qcom_spi_set_read_loc(snandc, cw, 1, read_loc, oob_size1, 0);
+ read_loc += oob_size1;
+
+ qcom_spi_set_read_loc(snandc, cw, 2, read_loc, data_size2, 0);
+ read_loc += data_size2;
+
+ qcom_spi_set_read_loc(snandc, cw, 3, read_loc, oob_size2, 1);
+
+ qcom_spi_config_cw_read(snandc, false, raw_cw);
+
+ qcom_read_data_dma(snandc, reg_off, data_buf, data_size1, 0);
+ reg_off += data_size1;
+
+ qcom_read_data_dma(snandc, reg_off, oob_buf, oob_size1, 0);
+ reg_off += oob_size1;
+
+ qcom_read_data_dma(snandc, reg_off, data_buf + data_size1, data_size2, 0);
+ reg_off += data_size2;
+
+ qcom_read_data_dma(snandc, reg_off, oob_buf + oob_size1, oob_size2, 0);
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failure to read raw cw %d\n", cw);
+ return ret;
+ }
+
+ return qcom_spi_check_raw_flash_errors(snandc, 1);
+}
+
+static int qcom_spi_read_page_raw(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ u8 *data_buf = NULL, *oob_buf = NULL;
+ int ret, cw;
+ u32 num_cw = snandc->qspi->num_cw;
+
+ if (snandc->qspi->page_rw)
+ data_buf = op->data.buf.in;
+
+ oob_buf = snandc->qspi->oob_buf;
+ memset(oob_buf, 0xff, OOB_BUF_SIZE);
+
+ for (cw = 0; cw < num_cw; cw++) {
+ ret = qcom_spi_read_cw_raw(snandc, data_buf, oob_buf, cw);
+ if (ret)
+ return ret;
+
+ if (data_buf)
+ data_buf += ecc_cfg->cw_data;
+ if (oob_buf)
+ oob_buf += ecc_cfg->bytes;
+ }
+
+ return 0;
+}
+
+static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ u8 *data_buf = NULL, *oob_buf = NULL;
+ int ret, i;
+ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
+
+ data_buf = op->data.buf.in;
+ oob_buf = snandc->qspi->oob_buf;
+
+ snandc->buf_count = 0;
+ snandc->buf_start = 0;
+ qcom_clear_read_regs(snandc);
+
+ cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) |
+ FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
+ cfg1 = ecc_cfg->cfg1;
+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
+
+ snandc->regs->addr0 = snandc->qspi->addr1;
+ snandc->regs->addr1 = snandc->qspi->addr2;
+ snandc->regs->cmd = snandc->qspi->cmd;
+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
+ snandc->regs->exec = cpu_to_le32(1);
+
+ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
+
+ qcom_clear_bam_transaction(snandc);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
+ NAND_ERASED_CW_DETECT_CFG, 1,
+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
+
+ for (i = 0; i < num_cw; i++) {
+ int data_size, oob_size;
+
+ if (i == (num_cw - 1)) {
+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
+ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
+ ecc_cfg->spare_bytes;
+ } else {
+ data_size = ecc_cfg->cw_data;
+ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
+ }
+
+ if (data_buf && oob_buf) {
+ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 0);
+ qcom_spi_set_read_loc(snandc, i, 1, data_size, oob_size, 1);
+ } else if (data_buf) {
+ qcom_spi_set_read_loc(snandc, i, 0, 0, data_size, 1);
+ } else {
+ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
+ }
+
+ qcom_spi_config_cw_read(snandc, true, i);
+
+ if (data_buf)
+ qcom_read_data_dma(snandc, FLASH_BUF_ACC, data_buf,
+ data_size, 0);
+ if (oob_buf) {
+ int j;
+
+ for (j = 0; j < ecc_cfg->bbm_size; j++)
+ *oob_buf++ = 0xff;
+
+ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
+ oob_buf, oob_size, 0);
+ }
+
+ if (data_buf)
+ data_buf += data_size;
+ if (oob_buf)
+ oob_buf += oob_size;
+ }
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failure to read page\n");
+ return ret;
+ }
+
+ return qcom_spi_check_error(snandc);
+}
+
+static int qcom_spi_read_page_oob(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ u8 *oob_buf = NULL;
+ int ret, i;
+ u32 cfg0, cfg1, ecc_bch_cfg, num_cw = snandc->qspi->num_cw;
+
+ oob_buf = op->data.buf.in;
+
+ snandc->buf_count = 0;
+ snandc->buf_start = 0;
+ qcom_clear_read_regs(snandc);
+ qcom_clear_bam_transaction(snandc);
+
+ cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) |
+ FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
+ cfg1 = ecc_cfg->cfg1;
+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
+
+ snandc->regs->addr0 = snandc->qspi->addr1;
+ snandc->regs->addr1 = snandc->qspi->addr2;
+ snandc->regs->cmd = snandc->qspi->cmd;
+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
+ snandc->regs->exec = cpu_to_le32(1);
+
+ qcom_spi_set_read_loc(snandc, 0, 0, 0, ecc_cfg->cw_data, 1);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr,
+ NAND_ERASED_CW_DETECT_CFG, 1, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set,
+ NAND_ERASED_CW_DETECT_CFG, 1,
+ NAND_ERASED_CW_SET | NAND_BAM_NEXT_SGL);
+
+ for (i = 0; i < num_cw; i++) {
+ int data_size, oob_size;
+
+ if (i == (num_cw - 1)) {
+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
+ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
+ ecc_cfg->spare_bytes;
+ } else {
+ data_size = ecc_cfg->cw_data;
+ oob_size = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
+ }
+
+ qcom_spi_set_read_loc(snandc, i, 0, data_size, oob_size, 1);
+
+ qcom_spi_config_cw_read(snandc, true, i);
+
+ if (oob_buf) {
+ int j;
+
+ for (j = 0; j < ecc_cfg->bbm_size; j++)
+ *oob_buf++ = 0xff;
+
+ qcom_read_data_dma(snandc, FLASH_BUF_ACC + data_size,
+ oob_buf, oob_size, 0);
+ }
+
+ if (oob_buf)
+ oob_buf += oob_size;
+ }
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failure to read oob\n");
+ return ret;
+ }
+
+ return qcom_spi_check_error(snandc);
+}
+
+static int qcom_spi_read_page(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
+ return qcom_spi_read_page_raw(snandc, op);
+
+ if (snandc->qspi->page_rw)
+ return qcom_spi_read_page_ecc(snandc, op);
+
+ if (snandc->qspi->oob_rw && snandc->qspi->raw_rw)
+ return qcom_spi_read_last_cw(snandc, op);
+
+ if (snandc->qspi->oob_rw)
+ return qcom_spi_read_page_oob(snandc, op);
+
+ return 0;
+}
+
+static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc)
+{
+ qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG,
+ 1, NAND_BAM_NEXT_SGL);
+}
+
+static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc)
+{
+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 1, NAND_BAM_NEXT_SGL);
+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+ qcom_read_reg_dma(snandc, NAND_FLASH_STATUS, 1, NAND_BAM_NEXT_SGL);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->clrflashstatus, NAND_FLASH_STATUS, 1, 0);
+ qcom_write_reg_dma(snandc, &snandc->regs->clrreadstatus, NAND_READ_STATUS, 1,
+ NAND_BAM_NEXT_SGL);
+}
+
+static int qcom_spi_program_raw(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ struct mtd_info *mtd = snandc->qspi->mtd;
+ u8 *data_buf = NULL, *oob_buf = NULL;
+ int i, ret;
+ int num_cw = snandc->qspi->num_cw;
+ u32 cfg0, cfg1, ecc_bch_cfg;
+
+ cfg0 = (ecc_cfg->cfg0_raw & ~CW_PER_PAGE_MASK) |
+ FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
+ cfg1 = ecc_cfg->cfg1_raw;
+ ecc_bch_cfg = ECC_CFG_ECC_DISABLE;
+
+ data_buf = snandc->qspi->data_buf;
+
+ oob_buf = snandc->qspi->oob_buf;
+ memset(oob_buf, 0xff, OOB_BUF_SIZE);
+
+ snandc->buf_count = 0;
+ snandc->buf_start = 0;
+ qcom_clear_read_regs(snandc);
+ qcom_clear_bam_transaction(snandc);
+
+ snandc->regs->addr0 = snandc->qspi->addr1;
+ snandc->regs->addr1 = snandc->qspi->addr2;
+ snandc->regs->cmd = snandc->qspi->cmd;
+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
+ snandc->regs->exec = cpu_to_le32(1);
+
+ qcom_spi_config_page_write(snandc);
+
+ for (i = 0; i < num_cw; i++) {
+ int data_size1, data_size2, oob_size1, oob_size2;
+ int reg_off = FLASH_BUF_ACC;
+
+ data_size1 = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
+ oob_size1 = ecc_cfg->bbm_size;
+
+ if (i == (num_cw - 1)) {
+ data_size2 = NANDC_STEP_SIZE - data_size1 -
+ ((num_cw - 1) << 2);
+ oob_size2 = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
+ ecc_cfg->spare_bytes;
+ } else {
+ data_size2 = ecc_cfg->cw_data - data_size1;
+ oob_size2 = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes;
+ }
+
+ qcom_write_data_dma(snandc, reg_off, data_buf, data_size1,
+ NAND_BAM_NO_EOT);
+ reg_off += data_size1;
+ data_buf += data_size1;
+
+ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size1,
+ NAND_BAM_NO_EOT);
+ oob_buf += oob_size1;
+ reg_off += oob_size1;
+
+ qcom_write_data_dma(snandc, reg_off, data_buf, data_size2,
+ NAND_BAM_NO_EOT);
+ reg_off += data_size2;
+ data_buf += data_size2;
+
+ qcom_write_data_dma(snandc, reg_off, oob_buf, oob_size2, 0);
+ oob_buf += oob_size2;
+
+ qcom_spi_config_cw_write(snandc);
+ }
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failure to write raw page\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qcom_spi_program_ecc(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ u8 *data_buf = NULL, *oob_buf = NULL;
+ int i, ret;
+ int num_cw = snandc->qspi->num_cw;
+ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
+
+ cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) |
+ FIELD_PREP(CW_PER_PAGE_MASK, num_cw - 1);
+ cfg1 = ecc_cfg->cfg1;
+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
+ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
+
+ if (snandc->qspi->data_buf)
+ data_buf = snandc->qspi->data_buf;
+
+ oob_buf = snandc->qspi->oob_buf;
+
+ snandc->buf_count = 0;
+ snandc->buf_start = 0;
+ qcom_clear_read_regs(snandc);
+ qcom_clear_bam_transaction(snandc);
+
+ snandc->regs->addr0 = snandc->qspi->addr1;
+ snandc->regs->addr1 = snandc->qspi->addr2;
+ snandc->regs->cmd = snandc->qspi->cmd;
+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
+ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
+ snandc->regs->exec = cpu_to_le32(1);
+
+ qcom_spi_config_page_write(snandc);
+
+ for (i = 0; i < num_cw; i++) {
+ int data_size, oob_size;
+
+ if (i == (num_cw - 1)) {
+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
+ oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
+ ecc_cfg->spare_bytes;
+ } else {
+ data_size = ecc_cfg->cw_data;
+ oob_size = ecc_cfg->bytes;
+ }
+
+ if (data_buf)
+ qcom_write_data_dma(snandc, FLASH_BUF_ACC, data_buf, data_size,
+ i == (num_cw - 1) ? NAND_BAM_NO_EOT : 0);
+
+ if (i == (num_cw - 1)) {
+ if (oob_buf) {
+ oob_buf += ecc_cfg->bbm_size;
+ qcom_write_data_dma(snandc, FLASH_BUF_ACC + data_size,
+ oob_buf, oob_size, 0);
+ }
+ }
+
+ qcom_spi_config_cw_write(snandc);
+
+ if (data_buf)
+ data_buf += data_size;
+ if (oob_buf)
+ oob_buf += oob_size;
+ }
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failure to write page\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qcom_spi_program_oob(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ struct qpic_ecc *ecc_cfg = snandc->qspi->ecc;
+ u8 *oob_buf = NULL;
+ int ret, col, data_size, oob_size;
+ int num_cw = snandc->qspi->num_cw;
+ u32 cfg0, cfg1, ecc_bch_cfg, ecc_buf_cfg;
+
+ cfg0 = (ecc_cfg->cfg0 & ~CW_PER_PAGE_MASK) |
+ FIELD_PREP(CW_PER_PAGE_MASK, 0);
+ cfg1 = ecc_cfg->cfg1;
+ ecc_bch_cfg = ecc_cfg->ecc_bch_cfg;
+ ecc_buf_cfg = ecc_cfg->ecc_buf_cfg;
+
+ col = ecc_cfg->cw_size * (num_cw - 1);
+
+ oob_buf = snandc->qspi->data_buf;
+
+ snandc->buf_count = 0;
+ snandc->buf_start = 0;
+ qcom_clear_read_regs(snandc);
+ qcom_clear_bam_transaction(snandc);
+ snandc->regs->addr0 = (snandc->qspi->addr1 | cpu_to_le32(col));
+ snandc->regs->addr1 = snandc->qspi->addr2;
+ snandc->regs->cmd = snandc->qspi->cmd;
+ snandc->regs->cfg0 = cpu_to_le32(cfg0);
+ snandc->regs->cfg1 = cpu_to_le32(cfg1);
+ snandc->regs->ecc_bch_cfg = cpu_to_le32(ecc_bch_cfg);
+ snandc->regs->ecc_buf_cfg = cpu_to_le32(ecc_buf_cfg);
+ snandc->regs->exec = cpu_to_le32(1);
+
+ /* calculate the data and oob size for the last codeword/step */
+ data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
+ oob_size = snandc->qspi->mtd->oobavail;
+
+ memset(snandc->data_buffer, 0xff, ecc_cfg->cw_data);
+ /* override new oob content to last codeword */
+ mtd_ooblayout_get_databytes(snandc->qspi->mtd, snandc->data_buffer + data_size,
+ oob_buf, 0, snandc->qspi->mtd->oobavail);
+ qcom_spi_config_page_write(snandc);
+ qcom_write_data_dma(snandc, FLASH_BUF_ACC, snandc->data_buffer, data_size + oob_size, 0);
+ qcom_spi_config_cw_write(snandc);
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failure to write oob\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qcom_spi_program_execute(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ if (snandc->qspi->page_rw && snandc->qspi->raw_rw)
+ return qcom_spi_program_raw(snandc, op);
+
+ if (snandc->qspi->page_rw)
+ return qcom_spi_program_ecc(snandc, op);
+
+ if (snandc->qspi->oob_rw)
+ return qcom_spi_program_oob(snandc, op);
+
+ return 0;
+}
+
+static int qcom_spi_cmd_mapping(struct qcom_nand_controller *snandc, u32 opcode, u32 *cmd)
+{
+ switch (opcode) {
+ case SPINAND_RESET:
+ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_RESET_DEVICE);
+ break;
+ case SPINAND_READID:
+ *cmd = (SPI_WP | SPI_HOLD | SPI_TRANSFER_MODE_x1 | OP_FETCH_ID);
+ break;
+ case SPINAND_GET_FEATURE:
+ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE);
+ break;
+ case SPINAND_SET_FEATURE:
+ *cmd = (SPI_TRANSFER_MODE_x1 | SPI_WP | SPI_HOLD | ACC_FEATURE |
+ QPIC_SET_FEATURE);
+ break;
+ case SPINAND_READ:
+ if (snandc->qspi->raw_rw) {
+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
+ SPI_WP | SPI_HOLD | OP_PAGE_READ);
+ } else {
+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
+ SPI_WP | SPI_HOLD | OP_PAGE_READ_WITH_ECC);
+ }
+
+ break;
+ case SPINAND_ERASE:
+ *cmd = OP_BLOCK_ERASE | PAGE_ACC | LAST_PAGE | SPI_WP |
+ SPI_HOLD | SPI_TRANSFER_MODE_x1;
+ break;
+ case SPINAND_WRITE_EN:
+ *cmd = SPINAND_WRITE_EN;
+ break;
+ case SPINAND_PROGRAM_EXECUTE:
+ *cmd = (PAGE_ACC | LAST_PAGE | SPI_TRANSFER_MODE_x1 |
+ SPI_WP | SPI_HOLD | OP_PROGRAM_PAGE);
+ break;
+ case SPINAND_PROGRAM_LOAD:
+ *cmd = SPINAND_PROGRAM_LOAD;
+ break;
+ default:
+ dev_err(snandc->dev, "Opcode not supported: %u\n", opcode);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int qcom_spi_write_page(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ int ret;
+ u32 cmd;
+
+ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
+ if (ret < 0)
+ return ret;
+
+ if (op->cmd.opcode == SPINAND_PROGRAM_LOAD)
+ snandc->qspi->data_buf = (u8 *)op->data.buf.out;
+
+ return 0;
+}
+
+static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
+ const struct spi_mem_op *op)
+{
+ u32 cmd;
+ int ret, opcode;
+
+ ret = qcom_spi_cmd_mapping(snandc, op->cmd.opcode, &cmd);
+ if (ret < 0)
+ return ret;
+
+ opcode = op->cmd.opcode;
+
+ switch (opcode) {
+ case SPINAND_WRITE_EN:
+ return 0;
+ case SPINAND_PROGRAM_EXECUTE:
+ snandc->qspi->addr1 = cpu_to_le32(op->addr.val << 16);
+ snandc->qspi->addr2 = cpu_to_le32(op->addr.val >> 16 & 0xff);
+ snandc->qspi->cmd = cpu_to_le32(cmd);
+ return qcom_spi_program_execute(snandc, op);
+ case SPINAND_READ:
+ snandc->qspi->addr1 = cpu_to_le32(op->addr.val << 16);
+ snandc->qspi->addr2 = cpu_to_le32(op->addr.val >> 16 & 0xff);
+ snandc->qspi->cmd = cpu_to_le32(cmd);
+ return 0;
+ case SPINAND_ERASE:
+ snandc->qspi->addr1 = cpu_to_le32(op->addr.val << 16);
+ snandc->qspi->addr2 = cpu_to_le32(op->addr.val >> 16 & 0xffff);
+ snandc->qspi->cmd = cpu_to_le32(cmd);
+ return qcom_spi_block_erase(snandc);
+ default:
+ break;
+ }
+
+ snandc->buf_count = 0;
+ snandc->buf_start = 0;
+ qcom_clear_read_regs(snandc);
+ qcom_clear_bam_transaction(snandc);
+
+ snandc->regs->cmd = cpu_to_le32(cmd);
+ snandc->regs->exec = cpu_to_le32(1);
+ snandc->regs->addr0 = cpu_to_le32(op->addr.val);
+ snandc->regs->addr1 = cpu_to_le32(0);
+
+ qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
+ qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);
+
+ ret = qcom_submit_descs(snandc);
+ if (ret)
+ dev_err(snandc->dev, "failure in submitting cmd descriptor\n");
+
+ return ret;
+}
+
+static int qcom_spi_io_op(struct qcom_nand_controller *snandc, const struct spi_mem_op *op)
+{
+ int ret, val, opcode;
+ bool copy = false, copy_ftr = false;
+
+ ret = qcom_spi_send_cmdaddr(snandc, op);
+ if (ret)
+ return ret;
+
+ snandc->buf_count = 0;
+ snandc->buf_start = 0;
+ qcom_clear_read_regs(snandc);
+ qcom_clear_bam_transaction(snandc);
+ opcode = op->cmd.opcode;
+
+ switch (opcode) {
+ case SPINAND_READID:
+ snandc->buf_count = 4;
+ qcom_read_reg_dma(snandc, NAND_READ_ID, 1, NAND_BAM_NEXT_SGL);
+ copy = true;
+ break;
+ case SPINAND_GET_FEATURE:
+ snandc->buf_count = 4;
+ qcom_read_reg_dma(snandc, NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
+ copy_ftr = true;
+ break;
+ case SPINAND_SET_FEATURE:
+ snandc->regs->flash_feature = cpu_to_le32(*(u32 *)op->data.buf.out);
+ qcom_write_reg_dma(snandc, &snandc->regs->flash_feature,
+ NAND_FLASH_FEATURES, 1, NAND_BAM_NEXT_SGL);
+ break;
+ case SPINAND_PROGRAM_EXECUTE:
+ case SPINAND_WRITE_EN:
+ case SPINAND_RESET:
+ case SPINAND_ERASE:
+ case SPINAND_READ:
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ ret = qcom_submit_descs(snandc);
+ if (ret) {
+ dev_err(snandc->dev, "failure in submitting descriptor for:%d\n", opcode);
+ return ret;
+ }
+
+ if (copy) {
+ qcom_nandc_dev_to_mem(snandc, true);
+ memcpy(op->data.buf.in, snandc->reg_read_buf, snandc->buf_count);
+ }
+
+ if (copy_ftr) {
+ qcom_nandc_dev_to_mem(snandc, true);
+ val = le32_to_cpu(*(__le32 *)snandc->reg_read_buf);
+ val >>= 8;
+ memcpy(op->data.buf.in, &val, snandc->buf_count);
+ }
+
+ return 0;
+}
+
+static bool qcom_spi_is_page_op(const struct spi_mem_op *op)
+{
+ if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && op->addr.buswidth != 4)
+ return false;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ if (op->addr.buswidth == 4 && op->data.buswidth == 4)
+ return true;
+
+ if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
+ return true;
+
+ } else if (op->data.dir == SPI_MEM_DATA_OUT) {
+ if (op->data.buswidth == 4)
+ return true;
+ if (op->addr.nbytes == 2 && op->addr.buswidth == 1)
+ return true;
+ }
+
+ return false;
+}
+
+static bool qcom_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ if (!spi_mem_default_supports_op(mem, op))
+ return false;
+
+ if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1)
+ return false;
+
+ if (qcom_spi_is_page_op(op))
+ return true;
+
+ return ((!op->addr.nbytes || op->addr.buswidth == 1) &&
+ (!op->dummy.nbytes || op->dummy.buswidth == 1) &&
+ (!op->data.nbytes || op->data.buswidth == 1));
+}
+
+static int qcom_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ struct qcom_nand_controller *snandc = spi_controller_get_devdata(mem->spi->controller);
+
+ dev_dbg(snandc->dev, "OP %02x ADDR %08llX@%d:%u DATA %d:%u", op->cmd.opcode,
+ op->addr.val, op->addr.buswidth, op->addr.nbytes,
+ op->data.buswidth, op->data.nbytes);
+
+ if (qcom_spi_is_page_op(op)) {
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ return qcom_spi_read_page(snandc, op);
+ if (op->data.dir == SPI_MEM_DATA_OUT)
+ return qcom_spi_write_page(snandc, op);
+ } else {
+ return qcom_spi_io_op(snandc, op);
+ }
+
+ return 0;
+}
+
+static const struct spi_controller_mem_ops qcom_spi_mem_ops = {
+ .supports_op = qcom_spi_supports_op,
+ .exec_op = qcom_spi_exec_op,
+};
+
+static const struct spi_controller_mem_caps qcom_spi_mem_caps = {
+ .ecc = true,
+};
+
+static int qcom_spi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_controller *ctlr;
+ struct qcom_nand_controller *snandc;
+ struct qpic_spi_nand *qspi;
+ struct qpic_ecc *ecc;
+ struct resource *res;
+ const void *dev_data;
+ int ret;
+
+ ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
+ if (!ecc)
+ return -ENOMEM;
+
+ qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
+ if (!qspi)
+ return -ENOMEM;
+
+ ctlr = __devm_spi_alloc_controller(dev, sizeof(*snandc), false);
+ if (!ctlr)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ctlr);
+
+ snandc = spi_controller_get_devdata(ctlr);
+ qspi->snandc = snandc;
+
+ snandc->dev = dev;
+ snandc->qspi = qspi;
+ snandc->qspi->ctlr = ctlr;
+ snandc->qspi->ecc = ecc;
+
+ dev_data = of_device_get_match_data(dev);
+ if (!dev_data) {
+ dev_err(&pdev->dev, "failed to get device data\n");
+ return -ENODEV;
+ }
+
+ snandc->props = dev_data;
+
+ snandc->core_clk = devm_clk_get_enabled(dev, "core");
+ if (IS_ERR(snandc->core_clk))
+ return PTR_ERR(snandc->core_clk);
+
+ snandc->aon_clk = devm_clk_get_enabled(dev, "aon");
+ if (IS_ERR(snandc->aon_clk))
+ return PTR_ERR(snandc->aon_clk);
+
+ snandc->qspi->iomacro_clk = devm_clk_get_enabled(dev, "iom");
+ if (IS_ERR(snandc->qspi->iomacro_clk))
+ return PTR_ERR(snandc->qspi->iomacro_clk);
+
+ snandc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(snandc->base))
+ return PTR_ERR(snandc->base);
+
+ snandc->base_phys = res->start;
+ snandc->base_dma = dma_map_resource(dev, res->start, resource_size(res),
+ DMA_BIDIRECTIONAL, 0);
+ if (dma_mapping_error(dev, snandc->base_dma))
+ return -ENXIO;
+
+ ret = qcom_nandc_alloc(snandc);
+ if (ret)
+ goto err_snand_alloc;
+
+ ret = qcom_spi_init(snandc);
+ if (ret)
+ goto err_spi_init;
+
+ /* setup ECC engine */
+ snandc->qspi->ecc_eng.dev = &pdev->dev;
+ snandc->qspi->ecc_eng.integration = NAND_ECC_ENGINE_INTEGRATION_PIPELINED;
+ snandc->qspi->ecc_eng.ops = &qcom_spi_ecc_engine_ops_pipelined;
+ snandc->qspi->ecc_eng.priv = snandc;
+
+ ret = nand_ecc_register_on_host_hw_engine(&snandc->qspi->ecc_eng);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register ecc engine:%d\n", ret);
+ goto err_spi_init;
+ }
+
+ ctlr->num_chipselect = QPIC_QSPI_NUM_CS;
+ ctlr->mem_ops = &qcom_spi_mem_ops;
+ ctlr->mem_caps = &qcom_spi_mem_caps;
+ ctlr->dev.of_node = pdev->dev.of_node;
+ ctlr->mode_bits = SPI_TX_DUAL | SPI_RX_DUAL |
+ SPI_TX_QUAD | SPI_RX_QUAD;
+
+ ret = spi_register_controller(ctlr);
+ if (ret) {
+ dev_err(&pdev->dev, "spi_register_controller failed.\n");
+ goto err_register_controller;
+ }
+
+ return 0;
+
+err_register_controller:
+ nand_ecc_unregister_on_host_hw_engine(&snandc->qspi->ecc_eng);
+err_spi_init:
+ qcom_nandc_unalloc(snandc);
+err_snand_alloc:
+ dma_unmap_resource(dev, res->start, resource_size(res),
+ DMA_BIDIRECTIONAL, 0);
+ return ret;
+}
+
+static void qcom_spi_remove(struct platform_device *pdev)
+{
+ struct spi_controller *ctlr = platform_get_drvdata(pdev);
+ struct qcom_nand_controller *snandc = spi_controller_get_devdata(ctlr);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ spi_unregister_controller(ctlr);
+ nand_ecc_unregister_on_host_hw_engine(&snandc->qspi->ecc_eng);
+ qcom_nandc_unalloc(snandc);
+ dma_unmap_resource(&pdev->dev, snandc->base_dma, resource_size(res),
+ DMA_BIDIRECTIONAL, 0);
+}
+
+static const struct qcom_nandc_props ipq9574_snandc_props = {
+ .dev_cmd_reg_start = 0x7000,
+ .bam_offset = 0x30000,
+ .supports_bam = true,
+};
+
+static const struct of_device_id qcom_snandc_of_match[] = {
+ {
+ .compatible = "qcom,ipq9574-snand",
+ .data = &ipq9574_snandc_props,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, qcom_snandc_of_match);
+
+static struct platform_driver qcom_spi_driver = {
+ .driver = {
+ .name = "qcom_snand",
+ .of_match_table = qcom_snandc_of_match,
+ },
+ .probe = qcom_spi_probe,
+ .remove = qcom_spi_remove,
+};
+module_platform_driver(qcom_spi_driver);
+
+MODULE_DESCRIPTION("SPI driver for QPIC QSPI cores");
+MODULE_AUTHOR("Md Sadre Alam <quic_mdalam@quicinc.com>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 00e5e88e72c4..7d647edf6bc3 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -5,18 +5,20 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
+#include <linux/interconnect.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
+#include "internals.h"
#define QUP_CONFIG 0x0000
#define QUP_STATE 0x0004
@@ -122,11 +124,14 @@
#define SPI_DELAY_THRESHOLD 1
#define SPI_DELAY_RETRY 10
+#define SPI_BUS_WIDTH 8
+
struct spi_qup {
void __iomem *base;
struct device *dev;
struct clk *cclk; /* core clock */
struct clk *iclk; /* interface clock */
+ struct icc_path *icc_path; /* interconnect to RAM */
int irq;
spinlock_t lock;
@@ -149,6 +154,8 @@ struct spi_qup {
int mode;
struct dma_slave_config rx_conf;
struct dma_slave_config tx_conf;
+
+ u32 bw_speed_hz;
};
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer);
@@ -181,6 +188,23 @@ static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
return opstate & QUP_STATE_VALID;
}
+static int spi_qup_vote_bw(struct spi_qup *controller, u32 speed_hz)
+{
+ u32 needed_peak_bw;
+ int ret;
+
+ if (controller->bw_speed_hz == speed_hz)
+ return 0;
+
+ needed_peak_bw = Bps_to_icc(speed_hz * SPI_BUS_WIDTH);
+ ret = icc_set_bw(controller->icc_path, 0, needed_peak_bw);
+ if (ret)
+ return ret;
+
+ controller->bw_speed_hz = speed_hz;
+ return 0;
+}
+
static int spi_qup_set_state(struct spi_qup *controller, u32 state)
{
unsigned long loop;
@@ -386,20 +410,20 @@ static void spi_qup_write(struct spi_qup *controller)
} while (remainder);
}
-static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
+static int spi_qup_prep_sg(struct spi_controller *host, struct scatterlist *sgl,
unsigned int nents, enum dma_transfer_direction dir,
dma_async_tx_callback callback)
{
- struct spi_qup *qup = spi_master_get_devdata(master);
+ struct spi_qup *qup = spi_controller_get_devdata(host);
unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan;
dma_cookie_t cookie;
if (dir == DMA_MEM_TO_DEV)
- chan = master->dma_tx;
+ chan = host->dma_tx;
else
- chan = master->dma_rx;
+ chan = host->dma_rx;
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
if (IS_ERR_OR_NULL(desc))
@@ -413,13 +437,13 @@ static int spi_qup_prep_sg(struct spi_master *master, struct scatterlist *sgl,
return dma_submit_error(cookie);
}
-static void spi_qup_dma_terminate(struct spi_master *master,
+static void spi_qup_dma_terminate(struct spi_controller *host,
struct spi_transfer *xfer)
{
if (xfer->tx_buf)
- dmaengine_terminate_all(master->dma_tx);
+ dmaengine_terminate_all(host->dma_tx);
if (xfer->rx_buf)
- dmaengine_terminate_all(master->dma_rx);
+ dmaengine_terminate_all(host->dma_rx);
}
static u32 spi_qup_sgl_get_nents_len(struct scatterlist *sgl, u32 max,
@@ -446,11 +470,17 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
- struct spi_master *master = spi->master;
- struct spi_qup *qup = spi_master_get_devdata(master);
+ struct spi_controller *host = spi->controller;
+ struct spi_qup *qup = spi_controller_get_devdata(host);
struct scatterlist *tx_sgl, *rx_sgl;
int ret;
+ ret = spi_qup_vote_bw(qup, xfer->speed_hz);
+ if (ret) {
+ dev_err(qup->dev, "fail to vote for ICC bandwidth: %d\n", ret);
+ return -EIO;
+ }
+
if (xfer->rx_buf)
rx_done = spi_qup_dma_done;
else if (xfer->tx_buf)
@@ -482,20 +512,20 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
return ret;
}
if (rx_sgl) {
- ret = spi_qup_prep_sg(master, rx_sgl, rx_nents,
+ ret = spi_qup_prep_sg(host, rx_sgl, rx_nents,
DMA_DEV_TO_MEM, rx_done);
if (ret)
return ret;
- dma_async_issue_pending(master->dma_rx);
+ dma_async_issue_pending(host->dma_rx);
}
if (tx_sgl) {
- ret = spi_qup_prep_sg(master, tx_sgl, tx_nents,
+ ret = spi_qup_prep_sg(host, tx_sgl, tx_nents,
DMA_MEM_TO_DEV, tx_done);
if (ret)
return ret;
- dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(host->dma_tx);
}
if (!wait_for_completion_timeout(&qup->done, timeout))
@@ -514,8 +544,8 @@ static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
- struct spi_master *master = spi->master;
- struct spi_qup *qup = spi_master_get_devdata(master);
+ struct spi_controller *host = spi->controller;
+ struct spi_qup *qup = spi_controller_get_devdata(host);
int ret, n_words, iterations, offset = 0;
n_words = qup->n_words;
@@ -659,7 +689,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
/* set clock freq ... bits per word, determine mode */
static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct spi_qup *controller = spi_master_get_devdata(spi->master);
+ struct spi_qup *controller = spi_controller_get_devdata(spi->controller);
int ret;
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
@@ -668,7 +698,7 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
return -EIO;
}
- ret = clk_set_rate(controller->cclk, xfer->speed_hz);
+ ret = dev_pm_opp_set_rate(controller->dev, xfer->speed_hz);
if (ret) {
dev_err(controller->dev, "fail to set frequency %d",
xfer->speed_hz);
@@ -680,9 +710,7 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
if (controller->n_words <= (controller->in_fifo_sz / sizeof(u32)))
controller->mode = QUP_IO_M_MODE_FIFO;
- else if (spi->master->can_dma &&
- spi->master->can_dma(spi->master, spi, xfer) &&
- spi->master->cur_msg_mapped)
+ else if (spi_xfer_is_dma_mapped(spi->controller, spi, xfer))
controller->mode = QUP_IO_M_MODE_BAM;
else
controller->mode = QUP_IO_M_MODE_BLOCK;
@@ -693,7 +721,7 @@ static int spi_qup_io_prep(struct spi_device *spi, struct spi_transfer *xfer)
/* prep qup for another spi transaction of specific type */
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct spi_qup *controller = spi_master_get_devdata(spi->master);
+ struct spi_qup *controller = spi_controller_get_devdata(spi->controller);
u32 config, iomode, control;
unsigned long flags;
@@ -841,11 +869,11 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
return 0;
}
-static int spi_qup_transfer_one(struct spi_master *master,
+static int spi_qup_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
unsigned long timeout, flags;
int ret;
@@ -879,21 +907,21 @@ static int spi_qup_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&controller->lock, flags);
if (ret && spi_qup_is_dma_xfer(controller->mode))
- spi_qup_dma_terminate(master, xfer);
+ spi_qup_dma_terminate(host, xfer);
return ret;
}
-static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
+static bool spi_qup_can_dma(struct spi_controller *host, struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct spi_qup *qup = spi_master_get_devdata(master);
+ struct spi_qup *qup = spi_controller_get_devdata(host);
size_t dma_align = dma_get_cache_alignment();
int n_words;
if (xfer->rx_buf) {
if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
- IS_ERR_OR_NULL(master->dma_rx))
+ IS_ERR_OR_NULL(host->dma_rx))
return false;
if (qup->qup_v1 && (xfer->len % qup->in_blk_sz))
return false;
@@ -901,7 +929,7 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
if (xfer->tx_buf) {
if (!IS_ALIGNED((size_t)xfer->tx_buf, dma_align) ||
- IS_ERR_OR_NULL(master->dma_tx))
+ IS_ERR_OR_NULL(host->dma_tx))
return false;
if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
return false;
@@ -914,30 +942,30 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
return true;
}
-static void spi_qup_release_dma(struct spi_master *master)
+static void spi_qup_release_dma(struct spi_controller *host)
{
- if (!IS_ERR_OR_NULL(master->dma_rx))
- dma_release_channel(master->dma_rx);
- if (!IS_ERR_OR_NULL(master->dma_tx))
- dma_release_channel(master->dma_tx);
+ if (!IS_ERR_OR_NULL(host->dma_rx))
+ dma_release_channel(host->dma_rx);
+ if (!IS_ERR_OR_NULL(host->dma_tx))
+ dma_release_channel(host->dma_tx);
}
-static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
+static int spi_qup_init_dma(struct spi_controller *host, resource_size_t base)
{
- struct spi_qup *spi = spi_master_get_devdata(master);
+ struct spi_qup *spi = spi_controller_get_devdata(host);
struct dma_slave_config *rx_conf = &spi->rx_conf,
*tx_conf = &spi->tx_conf;
struct device *dev = spi->dev;
int ret;
/* allocate dma resources, if available */
- master->dma_rx = dma_request_chan(dev, "rx");
- if (IS_ERR(master->dma_rx))
- return PTR_ERR(master->dma_rx);
+ host->dma_rx = dma_request_chan(dev, "rx");
+ if (IS_ERR(host->dma_rx))
+ return PTR_ERR(host->dma_rx);
- master->dma_tx = dma_request_chan(dev, "tx");
- if (IS_ERR(master->dma_tx)) {
- ret = PTR_ERR(master->dma_tx);
+ host->dma_tx = dma_request_chan(dev, "tx");
+ if (IS_ERR(host->dma_tx)) {
+ ret = PTR_ERR(host->dma_tx);
goto err_tx;
}
@@ -952,13 +980,13 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
tx_conf->dst_addr = base + QUP_OUTPUT_FIFO;
tx_conf->dst_maxburst = spi->out_blk_sz;
- ret = dmaengine_slave_config(master->dma_rx, rx_conf);
+ ret = dmaengine_slave_config(host->dma_rx, rx_conf);
if (ret) {
dev_err(dev, "failed to configure RX channel\n");
goto err;
}
- ret = dmaengine_slave_config(master->dma_tx, tx_conf);
+ ret = dmaengine_slave_config(host->dma_tx, tx_conf);
if (ret) {
dev_err(dev, "failed to configure TX channel\n");
goto err;
@@ -967,9 +995,9 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
return 0;
err:
- dma_release_channel(master->dma_tx);
+ dma_release_channel(host->dma_tx);
err_tx:
- dma_release_channel(master->dma_rx);
+ dma_release_channel(host->dma_rx);
return ret;
}
@@ -979,7 +1007,7 @@ static void spi_qup_set_cs(struct spi_device *spi, bool val)
u32 spi_ioc;
u32 spi_ioc_orig;
- controller = spi_master_get_devdata(spi->master);
+ controller = spi_controller_get_devdata(spi->controller);
spi_ioc = readl_relaxed(controller->base + SPI_IO_CONTROL);
spi_ioc_orig = spi_ioc;
if (!val)
@@ -993,7 +1021,8 @@ static void spi_qup_set_cs(struct spi_device *spi, bool val)
static int spi_qup_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
+ struct icc_path *icc_path;
struct clk *iclk, *cclk;
struct spi_qup *controller;
struct resource *res;
@@ -1019,6 +1048,11 @@ static int spi_qup_probe(struct platform_device *pdev)
if (IS_ERR(iclk))
return PTR_ERR(iclk);
+ icc_path = devm_of_icc_get(dev, NULL);
+ if (IS_ERR(icc_path))
+ return dev_err_probe(dev, PTR_ERR(icc_path),
+ "failed to get interconnect path\n");
+
/* This is optional parameter */
if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
max_freq = SPI_MAX_RATE;
@@ -1028,51 +1062,61 @@ static int spi_qup_probe(struct platform_device *pdev)
return -ENXIO;
}
- master = spi_alloc_master(dev, sizeof(struct spi_qup));
- if (!master) {
- dev_err(dev, "cannot allocate master\n");
+ ret = devm_pm_opp_set_clkname(dev, "core");
+ if (ret)
+ return ret;
+
+ /* OPP table is optional */
+ ret = devm_pm_opp_of_add_table(dev);
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "invalid OPP table\n");
+
+ host = spi_alloc_host(dev, sizeof(struct spi_qup));
+ if (!host) {
+ dev_err(dev, "cannot allocate host\n");
return -ENOMEM;
}
/* use num-cs unless not present or out of range */
if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) ||
num_cs > SPI_NUM_CHIPSELECTS)
- master->num_chipselect = SPI_NUM_CHIPSELECTS;
+ host->num_chipselect = SPI_NUM_CHIPSELECTS;
else
- master->num_chipselect = num_cs;
+ host->num_chipselect = num_cs;
- master->use_gpio_descriptors = true;
- master->max_native_cs = SPI_NUM_CHIPSELECTS;
- master->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
- master->max_speed_hz = max_freq;
- master->transfer_one = spi_qup_transfer_one;
- master->dev.of_node = pdev->dev.of_node;
- master->auto_runtime_pm = true;
- master->dma_alignment = dma_get_cache_alignment();
- master->max_dma_len = SPI_MAX_XFER;
+ host->use_gpio_descriptors = true;
+ host->max_native_cs = SPI_NUM_CHIPSELECTS;
+ host->bus_num = pdev->id;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ host->max_speed_hz = max_freq;
+ host->transfer_one = spi_qup_transfer_one;
+ host->dev.of_node = pdev->dev.of_node;
+ host->auto_runtime_pm = true;
+ host->dma_alignment = dma_get_cache_alignment();
+ host->max_dma_len = SPI_MAX_XFER;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- controller = spi_master_get_devdata(master);
+ controller = spi_controller_get_devdata(host);
controller->dev = dev;
controller->base = base;
controller->iclk = iclk;
controller->cclk = cclk;
+ controller->icc_path = icc_path;
controller->irq = irq;
- ret = spi_qup_init_dma(master, res->start);
+ ret = spi_qup_init_dma(host, res->start);
if (ret == -EPROBE_DEFER)
goto error;
else if (!ret)
- master->can_dma = spi_qup_can_dma;
+ host->can_dma = spi_qup_can_dma;
controller->qup_v1 = (uintptr_t)of_device_get_match_data(dev);
if (!controller->qup_v1)
- master->set_cs = spi_qup_set_cs;
+ host->set_cs = spi_qup_set_cs;
spin_lock_init(&controller->lock);
init_completion(&controller->done);
@@ -1150,7 +1194,7 @@ static int spi_qup_probe(struct platform_device *pdev)
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
- ret = devm_spi_register_master(dev, master);
+ ret = devm_spi_register_controller(dev, host);
if (ret)
goto disable_pm;
@@ -1162,17 +1206,17 @@ error_clk:
clk_disable_unprepare(cclk);
clk_disable_unprepare(iclk);
error_dma:
- spi_qup_release_dma(master);
+ spi_qup_release_dma(host);
error:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
#ifdef CONFIG_PM
static int spi_qup_pm_suspend_runtime(struct device *device)
{
- struct spi_master *master = dev_get_drvdata(device);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
u32 config;
/* Enable clocks auto gaiting */
@@ -1181,6 +1225,7 @@ static int spi_qup_pm_suspend_runtime(struct device *device)
writel_relaxed(config, controller->base + QUP_CONFIG);
clk_disable_unprepare(controller->cclk);
+ spi_qup_vote_bw(controller, 0);
clk_disable_unprepare(controller->iclk);
return 0;
@@ -1188,8 +1233,8 @@ static int spi_qup_pm_suspend_runtime(struct device *device)
static int spi_qup_pm_resume_runtime(struct device *device)
{
- struct spi_master *master = dev_get_drvdata(device);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
u32 config;
int ret;
@@ -1214,8 +1259,8 @@ static int spi_qup_pm_resume_runtime(struct device *device)
#ifdef CONFIG_PM_SLEEP
static int spi_qup_suspend(struct device *device)
{
- struct spi_master *master = dev_get_drvdata(device);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
int ret;
if (pm_runtime_suspended(device)) {
@@ -1223,7 +1268,7 @@ static int spi_qup_suspend(struct device *device)
if (ret)
return ret;
}
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -1232,14 +1277,15 @@ static int spi_qup_suspend(struct device *device)
return ret;
clk_disable_unprepare(controller->cclk);
+ spi_qup_vote_bw(controller, 0);
clk_disable_unprepare(controller->iclk);
return 0;
}
static int spi_qup_resume(struct device *device)
{
- struct spi_master *master = dev_get_drvdata(device);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(device);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(controller->iclk);
@@ -1256,7 +1302,7 @@ static int spi_qup_resume(struct device *device)
if (ret)
goto disable_clk;
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret)
goto disable_clk;
@@ -1271,8 +1317,8 @@ disable_clk:
static void spi_qup_remove(struct platform_device *pdev)
{
- struct spi_master *master = dev_get_drvdata(&pdev->dev);
- struct spi_qup *controller = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(&pdev->dev);
+ struct spi_qup *controller = spi_controller_get_devdata(host);
int ret;
ret = pm_runtime_get_sync(&pdev->dev);
@@ -1290,7 +1336,7 @@ static void spi_qup_remove(struct platform_device *pdev)
ERR_PTR(ret));
}
- spi_qup_release_dma(master);
+ spi_qup_release_dma(host);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
@@ -1318,9 +1364,10 @@ static struct platform_driver spi_qup_driver = {
.of_match_table = spi_qup_dt_match,
},
.probe = spi_qup_probe,
- .remove_new = spi_qup_remove,
+ .remove = spi_qup_remove,
};
module_platform_driver(spi_qup_driver);
+MODULE_DESCRIPTION("Qualcomm SPI controller with QUP interface");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:spi_qup");
diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c
index 5073736d3d1f..22b86fc89132 100644
--- a/drivers/spi/spi-rb4xx.c
+++ b/drivers/spi/spi-rb4xx.c
@@ -16,7 +16,16 @@
#include <linux/spi/spi.h>
#include <linux/of.h>
-#include <asm/mach-ath79/ar71xx_regs.h>
+#define AR71XX_SPI_REG_FS 0x00 /* Function Select */
+#define AR71XX_SPI_REG_CTRL 0x04 /* SPI Control */
+#define AR71XX_SPI_REG_IOC 0x08 /* SPI I/O Control */
+#define AR71XX_SPI_REG_RDS 0x0c /* Read Data Shift */
+
+#define AR71XX_SPI_FS_GPIO BIT(0) /* Enable GPIO mode */
+
+#define AR71XX_SPI_IOC_DO BIT(0) /* Data Out pin */
+#define AR71XX_SPI_IOC_CLK BIT(8) /* CLK pin */
+#define AR71XX_SPI_IOC_CS(n) BIT(16 + (n))
struct rb4xx_spi {
void __iomem *base;
@@ -63,7 +72,7 @@ static inline void do_spi_clk_two(struct rb4xx_spi *rbspi, u32 spi_ioc,
if (value & BIT(1))
regval |= AR71XX_SPI_IOC_DO;
if (value & BIT(0))
- regval |= AR71XX_SPI_IOC_CS2;
+ regval |= AR71XX_SPI_IOC_CS(2);
rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval);
rb4xx_write(rbspi, AR71XX_SPI_REG_IOC, regval | AR71XX_SPI_IOC_CLK);
@@ -80,7 +89,7 @@ static void do_spi_byte_two(struct rb4xx_spi *rbspi, u32 spi_ioc, u8 byte)
static void rb4xx_set_cs(struct spi_device *spi, bool enable)
{
- struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master);
+ struct rb4xx_spi *rbspi = spi_controller_get_devdata(spi->controller);
/*
* Setting CS is done along with bitbanging the actual values,
@@ -89,13 +98,13 @@ static void rb4xx_set_cs(struct spi_device *spi, bool enable)
*/
if (enable)
rb4xx_write(rbspi, AR71XX_SPI_REG_IOC,
- AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1);
+ AR71XX_SPI_IOC_CS(0) | AR71XX_SPI_IOC_CS(1));
}
-static int rb4xx_transfer_one(struct spi_master *master,
+static int rb4xx_transfer_one(struct spi_controller *host,
struct spi_device *spi, struct spi_transfer *t)
{
- struct rb4xx_spi *rbspi = spi_master_get_devdata(master);
+ struct rb4xx_spi *rbspi = spi_controller_get_devdata(host);
int i;
u32 spi_ioc;
u8 *rx_buf;
@@ -109,10 +118,10 @@ static int rb4xx_transfer_one(struct spi_master *master,
*/
if (spi_get_chipselect(spi, 0) == 2)
/* MMC */
- spi_ioc = AR71XX_SPI_IOC_CS0;
+ spi_ioc = AR71XX_SPI_IOC_CS(0);
else
/* Boot flash and CPLD */
- spi_ioc = AR71XX_SPI_IOC_CS1;
+ spi_ioc = AR71XX_SPI_IOC_CS(1);
tx_buf = t->tx_buf;
rx_buf = t->rx_buf;
@@ -126,14 +135,14 @@ static int rb4xx_transfer_one(struct spi_master *master,
continue;
rx_buf[i] = rb4xx_read(rbspi, AR71XX_SPI_REG_RDS);
}
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return 0;
}
static int rb4xx_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct clk *ahb_clk;
struct rb4xx_spi *rbspi;
int err;
@@ -143,51 +152,39 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
if (IS_ERR(spi_base))
return PTR_ERR(spi_base);
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*rbspi));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*rbspi));
+ if (!host)
return -ENOMEM;
- ahb_clk = devm_clk_get(&pdev->dev, "ahb");
+ ahb_clk = devm_clk_get_enabled(&pdev->dev, "ahb");
if (IS_ERR(ahb_clk))
return PTR_ERR(ahb_clk);
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = 0;
- master->num_chipselect = 3;
- master->mode_bits = SPI_TX_DUAL;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->flags = SPI_MASTER_MUST_TX;
- master->transfer_one = rb4xx_transfer_one;
- master->set_cs = rb4xx_set_cs;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = 0;
+ host->num_chipselect = 3;
+ host->mode_bits = SPI_TX_DUAL;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->flags = SPI_CONTROLLER_MUST_TX;
+ host->transfer_one = rb4xx_transfer_one;
+ host->set_cs = rb4xx_set_cs;
- rbspi = spi_master_get_devdata(master);
+ rbspi = spi_controller_get_devdata(host);
rbspi->base = spi_base;
rbspi->clk = ahb_clk;
- platform_set_drvdata(pdev, rbspi);
- err = devm_spi_register_master(&pdev->dev, master);
+ err = devm_spi_register_controller(&pdev->dev, host);
if (err) {
- dev_err(&pdev->dev, "failed to register SPI master\n");
+ dev_err(&pdev->dev, "failed to register SPI host\n");
return err;
}
- err = clk_prepare_enable(ahb_clk);
- if (err)
- return err;
-
/* Enable SPI */
rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
return 0;
}
-static void rb4xx_spi_remove(struct platform_device *pdev)
-{
- struct rb4xx_spi *rbspi = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(rbspi->clk);
-}
-
static const struct of_device_id rb4xx_spi_dt_match[] = {
{ .compatible = "mikrotik,rb4xx-spi" },
{ },
@@ -196,10 +193,9 @@ MODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match);
static struct platform_driver rb4xx_spi_drv = {
.probe = rb4xx_spi_probe,
- .remove_new = rb4xx_spi_remove,
.driver = {
.name = "rb4xx-spi",
- .of_match_table = of_match_ptr(rb4xx_spi_dt_match),
+ .of_match_table = rb4xx_spi_dt_match,
},
};
diff --git a/drivers/spi/spi-realtek-rtl-snand.c b/drivers/spi/spi-realtek-rtl-snand.c
new file mode 100644
index 000000000000..741cf2af3e91
--- /dev/null
+++ b/drivers/spi/spi-realtek-rtl-snand.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+
+#define SNAFCFR 0x00
+#define SNAFCFR_DMA_IE BIT(20)
+#define SNAFCCR 0x04
+#define SNAFWCMR 0x08
+#define SNAFRCMR 0x0c
+#define SNAFRDR 0x10
+#define SNAFWDR 0x14
+#define SNAFDTR 0x18
+#define SNAFDRSAR 0x1c
+#define SNAFDIR 0x20
+#define SNAFDIR_DMA_IP BIT(0)
+#define SNAFDLR 0x24
+#define SNAFSR 0x40
+#define SNAFSR_NFCOS BIT(3)
+#define SNAFSR_NFDRS BIT(2)
+#define SNAFSR_NFDWS BIT(1)
+
+#define CMR_LEN(len) ((len) - 1)
+#define CMR_WID(width) (((width) >> 1) << 28)
+
+struct rtl_snand {
+ struct device *dev;
+ struct regmap *regmap;
+ struct completion comp;
+};
+
+static irqreturn_t rtl_snand_irq(int irq, void *data)
+{
+ struct rtl_snand *snand = data;
+ u32 val = 0;
+
+ regmap_read(snand->regmap, SNAFSR, &val);
+ if (val & (SNAFSR_NFCOS | SNAFSR_NFDRS | SNAFSR_NFDWS))
+ return IRQ_NONE;
+
+ regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP);
+ complete(&snand->comp);
+
+ return IRQ_HANDLED;
+}
+
+static bool rtl_snand_supports_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ if (!spi_mem_default_supports_op(mem, op))
+ return false;
+ if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1)
+ return false;
+ return true;
+}
+
+static void rtl_snand_set_cs(struct rtl_snand *snand, int cs, bool active)
+{
+ u32 val;
+
+ if (active)
+ val = ~(1 << (4 * cs));
+ else
+ val = ~0;
+
+ regmap_write(snand->regmap, SNAFCCR, val);
+}
+
+static int rtl_snand_wait_ready(struct rtl_snand *snand)
+{
+ u32 val;
+
+ return regmap_read_poll_timeout(snand->regmap, SNAFSR, val, !(val & SNAFSR_NFCOS),
+ 0, 2 * USEC_PER_MSEC);
+}
+
+static int rtl_snand_xfer_head(struct rtl_snand *snand, int cs, const struct spi_mem_op *op)
+{
+ int ret;
+ u32 val, len = 0;
+
+ rtl_snand_set_cs(snand, cs, true);
+
+ val = op->cmd.opcode << 24;
+ len = 1;
+ if (op->addr.nbytes && op->addr.buswidth == 1) {
+ val |= op->addr.val << ((3 - op->addr.nbytes) * 8);
+ len += op->addr.nbytes;
+ }
+
+ ret = rtl_snand_wait_ready(snand);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(len));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(snand->regmap, SNAFWDR, val);
+ if (ret)
+ return ret;
+
+ ret = rtl_snand_wait_ready(snand);
+ if (ret)
+ return ret;
+
+ if (op->addr.buswidth > 1) {
+ val = op->addr.val << ((3 - op->addr.nbytes) * 8);
+ len = op->addr.nbytes;
+
+ ret = regmap_write(snand->regmap, SNAFWCMR,
+ CMR_WID(op->addr.buswidth) | CMR_LEN(len));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(snand->regmap, SNAFWDR, val);
+ if (ret)
+ return ret;
+
+ ret = rtl_snand_wait_ready(snand);
+ if (ret)
+ return ret;
+ }
+
+ if (op->dummy.nbytes) {
+ val = 0;
+
+ ret = regmap_write(snand->regmap, SNAFWCMR,
+ CMR_WID(op->dummy.buswidth) | CMR_LEN(op->dummy.nbytes));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(snand->regmap, SNAFWDR, val);
+ if (ret)
+ return ret;
+
+ ret = rtl_snand_wait_ready(snand);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rtl_snand_xfer_tail(struct rtl_snand *snand, int cs)
+{
+ rtl_snand_set_cs(snand, cs, false);
+}
+
+static int rtl_snand_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op)
+{
+ unsigned int pos, nbytes;
+ int ret;
+ u32 val, len = 0;
+
+ ret = rtl_snand_xfer_head(snand, cs, op);
+ if (ret)
+ goto out_deselect;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ pos = 0;
+ len = op->data.nbytes;
+
+ while (pos < len) {
+ nbytes = len - pos;
+ if (nbytes > 4)
+ nbytes = 4;
+
+ ret = rtl_snand_wait_ready(snand);
+ if (ret)
+ goto out_deselect;
+
+ ret = regmap_write(snand->regmap, SNAFRCMR,
+ CMR_WID(op->data.buswidth) | CMR_LEN(nbytes));
+ if (ret)
+ goto out_deselect;
+
+ ret = rtl_snand_wait_ready(snand);
+ if (ret)
+ goto out_deselect;
+
+ ret = regmap_read(snand->regmap, SNAFRDR, &val);
+ if (ret)
+ goto out_deselect;
+
+ memcpy(op->data.buf.in + pos, &val, nbytes);
+
+ pos += nbytes;
+ }
+ } else if (op->data.dir == SPI_MEM_DATA_OUT) {
+ pos = 0;
+ len = op->data.nbytes;
+
+ while (pos < len) {
+ nbytes = len - pos;
+ if (nbytes > 4)
+ nbytes = 4;
+
+ memcpy(&val, op->data.buf.out + pos, nbytes);
+
+ pos += nbytes;
+
+ ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(nbytes));
+ if (ret)
+ goto out_deselect;
+
+ ret = regmap_write(snand->regmap, SNAFWDR, val);
+ if (ret)
+ goto out_deselect;
+
+ ret = rtl_snand_wait_ready(snand);
+ if (ret)
+ goto out_deselect;
+ }
+ }
+
+out_deselect:
+ rtl_snand_xfer_tail(snand, cs);
+
+ if (ret)
+ dev_err(snand->dev, "transfer failed %d\n", ret);
+
+ return ret;
+}
+
+static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op)
+{
+ unsigned int pos, nbytes;
+ int ret;
+ dma_addr_t buf_dma;
+ enum dma_data_direction dir;
+ u32 trig, len, maxlen;
+
+ ret = rtl_snand_xfer_head(snand, cs, op);
+ if (ret)
+ goto out_deselect;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ maxlen = 2080;
+ dir = DMA_FROM_DEVICE;
+ trig = 0;
+ } else if (op->data.dir == SPI_MEM_DATA_OUT) {
+ maxlen = 520;
+ dir = DMA_TO_DEVICE;
+ trig = 1;
+ } else {
+ ret = -EOPNOTSUPP;
+ goto out_deselect;
+ }
+
+ buf_dma = dma_map_single(snand->dev, op->data.buf.in, op->data.nbytes, dir);
+ ret = dma_mapping_error(snand->dev, buf_dma);
+ if (ret)
+ goto out_deselect;
+
+ ret = regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP);
+ if (ret)
+ goto out_unmap;
+
+ ret = regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, SNAFCFR_DMA_IE);
+ if (ret)
+ goto out_unmap;
+
+ pos = 0;
+ len = op->data.nbytes;
+
+ while (pos < len) {
+ nbytes = len - pos;
+ if (nbytes > maxlen)
+ nbytes = maxlen;
+
+ reinit_completion(&snand->comp);
+
+ ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma + pos);
+ if (ret)
+ goto out_disable_int;
+
+ pos += nbytes;
+
+ ret = regmap_write(snand->regmap, SNAFDLR,
+ CMR_WID(op->data.buswidth) | nbytes);
+ if (ret)
+ goto out_disable_int;
+
+ ret = regmap_write(snand->regmap, SNAFDTR, trig);
+ if (ret)
+ goto out_disable_int;
+
+ if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000)))
+ ret = -ETIMEDOUT;
+
+ if (ret)
+ goto out_disable_int;
+ }
+
+out_disable_int:
+ regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0);
+out_unmap:
+ dma_unmap_single(snand->dev, buf_dma, op->data.nbytes, dir);
+out_deselect:
+ rtl_snand_xfer_tail(snand, cs);
+
+ if (ret)
+ dev_err(snand->dev, "transfer failed %d\n", ret);
+
+ return ret;
+}
+
+static bool rtl_snand_dma_op(const struct spi_mem_op *op)
+{
+ switch (op->data.dir) {
+ case SPI_MEM_DATA_IN:
+ case SPI_MEM_DATA_OUT:
+ return op->data.nbytes > 32;
+ default:
+ return false;
+ }
+}
+
+static int rtl_snand_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ struct rtl_snand *snand = spi_controller_get_devdata(mem->spi->controller);
+ int cs = spi_get_chipselect(mem->spi, 0);
+
+ dev_dbg(snand->dev, "cs %d op cmd %02x %d:%d, dummy %d:%d, addr %08llx@%d:%d, data %d:%d\n",
+ cs, op->cmd.opcode,
+ op->cmd.buswidth, op->cmd.nbytes, op->dummy.buswidth,
+ op->dummy.nbytes, op->addr.val, op->addr.buswidth,
+ op->addr.nbytes, op->data.buswidth, op->data.nbytes);
+
+ if (rtl_snand_dma_op(op))
+ return rtl_snand_dma_xfer(snand, cs, op);
+ else
+ return rtl_snand_xfer(snand, cs, op);
+}
+
+static const struct spi_controller_mem_ops rtl_snand_mem_ops = {
+ .supports_op = rtl_snand_supports_op,
+ .exec_op = rtl_snand_exec_op,
+};
+
+static const struct of_device_id rtl_snand_match[] = {
+ { .compatible = "realtek,rtl9301-snand" },
+ { .compatible = "realtek,rtl9302b-snand" },
+ { .compatible = "realtek,rtl9302c-snand" },
+ { .compatible = "realtek,rtl9303-snand" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rtl_snand_match);
+
+static int rtl_snand_probe(struct platform_device *pdev)
+{
+ struct rtl_snand *snand;
+ struct device *dev = &pdev->dev;
+ struct spi_controller *ctrl;
+ void __iomem *base;
+ const struct regmap_config rc = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ };
+ int irq, ret;
+
+ ctrl = devm_spi_alloc_host(dev, sizeof(*snand));
+ if (!ctrl)
+ return -ENOMEM;
+
+ snand = spi_controller_get_devdata(ctrl);
+ snand->dev = dev;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ snand->regmap = devm_regmap_init_mmio(dev, base, &rc);
+ if (IS_ERR(snand->regmap))
+ return PTR_ERR(snand->regmap);
+
+ init_completion(&snand->comp);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = dma_set_mask(snand->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set DMA mask\n");
+
+ ret = devm_request_irq(dev, irq, rtl_snand_irq, 0, "rtl-snand", snand);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to request irq\n");
+
+ ctrl->num_chipselect = 2;
+ ctrl->mem_ops = &rtl_snand_mem_ops;
+ ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
+ ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD;
+ device_set_node(&ctrl->dev, dev_fwnode(dev));
+
+ return devm_spi_register_controller(dev, ctrl);
+}
+
+static struct platform_driver rtl_snand_driver = {
+ .driver = {
+ .name = "realtek-rtl-snand",
+ .of_match_table = rtl_snand_match,
+ },
+ .probe = rtl_snand_probe,
+};
+module_platform_driver(rtl_snand_driver);
+
+MODULE_DESCRIPTION("Realtek SPI-NAND Flash Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-realtek-rtl.c b/drivers/spi/spi-realtek-rtl.c
index 866b0477dbd7..0b0123e20b54 100644
--- a/drivers/spi/spi-realtek-rtl.c
+++ b/drivers/spi/spi-realtek-rtl.c
@@ -153,7 +153,7 @@ static int realtek_rtl_spi_probe(struct platform_device *pdev)
struct rtspi *rtspi;
int err;
- ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*rtspi));
+ ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*rtspi));
if (!ctrl) {
dev_err(&pdev->dev, "Error allocating SPI controller\n");
return -ENOMEM;
diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c
index 583f4187f030..b3c2b03b1153 100644
--- a/drivers/spi/spi-rockchip-sfc.c
+++ b/drivers/spi/spi-rockchip-sfc.c
@@ -13,12 +13,14 @@
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
+#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
-#include <linux/interrupt.h>
#include <linux/spi/spi-mem.h>
/* System control */
@@ -110,8 +112,9 @@
#define SFC_VER_3 0x3
#define SFC_VER_4 0x4
#define SFC_VER_5 0x5
+#define SFC_VER_8 0x8
-/* Delay line controller resiter */
+/* Delay line controller register */
#define SFC_DLL_CTRL0 0x3C
#define SFC_DLL_CTRL0_SCLK_SMP_DLL BIT(15)
#define SFC_DLL_CTRL0_DLL_MAX_VER4 0xFFU
@@ -150,16 +153,13 @@
/* Data */
#define SFC_DATA 0x108
-/* The controller and documentation reports that it supports up to 4 CS
- * devices (0-3), however I have only been able to test a single CS (CS 0)
- * due to the configuration of my device.
- */
-#define SFC_MAX_CHIPSELECT_NUM 4
+#define SFC_CS1_REG_OFFSET 0x200
+
+#define SFC_MAX_CHIPSELECT_NUM 2
-/* The SFC can transfer max 16KB - 1 at one time
- * we set it to 15.5KB here for alignment.
- */
#define SFC_MAX_IOSIZE_VER3 (512 * 31)
+/* Although up to 4GB, 64KB is enough with less mem reserved */
+#define SFC_MAX_IOSIZE_VER4 (0x10000U)
/* DMA is only enabled for large data transmission */
#define SFC_DMA_TRANS_THRETHOLD (0x40)
@@ -169,12 +169,14 @@
*/
#define SFC_MAX_SPEED (150 * 1000 * 1000)
+#define ROCKCHIP_AUTOSUSPEND_DELAY 2000
+
struct rockchip_sfc {
struct device *dev;
void __iomem *regbase;
struct clk *hclk;
struct clk *clk;
- u32 frequency;
+ u32 speed[SFC_MAX_CHIPSELECT_NUM];
/* virtual mapped addr for dma_buffer */
void *buffer;
dma_addr_t dma_buffer;
@@ -182,6 +184,7 @@ struct rockchip_sfc {
bool use_dma;
u32 max_iosize;
u16 version;
+ struct spi_controller *host;
};
static int rockchip_sfc_reset(struct rockchip_sfc *sfc)
@@ -215,6 +218,22 @@ static u32 rockchip_sfc_get_max_iosize(struct rockchip_sfc *sfc)
return SFC_MAX_IOSIZE_VER3;
}
+static int rockchip_sfc_clk_set_rate(struct rockchip_sfc *sfc, unsigned long speed)
+{
+ if (sfc->version >= SFC_VER_8)
+ return clk_set_rate(sfc->clk, speed * 2);
+ else
+ return clk_set_rate(sfc->clk, speed);
+}
+
+static unsigned long rockchip_sfc_clk_get_rate(struct rockchip_sfc *sfc)
+{
+ if (sfc->version >= SFC_VER_8)
+ return clk_get_rate(sfc->clk) / 2;
+ else
+ return clk_get_rate(sfc->clk);
+}
+
static void rockchip_sfc_irq_unmask(struct rockchip_sfc *sfc, u32 mask)
{
u32 reg;
@@ -301,6 +320,7 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
u32 len)
{
u32 ctrl = 0, cmd = 0;
+ u8 cs = spi_get_chipselect(mem->spi, 0);
/* set CMD */
cmd = op->cmd.opcode;
@@ -314,7 +334,8 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
cmd |= SFC_CMD_ADDR_24BITS << SFC_CMD_ADDR_SHIFT;
} else {
cmd |= SFC_CMD_ADDR_XBITS << SFC_CMD_ADDR_SHIFT;
- writel(op->addr.nbytes * 8 - 1, sfc->regbase + SFC_ABIT);
+ writel(op->addr.nbytes * 8 - 1,
+ sfc->regbase + cs * SFC_CS1_REG_OFFSET + SFC_ABIT);
}
ctrl |= ((op->addr.buswidth >> 1) << SFC_CTRL_ADDR_BITS_SHIFT);
@@ -346,7 +367,7 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
/* set the Controller */
ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE;
- cmd |= spi_get_chipselect(mem->spi, 0) << SFC_CMD_CS_SHIFT;
+ cmd |= cs << SFC_CMD_CS_SHIFT;
dev_dbg(sfc->dev, "sfc addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n",
op->addr.nbytes, op->addr.buswidth,
@@ -354,7 +375,7 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc,
dev_dbg(sfc->dev, "sfc ctrl=%x cmd=%x addr=%llx len=%x\n",
ctrl, cmd, op->addr.val, len);
- writel(ctrl, sfc->regbase + SFC_CTRL);
+ writel(ctrl, sfc->regbase + cs * SFC_CS1_REG_OFFSET + SFC_CTRL);
writel(cmd, sfc->regbase + SFC_CMD);
if (op->addr.nbytes)
writel(op->addr.val, sfc->regbase + SFC_ADDR);
@@ -452,8 +473,10 @@ static int rockchip_sfc_xfer_data_dma(struct rockchip_sfc *sfc,
dev_dbg(sfc->dev, "sfc xfer_dma len=%x\n", len);
- if (op->data.dir == SPI_MEM_DATA_OUT)
+ if (op->data.dir == SPI_MEM_DATA_OUT) {
memcpy(sfc->buffer, op->data.buf.out, len);
+ dma_sync_single_for_device(sfc->dev, sfc->dma_buffer, len, DMA_TO_DEVICE);
+ }
ret = rockchip_sfc_fifo_transfer_dma(sfc, sfc->dma_buffer, len);
if (!wait_for_completion_timeout(&sfc->cp, msecs_to_jiffies(2000))) {
@@ -461,8 +484,11 @@ static int rockchip_sfc_xfer_data_dma(struct rockchip_sfc *sfc,
ret = -ETIMEDOUT;
}
rockchip_sfc_irq_mask(sfc, SFC_IMR_DMA);
- if (op->data.dir == SPI_MEM_DATA_IN)
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ dma_sync_single_for_cpu(sfc->dev, sfc->dma_buffer, len, DMA_FROM_DEVICE);
memcpy(op->data.buf.in, sfc->buffer, len);
+ }
return ret;
}
@@ -472,6 +498,16 @@ static int rockchip_sfc_xfer_done(struct rockchip_sfc *sfc, u32 timeout_us)
int ret = 0;
u32 status;
+ /*
+ * There is very little data left in fifo, and the controller will
+ * complete the transmission in a short period of time.
+ */
+ ret = readl_poll_timeout(sfc->regbase + SFC_SR, status,
+ !(status & SFC_SR_IS_BUSY),
+ 0, 10);
+ if (!ret)
+ return 0;
+
ret = readl_poll_timeout(sfc->regbase + SFC_SR, status,
!(status & SFC_SR_IS_BUSY),
20, timeout_us);
@@ -487,23 +523,31 @@ static int rockchip_sfc_xfer_done(struct rockchip_sfc *sfc, u32 timeout_us)
static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master);
+ struct rockchip_sfc *sfc = spi_controller_get_devdata(mem->spi->controller);
u32 len = op->data.nbytes;
int ret;
+ u8 cs = spi_get_chipselect(mem->spi, 0);
+
+ ret = pm_runtime_get_sync(sfc->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(sfc->dev);
+ return ret;
+ }
- if (unlikely(mem->spi->max_speed_hz != sfc->frequency)) {
- ret = clk_set_rate(sfc->clk, mem->spi->max_speed_hz);
+ if (unlikely(op->max_freq != sfc->speed[cs]) &&
+ !has_acpi_companion(sfc->dev)) {
+ ret = rockchip_sfc_clk_set_rate(sfc, op->max_freq);
if (ret)
- return ret;
- sfc->frequency = mem->spi->max_speed_hz;
+ goto out;
+ sfc->speed[cs] = op->max_freq;
dev_dbg(sfc->dev, "set_freq=%dHz real_freq=%ldHz\n",
- sfc->frequency, clk_get_rate(sfc->clk));
+ sfc->speed[cs], rockchip_sfc_clk_get_rate(sfc));
}
rockchip_sfc_adjust_op_work((struct spi_mem_op *)op);
rockchip_sfc_xfer_setup(sfc, mem, op, len);
if (len) {
- if (likely(sfc->use_dma) && len >= SFC_DMA_TRANS_THRETHOLD) {
+ if (likely(sfc->use_dma) && len >= SFC_DMA_TRANS_THRETHOLD && !(len & 0x3)) {
init_completion(&sfc->cp);
rockchip_sfc_irq_unmask(sfc, SFC_IMR_DMA);
ret = rockchip_sfc_xfer_data_dma(sfc, op, len);
@@ -514,16 +558,21 @@ static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op
if (ret != len) {
dev_err(sfc->dev, "xfer data failed ret %d dir %d\n", ret, op->data.dir);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
}
- return rockchip_sfc_xfer_done(sfc, 100000);
+ ret = rockchip_sfc_xfer_done(sfc, 100000);
+out:
+ pm_runtime_put_autosuspend(sfc->dev);
+
+ return ret;
}
static int rockchip_sfc_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master);
+ struct rockchip_sfc *sfc = spi_controller_get_devdata(mem->spi->controller);
op->data.nbytes = min(op->data.nbytes, sfc->max_iosize);
@@ -535,6 +584,10 @@ static const struct spi_controller_mem_ops rockchip_sfc_mem_ops = {
.adjust_op_size = rockchip_sfc_adjust_op_size,
};
+static const struct spi_controller_mem_caps rockchip_sfc_mem_caps = {
+ .per_op_freq = true,
+};
+
static irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id)
{
struct rockchip_sfc *sfc = dev_id;
@@ -557,57 +610,54 @@ static irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id)
static int rockchip_sfc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct spi_master *master;
+ struct spi_controller *host;
struct rockchip_sfc *sfc;
int ret;
+ u32 i, val;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*sfc));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*sfc));
+ if (!host)
return -ENOMEM;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->mem_ops = &rockchip_sfc_mem_ops;
- master->dev.of_node = pdev->dev.of_node;
- master->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL;
- master->max_speed_hz = SFC_MAX_SPEED;
- master->num_chipselect = SFC_MAX_CHIPSELECT_NUM;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->mem_ops = &rockchip_sfc_mem_ops;
+ host->mem_caps = &rockchip_sfc_mem_caps;
+ host->dev.of_node = pdev->dev.of_node;
+ host->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL;
+ host->max_speed_hz = SFC_MAX_SPEED;
+ host->num_chipselect = SFC_MAX_CHIPSELECT_NUM;
- sfc = spi_master_get_devdata(master);
+ sfc = spi_controller_get_devdata(host);
sfc->dev = dev;
+ sfc->host = host;
sfc->regbase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sfc->regbase))
return PTR_ERR(sfc->regbase);
- sfc->clk = devm_clk_get(&pdev->dev, "clk_sfc");
- if (IS_ERR(sfc->clk)) {
- dev_err(&pdev->dev, "Failed to get sfc interface clk\n");
- return PTR_ERR(sfc->clk);
- }
+ if (!has_acpi_companion(&pdev->dev))
+ sfc->clk = devm_clk_get(&pdev->dev, "clk_sfc");
+ if (IS_ERR(sfc->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sfc->clk),
+ "Failed to get sfc interface clk\n");
- sfc->hclk = devm_clk_get(&pdev->dev, "hclk_sfc");
- if (IS_ERR(sfc->hclk)) {
- dev_err(&pdev->dev, "Failed to get sfc ahb clk\n");
- return PTR_ERR(sfc->hclk);
- }
-
- sfc->use_dma = !of_property_read_bool(sfc->dev->of_node,
- "rockchip,sfc-no-dma");
-
- if (sfc->use_dma) {
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
- if (ret) {
- dev_warn(dev, "Unable to set dma mask\n");
- return ret;
- }
+ if (!has_acpi_companion(&pdev->dev))
+ sfc->hclk = devm_clk_get(&pdev->dev, "hclk_sfc");
+ if (IS_ERR(sfc->hclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(sfc->hclk),
+ "Failed to get sfc ahb clk\n");
- sfc->buffer = dmam_alloc_coherent(dev, SFC_MAX_IOSIZE_VER3,
- &sfc->dma_buffer,
- GFP_KERNEL);
- if (!sfc->buffer)
- return -ENOMEM;
+ if (has_acpi_companion(&pdev->dev)) {
+ ret = device_property_read_u32(&pdev->dev, "clock-frequency", &val);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to find clock-frequency in ACPI\n");
+ for (i = 0; i < SFC_MAX_CHIPSELECT_NUM; i++)
+ sfc->speed[i] = val;
}
+ sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, "rockchip,sfc-no-dma");
+
ret = clk_prepare_enable(sfc->hclk);
if (ret) {
dev_err(&pdev->dev, "Failed to enable ahb clk\n");
@@ -629,23 +679,57 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
0, pdev->name, sfc);
if (ret) {
dev_err(dev, "Failed to request irq\n");
-
goto err_irq;
}
+ platform_set_drvdata(pdev, sfc);
+
ret = rockchip_sfc_init(sfc);
if (ret)
goto err_irq;
- sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc);
sfc->version = rockchip_sfc_get_version(sfc);
+ sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc);
- ret = spi_register_master(master);
+ pm_runtime_set_autosuspend_delay(dev, ROCKCHIP_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_get_noresume(dev);
+
+ if (sfc->use_dma) {
+ sfc->buffer = (u8 *)__get_free_pages(GFP_KERNEL | GFP_DMA32,
+ get_order(sfc->max_iosize));
+ if (!sfc->buffer) {
+ ret = -ENOMEM;
+ goto err_dma;
+ }
+ sfc->dma_buffer = dma_map_single(dev, sfc->buffer,
+ sfc->max_iosize, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev, sfc->dma_buffer)) {
+ ret = -ENOMEM;
+ goto err_dma_map;
+ }
+ }
+
+ ret = devm_spi_register_controller(dev, host);
if (ret)
- goto err_irq;
+ goto err_register;
- return 0;
+ pm_runtime_put_autosuspend(dev);
+ return 0;
+err_register:
+ dma_unmap_single(dev, sfc->dma_buffer, sfc->max_iosize,
+ DMA_BIDIRECTIONAL);
+err_dma_map:
+ free_pages((unsigned long)sfc->buffer, get_order(sfc->max_iosize));
+err_dma:
+ pm_runtime_get_sync(dev);
+ pm_runtime_put_noidle(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_dont_use_autosuspend(dev);
err_irq:
clk_disable_unprepare(sfc->clk);
err_clk:
@@ -656,15 +740,85 @@ err_hclk:
static void rockchip_sfc_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
struct rockchip_sfc *sfc = platform_get_drvdata(pdev);
+ struct spi_controller *host = sfc->host;
- spi_unregister_master(master);
+ spi_unregister_controller(host);
+ dma_unmap_single(&pdev->dev, sfc->dma_buffer, sfc->max_iosize,
+ DMA_BIDIRECTIONAL);
+ free_pages((unsigned long)sfc->buffer, get_order(sfc->max_iosize));
clk_disable_unprepare(sfc->clk);
clk_disable_unprepare(sfc->hclk);
}
+#ifdef CONFIG_PM
+static int rockchip_sfc_runtime_suspend(struct device *dev)
+{
+ struct rockchip_sfc *sfc = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(sfc->clk);
+ clk_disable_unprepare(sfc->hclk);
+
+ return 0;
+}
+
+static int rockchip_sfc_runtime_resume(struct device *dev)
+{
+ struct rockchip_sfc *sfc = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(sfc->hclk);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(sfc->clk);
+ if (ret < 0)
+ clk_disable_unprepare(sfc->hclk);
+
+ return ret;
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_sfc_suspend(struct device *dev)
+{
+ pinctrl_pm_select_sleep_state(dev);
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int rockchip_sfc_resume(struct device *dev)
+{
+ struct rockchip_sfc *sfc = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ return ret;
+
+ pinctrl_pm_select_default_state(dev);
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(dev);
+ return ret;
+ }
+
+ rockchip_sfc_init(sfc);
+
+ pm_runtime_put_autosuspend(dev);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops rockchip_sfc_pm_ops = {
+ SET_RUNTIME_PM_OPS(rockchip_sfc_runtime_suspend,
+ rockchip_sfc_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(rockchip_sfc_suspend, rockchip_sfc_resume)
+};
+
static const struct of_device_id rockchip_sfc_dt_ids[] = {
{ .compatible = "rockchip,sfc"},
{ /* sentinel */ }
@@ -675,9 +829,10 @@ static struct platform_driver rockchip_sfc_driver = {
.driver = {
.name = "rockchip-sfc",
.of_match_table = rockchip_sfc_dt_ids,
+ .pm = &rockchip_sfc_pm_ops,
},
.probe = rockchip_sfc_probe,
- .remove_new = rockchip_sfc_remove,
+ .remove = rockchip_sfc_remove,
};
module_platform_driver(rockchip_sfc_driver);
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 143ede958ac1..1a6381de6f33 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -104,8 +104,8 @@
#define CR0_XFM_RO 0x2
#define CR0_OPM_OFFSET 20
-#define CR0_OPM_MASTER 0x0
-#define CR0_OPM_SLAVE 0x1
+#define CR0_OPM_HOST 0x0
+#define CR0_OPM_TARGET 0x1
#define CR0_SOI_OFFSET 23
@@ -125,7 +125,7 @@
#define SR_TF_EMPTY (1 << 2)
#define SR_RF_EMPTY (1 << 3)
#define SR_RF_FULL (1 << 4)
-#define SR_SLAVE_TX_BUSY (1 << 5)
+#define SR_TARGET_TX_BUSY (1 << 5)
/* Bit fields in ISR, IMR, ISR, RISR, 5bit */
#define INT_MASK 0x1f
@@ -151,7 +151,7 @@
#define RXDMA (1 << 0)
#define TXDMA (1 << 1)
-/* sclk_out: spi master internal logic in rk3x can support 50Mhz */
+/* sclk_out: spi host internal logic in rk3x can support 50Mhz */
#define MAX_SCLK_OUT 50000000U
/*
@@ -160,8 +160,7 @@
*/
#define ROCKCHIP_SPI_MAX_TRANLEN 0xffff
-/* 2 for native cs, 2 for cs-gpio */
-#define ROCKCHIP_SPI_MAX_CS_NUM 4
+#define ROCKCHIP_SPI_MAX_NATIVE_CS_NUM 2
#define ROCKCHIP_SPI_VER2_TYPE1 0x05EC0002
#define ROCKCHIP_SPI_VER2_TYPE2 0x00110002
@@ -192,10 +191,8 @@ struct rockchip_spi {
u8 n_bytes;
u8 rsd;
- bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
-
- bool slave_abort;
- bool cs_inactive; /* spi slave tansmition stop when cs inactive */
+ bool target_abort;
+ bool cs_inactive; /* spi target transmission stop when cs inactive */
bool cs_high_supported; /* native CS supports active-high polarity */
struct spi_transfer *xfer; /* Store xfer temporarily */
@@ -206,13 +203,13 @@ static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
}
-static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool slave_mode)
+static inline void wait_for_tx_idle(struct rockchip_spi *rs, bool target_mode)
{
unsigned long timeout = jiffies + msecs_to_jiffies(5);
do {
- if (slave_mode) {
- if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_SLAVE_TX_BUSY) &&
+ if (target_mode) {
+ if (!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_TARGET_TX_BUSY) &&
!((readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)))
return;
} else {
@@ -244,9 +241,19 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
struct spi_controller *ctlr = spi->controller;
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
bool cs_asserted = spi->mode & SPI_CS_HIGH ? enable : !enable;
+ bool cs_actual;
- /* Return immediately for no-op */
- if (cs_asserted == rs->cs_asserted[spi_get_chipselect(spi, 0)])
+ /*
+ * SPI subsystem tries to avoid no-op calls that would break the PM
+ * refcount below. It can't however for the first time it is used.
+ * To detect this case we read it here and bail out early for no-ops.
+ */
+ if (spi_get_csgpiod(spi, 0))
+ cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & 1);
+ else
+ cs_actual = !!(readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) &
+ BIT(spi_get_chipselect(spi, 0)));
+ if (unlikely(cs_actual == cs_asserted))
return;
if (cs_asserted) {
@@ -268,8 +275,6 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
/* Drop reference from when we first asserted CS */
pm_runtime_put(rs->dev);
}
-
- rs->cs_asserted[spi_get_chipselect(spi, 0)] = cs_asserted;
}
static void rockchip_spi_handle_err(struct spi_controller *ctlr,
@@ -351,9 +356,9 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)
struct spi_controller *ctlr = dev_id;
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
- /* When int_cs_inactive comes, spi slave abort */
+ /* When int_cs_inactive comes, spi target abort */
if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) {
- ctlr->slave_abort(ctlr);
+ ctlr->target_abort(ctlr);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
writel_relaxed(0xffffffff, rs->regs + ROCKCHIP_SPI_ICR);
@@ -405,7 +410,7 @@ static void rockchip_spi_dma_rxcb(void *data)
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
int state = atomic_fetch_andnot(RXDMA, &rs->state);
- if (state & TXDMA && !rs->slave_abort)
+ if (state & TXDMA && !rs->target_abort)
return;
if (rs->cs_inactive)
@@ -421,11 +426,11 @@ static void rockchip_spi_dma_txcb(void *data)
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
int state = atomic_fetch_andnot(TXDMA, &rs->state);
- if (state & RXDMA && !rs->slave_abort)
+ if (state & RXDMA && !rs->target_abort)
return;
/* Wait until the FIFO data completely. */
- wait_for_tx_idle(rs, ctlr->slave);
+ wait_for_tx_idle(rs, ctlr->target);
spi_enable_chip(rs, false);
spi_finalize_current_transfer(ctlr);
@@ -525,7 +530,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
static int rockchip_spi_config(struct rockchip_spi *rs,
struct spi_device *spi, struct spi_transfer *xfer,
- bool use_dma, bool slave_mode)
+ bool use_dma, bool target_mode)
{
u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET
| CR0_BHT_8BIT << CR0_BHT_OFFSET
@@ -534,15 +539,15 @@ static int rockchip_spi_config(struct rockchip_spi *rs,
u32 cr1;
u32 dmacr = 0;
- if (slave_mode)
- cr0 |= CR0_OPM_SLAVE << CR0_OPM_OFFSET;
- rs->slave_abort = false;
+ if (target_mode)
+ cr0 |= CR0_OPM_TARGET << CR0_OPM_OFFSET;
+ rs->target_abort = false;
cr0 |= rs->rsd << CR0_RSD_OFFSET;
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
if (spi->mode & SPI_LSB_FIRST)
cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET;
- if (spi->mode & SPI_CS_HIGH)
+ if ((spi->mode & SPI_CS_HIGH) && !(spi_get_csgpiod(spi, 0)))
cr0 |= BIT(spi_get_chipselect(spi, 0)) << CR0_SOI_OFFSET;
if (xfer->rx_buf && xfer->tx_buf)
@@ -614,7 +619,7 @@ static size_t rockchip_spi_max_transfer_size(struct spi_device *spi)
return ROCKCHIP_SPI_MAX_TRANLEN;
}
-static int rockchip_spi_slave_abort(struct spi_controller *ctlr)
+static int rockchip_spi_target_abort(struct spi_controller *ctlr)
{
struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
u32 rx_fifo_left;
@@ -659,7 +664,7 @@ out:
dmaengine_terminate_sync(ctlr->dma_tx);
atomic_set(&rs->state, 0);
spi_enable_chip(rs, false);
- rs->slave_abort = true;
+ rs->target_abort = true;
spi_finalize_current_transfer(ctlr);
return 0;
@@ -697,7 +702,7 @@ static int rockchip_spi_transfer_one(
rs->xfer = xfer;
use_dma = ctlr->can_dma ? ctlr->can_dma(ctlr, spi, xfer) : false;
- ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->slave);
+ ret = rockchip_spi_config(rs, spi, xfer, use_dma, ctlr->target);
if (ret)
return ret;
@@ -751,22 +756,20 @@ static int rockchip_spi_setup(struct spi_device *spi)
static int rockchip_spi_probe(struct platform_device *pdev)
{
- int ret;
- struct rockchip_spi *rs;
+ struct device_node *np = pdev->dev.of_node;
struct spi_controller *ctlr;
+ struct rockchip_spi *rs;
struct resource *mem;
- struct device_node *np = pdev->dev.of_node;
u32 rsd_nsecs, num_cs;
- bool slave_mode;
+ bool target_mode;
+ int ret;
- slave_mode = of_property_read_bool(np, "spi-slave");
+ target_mode = of_property_read_bool(np, "spi-slave");
- if (slave_mode)
- ctlr = spi_alloc_slave(&pdev->dev,
- sizeof(struct rockchip_spi));
+ if (target_mode)
+ ctlr = spi_alloc_target(&pdev->dev, sizeof(struct rockchip_spi));
else
- ctlr = spi_alloc_master(&pdev->dev,
- sizeof(struct rockchip_spi));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(struct rockchip_spi));
if (!ctlr)
return -ENOMEM;
@@ -778,46 +781,34 @@ static int rockchip_spi_probe(struct platform_device *pdev)
/* Get basic io resource and map it */
rs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
if (IS_ERR(rs->regs)) {
- ret = PTR_ERR(rs->regs);
+ ret = PTR_ERR(rs->regs);
goto err_put_ctlr;
}
- rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk");
+ rs->apb_pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk");
if (IS_ERR(rs->apb_pclk)) {
- dev_err(&pdev->dev, "Failed to get apb_pclk\n");
- ret = PTR_ERR(rs->apb_pclk);
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->apb_pclk),
+ "Failed to get apb_pclk\n");
goto err_put_ctlr;
}
- rs->spiclk = devm_clk_get(&pdev->dev, "spiclk");
+ rs->spiclk = devm_clk_get_enabled(&pdev->dev, "spiclk");
if (IS_ERR(rs->spiclk)) {
- dev_err(&pdev->dev, "Failed to get spi_pclk\n");
- ret = PTR_ERR(rs->spiclk);
- goto err_put_ctlr;
- }
-
- ret = clk_prepare_enable(rs->apb_pclk);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to enable apb_pclk\n");
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->spiclk),
+ "Failed to get spi_pclk\n");
goto err_put_ctlr;
}
- ret = clk_prepare_enable(rs->spiclk);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to enable spi_clk\n");
- goto err_disable_apbclk;
- }
-
spi_enable_chip(rs, false);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
- goto err_disable_spiclk;
+ goto err_put_ctlr;
ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL,
- IRQF_ONESHOT, dev_name(&pdev->dev), ctlr);
+ IRQF_ONESHOT, dev_name(&pdev->dev), ctlr);
if (ret)
- goto err_disable_spiclk;
+ goto err_put_ctlr;
rs->dev = &pdev->dev;
rs->freq = clk_get_rate(rs->spiclk);
@@ -825,25 +816,23 @@ static int rockchip_spi_probe(struct platform_device *pdev)
if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
&rsd_nsecs)) {
/* rx sample delay is expressed in parent clock cycles (max 3) */
- u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8),
- 1000000000 >> 8);
+ u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), 1000000000 >> 8);
if (!rsd) {
dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay\n",
- rs->freq, rsd_nsecs);
+ rs->freq, rsd_nsecs);
} else if (rsd > CR0_RSD_MAX) {
rsd = CR0_RSD_MAX;
- dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns\n",
- rs->freq, rsd_nsecs,
- CR0_RSD_MAX * 1000000000U / rs->freq);
+ dev_warn(rs->dev,
+ "%u Hz are too fast to express %u ns delay, clamping at %u ns\n",
+ rs->freq, rsd_nsecs, CR0_RSD_MAX * 1000000000U / rs->freq);
}
rs->rsd = rsd;
}
rs->fifo_len = get_fifo_len(rs);
if (!rs->fifo_len) {
- dev_err(&pdev->dev, "Failed to get fifo length\n");
- ret = -EINVAL;
- goto err_disable_spiclk;
+ ret = dev_err_probe(&pdev->dev, -EINVAL, "Failed to get fifo length\n");
+ goto err_put_ctlr;
}
pm_runtime_set_autosuspend_delay(&pdev->dev, ROCKCHIP_AUTOSUSPEND_TIMEOUT);
@@ -854,12 +843,12 @@ static int rockchip_spi_probe(struct platform_device *pdev)
ctlr->auto_runtime_pm = true;
ctlr->bus_num = pdev->id;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST;
- if (slave_mode) {
+ if (target_mode) {
ctlr->mode_bits |= SPI_NO_CS;
- ctlr->slave_abort = rockchip_spi_slave_abort;
+ ctlr->target_abort = rockchip_spi_target_abort;
} else {
- ctlr->flags = SPI_MASTER_GPIO_SS;
- ctlr->max_native_cs = ROCKCHIP_SPI_MAX_CS_NUM;
+ ctlr->flags = SPI_CONTROLLER_GPIO_SS;
+ ctlr->max_native_cs = ROCKCHIP_SPI_MAX_NATIVE_CS_NUM;
/*
* rk spi0 has two native cs, spi1..5 one cs only
* if num-cs is missing in the dts, default to 1
@@ -882,22 +871,21 @@ static int rockchip_spi_probe(struct platform_device *pdev)
ctlr->dma_tx = dma_request_chan(rs->dev, "tx");
if (IS_ERR(ctlr->dma_tx)) {
- /* Check tx to see if we need defer probing driver */
- if (PTR_ERR(ctlr->dma_tx) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
+ /* Check tx to see if we need to defer driver probing */
+ ret = dev_warn_probe(rs->dev, PTR_ERR(ctlr->dma_tx),
+ "Failed to request optional TX DMA channel\n");
+ if (ret == -EPROBE_DEFER)
goto err_disable_pm_runtime;
- }
- dev_warn(rs->dev, "Failed to request TX DMA channel\n");
ctlr->dma_tx = NULL;
}
ctlr->dma_rx = dma_request_chan(rs->dev, "rx");
if (IS_ERR(ctlr->dma_rx)) {
- if (PTR_ERR(ctlr->dma_rx) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
+ /* Check rx to see if we need to defer driver probing */
+ ret = dev_warn_probe(rs->dev, PTR_ERR(ctlr->dma_rx),
+ "Failed to request optional RX DMA channel\n");
+ if (ret == -EPROBE_DEFER)
goto err_free_dma_tx;
- }
- dev_warn(rs->dev, "Failed to request RX DMA channel\n");
ctlr->dma_rx = NULL;
}
@@ -911,7 +899,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
case ROCKCHIP_SPI_VER2_TYPE2:
rs->cs_high_supported = true;
ctlr->mode_bits |= SPI_CS_HIGH;
- if (ctlr->can_dma && slave_mode)
+ if (ctlr->can_dma && target_mode)
rs->cs_inactive = true;
else
rs->cs_inactive = false;
@@ -937,10 +925,6 @@ err_free_dma_tx:
dma_release_channel(ctlr->dma_tx);
err_disable_pm_runtime:
pm_runtime_disable(&pdev->dev);
-err_disable_spiclk:
- clk_disable_unprepare(rs->spiclk);
-err_disable_apbclk:
- clk_disable_unprepare(rs->apb_pclk);
err_put_ctlr:
spi_controller_put(ctlr);
@@ -950,13 +934,9 @@ err_put_ctlr:
static void rockchip_spi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr = spi_controller_get(platform_get_drvdata(pdev));
- struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
pm_runtime_get_sync(&pdev->dev);
- clk_disable_unprepare(rs->spiclk);
- clk_disable_unprepare(rs->apb_pclk);
-
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
@@ -974,14 +954,16 @@ static int rockchip_spi_suspend(struct device *dev)
{
int ret;
struct spi_controller *ctlr = dev_get_drvdata(dev);
- struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
ret = spi_controller_suspend(ctlr);
if (ret < 0)
return ret;
- clk_disable_unprepare(rs->spiclk);
- clk_disable_unprepare(rs->apb_pclk);
+ ret = pm_runtime_force_suspend(dev);
+ if (ret < 0) {
+ spi_controller_resume(ctlr);
+ return ret;
+ }
pinctrl_pm_select_sleep_state(dev);
@@ -992,25 +974,14 @@ static int rockchip_spi_resume(struct device *dev)
{
int ret;
struct spi_controller *ctlr = dev_get_drvdata(dev);
- struct rockchip_spi *rs = spi_controller_get_devdata(ctlr);
pinctrl_pm_select_default_state(dev);
- ret = clk_prepare_enable(rs->apb_pclk);
+ ret = pm_runtime_force_resume(dev);
if (ret < 0)
return ret;
- ret = clk_prepare_enable(rs->spiclk);
- if (ret < 0)
- clk_disable_unprepare(rs->apb_pclk);
-
- ret = spi_controller_resume(ctlr);
- if (ret < 0) {
- clk_disable_unprepare(rs->spiclk);
- clk_disable_unprepare(rs->apb_pclk);
- }
-
- return 0;
+ return spi_controller_resume(ctlr);
}
#endif /* CONFIG_PM_SLEEP */
@@ -1074,7 +1045,7 @@ static struct platform_driver rockchip_spi_driver = {
.of_match_table = of_match_ptr(rockchip_spi_dt_match),
},
.probe = rockchip_spi_probe,
- .remove_new = rockchip_spi_remove,
+ .remove = rockchip_spi_remove,
};
module_platform_driver(rockchip_spi_driver);
diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c
index 2f78124a1b59..6edc0c4db854 100644
--- a/drivers/spi/spi-rpc-if.c
+++ b/drivers/spi/spi-rpc-if.c
@@ -14,7 +14,7 @@
#include <memory/renesas-rpc-if.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
static void rpcif_spi_mem_prepare(struct spi_device *spi_dev,
const struct spi_mem_op *spi_op,
@@ -75,6 +75,19 @@ static bool rpcif_spi_mem_supports_op(struct spi_mem *mem,
return true;
}
+static ssize_t xspi_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, const void *buf)
+{
+ struct rpcif *rpc = spi_controller_get_devdata(desc->mem->spi->controller);
+
+ if (offs + desc->info.offset + len > U32_MAX)
+ return -EINVAL;
+
+ rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len);
+
+ return xspi_dirmap_write(rpc->dev, offs, len, buf);
+}
+
static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
@@ -95,16 +108,16 @@ static int rpcif_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc)
spi_controller_get_devdata(desc->mem->spi->controller);
if (desc->info.offset + desc->info.length > U32_MAX)
- return -ENOTSUPP;
+ return -EINVAL;
if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
- if (!rpc->dirmap && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN)
- return -ENOTSUPP;
+ if (!rpc->dirmap)
+ return -EOPNOTSUPP;
- if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT)
- return -ENOTSUPP;
+ if (!rpc->xspi && desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
+ return -EOPNOTSUPP;
return 0;
}
@@ -125,6 +138,7 @@ static const struct spi_controller_mem_ops rpcif_spi_mem_ops = {
.exec_op = rpcif_spi_mem_exec_op,
.dirmap_create = rpcif_spi_mem_dirmap_create,
.dirmap_read = rpcif_spi_mem_dirmap_read,
+ .dirmap_write = xspi_spi_mem_dirmap_write,
};
static int rpcif_spi_probe(struct platform_device *pdev)
@@ -134,7 +148,7 @@ static int rpcif_spi_probe(struct platform_device *pdev)
struct rpcif *rpc;
int error;
- ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*rpc));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*rpc));
if (!ctlr)
return -ENOMEM;
@@ -182,30 +196,37 @@ static void rpcif_spi_remove(struct platform_device *pdev)
pm_runtime_disable(rpc->dev);
}
-static int __maybe_unused rpcif_spi_suspend(struct device *dev)
+static int rpcif_spi_suspend(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
return spi_controller_suspend(ctlr);
}
-static int __maybe_unused rpcif_spi_resume(struct device *dev)
+static int rpcif_spi_resume(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
+ rpcif_hw_init(dev, false);
+
return spi_controller_resume(ctlr);
}
-static SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(rpcif_spi_pm_ops, rpcif_spi_suspend, rpcif_spi_resume);
+
+static const struct platform_device_id rpc_if_spi_id_table[] = {
+ { .name = "rpc-if-spi" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, rpc_if_spi_id_table);
static struct platform_driver rpcif_spi_driver = {
.probe = rpcif_spi_probe,
- .remove_new = rpcif_spi_remove,
+ .remove = rpcif_spi_remove,
+ .id_table = rpc_if_spi_id_table,
.driver = {
.name = "rpc-if-spi",
-#ifdef CONFIG_PM_SLEEP
- .pm = &rpcif_spi_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&rpcif_spi_pm_ops),
},
};
module_platform_driver(rpcif_spi_driver);
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 08ceebbaf69b..8e1d911b88b5 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -19,12 +19,11 @@
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/sh_dma.h>
#include <linux/spi/spi.h>
-#include <linux/spi/rspi.h>
#include <linux/spinlock.h>
#define RSPI_SPCR 0x00 /* Control Register */
@@ -1131,16 +1130,12 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev,
static int rspi_request_dma(struct device *dev, struct spi_controller *ctlr,
const struct resource *res)
{
- const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev);
unsigned int dma_tx_id, dma_rx_id;
if (dev->of_node) {
/* In the OF case we will get the slave IDs from the DT */
dma_tx_id = 0;
dma_rx_id = 0;
- } else if (rspi_pd && rspi_pd->dma_tx_id && rspi_pd->dma_rx_id) {
- dma_tx_id = rspi_pd->dma_tx_id;
- dma_rx_id = rspi_pd->dma_rx_id;
} else {
/* The driver assumes no error. */
return 0;
@@ -1290,11 +1285,10 @@ static int rspi_probe(struct platform_device *pdev)
struct spi_controller *ctlr;
struct rspi_data *rspi;
int ret;
- const struct rspi_plat_data *rspi_pd;
const struct spi_ops *ops;
unsigned long clksrc;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(struct rspi_data));
if (ctlr == NULL)
return -ENOMEM;
@@ -1305,11 +1299,7 @@ static int rspi_probe(struct platform_device *pdev)
goto error1;
} else {
ops = (struct spi_ops *)pdev->id_entry->driver_data;
- rspi_pd = dev_get_platdata(&pdev->dev);
- if (rspi_pd && rspi_pd->num_chipselect)
- ctlr->num_chipselect = rspi_pd->num_chipselect;
- else
- ctlr->num_chipselect = 2; /* default */
+ ctlr->num_chipselect = 2; /* default */
}
rspi = spi_controller_get_devdata(ctlr);
@@ -1317,8 +1307,7 @@ static int rspi_probe(struct platform_device *pdev)
rspi->ops = ops;
rspi->ctlr = ctlr;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rspi->addr = devm_ioremap_resource(&pdev->dev, res);
+ rspi->addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(rspi->addr)) {
ret = PTR_ERR(rspi->addr);
goto error1;
@@ -1415,7 +1404,6 @@ static const struct platform_device_id spi_driver_ids[] = {
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
-#ifdef CONFIG_PM_SLEEP
static int rspi_suspend(struct device *dev)
{
struct rspi_data *rspi = dev_get_drvdata(dev);
@@ -1430,19 +1418,15 @@ static int rspi_resume(struct device *dev)
return spi_controller_resume(rspi->ctlr);
}
-static SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume);
-#define DEV_PM_OPS &rspi_pm_ops
-#else
-#define DEV_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume);
static struct platform_driver rspi_driver = {
.probe = rspi_probe,
- .remove_new = rspi_remove,
+ .remove = rspi_remove,
.id_table = spi_driver_ids,
.driver = {
.name = "renesas_spi",
- .pm = DEV_PM_OPS,
+ .pm = pm_sleep_ptr(&rspi_pm_ops),
.of_match_table = of_match_ptr(rspi_of_match),
},
};
diff --git a/drivers/spi/spi-rzv2h-rspi.c b/drivers/spi/spi-rzv2h-rspi.c
new file mode 100644
index 000000000000..1db7e4e5d64e
--- /dev/null
+++ b/drivers/spi/spi-rzv2h-rspi.c
@@ -0,0 +1,687 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Renesas RZ/V2H Renesas Serial Peripheral Interface (RSPI)
+ *
+ * Copyright (C) 2025 Renesas Electronics Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/limits.h>
+#include <linux/log2.h>
+#include <linux/math.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
+
+/* Registers */
+#define RSPI_SPDR 0x00
+#define RSPI_SPCR 0x08
+#define RSPI_SPPCR 0x0e
+#define RSPI_SSLP 0x10
+#define RSPI_SPBR 0x11
+#define RSPI_SPSCR 0x13
+#define RSPI_SPCMD 0x14
+#define RSPI_SPDCR2 0x44
+#define RSPI_SPSR 0x52
+#define RSPI_SPSRC 0x6a
+#define RSPI_SPFCR 0x6c
+
+/* Register SPCR */
+#define RSPI_SPCR_BPEN BIT(31)
+#define RSPI_SPCR_MSTR BIT(30)
+#define RSPI_SPCR_SPRIE BIT(17)
+#define RSPI_SPCR_SCKASE BIT(12)
+#define RSPI_SPCR_SPE BIT(0)
+
+/* Register SPPCR */
+#define RSPI_SPPCR_SPLP2 BIT(1)
+
+/* Register SPBR */
+#define RSPI_SPBR_SPR_MIN 0
+#define RSPI_SPBR_SPR_PCLK_MIN 1
+#define RSPI_SPBR_SPR_MAX 255
+
+/* Register SPCMD */
+#define RSPI_SPCMD_SSLA GENMASK(25, 24)
+#define RSPI_SPCMD_SPB GENMASK(20, 16)
+#define RSPI_SPCMD_LSBF BIT(12)
+#define RSPI_SPCMD_SSLKP BIT(7)
+#define RSPI_SPCMD_BRDV GENMASK(3, 2)
+#define RSPI_SPCMD_CPOL BIT(1)
+#define RSPI_SPCMD_CPHA BIT(0)
+
+#define RSPI_SPCMD_BRDV_MIN 0
+#define RSPI_SPCMD_BRDV_MAX 3
+
+/* Register SPDCR2 */
+#define RSPI_SPDCR2_TTRG GENMASK(11, 8)
+#define RSPI_SPDCR2_RTRG GENMASK(3, 0)
+
+/* Register SPSR */
+#define RSPI_SPSR_SPRF BIT(15)
+
+/* Register RSPI_SPSRC */
+#define RSPI_SPSRC_CLEAR 0xfd80
+
+#define RSPI_RESET_NUM 2
+
+struct rzv2h_rspi_best_clock {
+ struct clk *clk;
+ unsigned long clk_rate;
+ unsigned long error;
+ u32 actual_hz;
+ u8 brdv;
+ u8 spr;
+};
+
+struct rzv2h_rspi_info {
+ void (*find_tclk_rate)(struct clk *clk, u32 hz, u8 spr_min, u8 spr_max,
+ struct rzv2h_rspi_best_clock *best_clk);
+ void (*find_pclk_rate)(struct clk *clk, u32 hz, u8 spr_low, u8 spr_high,
+ struct rzv2h_rspi_best_clock *best_clk);
+ const char *tclk_name;
+ unsigned int fifo_size;
+ unsigned int num_clks;
+};
+
+struct rzv2h_rspi_priv {
+ struct reset_control_bulk_data resets[RSPI_RESET_NUM];
+ struct spi_controller *controller;
+ const struct rzv2h_rspi_info *info;
+ void __iomem *base;
+ struct clk *tclk;
+ struct clk *pclk;
+ wait_queue_head_t wait;
+ unsigned int bytes_per_word;
+ u32 last_speed_hz;
+ u32 freq;
+ u16 status;
+ u8 spr;
+ u8 brdv;
+ bool use_pclk;
+};
+
+#define RZV2H_RSPI_TX(func, type) \
+static inline void rzv2h_rspi_tx_##type(struct rzv2h_rspi_priv *rspi, \
+ const void *txbuf, \
+ unsigned int index) { \
+ type buf = 0; \
+ \
+ if (txbuf) \
+ buf = ((type *)txbuf)[index]; \
+ \
+ func(buf, rspi->base + RSPI_SPDR); \
+}
+
+#define RZV2H_RSPI_RX(func, type) \
+static inline void rzv2h_rspi_rx_##type(struct rzv2h_rspi_priv *rspi, \
+ void *rxbuf, \
+ unsigned int index) { \
+ type buf = func(rspi->base + RSPI_SPDR); \
+ \
+ if (rxbuf) \
+ ((type *)rxbuf)[index] = buf; \
+}
+
+RZV2H_RSPI_TX(writel, u32)
+RZV2H_RSPI_TX(writew, u16)
+RZV2H_RSPI_TX(writeb, u8)
+RZV2H_RSPI_RX(readl, u32)
+RZV2H_RSPI_RX(readw, u16)
+RZV2H_RSPI_RX(readl, u8)
+
+static void rzv2h_rspi_reg_rmw(const struct rzv2h_rspi_priv *rspi,
+ int reg_offs, u32 bit_mask, u32 value)
+{
+ u32 tmp;
+
+ value <<= __ffs(bit_mask);
+ tmp = (readl(rspi->base + reg_offs) & ~bit_mask) | value;
+ writel(tmp, rspi->base + reg_offs);
+}
+
+static inline void rzv2h_rspi_spe_disable(const struct rzv2h_rspi_priv *rspi)
+{
+ rzv2h_rspi_reg_rmw(rspi, RSPI_SPCR, RSPI_SPCR_SPE, 0);
+}
+
+static inline void rzv2h_rspi_spe_enable(const struct rzv2h_rspi_priv *rspi)
+{
+ rzv2h_rspi_reg_rmw(rspi, RSPI_SPCR, RSPI_SPCR_SPE, 1);
+}
+
+static inline void rzv2h_rspi_clear_fifos(const struct rzv2h_rspi_priv *rspi)
+{
+ writeb(1, rspi->base + RSPI_SPFCR);
+}
+
+static inline void rzv2h_rspi_clear_all_irqs(struct rzv2h_rspi_priv *rspi)
+{
+ writew(RSPI_SPSRC_CLEAR, rspi->base + RSPI_SPSRC);
+ rspi->status = 0;
+}
+
+static irqreturn_t rzv2h_rx_irq_handler(int irq, void *data)
+{
+ struct rzv2h_rspi_priv *rspi = data;
+
+ rspi->status = readw(rspi->base + RSPI_SPSR);
+ wake_up(&rspi->wait);
+
+ return IRQ_HANDLED;
+}
+
+static inline int rzv2h_rspi_wait_for_interrupt(struct rzv2h_rspi_priv *rspi,
+ u32 wait_mask)
+{
+ return wait_event_timeout(rspi->wait, (rspi->status & wait_mask),
+ HZ) == 0 ? -ETIMEDOUT : 0;
+}
+
+static void rzv2h_rspi_send(struct rzv2h_rspi_priv *rspi, const void *txbuf,
+ unsigned int index)
+{
+ switch (rspi->bytes_per_word) {
+ case 4:
+ rzv2h_rspi_tx_u32(rspi, txbuf, index);
+ break;
+ case 2:
+ rzv2h_rspi_tx_u16(rspi, txbuf, index);
+ break;
+ default:
+ rzv2h_rspi_tx_u8(rspi, txbuf, index);
+ }
+}
+
+static int rzv2h_rspi_receive(struct rzv2h_rspi_priv *rspi, void *rxbuf,
+ unsigned int index)
+{
+ int ret;
+
+ ret = rzv2h_rspi_wait_for_interrupt(rspi, RSPI_SPSR_SPRF);
+ if (ret)
+ return ret;
+
+ switch (rspi->bytes_per_word) {
+ case 4:
+ rzv2h_rspi_rx_u32(rspi, rxbuf, index);
+ break;
+ case 2:
+ rzv2h_rspi_rx_u16(rspi, rxbuf, index);
+ break;
+ default:
+ rzv2h_rspi_rx_u8(rspi, rxbuf, index);
+ }
+
+ return 0;
+}
+
+static int rzv2h_rspi_transfer_one(struct spi_controller *controller,
+ struct spi_device *spi,
+ struct spi_transfer *transfer)
+{
+ struct rzv2h_rspi_priv *rspi = spi_controller_get_devdata(controller);
+ unsigned int words_to_transfer, i;
+ int ret = 0;
+
+ transfer->effective_speed_hz = rspi->freq;
+ words_to_transfer = transfer->len / rspi->bytes_per_word;
+
+ for (i = 0; i < words_to_transfer; i++) {
+ rzv2h_rspi_clear_all_irqs(rspi);
+
+ rzv2h_rspi_send(rspi, transfer->tx_buf, i);
+
+ ret = rzv2h_rspi_receive(rspi, transfer->rx_buf, i);
+ if (ret)
+ break;
+ }
+
+ rzv2h_rspi_clear_all_irqs(rspi);
+
+ if (ret)
+ transfer->error = SPI_TRANS_FAIL_IO;
+
+ spi_finalize_current_transfer(controller);
+
+ return ret;
+}
+
+static inline u32 rzv2h_rspi_calc_bitrate(unsigned long tclk_rate, u8 spr,
+ u8 brdv)
+{
+ return DIV_ROUND_UP(tclk_rate, (2 * (spr + 1) * (1 << brdv)));
+}
+
+static void rzv2h_rspi_find_rate_variable(struct clk *clk, u32 hz,
+ u8 spr_min, u8 spr_max,
+ struct rzv2h_rspi_best_clock *best)
+{
+ long clk_rate, clk_min_rate, clk_max_rate;
+ int min_rate_spr, max_rate_spr;
+ unsigned long error;
+ u32 actual_hz;
+ u8 brdv;
+ int spr;
+
+ /*
+ * On T2H / N2H, the source for the SPI clock is PCLKSPIn, which is a
+ * 1/32, 1/30, 1/25 or 1/24 divider of PLL4, which is 2400MHz,
+ * resulting in either 75MHz, 80MHz, 96MHz or 100MHz.
+ */
+ clk_min_rate = clk_round_rate(clk, 0);
+ if (clk_min_rate < 0)
+ return;
+
+ clk_max_rate = clk_round_rate(clk, ULONG_MAX);
+ if (clk_max_rate < 0)
+ return;
+
+ /*
+ * From the manual:
+ * Bit rate = f(PCLKSPIn) / (2 * (n + 1) * 2^N)
+ *
+ * If we adapt it to the current context, we get the following:
+ * hz = rate / ((spr + 1) * (1 << (brdv + 1)))
+ *
+ * This can be written in multiple forms depending on what we want to
+ * determine.
+ *
+ * To find the rate, having hz, spr and brdv:
+ * rate = hz * (spr + 1) * (1 << (brdv + 1)
+ *
+ * To find the spr, having rate, hz, and spr:
+ * spr = rate / (hz * (1 << (brdv + 1)) - 1
+ */
+
+ for (brdv = RSPI_SPCMD_BRDV_MIN; brdv <= RSPI_SPCMD_BRDV_MAX; brdv++) {
+ /* Calculate the divisor needed to find the SPR from a rate. */
+ u32 rate_div = hz * (1 << (brdv + 1));
+
+ /*
+ * If the SPR for the minimum rate is greater than the maximum
+ * allowed value skip this BRDV. The divisor increases with each
+ * BRDV iteration, so the following BRDV might result in a
+ * minimum SPR that is in the valid range.
+ */
+ min_rate_spr = DIV_ROUND_CLOSEST(clk_min_rate, rate_div) - 1;
+ if (min_rate_spr > spr_max)
+ continue;
+
+ /*
+ * If the SPR for the maximum rate is less than the minimum
+ * allowed value, exit. The divisor only increases with each
+ * BRDV iteration, so the following BRDV cannot result in a
+ * maximum SPR that is in the valid range.
+ */
+ max_rate_spr = DIV_ROUND_CLOSEST(clk_max_rate, rate_div) - 1;
+ if (max_rate_spr < spr_min)
+ break;
+
+ if (min_rate_spr < spr_min)
+ min_rate_spr = spr_min;
+
+ if (max_rate_spr > spr_max)
+ max_rate_spr = spr_max;
+
+ for (spr = min_rate_spr; spr <= max_rate_spr; spr++) {
+ clk_rate = (spr + 1) * rate_div;
+
+ clk_rate = clk_round_rate(clk, clk_rate);
+ if (clk_rate <= 0)
+ continue;
+
+ actual_hz = rzv2h_rspi_calc_bitrate(clk_rate, spr, brdv);
+ error = abs((long)hz - (long)actual_hz);
+
+ if (error >= best->error)
+ continue;
+
+ *best = (struct rzv2h_rspi_best_clock) {
+ .clk = clk,
+ .clk_rate = clk_rate,
+ .error = error,
+ .actual_hz = actual_hz,
+ .brdv = brdv,
+ .spr = spr,
+ };
+
+ if (!error)
+ return;
+ }
+ }
+}
+
+static void rzv2h_rspi_find_rate_fixed(struct clk *clk, u32 hz,
+ u8 spr_min, u8 spr_max,
+ struct rzv2h_rspi_best_clock *best)
+{
+ unsigned long clk_rate;
+ unsigned long error;
+ u32 actual_hz;
+ int spr;
+ u8 brdv;
+
+ /*
+ * From the manual:
+ * Bit rate = f(RSPI_n_TCLK)/(2*(n+1)*2^(N))
+ *
+ * Where:
+ * * RSPI_n_TCLK is fixed to 200MHz on V2H
+ * * n = SPR - is RSPI_SPBR.SPR (from 0 to 255)
+ * * N = BRDV - is RSPI_SPCMD.BRDV (from 0 to 3)
+ */
+ clk_rate = clk_get_rate(clk);
+ for (brdv = RSPI_SPCMD_BRDV_MIN; brdv <= RSPI_SPCMD_BRDV_MAX; brdv++) {
+ spr = DIV_ROUND_UP(clk_rate, hz * (1 << (brdv + 1)));
+ spr--;
+ if (spr >= spr_min && spr <= spr_max)
+ goto clock_found;
+ }
+
+ return;
+
+clock_found:
+ actual_hz = rzv2h_rspi_calc_bitrate(clk_rate, spr, brdv);
+ error = abs((long)hz - (long)actual_hz);
+
+ if (error >= best->error)
+ return;
+
+ *best = (struct rzv2h_rspi_best_clock) {
+ .clk = clk,
+ .clk_rate = clk_rate,
+ .error = error,
+ .actual_hz = actual_hz,
+ .brdv = brdv,
+ .spr = spr,
+ };
+}
+
+static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz)
+{
+ struct rzv2h_rspi_best_clock best_clock = {
+ .error = ULONG_MAX,
+ };
+ int ret;
+
+ rspi->info->find_tclk_rate(rspi->tclk, hz, RSPI_SPBR_SPR_MIN,
+ RSPI_SPBR_SPR_MAX, &best_clock);
+
+ /*
+ * T2H and N2H can also use PCLK as a source, which is 125MHz, but not
+ * when both SPR and BRDV are 0.
+ */
+ if (best_clock.error && rspi->info->find_pclk_rate)
+ rspi->info->find_pclk_rate(rspi->pclk, hz, RSPI_SPBR_SPR_PCLK_MIN,
+ RSPI_SPBR_SPR_MAX, &best_clock);
+
+ if (!best_clock.clk_rate)
+ return -EINVAL;
+
+ ret = clk_set_rate(best_clock.clk, best_clock.clk_rate);
+ if (ret)
+ return 0;
+
+ rspi->use_pclk = best_clock.clk == rspi->pclk;
+ rspi->spr = best_clock.spr;
+ rspi->brdv = best_clock.brdv;
+
+ return best_clock.actual_hz;
+}
+
+static int rzv2h_rspi_prepare_message(struct spi_controller *ctlr,
+ struct spi_message *message)
+{
+ struct rzv2h_rspi_priv *rspi = spi_controller_get_devdata(ctlr);
+ const struct spi_device *spi = message->spi;
+ struct spi_transfer *xfer;
+ u32 speed_hz = U32_MAX;
+ u8 bits_per_word;
+ u32 conf32;
+ u16 conf16;
+ u8 conf8;
+
+ /* Make sure SPCR.SPE is 0 before amending the configuration */
+ rzv2h_rspi_spe_disable(rspi);
+
+ list_for_each_entry(xfer, &message->transfers, transfer_list) {
+ if (!xfer->speed_hz)
+ continue;
+
+ speed_hz = min(xfer->speed_hz, speed_hz);
+ bits_per_word = xfer->bits_per_word;
+ }
+
+ if (speed_hz == U32_MAX)
+ return -EINVAL;
+
+ rspi->bytes_per_word = roundup_pow_of_two(BITS_TO_BYTES(bits_per_word));
+
+ if (speed_hz != rspi->last_speed_hz) {
+ rspi->freq = rzv2h_rspi_setup_clock(rspi, speed_hz);
+ if (!rspi->freq)
+ return -EINVAL;
+
+ rspi->last_speed_hz = speed_hz;
+ }
+
+ writeb(rspi->spr, rspi->base + RSPI_SPBR);
+
+ /* Configure the device to work in "host" mode */
+ conf32 = RSPI_SPCR_MSTR;
+
+ /* Auto-stop function */
+ conf32 |= RSPI_SPCR_SCKASE;
+
+ /* SPI receive buffer full interrupt enable */
+ conf32 |= RSPI_SPCR_SPRIE;
+
+ /* Bypass synchronization circuit */
+ conf32 |= FIELD_PREP(RSPI_SPCR_BPEN, rspi->use_pclk);
+
+ writel(conf32, rspi->base + RSPI_SPCR);
+
+ /* Use SPCMD0 only */
+ writeb(0x0, rspi->base + RSPI_SPSCR);
+
+ /* Setup loopback */
+ conf8 = FIELD_PREP(RSPI_SPPCR_SPLP2, !!(spi->mode & SPI_LOOP));
+ writeb(conf8, rspi->base + RSPI_SPPCR);
+
+ /* Setup mode */
+ conf32 = FIELD_PREP(RSPI_SPCMD_CPOL, !!(spi->mode & SPI_CPOL));
+ conf32 |= FIELD_PREP(RSPI_SPCMD_CPHA, !!(spi->mode & SPI_CPHA));
+ conf32 |= FIELD_PREP(RSPI_SPCMD_LSBF, !!(spi->mode & SPI_LSB_FIRST));
+ conf32 |= FIELD_PREP(RSPI_SPCMD_SPB, bits_per_word - 1);
+ conf32 |= FIELD_PREP(RSPI_SPCMD_BRDV, rspi->brdv);
+ conf32 |= FIELD_PREP(RSPI_SPCMD_SSLKP, 1);
+ conf32 |= FIELD_PREP(RSPI_SPCMD_SSLA, spi_get_chipselect(spi, 0));
+ writel(conf32, rspi->base + RSPI_SPCMD);
+ if (spi->mode & SPI_CS_HIGH)
+ writeb(BIT(spi_get_chipselect(spi, 0)), rspi->base + RSPI_SSLP);
+ else
+ writeb(0, rspi->base + RSPI_SSLP);
+
+ /* Setup FIFO thresholds */
+ conf16 = FIELD_PREP(RSPI_SPDCR2_TTRG, rspi->info->fifo_size - 1);
+ conf16 |= FIELD_PREP(RSPI_SPDCR2_RTRG, 0);
+ writew(conf16, rspi->base + RSPI_SPDCR2);
+
+ rzv2h_rspi_clear_fifos(rspi);
+
+ rzv2h_rspi_spe_enable(rspi);
+
+ return 0;
+}
+
+static int rzv2h_rspi_unprepare_message(struct spi_controller *ctlr,
+ struct spi_message *message)
+{
+ struct rzv2h_rspi_priv *rspi = spi_controller_get_devdata(ctlr);
+
+ rzv2h_rspi_spe_disable(rspi);
+
+ return 0;
+}
+
+static int rzv2h_rspi_probe(struct platform_device *pdev)
+{
+ struct spi_controller *controller;
+ struct device *dev = &pdev->dev;
+ struct rzv2h_rspi_priv *rspi;
+ struct clk_bulk_data *clks;
+ int irq_rx, ret, i;
+ long tclk_rate;
+
+ controller = devm_spi_alloc_host(dev, sizeof(*rspi));
+ if (!controller)
+ return -ENOMEM;
+
+ rspi = spi_controller_get_devdata(controller);
+ platform_set_drvdata(pdev, rspi);
+
+ rspi->controller = controller;
+
+ rspi->info = device_get_match_data(dev);
+
+ rspi->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(rspi->base))
+ return PTR_ERR(rspi->base);
+
+ ret = devm_clk_bulk_get_all_enabled(dev, &clks);
+ if (ret != rspi->info->num_clks)
+ return dev_err_probe(dev, ret >= 0 ? -EINVAL : ret,
+ "cannot get clocks\n");
+ for (i = 0; i < rspi->info->num_clks; i++) {
+ if (!strcmp(clks[i].id, rspi->info->tclk_name)) {
+ rspi->tclk = clks[i].clk;
+ } else if (rspi->info->find_pclk_rate &&
+ !strcmp(clks[i].id, "pclk")) {
+ rspi->pclk = clks[i].clk;
+ }
+ }
+
+ if (!rspi->tclk)
+ return dev_err_probe(dev, -EINVAL, "Failed to get tclk\n");
+
+ rspi->resets[0].id = "presetn";
+ rspi->resets[1].id = "tresetn";
+ ret = devm_reset_control_bulk_get_optional_exclusive(dev, RSPI_RESET_NUM,
+ rspi->resets);
+ if (ret)
+ return dev_err_probe(dev, ret, "cannot get resets\n");
+
+ irq_rx = platform_get_irq_byname(pdev, "rx");
+ if (irq_rx < 0)
+ return dev_err_probe(dev, irq_rx, "cannot get IRQ 'rx'\n");
+
+ ret = reset_control_bulk_deassert(RSPI_RESET_NUM, rspi->resets);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to deassert resets\n");
+
+ init_waitqueue_head(&rspi->wait);
+
+ ret = devm_request_irq(dev, irq_rx, rzv2h_rx_irq_handler, 0,
+ dev_name(dev), rspi);
+ if (ret) {
+ dev_err(dev, "cannot request `rx` IRQ\n");
+ goto quit_resets;
+ }
+
+ controller->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
+ SPI_LSB_FIRST | SPI_LOOP;
+ controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ controller->prepare_message = rzv2h_rspi_prepare_message;
+ controller->unprepare_message = rzv2h_rspi_unprepare_message;
+ controller->num_chipselect = 4;
+ controller->transfer_one = rzv2h_rspi_transfer_one;
+
+ tclk_rate = clk_round_rate(rspi->tclk, 0);
+ if (tclk_rate < 0) {
+ ret = tclk_rate;
+ goto quit_resets;
+ }
+
+ controller->min_speed_hz = rzv2h_rspi_calc_bitrate(tclk_rate,
+ RSPI_SPBR_SPR_MAX,
+ RSPI_SPCMD_BRDV_MAX);
+
+ tclk_rate = clk_round_rate(rspi->tclk, ULONG_MAX);
+ if (tclk_rate < 0) {
+ ret = tclk_rate;
+ goto quit_resets;
+ }
+
+ controller->max_speed_hz = rzv2h_rspi_calc_bitrate(tclk_rate,
+ RSPI_SPBR_SPR_MIN,
+ RSPI_SPCMD_BRDV_MIN);
+
+ device_set_node(&controller->dev, dev_fwnode(dev));
+
+ ret = spi_register_controller(controller);
+ if (ret) {
+ dev_err(dev, "register controller failed\n");
+ goto quit_resets;
+ }
+
+ return 0;
+
+quit_resets:
+ reset_control_bulk_assert(RSPI_RESET_NUM, rspi->resets);
+
+ return ret;
+}
+
+static void rzv2h_rspi_remove(struct platform_device *pdev)
+{
+ struct rzv2h_rspi_priv *rspi = platform_get_drvdata(pdev);
+
+ spi_unregister_controller(rspi->controller);
+
+ reset_control_bulk_assert(RSPI_RESET_NUM, rspi->resets);
+}
+
+static const struct rzv2h_rspi_info rzv2h_info = {
+ .find_tclk_rate = rzv2h_rspi_find_rate_fixed,
+ .tclk_name = "tclk",
+ .fifo_size = 16,
+ .num_clks = 3,
+};
+
+static const struct rzv2h_rspi_info rzt2h_info = {
+ .find_tclk_rate = rzv2h_rspi_find_rate_variable,
+ .find_pclk_rate = rzv2h_rspi_find_rate_fixed,
+ .tclk_name = "pclkspi",
+ .fifo_size = 4,
+ .num_clks = 2,
+};
+
+static const struct of_device_id rzv2h_rspi_match[] = {
+ { .compatible = "renesas,r9a09g057-rspi", &rzv2h_info },
+ { .compatible = "renesas,r9a09g077-rspi", &rzt2h_info },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzv2h_rspi_match);
+
+static struct platform_driver rzv2h_rspi_drv = {
+ .probe = rzv2h_rspi_probe,
+ .remove = rzv2h_rspi_remove,
+ .driver = {
+ .name = "rzv2h_rspi",
+ .of_match_table = rzv2h_rspi_match,
+ },
+};
+module_platform_driver(rzv2h_rspi_drv);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>");
+MODULE_DESCRIPTION("Renesas RZ/V2H(P) Serial Peripheral Interface Driver");
diff --git a/drivers/spi/spi-rzv2m-csi.c b/drivers/spi/spi-rzv2m-csi.c
index 14ad65da930d..7c0442883ac0 100644
--- a/drivers/spi/spi-rzv2m-csi.c
+++ b/drivers/spi/spi-rzv2m-csi.c
@@ -5,13 +5,18 @@
* Copyright (C) 2023 Renesas Electronics Corporation
*/
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/count_zeros.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
+#include <linux/log2.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
+#include <linux/units.h>
/* Registers */
#define CSI_MODE 0x00 /* CSI mode control */
@@ -34,8 +39,12 @@
#define CSI_MODE_SETUP 0x00000040
/* CSI_CLKSEL */
+#define CSI_CLKSEL_SS_ENA BIT(19)
+#define CSI_CLKSEL_SS_POL BIT(18)
+#define CSI_CLKSEL_SS (CSI_CLKSEL_SS_ENA | CSI_CLKSEL_SS_POL)
#define CSI_CLKSEL_CKP BIT(17)
#define CSI_CLKSEL_DAP BIT(16)
+#define CSI_CLKSEL_MODE (CSI_CLKSEL_CKP|CSI_CLKSEL_DAP)
#define CSI_CLKSEL_SLAVE BIT(15)
#define CSI_CLKSEL_CKS GENMASK(14, 1)
@@ -60,17 +69,26 @@
/* CSI_FIFOTRG */
#define CSI_FIFOTRG_R_TRG GENMASK(2, 0)
-#define CSI_FIFO_SIZE_BYTES 32
-#define CSI_FIFO_HALF_SIZE 16
+#define CSI_FIFO_SIZE_BYTES 32U
+#define CSI_FIFO_HALF_SIZE 16U
#define CSI_EN_DIS_TIMEOUT_US 100
-#define CSI_CKS_MAX 0x3FFF
+/*
+ * Clock "csiclk" gets divided by 2 * CSI_CLKSEL_CKS in order to generate the
+ * serial clock (output from master), with CSI_CLKSEL_CKS ranging from 0x1 (that
+ * means "csiclk" is divided by 2) to 0x3FFF ("csiclk" is divided by 32766).
+ */
+#define CSI_CKS_MAX GENMASK(13, 0)
#define UNDERRUN_ERROR BIT(0)
#define OVERFLOW_ERROR BIT(1)
#define TX_TIMEOUT_ERROR BIT(2)
#define RX_TIMEOUT_ERROR BIT(3)
-#define CSI_MAX_SPI_SCKO 8000000
+#define CSI_MAX_SPI_SCKO (8 * HZ_PER_MHZ)
+
+#define CSI_CLKSEL_SS_DISABLED 0
+#define CSI_CLKSEL_SS_ENABLED_ACTIVE_LOW BIT(1)
+#define CSI_CLKSEL_SS_ENABLED_ACTIVE_HIGH GENMASK(1, 0)
struct rzv2m_csi_priv {
void __iomem *base;
@@ -78,31 +96,19 @@ struct rzv2m_csi_priv {
struct clk *pclk;
struct device *dev;
struct spi_controller *controller;
- const u8 *txbuf;
- u8 *rxbuf;
- int buffer_len;
- int bytes_sent;
- int bytes_received;
- int bytes_to_transfer;
- int words_to_transfer;
- unsigned char bytes_per_word;
+ const void *txbuf;
+ void *rxbuf;
+ unsigned int buffer_len;
+ unsigned int bytes_sent;
+ unsigned int bytes_received;
+ unsigned int bytes_to_transfer;
+ unsigned int words_to_transfer;
+ unsigned int bytes_per_word;
wait_queue_head_t wait;
- u8 errors;
+ u32 errors;
u32 status;
-};
-
-static const unsigned char x_trg[] = {
- 0, 1, 1, 2, 2, 2, 2, 3,
- 3, 3, 3, 3, 3, 3, 3, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 5
-};
-
-static const unsigned char x_trg_words[] = {
- 1, 2, 2, 4, 4, 4, 4, 8,
- 8, 8, 8, 8, 8, 8, 8, 16,
- 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 32
+ bool target_aborted;
+ bool use_ss_pin;
};
static void rzv2m_csi_reg_write_bit(const struct rzv2m_csi_priv *csi,
@@ -124,13 +130,12 @@ static int rzv2m_csi_sw_reset(struct rzv2m_csi_priv *csi, int assert)
rzv2m_csi_reg_write_bit(csi, CSI_CNT, CSI_CNT_CSIRST, assert);
- if (assert) {
- return readl_poll_timeout(csi->base + CSI_MODE, reg,
- !(reg & CSI_MODE_CSOT), 0,
- CSI_EN_DIS_TIMEOUT_US);
- }
+ if (!assert)
+ return 0;
- return 0;
+ return readl_poll_timeout(csi->base + CSI_MODE, reg,
+ !(reg & CSI_MODE_CSOT), 0,
+ CSI_EN_DIS_TIMEOUT_US);
}
static int rzv2m_csi_start_stop_operation(const struct rzv2m_csi_priv *csi,
@@ -140,28 +145,28 @@ static int rzv2m_csi_start_stop_operation(const struct rzv2m_csi_priv *csi,
rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_CSIE, enable);
- if (!enable && wait)
- return readl_poll_timeout(csi->base + CSI_MODE, reg,
- !(reg & CSI_MODE_CSOT), 0,
- CSI_EN_DIS_TIMEOUT_US);
+ if (enable || !wait)
+ return 0;
- return 0;
+ return readl_poll_timeout(csi->base + CSI_MODE, reg,
+ !(reg & CSI_MODE_CSOT), 0,
+ CSI_EN_DIS_TIMEOUT_US);
}
static int rzv2m_csi_fill_txfifo(struct rzv2m_csi_priv *csi)
{
- int i;
+ unsigned int i;
if (readl(csi->base + CSI_OFIFOL))
return -EIO;
if (csi->bytes_per_word == 2) {
- u16 *buf = (u16 *)csi->txbuf;
+ const u16 *buf = csi->txbuf;
for (i = 0; i < csi->words_to_transfer; i++)
writel(buf[i], csi->base + CSI_OFIFO);
} else {
- u8 *buf = (u8 *)csi->txbuf;
+ const u8 *buf = csi->txbuf;
for (i = 0; i < csi->words_to_transfer; i++)
writel(buf[i], csi->base + CSI_OFIFO);
@@ -175,18 +180,18 @@ static int rzv2m_csi_fill_txfifo(struct rzv2m_csi_priv *csi)
static int rzv2m_csi_read_rxfifo(struct rzv2m_csi_priv *csi)
{
- int i;
+ unsigned int i;
if (readl(csi->base + CSI_IFIFOL) != csi->bytes_to_transfer)
return -EIO;
if (csi->bytes_per_word == 2) {
- u16 *buf = (u16 *)csi->rxbuf;
+ u16 *buf = csi->rxbuf;
for (i = 0; i < csi->words_to_transfer; i++)
buf[i] = (u16)readl(csi->base + CSI_IFIFO);
} else {
- u8 *buf = (u8 *)csi->rxbuf;
+ u8 *buf = csi->rxbuf;
for (i = 0; i < csi->words_to_transfer; i++)
buf[i] = (u8)readl(csi->base + CSI_IFIFO);
@@ -198,11 +203,19 @@ static int rzv2m_csi_read_rxfifo(struct rzv2m_csi_priv *csi)
return 0;
}
+static inline void rzv2m_csi_empty_rxfifo(struct rzv2m_csi_priv *csi)
+{
+ unsigned int i;
+
+ for (i = 0; i < csi->words_to_transfer; i++)
+ readl(csi->base + CSI_IFIFO);
+}
+
static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
{
- int bytes_transferred = max_t(int, csi->bytes_received, csi->bytes_sent);
- int bytes_remaining = csi->buffer_len - bytes_transferred;
- int to_transfer;
+ unsigned int bytes_transferred = max(csi->bytes_received, csi->bytes_sent);
+ unsigned int bytes_remaining = csi->buffer_len - bytes_transferred;
+ unsigned int to_transfer;
if (csi->txbuf)
/*
@@ -210,9 +223,9 @@ static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
* hard to raise an overflow error (which is only possible
* when IP transmits and receives at the same time).
*/
- to_transfer = min_t(int, CSI_FIFO_HALF_SIZE, bytes_remaining);
+ to_transfer = min(CSI_FIFO_HALF_SIZE, bytes_remaining);
else
- to_transfer = min_t(int, CSI_FIFO_SIZE_BYTES, bytes_remaining);
+ to_transfer = min(CSI_FIFO_SIZE_BYTES, bytes_remaining);
if (csi->bytes_per_word == 2)
to_transfer >>= 1;
@@ -223,7 +236,7 @@ static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
* less than or equal to the number of bytes we need to transfer.
* This may result in multiple smaller transfers.
*/
- csi->words_to_transfer = x_trg_words[to_transfer - 1];
+ csi->words_to_transfer = rounddown_pow_of_two(to_transfer);
if (csi->bytes_per_word == 2)
csi->bytes_to_transfer = csi->words_to_transfer << 1;
@@ -234,7 +247,7 @@ static inline void rzv2m_csi_calc_current_transfer(struct rzv2m_csi_priv *csi)
static inline void rzv2m_csi_set_rx_fifo_trigger_level(struct rzv2m_csi_priv *csi)
{
rzv2m_csi_reg_write_bit(csi, CSI_FIFOTRG, CSI_FIFOTRG_R_TRG,
- x_trg[csi->words_to_transfer - 1]);
+ ilog2(csi->words_to_transfer));
}
static inline void rzv2m_csi_enable_rx_trigger(struct rzv2m_csi_priv *csi,
@@ -284,33 +297,23 @@ static int rzv2m_csi_wait_for_interrupt(struct rzv2m_csi_priv *csi,
rzv2m_csi_enable_irqs(csi, enable_bits);
- ret = wait_event_timeout(csi->wait,
- ((csi->status & wait_mask) == wait_mask) ||
- csi->errors, HZ);
+ if (spi_controller_is_target(csi->controller)) {
+ ret = wait_event_interruptible(csi->wait,
+ ((csi->status & wait_mask) == wait_mask) ||
+ csi->errors || csi->target_aborted);
+ if (ret || csi->target_aborted)
+ ret = -EINTR;
+ } else {
+ ret = wait_event_timeout(csi->wait,
+ ((csi->status & wait_mask) == wait_mask) ||
+ csi->errors, HZ) == 0 ? -ETIMEDOUT : 0;
+ }
rzv2m_csi_disable_irqs(csi, enable_bits);
if (csi->errors)
return -EIO;
- if (!ret)
- return -ETIMEDOUT;
-
- return 0;
-}
-
-static int rzv2m_csi_wait_for_tx_empty(struct rzv2m_csi_priv *csi)
-{
- int ret;
-
- if (readl(csi->base + CSI_OFIFOL) == 0)
- return 0;
-
- ret = rzv2m_csi_wait_for_interrupt(csi, CSI_INT_TREND, CSI_CNT_TREND_E);
-
- if (ret == -ETIMEDOUT)
- csi->errors |= TX_TIMEOUT_ERROR;
-
return ret;
}
@@ -318,12 +321,11 @@ static inline int rzv2m_csi_wait_for_rx_ready(struct rzv2m_csi_priv *csi)
{
int ret;
- if (readl(csi->base + CSI_IFIFOL) == csi->bytes_to_transfer)
+ if (readl(csi->base + CSI_IFIFOL) >= csi->bytes_to_transfer)
return 0;
ret = rzv2m_csi_wait_for_interrupt(csi, CSI_INT_R_TRGR,
CSI_CNT_R_TRGR_E);
-
if (ret == -ETIMEDOUT)
csi->errors |= RX_TIMEOUT_ERROR;
@@ -332,7 +334,7 @@ static inline int rzv2m_csi_wait_for_rx_ready(struct rzv2m_csi_priv *csi)
static irqreturn_t rzv2m_csi_irq_handler(int irq, void *data)
{
- struct rzv2m_csi_priv *csi = (struct rzv2m_csi_priv *)data;
+ struct rzv2m_csi_priv *csi = data;
csi->status = readl(csi->base + CSI_INT);
rzv2m_csi_disable_irqs(csi, csi->status);
@@ -395,6 +397,7 @@ static void rzv2m_csi_setup_operating_mode(struct rzv2m_csi_priv *csi,
static int rzv2m_csi_setup(struct spi_device *spi)
{
struct rzv2m_csi_priv *csi = spi_controller_get_devdata(spi->controller);
+ u32 slave_selection = CSI_CLKSEL_SS_DISABLED;
int ret;
rzv2m_csi_sw_reset(csi, 0);
@@ -402,17 +405,24 @@ static int rzv2m_csi_setup(struct spi_device *spi)
writel(CSI_MODE_SETUP, csi->base + CSI_MODE);
/* Setup clock polarity and phase timing */
- rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_CKP,
- !(spi->mode & SPI_CPOL));
- rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_DAP,
- !(spi->mode & SPI_CPHA));
+ rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_MODE,
+ ~spi->mode & SPI_MODE_X_MASK);
/* Setup serial data order */
rzv2m_csi_reg_write_bit(csi, CSI_MODE, CSI_MODE_DIR,
!!(spi->mode & SPI_LSB_FIRST));
- /* Set the operation mode as master */
- rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_SLAVE, 0);
+ /* Set the role, 1 for target and 0 for host */
+ rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_SLAVE,
+ !!spi_controller_is_target(csi->controller));
+
+ if (csi->use_ss_pin)
+ slave_selection = spi->mode & SPI_CS_HIGH ?
+ CSI_CLKSEL_SS_ENABLED_ACTIVE_HIGH :
+ CSI_CLKSEL_SS_ENABLED_ACTIVE_LOW;
+
+ /* Configure the slave selection (SS) pin */
+ rzv2m_csi_reg_write_bit(csi, CSI_CLKSEL, CSI_CLKSEL_SS, slave_selection);
/* Give the IP a SW reset */
ret = rzv2m_csi_sw_reset(csi, 1);
@@ -433,16 +443,20 @@ static int rzv2m_csi_setup(struct spi_device *spi)
static int rzv2m_csi_pio_transfer(struct rzv2m_csi_priv *csi)
{
- bool tx_completed = csi->txbuf ? false : true;
- bool rx_completed = csi->rxbuf ? false : true;
+ bool tx_completed = !csi->txbuf;
+ bool rx_completed = !csi->rxbuf;
int ret = 0;
/* Make sure the TX FIFO is empty */
writel(0, csi->base + CSI_OFIFOL);
+ /* Make sure the RX FIFO is empty */
+ writel(0, csi->base + CSI_IFIFOL);
+
csi->bytes_sent = 0;
csi->bytes_received = 0;
csi->errors = 0;
+ csi->target_aborted = false;
rzv2m_csi_disable_all_irqs(csi);
rzv2m_csi_clear_all_irqs(csi);
@@ -461,28 +475,21 @@ static int rzv2m_csi_pio_transfer(struct rzv2m_csi_priv *csi)
rzv2m_csi_enable_irqs(csi, CSI_INT_OVERF | CSI_INT_UNDER);
- /* Make sure the RX FIFO is empty */
- writel(0, csi->base + CSI_IFIFOL);
-
writel(readl(csi->base + CSI_INT), csi->base + CSI_INT);
csi->status = 0;
- rzv2m_csi_start_stop_operation(csi, 1, false);
-
/* TX */
if (csi->txbuf) {
ret = rzv2m_csi_fill_txfifo(csi);
if (ret)
break;
- ret = rzv2m_csi_wait_for_tx_empty(csi);
- if (ret)
- break;
-
if (csi->bytes_sent == csi->buffer_len)
tx_completed = true;
}
+ rzv2m_csi_start_stop_operation(csi, 1, false);
+
/*
* Make sure the RX FIFO contains the desired number of words.
* We then either flush its content, or we copy it onto
@@ -492,31 +499,28 @@ static int rzv2m_csi_pio_transfer(struct rzv2m_csi_priv *csi)
if (ret)
break;
- /* RX */
- if (csi->rxbuf) {
+ if (!spi_controller_is_target(csi->controller))
rzv2m_csi_start_stop_operation(csi, 0, false);
+ /* RX */
+ if (csi->rxbuf) {
ret = rzv2m_csi_read_rxfifo(csi);
if (ret)
break;
if (csi->bytes_received == csi->buffer_len)
rx_completed = true;
+ } else {
+ rzv2m_csi_empty_rxfifo(csi);
}
- ret = rzv2m_csi_start_stop_operation(csi, 0, true);
- if (ret)
- goto pio_quit;
-
if (csi->errors) {
ret = -EIO;
- goto pio_quit;
+ break;
}
}
rzv2m_csi_start_stop_operation(csi, 0, true);
-
-pio_quit:
rzv2m_csi_disable_all_irqs(csi);
rzv2m_csi_enable_rx_trigger(csi, false);
rzv2m_csi_clear_all_irqs(csi);
@@ -538,7 +542,8 @@ static int rzv2m_csi_transfer_one(struct spi_controller *controller,
rzv2m_csi_setup_operating_mode(csi, transfer);
- rzv2m_csi_setup_clock(csi, transfer->speed_hz);
+ if (!spi_controller_is_target(csi->controller))
+ rzv2m_csi_setup_clock(csi, transfer->speed_hz);
ret = rzv2m_csi_pio_transfer(csi);
if (ret) {
@@ -555,24 +560,48 @@ static int rzv2m_csi_transfer_one(struct spi_controller *controller,
return ret;
}
+static int rzv2m_csi_target_abort(struct spi_controller *ctlr)
+{
+ struct rzv2m_csi_priv *csi = spi_controller_get_devdata(ctlr);
+
+ csi->target_aborted = true;
+ wake_up(&csi->wait);
+
+ return 0;
+}
+
static int rzv2m_csi_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct spi_controller *controller;
struct device *dev = &pdev->dev;
struct rzv2m_csi_priv *csi;
struct reset_control *rstc;
+ bool target_mode;
int irq;
int ret;
- controller = devm_spi_alloc_master(dev, sizeof(*csi));
+ target_mode = of_property_read_bool(np, "spi-slave");
+
+ if (target_mode)
+ controller = devm_spi_alloc_target(dev, sizeof(*csi));
+ else
+ controller = devm_spi_alloc_host(dev, sizeof(*csi));
+
if (!controller)
return -ENOMEM;
csi = spi_controller_get_devdata(controller);
platform_set_drvdata(pdev, csi);
+ csi->use_ss_pin = false;
+ if (spi_controller_is_target(controller) &&
+ !of_property_read_bool(np, "renesas,csi-no-ss"))
+ csi->use_ss_pin = true;
+
csi->dev = dev;
csi->controller = controller;
+ csi->target_aborted = false;
csi->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(csi->base))
@@ -598,12 +627,14 @@ static int rzv2m_csi_probe(struct platform_device *pdev)
init_waitqueue_head(&csi->wait);
- controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
- controller->dev.of_node = pdev->dev.of_node;
+ controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH;
controller->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
controller->setup = rzv2m_csi_setup;
controller->transfer_one = rzv2m_csi_transfer_one;
controller->use_gpio_descriptors = true;
+ controller->target_abort = rzv2m_csi_target_abort;
+
+ device_set_node(&controller->dev, dev_fwnode(dev));
ret = devm_request_irq(dev, irq, rzv2m_csi_irq_handler, 0,
dev_name(dev), csi);
@@ -635,15 +666,13 @@ static int rzv2m_csi_probe(struct platform_device *pdev)
return 0;
}
-static int rzv2m_csi_remove(struct platform_device *pdev)
+static void rzv2m_csi_remove(struct platform_device *pdev)
{
struct rzv2m_csi_priv *csi = platform_get_drvdata(pdev);
spi_unregister_controller(csi->controller);
rzv2m_csi_sw_reset(csi, 1);
clk_disable_unprepare(csi->csiclk);
-
- return 0;
}
static const struct of_device_id rzv2m_csi_match[] = {
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index b6c2659a66ca..aab36c779c06 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -3,20 +3,22 @@
// Copyright (c) 2009 Samsung Electronics Co., Ltd.
// Jaswinder Singh <jassi.brar@samsung.com>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_data/spi-s3c64xx.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-
-#include <linux/platform_data/spi-s3c64xx.h>
+#include <linux/types.h>
#define MAX_SPI_PORTS 12
#define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1)
@@ -77,6 +79,9 @@
#define S3C64XX_SPI_INT_RX_FIFORDY_EN (1<<1)
#define S3C64XX_SPI_INT_TX_FIFORDY_EN (1<<0)
+#define S3C64XX_SPI_ST_RX_FIFO_RDY_V2 GENMASK(23, 15)
+#define S3C64XX_SPI_ST_TX_FIFO_RDY_V2 GENMASK(14, 6)
+#define S3C64XX_SPI_ST_TX_FIFO_LVL_SHIFT 6
#define S3C64XX_SPI_ST_RX_OVERRUN_ERR (1<<5)
#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4)
#define S3C64XX_SPI_ST_TX_OVERRUN_ERR (1<<3)
@@ -107,15 +112,15 @@
#define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id])
#define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \
(1 << (i)->port_conf->tx_st_done)) ? 1 : 0)
-#define TX_FIFO_LVL(v, i) (((v) >> 6) & FIFO_LVL_MASK(i))
-#define RX_FIFO_LVL(v, i) (((v) >> (i)->port_conf->rx_lvl_offset) & \
- FIFO_LVL_MASK(i))
+#define TX_FIFO_LVL(v, sdd) (((v) & (sdd)->tx_fifomask) >> \
+ __ffs((sdd)->tx_fifomask))
+#define RX_FIFO_LVL(v, sdd) (((v) & (sdd)->rx_fifomask) >> \
+ __ffs((sdd)->rx_fifomask))
+#define FIFO_DEPTH(i) ((FIFO_LVL_MASK(i) >> 1) + 1)
#define S3C64XX_SPI_MAX_TRAILCNT 0x3ff
#define S3C64XX_SPI_TRAILCNT_OFF 19
-#define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT
-
#define S3C64XX_SPI_POLLING_SIZE 32
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
@@ -132,8 +137,15 @@ struct s3c64xx_spi_dma_data {
/**
* struct s3c64xx_spi_port_config - SPI Controller hardware info
- * @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register.
- * @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter.
+ * @fifo_lvl_mask: [DEPRECATED] use @{rx, tx}_fifomask instead.
+ * @rx_lvl_offset: [DEPRECATED] use @{rx,tx}_fifomask instead.
+ * @fifo_depth: depth of the FIFOs. Used by compatibles where all the instances
+ * of the IP define the same FIFO depth. It has higher precedence
+ * than the FIFO depth specified via DT.
+ * @rx_fifomask: SPI_STATUS.RX_FIFO_LVL mask. Shifted mask defining the field's
+ * length and position.
+ * @tx_fifomask: SPI_STATUS.TX_FIFO_LVL mask. Shifted mask defining the field's
+ * length and position.
* @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter.
* @clk_div: Internal clock divider
* @quirks: Bitmask of known quirks
@@ -142,6 +154,7 @@ struct s3c64xx_spi_dma_data {
* prescaler unit.
* @clk_ioclk: True if clock is present on this device
* @has_loopback: True if loopback mode can be supported
+ * @use_32bit_io: True if the SoC allows only 32-bit register accesses.
*
* The Samsung s3c64xx SPI controller are used on various Samsung SoC's but
* differ in some aspects such as the size of the fifo and spi bus clock
@@ -151,6 +164,9 @@ struct s3c64xx_spi_dma_data {
struct s3c64xx_spi_port_config {
int fifo_lvl_mask[MAX_SPI_PORTS];
int rx_lvl_offset;
+ unsigned int fifo_depth;
+ u32 rx_fifomask;
+ u32 tx_fifomask;
int tx_st_done;
int quirks;
int clk_div;
@@ -158,15 +174,16 @@ struct s3c64xx_spi_port_config {
bool clk_from_cmu;
bool clk_ioclk;
bool has_loopback;
+ bool use_32bit_io;
};
/**
* struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
* @clk: Pointer to the spi clock.
* @src_clk: Pointer to the clock used to generate SPI signals.
- * @ioclk: Pointer to the i/o clock between master and slave
+ * @ioclk: Pointer to the i/o clock between host and target
* @pdev: Pointer to device's platform device data
- * @master: Pointer to the SPI Protocol master.
+ * @host: Pointer to the SPI Protocol host.
* @cntrlr_info: Platform specific data for the controller this driver manages.
* @lock: Controller specific lock.
* @state: Set of FLAGS to indicate status.
@@ -178,8 +195,13 @@ struct s3c64xx_spi_port_config {
* @cur_speed: Current clock speed
* @rx_dma: Local receive DMA data (e.g. chan and direction)
* @tx_dma: Local transmit DMA data (e.g. chan and direction)
- * @port_conf: Local SPI port configuartion data
- * @port_id: Port identification number
+ * @port_conf: Local SPI port configuration data
+ * @port_id: [DEPRECATED] use @{rx,tx}_fifomask instead.
+ * @fifo_depth: depth of the FIFO.
+ * @rx_fifomask: SPI_STATUS.RX_FIFO_LVL mask. Shifted mask defining the field's
+ * length and position.
+ * @tx_fifomask: SPI_STATUS.TX_FIFO_LVL mask. Shifted mask defining the field's
+ * length and position.
*/
struct s3c64xx_spi_driver_data {
void __iomem *regs;
@@ -187,7 +209,7 @@ struct s3c64xx_spi_driver_data {
struct clk *src_clk;
struct clk *ioclk;
struct platform_device *pdev;
- struct spi_master *master;
+ struct spi_controller *host;
struct s3c64xx_spi_info *cntrlr_info;
spinlock_t lock;
unsigned long sfr_start;
@@ -199,6 +221,9 @@ struct s3c64xx_spi_driver_data {
struct s3c64xx_spi_dma_data tx_dma;
const struct s3c64xx_spi_port_config *port_conf;
unsigned int port_id;
+ unsigned int fifo_depth;
+ u32 rx_fifomask;
+ u32 tx_fifomask;
};
static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd)
@@ -222,7 +247,7 @@ static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd)
loops = msecs_to_loops(1);
do {
val = readl(regs + S3C64XX_SPI_STATUS);
- } while (TX_FIFO_LVL(val, sdd) && loops--);
+ } while (TX_FIFO_LVL(val, sdd) && --loops);
if (loops == 0)
dev_warn(&sdd->pdev->dev, "Timed out flushing TX FIFO\n");
@@ -235,7 +260,7 @@ static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd)
readl(regs + S3C64XX_SPI_RX_DATA);
else
break;
- } while (loops--);
+ } while (--loops);
if (loops == 0)
dev_warn(&sdd->pdev->dev, "Timed out flushing RX FIFO\n");
@@ -277,8 +302,8 @@ static void s3c64xx_spi_dmacb(void *data)
spin_unlock_irqrestore(&sdd->lock, flags);
}
-static int prepare_dma(struct s3c64xx_spi_dma_data *dma,
- struct sg_table *sgt)
+static int s3c64xx_prepare_dma(struct s3c64xx_spi_dma_data *dma,
+ struct sg_table *sgt)
{
struct s3c64xx_spi_driver_data *sdd;
struct dma_slave_config config;
@@ -290,20 +315,20 @@ static int prepare_dma(struct s3c64xx_spi_dma_data *dma,
if (dma->direction == DMA_DEV_TO_MEM) {
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, rx_dma);
- config.direction = dma->direction;
config.src_addr = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
config.src_addr_width = sdd->cur_bpw / 8;
config.src_maxburst = 1;
- dmaengine_slave_config(dma->ch, &config);
} else {
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, tx_dma);
- config.direction = dma->direction;
config.dst_addr = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
config.dst_addr_width = sdd->cur_bpw / 8;
config.dst_maxburst = 1;
- dmaengine_slave_config(dma->ch, &config);
}
+ config.direction = dma->direction;
+ ret = dmaengine_slave_config(dma->ch, &config);
+ if (ret)
+ return ret;
desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents,
dma->direction, DMA_PREP_INTERRUPT);
@@ -320,7 +345,7 @@ static int prepare_dma(struct s3c64xx_spi_dma_data *dma,
ret = dma_submit_error(dma->cookie);
if (ret) {
dev_err(&sdd->pdev->dev, "DMA submission failed");
- return -EIO;
+ return ret;
}
dma_async_issue_pending(dma->ch);
@@ -330,7 +355,7 @@ static int prepare_dma(struct s3c64xx_spi_dma_data *dma,
static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
{
struct s3c64xx_spi_driver_data *sdd =
- spi_master_get_devdata(spi->master);
+ spi_controller_get_devdata(spi->controller);
if (sdd->cntrlr_info->no_cs)
return;
@@ -352,9 +377,9 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
}
}
-static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
+static int s3c64xx_spi_prepare_transfer(struct spi_controller *spi)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(spi);
if (is_polling(sdd))
return 0;
@@ -382,9 +407,9 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
return 0;
}
-static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
+static int s3c64xx_spi_unprepare_transfer(struct spi_controller *spi)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(spi);
if (is_polling(sdd))
return 0;
@@ -400,18 +425,66 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
return 0;
}
-static bool s3c64xx_spi_can_dma(struct spi_master *master,
+static bool s3c64xx_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
- if (sdd->rx_dma.ch && sdd->tx_dma.ch) {
- return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
- } else {
- return false;
+ if (sdd->rx_dma.ch && sdd->tx_dma.ch)
+ return xfer->len >= sdd->fifo_depth;
+
+ return false;
+}
+
+static void s3c64xx_iowrite8_32_rep(volatile void __iomem *addr,
+ const void *buffer, unsigned int count)
+{
+ if (count) {
+ const u8 *buf = buffer;
+
+ do {
+ __raw_writel(*buf++, addr);
+ } while (--count);
+ }
+}
+
+static void s3c64xx_iowrite16_32_rep(volatile void __iomem *addr,
+ const void *buffer, unsigned int count)
+{
+ if (count) {
+ const u16 *buf = buffer;
+
+ do {
+ __raw_writel(*buf++, addr);
+ } while (--count);
}
+}
+
+static void s3c64xx_iowrite_rep(const struct s3c64xx_spi_driver_data *sdd,
+ struct spi_transfer *xfer)
+{
+ void __iomem *addr = sdd->regs + S3C64XX_SPI_TX_DATA;
+ const void *buf = xfer->tx_buf;
+ unsigned int len = xfer->len;
+ switch (sdd->cur_bpw) {
+ case 32:
+ iowrite32_rep(addr, buf, len / 4);
+ break;
+ case 16:
+ if (sdd->port_conf->use_32bit_io)
+ s3c64xx_iowrite16_32_rep(addr, buf, len / 2);
+ else
+ iowrite16_rep(addr, buf, len / 2);
+ break;
+ default:
+ if (sdd->port_conf->use_32bit_io)
+ s3c64xx_iowrite8_32_rep(addr, buf, len);
+ else
+ iowrite8_rep(addr, buf, len);
+ break;
+ }
}
static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd,
@@ -445,22 +518,9 @@ static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd,
chcfg |= S3C64XX_SPI_CH_TXCH_ON;
if (dma_mode) {
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
- ret = prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
+ ret = s3c64xx_prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
} else {
- switch (sdd->cur_bpw) {
- case 32:
- iowrite32_rep(regs + S3C64XX_SPI_TX_DATA,
- xfer->tx_buf, xfer->len / 4);
- break;
- case 16:
- iowrite16_rep(regs + S3C64XX_SPI_TX_DATA,
- xfer->tx_buf, xfer->len / 2);
- break;
- default:
- iowrite8_rep(regs + S3C64XX_SPI_TX_DATA,
- xfer->tx_buf, xfer->len);
- break;
- }
+ s3c64xx_iowrite_rep(sdd, xfer);
}
}
@@ -477,7 +537,7 @@ static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
| S3C64XX_SPI_PACKET_CNT_EN,
regs + S3C64XX_SPI_PACKET_CNT);
- ret = prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
+ ret = s3c64xx_prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
}
}
@@ -496,9 +556,7 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
void __iomem *regs = sdd->regs;
unsigned long val = 1;
u32 status;
-
- /* max fifo depth available */
- u32 max_fifo = (FIFO_LVL_MASK(sdd) >> 1) + 1;
+ u32 max_fifo = sdd->fifo_depth;
if (timeout_ms)
val = msecs_to_loops(timeout_ms);
@@ -529,7 +587,7 @@ static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
/*
* If the previous xfer was completed within timeout, then
- * proceed further else return -EIO.
+ * proceed further else return -ETIMEDOUT.
* DmaTx returns after simply writing data in the FIFO,
* w/o waiting for real transmission on the bus to finish.
* DmaRx returns only after Dma read data from FIFO which
@@ -550,7 +608,7 @@ static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
/* If timed out while checking rx/tx status return error */
if (!val)
- return -EIO;
+ return -ETIMEDOUT;
return 0;
}
@@ -580,7 +638,7 @@ static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
if (use_irq) {
val = msecs_to_jiffies(ms);
if (!wait_for_completion_timeout(&sdd->xfer_completion, val))
- return -EIO;
+ return -ETIMEDOUT;
}
val = msecs_to_loops(ms);
@@ -605,7 +663,7 @@ static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
* For any size less than the fifo size the below code is
* executed atleast once.
*/
- loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
+ loops = xfer->len / sdd->fifo_depth;
buf = xfer->rx_buf;
do {
/* wait for data to be received in the fifo */
@@ -713,10 +771,10 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
#define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
-static int s3c64xx_spi_prepare_message(struct spi_master *master,
+static int s3c64xx_spi_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
@@ -737,12 +795,12 @@ static size_t s3c64xx_spi_max_transfer_size(struct spi_device *spi)
return ctlr->can_dma ? S3C64XX_SPI_PACKET_CNT_MASK : SIZE_MAX;
}
-static int s3c64xx_spi_transfer_one(struct spi_master *master,
+static int s3c64xx_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
- const unsigned int fifo_len = (FIFO_LVL_MASK(sdd) >> 1) + 1;
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
+ const unsigned int fifo_len = sdd->fifo_depth;
const void *tx_buf = NULL;
void *rx_buf = NULL;
int target_len = 0, origin_len = 0;
@@ -770,10 +828,9 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
return status;
}
- if (!is_polling(sdd) && (xfer->len > fifo_len) &&
+ if (!is_polling(sdd) && xfer->len >= fifo_len &&
sdd->rx_dma.ch && sdd->tx_dma.ch) {
use_dma = 1;
-
} else if (xfer->len >= fifo_len) {
tx_buf = xfer->tx_buf;
rx_buf = xfer->rx_buf;
@@ -891,15 +948,15 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
return status;
}
-static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
+static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata(
struct spi_device *spi)
{
struct s3c64xx_spi_csinfo *cs;
- struct device_node *slave_np, *data_np = NULL;
+ struct device_node *target_np;
u32 fb_delay = 0;
- slave_np = spi->dev.of_node;
- if (!slave_np) {
+ target_np = spi->dev.of_node;
+ if (!target_np) {
dev_err(&spi->dev, "device node not found\n");
return ERR_PTR(-EINVAL);
}
@@ -908,7 +965,8 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
if (!cs)
return ERR_PTR(-ENOMEM);
- data_np = of_get_child_by_name(slave_np, "controller-data");
+ struct device_node *data_np __free(device_node) =
+ of_get_child_by_name(target_np, "controller-data");
if (!data_np) {
dev_info(&spi->dev, "feedback delay set to default (0)\n");
return cs;
@@ -916,7 +974,6 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay);
cs->fb_delay = fb_delay;
- of_node_put(data_np);
return cs;
}
@@ -933,9 +990,9 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
int err;
int div;
- sdd = spi_master_get_devdata(spi->master);
+ sdd = spi_controller_get_devdata(spi->controller);
if (spi->dev.of_node) {
- cs = s3c64xx_get_slave_ctrldata(spi);
+ cs = s3c64xx_get_target_ctrldata(spi);
spi->controller_data = cs;
}
@@ -988,14 +1045,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
}
}
- pm_runtime_mark_last_busy(&sdd->pdev->dev);
pm_runtime_put_autosuspend(&sdd->pdev->dev);
s3c64xx_spi_set_cs(spi, false);
return 0;
setup_exit:
- pm_runtime_mark_last_busy(&sdd->pdev->dev);
pm_runtime_put_autosuspend(&sdd->pdev->dev);
/* setup() returns with device de-selected */
s3c64xx_spi_set_cs(spi, false);
@@ -1023,7 +1078,7 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi)
static irqreturn_t s3c64xx_spi_irq(int irq, void *data)
{
struct s3c64xx_spi_driver_data *sdd = data;
- struct spi_master *spi = sdd->master;
+ struct spi_controller *spi = sdd->host;
unsigned int val, clr = 0;
val = readl(sdd->regs + S3C64XX_SPI_STATUS);
@@ -1094,8 +1149,7 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd)
val = readl(regs + S3C64XX_SPI_MODE_CFG);
val &= ~S3C64XX_SPI_MODE_4BURST;
- val &= ~(S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
- val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
+ val |= (S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
writel(val, regs + S3C64XX_SPI_MODE_CFG);
s3c64xx_flush_fifo(sdd);
@@ -1112,14 +1166,14 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
return ERR_PTR(-ENOMEM);
if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) {
- dev_warn(dev, "spi bus clock parent not specified, using clock at index 0 as parent\n");
+ dev_dbg(dev, "spi bus clock parent not specified, using clock at index 0 as parent\n");
sci->src_clk_nr = 0;
} else {
sci->src_clk_nr = temp;
}
if (of_property_read_u32(dev->of_node, "num-cs", &temp)) {
- dev_warn(dev, "number of chip select lines not specified, assuming 1 chip select line\n");
+ dev_dbg(dev, "number of chip select lines not specified, assuming 1 chip select line\n");
sci->num_cs = 1;
} else {
sci->num_cs = temp;
@@ -1147,12 +1201,54 @@ static inline const struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
return (const struct s3c64xx_spi_port_config *)platform_get_device_id(pdev)->driver_data;
}
+static int s3c64xx_spi_set_port_id(struct platform_device *pdev,
+ struct s3c64xx_spi_driver_data *sdd)
+{
+ const struct s3c64xx_spi_port_config *port_conf = sdd->port_conf;
+ int ret;
+
+ if (port_conf->rx_fifomask && port_conf->tx_fifomask)
+ return 0;
+
+ if (pdev->dev.of_node) {
+ ret = of_alias_get_id(pdev->dev.of_node, "spi");
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to get alias id\n");
+ sdd->port_id = ret;
+ } else {
+ if (pdev->id < 0)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Negative platform ID is not allowed\n");
+ sdd->port_id = pdev->id;
+ }
+
+ return 0;
+}
+
+static void s3c64xx_spi_set_fifomask(struct s3c64xx_spi_driver_data *sdd)
+{
+ const struct s3c64xx_spi_port_config *port_conf = sdd->port_conf;
+
+ if (port_conf->rx_fifomask)
+ sdd->rx_fifomask = port_conf->rx_fifomask;
+ else
+ sdd->rx_fifomask = FIFO_LVL_MASK(sdd) <<
+ port_conf->rx_lvl_offset;
+
+ if (port_conf->tx_fifomask)
+ sdd->tx_fifomask = port_conf->tx_fifomask;
+ else
+ sdd->tx_fifomask = FIFO_LVL_MASK(sdd) <<
+ S3C64XX_SPI_ST_TX_FIFO_LVL_SHIFT;
+}
+
static int s3c64xx_spi_probe(struct platform_device *pdev)
{
struct resource *mem_res;
struct s3c64xx_spi_driver_data *sdd;
struct s3c64xx_spi_info *sci = dev_get_platdata(&pdev->dev);
- struct spi_master *master;
+ struct spi_controller *host;
int ret, irq;
char clk_name[16];
@@ -1166,68 +1262,65 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, -ENODEV,
"Platform_data missing!\n");
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res)
- return dev_err_probe(&pdev->dev, -ENXIO,
- "Unable to get SPI MEM resource\n");
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
- return dev_err_probe(&pdev->dev, irq, "Failed to get IRQ\n");
+ return irq;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*sdd));
- if (!master)
- return dev_err_probe(&pdev->dev, -ENOMEM,
- "Unable to allocate SPI Master\n");
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*sdd));
+ if (!host)
+ return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- sdd = spi_master_get_devdata(master);
+ sdd = spi_controller_get_devdata(host);
sdd->port_conf = s3c64xx_spi_get_port_config(pdev);
- sdd->master = master;
+ sdd->host = host;
sdd->cntrlr_info = sci;
sdd->pdev = pdev;
- sdd->sfr_start = mem_res->start;
- if (pdev->dev.of_node) {
- ret = of_alias_get_id(pdev->dev.of_node, "spi");
- if (ret < 0)
- return dev_err_probe(&pdev->dev, ret,
- "Failed to get alias id\n");
- sdd->port_id = ret;
- } else {
- sdd->port_id = pdev->id;
- }
+
+ ret = s3c64xx_spi_set_port_id(pdev, sdd);
+ if (ret)
+ return ret;
+
+ if (sdd->port_conf->fifo_depth)
+ sdd->fifo_depth = sdd->port_conf->fifo_depth;
+ else if (of_property_read_u32(pdev->dev.of_node, "fifo-depth",
+ &sdd->fifo_depth))
+ sdd->fifo_depth = FIFO_DEPTH(sdd);
+
+ s3c64xx_spi_set_fifomask(sdd);
sdd->cur_bpw = 8;
sdd->tx_dma.direction = DMA_MEM_TO_DEV;
sdd->rx_dma.direction = DMA_DEV_TO_MEM;
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = sdd->port_id;
- master->setup = s3c64xx_spi_setup;
- master->cleanup = s3c64xx_spi_cleanup;
- master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
- master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
- master->prepare_message = s3c64xx_spi_prepare_message;
- master->transfer_one = s3c64xx_spi_transfer_one;
- master->max_transfer_size = s3c64xx_spi_max_transfer_size;
- master->num_chipselect = sci->num_cs;
- master->use_gpio_descriptors = true;
- master->dma_alignment = 8;
- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
- SPI_BPW_MASK(8);
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = -1;
+ host->setup = s3c64xx_spi_setup;
+ host->cleanup = s3c64xx_spi_cleanup;
+ host->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
+ host->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
+ host->prepare_message = s3c64xx_spi_prepare_message;
+ host->transfer_one = s3c64xx_spi_transfer_one;
+ host->max_transfer_size = s3c64xx_spi_max_transfer_size;
+ host->num_chipselect = sci->num_cs;
+ host->use_gpio_descriptors = true;
+ host->dma_alignment = 8;
+ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
if (sdd->port_conf->has_loopback)
- master->mode_bits |= SPI_LOOP;
- master->auto_runtime_pm = true;
+ host->mode_bits |= SPI_LOOP;
+ host->auto_runtime_pm = true;
if (!is_polling(sdd))
- master->can_dma = s3c64xx_spi_can_dma;
+ host->can_dma = s3c64xx_spi_can_dma;
- sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
+ sdd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
if (IS_ERR(sdd->regs))
return PTR_ERR(sdd->regs);
+ sdd->sfr_start = mem_res->start;
if (sci->cfg_gpio && sci->cfg_gpio())
return dev_err_probe(&pdev->dev, -EBUSY,
@@ -1259,7 +1352,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- /* Setup Deufult Mode */
+ /* Setup Default Mode */
s3c64xx_spi_hwinit(sdd);
spin_lock_init(&sdd->lock);
@@ -1277,18 +1370,17 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
sdd->regs + S3C64XX_SPI_INT_EN);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret != 0) {
- dev_err(&pdev->dev, "cannot register SPI master: %d\n", ret);
+ dev_err(&pdev->dev, "cannot register SPI host: %d\n", ret);
goto err_pm_put;
}
- dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
- sdd->port_id, master->num_chipselect);
+ dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Targets attached\n",
+ host->bus_num, host->num_chipselect);
dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\n",
- mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1);
+ mem_res, sdd->fifo_depth);
- pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
@@ -1303,8 +1395,8 @@ err_pm_put:
static void s3c64xx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
pm_runtime_get_sync(&pdev->dev);
@@ -1323,10 +1415,11 @@ static void s3c64xx_spi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int s3c64xx_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
+ int ret;
- int ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -1341,8 +1434,8 @@ static int s3c64xx_spi_suspend(struct device *dev)
static int s3c64xx_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
int ret;
@@ -1353,15 +1446,15 @@ static int s3c64xx_spi_resume(struct device *dev)
if (ret < 0)
return ret;
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int s3c64xx_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
clk_disable_unprepare(sdd->clk);
clk_disable_unprepare(sdd->src_clk);
@@ -1372,8 +1465,8 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev)
static int s3c64xx_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);
int ret;
if (sdd->port_conf->clk_ioclk) {
@@ -1413,23 +1506,19 @@ static const struct dev_pm_ops s3c64xx_spi_pm = {
s3c64xx_spi_runtime_resume, NULL)
};
-static const struct s3c64xx_spi_port_config s3c2443_spi_port_config = {
- .fifo_lvl_mask = { 0x7f },
- .rx_lvl_offset = 13,
- .tx_st_done = 21,
- .clk_div = 2,
- .high_speed = true,
-};
-
static const struct s3c64xx_spi_port_config s3c6410_spi_port_config = {
+ /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */
.fifo_lvl_mask = { 0x7f, 0x7F },
+ /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */
.rx_lvl_offset = 13,
.tx_st_done = 21,
.clk_div = 2,
};
static const struct s3c64xx_spi_port_config s5pv210_spi_port_config = {
+ /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */
.fifo_lvl_mask = { 0x1ff, 0x7F },
+ /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */
.rx_lvl_offset = 15,
.tx_st_done = 25,
.clk_div = 2,
@@ -1437,7 +1526,9 @@ static const struct s3c64xx_spi_port_config s5pv210_spi_port_config = {
};
static const struct s3c64xx_spi_port_config exynos4_spi_port_config = {
+ /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */
.fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F },
+ /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */
.rx_lvl_offset = 15,
.tx_st_done = 25,
.clk_div = 2,
@@ -1447,7 +1538,9 @@ static const struct s3c64xx_spi_port_config exynos4_spi_port_config = {
};
static const struct s3c64xx_spi_port_config exynos7_spi_port_config = {
+ /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */
.fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff},
+ /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */
.rx_lvl_offset = 15,
.tx_st_done = 25,
.clk_div = 2,
@@ -1457,7 +1550,9 @@ static const struct s3c64xx_spi_port_config exynos7_spi_port_config = {
};
static const struct s3c64xx_spi_port_config exynos5433_spi_port_config = {
+ /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */
.fifo_lvl_mask = { 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff},
+ /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */
.rx_lvl_offset = 15,
.tx_st_done = 25,
.clk_div = 2,
@@ -1467,9 +1562,23 @@ static const struct s3c64xx_spi_port_config exynos5433_spi_port_config = {
.quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
};
+static const struct s3c64xx_spi_port_config exynos850_spi_port_config = {
+ .fifo_depth = 64,
+ .rx_fifomask = S3C64XX_SPI_ST_RX_FIFO_RDY_V2,
+ .tx_fifomask = S3C64XX_SPI_ST_TX_FIFO_RDY_V2,
+ .tx_st_done = 25,
+ .clk_div = 4,
+ .high_speed = true,
+ .clk_from_cmu = true,
+ .has_loopback = true,
+ .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
+};
+
static const struct s3c64xx_spi_port_config exynosautov9_spi_port_config = {
+ /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */
.fifo_lvl_mask = { 0x1ff, 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f},
+ /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */
.rx_lvl_offset = 15,
.tx_st_done = 25,
.clk_div = 4,
@@ -1481,7 +1590,9 @@ static const struct s3c64xx_spi_port_config exynosautov9_spi_port_config = {
};
static const struct s3c64xx_spi_port_config fsd_spi_port_config = {
+ /* fifo_lvl_mask is deprecated. Use {rx, tx}_fifomask instead. */
.fifo_lvl_mask = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f},
+ /* rx_lvl_offset is deprecated. Use {rx, tx}_fifomask instead. */
.rx_lvl_offset = 15,
.tx_st_done = 25,
.clk_div = 2,
@@ -1491,41 +1602,55 @@ static const struct s3c64xx_spi_port_config fsd_spi_port_config = {
.quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
};
+static const struct s3c64xx_spi_port_config gs101_spi_port_config = {
+ .fifo_depth = 64,
+ .rx_fifomask = S3C64XX_SPI_ST_RX_FIFO_RDY_V2,
+ .tx_fifomask = S3C64XX_SPI_ST_TX_FIFO_RDY_V2,
+ .tx_st_done = 25,
+ .clk_div = 4,
+ .high_speed = true,
+ .clk_from_cmu = true,
+ .has_loopback = true,
+ .use_32bit_io = true,
+ .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
+};
+
static const struct platform_device_id s3c64xx_spi_driver_ids[] = {
{
- .name = "s3c2443-spi",
- .driver_data = (kernel_ulong_t)&s3c2443_spi_port_config,
- }, {
.name = "s3c6410-spi",
.driver_data = (kernel_ulong_t)&s3c6410_spi_port_config,
},
{ },
};
+MODULE_DEVICE_TABLE(platform, s3c64xx_spi_driver_ids);
static const struct of_device_id s3c64xx_spi_dt_match[] = {
- { .compatible = "samsung,s3c2443-spi",
- .data = (void *)&s3c2443_spi_port_config,
+ { .compatible = "google,gs101-spi",
+ .data = &gs101_spi_port_config,
},
{ .compatible = "samsung,s3c6410-spi",
- .data = (void *)&s3c6410_spi_port_config,
+ .data = &s3c6410_spi_port_config,
},
{ .compatible = "samsung,s5pv210-spi",
- .data = (void *)&s5pv210_spi_port_config,
+ .data = &s5pv210_spi_port_config,
},
{ .compatible = "samsung,exynos4210-spi",
- .data = (void *)&exynos4_spi_port_config,
+ .data = &exynos4_spi_port_config,
},
{ .compatible = "samsung,exynos7-spi",
- .data = (void *)&exynos7_spi_port_config,
+ .data = &exynos7_spi_port_config,
},
{ .compatible = "samsung,exynos5433-spi",
- .data = (void *)&exynos5433_spi_port_config,
+ .data = &exynos5433_spi_port_config,
+ },
+ { .compatible = "samsung,exynos850-spi",
+ .data = &exynos850_spi_port_config,
},
{ .compatible = "samsung,exynosautov9-spi",
- .data = (void *)&exynosautov9_spi_port_config,
+ .data = &exynosautov9_spi_port_config,
},
{ .compatible = "tesla,fsd-spi",
- .data = (void *)&fsd_spi_port_config,
+ .data = &fsd_spi_port_config,
},
{ },
};
@@ -1538,7 +1663,7 @@ static struct platform_driver s3c64xx_spi_driver = {
.of_match_table = of_match_ptr(s3c64xx_spi_dt_match),
},
.probe = s3c64xx_spi_probe,
- .remove_new = s3c64xx_spi_remove,
+ .remove = s3c64xx_spi_remove,
.id_table = s3c64xx_spi_driver_ids,
};
MODULE_ALIAS("platform:s3c64xx-spi");
diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c
index d52ed67243f7..1627aa66c965 100644
--- a/drivers/spi/spi-sc18is602.c
+++ b/drivers/spi/spi-sc18is602.c
@@ -7,14 +7,15 @@
#include <linux/kernel.h>
#include <linux/err.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
-#include <linux/of_device.h>
-#include <linux/of.h>
#include <linux/platform_data/sc18is602.h>
+#include <linux/property.h>
+
#include <linux/gpio/consumer.h>
enum chips { sc18is602, sc18is602b, sc18is603 };
@@ -31,7 +32,7 @@ enum chips { sc18is602, sc18is602b, sc18is603 };
#define SC18IS602_MODE_CLOCK_DIV_128 0x3
struct sc18is602 {
- struct spi_master *master;
+ struct spi_controller *host;
struct device *dev;
u8 ctrl;
u32 freq;
@@ -180,10 +181,10 @@ static int sc18is602_check_transfer(struct spi_device *spi,
return 0;
}
-static int sc18is602_transfer_one(struct spi_master *master,
+static int sc18is602_transfer_one(struct spi_controller *host,
struct spi_message *m)
{
- struct sc18is602 *hw = spi_master_get_devdata(master);
+ struct sc18is602 *hw = spi_controller_get_devdata(host);
struct spi_device *spi = m->spi;
struct spi_transfer *t;
int status = 0;
@@ -214,7 +215,7 @@ static int sc18is602_transfer_one(struct spi_master *master,
spi_transfer_delay_exec(t);
}
m->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return status;
}
@@ -226,7 +227,7 @@ static size_t sc18is602_max_transfer_size(struct spi_device *spi)
static int sc18is602_setup(struct spi_device *spi)
{
- struct sc18is602 *hw = spi_master_get_devdata(spi->master);
+ struct sc18is602 *hw = spi_controller_get_devdata(spi->controller);
/* SC18IS602 does not support CS2 */
if (hw->id == sc18is602 && (spi_get_chipselect(spi, 0) == 2))
@@ -237,23 +238,22 @@ static int sc18is602_setup(struct spi_device *spi)
static int sc18is602_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device *dev = &client->dev;
- struct device_node *np = dev->of_node;
struct sc18is602_platform_data *pdata = dev_get_platdata(dev);
struct sc18is602 *hw;
- struct spi_master *master;
+ struct spi_controller *host;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EINVAL;
- master = devm_spi_alloc_master(dev, sizeof(struct sc18is602));
- if (!master)
+ host = devm_spi_alloc_host(dev, sizeof(struct sc18is602));
+ if (!host)
return -ENOMEM;
- hw = spi_master_get_devdata(master);
- i2c_set_clientdata(client, hw);
+ device_set_node(&host->dev, dev_fwnode(dev));
+
+ hw = spi_controller_get_devdata(host);
/* assert reset and then release */
hw->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
@@ -261,50 +261,39 @@ static int sc18is602_probe(struct i2c_client *client)
return PTR_ERR(hw->reset);
gpiod_set_value_cansleep(hw->reset, 0);
- hw->master = master;
+ hw->host = host;
hw->client = client;
hw->dev = dev;
hw->ctrl = 0xff;
- if (client->dev.of_node)
- hw->id = (enum chips)of_device_get_match_data(&client->dev);
- else
- hw->id = id->driver_data;
-
+ hw->id = (uintptr_t)i2c_get_match_data(client);
switch (hw->id) {
case sc18is602:
case sc18is602b:
- master->num_chipselect = 4;
+ host->num_chipselect = 4;
hw->freq = SC18IS602_CLOCK;
break;
case sc18is603:
- master->num_chipselect = 2;
- if (pdata) {
+ host->num_chipselect = 2;
+ if (pdata)
hw->freq = pdata->clock_frequency;
- } else {
- const __be32 *val;
- int len;
-
- val = of_get_property(np, "clock-frequency", &len);
- if (val && len >= sizeof(__be32))
- hw->freq = be32_to_cpup(val);
- }
+ else
+ device_property_read_u32(dev, "clock-frequency", &hw->freq);
if (!hw->freq)
hw->freq = SC18IS602_CLOCK;
break;
}
- master->bus_num = np ? -1 : client->adapter->nr;
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->setup = sc18is602_setup;
- master->transfer_one_message = sc18is602_transfer_one;
- master->max_transfer_size = sc18is602_max_transfer_size;
- master->max_message_size = sc18is602_max_transfer_size;
- master->dev.of_node = np;
- master->min_speed_hz = hw->freq / 128;
- master->max_speed_hz = hw->freq / 4;
-
- return devm_spi_register_master(dev, master);
+ host->bus_num = dev_fwnode(dev) ? -1 : client->adapter->nr;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->setup = sc18is602_setup;
+ host->transfer_one_message = sc18is602_transfer_one;
+ host->max_transfer_size = sc18is602_max_transfer_size;
+ host->max_message_size = sc18is602_max_transfer_size;
+ host->min_speed_hz = hw->freq / 128;
+ host->max_speed_hz = hw->freq / 4;
+
+ return devm_spi_register_controller(dev, host);
}
static const struct i2c_device_id sc18is602_id[] = {
@@ -315,7 +304,7 @@ static const struct i2c_device_id sc18is602_id[] = {
};
MODULE_DEVICE_TABLE(i2c, sc18is602_id);
-static const struct of_device_id sc18is602_of_match[] __maybe_unused = {
+static const struct of_device_id sc18is602_of_match[] = {
{
.compatible = "nxp,sc18is602",
.data = (void *)sc18is602
@@ -335,7 +324,7 @@ MODULE_DEVICE_TABLE(of, sc18is602_of_match);
static struct i2c_driver sc18is602_driver = {
.driver = {
.name = "sc18is602",
- .of_match_table = of_match_ptr(sc18is602_of_match),
+ .of_match_table = sc18is602_of_match,
},
.probe = sc18is602_probe,
.id_table = sc18is602_id,
@@ -343,6 +332,6 @@ static struct i2c_driver sc18is602_driver = {
module_i2c_driver(sc18is602_driver);
-MODULE_DESCRIPTION("SC18IS602/603 SPI Master Driver");
+MODULE_DESCRIPTION("SC18IS602/603 SPI Host Driver");
MODULE_AUTHOR("Guenter Roeck");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-sg2044-nor.c b/drivers/spi/spi-sg2044-nor.c
new file mode 100644
index 000000000000..37f1cfe10be4
--- /dev/null
+++ b/drivers/spi/spi-sg2044-nor.c
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SG2044 SPI NOR controller driver
+ *
+ * Copyright (c) 2025 Longbin Li <looong.bin@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi-mem.h>
+
+/* Hardware register definitions */
+#define SPIFMC_CTRL 0x00
+#define SPIFMC_CTRL_CPHA BIT(12)
+#define SPIFMC_CTRL_CPOL BIT(13)
+#define SPIFMC_CTRL_HOLD_OL BIT(14)
+#define SPIFMC_CTRL_WP_OL BIT(15)
+#define SPIFMC_CTRL_LSBF BIT(20)
+#define SPIFMC_CTRL_SRST BIT(21)
+#define SPIFMC_CTRL_SCK_DIV_SHIFT 0
+#define SPIFMC_CTRL_FRAME_LEN_SHIFT 16
+#define SPIFMC_CTRL_SCK_DIV_MASK 0x7FF
+
+#define SPIFMC_CE_CTRL 0x04
+#define SPIFMC_CE_CTRL_CEMANUAL BIT(0)
+#define SPIFMC_CE_CTRL_CEMANUAL_EN BIT(1)
+
+#define SPIFMC_DLY_CTRL 0x08
+#define SPIFMC_CTRL_FM_INTVL_MASK 0x000f
+#define SPIFMC_CTRL_FM_INTVL BIT(0)
+#define SPIFMC_CTRL_CET_MASK 0x0f00
+#define SPIFMC_CTRL_CET BIT(8)
+
+#define SPIFMC_DMMR 0x0c
+
+#define SPIFMC_TRAN_CSR 0x10
+#define SPIFMC_TRAN_CSR_TRAN_MODE_MASK GENMASK(1, 0)
+#define SPIFMC_TRAN_CSR_TRAN_MODE_RX BIT(0)
+#define SPIFMC_TRAN_CSR_TRAN_MODE_TX BIT(1)
+#define SPIFMC_TRAN_CSR_FAST_MODE BIT(3)
+#define SPIFMC_TRAN_CSR_BUS_WIDTH_MASK GENMASK(5, 4)
+#define SPIFMC_TRAN_CSR_BUS_WIDTH_1_BIT (0x00 << 4)
+#define SPIFMC_TRAN_CSR_BUS_WIDTH_2_BIT (0x01 << 4)
+#define SPIFMC_TRAN_CSR_BUS_WIDTH_4_BIT (0x02 << 4)
+#define SPIFMC_TRAN_CSR_DMA_EN BIT(6)
+#define SPIFMC_TRAN_CSR_MISO_LEVEL BIT(7)
+#define SPIFMC_TRAN_CSR_ADDR_BYTES_MASK GENMASK(10, 8)
+#define SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT 8
+#define SPIFMC_TRAN_CSR_WITH_CMD BIT(11)
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_MASK GENMASK(13, 12)
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE (0x00 << 12)
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_2_BYTE (0x01 << 12)
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_4_BYTE (0x02 << 12)
+#define SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE (0x03 << 12)
+#define SPIFMC_TRAN_CSR_GO_BUSY BIT(15)
+#define SPIFMC_TRAN_CSR_ADDR4B_SHIFT 20
+#define SPIFMC_TRAN_CSR_CMD4B_SHIFT 21
+
+#define SPIFMC_TRAN_NUM 0x14
+#define SPIFMC_FIFO_PORT 0x18
+#define SPIFMC_FIFO_PT 0x20
+
+#define SPIFMC_INT_STS 0x28
+#define SPIFMC_INT_TRAN_DONE BIT(0)
+#define SPIFMC_INT_RD_FIFO BIT(2)
+#define SPIFMC_INT_WR_FIFO BIT(3)
+#define SPIFMC_INT_RX_FRAME BIT(4)
+#define SPIFMC_INT_TX_FRAME BIT(5)
+
+#define SPIFMC_INT_EN 0x2c
+#define SPIFMC_INT_TRAN_DONE_EN BIT(0)
+#define SPIFMC_INT_RD_FIFO_EN BIT(2)
+#define SPIFMC_INT_WR_FIFO_EN BIT(3)
+#define SPIFMC_INT_RX_FRAME_EN BIT(4)
+#define SPIFMC_INT_TX_FRAME_EN BIT(5)
+
+#define SPIFMC_OPT 0x030
+#define SPIFMC_OPT_DISABLE_FIFO_FLUSH BIT(1)
+
+#define SPIFMC_MAX_FIFO_DEPTH 8
+
+#define SPIFMC_MAX_READ_SIZE 0x10000
+
+struct sg204x_spifmc_chip_info {
+ bool has_opt_reg;
+ u32 rd_fifo_int_trigger_level;
+};
+
+struct sg2044_spifmc {
+ struct spi_controller *ctrl;
+ void __iomem *io_base;
+ struct device *dev;
+ struct mutex lock;
+ struct clk *clk;
+ const struct sg204x_spifmc_chip_info *chip_info;
+};
+
+static int sg2044_spifmc_wait_int(struct sg2044_spifmc *spifmc, u8 int_type)
+{
+ u32 stat;
+
+ return readl_poll_timeout(spifmc->io_base + SPIFMC_INT_STS, stat,
+ (stat & int_type), 0, 1000000);
+}
+
+static int sg2044_spifmc_wait_xfer_size(struct sg2044_spifmc *spifmc,
+ int xfer_size)
+{
+ u8 stat;
+
+ return readl_poll_timeout(spifmc->io_base + SPIFMC_FIFO_PT, stat,
+ ((stat & 0xf) == xfer_size), 1, 1000000);
+}
+
+static u32 sg2044_spifmc_init_reg(struct sg2044_spifmc *spifmc)
+{
+ u32 reg;
+
+ reg = readl(spifmc->io_base + SPIFMC_TRAN_CSR);
+ reg &= ~(SPIFMC_TRAN_CSR_TRAN_MODE_MASK |
+ SPIFMC_TRAN_CSR_FAST_MODE |
+ SPIFMC_TRAN_CSR_BUS_WIDTH_MASK |
+ SPIFMC_TRAN_CSR_DMA_EN |
+ SPIFMC_TRAN_CSR_ADDR_BYTES_MASK |
+ SPIFMC_TRAN_CSR_WITH_CMD |
+ SPIFMC_TRAN_CSR_FIFO_TRG_LVL_MASK);
+
+ writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+
+ return reg;
+}
+
+static ssize_t sg2044_spifmc_read_64k(struct sg2044_spifmc *spifmc,
+ const struct spi_mem_op *op, loff_t from,
+ size_t len, u_char *buf)
+{
+ int xfer_size, offset;
+ u32 reg;
+ int ret;
+ int i;
+
+ reg = sg2044_spifmc_init_reg(spifmc);
+ reg |= (op->addr.nbytes + op->dummy.nbytes) << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
+ reg |= spifmc->chip_info->rd_fifo_int_trigger_level;
+ reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+ reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX;
+
+ writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+ writeb(op->cmd.opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ for (i = op->addr.nbytes - 1; i >= 0; i--)
+ writeb((from >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ for (i = 0; i < op->dummy.nbytes; i++)
+ writeb(0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
+ writel(0, spifmc->io_base + SPIFMC_INT_STS);
+ reg |= SPIFMC_TRAN_CSR_GO_BUSY;
+ writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+
+ ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_RD_FIFO);
+ if (ret < 0)
+ return ret;
+
+ offset = 0;
+ while (offset < len) {
+ xfer_size = min_t(size_t, SPIFMC_MAX_FIFO_DEPTH, len - offset);
+
+ ret = sg2044_spifmc_wait_xfer_size(spifmc, xfer_size);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < xfer_size; i++)
+ buf[i + offset] = readb(spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ offset += xfer_size;
+ }
+
+ ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
+ if (ret < 0)
+ return ret;
+
+ writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+ return len;
+}
+
+static ssize_t sg2044_spifmc_read(struct sg2044_spifmc *spifmc,
+ const struct spi_mem_op *op)
+{
+ size_t xfer_size;
+ size_t offset;
+ loff_t from = op->addr.val;
+ size_t len = op->data.nbytes;
+ int ret;
+ u8 *din = op->data.buf.in;
+
+ offset = 0;
+ while (offset < len) {
+ xfer_size = min_t(size_t, SPIFMC_MAX_READ_SIZE, len - offset);
+
+ ret = sg2044_spifmc_read_64k(spifmc, op, from, xfer_size, din);
+ if (ret < 0)
+ return ret;
+
+ offset += xfer_size;
+ din += xfer_size;
+ from += xfer_size;
+ }
+
+ return 0;
+}
+
+static ssize_t sg2044_spifmc_write(struct sg2044_spifmc *spifmc,
+ const struct spi_mem_op *op)
+{
+ size_t xfer_size;
+ const u8 *dout = op->data.buf.out;
+ int i, offset;
+ int ret;
+ u32 reg;
+
+ reg = sg2044_spifmc_init_reg(spifmc);
+ reg |= (op->addr.nbytes + op->dummy.nbytes) << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
+ reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE;
+ reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+ reg |= SPIFMC_TRAN_CSR_TRAN_MODE_TX;
+
+ writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+ writeb(op->cmd.opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ for (i = op->addr.nbytes - 1; i >= 0; i--)
+ writeb((op->addr.val >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ for (i = 0; i < op->dummy.nbytes; i++)
+ writeb(0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ writel(0, spifmc->io_base + SPIFMC_INT_STS);
+ writel(op->data.nbytes, spifmc->io_base + SPIFMC_TRAN_NUM);
+ reg |= SPIFMC_TRAN_CSR_GO_BUSY;
+ writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+
+ ret = sg2044_spifmc_wait_xfer_size(spifmc, 0);
+ if (ret < 0)
+ return ret;
+
+ writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+ offset = 0;
+ while (offset < op->data.nbytes) {
+ xfer_size = min_t(size_t, SPIFMC_MAX_FIFO_DEPTH, op->data.nbytes - offset);
+
+ ret = sg2044_spifmc_wait_xfer_size(spifmc, 0);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < xfer_size; i++)
+ writeb(dout[i + offset], spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ offset += xfer_size;
+ }
+
+ ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
+ if (ret < 0)
+ return ret;
+
+ writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+ return 0;
+}
+
+static ssize_t sg2044_spifmc_tran_cmd(struct sg2044_spifmc *spifmc,
+ const struct spi_mem_op *op)
+{
+ int i, ret;
+ u32 reg;
+
+ reg = sg2044_spifmc_init_reg(spifmc);
+ reg |= (op->addr.nbytes + op->dummy.nbytes) << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
+ reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE;
+ reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+
+ writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+ writeb(op->cmd.opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ for (i = op->addr.nbytes - 1; i >= 0; i--)
+ writeb((op->addr.val >> i * 8) & 0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ for (i = 0; i < op->dummy.nbytes; i++)
+ writeb(0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ writel(0, spifmc->io_base + SPIFMC_INT_STS);
+ reg |= SPIFMC_TRAN_CSR_GO_BUSY;
+ writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+
+ ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
+ if (ret < 0)
+ return ret;
+
+ writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+ return 0;
+}
+
+static void sg2044_spifmc_trans(struct sg2044_spifmc *spifmc,
+ const struct spi_mem_op *op)
+{
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ sg2044_spifmc_read(spifmc, op);
+ else if (op->data.dir == SPI_MEM_DATA_OUT)
+ sg2044_spifmc_write(spifmc, op);
+ else
+ sg2044_spifmc_tran_cmd(spifmc, op);
+}
+
+static ssize_t sg2044_spifmc_trans_reg(struct sg2044_spifmc *spifmc,
+ const struct spi_mem_op *op)
+{
+ const u8 *dout = NULL;
+ u8 *din = NULL;
+ size_t len = op->data.nbytes;
+ int ret, i;
+ u32 reg;
+
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ din = op->data.buf.in;
+ else
+ dout = op->data.buf.out;
+
+ reg = sg2044_spifmc_init_reg(spifmc);
+ reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE;
+ reg |= SPIFMC_TRAN_CSR_WITH_CMD;
+
+ if (din) {
+ reg |= SPIFMC_TRAN_CSR_BUS_WIDTH_1_BIT;
+ reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX;
+ reg |= SPIFMC_TRAN_CSR_TRAN_MODE_TX;
+
+ if (spifmc->chip_info->has_opt_reg)
+ writel(SPIFMC_OPT_DISABLE_FIFO_FLUSH, spifmc->io_base + SPIFMC_OPT);
+ } else {
+ /*
+ * If write values to the Status Register,
+ * configure TRAN_CSR register as the same as
+ * sg2044_spifmc_read_reg.
+ */
+ if (op->cmd.opcode == 0x01) {
+ reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX;
+ reg |= SPIFMC_TRAN_CSR_TRAN_MODE_TX;
+ writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
+ }
+ }
+
+ writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+ writeb(op->cmd.opcode, spifmc->io_base + SPIFMC_FIFO_PORT);
+
+ for (i = 0; i < len; i++) {
+ if (din)
+ writeb(0xff, spifmc->io_base + SPIFMC_FIFO_PORT);
+ else
+ writeb(dout[i], spifmc->io_base + SPIFMC_FIFO_PORT);
+ }
+
+ writel(0, spifmc->io_base + SPIFMC_INT_STS);
+ writel(len, spifmc->io_base + SPIFMC_TRAN_NUM);
+ reg |= SPIFMC_TRAN_CSR_GO_BUSY;
+ writel(reg, spifmc->io_base + SPIFMC_TRAN_CSR);
+
+ ret = sg2044_spifmc_wait_int(spifmc, SPIFMC_INT_TRAN_DONE);
+ if (ret < 0)
+ return ret;
+
+ if (din) {
+ while (len--)
+ *din++ = readb(spifmc->io_base + SPIFMC_FIFO_PORT);
+ }
+
+ writel(0, spifmc->io_base + SPIFMC_FIFO_PT);
+
+ return 0;
+}
+
+static int sg2044_spifmc_exec_op(struct spi_mem *mem,
+ const struct spi_mem_op *op)
+{
+ struct sg2044_spifmc *spifmc;
+
+ spifmc = spi_controller_get_devdata(mem->spi->controller);
+
+ mutex_lock(&spifmc->lock);
+
+ if (op->addr.nbytes == 0)
+ sg2044_spifmc_trans_reg(spifmc, op);
+ else
+ sg2044_spifmc_trans(spifmc, op);
+
+ mutex_unlock(&spifmc->lock);
+
+ return 0;
+}
+
+static const struct spi_controller_mem_ops sg2044_spifmc_mem_ops = {
+ .exec_op = sg2044_spifmc_exec_op,
+};
+
+static void sg2044_spifmc_init(struct sg2044_spifmc *spifmc)
+{
+ u32 tran_csr;
+ u32 reg;
+
+ writel(0, spifmc->io_base + SPIFMC_DMMR);
+
+ reg = readl(spifmc->io_base + SPIFMC_CTRL);
+ reg |= SPIFMC_CTRL_SRST;
+ reg &= ~(SPIFMC_CTRL_SCK_DIV_MASK);
+ reg |= 1;
+ writel(reg, spifmc->io_base + SPIFMC_CTRL);
+
+ writel(0, spifmc->io_base + SPIFMC_CE_CTRL);
+
+ tran_csr = readl(spifmc->io_base + SPIFMC_TRAN_CSR);
+ tran_csr |= (0 << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT);
+ tran_csr |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_4_BYTE;
+ tran_csr |= SPIFMC_TRAN_CSR_WITH_CMD;
+ writel(tran_csr, spifmc->io_base + SPIFMC_TRAN_CSR);
+}
+
+static int sg2044_spifmc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_controller *ctrl;
+ struct sg2044_spifmc *spifmc;
+ int ret;
+
+ ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*spifmc));
+ if (!ctrl)
+ return -ENOMEM;
+
+ spifmc = spi_controller_get_devdata(ctrl);
+
+ spifmc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(spifmc->clk))
+ return dev_err_probe(dev, PTR_ERR(spifmc->clk), "Cannot get and enable AHB clock\n");
+
+ spifmc->dev = &pdev->dev;
+ spifmc->ctrl = ctrl;
+
+ spifmc->io_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(spifmc->io_base))
+ return PTR_ERR(spifmc->io_base);
+
+ ctrl->num_chipselect = 1;
+ ctrl->dev.of_node = pdev->dev.of_node;
+ ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
+ ctrl->auto_runtime_pm = false;
+ ctrl->mem_ops = &sg2044_spifmc_mem_ops;
+ ctrl->mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | SPI_RX_QUAD | SPI_TX_QUAD;
+
+ ret = devm_mutex_init(dev, &spifmc->lock);
+ if (ret)
+ return ret;
+ spifmc->chip_info = device_get_match_data(&pdev->dev);
+ if (!spifmc->chip_info) {
+ dev_err(&pdev->dev, "Failed to get specific chip info\n");
+ return -EINVAL;
+ }
+
+ sg2044_spifmc_init(spifmc);
+ sg2044_spifmc_init_reg(spifmc);
+
+ ret = devm_spi_register_controller(&pdev->dev, ctrl);
+ if (ret)
+ return dev_err_probe(dev, ret, "spi_register_controller failed\n");
+
+ return 0;
+}
+
+static const struct sg204x_spifmc_chip_info sg2044_chip_info = {
+ .has_opt_reg = true,
+ .rd_fifo_int_trigger_level = SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE,
+};
+
+static const struct sg204x_spifmc_chip_info sg2042_chip_info = {
+ .has_opt_reg = false,
+ .rd_fifo_int_trigger_level = SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE,
+};
+
+static const struct of_device_id sg2044_spifmc_match[] = {
+ { .compatible = "sophgo,sg2044-spifmc-nor", .data = &sg2044_chip_info },
+ { .compatible = "sophgo,sg2042-spifmc-nor", .data = &sg2042_chip_info },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sg2044_spifmc_match);
+
+static struct platform_driver sg2044_nor_driver = {
+ .driver = {
+ .name = "sg2044,spifmc-nor",
+ .of_match_table = sg2044_spifmc_match,
+ },
+ .probe = sg2044_spifmc_probe,
+};
+module_platform_driver(sg2044_nor_driver);
+
+MODULE_DESCRIPTION("SG2044 SPI NOR controller driver");
+MODULE_AUTHOR("Longbin Li <looong.bin@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index d6ffeae66ed3..93017faeb7b5 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -82,7 +82,7 @@ static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val)
}
/*
- * spi master function
+ * spi host function
*/
#define hspi_hw_cs_enable(hspi) hspi_hw_cs_ctrl(hspi, 0)
@@ -224,7 +224,7 @@ static int hspi_probe(struct platform_device *pdev)
return -EINVAL;
}
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*hspi));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*hspi));
if (!ctlr)
return -ENOMEM;
@@ -293,7 +293,7 @@ MODULE_DEVICE_TABLE(of, hspi_of_match);
static struct platform_driver hspi_driver = {
.probe = hspi_probe,
- .remove_new = hspi_remove,
+ .remove = hspi_remove,
.driver = {
.name = "sh-hspi",
.of_match_table = hspi_of_match,
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 9e90b4f8b357..b695870fae8c 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -20,7 +20,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sh_dma.h>
@@ -28,7 +28,9 @@
#include <linux/spi/sh_msiof.h>
#include <linux/spi/spi.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
+
+#define SH_MSIOF_FLAG_FIXED_DTDL_200 BIT(0)
struct sh_msiof_chipdata {
u32 bits_per_word_mask;
@@ -36,6 +38,7 @@ struct sh_msiof_chipdata {
u16 rx_fifo_size;
u16 ctlr_flags;
u16 min_div_pow;
+ u32 flags;
};
struct sh_msiof_spi_priv {
@@ -55,140 +58,11 @@ struct sh_msiof_spi_priv {
dma_addr_t rx_dma_addr;
bool native_cs_inited;
bool native_cs_high;
- bool slave_aborted;
+ bool target_aborted;
};
#define MAX_SS 3 /* Maximum number of native chip selects */
-#define SITMDR1 0x00 /* Transmit Mode Register 1 */
-#define SITMDR2 0x04 /* Transmit Mode Register 2 */
-#define SITMDR3 0x08 /* Transmit Mode Register 3 */
-#define SIRMDR1 0x10 /* Receive Mode Register 1 */
-#define SIRMDR2 0x14 /* Receive Mode Register 2 */
-#define SIRMDR3 0x18 /* Receive Mode Register 3 */
-#define SITSCR 0x20 /* Transmit Clock Select Register */
-#define SIRSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */
-#define SICTR 0x28 /* Control Register */
-#define SIFCTR 0x30 /* FIFO Control Register */
-#define SISTR 0x40 /* Status Register */
-#define SIIER 0x44 /* Interrupt Enable Register */
-#define SITDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */
-#define SITDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */
-#define SITFDR 0x50 /* Transmit FIFO Data Register */
-#define SIRDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */
-#define SIRDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */
-#define SIRFDR 0x60 /* Receive FIFO Data Register */
-
-/* SITMDR1 and SIRMDR1 */
-#define SIMDR1_TRMD BIT(31) /* Transfer Mode (1 = Master mode) */
-#define SIMDR1_SYNCMD_MASK GENMASK(29, 28) /* SYNC Mode */
-#define SIMDR1_SYNCMD_SPI (2 << 28) /* Level mode/SPI */
-#define SIMDR1_SYNCMD_LR (3 << 28) /* L/R mode */
-#define SIMDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */
-#define SIMDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */
-#define SIMDR1_DTDL_SHIFT 20 /* Data Pin Bit Delay for MSIOF_SYNC */
-#define SIMDR1_SYNCDL_SHIFT 16 /* Frame Sync Signal Timing Delay */
-#define SIMDR1_FLD_MASK GENMASK(3, 2) /* Frame Sync Signal Interval (0-3) */
-#define SIMDR1_FLD_SHIFT 2
-#define SIMDR1_XXSTP BIT(0) /* Transmission/Reception Stop on FIFO */
-/* SITMDR1 */
-#define SITMDR1_PCON BIT(30) /* Transfer Signal Connection */
-#define SITMDR1_SYNCCH_MASK GENMASK(27, 26) /* Sync Signal Channel Select */
-#define SITMDR1_SYNCCH_SHIFT 26 /* 0=MSIOF_SYNC, 1=MSIOF_SS1, 2=MSIOF_SS2 */
-
-/* SITMDR2 and SIRMDR2 */
-#define SIMDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */
-#define SIMDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */
-#define SIMDR2_GRPMASK1 BIT(0) /* Group Output Mask 1 (SH, A1) */
-
-/* SITSCR and SIRSCR */
-#define SISCR_BRPS_MASK GENMASK(12, 8) /* Prescaler Setting (1-32) */
-#define SISCR_BRPS(i) (((i) - 1) << 8)
-#define SISCR_BRDV_MASK GENMASK(2, 0) /* Baud Rate Generator's Division Ratio */
-#define SISCR_BRDV_DIV_2 0
-#define SISCR_BRDV_DIV_4 1
-#define SISCR_BRDV_DIV_8 2
-#define SISCR_BRDV_DIV_16 3
-#define SISCR_BRDV_DIV_32 4
-#define SISCR_BRDV_DIV_1 7
-
-/* SICTR */
-#define SICTR_TSCKIZ_MASK GENMASK(31, 30) /* Transmit Clock I/O Polarity Select */
-#define SICTR_TSCKIZ_SCK BIT(31) /* Disable SCK when TX disabled */
-#define SICTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */
-#define SICTR_RSCKIZ_MASK GENMASK(29, 28) /* Receive Clock Polarity Select */
-#define SICTR_RSCKIZ_SCK BIT(29) /* Must match CTR_TSCKIZ_SCK */
-#define SICTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */
-#define SICTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */
-#define SICTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */
-#define SICTR_TXDIZ_MASK GENMASK(23, 22) /* Pin Output When TX is Disabled */
-#define SICTR_TXDIZ_LOW (0 << 22) /* 0 */
-#define SICTR_TXDIZ_HIGH (1 << 22) /* 1 */
-#define SICTR_TXDIZ_HIZ (2 << 22) /* High-impedance */
-#define SICTR_TSCKE BIT(15) /* Transmit Serial Clock Output Enable */
-#define SICTR_TFSE BIT(14) /* Transmit Frame Sync Signal Output Enable */
-#define SICTR_TXE BIT(9) /* Transmit Enable */
-#define SICTR_RXE BIT(8) /* Receive Enable */
-#define SICTR_TXRST BIT(1) /* Transmit Reset */
-#define SICTR_RXRST BIT(0) /* Receive Reset */
-
-/* SIFCTR */
-#define SIFCTR_TFWM_MASK GENMASK(31, 29) /* Transmit FIFO Watermark */
-#define SIFCTR_TFWM_64 (0 << 29) /* Transfer Request when 64 empty stages */
-#define SIFCTR_TFWM_32 (1 << 29) /* Transfer Request when 32 empty stages */
-#define SIFCTR_TFWM_24 (2 << 29) /* Transfer Request when 24 empty stages */
-#define SIFCTR_TFWM_16 (3 << 29) /* Transfer Request when 16 empty stages */
-#define SIFCTR_TFWM_12 (4 << 29) /* Transfer Request when 12 empty stages */
-#define SIFCTR_TFWM_8 (5 << 29) /* Transfer Request when 8 empty stages */
-#define SIFCTR_TFWM_4 (6 << 29) /* Transfer Request when 4 empty stages */
-#define SIFCTR_TFWM_1 (7 << 29) /* Transfer Request when 1 empty stage */
-#define SIFCTR_TFUA_MASK GENMASK(26, 20) /* Transmit FIFO Usable Area */
-#define SIFCTR_TFUA_SHIFT 20
-#define SIFCTR_TFUA(i) ((i) << SIFCTR_TFUA_SHIFT)
-#define SIFCTR_RFWM_MASK GENMASK(15, 13) /* Receive FIFO Watermark */
-#define SIFCTR_RFWM_1 (0 << 13) /* Transfer Request when 1 valid stages */
-#define SIFCTR_RFWM_4 (1 << 13) /* Transfer Request when 4 valid stages */
-#define SIFCTR_RFWM_8 (2 << 13) /* Transfer Request when 8 valid stages */
-#define SIFCTR_RFWM_16 (3 << 13) /* Transfer Request when 16 valid stages */
-#define SIFCTR_RFWM_32 (4 << 13) /* Transfer Request when 32 valid stages */
-#define SIFCTR_RFWM_64 (5 << 13) /* Transfer Request when 64 valid stages */
-#define SIFCTR_RFWM_128 (6 << 13) /* Transfer Request when 128 valid stages */
-#define SIFCTR_RFWM_256 (7 << 13) /* Transfer Request when 256 valid stages */
-#define SIFCTR_RFUA_MASK GENMASK(12, 4) /* Receive FIFO Usable Area (0x40 = full) */
-#define SIFCTR_RFUA_SHIFT 4
-#define SIFCTR_RFUA(i) ((i) << SIFCTR_RFUA_SHIFT)
-
-/* SISTR */
-#define SISTR_TFEMP BIT(29) /* Transmit FIFO Empty */
-#define SISTR_TDREQ BIT(28) /* Transmit Data Transfer Request */
-#define SISTR_TEOF BIT(23) /* Frame Transmission End */
-#define SISTR_TFSERR BIT(21) /* Transmit Frame Synchronization Error */
-#define SISTR_TFOVF BIT(20) /* Transmit FIFO Overflow */
-#define SISTR_TFUDF BIT(19) /* Transmit FIFO Underflow */
-#define SISTR_RFFUL BIT(13) /* Receive FIFO Full */
-#define SISTR_RDREQ BIT(12) /* Receive Data Transfer Request */
-#define SISTR_REOF BIT(7) /* Frame Reception End */
-#define SISTR_RFSERR BIT(5) /* Receive Frame Synchronization Error */
-#define SISTR_RFUDF BIT(4) /* Receive FIFO Underflow */
-#define SISTR_RFOVF BIT(3) /* Receive FIFO Overflow */
-
-/* SIIER */
-#define SIIER_TDMAE BIT(31) /* Transmit Data DMA Transfer Req. Enable */
-#define SIIER_TFEMPE BIT(29) /* Transmit FIFO Empty Enable */
-#define SIIER_TDREQE BIT(28) /* Transmit Data Transfer Request Enable */
-#define SIIER_TEOFE BIT(23) /* Frame Transmission End Enable */
-#define SIIER_TFSERRE BIT(21) /* Transmit Frame Sync Error Enable */
-#define SIIER_TFOVFE BIT(20) /* Transmit FIFO Overflow Enable */
-#define SIIER_TFUDFE BIT(19) /* Transmit FIFO Underflow Enable */
-#define SIIER_RDMAE BIT(15) /* Receive Data DMA Transfer Req. Enable */
-#define SIIER_RFFULE BIT(13) /* Receive FIFO Full Enable */
-#define SIIER_RDREQE BIT(12) /* Receive Data Transfer Request Enable */
-#define SIIER_REOFE BIT(7) /* Frame Reception End Enable */
-#define SIIER_RFSERRE BIT(5) /* Receive Frame Sync Error Enable */
-#define SIIER_RFUDFE BIT(4) /* Receive FIFO Underflow Enable */
-#define SIIER_RFOVFE BIT(3) /* Receive FIFO Overflow Enable */
-
-
static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
{
switch (reg_offs) {
@@ -253,11 +127,6 @@ static void sh_msiof_spi_reset_regs(struct sh_msiof_spi_priv *p)
100);
}
-static const u32 sh_msiof_spi_div_array[] = {
- SISCR_BRDV_DIV_1, SISCR_BRDV_DIV_2, SISCR_BRDV_DIV_4,
- SISCR_BRDV_DIV_8, SISCR_BRDV_DIV_16, SISCR_BRDV_DIV_32,
-};
-
static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
struct spi_transfer *t)
{
@@ -296,7 +165,9 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
t->effective_speed_hz = parent_rate / (brps << div_pow);
- scr = sh_msiof_spi_div_array[div_pow] | SISCR_BRPS(brps);
+ /* div_pow == 0 maps to SISCR_BRDV_DIV_1 == all ones */
+ scr = FIELD_PREP(SISCR_BRDV, div_pow - 1) |
+ FIELD_PREP(SISCR_BRPS, brps - 1);
sh_msiof_write(p, SITSCR, scr);
if (!(p->ctlr->flags & SPI_CONTROLLER_MUST_TX))
sh_msiof_write(p, SIRSCR, scr);
@@ -338,18 +209,19 @@ static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p)
return 0;
}
- val = sh_msiof_get_delay_bit(p->info->dtdl) << SIMDR1_DTDL_SHIFT;
- val |= sh_msiof_get_delay_bit(p->info->syncdl) << SIMDR1_SYNCDL_SHIFT;
+ val = FIELD_PREP(SIMDR1_DTDL, sh_msiof_get_delay_bit(p->info->dtdl)) |
+ FIELD_PREP(SIMDR1_SYNCDL,
+ sh_msiof_get_delay_bit(p->info->syncdl));
return val;
}
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)
+ bool cpol, bool cpha, bool tx_hi_z,
+ bool lsb_first, bool cs_high)
{
+ bool edge;
u32 tmp;
- int edge;
/*
* CPOL CPHA TSCKIZ RSCKIZ TEDG REDG
@@ -358,16 +230,18 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, u32 ss,
* 1 0 11 11 0 0
* 1 1 11 11 1 1
*/
- tmp = SIMDR1_SYNCMD_SPI | 1 << SIMDR1_FLD_SHIFT | SIMDR1_XXSTP;
- tmp |= !cs_high << SIMDR1_SYNCAC_SHIFT;
- tmp |= lsb_first << SIMDR1_BITLSB_SHIFT;
+ tmp = FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_SPI) |
+ FIELD_PREP(SIMDR1_FLD, 1) | SIMDR1_XXSTP |
+ FIELD_PREP(SIMDR1_SYNCAC, !cs_high) |
+ FIELD_PREP(SIMDR1_BITLSB, lsb_first);
tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
- if (spi_controller_is_slave(p->ctlr)) {
+ if (spi_controller_is_target(p->ctlr)) {
sh_msiof_write(p, SITMDR1, tmp | SITMDR1_PCON);
} else {
sh_msiof_write(p, SITMDR1,
tmp | SIMDR1_TRMD | SITMDR1_PCON |
- (ss < MAX_SS ? ss : 0) << SITMDR1_SYNCCH_SHIFT);
+ FIELD_PREP(SITMDR1_SYNCCH,
+ ss < MAX_SS ? ss : 0));
}
if (p->ctlr->flags & SPI_CONTROLLER_MUST_TX) {
/* These bits are reserved if RX needs TX */
@@ -376,30 +250,42 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, u32 ss,
sh_msiof_write(p, SIRMDR1, tmp);
tmp = 0;
- tmp |= SICTR_TSCKIZ_SCK | cpol << SICTR_TSCKIZ_POL_SHIFT;
- tmp |= SICTR_RSCKIZ_SCK | cpol << SICTR_RSCKIZ_POL_SHIFT;
+ tmp |= SICTR_TSCKIZ_SCK | FIELD_PREP(SICTR_TSCKIZ_POL, cpol);
+ tmp |= SICTR_RSCKIZ_SCK | FIELD_PREP(SICTR_RSCKIZ_POL, cpol);
edge = cpol ^ !cpha;
- tmp |= edge << SICTR_TEDG_SHIFT;
- tmp |= edge << SICTR_REDG_SHIFT;
- tmp |= tx_hi_z ? SICTR_TXDIZ_HIZ : SICTR_TXDIZ_LOW;
+ tmp |= FIELD_PREP(SICTR_TEDG, edge);
+ tmp |= FIELD_PREP(SICTR_REDG, edge);
+ tmp |= FIELD_PREP(SICTR_TXDIZ,
+ tx_hi_z ? SICTR_TXDIZ_HIZ : SICTR_TXDIZ_LOW);
sh_msiof_write(p, SICTR, tmp);
}
static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
const void *tx_buf, void *rx_buf,
- u32 bits, u32 words)
+ u32 bits, u32 words1, u32 words2)
{
- u32 dr2 = SIMDR2_BITLEN1(bits) | SIMDR2_WDLEN1(words);
+ u32 dr2 = FIELD_PREP(SIMDR2_GRP, words2 ? 1 : 0) |
+ FIELD_PREP(SIMDR2_BITLEN1, bits - 1) |
+ FIELD_PREP(SIMDR2_WDLEN1, words1 - 1);
if (tx_buf || (p->ctlr->flags & SPI_CONTROLLER_MUST_TX))
sh_msiof_write(p, SITMDR2, dr2);
else
- sh_msiof_write(p, SITMDR2, dr2 | SIMDR2_GRPMASK1);
+ sh_msiof_write(p, SITMDR2, dr2 | SIMDR2_GRPMASK);
if (rx_buf)
sh_msiof_write(p, SIRMDR2, dr2);
+
+ if (words2) {
+ u32 dr3 = FIELD_PREP(SIMDR3_BITLEN2, bits - 1) |
+ FIELD_PREP(SIMDR3_WDLEN2, words2 - 1);
+
+ sh_msiof_write(p, SITMDR3, dr3);
+ if (rx_buf)
+ sh_msiof_write(p, SIRMDR3, dr3);
+ }
}
static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p)
@@ -409,140 +295,154 @@ static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p)
}
static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p,
- const void *tx_buf, int words, int fs)
+ const void *tx_buf, unsigned int words,
+ unsigned int fs)
{
const u8 *buf_8 = tx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
sh_msiof_write(p, SITFDR, buf_8[k] << fs);
}
static void sh_msiof_spi_write_fifo_16(struct sh_msiof_spi_priv *p,
- const void *tx_buf, int words, int fs)
+ const void *tx_buf, unsigned int words,
+ unsigned int fs)
{
const u16 *buf_16 = tx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
sh_msiof_write(p, SITFDR, buf_16[k] << fs);
}
static void sh_msiof_spi_write_fifo_16u(struct sh_msiof_spi_priv *p,
- const void *tx_buf, int words, int fs)
+ const void *tx_buf, unsigned int words,
+ unsigned int fs)
{
const u16 *buf_16 = tx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
sh_msiof_write(p, SITFDR, get_unaligned(&buf_16[k]) << fs);
}
static void sh_msiof_spi_write_fifo_32(struct sh_msiof_spi_priv *p,
- const void *tx_buf, int words, int fs)
+ const void *tx_buf, unsigned int words,
+ unsigned int fs)
{
const u32 *buf_32 = tx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
sh_msiof_write(p, SITFDR, buf_32[k] << fs);
}
static void sh_msiof_spi_write_fifo_32u(struct sh_msiof_spi_priv *p,
- const void *tx_buf, int words, int fs)
+ const void *tx_buf, unsigned int words,
+ unsigned int fs)
{
const u32 *buf_32 = tx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
sh_msiof_write(p, SITFDR, get_unaligned(&buf_32[k]) << fs);
}
static void sh_msiof_spi_write_fifo_s32(struct sh_msiof_spi_priv *p,
- const void *tx_buf, int words, int fs)
+ const void *tx_buf, unsigned int words,
+ unsigned int fs)
{
const u32 *buf_32 = tx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
sh_msiof_write(p, SITFDR, swab32(buf_32[k] << fs));
}
static void sh_msiof_spi_write_fifo_s32u(struct sh_msiof_spi_priv *p,
- const void *tx_buf, int words, int fs)
+ const void *tx_buf,
+ unsigned int words, unsigned int fs)
{
const u32 *buf_32 = tx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
sh_msiof_write(p, SITFDR, swab32(get_unaligned(&buf_32[k]) << fs));
}
static void sh_msiof_spi_read_fifo_8(struct sh_msiof_spi_priv *p,
- void *rx_buf, int words, int fs)
+ void *rx_buf, unsigned int words,
+ unsigned int fs)
{
u8 *buf_8 = rx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
buf_8[k] = sh_msiof_read(p, SIRFDR) >> fs;
}
static void sh_msiof_spi_read_fifo_16(struct sh_msiof_spi_priv *p,
- void *rx_buf, int words, int fs)
+ void *rx_buf, unsigned int words,
+ unsigned int fs)
{
u16 *buf_16 = rx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
buf_16[k] = sh_msiof_read(p, SIRFDR) >> fs;
}
static void sh_msiof_spi_read_fifo_16u(struct sh_msiof_spi_priv *p,
- void *rx_buf, int words, int fs)
+ void *rx_buf, unsigned int words,
+ unsigned int fs)
{
u16 *buf_16 = rx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
put_unaligned(sh_msiof_read(p, SIRFDR) >> fs, &buf_16[k]);
}
static void sh_msiof_spi_read_fifo_32(struct sh_msiof_spi_priv *p,
- void *rx_buf, int words, int fs)
+ void *rx_buf, unsigned int words,
+ unsigned int fs)
{
u32 *buf_32 = rx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
buf_32[k] = sh_msiof_read(p, SIRFDR) >> fs;
}
static void sh_msiof_spi_read_fifo_32u(struct sh_msiof_spi_priv *p,
- void *rx_buf, int words, int fs)
+ void *rx_buf, unsigned int words,
+ unsigned int fs)
{
u32 *buf_32 = rx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
put_unaligned(sh_msiof_read(p, SIRFDR) >> fs, &buf_32[k]);
}
static void sh_msiof_spi_read_fifo_s32(struct sh_msiof_spi_priv *p,
- void *rx_buf, int words, int fs)
+ void *rx_buf, unsigned int words,
+ unsigned int fs)
{
u32 *buf_32 = rx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
buf_32[k] = swab32(sh_msiof_read(p, SIRFDR) >> fs);
}
static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p,
- void *rx_buf, int words, int fs)
+ void *rx_buf, unsigned int words,
+ unsigned int fs)
{
u32 *buf_32 = rx_buf;
- int k;
+ unsigned int k;
for (k = 0; k < words; k++)
put_unaligned(swab32(sh_msiof_read(p, SIRFDR) >> fs), &buf_32[k]);
@@ -554,7 +454,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
spi_controller_get_devdata(spi->controller);
u32 clr, set, tmp;
- if (spi_get_csgpiod(spi, 0) || spi_controller_is_slave(p->ctlr))
+ if (spi_get_csgpiod(spi, 0) || spi_controller_is_target(p->ctlr))
return 0;
if (p->native_cs_inited &&
@@ -562,12 +462,12 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
return 0;
/* Configure native chip select mode/polarity early */
- clr = SIMDR1_SYNCMD_MASK;
- set = SIMDR1_SYNCMD_SPI;
+ clr = SIMDR1_SYNCMD;
+ set = FIELD_PREP(SIMDR1_SYNCMD, SIMDR1_SYNCMD_SPI);
if (spi->mode & SPI_CS_HIGH)
- clr |= BIT(SIMDR1_SYNCAC_SHIFT);
+ clr |= SIMDR1_SYNCAC;
else
- set |= BIT(SIMDR1_SYNCAC_SHIFT);
+ set |= SIMDR1_SYNCAC;
pm_runtime_get_sync(&p->pdev->dev);
tmp = sh_msiof_read(p, SITMDR1) & ~clr;
sh_msiof_write(p, SITMDR1, tmp | set | SIMDR1_TRMD | SITMDR1_PCON);
@@ -584,7 +484,8 @@ static int sh_msiof_prepare_message(struct spi_controller *ctlr,
{
struct sh_msiof_spi_priv *p = spi_controller_get_devdata(ctlr);
const struct spi_device *spi = msg->spi;
- u32 ss, cs_high;
+ bool cs_high;
+ u32 ss;
/* Configure pins before asserting CS */
if (spi_get_csgpiod(spi, 0)) {
@@ -592,22 +493,21 @@ static int sh_msiof_prepare_message(struct spi_controller *ctlr,
cs_high = p->native_cs_high;
} else {
ss = spi_get_chipselect(spi, 0);
- cs_high = !!(spi->mode & SPI_CS_HIGH);
+ 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), 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, cs_high);
return 0;
}
static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
{
- bool slave = spi_controller_is_slave(p->ctlr);
+ bool target = spi_controller_is_target(p->ctlr);
int ret = 0;
/* setup clock and rx/tx signals */
- if (!slave)
+ if (!target)
ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_TSCKE);
if (rx_buf && !ret)
ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_RXE);
@@ -615,7 +515,7 @@ static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_TXE);
/* start by setting frame bit */
- if (!ret && !slave)
+ if (!ret && !target)
ret = sh_msiof_modify_ctr_wait(p, 0, SICTR_TFSE);
return ret;
@@ -623,27 +523,27 @@ static int sh_msiof_spi_start(struct sh_msiof_spi_priv *p, void *rx_buf)
static int sh_msiof_spi_stop(struct sh_msiof_spi_priv *p, void *rx_buf)
{
- bool slave = spi_controller_is_slave(p->ctlr);
+ bool target = spi_controller_is_target(p->ctlr);
int ret = 0;
/* shut down frame, rx/tx and clock signals */
- if (!slave)
+ if (!target)
ret = sh_msiof_modify_ctr_wait(p, SICTR_TFSE, 0);
if (!ret)
ret = sh_msiof_modify_ctr_wait(p, SICTR_TXE, 0);
if (rx_buf && !ret)
ret = sh_msiof_modify_ctr_wait(p, SICTR_RXE, 0);
- if (!ret && !slave)
+ if (!ret && !target)
ret = sh_msiof_modify_ctr_wait(p, SICTR_TSCKE, 0);
return ret;
}
-static int sh_msiof_slave_abort(struct spi_controller *ctlr)
+static int sh_msiof_target_abort(struct spi_controller *ctlr)
{
struct sh_msiof_spi_priv *p = spi_controller_get_devdata(ctlr);
- p->slave_aborted = true;
+ p->target_aborted = true;
complete(&p->done);
complete(&p->done_txdma);
return 0;
@@ -652,9 +552,9 @@ static int sh_msiof_slave_abort(struct spi_controller *ctlr)
static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p,
struct completion *x)
{
- if (spi_controller_is_slave(p->ctlr)) {
+ if (spi_controller_is_target(p->ctlr)) {
if (wait_for_completion_interruptible(x) ||
- p->slave_aborted) {
+ p->target_aborted) {
dev_dbg(&p->pdev->dev, "interrupted\n");
return -EINTR;
}
@@ -670,20 +570,22 @@ static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p,
static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
void (*tx_fifo)(struct sh_msiof_spi_priv *,
- const void *, int, int),
+ const void *, unsigned int,
+ unsigned int),
void (*rx_fifo)(struct sh_msiof_spi_priv *,
- void *, int, int),
+ void *, unsigned int,
+ unsigned int),
const void *tx_buf, void *rx_buf,
- int words, int bits)
+ unsigned int words, unsigned int bits)
{
- int fifo_shift;
+ unsigned int fifo_shift;
int ret;
/* limit maximum word transfer to rx/tx fifo size */
if (tx_buf)
- words = min_t(int, words, p->tx_fifo_size);
+ words = min(words, p->tx_fifo_size);
if (rx_buf)
- words = min_t(int, words, p->rx_fifo_size);
+ words = min(words, p->rx_fifo_size);
/* the fifo contents need shifting */
fifo_shift = 32 - bits;
@@ -692,7 +594,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
sh_msiof_write(p, SIFCTR, 0);
/* setup msiof transfer mode registers */
- sh_msiof_spi_set_mode_regs(p, tx_buf, rx_buf, bits, words);
+ sh_msiof_spi_set_mode_regs(p, tx_buf, rx_buf, bits, words, 0);
sh_msiof_write(p, SIIER, SIIER_TEOFE | SIIER_REOFE);
/* write tx fifo */
@@ -700,7 +602,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
tx_fifo(p, tx_buf, words, fifo_shift);
reinit_completion(&p->done);
- p->slave_aborted = false;
+ p->target_aborted = false;
ret = sh_msiof_spi_start(p, rx_buf);
if (ret) {
@@ -742,10 +644,12 @@ static void sh_msiof_dma_complete(void *arg)
}
static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
- void *rx, unsigned int len)
+ void *rx, unsigned int len,
+ unsigned int max_wdlen)
{
u32 ier_bits = 0;
struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
+ unsigned int words1, words2;
dma_cookie_t cookie;
int ret;
@@ -787,17 +691,21 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
}
/* 1 stage FIFO watermarks for DMA */
- sh_msiof_write(p, SIFCTR, SIFCTR_TFWM_1 | SIFCTR_RFWM_1);
+ sh_msiof_write(p, SIFCTR,
+ FIELD_PREP(SIFCTR_TFWM, SIFCTR_TFWM_1) |
+ FIELD_PREP(SIFCTR_RFWM, SIFCTR_RFWM_1));
/* setup msiof transfer mode registers (32-bit words) */
- sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4);
+ words1 = min(len / 4, max_wdlen);
+ words2 = len / 4 - words1;
+ sh_msiof_spi_set_mode_regs(p, tx, rx, 32, words1, words2);
sh_msiof_write(p, SIIER, ier_bits);
reinit_completion(&p->done);
if (tx)
reinit_completion(&p->done_txdma);
- p->slave_aborted = false;
+ p->target_aborted = false;
/* Now start DMA */
if (rx)
@@ -909,9 +817,12 @@ static int sh_msiof_transfer_one(struct spi_controller *ctlr,
struct spi_transfer *t)
{
struct sh_msiof_spi_priv *p = spi_controller_get_devdata(ctlr);
+ unsigned int max_wdlen = FIELD_MAX(SIMDR2_WDLEN1) + 1;
void (*copy32)(u32 *, const u32 *, unsigned int);
- void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int);
- void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int);
+ void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, unsigned int,
+ unsigned int);
+ void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, unsigned int,
+ unsigned int);
const void *tx_buf = t->tx_buf;
void *rx_buf = t->rx_buf;
unsigned int len = t->len;
@@ -926,20 +837,20 @@ static int sh_msiof_transfer_one(struct spi_controller *ctlr,
sh_msiof_spi_reset_regs(p);
/* setup clocks (clock already enabled in chipselect()) */
- if (!spi_controller_is_slave(p->ctlr))
+ if (!spi_controller_is_target(p->ctlr))
sh_msiof_spi_set_clk_regs(p, t);
+ if (tx_buf)
+ max_wdlen = min(max_wdlen, p->tx_fifo_size);
+ if (rx_buf)
+ max_wdlen = min(max_wdlen, p->rx_fifo_size);
+
while (ctlr->dma_tx && len > 15) {
/*
* DMA supports 32-bit words only, hence pack 8-bit and 16-bit
* words, with byte resp. word swapping.
*/
- unsigned int l = 0;
-
- if (tx_buf)
- l = min(round_down(len, 4), p->tx_fifo_size * 4);
- if (rx_buf)
- l = min(round_down(len, 4), p->rx_fifo_size * 4);
+ unsigned int l = min(round_down(len, 4), 2 * max_wdlen * 4);
if (bits <= 8) {
copy32 = copy_bswap32;
@@ -952,7 +863,7 @@ static int sh_msiof_transfer_one(struct spi_controller *ctlr,
if (tx_buf)
copy32(p->tx_dma_page, tx_buf, l / 4);
- ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l);
+ ret = sh_msiof_dma_once(p, tx_buf, rx_buf, l, max_wdlen);
if (ret == -EAGAIN) {
dev_warn_once(&p->pdev->dev,
"DMA not available, falling back to PIO\n");
@@ -1059,7 +970,7 @@ static const struct sh_msiof_chipdata rcar_gen2_data = {
.bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
SPI_BPW_MASK(24) | SPI_BPW_MASK(32),
.tx_fifo_size = 64,
- .rx_fifo_size = 64,
+ .rx_fifo_size = 128,
.ctlr_flags = SPI_CONTROLLER_MUST_TX,
.min_div_pow = 0,
};
@@ -1068,26 +979,40 @@ static const struct sh_msiof_chipdata rcar_gen3_data = {
.bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
SPI_BPW_MASK(24) | SPI_BPW_MASK(32),
.tx_fifo_size = 64,
- .rx_fifo_size = 64,
+ .rx_fifo_size = 256,
.ctlr_flags = SPI_CONTROLLER_MUST_TX,
.min_div_pow = 1,
};
+static const struct sh_msiof_chipdata rcar_gen4_data = {
+ .bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(24) | SPI_BPW_MASK(32),
+ .tx_fifo_size = 256,
+ .rx_fifo_size = 256,
+ .ctlr_flags = SPI_CONTROLLER_MUST_TX,
+ .min_div_pow = 1,
+};
+
+static const struct sh_msiof_chipdata rcar_r8a7795_data = {
+ .bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(24) | SPI_BPW_MASK(32),
+ .tx_fifo_size = 64,
+ .rx_fifo_size = 256,
+ .ctlr_flags = SPI_CONTROLLER_MUST_TX,
+ .min_div_pow = 1,
+ .flags = SH_MSIOF_FLAG_FIXED_DTDL_200,
+};
+
static const struct of_device_id sh_msiof_match[] __maybe_unused = {
{ .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
- { .compatible = "renesas,msiof-r8a7743", .data = &rcar_gen2_data },
- { .compatible = "renesas,msiof-r8a7745", .data = &rcar_gen2_data },
- { .compatible = "renesas,msiof-r8a7790", .data = &rcar_gen2_data },
- { .compatible = "renesas,msiof-r8a7791", .data = &rcar_gen2_data },
- { .compatible = "renesas,msiof-r8a7792", .data = &rcar_gen2_data },
- { .compatible = "renesas,msiof-r8a7793", .data = &rcar_gen2_data },
- { .compatible = "renesas,msiof-r8a7794", .data = &rcar_gen2_data },
{ .compatible = "renesas,rcar-gen2-msiof", .data = &rcar_gen2_data },
- { .compatible = "renesas,msiof-r8a7796", .data = &rcar_gen3_data },
+ { .compatible = "renesas,msiof-r8a7795", .data = &rcar_r8a7795_data },
{ .compatible = "renesas,rcar-gen3-msiof", .data = &rcar_gen3_data },
- { .compatible = "renesas,rcar-gen4-msiof", .data = &rcar_gen3_data },
+ { .compatible = "renesas,msiof-r8a779a0", .data = &rcar_gen3_data },
+ { .compatible = "renesas,msiof-r8a779f0", .data = &rcar_gen3_data },
+ { .compatible = "renesas,rcar-gen4-msiof", .data = &rcar_gen4_data },
{ .compatible = "renesas,sh-msiof", .data = &sh_data }, /* Deprecated */
- {},
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sh_msiof_match);
@@ -1102,11 +1027,11 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
if (!info)
return NULL;
- info->mode = of_property_read_bool(np, "spi-slave") ? MSIOF_SPI_SLAVE
- : MSIOF_SPI_MASTER;
+ info->mode = of_property_read_bool(np, "spi-slave") ? MSIOF_SPI_TARGET
+ : MSIOF_SPI_HOST;
/* Parse the MSIOF properties */
- if (info->mode == MSIOF_SPI_MASTER)
+ if (info->mode == MSIOF_SPI_HOST)
of_property_read_u32(np, "num-cs", &num_cs);
of_property_read_u32(np, "renesas,tx-fifo-size",
&info->tx_fifo_override);
@@ -1263,29 +1188,36 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info;
struct sh_msiof_spi_priv *p;
+ struct device *dev = &pdev->dev;
unsigned long clksrc;
int i;
int ret;
- chipdata = of_device_get_match_data(&pdev->dev);
+ /* Check whether MSIOF is used as I2S mode or SPI mode by checking "port" node */
+ struct device_node *port __free(device_node) = of_graph_get_next_port(dev->of_node, NULL);
+ if (port) /* It was MSIOF-I2S */
+ return -ENODEV;
+
+ chipdata = of_device_get_match_data(dev);
if (chipdata) {
- info = sh_msiof_spi_parse_dt(&pdev->dev);
+ info = sh_msiof_spi_parse_dt(dev);
} else {
chipdata = (const void *)pdev->id_entry->driver_data;
- info = dev_get_platdata(&pdev->dev);
+ info = dev_get_platdata(dev);
}
if (!info) {
- dev_err(&pdev->dev, "failed to obtain device info\n");
+ dev_err(dev, "failed to obtain device info\n");
return -ENXIO;
}
- if (info->mode == MSIOF_SPI_SLAVE)
- ctlr = spi_alloc_slave(&pdev->dev,
- sizeof(struct sh_msiof_spi_priv));
+ if (chipdata->flags & SH_MSIOF_FLAG_FIXED_DTDL_200)
+ info->dtdl = 200;
+
+ if (info->mode == MSIOF_SPI_TARGET)
+ ctlr = spi_alloc_target(dev, sizeof(struct sh_msiof_spi_priv));
else
- ctlr = spi_alloc_master(&pdev->dev,
- sizeof(struct sh_msiof_spi_priv));
+ ctlr = spi_alloc_host(dev, sizeof(struct sh_msiof_spi_priv));
if (ctlr == NULL)
return -ENOMEM;
@@ -1299,9 +1231,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
init_completion(&p->done);
init_completion(&p->done_txdma);
- p->clk = devm_clk_get(&pdev->dev, NULL);
+ p->clk = devm_clk_get(dev, NULL);
if (IS_ERR(p->clk)) {
- dev_err(&pdev->dev, "cannot get clock\n");
+ dev_err(dev, "cannot get clock\n");
ret = PTR_ERR(p->clk);
goto err1;
}
@@ -1318,15 +1250,14 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
goto err1;
}
- ret = devm_request_irq(&pdev->dev, i, sh_msiof_spi_irq, 0,
- dev_name(&pdev->dev), p);
+ ret = devm_request_irq(dev, i, sh_msiof_spi_irq, 0, dev_name(dev), p);
if (ret) {
- dev_err(&pdev->dev, "unable to request irq\n");
+ dev_err(dev, "unable to request irq\n");
goto err1;
}
p->pdev = pdev;
- pm_runtime_enable(&pdev->dev);
+ pm_runtime_enable(dev);
/* Platform data may override FIFO sizes */
p->tx_fifo_size = chipdata->tx_fifo_size;
@@ -1345,10 +1276,10 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
ctlr->flags = chipdata->ctlr_flags;
ctlr->bus_num = pdev->id;
ctlr->num_chipselect = p->info->num_chipselect;
- ctlr->dev.of_node = pdev->dev.of_node;
+ ctlr->dev.of_node = dev->of_node;
ctlr->setup = sh_msiof_spi_setup;
ctlr->prepare_message = sh_msiof_prepare_message;
- ctlr->slave_abort = sh_msiof_slave_abort;
+ ctlr->target_abort = sh_msiof_target_abort;
ctlr->bits_per_word_mask = chipdata->bits_per_word_mask;
ctlr->auto_runtime_pm = true;
ctlr->transfer_one = sh_msiof_transfer_one;
@@ -1357,11 +1288,11 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
ret = sh_msiof_request_dma(p);
if (ret < 0)
- dev_warn(&pdev->dev, "DMA not available, using PIO\n");
+ dev_warn(dev, "DMA not available, using PIO\n");
- ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ ret = devm_spi_register_controller(dev, ctlr);
if (ret < 0) {
- dev_err(&pdev->dev, "devm_spi_register_controller error.\n");
+ dev_err(dev, "devm_spi_register_controller error.\n");
goto err2;
}
@@ -1369,7 +1300,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
err2:
sh_msiof_release_dma(p);
- pm_runtime_disable(&pdev->dev);
+ pm_runtime_disable(dev);
err1:
spi_controller_put(ctlr);
return ret;
@@ -1389,7 +1320,6 @@ static const struct platform_device_id spi_driver_ids[] = {
};
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
-#ifdef CONFIG_PM_SLEEP
static int sh_msiof_spi_suspend(struct device *dev)
{
struct sh_msiof_spi_priv *p = dev_get_drvdata(dev);
@@ -1404,20 +1334,16 @@ static int sh_msiof_spi_resume(struct device *dev)
return spi_controller_resume(p->ctlr);
}
-static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend,
- sh_msiof_spi_resume);
-#define DEV_PM_OPS (&sh_msiof_spi_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
+static DEFINE_SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend,
+ sh_msiof_spi_resume);
static struct platform_driver sh_msiof_spi_drv = {
.probe = sh_msiof_spi_probe,
- .remove_new = sh_msiof_spi_remove,
+ .remove = sh_msiof_spi_remove,
.id_table = spi_driver_ids,
.driver = {
.name = "spi_sh_msiof",
- .pm = DEV_PM_OPS,
+ .pm = pm_sleep_ptr(&sh_msiof_spi_pm_ops),
.of_match_table = of_match_ptr(sh_msiof_match),
},
};
diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c
index 92ca3f2d61ba..f66efaabcaca 100644
--- a/drivers/spi/spi-sh-sci.c
+++ b/drivers/spi/spi-sh-sci.c
@@ -56,17 +56,17 @@ static inline void setbits(struct sh_sci_spi *sp, int bits, int on)
static inline void setsck(struct spi_device *dev, int on)
{
- setbits(spi_master_get_devdata(dev->master), PIN_SCK, on);
+ setbits(spi_controller_get_devdata(dev->controller), PIN_SCK, on);
}
static inline void setmosi(struct spi_device *dev, int on)
{
- setbits(spi_master_get_devdata(dev->master), PIN_TXD, on);
+ setbits(spi_controller_get_devdata(dev->controller), PIN_TXD, on);
}
static inline u32 getmiso(struct spi_device *dev)
{
- struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+ struct sh_sci_spi *sp = spi_controller_get_devdata(dev->controller);
return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0;
}
@@ -105,7 +105,7 @@ static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi,
static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
{
- struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
+ struct sh_sci_spi *sp = spi_controller_get_devdata(dev->controller);
if (sp->info->chip_select)
(sp->info->chip_select)(sp->info, spi_get_chipselect(dev, 0), value);
@@ -114,18 +114,18 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
static int sh_sci_spi_probe(struct platform_device *dev)
{
struct resource *r;
- struct spi_master *master;
+ struct spi_controller *host;
struct sh_sci_spi *sp;
int ret;
- master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi));
- if (master == NULL) {
- dev_err(&dev->dev, "failed to allocate spi master\n");
+ host = spi_alloc_host(&dev->dev, sizeof(struct sh_sci_spi));
+ if (host == NULL) {
+ dev_err(&dev->dev, "failed to allocate spi host\n");
ret = -ENOMEM;
goto err0;
}
- sp = spi_master_get_devdata(master);
+ sp = spi_controller_get_devdata(host);
platform_set_drvdata(dev, sp);
sp->info = dev_get_platdata(&dev->dev);
@@ -136,9 +136,9 @@ static int sh_sci_spi_probe(struct platform_device *dev)
}
/* setup spi bitbang adaptor */
- sp->bitbang.master = master;
- sp->bitbang.master->bus_num = sp->info->bus_num;
- sp->bitbang.master->num_chipselect = sp->info->num_chipselect;
+ sp->bitbang.ctlr = host;
+ sp->bitbang.ctlr->bus_num = sp->info->bus_num;
+ sp->bitbang.ctlr->num_chipselect = sp->info->num_chipselect;
sp->bitbang.chipselect = sh_sci_spi_chipselect;
sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0;
@@ -166,7 +166,7 @@ static int sh_sci_spi_probe(struct platform_device *dev)
setbits(sp, PIN_INIT, 0);
iounmap(sp->membase);
err1:
- spi_master_put(sp->bitbang.master);
+ spi_controller_put(sp->bitbang.ctlr);
err0:
return ret;
}
@@ -178,12 +178,12 @@ static void sh_sci_spi_remove(struct platform_device *dev)
spi_bitbang_stop(&sp->bitbang);
setbits(sp, PIN_INIT, 0);
iounmap(sp->membase);
- spi_master_put(sp->bitbang.master);
+ spi_controller_put(sp->bitbang.ctlr);
}
static struct platform_driver sh_sci_spi_drv = {
.probe = sh_sci_spi_probe,
- .remove_new = sh_sci_spi_remove,
+ .remove = sh_sci_spi_remove,
.driver = {
.name = "spi_sh_sci",
},
diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c
index d358a2a9c3f5..130d7fc452fa 100644
--- a/drivers/spi/spi-sh.c
+++ b/drivers/spi/spi-sh.c
@@ -72,7 +72,7 @@
struct spi_sh_data {
void __iomem *addr;
int irq;
- struct spi_master *master;
+ struct spi_controller *host;
unsigned long cr1;
wait_queue_head_t wait;
int width;
@@ -327,7 +327,7 @@ static int spi_sh_transfer_one_message(struct spi_controller *ctlr,
static int spi_sh_setup(struct spi_device *spi)
{
- struct spi_sh_data *ss = spi_master_get_devdata(spi->master);
+ struct spi_sh_data *ss = spi_controller_get_devdata(spi->controller);
pr_debug("%s: enter\n", __func__);
@@ -346,7 +346,7 @@ static int spi_sh_setup(struct spi_device *spi)
static void spi_sh_cleanup(struct spi_device *spi)
{
- struct spi_sh_data *ss = spi_master_get_devdata(spi->master);
+ struct spi_sh_data *ss = spi_controller_get_devdata(spi->controller);
pr_debug("%s: enter\n", __func__);
@@ -381,14 +381,14 @@ static void spi_sh_remove(struct platform_device *pdev)
{
struct spi_sh_data *ss = platform_get_drvdata(pdev);
- spi_unregister_master(ss->master);
+ spi_unregister_controller(ss->host);
free_irq(ss->irq, ss);
}
static int spi_sh_probe(struct platform_device *pdev)
{
struct resource *res;
- struct spi_master *master;
+ struct spi_controller *host;
struct spi_sh_data *ss;
int ret, irq;
@@ -403,13 +403,13 @@ static int spi_sh_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(struct spi_sh_data));
- if (master == NULL) {
- dev_err(&pdev->dev, "spi_alloc_master error.\n");
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(struct spi_sh_data));
+ if (host == NULL) {
+ dev_err(&pdev->dev, "devm_spi_alloc_host error.\n");
return -ENOMEM;
}
- ss = spi_master_get_devdata(master);
+ ss = spi_controller_get_devdata(host);
platform_set_drvdata(pdev, ss);
switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
@@ -424,7 +424,7 @@ static int spi_sh_probe(struct platform_device *pdev)
return -ENODEV;
}
ss->irq = irq;
- ss->master = master;
+ ss->host = host;
ss->addr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (ss->addr == NULL) {
dev_err(&pdev->dev, "ioremap error.\n");
@@ -438,15 +438,15 @@ static int spi_sh_probe(struct platform_device *pdev)
return ret;
}
- master->num_chipselect = 2;
- master->bus_num = pdev->id;
- master->setup = spi_sh_setup;
- master->transfer_one_message = spi_sh_transfer_one_message;
- master->cleanup = spi_sh_cleanup;
+ host->num_chipselect = 2;
+ host->bus_num = pdev->id;
+ host->setup = spi_sh_setup;
+ host->transfer_one_message = spi_sh_transfer_one_message;
+ host->cleanup = spi_sh_cleanup;
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret < 0) {
- printk(KERN_ERR "spi_register_master error.\n");
+ printk(KERN_ERR "spi_register_controller error.\n");
goto error3;
}
@@ -459,7 +459,7 @@ static int spi_sh_probe(struct platform_device *pdev)
static struct platform_driver spi_sh_driver = {
.probe = spi_sh_probe,
- .remove_new = spi_sh_remove,
+ .remove = spi_sh_remove,
.driver = {
.name = "sh_spi",
},
diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c
index dae9e097c333..87bde2a207a3 100644
--- a/drivers/spi/spi-sifive.c
+++ b/drivers/spi/spi-sifive.c
@@ -128,9 +128,9 @@ static void sifive_spi_init(struct sifive_spi *spi)
}
static int
-sifive_spi_prepare_message(struct spi_master *master, struct spi_message *msg)
+sifive_spi_prepare_message(struct spi_controller *host, struct spi_message *msg)
{
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
struct spi_device *device = msg->spi;
/* Update the chip select polarity */
@@ -152,7 +152,7 @@ sifive_spi_prepare_message(struct spi_master *master, struct spi_message *msg)
static void sifive_spi_set_cs(struct spi_device *device, bool is_high)
{
- struct sifive_spi *spi = spi_master_get_devdata(device->master);
+ struct sifive_spi *spi = spi_controller_get_devdata(device->controller);
/* Reverse polarity is handled by SCMR/CPOL. Not inverted CS. */
if (device->mode & SPI_CS_HIGH)
@@ -252,10 +252,10 @@ static void sifive_spi_rx(struct sifive_spi *spi, u8 *rx_ptr)
}
static int
-sifive_spi_transfer_one(struct spi_master *master, struct spi_device *device,
+sifive_spi_transfer_one(struct spi_controller *host, struct spi_device *device,
struct spi_transfer *t)
{
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
int poll = sifive_spi_prep_transfer(spi, device, t);
const u8 *tx_ptr = t->tx_buf;
u8 *rx_ptr = t->rx_buf;
@@ -294,35 +294,35 @@ static int sifive_spi_probe(struct platform_device *pdev)
struct sifive_spi *spi;
int ret, irq, num_cs;
u32 cs_bits, max_bits_per_word;
- struct spi_master *master;
+ struct spi_controller *host;
- master = spi_alloc_master(&pdev->dev, sizeof(struct sifive_spi));
- if (!master) {
+ host = spi_alloc_host(&pdev->dev, sizeof(struct sifive_spi));
+ if (!host) {
dev_err(&pdev->dev, "out of memory\n");
return -ENOMEM;
}
- spi = spi_master_get_devdata(master);
+ spi = spi_controller_get_devdata(host);
init_completion(&spi->done);
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
spi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(spi->regs)) {
ret = PTR_ERR(spi->regs);
- goto put_master;
+ goto put_host;
}
spi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(spi->clk)) {
dev_err(&pdev->dev, "Unable to find bus clock\n");
ret = PTR_ERR(spi->clk);
- goto put_master;
+ goto put_host;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto put_master;
+ goto put_host;
}
/* Optional parameters */
@@ -339,14 +339,14 @@ static int sifive_spi_probe(struct platform_device *pdev)
if (!ret && max_bits_per_word < 8) {
dev_err(&pdev->dev, "Only 8bit SPI words supported by the driver\n");
ret = -EINVAL;
- goto put_master;
+ goto put_host;
}
/* Spin up the bus clock before hitting registers */
ret = clk_prepare_enable(spi->clk);
if (ret) {
dev_err(&pdev->dev, "Unable to enable bus clock\n");
- goto put_master;
+ goto put_host;
}
/* probe the number of CS lines */
@@ -362,30 +362,30 @@ static int sifive_spi_probe(struct platform_device *pdev)
num_cs = ilog2(cs_bits) + 1;
if (num_cs > SIFIVE_SPI_MAX_CS) {
- dev_err(&pdev->dev, "Invalid number of spi slaves\n");
+ dev_err(&pdev->dev, "Invalid number of spi targets\n");
ret = -EINVAL;
goto disable_clk;
}
- /* Define our master */
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = pdev->id;
- master->num_chipselect = num_cs;
- master->mode_bits = SPI_CPHA | SPI_CPOL
+ /* Define our host */
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = pdev->id;
+ host->num_chipselect = num_cs;
+ host->mode_bits = SPI_CPHA | SPI_CPOL
| SPI_CS_HIGH | SPI_LSB_FIRST
| SPI_TX_DUAL | SPI_TX_QUAD
| SPI_RX_DUAL | SPI_RX_QUAD;
/* TODO: add driver support for bits_per_word < 8
* we need to "left-align" the bits (unless SPI_LSB_FIRST)
*/
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->flags = SPI_CONTROLLER_MUST_TX | SPI_MASTER_GPIO_SS;
- master->prepare_message = sifive_spi_prepare_message;
- master->set_cs = sifive_spi_set_cs;
- master->transfer_one = sifive_spi_transfer_one;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->flags = SPI_CONTROLLER_MUST_TX | SPI_CONTROLLER_GPIO_SS;
+ host->prepare_message = sifive_spi_prepare_message;
+ host->set_cs = sifive_spi_set_cs;
+ host->transfer_one = sifive_spi_transfer_one;
pdev->dev.dma_mask = NULL;
- /* Configure the SPI master hardware */
+ /* Configure the SPI host hardware */
sifive_spi_init(spi);
/* Register for SPI Interrupt */
@@ -397,11 +397,11 @@ static int sifive_spi_probe(struct platform_device *pdev)
}
dev_info(&pdev->dev, "mapped; irq=%d, cs=%d\n",
- irq, master->num_chipselect);
+ irq, host->num_chipselect);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret < 0) {
- dev_err(&pdev->dev, "spi_register_master failed\n");
+ dev_err(&pdev->dev, "spi_register_host failed\n");
goto disable_clk;
}
@@ -409,16 +409,16 @@ static int sifive_spi_probe(struct platform_device *pdev)
disable_clk:
clk_disable_unprepare(spi->clk);
-put_master:
- spi_master_put(master);
+put_host:
+ spi_controller_put(host);
return ret;
}
static void sifive_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
/* Disable all the interrupts just in case */
sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
@@ -427,11 +427,11 @@ static void sifive_spi_remove(struct platform_device *pdev)
static int sifive_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -445,14 +445,14 @@ static int sifive_spi_suspend(struct device *dev)
static int sifive_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sifive_spi *spi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sifive_spi *spi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(spi->clk);
if (ret)
return ret;
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret)
clk_disable_unprepare(spi->clk);
@@ -471,7 +471,7 @@ MODULE_DEVICE_TABLE(of, sifive_spi_of_match);
static struct platform_driver sifive_spi_driver = {
.probe = sifive_spi_probe,
- .remove_new = sifive_spi_remove,
+ .remove = sifive_spi_remove,
.driver = {
.name = SIFIVE_SPI_DRIVER_NAME,
.pm = &sifive_spi_pm_ops,
diff --git a/drivers/spi/spi-slave-mt27xx.c b/drivers/spi/spi-slave-mt27xx.c
index 4e4d426bfb43..e331df967385 100644
--- a/drivers/spi/spi-slave-mt27xx.c
+++ b/drivers/spi/spi-slave-mt27xx.c
@@ -69,7 +69,7 @@ struct mtk_spi_slave {
struct clk *spi_clk;
struct completion xfer_done;
struct spi_transfer *cur_transfer;
- bool slave_aborted;
+ bool target_aborted;
const struct mtk_spi_compatible *dev_comp;
};
@@ -118,7 +118,7 @@ static void mtk_spi_slave_disable_xfer(struct mtk_spi_slave *mdata)
static int mtk_spi_slave_wait_for_completion(struct mtk_spi_slave *mdata)
{
if (wait_for_completion_interruptible(&mdata->xfer_done) ||
- mdata->slave_aborted) {
+ mdata->target_aborted) {
dev_err(mdata->dev, "interrupted\n");
return -EINTR;
}
@@ -286,7 +286,7 @@ static int mtk_spi_slave_transfer_one(struct spi_controller *ctlr,
struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
reinit_completion(&mdata->xfer_done);
- mdata->slave_aborted = false;
+ mdata->target_aborted = false;
mdata->cur_transfer = xfer;
if (xfer->len > mdata->dev_comp->max_fifo_size)
@@ -297,7 +297,7 @@ static int mtk_spi_slave_transfer_one(struct spi_controller *ctlr,
static int mtk_spi_slave_setup(struct spi_device *spi)
{
- struct mtk_spi_slave *mdata = spi_controller_get_devdata(spi->master);
+ struct mtk_spi_slave *mdata = spi_controller_get_devdata(spi->controller);
u32 reg_val;
reg_val = DMA_DONE_EN | DATA_DONE_EN |
@@ -314,11 +314,11 @@ static int mtk_spi_slave_setup(struct spi_device *spi)
return 0;
}
-static int mtk_slave_abort(struct spi_controller *ctlr)
+static int mtk_target_abort(struct spi_controller *ctlr)
{
struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
- mdata->slave_aborted = true;
+ mdata->target_aborted = true;
complete(&mdata->xfer_done);
return 0;
@@ -388,9 +388,9 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
int irq, ret;
const struct of_device_id *of_id;
- ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata));
+ ctlr = spi_alloc_target(&pdev->dev, sizeof(*mdata));
if (!ctlr) {
- dev_err(&pdev->dev, "failed to alloc spi slave\n");
+ dev_err(&pdev->dev, "failed to alloc spi target\n");
return -ENOMEM;
}
@@ -402,7 +402,7 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
ctlr->prepare_message = mtk_spi_slave_prepare_message;
ctlr->transfer_one = mtk_spi_slave_transfer_one;
ctlr->setup = mtk_spi_slave_setup;
- ctlr->slave_abort = mtk_slave_abort;
+ ctlr->target_abort = mtk_target_abort;
of_id = of_match_node(mtk_spi_slave_of_match, pdev->dev.of_node);
if (!of_id) {
@@ -414,7 +414,7 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
mdata->dev_comp = of_id->data;
if (mdata->dev_comp->must_rx)
- ctlr->flags = SPI_MASTER_MUST_RX;
+ ctlr->flags = SPI_CONTROLLER_MUST_RX;
platform_set_drvdata(pdev, ctlr);
@@ -455,15 +455,13 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ clk_disable_unprepare(mdata->spi_clk);
if (ret) {
dev_err(&pdev->dev,
"failed to register slave controller(%d)\n", ret);
- clk_disable_unprepare(mdata->spi_clk);
goto err_disable_runtime_pm;
}
- clk_disable_unprepare(mdata->spi_clk);
-
return 0;
err_disable_runtime_pm:
@@ -558,7 +556,7 @@ static struct platform_driver mtk_spi_slave_driver = {
.of_match_table = mtk_spi_slave_of_match,
},
.probe = mtk_spi_slave_probe,
- .remove_new = mtk_spi_slave_remove,
+ .remove = mtk_spi_slave_remove,
};
module_platform_driver(mtk_spi_slave_driver);
diff --git a/drivers/spi/spi-slave-system-control.c b/drivers/spi/spi-slave-system-control.c
index d37cfe995a63..8f5c32b61a5b 100644
--- a/drivers/spi/spi-slave-system-control.c
+++ b/drivers/spi/spi-slave-system-control.c
@@ -136,7 +136,7 @@ static void spi_slave_system_control_remove(struct spi_device *spi)
{
struct spi_slave_system_control_priv *priv = spi_get_drvdata(spi);
- spi_slave_abort(spi);
+ spi_target_abort(spi);
wait_for_completion(&priv->finished);
}
diff --git a/drivers/spi/spi-slave-time.c b/drivers/spi/spi-slave-time.c
index f56c1afb8534..8bb3070e4b80 100644
--- a/drivers/spi/spi-slave-time.c
+++ b/drivers/spi/spi-slave-time.c
@@ -110,7 +110,7 @@ static void spi_slave_time_remove(struct spi_device *spi)
{
struct spi_slave_time_priv *priv = spi_get_drvdata(spi);
- spi_slave_abort(spi);
+ spi_target_abort(spi);
wait_for_completion(&priv->finished);
}
diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c
index d64d3f75c726..c4969f66a0ba 100644
--- a/drivers/spi/spi-sn-f-ospi.c
+++ b/drivers/spi/spi-sn-f-ospi.c
@@ -10,7 +10,7 @@
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
@@ -116,6 +116,9 @@ struct f_ospi {
static u32 f_ospi_get_dummy_cycle(const struct spi_mem_op *op)
{
+ if (!op->dummy.nbytes)
+ return 0;
+
return (op->dummy.nbytes * 8) / op->dummy.buswidth;
}
@@ -335,7 +338,6 @@ static void f_ospi_config_indir_protocol(struct f_ospi *ospi,
static int f_ospi_indir_prepare_op(struct f_ospi *ospi, struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct spi_device *spi = mem->spi;
u32 irq_stat_en;
int ret;
@@ -343,7 +345,7 @@ static int f_ospi_indir_prepare_op(struct f_ospi *ospi, struct spi_mem *mem,
if (ret)
return ret;
- f_ospi_config_clk(ospi, spi->max_speed_hz);
+ f_ospi_config_clk(ospi, op->max_freq);
f_ospi_config_indir_protocol(ospi, mem, op);
@@ -501,7 +503,7 @@ out:
static int f_ospi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct f_ospi *ospi = spi_controller_get_devdata(mem->spi->master);
+ struct f_ospi *ospi = spi_controller_get_devdata(mem->spi->controller);
int err = 0;
switch (op->data.dir) {
@@ -577,6 +579,10 @@ static const struct spi_controller_mem_ops f_ospi_mem_ops = {
.exec_op = f_ospi_exec_op,
};
+static const struct spi_controller_mem_caps f_ospi_mem_caps = {
+ .per_op_freq = true,
+};
+
static int f_ospi_init(struct f_ospi *ospi)
{
int ret;
@@ -606,7 +612,7 @@ static int f_ospi_probe(struct platform_device *pdev)
u32 num_cs = OSPI_NUM_CS;
int ret;
- ctlr = spi_alloc_master(dev, sizeof(*ospi));
+ ctlr = spi_alloc_host(dev, sizeof(*ospi));
if (!ctlr)
return -ENOMEM;
@@ -614,6 +620,7 @@ static int f_ospi_probe(struct platform_device *pdev)
| SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL
| SPI_MODE_0 | SPI_MODE_1 | SPI_LSB_FIRST;
ctlr->mem_ops = &f_ospi_mem_ops;
+ ctlr->mem_caps = &f_ospi_mem_caps;
ctlr->bus_num = -1;
of_property_read_u32(dev->of_node, "num-cs", &num_cs);
if (num_cs > OSPI_NUM_CS) {
@@ -680,7 +687,7 @@ static struct platform_driver f_ospi_driver = {
.of_match_table = f_ospi_dt_ids,
},
.probe = f_ospi_probe,
- .remove_new = f_ospi_remove,
+ .remove = f_ospi_remove,
};
module_platform_driver(f_ospi_driver);
diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c
index 22e39c4c12c4..262c11d977ea 100644
--- a/drivers/spi/spi-sprd-adi.c
+++ b/drivers/spi/spi-sprd-adi.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/spi/spi.h>
@@ -139,8 +138,7 @@ struct sprd_adi_data {
u32 slave_offset;
u32 slave_addr_size;
int (*read_check)(u32 val, u32 reg);
- int (*restart)(struct notifier_block *this,
- unsigned long mode, void *cmd);
+ int (*restart)(struct sys_off_data *data);
void (*wdg_rst)(void *p);
};
@@ -151,7 +149,6 @@ struct sprd_adi {
struct hwspinlock *hwlock;
unsigned long slave_vbase;
unsigned long slave_pbase;
- struct notifier_block restart_handler;
const struct sprd_adi_data *data;
};
@@ -371,11 +368,9 @@ static void sprd_adi_set_wdt_rst_mode(void *p)
#endif
}
-static int sprd_adi_restart(struct notifier_block *this, unsigned long mode,
- void *cmd, struct sprd_adi_wdg *wdg)
+static int sprd_adi_restart(struct sprd_adi *sadi, unsigned long mode,
+ const char *cmd, struct sprd_adi_wdg *wdg)
{
- struct sprd_adi *sadi = container_of(this, struct sprd_adi,
- restart_handler);
u32 val, reboot_mode = 0;
if (!cmd)
@@ -449,8 +444,7 @@ static int sprd_adi_restart(struct notifier_block *this, unsigned long mode,
return NOTIFY_DONE;
}
-static int sprd_adi_restart_sc9860(struct notifier_block *this,
- unsigned long mode, void *cmd)
+static int sprd_adi_restart_sc9860(struct sys_off_data *data)
{
struct sprd_adi_wdg wdg = {
.base = PMIC_WDG_BASE,
@@ -459,7 +453,7 @@ static int sprd_adi_restart_sc9860(struct notifier_block *this,
.wdg_clk = PMIC_CLK_EN,
};
- return sprd_adi_restart(this, mode, cmd, &wdg);
+ return sprd_adi_restart(data->cb_data, data->mode, data->cmd, &wdg);
}
static void sprd_adi_hw_init(struct sprd_adi *sadi)
@@ -534,7 +528,7 @@ static int sprd_adi_probe(struct platform_device *pdev)
pdev->id = of_alias_get_id(np, "spi");
num_chipselect = of_get_child_count(np);
- ctlr = spi_alloc_master(&pdev->dev, sizeof(struct sprd_adi));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(struct sprd_adi));
if (!ctlr)
return -ENOMEM;
@@ -580,7 +574,7 @@ static int sprd_adi_probe(struct platform_device *pdev)
ctlr->dev.of_node = pdev->dev.of_node;
ctlr->bus_num = pdev->id;
ctlr->num_chipselect = num_chipselect;
- ctlr->flags = SPI_MASTER_HALF_DUPLEX;
+ ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
ctlr->bits_per_word_mask = 0;
ctlr->transfer_one = sprd_adi_transfer_one;
@@ -591,9 +585,9 @@ static int sprd_adi_probe(struct platform_device *pdev)
}
if (sadi->data->restart) {
- sadi->restart_handler.notifier_call = sadi->data->restart;
- sadi->restart_handler.priority = 128;
- ret = register_restart_handler(&sadi->restart_handler);
+ ret = devm_register_restart_handler(&pdev->dev,
+ sadi->data->restart,
+ sadi);
if (ret) {
dev_err(&pdev->dev, "can not register restart handler\n");
goto put_ctlr;
@@ -607,14 +601,6 @@ put_ctlr:
return ret;
}
-static void sprd_adi_remove(struct platform_device *pdev)
-{
- struct spi_controller *ctlr = dev_get_drvdata(&pdev->dev);
- struct sprd_adi *sadi = spi_controller_get_devdata(ctlr);
-
- unregister_restart_handler(&sadi->restart_handler);
-}
-
static struct sprd_adi_data sc9860_data = {
.slave_offset = ADI_10BIT_SLAVE_OFFSET,
.slave_addr_size = ADI_10BIT_SLAVE_ADDR_SIZE,
@@ -658,7 +644,6 @@ static struct platform_driver sprd_adi_driver = {
.of_match_table = sprd_adi_of_match,
},
.probe = sprd_adi_probe,
- .remove_new = sprd_adi_remove,
};
module_platform_driver(sprd_adi_driver);
diff --git a/drivers/spi/spi-sprd.c b/drivers/spi/spi-sprd.c
index 518c7eaca84e..ad75f5f0f2bf 100644
--- a/drivers/spi/spi-sprd.c
+++ b/drivers/spi/spi-sprd.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -579,7 +578,7 @@ static void sprd_spi_dma_release(struct sprd_spi *ss)
static int sprd_spi_dma_txrx_bufs(struct spi_device *sdev,
struct spi_transfer *t)
{
- struct sprd_spi *ss = spi_master_get_devdata(sdev->master);
+ struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller);
u32 trans_len = ss->trans_len;
int ret, write_size = 0;
@@ -729,7 +728,7 @@ static int sprd_spi_setup_transfer(struct spi_device *sdev,
if (ret)
return ret;
- /* Set tansfer speed and valid bits */
+ /* Set transfer speed and valid bits */
sprd_spi_set_speed(ss, t->speed_hz);
sprd_spi_set_transfer_bits(ss, bits_per_word);
@@ -924,7 +923,7 @@ static int sprd_spi_probe(struct platform_device *pdev)
int ret;
pdev->id = of_alias_get_id(pdev->dev.of_node, "spi");
- sctlr = spi_alloc_master(&pdev->dev, sizeof(*ss));
+ sctlr = spi_alloc_host(&pdev->dev, sizeof(*ss));
if (!sctlr)
return -ENOMEM;
@@ -983,7 +982,6 @@ static int sprd_spi_probe(struct platform_device *pdev)
if (ret)
goto err_rpm_put;
- pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
@@ -1073,7 +1071,7 @@ static struct platform_driver sprd_spi_driver = {
.pm = &sprd_spi_pm_ops,
},
.probe = sprd_spi_probe,
- .remove_new = sprd_spi_remove,
+ .remove = sprd_spi_remove,
};
module_platform_driver(sprd_spi_driver);
diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c
index 7fcff9c539e2..c07c61dc4938 100644
--- a/drivers/spi/spi-st-ssc4.c
+++ b/drivers/spi/spi-st-ssc4.c
@@ -6,7 +6,7 @@
* Patrice Chotard <patrice.chotard@st.com>
* Lee Jones <lee.jones@linaro.org>
*
- * SPI master mode controller driver, used in STMicroelectronics devices.
+ * SPI host mode controller driver, used in STMicroelectronics devices.
*/
#include <linux/clk.h>
@@ -115,10 +115,10 @@ static void ssc_read_rx_fifo(struct spi_st *spi_st)
spi_st->words_remaining -= count;
}
-static int spi_st_transfer_one(struct spi_master *master,
+static int spi_st_transfer_one(struct spi_controller *host,
struct spi_device *spi, struct spi_transfer *t)
{
- struct spi_st *spi_st = spi_master_get_devdata(master);
+ struct spi_st *spi_st = spi_controller_get_devdata(host);
uint32_t ctl = 0;
/* Setup transfer */
@@ -165,7 +165,7 @@ static int spi_st_transfer_one(struct spi_master *master,
if (ctl)
writel_relaxed(ctl, spi_st->base + SSC_CTL);
- spi_finalize_current_transfer(spi->master);
+ spi_finalize_current_transfer(spi->controller);
return t->len;
}
@@ -174,7 +174,7 @@ static int spi_st_transfer_one(struct spi_master *master,
#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH)
static int spi_st_setup(struct spi_device *spi)
{
- struct spi_st *spi_st = spi_master_get_devdata(spi->master);
+ struct spi_st *spi_st = spi_controller_get_devdata(spi->controller);
u32 spi_st_clk, sscbrg, var;
u32 hz = spi->max_speed_hz;
@@ -274,35 +274,35 @@ static irqreturn_t spi_st_irq(int irq, void *dev_id)
static int spi_st_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct spi_master *master;
+ struct spi_controller *host;
struct spi_st *spi_st;
int irq, ret = 0;
u32 var;
- master = spi_alloc_master(&pdev->dev, sizeof(*spi_st));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*spi_st));
+ if (!host)
return -ENOMEM;
- master->dev.of_node = np;
- master->mode_bits = MODEBITS;
- master->setup = spi_st_setup;
- master->transfer_one = spi_st_transfer_one;
- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
- master->auto_runtime_pm = true;
- master->bus_num = pdev->id;
- master->use_gpio_descriptors = true;
- spi_st = spi_master_get_devdata(master);
+ host->dev.of_node = np;
+ host->mode_bits = MODEBITS;
+ host->setup = spi_st_setup;
+ host->transfer_one = spi_st_transfer_one;
+ host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ host->auto_runtime_pm = true;
+ host->bus_num = pdev->id;
+ host->use_gpio_descriptors = true;
+ spi_st = spi_controller_get_devdata(host);
spi_st->clk = devm_clk_get(&pdev->dev, "ssc");
if (IS_ERR(spi_st->clk)) {
dev_err(&pdev->dev, "Unable to request clock\n");
ret = PTR_ERR(spi_st->clk);
- goto put_master;
+ goto put_host;
}
ret = clk_prepare_enable(spi_st->clk);
if (ret)
- goto put_master;
+ goto put_host;
init_completion(&spi_st->done);
@@ -324,7 +324,7 @@ static int spi_st_probe(struct platform_device *pdev)
var &= ~SSC_CTL_SR;
writel_relaxed(var, spi_st->base + SSC_CTL);
- /* Set SSC into slave mode before reconfiguring PIO pins */
+ /* Set SSC into target mode before reconfiguring PIO pins */
var = readl_relaxed(spi_st->base + SSC_CTL);
var &= ~SSC_CTL_MS;
writel_relaxed(var, spi_st->base + SSC_CTL);
@@ -347,11 +347,11 @@ static int spi_st_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&pdev->dev, "Failed to register master\n");
+ dev_err(&pdev->dev, "Failed to register host\n");
goto rpm_disable;
}
@@ -361,15 +361,15 @@ rpm_disable:
pm_runtime_disable(&pdev->dev);
clk_disable:
clk_disable_unprepare(spi_st->clk);
-put_master:
- spi_master_put(master);
+put_host:
+ spi_controller_put(host);
return ret;
}
static void spi_st_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct spi_st *spi_st = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct spi_st *spi_st = spi_controller_get_devdata(host);
pm_runtime_disable(&pdev->dev);
@@ -378,11 +378,10 @@ static void spi_st_remove(struct platform_device *pdev)
pinctrl_pm_select_sleep_state(&pdev->dev);
}
-#ifdef CONFIG_PM
static int spi_st_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct spi_st *spi_st = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct spi_st *spi_st = spi_controller_get_devdata(host);
writel_relaxed(0, spi_st->base + SSC_IEN);
pinctrl_pm_select_sleep_state(dev);
@@ -394,8 +393,8 @@ static int spi_st_runtime_suspend(struct device *dev)
static int spi_st_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct spi_st *spi_st = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct spi_st *spi_st = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(spi_st->clk);
@@ -403,37 +402,34 @@ static int spi_st_runtime_resume(struct device *dev)
return ret;
}
-#endif
-#ifdef CONFIG_PM_SLEEP
-static int spi_st_suspend(struct device *dev)
+static int __maybe_unused spi_st_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
return pm_runtime_force_suspend(dev);
}
-static int spi_st_resume(struct device *dev)
+static int __maybe_unused spi_st_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
int ret;
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret)
return ret;
return pm_runtime_force_resume(dev);
}
-#endif
static const struct dev_pm_ops spi_st_pm = {
- SET_SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume)
- SET_RUNTIME_PM_OPS(spi_st_runtime_suspend, spi_st_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume)
+ RUNTIME_PM_OPS(spi_st_runtime_suspend, spi_st_runtime_resume, NULL)
};
static const struct of_device_id stm_spi_match[] = {
@@ -445,11 +441,11 @@ MODULE_DEVICE_TABLE(of, stm_spi_match);
static struct platform_driver spi_st_driver = {
.driver = {
.name = "spi-st",
- .pm = &spi_st_pm,
+ .pm = pm_ptr(&spi_st_pm),
.of_match_table = of_match_ptr(stm_spi_match),
},
.probe = spi_st_probe,
- .remove_new = spi_st_remove,
+ .remove = spi_st_remove,
};
module_platform_driver(spi_st_driver);
diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
new file mode 100644
index 000000000000..f36fd36da269
--- /dev/null
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -0,0 +1,1068 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2025 - All Rights Reserved
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/types.h>
+
+#define OSPI_CR 0x00
+#define CR_EN BIT(0)
+#define CR_ABORT BIT(1)
+#define CR_DMAEN BIT(2)
+#define CR_FTHRES_SHIFT 8
+#define CR_TEIE BIT(16)
+#define CR_TCIE BIT(17)
+#define CR_SMIE BIT(19)
+#define CR_APMS BIT(22)
+#define CR_CSSEL BIT(24)
+#define CR_FMODE_MASK GENMASK(29, 28)
+#define CR_FMODE_INDW (0U)
+#define CR_FMODE_INDR (1U)
+#define CR_FMODE_APM (2U)
+#define CR_FMODE_MM (3U)
+
+#define OSPI_DCR1 0x08
+#define DCR1_DLYBYP BIT(3)
+#define DCR1_DEVSIZE_MASK GENMASK(20, 16)
+#define DCR1_MTYP_MASK GENMASK(26, 24)
+#define DCR1_MTYP_MX_MODE 1
+#define DCR1_MTYP_HP_MEMMODE 4
+
+#define OSPI_DCR2 0x0c
+#define DCR2_PRESC_MASK GENMASK(7, 0)
+
+#define OSPI_SR 0x20
+#define SR_TEF BIT(0)
+#define SR_TCF BIT(1)
+#define SR_FTF BIT(2)
+#define SR_SMF BIT(3)
+#define SR_BUSY BIT(5)
+
+#define OSPI_FCR 0x24
+#define FCR_CTEF BIT(0)
+#define FCR_CTCF BIT(1)
+#define FCR_CSMF BIT(3)
+
+#define OSPI_DLR 0x40
+#define OSPI_AR 0x48
+#define OSPI_DR 0x50
+#define OSPI_PSMKR 0x80
+#define OSPI_PSMAR 0x88
+
+#define OSPI_CCR 0x100
+#define CCR_IMODE_MASK GENMASK(2, 0)
+#define CCR_IDTR BIT(3)
+#define CCR_ISIZE_MASK GENMASK(5, 4)
+#define CCR_ADMODE_MASK GENMASK(10, 8)
+#define CCR_ADMODE_8LINES 4
+#define CCR_ADDTR BIT(11)
+#define CCR_ADSIZE_MASK GENMASK(13, 12)
+#define CCR_ADSIZE_32BITS 3
+#define CCR_DMODE_MASK GENMASK(26, 24)
+#define CCR_DMODE_8LINES 4
+#define CCR_DQSE BIT(29)
+#define CCR_DDTR BIT(27)
+#define CCR_BUSWIDTH_0 0x0
+#define CCR_BUSWIDTH_1 0x1
+#define CCR_BUSWIDTH_2 0x2
+#define CCR_BUSWIDTH_4 0x3
+#define CCR_BUSWIDTH_8 0x4
+
+#define OSPI_TCR 0x108
+#define TCR_DCYC_MASK GENMASK(4, 0)
+#define TCR_DHQC BIT(28)
+#define TCR_SSHIFT BIT(30)
+
+#define OSPI_IR 0x110
+
+#define STM32_OSPI_MAX_MMAP_SZ SZ_256M
+#define STM32_OSPI_MAX_NORCHIP 2
+
+#define STM32_FIFO_TIMEOUT_US 30000
+#define STM32_ABT_TIMEOUT_US 100000
+#define STM32_COMP_TIMEOUT_MS 5000
+#define STM32_BUSY_TIMEOUT_US 100000
+
+
+#define STM32_AUTOSUSPEND_DELAY -1
+
+struct stm32_ospi {
+ struct device *dev;
+ struct spi_controller *ctrl;
+ struct clk *clk;
+ struct reset_control *rstc;
+
+ struct completion data_completion;
+ struct completion match_completion;
+
+ struct dma_chan *dma_chtx;
+ struct dma_chan *dma_chrx;
+ struct completion dma_completion;
+
+ void __iomem *regs_base;
+ void __iomem *mm_base;
+ phys_addr_t regs_phys_base;
+ resource_size_t mm_size;
+ u32 clk_rate;
+ u32 fmode;
+ u32 cr_reg;
+ u32 dcr_reg;
+ u32 flash_presc[STM32_OSPI_MAX_NORCHIP];
+ int irq;
+ unsigned long status_timeout;
+
+ /*
+ * To protect device configuration, could be different between
+ * 2 flash access
+ */
+ struct mutex lock;
+};
+
+static void stm32_ospi_read_fifo(u8 *val, void __iomem *addr)
+{
+ *val = readb_relaxed(addr);
+}
+
+static void stm32_ospi_write_fifo(u8 *val, void __iomem *addr)
+{
+ writeb_relaxed(*val, addr);
+}
+
+static int stm32_ospi_abort(struct stm32_ospi *ospi)
+{
+ void __iomem *regs_base = ospi->regs_base;
+ u32 cr;
+ int timeout;
+
+ cr = readl_relaxed(regs_base + OSPI_CR) | CR_ABORT;
+ writel_relaxed(cr, regs_base + OSPI_CR);
+
+ /* wait clear of abort bit by hw */
+ timeout = readl_relaxed_poll_timeout_atomic(regs_base + OSPI_CR,
+ cr, !(cr & CR_ABORT), 1,
+ STM32_ABT_TIMEOUT_US);
+
+ if (timeout)
+ dev_err(ospi->dev, "%s abort timeout:%d\n", __func__, timeout);
+
+ return timeout;
+}
+
+static int stm32_ospi_poll(struct stm32_ospi *ospi, u8 *buf, u32 len, bool read)
+{
+ void __iomem *regs_base = ospi->regs_base;
+ void (*fifo)(u8 *val, void __iomem *addr);
+ u32 sr;
+ int ret;
+
+ if (read)
+ fifo = stm32_ospi_read_fifo;
+ else
+ fifo = stm32_ospi_write_fifo;
+
+ while (len--) {
+ ret = readl_relaxed_poll_timeout_atomic(regs_base + OSPI_SR,
+ sr, sr & SR_FTF, 1,
+ STM32_FIFO_TIMEOUT_US);
+ if (ret) {
+ dev_err(ospi->dev, "fifo timeout (len:%d stat:%#x)\n",
+ len, sr);
+ return ret;
+ }
+ fifo(buf++, regs_base + OSPI_DR);
+ }
+
+ return 0;
+}
+
+static int stm32_ospi_wait_nobusy(struct stm32_ospi *ospi)
+{
+ u32 sr;
+
+ return readl_relaxed_poll_timeout_atomic(ospi->regs_base + OSPI_SR,
+ sr, !(sr & SR_BUSY), 1,
+ STM32_BUSY_TIMEOUT_US);
+}
+
+static int stm32_ospi_wait_cmd(struct stm32_ospi *ospi)
+{
+ void __iomem *regs_base = ospi->regs_base;
+ u32 cr, sr;
+ int err = 0;
+
+ if ((readl_relaxed(regs_base + OSPI_SR) & SR_TCF) ||
+ ospi->fmode == CR_FMODE_APM)
+ goto out;
+
+ reinit_completion(&ospi->data_completion);
+ cr = readl_relaxed(regs_base + OSPI_CR);
+ writel_relaxed(cr | CR_TCIE | CR_TEIE, regs_base + OSPI_CR);
+
+ if (!wait_for_completion_timeout(&ospi->data_completion,
+ msecs_to_jiffies(STM32_COMP_TIMEOUT_MS)))
+ err = -ETIMEDOUT;
+
+ sr = readl_relaxed(regs_base + OSPI_SR);
+ if (sr & SR_TCF)
+ /* avoid false timeout */
+ err = 0;
+ if (sr & SR_TEF)
+ err = -EIO;
+
+out:
+ /* clear flags */
+ writel_relaxed(FCR_CTCF | FCR_CTEF, regs_base + OSPI_FCR);
+
+ if (!err)
+ err = stm32_ospi_wait_nobusy(ospi);
+
+ return err;
+}
+
+static void stm32_ospi_dma_callback(void *arg)
+{
+ struct completion *dma_completion = arg;
+
+ complete(dma_completion);
+}
+
+static irqreturn_t stm32_ospi_irq(int irq, void *dev_id)
+{
+ struct stm32_ospi *ospi = (struct stm32_ospi *)dev_id;
+ void __iomem *regs_base = ospi->regs_base;
+ u32 cr, sr;
+
+ cr = readl_relaxed(regs_base + OSPI_CR);
+ sr = readl_relaxed(regs_base + OSPI_SR);
+
+ if (cr & CR_SMIE && sr & SR_SMF) {
+ /* disable irq */
+ cr &= ~CR_SMIE;
+ writel_relaxed(cr, regs_base + OSPI_CR);
+ complete(&ospi->match_completion);
+
+ return IRQ_HANDLED;
+ }
+
+ if (sr & (SR_TEF | SR_TCF)) {
+ /* disable irq */
+ cr &= ~CR_TCIE & ~CR_TEIE;
+ writel_relaxed(cr, regs_base + OSPI_CR);
+ complete(&ospi->data_completion);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void stm32_ospi_dma_setup(struct stm32_ospi *ospi,
+ struct dma_slave_config *dma_cfg)
+{
+ if (dma_cfg && ospi->dma_chrx) {
+ if (dmaengine_slave_config(ospi->dma_chrx, dma_cfg)) {
+ dev_err(ospi->dev, "dma rx config failed\n");
+ dma_release_channel(ospi->dma_chrx);
+ ospi->dma_chrx = NULL;
+ }
+ }
+
+ if (dma_cfg && ospi->dma_chtx) {
+ if (dmaengine_slave_config(ospi->dma_chtx, dma_cfg)) {
+ dev_err(ospi->dev, "dma tx config failed\n");
+ dma_release_channel(ospi->dma_chtx);
+ ospi->dma_chtx = NULL;
+ }
+ }
+
+ init_completion(&ospi->dma_completion);
+}
+
+static int stm32_ospi_tx_mm(struct stm32_ospi *ospi,
+ const struct spi_mem_op *op)
+{
+ memcpy_fromio(op->data.buf.in, ospi->mm_base + op->addr.val,
+ op->data.nbytes);
+ return 0;
+}
+
+static int stm32_ospi_tx_dma(struct stm32_ospi *ospi,
+ const struct spi_mem_op *op)
+{
+ struct dma_async_tx_descriptor *desc;
+ void __iomem *regs_base = ospi->regs_base;
+ enum dma_transfer_direction dma_dir;
+ struct dma_chan *dma_ch;
+ struct sg_table sgt;
+ dma_cookie_t cookie;
+ u32 cr, t_out;
+ int err;
+
+ if (op->data.dir == SPI_MEM_DATA_IN) {
+ dma_dir = DMA_DEV_TO_MEM;
+ dma_ch = ospi->dma_chrx;
+ } else {
+ dma_dir = DMA_MEM_TO_DEV;
+ dma_ch = ospi->dma_chtx;
+ }
+
+ /*
+ * Spi_map_buf return -EINVAL if the buffer is not DMA-able
+ * (DMA-able: in vmalloc | kmap | virt_addr_valid)
+ */
+ err = spi_controller_dma_map_mem_op_data(ospi->ctrl, op, &sgt);
+ if (err)
+ return err;
+
+ desc = dmaengine_prep_slave_sg(dma_ch, sgt.sgl, sgt.nents,
+ dma_dir, DMA_PREP_INTERRUPT);
+ if (!desc) {
+ err = -ENOMEM;
+ goto out_unmap;
+ }
+
+ cr = readl_relaxed(regs_base + OSPI_CR);
+
+ reinit_completion(&ospi->dma_completion);
+ desc->callback = stm32_ospi_dma_callback;
+ desc->callback_param = &ospi->dma_completion;
+ cookie = dmaengine_submit(desc);
+ err = dma_submit_error(cookie);
+ if (err)
+ goto out;
+
+ dma_async_issue_pending(dma_ch);
+
+ writel_relaxed(cr | CR_DMAEN, regs_base + OSPI_CR);
+
+ t_out = sgt.nents * STM32_COMP_TIMEOUT_MS;
+ if (!wait_for_completion_timeout(&ospi->dma_completion,
+ msecs_to_jiffies(t_out)))
+ err = -ETIMEDOUT;
+
+ if (err)
+ dmaengine_terminate_all(dma_ch);
+
+out:
+ writel_relaxed(cr & ~CR_DMAEN, regs_base + OSPI_CR);
+out_unmap:
+ spi_controller_dma_unmap_mem_op_data(ospi->ctrl, op, &sgt);
+
+ return err;
+}
+
+static int stm32_ospi_xfer(struct stm32_ospi *ospi, const struct spi_mem_op *op)
+{
+ u8 *buf;
+
+ if (!op->data.nbytes)
+ return 0;
+
+ if (ospi->fmode == CR_FMODE_MM)
+ return stm32_ospi_tx_mm(ospi, op);
+ else if (((op->data.dir == SPI_MEM_DATA_IN && ospi->dma_chrx) ||
+ (op->data.dir == SPI_MEM_DATA_OUT && ospi->dma_chtx)) &&
+ op->data.nbytes > 8)
+ if (!stm32_ospi_tx_dma(ospi, op))
+ return 0;
+
+ if (op->data.dir == SPI_MEM_DATA_IN)
+ buf = op->data.buf.in;
+ else
+ buf = (u8 *)op->data.buf.out;
+
+ return stm32_ospi_poll(ospi, buf, op->data.nbytes,
+ op->data.dir == SPI_MEM_DATA_IN);
+}
+
+static int stm32_ospi_wait_poll_status(struct stm32_ospi *ospi,
+ const struct spi_mem_op *op)
+{
+ void __iomem *regs_base = ospi->regs_base;
+ u32 cr;
+
+ reinit_completion(&ospi->match_completion);
+ cr = readl_relaxed(regs_base + OSPI_CR);
+ writel_relaxed(cr | CR_SMIE, regs_base + OSPI_CR);
+
+ if (!wait_for_completion_timeout(&ospi->match_completion,
+ msecs_to_jiffies(ospi->status_timeout))) {
+ u32 sr = readl_relaxed(regs_base + OSPI_SR);
+
+ /* Avoid false timeout */
+ if (!(sr & SR_SMF))
+ return -ETIMEDOUT;
+ }
+
+ writel_relaxed(FCR_CSMF, regs_base + OSPI_FCR);
+
+ return 0;
+}
+
+static int stm32_ospi_get_mode(u8 buswidth)
+{
+ switch (buswidth) {
+ case 8:
+ return CCR_BUSWIDTH_8;
+ case 4:
+ return CCR_BUSWIDTH_4;
+ default:
+ return buswidth;
+ }
+}
+
+static int stm32_ospi_send(struct spi_device *spi, const struct spi_mem_op *op)
+{
+ struct stm32_ospi *ospi = spi_controller_get_devdata(spi->controller);
+ void __iomem *regs_base = ospi->regs_base;
+ u32 ccr, cr, dcr2, tcr;
+ int timeout, err = 0, err_poll_status = 0;
+ u8 cs = spi->chip_select[ffs(spi->cs_index_mask) - 1];
+
+ dev_dbg(ospi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
+ op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+ op->dummy.buswidth, op->data.buswidth,
+ op->addr.val, op->data.nbytes);
+
+ cr = readl_relaxed(ospi->regs_base + OSPI_CR);
+ cr &= ~CR_CSSEL;
+ cr |= FIELD_PREP(CR_CSSEL, cs);
+ cr &= ~CR_FMODE_MASK;
+ cr |= FIELD_PREP(CR_FMODE_MASK, ospi->fmode);
+ writel_relaxed(cr, regs_base + OSPI_CR);
+
+ if (op->data.nbytes)
+ writel_relaxed(op->data.nbytes - 1, regs_base + OSPI_DLR);
+
+ /* set prescaler */
+ dcr2 = readl_relaxed(regs_base + OSPI_DCR2);
+ dcr2 |= FIELD_PREP(DCR2_PRESC_MASK, ospi->flash_presc[cs]);
+ writel_relaxed(dcr2, regs_base + OSPI_DCR2);
+
+ ccr = FIELD_PREP(CCR_IMODE_MASK, stm32_ospi_get_mode(op->cmd.buswidth));
+
+ if (op->addr.nbytes) {
+ ccr |= FIELD_PREP(CCR_ADMODE_MASK,
+ stm32_ospi_get_mode(op->addr.buswidth));
+ ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1);
+ }
+
+ tcr = TCR_SSHIFT;
+ if (op->dummy.buswidth && op->dummy.nbytes) {
+ tcr |= FIELD_PREP(TCR_DCYC_MASK,
+ op->dummy.nbytes * 8 / op->dummy.buswidth);
+ }
+ writel_relaxed(tcr, regs_base + OSPI_TCR);
+
+ if (op->data.nbytes) {
+ ccr |= FIELD_PREP(CCR_DMODE_MASK,
+ stm32_ospi_get_mode(op->data.buswidth));
+ }
+
+ writel_relaxed(ccr, regs_base + OSPI_CCR);
+
+ /* set instruction, must be set after ccr register update */
+ writel_relaxed(op->cmd.opcode, regs_base + OSPI_IR);
+
+ if (op->addr.nbytes && ospi->fmode != CR_FMODE_MM)
+ writel_relaxed(op->addr.val, regs_base + OSPI_AR);
+
+ if (ospi->fmode == CR_FMODE_APM)
+ err_poll_status = stm32_ospi_wait_poll_status(ospi, op);
+
+ err = stm32_ospi_xfer(ospi, op);
+
+ /*
+ * Abort in:
+ * -error case
+ * -read memory map: prefetching must be stopped if we read the last
+ * byte of device (device size - fifo size). like device size is not
+ * knows, the prefetching is always stop.
+ */
+ if (err || err_poll_status || ospi->fmode == CR_FMODE_MM)
+ goto abort;
+
+ /* Wait end of tx in indirect mode */
+ err = stm32_ospi_wait_cmd(ospi);
+ if (err)
+ goto abort;
+
+ return 0;
+
+abort:
+ timeout = stm32_ospi_abort(ospi);
+ writel_relaxed(FCR_CTCF | FCR_CSMF, regs_base + OSPI_FCR);
+
+ if (err || err_poll_status || timeout)
+ dev_err(ospi->dev, "%s err:%d err_poll_status:%d abort timeout:%d\n",
+ __func__, err, err_poll_status, timeout);
+
+ return err;
+}
+
+static int stm32_ospi_poll_status(struct spi_mem *mem,
+ const struct spi_mem_op *op,
+ u16 mask, u16 match,
+ unsigned long initial_delay_us,
+ unsigned long polling_rate_us,
+ unsigned long timeout_ms)
+{
+ struct stm32_ospi *ospi = spi_controller_get_devdata(mem->spi->controller);
+ void __iomem *regs_base = ospi->regs_base;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(ospi->dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&ospi->lock);
+
+ writel_relaxed(mask, regs_base + OSPI_PSMKR);
+ writel_relaxed(match, regs_base + OSPI_PSMAR);
+ ospi->fmode = CR_FMODE_APM;
+ ospi->status_timeout = timeout_ms;
+
+ ret = stm32_ospi_send(mem->spi, op);
+ mutex_unlock(&ospi->lock);
+
+ pm_runtime_put_autosuspend(ospi->dev);
+
+ return ret;
+}
+
+static int stm32_ospi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ struct stm32_ospi *ospi = spi_controller_get_devdata(mem->spi->controller);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(ospi->dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&ospi->lock);
+ if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes)
+ ospi->fmode = CR_FMODE_INDR;
+ else
+ ospi->fmode = CR_FMODE_INDW;
+
+ ret = stm32_ospi_send(mem->spi, op);
+ mutex_unlock(&ospi->lock);
+
+ pm_runtime_put_autosuspend(ospi->dev);
+
+ return ret;
+}
+
+static int stm32_ospi_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+ struct stm32_ospi *ospi = spi_controller_get_devdata(desc->mem->spi->controller);
+
+ if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT)
+ return -EOPNOTSUPP;
+
+ /* Should never happen, as mm_base == null is an error probe exit condition */
+ if (!ospi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN)
+ return -EOPNOTSUPP;
+
+ if (!ospi->mm_size)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static ssize_t stm32_ospi_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offs, size_t len, void *buf)
+{
+ struct stm32_ospi *ospi = spi_controller_get_devdata(desc->mem->spi->controller);
+ struct spi_mem_op op;
+ u32 addr_max;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(ospi->dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&ospi->lock);
+ /*
+ * Make a local copy of desc op_tmpl and complete dirmap rdesc
+ * spi_mem_op template with offs, len and *buf in order to get
+ * all needed transfer information into struct spi_mem_op
+ */
+ memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op));
+ dev_dbg(ospi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf);
+
+ op.data.nbytes = len;
+ op.addr.val = desc->info.offset + offs;
+ op.data.buf.in = buf;
+
+ addr_max = op.addr.val + op.data.nbytes + 1;
+ if (addr_max < ospi->mm_size && op.addr.buswidth)
+ ospi->fmode = CR_FMODE_MM;
+ else
+ ospi->fmode = CR_FMODE_INDR;
+
+ ret = stm32_ospi_send(desc->mem->spi, &op);
+ mutex_unlock(&ospi->lock);
+
+ pm_runtime_put_autosuspend(ospi->dev);
+
+ return ret ?: len;
+}
+
+static int stm32_ospi_transfer_one_message(struct spi_controller *ctrl,
+ struct spi_message *msg)
+{
+ struct stm32_ospi *ospi = spi_controller_get_devdata(ctrl);
+ struct spi_transfer *transfer;
+ struct spi_device *spi = msg->spi;
+ struct spi_mem_op op;
+ struct gpio_desc *cs_gpiod = spi->cs_gpiod[ffs(spi->cs_index_mask) - 1];
+ int ret = 0;
+
+ if (!cs_gpiod)
+ return -EOPNOTSUPP;
+
+ ret = pm_runtime_resume_and_get(ospi->dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&ospi->lock);
+
+ gpiod_set_value_cansleep(cs_gpiod, true);
+
+ list_for_each_entry(transfer, &msg->transfers, transfer_list) {
+ u8 dummy_bytes = 0;
+
+ memset(&op, 0, sizeof(op));
+
+ dev_dbg(ospi->dev, "tx_buf:%p tx_nbits:%d rx_buf:%p rx_nbits:%d len:%d dummy_data:%d\n",
+ transfer->tx_buf, transfer->tx_nbits,
+ transfer->rx_buf, transfer->rx_nbits,
+ transfer->len, transfer->dummy_data);
+
+ /*
+ * OSPI hardware supports dummy bytes transfer.
+ * If current transfer is dummy byte, merge it with the next
+ * transfer in order to take into account OSPI block constraint
+ */
+ if (transfer->dummy_data) {
+ op.dummy.buswidth = transfer->tx_nbits;
+ op.dummy.nbytes = transfer->len;
+ dummy_bytes = transfer->len;
+
+ /* If happens, means that message is not correctly built */
+ if (list_is_last(&transfer->transfer_list, &msg->transfers)) {
+ ret = -EINVAL;
+ goto end_of_transfer;
+ }
+
+ transfer = list_next_entry(transfer, transfer_list);
+ }
+
+ op.data.nbytes = transfer->len;
+
+ if (transfer->rx_buf) {
+ ospi->fmode = CR_FMODE_INDR;
+ op.data.buswidth = transfer->rx_nbits;
+ op.data.dir = SPI_MEM_DATA_IN;
+ op.data.buf.in = transfer->rx_buf;
+ } else {
+ ospi->fmode = CR_FMODE_INDW;
+ op.data.buswidth = transfer->tx_nbits;
+ op.data.dir = SPI_MEM_DATA_OUT;
+ op.data.buf.out = transfer->tx_buf;
+ }
+
+ ret = stm32_ospi_send(spi, &op);
+ if (ret)
+ goto end_of_transfer;
+
+ msg->actual_length += transfer->len + dummy_bytes;
+ }
+
+end_of_transfer:
+ gpiod_set_value_cansleep(cs_gpiod, false);
+
+ mutex_unlock(&ospi->lock);
+
+ msg->status = ret;
+ spi_finalize_current_message(ctrl);
+
+ pm_runtime_put_autosuspend(ospi->dev);
+
+ return ret;
+}
+
+static int stm32_ospi_setup(struct spi_device *spi)
+{
+ struct spi_controller *ctrl = spi->controller;
+ struct stm32_ospi *ospi = spi_controller_get_devdata(ctrl);
+ void __iomem *regs_base = ospi->regs_base;
+ int ret;
+ u8 cs = spi->chip_select[ffs(spi->cs_index_mask) - 1];
+
+ if (ctrl->busy)
+ return -EBUSY;
+
+ if (!spi->max_speed_hz)
+ return -EINVAL;
+
+ ret = pm_runtime_resume_and_get(ospi->dev);
+ if (ret < 0)
+ return ret;
+
+ ospi->flash_presc[cs] = DIV_ROUND_UP(ospi->clk_rate, spi->max_speed_hz) - 1;
+
+ mutex_lock(&ospi->lock);
+
+ ospi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_EN;
+ writel_relaxed(ospi->cr_reg, regs_base + OSPI_CR);
+
+ /* set dcr fsize to max address */
+ ospi->dcr_reg = DCR1_DEVSIZE_MASK | DCR1_DLYBYP;
+ writel_relaxed(ospi->dcr_reg, regs_base + OSPI_DCR1);
+
+ mutex_unlock(&ospi->lock);
+
+ pm_runtime_put_autosuspend(ospi->dev);
+
+ return 0;
+}
+
+/*
+ * No special host constraint, so use default spi_mem_default_supports_op
+ * to check supported mode.
+ */
+static const struct spi_controller_mem_ops stm32_ospi_mem_ops = {
+ .exec_op = stm32_ospi_exec_op,
+ .dirmap_create = stm32_ospi_dirmap_create,
+ .dirmap_read = stm32_ospi_dirmap_read,
+ .poll_status = stm32_ospi_poll_status,
+};
+
+static int stm32_ospi_get_resources(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct stm32_ospi *ospi = platform_get_drvdata(pdev);
+ struct resource *res, _res;
+ int ret;
+
+ ospi->regs_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(ospi->regs_base))
+ return PTR_ERR(ospi->regs_base);
+
+ ospi->regs_phys_base = res->start;
+
+ ospi->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(ospi->clk))
+ return dev_err_probe(dev, PTR_ERR(ospi->clk),
+ "Can't get clock\n");
+
+ ospi->clk_rate = clk_get_rate(ospi->clk);
+ if (!ospi->clk_rate) {
+ dev_err(dev, "Invalid clock rate\n");
+ return -EINVAL;
+ }
+
+ ospi->irq = platform_get_irq(pdev, 0);
+ if (ospi->irq < 0)
+ return ospi->irq;
+
+ ret = devm_request_irq(dev, ospi->irq, stm32_ospi_irq, 0,
+ dev_name(dev), ospi);
+ if (ret) {
+ dev_err(dev, "Failed to request irq\n");
+ return ret;
+ }
+
+ ospi->rstc = devm_reset_control_array_get_exclusive_released(dev);
+ if (IS_ERR(ospi->rstc))
+ return dev_err_probe(dev, PTR_ERR(ospi->rstc),
+ "Can't get reset\n");
+
+ ospi->dma_chrx = dma_request_chan(dev, "rx");
+ if (IS_ERR(ospi->dma_chrx)) {
+ ret = PTR_ERR(ospi->dma_chrx);
+ ospi->dma_chrx = NULL;
+ if (ret == -EPROBE_DEFER)
+ goto err_dma;
+ }
+
+ ospi->dma_chtx = dma_request_chan(dev, "tx");
+ if (IS_ERR(ospi->dma_chtx)) {
+ ret = PTR_ERR(ospi->dma_chtx);
+ ospi->dma_chtx = NULL;
+ if (ret == -EPROBE_DEFER)
+ goto err_dma;
+ }
+
+ res = &_res;
+ ret = of_reserved_mem_region_to_resource(dev->of_node, 0, res);
+ if (!ret) {
+ ospi->mm_size = resource_size(res);
+ ospi->mm_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ospi->mm_base)) {
+ dev_err(dev, "unable to map memory region: %pR\n", res);
+ ret = PTR_ERR(ospi->mm_base);
+ goto err_dma;
+ }
+
+ if (ospi->mm_size > STM32_OSPI_MAX_MMAP_SZ) {
+ dev_err(dev, "Memory map size outsize bounds\n");
+ ret = -EINVAL;
+ goto err_dma;
+ }
+ } else {
+ dev_info(dev, "No memory-map region found\n");
+ }
+
+ init_completion(&ospi->data_completion);
+ init_completion(&ospi->match_completion);
+
+ return 0;
+
+err_dma:
+ dev_info(dev, "Can't get all resources (%d)\n", ret);
+
+ if (ospi->dma_chtx)
+ dma_release_channel(ospi->dma_chtx);
+ if (ospi->dma_chrx)
+ dma_release_channel(ospi->dma_chrx);
+
+ return ret;
+};
+
+static int stm32_ospi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spi_controller *ctrl;
+ struct stm32_ospi *ospi;
+ struct dma_slave_config dma_cfg;
+ struct device_node *child;
+ int ret;
+ u8 spi_flash_count = 0;
+
+ /*
+ * Flash subnodes sanity check:
+ * 1 or 2 spi-nand/spi-nor flashes => supported
+ * All other flash node configuration => not supported
+ */
+ for_each_available_child_of_node(dev->of_node, child) {
+ if (of_device_is_compatible(child, "jedec,spi-nor") ||
+ of_device_is_compatible(child, "spi-nand"))
+ spi_flash_count++;
+ }
+
+ if (spi_flash_count == 0 || spi_flash_count > 2) {
+ dev_err(dev, "Incorrect DT flash node\n");
+ return -ENODEV;
+ }
+
+ ctrl = devm_spi_alloc_host(dev, sizeof(*ospi));
+ if (!ctrl)
+ return -ENOMEM;
+
+ ospi = spi_controller_get_devdata(ctrl);
+ ospi->ctrl = ctrl;
+
+ ospi->dev = &pdev->dev;
+ platform_set_drvdata(pdev, ospi);
+
+ ret = stm32_ospi_get_resources(pdev);
+ if (ret)
+ return ret;
+
+ memset(&dma_cfg, 0, sizeof(dma_cfg));
+ dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_cfg.src_addr = ospi->regs_phys_base + OSPI_DR;
+ dma_cfg.dst_addr = ospi->regs_phys_base + OSPI_DR;
+ dma_cfg.src_maxburst = 4;
+ dma_cfg.dst_maxburst = 4;
+ stm32_ospi_dma_setup(ospi, &dma_cfg);
+
+ mutex_init(&ospi->lock);
+
+ ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
+ SPI_TX_DUAL | SPI_TX_QUAD |
+ SPI_TX_OCTAL | SPI_RX_OCTAL;
+ ctrl->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ ctrl->setup = stm32_ospi_setup;
+ ctrl->bus_num = -1;
+ ctrl->mem_ops = &stm32_ospi_mem_ops;
+ ctrl->use_gpio_descriptors = true;
+ ctrl->transfer_one_message = stm32_ospi_transfer_one_message;
+ ctrl->num_chipselect = STM32_OSPI_MAX_NORCHIP;
+ ctrl->dev.of_node = dev->of_node;
+
+ pm_runtime_enable(ospi->dev);
+ pm_runtime_set_autosuspend_delay(ospi->dev, STM32_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(ospi->dev);
+
+ ret = pm_runtime_resume_and_get(ospi->dev);
+ if (ret < 0)
+ goto err_pm_enable;
+
+ ret = reset_control_acquire(ospi->rstc);
+ if (ret) {
+ dev_err_probe(dev, ret, "Can not acquire reset %d\n", ret);
+ goto err_pm_resume;
+ }
+
+ reset_control_assert(ospi->rstc);
+ udelay(2);
+ reset_control_deassert(ospi->rstc);
+
+ ret = spi_register_controller(ctrl);
+ if (ret) {
+ /* Disable ospi */
+ writel_relaxed(0, ospi->regs_base + OSPI_CR);
+ goto err_pm_resume;
+ }
+
+ pm_runtime_put_autosuspend(ospi->dev);
+
+ return 0;
+
+err_pm_resume:
+ pm_runtime_put_sync_suspend(ospi->dev);
+
+err_pm_enable:
+ pm_runtime_force_suspend(ospi->dev);
+ mutex_destroy(&ospi->lock);
+ if (ospi->dma_chtx)
+ dma_release_channel(ospi->dma_chtx);
+ if (ospi->dma_chrx)
+ dma_release_channel(ospi->dma_chrx);
+
+ return ret;
+}
+
+static void stm32_ospi_remove(struct platform_device *pdev)
+{
+ struct stm32_ospi *ospi = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(ospi->dev);
+ if (ret < 0)
+ return;
+
+ spi_unregister_controller(ospi->ctrl);
+ /* Disable ospi */
+ writel_relaxed(0, ospi->regs_base + OSPI_CR);
+ mutex_destroy(&ospi->lock);
+
+ if (ospi->dma_chtx)
+ dma_release_channel(ospi->dma_chtx);
+ if (ospi->dma_chrx)
+ dma_release_channel(ospi->dma_chrx);
+
+ reset_control_release(ospi->rstc);
+
+ pm_runtime_put_sync_suspend(ospi->dev);
+ pm_runtime_force_suspend(ospi->dev);
+}
+
+static int __maybe_unused stm32_ospi_suspend(struct device *dev)
+{
+ struct stm32_ospi *ospi = dev_get_drvdata(dev);
+
+ pinctrl_pm_select_sleep_state(dev);
+
+ reset_control_release(ospi->rstc);
+
+ return pm_runtime_force_suspend(ospi->dev);
+}
+
+static int __maybe_unused stm32_ospi_resume(struct device *dev)
+{
+ struct stm32_ospi *ospi = dev_get_drvdata(dev);
+ void __iomem *regs_base = ospi->regs_base;
+ int ret;
+
+ ret = pm_runtime_force_resume(ospi->dev);
+ if (ret < 0)
+ return ret;
+
+ pinctrl_pm_select_default_state(dev);
+
+ ret = pm_runtime_resume_and_get(ospi->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = reset_control_acquire(ospi->rstc);
+ if (ret) {
+ dev_err(dev, "Can not acquire reset\n");
+ return ret;
+ }
+
+ writel_relaxed(ospi->cr_reg, regs_base + OSPI_CR);
+ writel_relaxed(ospi->dcr_reg, regs_base + OSPI_DCR1);
+ pm_runtime_put_autosuspend(ospi->dev);
+
+ return 0;
+}
+
+static int __maybe_unused stm32_ospi_runtime_suspend(struct device *dev)
+{
+ struct stm32_ospi *ospi = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(ospi->clk);
+
+ return 0;
+}
+
+static int __maybe_unused stm32_ospi_runtime_resume(struct device *dev)
+{
+ struct stm32_ospi *ospi = dev_get_drvdata(dev);
+
+ return clk_prepare_enable(ospi->clk);
+}
+
+static const struct dev_pm_ops stm32_ospi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(stm32_ospi_suspend, stm32_ospi_resume)
+ SET_RUNTIME_PM_OPS(stm32_ospi_runtime_suspend,
+ stm32_ospi_runtime_resume, NULL)
+};
+
+static const struct of_device_id stm32_ospi_of_match[] = {
+ { .compatible = "st,stm32mp25-ospi" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_ospi_of_match);
+
+static struct platform_driver stm32_ospi_driver = {
+ .probe = stm32_ospi_probe,
+ .remove = stm32_ospi_remove,
+ .driver = {
+ .name = "stm32-ospi",
+ .pm = &stm32_ospi_pm_ops,
+ .of_match_table = stm32_ospi_of_match,
+ },
+};
+module_platform_driver(stm32_ospi_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 OCTO SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index 2b6804aa6901..f2d19f1c5ab1 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -8,14 +8,13 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
@@ -350,7 +349,7 @@ static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi)
static int stm32_qspi_get_mode(u8 buswidth)
{
- if (buswidth == 4)
+ if (buswidth >= 4)
return CCR_BUSWIDTH_4;
return buswidth;
@@ -358,16 +357,11 @@ static int stm32_qspi_get_mode(u8 buswidth)
static int stm32_qspi_send(struct spi_device *spi, const struct spi_mem_op *op)
{
- struct stm32_qspi *qspi = spi_controller_get_devdata(spi->master);
+ struct stm32_qspi *qspi = spi_controller_get_devdata(spi->controller);
struct stm32_qspi_flash *flash = &qspi->flash[spi_get_chipselect(spi, 0)];
u32 ccr, cr;
int timeout, err = 0, err_poll_status = 0;
- dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
- op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
- op->dummy.buswidth, op->data.buswidth,
- op->addr.val, op->data.nbytes);
-
cr = readl_relaxed(qspi->io_base + QSPI_CR);
cr &= ~CR_PRESC_MASK & ~CR_FSEL;
cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc);
@@ -449,7 +443,7 @@ static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *
unsigned long polling_rate_us,
unsigned long timeout_ms)
{
- struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+ struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->controller);
int ret;
if (!spi_mem_supports_op(mem, op))
@@ -469,7 +463,6 @@ static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *
ret = stm32_qspi_send(mem->spi, op);
mutex_unlock(&qspi->lock);
- pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return ret;
@@ -477,7 +470,7 @@ static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *
static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
- struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+ struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->controller);
int ret;
ret = pm_runtime_resume_and_get(qspi->dev);
@@ -493,7 +486,6 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
ret = stm32_qspi_send(mem->spi, op);
mutex_unlock(&qspi->lock);
- pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return ret;
@@ -501,7 +493,7 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
static int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
- struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master);
+ struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->controller);
if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT)
return -EOPNOTSUPP;
@@ -519,7 +511,7 @@ static int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc)
static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
- struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master);
+ struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->controller);
struct spi_mem_op op;
u32 addr_max;
int ret;
@@ -549,7 +541,6 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc,
ret = stm32_qspi_send(desc->mem->spi, &op);
mutex_unlock(&qspi->lock);
- pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return ret ?: len;
@@ -633,7 +624,6 @@ end_of_transfer:
msg->status = ret;
spi_finalize_current_message(ctrl);
- pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return ret;
@@ -641,7 +631,7 @@ end_of_transfer:
static int stm32_qspi_setup(struct spi_device *spi)
{
- struct spi_controller *ctrl = spi->master;
+ struct spi_controller *ctrl = spi->controller;
struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl);
struct stm32_qspi_flash *flash;
u32 presc, mode;
@@ -654,9 +644,7 @@ static int stm32_qspi_setup(struct spi_device *spi)
return -EINVAL;
mode = spi->mode & (SPI_TX_OCTAL | SPI_RX_OCTAL);
- if ((mode == SPI_TX_OCTAL || mode == SPI_RX_OCTAL) ||
- ((mode == (SPI_TX_OCTAL | SPI_RX_OCTAL)) &&
- gpiod_count(qspi->dev, "cs") == -ENOENT)) {
+ if (mode && gpiod_count(qspi->dev, "cs") == -ENOENT) {
dev_err(qspi->dev, "spi-rx-bus-width\\/spi-tx-bus-width\\/cs-gpios\n");
dev_err(qspi->dev, "configuration not supported\n");
@@ -677,10 +665,10 @@ static int stm32_qspi_setup(struct spi_device *spi)
qspi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN;
/*
- * Dual flash mode is only enable in case SPI_TX_OCTAL and SPI_TX_OCTAL
- * are both set in spi->mode and "cs-gpios" properties is found in DT
+ * Dual flash mode is only enable in case SPI_TX_OCTAL or SPI_RX_OCTAL
+ * is set in spi->mode and "cs-gpios" properties is found in DT
*/
- if (mode == (SPI_TX_OCTAL | SPI_RX_OCTAL)) {
+ if (mode) {
qspi->cr_reg |= CR_DFM;
dev_dbg(qspi->dev, "Dual flash mode enable");
}
@@ -692,7 +680,6 @@ static int stm32_qspi_setup(struct spi_device *spi)
writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR);
mutex_unlock(&qspi->lock);
- pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return 0;
@@ -776,7 +763,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
struct resource *res;
int ret, irq;
- ctrl = devm_spi_alloc_master(dev, sizeof(*qspi));
+ ctrl = devm_spi_alloc_host(dev, sizeof(*qspi));
if (!ctrl)
return -ENOMEM;
@@ -862,11 +849,10 @@ static int stm32_qspi_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_runtime_get_noresume(dev);
- ret = spi_register_master(ctrl);
+ ret = spi_register_controller(ctrl);
if (ret)
goto err_pm_runtime_free;
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -893,7 +879,7 @@ static void stm32_qspi_remove(struct platform_device *pdev)
struct stm32_qspi *qspi = platform_get_drvdata(pdev);
pm_runtime_get_sync(qspi->dev);
- spi_unregister_master(qspi->ctrl);
+ spi_unregister_controller(qspi->ctrl);
/* disable qspi */
writel_relaxed(0, qspi->io_base + QSPI_CR);
stm32_qspi_dma_free(qspi);
@@ -946,7 +932,6 @@ static int __maybe_unused stm32_qspi_resume(struct device *dev)
writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR);
writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -966,7 +951,7 @@ MODULE_DEVICE_TABLE(of, stm32_qspi_match);
static struct platform_driver stm32_qspi_driver = {
.probe = stm32_qspi_probe,
- .remove_new = stm32_qspi_remove,
+ .remove = stm32_qspi_remove,
.driver = {
.name = "stm32-qspi",
.of_match_table = stm32_qspi_match,
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 6d10fa4ab783..2c804c1aef98 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -9,11 +9,14 @@
#include <linux/debugfs.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
+#include <linux/genalloc.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/module.h>
-#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -21,58 +24,65 @@
#define DRIVER_NAME "spi_stm32"
-/* STM32F4 SPI registers */
-#define STM32F4_SPI_CR1 0x00
-#define STM32F4_SPI_CR2 0x04
-#define STM32F4_SPI_SR 0x08
-#define STM32F4_SPI_DR 0x0C
-#define STM32F4_SPI_I2SCFGR 0x1C
-
-/* STM32F4_SPI_CR1 bit fields */
-#define STM32F4_SPI_CR1_CPHA BIT(0)
-#define STM32F4_SPI_CR1_CPOL BIT(1)
-#define STM32F4_SPI_CR1_MSTR BIT(2)
-#define STM32F4_SPI_CR1_BR_SHIFT 3
-#define STM32F4_SPI_CR1_BR GENMASK(5, 3)
-#define STM32F4_SPI_CR1_SPE BIT(6)
-#define STM32F4_SPI_CR1_LSBFRST BIT(7)
-#define STM32F4_SPI_CR1_SSI BIT(8)
-#define STM32F4_SPI_CR1_SSM BIT(9)
-#define STM32F4_SPI_CR1_RXONLY BIT(10)
+/* STM32F4/7 SPI registers */
+#define STM32FX_SPI_CR1 0x00
+#define STM32FX_SPI_CR2 0x04
+#define STM32FX_SPI_SR 0x08
+#define STM32FX_SPI_DR 0x0C
+#define STM32FX_SPI_I2SCFGR 0x1C
+
+/* STM32FX_SPI_CR1 bit fields */
+#define STM32FX_SPI_CR1_CPHA BIT(0)
+#define STM32FX_SPI_CR1_CPOL BIT(1)
+#define STM32FX_SPI_CR1_MSTR BIT(2)
+#define STM32FX_SPI_CR1_BR_SHIFT 3
+#define STM32FX_SPI_CR1_BR GENMASK(5, 3)
+#define STM32FX_SPI_CR1_SPE BIT(6)
+#define STM32FX_SPI_CR1_LSBFRST BIT(7)
+#define STM32FX_SPI_CR1_SSI BIT(8)
+#define STM32FX_SPI_CR1_SSM BIT(9)
+#define STM32FX_SPI_CR1_RXONLY BIT(10)
#define STM32F4_SPI_CR1_DFF BIT(11)
-#define STM32F4_SPI_CR1_CRCNEXT BIT(12)
-#define STM32F4_SPI_CR1_CRCEN BIT(13)
-#define STM32F4_SPI_CR1_BIDIOE BIT(14)
-#define STM32F4_SPI_CR1_BIDIMODE BIT(15)
-#define STM32F4_SPI_CR1_BR_MIN 0
-#define STM32F4_SPI_CR1_BR_MAX (GENMASK(5, 3) >> 3)
-
-/* STM32F4_SPI_CR2 bit fields */
-#define STM32F4_SPI_CR2_RXDMAEN BIT(0)
-#define STM32F4_SPI_CR2_TXDMAEN BIT(1)
-#define STM32F4_SPI_CR2_SSOE BIT(2)
-#define STM32F4_SPI_CR2_FRF BIT(4)
-#define STM32F4_SPI_CR2_ERRIE BIT(5)
-#define STM32F4_SPI_CR2_RXNEIE BIT(6)
-#define STM32F4_SPI_CR2_TXEIE BIT(7)
-
-/* STM32F4_SPI_SR bit fields */
-#define STM32F4_SPI_SR_RXNE BIT(0)
-#define STM32F4_SPI_SR_TXE BIT(1)
-#define STM32F4_SPI_SR_CHSIDE BIT(2)
-#define STM32F4_SPI_SR_UDR BIT(3)
-#define STM32F4_SPI_SR_CRCERR BIT(4)
-#define STM32F4_SPI_SR_MODF BIT(5)
-#define STM32F4_SPI_SR_OVR BIT(6)
-#define STM32F4_SPI_SR_BSY BIT(7)
-#define STM32F4_SPI_SR_FRE BIT(8)
-
-/* STM32F4_SPI_I2SCFGR bit fields */
-#define STM32F4_SPI_I2SCFGR_I2SMOD BIT(11)
+#define STM32F7_SPI_CR1_CRCL BIT(11)
+#define STM32FX_SPI_CR1_CRCNEXT BIT(12)
+#define STM32FX_SPI_CR1_CRCEN BIT(13)
+#define STM32FX_SPI_CR1_BIDIOE BIT(14)
+#define STM32FX_SPI_CR1_BIDIMODE BIT(15)
+#define STM32FX_SPI_CR1_BR_MIN 0
+#define STM32FX_SPI_CR1_BR_MAX (GENMASK(5, 3) >> 3)
+
+/* STM32FX_SPI_CR2 bit fields */
+#define STM32FX_SPI_CR2_RXDMAEN BIT(0)
+#define STM32FX_SPI_CR2_TXDMAEN BIT(1)
+#define STM32FX_SPI_CR2_SSOE BIT(2)
+#define STM32FX_SPI_CR2_FRF BIT(4)
+#define STM32FX_SPI_CR2_ERRIE BIT(5)
+#define STM32FX_SPI_CR2_RXNEIE BIT(6)
+#define STM32FX_SPI_CR2_TXEIE BIT(7)
+#define STM32F7_SPI_CR2_DS GENMASK(11, 8)
+#define STM32F7_SPI_CR2_FRXTH BIT(12)
+#define STM32F7_SPI_CR2_LDMA_RX BIT(13)
+#define STM32F7_SPI_CR2_LDMA_TX BIT(14)
+
+/* STM32FX_SPI_SR bit fields */
+#define STM32FX_SPI_SR_RXNE BIT(0)
+#define STM32FX_SPI_SR_TXE BIT(1)
+#define STM32FX_SPI_SR_CHSIDE BIT(2)
+#define STM32FX_SPI_SR_UDR BIT(3)
+#define STM32FX_SPI_SR_CRCERR BIT(4)
+#define STM32FX_SPI_SR_MODF BIT(5)
+#define STM32FX_SPI_SR_OVR BIT(6)
+#define STM32FX_SPI_SR_BSY BIT(7)
+#define STM32FX_SPI_SR_FRE BIT(8)
+#define STM32F7_SPI_SR_FRLVL GENMASK(10, 9)
+#define STM32F7_SPI_SR_FTLVL GENMASK(12, 11)
+
+/* STM32FX_SPI_I2SCFGR bit fields */
+#define STM32FX_SPI_I2SCFGR_I2SMOD BIT(11)
/* STM32F4 SPI Baud Rate min/max divisor */
-#define STM32F4_SPI_BR_DIV_MIN (2 << STM32F4_SPI_CR1_BR_MIN)
-#define STM32F4_SPI_BR_DIV_MAX (2 << STM32F4_SPI_CR1_BR_MAX)
+#define STM32FX_SPI_BR_DIV_MIN (2 << STM32FX_SPI_CR1_BR_MIN)
+#define STM32FX_SPI_BR_DIV_MAX (2 << STM32FX_SPI_CR1_BR_MAX)
/* STM32H7 SPI registers */
#define STM32H7_SPI_CR1 0x00
@@ -146,6 +156,23 @@
/* STM32H7_SPI_I2SCFGR bit fields */
#define STM32H7_SPI_I2SCFGR_I2SMOD BIT(0)
+/* STM32MP25_SPICFG2 bit fields */
+#define STM32MP25_SPI_CFG2_RDIOM BIT(13)
+
+/* STM32MP25 SPI registers bit fields */
+#define STM32MP25_SPI_HWCFGR1 0x3F0
+
+/* STM32MP25_SPI_CR2 bit fields */
+#define STM32MP25_SPI_TSIZE_MAX_LIMITED GENMASK(9, 0)
+
+/* STM32MP25_SPI_HWCFGR1 */
+#define STM32MP25_SPI_HWCFGR1_FULLCFG GENMASK(27, 24)
+#define STM32MP25_SPI_HWCFGR1_FULLCFG_LIMITED 0x0
+#define STM32MP25_SPI_HWCFGR1_FULLCFG_FULL 0x1
+#define STM32MP25_SPI_HWCFGR1_DSCFG GENMASK(19, 16)
+#define STM32MP25_SPI_HWCFGR1_DSCFG_16_B 0x0
+#define STM32MP25_SPI_HWCFGR1_DSCFG_32_B 0x1
+
/* STM32H7 SPI Master Baud Rate min/max divisor */
#define STM32H7_SPI_MBR_DIV_MIN (2 << STM32H7_SPI_CFG1_MBR_MIN)
#define STM32H7_SPI_MBR_DIV_MAX (2 << STM32H7_SPI_CFG1_MBR_MAX)
@@ -172,7 +199,7 @@
#define SPI_DMA_MIN_BYTES 16
/* STM32 SPI driver helpers */
-#define STM32_SPI_MASTER_MODE(stm32_spi) (!(stm32_spi)->device_mode)
+#define STM32_SPI_HOST_MODE(stm32_spi) (!(stm32_spi)->device_mode)
#define STM32_SPI_DEVICE_MODE(stm32_spi) ((stm32_spi)->device_mode)
/**
@@ -199,6 +226,8 @@ struct stm32_spi_reg {
* @br: baud rate register and bitfields
* @rx: SPI RX data register
* @tx: SPI TX data register
+ * @fullcfg: SPI full or limited feature set register
+ * @rdy_en: SPI ready feature register
*/
struct stm32_spi_regspec {
const struct stm32_spi_reg en;
@@ -211,6 +240,8 @@ struct stm32_spi_regspec {
const struct stm32_spi_reg br;
const struct stm32_spi_reg rx;
const struct stm32_spi_reg tx;
+ const struct stm32_spi_reg fullcfg;
+ const struct stm32_spi_reg rdy_en;
};
struct stm32_spi;
@@ -221,13 +252,15 @@ struct stm32_spi;
* @get_fifo_size: routine to get fifo size
* @get_bpw_mask: routine to get bits per word mask
* @disable: routine to disable controller
- * @config: routine to configure controller as SPI Master
+ * @config: routine to configure controller as SPI Host
* @set_bpw: routine to configure registers to for bits per word
* @set_mode: routine to configure registers to desired mode
* @set_data_idleness: optional routine to configure registers to desired idle
* time between frames (if driver has this functionality)
* @set_number_of_data: optional routine to configure registers to desired
* number of data (if driver has this functionality)
+ * @write_tx: routine to write to transmit register/FIFO
+ * @read_rx: routine to read from receive register/FIFO
* @transfer_one_dma_start: routine to start transfer a single spi_transfer
* using DMA
* @dma_rx_cb: routine to call after DMA RX channel operation is complete
@@ -238,7 +271,9 @@ struct stm32_spi;
* @baud_rate_div_min: minimum baud rate divisor
* @baud_rate_div_max: maximum baud rate divisor
* @has_fifo: boolean to know if fifo is used for driver
+ * @has_device_mode: is this compatible capable to switch on device mode
* @flags: compatible specific SPI controller flags used at registration time
+ * @prevent_dma_burst: boolean to indicate to prevent DMA burst
*/
struct stm32_spi_cfg {
const struct stm32_spi_regspec *regs;
@@ -248,8 +283,10 @@ struct stm32_spi_cfg {
int (*config)(struct stm32_spi *spi);
void (*set_bpw)(struct stm32_spi *spi);
int (*set_mode)(struct stm32_spi *spi, unsigned int comm_type);
- void (*set_data_idleness)(struct stm32_spi *spi, u32 length);
+ void (*set_data_idleness)(struct stm32_spi *spi, struct spi_transfer *xfer);
int (*set_number_of_data)(struct stm32_spi *spi, u32 length);
+ void (*write_tx)(struct stm32_spi *spi);
+ void (*read_rx)(struct stm32_spi *spi);
void (*transfer_one_dma_start)(struct stm32_spi *spi);
void (*dma_rx_cb)(void *data);
void (*dma_tx_cb)(void *data);
@@ -259,7 +296,9 @@ struct stm32_spi_cfg {
unsigned int baud_rate_div_min;
unsigned int baud_rate_div_max;
bool has_fifo;
+ bool has_device_mode;
u16 flags;
+ bool prevent_dma_burst;
};
/**
@@ -273,8 +312,11 @@ struct stm32_spi_cfg {
* @lock: prevent I/O concurrent access
* @irq: SPI controller interrupt line
* @fifo_size: size of the embedded fifo in bytes
- * @cur_midi: master inter-data idleness in ns
+ * @t_size_max: maximum number of data of one transfer
+ * @feature_set: SPI full or limited feature set
+ * @cur_midi: host inter-data idleness in ns
* @cur_speed: speed configured in Hz
+ * @cur_half_period: time of a half bit in us
* @cur_bpw: number of bits in a single SPI data frame
* @cur_fthlv: fifo threshold level (data frames in a single data packet)
* @cur_comm: SPI communication mode
@@ -288,6 +330,11 @@ struct stm32_spi_cfg {
* @dma_rx: dma channel for RX transfer
* @phys_addr: SPI registers physical base address
* @device_mode: the controller is configured as SPI device
+ * @sram_pool: SRAM pool for DMA transfers
+ * @sram_rx_buf_size: size of SRAM buffer for RX transfer
+ * @sram_rx_buf: SRAM buffer for RX transfer
+ * @sram_dma_rx_buf: SRAM buffer physical address for RX transfer
+ * @mdma_rx: MDMA channel for RX transfer
*/
struct stm32_spi {
struct device *dev;
@@ -299,9 +346,14 @@ struct stm32_spi {
spinlock_t lock; /* prevent I/O concurrent access */
int irq;
unsigned int fifo_size;
+ unsigned int t_size_max;
+ unsigned int feature_set;
+#define STM32_SPI_FEATURE_LIMITED STM32MP25_SPI_HWCFGR1_FULLCFG_LIMITED /* 0x0 */
+#define STM32_SPI_FEATURE_FULL STM32MP25_SPI_HWCFGR1_FULLCFG_FULL /* 0x1 */
unsigned int cur_midi;
unsigned int cur_speed;
+ unsigned int cur_half_period;
unsigned int cur_bpw;
unsigned int cur_fthlv;
unsigned int cur_comm;
@@ -317,22 +369,28 @@ struct stm32_spi {
dma_addr_t phys_addr;
bool device_mode;
+
+ struct gen_pool *sram_pool;
+ size_t sram_rx_buf_size;
+ void *sram_rx_buf;
+ dma_addr_t sram_dma_rx_buf;
+ struct dma_chan *mdma_rx;
};
-static const struct stm32_spi_regspec stm32f4_spi_regspec = {
- .en = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE },
+static const struct stm32_spi_regspec stm32fx_spi_regspec = {
+ .en = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_SPE },
- .dma_rx_en = { STM32F4_SPI_CR2, STM32F4_SPI_CR2_RXDMAEN },
- .dma_tx_en = { STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXDMAEN },
+ .dma_rx_en = { STM32FX_SPI_CR2, STM32FX_SPI_CR2_RXDMAEN },
+ .dma_tx_en = { STM32FX_SPI_CR2, STM32FX_SPI_CR2_TXDMAEN },
- .cpol = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPOL },
- .cpha = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_CPHA },
- .lsb_first = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_LSBFRST },
+ .cpol = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_CPOL },
+ .cpha = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_CPHA },
+ .lsb_first = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_LSBFRST },
.cs_high = {},
- .br = { STM32F4_SPI_CR1, STM32F4_SPI_CR1_BR, STM32F4_SPI_CR1_BR_SHIFT },
+ .br = { STM32FX_SPI_CR1, STM32FX_SPI_CR1_BR, STM32FX_SPI_CR1_BR_SHIFT },
- .rx = { STM32F4_SPI_DR },
- .tx = { STM32F4_SPI_DR },
+ .rx = { STM32FX_SPI_DR },
+ .tx = { STM32FX_SPI_DR },
};
static const struct stm32_spi_regspec stm32h7_spi_regspec = {
@@ -355,6 +413,30 @@ static const struct stm32_spi_regspec stm32h7_spi_regspec = {
.tx = { STM32H7_SPI_TXDR },
};
+static const struct stm32_spi_regspec stm32mp25_spi_regspec = {
+ /* SPI data transfer is enabled but spi_ker_ck is idle.
+ * CFG1 and CFG2 registers are write protected when SPE is enabled.
+ */
+ .en = { STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE },
+
+ .dma_rx_en = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_RXDMAEN },
+ .dma_tx_en = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_TXDMAEN },
+
+ .cpol = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPOL },
+ .cpha = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_CPHA },
+ .lsb_first = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_LSBFRST },
+ .cs_high = { STM32H7_SPI_CFG2, STM32H7_SPI_CFG2_SSIOP },
+ .br = { STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_MBR,
+ STM32H7_SPI_CFG1_MBR_SHIFT },
+
+ .rx = { STM32H7_SPI_RXDR },
+ .tx = { STM32H7_SPI_TXDR },
+
+ .fullcfg = { STM32MP25_SPI_HWCFGR1, STM32MP25_SPI_HWCFGR1_FULLCFG },
+
+ .rdy_en = { STM32H7_SPI_CFG2, STM32MP25_SPI_CFG2_RDIOM },
+};
+
static inline void stm32_spi_set_bits(struct stm32_spi *spi,
u32 offset, u32 bits)
{
@@ -405,6 +487,16 @@ static int stm32f4_spi_get_bpw_mask(struct stm32_spi *spi)
}
/**
+ * stm32f7_spi_get_bpw_mask - Return bits per word mask
+ * @spi: pointer to the spi controller data structure
+ */
+static int stm32f7_spi_get_bpw_mask(struct stm32_spi *spi)
+{
+ dev_dbg(spi->dev, "16-bit maximum data frame\n");
+ return SPI_BPW_RANGE_MASK(4, 16);
+}
+
+/**
* stm32h7_spi_get_bpw_mask - Return bits per word mask
* @spi: pointer to the spi controller data structure
*/
@@ -432,6 +524,28 @@ static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi)
}
/**
+ * stm32mp25_spi_get_bpw_mask - Return bits per word mask
+ * @spi: pointer to the spi controller data structure
+ */
+static int stm32mp25_spi_get_bpw_mask(struct stm32_spi *spi)
+{
+ u32 dscfg, max_bpw;
+
+ if (spi->feature_set == STM32_SPI_FEATURE_LIMITED) {
+ dev_dbg(spi->dev, "8-bit or 16-bit data frame supported\n");
+ return SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ }
+
+ dscfg = FIELD_GET(STM32MP25_SPI_HWCFGR1_DSCFG,
+ readl_relaxed(spi->base + STM32MP25_SPI_HWCFGR1));
+ max_bpw = 16;
+ if (dscfg == STM32MP25_SPI_HWCFGR1_DSCFG_32_B)
+ max_bpw = 32;
+ dev_dbg(spi->dev, "%d-bit maximum data frame\n", max_bpw);
+ return SPI_BPW_RANGE_MASK(4, max_bpw);
+}
+
+/**
* stm32_spi_prepare_mbr - Determine baud rate divisor value
* @spi: pointer to the spi controller data structure
* @speed_hz: requested speed
@@ -466,6 +580,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz,
spi->cur_speed = spi->clk_rate / (1 << mbrdiv);
+ spi->cur_half_period = DIV_ROUND_CLOSEST(USEC_PER_SEC, 2 * spi->cur_speed);
+
return mbrdiv - 1;
}
@@ -495,19 +611,48 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi, u32 xfer_len)
*/
static void stm32f4_spi_write_tx(struct stm32_spi *spi)
{
- if ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32F4_SPI_SR) &
- STM32F4_SPI_SR_TXE)) {
+ if ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32FX_SPI_SR) &
+ STM32FX_SPI_SR_TXE)) {
u32 offs = spi->cur_xferlen - spi->tx_len;
if (spi->cur_bpw == 16) {
const u16 *tx_buf16 = (const u16 *)(spi->tx_buf + offs);
- writew_relaxed(*tx_buf16, spi->base + STM32F4_SPI_DR);
+ writew_relaxed(*tx_buf16, spi->base + STM32FX_SPI_DR);
spi->tx_len -= sizeof(u16);
} else {
const u8 *tx_buf8 = (const u8 *)(spi->tx_buf + offs);
- writeb_relaxed(*tx_buf8, spi->base + STM32F4_SPI_DR);
+ writeb_relaxed(*tx_buf8, spi->base + STM32FX_SPI_DR);
+ spi->tx_len -= sizeof(u8);
+ }
+ }
+
+ dev_dbg(spi->dev, "%s: %d bytes left\n", __func__, spi->tx_len);
+}
+
+/**
+ * stm32f7_spi_write_tx - Write bytes to Transmit Data Register
+ * @spi: pointer to the spi controller data structure
+ *
+ * Read from tx_buf depends on remaining bytes to avoid to read beyond
+ * tx_buf end.
+ */
+static void stm32f7_spi_write_tx(struct stm32_spi *spi)
+{
+ if ((spi->tx_len > 0) && (readl_relaxed(spi->base + STM32FX_SPI_SR) &
+ STM32FX_SPI_SR_TXE)) {
+ u32 offs = spi->cur_xferlen - spi->tx_len;
+
+ if (spi->tx_len >= sizeof(u16)) {
+ const u16 *tx_buf16 = (const u16 *)(spi->tx_buf + offs);
+
+ writew_relaxed(*tx_buf16, spi->base + STM32FX_SPI_DR);
+ spi->tx_len -= sizeof(u16);
+ } else {
+ const u8 *tx_buf8 = (const u8 *)(spi->tx_buf + offs);
+
+ writeb_relaxed(*tx_buf8, spi->base + STM32FX_SPI_DR);
spi->tx_len -= sizeof(u8);
}
}
@@ -559,19 +704,19 @@ static void stm32h7_spi_write_txfifo(struct stm32_spi *spi)
*/
static void stm32f4_spi_read_rx(struct stm32_spi *spi)
{
- if ((spi->rx_len > 0) && (readl_relaxed(spi->base + STM32F4_SPI_SR) &
- STM32F4_SPI_SR_RXNE)) {
+ if ((spi->rx_len > 0) && (readl_relaxed(spi->base + STM32FX_SPI_SR) &
+ STM32FX_SPI_SR_RXNE)) {
u32 offs = spi->cur_xferlen - spi->rx_len;
if (spi->cur_bpw == 16) {
u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs);
- *rx_buf16 = readw_relaxed(spi->base + STM32F4_SPI_DR);
+ *rx_buf16 = readw_relaxed(spi->base + STM32FX_SPI_DR);
spi->rx_len -= sizeof(u16);
} else {
u8 *rx_buf8 = (u8 *)(spi->rx_buf + offs);
- *rx_buf8 = readb_relaxed(spi->base + STM32F4_SPI_DR);
+ *rx_buf8 = readb_relaxed(spi->base + STM32FX_SPI_DR);
spi->rx_len -= sizeof(u8);
}
}
@@ -580,6 +725,46 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi)
}
/**
+ * stm32f7_spi_read_rx - Read bytes from Receive Data Register
+ * @spi: pointer to the spi controller data structure
+ *
+ * Write in rx_buf depends on remaining bytes to avoid to write beyond
+ * rx_buf end.
+ */
+static void stm32f7_spi_read_rx(struct stm32_spi *spi)
+{
+ u32 sr = readl_relaxed(spi->base + STM32FX_SPI_SR);
+ u32 frlvl = FIELD_GET(STM32F7_SPI_SR_FRLVL, sr);
+
+ while ((spi->rx_len > 0) && (frlvl > 0)) {
+ u32 offs = spi->cur_xferlen - spi->rx_len;
+
+ if ((spi->rx_len >= sizeof(u16)) && (frlvl >= 2)) {
+ u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs);
+
+ *rx_buf16 = readw_relaxed(spi->base + STM32FX_SPI_DR);
+ spi->rx_len -= sizeof(u16);
+ } else {
+ u8 *rx_buf8 = (u8 *)(spi->rx_buf + offs);
+
+ *rx_buf8 = readb_relaxed(spi->base + STM32FX_SPI_DR);
+ spi->rx_len -= sizeof(u8);
+ }
+
+ sr = readl_relaxed(spi->base + STM32FX_SPI_SR);
+ frlvl = FIELD_GET(STM32F7_SPI_SR_FRLVL, sr);
+ }
+
+ if (spi->rx_len >= sizeof(u16))
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
+ else
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
+
+ dev_dbg(spi->dev, "%s: %d bytes left (sr=%08x)\n",
+ __func__, spi->rx_len, sr);
+}
+
+/**
* stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register
* @spi: pointer to the spi controller data structure
*
@@ -638,10 +823,10 @@ static void stm32_spi_enable(struct stm32_spi *spi)
}
/**
- * stm32f4_spi_disable - Disable SPI controller
+ * stm32fx_spi_disable - Disable SPI controller
* @spi: pointer to the spi controller data structure
*/
-static void stm32f4_spi_disable(struct stm32_spi *spi)
+static void stm32fx_spi_disable(struct stm32_spi *spi)
{
unsigned long flags;
u32 sr;
@@ -650,20 +835,20 @@ static void stm32f4_spi_disable(struct stm32_spi *spi)
spin_lock_irqsave(&spi->lock, flags);
- if (!(readl_relaxed(spi->base + STM32F4_SPI_CR1) &
- STM32F4_SPI_CR1_SPE)) {
+ if (!(readl_relaxed(spi->base + STM32FX_SPI_CR1) &
+ STM32FX_SPI_CR1_SPE)) {
spin_unlock_irqrestore(&spi->lock, flags);
return;
}
/* Disable interrupts */
- stm32_spi_clr_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXEIE |
- STM32F4_SPI_CR2_RXNEIE |
- STM32F4_SPI_CR2_ERRIE);
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32FX_SPI_CR2_TXEIE |
+ STM32FX_SPI_CR2_RXNEIE |
+ STM32FX_SPI_CR2_ERRIE);
/* Wait until BSY = 0 */
- if (readl_relaxed_poll_timeout_atomic(spi->base + STM32F4_SPI_SR,
- sr, !(sr & STM32F4_SPI_SR_BSY),
+ if (readl_relaxed_poll_timeout_atomic(spi->base + STM32FX_SPI_SR,
+ sr, !(sr & STM32FX_SPI_SR_BSY),
10, 100000) < 0) {
dev_warn(spi->dev, "disabling condition timeout\n");
}
@@ -673,14 +858,14 @@ static void stm32f4_spi_disable(struct stm32_spi *spi)
if (spi->cur_usedma && spi->dma_rx)
dmaengine_terminate_async(spi->dma_rx);
- stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_SPE);
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR1, STM32FX_SPI_CR1_SPE);
- stm32_spi_clr_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_TXDMAEN |
- STM32F4_SPI_CR2_RXDMAEN);
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32FX_SPI_CR2_TXDMAEN |
+ STM32FX_SPI_CR2_RXDMAEN);
/* Sequence to clear OVR flag */
- readl_relaxed(spi->base + STM32F4_SPI_DR);
- readl_relaxed(spi->base + STM32F4_SPI_SR);
+ readl_relaxed(spi->base + STM32FX_SPI_DR);
+ readl_relaxed(spi->base + STM32FX_SPI_SR);
spin_unlock_irqrestore(&spi->lock, flags);
}
@@ -707,10 +892,17 @@ static void stm32h7_spi_disable(struct stm32_spi *spi)
return;
}
+ /* Add a delay to make sure that transmission is ended. */
+ if (spi->cur_half_period)
+ udelay(spi->cur_half_period);
+
if (spi->cur_usedma && spi->dma_tx)
dmaengine_terminate_async(spi->dma_tx);
- if (spi->cur_usedma && spi->dma_rx)
+ if (spi->cur_usedma && spi->dma_rx) {
dmaengine_terminate_async(spi->dma_rx);
+ if (spi->mdma_rx)
+ dmaengine_terminate_async(spi->mdma_rx);
+ }
stm32_spi_clr_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE);
@@ -752,11 +944,11 @@ static bool stm32_spi_can_dma(struct spi_controller *ctrl,
}
/**
- * stm32f4_spi_irq_event - Interrupt handler for SPI controller events
+ * stm32fx_spi_irq_event - Interrupt handler for SPI controller events
* @irq: interrupt line
* @dev_id: SPI controller ctrl interface
*/
-static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
+static irqreturn_t stm32fx_spi_irq_event(int irq, void *dev_id)
{
struct spi_controller *ctrl = dev_id;
struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
@@ -765,26 +957,26 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
spin_lock(&spi->lock);
- sr = readl_relaxed(spi->base + STM32F4_SPI_SR);
+ sr = readl_relaxed(spi->base + STM32FX_SPI_SR);
/*
* BSY flag is not handled in interrupt but it is normal behavior when
* this flag is set.
*/
- sr &= ~STM32F4_SPI_SR_BSY;
+ sr &= ~STM32FX_SPI_SR_BSY;
if (!spi->cur_usedma && (spi->cur_comm == SPI_SIMPLEX_TX ||
spi->cur_comm == SPI_3WIRE_TX)) {
/* OVR flag shouldn't be handled for TX only mode */
- sr &= ~(STM32F4_SPI_SR_OVR | STM32F4_SPI_SR_RXNE);
- mask |= STM32F4_SPI_SR_TXE;
+ sr &= ~(STM32FX_SPI_SR_OVR | STM32FX_SPI_SR_RXNE);
+ mask |= STM32FX_SPI_SR_TXE;
}
if (!spi->cur_usedma && (spi->cur_comm == SPI_FULL_DUPLEX ||
spi->cur_comm == SPI_SIMPLEX_RX ||
spi->cur_comm == SPI_3WIRE_RX)) {
/* TXE flag is set and is handled when RXNE flag occurs */
- sr &= ~STM32F4_SPI_SR_TXE;
- mask |= STM32F4_SPI_SR_RXNE | STM32F4_SPI_SR_OVR;
+ sr &= ~STM32FX_SPI_SR_TXE;
+ mask |= STM32FX_SPI_SR_RXNE | STM32FX_SPI_SR_OVR;
}
if (!(sr & mask)) {
@@ -793,12 +985,12 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
return IRQ_NONE;
}
- if (sr & STM32F4_SPI_SR_OVR) {
+ if (sr & STM32FX_SPI_SR_OVR) {
dev_warn(spi->dev, "Overrun: received value discarded\n");
/* Sequence to clear OVR flag */
- readl_relaxed(spi->base + STM32F4_SPI_DR);
- readl_relaxed(spi->base + STM32F4_SPI_SR);
+ readl_relaxed(spi->base + STM32FX_SPI_DR);
+ readl_relaxed(spi->base + STM32FX_SPI_SR);
/*
* If overrun is detected, it means that something went wrong,
@@ -809,28 +1001,28 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
goto end_irq;
}
- if (sr & STM32F4_SPI_SR_TXE) {
+ if (sr & STM32FX_SPI_SR_TXE) {
if (spi->tx_buf)
- stm32f4_spi_write_tx(spi);
+ spi->cfg->write_tx(spi);
if (spi->tx_len == 0)
end = true;
}
- if (sr & STM32F4_SPI_SR_RXNE) {
- stm32f4_spi_read_rx(spi);
+ if (sr & STM32FX_SPI_SR_RXNE) {
+ spi->cfg->read_rx(spi);
if (spi->rx_len == 0)
end = true;
else if (spi->tx_buf)/* Load data for discontinuous mode */
- stm32f4_spi_write_tx(spi);
+ spi->cfg->write_tx(spi);
}
end_irq:
if (end) {
/* Immediately disable interrupts to do not generate new one */
- stm32_spi_clr_bits(spi, STM32F4_SPI_CR2,
- STM32F4_SPI_CR2_TXEIE |
- STM32F4_SPI_CR2_RXNEIE |
- STM32F4_SPI_CR2_ERRIE);
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR2,
+ STM32FX_SPI_CR2_TXEIE |
+ STM32FX_SPI_CR2_RXNEIE |
+ STM32FX_SPI_CR2_ERRIE);
spin_unlock(&spi->lock);
return IRQ_WAKE_THREAD;
}
@@ -840,17 +1032,17 @@ end_irq:
}
/**
- * stm32f4_spi_irq_thread - Thread of interrupt handler for SPI controller
+ * stm32fx_spi_irq_thread - Thread of interrupt handler for SPI controller
* @irq: interrupt line
* @dev_id: SPI controller interface
*/
-static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id)
+static irqreturn_t stm32fx_spi_irq_thread(int irq, void *dev_id)
{
struct spi_controller *ctrl = dev_id;
struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
spi_finalize_current_transfer(ctrl);
- stm32f4_spi_disable(spi);
+ stm32fx_spi_disable(spi);
return IRQ_HANDLED;
}
@@ -888,7 +1080,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
mask |= STM32H7_SPI_SR_TXP | STM32H7_SPI_SR_RXP;
if (!(sr & mask)) {
- dev_warn(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n",
+ dev_vdbg(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n",
sr, ier);
spin_unlock_irqrestore(&spi->lock, flags);
return IRQ_NONE;
@@ -922,10 +1114,13 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
}
if (sr & STM32H7_SPI_SR_EOT) {
+ dev_dbg(spi->dev, "End of transfer\n");
if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
stm32h7_spi_read_rxfifo(spi);
if (!spi->cur_usedma ||
- (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX))
+ (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) ||
+ (spi->mdma_rx && (spi->cur_comm == SPI_SIMPLEX_RX ||
+ spi->cur_comm == SPI_FULL_DUPLEX)))
end = true;
}
@@ -942,6 +1137,11 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
spin_unlock_irqrestore(&spi->lock, flags);
if (end) {
+ if (spi->cur_usedma && spi->mdma_rx) {
+ dmaengine_pause(spi->dma_rx);
+ /* Wait for callback */
+ return IRQ_HANDLED;
+ }
stm32h7_spi_disable(spi);
spi_finalize_current_transfer(ctrl);
}
@@ -949,6 +1149,21 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int stm32_spi_optimize_message(struct spi_message *msg)
+{
+ struct spi_controller *ctrl = msg->spi->controller;
+ struct stm32_spi *spi = spi_controller_get_devdata(ctrl);
+
+ /* On STM32H7, messages should not exceed a maximum size set
+ * later via the set_number_of_data function. In order to
+ * ensure that, split large messages into several messages
+ */
+ if (spi->cfg->set_number_of_data)
+ return spi_split_transfers_maxwords(ctrl, msg, spi->t_size_max);
+
+ return 0;
+}
+
/**
* stm32_spi_prepare_msg - set up the controller to transfer a single message
* @ctrl: controller interface
@@ -963,7 +1178,7 @@ static int stm32_spi_prepare_msg(struct spi_controller *ctrl,
unsigned long flags;
u32 clrb = 0, setb = 0;
- /* SPI slave device may need time between data frames */
+ /* SPI target device may need time between data frames */
spi->cur_midi = 0;
if (np && !of_property_read_u32(np, "st,spi-midi-ns", &spi->cur_midi))
dev_dbg(spi->dev, "%dns inter-data idleness\n", spi->cur_midi);
@@ -988,29 +1203,21 @@ static int stm32_spi_prepare_msg(struct spi_controller *ctrl,
else
clrb |= spi->cfg->regs->cs_high.mask;
- dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d\n",
+ if (spi_dev->mode & SPI_READY)
+ setb |= spi->cfg->regs->rdy_en.mask;
+ else
+ clrb |= spi->cfg->regs->rdy_en.mask;
+
+ dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d rdy=%d\n",
!!(spi_dev->mode & SPI_CPOL),
!!(spi_dev->mode & SPI_CPHA),
!!(spi_dev->mode & SPI_LSB_FIRST),
- !!(spi_dev->mode & SPI_CS_HIGH));
-
- /* On STM32H7, messages should not exceed a maximum size setted
- * afterward via the set_number_of_data function. In order to
- * ensure that, split large messages into several messages
- */
- if (spi->cfg->set_number_of_data) {
- int ret;
-
- ret = spi_split_transfers_maxsize(ctrl, msg,
- STM32H7_SPI_TSIZE_MAX,
- GFP_KERNEL | GFP_DMA);
- if (ret)
- return ret;
- }
+ !!(spi_dev->mode & SPI_CS_HIGH),
+ !!(spi_dev->mode & SPI_READY));
spin_lock_irqsave(&spi->lock, flags);
- /* CPOL, CPHA and LSB FIRST bits have common register */
+ /* CPOL, CPHA, LSB FIRST, CS_HIGH and RDY_EN bits have common register */
if (clrb || setb)
writel_relaxed(
(readl_relaxed(spi->base + spi->cfg->regs->cpol.reg) &
@@ -1023,18 +1230,18 @@ static int stm32_spi_prepare_msg(struct spi_controller *ctrl,
}
/**
- * stm32f4_spi_dma_tx_cb - dma callback
+ * stm32fx_spi_dma_tx_cb - dma callback
* @data: pointer to the spi controller data structure
*
* DMA callback is called when the transfer is complete for DMA TX channel.
*/
-static void stm32f4_spi_dma_tx_cb(void *data)
+static void stm32fx_spi_dma_tx_cb(void *data)
{
struct stm32_spi *spi = data;
if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) {
spi_finalize_current_transfer(spi->ctrl);
- stm32f4_spi_disable(spi);
+ stm32fx_spi_disable(spi);
}
}
@@ -1056,15 +1263,19 @@ static void stm32_spi_dma_rx_cb(void *data)
* stm32_spi_dma_config - configure dma slave channel depending on current
* transfer bits_per_word.
* @spi: pointer to the spi controller data structure
+ * @dma_chan: pointer to the DMA channel
* @dma_conf: pointer to the dma_slave_config structure
* @dir: direction of the dma transfer
*/
static void stm32_spi_dma_config(struct stm32_spi *spi,
+ struct dma_chan *dma_chan,
struct dma_slave_config *dma_conf,
enum dma_transfer_direction dir)
{
enum dma_slave_buswidth buswidth;
- u32 maxburst;
+ struct dma_slave_caps caps;
+ u32 maxburst = 1;
+ int ret;
if (spi->cur_bpw <= 8)
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
@@ -1073,15 +1284,14 @@ static void stm32_spi_dma_config(struct stm32_spi *spi,
else
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
- if (spi->cfg->has_fifo) {
- /* Valid for DMA Half or Full Fifo threshold */
- if (spi->cur_fthlv == 2)
- maxburst = 1;
- else
- maxburst = spi->cur_fthlv;
- } else {
- maxburst = 1;
- }
+ /* Valid for DMA Half or Full Fifo threshold */
+ if (!spi->cfg->prevent_dma_burst && spi->cfg->has_fifo && spi->cur_fthlv != 2)
+ maxburst = spi->cur_fthlv;
+
+ /* Get the DMA channel caps, and adjust maxburst if possible */
+ ret = dma_get_slave_caps(dma_chan, &caps);
+ if (!ret)
+ maxburst = min(maxburst, caps.max_burst);
memset(dma_conf, 0, sizeof(struct dma_slave_config));
dma_conf->direction = dir;
@@ -1103,21 +1313,21 @@ static void stm32_spi_dma_config(struct stm32_spi *spi,
}
/**
- * stm32f4_spi_transfer_one_irq - transfer a single spi_transfer using
+ * stm32fx_spi_transfer_one_irq - transfer a single spi_transfer using
* interrupts
* @spi: pointer to the spi controller data structure
*
* It must returns 0 if the transfer is finished or 1 if the transfer is still
* in progress.
*/
-static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi)
+static int stm32fx_spi_transfer_one_irq(struct stm32_spi *spi)
{
unsigned long flags;
u32 cr2 = 0;
/* Enable the interrupts relative to the current communication mode */
if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) {
- cr2 |= STM32F4_SPI_CR2_TXEIE;
+ cr2 |= STM32FX_SPI_CR2_TXEIE;
} else if (spi->cur_comm == SPI_FULL_DUPLEX ||
spi->cur_comm == SPI_SIMPLEX_RX ||
spi->cur_comm == SPI_3WIRE_RX) {
@@ -1125,20 +1335,20 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi)
* since the received data are never read. Therefore set OVR
* interrupt only when rx buffer is available.
*/
- cr2 |= STM32F4_SPI_CR2_RXNEIE | STM32F4_SPI_CR2_ERRIE;
+ cr2 |= STM32FX_SPI_CR2_RXNEIE | STM32FX_SPI_CR2_ERRIE;
} else {
return -EINVAL;
}
spin_lock_irqsave(&spi->lock, flags);
- stm32_spi_set_bits(spi, STM32F4_SPI_CR2, cr2);
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR2, cr2);
stm32_spi_enable(spi);
/* starting data transfer when buffer is loaded */
if (spi->tx_buf)
- stm32f4_spi_write_tx(spi);
+ spi->cfg->write_tx(spi);
spin_unlock_irqrestore(&spi->lock, flags);
@@ -1178,7 +1388,7 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi)
if (spi->tx_buf)
stm32h7_spi_write_txfifo(spi);
- if (STM32_SPI_MASTER_MODE(spi))
+ if (STM32_SPI_HOST_MODE(spi))
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART);
writel_relaxed(ier, spi->base + STM32H7_SPI_IER);
@@ -1189,11 +1399,11 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi)
}
/**
- * stm32f4_spi_transfer_one_dma_start - Set SPI driver registers to start
+ * stm32fx_spi_transfer_one_dma_start - Set SPI driver registers to start
* transfer using DMA
* @spi: pointer to the spi controller data structure
*/
-static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi)
+static void stm32fx_spi_transfer_one_dma_start(struct stm32_spi *spi)
{
/* In DMA mode end of transfer is handled by DMA TX or RX callback. */
if (spi->cur_comm == SPI_SIMPLEX_RX || spi->cur_comm == SPI_3WIRE_RX ||
@@ -1203,13 +1413,29 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi)
* since the received data are never read. Therefore set OVR
* interrupt only when rx buffer is available.
*/
- stm32_spi_set_bits(spi, STM32F4_SPI_CR2, STM32F4_SPI_CR2_ERRIE);
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR2, STM32FX_SPI_CR2_ERRIE);
}
stm32_spi_enable(spi);
}
/**
+ * stm32f7_spi_transfer_one_dma_start - Set SPI driver registers to start
+ * transfer using DMA
+ * @spi: pointer to the spi controller data structure
+ */
+static void stm32f7_spi_transfer_one_dma_start(struct stm32_spi *spi)
+{
+ /* Configure DMA request trigger threshold according to DMA width */
+ if (spi->cur_bpw <= 8)
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
+ else
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR2, STM32F7_SPI_CR2_FRXTH);
+
+ stm32fx_spi_transfer_one_dma_start(spi);
+}
+
+/**
* stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start
* transfer using DMA
* @spi: pointer to the spi controller data structure
@@ -1221,16 +1447,133 @@ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi)
/* Enable the interrupts */
if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX)
ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE;
+ if (spi->mdma_rx && (spi->cur_comm == SPI_SIMPLEX_RX || spi->cur_comm == SPI_FULL_DUPLEX))
+ ier |= STM32H7_SPI_IER_EOTIE;
stm32_spi_set_bits(spi, STM32H7_SPI_IER, ier);
stm32_spi_enable(spi);
- if (STM32_SPI_MASTER_MODE(spi))
+ if (STM32_SPI_HOST_MODE(spi))
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART);
}
/**
+ * stm32_spi_prepare_rx_dma_mdma_chaining - Prepare RX DMA and MDMA chaining
+ * @spi: pointer to the spi controller data structure
+ * @xfer: pointer to the spi transfer
+ * @rx_dma_conf: pointer to the DMA configuration for RX channel
+ * @rx_dma_desc: pointer to the RX DMA descriptor
+ * @rx_mdma_desc: pointer to the RX MDMA descriptor
+ *
+ * It must return 0 if the chaining is possible or an error code if not.
+ */
+static int stm32_spi_prepare_rx_dma_mdma_chaining(struct stm32_spi *spi,
+ struct spi_transfer *xfer,
+ struct dma_slave_config *rx_dma_conf,
+ struct dma_async_tx_descriptor **rx_dma_desc,
+ struct dma_async_tx_descriptor **rx_mdma_desc)
+{
+ struct dma_async_tx_descriptor *_mdma_desc = *rx_mdma_desc;
+ struct dma_async_tx_descriptor *_dma_desc = *rx_dma_desc;
+ struct dma_slave_config rx_mdma_conf = {0};
+ u32 sram_period, nents = 0, spi_s_len;
+ struct sg_table dma_sgt, mdma_sgt;
+ struct scatterlist *spi_s, *s;
+ dma_addr_t dma_buf;
+ int i, ret;
+
+ sram_period = spi->sram_rx_buf_size / 2;
+
+ /* Configure MDMA RX channel */
+ rx_mdma_conf.direction = rx_dma_conf->direction;
+ rx_mdma_conf.src_addr = spi->sram_dma_rx_buf;
+ rx_mdma_conf.peripheral_config = rx_dma_conf->peripheral_config;
+ rx_mdma_conf.peripheral_size = rx_dma_conf->peripheral_size;
+ dmaengine_slave_config(spi->mdma_rx, &rx_mdma_conf);
+
+ /* Count the number of entries needed */
+ for_each_sg(xfer->rx_sg.sgl, spi_s, xfer->rx_sg.nents, i)
+ if (sg_dma_len(spi_s) > sram_period)
+ nents += DIV_ROUND_UP(sg_dma_len(spi_s), sram_period);
+ else
+ nents++;
+
+ /* Prepare DMA slave_sg DBM transfer DEV_TO_MEM (RX>MEM=SRAM) */
+ ret = sg_alloc_table(&dma_sgt, nents, GFP_ATOMIC);
+ if (ret)
+ return ret;
+
+ spi_s = xfer->rx_sg.sgl;
+ spi_s_len = sg_dma_len(spi_s);
+ dma_buf = spi->sram_dma_rx_buf;
+ for_each_sg(dma_sgt.sgl, s, dma_sgt.nents, i) {
+ size_t bytes = min_t(size_t, spi_s_len, sram_period);
+
+ sg_dma_len(s) = bytes;
+ sg_dma_address(s) = dma_buf;
+ spi_s_len -= bytes;
+
+ if (!spi_s_len && sg_next(spi_s)) {
+ spi_s = sg_next(spi_s);
+ spi_s_len = sg_dma_len(spi_s);
+ dma_buf = spi->sram_dma_rx_buf;
+ } else { /* DMA configured in DBM: it will swap between the SRAM periods */
+ if (i & 1)
+ dma_buf += sram_period;
+ else
+ dma_buf = spi->sram_dma_rx_buf;
+ }
+ }
+
+ _dma_desc = dmaengine_prep_slave_sg(spi->dma_rx, dma_sgt.sgl,
+ dma_sgt.nents, rx_dma_conf->direction,
+ DMA_PREP_INTERRUPT);
+ sg_free_table(&dma_sgt);
+
+ if (!_dma_desc)
+ return -EINVAL;
+
+ /* Prepare MDMA slave_sg transfer MEM_TO_MEM (SRAM>DDR) */
+ ret = sg_alloc_table(&mdma_sgt, nents, GFP_ATOMIC);
+ if (ret) {
+ _dma_desc = NULL;
+ return ret;
+ }
+
+ spi_s = xfer->rx_sg.sgl;
+ spi_s_len = sg_dma_len(spi_s);
+ dma_buf = sg_dma_address(spi_s);
+ for_each_sg(mdma_sgt.sgl, s, mdma_sgt.nents, i) {
+ size_t bytes = min_t(size_t, spi_s_len, sram_period);
+
+ sg_dma_len(s) = bytes;
+ sg_dma_address(s) = dma_buf;
+ spi_s_len -= bytes;
+
+ if (!spi_s_len && sg_next(spi_s)) {
+ spi_s = sg_next(spi_s);
+ spi_s_len = sg_dma_len(spi_s);
+ dma_buf = sg_dma_address(spi_s);
+ } else {
+ dma_buf += bytes;
+ }
+ }
+
+ _mdma_desc = dmaengine_prep_slave_sg(spi->mdma_rx, mdma_sgt.sgl,
+ mdma_sgt.nents, rx_mdma_conf.direction,
+ DMA_PREP_INTERRUPT);
+ sg_free_table(&mdma_sgt);
+
+ if (!_mdma_desc) {
+ _dma_desc = NULL;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
* stm32_spi_transfer_one_dma - transfer a single spi_transfer using DMA
* @spi: pointer to the spi controller data structure
* @xfer: pointer to the spi_transfer structure
@@ -1241,38 +1584,43 @@ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi)
static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
struct spi_transfer *xfer)
{
+ struct dma_async_tx_descriptor *rx_mdma_desc = NULL, *rx_dma_desc = NULL;
+ struct dma_async_tx_descriptor *tx_dma_desc = NULL;
struct dma_slave_config tx_dma_conf, rx_dma_conf;
- struct dma_async_tx_descriptor *tx_dma_desc, *rx_dma_desc;
unsigned long flags;
+ int ret = 0;
spin_lock_irqsave(&spi->lock, flags);
- rx_dma_desc = NULL;
if (spi->rx_buf && spi->dma_rx) {
- stm32_spi_dma_config(spi, &rx_dma_conf, DMA_DEV_TO_MEM);
- dmaengine_slave_config(spi->dma_rx, &rx_dma_conf);
-
- /* Enable Rx DMA request */
- stm32_spi_set_bits(spi, spi->cfg->regs->dma_rx_en.reg,
- spi->cfg->regs->dma_rx_en.mask);
-
- rx_dma_desc = dmaengine_prep_slave_sg(
- spi->dma_rx, xfer->rx_sg.sgl,
- xfer->rx_sg.nents,
- rx_dma_conf.direction,
- DMA_PREP_INTERRUPT);
+ stm32_spi_dma_config(spi, spi->dma_rx, &rx_dma_conf, DMA_DEV_TO_MEM);
+ if (spi->mdma_rx) {
+ rx_dma_conf.peripheral_size = 1;
+ dmaengine_slave_config(spi->dma_rx, &rx_dma_conf);
+
+ ret = stm32_spi_prepare_rx_dma_mdma_chaining(spi, xfer, &rx_dma_conf,
+ &rx_dma_desc, &rx_mdma_desc);
+ if (ret) { /* RX DMA MDMA chaining not possible, fallback to DMA only */
+ rx_dma_conf.peripheral_config = 0;
+ rx_dma_desc = NULL;
+ }
+ }
+ if (!rx_dma_desc) {
+ dmaengine_slave_config(spi->dma_rx, &rx_dma_conf);
+ rx_dma_desc = dmaengine_prep_slave_sg(spi->dma_rx, xfer->rx_sg.sgl,
+ xfer->rx_sg.nents,
+ rx_dma_conf.direction,
+ DMA_PREP_INTERRUPT);
+ }
}
- tx_dma_desc = NULL;
if (spi->tx_buf && spi->dma_tx) {
- stm32_spi_dma_config(spi, &tx_dma_conf, DMA_MEM_TO_DEV);
+ stm32_spi_dma_config(spi, spi->dma_tx, &tx_dma_conf, DMA_MEM_TO_DEV);
dmaengine_slave_config(spi->dma_tx, &tx_dma_conf);
-
- tx_dma_desc = dmaengine_prep_slave_sg(
- spi->dma_tx, xfer->tx_sg.sgl,
- xfer->tx_sg.nents,
- tx_dma_conf.direction,
- DMA_PREP_INTERRUPT);
+ tx_dma_desc = dmaengine_prep_slave_sg(spi->dma_tx, xfer->tx_sg.sgl,
+ xfer->tx_sg.nents,
+ tx_dma_conf.direction,
+ DMA_PREP_INTERRUPT);
}
if ((spi->tx_buf && spi->dma_tx && !tx_dma_desc) ||
@@ -1283,9 +1631,25 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
goto dma_desc_error;
if (rx_dma_desc) {
- rx_dma_desc->callback = spi->cfg->dma_rx_cb;
- rx_dma_desc->callback_param = spi;
+ if (rx_mdma_desc) {
+ rx_mdma_desc->callback = spi->cfg->dma_rx_cb;
+ rx_mdma_desc->callback_param = spi;
+ } else {
+ rx_dma_desc->callback = spi->cfg->dma_rx_cb;
+ rx_dma_desc->callback_param = spi;
+ }
+ /* Enable Rx DMA request */
+ stm32_spi_set_bits(spi, spi->cfg->regs->dma_rx_en.reg,
+ spi->cfg->regs->dma_rx_en.mask);
+ if (rx_mdma_desc) {
+ if (dma_submit_error(dmaengine_submit(rx_mdma_desc))) {
+ dev_err(spi->dev, "Rx MDMA submit failed\n");
+ goto dma_desc_error;
+ }
+ /* Enable Rx MDMA channel */
+ dma_async_issue_pending(spi->mdma_rx);
+ }
if (dma_submit_error(dmaengine_submit(rx_dma_desc))) {
dev_err(spi->dev, "Rx DMA submit failed\n");
goto dma_desc_error;
@@ -1320,6 +1684,8 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
return 1;
dma_submit_error:
+ if (spi->mdma_rx)
+ dmaengine_terminate_sync(spi->mdma_rx);
if (spi->dma_rx)
dmaengine_terminate_sync(spi->dma_rx);
@@ -1331,6 +1697,9 @@ dma_desc_error:
dev_info(spi->dev, "DMA issue: fall back to irq transfer\n");
+ if (spi->sram_rx_buf)
+ memset(spi->sram_rx_buf, 0, spi->sram_rx_buf_size);
+
spi->cur_usedma = false;
return spi->cfg->transfer_one_irq(spi);
}
@@ -1342,9 +1711,34 @@ dma_desc_error:
static void stm32f4_spi_set_bpw(struct stm32_spi *spi)
{
if (spi->cur_bpw == 16)
- stm32_spi_set_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_DFF);
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR1, STM32F4_SPI_CR1_DFF);
+ else
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR1, STM32F4_SPI_CR1_DFF);
+}
+
+/**
+ * stm32f7_spi_set_bpw - Configure bits per word
+ * @spi: pointer to the spi controller data structure
+ */
+static void stm32f7_spi_set_bpw(struct stm32_spi *spi)
+{
+ u32 bpw;
+ u32 cr2_clrb = 0, cr2_setb = 0;
+
+ bpw = spi->cur_bpw - 1;
+
+ cr2_clrb |= STM32F7_SPI_CR2_DS;
+ cr2_setb |= FIELD_PREP(STM32F7_SPI_CR2_DS, bpw);
+
+ if (spi->rx_len >= sizeof(u16))
+ cr2_clrb |= STM32F7_SPI_CR2_FRXTH;
else
- stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_DFF);
+ cr2_setb |= STM32F7_SPI_CR2_FRXTH;
+
+ writel_relaxed(
+ (readl_relaxed(spi->base + STM32FX_SPI_CR2) &
+ ~cr2_clrb) | cr2_setb,
+ spi->base + STM32FX_SPI_CR2);
}
/**
@@ -1374,7 +1768,7 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi)
}
/**
- * stm32_spi_set_mbr - Configure baud rate divisor in master mode
+ * stm32_spi_set_mbr - Configure baud rate divisor in host mode
* @spi: pointer to the spi controller data structure
* @mbrdiv: baud rate divisor value
*/
@@ -1422,26 +1816,26 @@ static unsigned int stm32_spi_communication_type(struct spi_device *spi_dev,
}
/**
- * stm32f4_spi_set_mode - configure communication mode
+ * stm32fx_spi_set_mode - configure communication mode
* @spi: pointer to the spi controller data structure
* @comm_type: type of communication to configure
*/
-static int stm32f4_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
+static int stm32fx_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
{
if (comm_type == SPI_3WIRE_TX || comm_type == SPI_SIMPLEX_TX) {
- stm32_spi_set_bits(spi, STM32F4_SPI_CR1,
- STM32F4_SPI_CR1_BIDIMODE |
- STM32F4_SPI_CR1_BIDIOE);
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR1,
+ STM32FX_SPI_CR1_BIDIMODE |
+ STM32FX_SPI_CR1_BIDIOE);
} else if (comm_type == SPI_FULL_DUPLEX ||
comm_type == SPI_SIMPLEX_RX) {
- stm32_spi_clr_bits(spi, STM32F4_SPI_CR1,
- STM32F4_SPI_CR1_BIDIMODE |
- STM32F4_SPI_CR1_BIDIOE);
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR1,
+ STM32FX_SPI_CR1_BIDIMODE |
+ STM32FX_SPI_CR1_BIDIOE);
} else if (comm_type == SPI_3WIRE_RX) {
- stm32_spi_set_bits(spi, STM32F4_SPI_CR1,
- STM32F4_SPI_CR1_BIDIMODE);
- stm32_spi_clr_bits(spi, STM32F4_SPI_CR1,
- STM32F4_SPI_CR1_BIDIOE);
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR1,
+ STM32FX_SPI_CR1_BIDIMODE);
+ stm32_spi_clr_bits(spi, STM32FX_SPI_CR1,
+ STM32FX_SPI_CR1_BIDIOE);
} else {
return -EINVAL;
}
@@ -1486,13 +1880,28 @@ static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
/**
* stm32h7_spi_data_idleness - configure minimum time delay inserted between two
- * consecutive data frames in master mode
+ * consecutive data frames in host mode
* @spi: pointer to the spi controller data structure
- * @len: transfer len
+ * @xfer: pointer to spi transfer
*/
-static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len)
+static void stm32h7_spi_data_idleness(struct stm32_spi *spi, struct spi_transfer *xfer)
{
u32 cfg2_clrb = 0, cfg2_setb = 0;
+ u32 len = xfer->len;
+ u32 spi_delay_ns;
+
+ spi_delay_ns = spi_delay_to_ns(&xfer->word_delay, xfer);
+
+ if (spi->cur_midi != 0) {
+ dev_warn(spi->dev, "st,spi-midi-ns DT property is deprecated\n");
+ if (spi_delay_ns) {
+ dev_warn(spi->dev, "Overriding st,spi-midi-ns with word_delay_ns %d\n",
+ spi_delay_ns);
+ spi->cur_midi = spi_delay_ns;
+ }
+ } else {
+ spi->cur_midi = spi_delay_ns;
+ }
cfg2_clrb |= STM32H7_SPI_CFG2_MIDI;
if ((len > 1) && (spi->cur_midi > 0)) {
@@ -1520,7 +1929,7 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len)
*/
static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words)
{
- if (nb_words <= STM32H7_SPI_TSIZE_MAX) {
+ if (nb_words <= spi->t_size_max) {
writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSIZE, nb_words),
spi->base + STM32H7_SPI_CR2);
} else {
@@ -1554,8 +1963,15 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
spi->cur_bpw = transfer->bits_per_word;
spi->cfg->set_bpw(spi);
+ if (spi_dev->mode & SPI_READY && spi->cur_bpw < 8) {
+ writel_relaxed(readl_relaxed(spi->base + spi->cfg->regs->rdy_en.reg) &
+ ~spi->cfg->regs->rdy_en.mask,
+ spi->base + spi->cfg->regs->rdy_en.reg);
+ dev_dbg(spi->dev, "RDY logic disabled as bits per word < 8\n");
+ }
+
/* Update spi->cur_speed with real clock speed */
- if (STM32_SPI_MASTER_MODE(spi)) {
+ if (STM32_SPI_HOST_MODE(spi)) {
mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz,
spi->cfg->baud_rate_div_min,
spi->cfg->baud_rate_div_max);
@@ -1575,8 +1991,8 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
spi->cur_comm = comm_type;
- if (STM32_SPI_MASTER_MODE(spi) && spi->cfg->set_data_idleness)
- spi->cfg->set_data_idleness(spi, transfer->len);
+ if (STM32_SPI_HOST_MODE(spi) && spi->cfg->set_data_idleness)
+ spi->cfg->set_data_idleness(spi, transfer);
if (spi->cur_bpw <= 8)
nb_words = transfer->len;
@@ -1596,7 +2012,7 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
dev_dbg(spi->dev,
"data frame of %d-bit, data packet of %d data frames\n",
spi->cur_bpw, spi->cur_fthlv);
- if (STM32_SPI_MASTER_MODE(spi))
+ if (STM32_SPI_HOST_MODE(spi))
dev_dbg(spi->dev, "speed set to %dHz\n", spi->cur_speed);
dev_dbg(spi->dev, "transfer of %d bytes (%d data frames)\n",
spi->cur_xferlen, nb_words);
@@ -1657,34 +2073,37 @@ static int stm32_spi_unprepare_msg(struct spi_controller *ctrl,
spi->cfg->disable(spi);
+ if (spi->sram_rx_buf)
+ memset(spi->sram_rx_buf, 0, spi->sram_rx_buf_size);
+
return 0;
}
/**
- * stm32f4_spi_config - Configure SPI controller as SPI master
+ * stm32fx_spi_config - Configure SPI controller as SPI host
* @spi: pointer to the spi controller data structure
*/
-static int stm32f4_spi_config(struct stm32_spi *spi)
+static int stm32fx_spi_config(struct stm32_spi *spi)
{
unsigned long flags;
spin_lock_irqsave(&spi->lock, flags);
/* Ensure I2SMOD bit is kept cleared */
- stm32_spi_clr_bits(spi, STM32F4_SPI_I2SCFGR,
- STM32F4_SPI_I2SCFGR_I2SMOD);
+ stm32_spi_clr_bits(spi, STM32FX_SPI_I2SCFGR,
+ STM32FX_SPI_I2SCFGR_I2SMOD);
/*
* - SS input value high
* - transmitter half duplex direction
- * - Set the master mode (default Motorola mode)
- * - Consider 1 master/n slaves configuration and
+ * - Set the host mode (default Motorola mode)
+ * - Consider 1 host/n targets configuration and
* SS input value is determined by the SSI bit
*/
- stm32_spi_set_bits(spi, STM32F4_SPI_CR1, STM32F4_SPI_CR1_SSI |
- STM32F4_SPI_CR1_BIDIOE |
- STM32F4_SPI_CR1_MSTR |
- STM32F4_SPI_CR1_SSM);
+ stm32_spi_set_bits(spi, STM32FX_SPI_CR1, STM32FX_SPI_CR1_SSI |
+ STM32FX_SPI_CR1_BIDIOE |
+ STM32FX_SPI_CR1_MSTR |
+ STM32FX_SPI_CR1_SSM);
spin_unlock_irqrestore(&spi->lock, flags);
@@ -1718,8 +2137,8 @@ static int stm32h7_spi_config(struct stm32_spi *spi)
cr1 |= STM32H7_SPI_CR1_HDDIR | STM32H7_SPI_CR1_MASRX | STM32H7_SPI_CR1_SSI;
/*
- * - Set the master mode (default Motorola mode)
- * - Consider 1 master/n devices configuration and
+ * - Set the host mode (default Motorola mode)
+ * - Consider 1 host/n devices configuration and
* SS input value is determined by the SSI bit
* - keep control of all associated GPIOs
*/
@@ -1735,22 +2154,46 @@ static int stm32h7_spi_config(struct stm32_spi *spi)
}
static const struct stm32_spi_cfg stm32f4_spi_cfg = {
- .regs = &stm32f4_spi_regspec,
+ .regs = &stm32fx_spi_regspec,
.get_bpw_mask = stm32f4_spi_get_bpw_mask,
- .disable = stm32f4_spi_disable,
- .config = stm32f4_spi_config,
+ .disable = stm32fx_spi_disable,
+ .config = stm32fx_spi_config,
.set_bpw = stm32f4_spi_set_bpw,
- .set_mode = stm32f4_spi_set_mode,
- .transfer_one_dma_start = stm32f4_spi_transfer_one_dma_start,
- .dma_tx_cb = stm32f4_spi_dma_tx_cb,
+ .set_mode = stm32fx_spi_set_mode,
+ .write_tx = stm32f4_spi_write_tx,
+ .read_rx = stm32f4_spi_read_rx,
+ .transfer_one_dma_start = stm32fx_spi_transfer_one_dma_start,
+ .dma_tx_cb = stm32fx_spi_dma_tx_cb,
.dma_rx_cb = stm32_spi_dma_rx_cb,
- .transfer_one_irq = stm32f4_spi_transfer_one_irq,
- .irq_handler_event = stm32f4_spi_irq_event,
- .irq_handler_thread = stm32f4_spi_irq_thread,
- .baud_rate_div_min = STM32F4_SPI_BR_DIV_MIN,
- .baud_rate_div_max = STM32F4_SPI_BR_DIV_MAX,
+ .transfer_one_irq = stm32fx_spi_transfer_one_irq,
+ .irq_handler_event = stm32fx_spi_irq_event,
+ .irq_handler_thread = stm32fx_spi_irq_thread,
+ .baud_rate_div_min = STM32FX_SPI_BR_DIV_MIN,
+ .baud_rate_div_max = STM32FX_SPI_BR_DIV_MAX,
.has_fifo = false,
- .flags = SPI_MASTER_MUST_TX,
+ .has_device_mode = false,
+ .flags = SPI_CONTROLLER_MUST_TX,
+};
+
+static const struct stm32_spi_cfg stm32f7_spi_cfg = {
+ .regs = &stm32fx_spi_regspec,
+ .get_bpw_mask = stm32f7_spi_get_bpw_mask,
+ .disable = stm32fx_spi_disable,
+ .config = stm32fx_spi_config,
+ .set_bpw = stm32f7_spi_set_bpw,
+ .set_mode = stm32fx_spi_set_mode,
+ .write_tx = stm32f7_spi_write_tx,
+ .read_rx = stm32f7_spi_read_rx,
+ .transfer_one_dma_start = stm32f7_spi_transfer_one_dma_start,
+ .dma_tx_cb = stm32fx_spi_dma_tx_cb,
+ .dma_rx_cb = stm32_spi_dma_rx_cb,
+ .transfer_one_irq = stm32fx_spi_transfer_one_irq,
+ .irq_handler_event = stm32fx_spi_irq_event,
+ .irq_handler_thread = stm32fx_spi_irq_thread,
+ .baud_rate_div_min = STM32FX_SPI_BR_DIV_MIN,
+ .baud_rate_div_max = STM32FX_SPI_BR_DIV_MAX,
+ .has_fifo = false,
+ .flags = SPI_CONTROLLER_MUST_TX,
};
static const struct stm32_spi_cfg stm32h7_spi_cfg = {
@@ -1763,6 +2206,8 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
.set_mode = stm32h7_spi_set_mode,
.set_data_idleness = stm32h7_spi_data_idleness,
.set_number_of_data = stm32h7_spi_number_of_data,
+ .write_tx = stm32h7_spi_write_txfifo,
+ .read_rx = stm32h7_spi_read_rxfifo,
.transfer_one_dma_start = stm32h7_spi_transfer_one_dma_start,
.dma_rx_cb = stm32_spi_dma_rx_cb,
/*
@@ -1774,11 +2219,44 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = {
.baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
.baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
.has_fifo = true,
+ .has_device_mode = true,
+};
+
+/*
+ * STM32MP2 is compatible with the STM32H7 except:
+ * - enforce the DMA maxburst value to 1
+ * - spi8 have limited feature set (TSIZE_MAX = 1024, BPW of 8 OR 16)
+ */
+static const struct stm32_spi_cfg stm32mp25_spi_cfg = {
+ .regs = &stm32mp25_spi_regspec,
+ .get_fifo_size = stm32h7_spi_get_fifo_size,
+ .get_bpw_mask = stm32mp25_spi_get_bpw_mask,
+ .disable = stm32h7_spi_disable,
+ .config = stm32h7_spi_config,
+ .set_bpw = stm32h7_spi_set_bpw,
+ .set_mode = stm32h7_spi_set_mode,
+ .set_data_idleness = stm32h7_spi_data_idleness,
+ .set_number_of_data = stm32h7_spi_number_of_data,
+ .transfer_one_dma_start = stm32h7_spi_transfer_one_dma_start,
+ .dma_rx_cb = stm32_spi_dma_rx_cb,
+ /*
+ * dma_tx_cb is not necessary since in case of TX, dma is followed by
+ * SPI access hence handling is performed within the SPI interrupt
+ */
+ .transfer_one_irq = stm32h7_spi_transfer_one_irq,
+ .irq_handler_thread = stm32h7_spi_irq_thread,
+ .baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN,
+ .baud_rate_div_max = STM32H7_SPI_MBR_DIV_MAX,
+ .has_fifo = true,
+ .prevent_dma_burst = true,
+ .has_device_mode = true,
};
static const struct of_device_id stm32_spi_of_match[] = {
+ { .compatible = "st,stm32mp25-spi", .data = (void *)&stm32mp25_spi_cfg },
{ .compatible = "st,stm32h7-spi", .data = (void *)&stm32h7_spi_cfg },
{ .compatible = "st,stm32f4-spi", .data = (void *)&stm32f4_spi_cfg },
+ { .compatible = "st,stm32f7-spi", .data = (void *)&stm32f7_spi_cfg },
{},
};
MODULE_DEVICE_TABLE(of, stm32_spi_of_match);
@@ -1796,15 +2274,26 @@ static int stm32_spi_probe(struct platform_device *pdev)
struct resource *res;
struct reset_control *rst;
struct device_node *np = pdev->dev.of_node;
+ const struct stm32_spi_cfg *cfg;
bool device_mode;
int ret;
+ cfg = of_device_get_match_data(&pdev->dev);
+ if (!cfg) {
+ dev_err(&pdev->dev, "Failed to get match data for platform\n");
+ return -ENODEV;
+ }
+
device_mode = of_property_read_bool(np, "spi-slave");
+ if (!cfg->has_device_mode && device_mode) {
+ dev_err(&pdev->dev, "spi-slave not supported\n");
+ return -EPERM;
+ }
if (device_mode)
- ctrl = devm_spi_alloc_slave(&pdev->dev, sizeof(struct stm32_spi));
+ ctrl = devm_spi_alloc_target(&pdev->dev, sizeof(struct stm32_spi));
else
- ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi));
+ ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(struct stm32_spi));
if (!ctrl) {
dev_err(&pdev->dev, "spi controller allocation failed\n");
return -ENOMEM;
@@ -1817,9 +2306,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
spi->device_mode = device_mode;
spin_lock_init(&spi->lock);
- spi->cfg = (const struct stm32_spi_cfg *)
- of_match_device(pdev->dev.driver->of_match_table,
- &pdev->dev)->data;
+ spi->cfg = cfg;
spi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(spi->base))
@@ -1829,8 +2316,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
spi->irq = platform_get_irq(pdev, 0);
if (spi->irq <= 0)
- return dev_err_probe(&pdev->dev, spi->irq,
- "failed to get irq\n");
+ return spi->irq;
ret = devm_request_threaded_irq(&pdev->dev, spi->irq,
spi->cfg->irq_handler_event,
@@ -1877,6 +2363,22 @@ static int stm32_spi_probe(struct platform_device *pdev)
if (spi->cfg->has_fifo)
spi->fifo_size = spi->cfg->get_fifo_size(spi);
+ spi->feature_set = STM32_SPI_FEATURE_FULL;
+ if (spi->cfg->regs->fullcfg.reg) {
+ spi->feature_set =
+ FIELD_GET(STM32MP25_SPI_HWCFGR1_FULLCFG,
+ readl_relaxed(spi->base + spi->cfg->regs->fullcfg.reg));
+
+ dev_dbg(spi->dev, "%s feature set\n",
+ spi->feature_set == STM32_SPI_FEATURE_FULL ? "full" : "limited");
+ }
+
+ /* Only for STM32H7 and after */
+ spi->t_size_max = spi->feature_set == STM32_SPI_FEATURE_FULL ?
+ STM32H7_SPI_TSIZE_MAX :
+ STM32MP25_SPI_TSIZE_MAX_LIMITED;
+ dev_dbg(spi->dev, "one message max size %d\n", spi->t_size_max);
+
ret = spi->cfg->config(spi);
if (ret) {
dev_err(&pdev->dev, "controller configuration failed: %d\n",
@@ -1888,17 +2390,18 @@ static int stm32_spi_probe(struct platform_device *pdev)
ctrl->auto_runtime_pm = true;
ctrl->bus_num = pdev->id;
ctrl->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST |
- SPI_3WIRE;
+ SPI_3WIRE | SPI_READY;
ctrl->bits_per_word_mask = spi->cfg->get_bpw_mask(spi);
ctrl->max_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_min;
ctrl->min_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_max;
ctrl->use_gpio_descriptors = true;
+ ctrl->optimize_message = stm32_spi_optimize_message;
ctrl->prepare_message = stm32_spi_prepare_msg;
ctrl->transfer_one = stm32_spi_transfer_one;
ctrl->unprepare_message = stm32_spi_unprepare_msg;
ctrl->flags = spi->cfg->flags;
if (STM32_SPI_DEVICE_MODE(spi))
- ctrl->slave_abort = stm32h7_spi_device_abort;
+ ctrl->target_abort = stm32h7_spi_device_abort;
spi->dma_tx = dma_request_chan(spi->dev, "tx");
if (IS_ERR(spi->dma_tx)) {
@@ -1927,6 +2430,33 @@ static int stm32_spi_probe(struct platform_device *pdev)
if (spi->dma_tx || spi->dma_rx)
ctrl->can_dma = stm32_spi_can_dma;
+ spi->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
+ if (spi->sram_pool) {
+ spi->sram_rx_buf_size = gen_pool_size(spi->sram_pool);
+ dev_info(&pdev->dev, "SRAM pool: %zu KiB for RX DMA/MDMA chaining\n",
+ spi->sram_rx_buf_size / 1024);
+ spi->sram_rx_buf = gen_pool_dma_zalloc(spi->sram_pool, spi->sram_rx_buf_size,
+ &spi->sram_dma_rx_buf);
+ if (!spi->sram_rx_buf) {
+ dev_err(&pdev->dev, "failed to allocate SRAM buffer\n");
+ } else {
+ spi->mdma_rx = dma_request_chan(spi->dev, "rxm2m");
+ if (IS_ERR(spi->mdma_rx)) {
+ ret = PTR_ERR(spi->mdma_rx);
+ spi->mdma_rx = NULL;
+ if (ret == -EPROBE_DEFER) {
+ goto err_pool_free;
+ } else {
+ gen_pool_free(spi->sram_pool,
+ (unsigned long)spi->sram_rx_buf,
+ spi->sram_rx_buf_size);
+ dev_warn(&pdev->dev,
+ "failed to request rx mdma channel, DMA only\n");
+ }
+ }
+ }
+ }
+
pm_runtime_set_autosuspend_delay(&pdev->dev,
STM32_SPI_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(&pdev->dev);
@@ -1941,11 +2471,10 @@ static int stm32_spi_probe(struct platform_device *pdev)
goto err_pm_disable;
}
- pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
dev_info(&pdev->dev, "driver initialized (%s mode)\n",
- STM32_SPI_MASTER_MODE(spi) ? "master" : "device");
+ STM32_SPI_HOST_MODE(spi) ? "host" : "device");
return 0;
@@ -1954,6 +2483,13 @@ err_pm_disable:
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
+
+ if (spi->mdma_rx)
+ dma_release_channel(spi->mdma_rx);
+err_pool_free:
+ if (spi->sram_pool)
+ gen_pool_free(spi->sram_pool, (unsigned long)spi->sram_rx_buf,
+ spi->sram_rx_buf_size);
err_dma_release:
if (spi->dma_tx)
dma_release_channel(spi->dma_tx);
@@ -1984,6 +2520,11 @@ static void stm32_spi_remove(struct platform_device *pdev)
dma_release_channel(ctrl->dma_tx);
if (ctrl->dma_rx)
dma_release_channel(ctrl->dma_rx);
+ if (spi->mdma_rx)
+ dma_release_channel(spi->mdma_rx);
+ if (spi->sram_rx_buf)
+ gen_pool_free(spi->sram_pool, (unsigned long)spi->sram_rx_buf,
+ spi->sram_rx_buf_size);
clk_disable_unprepare(spi->clk);
@@ -2050,7 +2591,6 @@ static int __maybe_unused stm32_spi_resume(struct device *dev)
spi->cfg->config(spi);
- pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -2064,7 +2604,7 @@ static const struct dev_pm_ops stm32_spi_pm_ops = {
static struct platform_driver stm32_spi_driver = {
.probe = stm32_spi_probe,
- .remove_new = stm32_spi_remove,
+ .remove = stm32_spi_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &stm32_spi_pm_ops,
diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index b8947265d329..aa92fd5a35a9 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -75,7 +75,7 @@
#define SUN4I_FIFO_STA_TF_CNT_BITS 16
struct sun4i_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base_addr;
struct clk *hclk;
struct clk *mclk;
@@ -161,7 +161,7 @@ static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
+ struct sun4i_spi *sspi = spi_controller_get_devdata(spi->controller);
u32 reg;
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
@@ -201,12 +201,13 @@ static size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
return SUN4I_MAX_XFER_SIZE - 1;
}
-static int sun4i_spi_transfer_one(struct spi_master *master,
+static int sun4i_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct sun4i_spi *sspi = spi_master_get_devdata(master);
- unsigned int mclk_rate, div, timeout;
+ struct sun4i_spi *sspi = spi_controller_get_devdata(host);
+ unsigned int mclk_rate, div;
+ unsigned long time_left;
unsigned int start, end, tx_time;
unsigned int tx_len = 0;
int ret = 0;
@@ -263,6 +264,9 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
else
reg |= SUN4I_CTL_DHB;
+ /* Now that the settings are correct, enable the interface */
+ reg |= SUN4I_CTL_ENABLE;
+
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
/* Ensure that we have a parent clock fast enough */
@@ -327,11 +331,11 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
start = jiffies;
- timeout = wait_for_completion_timeout(&sspi->done,
- msecs_to_jiffies(tx_time));
+ time_left = wait_for_completion_timeout(&sspi->done,
+ msecs_to_jiffies(tx_time));
end = jiffies;
- if (!timeout) {
- dev_warn(&master->dev,
+ if (!time_left) {
+ dev_warn(&host->dev,
"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
dev_name(&spi->dev), tfr->len, tfr->speed_hz,
jiffies_to_msecs(end - start), tx_time);
@@ -386,8 +390,8 @@ static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
static int sun4i_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(sspi->hclk);
@@ -403,7 +407,7 @@ static int sun4i_spi_runtime_resume(struct device *dev)
}
sun4i_spi_write(sspi, SUN4I_CTL_REG,
- SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP);
+ SUN4I_CTL_MASTER | SUN4I_CTL_TP);
return 0;
@@ -415,8 +419,8 @@ out:
static int sun4i_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sun4i_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sun4i_spi *sspi = spi_controller_get_devdata(host);
clk_disable_unprepare(sspi->mclk);
clk_disable_unprepare(sspi->hclk);
@@ -426,62 +430,63 @@ static int sun4i_spi_runtime_suspend(struct device *dev)
static int sun4i_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct sun4i_spi *sspi;
int ret = 0, irq;
- master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
- if (!master) {
- dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(struct sun4i_spi));
+ if (!host) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Host\n");
return -ENOMEM;
}
- platform_set_drvdata(pdev, master);
- sspi = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, host);
+ sspi = spi_controller_get_devdata(host);
sspi->base_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sspi->base_addr)) {
ret = PTR_ERR(sspi->base_addr);
- goto err_free_master;
+ goto err_free_host;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
- goto err_free_master;
+ goto err_free_host;
}
ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
0, "sun4i-spi", sspi);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
- goto err_free_master;
+ goto err_free_host;
}
- sspi->master = master;
- master->max_speed_hz = 100 * 1000 * 1000;
- master->min_speed_hz = 3 * 1000;
- master->set_cs = sun4i_spi_set_cs;
- master->transfer_one = sun4i_spi_transfer_one;
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->dev.of_node = pdev->dev.of_node;
- master->auto_runtime_pm = true;
- master->max_transfer_size = sun4i_spi_max_transfer_size;
+ sspi->host = host;
+ host->max_speed_hz = 100 * 1000 * 1000;
+ host->min_speed_hz = 3 * 1000;
+ host->use_gpio_descriptors = true;
+ host->set_cs = sun4i_spi_set_cs;
+ host->transfer_one = sun4i_spi_transfer_one;
+ host->num_chipselect = 4;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->dev.of_node = pdev->dev.of_node;
+ host->auto_runtime_pm = true;
+ host->max_transfer_size = sun4i_spi_max_transfer_size;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
ret = PTR_ERR(sspi->hclk);
- goto err_free_master;
+ goto err_free_host;
}
sspi->mclk = devm_clk_get(&pdev->dev, "mod");
if (IS_ERR(sspi->mclk)) {
dev_err(&pdev->dev, "Unable to acquire module clock\n");
ret = PTR_ERR(sspi->mclk);
- goto err_free_master;
+ goto err_free_host;
}
init_completion(&sspi->done);
@@ -493,16 +498,16 @@ static int sun4i_spi_probe(struct platform_device *pdev)
ret = sun4i_spi_runtime_resume(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't resume the device\n");
- goto err_free_master;
+ goto err_free_host;
}
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&pdev->dev, "cannot register SPI master\n");
+ dev_err(&pdev->dev, "cannot register SPI host\n");
goto err_pm_disable;
}
@@ -511,8 +516,8 @@ static int sun4i_spi_probe(struct platform_device *pdev)
err_pm_disable:
pm_runtime_disable(&pdev->dev);
sun4i_spi_runtime_suspend(&pdev->dev);
-err_free_master:
- spi_master_put(master);
+err_free_host:
+ spi_controller_put(host);
return ret;
}
@@ -534,7 +539,7 @@ static const struct dev_pm_ops sun4i_spi_pm_ops = {
static struct platform_driver sun4i_spi_driver = {
.probe = sun4i_spi_probe,
- .remove_new = sun4i_spi_remove,
+ .remove = sun4i_spi_remove,
.driver = {
.name = "sun4i-spi",
.of_match_table = sun4i_spi_match,
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 30d541612253..871dfd3e77be 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -83,6 +83,9 @@
#define SUN6I_XMIT_CNT_REG 0x34
#define SUN6I_BURST_CTL_CNT_REG 0x38
+#define SUN6I_BURST_CTL_CNT_STC_MASK GENMASK(23, 0)
+#define SUN6I_BURST_CTL_CNT_DRM BIT(28)
+#define SUN6I_BURST_CTL_CNT_QUAD_EN BIT(29)
#define SUN6I_TXDATA_REG 0x200
#define SUN6I_RXDATA_REG 0x300
@@ -90,10 +93,11 @@
struct sun6i_spi_cfg {
unsigned long fifo_depth;
bool has_clk_ctl;
+ u32 mode_bits;
};
struct sun6i_spi {
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base_addr;
dma_addr_t dma_addr_rx;
dma_addr_t dma_addr_tx;
@@ -102,6 +106,7 @@ struct sun6i_spi {
struct reset_control *rstc;
struct completion done;
+ struct completion dma_rx_done;
const u8 *tx_buf;
u8 *rx_buf;
@@ -176,7 +181,7 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi)
static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
+ struct sun6i_spi *sspi = spi_controller_get_devdata(spi->controller);
u32 reg;
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -196,30 +201,39 @@ static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
return SUN6I_MAX_XFER_SIZE - 1;
}
+static void sun6i_spi_dma_rx_cb(void *param)
+{
+ struct sun6i_spi *sspi = param;
+
+ complete(&sspi->dma_rx_done);
+}
+
static int sun6i_spi_prepare_dma(struct sun6i_spi *sspi,
struct spi_transfer *tfr)
{
struct dma_async_tx_descriptor *rxdesc, *txdesc;
- struct spi_master *master = sspi->master;
+ struct spi_controller *host = sspi->host;
rxdesc = NULL;
if (tfr->rx_buf) {
struct dma_slave_config rxconf = {
.direction = DMA_DEV_TO_MEM,
.src_addr = sspi->dma_addr_rx,
- .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
.src_maxburst = 8,
};
- dmaengine_slave_config(master->dma_rx, &rxconf);
+ dmaengine_slave_config(host->dma_rx, &rxconf);
- rxdesc = dmaengine_prep_slave_sg(master->dma_rx,
+ rxdesc = dmaengine_prep_slave_sg(host->dma_rx,
tfr->rx_sg.sgl,
tfr->rx_sg.nents,
DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!rxdesc)
return -EINVAL;
+ rxdesc->callback_param = sspi;
+ rxdesc->callback = sun6i_spi_dma_rx_cb;
}
txdesc = NULL;
@@ -231,42 +245,43 @@ static int sun6i_spi_prepare_dma(struct sun6i_spi *sspi,
.dst_maxburst = 8,
};
- dmaengine_slave_config(master->dma_tx, &txconf);
+ dmaengine_slave_config(host->dma_tx, &txconf);
- txdesc = dmaengine_prep_slave_sg(master->dma_tx,
+ txdesc = dmaengine_prep_slave_sg(host->dma_tx,
tfr->tx_sg.sgl,
tfr->tx_sg.nents,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT);
if (!txdesc) {
if (rxdesc)
- dmaengine_terminate_sync(master->dma_rx);
+ dmaengine_terminate_sync(host->dma_rx);
return -EINVAL;
}
}
if (tfr->rx_buf) {
dmaengine_submit(rxdesc);
- dma_async_issue_pending(master->dma_rx);
+ dma_async_issue_pending(host->dma_rx);
}
if (tfr->tx_buf) {
dmaengine_submit(txdesc);
- dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(host->dma_tx);
}
return 0;
}
-static int sun6i_spi_transfer_one(struct spi_master *master,
+static int sun6i_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *tfr)
{
- struct sun6i_spi *sspi = spi_master_get_devdata(master);
- unsigned int div, div_cdr1, div_cdr2, timeout;
+ struct sun6i_spi *sspi = spi_controller_get_devdata(host);
+ unsigned int div, div_cdr1, div_cdr2;
+ unsigned long time_left;
unsigned int start, end, tx_time;
unsigned int trig_level;
- unsigned int tx_len = 0, rx_len = 0;
+ unsigned int tx_len = 0, rx_len = 0, nbits = 0;
bool use_dma;
int ret = 0;
u32 reg;
@@ -275,10 +290,11 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
return -EINVAL;
reinit_completion(&sspi->done);
+ reinit_completion(&sspi->dma_rx_done);
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
- use_dma = master->can_dma ? master->can_dma(master, spi, tfr) : false;
+ use_dma = host->can_dma ? host->can_dma(host, spi, tfr) : false;
/* Clear pending interrupts */
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
@@ -418,13 +434,29 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);
/* Setup the transfer now... */
- if (sspi->tx_buf)
+ if (sspi->tx_buf) {
tx_len = tfr->len;
+ nbits = tfr->tx_nbits;
+ } else if (tfr->rx_buf) {
+ nbits = tfr->rx_nbits;
+ }
+
+ switch (nbits) {
+ case SPI_NBITS_DUAL:
+ reg = SUN6I_BURST_CTL_CNT_DRM;
+ break;
+ case SPI_NBITS_QUAD:
+ reg = SUN6I_BURST_CTL_CNT_QUAD_EN;
+ break;
+ case SPI_NBITS_SINGLE:
+ default:
+ reg = FIELD_PREP(SUN6I_BURST_CTL_CNT_STC_MASK, tx_len);
+ }
/* Setup the counters */
+ sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, reg);
sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, tfr->len);
sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_len);
- sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len);
if (!use_dma) {
/* Fill the TX FIFO */
@@ -432,7 +464,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
} else {
ret = sun6i_spi_prepare_dma(sspi, tfr);
if (ret) {
- dev_warn(&master->dev,
+ dev_warn(&host->dev,
"%s: prepare DMA failed, ret=%d",
dev_name(&spi->dev), ret);
return ret;
@@ -455,13 +487,29 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
- tx_time = spi_controller_xfer_timeout(master, tfr);
+ tx_time = spi_controller_xfer_timeout(host, tfr);
start = jiffies;
- timeout = wait_for_completion_timeout(&sspi->done,
- msecs_to_jiffies(tx_time));
+ time_left = wait_for_completion_timeout(&sspi->done,
+ msecs_to_jiffies(tx_time));
+
+ if (!use_dma) {
+ sun6i_spi_drain_fifo(sspi);
+ } else {
+ if (time_left && rx_len) {
+ /*
+ * Even though RX on the peripheral side has finished
+ * RX DMA might still be in flight
+ */
+ time_left = wait_for_completion_timeout(&sspi->dma_rx_done,
+ time_left);
+ if (!time_left)
+ dev_warn(&host->dev, "RX DMA timeout\n");
+ }
+ }
+
end = jiffies;
- if (!timeout) {
- dev_warn(&master->dev,
+ if (!time_left) {
+ dev_warn(&host->dev,
"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
dev_name(&spi->dev), tfr->len, tfr->speed_hz,
jiffies_to_msecs(end - start), tx_time);
@@ -471,8 +519,8 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
if (ret && use_dma) {
- dmaengine_terminate_sync(master->dma_rx);
- dmaengine_terminate_sync(master->dma_tx);
+ dmaengine_terminate_sync(host->dma_rx);
+ dmaengine_terminate_sync(host->dma_tx);
}
return ret;
@@ -486,7 +534,6 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
/* Transfer complete */
if (status & SUN6I_INT_CTL_TC) {
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
- sun6i_spi_drain_fifo(sspi);
complete(&sspi->done);
return IRQ_HANDLED;
}
@@ -518,8 +565,8 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
static int sun6i_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(sspi->hclk);
@@ -555,8 +602,8 @@ out:
static int sun6i_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct sun6i_spi *sspi = spi_controller_get_devdata(host);
reset_control_assert(sspi->rstc);
clk_disable_unprepare(sspi->mclk);
@@ -565,11 +612,11 @@ static int sun6i_spi_runtime_suspend(struct device *dev)
return 0;
}
-static bool sun6i_spi_can_dma(struct spi_master *master,
+static bool sun6i_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct sun6i_spi *sspi = spi_master_get_devdata(master);
+ struct sun6i_spi *sspi = spi_controller_get_devdata(host);
/*
* If the number of spi words to transfer is less or equal than
@@ -581,102 +628,104 @@ static bool sun6i_spi_can_dma(struct spi_master *master,
static int sun6i_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct sun6i_spi *sspi;
struct resource *mem;
int ret = 0, irq;
- master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
- if (!master) {
- dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(struct sun6i_spi));
+ if (!host) {
+ dev_err(&pdev->dev, "Unable to allocate SPI Host\n");
return -ENOMEM;
}
- platform_set_drvdata(pdev, master);
- sspi = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, host);
+ sspi = spi_controller_get_devdata(host);
sspi->base_addr = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
if (IS_ERR(sspi->base_addr)) {
ret = PTR_ERR(sspi->base_addr);
- goto err_free_master;
+ goto err_free_host;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
- goto err_free_master;
+ goto err_free_host;
}
ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
0, "sun6i-spi", sspi);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
- goto err_free_master;
+ goto err_free_host;
}
- sspi->master = master;
+ sspi->host = host;
sspi->cfg = of_device_get_match_data(&pdev->dev);
- master->max_speed_hz = 100 * 1000 * 1000;
- master->min_speed_hz = 3 * 1000;
- master->use_gpio_descriptors = true;
- master->set_cs = sun6i_spi_set_cs;
- master->transfer_one = sun6i_spi_transfer_one;
- master->num_chipselect = 4;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->dev.of_node = pdev->dev.of_node;
- master->auto_runtime_pm = true;
- master->max_transfer_size = sun6i_spi_max_transfer_size;
+ host->max_speed_hz = 100 * 1000 * 1000;
+ host->min_speed_hz = 3 * 1000;
+ host->use_gpio_descriptors = true;
+ host->set_cs = sun6i_spi_set_cs;
+ host->transfer_one = sun6i_spi_transfer_one;
+ host->num_chipselect = 4;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
+ sspi->cfg->mode_bits;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->dev.of_node = pdev->dev.of_node;
+ host->auto_runtime_pm = true;
+ host->max_transfer_size = sun6i_spi_max_transfer_size;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
ret = PTR_ERR(sspi->hclk);
- goto err_free_master;
+ goto err_free_host;
}
sspi->mclk = devm_clk_get(&pdev->dev, "mod");
if (IS_ERR(sspi->mclk)) {
dev_err(&pdev->dev, "Unable to acquire module clock\n");
ret = PTR_ERR(sspi->mclk);
- goto err_free_master;
+ goto err_free_host;
}
init_completion(&sspi->done);
+ init_completion(&sspi->dma_rx_done);
sspi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(sspi->rstc)) {
dev_err(&pdev->dev, "Couldn't get reset controller\n");
ret = PTR_ERR(sspi->rstc);
- goto err_free_master;
+ goto err_free_host;
}
- master->dma_tx = dma_request_chan(&pdev->dev, "tx");
- if (IS_ERR(master->dma_tx)) {
+ host->dma_tx = dma_request_chan(&pdev->dev, "tx");
+ if (IS_ERR(host->dma_tx)) {
/* Check tx to see if we need defer probing driver */
- if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) {
+ if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
- goto err_free_master;
+ goto err_free_host;
}
dev_warn(&pdev->dev, "Failed to request TX DMA channel\n");
- master->dma_tx = NULL;
+ host->dma_tx = NULL;
}
- master->dma_rx = dma_request_chan(&pdev->dev, "rx");
- if (IS_ERR(master->dma_rx)) {
- if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
+ host->dma_rx = dma_request_chan(&pdev->dev, "rx");
+ if (IS_ERR(host->dma_rx)) {
+ if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto err_free_dma_tx;
}
dev_warn(&pdev->dev, "Failed to request RX DMA channel\n");
- master->dma_rx = NULL;
+ host->dma_rx = NULL;
}
- if (master->dma_tx && master->dma_rx) {
+ if (host->dma_tx && host->dma_rx) {
sspi->dma_addr_tx = mem->start + SUN6I_TXDATA_REG;
sspi->dma_addr_rx = mem->start + SUN6I_RXDATA_REG;
- master->can_dma = sun6i_spi_can_dma;
+ host->can_dma = sun6i_spi_can_dma;
}
/*
@@ -694,9 +743,9 @@ static int sun6i_spi_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret) {
- dev_err(&pdev->dev, "cannot register SPI master\n");
+ dev_err(&pdev->dev, "cannot register SPI host\n");
goto err_pm_disable;
}
@@ -706,26 +755,26 @@ err_pm_disable:
pm_runtime_disable(&pdev->dev);
sun6i_spi_runtime_suspend(&pdev->dev);
err_free_dma_rx:
- if (master->dma_rx)
- dma_release_channel(master->dma_rx);
+ if (host->dma_rx)
+ dma_release_channel(host->dma_rx);
err_free_dma_tx:
- if (master->dma_tx)
- dma_release_channel(master->dma_tx);
-err_free_master:
- spi_master_put(master);
+ if (host->dma_tx)
+ dma_release_channel(host->dma_tx);
+err_free_host:
+ spi_controller_put(host);
return ret;
}
static void sun6i_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_controller *host = platform_get_drvdata(pdev);
pm_runtime_force_suspend(&pdev->dev);
- if (master->dma_tx)
- dma_release_channel(master->dma_tx);
- if (master->dma_rx)
- dma_release_channel(master->dma_rx);
+ if (host->dma_tx)
+ dma_release_channel(host->dma_tx);
+ if (host->dma_rx)
+ dma_release_channel(host->dma_rx);
}
static const struct sun6i_spi_cfg sun6i_a31_spi_cfg = {
@@ -740,6 +789,7 @@ static const struct sun6i_spi_cfg sun8i_h3_spi_cfg = {
static const struct sun6i_spi_cfg sun50i_r329_spi_cfg = {
.fifo_depth = SUN8I_FIFO_DEPTH,
+ .mode_bits = SPI_RX_DUAL | SPI_TX_DUAL | SPI_RX_QUAD | SPI_TX_QUAD,
};
static const struct of_device_id sun6i_spi_match[] = {
@@ -760,7 +810,7 @@ static const struct dev_pm_ops sun6i_spi_pm_ops = {
static struct platform_driver sun6i_spi_driver = {
.probe = sun6i_spi_probe,
- .remove_new = sun6i_spi_remove,
+ .remove = sun6i_spi_remove,
.driver = {
.name = "sun6i-spi",
.of_match_table = sun6i_spi_match,
diff --git a/drivers/spi/spi-sunplus-sp7021.c b/drivers/spi/spi-sunplus-sp7021.c
index eb8f835a4771..256ae07db6be 100644
--- a/drivers/spi/spi-sunplus-sp7021.c
+++ b/drivers/spi/spi-sunplus-sp7021.c
@@ -70,8 +70,8 @@
#define SP7021_FIFO_DATA_LEN (16)
enum {
- SP7021_MASTER_MODE = 0,
- SP7021_SLAVE_MODE = 1,
+ SP7021_HOST_MODE = 0,
+ SP7021_TARGET_MODE = 1,
};
struct sp7021_spi_ctlr {
@@ -88,7 +88,7 @@ struct sp7021_spi_ctlr {
// data xfer lock
struct mutex buf_lock;
struct completion isr_done;
- struct completion slave_isr;
+ struct completion target_isr;
unsigned int rx_cur_len;
unsigned int tx_cur_len;
unsigned int data_unit;
@@ -96,33 +96,33 @@ struct sp7021_spi_ctlr {
u8 *rx_buf;
};
-static irqreturn_t sp7021_spi_slave_irq(int irq, void *dev)
+static irqreturn_t sp7021_spi_target_irq(int irq, void *dev)
{
struct sp7021_spi_ctlr *pspim = dev;
unsigned int data_status;
data_status = readl(pspim->s_base + SP7021_DATA_RDY_REG);
data_status |= SP7021_SLAVE_CLR_INT;
- writel(data_status , pspim->s_base + SP7021_DATA_RDY_REG);
- complete(&pspim->slave_isr);
+ writel(data_status, pspim->s_base + SP7021_DATA_RDY_REG);
+ complete(&pspim->target_isr);
return IRQ_HANDLED;
}
-static int sp7021_spi_slave_abort(struct spi_controller *ctlr)
+static int sp7021_spi_target_abort(struct spi_controller *ctlr)
{
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
- complete(&pspim->slave_isr);
+ complete(&pspim->target_isr);
complete(&pspim->isr_done);
return 0;
}
-static int sp7021_spi_slave_tx(struct spi_device *spi, struct spi_transfer *xfer)
+static int sp7021_spi_target_tx(struct spi_device *spi, struct spi_transfer *xfer)
{
struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller);
u32 value;
- reinit_completion(&pspim->slave_isr);
+ reinit_completion(&pspim->target_isr);
value = SP7021_SLAVE_DMA_EN | SP7021_SLAVE_DMA_RW | FIELD_PREP(SP7021_SLAVE_DMA_CMD, 3);
writel(value, pspim->s_base + SP7021_SLAVE_DMA_CTRL_REG);
writel(xfer->len, pspim->s_base + SP7021_SLAVE_DMA_LENGTH_REG);
@@ -137,7 +137,7 @@ static int sp7021_spi_slave_tx(struct spi_device *spi, struct spi_transfer *xfer
return 0;
}
-static int sp7021_spi_slave_rx(struct spi_device *spi, struct spi_transfer *xfer)
+static int sp7021_spi_target_rx(struct spi_device *spi, struct spi_transfer *xfer)
{
struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(spi->controller);
u32 value;
@@ -155,7 +155,7 @@ static int sp7021_spi_slave_rx(struct spi_device *spi, struct spi_transfer *xfer
return 0;
}
-static void sp7021_spi_master_rb(struct sp7021_spi_ctlr *pspim, unsigned int len)
+static void sp7021_spi_host_rb(struct sp7021_spi_ctlr *pspim, unsigned int len)
{
int i;
@@ -166,7 +166,7 @@ static void sp7021_spi_master_rb(struct sp7021_spi_ctlr *pspim, unsigned int len
}
}
-static void sp7021_spi_master_wb(struct sp7021_spi_ctlr *pspim, unsigned int len)
+static void sp7021_spi_host_wb(struct sp7021_spi_ctlr *pspim, unsigned int len)
{
int i;
@@ -177,7 +177,7 @@ static void sp7021_spi_master_wb(struct sp7021_spi_ctlr *pspim, unsigned int len
}
}
-static irqreturn_t sp7021_spi_master_irq(int irq, void *dev)
+static irqreturn_t sp7021_spi_host_irq(int irq, void *dev)
{
struct sp7021_spi_ctlr *pspim = dev;
unsigned int tx_cnt, total_len;
@@ -206,9 +206,9 @@ static irqreturn_t sp7021_spi_master_irq(int irq, void *dev)
fd_status, rx_cnt, tx_cnt, tx_len);
if (rx_cnt > 0)
- sp7021_spi_master_rb(pspim, rx_cnt);
+ sp7021_spi_host_rb(pspim, rx_cnt);
if (tx_cnt > 0)
- sp7021_spi_master_wb(pspim, tx_cnt);
+ sp7021_spi_host_wb(pspim, tx_cnt);
fd_status = readl(pspim->m_base + SP7021_SPI_STATUS_REG);
tx_len = FIELD_GET(SP7021_TX_LEN_MASK, fd_status);
@@ -224,7 +224,7 @@ static irqreturn_t sp7021_spi_master_irq(int irq, void *dev)
rx_cnt = FIELD_GET(SP7021_RX_CNT_MASK, fd_status);
if (rx_cnt > 0)
- sp7021_spi_master_rb(pspim, rx_cnt);
+ sp7021_spi_host_rb(pspim, rx_cnt);
}
value = readl(pspim->m_base + SP7021_INT_BUSY_REG);
value |= SP7021_CLR_MASTER_INT;
@@ -240,7 +240,7 @@ static irqreturn_t sp7021_spi_master_irq(int irq, void *dev)
static void sp7021_prep_transfer(struct spi_controller *ctlr, struct spi_device *spi)
{
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
pspim->tx_cur_len = 0;
pspim->rx_cur_len = 0;
@@ -251,7 +251,7 @@ static void sp7021_prep_transfer(struct spi_controller *ctlr, struct spi_device
static int sp7021_spi_controller_prepare_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
struct spi_device *s = msg->spi;
u32 valus, rs = 0;
@@ -283,7 +283,7 @@ static int sp7021_spi_controller_prepare_message(struct spi_controller *ctlr,
static void sp7021_spi_setup_clk(struct spi_controller *ctlr, struct spi_transfer *xfer)
{
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
u32 clk_rate, clk_sel, div;
clk_rate = clk_get_rate(pspim->spi_clk);
@@ -295,10 +295,10 @@ static void sp7021_spi_setup_clk(struct spi_controller *ctlr, struct spi_transfe
writel(pspim->xfer_conf, pspim->m_base + SP7021_SPI_CONFIG_REG);
}
-static int sp7021_spi_master_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
- struct spi_transfer *xfer)
+static int sp7021_spi_host_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
unsigned long timeout = msecs_to_jiffies(1000);
unsigned int xfer_cnt, xfer_len, last_len;
unsigned int i, len_temp;
@@ -323,7 +323,7 @@ static int sp7021_spi_master_transfer_one(struct spi_controller *ctlr, struct sp
if (pspim->tx_cur_len < xfer_len) {
len_temp = min(pspim->data_unit, xfer_len);
- sp7021_spi_master_wb(pspim, len_temp);
+ sp7021_spi_host_wb(pspim, len_temp);
}
reg_temp = readl(pspim->m_base + SP7021_SPI_CONFIG_REG);
reg_temp &= ~SP7021_CLEAN_RW_BYTE;
@@ -359,10 +359,10 @@ static int sp7021_spi_master_transfer_one(struct spi_controller *ctlr, struct sp
return 0;
}
-static int sp7021_spi_slave_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
- struct spi_transfer *xfer)
+static int sp7021_spi_target_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
+ struct spi_transfer *xfer)
{
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
struct device *dev = pspim->dev;
int ret;
@@ -371,14 +371,14 @@ static int sp7021_spi_slave_transfer_one(struct spi_controller *ctlr, struct spi
xfer->len, DMA_TO_DEVICE);
if (dma_mapping_error(dev, xfer->tx_dma))
return -ENOMEM;
- ret = sp7021_spi_slave_tx(spi, xfer);
+ ret = sp7021_spi_target_tx(spi, xfer);
dma_unmap_single(dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE);
} else if (xfer->rx_buf && !xfer->tx_buf) {
xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, xfer->len,
DMA_FROM_DEVICE);
if (dma_mapping_error(dev, xfer->rx_dma))
return -ENOMEM;
- ret = sp7021_spi_slave_rx(spi, xfer);
+ ret = sp7021_spi_target_rx(spi, xfer);
dma_unmap_single(dev, xfer->rx_dma, xfer->len, DMA_FROM_DEVICE);
} else {
dev_dbg(&ctlr->dev, "%s() wrong command\n", __func__);
@@ -409,14 +409,14 @@ static int sp7021_spi_controller_probe(struct platform_device *pdev)
pdev->id = of_alias_get_id(pdev->dev.of_node, "sp_spi");
if (device_property_read_bool(dev, "spi-slave"))
- mode = SP7021_SLAVE_MODE;
+ mode = SP7021_TARGET_MODE;
else
- mode = SP7021_MASTER_MODE;
+ mode = SP7021_HOST_MODE;
- if (mode == SP7021_SLAVE_MODE)
- ctlr = devm_spi_alloc_slave(dev, sizeof(*pspim));
+ if (mode == SP7021_TARGET_MODE)
+ ctlr = devm_spi_alloc_target(dev, sizeof(*pspim));
else
- ctlr = devm_spi_alloc_master(dev, sizeof(*pspim));
+ ctlr = devm_spi_alloc_host(dev, sizeof(*pspim));
if (!ctlr)
return -ENOMEM;
device_set_node(&ctlr->dev, dev_fwnode(dev));
@@ -424,9 +424,9 @@ static int sp7021_spi_controller_probe(struct platform_device *pdev)
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
ctlr->auto_runtime_pm = true;
ctlr->prepare_message = sp7021_spi_controller_prepare_message;
- if (mode == SP7021_SLAVE_MODE) {
- ctlr->transfer_one = sp7021_spi_slave_transfer_one;
- ctlr->slave_abort = sp7021_spi_slave_abort;
+ if (mode == SP7021_TARGET_MODE) {
+ ctlr->transfer_one = sp7021_spi_target_transfer_one;
+ ctlr->target_abort = sp7021_spi_target_abort;
ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
} else {
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
@@ -434,7 +434,7 @@ static int sp7021_spi_controller_probe(struct platform_device *pdev)
ctlr->max_speed_hz = 25000000;
ctlr->use_gpio_descriptors = true;
ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
- ctlr->transfer_one = sp7021_spi_master_transfer_one;
+ ctlr->transfer_one = sp7021_spi_host_transfer_one;
}
platform_set_drvdata(pdev, ctlr);
pspim = spi_controller_get_devdata(ctlr);
@@ -443,7 +443,7 @@ static int sp7021_spi_controller_probe(struct platform_device *pdev)
pspim->dev = dev;
mutex_init(&pspim->buf_lock);
init_completion(&pspim->isr_done);
- init_completion(&pspim->slave_isr);
+ init_completion(&pspim->target_isr);
pspim->m_base = devm_platform_ioremap_resource_byname(pdev, "master");
if (IS_ERR(pspim->m_base))
@@ -485,12 +485,12 @@ static int sp7021_spi_controller_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = devm_request_irq(dev, pspim->m_irq, sp7021_spi_master_irq,
+ ret = devm_request_irq(dev, pspim->m_irq, sp7021_spi_host_irq,
IRQF_TRIGGER_RISING, pdev->name, pspim);
if (ret)
return ret;
- ret = devm_request_irq(dev, pspim->s_irq, sp7021_spi_slave_irq,
+ ret = devm_request_irq(dev, pspim->s_irq, sp7021_spi_target_irq,
IRQF_TRIGGER_RISING, pdev->name, pspim);
if (ret)
return ret;
@@ -499,7 +499,7 @@ static int sp7021_spi_controller_probe(struct platform_device *pdev)
ret = spi_register_controller(ctlr);
if (ret) {
pm_runtime_disable(dev);
- return dev_err_probe(dev, ret, "spi_register_master fail\n");
+ return dev_err_probe(dev, ret, "spi_register_controller fail\n");
}
return 0;
}
@@ -516,7 +516,7 @@ static void sp7021_spi_controller_remove(struct platform_device *pdev)
static int __maybe_unused sp7021_spi_controller_suspend(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
return reset_control_assert(pspim->rstc);
}
@@ -524,7 +524,7 @@ static int __maybe_unused sp7021_spi_controller_suspend(struct device *dev)
static int __maybe_unused sp7021_spi_controller_resume(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
reset_control_deassert(pspim->rstc);
return clk_prepare_enable(pspim->spi_clk);
@@ -534,7 +534,7 @@ static int __maybe_unused sp7021_spi_controller_resume(struct device *dev)
static int sp7021_spi_runtime_suspend(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
return reset_control_assert(pspim->rstc);
}
@@ -542,7 +542,7 @@ static int sp7021_spi_runtime_suspend(struct device *dev)
static int sp7021_spi_runtime_resume(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
- struct sp7021_spi_ctlr *pspim = spi_master_get_devdata(ctlr);
+ struct sp7021_spi_ctlr *pspim = spi_controller_get_devdata(ctlr);
return reset_control_deassert(pspim->rstc);
}
@@ -563,7 +563,7 @@ MODULE_DEVICE_TABLE(of, sp7021_spi_controller_ids);
static struct platform_driver sp7021_spi_controller_driver = {
.probe = sp7021_spi_controller_probe,
- .remove_new = sp7021_spi_controller_remove,
+ .remove = sp7021_spi_controller_remove,
.driver = {
.name = "sunplus,sp7021-spi-controller",
.of_match_table = sp7021_spi_controller_ids,
diff --git a/drivers/spi/spi-synquacer.c b/drivers/spi/spi-synquacer.c
index aeaf7db022f0..eaf560487591 100644
--- a/drivers/spi/spi-synquacer.c
+++ b/drivers/spi/spi-synquacer.c
@@ -225,11 +225,11 @@ static int write_fifo(struct synquacer_spi *sspi)
return 0;
}
-static int synquacer_spi_config(struct spi_master *master,
+static int synquacer_spi_config(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
unsigned int speed, mode, bpw, cs, bus_width, transfer_mode;
u32 rate, val, div;
@@ -263,7 +263,7 @@ static int synquacer_spi_config(struct spi_master *master,
}
sspi->transfer_mode = transfer_mode;
- rate = master->max_speed_hz;
+ rate = host->max_speed_hz;
div = DIV_ROUND_UP(rate, speed);
if (div > 254) {
@@ -350,11 +350,11 @@ static int synquacer_spi_config(struct spi_master *master,
return 0;
}
-static int synquacer_spi_transfer_one(struct spi_master *master,
+static int synquacer_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
int ret;
int status = 0;
u32 words;
@@ -378,7 +378,7 @@ static int synquacer_spi_transfer_one(struct spi_master *master,
if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST))
xfer->bits_per_word = 32;
- ret = synquacer_spi_config(master, spi, xfer);
+ ret = synquacer_spi_config(host, spi, xfer);
/* restore */
xfer->bits_per_word = bpw;
@@ -482,7 +482,7 @@ static int synquacer_spi_transfer_one(struct spi_master *master,
static void synquacer_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct synquacer_spi *sspi = spi_master_get_devdata(spi->master);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(spi->controller);
u32 val;
val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
@@ -517,11 +517,11 @@ static int synquacer_spi_wait_status_update(struct synquacer_spi *sspi,
return -EBUSY;
}
-static int synquacer_spi_enable(struct spi_master *master)
+static int synquacer_spi_enable(struct spi_controller *host)
{
u32 val;
int status;
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
/* Disable module */
writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
@@ -601,18 +601,18 @@ static irqreturn_t sq_spi_tx_handler(int irq, void *priv)
static int synquacer_spi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct spi_master *master;
+ struct spi_controller *host;
struct synquacer_spi *sspi;
int ret;
int rx_irq, tx_irq;
- master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*sspi));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- sspi = spi_master_get_devdata(master);
+ sspi = spi_controller_get_devdata(host);
sspi->dev = &pdev->dev;
init_completion(&sspi->transfer_done);
@@ -625,7 +625,7 @@ static int synquacer_spi_probe(struct platform_device *pdev)
sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */
device_property_read_u32(&pdev->dev, "socionext,ihclk-rate",
- &master->max_speed_hz); /* for ACPI */
+ &host->max_speed_hz); /* for ACPI */
if (dev_of_node(&pdev->dev)) {
if (device_property_match_string(&pdev->dev,
@@ -655,21 +655,21 @@ static int synquacer_spi_probe(struct platform_device *pdev)
goto put_spi;
}
- master->max_speed_hz = clk_get_rate(sspi->clk);
+ host->max_speed_hz = clk_get_rate(sspi->clk);
}
- if (!master->max_speed_hz) {
+ if (!host->max_speed_hz) {
dev_err(&pdev->dev, "missing clock source\n");
ret = -EINVAL;
goto disable_clk;
}
- master->min_speed_hz = master->max_speed_hz / 254;
+ host->min_speed_hz = host->max_speed_hz / 254;
sspi->aces = device_property_read_bool(&pdev->dev,
"socionext,set-aces");
sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm");
- master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
+ host->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
rx_irq = platform_get_irq(pdev, 0);
if (rx_irq <= 0) {
@@ -699,27 +699,27 @@ static int synquacer_spi_probe(struct platform_device *pdev)
goto disable_clk;
}
- master->dev.of_node = np;
- master->dev.fwnode = pdev->dev.fwnode;
- master->auto_runtime_pm = true;
- master->bus_num = pdev->id;
+ host->dev.of_node = np;
+ host->dev.fwnode = pdev->dev.fwnode;
+ host->auto_runtime_pm = true;
+ host->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
- SPI_TX_QUAD | SPI_RX_QUAD;
- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
- SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
+ SPI_TX_QUAD | SPI_RX_QUAD;
+ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
+ SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
- master->set_cs = synquacer_spi_set_cs;
- master->transfer_one = synquacer_spi_transfer_one;
+ host->set_cs = synquacer_spi_set_cs;
+ host->transfer_one = synquacer_spi_transfer_one;
- ret = synquacer_spi_enable(master);
+ ret = synquacer_spi_enable(host);
if (ret)
goto disable_clk;
pm_runtime_set_active(sspi->dev);
pm_runtime_enable(sspi->dev);
- ret = devm_spi_register_master(sspi->dev, master);
+ ret = devm_spi_register_controller(sspi->dev, host);
if (ret)
goto disable_pm;
@@ -730,15 +730,15 @@ disable_pm:
disable_clk:
clk_disable_unprepare(sspi->clk);
put_spi:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
static void synquacer_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
pm_runtime_disable(sspi->dev);
@@ -747,11 +747,11 @@ static void synquacer_spi_remove(struct platform_device *pdev)
static int __maybe_unused synquacer_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
int ret;
- ret = spi_master_suspend(master);
+ ret = spi_controller_suspend(host);
if (ret)
return ret;
@@ -763,8 +763,8 @@ static int __maybe_unused synquacer_spi_suspend(struct device *dev)
static int __maybe_unused synquacer_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct synquacer_spi *sspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct synquacer_spi *sspi = spi_controller_get_devdata(host);
int ret;
if (!pm_runtime_suspended(dev)) {
@@ -778,7 +778,7 @@ static int __maybe_unused synquacer_spi_resume(struct device *dev)
return ret;
}
- ret = synquacer_spi_enable(master);
+ ret = synquacer_spi_enable(host);
if (ret) {
clk_disable_unprepare(sspi->clk);
dev_err(dev, "failed to enable spi (%d)\n", ret);
@@ -786,7 +786,7 @@ static int __maybe_unused synquacer_spi_resume(struct device *dev)
}
}
- ret = spi_master_resume(master);
+ ret = spi_controller_resume(host);
if (ret < 0)
clk_disable_unprepare(sspi->clk);
@@ -818,7 +818,7 @@ static struct platform_driver synquacer_spi_driver = {
.acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids),
},
.probe = synquacer_spi_probe,
- .remove_new = synquacer_spi_remove,
+ .remove = synquacer_spi_remove,
};
module_platform_driver(synquacer_spi_driver);
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 488df681eaef..795a8482c2c7 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -20,7 +20,6 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
@@ -165,7 +164,7 @@ struct tegra_spi_client_data {
struct tegra_spi_data {
struct device *dev;
- struct spi_master *master;
+ struct spi_controller *host;
spinlock_t lock;
struct clk *clk;
@@ -719,31 +718,27 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
static int tegra_spi_set_hw_cs_timing(struct spi_device *spi)
{
- struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(spi->controller);
struct spi_delay *setup = &spi->cs_setup;
struct spi_delay *hold = &spi->cs_hold;
struct spi_delay *inactive = &spi->cs_inactive;
- u8 setup_dly, hold_dly, inactive_dly;
+ u8 setup_dly, hold_dly;
u32 setup_hold;
u32 spi_cs_timing;
u32 inactive_cycles;
u8 cs_state;
- if ((setup && setup->unit != SPI_DELAY_UNIT_SCK) ||
- (hold && hold->unit != SPI_DELAY_UNIT_SCK) ||
- (inactive && inactive->unit != SPI_DELAY_UNIT_SCK)) {
+ if ((setup->value && setup->unit != SPI_DELAY_UNIT_SCK) ||
+ (hold->value && hold->unit != SPI_DELAY_UNIT_SCK) ||
+ (inactive->value && inactive->unit != SPI_DELAY_UNIT_SCK)) {
dev_err(&spi->dev,
"Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n",
SPI_DELAY_UNIT_SCK);
return -EINVAL;
}
- setup_dly = setup ? setup->value : 0;
- hold_dly = hold ? hold->value : 0;
- inactive_dly = inactive ? inactive->value : 0;
-
- setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
- hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
+ setup_dly = min_t(u8, setup->value, MAX_SETUP_HOLD_CYCLES);
+ hold_dly = min_t(u8, hold->value, MAX_SETUP_HOLD_CYCLES);
if (setup_dly && hold_dly) {
setup_hold = SPI_SETUP_HOLD(setup_dly - 1, hold_dly - 1);
spi_cs_timing = SPI_CS_SETUP_HOLD(tspi->spi_cs_timing1,
@@ -755,7 +750,7 @@ static int tegra_spi_set_hw_cs_timing(struct spi_device *spi)
}
}
- inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES);
+ inactive_cycles = min_t(u8, inactive->value, MAX_INACTIVE_CYCLES);
if (inactive_cycles)
inactive_cycles--;
cs_state = inactive_cycles ? 0 : 1;
@@ -777,7 +772,7 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
bool is_first_of_msg,
bool is_single_xfer)
{
- struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(spi->controller);
struct tegra_spi_client_data *cdata = spi->controller_data;
u32 speed = t->speed_hz;
u8 bits_per_word = t->bits_per_word;
@@ -870,7 +865,7 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
static int tegra_spi_start_transfer_one(struct spi_device *spi,
struct spi_transfer *t, u32 command1)
{
- struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(spi->controller);
unsigned total_fifo_words;
int ret;
@@ -917,10 +912,10 @@ static struct tegra_spi_client_data
*tegra_spi_parse_cdata_dt(struct spi_device *spi)
{
struct tegra_spi_client_data *cdata;
- struct device_node *slave_np;
+ struct device_node *target_np;
- slave_np = spi->dev.of_node;
- if (!slave_np) {
+ target_np = spi->dev.of_node;
+ if (!target_np) {
dev_dbg(&spi->dev, "device node not found\n");
return NULL;
}
@@ -929,9 +924,9 @@ static struct tegra_spi_client_data
if (!cdata)
return NULL;
- of_property_read_u32(slave_np, "nvidia,tx-clk-tap-delay",
+ of_property_read_u32(target_np, "nvidia,tx-clk-tap-delay",
&cdata->tx_clk_tap_delay);
- of_property_read_u32(slave_np, "nvidia,rx-clk-tap-delay",
+ of_property_read_u32(target_np, "nvidia,rx-clk-tap-delay",
&cdata->rx_clk_tap_delay);
return cdata;
}
@@ -947,7 +942,7 @@ static void tegra_spi_cleanup(struct spi_device *spi)
static int tegra_spi_setup(struct spi_device *spi)
{
- struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(spi->controller);
struct tegra_spi_client_data *cdata = spi->controller_data;
u32 val;
unsigned long flags;
@@ -998,7 +993,7 @@ static int tegra_spi_setup(struct spi_device *spi)
static void tegra_spi_transfer_end(struct spi_device *spi)
{
- struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(spi->controller);
int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
/* GPIO based chip select control */
@@ -1030,11 +1025,11 @@ static void tegra_spi_dump_regs(struct tegra_spi_data *tspi)
tegra_spi_readl(tspi, SPI_FIFO_STATUS));
}
-static int tegra_spi_transfer_one_message(struct spi_master *master,
+static int tegra_spi_transfer_one_message(struct spi_controller *host,
struct spi_message *msg)
{
bool is_first_msg = true;
- struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(host);
struct spi_transfer *xfer;
struct spi_device *spi = msg->spi;
int ret;
@@ -1083,7 +1078,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
reset_control_assert(tspi->rst);
udelay(2);
reset_control_deassert(tspi->rst);
- tspi->last_used_cs = master->num_chipselect + 1;
+ tspi->last_used_cs = host->num_chipselect + 1;
goto complete_xfer;
}
@@ -1117,7 +1112,7 @@ complete_xfer:
ret = 0;
exit:
msg->status = ret;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return ret;
}
@@ -1298,40 +1293,40 @@ MODULE_DEVICE_TABLE(of, tegra_spi_of_match);
static int tegra_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct tegra_spi_data *tspi;
struct resource *r;
int ret, spi_irq;
int bus_num;
- master = spi_alloc_master(&pdev->dev, sizeof(*tspi));
- if (!master) {
- dev_err(&pdev->dev, "master allocation failed\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(*tspi));
+ if (!host) {
+ dev_err(&pdev->dev, "host allocation failed\n");
return -ENOMEM;
}
- platform_set_drvdata(pdev, master);
- tspi = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, host);
+ tspi = spi_controller_get_devdata(host);
if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency",
- &master->max_speed_hz))
- master->max_speed_hz = 25000000; /* 25MHz */
+ &host->max_speed_hz))
+ host->max_speed_hz = 25000000; /* 25MHz */
/* the spi->mode bits understood by this driver: */
- master->use_gpio_descriptors = true;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
- SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
- master->setup = tegra_spi_setup;
- master->cleanup = tegra_spi_cleanup;
- master->transfer_one_message = tegra_spi_transfer_one_message;
- master->set_cs_timing = tegra_spi_set_hw_cs_timing;
- master->num_chipselect = MAX_CHIP_SELECT;
- master->auto_runtime_pm = true;
+ host->use_gpio_descriptors = true;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
+ SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ host->setup = tegra_spi_setup;
+ host->cleanup = tegra_spi_cleanup;
+ host->transfer_one_message = tegra_spi_transfer_one_message;
+ host->set_cs_timing = tegra_spi_set_hw_cs_timing;
+ host->num_chipselect = MAX_CHIP_SELECT;
+ host->auto_runtime_pm = true;
bus_num = of_alias_get_id(pdev->dev.of_node, "spi");
if (bus_num >= 0)
- master->bus_num = bus_num;
+ host->bus_num = bus_num;
- tspi->master = master;
+ tspi->host = host;
tspi->dev = &pdev->dev;
spin_lock_init(&tspi->lock);
@@ -1339,20 +1334,20 @@ static int tegra_spi_probe(struct platform_device *pdev)
if (!tspi->soc_data) {
dev_err(&pdev->dev, "unsupported tegra\n");
ret = -ENODEV;
- goto exit_free_master;
+ goto exit_free_host;
}
tspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(tspi->base)) {
ret = PTR_ERR(tspi->base);
- goto exit_free_master;
+ goto exit_free_host;
}
tspi->phys = r->start;
spi_irq = platform_get_irq(pdev, 0);
if (spi_irq < 0) {
ret = spi_irq;
- goto exit_free_master;
+ goto exit_free_host;
}
tspi->irq = spi_irq;
@@ -1360,14 +1355,14 @@ static int tegra_spi_probe(struct platform_device *pdev)
if (IS_ERR(tspi->clk)) {
dev_err(&pdev->dev, "can not get clock\n");
ret = PTR_ERR(tspi->clk);
- goto exit_free_master;
+ goto exit_free_host;
}
tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi");
if (IS_ERR(tspi->rst)) {
dev_err(&pdev->dev, "can not get reset\n");
ret = PTR_ERR(tspi->rst);
- goto exit_free_master;
+ goto exit_free_host;
}
tspi->max_buf_size = SPI_FIFO_DEPTH << 2;
@@ -1375,7 +1370,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
ret = tegra_spi_init_dma_param(tspi, true);
if (ret < 0)
- goto exit_free_master;
+ goto exit_free_host;
ret = tegra_spi_init_dma_param(tspi, false);
if (ret < 0)
goto exit_rx_dma_free;
@@ -1406,7 +1401,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1);
tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2);
tspi->def_command2_reg = tegra_spi_readl(tspi, SPI_COMMAND2);
- tspi->last_used_cs = master->num_chipselect + 1;
+ tspi->last_used_cs = host->num_chipselect + 1;
pm_runtime_put(&pdev->dev);
ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
tegra_spi_isr_thread, IRQF_ONESHOT,
@@ -1417,10 +1412,10 @@ static int tegra_spi_probe(struct platform_device *pdev)
goto exit_pm_disable;
}
- master->dev.of_node = pdev->dev.of_node;
- ret = devm_spi_register_master(&pdev->dev, master);
+ host->dev.of_node = pdev->dev.of_node;
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret < 0) {
- dev_err(&pdev->dev, "can not register to master err %d\n", ret);
+ dev_err(&pdev->dev, "can not register to host err %d\n", ret);
goto exit_free_irq;
}
return ret;
@@ -1434,15 +1429,15 @@ exit_pm_disable:
tegra_spi_deinit_dma_param(tspi, false);
exit_rx_dma_free:
tegra_spi_deinit_dma_param(tspi, true);
-exit_free_master:
- spi_master_put(master);
+exit_free_host:
+ spi_controller_put(host);
return ret;
}
static void tegra_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(host);
free_irq(tspi->irq, tspi);
@@ -1460,15 +1455,15 @@ static void tegra_spi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int tegra_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
- return spi_master_suspend(master);
+ return spi_controller_suspend(host);
}
static int tegra_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(host);
int ret;
ret = pm_runtime_resume_and_get(dev);
@@ -1478,17 +1473,17 @@ static int tegra_spi_resume(struct device *dev)
}
tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
tegra_spi_writel(tspi, tspi->def_command2_reg, SPI_COMMAND2);
- tspi->last_used_cs = master->num_chipselect + 1;
+ tspi->last_used_cs = host->num_chipselect + 1;
pm_runtime_put(dev);
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif
static int tegra_spi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(host);
/* Flush all write which are in PPSB queue by reading back */
tegra_spi_readl(tspi, SPI_COMMAND1);
@@ -1499,8 +1494,8 @@ static int tegra_spi_runtime_suspend(struct device *dev)
static int tegra_spi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_spi_data *tspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_spi_data *tspi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(tspi->clk);
@@ -1523,7 +1518,7 @@ static struct platform_driver tegra_spi_driver = {
.of_match_table = tegra_spi_of_match,
},
.probe = tegra_spi_probe,
- .remove_new = tegra_spi_remove,
+ .remove = tegra_spi_remove,
};
module_platform_driver(tegra_spi_driver);
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index 4286310628a2..d5c8ee20b8e5 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -102,7 +102,7 @@
struct tegra_sflash_data {
struct device *dev;
- struct spi_master *master;
+ struct spi_controller *host;
spinlock_t lock;
struct clk *clk;
@@ -251,7 +251,7 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi,
struct spi_transfer *t, bool is_first_of_msg,
bool is_single_xfer)
{
- struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
+ struct tegra_sflash_data *tsd = spi_controller_get_devdata(spi->controller);
u32 speed;
u32 command;
@@ -303,12 +303,12 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi,
return tegra_sflash_start_cpu_based_transfer(tsd, t);
}
-static int tegra_sflash_transfer_one_message(struct spi_master *master,
+static int tegra_sflash_transfer_one_message(struct spi_controller *host,
struct spi_message *msg)
{
bool is_first_msg = true;
int single_xfer;
- struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+ struct tegra_sflash_data *tsd = spi_controller_get_devdata(host);
struct spi_transfer *xfer;
struct spi_device *spi = msg->spi;
int ret;
@@ -351,7 +351,7 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master,
exit:
tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND);
msg->status = ret;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return ret;
}
@@ -416,7 +416,7 @@ MODULE_DEVICE_TABLE(of, tegra_sflash_of_match);
static int tegra_sflash_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct tegra_sflash_data *tsd;
int ret;
const struct of_device_id *match;
@@ -427,41 +427,45 @@ static int tegra_sflash_probe(struct platform_device *pdev)
return -ENODEV;
}
- master = spi_alloc_master(&pdev->dev, sizeof(*tsd));
- if (!master) {
- dev_err(&pdev->dev, "master allocation failed\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(*tsd));
+ if (!host) {
+ dev_err(&pdev->dev, "host allocation failed\n");
return -ENOMEM;
}
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA;
- master->transfer_one_message = tegra_sflash_transfer_one_message;
- master->auto_runtime_pm = true;
- master->num_chipselect = MAX_CHIP_SELECT;
-
- platform_set_drvdata(pdev, master);
- tsd = spi_master_get_devdata(master);
- tsd->master = master;
+ host->mode_bits = SPI_CPOL | SPI_CPHA;
+ host->transfer_one_message = tegra_sflash_transfer_one_message;
+ host->auto_runtime_pm = true;
+ host->num_chipselect = MAX_CHIP_SELECT;
+
+ platform_set_drvdata(pdev, host);
+ tsd = spi_controller_get_devdata(host);
+ tsd->host = host;
tsd->dev = &pdev->dev;
spin_lock_init(&tsd->lock);
if (of_property_read_u32(tsd->dev->of_node, "spi-max-frequency",
- &master->max_speed_hz))
- master->max_speed_hz = 25000000; /* 25MHz */
+ &host->max_speed_hz))
+ host->max_speed_hz = 25000000; /* 25MHz */
tsd->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(tsd->base)) {
ret = PTR_ERR(tsd->base);
- goto exit_free_master;
+ goto exit_free_host;
}
- tsd->irq = platform_get_irq(pdev, 0);
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ goto exit_free_host;
+ tsd->irq = ret;
+
ret = request_irq(tsd->irq, tegra_sflash_isr, 0,
dev_name(&pdev->dev), tsd);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n",
tsd->irq);
- goto exit_free_master;
+ goto exit_free_host;
}
tsd->clk = devm_clk_get(&pdev->dev, NULL);
@@ -501,10 +505,10 @@ static int tegra_sflash_probe(struct platform_device *pdev)
tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND);
pm_runtime_put(&pdev->dev);
- master->dev.of_node = pdev->dev.of_node;
- ret = devm_spi_register_master(&pdev->dev, master);
+ host->dev.of_node = pdev->dev.of_node;
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret < 0) {
- dev_err(&pdev->dev, "can not register to master err %d\n", ret);
+ dev_err(&pdev->dev, "can not register to host err %d\n", ret);
goto exit_pm_disable;
}
return ret;
@@ -515,15 +519,15 @@ exit_pm_disable:
tegra_sflash_runtime_suspend(&pdev->dev);
exit_free_irq:
free_irq(tsd->irq, tsd);
-exit_free_master:
- spi_master_put(master);
+exit_free_host:
+ spi_controller_put(host);
return ret;
}
static void tegra_sflash_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct tegra_sflash_data *tsd = spi_controller_get_devdata(host);
free_irq(tsd->irq, tsd);
@@ -535,15 +539,15 @@ static void tegra_sflash_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int tegra_sflash_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
- return spi_master_suspend(master);
+ return spi_controller_suspend(host);
}
static int tegra_sflash_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_sflash_data *tsd = spi_controller_get_devdata(host);
int ret;
ret = pm_runtime_resume_and_get(dev);
@@ -554,14 +558,14 @@ static int tegra_sflash_resume(struct device *dev)
tegra_sflash_writel(tsd, tsd->command_reg, SPI_COMMAND);
pm_runtime_put(dev);
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif
static int tegra_sflash_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_sflash_data *tsd = spi_controller_get_devdata(host);
/* Flush all write which are in PPSB queue by reading back */
tegra_sflash_readl(tsd, SPI_COMMAND);
@@ -572,8 +576,8 @@ static int tegra_sflash_runtime_suspend(struct device *dev)
static int tegra_sflash_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_sflash_data *tsd = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(tsd->clk);
@@ -596,7 +600,7 @@ static struct platform_driver tegra_sflash_driver = {
.of_match_table = tegra_sflash_of_match,
},
.probe = tegra_sflash_probe,
- .remove_new = tegra_sflash_remove,
+ .remove = tegra_sflash_remove,
};
module_platform_driver(tegra_sflash_driver);
diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c
index c2915f7672cc..fe452d03c1ee 100644
--- a/drivers/spi/spi-tegra20-slink.c
+++ b/drivers/spi/spi-tegra20-slink.c
@@ -21,7 +21,6 @@
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
@@ -153,7 +152,7 @@ struct tegra_slink_chip_data {
struct tegra_slink_data {
struct device *dev;
- struct spi_master *master;
+ struct spi_controller *host;
const struct tegra_slink_chip_data *chip_data;
spinlock_t lock;
@@ -543,7 +542,7 @@ static int tegra_slink_start_dma_based_transfer(
if (tspi->is_packed) {
val |= SLINK_PACKED;
tegra_slink_writel(tspi, val, SLINK_DMA_CTL);
- /* HW need small delay after settign Packed mode */
+ /* HW need small delay after setting Packed mode */
udelay(1);
}
tspi->dma_control_reg = val;
@@ -672,7 +671,7 @@ static void tegra_slink_deinit_dma_param(struct tegra_slink_data *tspi,
static int tegra_slink_start_transfer_one(struct spi_device *spi,
struct spi_transfer *t)
{
- struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_slink_data *tspi = spi_controller_get_devdata(spi->controller);
u32 speed;
u8 bits_per_word;
unsigned total_fifo_words;
@@ -738,7 +737,7 @@ static int tegra_slink_setup(struct spi_device *spi)
SLINK_CS_POLARITY3,
};
- struct tegra_slink_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_slink_data *tspi = spi_controller_get_devdata(spi->controller);
u32 val;
unsigned long flags;
int ret;
@@ -769,10 +768,10 @@ static int tegra_slink_setup(struct spi_device *spi)
return 0;
}
-static int tegra_slink_prepare_message(struct spi_master *master,
+static int tegra_slink_prepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ struct tegra_slink_data *tspi = spi_controller_get_devdata(host);
struct spi_device *spi = msg->spi;
tegra_slink_clear_status(tspi);
@@ -795,11 +794,11 @@ static int tegra_slink_prepare_message(struct spi_master *master,
return 0;
}
-static int tegra_slink_transfer_one(struct spi_master *master,
+static int tegra_slink_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *xfer)
{
- struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ struct tegra_slink_data *tspi = spi_controller_get_devdata(host);
int ret;
reinit_completion(&tspi->xfer_completion);
@@ -826,10 +825,10 @@ static int tegra_slink_transfer_one(struct spi_master *master,
return 0;
}
-static int tegra_slink_unprepare_message(struct spi_master *master,
+static int tegra_slink_unprepare_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ struct tegra_slink_data *tspi = spi_controller_get_devdata(host);
tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
@@ -1000,7 +999,7 @@ MODULE_DEVICE_TABLE(of, tegra_slink_of_match);
static int tegra_slink_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct tegra_slink_data *tspi;
struct resource *r;
int ret, spi_irq;
@@ -1008,70 +1007,64 @@ static int tegra_slink_probe(struct platform_device *pdev)
cdata = of_device_get_match_data(&pdev->dev);
- master = spi_alloc_master(&pdev->dev, sizeof(*tspi));
- if (!master) {
- dev_err(&pdev->dev, "master allocation failed\n");
+ host = spi_alloc_host(&pdev->dev, sizeof(*tspi));
+ if (!host) {
+ dev_err(&pdev->dev, "host allocation failed\n");
return -ENOMEM;
}
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->setup = tegra_slink_setup;
- master->prepare_message = tegra_slink_prepare_message;
- master->transfer_one = tegra_slink_transfer_one;
- master->unprepare_message = tegra_slink_unprepare_message;
- master->auto_runtime_pm = true;
- master->num_chipselect = MAX_CHIP_SELECT;
-
- platform_set_drvdata(pdev, master);
- tspi = spi_master_get_devdata(master);
- tspi->master = master;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->setup = tegra_slink_setup;
+ host->prepare_message = tegra_slink_prepare_message;
+ host->transfer_one = tegra_slink_transfer_one;
+ host->unprepare_message = tegra_slink_unprepare_message;
+ host->auto_runtime_pm = true;
+ host->num_chipselect = MAX_CHIP_SELECT;
+
+ platform_set_drvdata(pdev, host);
+ tspi = spi_controller_get_devdata(host);
+ tspi->host = host;
tspi->dev = &pdev->dev;
tspi->chip_data = cdata;
spin_lock_init(&tspi->lock);
if (of_property_read_u32(tspi->dev->of_node, "spi-max-frequency",
- &master->max_speed_hz))
- master->max_speed_hz = 25000000; /* 25MHz */
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "No IO memory resource\n");
- ret = -ENODEV;
- goto exit_free_master;
- }
- tspi->phys = r->start;
- tspi->base = devm_ioremap_resource(&pdev->dev, r);
+ &host->max_speed_hz))
+ host->max_speed_hz = 25000000; /* 25MHz */
+
+ tspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(tspi->base)) {
ret = PTR_ERR(tspi->base);
- goto exit_free_master;
+ goto exit_free_host;
}
+ tspi->phys = r->start;
/* disabled clock may cause interrupt storm upon request */
tspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(tspi->clk)) {
ret = PTR_ERR(tspi->clk);
dev_err(&pdev->dev, "Can not get clock %d\n", ret);
- goto exit_free_master;
+ goto exit_free_host;
}
tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi");
if (IS_ERR(tspi->rst)) {
dev_err(&pdev->dev, "can not get reset\n");
ret = PTR_ERR(tspi->rst);
- goto exit_free_master;
+ goto exit_free_host;
}
ret = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (ret)
- goto exit_free_master;
+ goto exit_free_host;
tspi->max_buf_size = SLINK_FIFO_DEPTH << 2;
tspi->dma_buf_size = DEFAULT_SPI_DMA_BUF_LEN;
ret = tegra_slink_init_dma_param(tspi, true);
if (ret < 0)
- goto exit_free_master;
+ goto exit_free_host;
ret = tegra_slink_init_dma_param(tspi, false);
if (ret < 0)
goto exit_rx_dma_free;
@@ -1093,6 +1086,8 @@ static int tegra_slink_probe(struct platform_device *pdev)
reset_control_deassert(tspi->rst);
spi_irq = platform_get_irq(pdev, 0);
+ if (spi_irq < 0)
+ return spi_irq;
tspi->irq = spi_irq;
ret = request_threaded_irq(tspi->irq, tegra_slink_isr,
tegra_slink_isr_thread, IRQF_ONESHOT,
@@ -1108,10 +1103,10 @@ static int tegra_slink_probe(struct platform_device *pdev)
tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
- master->dev.of_node = pdev->dev.of_node;
- ret = spi_register_master(master);
+ host->dev.of_node = pdev->dev.of_node;
+ ret = spi_register_controller(host);
if (ret < 0) {
- dev_err(&pdev->dev, "can not register to master err %d\n", ret);
+ dev_err(&pdev->dev, "can not register to host err %d\n", ret);
goto exit_free_irq;
}
@@ -1129,17 +1124,17 @@ exit_pm_disable:
tegra_slink_deinit_dma_param(tspi, false);
exit_rx_dma_free:
tegra_slink_deinit_dma_param(tspi, true);
-exit_free_master:
- spi_master_put(master);
+exit_free_host:
+ spi_controller_put(host);
return ret;
}
static void tegra_slink_remove(struct platform_device *pdev)
{
- struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
- struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ struct spi_controller *host = spi_controller_get(platform_get_drvdata(pdev));
+ struct tegra_slink_data *tspi = spi_controller_get_devdata(host);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
free_irq(tspi->irq, tspi);
@@ -1151,21 +1146,21 @@ static void tegra_slink_remove(struct platform_device *pdev)
if (tspi->rx_dma_chan)
tegra_slink_deinit_dma_param(tspi, true);
- spi_master_put(master);
+ spi_controller_put(host);
}
#ifdef CONFIG_PM_SLEEP
static int tegra_slink_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
- return spi_master_suspend(master);
+ return spi_controller_suspend(host);
}
static int tegra_slink_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_slink_data *tspi = spi_controller_get_devdata(host);
int ret;
ret = pm_runtime_resume_and_get(dev);
@@ -1177,14 +1172,14 @@ static int tegra_slink_resume(struct device *dev)
tegra_slink_writel(tspi, tspi->command2_reg, SLINK_COMMAND2);
pm_runtime_put(dev);
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
#endif
static int __maybe_unused tegra_slink_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_slink_data *tspi = spi_controller_get_devdata(host);
/* Flush all write which are in PPSB queue by reading back */
tegra_slink_readl(tspi, SLINK_MAS_DATA);
@@ -1195,8 +1190,8 @@ static int __maybe_unused tegra_slink_runtime_suspend(struct device *dev)
static int __maybe_unused tegra_slink_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_slink_data *tspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_slink_data *tspi = spi_controller_get_devdata(host);
int ret;
ret = clk_prepare_enable(tspi->clk);
@@ -1219,7 +1214,7 @@ static struct platform_driver tegra_slink_driver = {
.of_match_table = tegra_slink_of_match,
},
.probe = tegra_slink_probe,
- .remove_new = tegra_slink_remove,
+ .remove = tegra_slink_remove,
};
module_platform_driver(tegra_slink_driver);
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index fbd14dd7be44..cdc3cb7c01f9 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -18,11 +18,11 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
#include <linux/acpi.h>
#include <linux/property.h>
+#include <linux/sizes.h>
#define QSPI_COMMAND1 0x000
#define QSPI_BIT_LENGTH(x) (((x) & 0x1f) << 0)
@@ -111,6 +111,9 @@
#define QSPI_DMA_BLK 0x024
#define QSPI_DMA_BLK_SET(x) (((x) & 0xffff) << 0)
+#define QSPI_DMA_MEM_ADDRESS 0x028
+#define QSPI_DMA_HI_ADDRESS 0x02c
+
#define QSPI_TX_FIFO 0x108
#define QSPI_RX_FIFO 0x188
@@ -135,7 +138,7 @@
#define QSPI_COMMAND_VALUE_SET(X) (((x) & 0xFF) << 0)
#define QSPI_CMB_SEQ_CMD_CFG 0x1a0
-#define QSPI_COMMAND_X1_X2_X4(x) (((x) & 0x3) << 13)
+#define QSPI_COMMAND_X1_X2_X4(x) ((((x) >> 1) & 0x3) << 13)
#define QSPI_COMMAND_X1_X2_X4_MASK (0x03 << 13)
#define QSPI_COMMAND_SDR_DDR BIT(12)
#define QSPI_COMMAND_SIZE_SET(x) (((x) & 0xFF) << 0)
@@ -148,7 +151,7 @@
#define QSPI_ADDRESS_VALUE_SET(X) (((x) & 0xFFFF) << 0)
#define QSPI_CMB_SEQ_ADDR_CFG 0x1ac
-#define QSPI_ADDRESS_X1_X2_X4(x) (((x) & 0x3) << 13)
+#define QSPI_ADDRESS_X1_X2_X4(x) ((((x) >> 1) & 0x3) << 13)
#define QSPI_ADDRESS_X1_X2_X4_MASK (0x03 << 13)
#define QSPI_ADDRESS_SDR_DDR BIT(12)
#define QSPI_ADDRESS_SIZE_SET(x) (((x) & 0xFF) << 0)
@@ -157,15 +160,19 @@
#define DATA_DIR_RX BIT(1)
#define QSPI_DMA_TIMEOUT (msecs_to_jiffies(1000))
-#define DEFAULT_QSPI_DMA_BUF_LEN (64 * 1024)
-#define CMD_TRANSFER 0
-#define ADDR_TRANSFER 1
-#define DATA_TRANSFER 2
+#define DEFAULT_QSPI_DMA_BUF_LEN SZ_64K
+
+enum tegra_qspi_transfer_type {
+ CMD_TRANSFER = 0,
+ ADDR_TRANSFER = 1,
+ DUMMY_TRANSFER = 2,
+ DATA_TRANSFER = 3
+};
struct tegra_qspi_soc_data {
- bool has_dma;
bool cmb_xfer_capable;
bool supports_tpm;
+ bool has_ext_dma;
unsigned int cs_count;
};
@@ -176,7 +183,7 @@ struct tegra_qspi_client_data {
struct tegra_qspi {
struct device *dev;
- struct spi_master *master;
+ struct spi_controller *host;
/* lock to protect data accessed by irq */
spinlock_t lock;
@@ -342,7 +349,7 @@ tegra_qspi_fill_tx_fifo_from_client_txbuf(struct tegra_qspi *tqspi, struct spi_t
for (count = 0; count < max_n_32bit; count++) {
u32 x = 0;
- for (i = 0; len && (i < bytes_per_word); i++, len--)
+ for (i = 0; len && (i < min(4, bytes_per_word)); i++, len--)
x |= (u32)(*tx_buf++) << (i * 8);
tegra_qspi_writel(tqspi, x, QSPI_TX_FIFO);
}
@@ -400,9 +407,6 @@ tegra_qspi_read_rx_fifo_to_client_rxbuf(struct tegra_qspi *tqspi, struct spi_tra
static void
tegra_qspi_copy_client_txbuf_to_qspi_txbuf(struct tegra_qspi *tqspi, struct spi_transfer *t)
{
- dma_sync_single_for_cpu(tqspi->dev, tqspi->tx_dma_phys,
- tqspi->dma_buf_size, DMA_TO_DEVICE);
-
/*
* In packed mode, each word in FIFO may contain multiple packets
* based on bits per word. So all bytes in each FIFO word are valid.
@@ -435,17 +439,11 @@ tegra_qspi_copy_client_txbuf_to_qspi_txbuf(struct tegra_qspi *tqspi, struct spi_
tqspi->cur_tx_pos += write_bytes;
}
-
- dma_sync_single_for_device(tqspi->dev, tqspi->tx_dma_phys,
- tqspi->dma_buf_size, DMA_TO_DEVICE);
}
static void
tegra_qspi_copy_qspi_rxbuf_to_client_rxbuf(struct tegra_qspi *tqspi, struct spi_transfer *t)
{
- dma_sync_single_for_cpu(tqspi->dev, tqspi->rx_dma_phys,
- tqspi->dma_buf_size, DMA_FROM_DEVICE);
-
if (tqspi->is_packed) {
tqspi->cur_rx_pos += tqspi->curr_dma_words * tqspi->bytes_per_word;
} else {
@@ -471,9 +469,6 @@ tegra_qspi_copy_qspi_rxbuf_to_client_rxbuf(struct tegra_qspi *tqspi, struct spi_
tqspi->cur_rx_pos += read_bytes;
}
-
- dma_sync_single_for_device(tqspi->dev, tqspi->rx_dma_phys,
- tqspi->dma_buf_size, DMA_FROM_DEVICE);
}
static void tegra_qspi_dma_complete(void *args)
@@ -601,13 +596,16 @@ static void tegra_qspi_dma_unmap_xfer(struct tegra_qspi *tqspi, struct spi_trans
len = DIV_ROUND_UP(tqspi->curr_dma_words * tqspi->bytes_per_word, 4) * 4;
- dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE);
- dma_unmap_single(tqspi->dev, t->rx_dma, len, DMA_FROM_DEVICE);
+ if (t->tx_buf)
+ dma_unmap_single(tqspi->dev, t->tx_dma, len, DMA_TO_DEVICE);
+ if (t->rx_buf)
+ dma_unmap_single(tqspi->dev, t->rx_dma, len, DMA_FROM_DEVICE);
}
static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct spi_transfer *t)
{
struct dma_slave_config dma_sconfig = { 0 };
+ dma_addr_t rx_dma_phys, tx_dma_phys;
unsigned int len;
u8 dma_burst;
int ret = 0;
@@ -630,60 +628,84 @@ static int tegra_qspi_start_dma_based_transfer(struct tegra_qspi *tqspi, struct
len = tqspi->curr_dma_words * 4;
/* set attention level based on length of transfer */
- val = 0;
- if (len & 0xf) {
- val |= QSPI_TX_TRIG_1 | QSPI_RX_TRIG_1;
- dma_burst = 1;
- } else if (((len) >> 4) & 0x1) {
- val |= QSPI_TX_TRIG_4 | QSPI_RX_TRIG_4;
- dma_burst = 4;
- } else {
- val |= QSPI_TX_TRIG_8 | QSPI_RX_TRIG_8;
- dma_burst = 8;
+ if (tqspi->soc_data->has_ext_dma) {
+ val = 0;
+ if (len & 0xf) {
+ val |= QSPI_TX_TRIG_1 | QSPI_RX_TRIG_1;
+ dma_burst = 1;
+ } else if (((len) >> 4) & 0x1) {
+ val |= QSPI_TX_TRIG_4 | QSPI_RX_TRIG_4;
+ dma_burst = 4;
+ } else {
+ val |= QSPI_TX_TRIG_8 | QSPI_RX_TRIG_8;
+ dma_burst = 8;
+ }
+
+ tegra_qspi_writel(tqspi, val, QSPI_DMA_CTL);
}
- tegra_qspi_writel(tqspi, val, QSPI_DMA_CTL);
tqspi->dma_control_reg = val;
dma_sconfig.device_fc = true;
+
if (tqspi->cur_direction & DATA_DIR_TX) {
- dma_sconfig.dst_addr = tqspi->phys + QSPI_TX_FIFO;
- dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dma_sconfig.dst_maxburst = dma_burst;
- ret = dmaengine_slave_config(tqspi->tx_dma_chan, &dma_sconfig);
- if (ret < 0) {
- dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
- return ret;
- }
+ if (tqspi->tx_dma_chan) {
+ dma_sconfig.dst_addr = tqspi->phys + QSPI_TX_FIFO;
+ dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dma_sconfig.dst_maxburst = dma_burst;
+ ret = dmaengine_slave_config(tqspi->tx_dma_chan, &dma_sconfig);
+ if (ret < 0) {
+ dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
+ return ret;
+ }
- tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
- ret = tegra_qspi_start_tx_dma(tqspi, t, len);
- if (ret < 0) {
- dev_err(tqspi->dev, "failed to starting TX DMA: %d\n", ret);
- return ret;
+ tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
+ ret = tegra_qspi_start_tx_dma(tqspi, t, len);
+ if (ret < 0) {
+ dev_err(tqspi->dev, "failed to starting TX DMA: %d\n", ret);
+ return ret;
+ }
+ } else {
+ if (tqspi->is_packed)
+ tx_dma_phys = t->tx_dma;
+ else
+ tx_dma_phys = tqspi->tx_dma_phys;
+ tegra_qspi_copy_client_txbuf_to_qspi_txbuf(tqspi, t);
+ tegra_qspi_writel(tqspi, lower_32_bits(tx_dma_phys),
+ QSPI_DMA_MEM_ADDRESS);
+ tegra_qspi_writel(tqspi, (upper_32_bits(tx_dma_phys) & 0xff),
+ QSPI_DMA_HI_ADDRESS);
}
}
if (tqspi->cur_direction & DATA_DIR_RX) {
- dma_sconfig.src_addr = tqspi->phys + QSPI_RX_FIFO;
- dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dma_sconfig.src_maxburst = dma_burst;
- ret = dmaengine_slave_config(tqspi->rx_dma_chan, &dma_sconfig);
- if (ret < 0) {
- dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
- return ret;
- }
-
- dma_sync_single_for_device(tqspi->dev, tqspi->rx_dma_phys,
- tqspi->dma_buf_size,
- DMA_FROM_DEVICE);
+ if (tqspi->rx_dma_chan) {
+ dma_sconfig.src_addr = tqspi->phys + QSPI_RX_FIFO;
+ dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dma_sconfig.src_maxburst = dma_burst;
+ ret = dmaengine_slave_config(tqspi->rx_dma_chan, &dma_sconfig);
+ if (ret < 0) {
+ dev_err(tqspi->dev, "failed DMA slave config: %d\n", ret);
+ return ret;
+ }
- ret = tegra_qspi_start_rx_dma(tqspi, t, len);
- if (ret < 0) {
- dev_err(tqspi->dev, "failed to start RX DMA: %d\n", ret);
- if (tqspi->cur_direction & DATA_DIR_TX)
- dmaengine_terminate_all(tqspi->tx_dma_chan);
- return ret;
+ ret = tegra_qspi_start_rx_dma(tqspi, t, len);
+ if (ret < 0) {
+ dev_err(tqspi->dev, "failed to start RX DMA: %d\n", ret);
+ if (tqspi->cur_direction & DATA_DIR_TX)
+ dmaengine_terminate_all(tqspi->tx_dma_chan);
+ return ret;
+ }
+ } else {
+ if (tqspi->is_packed)
+ rx_dma_phys = t->rx_dma;
+ else
+ rx_dma_phys = tqspi->rx_dma_phys;
+
+ tegra_qspi_writel(tqspi, lower_32_bits(rx_dma_phys),
+ QSPI_DMA_MEM_ADDRESS);
+ tegra_qspi_writel(tqspi, (upper_32_bits(rx_dma_phys) & 0xff),
+ QSPI_DMA_HI_ADDRESS);
}
}
@@ -722,9 +744,6 @@ static int tegra_qspi_start_cpu_based_transfer(struct tegra_qspi *qspi, struct s
static void tegra_qspi_deinit_dma(struct tegra_qspi *tqspi)
{
- if (!tqspi->soc_data->has_dma)
- return;
-
if (tqspi->tx_dma_buf) {
dma_free_coherent(tqspi->dev, tqspi->dma_buf_size,
tqspi->tx_dma_buf, tqspi->tx_dma_phys);
@@ -755,16 +774,29 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
u32 *dma_buf;
int err;
- if (!tqspi->soc_data->has_dma)
- return 0;
+ if (tqspi->soc_data->has_ext_dma) {
+ dma_chan = dma_request_chan(tqspi->dev, "rx");
+ if (IS_ERR(dma_chan)) {
+ err = PTR_ERR(dma_chan);
+ goto err_out;
+ }
- dma_chan = dma_request_chan(tqspi->dev, "rx");
- if (IS_ERR(dma_chan)) {
- err = PTR_ERR(dma_chan);
- goto err_out;
- }
+ tqspi->rx_dma_chan = dma_chan;
+
+ dma_chan = dma_request_chan(tqspi->dev, "tx");
+ if (IS_ERR(dma_chan)) {
+ err = PTR_ERR(dma_chan);
+ goto err_out;
+ }
- tqspi->rx_dma_chan = dma_chan;
+ tqspi->tx_dma_chan = dma_chan;
+ } else {
+ if (!device_iommu_mapped(tqspi->dev)) {
+ dev_warn(tqspi->dev,
+ "IOMMU not enabled in device-tree, falling back to PIO mode\n");
+ return 0;
+ }
+ }
dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
if (!dma_buf) {
@@ -775,14 +807,6 @@ static int tegra_qspi_init_dma(struct tegra_qspi *tqspi)
tqspi->rx_dma_buf = dma_buf;
tqspi->rx_dma_phys = dma_phys;
- dma_chan = dma_request_chan(tqspi->dev, "tx");
- if (IS_ERR(dma_chan)) {
- err = PTR_ERR(dma_chan);
- goto err_out;
- }
-
- tqspi->tx_dma_chan = dma_chan;
-
dma_buf = dma_alloc_coherent(tqspi->dev, tqspi->dma_buf_size, &dma_phys, GFP_KERNEL);
if (!dma_buf) {
err = -ENOMEM;
@@ -810,7 +834,7 @@ err_out:
static u32 tegra_qspi_setup_transfer_one(struct spi_device *spi, struct spi_transfer *t,
bool is_first_of_msg)
{
- struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(spi->controller);
struct tegra_qspi_client_data *cdata = spi->controller_data;
u32 command1, command2, speed = t->speed_hz;
u8 bits_per_word = t->bits_per_word;
@@ -871,7 +895,7 @@ static u32 tegra_qspi_setup_transfer_one(struct spi_device *spi, struct spi_tran
static int tegra_qspi_start_transfer_one(struct spi_device *spi,
struct spi_transfer *t, u32 command1)
{
- struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(spi->controller);
unsigned int total_fifo_words;
u8 bus_width = 0;
int ret;
@@ -926,7 +950,7 @@ static int tegra_qspi_start_transfer_one(struct spi_device *spi,
static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_device *spi)
{
struct tegra_qspi_client_data *cdata;
- struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(spi->controller);
cdata = devm_kzalloc(tqspi->dev, sizeof(*cdata), GFP_KERNEL);
if (!cdata)
@@ -942,7 +966,7 @@ static struct tegra_qspi_client_data *tegra_qspi_parse_cdata_dt(struct spi_devic
static int tegra_qspi_setup(struct spi_device *spi)
{
- struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(spi->controller);
struct tegra_qspi_client_data *cdata = spi->controller_data;
unsigned long flags;
u32 val;
@@ -995,18 +1019,25 @@ static void tegra_qspi_dump_regs(struct tegra_qspi *tqspi)
tegra_qspi_readl(tqspi, QSPI_FIFO_STATUS));
}
+static void tegra_qspi_reset(struct tegra_qspi *tqspi)
+{
+ if (device_reset(tqspi->dev) < 0) {
+ dev_warn_once(tqspi->dev, "device reset failed\n");
+ tegra_qspi_mask_clear_irq(tqspi);
+ }
+}
+
static void tegra_qspi_handle_error(struct tegra_qspi *tqspi)
{
dev_err(tqspi->dev, "error in transfer, fifo status 0x%08x\n", tqspi->status_reg);
tegra_qspi_dump_regs(tqspi);
tegra_qspi_flush_fifos(tqspi, true);
- if (device_reset(tqspi->dev) < 0)
- dev_warn_once(tqspi->dev, "device reset failed\n");
+ tegra_qspi_reset(tqspi);
}
static void tegra_qspi_transfer_end(struct spi_device *spi)
{
- struct tegra_qspi *tqspi = spi_master_get_devdata(spi->master);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(spi->controller);
int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
if (cs_val)
@@ -1017,6 +1048,49 @@ static void tegra_qspi_transfer_end(struct spi_device *spi)
tegra_qspi_writel(tqspi, tqspi->def_command1_reg, QSPI_COMMAND1);
}
+static irqreturn_t handle_cpu_based_xfer(struct tegra_qspi *tqspi);
+static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi);
+
+/**
+ * tegra_qspi_handle_timeout - Handle transfer timeout with hardware check
+ * @tqspi: QSPI controller instance
+ *
+ * When a timeout occurs but hardware has completed the transfer (interrupt
+ * was lost or delayed), manually trigger transfer completion processing.
+ * This avoids failing transfers that actually succeeded.
+ *
+ * Returns: 0 if transfer was completed, -ETIMEDOUT if real timeout
+ */
+static int tegra_qspi_handle_timeout(struct tegra_qspi *tqspi)
+{
+ irqreturn_t ret;
+ u32 status;
+
+ /* Check if hardware actually completed the transfer */
+ status = tegra_qspi_readl(tqspi, QSPI_TRANS_STATUS);
+ if (!(status & QSPI_RDY))
+ return -ETIMEDOUT;
+
+ /*
+ * Hardware completed but interrupt was lost/delayed. Manually
+ * process the completion by calling the appropriate handler.
+ */
+ dev_warn_ratelimited(tqspi->dev,
+ "QSPI interrupt timeout, but transfer complete\n");
+
+ /* Clear the transfer status */
+ status = tegra_qspi_readl(tqspi, QSPI_TRANS_STATUS);
+ tegra_qspi_writel(tqspi, status, QSPI_TRANS_STATUS);
+
+ /* Manually trigger completion handler */
+ if (!tqspi->is_curr_dma_xfer)
+ ret = handle_cpu_based_xfer(tqspi);
+ else
+ ret = handle_dma_based_xfer(tqspi);
+
+ return (ret == IRQ_HANDLED) ? 0 : -EIO;
+}
+
static u32 tegra_qspi_cmd_config(bool is_ddr, u8 bus_width, u8 len)
{
u32 cmd_config = 0;
@@ -1037,10 +1111,6 @@ static u32 tegra_qspi_addr_config(bool is_ddr, u8 bus_width, u8 len)
{
u32 addr_config = 0;
- /* Extract Address configuration and value */
- is_ddr = 0; //Only SDR mode supported
- bus_width = 0; //X1 mode
-
if (is_ddr)
addr_config |= QSPI_ADDRESS_SDR_DDR;
else
@@ -1052,6 +1122,30 @@ static u32 tegra_qspi_addr_config(bool is_ddr, u8 bus_width, u8 len)
return addr_config;
}
+static void tegra_qspi_dma_stop(struct tegra_qspi *tqspi)
+{
+ u32 value;
+
+ if ((tqspi->cur_direction & DATA_DIR_TX) && tqspi->tx_dma_chan)
+ dmaengine_terminate_all(tqspi->tx_dma_chan);
+
+ if ((tqspi->cur_direction & DATA_DIR_RX) && tqspi->rx_dma_chan)
+ dmaengine_terminate_all(tqspi->rx_dma_chan);
+
+ value = tegra_qspi_readl(tqspi, QSPI_DMA_CTL);
+ value &= ~QSPI_DMA_EN;
+ tegra_qspi_writel(tqspi, value, QSPI_DMA_CTL);
+}
+
+static void tegra_qspi_pio_stop(struct tegra_qspi *tqspi)
+{
+ u32 value;
+
+ value = tegra_qspi_readl(tqspi, QSPI_COMMAND1);
+ value &= ~QSPI_PIO;
+ tegra_qspi_writel(tqspi, value, QSPI_COMMAND1);
+}
+
static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
struct spi_message *msg)
{
@@ -1059,7 +1153,7 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
struct spi_transfer *xfer;
struct spi_device *spi = msg->spi;
u8 transfer_phase = 0;
- u32 cmd1 = 0, dma_ctl = 0;
+ u32 cmd1 = 0;
int ret = 0;
u32 address_value = 0;
u32 cmd_config = 0, addr_config = 0;
@@ -1080,16 +1174,23 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
switch (transfer_phase) {
case CMD_TRANSFER:
/* X1 SDR mode */
- cmd_config = tegra_qspi_cmd_config(false, 0,
+ cmd_config = tegra_qspi_cmd_config(false, xfer->tx_nbits,
xfer->len);
cmd_value = *((const u8 *)(xfer->tx_buf));
break;
case ADDR_TRANSFER:
/* X1 SDR mode */
- addr_config = tegra_qspi_addr_config(false, 0,
+ addr_config = tegra_qspi_addr_config(false, xfer->tx_nbits,
xfer->len);
address_value = *((const u32 *)(xfer->tx_buf));
break;
+ case DUMMY_TRANSFER:
+ if (xfer->dummy_data) {
+ tqspi->dummy_cycles = xfer->len * 8 / xfer->tx_nbits;
+ break;
+ }
+ transfer_phase++;
+ fallthrough;
case DATA_TRANSFER:
/* Program Command, Address value in register */
tegra_qspi_writel(tqspi, cmd_value, QSPI_CMB_SEQ_CMD);
@@ -1118,43 +1219,29 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
(&tqspi->xfer_completion,
QSPI_DMA_TIMEOUT);
- if (WARN_ON(ret == 0)) {
- dev_err(tqspi->dev, "QSPI Transfer failed with timeout: %d\n",
- ret);
- if (tqspi->is_curr_dma_xfer &&
- (tqspi->cur_direction & DATA_DIR_TX))
- dmaengine_terminate_all
- (tqspi->tx_dma_chan);
-
- if (tqspi->is_curr_dma_xfer &&
- (tqspi->cur_direction & DATA_DIR_RX))
- dmaengine_terminate_all
- (tqspi->rx_dma_chan);
-
- /* Abort transfer by resetting pio/dma bit */
- if (!tqspi->is_curr_dma_xfer) {
- cmd1 = tegra_qspi_readl
- (tqspi,
- QSPI_COMMAND1);
- cmd1 &= ~QSPI_PIO;
- tegra_qspi_writel
- (tqspi, cmd1,
- QSPI_COMMAND1);
- } else {
- dma_ctl = tegra_qspi_readl
- (tqspi,
- QSPI_DMA_CTL);
- dma_ctl &= ~QSPI_DMA_EN;
- tegra_qspi_writel(tqspi, dma_ctl,
- QSPI_DMA_CTL);
+ if (WARN_ON_ONCE(ret == 0)) {
+ /*
+ * Check if hardware completed the transfer
+ * even though interrupt was lost or delayed.
+ * If so, process the completion and continue.
+ */
+ ret = tegra_qspi_handle_timeout(tqspi);
+ if (ret < 0) {
+ /* Real timeout - clean up and fail */
+ dev_err(tqspi->dev, "transfer timeout\n");
+
+ /* Abort transfer by resetting pio/dma bit */
+ if (tqspi->is_curr_dma_xfer)
+ tegra_qspi_dma_stop(tqspi);
+ else
+ tegra_qspi_pio_stop(tqspi);
+
+ /* Reset controller if timeout happens */
+ tegra_qspi_reset(tqspi);
+
+ ret = -EIO;
+ goto exit;
}
-
- /* Reset controller if timeout happens */
- if (device_reset(tqspi->dev) < 0)
- dev_warn_once(tqspi->dev,
- "device reset failed\n");
- ret = -EIO;
- goto exit;
}
if (tqspi->tx_status || tqspi->rx_status) {
@@ -1164,26 +1251,24 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
ret = -EIO;
goto exit;
}
- if (!xfer->cs_change) {
- tegra_qspi_transfer_end(spi);
- spi_transfer_delay_exec(xfer);
- }
break;
default:
ret = -EINVAL;
goto exit;
}
msg->actual_length += xfer->len;
+ if (!xfer->cs_change && transfer_phase == DATA_TRANSFER) {
+ tegra_qspi_transfer_end(spi);
+ spi_transfer_delay_exec(xfer);
+ }
+ tqspi->curr_xfer = NULL;
transfer_phase++;
}
ret = 0;
exit:
+ tqspi->curr_xfer = NULL;
msg->status = ret;
- if (ret < 0) {
- tegra_qspi_transfer_end(spi);
- spi_transfer_delay_exec(xfer);
- }
return ret;
}
@@ -1247,14 +1332,23 @@ static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi,
ret = wait_for_completion_timeout(&tqspi->xfer_completion,
QSPI_DMA_TIMEOUT);
if (WARN_ON(ret == 0)) {
- dev_err(tqspi->dev, "transfer timeout\n");
- if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_TX))
- dmaengine_terminate_all(tqspi->tx_dma_chan);
- if (tqspi->is_curr_dma_xfer && (tqspi->cur_direction & DATA_DIR_RX))
- dmaengine_terminate_all(tqspi->rx_dma_chan);
- tegra_qspi_handle_error(tqspi);
- ret = -EIO;
- goto complete_xfer;
+ /*
+ * Check if hardware completed the transfer even though
+ * interrupt was lost or delayed. If so, process the
+ * completion and continue.
+ */
+ ret = tegra_qspi_handle_timeout(tqspi);
+ if (ret < 0) {
+ /* Real timeout - clean up and fail */
+ dev_err(tqspi->dev, "transfer timeout\n");
+
+ if (tqspi->is_curr_dma_xfer)
+ tegra_qspi_dma_stop(tqspi);
+
+ tegra_qspi_handle_error(tqspi);
+ ret = -EIO;
+ goto complete_xfer;
+ }
}
if (tqspi->tx_status || tqspi->rx_status) {
@@ -1266,6 +1360,8 @@ static int tegra_qspi_non_combined_seq_xfer(struct tegra_qspi *tqspi,
msg->actual_length += xfer->len + dummy_bytes;
complete_xfer:
+ tqspi->curr_xfer = NULL;
+
if (ret < 0) {
tegra_qspi_transfer_end(spi);
spi_transfer_delay_exec(xfer);
@@ -1301,7 +1397,9 @@ static bool tegra_qspi_validate_cmb_seq(struct tegra_qspi *tqspi,
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
transfer_count++;
}
- if (!tqspi->soc_data->cmb_xfer_capable || transfer_count != 3)
+ if (!tqspi->soc_data->cmb_xfer_capable)
+ return false;
+ if (transfer_count > 4 || transfer_count < 3)
return false;
xfer = list_first_entry(&msg->transfers, typeof(*xfer),
transfer_list);
@@ -1311,16 +1409,23 @@ static bool tegra_qspi_validate_cmb_seq(struct tegra_qspi *tqspi,
if (xfer->len > 4 || xfer->len < 3)
return false;
xfer = list_next_entry(xfer, transfer_list);
- if (!tqspi->soc_data->has_dma && xfer->len > (QSPI_FIFO_DEPTH << 2))
+ if (transfer_count == 4) {
+ if (xfer->dummy_data != 1)
+ return false;
+ if ((xfer->len * 8 / xfer->tx_nbits) > QSPI_DUMMY_CYCLES_MAX)
+ return false;
+ xfer = list_next_entry(xfer, transfer_list);
+ }
+ if (!tqspi->soc_data->has_ext_dma && xfer->len > (QSPI_FIFO_DEPTH << 2))
return false;
return true;
}
-static int tegra_qspi_transfer_one_message(struct spi_master *master,
+static int tegra_qspi_transfer_one_message(struct spi_controller *host,
struct spi_message *msg)
{
- struct tegra_qspi *tqspi = spi_master_get_devdata(master);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(host);
int ret;
if (tegra_qspi_validate_cmb_seq(tqspi, msg))
@@ -1328,7 +1433,7 @@ static int tegra_qspi_transfer_one_message(struct spi_master *master,
else
ret = tegra_qspi_non_combined_seq_xfer(tqspi, msg);
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return ret;
}
@@ -1362,6 +1467,7 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_qspi *tqspi)
tegra_qspi_calculate_curr_xfer_param(tqspi, t);
tegra_qspi_start_cpu_based_transfer(tqspi, t);
exit:
+ tqspi->curr_xfer = NULL;
spin_unlock_irqrestore(&tqspi->lock, flags);
return IRQ_HANDLED;
}
@@ -1372,41 +1478,43 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi)
unsigned int total_fifo_words;
unsigned long flags;
long wait_status;
- int err = 0;
+ int num_errors = 0;
if (tqspi->cur_direction & DATA_DIR_TX) {
if (tqspi->tx_status) {
- dmaengine_terminate_all(tqspi->tx_dma_chan);
- err += 1;
- } else {
+ if (tqspi->tx_dma_chan)
+ dmaengine_terminate_all(tqspi->tx_dma_chan);
+ num_errors++;
+ } else if (tqspi->tx_dma_chan) {
wait_status = wait_for_completion_interruptible_timeout(
&tqspi->tx_dma_complete, QSPI_DMA_TIMEOUT);
if (wait_status <= 0) {
dmaengine_terminate_all(tqspi->tx_dma_chan);
dev_err(tqspi->dev, "failed TX DMA transfer\n");
- err += 1;
+ num_errors++;
}
}
}
if (tqspi->cur_direction & DATA_DIR_RX) {
if (tqspi->rx_status) {
- dmaengine_terminate_all(tqspi->rx_dma_chan);
- err += 2;
- } else {
+ if (tqspi->rx_dma_chan)
+ dmaengine_terminate_all(tqspi->rx_dma_chan);
+ num_errors++;
+ } else if (tqspi->rx_dma_chan) {
wait_status = wait_for_completion_interruptible_timeout(
&tqspi->rx_dma_complete, QSPI_DMA_TIMEOUT);
if (wait_status <= 0) {
dmaengine_terminate_all(tqspi->rx_dma_chan);
dev_err(tqspi->dev, "failed RX DMA transfer\n");
- err += 2;
+ num_errors++;
}
}
}
spin_lock_irqsave(&tqspi->lock, flags);
- if (err) {
+ if (num_errors) {
tegra_qspi_dma_unmap_xfer(tqspi, t);
tegra_qspi_handle_error(tqspi);
complete(&tqspi->xfer_completion);
@@ -1432,9 +1540,9 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_qspi *tqspi)
/* continue transfer in current message */
total_fifo_words = tegra_qspi_calculate_curr_xfer_param(tqspi, t);
if (total_fifo_words > QSPI_FIFO_DEPTH)
- err = tegra_qspi_start_dma_based_transfer(tqspi, t);
+ num_errors = tegra_qspi_start_dma_based_transfer(tqspi, t);
else
- err = tegra_qspi_start_cpu_based_transfer(tqspi, t);
+ num_errors = tegra_qspi_start_cpu_based_transfer(tqspi, t);
exit:
spin_unlock_irqrestore(&tqspi->lock, flags);
@@ -1445,6 +1553,15 @@ static irqreturn_t tegra_qspi_isr_thread(int irq, void *context_data)
{
struct tegra_qspi *tqspi = context_data;
+ /*
+ * Occasionally the IRQ thread takes a long time to wake up (usually
+ * when the CPU that it's running on is excessively busy) and we have
+ * already reached the timeout before and cleaned up the timed out
+ * transfer. Avoid any processing in that case and bail out early.
+ */
+ if (!tqspi->curr_xfer)
+ return IRQ_NONE;
+
tqspi->status_reg = tegra_qspi_readl(tqspi, QSPI_FIFO_STATUS);
if (tqspi->cur_direction & DATA_DIR_TX)
@@ -1462,28 +1579,28 @@ static irqreturn_t tegra_qspi_isr_thread(int irq, void *context_data)
}
static struct tegra_qspi_soc_data tegra210_qspi_soc_data = {
- .has_dma = true,
+ .has_ext_dma = true,
.cmb_xfer_capable = false,
.supports_tpm = false,
.cs_count = 1,
};
static struct tegra_qspi_soc_data tegra186_qspi_soc_data = {
- .has_dma = true,
+ .has_ext_dma = true,
.cmb_xfer_capable = true,
.supports_tpm = false,
.cs_count = 1,
};
static struct tegra_qspi_soc_data tegra234_qspi_soc_data = {
- .has_dma = false,
+ .has_ext_dma = false,
.cmb_xfer_capable = true,
.supports_tpm = true,
.cs_count = 1,
};
static struct tegra_qspi_soc_data tegra241_qspi_soc_data = {
- .has_dma = false,
+ .has_ext_dma = true,
.cmb_xfer_capable = true,
.supports_tpm = true,
.cs_count = 4,
@@ -1534,38 +1651,38 @@ MODULE_DEVICE_TABLE(acpi, tegra_qspi_acpi_match);
static int tegra_qspi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct tegra_qspi *tqspi;
struct resource *r;
int ret, qspi_irq;
int bus_num;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(*tqspi));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(*tqspi));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
- tqspi = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, host);
+ tqspi = spi_controller_get_devdata(host);
- master->mode_bits = SPI_MODE_0 | SPI_MODE_3 | SPI_CS_HIGH |
- SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
- master->flags = SPI_CONTROLLER_HALF_DUPLEX;
- master->setup = tegra_qspi_setup;
- master->transfer_one_message = tegra_qspi_transfer_one_message;
- master->num_chipselect = 1;
- master->auto_runtime_pm = true;
+ host->mode_bits = SPI_MODE_0 | SPI_MODE_3 | SPI_CS_HIGH |
+ SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
+ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->setup = tegra_qspi_setup;
+ host->transfer_one_message = tegra_qspi_transfer_one_message;
+ host->num_chipselect = 1;
+ host->auto_runtime_pm = true;
bus_num = of_alias_get_id(pdev->dev.of_node, "spi");
if (bus_num >= 0)
- master->bus_num = bus_num;
+ host->bus_num = bus_num;
- tqspi->master = master;
+ tqspi->host = host;
tqspi->dev = &pdev->dev;
spin_lock_init(&tqspi->lock);
tqspi->soc_data = device_get_match_data(&pdev->dev);
- master->num_chipselect = tqspi->soc_data->cs_count;
+ host->num_chipselect = tqspi->soc_data->cs_count;
tqspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(tqspi->base))
return PTR_ERR(tqspi->base);
@@ -1626,10 +1743,10 @@ static int tegra_qspi_probe(struct platform_device *pdev)
goto exit_pm_disable;
}
- master->dev.of_node = pdev->dev.of_node;
- ret = spi_register_master(master);
+ host->dev.of_node = pdev->dev.of_node;
+ ret = spi_register_controller(host);
if (ret < 0) {
- dev_err(&pdev->dev, "failed to register master: %d\n", ret);
+ dev_err(&pdev->dev, "failed to register host: %d\n", ret);
goto exit_free_irq;
}
@@ -1645,10 +1762,10 @@ exit_pm_disable:
static void tegra_qspi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct tegra_qspi *tqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(host);
- spi_unregister_master(master);
+ spi_unregister_controller(host);
free_irq(tqspi->irq, tqspi);
pm_runtime_force_suspend(&pdev->dev);
tegra_qspi_deinit_dma(tqspi);
@@ -1656,15 +1773,15 @@ static void tegra_qspi_remove(struct platform_device *pdev)
static int __maybe_unused tegra_qspi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_controller *host = dev_get_drvdata(dev);
- return spi_master_suspend(master);
+ return spi_controller_suspend(host);
}
static int __maybe_unused tegra_qspi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_qspi *tqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(host);
int ret;
ret = pm_runtime_resume_and_get(dev);
@@ -1677,13 +1794,13 @@ static int __maybe_unused tegra_qspi_resume(struct device *dev)
tegra_qspi_writel(tqspi, tqspi->def_command2_reg, QSPI_COMMAND2);
pm_runtime_put(dev);
- return spi_master_resume(master);
+ return spi_controller_resume(host);
}
static int __maybe_unused tegra_qspi_runtime_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_qspi *tqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(host);
/* Runtime pm disabled with ACPI */
if (has_acpi_companion(tqspi->dev))
@@ -1698,8 +1815,8 @@ static int __maybe_unused tegra_qspi_runtime_suspend(struct device *dev)
static int __maybe_unused tegra_qspi_runtime_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct tegra_qspi *tqspi = spi_master_get_devdata(master);
+ struct spi_controller *host = dev_get_drvdata(dev);
+ struct tegra_qspi *tqspi = spi_controller_get_devdata(host);
int ret;
/* Runtime pm disabled with ACPI */
@@ -1725,7 +1842,7 @@ static struct platform_driver tegra_qspi_driver = {
.acpi_match_table = ACPI_PTR(tegra_qspi_acpi_match),
},
.probe = tegra_qspi_probe,
- .remove_new = tegra_qspi_remove,
+ .remove = tegra_qspi_remove,
};
module_platform_driver(tegra_qspi_driver);
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 5914335ff63d..0b7eaccbc797 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -22,7 +22,6 @@
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
@@ -41,7 +40,7 @@ struct ti_qspi {
/* list synchronization */
struct mutex list_lock;
- struct spi_master *master;
+ struct spi_controller *host;
void __iomem *base;
void __iomem *mmap_base;
size_t mmap_size;
@@ -138,20 +137,20 @@ static inline void ti_qspi_write(struct ti_qspi *qspi,
static int ti_qspi_setup(struct spi_device *spi)
{
- struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller);
int ret;
- if (spi->master->busy) {
- dev_dbg(qspi->dev, "master busy doing other transfers\n");
+ if (spi->controller->busy) {
+ dev_dbg(qspi->dev, "host busy doing other transfers\n");
return -EBUSY;
}
- if (!qspi->master->max_speed_hz) {
+ if (!qspi->host->max_speed_hz) {
dev_err(qspi->dev, "spi max frequency not defined\n");
return -EINVAL;
}
- spi->max_speed_hz = min(spi->max_speed_hz, qspi->master->max_speed_hz);
+ spi->max_speed_hz = min(spi->max_speed_hz, qspi->host->max_speed_hz);
ret = pm_runtime_resume_and_get(qspi->dev);
if (ret < 0) {
@@ -159,7 +158,6 @@ static int ti_qspi_setup(struct spi_device *spi)
return ret;
}
- pm_runtime_mark_last_busy(qspi->dev);
ret = pm_runtime_put_autosuspend(qspi->dev);
if (ret < 0) {
dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n");
@@ -196,7 +194,6 @@ static void ti_qspi_setup_clk(struct ti_qspi *qspi, u32 speed_hz)
ctx_reg->clkctrl = clk_ctrl_new;
}
- pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
}
@@ -527,7 +524,7 @@ static int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg,
static void ti_qspi_enable_memory_map(struct spi_device *spi)
{
- struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller);
ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG);
if (qspi->ctrl_base) {
@@ -541,7 +538,7 @@ static void ti_qspi_enable_memory_map(struct spi_device *spi)
static void ti_qspi_disable_memory_map(struct spi_device *spi)
{
- struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller);
ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG);
if (qspi->ctrl_base)
@@ -555,7 +552,7 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
u8 data_nbits, u8 addr_width,
u8 dummy_bytes)
{
- struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(spi->controller);
u32 memval = opcode;
switch (data_nbits) {
@@ -577,7 +574,7 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
- struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->controller);
size_t max_len;
if (op->data.dir == SPI_MEM_DATA_IN) {
@@ -607,24 +604,24 @@ static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
static int ti_qspi_exec_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->controller);
u32 from = 0;
int ret = 0;
/* Only optimize read path. */
if (!op->data.nbytes || op->data.dir != SPI_MEM_DATA_IN ||
!op->addr.nbytes || op->addr.nbytes > 4)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
/* Address exceeds MMIO window size, fall back to regular mode. */
from = op->addr.val;
if (from + op->data.nbytes > qspi->mmap_size)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
mutex_lock(&qspi->list_lock);
if (!qspi->mmap_enabled || qspi->current_cs != spi_get_chipselect(mem->spi, 0)) {
- ti_qspi_setup_clk(qspi, mem->spi->max_speed_hz);
+ ti_qspi_setup_clk(qspi, op->max_freq);
ti_qspi_enable_memory_map(mem->spi);
}
ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
@@ -634,10 +631,10 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
struct sg_table sgt;
if (virt_addr_valid(op->data.buf.in) &&
- !spi_controller_dma_map_mem_op_data(mem->spi->master, op,
+ !spi_controller_dma_map_mem_op_data(mem->spi->controller, op,
&sgt)) {
ret = ti_qspi_dma_xfer_sg(qspi, sgt, from);
- spi_controller_dma_unmap_mem_op_data(mem->spi->master,
+ spi_controller_dma_unmap_mem_op_data(mem->spi->controller,
op, &sgt);
} else {
ret = ti_qspi_dma_bounce_buffer(qspi, from,
@@ -659,10 +656,14 @@ static const struct spi_controller_mem_ops ti_qspi_mem_ops = {
.adjust_op_size = ti_qspi_adjust_op_size,
};
-static int ti_qspi_start_transfer_one(struct spi_master *master,
+static const struct spi_controller_mem_caps ti_qspi_mem_caps = {
+ .per_op_freq = true,
+};
+
+static int ti_qspi_start_transfer_one(struct spi_controller *host,
struct spi_message *m)
{
- struct ti_qspi *qspi = spi_master_get_devdata(master);
+ struct ti_qspi *qspi = spi_controller_get_devdata(host);
struct spi_device *spi = m->spi;
struct spi_transfer *t;
int status = 0, ret;
@@ -721,7 +722,7 @@ static int ti_qspi_start_transfer_one(struct spi_master *master,
ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG);
m->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return status;
}
@@ -757,33 +758,34 @@ MODULE_DEVICE_TABLE(of, ti_qspi_match);
static int ti_qspi_probe(struct platform_device *pdev)
{
struct ti_qspi *qspi;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *r, *res_mmap;
struct device_node *np = pdev->dev.of_node;
u32 max_freq;
int ret = 0, num_cs, irq;
dma_cap_mask_t mask;
- master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*qspi));
+ if (!host)
return -ENOMEM;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->setup = ti_qspi_setup;
- master->auto_runtime_pm = true;
- master->transfer_one_message = ti_qspi_start_transfer_one;
- master->dev.of_node = pdev->dev.of_node;
- master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
- SPI_BPW_MASK(8);
- master->mem_ops = &ti_qspi_mem_ops;
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->setup = ti_qspi_setup;
+ host->auto_runtime_pm = true;
+ host->transfer_one_message = ti_qspi_start_transfer_one;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
+ SPI_BPW_MASK(8);
+ host->mem_ops = &ti_qspi_mem_ops;
+ host->mem_caps = &ti_qspi_mem_caps;
if (!of_property_read_u32(np, "num-cs", &num_cs))
- master->num_chipselect = num_cs;
+ host->num_chipselect = num_cs;
- qspi = spi_master_get_devdata(master);
- qspi->master = master;
+ qspi = spi_controller_get_devdata(host);
+ qspi->host = host;
qspi->dev = &pdev->dev;
platform_set_drvdata(pdev, qspi);
@@ -793,7 +795,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (r == NULL) {
dev_err(&pdev->dev, "missing platform data\n");
ret = -ENODEV;
- goto free_master;
+ goto free_host;
}
}
@@ -813,7 +815,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
- goto free_master;
+ goto free_host;
}
mutex_init(&qspi->list_lock);
@@ -821,25 +823,17 @@ static int ti_qspi_probe(struct platform_device *pdev)
qspi->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(qspi->base)) {
ret = PTR_ERR(qspi->base);
- goto free_master;
+ goto free_host;
}
- if (of_property_read_bool(np, "syscon-chipselects")) {
+ if (of_property_present(np, "syscon-chipselects")) {
qspi->ctrl_base =
- syscon_regmap_lookup_by_phandle(np,
- "syscon-chipselects");
+ syscon_regmap_lookup_by_phandle_args(np, "syscon-chipselects",
+ 1, &qspi->ctrl_reg);
if (IS_ERR(qspi->ctrl_base)) {
ret = PTR_ERR(qspi->ctrl_base);
- goto free_master;
- }
- ret = of_property_read_u32_index(np,
- "syscon-chipselects",
- 1, &qspi->ctrl_reg);
- if (ret) {
- dev_err(&pdev->dev,
- "couldn't get ctrl_mod reg index\n");
- goto free_master;
+ goto free_host;
}
}
@@ -854,7 +848,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
- master->max_speed_hz = max_freq;
+ host->max_speed_hz = max_freq;
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
@@ -864,7 +858,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
dev_err(qspi->dev,
"No Rx DMA available, trying mmap mode\n");
qspi->rx_chan = NULL;
- ret = 0;
goto no_dma;
}
qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev,
@@ -877,7 +870,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
dma_release_channel(qspi->rx_chan);
goto no_dma;
}
- master->dma_rx = qspi->rx_chan;
+ host->dma_rx = qspi->rx_chan;
init_completion(&qspi->transfer_complete);
if (res_mmap)
qspi->mmap_phys_base = (dma_addr_t)res_mmap->start;
@@ -890,39 +883,40 @@ no_dma:
"mmap failed with error %ld using PIO mode\n",
PTR_ERR(qspi->mmap_base));
qspi->mmap_base = NULL;
- master->mem_ops = NULL;
+ host->mem_ops = NULL;
}
}
qspi->mmap_enabled = false;
qspi->current_cs = -1;
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (!ret)
return 0;
ti_qspi_dma_cleanup(qspi);
pm_runtime_disable(&pdev->dev);
-free_master:
- spi_master_put(master);
+free_host:
+ spi_controller_put(host);
return ret;
}
-static int ti_qspi_remove(struct platform_device *pdev)
+static void ti_qspi_remove(struct platform_device *pdev)
{
struct ti_qspi *qspi = platform_get_drvdata(pdev);
int rc;
- rc = spi_master_suspend(qspi->master);
- if (rc)
- return rc;
+ rc = spi_controller_suspend(qspi->host);
+ if (rc) {
+ dev_alert(&pdev->dev, "spi_controller_suspend() failed (%pe)\n",
+ ERR_PTR(rc));
+ return;
+ }
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
ti_qspi_dma_cleanup(qspi);
-
- return 0;
}
static const struct dev_pm_ops ti_qspi_pm_ops = {
diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c
index a565352f6381..663c0136d119 100644
--- a/drivers/spi/spi-tle62x0.c
+++ b/drivers/spi/spi-tle62x0.c
@@ -141,7 +141,7 @@ static ssize_t tle62x0_gpio_show(struct device *dev,
value = (st->gpio_state >> gpio_num) & 1;
mutex_unlock(&st->lock);
- return sysfs_emit(buf, "%d", value);
+ return sysfs_emit(buf, "%d\n", value);
}
static ssize_t tle62x0_gpio_store(struct device *dev,
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index af5846cfe5e9..60fce5c73031 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -124,7 +124,7 @@ struct pch_spi_dma_ctrl {
* struct pch_spi_data - Holds the SPI channel specific details
* @io_remap_addr: The remapped PCI base address
* @io_base_addr: Base address
- * @master: Pointer to the SPI master structure
+ * @host: Pointer to the SPI controller structure
* @work: Reference to work queue handler
* @wait: Wait queue for waking up upon receiving an
* interrupt.
@@ -161,7 +161,7 @@ struct pch_spi_dma_ctrl {
struct pch_spi_data {
void __iomem *io_remap_addr;
unsigned long io_base_addr;
- struct spi_master *master;
+ struct spi_controller *host;
struct work_struct work;
wait_queue_head_t wait;
u8 transfer_complete;
@@ -216,48 +216,48 @@ static const struct pci_device_id pch_spi_pcidev_id[] = {
/**
* pch_spi_writereg() - Performs register writes
- * @master: Pointer to struct spi_master.
+ * @host: Pointer to struct spi_controller.
* @idx: Register offset.
* @val: Value to be written to register.
*/
-static inline void pch_spi_writereg(struct spi_master *master, int idx, u32 val)
+static inline void pch_spi_writereg(struct spi_controller *host, int idx, u32 val)
{
- struct pch_spi_data *data = spi_master_get_devdata(master);
+ struct pch_spi_data *data = spi_controller_get_devdata(host);
iowrite32(val, (data->io_remap_addr + idx));
}
/**
* pch_spi_readreg() - Performs register reads
- * @master: Pointer to struct spi_master.
+ * @host: Pointer to struct spi_controller.
* @idx: Register offset.
*/
-static inline u32 pch_spi_readreg(struct spi_master *master, int idx)
+static inline u32 pch_spi_readreg(struct spi_controller *host, int idx)
{
- struct pch_spi_data *data = spi_master_get_devdata(master);
+ struct pch_spi_data *data = spi_controller_get_devdata(host);
return ioread32(data->io_remap_addr + idx);
}
-static inline void pch_spi_setclr_reg(struct spi_master *master, int idx,
+static inline void pch_spi_setclr_reg(struct spi_controller *host, int idx,
u32 set, u32 clr)
{
- u32 tmp = pch_spi_readreg(master, idx);
+ u32 tmp = pch_spi_readreg(host, idx);
tmp = (tmp & ~clr) | set;
- pch_spi_writereg(master, idx, tmp);
+ pch_spi_writereg(host, idx, tmp);
}
-static void pch_spi_set_master_mode(struct spi_master *master)
+static void pch_spi_set_host_mode(struct spi_controller *host)
{
- pch_spi_setclr_reg(master, PCH_SPCR, SPCR_MSTR_BIT, 0);
+ pch_spi_setclr_reg(host, PCH_SPCR, SPCR_MSTR_BIT, 0);
}
/**
* pch_spi_clear_fifo() - Clears the Transmit and Receive FIFOs
- * @master: Pointer to struct spi_master.
+ * @host: Pointer to struct spi_controller.
*/
-static void pch_spi_clear_fifo(struct spi_master *master)
+static void pch_spi_clear_fifo(struct spi_controller *host)
{
- pch_spi_setclr_reg(master, PCH_SPCR, SPCR_FICLR_BIT, 0);
- pch_spi_setclr_reg(master, PCH_SPCR, 0, SPCR_FICLR_BIT);
+ pch_spi_setclr_reg(host, PCH_SPCR, SPCR_FICLR_BIT, 0);
+ pch_spi_setclr_reg(host, PCH_SPCR, 0, SPCR_FICLR_BIT);
}
static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
@@ -312,7 +312,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
if (reg_spsr_val & SPSR_FI_BIT) {
if ((tx_index == bpw_len) && (rx_index == tx_index)) {
/* disable interrupts */
- pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
+ pch_spi_setclr_reg(data->host, PCH_SPCR, 0,
PCH_ALL);
/* transfer is completed;
@@ -321,7 +321,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
data->transfer_active = false;
wake_up(&data->wait);
} else {
- dev_vdbg(&data->master->dev,
+ dev_vdbg(&data->host->dev,
"%s : Transfer is not completed",
__func__);
}
@@ -383,10 +383,10 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id)
/**
* pch_spi_set_baud_rate() - Sets SPBR field in SPBRR
- * @master: Pointer to struct spi_master.
+ * @host: Pointer to struct spi_controller.
* @speed_hz: Baud rate.
*/
-static void pch_spi_set_baud_rate(struct spi_master *master, u32 speed_hz)
+static void pch_spi_set_baud_rate(struct spi_controller *host, u32 speed_hz)
{
u32 n_spbr = PCH_CLOCK_HZ / (speed_hz * 2);
@@ -394,21 +394,21 @@ static void pch_spi_set_baud_rate(struct spi_master *master, u32 speed_hz)
if (n_spbr > PCH_MAX_SPBR)
n_spbr = PCH_MAX_SPBR;
- pch_spi_setclr_reg(master, PCH_SPBRR, n_spbr, MASK_SPBRR_SPBR_BITS);
+ pch_spi_setclr_reg(host, PCH_SPBRR, n_spbr, MASK_SPBRR_SPBR_BITS);
}
/**
* pch_spi_set_bits_per_word() - Sets SIZE field in SPBRR
- * @master: Pointer to struct spi_master.
+ * @host: Pointer to struct spi_controller.
* @bits_per_word: Bits per word for SPI transfer.
*/
-static void pch_spi_set_bits_per_word(struct spi_master *master,
+static void pch_spi_set_bits_per_word(struct spi_controller *host,
u8 bits_per_word)
{
if (bits_per_word == 8)
- pch_spi_setclr_reg(master, PCH_SPBRR, 0, SPBRR_SIZE_BIT);
+ pch_spi_setclr_reg(host, PCH_SPBRR, 0, SPBRR_SIZE_BIT);
else
- pch_spi_setclr_reg(master, PCH_SPBRR, SPBRR_SIZE_BIT, 0);
+ pch_spi_setclr_reg(host, PCH_SPBRR, SPBRR_SIZE_BIT, 0);
}
/**
@@ -420,12 +420,12 @@ static void pch_spi_setup_transfer(struct spi_device *spi)
u32 flags = 0;
dev_dbg(&spi->dev, "%s SPBRR content =%x setting baud rate=%d\n",
- __func__, pch_spi_readreg(spi->master, PCH_SPBRR),
+ __func__, pch_spi_readreg(spi->controller, PCH_SPBRR),
spi->max_speed_hz);
- pch_spi_set_baud_rate(spi->master, spi->max_speed_hz);
+ pch_spi_set_baud_rate(spi->controller, spi->max_speed_hz);
/* set bits per word */
- pch_spi_set_bits_per_word(spi->master, spi->bits_per_word);
+ pch_spi_set_bits_per_word(spi->controller, spi->bits_per_word);
if (!(spi->mode & SPI_LSB_FIRST))
flags |= SPCR_LSBF_BIT;
@@ -433,29 +433,29 @@ static void pch_spi_setup_transfer(struct spi_device *spi)
flags |= SPCR_CPOL_BIT;
if (spi->mode & SPI_CPHA)
flags |= SPCR_CPHA_BIT;
- pch_spi_setclr_reg(spi->master, PCH_SPCR, flags,
+ pch_spi_setclr_reg(spi->controller, PCH_SPCR, flags,
(SPCR_LSBF_BIT | SPCR_CPOL_BIT | SPCR_CPHA_BIT));
/* Clear the FIFO by toggling FICLR to 1 and back to 0 */
- pch_spi_clear_fifo(spi->master);
+ pch_spi_clear_fifo(spi->controller);
}
/**
* pch_spi_reset() - Clears SPI registers
- * @master: Pointer to struct spi_master.
+ * @host: Pointer to struct spi_controller.
*/
-static void pch_spi_reset(struct spi_master *master)
+static void pch_spi_reset(struct spi_controller *host)
{
/* write 1 to reset SPI */
- pch_spi_writereg(master, PCH_SRST, 0x1);
+ pch_spi_writereg(host, PCH_SRST, 0x1);
/* clear reset */
- pch_spi_writereg(master, PCH_SRST, 0x0);
+ pch_spi_writereg(host, PCH_SRST, 0x0);
}
static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
{
- struct pch_spi_data *data = spi_master_get_devdata(pspi->master);
+ struct pch_spi_data *data = spi_controller_get_devdata(pspi->controller);
int retval;
unsigned long flags;
@@ -524,15 +524,15 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
/* set baud rate if needed */
if (data->cur_trans->speed_hz) {
- dev_dbg(&data->master->dev, "%s:setting baud rate\n", __func__);
- pch_spi_set_baud_rate(data->master, data->cur_trans->speed_hz);
+ dev_dbg(&data->host->dev, "%s:setting baud rate\n", __func__);
+ pch_spi_set_baud_rate(data->host, data->cur_trans->speed_hz);
}
/* set bits per word if needed */
if (data->cur_trans->bits_per_word &&
(data->current_msg->spi->bits_per_word != data->cur_trans->bits_per_word)) {
- dev_dbg(&data->master->dev, "%s:set bits per word\n", __func__);
- pch_spi_set_bits_per_word(data->master,
+ dev_dbg(&data->host->dev, "%s:set bits per word\n", __func__);
+ pch_spi_set_bits_per_word(data->host,
data->cur_trans->bits_per_word);
*bpw = data->cur_trans->bits_per_word;
} else {
@@ -590,13 +590,13 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
if (n_writes > PCH_MAX_FIFO_DEPTH)
n_writes = PCH_MAX_FIFO_DEPTH;
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"\n%s:Pulling down SSN low - writing 0x2 to SSNXCR\n",
__func__);
- pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
+ pch_spi_writereg(data->host, PCH_SSNXCR, SSN_LOW);
for (j = 0; j < n_writes; j++)
- pch_spi_writereg(data->master, PCH_SPDWR, data->pkt_tx_buff[j]);
+ pch_spi_writereg(data->host, PCH_SPDWR, data->pkt_tx_buff[j]);
/* update tx_index */
data->tx_index = j;
@@ -609,13 +609,13 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
static void pch_spi_nomore_transfer(struct pch_spi_data *data)
{
struct spi_message *pmsg, *tmp;
- dev_dbg(&data->master->dev, "%s called\n", __func__);
+ dev_dbg(&data->host->dev, "%s called\n", __func__);
/* Invoke complete callback
* [To the spi core..indicating end of transfer] */
data->current_msg->status = 0;
if (data->current_msg->complete) {
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s:Invoking callback of SPI core\n", __func__);
data->current_msg->complete(data->current_msg->context);
}
@@ -623,7 +623,7 @@ static void pch_spi_nomore_transfer(struct pch_spi_data *data)
/* update status in global variable */
data->bcurrent_msg_processing = false;
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s:data->bcurrent_msg_processing = false\n", __func__);
data->current_msg = NULL;
@@ -638,11 +638,11 @@ static void pch_spi_nomore_transfer(struct pch_spi_data *data)
* bpw;sfer requests in the current message or there are
*more messages)
*/
- dev_dbg(&data->master->dev, "%s:Invoke queue_work\n", __func__);
+ dev_dbg(&data->host->dev, "%s:Invoke queue_work\n", __func__);
schedule_work(&data->work);
} else if (data->board_dat->suspend_sts ||
data->status == STATUS_EXITING) {
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s suspend/remove initiated, flushing queue\n",
__func__);
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
@@ -662,14 +662,14 @@ static void pch_spi_set_ir(struct pch_spi_data *data)
/* enable interrupts, set threshold, enable SPI */
if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH)
/* set receive threshold to PCH_RX_THOLD */
- pch_spi_setclr_reg(data->master, PCH_SPCR,
+ pch_spi_setclr_reg(data->host, PCH_SPCR,
PCH_RX_THOLD << SPCR_RFIC_FIELD |
SPCR_FIE_BIT | SPCR_RFIE_BIT |
SPCR_ORIE_BIT | SPCR_SPE_BIT,
MASK_RFIC_SPCR_BITS | PCH_ALL);
else
/* set receive threshold to maximum */
- pch_spi_setclr_reg(data->master, PCH_SPCR,
+ pch_spi_setclr_reg(data->host, PCH_SPCR,
PCH_RX_THOLD_MAX << SPCR_RFIC_FIELD |
SPCR_FIE_BIT | SPCR_ORIE_BIT |
SPCR_SPE_BIT,
@@ -677,18 +677,18 @@ static void pch_spi_set_ir(struct pch_spi_data *data)
/* Wait until the transfer completes; go to sleep after
initiating the transfer. */
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s:waiting for transfer to get over\n", __func__);
wait_event_interruptible(data->wait, data->transfer_complete);
/* clear all interrupts */
- pch_spi_writereg(data->master, PCH_SPSR,
- pch_spi_readreg(data->master, PCH_SPSR));
+ pch_spi_writereg(data->host, PCH_SPSR,
+ pch_spi_readreg(data->host, PCH_SPSR));
/* Disable interrupts and SPI transfer */
- pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL | SPCR_SPE_BIT);
+ pch_spi_setclr_reg(data->host, PCH_SPCR, 0, PCH_ALL | SPCR_SPE_BIT);
/* clear FIFO */
- pch_spi_clear_fifo(data->master);
+ pch_spi_clear_fifo(data->host);
}
static void pch_spi_copy_rx_data(struct pch_spi_data *data, int bpw)
@@ -750,25 +750,25 @@ static int pch_spi_start_transfer(struct pch_spi_data *data)
spin_lock_irqsave(&data->lock, flags);
/* disable interrupts, SPI set enable */
- pch_spi_setclr_reg(data->master, PCH_SPCR, SPCR_SPE_BIT, PCH_ALL);
+ pch_spi_setclr_reg(data->host, PCH_SPCR, SPCR_SPE_BIT, PCH_ALL);
spin_unlock_irqrestore(&data->lock, flags);
/* Wait until the transfer completes; go to sleep after
initiating the transfer. */
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s:waiting for transfer to get over\n", __func__);
rtn = wait_event_interruptible_timeout(data->wait,
data->transfer_complete,
msecs_to_jiffies(2 * HZ));
if (!rtn)
- dev_err(&data->master->dev,
+ dev_err(&data->host->dev,
"%s wait-event timeout\n", __func__);
- dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent,
+ dma_sync_sg_for_cpu(&data->host->dev, dma->sg_rx_p, dma->nent,
DMA_FROM_DEVICE);
- dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent,
+ dma_sync_sg_for_cpu(&data->host->dev, dma->sg_tx_p, dma->nent,
DMA_FROM_DEVICE);
memset(data->dma.tx_buf_virt, 0, PAGE_SIZE);
@@ -780,14 +780,14 @@ static int pch_spi_start_transfer(struct pch_spi_data *data)
spin_lock_irqsave(&data->lock, flags);
/* clear fifo threshold, disable interrupts, disable SPI transfer */
- pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
+ pch_spi_setclr_reg(data->host, PCH_SPCR, 0,
MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS | PCH_ALL |
SPCR_SPE_BIT);
/* clear all interrupts */
- pch_spi_writereg(data->master, PCH_SPSR,
- pch_spi_readreg(data->master, PCH_SPSR));
+ pch_spi_writereg(data->host, PCH_SPSR,
+ pch_spi_readreg(data->host, PCH_SPSR));
/* clear FIFO */
- pch_spi_clear_fifo(data->master);
+ pch_spi_clear_fifo(data->host);
spin_unlock_irqrestore(&data->lock, flags);
@@ -846,7 +846,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
param->width = width;
chan = dma_request_channel(mask, pch_spi_filter, param);
if (!chan) {
- dev_err(&data->master->dev,
+ dev_err(&data->host->dev,
"ERROR: dma_request_channel FAILS(Tx)\n");
goto out;
}
@@ -860,7 +860,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
param->width = width;
chan = dma_request_channel(mask, pch_spi_filter, param);
if (!chan) {
- dev_err(&data->master->dev,
+ dev_err(&data->host->dev,
"ERROR: dma_request_channel FAILS(Rx)\n");
dma_release_channel(dma->chan_tx);
dma->chan_tx = NULL;
@@ -913,9 +913,9 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
/* set baud rate if needed */
if (data->cur_trans->speed_hz) {
- dev_dbg(&data->master->dev, "%s:setting baud rate\n", __func__);
+ dev_dbg(&data->host->dev, "%s:setting baud rate\n", __func__);
spin_lock_irqsave(&data->lock, flags);
- pch_spi_set_baud_rate(data->master, data->cur_trans->speed_hz);
+ pch_spi_set_baud_rate(data->host, data->cur_trans->speed_hz);
spin_unlock_irqrestore(&data->lock, flags);
}
@@ -923,9 +923,9 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
if (data->cur_trans->bits_per_word &&
(data->current_msg->spi->bits_per_word !=
data->cur_trans->bits_per_word)) {
- dev_dbg(&data->master->dev, "%s:set bits per word\n", __func__);
+ dev_dbg(&data->host->dev, "%s:set bits per word\n", __func__);
spin_lock_irqsave(&data->lock, flags);
- pch_spi_set_bits_per_word(data->master,
+ pch_spi_set_bits_per_word(data->host,
data->cur_trans->bits_per_word);
spin_unlock_irqrestore(&data->lock, flags);
*bpw = data->cur_trans->bits_per_word;
@@ -969,12 +969,12 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
size = data->bpw_len;
rem = data->bpw_len;
}
- dev_dbg(&data->master->dev, "%s num=%d size=%d rem=%d\n",
+ dev_dbg(&data->host->dev, "%s num=%d size=%d rem=%d\n",
__func__, num, size, rem);
spin_lock_irqsave(&data->lock, flags);
/* set receive fifo threshold and transmit fifo threshold */
- pch_spi_setclr_reg(data->master, PCH_SPCR,
+ pch_spi_setclr_reg(data->host, PCH_SPCR,
((size - 1) << SPCR_RFIC_FIELD) |
(PCH_TX_THOLD << SPCR_TFIC_FIELD),
MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS);
@@ -1016,11 +1016,11 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
num, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx) {
- dev_err(&data->master->dev,
+ dev_err(&data->host->dev,
"%s:dmaengine_prep_slave_sg Failed\n", __func__);
return;
}
- dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_FROM_DEVICE);
+ dma_sync_sg_for_device(&data->host->dev, sg, num, DMA_FROM_DEVICE);
desc_rx->callback = pch_dma_rx_complete;
desc_rx->callback_param = data;
dma->nent = num;
@@ -1078,20 +1078,20 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
sg, num, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) {
- dev_err(&data->master->dev,
+ dev_err(&data->host->dev,
"%s:dmaengine_prep_slave_sg Failed\n", __func__);
return;
}
- dma_sync_sg_for_device(&data->master->dev, sg, num, DMA_TO_DEVICE);
+ dma_sync_sg_for_device(&data->host->dev, sg, num, DMA_TO_DEVICE);
desc_tx->callback = NULL;
desc_tx->callback_param = data;
dma->nent = num;
dma->desc_tx = desc_tx;
- dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__);
+ dev_dbg(&data->host->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__);
spin_lock_irqsave(&data->lock, flags);
- pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
+ pch_spi_writereg(data->host, PCH_SSNXCR, SSN_LOW);
desc_rx->tx_submit(desc_rx);
desc_tx->tx_submit(desc_tx);
spin_unlock_irqrestore(&data->lock, flags);
@@ -1107,12 +1107,12 @@ static void pch_spi_process_messages(struct work_struct *pwork)
int bpw;
data = container_of(pwork, struct pch_spi_data, work);
- dev_dbg(&data->master->dev, "%s data initialized\n", __func__);
+ dev_dbg(&data->host->dev, "%s data initialized\n", __func__);
spin_lock(&data->lock);
/* check if suspend has been initiated;if yes flush queue */
if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) {
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s suspend/remove initiated, flushing queue\n", __func__);
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
pmsg->status = -EIO;
@@ -1132,7 +1132,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
}
data->bcurrent_msg_processing = true;
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s Set data->bcurrent_msg_processing= true\n", __func__);
/* Get the message from the queue and delete it from there. */
@@ -1150,7 +1150,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
if (data->use_dma)
pch_spi_request_dma(data,
data->current_msg->spi->bits_per_word);
- pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
+ pch_spi_writereg(data->host, PCH_SSNXCR, SSN_NO_CONTROL);
do {
int cnt;
/* If we are already processing a message get the next
@@ -1161,14 +1161,14 @@ static void pch_spi_process_messages(struct work_struct *pwork)
data->cur_trans =
list_entry(data->current_msg->transfers.next,
struct spi_transfer, transfer_list);
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s :Getting 1st transfer message\n",
__func__);
} else {
data->cur_trans =
list_entry(data->cur_trans->transfer_list.next,
struct spi_transfer, transfer_list);
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s :Getting next transfer message\n",
__func__);
}
@@ -1210,7 +1210,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
data->cur_trans->len = data->save_total_len;
data->current_msg->actual_length += data->cur_trans->len;
- dev_dbg(&data->master->dev,
+ dev_dbg(&data->host->dev,
"%s:data->current_msg->actual_length=%d\n",
__func__, data->current_msg->actual_length);
@@ -1229,7 +1229,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
} while (data->cur_trans != NULL);
out:
- pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH);
+ pch_spi_writereg(data->host, PCH_SSNXCR, SSN_HIGH);
if (data->use_dma)
pch_spi_release_dma(data);
}
@@ -1248,7 +1248,7 @@ static int pch_spi_get_resources(struct pch_spi_board_data *board_dat,
dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__);
/* reset PCH SPI h/w */
- pch_spi_reset(data->master);
+ pch_spi_reset(data->host);
dev_dbg(&board_dat->pdev->dev,
"%s pch_spi_reset invoked successfully\n", __func__);
@@ -1297,22 +1297,22 @@ static int pch_alloc_dma_buf(struct pch_spi_board_data *board_dat,
static int pch_spi_pd_probe(struct platform_device *plat_dev)
{
int ret;
- struct spi_master *master;
+ struct spi_controller *host;
struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev);
struct pch_spi_data *data;
dev_dbg(&plat_dev->dev, "%s:debug\n", __func__);
- master = spi_alloc_master(&board_dat->pdev->dev,
+ host = spi_alloc_host(&board_dat->pdev->dev,
sizeof(struct pch_spi_data));
- if (!master) {
- dev_err(&plat_dev->dev, "spi_alloc_master[%d] failed.\n",
+ if (!host) {
+ dev_err(&plat_dev->dev, "spi_alloc_host[%d] failed.\n",
plat_dev->id);
return -ENOMEM;
}
- data = spi_master_get_devdata(master);
- data->master = master;
+ data = spi_controller_get_devdata(host);
+ data->host = host;
platform_set_drvdata(plat_dev, data);
@@ -1330,13 +1330,13 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
dev_dbg(&plat_dev->dev, "[ch%d] remap_addr=%p\n",
plat_dev->id, data->io_remap_addr);
- /* initialize members of SPI master */
- master->num_chipselect = PCH_MAX_CS;
- master->transfer = pch_spi_transfer;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
- master->max_speed_hz = PCH_MAX_BAUDRATE;
- master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
+ /* initialize members of SPI host */
+ host->num_chipselect = PCH_MAX_CS;
+ host->transfer = pch_spi_transfer;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ host->max_speed_hz = PCH_MAX_BAUDRATE;
+ host->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
data->board_dat = board_dat;
data->plat_dev = plat_dev;
@@ -1365,25 +1365,25 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
}
data->irq_reg_sts = true;
- pch_spi_set_master_mode(master);
+ pch_spi_set_host_mode(host);
if (use_dma) {
dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
ret = pch_alloc_dma_buf(board_dat, data);
if (ret)
- goto err_spi_register_master;
+ goto err_spi_register_controller;
}
- ret = spi_register_master(master);
+ ret = spi_register_controller(host);
if (ret != 0) {
dev_err(&plat_dev->dev,
- "%s spi_register_master FAILED\n", __func__);
- goto err_spi_register_master;
+ "%s spi_register_controller FAILED\n", __func__);
+ goto err_spi_register_controller;
}
return 0;
-err_spi_register_master:
+err_spi_register_controller:
pch_free_dma_buf(board_dat, data);
free_irq(board_dat->pdev->irq, data);
err_request_irq:
@@ -1391,7 +1391,7 @@ err_request_irq:
err_spi_get_resources:
pci_iounmap(board_dat->pdev, data->io_remap_addr);
err_pci_iomap:
- spi_master_put(master);
+ spi_controller_put(host);
return ret;
}
@@ -1427,13 +1427,13 @@ static void pch_spi_pd_remove(struct platform_device *plat_dev)
/* disable interrupts & free IRQ */
if (data->irq_reg_sts) {
/* disable interrupts */
- pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
+ pch_spi_setclr_reg(data->host, PCH_SPCR, 0, PCH_ALL);
data->irq_reg_sts = false;
free_irq(board_dat->pdev->irq, data);
}
pci_iounmap(board_dat->pdev, data->io_remap_addr);
- spi_unregister_master(data->master);
+ spi_unregister_controller(data->host);
}
#ifdef CONFIG_PM
static int pch_spi_pd_suspend(struct platform_device *pd_dev,
@@ -1463,8 +1463,8 @@ static int pch_spi_pd_suspend(struct platform_device *pd_dev,
/* Free IRQ */
if (data->irq_reg_sts) {
/* disable all interrupts */
- pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
- pch_spi_reset(data->master);
+ pch_spi_setclr_reg(data->host, PCH_SPCR, 0, PCH_ALL);
+ pch_spi_reset(data->host);
free_irq(board_dat->pdev->irq, data);
data->irq_reg_sts = false;
@@ -1498,8 +1498,8 @@ static int pch_spi_pd_resume(struct platform_device *pd_dev)
}
/* reset PCH SPI h/w */
- pch_spi_reset(data->master);
- pch_spi_set_master_mode(data->master);
+ pch_spi_reset(data->host);
+ pch_spi_set_host_mode(data->host);
data->irq_reg_sts = true;
}
return 0;
@@ -1514,7 +1514,7 @@ static struct platform_driver pch_spi_pd_driver = {
.name = "pch-spi",
},
.probe = pch_spi_pd_probe,
- .remove_new = pch_spi_pd_remove,
+ .remove = pch_spi_pd_remove,
.suspend = pch_spi_pd_suspend,
.resume = pch_spi_pd_resume
};
diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c
index f5344527af0b..ff2142f87277 100644
--- a/drivers/spi/spi-uniphier.c
+++ b/drivers/spi/spi-uniphier.c
@@ -15,7 +15,7 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SSI_TIMEOUT_MS 2000
#define SSI_POLL_TIMEOUT_US 200
@@ -26,7 +26,7 @@ struct uniphier_spi_priv {
void __iomem *base;
dma_addr_t base_dma_addr;
struct clk *clk;
- struct spi_master *master;
+ struct spi_controller *host;
struct completion xfer_done;
int error;
@@ -127,7 +127,7 @@ static inline void uniphier_spi_irq_disable(struct uniphier_spi_priv *priv,
static void uniphier_spi_set_mode(struct spi_device *spi)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val1, val2;
/*
@@ -180,7 +180,7 @@ static void uniphier_spi_set_mode(struct spi_device *spi)
static void uniphier_spi_set_transfer_size(struct spi_device *spi, int size)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val;
val = readl(priv->base + SSI_TXWDS);
@@ -198,7 +198,7 @@ static void uniphier_spi_set_transfer_size(struct spi_device *spi, int size)
static void uniphier_spi_set_baudrate(struct spi_device *spi,
unsigned int speed)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val, ckdiv;
/*
@@ -217,7 +217,7 @@ static void uniphier_spi_set_baudrate(struct spi_device *spi,
static void uniphier_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val;
priv->error = 0;
@@ -333,7 +333,7 @@ static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv)
static void uniphier_spi_set_cs(struct spi_device *spi, bool enable)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(spi->master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(spi->controller);
u32 val;
val = readl(priv->base + SSI_FPS);
@@ -346,16 +346,16 @@ static void uniphier_spi_set_cs(struct spi_device *spi, bool enable)
writel(val, priv->base + SSI_FPS);
}
-static bool uniphier_spi_can_dma(struct spi_master *master,
+static bool uniphier_spi_can_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
unsigned int bpw = bytes_per_word(priv->bits_per_word);
- if ((!master->dma_tx && !master->dma_rx)
- || (!master->dma_tx && t->tx_buf)
- || (!master->dma_rx && t->rx_buf))
+ if ((!host->dma_tx && !host->dma_rx)
+ || (!host->dma_tx && t->tx_buf)
+ || (!host->dma_rx && t->rx_buf))
return false;
return DIV_ROUND_UP(t->len, bpw) > SSI_FIFO_DEPTH;
@@ -363,33 +363,33 @@ static bool uniphier_spi_can_dma(struct spi_master *master,
static void uniphier_spi_dma_rxcb(void *data)
{
- struct spi_master *master = data;
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct spi_controller *host = data;
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
int state = atomic_fetch_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy);
uniphier_spi_irq_disable(priv, SSI_IE_RXRE);
if (!(state & SSI_DMA_TX_BUSY))
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
}
static void uniphier_spi_dma_txcb(void *data)
{
- struct spi_master *master = data;
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct spi_controller *host = data;
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
int state = atomic_fetch_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy);
uniphier_spi_irq_disable(priv, SSI_IE_TXRE);
if (!(state & SSI_DMA_RX_BUSY))
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
}
-static int uniphier_spi_transfer_one_dma(struct spi_master *master,
+static int uniphier_spi_transfer_one_dma(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL;
int buswidth;
@@ -412,23 +412,23 @@ static int uniphier_spi_transfer_one_dma(struct spi_master *master,
.src_maxburst = SSI_FIFO_BURST_NUM,
};
- dmaengine_slave_config(master->dma_rx, &rxconf);
+ dmaengine_slave_config(host->dma_rx, &rxconf);
rxdesc = dmaengine_prep_slave_sg(
- master->dma_rx,
+ host->dma_rx,
t->rx_sg.sgl, t->rx_sg.nents,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!rxdesc)
goto out_err_prep;
rxdesc->callback = uniphier_spi_dma_rxcb;
- rxdesc->callback_param = master;
+ rxdesc->callback_param = host;
uniphier_spi_irq_enable(priv, SSI_IE_RXRE);
atomic_or(SSI_DMA_RX_BUSY, &priv->dma_busy);
dmaengine_submit(rxdesc);
- dma_async_issue_pending(master->dma_rx);
+ dma_async_issue_pending(host->dma_rx);
}
if (priv->tx_buf) {
@@ -439,23 +439,23 @@ static int uniphier_spi_transfer_one_dma(struct spi_master *master,
.dst_maxburst = SSI_FIFO_BURST_NUM,
};
- dmaengine_slave_config(master->dma_tx, &txconf);
+ dmaengine_slave_config(host->dma_tx, &txconf);
txdesc = dmaengine_prep_slave_sg(
- master->dma_tx,
+ host->dma_tx,
t->tx_sg.sgl, t->tx_sg.nents,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!txdesc)
goto out_err_prep;
txdesc->callback = uniphier_spi_dma_txcb;
- txdesc->callback_param = master;
+ txdesc->callback_param = host;
uniphier_spi_irq_enable(priv, SSI_IE_TXRE);
atomic_or(SSI_DMA_TX_BUSY, &priv->dma_busy);
dmaengine_submit(txdesc);
- dma_async_issue_pending(master->dma_tx);
+ dma_async_issue_pending(host->dma_tx);
}
/* signal that we need to wait for completion */
@@ -463,17 +463,17 @@ static int uniphier_spi_transfer_one_dma(struct spi_master *master,
out_err_prep:
if (rxdesc)
- dmaengine_terminate_sync(master->dma_rx);
+ dmaengine_terminate_sync(host->dma_rx);
return -EINVAL;
}
-static int uniphier_spi_transfer_one_irq(struct spi_master *master,
+static int uniphier_spi_transfer_one_irq(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
- struct device *dev = master->dev.parent;
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
+ struct device *dev = host->dev.parent;
unsigned long time_left;
reinit_completion(&priv->xfer_done);
@@ -495,11 +495,11 @@ static int uniphier_spi_transfer_one_irq(struct spi_master *master,
return priv->error;
}
-static int uniphier_spi_transfer_one_poll(struct spi_master *master,
+static int uniphier_spi_transfer_one_poll(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
int loop = SSI_POLL_TIMEOUT_US * 10;
while (priv->tx_bytes) {
@@ -520,14 +520,14 @@ static int uniphier_spi_transfer_one_poll(struct spi_master *master,
return 0;
irq_transfer:
- return uniphier_spi_transfer_one_irq(master, spi, t);
+ return uniphier_spi_transfer_one_irq(host, spi, t);
}
-static int uniphier_spi_transfer_one(struct spi_master *master,
+static int uniphier_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
unsigned long threshold;
bool use_dma;
@@ -537,9 +537,9 @@ static int uniphier_spi_transfer_one(struct spi_master *master,
uniphier_spi_setup_transfer(spi, t);
- use_dma = master->can_dma ? master->can_dma(master, spi, t) : false;
+ use_dma = host->can_dma ? host->can_dma(host, spi, t) : false;
if (use_dma)
- return uniphier_spi_transfer_one_dma(master, spi, t);
+ return uniphier_spi_transfer_one_dma(host, spi, t);
/*
* If the transfer operation will take longer than
@@ -548,33 +548,33 @@ static int uniphier_spi_transfer_one(struct spi_master *master,
threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz,
USEC_PER_SEC * BITS_PER_BYTE);
if (t->len > threshold)
- return uniphier_spi_transfer_one_irq(master, spi, t);
+ return uniphier_spi_transfer_one_irq(host, spi, t);
else
- return uniphier_spi_transfer_one_poll(master, spi, t);
+ return uniphier_spi_transfer_one_poll(host, spi, t);
}
-static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master)
+static int uniphier_spi_prepare_transfer_hardware(struct spi_controller *host)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
writel(SSI_CTL_EN, priv->base + SSI_CTL);
return 0;
}
-static int uniphier_spi_unprepare_transfer_hardware(struct spi_master *master)
+static int uniphier_spi_unprepare_transfer_hardware(struct spi_controller *host)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
writel(0, priv->base + SSI_CTL);
return 0;
}
-static void uniphier_spi_handle_err(struct spi_master *master,
+static void uniphier_spi_handle_err(struct spi_controller *host,
struct spi_message *msg)
{
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
u32 val;
/* stop running spi transfer */
@@ -587,12 +587,12 @@ static void uniphier_spi_handle_err(struct spi_master *master,
uniphier_spi_irq_disable(priv, SSI_IE_ALL_MASK);
if (atomic_read(&priv->dma_busy) & SSI_DMA_TX_BUSY) {
- dmaengine_terminate_async(master->dma_tx);
+ dmaengine_terminate_async(host->dma_tx);
atomic_andnot(SSI_DMA_TX_BUSY, &priv->dma_busy);
}
if (atomic_read(&priv->dma_busy) & SSI_DMA_RX_BUSY) {
- dmaengine_terminate_async(master->dma_rx);
+ dmaengine_terminate_async(host->dma_rx);
atomic_andnot(SSI_DMA_RX_BUSY, &priv->dma_busy);
}
}
@@ -641,7 +641,7 @@ done:
static int uniphier_spi_probe(struct platform_device *pdev)
{
struct uniphier_spi_priv *priv;
- struct spi_master *master;
+ struct spi_controller *host;
struct resource *res;
struct dma_slave_caps caps;
u32 dma_tx_burst = 0, dma_rx_burst = 0;
@@ -649,20 +649,20 @@ static int uniphier_spi_probe(struct platform_device *pdev)
int irq;
int ret;
- master = spi_alloc_master(&pdev->dev, sizeof(*priv));
- if (!master)
+ host = spi_alloc_host(&pdev->dev, sizeof(*priv));
+ if (!host)
return -ENOMEM;
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
- priv = spi_master_get_devdata(master);
- priv->master = master;
+ priv = spi_controller_get_devdata(host);
+ priv->host = host;
priv->is_save_param = false;
priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->base)) {
ret = PTR_ERR(priv->base);
- goto out_master_put;
+ goto out_host_put;
}
priv->base_dma_addr = res->start;
@@ -670,12 +670,12 @@ static int uniphier_spi_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(priv->clk);
- goto out_master_put;
+ goto out_host_put;
}
ret = clk_prepare_enable(priv->clk);
if (ret)
- goto out_master_put;
+ goto out_host_put;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -694,35 +694,35 @@ static int uniphier_spi_probe(struct platform_device *pdev)
clk_rate = clk_get_rate(priv->clk);
- master->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER);
- master->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER);
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
- master->dev.of_node = pdev->dev.of_node;
- master->bus_num = pdev->id;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ host->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER);
+ host->min_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MAX_CLK_DIVIDER);
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ host->dev.of_node = pdev->dev.of_node;
+ host->bus_num = pdev->id;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
- master->set_cs = uniphier_spi_set_cs;
- master->transfer_one = uniphier_spi_transfer_one;
- master->prepare_transfer_hardware
+ host->set_cs = uniphier_spi_set_cs;
+ host->transfer_one = uniphier_spi_transfer_one;
+ host->prepare_transfer_hardware
= uniphier_spi_prepare_transfer_hardware;
- master->unprepare_transfer_hardware
+ host->unprepare_transfer_hardware
= uniphier_spi_unprepare_transfer_hardware;
- master->handle_err = uniphier_spi_handle_err;
- master->can_dma = uniphier_spi_can_dma;
+ host->handle_err = uniphier_spi_handle_err;
+ host->can_dma = uniphier_spi_can_dma;
- master->num_chipselect = 1;
- master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
+ host->num_chipselect = 1;
+ host->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
- master->dma_tx = dma_request_chan(&pdev->dev, "tx");
- if (IS_ERR_OR_NULL(master->dma_tx)) {
- if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) {
+ host->dma_tx = dma_request_chan(&pdev->dev, "tx");
+ if (IS_ERR_OR_NULL(host->dma_tx)) {
+ if (PTR_ERR(host->dma_tx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto out_disable_clk;
}
- master->dma_tx = NULL;
+ host->dma_tx = NULL;
dma_tx_burst = INT_MAX;
} else {
- ret = dma_get_slave_caps(master->dma_tx, &caps);
+ ret = dma_get_slave_caps(host->dma_tx, &caps);
if (ret) {
dev_err(&pdev->dev, "failed to get TX DMA capacities: %d\n",
ret);
@@ -731,16 +731,16 @@ static int uniphier_spi_probe(struct platform_device *pdev)
dma_tx_burst = caps.max_burst;
}
- master->dma_rx = dma_request_chan(&pdev->dev, "rx");
- if (IS_ERR_OR_NULL(master->dma_rx)) {
- if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
+ host->dma_rx = dma_request_chan(&pdev->dev, "rx");
+ if (IS_ERR_OR_NULL(host->dma_rx)) {
+ if (PTR_ERR(host->dma_rx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto out_release_dma;
}
- master->dma_rx = NULL;
+ host->dma_rx = NULL;
dma_rx_burst = INT_MAX;
} else {
- ret = dma_get_slave_caps(master->dma_rx, &caps);
+ ret = dma_get_slave_caps(host->dma_rx, &caps);
if (ret) {
dev_err(&pdev->dev, "failed to get RX DMA capacities: %d\n",
ret);
@@ -749,41 +749,41 @@ static int uniphier_spi_probe(struct platform_device *pdev)
dma_rx_burst = caps.max_burst;
}
- master->max_dma_len = min(dma_tx_burst, dma_rx_burst);
+ host->max_dma_len = min(dma_tx_burst, dma_rx_burst);
- ret = devm_spi_register_master(&pdev->dev, master);
+ ret = devm_spi_register_controller(&pdev->dev, host);
if (ret)
goto out_release_dma;
return 0;
out_release_dma:
- if (!IS_ERR_OR_NULL(master->dma_rx)) {
- dma_release_channel(master->dma_rx);
- master->dma_rx = NULL;
+ if (!IS_ERR_OR_NULL(host->dma_rx)) {
+ dma_release_channel(host->dma_rx);
+ host->dma_rx = NULL;
}
- if (!IS_ERR_OR_NULL(master->dma_tx)) {
- dma_release_channel(master->dma_tx);
- master->dma_tx = NULL;
+ if (!IS_ERR_OR_NULL(host->dma_tx)) {
+ dma_release_channel(host->dma_tx);
+ host->dma_tx = NULL;
}
out_disable_clk:
clk_disable_unprepare(priv->clk);
-out_master_put:
- spi_master_put(master);
+out_host_put:
+ spi_controller_put(host);
return ret;
}
static void uniphier_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct uniphier_spi_priv *priv = spi_controller_get_devdata(host);
- if (master->dma_tx)
- dma_release_channel(master->dma_tx);
- if (master->dma_rx)
- dma_release_channel(master->dma_rx);
+ if (host->dma_tx)
+ dma_release_channel(host->dma_tx);
+ if (host->dma_rx)
+ dma_release_channel(host->dma_rx);
clk_disable_unprepare(priv->clk);
}
@@ -796,7 +796,7 @@ MODULE_DEVICE_TABLE(of, uniphier_spi_match);
static struct platform_driver uniphier_spi_driver = {
.probe = uniphier_spi_probe,
- .remove_new = uniphier_spi_remove,
+ .remove = uniphier_spi_remove,
.driver = {
.name = "uniphier-spi",
.of_match_table = uniphier_spi_match,
diff --git a/drivers/spi/spi-virtio.c b/drivers/spi/spi-virtio.c
new file mode 100644
index 000000000000..2acb929b2c69
--- /dev/null
+++ b/drivers/spi/spi-virtio.c
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SPI bus driver for the Virtio SPI controller
+ * Copyright (C) 2023 OpenSynergy GmbH
+ * Copyright (C) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/stddef.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_spi.h>
+
+#define VIRTIO_SPI_MODE_MASK \
+ (SPI_MODE_X_MASK | SPI_CS_HIGH | SPI_LSB_FIRST)
+
+struct virtio_spi_req {
+ struct completion completion;
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ struct spi_transfer_head transfer_head ____cacheline_aligned;
+ struct spi_transfer_result result;
+};
+
+struct virtio_spi_priv {
+ /* The virtio device we're associated with */
+ struct virtio_device *vdev;
+ /* Pointer to the virtqueue */
+ struct virtqueue *vq;
+ /* Copy of config space mode_func_supported */
+ u32 mode_func_supported;
+ /* Copy of config space max_freq_hz */
+ u32 max_freq_hz;
+};
+
+static void virtio_spi_msg_done(struct virtqueue *vq)
+{
+ struct virtio_spi_req *req;
+ unsigned int len;
+
+ while ((req = virtqueue_get_buf(vq, &len)))
+ complete(&req->completion);
+}
+
+/*
+ * virtio_spi_set_delays - Set delay parameters for SPI transfer
+ *
+ * This function sets various delay parameters for SPI transfer,
+ * including delay after CS asserted, timing intervals between
+ * adjacent words within a transfer, delay before and after CS
+ * deasserted. It converts these delay parameters to nanoseconds
+ * using spi_delay_to_ns and stores the results in spi_transfer_head
+ * structure.
+ * If the conversion fails, the function logs a warning message and
+ * returns an error code.
+ * . . . . . . . . . .
+ * Delay + A + + B + + C + D + E + F + A +
+ * . . . . . . . . . .
+ * ___. . . . . . .___.___. .
+ * CS# |___.______.____.____.___.___| . |___._____________
+ * . . . . . . . . . .
+ * . . . . . . . . . .
+ * SCLK__.___.___NNN_____NNN__.___.___.___.___.___.___NNN_______
+ *
+ * NOTE: 1st transfer has two words, the delay between these two words are
+ * 'B' in the diagram.
+ *
+ * A => struct spi_device -> cs_setup
+ * B => max{struct spi_transfer -> word_delay, struct spi_device -> word_delay}
+ * Note: spi_device and spi_transfer both have word_delay, Linux
+ * choose the bigger one, refer to _spi_xfer_word_delay_update function
+ * C => struct spi_transfer -> delay
+ * D => struct spi_device -> cs_hold
+ * E => struct spi_device -> cs_inactive
+ * F => struct spi_transfer -> cs_change_delay
+ *
+ * So the corresponding relationship:
+ * A <===> cs_setup_ns (after CS asserted)
+ * B <===> word_delay_ns (delay between adjacent words within a transfer)
+ * C+D <===> cs_delay_hold_ns (before CS deasserted)
+ * E+F <===> cs_change_delay_inactive_ns (after CS deasserted, these two
+ * values are also recommended in the Linux driver to be added up)
+ */
+static int virtio_spi_set_delays(struct spi_transfer_head *th,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ int cs_setup;
+ int cs_word_delay_xfer;
+ int cs_word_delay_spi;
+ int delay;
+ int cs_hold;
+ int cs_inactive;
+ int cs_change_delay;
+
+ cs_setup = spi_delay_to_ns(&spi->cs_setup, xfer);
+ if (cs_setup < 0) {
+ dev_warn(&spi->dev, "Cannot convert cs_setup\n");
+ return cs_setup;
+ }
+ th->cs_setup_ns = cpu_to_le32(cs_setup);
+
+ cs_word_delay_xfer = spi_delay_to_ns(&xfer->word_delay, xfer);
+ if (cs_word_delay_xfer < 0) {
+ dev_warn(&spi->dev, "Cannot convert cs_word_delay_xfer\n");
+ return cs_word_delay_xfer;
+ }
+ cs_word_delay_spi = spi_delay_to_ns(&spi->word_delay, xfer);
+ if (cs_word_delay_spi < 0) {
+ dev_warn(&spi->dev, "Cannot convert cs_word_delay_spi\n");
+ return cs_word_delay_spi;
+ }
+
+ th->word_delay_ns = cpu_to_le32(max(cs_word_delay_spi, cs_word_delay_xfer));
+
+ delay = spi_delay_to_ns(&xfer->delay, xfer);
+ if (delay < 0) {
+ dev_warn(&spi->dev, "Cannot convert delay\n");
+ return delay;
+ }
+ cs_hold = spi_delay_to_ns(&spi->cs_hold, xfer);
+ if (cs_hold < 0) {
+ dev_warn(&spi->dev, "Cannot convert cs_hold\n");
+ return cs_hold;
+ }
+ th->cs_delay_hold_ns = cpu_to_le32(delay + cs_hold);
+
+ cs_inactive = spi_delay_to_ns(&spi->cs_inactive, xfer);
+ if (cs_inactive < 0) {
+ dev_warn(&spi->dev, "Cannot convert cs_inactive\n");
+ return cs_inactive;
+ }
+ cs_change_delay = spi_delay_to_ns(&xfer->cs_change_delay, xfer);
+ if (cs_change_delay < 0) {
+ dev_warn(&spi->dev, "Cannot convert cs_change_delay\n");
+ return cs_change_delay;
+ }
+ th->cs_change_delay_inactive_ns =
+ cpu_to_le32(cs_inactive + cs_change_delay);
+
+ return 0;
+}
+
+static int virtio_spi_transfer_one(struct spi_controller *ctrl,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct virtio_spi_priv *priv = spi_controller_get_devdata(ctrl);
+ struct virtio_spi_req *spi_req __free(kfree) = NULL;
+ struct spi_transfer_head *th;
+ struct scatterlist sg_out_head, sg_out_payload;
+ struct scatterlist sg_in_result, sg_in_payload;
+ struct scatterlist *sgs[4];
+ unsigned int outcnt = 0;
+ unsigned int incnt = 0;
+ int ret;
+
+ spi_req = kzalloc(sizeof(*spi_req), GFP_KERNEL);
+ if (!spi_req)
+ return -ENOMEM;
+
+ init_completion(&spi_req->completion);
+
+ th = &spi_req->transfer_head;
+
+ /* Fill struct spi_transfer_head */
+ th->chip_select_id = spi_get_chipselect(spi, 0);
+ th->bits_per_word = spi->bits_per_word;
+ th->cs_change = xfer->cs_change;
+ th->tx_nbits = xfer->tx_nbits;
+ th->rx_nbits = xfer->rx_nbits;
+ th->reserved[0] = 0;
+ th->reserved[1] = 0;
+ th->reserved[2] = 0;
+
+ static_assert(VIRTIO_SPI_CPHA == SPI_CPHA,
+ "VIRTIO_SPI_CPHA must match SPI_CPHA");
+ static_assert(VIRTIO_SPI_CPOL == SPI_CPOL,
+ "VIRTIO_SPI_CPOL must match SPI_CPOL");
+ static_assert(VIRTIO_SPI_CS_HIGH == SPI_CS_HIGH,
+ "VIRTIO_SPI_CS_HIGH must match SPI_CS_HIGH");
+ static_assert(VIRTIO_SPI_MODE_LSB_FIRST == SPI_LSB_FIRST,
+ "VIRTIO_SPI_MODE_LSB_FIRST must match SPI_LSB_FIRST");
+
+ th->mode = cpu_to_le32(spi->mode & VIRTIO_SPI_MODE_MASK);
+ if (spi->mode & SPI_LOOP)
+ th->mode |= cpu_to_le32(VIRTIO_SPI_MODE_LOOP);
+
+ th->freq = cpu_to_le32(xfer->speed_hz);
+
+ ret = virtio_spi_set_delays(th, spi, xfer);
+ if (ret)
+ goto msg_done;
+
+ /* Set buffers */
+ spi_req->tx_buf = xfer->tx_buf;
+ spi_req->rx_buf = xfer->rx_buf;
+
+ /* Prepare sending of virtio message */
+ init_completion(&spi_req->completion);
+
+ sg_init_one(&sg_out_head, th, sizeof(*th));
+ sgs[outcnt] = &sg_out_head;
+ outcnt++;
+
+ if (spi_req->tx_buf) {
+ sg_init_one(&sg_out_payload, spi_req->tx_buf, xfer->len);
+ sgs[outcnt] = &sg_out_payload;
+ outcnt++;
+ }
+
+ if (spi_req->rx_buf) {
+ sg_init_one(&sg_in_payload, spi_req->rx_buf, xfer->len);
+ sgs[outcnt] = &sg_in_payload;
+ incnt++;
+ }
+
+ sg_init_one(&sg_in_result, &spi_req->result,
+ sizeof(struct spi_transfer_result));
+ sgs[outcnt + incnt] = &sg_in_result;
+ incnt++;
+
+ ret = virtqueue_add_sgs(priv->vq, sgs, outcnt, incnt, spi_req,
+ GFP_KERNEL);
+ if (ret)
+ goto msg_done;
+
+ /* Simple implementation: There can be only one transfer in flight */
+ virtqueue_kick(priv->vq);
+
+ wait_for_completion(&spi_req->completion);
+
+ /* Read result from message and translate return code */
+ switch (spi_req->result.result) {
+ case VIRTIO_SPI_TRANS_OK:
+ break;
+ case VIRTIO_SPI_PARAM_ERR:
+ ret = -EINVAL;
+ break;
+ case VIRTIO_SPI_TRANS_ERR:
+ ret = -EIO;
+ break;
+ default:
+ ret = -EIO;
+ break;
+ }
+
+msg_done:
+ if (ret)
+ ctrl->cur_msg->status = ret;
+
+ return ret;
+}
+
+static void virtio_spi_read_config(struct virtio_device *vdev)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(&vdev->dev);
+ struct virtio_spi_priv *priv = vdev->priv;
+ u8 cs_max_number;
+ u8 tx_nbits_supported;
+ u8 rx_nbits_supported;
+
+ cs_max_number = virtio_cread8(vdev, offsetof(struct virtio_spi_config,
+ cs_max_number));
+ ctrl->num_chipselect = cs_max_number;
+
+ /* Set the mode bits which are understood by this driver */
+ priv->mode_func_supported =
+ virtio_cread32(vdev, offsetof(struct virtio_spi_config,
+ mode_func_supported));
+ ctrl->mode_bits = priv->mode_func_supported &
+ (VIRTIO_SPI_CS_HIGH | VIRTIO_SPI_MODE_LSB_FIRST);
+ if (priv->mode_func_supported & VIRTIO_SPI_MF_SUPPORT_CPHA_1)
+ ctrl->mode_bits |= VIRTIO_SPI_CPHA;
+ if (priv->mode_func_supported & VIRTIO_SPI_MF_SUPPORT_CPOL_1)
+ ctrl->mode_bits |= VIRTIO_SPI_CPOL;
+ if (priv->mode_func_supported & VIRTIO_SPI_MF_SUPPORT_LSB_FIRST)
+ ctrl->mode_bits |= SPI_LSB_FIRST;
+ if (priv->mode_func_supported & VIRTIO_SPI_MF_SUPPORT_LOOPBACK)
+ ctrl->mode_bits |= SPI_LOOP;
+ tx_nbits_supported =
+ virtio_cread8(vdev, offsetof(struct virtio_spi_config,
+ tx_nbits_supported));
+ if (tx_nbits_supported & VIRTIO_SPI_RX_TX_SUPPORT_DUAL)
+ ctrl->mode_bits |= SPI_TX_DUAL;
+ if (tx_nbits_supported & VIRTIO_SPI_RX_TX_SUPPORT_QUAD)
+ ctrl->mode_bits |= SPI_TX_QUAD;
+ if (tx_nbits_supported & VIRTIO_SPI_RX_TX_SUPPORT_OCTAL)
+ ctrl->mode_bits |= SPI_TX_OCTAL;
+ rx_nbits_supported =
+ virtio_cread8(vdev, offsetof(struct virtio_spi_config,
+ rx_nbits_supported));
+ if (rx_nbits_supported & VIRTIO_SPI_RX_TX_SUPPORT_DUAL)
+ ctrl->mode_bits |= SPI_RX_DUAL;
+ if (rx_nbits_supported & VIRTIO_SPI_RX_TX_SUPPORT_QUAD)
+ ctrl->mode_bits |= SPI_RX_QUAD;
+ if (rx_nbits_supported & VIRTIO_SPI_RX_TX_SUPPORT_OCTAL)
+ ctrl->mode_bits |= SPI_RX_OCTAL;
+
+ ctrl->bits_per_word_mask =
+ virtio_cread32(vdev, offsetof(struct virtio_spi_config,
+ bits_per_word_mask));
+
+ priv->max_freq_hz =
+ virtio_cread32(vdev, offsetof(struct virtio_spi_config,
+ max_freq_hz));
+}
+
+static int virtio_spi_find_vqs(struct virtio_spi_priv *priv)
+{
+ struct virtqueue *vq;
+
+ vq = virtio_find_single_vq(priv->vdev, virtio_spi_msg_done, "spi-rq");
+ if (IS_ERR(vq))
+ return PTR_ERR(vq);
+ priv->vq = vq;
+ return 0;
+}
+
+/* Function must not be called before virtio_spi_find_vqs() has been run */
+static void virtio_spi_del_vq(void *data)
+{
+ struct virtio_device *vdev = data;
+
+ virtio_reset_device(vdev);
+ vdev->config->del_vqs(vdev);
+}
+
+static int virtio_spi_probe(struct virtio_device *vdev)
+{
+ struct virtio_spi_priv *priv;
+ struct spi_controller *ctrl;
+ int ret;
+
+ ctrl = devm_spi_alloc_host(&vdev->dev, sizeof(*priv));
+ if (!ctrl)
+ return -ENOMEM;
+
+ priv = spi_controller_get_devdata(ctrl);
+ priv->vdev = vdev;
+ vdev->priv = priv;
+
+ device_set_node(&ctrl->dev, dev_fwnode(&vdev->dev));
+
+ dev_set_drvdata(&vdev->dev, ctrl);
+
+ virtio_spi_read_config(vdev);
+
+ ctrl->transfer_one = virtio_spi_transfer_one;
+
+ ret = virtio_spi_find_vqs(priv);
+ if (ret)
+ return dev_err_probe(&vdev->dev, ret, "Cannot setup virtqueues\n");
+
+ /* Register cleanup for virtqueues using devm */
+ ret = devm_add_action_or_reset(&vdev->dev, virtio_spi_del_vq, vdev);
+ if (ret)
+ return dev_err_probe(&vdev->dev, ret, "Cannot register virtqueue cleanup\n");
+
+ /* Use devm version to register controller */
+ ret = devm_spi_register_controller(&vdev->dev, ctrl);
+ if (ret)
+ return dev_err_probe(&vdev->dev, ret, "Cannot register controller\n");
+
+ return 0;
+}
+
+static int virtio_spi_freeze(struct device *dev)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct virtio_device *vdev = dev_to_virtio(dev);
+ int ret;
+
+ ret = spi_controller_suspend(ctrl);
+ if (ret) {
+ dev_warn(dev, "cannot suspend controller (%d)\n", ret);
+ return ret;
+ }
+
+ virtio_spi_del_vq(vdev);
+ return 0;
+}
+
+static int virtio_spi_restore(struct device *dev)
+{
+ struct spi_controller *ctrl = dev_get_drvdata(dev);
+ struct virtio_device *vdev = dev_to_virtio(dev);
+ int ret;
+
+ ret = virtio_spi_find_vqs(vdev->priv);
+ if (ret) {
+ dev_err(dev, "problem starting vqueue (%d)\n", ret);
+ return ret;
+ }
+
+ ret = spi_controller_resume(ctrl);
+ if (ret)
+ dev_err(dev, "problem resuming controller (%d)\n", ret);
+
+ return ret;
+}
+
+static struct virtio_device_id virtio_spi_id_table[] = {
+ { VIRTIO_ID_SPI, VIRTIO_DEV_ANY_ID },
+ {}
+};
+MODULE_DEVICE_TABLE(virtio, virtio_spi_id_table);
+
+static const struct dev_pm_ops virtio_spi_pm_ops = {
+ .freeze = pm_sleep_ptr(virtio_spi_freeze),
+ .restore = pm_sleep_ptr(virtio_spi_restore),
+};
+
+static struct virtio_driver virtio_spi_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .pm = &virtio_spi_pm_ops,
+ },
+ .id_table = virtio_spi_id_table,
+ .probe = virtio_spi_probe,
+};
+module_virtio_driver(virtio_spi_driver);
+
+MODULE_AUTHOR("OpenSynergy GmbH");
+MODULE_AUTHOR("Haixu Cui <quic_haixcui@quicinc.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Virtio SPI bus driver");
diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c
index f15312fdcdaf..a9aee2a6c7dc 100644
--- a/drivers/spi/spi-wpcm-fiu.c
+++ b/drivers/spi/spi-wpcm-fiu.c
@@ -3,9 +3,8 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi-mem.h>
@@ -362,7 +361,7 @@ static int wpcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
wpcm_fiu_stall_host(fiu, false);
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
static int wpcm_fiu_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
@@ -379,7 +378,7 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
int cs = spi_get_chipselect(desc->mem->spi, 0);
if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
/*
* Unfortunately, FIU only supports a 16 MiB direct mapping window (per
@@ -388,11 +387,11 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
* flashes that are bigger than 16 MiB.
*/
if (desc->info.offset + desc->info.length > MAX_MEMORY_SIZE_PER_CS)
- return -ENOTSUPP;
+ return -EINVAL;
/* Don't read past the memory window */
if (cs * MAX_MEMORY_SIZE_PER_CS + desc->info.offset + desc->info.length > fiu->memory_size)
- return -ENOTSUPP;
+ return -EINVAL;
return 0;
}
@@ -442,19 +441,17 @@ static int wpcm_fiu_probe(struct platform_device *pdev)
struct wpcm_fiu_spi *fiu;
struct resource *res;
- ctrl = devm_spi_alloc_master(dev, sizeof(*fiu));
+ ctrl = devm_spi_alloc_host(dev, sizeof(*fiu));
if (!ctrl)
return -ENOMEM;
fiu = spi_controller_get_devdata(ctrl);
fiu->dev = dev;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
- fiu->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(fiu->regs)) {
- dev_err(dev, "Failed to map registers\n");
- return PTR_ERR(fiu->regs);
- }
+ fiu->regs = devm_platform_ioremap_resource_byname(pdev, "control");
+ if (IS_ERR(fiu->regs))
+ return dev_err_probe(dev, PTR_ERR(fiu->regs),
+ "Failed to map registers\n");
fiu->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(fiu->clk))
@@ -463,10 +460,9 @@ static int wpcm_fiu_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory");
fiu->memory = devm_ioremap_resource(dev, res);
fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL);
- if (IS_ERR(fiu->memory)) {
- dev_err(dev, "Failed to map flash memory window\n");
- return PTR_ERR(fiu->memory);
- }
+ if (IS_ERR(fiu->memory))
+ return dev_err_probe(dev, PTR_ERR(fiu->memory),
+ "Failed to map flash memory window\n");
fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm");
diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c
index ae6218bcd02a..33b78c537520 100644
--- a/drivers/spi/spi-xcomm.c
+++ b/drivers/spi/spi-xcomm.c
@@ -10,8 +10,9 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
+#include <linux/gpio/driver.h>
#include <linux/spi/spi.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SPI_XCOMM_SETTINGS_LEN_OFFSET 10
#define SPI_XCOMM_SETTINGS_3WIRE BIT(6)
@@ -26,24 +27,63 @@
#define SPI_XCOMM_CMD_UPDATE_CONFIG 0x03
#define SPI_XCOMM_CMD_WRITE 0x04
+#define SPI_XCOMM_CMD_GPIO_SET 0x05
#define SPI_XCOMM_CLOCK 48000000
struct spi_xcomm {
struct i2c_client *i2c;
- uint16_t settings;
- uint16_t chipselect;
+ struct gpio_chip gc;
+
+ u16 settings;
+ u16 chipselect;
unsigned int current_speed;
- uint8_t buf[63];
+ u8 buf[63];
};
+static int spi_xcomm_gpio_set_value(struct gpio_chip *chip,
+ unsigned int offset, int val)
+{
+ struct spi_xcomm *spi_xcomm = gpiochip_get_data(chip);
+ unsigned char buf[2];
+
+ buf[0] = SPI_XCOMM_CMD_GPIO_SET;
+ buf[1] = !!val;
+
+ return i2c_master_send(spi_xcomm->i2c, buf, 2);
+}
+
+static int spi_xcomm_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int spi_xcomm_gpio_add(struct spi_xcomm *spi_xcomm)
+{
+ struct device *dev = &spi_xcomm->i2c->dev;
+
+ if (!IS_ENABLED(CONFIG_GPIOLIB))
+ return 0;
+
+ spi_xcomm->gc.get_direction = spi_xcomm_gpio_get_direction;
+ spi_xcomm->gc.set = spi_xcomm_gpio_set_value;
+ spi_xcomm->gc.can_sleep = 1;
+ spi_xcomm->gc.base = -1;
+ spi_xcomm->gc.ngpio = 1;
+ spi_xcomm->gc.label = spi_xcomm->i2c->name;
+ spi_xcomm->gc.owner = THIS_MODULE;
+
+ return devm_gpiochip_add_data(dev, &spi_xcomm->gc, spi_xcomm);
+}
+
static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len)
{
- uint16_t settings;
- uint8_t *buf = spi_xcomm->buf;
+ u16 settings;
+ u8 *buf = spi_xcomm->buf;
settings = spi_xcomm->settings;
settings |= len << SPI_XCOMM_SETTINGS_LEN_OFFSET;
@@ -56,10 +96,10 @@ static int spi_xcomm_sync_config(struct spi_xcomm *spi_xcomm, unsigned int len)
}
static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
- struct spi_device *spi, int is_active)
+ struct spi_device *spi, int is_active)
{
unsigned long cs = spi_get_chipselect(spi, 0);
- uint16_t chipselect = spi_xcomm->chipselect;
+ u16 chipselect = spi_xcomm->chipselect;
if (is_active)
chipselect |= BIT(cs);
@@ -70,7 +110,8 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
}
static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
- struct spi_device *spi, struct spi_transfer *t, unsigned int *settings)
+ struct spi_device *spi, struct spi_transfer *t,
+ unsigned int *settings)
{
if (t->len > 62)
return -EINVAL;
@@ -108,7 +149,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
}
static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm,
- struct spi_device *spi, struct spi_transfer *t)
+ struct spi_device *spi, struct spi_transfer *t)
{
int ret;
@@ -119,26 +160,26 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm,
ret = i2c_master_send(spi_xcomm->i2c, spi_xcomm->buf, t->len + 1);
if (ret < 0)
return ret;
- else if (ret != t->len + 1)
+ if (ret != t->len + 1)
return -EIO;
} else if (t->rx_buf) {
ret = i2c_master_recv(spi_xcomm->i2c, t->rx_buf, t->len);
if (ret < 0)
return ret;
- else if (ret != t->len)
+ if (ret != t->len)
return -EIO;
}
return t->len;
}
-static int spi_xcomm_transfer_one(struct spi_master *master,
- struct spi_message *msg)
+static int spi_xcomm_transfer_one(struct spi_controller *host,
+ struct spi_message *msg)
{
- struct spi_xcomm *spi_xcomm = spi_master_get_devdata(master);
+ struct spi_xcomm *spi_xcomm = spi_controller_get_devdata(host);
unsigned int settings = spi_xcomm->settings;
struct spi_device *spi = msg->spi;
- unsigned cs_change = 0;
+ unsigned int cs_change = 0;
struct spi_transfer *t;
bool is_first = true;
int status = 0;
@@ -147,7 +188,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
spi_xcomm_chipselect(spi_xcomm, spi, true);
list_for_each_entry(t, &msg->transfers, transfer_list) {
-
if (!t->tx_buf && !t->rx_buf && t->len) {
status = -EINVAL;
break;
@@ -197,7 +237,7 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
spi_xcomm_chipselect(spi_xcomm, spi, false);
msg->status = status;
- spi_finalize_current_message(master);
+ spi_finalize_current_message(host);
return status;
}
@@ -205,29 +245,28 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
static int spi_xcomm_probe(struct i2c_client *i2c)
{
struct spi_xcomm *spi_xcomm;
- struct spi_master *master;
+ struct spi_controller *host;
int ret;
- master = spi_alloc_master(&i2c->dev, sizeof(*spi_xcomm));
- if (!master)
+ host = devm_spi_alloc_host(&i2c->dev, sizeof(*spi_xcomm));
+ if (!host)
return -ENOMEM;
- spi_xcomm = spi_master_get_devdata(master);
+ spi_xcomm = spi_controller_get_devdata(host);
spi_xcomm->i2c = i2c;
- master->num_chipselect = 16;
- master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_3WIRE;
- master->bits_per_word_mask = SPI_BPW_MASK(8);
- master->flags = SPI_MASTER_HALF_DUPLEX;
- master->transfer_one_message = spi_xcomm_transfer_one;
- master->dev.of_node = i2c->dev.of_node;
- i2c_set_clientdata(i2c, master);
+ host->num_chipselect = 16;
+ host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_3WIRE;
+ host->bits_per_word_mask = SPI_BPW_MASK(8);
+ host->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ host->transfer_one_message = spi_xcomm_transfer_one;
+ host->dev.of_node = i2c->dev.of_node;
- ret = devm_spi_register_master(&i2c->dev, master);
+ ret = devm_spi_register_controller(&i2c->dev, host);
if (ret < 0)
- spi_master_put(master);
+ return ret;
- return ret;
+ return spi_xcomm_gpio_add(spi_xcomm);
}
static const struct i2c_device_id spi_xcomm_ids[] = {
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 8e6e3876aa9a..c86dc56f38b4 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Xilinx SPI controller driver (master mode only)
+ * Xilinx SPI controller driver (host mode only)
*
* Author: MontaVista Software, Inc.
* source@mvista.com
@@ -83,14 +83,14 @@ struct xilinx_spi {
void __iomem *regs; /* virt. address of the control registers */
int irq;
- bool force_irq; /* force irq to setup master inhibit */
+ bool force_irq; /* force irq to setup host inhibit */
u8 *rx_ptr; /* pointer in the Tx buffer */
const u8 *tx_ptr; /* pointer in the Rx buffer */
u8 bytes_per_word;
int buffer_size; /* buffer size in words */
u32 cs_inactive; /* Level of the CS pins when inactive*/
- unsigned int (*read_fn)(void __iomem *);
- void (*write_fn)(u32, void __iomem *);
+ unsigned int (*read_fn)(void __iomem *addr);
+ void (*write_fn)(u32 val, void __iomem *addr);
};
static void xspi_write32(u32 val, void __iomem *addr)
@@ -174,10 +174,10 @@ static void xspi_init_hw(struct xilinx_spi *xspi)
regs_base + XIPIF_V123B_IIER_OFFSET);
/* Disable the global IPIF interrupt */
xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
- /* Deselect the slave on the SPI bus */
+ /* Deselect the Target on the SPI bus */
xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET);
- /* Disable the transmitter, enable Manual Slave Select Assertion,
- * put SPI controller into master mode, and enable it */
+ /* Disable the transmitter, enable Manual Target Select Assertion,
+ * put SPI controller into host mode, and enable it */
xspi->write_fn(XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE |
XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET,
regs_base + XSPI_CR_OFFSET);
@@ -185,12 +185,12 @@ static void xspi_init_hw(struct xilinx_spi *xspi)
static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+ struct xilinx_spi *xspi = spi_controller_get_devdata(spi->controller);
u16 cr;
u32 cs;
if (is_on == BITBANG_CS_INACTIVE) {
- /* Deselect the slave on the SPI bus */
+ /* Deselect the target on the SPI bus */
xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET);
return;
}
@@ -225,7 +225,7 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+ struct xilinx_spi *xspi = spi_controller_get_devdata(spi->controller);
if (spi->mode & SPI_CS_HIGH)
xspi->cs_inactive &= ~BIT(spi_get_chipselect(spi, 0));
@@ -237,7 +237,7 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+ struct xilinx_spi *xspi = spi_controller_get_devdata(spi->controller);
int remaining_words; /* the number of words left to transfer */
bool use_irq = false;
u16 cr = 0;
@@ -251,6 +251,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
if (xspi->irq >= 0 &&
(xspi->force_irq || remaining_words > xspi->buffer_size)) {
u32 isr;
+
use_irq = true;
/* Inhibit irq to avoid spurious irqs on tx_empty*/
cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
@@ -299,7 +300,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
/* Read out all the data from the Rx FIFO */
rx_words = n_words;
- stalled = 10;
+ stalled = 32;
while (rx_words) {
if (rx_words == n_words && !(stalled--) &&
!(sr & XSPI_SR_TX_EMPTY_MASK) &&
@@ -335,9 +336,9 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
}
-/* This driver supports single master mode only. Hence Tx FIFO Empty
+/* This driver supports single host mode only. Hence Tx FIFO Empty
* is the only interrupt we care about.
- * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode
+ * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Target Mode
* Fault are not to happen.
*/
static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
@@ -393,7 +394,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
struct xspi_platform_data *pdata;
struct resource *res;
int ret, num_cs = 0, bits_per_word;
- struct spi_master *master;
+ struct spi_controller *host;
bool force_irq = false;
u32 tmp;
u8 i;
@@ -415,26 +416,26 @@ static int xilinx_spi_probe(struct platform_device *pdev)
if (!num_cs) {
dev_err(&pdev->dev,
- "Missing slave select configuration data\n");
+ "Missing target select configuration data\n");
return -EINVAL;
}
if (num_cs > XILINX_SPI_MAX_CS) {
- dev_err(&pdev->dev, "Invalid number of spi slaves\n");
+ dev_err(&pdev->dev, "Invalid number of spi targets\n");
return -EINVAL;
}
- master = devm_spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(struct xilinx_spi));
+ if (!host)
return -ENODEV;
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP |
- SPI_CS_HIGH;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP |
+ SPI_CS_HIGH;
- xspi = spi_master_get_devdata(master);
+ xspi = spi_controller_get_devdata(host);
xspi->cs_inactive = 0xffffffff;
- xspi->bitbang.master = master;
+ xspi->bitbang.ctlr = host;
xspi->bitbang.chipselect = xilinx_spi_chipselect;
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
@@ -444,9 +445,9 @@ static int xilinx_spi_probe(struct platform_device *pdev)
if (IS_ERR(xspi->regs))
return PTR_ERR(xspi->regs);
- master->bus_num = pdev->id;
- master->num_chipselect = num_cs;
- master->dev.of_node = pdev->dev.of_node;
+ host->bus_num = pdev->id;
+ host->num_chipselect = num_cs;
+ host->dev.of_node = pdev->dev.of_node;
/*
* Detect endianess on the IP via loop bit in CR. Detection
@@ -466,7 +467,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
xspi->write_fn = xspi_write32_be;
}
- master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
+ host->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
xspi->bytes_per_word = bits_per_word / 8;
xspi->buffer_size = xilinx_spi_find_buffer_size(xspi);
@@ -496,17 +497,17 @@ static int xilinx_spi_probe(struct platform_device *pdev)
if (pdata) {
for (i = 0; i < pdata->num_devices; i++)
- spi_new_device(master, pdata->devices + i);
+ spi_new_device(host, pdata->devices + i);
}
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
return 0;
}
static void xilinx_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct xilinx_spi *xspi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct xilinx_spi *xspi = spi_controller_get_devdata(host);
void __iomem *regs_base = xspi->regs;
spi_bitbang_stop(&xspi->bitbang);
@@ -516,7 +517,7 @@ static void xilinx_spi_remove(struct platform_device *pdev)
/* Disable the global IPIF interrupt */
xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
- spi_master_put(xspi->bitbang.master);
+ spi_controller_put(xspi->bitbang.ctlr);
}
/* work with hotplug and coldplug */
@@ -524,7 +525,7 @@ MODULE_ALIAS("platform:" XILINX_SPI_NAME);
static struct platform_driver xilinx_spi_driver = {
.probe = xilinx_spi_probe,
- .remove_new = xilinx_spi_remove,
+ .remove = xilinx_spi_remove,
.driver = {
.name = XILINX_SPI_NAME,
.of_match_table = xilinx_spi_of_match,
diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c
index 3b91cdd5ae21..2fec18b68449 100644
--- a/drivers/spi/spi-xlp.c
+++ b/drivers/spi/spi-xlp.c
@@ -95,7 +95,7 @@ struct xlp_spi_priv {
int rx_len; /* rx xfer length */
int txerrors; /* TXFIFO underflow count */
int rxerrors; /* RXFIFO overflow count */
- int cs; /* slave device chip select */
+ int cs; /* target device chip select */
u32 spi_clk; /* spi clock frequency */
bool cmd_cont; /* cs active */
struct completion done; /* completion notification */
@@ -138,7 +138,7 @@ static int xlp_spi_setup(struct spi_device *spi)
u32 fdiv, cfg;
int cs;
- xspi = spi_master_get_devdata(spi->master);
+ xspi = spi_controller_get_devdata(spi->controller);
cs = spi_get_chipselect(spi, 0);
/*
* The value of fdiv must be between 4 and 65535.
@@ -270,7 +270,7 @@ static int xlp_spi_xfer_block(struct xlp_spi_priv *xs,
const unsigned char *tx_buf,
unsigned char *rx_buf, int xfer_len, int cmd_cont)
{
- int timeout;
+ unsigned long time_left;
u32 intr_mask = 0;
xs->tx_buf = tx_buf;
@@ -299,11 +299,11 @@ static int xlp_spi_xfer_block(struct xlp_spi_priv *xs,
intr_mask |= XLP_SPI_INTR_DONE;
xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, intr_mask);
- timeout = wait_for_completion_timeout(&xs->done,
- msecs_to_jiffies(1000));
+ time_left = wait_for_completion_timeout(&xs->done,
+ msecs_to_jiffies(1000));
/* Disable interrupts */
xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, 0x0);
- if (!timeout) {
+ if (!time_left) {
dev_err(&xs->dev, "xfer timedout!\n");
goto out;
}
@@ -343,17 +343,17 @@ static int xlp_spi_txrx_bufs(struct xlp_spi_priv *xs, struct spi_transfer *t)
return bytesleft;
}
-static int xlp_spi_transfer_one(struct spi_master *master,
+static int xlp_spi_transfer_one(struct spi_controller *host,
struct spi_device *spi,
struct spi_transfer *t)
{
- struct xlp_spi_priv *xspi = spi_master_get_devdata(master);
+ struct xlp_spi_priv *xspi = spi_controller_get_devdata(host);
int ret = 0;
xspi->cs = spi_get_chipselect(spi, 0);
xspi->dev = spi->dev;
- if (spi_transfer_is_last(master, t))
+ if (spi_transfer_is_last(host, t))
xspi->cmd_cont = 0;
else
xspi->cmd_cont = 1;
@@ -361,13 +361,13 @@ static int xlp_spi_transfer_one(struct spi_master *master,
if (xlp_spi_txrx_bufs(xspi, t))
ret = -EIO;
- spi_finalize_current_transfer(master);
+ spi_finalize_current_transfer(host);
return ret;
}
static int xlp_spi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
+ struct spi_controller *host;
struct xlp_spi_priv *xspi;
struct clk *clk;
int irq, err;
@@ -398,28 +398,28 @@ static int xlp_spi_probe(struct platform_device *pdev)
xspi->spi_clk = clk_get_rate(clk);
- master = spi_alloc_master(&pdev->dev, 0);
- if (!master) {
- dev_err(&pdev->dev, "could not alloc master\n");
+ host = spi_alloc_host(&pdev->dev, 0);
+ if (!host) {
+ dev_err(&pdev->dev, "could not alloc host\n");
return -ENOMEM;
}
- master->bus_num = 0;
- master->num_chipselect = XLP_SPI_MAX_CS;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
- master->setup = xlp_spi_setup;
- master->transfer_one = xlp_spi_transfer_one;
- master->dev.of_node = pdev->dev.of_node;
+ host->bus_num = 0;
+ host->num_chipselect = XLP_SPI_MAX_CS;
+ host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ host->setup = xlp_spi_setup;
+ host->transfer_one = xlp_spi_transfer_one;
+ host->dev.of_node = pdev->dev.of_node;
init_completion(&xspi->done);
- spi_master_set_devdata(master, xspi);
+ spi_controller_set_devdata(host, xspi);
xlp_spi_sysctl_setup(xspi);
/* register spi controller */
- err = devm_spi_register_master(&pdev->dev, master);
+ err = devm_spi_register_controller(&pdev->dev, host);
if (err) {
- dev_err(&pdev->dev, "spi register master failed!\n");
- spi_master_put(master);
+ dev_err(&pdev->dev, "spi register host failed!\n");
+ spi_controller_put(host);
return err;
}
diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c
index 24dc845b940e..1b54d8f9f5ec 100644
--- a/drivers/spi/spi-xtensa-xtfpga.c
+++ b/drivers/spi/spi-xtensa-xtfpga.c
@@ -53,7 +53,7 @@ static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi)
static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
u32 v, u8 bits, unsigned flags)
{
- struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
+ struct xtfpga_spi *xspi = spi_controller_get_devdata(spi->controller);
xspi->data = (xspi->data << bits) | (v & GENMASK(bits - 1, 0));
xspi->data_sz += bits;
@@ -71,7 +71,7 @@ static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on)
{
- struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
+ struct xtfpga_spi *xspi = spi_controller_get_devdata(spi->controller);
WARN_ON(xspi->data_sz != 0);
xspi->data_sz = 0;
@@ -81,19 +81,19 @@ static int xtfpga_spi_probe(struct platform_device *pdev)
{
struct xtfpga_spi *xspi;
int ret;
- struct spi_master *master;
+ struct spi_controller *host;
- master = devm_spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi));
- if (!master)
+ host = devm_spi_alloc_host(&pdev->dev, sizeof(struct xtfpga_spi));
+ if (!host)
return -ENOMEM;
- master->flags = SPI_MASTER_NO_RX;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
- master->bus_num = pdev->dev.id;
- master->dev.of_node = pdev->dev.of_node;
+ host->flags = SPI_CONTROLLER_NO_RX;
+ host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
+ host->bus_num = pdev->dev.id;
+ host->dev.of_node = pdev->dev.of_node;
- xspi = spi_master_get_devdata(master);
- xspi->bitbang.master = master;
+ xspi = spi_controller_get_devdata(host);
+ xspi->bitbang.ctlr = host;
xspi->bitbang.chipselect = xtfpga_spi_chipselect;
xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
xspi->regs = devm_platform_ioremap_resource(pdev, 0);
@@ -113,17 +113,17 @@ static int xtfpga_spi_probe(struct platform_device *pdev)
return ret;
}
- platform_set_drvdata(pdev, master);
+ platform_set_drvdata(pdev, host);
return 0;
}
static void xtfpga_spi_remove(struct platform_device *pdev)
{
- struct spi_master *master = platform_get_drvdata(pdev);
- struct xtfpga_spi *xspi = spi_master_get_devdata(master);
+ struct spi_controller *host = platform_get_drvdata(pdev);
+ struct xtfpga_spi *xspi = spi_controller_get_devdata(host);
spi_bitbang_stop(&xspi->bitbang);
- spi_master_put(master);
+ spi_controller_put(host);
}
MODULE_ALIAS("platform:" XTFPGA_SPI_NAME);
@@ -138,7 +138,7 @@ MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match);
static struct platform_driver xtfpga_spi_driver = {
.probe = xtfpga_spi_probe,
- .remove_new = xtfpga_spi_remove,
+ .remove = xtfpga_spi_remove,
.driver = {
.name = XTFPGA_SPI_NAME,
.of_match_table = of_match_ptr(xtfpga_spi_of_match),
diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c
index ee1995b91287..5232483c4a3a 100644
--- a/drivers/spi/spi-zynq-qspi.c
+++ b/drivers/spi/spi-zynq-qspi.c
@@ -54,10 +54,10 @@
#define ZYNQ_QSPI_CONFIG_MSTREN_MASK BIT(0) /* Master Mode */
/*
- * QSPI Configuration Register - Baud rate and slave select
+ * QSPI Configuration Register - Baud rate and target select
*
* These are the values used in the calculation of baud rate divisor and
- * setting the slave select.
+ * setting the target select.
*/
#define ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */
#define ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift */
@@ -164,14 +164,14 @@ static inline void zynq_qspi_write(struct zynq_qspi *xqspi, u32 offset,
*
* The default settings of the QSPI controller's configurable parameters on
* reset are
- * - Master mode
+ * - Host mode
* - Baud rate divisor is set to 2
* - Tx threshold set to 1l Rx threshold set to 32
* - Flash memory interface mode enabled
* - Size of the word to be transferred as 8 bit
* This function performs the following actions
* - Disable and clear all the interrupts
- * - Enable manual slave select
+ * - Enable manual target select
* - Enable manual start
* - Deselect all the chip select lines
* - Set the size of the word to be transferred as 32 bit
@@ -289,7 +289,7 @@ static void zynq_qspi_txfifo_op(struct zynq_qspi *xqspi, unsigned int size)
*/
static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
{
- struct spi_controller *ctlr = spi->master;
+ struct spi_controller *ctlr = spi->controller;
struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr);
u32 config_reg;
@@ -318,6 +318,7 @@ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
* zynq_qspi_config_op - Configure QSPI controller for specified transfer
* @xqspi: Pointer to the zynq_qspi structure
* @spi: Pointer to the spi_device structure
+ * @op: The memory operation to execute
*
* Sets the operational mode of QSPI controller for the next QSPI transfer and
* sets the requested clock frequency.
@@ -331,7 +332,8 @@ static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
* controller the driver will set the highest or lowest frequency supported by
* controller.
*/
-static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
+static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi,
+ const struct spi_mem_op *op)
{
u32 config_reg, baud_rate_val = 0;
@@ -346,7 +348,7 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
*/
while ((baud_rate_val < ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX) &&
(clk_get_rate(xqspi->refclk) / (2 << baud_rate_val)) >
- spi->max_speed_hz)
+ op->max_freq)
baud_rate_val++;
config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_CONFIG_OFFSET);
@@ -377,14 +379,23 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
*/
static int zynq_qspi_setup_op(struct spi_device *spi)
{
- struct spi_controller *ctlr = spi->master;
+ struct spi_controller *ctlr = spi->controller;
struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr);
+ int ret;
if (ctlr->busy)
return -EBUSY;
- clk_enable(qspi->refclk);
- clk_enable(qspi->pclk);
+ ret = clk_enable(qspi->refclk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(qspi->pclk);
+ if (ret) {
+ clk_disable(qspi->refclk);
+ return ret;
+ }
+
zynq_qspi_write(qspi, ZYNQ_QSPI_ENABLE_OFFSET,
ZYNQ_QSPI_ENABLE_ENABLE_MASK);
@@ -525,16 +536,12 @@ static irqreturn_t zynq_qspi_irq(int irq, void *dev_id)
static int zynq_qspi_exec_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->master);
+ struct zynq_qspi *xqspi = spi_controller_get_devdata(mem->spi->controller);
int err = 0, i;
u8 *tmpbuf;
- dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n",
- op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
- op->dummy.buswidth, op->data.buswidth);
-
zynq_qspi_chipselect(mem->spi, true);
- zynq_qspi_config_op(xqspi, mem->spi);
+ zynq_qspi_config_op(xqspi, mem->spi, op);
if (op->cmd.opcode) {
reinit_completion(&xqspi->data_completion);
@@ -569,7 +576,7 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem,
}
if (op->dummy.nbytes) {
- tmpbuf = kzalloc(op->dummy.nbytes, GFP_KERNEL);
+ tmpbuf = kmalloc(op->dummy.nbytes, GFP_KERNEL);
if (!tmpbuf)
return -ENOMEM;
@@ -620,6 +627,10 @@ static const struct spi_controller_mem_ops zynq_qspi_mem_ops = {
.exec_op = zynq_qspi_exec_mem_op,
};
+static const struct spi_controller_mem_caps zynq_qspi_mem_caps = {
+ .per_op_freq = true,
+};
+
/**
* zynq_qspi_probe - Probe method for the QSPI driver
* @pdev: Pointer to the platform_device structure
@@ -637,7 +648,7 @@ static int zynq_qspi_probe(struct platform_device *pdev)
struct zynq_qspi *xqspi;
u32 num_cs;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
+ ctlr = spi_alloc_host(&pdev->dev, sizeof(*xqspi));
if (!ctlr)
return -ENOMEM;
@@ -647,14 +658,14 @@ static int zynq_qspi_probe(struct platform_device *pdev)
xqspi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(xqspi->regs)) {
ret = PTR_ERR(xqspi->regs);
- goto remove_master;
+ goto remove_ctlr;
}
xqspi->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(xqspi->pclk)) {
dev_err(&pdev->dev, "pclk clock not found.\n");
ret = PTR_ERR(xqspi->pclk);
- goto remove_master;
+ goto remove_ctlr;
}
init_completion(&xqspi->data_completion);
@@ -663,13 +674,13 @@ static int zynq_qspi_probe(struct platform_device *pdev)
if (IS_ERR(xqspi->refclk)) {
dev_err(&pdev->dev, "ref_clk clock not found.\n");
ret = PTR_ERR(xqspi->refclk);
- goto remove_master;
+ goto remove_ctlr;
}
ret = clk_prepare_enable(xqspi->pclk);
if (ret) {
dev_err(&pdev->dev, "Unable to enable APB clock.\n");
- goto remove_master;
+ goto remove_ctlr;
}
ret = clk_prepare_enable(xqspi->refclk);
@@ -679,8 +690,8 @@ static int zynq_qspi_probe(struct platform_device *pdev)
}
xqspi->irq = platform_get_irq(pdev, 0);
- if (xqspi->irq <= 0) {
- ret = -ENXIO;
+ if (xqspi->irq < 0) {
+ ret = xqspi->irq;
goto clk_dis_all;
}
ret = devm_request_irq(&pdev->dev, xqspi->irq, zynq_qspi_irq,
@@ -706,6 +717,7 @@ static int zynq_qspi_probe(struct platform_device *pdev)
ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
SPI_TX_DUAL | SPI_TX_QUAD;
ctlr->mem_ops = &zynq_qspi_mem_ops;
+ ctlr->mem_caps = &zynq_qspi_mem_caps;
ctlr->setup = zynq_qspi_setup_op;
ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
ctlr->dev.of_node = np;
@@ -715,7 +727,7 @@ static int zynq_qspi_probe(struct platform_device *pdev)
ret = devm_spi_register_controller(&pdev->dev, ctlr);
if (ret) {
- dev_err(&pdev->dev, "spi_register_master failed\n");
+ dev_err(&pdev->dev, "devm_spi_register_controller failed\n");
goto clk_dis_all;
}
@@ -725,7 +737,7 @@ clk_dis_all:
clk_disable_unprepare(xqspi->refclk);
clk_dis_pclk:
clk_disable_unprepare(xqspi->pclk);
-remove_master:
+remove_ctlr:
spi_controller_put(ctlr);
return ret;
@@ -763,7 +775,7 @@ MODULE_DEVICE_TABLE(of, zynq_qspi_of_match);
*/
static struct platform_driver zynq_qspi_driver = {
.probe = zynq_qspi_probe,
- .remove_new = zynq_qspi_remove,
+ .remove = zynq_qspi_remove,
.driver = {
.name = "zynq-qspi",
.of_match_table = zynq_qspi_of_match,
diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index fb2ca9b90eab..502fd5eccc83 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Xilinx Zynq UltraScale+ MPSoC Quad-SPI (QSPI) controller driver
- * (master mode only)
+ * (host mode only)
*
* Copyright (C) 2009 - 2015 Xilinx, Inc.
*/
@@ -14,9 +14,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
@@ -84,7 +82,6 @@
#define GQSPI_GENFIFO_RX 0x00020000
#define GQSPI_GENFIFO_STRIPE 0x00040000
#define GQSPI_GENFIFO_POLL 0x00080000
-#define GQSPI_GENFIFO_EXP_START 0x00000100
#define GQSPI_FIFO_CTRL_RST_RX_FIFO_MASK 0x00000004
#define GQSPI_FIFO_CTRL_RST_TX_FIFO_MASK 0x00000002
#define GQSPI_FIFO_CTRL_RST_GEN_FIFO_MASK 0x00000001
@@ -237,21 +234,21 @@ static inline void zynqmp_gqspi_write(struct zynqmp_qspi *xqspi, u32 offset,
}
/**
- * zynqmp_gqspi_selectslave - For selection of slave device
+ * zynqmp_gqspi_selecttarget - For selection of target device
* @instanceptr: Pointer to the zynqmp_qspi structure
- * @slavecs: For chip select
- * @slavebus: To check which bus is selected- upper or lower
+ * @targetcs: For chip select
+ * @targetbus: To check which bus is selected- upper or lower
*/
-static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
- u8 slavecs, u8 slavebus)
+static void zynqmp_gqspi_selecttarget(struct zynqmp_qspi *instanceptr,
+ u8 targetcs, u8 targetbus)
{
/*
* Bus and CS lines selected here will be updated in the instance and
* used for subsequent GENFIFO entries during transfer.
*/
- /* Choose slave select line */
- switch (slavecs) {
+ /* Choose target select line */
+ switch (targetcs) {
case GQSPI_SELECT_FLASH_CS_BOTH:
instanceptr->genfifocs = GQSPI_GENFIFO_CS_LOWER |
GQSPI_GENFIFO_CS_UPPER;
@@ -263,11 +260,11 @@ static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
instanceptr->genfifocs = GQSPI_GENFIFO_CS_LOWER;
break;
default:
- dev_warn(instanceptr->dev, "Invalid slave select\n");
+ dev_warn(instanceptr->dev, "Invalid target select\n");
}
/* Choose the bus */
- switch (slavebus) {
+ switch (targetbus) {
case GQSPI_SELECT_FLASH_BUS_BOTH:
instanceptr->genfifobus = GQSPI_GENFIFO_BUS_LOWER |
GQSPI_GENFIFO_BUS_UPPER;
@@ -279,7 +276,7 @@ static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
instanceptr->genfifobus = GQSPI_GENFIFO_BUS_LOWER;
break;
default:
- dev_warn(instanceptr->dev, "Invalid slave bus\n");
+ dev_warn(instanceptr->dev, "Invalid target bus\n");
}
}
@@ -339,13 +336,13 @@ static void zynqmp_qspi_set_tapdelay(struct zynqmp_qspi *xqspi, u32 baudrateval)
*
* The default settings of the QSPI controller's configurable parameters on
* reset are
- * - Master mode
+ * - Host mode
* - TX threshold set to 1
* - RX threshold set to 1
* - Flash memory interface mode enabled
* This function performs the following actions
* - Disable and clear all the interrupts
- * - Enable manual slave select
+ * - Enable manual target select
* - Enable manual start
* - Deselect all the chip select lines
* - Set the little endian mode of TX FIFO
@@ -428,9 +425,9 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi *xqspi)
GQSPI_RX_FIFO_THRESHOLD);
zynqmp_gqspi_write(xqspi, GQSPI_GF_THRESHOLD_OFST,
GQSPI_GEN_FIFO_THRESHOLD_RESET_VAL);
- zynqmp_gqspi_selectslave(xqspi,
- GQSPI_SELECT_FLASH_CS_LOWER,
- GQSPI_SELECT_FLASH_BUS_LOWER);
+ zynqmp_gqspi_selecttarget(xqspi,
+ GQSPI_SELECT_FLASH_CS_LOWER,
+ GQSPI_SELECT_FLASH_BUS_LOWER);
/* Initialize DMA */
zynqmp_gqspi_write(xqspi,
GQSPI_QSPIDMA_DST_CTRL_OFST,
@@ -461,7 +458,7 @@ static void zynqmp_qspi_copy_read_data(struct zynqmp_qspi *xqspi,
*/
static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
{
- struct zynqmp_qspi *xqspi = spi_master_get_devdata(qspi->master);
+ struct zynqmp_qspi *xqspi = spi_controller_get_devdata(qspi->controller);
ulong timeout;
u32 genfifoentry = 0, statusreg;
@@ -537,7 +534,7 @@ static inline u32 zynqmp_qspi_selectspimode(struct zynqmp_qspi *xqspi,
* zynqmp_qspi_config_op - Configure QSPI controller for specified
* transfer
* @xqspi: Pointer to the zynqmp_qspi structure
- * @qspi: Pointer to the spi_device structure
+ * @op: The memory operation to execute
*
* Sets the operational mode of QSPI controller for the next QSPI transfer and
* sets the requested clock frequency.
@@ -555,12 +552,12 @@ static inline u32 zynqmp_qspi_selectspimode(struct zynqmp_qspi *xqspi,
* frequency supported by controller.
*/
static int zynqmp_qspi_config_op(struct zynqmp_qspi *xqspi,
- struct spi_device *qspi)
+ const struct spi_mem_op *op)
{
ulong clk_rate;
u32 config_reg, req_speed_hz, baud_rate_val = 0;
- req_speed_hz = qspi->max_speed_hz;
+ req_speed_hz = op->max_freq;
if (xqspi->speed_hz != req_speed_hz) {
xqspi->speed_hz = req_speed_hz;
@@ -582,6 +579,8 @@ static int zynqmp_qspi_config_op(struct zynqmp_qspi *xqspi,
zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
zynqmp_qspi_set_tapdelay(xqspi, baud_rate_val);
}
+
+ dev_dbg(xqspi->dev, "config speed %u\n", req_speed_hz);
return 0;
}
@@ -596,7 +595,7 @@ static int zynqmp_qspi_config_op(struct zynqmp_qspi *xqspi,
*/
static int zynqmp_qspi_setup_op(struct spi_device *qspi)
{
- struct spi_controller *ctlr = qspi->master;
+ struct spi_controller *ctlr = qspi->controller;
struct zynqmp_qspi *xqspi = spi_controller_get_devdata(ctlr);
if (ctlr->busy)
@@ -672,69 +671,77 @@ static void zynqmp_qspi_readrxfifo(struct zynqmp_qspi *xqspi, u32 size)
static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits,
u32 genfifoentry)
{
- u32 transfer_len = 0;
+ u32 transfer_len, tempcount, exponent;
+ u8 imm_data;
- if (xqspi->txbuf) {
- genfifoentry &= ~GQSPI_GENFIFO_RX;
- genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
- genfifoentry |= GQSPI_GENFIFO_TX;
- transfer_len = xqspi->bytes_to_transfer;
- } else if (xqspi->rxbuf) {
- genfifoentry &= ~GQSPI_GENFIFO_TX;
- genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
+ genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
+ if (xqspi->rxbuf) {
genfifoentry |= GQSPI_GENFIFO_RX;
if (xqspi->mode == GQSPI_MODE_DMA)
transfer_len = xqspi->dma_rx_bytes;
else
transfer_len = xqspi->bytes_to_receive;
} else {
- /* Sending dummy circles here */
- genfifoentry &= ~(GQSPI_GENFIFO_TX | GQSPI_GENFIFO_RX);
- genfifoentry |= GQSPI_GENFIFO_DATA_XFER;
transfer_len = xqspi->bytes_to_transfer;
}
+
+ if (xqspi->txbuf)
+ genfifoentry |= GQSPI_GENFIFO_TX;
+
genfifoentry |= zynqmp_qspi_selectspimode(xqspi, nbits);
xqspi->genfifoentry = genfifoentry;
-
- if ((transfer_len) < GQSPI_GENFIFO_IMM_DATA_MASK) {
- genfifoentry &= ~GQSPI_GENFIFO_IMM_DATA_MASK;
- genfifoentry |= transfer_len;
- zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry);
- } else {
- int tempcount = transfer_len;
- u32 exponent = 8; /* 2^8 = 256 */
- u8 imm_data = tempcount & 0xFF;
-
- tempcount &= ~(tempcount & 0xFF);
- /* Immediate entry */
- if (tempcount != 0) {
- /* Exponent entries */
- genfifoentry |= GQSPI_GENFIFO_EXP;
- while (tempcount != 0) {
- if (tempcount & GQSPI_GENFIFO_EXP_START) {
- genfifoentry &=
- ~GQSPI_GENFIFO_IMM_DATA_MASK;
- genfifoentry |= exponent;
- zynqmp_gqspi_write(xqspi,
- GQSPI_GEN_FIFO_OFST,
- genfifoentry);
- }
- tempcount = tempcount >> 1;
- exponent++;
- }
- }
- if (imm_data != 0) {
- genfifoentry &= ~GQSPI_GENFIFO_EXP;
- genfifoentry &= ~GQSPI_GENFIFO_IMM_DATA_MASK;
- genfifoentry |= (u8)(imm_data & 0xFF);
+ dev_dbg(xqspi->dev, "genfifo %05x transfer_len %u\n",
+ genfifoentry, transfer_len);
+
+ /* Exponent entries */
+ imm_data = transfer_len;
+ tempcount = transfer_len >> 8;
+ exponent = 8;
+ genfifoentry |= GQSPI_GENFIFO_EXP;
+ while (tempcount) {
+ if (tempcount & 1)
zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST,
- genfifoentry);
- }
- }
- if (xqspi->mode == GQSPI_MODE_IO && xqspi->rxbuf) {
- /* Dummy generic FIFO entry */
- zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0);
+ genfifoentry | exponent);
+ tempcount >>= 1;
+ exponent++;
}
+
+ /* Immediate entry */
+ genfifoentry &= ~GQSPI_GENFIFO_EXP;
+ if (imm_data)
+ zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST,
+ genfifoentry | imm_data);
+
+ /* Dummy generic FIFO entry */
+ if (xqspi->mode == GQSPI_MODE_IO && xqspi->rxbuf)
+ zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0);
+}
+
+/**
+ * zynqmp_qspi_disable_dma() - Disable DMA mode
+ * @xqspi: GQSPI instance
+ */
+static void zynqmp_qspi_disable_dma(struct zynqmp_qspi *xqspi)
+{
+ u32 config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
+
+ config_reg &= ~GQSPI_CFG_MODE_EN_MASK;
+ zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
+ xqspi->mode = GQSPI_MODE_IO;
+}
+
+/**
+ * zynqmp_qspi_enable_dma() - Enable DMA mode
+ * @xqspi: GQSPI instance
+ */
+static void zynqmp_qspi_enable_dma(struct zynqmp_qspi *xqspi)
+{
+ u32 config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
+
+ config_reg &= ~GQSPI_CFG_MODE_EN_MASK;
+ config_reg |= GQSPI_CFG_MODE_EN_DMA_MASK;
+ zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
+ xqspi->mode = GQSPI_MODE_DMA;
}
/**
@@ -746,7 +753,7 @@ static void zynqmp_qspi_fillgenfifo(struct zynqmp_qspi *xqspi, u8 nbits,
*/
static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi)
{
- u32 config_reg, genfifoentry;
+ u32 genfifoentry;
dma_unmap_single(xqspi->dev, xqspi->dma_addr,
xqspi->dma_rx_bytes, DMA_FROM_DEVICE);
@@ -760,9 +767,7 @@ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi)
if (xqspi->bytes_to_receive > 0) {
/* Switch to IO mode,for remaining bytes to receive */
- config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
- config_reg &= ~GQSPI_CFG_MODE_EN_MASK;
- zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
+ zynqmp_qspi_disable_dma(xqspi);
/* Initiate the transfer of remaining bytes */
genfifoentry = xqspi->genfifoentry;
@@ -801,7 +806,6 @@ static void zynqmp_process_dma_irq(struct zynqmp_qspi *xqspi)
static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id)
{
struct zynqmp_qspi *xqspi = (struct zynqmp_qspi *)dev_id;
- irqreturn_t ret = IRQ_NONE;
u32 status, mask, dma_status = 0;
status = zynqmp_gqspi_read(xqspi, GQSPI_ISR_OFST);
@@ -816,27 +820,24 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id)
dma_status);
}
- if (mask & GQSPI_ISR_TXNOT_FULL_MASK) {
+ if (!mask && !dma_status)
+ return IRQ_NONE;
+
+ if (mask & GQSPI_ISR_TXNOT_FULL_MASK)
zynqmp_qspi_filltxfifo(xqspi, GQSPI_TX_FIFO_FILL);
- ret = IRQ_HANDLED;
- }
- if (dma_status & GQSPI_QSPIDMA_DST_I_STS_DONE_MASK) {
+ if (dma_status & GQSPI_QSPIDMA_DST_I_STS_DONE_MASK)
zynqmp_process_dma_irq(xqspi);
- ret = IRQ_HANDLED;
- } else if (!(mask & GQSPI_IER_RXEMPTY_MASK) &&
- (mask & GQSPI_IER_GENFIFOEMPTY_MASK)) {
+ else if (!(mask & GQSPI_IER_RXEMPTY_MASK) &&
+ (mask & GQSPI_IER_GENFIFOEMPTY_MASK))
zynqmp_qspi_readrxfifo(xqspi, GQSPI_RX_FIFO_FILL);
- ret = IRQ_HANDLED;
- }
if (xqspi->bytes_to_receive == 0 && xqspi->bytes_to_transfer == 0 &&
((status & GQSPI_IRQ_MASK) == GQSPI_IRQ_MASK)) {
zynqmp_gqspi_write(xqspi, GQSPI_IDR_OFST, GQSPI_ISR_IDR_MASK);
complete(&xqspi->data_completion);
- ret = IRQ_HANDLED;
}
- return ret;
+ return IRQ_HANDLED;
}
/**
@@ -847,17 +848,14 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id)
*/
static int zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
{
- u32 rx_bytes, rx_rem, config_reg;
+ u32 rx_bytes, rx_rem;
dma_addr_t addr;
u64 dma_align = (u64)(uintptr_t)xqspi->rxbuf;
if (xqspi->bytes_to_receive < 8 ||
((dma_align & GQSPI_DMA_UNALIGN) != 0x0)) {
/* Setting to IO mode */
- config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
- config_reg &= ~GQSPI_CFG_MODE_EN_MASK;
- zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
- xqspi->mode = GQSPI_MODE_IO;
+ zynqmp_qspi_disable_dma(xqspi);
xqspi->dma_rx_bytes = 0;
return 0;
}
@@ -880,14 +878,7 @@ static int zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_ADDR_MSB_OFST,
((u32)addr) & 0xfff);
- /* Enabling the DMA mode */
- config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
- config_reg &= ~GQSPI_CFG_MODE_EN_MASK;
- config_reg |= GQSPI_CFG_MODE_EN_DMA_MASK;
- zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
-
- /* Switch to DMA mode */
- xqspi->mode = GQSPI_MODE_DMA;
+ zynqmp_qspi_enable_dma(xqspi);
/* Write the number of bytes to transfer */
zynqmp_gqspi_write(xqspi, GQSPI_QSPIDMA_DST_SIZE_OFST, rx_bytes);
@@ -907,18 +898,10 @@ static int zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
static void zynqmp_qspi_write_op(struct zynqmp_qspi *xqspi, u8 tx_nbits,
u32 genfifoentry)
{
- u32 config_reg;
-
zynqmp_qspi_fillgenfifo(xqspi, tx_nbits, genfifoentry);
zynqmp_qspi_filltxfifo(xqspi, GQSPI_TXD_DEPTH);
- if (xqspi->mode == GQSPI_MODE_DMA) {
- config_reg = zynqmp_gqspi_read(xqspi,
- GQSPI_CONFIG_OFST);
- config_reg &= ~GQSPI_CFG_MODE_EN_MASK;
- zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
- config_reg);
- xqspi->mode = GQSPI_MODE_IO;
- }
+ if (xqspi->mode == GQSPI_MODE_DMA)
+ zynqmp_qspi_disable_dma(xqspi);
}
/**
@@ -1035,6 +1018,18 @@ static int __maybe_unused zynqmp_runtime_resume(struct device *dev)
return 0;
}
+static unsigned long zynqmp_qspi_timeout(struct zynqmp_qspi *xqspi, u8 bits,
+ unsigned long bytes)
+{
+ unsigned long timeout;
+
+ /* Assume we are at most 2x slower than the nominal bus speed */
+ timeout = mult_frac(bytes, 2 * 8 * MSEC_PER_SEC,
+ bits * xqspi->speed_hz);
+ /* And add 100 ms for scheduling delays */
+ return msecs_to_jiffies(timeout + 100);
+}
+
/**
* zynqmp_qspi_exec_op() - Initiates the QSPI transfer
* @mem: The SPI memory
@@ -1049,19 +1044,16 @@ static int __maybe_unused zynqmp_runtime_resume(struct device *dev)
static int zynqmp_qspi_exec_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
- struct zynqmp_qspi *xqspi = spi_controller_get_devdata
- (mem->spi->master);
+ struct zynqmp_qspi *xqspi =
+ spi_controller_get_devdata(mem->spi->controller);
+ unsigned long timeout;
int err = 0, i;
u32 genfifoentry = 0;
u16 opcode = op->cmd.opcode;
u64 opaddr;
- dev_dbg(xqspi->dev, "cmd:%#x mode:%d.%d.%d.%d\n",
- op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
- op->dummy.buswidth, op->data.buswidth);
-
mutex_lock(&xqspi->op_lock);
- zynqmp_qspi_config_op(xqspi, mem->spi);
+ zynqmp_qspi_config_op(xqspi, op);
zynqmp_qspi_chipselect(mem->spi, false);
genfifoentry |= xqspi->genfifocs;
genfifoentry |= xqspi->genfifobus;
@@ -1079,8 +1071,10 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
zynqmp_gqspi_write(xqspi, GQSPI_IER_OFST,
GQSPI_IER_GENFIFOEMPTY_MASK |
GQSPI_IER_TXNOT_FULL_MASK);
- if (!wait_for_completion_timeout
- (&xqspi->data_completion, msecs_to_jiffies(1000))) {
+ timeout = zynqmp_qspi_timeout(xqspi, op->cmd.buswidth,
+ op->cmd.nbytes);
+ if (!wait_for_completion_timeout(&xqspi->data_completion,
+ timeout)) {
err = -ETIMEDOUT;
goto return_err;
}
@@ -1106,8 +1100,10 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
GQSPI_IER_TXEMPTY_MASK |
GQSPI_IER_GENFIFOEMPTY_MASK |
GQSPI_IER_TXNOT_FULL_MASK);
- if (!wait_for_completion_timeout
- (&xqspi->data_completion, msecs_to_jiffies(1000))) {
+ timeout = zynqmp_qspi_timeout(xqspi, op->addr.buswidth,
+ op->addr.nbytes);
+ if (!wait_for_completion_timeout(&xqspi->data_completion,
+ timeout)) {
err = -ETIMEDOUT;
goto return_err;
}
@@ -1175,8 +1171,9 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem,
GQSPI_IER_RXEMPTY_MASK);
}
}
- if (!wait_for_completion_timeout
- (&xqspi->data_completion, msecs_to_jiffies(1000)))
+ timeout = zynqmp_qspi_timeout(xqspi, op->data.buswidth,
+ op->data.nbytes);
+ if (!wait_for_completion_timeout(&xqspi->data_completion, timeout))
err = -ETIMEDOUT;
}
@@ -1208,6 +1205,10 @@ static const struct spi_controller_mem_ops zynqmp_qspi_mem_ops = {
.exec_op = zynqmp_qspi_exec_op,
};
+static const struct spi_controller_mem_caps zynqmp_qspi_mem_caps = {
+ .per_op_freq = true,
+};
+
/**
* zynqmp_qspi_probe - Probe method for the QSPI driver
* @pdev: Pointer to the platform_device structure
@@ -1226,7 +1227,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
u32 num_cs;
const struct qspi_platform_data *p_data;
- ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
+ ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*xqspi));
if (!ctlr)
return -ENOMEM;
@@ -1240,30 +1241,22 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
xqspi->has_tapdelay = true;
xqspi->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(xqspi->regs)) {
- ret = PTR_ERR(xqspi->regs);
- goto remove_master;
- }
+ if (IS_ERR(xqspi->regs))
+ return PTR_ERR(xqspi->regs);
xqspi->pclk = devm_clk_get(&pdev->dev, "pclk");
- if (IS_ERR(xqspi->pclk)) {
- dev_err(dev, "pclk clock not found.\n");
- ret = PTR_ERR(xqspi->pclk);
- goto remove_master;
- }
+ if (IS_ERR(xqspi->pclk))
+ return dev_err_probe(dev, PTR_ERR(xqspi->pclk),
+ "pclk clock not found.\n");
xqspi->refclk = devm_clk_get(&pdev->dev, "ref_clk");
- if (IS_ERR(xqspi->refclk)) {
- dev_err(dev, "ref_clk clock not found.\n");
- ret = PTR_ERR(xqspi->refclk);
- goto remove_master;
- }
+ if (IS_ERR(xqspi->refclk))
+ return dev_err_probe(dev, PTR_ERR(xqspi->refclk),
+ "ref_clk clock not found.\n");
ret = clk_prepare_enable(xqspi->pclk);
- if (ret) {
- dev_err(dev, "Unable to enable APB clock.\n");
- goto remove_master;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "Unable to enable APB clock.\n");
ret = clk_prepare_enable(xqspi->refclk);
if (ret) {
@@ -1295,8 +1288,8 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
zynqmp_qspi_init_hw(xqspi);
xqspi->irq = platform_get_irq(pdev, 0);
- if (xqspi->irq <= 0) {
- ret = -ENXIO;
+ if (xqspi->irq < 0) {
+ ret = xqspi->irq;
goto clk_dis_all;
}
ret = devm_request_irq(&pdev->dev, xqspi->irq, zynqmp_qspi_irq,
@@ -1325,6 +1318,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->mem_ops = &zynqmp_qspi_mem_ops;
+ ctlr->mem_caps = &zynqmp_qspi_mem_caps;
ctlr->setup = zynqmp_qspi_setup_op;
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->dev.of_node = np;
@@ -1336,20 +1330,18 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
goto clk_dis_all;
}
- pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
clk_dis_all:
- pm_runtime_put_sync(&pdev->dev);
- pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
clk_disable_unprepare(xqspi->refclk);
clk_dis_pclk:
clk_disable_unprepare(xqspi->pclk);
-remove_master:
- spi_controller_put(ctlr);
return ret;
}
@@ -1368,18 +1360,23 @@ static void zynqmp_qspi_remove(struct platform_device *pdev)
{
struct zynqmp_qspi *xqspi = platform_get_drvdata(pdev);
+ pm_runtime_get_sync(&pdev->dev);
+
zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
clk_disable_unprepare(xqspi->refclk);
clk_disable_unprepare(xqspi->pclk);
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
}
MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match);
static struct platform_driver zynqmp_qspi_driver = {
.probe = zynqmp_qspi_probe,
- .remove_new = zynqmp_qspi_remove,
+ .remove = zynqmp_qspi_remove,
.driver = {
.name = "zynqmp-qspi",
.of_match_table = zynqmp_qspi_of_match,
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 9291b2a0e887..e25df9990f82 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -4,36 +4,37 @@
// Copyright (C) 2005 David Brownell
// Copyright (C) 2008 Secret Lab Technologies Ltd.
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/init.h>
+#include <linux/acpi.h>
#include <linux/cache.h>
-#include <linux/dma-mapping.h>
+#include <linux/clk/clk-conf.h>
+#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <linux/gpio/consumer.h>
+#include <linux/highmem.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
-#include <linux/clk/clk-conf.h>
-#include <linux/slab.h>
-#include <linux/mod_devicetable.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/spi-mem.h>
-#include <linux/gpio/consumer.h>
-#include <linux/pm_runtime.h>
+#include <linux/percpu.h>
+#include <linux/platform_data/x86/apple.h>
#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
#include <linux/property.h>
-#include <linux/export.h>
+#include <linux/ptp_clock_kernel.h>
#include <linux/sched/rt.h>
+#include <linux/slab.h>
+#include <linux/spi/offload/types.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
#include <uapi/linux/sched/types.h>
-#include <linux/delay.h>
-#include <linux/kthread.h>
-#include <linux/ioport.h>
-#include <linux/acpi.h>
-#include <linux/highmem.h>
-#include <linux/idr.h>
-#include <linux/platform_data/x86/apple.h>
-#include <linux/ptp_clock_kernel.h>
-#include <linux/percpu.h>
#define CREATE_TRACE_POINTS
#include <trace/events/spi.h>
@@ -42,7 +43,7 @@ EXPORT_TRACEPOINT_SYMBOL(spi_transfer_stop);
#include "internals.h"
-static DEFINE_IDR(spi_master_idr);
+static DEFINE_IDR(spi_controller_idr);
static void spidev_release(struct device *dev)
{
@@ -64,7 +65,7 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)
if (len != -ENODEV)
return len;
- return sprintf(buf, "%s%s\n", SPI_MODULE_PREFIX, spi->modalias);
+ return sysfs_emit(buf, "%s%s\n", SPI_MODULE_PREFIX, spi->modalias);
}
static DEVICE_ATTR_RO(modalias);
@@ -89,7 +90,7 @@ static ssize_t driver_override_show(struct device *dev,
ssize_t len;
device_lock(dev);
- len = snprintf(buf, PAGE_SIZE, "%s\n", spi->driver_override ? : "");
+ len = sysfs_emit(buf, "%s\n", spi->driver_override ? : "");
device_unlock(dev);
return len;
}
@@ -305,14 +306,14 @@ static const struct attribute_group spi_controller_statistics_group = {
.attrs = spi_controller_statistics_attrs,
};
-static const struct attribute_group *spi_master_groups[] = {
+static const struct attribute_group *spi_controller_groups[] = {
&spi_controller_statistics_group,
NULL,
};
static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pcpu_stats,
struct spi_transfer *xfer,
- struct spi_controller *ctlr)
+ struct spi_message *msg)
{
int l2len = min(fls(xfer->len), SPI_STATISTICS_HISTO_SIZE) - 1;
struct spi_statistics *stats;
@@ -328,11 +329,9 @@ static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pc
u64_stats_inc(&stats->transfer_bytes_histo[l2len]);
u64_stats_add(&stats->bytes, xfer->len);
- if ((xfer->tx_buf) &&
- (xfer->tx_buf != ctlr->dummy_tx))
+ if (spi_valid_txbuf(msg, xfer))
u64_stats_add(&stats->bytes_tx, xfer->len);
- if ((xfer->rx_buf) &&
- (xfer->rx_buf != ctlr->dummy_rx))
+ if (spi_valid_rxbuf(msg, xfer))
u64_stats_add(&stats->bytes_rx, xfer->len);
u64_stats_update_end(&stats->syncp);
@@ -373,7 +372,7 @@ const void *spi_get_device_match_data(const struct spi_device *sdev)
}
EXPORT_SYMBOL_GPL(spi_get_device_match_data);
-static int spi_match_device(struct device *dev, struct device_driver *drv)
+static int spi_match_device(struct device *dev, const struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv);
@@ -412,29 +411,29 @@ static int spi_probe(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
struct spi_device *spi = to_spi_device(dev);
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
int ret;
ret = of_clk_set_defaults(dev->of_node, false);
if (ret)
return ret;
- if (dev->of_node) {
+ if (is_of_node(fwnode))
spi->irq = of_irq_get(dev->of_node, 0);
- if (spi->irq == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- if (spi->irq < 0)
- spi->irq = 0;
- }
+ else if (is_acpi_device_node(fwnode) && spi->irq < 0)
+ spi->irq = acpi_dev_gpio_irq_get(to_acpi_device_node(fwnode), 0);
+ if (spi->irq == -EPROBE_DEFER)
+ return dev_err_probe(dev, spi->irq, "Failed to get irq\n");
+ if (spi->irq < 0)
+ spi->irq = 0;
- ret = dev_pm_domain_attach(dev, true);
+ ret = dev_pm_domain_attach(dev, PD_FLAG_ATTACH_POWER_ON |
+ PD_FLAG_DETACH_POWER_OFF);
if (ret)
return ret;
- if (sdrv->probe) {
+ if (sdrv->probe)
ret = sdrv->probe(spi);
- if (ret)
- dev_pm_domain_detach(dev, true);
- }
return ret;
}
@@ -445,8 +444,6 @@ static void spi_remove(struct device *dev)
if (sdrv->remove)
sdrv->remove(to_spi_device(dev));
-
- dev_pm_domain_detach(dev, true);
}
static void spi_shutdown(struct device *dev)
@@ -459,7 +456,7 @@ static void spi_shutdown(struct device *dev)
}
}
-struct bus_type spi_bus_type = {
+const struct bus_type spi_bus_type = {
.name = "spi",
.dev_groups = spi_dev_groups,
.match = spi_match_device,
@@ -584,11 +581,12 @@ struct spi_device *spi_alloc_device(struct spi_controller *ctlr)
return NULL;
}
- spi->master = spi->controller = ctlr;
+ spi->controller = ctlr;
spi->dev.parent = &ctlr->dev;
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
spi->mode = ctlr->buswidth_override_bits;
+ spi->num_chipselect = 1;
device_initialize(&spi->dev);
return spi;
@@ -597,10 +595,16 @@ EXPORT_SYMBOL_GPL(spi_alloc_device);
static void spi_dev_set_name(struct spi_device *spi)
{
- struct acpi_device *adev = ACPI_COMPANION(&spi->dev);
+ struct device *dev = &spi->dev;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
- if (adev) {
- dev_set_name(&spi->dev, "spi-%s", acpi_dev_name(adev));
+ if (is_acpi_device_node(fwnode)) {
+ dev_set_name(dev, "spi-%s", acpi_dev_name(to_acpi_device_node(fwnode)));
+ return;
+ }
+
+ if (is_software_node(fwnode)) {
+ dev_set_name(dev, "spi-%pfwP", fwnode);
return;
}
@@ -608,14 +612,48 @@ static void spi_dev_set_name(struct spi_device *spi)
spi_get_chipselect(spi, 0));
}
+/*
+ * Zero(0) is a valid physical CS value and can be located at any
+ * logical CS in the spi->chip_select[]. If all the physical CS
+ * are initialized to 0 then It would be difficult to differentiate
+ * between a valid physical CS 0 & an unused logical CS whose physical
+ * CS can be 0. As a solution to this issue initialize all the CS to -1.
+ * Now all the unused logical CS will have -1 physical CS value & can be
+ * ignored while performing physical CS validity checks.
+ */
+#define SPI_INVALID_CS ((s8)-1)
+
+static inline int spi_dev_check_cs(struct device *dev,
+ struct spi_device *spi, u8 idx,
+ struct spi_device *new_spi, u8 new_idx)
+{
+ u8 cs, cs_new;
+ u8 idx_new;
+
+ cs = spi_get_chipselect(spi, idx);
+ for (idx_new = new_idx; idx_new < new_spi->num_chipselect; idx_new++) {
+ cs_new = spi_get_chipselect(new_spi, idx_new);
+ if (cs == cs_new) {
+ dev_err(dev, "chipselect %u already in use\n", cs_new);
+ return -EBUSY;
+ }
+ }
+ return 0;
+}
+
static int spi_dev_check(struct device *dev, void *data)
{
struct spi_device *spi = to_spi_device(dev);
struct spi_device *new_spi = data;
+ int status, idx;
- if (spi->controller == new_spi->controller &&
- spi_get_chipselect(spi, 0) == spi_get_chipselect(new_spi, 0))
- return -EBUSY;
+ if (spi->controller == new_spi->controller) {
+ for (idx = 0; idx < spi->num_chipselect; idx++) {
+ status = spi_dev_check_cs(dev, spi, idx, new_spi, 0);
+ if (status)
+ return status;
+ }
+ }
return 0;
}
@@ -629,7 +667,43 @@ static int __spi_add_device(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
struct device *dev = ctlr->dev.parent;
- int status;
+ int status, idx;
+ u8 cs;
+
+ if (spi->num_chipselect > SPI_DEVICE_CS_CNT_MAX) {
+ dev_err(dev, "num_cs %d > max %d\n", spi->num_chipselect,
+ SPI_DEVICE_CS_CNT_MAX);
+ return -EOVERFLOW;
+ }
+
+ for (idx = 0; idx < spi->num_chipselect; idx++) {
+ /* Chipselects are numbered 0..max; validate. */
+ cs = spi_get_chipselect(spi, idx);
+ if (cs >= ctlr->num_chipselect) {
+ dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, idx),
+ ctlr->num_chipselect);
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Make sure that multiple logical CS doesn't map to the same physical CS.
+ * For example, spi->chip_select[0] != spi->chip_select[1] and so on.
+ */
+ if (!spi_controller_is_target(ctlr)) {
+ for (idx = 0; idx < spi->num_chipselect; idx++) {
+ status = spi_dev_check_cs(dev, spi, idx, spi, idx + 1);
+ if (status)
+ return status;
+ }
+ }
+
+ /* Initialize unused logical CS as invalid */
+ for (idx = spi->num_chipselect; idx < SPI_DEVICE_CS_CNT_MAX; idx++)
+ spi_set_chipselect(spi, idx, SPI_INVALID_CS);
+
+ /* Set the bus ID string */
+ spi_dev_set_name(spi);
/*
* We need to make sure there's no other device with this
@@ -637,11 +711,8 @@ static int __spi_add_device(struct spi_device *spi)
* its configuration.
*/
status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
- if (status) {
- dev_err(dev, "chipselect %d already in use\n",
- spi_get_chipselect(spi, 0));
+ if (status)
return status;
- }
/* Controller may unregister concurrently */
if (IS_ENABLED(CONFIG_SPI_DYNAMIC) &&
@@ -649,8 +720,14 @@ static int __spi_add_device(struct spi_device *spi)
return -ENODEV;
}
- if (ctlr->cs_gpiods)
- spi_set_csgpiod(spi, 0, ctlr->cs_gpiods[spi_get_chipselect(spi, 0)]);
+ if (ctlr->cs_gpiods) {
+ u8 cs;
+
+ for (idx = 0; idx < spi->num_chipselect; idx++) {
+ cs = spi_get_chipselect(spi, idx);
+ spi_set_csgpiod(spi, idx, ctlr->cs_gpiods[cs]);
+ }
+ }
/*
* Drivers may modify this initial i/o setup, but will
@@ -682,23 +759,15 @@ static int __spi_add_device(struct spi_device *spi)
* @spi: spi_device to register
*
* Companion function to spi_alloc_device. Devices allocated with
- * spi_alloc_device can be added onto the spi bus with this function.
+ * spi_alloc_device can be added onto the SPI bus with this function.
*
* Return: 0 on success; negative errno on failure
*/
int spi_add_device(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
- struct device *dev = ctlr->dev.parent;
int status;
- /* Chipselects are numbered 0..max; validate. */
- if (spi_get_chipselect(spi, 0) >= ctlr->num_chipselect) {
- dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, 0),
- ctlr->num_chipselect);
- return -EINVAL;
- }
-
/* Set the bus ID string */
spi_dev_set_name(spi);
@@ -709,25 +778,6 @@ int spi_add_device(struct spi_device *spi)
}
EXPORT_SYMBOL_GPL(spi_add_device);
-static int spi_add_device_locked(struct spi_device *spi)
-{
- struct spi_controller *ctlr = spi->controller;
- struct device *dev = ctlr->dev.parent;
-
- /* Chipselects are numbered 0..max; validate. */
- if (spi_get_chipselect(spi, 0) >= ctlr->num_chipselect) {
- dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, 0),
- ctlr->num_chipselect);
- return -EINVAL;
- }
-
- /* Set the bus ID string */
- spi_dev_set_name(spi);
-
- WARN_ON(!mutex_is_locked(&ctlr->add_lock));
- return __spi_add_device(spi);
-}
-
/**
* spi_new_device - instantiate one new SPI device
* @ctlr: Controller to which device is connected
@@ -762,7 +812,9 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr,
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
+ /* Use provided chip-select for proxy device */
spi_set_chipselect(proxy, 0, chip->chip_select);
+
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
@@ -770,6 +822,11 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr,
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
+ /*
+ * By default spi->chip_select[0] will hold the physical CS number,
+ * so set bit 0 in spi->cs_index_mask.
+ */
+ proxy->cs_index_mask = BIT(0);
if (chip->swnode) {
status = device_add_software_node(&proxy->dev, chip->swnode);
@@ -802,15 +859,18 @@ EXPORT_SYMBOL_GPL(spi_new_device);
*/
void spi_unregister_device(struct spi_device *spi)
{
+ struct fwnode_handle *fwnode;
+
if (!spi)
return;
- if (spi->dev.of_node) {
- of_node_clear_flag(spi->dev.of_node, OF_POPULATED);
- of_node_put(spi->dev.of_node);
+ fwnode = dev_fwnode(&spi->dev);
+ if (is_of_node(fwnode)) {
+ of_node_clear_flag(to_of_node(fwnode), OF_POPULATED);
+ of_node_put(to_of_node(fwnode));
+ } else if (is_acpi_device_node(fwnode)) {
+ acpi_device_clear_enumerated(to_acpi_device_node(fwnode));
}
- if (ACPI_COMPANION(&spi->dev))
- acpi_device_clear_enumerated(ACPI_COMPANION(&spi->dev));
device_remove_software_node(&spi->dev);
device_del(&spi->dev);
spi_cleanup(spi);
@@ -889,7 +949,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
* spi_res_alloc - allocate a spi resource that is life-cycle managed
* during the processing of a spi_message while using
* spi_transfer_one
- * @spi: the spi device for which we allocate memory
+ * @spi: the SPI device for which we allocate memory
* @release: the release code to execute for this resource
* @size: size to alloc and return
* @gfp: GFP allocation flags
@@ -915,23 +975,20 @@ static void *spi_res_alloc(struct spi_device *spi, spi_res_release_t release,
}
/**
- * spi_res_free - free an spi resource
+ * spi_res_free - free an SPI resource
* @res: pointer to the custom data of a resource
*/
static void spi_res_free(void *res)
{
struct spi_res *sres = container_of(res, struct spi_res, data);
- if (!res)
- return;
-
WARN_ON(!list_empty(&sres->entry));
kfree(sres);
}
/**
* spi_res_add - add a spi_res to the spi_message
- * @message: the spi message
+ * @message: the SPI message
* @res: the spi_resource
*/
static void spi_res_add(struct spi_message *message, void *res)
@@ -943,7 +1000,7 @@ static void spi_res_add(struct spi_message *message, void *res)
}
/**
- * spi_res_release - release all spi resources for this message
+ * spi_res_release - release all SPI resources for this message
* @ctlr: the @spi_controller
* @message: the @spi_message
*/
@@ -962,58 +1019,97 @@ static void spi_res_release(struct spi_controller *ctlr, struct spi_message *mes
}
/*-------------------------------------------------------------------------*/
+#define spi_for_each_valid_cs(spi, idx) \
+ for (idx = 0; idx < spi->num_chipselect; idx++) \
+ if (!(spi->cs_index_mask & BIT(idx))) {} else
+
+static inline bool spi_is_last_cs(struct spi_device *spi)
+{
+ u8 idx;
+ bool last = false;
+
+ spi_for_each_valid_cs(spi, idx) {
+ if (spi->controller->last_cs[idx] == spi_get_chipselect(spi, idx))
+ last = true;
+ }
+ return last;
+}
+
+static void spi_toggle_csgpiod(struct spi_device *spi, u8 idx, bool enable, bool activate)
+{
+ /*
+ * Historically ACPI has no means of the GPIO polarity and
+ * thus the SPISerialBus() resource defines it on the per-chip
+ * basis. In order to avoid a chain of negations, the GPIO
+ * polarity is considered being Active High. Even for the cases
+ * when _DSD() is involved (in the updated versions of ACPI)
+ * the GPIO CS polarity must be defined Active High to avoid
+ * ambiguity. That's why we use enable, that takes SPI_CS_HIGH
+ * into account.
+ */
+ if (is_acpi_device_node(dev_fwnode(&spi->dev)))
+ gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx), !enable);
+ else
+ /* Polarity handled by GPIO library */
+ gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx), activate);
+
+ if (activate)
+ spi_delay_exec(&spi->cs_setup, NULL);
+ else
+ spi_delay_exec(&spi->cs_inactive, NULL);
+}
static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
{
bool activate = enable;
+ u8 idx;
/*
* Avoid calling into the driver (or doing delays) if the chip select
* isn't actually changing from the last time this was called.
*/
- if (!force && ((enable && spi->controller->last_cs == spi_get_chipselect(spi, 0)) ||
- (!enable && spi->controller->last_cs != spi_get_chipselect(spi, 0))) &&
+ if (!force && (enable == spi_is_last_cs(spi)) &&
+ (spi->controller->last_cs_index_mask == spi->cs_index_mask) &&
(spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH)))
return;
trace_spi_set_cs(spi, activate);
- spi->controller->last_cs = enable ? spi_get_chipselect(spi, 0) : -1;
+ spi->controller->last_cs_index_mask = spi->cs_index_mask;
+ for (idx = 0; idx < SPI_DEVICE_CS_CNT_MAX; idx++) {
+ if (enable && idx < spi->num_chipselect)
+ spi->controller->last_cs[idx] = spi_get_chipselect(spi, 0);
+ else
+ spi->controller->last_cs[idx] = SPI_INVALID_CS;
+ }
+
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
+ if (spi->controller->last_cs_mode_high)
+ enable = !enable;
- if ((spi_get_csgpiod(spi, 0) || !spi->controller->set_cs_timing) && !activate)
+ /*
+ * Handle chip select delays for GPIO based CS or controllers without
+ * programmable chip select timing.
+ */
+ if ((spi_is_csgpiod(spi) || !spi->controller->set_cs_timing) && !activate)
spi_delay_exec(&spi->cs_hold, NULL);
- if (spi->mode & SPI_CS_HIGH)
- enable = !enable;
-
- if (spi_get_csgpiod(spi, 0)) {
+ if (spi_is_csgpiod(spi)) {
if (!(spi->mode & SPI_NO_CS)) {
- /*
- * Historically ACPI has no means of the GPIO polarity and
- * thus the SPISerialBus() resource defines it on the per-chip
- * basis. In order to avoid a chain of negations, the GPIO
- * polarity is considered being Active High. Even for the cases
- * when _DSD() is involved (in the updated versions of ACPI)
- * the GPIO CS polarity must be defined Active High to avoid
- * ambiguity. That's why we use enable, that takes SPI_CS_HIGH
- * into account.
- */
- if (has_acpi_companion(&spi->dev))
- gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), !enable);
- else
- /* Polarity handled by GPIO library */
- gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), activate);
+ spi_for_each_valid_cs(spi, idx) {
+ if (spi_get_csgpiod(spi, idx))
+ spi_toggle_csgpiod(spi, idx, enable, activate);
+ }
}
- /* Some SPI masters need both GPIO CS & slave_select */
- if ((spi->controller->flags & SPI_MASTER_GPIO_SS) &&
+ /* Some SPI controllers need both GPIO CS & ->set_cs() */
+ if ((spi->controller->flags & SPI_CONTROLLER_GPIO_SS) &&
spi->controller->set_cs)
spi->controller->set_cs(spi, !enable);
} else if (spi->controller->set_cs) {
spi->controller->set_cs(spi, !enable);
}
- if (spi_get_csgpiod(spi, 0) || !spi->controller->set_cs_timing) {
+ if (spi_is_csgpiod(spi) || !spi->controller->set_cs_timing) {
if (activate)
spi_delay_exec(&spi->cs_setup, NULL);
else
@@ -1111,12 +1207,10 @@ static void spi_unmap_buf_attrs(struct spi_controller *ctlr,
enum dma_data_direction dir,
unsigned long attrs)
{
- if (sgt->orig_nents) {
- dma_unmap_sgtable(dev, sgt, dir, attrs);
- sg_free_table(sgt);
- sgt->orig_nents = 0;
- sgt->nents = 0;
- }
+ dma_unmap_sgtable(dev, sgt, dir, attrs);
+ sg_free_table(sgt);
+ sgt->orig_nents = 0;
+ sgt->nents = 0;
}
void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev,
@@ -1148,6 +1242,7 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
else
rx_dev = ctlr->dev.parent;
+ ret = -ENOMSG;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
/* The sync is done before each transfer. */
unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC;
@@ -1162,6 +1257,8 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
attrs);
if (ret != 0)
return ret;
+
+ xfer->tx_sg_mapped = true;
}
if (xfer->rx_buf != NULL) {
@@ -1175,12 +1272,16 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
return ret;
}
+
+ xfer->rx_sg_mapped = true;
}
}
+ /* No transfer has been mapped, bail out with success */
+ if (ret)
+ return 0;
ctlr->cur_rx_dma_dev = rx_dev;
ctlr->cur_tx_dma_dev = tx_dev;
- ctlr->cur_msg_mapped = true;
return 0;
}
@@ -1191,24 +1292,21 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg)
struct device *tx_dev = ctlr->cur_tx_dma_dev;
struct spi_transfer *xfer;
- if (!ctlr->cur_msg_mapped || !ctlr->can_dma)
- return 0;
-
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
/* The sync has already been done after each transfer. */
unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC;
- if (!ctlr->can_dma(ctlr, msg->spi, xfer))
- continue;
+ if (xfer->rx_sg_mapped)
+ spi_unmap_buf_attrs(ctlr, rx_dev, &xfer->rx_sg,
+ DMA_FROM_DEVICE, attrs);
+ xfer->rx_sg_mapped = false;
- spi_unmap_buf_attrs(ctlr, rx_dev, &xfer->rx_sg,
- DMA_FROM_DEVICE, attrs);
- spi_unmap_buf_attrs(ctlr, tx_dev, &xfer->tx_sg,
- DMA_TO_DEVICE, attrs);
+ if (xfer->tx_sg_mapped)
+ spi_unmap_buf_attrs(ctlr, tx_dev, &xfer->tx_sg,
+ DMA_TO_DEVICE, attrs);
+ xfer->tx_sg_mapped = false;
}
- ctlr->cur_msg_mapped = false;
-
return 0;
}
@@ -1218,12 +1316,9 @@ static void spi_dma_sync_for_device(struct spi_controller *ctlr,
struct device *rx_dev = ctlr->cur_rx_dma_dev;
struct device *tx_dev = ctlr->cur_tx_dma_dev;
- if (!ctlr->cur_msg_mapped)
- return;
-
- if (xfer->tx_sg.orig_nents)
+ if (xfer->tx_sg_mapped)
dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
- if (xfer->rx_sg.orig_nents)
+ if (xfer->rx_sg_mapped)
dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
}
@@ -1233,12 +1328,9 @@ static void spi_dma_sync_for_cpu(struct spi_controller *ctlr,
struct device *rx_dev = ctlr->cur_rx_dma_dev;
struct device *tx_dev = ctlr->cur_tx_dma_dev;
- if (!ctlr->cur_msg_mapped)
- return;
-
- if (xfer->rx_sg.orig_nents)
+ if (xfer->rx_sg_mapped)
dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
- if (xfer->tx_sg.orig_nents)
+ if (xfer->tx_sg_mapped)
dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
}
#else /* !CONFIG_HAS_DMA */
@@ -1345,7 +1437,7 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
u32 speed_hz = xfer->speed_hz;
unsigned long long ms;
- if (spi_controller_is_slave(ctlr)) {
+ if (spi_controller_is_target(ctlr)) {
if (wait_for_completion_interruptible(&ctlr->xfer_completion)) {
dev_dbg(&msg->spi->dev, "SPI transfer interrupted\n");
return -EINTR;
@@ -1381,6 +1473,9 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
"SPI transfer timed out\n");
return -ETIMEDOUT;
}
+
+ if (xfer->error & SPI_TRANS_FAIL_IO)
+ return -EIO;
}
return 0;
@@ -1395,10 +1490,7 @@ static void _spi_transfer_delay_ns(u32 ns)
} else {
u32 us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
- if (us <= 10)
- udelay(us);
- else
- usleep_range(us, us + DIV_ROUND_UP(us, 10));
+ fsleep(us);
}
}
@@ -1424,7 +1516,7 @@ int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
return -EINVAL;
/*
* If there is unknown effective speed, approximate it
- * by underestimating with half of the requested hz.
+ * by underestimating with half of the requested Hz.
*/
hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
if (!hz)
@@ -1516,8 +1608,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
trace_spi_transfer_start(msg, xfer);
- spi_statistics_add_transfer_stats(statm, xfer, ctlr);
- spi_statistics_add_transfer_stats(stats, xfer, ctlr);
+ spi_statistics_add_transfer_stats(statm, xfer, msg);
+ spi_statistics_add_transfer_stats(stats, xfer, msg);
if (!ctlr->ptp_sts_supported) {
xfer->ptp_sts_word_pre = 0;
@@ -1533,8 +1625,8 @@ fallback_pio:
if (ret < 0) {
spi_dma_sync_for_cpu(ctlr, xfer);
- if (ctlr->cur_msg_mapped &&
- (xfer->error & SPI_TRANS_FAIL_NO_START)) {
+ if ((xfer->tx_sg_mapped || xfer->rx_sg_mapped) &&
+ (xfer->error & SPI_TRANS_FAIL_NO_START)) {
__spi_unmap_msg(ctlr, msg);
ctlr->fallback = true;
xfer->error &= ~SPI_TRANS_FAIL_NO_START;
@@ -1627,7 +1719,6 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
static void spi_idle_runtime_pm(struct spi_controller *ctlr)
{
if (ctlr->auto_runtime_pm) {
- pm_runtime_mark_last_busy(ctlr->dev.parent);
pm_runtime_put_autosuspend(ctlr->dev.parent);
}
}
@@ -1644,6 +1735,10 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr,
pm_runtime_put_noidle(ctlr->dev.parent);
dev_err(&ctlr->dev, "Failed to power device: %d\n",
ret);
+
+ msg->status = ret;
+ spi_finalize_current_message(ctlr);
+
return ret;
}
}
@@ -1670,15 +1765,6 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr,
trace_spi_message_start(msg);
- ret = spi_split_transfers_maxsize(ctlr, msg,
- spi_max_transfer_size(msg->spi),
- GFP_KERNEL | GFP_DMA);
- if (ret) {
- msg->status = ret;
- spi_finalize_current_message(ctlr);
- return ret;
- }
-
if (ctlr->prepare_message) {
ret = ctlr->prepare_message(ctlr, msg);
if (ret) {
@@ -1739,11 +1825,11 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr,
}
/**
- * __spi_pump_messages - function which processes spi message queue
+ * __spi_pump_messages - function which processes SPI message queue
* @ctlr: controller to process queue for
* @in_kthread: true if we are in the context of the message pump thread
*
- * This function checks if there is any spi message in the queue that
+ * This function checks if there is any SPI message in the queue that
* needs processing and if so call out to the driver to initialize hardware
* and transfer each message.
*
@@ -1758,7 +1844,7 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
unsigned long flags;
int ret;
- /* Take the IO mutex */
+ /* Take the I/O mutex */
mutex_lock(&ctlr->io_mutex);
/* Lock queue */
@@ -1960,7 +2046,7 @@ static int spi_init_queue(struct spi_controller *ctlr)
ctlr->busy = false;
ctlr->queue_empty = true;
- ctlr->kworker = kthread_create_worker(0, dev_name(&ctlr->dev));
+ ctlr->kworker = kthread_run_worker(0, dev_name(&ctlr->dev));
if (IS_ERR(ctlr->kworker)) {
dev_err(&ctlr->dev, "failed to create message pump kworker\n");
return PTR_ERR(ctlr->kworker);
@@ -2006,6 +2092,44 @@ struct spi_message *spi_get_next_queued_message(struct spi_controller *ctlr)
}
EXPORT_SYMBOL_GPL(spi_get_next_queued_message);
+/*
+ * __spi_unoptimize_message - shared implementation of spi_unoptimize_message()
+ * and spi_maybe_unoptimize_message()
+ * @msg: the message to unoptimize
+ *
+ * Peripheral drivers should use spi_unoptimize_message() and callers inside
+ * core should use spi_maybe_unoptimize_message() rather than calling this
+ * function directly.
+ *
+ * It is not valid to call this on a message that is not currently optimized.
+ */
+static void __spi_unoptimize_message(struct spi_message *msg)
+{
+ struct spi_controller *ctlr = msg->spi->controller;
+
+ if (ctlr->unoptimize_message)
+ ctlr->unoptimize_message(msg);
+
+ spi_res_release(ctlr, msg);
+
+ msg->optimized = false;
+ msg->opt_state = NULL;
+}
+
+/*
+ * spi_maybe_unoptimize_message - unoptimize msg not managed by a peripheral
+ * @msg: the message to unoptimize
+ *
+ * This function is used to unoptimize a message if and only if it was
+ * optimized by the core (via spi_maybe_optimize_message()).
+ */
+static void spi_maybe_unoptimize_message(struct spi_message *msg)
+{
+ if (!msg->pre_optimized && msg->optimized &&
+ !msg->spi->controller->defer_optimize_message)
+ __spi_unoptimize_message(msg);
+}
+
/**
* spi_finalize_current_message() - the current message is complete
* @ctlr: the controller to return the message to
@@ -2034,15 +2158,6 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
spi_unmap_msg(ctlr, mesg);
- /*
- * In the prepare_messages callback the SPI bus has the opportunity
- * to split a transfer to smaller chunks.
- *
- * Release the split transfers here since spi_map_msg() is done on
- * the split transfers.
- */
- spi_res_release(ctlr, mesg);
-
if (mesg->prepared && ctlr->unprepare_message) {
ret = ctlr->unprepare_message(ctlr, mesg);
if (ret) {
@@ -2053,6 +2168,8 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
mesg->prepared = false;
+ spi_maybe_unoptimize_message(mesg);
+
WRITE_ONCE(ctlr->cur_msg_incomplete, false);
smp_mb(); /* See __spi_pump_transfer_message()... */
if (READ_ONCE(ctlr->cur_msg_need_completion))
@@ -2088,11 +2205,8 @@ static int spi_start_queue(struct spi_controller *ctlr)
static int spi_stop_queue(struct spi_controller *ctlr)
{
+ unsigned int limit = 500;
unsigned long flags;
- unsigned limit = 500;
- int ret = 0;
-
- spin_lock_irqsave(&ctlr->queue_lock, flags);
/*
* This is a bit lame, but is optimized for the common execution path.
@@ -2100,24 +2214,18 @@ static int spi_stop_queue(struct spi_controller *ctlr)
* execution path (pump_messages) would be required to call wake_up or
* friends on every SPI message. Do this instead.
*/
- while ((!list_empty(&ctlr->queue) || ctlr->busy) && limit--) {
+ do {
+ spin_lock_irqsave(&ctlr->queue_lock, flags);
+ if (list_empty(&ctlr->queue) && !ctlr->busy) {
+ ctlr->running = false;
+ spin_unlock_irqrestore(&ctlr->queue_lock, flags);
+ return 0;
+ }
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
usleep_range(10000, 11000);
- spin_lock_irqsave(&ctlr->queue_lock, flags);
- }
-
- if (!list_empty(&ctlr->queue) || ctlr->busy)
- ret = -EBUSY;
- else
- ctlr->running = false;
-
- spin_unlock_irqrestore(&ctlr->queue_lock, flags);
+ } while (--limit);
- if (ret) {
- dev_warn(&ctlr->dev, "could not stop message queue\n");
- return ret;
- }
- return ret;
+ return -EBUSY;
}
static int spi_destroy_queue(struct spi_controller *ctlr)
@@ -2169,8 +2277,8 @@ static int __spi_queued_transfer(struct spi_device *spi,
/**
* spi_queued_transfer - transfer function for queued transfers
- * @spi: spi device which is requesting transfer
- * @msg: spi message which is to handled is queued to driver queue
+ * @spi: SPI device which is requesting transfer
+ * @msg: SPI message which is to handled is queued to driver queue
*
* Return: zero on success, else a negative error code.
*/
@@ -2246,8 +2354,8 @@ static void of_spi_parse_dt_cs_delay(struct device_node *nc,
static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
struct device_node *nc)
{
- u32 value;
- int rc;
+ u32 value, cs[SPI_DEVICE_CS_CNT_MAX];
+ int rc, idx;
/* Mode (clock phase/polarity/etc.) */
if (of_property_read_bool(nc, "spi-cpha"))
@@ -2310,7 +2418,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
}
}
- if (spi_controller_is_slave(ctlr)) {
+ if (spi_controller_is_target(ctlr)) {
if (!of_node_name_eq(nc, "slave")) {
dev_err(&ctlr->dev, "%pOF is not called 'slave'\n",
nc);
@@ -2320,13 +2428,29 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
}
/* Device address */
- rc = of_property_read_u32(nc, "reg", &value);
- if (rc) {
+ rc = of_property_read_variable_u32_array(nc, "reg", &cs[0], 1,
+ SPI_DEVICE_CS_CNT_MAX);
+ if (rc < 0) {
dev_err(&ctlr->dev, "%pOF has no valid 'reg' property (%d)\n",
nc, rc);
return rc;
}
- spi_set_chipselect(spi, 0, value);
+
+ if ((of_property_present(nc, "parallel-memories")) &&
+ (!(ctlr->flags & SPI_CONTROLLER_MULTI_CS))) {
+ dev_err(&ctlr->dev, "SPI controller doesn't support multi CS\n");
+ return -EINVAL;
+ }
+
+ spi->num_chipselect = rc;
+ for (idx = 0; idx < rc; idx++)
+ spi_set_chipselect(spi, idx, cs[idx]);
+
+ /*
+ * By default spi->chip_select[0] will hold the physical CS number,
+ * so set bit 0 in spi->cs_index_mask.
+ */
+ spi->cs_index_mask = BIT(0);
/* Device speed */
if (!of_property_read_u32(nc, "spi-max-frequency", &value))
@@ -2392,16 +2516,13 @@ err_out:
* @ctlr: Pointer to spi_controller device
*
* Registers an spi_device for each child node of controller node which
- * represents a valid SPI slave.
+ * represents a valid SPI target device.
*/
static void of_register_spi_devices(struct spi_controller *ctlr)
{
struct spi_device *spi;
struct device_node *nc;
- if (!ctlr->dev.of_node)
- return;
-
for_each_available_child_of_node(ctlr->dev.of_node, nc) {
if (of_node_test_and_set_flag(nc, OF_POPULATED))
continue;
@@ -2432,11 +2553,12 @@ static void of_register_spi_devices(struct spi_controller *ctlr) { }
struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
u8 chip_select)
{
+ struct spi_controller *ctlr = spi->controller;
struct spi_device *ancillary;
- int rc = 0;
+ int rc;
/* Alloc an spi_device */
- ancillary = spi_alloc_device(spi->controller);
+ ancillary = spi_alloc_device(ctlr);
if (!ancillary) {
rc = -ENOMEM;
goto err_out;
@@ -2450,9 +2572,16 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
/* Take over SPI mode/speed from SPI main device */
ancillary->max_speed_hz = spi->max_speed_hz;
ancillary->mode = spi->mode;
+ /*
+ * By default spi->chip_select[0] will hold the physical CS number,
+ * so set bit 0 in spi->cs_index_mask.
+ */
+ ancillary->cs_index_mask = BIT(0);
+
+ WARN_ON(!mutex_is_locked(&ctlr->add_lock));
/* Register the new device */
- rc = spi_add_device_locked(ancillary);
+ rc = __spi_add_device(ancillary);
if (rc) {
dev_err(&spi->dev, "failed to register ancillary device\n");
goto err_out;
@@ -2499,7 +2628,7 @@ static int acpi_spi_count(struct acpi_resource *ares, void *data)
* acpi_spi_count_resources - Count the number of SpiSerialBus resources
* @adev: ACPI device
*
- * Returns the number of SpiSerialBus resources in the ACPI-device's
+ * Return: the number of SpiSerialBus resources in the ACPI-device's
* resource-list; or a negative error code.
*/
int acpi_spi_count_resources(struct acpi_device *adev)
@@ -2547,8 +2676,6 @@ static void acpi_spi_parse_apple_properties(struct acpi_device *dev,
lookup->mode |= SPI_CPHA;
}
-static struct spi_controller *acpi_spi_find_controller_by_adev(struct acpi_device *adev);
-
static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
{
struct acpi_spi_lookup *lookup = data;
@@ -2573,7 +2700,7 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
return -ENODEV;
if (ctlr) {
- if (ACPI_HANDLE(ctlr->dev.parent) != parent_handle)
+ if (!device_match_acpi_handle(ctlr->dev.parent, parent_handle))
return -ENODEV;
} else {
struct acpi_device *adev;
@@ -2633,10 +2760,10 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data)
* @adev: ACPI Device for the spi device
* @index: Index of the spi resource inside the ACPI Node
*
- * This should be used to allocate a new spi device from and ACPI Node.
- * The caller is responsible for calling spi_add_device to register the spi device.
+ * This should be used to allocate a new SPI device from and ACPI Device node.
+ * The caller is responsible for calling spi_add_device to register the SPI device.
*
- * If ctlr is set to NULL, the Controller for the spi device will be looked up
+ * If ctlr is set to NULL, the Controller for the SPI device will be looked up
* using the resource.
* If index is set to -1, index is not used.
* Note: If index is -1, ctlr must be set.
@@ -2672,8 +2799,8 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
if (!lookup.max_speed_hz &&
ACPI_SUCCESS(acpi_get_parent(adev->handle, &parent_handle)) &&
- ACPI_HANDLE(lookup.ctlr->dev.parent) == parent_handle) {
- /* Apple does not use _CRS but nested devices for SPI slaves */
+ device_match_acpi_handle(lookup.ctlr->dev.parent, parent_handle)) {
+ /* Apple does not use _CRS but nested devices for SPI target devices */
acpi_spi_parse_apple_properties(adev, &lookup);
}
@@ -2687,12 +2814,18 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
return ERR_PTR(-ENOMEM);
}
+ spi_set_chipselect(spi, 0, lookup.chip_select);
+
ACPI_COMPANION_SET(&spi->dev, adev);
spi->max_speed_hz = lookup.max_speed_hz;
spi->mode |= lookup.mode;
spi->irq = lookup.irq;
spi->bits_per_word = lookup.bits_per_word;
- spi_set_chipselect(spi, 0, lookup.chip_select);
+ /*
+ * By default spi->chip_select[0] will hold the physical CS number,
+ * so set bit 0 in spi->cs_index_mask.
+ */
+ spi->cs_index_mask = BIT(0);
return spi;
}
@@ -2718,6 +2851,15 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr,
acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias,
sizeof(spi->modalias));
+ /*
+ * This gets re-tried in spi_probe() for -EPROBE_DEFER handling in case
+ * the GPIO controller does not have a driver yet. This needs to be done
+ * here too, because this call sets the GPIO direction and/or bias.
+ * Setting these needs to be done even if there is no driver, in which
+ * case spi_probe() will never get called.
+ * TODO: ideally the setup of the GPIO should be handled in a generic
+ * manner in the ACPI/gpiolib core code.
+ */
if (spi->irq < 0)
spi->irq = acpi_dev_gpio_irq_get(adev, 0);
@@ -2761,7 +2903,7 @@ static void acpi_register_spi_devices(struct spi_controller *ctlr)
SPI_ACPI_ENUMERATE_MAX_DEPTH,
acpi_spi_add_device, NULL, ctlr, NULL);
if (ACPI_FAILURE(status))
- dev_warn(&ctlr->dev, "failed to enumerate SPI slaves\n");
+ dev_warn(&ctlr->dev, "failed to enumerate SPI target devices\n");
}
#else
static inline void acpi_register_spi_devices(struct spi_controller *ctlr) {}
@@ -2775,29 +2917,17 @@ static void spi_controller_release(struct device *dev)
kfree(ctlr);
}
-static struct class spi_master_class = {
+static const struct class spi_controller_class = {
.name = "spi_master",
.dev_release = spi_controller_release,
- .dev_groups = spi_master_groups,
+ .dev_groups = spi_controller_groups,
};
#ifdef CONFIG_SPI_SLAVE
/**
- * spi_slave_abort - abort the ongoing transfer request on an SPI slave
- * controller
+ * spi_target_abort - abort the ongoing transfer request on an SPI target controller
* @spi: device used for the current transfer
*/
-int spi_slave_abort(struct spi_device *spi)
-{
- struct spi_controller *ctlr = spi->controller;
-
- if (spi_controller_is_slave(ctlr) && ctlr->slave_abort)
- return ctlr->slave_abort(ctlr);
-
- return -ENOTSUPP;
-}
-EXPORT_SYMBOL_GPL(spi_slave_abort);
-
int spi_target_abort(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
@@ -2815,10 +2945,13 @@ static ssize_t slave_show(struct device *dev, struct device_attribute *attr,
struct spi_controller *ctlr = container_of(dev, struct spi_controller,
dev);
struct device *child;
+ int ret;
child = device_find_any_child(&ctlr->dev);
- return sprintf(buf, "%s\n",
- child ? to_spi_device(child)->modalias : NULL);
+ ret = sysfs_emit(buf, "%s\n", child ? to_spi_device(child)->modalias : NULL);
+ put_device(child);
+
+ return ret;
}
static ssize_t slave_store(struct device *dev, struct device_attribute *attr,
@@ -2837,13 +2970,13 @@ static ssize_t slave_store(struct device *dev, struct device_attribute *attr,
child = device_find_any_child(&ctlr->dev);
if (child) {
- /* Remove registered slave */
+ /* Remove registered target device */
device_unregister(child);
put_device(child);
}
if (strcmp(name, "(null)")) {
- /* Register new slave */
+ /* Register new target device */
spi = spi_alloc_device(ctlr);
if (!spi)
return -ENOMEM;
@@ -2862,40 +2995,40 @@ static ssize_t slave_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RW(slave);
-static struct attribute *spi_slave_attrs[] = {
+static struct attribute *spi_target_attrs[] = {
&dev_attr_slave.attr,
NULL,
};
-static const struct attribute_group spi_slave_group = {
- .attrs = spi_slave_attrs,
+static const struct attribute_group spi_target_group = {
+ .attrs = spi_target_attrs,
};
-static const struct attribute_group *spi_slave_groups[] = {
+static const struct attribute_group *spi_target_groups[] = {
&spi_controller_statistics_group,
- &spi_slave_group,
+ &spi_target_group,
NULL,
};
-static struct class spi_slave_class = {
+static const struct class spi_target_class = {
.name = "spi_slave",
.dev_release = spi_controller_release,
- .dev_groups = spi_slave_groups,
+ .dev_groups = spi_target_groups,
};
#else
-extern struct class spi_slave_class; /* dummy */
+extern struct class spi_target_class; /* dummy */
#endif
/**
- * __spi_alloc_controller - allocate an SPI master or slave controller
+ * __spi_alloc_controller - allocate an SPI host or target controller
* @dev: the controller, possibly using the platform_bus
* @size: how much zeroed driver-private data to allocate; the pointer to this
* memory is in the driver_data field of the returned device, accessible
* with spi_controller_get_devdata(); the memory is cacheline aligned;
* drivers granting DMA access to portions of their private data need to
* round up @size using ALIGN(size, dma_get_cache_alignment()).
- * @slave: flag indicating whether to allocate an SPI master (false) or SPI
- * slave (true) controller
+ * @target: flag indicating whether to allocate an SPI host (false) or SPI target (true)
+ * controller
* Context: can sleep
*
* This call is used only by SPI controller drivers, which are the
@@ -2912,7 +3045,7 @@ extern struct class spi_slave_class; /* dummy */
* Return: the SPI controller structure on success, else NULL.
*/
struct spi_controller *__spi_alloc_controller(struct device *dev,
- unsigned int size, bool slave)
+ unsigned int size, bool target)
{
struct spi_controller *ctlr;
size_t ctlr_size = ALIGN(sizeof(*ctlr), dma_get_cache_alignment());
@@ -2933,11 +3066,11 @@ struct spi_controller *__spi_alloc_controller(struct device *dev,
mutex_init(&ctlr->add_lock);
ctlr->bus_num = -1;
ctlr->num_chipselect = 1;
- ctlr->slave = slave;
- if (IS_ENABLED(CONFIG_SPI_SLAVE) && slave)
- ctlr->dev.class = &spi_slave_class;
+ ctlr->target = target;
+ if (IS_ENABLED(CONFIG_SPI_SLAVE) && target)
+ ctlr->dev.class = &spi_target_class;
else
- ctlr->dev.class = &spi_master_class;
+ ctlr->dev.class = &spi_controller_class;
ctlr->dev.parent = dev;
pm_suspend_ignore_children(&ctlr->dev, true);
spi_controller_set_devdata(ctlr, (void *)ctlr + ctlr_size);
@@ -2955,7 +3088,7 @@ static void devm_spi_release_controller(struct device *dev, void *ctlr)
* __devm_spi_alloc_controller - resource-managed __spi_alloc_controller()
* @dev: physical device of SPI controller
* @size: how much zeroed driver-private data to allocate
- * @slave: whether to allocate an SPI master (false) or SPI slave (true)
+ * @target: whether to allocate an SPI host (false) or SPI target (true) controller
* Context: can sleep
*
* Allocate an SPI controller and automatically release a reference on it
@@ -2968,7 +3101,7 @@ static void devm_spi_release_controller(struct device *dev, void *ctlr)
*/
struct spi_controller *__devm_spi_alloc_controller(struct device *dev,
unsigned int size,
- bool slave)
+ bool target)
{
struct spi_controller **ptr, *ctlr;
@@ -2977,7 +3110,7 @@ struct spi_controller *__devm_spi_alloc_controller(struct device *dev,
if (!ptr)
return NULL;
- ctlr = __spi_alloc_controller(dev, size, slave);
+ ctlr = __spi_alloc_controller(dev, size, target);
if (ctlr) {
ctlr->devm_allocated = true;
*ptr = ctlr;
@@ -2991,8 +3124,8 @@ struct spi_controller *__devm_spi_alloc_controller(struct device *dev,
EXPORT_SYMBOL_GPL(__devm_spi_alloc_controller);
/**
- * spi_get_gpio_descs() - grab chip select GPIOs for the master
- * @ctlr: The SPI master to grab GPIO descriptors for
+ * spi_get_gpio_descs() - grab chip select GPIOs for the controller
+ * @ctlr: The SPI controller to grab GPIO descriptors for
*/
static int spi_get_gpio_descs(struct spi_controller *ctlr)
{
@@ -3056,7 +3189,7 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr)
ctlr->unused_native_cs = ffs(~native_cs_mask) - 1;
- if ((ctlr->flags & SPI_MASTER_GPIO_SS) && num_cs_gpios &&
+ if ((ctlr->flags & SPI_CONTROLLER_GPIO_SS) && num_cs_gpios &&
ctlr->max_native_cs && ctlr->unused_native_cs >= ctlr->max_native_cs) {
dev_err(dev, "No unused native chip select available\n");
return -EINVAL;
@@ -3084,10 +3217,24 @@ static int spi_controller_check_ops(struct spi_controller *ctlr)
return 0;
}
+/* Allocate dynamic bus number using Linux idr */
+static int spi_controller_id_alloc(struct spi_controller *ctlr, int start, int end)
+{
+ int id;
+
+ mutex_lock(&board_lock);
+ id = idr_alloc(&spi_controller_idr, ctlr, start, end, GFP_KERNEL);
+ mutex_unlock(&board_lock);
+ if (WARN(id < 0, "couldn't get idr"))
+ return id == -ENOSPC ? -EBUSY : id;
+ ctlr->bus_num = id;
+ return 0;
+}
+
/**
- * spi_register_controller - register SPI master or slave controller
- * @ctlr: initialized master, originally from spi_alloc_master() or
- * spi_alloc_slave()
+ * spi_register_controller - register SPI host or target controller
+ * @ctlr: initialized controller, originally from spi_alloc_host() or
+ * spi_alloc_target()
* Context: can sleep
*
* SPI controllers connect to their drivers using some non-SPI bus,
@@ -3111,8 +3258,9 @@ int spi_register_controller(struct spi_controller *ctlr)
{
struct device *dev = ctlr->dev.parent;
struct boardinfo *bi;
+ int first_dynamic;
int status;
- int id, first_dynamic;
+ int idx;
if (!dev)
return -ENODEV;
@@ -3125,27 +3273,13 @@ int spi_register_controller(struct spi_controller *ctlr)
if (status)
return status;
+ if (ctlr->bus_num < 0)
+ ctlr->bus_num = of_alias_get_id(ctlr->dev.of_node, "spi");
if (ctlr->bus_num >= 0) {
/* Devices with a fixed bus num must check-in with the num */
- mutex_lock(&board_lock);
- id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
- ctlr->bus_num + 1, GFP_KERNEL);
- mutex_unlock(&board_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id == -ENOSPC ? -EBUSY : id;
- ctlr->bus_num = id;
- } else if (ctlr->dev.of_node) {
- /* Allocate dynamic bus number using Linux idr */
- id = of_alias_get_id(ctlr->dev.of_node, "spi");
- if (id >= 0) {
- ctlr->bus_num = id;
- mutex_lock(&board_lock);
- id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
- ctlr->bus_num + 1, GFP_KERNEL);
- mutex_unlock(&board_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id == -ENOSPC ? -EBUSY : id;
- }
+ status = spi_controller_id_alloc(ctlr, ctlr->bus_num, ctlr->bus_num + 1);
+ if (status)
+ return status;
}
if (ctlr->bus_num < 0) {
first_dynamic = of_alias_get_highest_id("spi");
@@ -3154,13 +3288,9 @@ int spi_register_controller(struct spi_controller *ctlr)
else
first_dynamic++;
- mutex_lock(&board_lock);
- id = idr_alloc(&spi_master_idr, ctlr, first_dynamic,
- 0, GFP_KERNEL);
- mutex_unlock(&board_lock);
- if (WARN(id < 0, "couldn't get idr"))
- return id;
- ctlr->bus_num = id;
+ status = spi_controller_id_alloc(ctlr, first_dynamic, 0);
+ if (status)
+ return status;
}
ctlr->bus_lock_flag = 0;
init_completion(&ctlr->xfer_completion);
@@ -3174,7 +3304,7 @@ int spi_register_controller(struct spi_controller *ctlr)
*/
dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);
- if (!spi_controller_is_slave(ctlr) && ctlr->use_gpio_descriptors) {
+ if (!spi_controller_is_target(ctlr) && ctlr->use_gpio_descriptors) {
status = spi_get_gpio_descs(ctlr);
if (status)
goto free_bus_id;
@@ -3194,14 +3324,15 @@ int spi_register_controller(struct spi_controller *ctlr)
goto free_bus_id;
}
- /* Setting last_cs to -1 means no chip selected */
- ctlr->last_cs = -1;
+ /* Setting last_cs to SPI_INVALID_CS means no chip selected */
+ for (idx = 0; idx < SPI_DEVICE_CS_CNT_MAX; idx++)
+ ctlr->last_cs[idx] = SPI_INVALID_CS;
status = device_add(&ctlr->dev);
if (status < 0)
goto free_bus_id;
dev_dbg(dev, "registered %s %s\n",
- spi_controller_is_slave(ctlr) ? "slave" : "master",
+ spi_controller_is_target(ctlr) ? "target" : "host",
dev_name(&ctlr->dev));
/*
@@ -3241,7 +3372,7 @@ destroy_queue:
spi_destroy_queue(ctlr);
free_bus_id:
mutex_lock(&board_lock);
- idr_remove(&spi_master_idr, ctlr->bus_num);
+ idr_remove(&spi_controller_idr, ctlr->bus_num);
mutex_unlock(&board_lock);
return status;
}
@@ -3253,11 +3384,10 @@ static void devm_spi_unregister(struct device *dev, void *res)
}
/**
- * devm_spi_register_controller - register managed SPI master or slave
- * controller
+ * devm_spi_register_controller - register managed SPI host or target controller
* @dev: device managing SPI controller
- * @ctlr: initialized controller, originally from spi_alloc_master() or
- * spi_alloc_slave()
+ * @ctlr: initialized controller, originally from spi_alloc_host() or
+ * spi_alloc_target()
* Context: can sleep
*
* Register a SPI device as with spi_register_controller() which will
@@ -3294,7 +3424,7 @@ static int __unregister(struct device *dev, void *null)
}
/**
- * spi_unregister_controller - unregister SPI master or slave controller
+ * spi_unregister_controller - unregister SPI host or target controller
* @ctlr: the controller being unregistered
* Context: can sleep
*
@@ -3318,7 +3448,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)
/* First make sure that this controller was ever added */
mutex_lock(&board_lock);
- found = idr_find(&spi_master_idr, id);
+ found = idr_find(&spi_controller_idr, id);
mutex_unlock(&board_lock);
if (ctlr->queued) {
if (spi_destroy_queue(ctlr))
@@ -3333,47 +3463,67 @@ void spi_unregister_controller(struct spi_controller *ctlr)
/* Free bus id */
mutex_lock(&board_lock);
if (found == ctlr)
- idr_remove(&spi_master_idr, id);
+ idr_remove(&spi_controller_idr, id);
mutex_unlock(&board_lock);
if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
mutex_unlock(&ctlr->add_lock);
- /* Release the last reference on the controller if its driver
- * has not yet been converted to devm_spi_alloc_master/slave().
+ /*
+ * Release the last reference on the controller if its driver
+ * has not yet been converted to devm_spi_alloc_host/target().
*/
if (!ctlr->devm_allocated)
put_device(&ctlr->dev);
}
EXPORT_SYMBOL_GPL(spi_unregister_controller);
+static inline int __spi_check_suspended(const struct spi_controller *ctlr)
+{
+ return ctlr->flags & SPI_CONTROLLER_SUSPENDED ? -ESHUTDOWN : 0;
+}
+
+static inline void __spi_mark_suspended(struct spi_controller *ctlr)
+{
+ mutex_lock(&ctlr->bus_lock_mutex);
+ ctlr->flags |= SPI_CONTROLLER_SUSPENDED;
+ mutex_unlock(&ctlr->bus_lock_mutex);
+}
+
+static inline void __spi_mark_resumed(struct spi_controller *ctlr)
+{
+ mutex_lock(&ctlr->bus_lock_mutex);
+ ctlr->flags &= ~SPI_CONTROLLER_SUSPENDED;
+ mutex_unlock(&ctlr->bus_lock_mutex);
+}
+
int spi_controller_suspend(struct spi_controller *ctlr)
{
- int ret;
+ int ret = 0;
/* Basically no-ops for non-queued controllers */
- if (!ctlr->queued)
- return 0;
-
- ret = spi_stop_queue(ctlr);
- if (ret)
- dev_err(&ctlr->dev, "queue stop failed\n");
+ if (ctlr->queued) {
+ ret = spi_stop_queue(ctlr);
+ if (ret)
+ dev_err(&ctlr->dev, "queue stop failed\n");
+ }
+ __spi_mark_suspended(ctlr);
return ret;
}
EXPORT_SYMBOL_GPL(spi_controller_suspend);
int spi_controller_resume(struct spi_controller *ctlr)
{
- int ret;
+ int ret = 0;
- if (!ctlr->queued)
- return 0;
-
- ret = spi_start_queue(ctlr);
- if (ret)
- dev_err(&ctlr->dev, "queue restart failed\n");
+ __spi_mark_resumed(ctlr);
+ if (ctlr->queued) {
+ ret = spi_start_queue(ctlr);
+ if (ret)
+ dev_err(&ctlr->dev, "queue restart failed\n");
+ }
return ret;
}
EXPORT_SYMBOL_GPL(spi_controller_resume);
@@ -3516,8 +3666,7 @@ static struct spi_replaced_transfers *spi_replace_transfers(
static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
struct spi_message *msg,
struct spi_transfer **xferp,
- size_t maxsize,
- gfp_t gfp)
+ size_t maxsize)
{
struct spi_transfer *xfer = *xferp, *xfers;
struct spi_replaced_transfers *srt;
@@ -3528,7 +3677,7 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
count = DIV_ROUND_UP(xfer->len, maxsize);
/* Create replacement */
- srt = spi_replace_transfers(msg, xfer, 1, count, NULL, 0, gfp);
+ srt = spi_replace_transfers(msg, xfer, 1, count, NULL, 0, GFP_KERNEL);
if (IS_ERR(srt))
return PTR_ERR(srt);
xfers = srt->inserted_transfers;
@@ -3539,9 +3688,6 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
* to the same values as *xferp, so tx_buf, rx_buf and len
* are all identical (as well as most others)
* so we just have to fix up len and the pointers.
- *
- * This also includes support for the depreciated
- * spi_message.is_dma_mapped interface.
*/
/*
@@ -3552,15 +3698,11 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
/* All the others need rx_buf/tx_buf also set */
for (i = 1, offset = maxsize; i < count; offset += maxsize, i++) {
- /* Update rx_buf, tx_buf and dma */
+ /* Update rx_buf, tx_buf and DMA */
if (xfers[i].rx_buf)
xfers[i].rx_buf += offset;
- if (xfers[i].rx_dma)
- xfers[i].rx_dma += offset;
if (xfers[i].tx_buf)
xfers[i].tx_buf += offset;
- if (xfers[i].tx_dma)
- xfers[i].tx_dma += offset;
/* Update length */
xfers[i].len = min(maxsize, xfers[i].len - offset);
@@ -3588,14 +3730,16 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
* @ctlr: the @spi_controller for this transfer
* @msg: the @spi_message to transform
* @maxsize: the maximum when to apply this
- * @gfp: GFP allocation flags
+ *
+ * This function allocates resources that are automatically freed during the
+ * spi message unoptimize phase so this function should only be called from
+ * optimize_message callbacks.
*
* Return: status of transformation
*/
int spi_split_transfers_maxsize(struct spi_controller *ctlr,
struct spi_message *msg,
- size_t maxsize,
- gfp_t gfp)
+ size_t maxsize)
{
struct spi_transfer *xfer;
int ret;
@@ -3610,7 +3754,7 @@ int spi_split_transfers_maxsize(struct spi_controller *ctlr,
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (xfer->len > maxsize) {
ret = __spi_split_transfer_maxsize(ctlr, msg, &xfer,
- maxsize, gfp);
+ maxsize);
if (ret)
return ret;
}
@@ -3622,20 +3766,22 @@ EXPORT_SYMBOL_GPL(spi_split_transfers_maxsize);
/**
- * spi_split_transfers_maxwords - split spi transfers into multiple transfers
+ * spi_split_transfers_maxwords - split SPI transfers into multiple transfers
* when an individual transfer exceeds a
* certain number of SPI words
* @ctlr: the @spi_controller for this transfer
* @msg: the @spi_message to transform
* @maxwords: the number of words to limit each transfer to
- * @gfp: GFP allocation flags
+ *
+ * This function allocates resources that are automatically freed during the
+ * spi message unoptimize phase so this function should only be called from
+ * optimize_message callbacks.
*
* Return: status of transformation
*/
int spi_split_transfers_maxwords(struct spi_controller *ctlr,
struct spi_message *msg,
- size_t maxwords,
- gfp_t gfp)
+ size_t maxwords)
{
struct spi_transfer *xfer;
@@ -3650,16 +3796,10 @@ int spi_split_transfers_maxwords(struct spi_controller *ctlr,
size_t maxsize;
int ret;
- if (xfer->bits_per_word <= 8)
- maxsize = maxwords;
- else if (xfer->bits_per_word <= 16)
- maxsize = 2 * maxwords;
- else
- maxsize = 4 * maxwords;
-
+ maxsize = maxwords * spi_bpw_to_bytes(xfer->bits_per_word);
if (xfer->len > maxsize) {
ret = __spi_split_transfer_maxsize(ctlr, msg, &xfer,
- maxsize, gfp);
+ maxsize);
if (ret)
return ret;
}
@@ -3671,7 +3811,8 @@ EXPORT_SYMBOL_GPL(spi_split_transfers_maxwords);
/*-------------------------------------------------------------------------*/
-/* Core methods for SPI controller protocol drivers. Some of the
+/*
+ * Core methods for SPI controller protocol drivers. Some of the
* other core methods are currently defined as inline functions.
*/
@@ -3711,7 +3852,6 @@ static int spi_set_cs_timing(struct spi_device *spi)
}
status = spi->controller->set_cs_timing(spi);
- pm_runtime_mark_last_busy(parent);
pm_runtime_put_autosuspend(parent);
} else {
status = spi->controller->set_cs_timing(spi);
@@ -3731,7 +3871,7 @@ static int spi_set_cs_timing(struct spi_device *spi)
* changes those settings, and must be called from a context that can sleep.
* Except for SPI_CS_HIGH, which takes effect immediately, the changes take
* effect the next time the device is selected and data is transferred to
- * or from it. When this function returns, the spi device is deselected.
+ * or from it. When this function returns, the SPI device is deselected.
*
* Note that this call will fail if the protocol driver specifies an option
* that the underlying controller or its driver does not support. For
@@ -3743,7 +3883,7 @@ static int spi_set_cs_timing(struct spi_device *spi)
int spi_setup(struct spi_device *spi)
{
unsigned bad_bits, ugly_bits;
- int status = 0;
+ int status;
/*
* Check mode to prevent that any two of DUAL, QUAD and NO_MOSI/MISO
@@ -3762,6 +3902,12 @@ int spi_setup(struct spi_device *spi)
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL |
SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
return -EINVAL;
+ /* Check against conflicting MOSI idle configuration */
+ if ((spi->mode & SPI_MOSI_IDLE_LOW) && (spi->mode & SPI_MOSI_IDLE_HIGH)) {
+ dev_err(&spi->dev,
+ "setup: MOSI configured to idle low and high at the same time.\n");
+ return -EINVAL;
+ }
/*
* Help drivers fail *cleanly* when they need options
* that aren't supported with their current controller.
@@ -3840,7 +3986,6 @@ int spi_setup(struct spi_device *spi)
status = 0;
spi_set_cs(spi, false, true);
- pm_runtime_mark_last_busy(spi->controller->dev.parent);
pm_runtime_put_autosuspend(spi->controller->dev.parent);
} else {
spi_set_cs(spi, false, true);
@@ -3897,35 +4042,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
if (list_empty(&message->transfers))
return -EINVAL;
- /*
- * If an SPI controller does not support toggling the CS line on each
- * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
- * for the CS line, we can emulate the CS-per-word hardware function by
- * splitting transfers into one-word transfers and ensuring that
- * cs_change is set for each transfer.
- */
- if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) ||
- spi_get_csgpiod(spi, 0))) {
- size_t maxsize;
- int ret;
-
- maxsize = (spi->bits_per_word + 7) / 8;
-
- /* spi_split_transfers_maxsize() requires message->spi */
- message->spi = spi;
-
- ret = spi_split_transfers_maxsize(ctlr, message, maxsize,
- GFP_KERNEL);
- if (ret)
- return ret;
-
- list_for_each_entry(xfer, &message->transfers, transfer_list) {
- /* Don't change cs_change on the last entry in the list */
- if (list_is_last(&xfer->transfer_list, &message->transfers))
- break;
- xfer->cs_change = 1;
- }
- }
+ message->spi = spi;
/*
* Half-duplex links include original MicroWire, and ones with
@@ -3971,6 +4088,13 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
if (__spi_validate_bits_per_word(ctlr, xfer->bits_per_word))
return -EINVAL;
+ /* DDR mode is supported only if controller has dtr_caps=true.
+ * default considered as SDR mode for SPI and QSPI controller.
+ * Note: This is applicable only to QSPI controller.
+ */
+ if (xfer->dtr_mode && !ctlr->dtr_caps)
+ return -EINVAL;
+
/*
* SPI transfer length should be multiple of SPI word size
* where SPI word size should be power-of-two multiple.
@@ -4004,13 +4128,17 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
return -EINVAL;
if (xfer->tx_nbits != SPI_NBITS_SINGLE &&
xfer->tx_nbits != SPI_NBITS_DUAL &&
- xfer->tx_nbits != SPI_NBITS_QUAD)
+ xfer->tx_nbits != SPI_NBITS_QUAD &&
+ xfer->tx_nbits != SPI_NBITS_OCTAL)
return -EINVAL;
if ((xfer->tx_nbits == SPI_NBITS_DUAL) &&
- !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
+ !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL)))
return -EINVAL;
if ((xfer->tx_nbits == SPI_NBITS_QUAD) &&
- !(spi->mode & SPI_TX_QUAD))
+ !(spi->mode & (SPI_TX_QUAD | SPI_TX_OCTAL)))
+ return -EINVAL;
+ if ((xfer->tx_nbits == SPI_NBITS_OCTAL) &&
+ !(spi->mode & SPI_TX_OCTAL))
return -EINVAL;
}
/* Check transfer rx_nbits */
@@ -4019,18 +4147,31 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
return -EINVAL;
if (xfer->rx_nbits != SPI_NBITS_SINGLE &&
xfer->rx_nbits != SPI_NBITS_DUAL &&
- xfer->rx_nbits != SPI_NBITS_QUAD)
+ xfer->rx_nbits != SPI_NBITS_QUAD &&
+ xfer->rx_nbits != SPI_NBITS_OCTAL)
return -EINVAL;
if ((xfer->rx_nbits == SPI_NBITS_DUAL) &&
- !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
+ !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))
return -EINVAL;
if ((xfer->rx_nbits == SPI_NBITS_QUAD) &&
- !(spi->mode & SPI_RX_QUAD))
+ !(spi->mode & (SPI_RX_QUAD | SPI_RX_OCTAL)))
+ return -EINVAL;
+ if ((xfer->rx_nbits == SPI_NBITS_OCTAL) &&
+ !(spi->mode & SPI_RX_OCTAL))
return -EINVAL;
}
if (_spi_xfer_word_delay_update(xfer, spi))
return -EINVAL;
+
+ /* Make sure controller supports required offload features. */
+ if (xfer->offload_flags) {
+ if (!message->offload)
+ return -EINVAL;
+
+ if (xfer->offload_flags & ~message->offload->xfer_flags)
+ return -EINVAL;
+ }
}
message->status = -EINPROGRESS;
@@ -4038,6 +4179,182 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
return 0;
}
+/*
+ * spi_split_transfers - generic handling of transfer splitting
+ * @msg: the message to split
+ *
+ * Under certain conditions, a SPI controller may not support arbitrary
+ * transfer sizes or other features required by a peripheral. This function
+ * will split the transfers in the message into smaller transfers that are
+ * supported by the controller.
+ *
+ * Controllers with special requirements not covered here can also split
+ * transfers in the optimize_message() callback.
+ *
+ * Context: can sleep
+ * Return: zero on success, else a negative error code
+ */
+static int spi_split_transfers(struct spi_message *msg)
+{
+ struct spi_controller *ctlr = msg->spi->controller;
+ struct spi_transfer *xfer;
+ int ret;
+
+ /*
+ * If an SPI controller does not support toggling the CS line on each
+ * transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
+ * for the CS line, we can emulate the CS-per-word hardware function by
+ * splitting transfers into one-word transfers and ensuring that
+ * cs_change is set for each transfer.
+ */
+ if ((msg->spi->mode & SPI_CS_WORD) &&
+ (!(ctlr->mode_bits & SPI_CS_WORD) || spi_is_csgpiod(msg->spi))) {
+ ret = spi_split_transfers_maxwords(ctlr, msg, 1);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ /* Don't change cs_change on the last entry in the list */
+ if (list_is_last(&xfer->transfer_list, &msg->transfers))
+ break;
+
+ xfer->cs_change = 1;
+ }
+ } else {
+ ret = spi_split_transfers_maxsize(ctlr, msg,
+ spi_max_transfer_size(msg->spi));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * __spi_optimize_message - shared implementation for spi_optimize_message()
+ * and spi_maybe_optimize_message()
+ * @spi: the device that will be used for the message
+ * @msg: the message to optimize
+ *
+ * Peripheral drivers will call spi_optimize_message() and the spi core will
+ * call spi_maybe_optimize_message() instead of calling this directly.
+ *
+ * It is not valid to call this on a message that has already been optimized.
+ *
+ * Return: zero on success, else a negative error code
+ */
+static int __spi_optimize_message(struct spi_device *spi,
+ struct spi_message *msg)
+{
+ struct spi_controller *ctlr = spi->controller;
+ int ret;
+
+ ret = __spi_validate(spi, msg);
+ if (ret)
+ return ret;
+
+ ret = spi_split_transfers(msg);
+ if (ret)
+ return ret;
+
+ if (ctlr->optimize_message) {
+ ret = ctlr->optimize_message(msg);
+ if (ret) {
+ spi_res_release(ctlr, msg);
+ return ret;
+ }
+ }
+
+ msg->optimized = true;
+
+ return 0;
+}
+
+/*
+ * spi_maybe_optimize_message - optimize message if it isn't already pre-optimized
+ * @spi: the device that will be used for the message
+ * @msg: the message to optimize
+ * Return: zero on success, else a negative error code
+ */
+static int spi_maybe_optimize_message(struct spi_device *spi,
+ struct spi_message *msg)
+{
+ if (spi->controller->defer_optimize_message) {
+ msg->spi = spi;
+ return 0;
+ }
+
+ if (msg->pre_optimized)
+ return 0;
+
+ return __spi_optimize_message(spi, msg);
+}
+
+/**
+ * spi_optimize_message - do any one-time validation and setup for a SPI message
+ * @spi: the device that will be used for the message
+ * @msg: the message to optimize
+ *
+ * Peripheral drivers that reuse the same message repeatedly may call this to
+ * perform as much message prep as possible once, rather than repeating it each
+ * time a message transfer is performed to improve throughput and reduce CPU
+ * usage.
+ *
+ * Once a message has been optimized, it cannot be modified with the exception
+ * of updating the contents of any xfer->tx_buf (the pointer can't be changed,
+ * only the data in the memory it points to).
+ *
+ * Calls to this function must be balanced with calls to spi_unoptimize_message()
+ * to avoid leaking resources.
+ *
+ * Context: can sleep
+ * Return: zero on success, else a negative error code
+ */
+int spi_optimize_message(struct spi_device *spi, struct spi_message *msg)
+{
+ int ret;
+
+ /*
+ * Pre-optimization is not supported and optimization is deferred e.g.
+ * when using spi-mux.
+ */
+ if (spi->controller->defer_optimize_message)
+ return 0;
+
+ ret = __spi_optimize_message(spi, msg);
+ if (ret)
+ return ret;
+
+ /*
+ * This flag indicates that the peripheral driver called spi_optimize_message()
+ * and therefore we shouldn't unoptimize message automatically when finalizing
+ * the message but rather wait until spi_unoptimize_message() is called
+ * by the peripheral driver.
+ */
+ msg->pre_optimized = true;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_optimize_message);
+
+/**
+ * spi_unoptimize_message - releases any resources allocated by spi_optimize_message()
+ * @msg: the message to unoptimize
+ *
+ * Calls to this function must be balanced with calls to spi_optimize_message().
+ *
+ * Context: can sleep
+ */
+void spi_unoptimize_message(struct spi_message *msg)
+{
+ if (msg->spi->controller->defer_optimize_message)
+ return;
+
+ __spi_unoptimize_message(msg);
+ msg->pre_optimized = false;
+}
+EXPORT_SYMBOL_GPL(spi_unoptimize_message);
+
static int __spi_async(struct spi_device *spi, struct spi_message *message)
{
struct spi_controller *ctlr = spi->controller;
@@ -4050,8 +4367,6 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
if (!ctlr->transfer)
return -ENOTSUPP;
- message->spi = spi;
-
SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_async);
SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_async);
@@ -4067,65 +4382,39 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
return ctlr->transfer(spi, message);
}
+static void devm_spi_unoptimize_message(void *msg)
+{
+ spi_unoptimize_message(msg);
+}
+
/**
- * spi_async - asynchronous SPI transfer
- * @spi: device with which data will be exchanged
- * @message: describes the data transfers, including completion callback
- * Context: any (irqs may be blocked, etc)
+ * devm_spi_optimize_message - managed version of spi_optimize_message()
+ * @dev: the device that manages @msg (usually @spi->dev)
+ * @spi: the device that will be used for the message
+ * @msg: the message to optimize
+ * Return: zero on success, else a negative error code
*
- * This call may be used in_irq and other contexts which can't sleep,
- * as well as from task contexts which can sleep.
- *
- * The completion callback is invoked in a context which can't sleep.
- * Before that invocation, the value of message->status is undefined.
- * When the callback is issued, message->status holds either zero (to
- * indicate complete success) or a negative error code. After that
- * callback returns, the driver which issued the transfer request may
- * deallocate the associated memory; it's no longer in use by any SPI
- * core or controller driver code.
- *
- * Note that although all messages to a spi_device are handled in
- * FIFO order, messages may go to different devices in other orders.
- * Some device might be higher priority, or have various "hard" access
- * time requirements, for example.
- *
- * On detection of any fault during the transfer, processing of
- * the entire message is aborted, and the device is deselected.
- * Until returning from the associated message completion callback,
- * no other spi_message queued to that device will be processed.
- * (This rule applies equally to all the synchronous transfer calls,
- * which are wrappers around this core asynchronous primitive.)
- *
- * Return: zero on success, else a negative error code.
+ * spi_unoptimize_message() will automatically be called when the device is
+ * removed.
*/
-int spi_async(struct spi_device *spi, struct spi_message *message)
+int devm_spi_optimize_message(struct device *dev, struct spi_device *spi,
+ struct spi_message *msg)
{
- struct spi_controller *ctlr = spi->controller;
int ret;
- unsigned long flags;
- ret = __spi_validate(spi, message);
- if (ret != 0)
+ ret = spi_optimize_message(spi, msg);
+ if (ret)
return ret;
- spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
-
- if (ctlr->bus_lock_flag)
- ret = -EBUSY;
- else
- ret = __spi_async(spi, message);
-
- spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
-
- return ret;
+ return devm_add_action_or_reset(dev, devm_spi_unoptimize_message, msg);
}
-EXPORT_SYMBOL_GPL(spi_async);
+EXPORT_SYMBOL_GPL(devm_spi_optimize_message);
/**
- * spi_async_locked - version of spi_async with exclusive bus usage
+ * spi_async - asynchronous SPI transfer
* @spi: device with which data will be exchanged
* @message: describes the data transfers, including completion callback
- * Context: any (irqs may be blocked, etc)
+ * Context: any (IRQs may be blocked, etc)
*
* This call may be used in_irq and other contexts which can't sleep,
* as well as from task contexts which can sleep.
@@ -4152,25 +4441,28 @@ EXPORT_SYMBOL_GPL(spi_async);
*
* Return: zero on success, else a negative error code.
*/
-static int spi_async_locked(struct spi_device *spi, struct spi_message *message)
+int spi_async(struct spi_device *spi, struct spi_message *message)
{
struct spi_controller *ctlr = spi->controller;
int ret;
unsigned long flags;
- ret = __spi_validate(spi, message);
- if (ret != 0)
+ ret = spi_maybe_optimize_message(spi, message);
+ if (ret)
return ret;
spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
- ret = __spi_async(spi, message);
+ if (ctlr->bus_lock_flag)
+ ret = -EBUSY;
+ else
+ ret = __spi_async(spi, message);
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
return ret;
-
}
+EXPORT_SYMBOL_GPL(spi_async);
static void __spi_transfer_message_noqueue(struct spi_controller *ctlr, struct spi_message *msg)
{
@@ -4184,8 +4476,7 @@ static void __spi_transfer_message_noqueue(struct spi_controller *ctlr, struct s
ctlr->cur_msg = msg;
ret = __spi_pump_transfer_message(ctlr, msg, was_busy);
if (ret)
- goto out;
-
+ dev_err(&ctlr->dev, "noqueue transfer failed\n");
ctlr->cur_msg = NULL;
ctlr->fallback = false;
@@ -4201,7 +4492,6 @@ static void __spi_transfer_message_noqueue(struct spi_controller *ctlr, struct s
spi_idle_runtime_pm(ctlr);
}
-out:
mutex_unlock(&ctlr->io_mutex);
}
@@ -4221,14 +4511,18 @@ static void spi_complete(void *arg)
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
+ unsigned long flags;
int status;
struct spi_controller *ctlr = spi->controller;
- status = __spi_validate(spi, message);
- if (status != 0)
- return status;
+ if (__spi_check_suspended(ctlr)) {
+ dev_warn_once(&spi->dev, "Attempted to sync while suspend\n");
+ return -ESHUTDOWN;
+ }
- message->spi = spi;
+ status = spi_maybe_optimize_message(spi, message);
+ if (status)
+ return status;
SPI_STATISTICS_INCREMENT_FIELD(ctlr->pcpu_statistics, spi_sync);
SPI_STATISTICS_INCREMENT_FIELD(spi->pcpu_statistics, spi_sync);
@@ -4261,11 +4555,16 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message)
*/
message->complete = spi_complete;
message->context = &done;
- status = spi_async_locked(spi, message);
+
+ spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
+ status = __spi_async(spi, message);
+ spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
+
if (status == 0) {
wait_for_completion(&done);
status = message->status;
}
+ message->complete = NULL;
message->context = NULL;
return status;
@@ -4328,7 +4627,7 @@ EXPORT_SYMBOL_GPL(spi_sync_locked);
/**
* spi_bus_lock - obtain a lock for exclusive SPI bus usage
- * @ctlr: SPI bus master that should be locked for exclusive bus access
+ * @ctlr: SPI bus controller that should be locked for exclusive bus access
* Context: can sleep
*
* This call may only be used from a context that may sleep. The sleep
@@ -4359,7 +4658,7 @@ EXPORT_SYMBOL_GPL(spi_bus_lock);
/**
* spi_bus_unlock - release the lock for exclusive SPI bus usage
- * @ctlr: SPI bus master that was locked for exclusive bus access
+ * @ctlr: SPI bus controller that was locked for exclusive bus access
* Context: can sleep
*
* This call may only be used from a context that may sleep. The sleep
@@ -4388,9 +4687,9 @@ static u8 *buf;
/**
* spi_write_then_read - SPI synchronous write followed by read
* @spi: device with which data will be exchanged
- * @txbuf: data to be written (need not be dma-safe)
+ * @txbuf: data to be written (need not be DMA-safe)
* @n_tx: size of txbuf, in bytes
- * @rxbuf: buffer into which data will be read (need not be dma-safe)
+ * @rxbuf: buffer into which data will be read (need not be DMA-safe)
* @n_rx: size of rxbuf, in bytes
* Context: can sleep
*
@@ -4401,7 +4700,7 @@ static u8 *buf;
*
* Parameters to this routine are always copied using a small buffer.
* Performance-sensitive or bulk transfer code should instead use
- * spi_{async,sync}() calls with dma-safe buffers.
+ * spi_{async,sync}() calls with DMA-safe buffers.
*
* Return: zero on success, else a negative error code.
*/
@@ -4446,7 +4745,7 @@ int spi_write_then_read(struct spi_device *spi,
x[0].tx_buf = local_buf;
x[1].rx_buf = local_buf + n_tx;
- /* Do the i/o */
+ /* Do the I/O */
status = spi_sync(spi, &message);
if (status == 0)
memcpy(rxbuf, x[1].rx_buf, n_rx);
@@ -4476,9 +4775,9 @@ static struct spi_controller *of_find_spi_controller_by_node(struct device_node
{
struct device *dev;
- dev = class_find_device_by_of_node(&spi_master_class, node);
+ dev = class_find_device_by_of_node(&spi_controller_class, node);
if (!dev && IS_ENABLED(CONFIG_SPI_SLAVE))
- dev = class_find_device_by_of_node(&spi_slave_class, node);
+ dev = class_find_device_by_of_node(&spi_target_class, node);
if (!dev)
return NULL;
@@ -4551,23 +4850,24 @@ extern struct notifier_block spi_of_notifier;
#if IS_ENABLED(CONFIG_ACPI)
static int spi_acpi_controller_match(struct device *dev, const void *data)
{
- return ACPI_COMPANION(dev->parent) == data;
+ return device_match_acpi_dev(dev->parent, data);
}
-static struct spi_controller *acpi_spi_find_controller_by_adev(struct acpi_device *adev)
+struct spi_controller *acpi_spi_find_controller_by_adev(struct acpi_device *adev)
{
struct device *dev;
- dev = class_find_device(&spi_master_class, NULL, adev,
+ dev = class_find_device(&spi_controller_class, NULL, adev,
spi_acpi_controller_match);
if (!dev && IS_ENABLED(CONFIG_SPI_SLAVE))
- dev = class_find_device(&spi_slave_class, NULL, adev,
+ dev = class_find_device(&spi_target_class, NULL, adev,
spi_acpi_controller_match);
if (!dev)
return NULL;
return container_of(dev, struct spi_controller, dev);
}
+EXPORT_SYMBOL_GPL(acpi_spi_find_controller_by_adev);
static struct spi_device *acpi_spi_find_device_by_adev(struct acpi_device *adev)
{
@@ -4630,12 +4930,12 @@ static int __init spi_init(void)
if (status < 0)
goto err1;
- status = class_register(&spi_master_class);
+ status = class_register(&spi_controller_class);
if (status < 0)
goto err2;
if (IS_ENABLED(CONFIG_SPI_SLAVE)) {
- status = class_register(&spi_slave_class);
+ status = class_register(&spi_target_class);
if (status < 0)
goto err3;
}
@@ -4648,7 +4948,7 @@ static int __init spi_init(void)
return 0;
err3:
- class_unregister(&spi_master_class);
+ class_unregister(&spi_controller_class);
err2:
bus_unregister(&spi_bus_type);
err1:
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index d13dc15cc191..9a0160f6dc3d 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -357,6 +357,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int retval = 0;
struct spidev_data *spidev;
struct spi_device *spi;
+ struct spi_controller *ctlr;
u32 tmp;
unsigned n_ioc;
struct spi_ioc_transfer *ioc;
@@ -376,6 +377,8 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return -ESHUTDOWN;
}
+ ctlr = spi->controller;
+
/* use the buffer lock here for triple duty:
* - prevent I/O (from us) so calling spi_setup() is safe;
* - prevent concurrent SPI_IOC_WR_* from morphing
@@ -388,22 +391,15 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/* read requests */
case SPI_IOC_RD_MODE:
case SPI_IOC_RD_MODE32:
- tmp = spi->mode;
-
- {
- struct spi_controller *ctlr = spi->controller;
+ tmp = spi->mode & SPI_MODE_MASK;
- if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
- ctlr->cs_gpiods[spi_get_chipselect(spi, 0)])
- tmp &= ~SPI_CS_HIGH;
- }
+ if (ctlr->use_gpio_descriptors && spi_get_csgpiod(spi, 0))
+ tmp &= ~SPI_CS_HIGH;
if (cmd == SPI_IOC_RD_MODE)
- retval = put_user(tmp & SPI_MODE_MASK,
- (__u8 __user *)arg);
+ retval = put_user(tmp, (__u8 __user *)arg);
else
- retval = put_user(tmp & SPI_MODE_MASK,
- (__u32 __user *)arg);
+ retval = put_user(tmp, (__u32 __user *)arg);
break;
case SPI_IOC_RD_LSB_FIRST:
retval = put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
@@ -424,7 +420,6 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
else
retval = get_user(tmp, (u32 __user *)arg);
if (retval == 0) {
- struct spi_controller *ctlr = spi->controller;
u32 save = spi->mode;
if (tmp & ~SPI_MODE_MASK) {
@@ -432,8 +427,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
break;
}
- if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
- ctlr->cs_gpiods[spi_get_chipselect(spi, 0)])
+ if (ctlr->use_gpio_descriptors && spi_get_csgpiod(spi, 0))
tmp |= SPI_CS_HIGH;
tmp |= spi->mode & ~SPI_MODE_MASK;
@@ -672,7 +666,7 @@ static int spidev_release(struct inode *inode, struct file *filp)
}
#ifdef CONFIG_SPI_SLAVE
if (!dofree)
- spi_slave_abort(spidev->spi);
+ spi_target_abort(spidev->spi);
#endif
mutex_unlock(&device_list_lock);
@@ -691,7 +685,6 @@ static const struct file_operations spidev_fops = {
.compat_ioctl = spidev_compat_ioctl,
.open = spidev_open,
.release = spidev_release,
- .llseek = no_llseek,
};
/*-------------------------------------------------------------------------*/
@@ -701,19 +694,31 @@ static const struct file_operations spidev_fops = {
* It also simplifies memory management.
*/
-static struct class *spidev_class;
+static const struct class spidev_class = {
+ .name = "spidev",
+};
+/*
+ * The spi device ids are expected to match the device names of the
+ * spidev_dt_ids array below. Both arrays are kept in the same ordering.
+ */
static const struct spi_device_id spidev_spi_ids[] = {
- { .name = "dh2228fv" },
- { .name = "ltc2488" },
- { .name = "sx1301" },
- { .name = "bk4" },
- { .name = "dhcom-board" },
- { .name = "m53cpld" },
- { .name = "spi-petra" },
- { .name = "spi-authenta" },
- { .name = "em3581" },
- { .name = "si3210" },
+ { .name = /* abb */ "spi-sensor" },
+ { .name = /* arduino */ "unoq-mcu" },
+ { .name = /* cisco */ "spi-petra" },
+ { .name = /* dh */ "dhcom-board" },
+ { .name = /* elgin */ "jg10309-01" },
+ { .name = /* gocontroll */ "moduline-module-slot"},
+ { .name = /* lineartechnology */ "ltc2488" },
+ { .name = /* lwn */ "bk4" },
+ { .name = /* lwn */ "bk4-spi" },
+ { .name = /* menlo */ "m53cpld" },
+ { .name = /* micron */ "spi-authenta" },
+ { .name = /* rohm */ "bh2228fv" },
+ { .name = /* rohm */ "dh2228fv" },
+ { .name = /* semtech */ "sx1301" },
+ { .name = /* silabs */ "em3581" },
+ { .name = /* silabs */ "si3210" },
{},
};
MODULE_DEVICE_TABLE(spi, spidev_spi_ids);
@@ -732,12 +737,18 @@ static int spidev_of_check(struct device *dev)
}
static const struct of_device_id spidev_dt_ids[] = {
+ { .compatible = "abb,spi-sensor", .data = &spidev_of_check },
+ { .compatible = "arduino,unoq-mcu", .data = &spidev_of_check },
{ .compatible = "cisco,spi-petra", .data = &spidev_of_check },
{ .compatible = "dh,dhcom-board", .data = &spidev_of_check },
+ { .compatible = "elgin,jg10309-01", .data = &spidev_of_check },
+ { .compatible = "gocontroll,moduline-module-slot", .data = &spidev_of_check},
{ .compatible = "lineartechnology,ltc2488", .data = &spidev_of_check },
{ .compatible = "lwn,bk4", .data = &spidev_of_check },
+ { .compatible = "lwn,bk4-spi", .data = &spidev_of_check },
{ .compatible = "menlo,m53cpld", .data = &spidev_of_check },
{ .compatible = "micron,spi-authenta", .data = &spidev_of_check },
+ { .compatible = "rohm,bh2228fv", .data = &spidev_of_check },
{ .compatible = "rohm,dh2228fv", .data = &spidev_of_check },
{ .compatible = "semtech,sx1301", .data = &spidev_of_check },
{ .compatible = "silabs,em3581", .data = &spidev_of_check },
@@ -804,9 +815,9 @@ static int spidev_probe(struct spi_device *spi)
struct device *dev;
spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
- dev = device_create(spidev_class, &spi->dev, spidev->devt,
+ dev = device_create(&spidev_class, &spi->dev, spidev->devt,
spidev, "spidev%d.%d",
- spi->master->bus_num, spi_get_chipselect(spi, 0));
+ spi->controller->bus_num, spi_get_chipselect(spi, 0));
status = PTR_ERR_OR_ZERO(dev);
} else {
dev_dbg(&spi->dev, "no minor number available!\n");
@@ -840,7 +851,7 @@ static void spidev_remove(struct spi_device *spi)
mutex_unlock(&spidev->spi_lock);
list_del(&spidev->device_entry);
- device_destroy(spidev_class, spidev->devt);
+ device_destroy(&spidev_class, spidev->devt);
clear_bit(MINOR(spidev->devt), minors);
if (spidev->users == 0)
kfree(spidev);
@@ -878,15 +889,15 @@ static int __init spidev_init(void)
if (status < 0)
return status;
- spidev_class = class_create("spidev");
- if (IS_ERR(spidev_class)) {
+ status = class_register(&spidev_class);
+ if (status) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
- return PTR_ERR(spidev_class);
+ return status;
}
status = spi_register_driver(&spidev_spi_driver);
if (status < 0) {
- class_destroy(spidev_class);
+ class_unregister(&spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
}
return status;
@@ -896,7 +907,7 @@ module_init(spidev_init);
static void __exit spidev_exit(void)
{
spi_unregister_driver(&spidev_spi_driver);
- class_destroy(spidev_class);
+ class_unregister(&spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
}
module_exit(spidev_exit);