diff options
Diffstat (limited to 'drivers/spi')
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, ®s); 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, &_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(®_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 = ®_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(®_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(®_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, ®_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(®_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(®_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); |
