diff options
Diffstat (limited to 'drivers/spi')
145 files changed, 7535 insertions, 1907 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index bc7021da2fe9..ea8a31032927 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -57,6 +57,16 @@ config SPI_MEM 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 +96,17 @@ config SPI_AMLOGIC_SPIFC_A1 This enables master mode support for the SPIFC (SPI flash controller) available in Amlogic A1 (A113L SoC). +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 @@ -216,11 +237,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 +267,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 +278,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 +288,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 @@ -284,6 +311,7 @@ config SPI_COLDFIRE_QSPI 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. @@ -514,6 +542,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 @@ -817,16 +857,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 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 4ff8d725ba5e..9db7554c1864 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -14,10 +14,12 @@ 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_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,6 +40,7 @@ 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 @@ -71,6 +74,7 @@ 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 @@ -106,7 +110,8 @@ 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 @@ -116,6 +121,7 @@ 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_RZV2M_CSI) += spi-rzv2m-csi.o diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c index 370c4d1572ed..d8c9be64d006 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,32 @@ #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 /* 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 +82,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 +103,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 +122,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 +150,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 +163,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 +225,74 @@ #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; }; +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 +312,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 +334,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 +347,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 +361,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 +414,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) { @@ -275,12 +462,31 @@ static int atmel_qspi_find_mode(const struct spi_mem_op *op) 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 +498,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 +596,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 +624,326 @@ 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) { + pm_runtime_mark_last_busy(&aq->pdev->dev); + pm_runtime_put_autosuspend(&aq->pdev->dev); + 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,46 +952,20 @@ 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); @@ -474,6 +984,159 @@ 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. */ + atmel_qspi_write(QSPI_CR_DLLON | QSPI_CR_STPCAL, aq, QSPI_CR); + + /* Check synchronization status before updating configuration. */ + ret = readl_poll_timeout(aq->regs + QSPI_SR2, val, + (val & QSPI_SR2_DLOCK) && + !(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 */ + 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); + + 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; + + if (aq->caps->octal) { + ret = atmel_qspi_set_pad_calibration(aq); + if (ret) + return ret; + } else { + 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 +1151,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,7 +1167,8 @@ 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); @@ -515,45 +1182,86 @@ 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); + 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_mark_last_busy(ctrl->dev.parent); 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 +1277,65 @@ 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 = dma_request_chan(&aq->pdev->dev, "rx"); + if (IS_ERR(aq->rx_chan)) { + aq->rx_chan = NULL; + return dev_err_probe(&aq->pdev->dev, PTR_ERR(aq->rx_chan), + "RX DMA channel is not available\n"); + } + + aq->tx_chan = 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"); + goto release_rx_chan; + } + + 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; + +release_rx_chan: + dma_release_channel(aq->rx_chan); + aq->rx_chan = NULL; + aq->tx_chan = NULL; + return ret; +} + +static void atmel_qspi_dma_release(struct atmel_qspi *aq) +{ + if (aq->rx_chan) + dma_release_channel(aq->rx_chan); + if (aq->tx_chan) + dma_release_channel(aq->tx_chan); +} + +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 +1347,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,81 +1376,66 @@ 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; + goto dma_release; } err = devm_request_irq(&pdev->dev, irq, atmel_qspi_interrupt, 0, dev_name(&pdev->dev), aq); if (err) - goto disable_qspick; + goto dma_release; pm_runtime_set_autosuspend_delay(&pdev->dev, 500); pm_runtime_use_autosuspend(&pdev->dev); @@ -677,7 +1443,9 @@ static int atmel_qspi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); - atmel_qspi_init(aq); + err = atmel_qspi_init(aq); + if (err) + goto dma_release; err = spi_register_controller(ctrl); if (err) { @@ -685,21 +1453,57 @@ static int atmel_qspi_probe(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); - goto disable_qspick; + goto dma_release; } pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); return 0; -disable_qspick: - clk_disable_unprepare(aq->qspick); -disable_pclk: - clk_disable_unprepare(aq->pclk); +dma_release: + if (aq->caps->has_dma) + atmel_qspi_dma_release(aq); return err; } +static int atmel_qspi_sama7g5_suspend(struct atmel_qspi *aq) +{ + int ret; + u32 val; + + 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); + + 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; + + ret = readl_poll_timeout(aq->regs + QSPI_SR2, val, + !(val & QSPI_SR2_CALBSY), 40, + ATMEL_QSPI_TIMEOUT); + if (ret) + return ret; + + return 0; +} + static void atmel_qspi_remove(struct platform_device *pdev) { struct spi_controller *ctrl = platform_get_drvdata(pdev); @@ -710,9 +1514,17 @@ static void atmel_qspi_remove(struct platform_device *pdev) ret = pm_runtime_get_sync(&pdev->dev); if (ret >= 0) { + if (aq->caps->has_dma) + atmel_qspi_dma_release(aq); + + 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 @@ -722,10 +1534,8 @@ 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_dont_use_autosuspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); } @@ -739,6 +1549,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 +1572,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) @@ -814,6 +1640,19 @@ static const struct atmel_qspi_caps atmel_sam9x60_qspi_caps = { .has_ricr = true, }; +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, +}; + +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, +}; + static const struct of_device_id atmel_qspi_dt_ids[] = { { .compatible = "atmel,sama5d2-qspi", @@ -823,6 +1662,15 @@ 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, + }, + { /* sentinel */ } }; @@ -835,7 +1683,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..dbe640986825 --- /dev/null +++ b/drivers/spi/spi-airoha-snfi.c @@ -0,0 +1,1106 @@ +// 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 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_QUAD 0x6b +#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 + +#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; + + struct { + size_t page_size; + size_t sec_size; + u8 sec_num; + u8 spare_size; + } nfi_cfg; +}; + +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, u8 cmd, + const u8 *data, int len) +{ + int i, data_len; + + 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 i, data_len; + + 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, 0xc, 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 int airoha_snand_nfi_config(struct airoha_snand_ctrl *as_ctrl) +{ + int err; + u32 val; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); + if (err) + return err; + + /* auto FDM */ + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_AUTO_FDM_EN); + if (err) + return err; + + /* HW ECC */ + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_HW_ECC_EN); + if (err) + return err; + + /* DMA Burst */ + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_BURST_EN); + if (err) + return err; + + /* page format */ + switch (as_ctrl->nfi_cfg.spare_size) { + case 26: + val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1); + break; + case 27: + val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2); + break; + case 28: + val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3); + break; + default: + val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0); + break; + } + + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, + SPI_NFI_SPARE_SIZE, val); + if (err) + return err; + + switch (as_ctrl->nfi_cfg.page_size) { + case 2048: + val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1); + break; + case 4096: + val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2); + break; + default: + val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0); + break; + } + + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, + SPI_NFI_PAGE_SIZE, val); + if (err) + return err; + + /* sec num */ + val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_SEC_NUM, val); + if (err) + return err; + + /* enable cust sec size */ + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + return err; + + /* set cust sec size */ + val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, as_ctrl->nfi_cfg.sec_size); + return regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE, val); +} + +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 int airoha_snand_adjust_op_size(struct spi_mem *mem, + struct spi_mem_op *op) +{ + size_t max_len; + + if (airoha_snand_is_page_ops(op)) { + struct airoha_snand_ctrl *as_ctrl; + + as_ctrl = spi_controller_get_devdata(mem->spi->controller); + max_len = as_ctrl->nfi_cfg.sec_size; + max_len += as_ctrl->nfi_cfg.spare_size; + max_len *= as_ctrl->nfi_cfg.sec_num; + + if (op->data.nbytes > max_len) + op->data.nbytes = max_len; + } else { + max_len = 1 + op->addr.nbytes + op->dummy.nbytes; + if (max_len >= 160) + return -EOPNOTSUPP; + + if (op->data.nbytes > 160 - max_len) + op->data.nbytes = 160 - max_len; + } + + return 0; +} + +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; + + 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_mem_op *op = &desc->info.op_tmpl; + 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; + int err; + + switch (op->cmd.opcode) { + case SPI_NAND_OP_READ_FROM_CACHE_DUAL: + rd_mode = 1; + break; + case SPI_NAND_OP_READ_FROM_CACHE_QUAD: + rd_mode = 2; + break; + default: + rd_mode = 0; + break; + } + + as_ctrl = spi_controller_get_devdata(spi->controller); + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0) + return err; + + err = airoha_snand_nfi_config(as_ctrl); + if (err) + return err; + + 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) + return err; + + /* set dma addr */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, + dma_addr); + if (err) + goto error_dma_unmap; + + /* set cust sec size */ + val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; + val = FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, val); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_READ_DATA_BYTE_NUM, val); + if (err) + goto error_dma_unmap; + + /* set read command */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2, + op->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 */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, 0x0); + if (err) + goto error_dma_unmap; + + /* set nfi read */ + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_OPMODE, + FIELD_PREP(SPI_NFI_OPMODE, 6)); + if (err) + goto error_dma_unmap; + + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE); + 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 start read */ + 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); + 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_mem_op *op = &desc->info.op_tmpl; + 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; + int err; + + as_ctrl = spi_controller_get_devdata(spi->controller); + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); + if (err < 0) + return err; + + memcpy(txrx_buf + offs, buf, len); + 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) + return err; + + err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); + if (err < 0) + goto error_dma_unmap; + + err = airoha_snand_nfi_config(as_ctrl); + if (err) + goto error_dma_unmap; + + if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD || + op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD) + wr_mode = BIT(1); + else + wr_mode = 0; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, + dma_addr); + if (err) + goto error_dma_unmap; + + val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, + as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); + err = regmap_update_bits(as_ctrl->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_PROG_LOAD_BYTE_NUM, val); + if (err) + goto error_dma_unmap; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1, + FIELD_PREP(SPI_NFI_PG_LOAD_CMD, + op->cmd.opcode)); + if (err) + goto error_dma_unmap; + + 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; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0); + if (err) + goto error_dma_unmap; + + err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_READ_MODE); + if (err) + goto error_dma_unmap; + + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_OPMODE, + FIELD_PREP(SPI_NFI_OPMODE, 3)); + if (err) + goto error_dma_unmap; + + err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_MODE); + if (err) + goto error_dma_unmap; + + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x80); + if (err) + goto error_dma_unmap; + + 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); + return err; +} + +static int airoha_snand_exec_op(struct spi_mem *mem, + const struct spi_mem_op *op) +{ + u8 data[8], cmd, opcode = op->cmd.opcode; + struct airoha_snand_ctrl *as_ctrl; + int i, err; + + as_ctrl = spi_controller_get_devdata(mem->spi->controller); + + /* 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 */ + err = airoha_snand_write_data(as_ctrl, 0x8, &opcode, sizeof(opcode)); + if (err) + return err; + + /* addr part */ + cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8; + put_unaligned_be64(op->addr.val, data); + + for (i = ARRAY_SIZE(data) - op->addr.nbytes; + i < ARRAY_SIZE(data); i++) { + err = airoha_snand_write_data(as_ctrl, cmd, &data[i], + sizeof(data[0])); + if (err) + return err; + } + + /* dummy */ + data[0] = 0xff; + for (i = 0; i < op->dummy.nbytes; i++) { + err = airoha_snand_write_data(as_ctrl, 0x8, &data[0], + sizeof(data[0])); + if (err) + return err; + } + + /* data */ + if (op->data.dir == SPI_MEM_DATA_IN) { + err = airoha_snand_read_data(as_ctrl, op->data.buf.in, + op->data.nbytes); + if (err) + return err; + } else { + err = airoha_snand_write_data(as_ctrl, 0x8, op->data.buf.out, + op->data.nbytes); + 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 = { + .adjust_op_size = airoha_snand_adjust_op_size, + .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 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 int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl) +{ + u32 val, sec_size, sec_num; + int err; + + err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, &val); + if (err) + return err; + + sec_num = FIELD_GET(SPI_NFI_SEC_NUM, val); + + err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, &val); + if (err) + return err; + + sec_size = FIELD_GET(SPI_NFI_CUS_SEC_SIZE, val); + + /* init default value */ + as_ctrl->nfi_cfg.sec_size = sec_size; + as_ctrl->nfi_cfg.sec_num = sec_num; + as_ctrl->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024); + as_ctrl->nfi_cfg.spare_size = 16; + + err = airoha_snand_nfi_init(as_ctrl); + if (err) + return err; + + return airoha_snand_nfi_config(as_ctrl); +} + +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; + void __iomem *base; + 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"); + + err = dma_set_mask(as_ctrl->dev, DMA_BIT_MASK(32)); + if (err) + return err; + + ctrl->num_chipselect = 2; + ctrl->mem_ops = &airoha_snand_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_setup(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..585393802e9f 100644 --- a/drivers/spi/spi-altera-platform.c +++ b/drivers/spi/spi-altera-platform.c @@ -169,4 +169,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.c b/drivers/spi/spi-amd.c index 5d9b246b6963..c85997478b81 100644 --- a/drivers/spi/spi-amd.c +++ b/drivers/spi/spi-amd.c @@ -7,12 +7,15 @@ // 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> #define AMD_SPI_CTRL0_REG 0x00 #define AMD_SPI_EXEC_CMD BIT(16) @@ -32,9 +35,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,17 +51,46 @@ #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_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_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 +#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) */ + /** * 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, }; enum amd_spi_speed { @@ -86,23 +121,27 @@ struct amd_spi_freq { /** * 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; }; 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 +152,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 +213,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 +223,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 +241,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 +267,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); @@ -236,19 +298,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++) 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,8 +326,6 @@ 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, @@ -347,6 +404,7 @@ 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: @@ -358,6 +416,294 @@ fin_msg: return message->status; } +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 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)) { + 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) || + 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)) + 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_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; + u32 nbytes = op->data.nbytes; + u32 left_data = nbytes; + u8 *buf; + int i; + + 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)) { + amd_spi_hiddma_read(amd_spi, op); + + for (i = 0; left_data >= 8; i++, left_data -= 8) + *buf_64++ = readq((u8 __iomem *)amd_spi->dma_virt_addr + (i * 8)); + + buf = (u8 *)buf_64; + for (i = 0; i < left_data; i++) + buf[i] = readb((u8 __iomem *)amd_spi->dma_virt_addr + + (nbytes - left_data + i)); + + /* 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) { @@ -378,6 +724,31 @@ 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 operation */ + amd_spi->dma_virt_addr = dma_alloc_coherent(dev, AMD_SPI_HID2_DMA_SIZE, + &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 operations. + */ + hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_INT_MASK); + hid_regval = (hid_regval & GENMASK(31, 8)) | BIT(19); + amd_spi_writereg32(amd_spi, AMD_SPI_HID2_INT_MASK, hid_regval); + + /* Configure buffer unit(4k) 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 & ~BIT(3)); + + return 0; +} + static int amd_spi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -401,14 +772,16 @@ static int amd_spi_probe(struct platform_device *pdev) amd_spi->version = (uintptr_t) device_get_match_data(dev); /* Initialize the spi_controller fields */ - host->bus_num = 0; + host->bus_num = (amd_spi->version == AMD_HID2_SPI) ? 2 : 0; host->num_chipselect = 4; - host->mode_bits = 0; + 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; @@ -417,13 +790,17 @@ static int amd_spi_probe(struct platform_device *pdev) if (err) return dev_err_probe(dev, err, "error registering SPI controller\n"); - return 0; + if (amd_spi->version == AMD_HID2_SPI) + err = amd_spi_setup_hiddma(amd_spi, dev); + + return err; } #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-amlogic-spifc-a1.c b/drivers/spi/spi-amlogic-spifc-a1.c index fadf6667cd51..18c9aa2cbc29 100644 --- a/drivers/spi/spi-amlogic-spifc-a1.c +++ b/drivers/spi/spi-amlogic-spifc-a1.c @@ -259,7 +259,7 @@ static int amlogic_spifc_a1_exec_op(struct spi_mem *mem, size_t data_size = op->data.nbytes; int ret; - ret = amlogic_spifc_a1_set_freq(spifc, mem->spi->max_speed_hz); + ret = amlogic_spifc_a1_set_freq(spifc, op->max_freq); if (ret) return ret; @@ -320,6 +320,10 @@ static const struct spi_controller_mem_ops amlogic_spifc_a1_mem_ops = { .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) { struct spi_controller *ctrl; @@ -356,6 +360,7 @@ static int amlogic_spifc_a1_probe(struct platform_device *pdev) 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-apple.c b/drivers/spi/spi-apple.c new file mode 100644 index 000000000000..6273352a2b28 --- /dev/null +++ b/drivers/spi/spi-apple.c @@ -0,0 +1,530 @@ +// 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,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 5ba988720851..86c54fff9d6e 100644 --- a/drivers/spi/spi-ar934x.c +++ b/drivers/spi/spi-ar934x.c @@ -223,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 3c9ed412932f..02c1e625742d 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -339,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; @@ -361,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 diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index bbd417c55e7f..e9beae95dded 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -239,7 +239,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,8 +249,9 @@ 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, @@ -261,10 +262,11 @@ static ssize_t aspeed_spi_write_user(struct aspeed_spi_chip *chip, 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_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 */ @@ -1189,7 +1191,7 @@ 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 1cea8e159344..bbe97ce89a2f 100644 --- a/drivers/spi/spi-at91-usart.c +++ b/drivers/spi/spi-at91-usart.c @@ -650,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 d78762d4db98..9a705a9fddd2 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -253,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 bad34998454a..89a6b46cd319 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -987,8 +987,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) @@ -1374,8 +1372,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; } @@ -1454,8 +1451,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) @@ -1785,7 +1781,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 825d2f1cdff8..b65798ccc679 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -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; @@ -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); @@ -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 7cc219d78551..7c252126b33e 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -15,6 +15,7 @@ #include <linux/overflow.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> +#include <trace/events/spi.h> #define SPI_ENGINE_REG_RESET 0x40 @@ -41,11 +42,13 @@ #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 @@ -73,6 +76,8 @@ 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)) struct spi_engine_program { unsigned int length; @@ -111,6 +116,8 @@ struct spi_engine { struct spi_engine_message_state msg_state; struct completion msg_complete; unsigned int int_enable; + /* shadows hardware CS inversion flag state */ + u8 cs_inv; }; static void spi_engine_program_add_cmd(struct spi_engine_program *p, @@ -132,6 +139,10 @@ 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; } @@ -164,16 +175,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, - int delay_ns, u32 sclk_hz) + int delay_ns, int inst_ns, u32 sclk_hz) { unsigned int t; - /* negative delay indicates error, e.g. from spi_delay_to_ns() */ - if (delay_ns <= 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; - /* rounding down since executing the instruction adds a couple of ticks delay */ - t = DIV_ROUND_DOWN_ULL((u64)delay_ns * sclk_hz, NSEC_PER_SEC); + t = DIV_ROUND_UP_ULL((u64)(delay_ns - inst_ns) * sclk_hz, NSEC_PER_SEC); while (t) { unsigned int n = min(t, 256U); @@ -220,10 +235,16 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry, struct spi_device *spi = msg->spi; struct spi_controller *host = spi->controller; struct spi_transfer *xfer; - int clk_div, new_clk_div; + 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; spi_engine_program_add_cmd(p, dry, @@ -243,7 +264,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry, clk_div - 1)); } - if (bits_per_word != xfer->bits_per_word) { + 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, @@ -252,7 +273,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry, spi_engine_gen_xfer(p, dry, xfer); spi_engine_gen_sleep(p, dry, spi_delay_to_ns(&xfer->delay, xfer), - xfer->effective_speed_hz); + inst_ns, xfer->effective_speed_hz); if (xfer->cs_change) { if (list_is_last(&xfer->transfer_list, &msg->transfers)) { @@ -262,7 +283,7 @@ static void spi_engine_compile_message(struct spi_message *msg, bool dry, spi_engine_gen_cs(p, dry, spi, false); spi_engine_gen_sleep(p, dry, spi_delay_to_ns( - &xfer->cs_change_delay, xfer), + &xfer->cs_change_delay, xfer), inst_ns, xfer->effective_speed_hz); if (!list_next_entry(xfer, transfer_list)->cs_off) @@ -530,6 +551,29 @@ static int spi_engine_unoptimize_message(struct spi_message *msg) return 0; } +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); + + 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_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); + + return 0; +} + static int spi_engine_transfer_one_message(struct spi_controller *host, struct spi_message *msg) { @@ -547,6 +591,13 @@ static int spi_engine_transfer_one_message(struct spi_controller *host, 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)) @@ -574,6 +625,13 @@ static int spi_engine_transfer_one_message(struct spi_controller *host, 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); + } + spi_finalize_current_message(host); return msg->status; @@ -623,7 +681,7 @@ static int spi_engine_probe(struct platform_device *pdev) 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.%c\n", + 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)); @@ -653,16 +711,20 @@ static int spi_engine_probe(struct platform_device *pdev) host->unoptimize_message = spi_engine_unoptimize_message; host->num_chipselect = 8; + /* Some features depend of the IP core version. */ + if (ADI_AXI_PCORE_VER_MAJOR(version) >= 1) { + if (ADI_AXI_PCORE_VER_MINOR(version) >= 2) { + host->mode_bits |= SPI_CS_HIGH; + host->setup = spi_engine_setup; + } + if (ADI_AXI_PCORE_VER_MINOR(version) >= 3) + host->mode_bits |= SPI_MOSI_IDLE_LOW | SPI_MOSI_IDLE_HIGH; + } + if (host->max_speed_hz == 0) return dev_err_probe(&pdev->dev, -EINVAL, "spi_clk rate is 0"); - ret = devm_spi_register_controller(&pdev->dev, host); - if (ret) - return ret; - - platform_set_drvdata(pdev, host); - - return 0; + return devm_spi_register_controller(&pdev->dev, host); } static const struct of_device_id spi_engine_match_table[] = { diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index e1b9b1235787..0d1aa6592484 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -1435,7 +1435,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 06fe155a70c9..90698d7d809d 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -577,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 1ca857c2a4aa..644b44d2aef2 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -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 aac41bd05f98..c8f64ec69344 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -466,12 +466,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) { @@ -582,13 +584,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_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,8 +600,6 @@ 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: @@ -654,7 +656,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 9f64afd8164e..f16298b75236 100644 --- a/drivers/spi/spi-bcmbca-hsspi.c +++ b/drivers/spi/spi-bcmbca-hsspi.c @@ -433,7 +433,6 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev) { 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,7 +480,7 @@ static int bcmbca_hsspi_probe(struct platform_device *pdev) } } - host = spi_alloc_host(&pdev->dev, sizeof(*bs)); + host = devm_spi_alloc_host(&pdev->dev, sizeof(*bs)); if (!host) { ret = -ENOMEM; goto out_disable_pll_clk; @@ -543,15 +536,17 @@ 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_host; + 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 */ @@ -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_host: - spi_controller_put(host); out_disable_pll_clk: clk_disable_unprepare(pll_clk); out_disable_clk: @@ -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.c b/drivers/spi/spi-bitbang.c index a0e2204fc039..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; } @@ -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,7 +239,7 @@ 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_controller_get_devdata(spi->controller); @@ -246,7 +252,7 @@ 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_CONTROLLER_NO_RX : SPI_CONTROLLER_NO_TX; return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t, flags); @@ -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,9 +412,9 @@ 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_controller, which will process requests in a @@ -417,7 +423,7 @@ EXPORT_SYMBOL_GPL(spi_bitbang_init); * * 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_master() to prevent a memory + * spi_controller_put() as counterpart of spi_alloc_host() to prevent a memory * leak. */ int spi_bitbang_start(struct spi_bitbang *bitbang) @@ -450,4 +456,4 @@ void spi_bitbang_stop(struct spi_bitbang *bitbang) 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 1d267e6c22a4..84eb454ed443 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -315,7 +315,6 @@ 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 350b3dab3a05..0cd37a7436d5 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -42,9 +42,14 @@ static_assert(CQSPI_MAX_CHIPSELECT <= SPI_CS_CNT_MAX); #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) /* Capabilities */ #define CQSPI_SUPPORTS_OCTAL BIT(0) +#define CQSPI_SUPPORTS_QUAD BIT(1) #define CQSPI_OP_WIDTH(part) ((part).nbytes ? ilog2((part).buswidth) : 0) @@ -102,11 +107,14 @@ struct cqspi_st { bool apb_ahb_hazard; bool is_jh7110; /* Flag for StarFive JH7110 SoC */ + bool disable_stig_mode; + + 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); @@ -117,6 +125,7 @@ struct cqspi_driver_platdata { /* 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 @@ -140,6 +149,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 @@ -295,13 +306,27 @@ 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) @@ -334,11 +359,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); @@ -434,8 +456,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"); @@ -492,8 +514,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); @@ -700,6 +725,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; @@ -723,17 +749,20 @@ 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); 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; @@ -775,7 +804,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); @@ -783,8 +812,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; @@ -808,6 +837,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; @@ -1084,8 +1132,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; @@ -1358,16 +1406,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; @@ -1388,7 +1433,7 @@ static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op) 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) { /* @@ -1397,7 +1442,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); @@ -1511,8 +1557,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)) { @@ -1542,8 +1588,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); @@ -1577,8 +1621,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) @@ -1617,6 +1682,7 @@ 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) @@ -1624,23 +1690,20 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) unsigned int max_cs = cqspi->num_chipselect - 1; 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; /* 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->num_chipselect) { dev_err(dev, "Chip select %d out of range.\n", cs); - of_node_put(np); return -EINVAL; } else if (cs < max_cs) { max_cs = cs; @@ -1651,10 +1714,8 @@ static int cqspi_setup_flash(struct cqspi_st *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; - } } cqspi->num_chipselect = max_cs + 1; @@ -1731,6 +1792,7 @@ static int cqspi_probe(struct platform_device *pdev) cqspi->pdev = pdev; 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. */ @@ -1822,13 +1884,14 @@ static int cqspi_probe(struct platform_device *pdev) /* 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) 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; @@ -1847,9 +1910,10 @@ static int cqspi_probe(struct platform_device *pdev) if (ret) goto probe_reset_failed; } + if (ddata->quirks & CQSPI_DISABLE_STIG_MODE) + cqspi->disable_stig_mode = true; - if (of_device_is_compatible(pdev->dev.of_node, - "xlnx,versal-ospi-1.0")) { + if (ddata->quirks & CQSPI_DMA_SET_MASK) { ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); if (ret) goto probe_reset_failed; @@ -1864,7 +1928,10 @@ 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; @@ -1876,6 +1943,9 @@ static int cqspi_probe(struct platform_device *pdev) host->num_chipselect = cqspi->num_chipselect; + if (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) @@ -1947,7 +2017,9 @@ static int cqspi_runtime_resume(struct device *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; @@ -1957,13 +2029,25 @@ static int cqspi_runtime_resume(struct device *dev) 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 spi_controller_suspend(cqspi->host); + return pm_runtime_force_suspend(dev); } static int cqspi_resume(struct device *dev) { struct cqspi_st *cqspi = dev_get_drvdata(dev); + int ret; + + 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); } @@ -1982,7 +2066,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, }; @@ -1993,12 +2077,23 @@ 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, }; 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, }; @@ -2012,6 +2107,12 @@ 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", @@ -2045,6 +2146,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 */ } }; @@ -2052,7 +2161,7 @@ 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 = pm_ptr(&cqspi_dev_pm_ops), diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c index 8648b8eb080d..aed98ab14334 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> @@ -19,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 @@ -145,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) ? \ @@ -157,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) ( \ @@ -173,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) ( \ @@ -189,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, @@ -205,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; @@ -212,6 +355,7 @@ struct cdns_xspi_dev { void __iomem *iobase; void __iomem *auxbase; void __iomem *sdmabase; + void __iomem *xferbase; int irq; int cur_cs; @@ -226,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)) { + 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; @@ -300,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; @@ -317,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; } @@ -344,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) @@ -351,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) @@ -359,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); @@ -375,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); @@ -386,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) @@ -427,6 +760,81 @@ static int cdns_xspi_mem_op_execute(struct spi_mem *mem, 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 = @@ -438,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; @@ -485,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; } } @@ -524,6 +942,204 @@ 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; @@ -540,13 +1156,29 @@ static int cdns_xspi_probe(struct platform_device *pdev) SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_OCTAL | SPI_RX_OCTAL | SPI_MODE_0 | SPI_MODE_3; - host->mem_ops = &cadence_xspi_mem_ops; + 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, host); - cdns_xspi = spi_controller_get_devdata(host); cdns_xspi->pdev = pdev; cdns_xspi->dev = &pdev->dev; cdns_xspi->cur_cs = 0; @@ -561,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); @@ -588,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); @@ -612,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 */} }; diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index e5140532071d..9e56bde87768 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -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 */ @@ -111,6 +112,7 @@ * @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; @@ -125,6 +127,7 @@ struct cdns_spi { u8 dev_busy; u32 is_decoded_cs; unsigned int tx_fifo_depth; + struct reset_control *rstc; }; /* Macros for the SPI controller read/write */ @@ -588,14 +591,24 @@ static int cdns_spi_probe(struct platform_device *pdev) goto remove_ctlr; } - if (!spi_controller_is_target(ctlr)) { - 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; - } + 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; + } + + reset_control_assert(xspi->rstc); + reset_control_deassert(xspi->rstc); + + 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); @@ -665,8 +678,8 @@ static int cdns_spi_probe(struct platform_device *pdev) clk_dis_all: if (!spi_controller_is_target(ctlr)) { - pm_runtime_set_suspended(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); } remove_ctlr: spi_controller_put(ctlr); @@ -688,8 +701,10 @@ static void cdns_spi_remove(struct platform_device *pdev) cdns_spi_write(xspi, CDNS_SPI_ER, CDNS_SPI_ER_DISABLE); - 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); } @@ -791,7 +806,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 4511c3b31223..a5ad90d66ec0 100644 --- a/drivers/spi/spi-cavium-octeon.c +++ b/drivers/spi/spi-cavium-octeon.c @@ -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-ch341.c b/drivers/spi/spi-ch341.c new file mode 100644 index 000000000000..46bc208f2d05 --- /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); + + 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-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index b341b6908df0..fdf37636cb9f 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -500,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 index aabef9fc84bd..ceefc253c549 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -5,10 +5,16 @@ // 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> @@ -16,12 +22,13 @@ #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 (40 * HZ_PER_MHZ) +#define CS42L43_SPI_ROOT_HZ 49152000 #define CS42L43_SPI_MAX_LENGTH 65532 enum cs42l43_spi_cmd { @@ -39,6 +46,26 @@ 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 const struct software_node cs42l43_gpiochip_swnode = { + .name = "cs42l43-pinctrl", +}; + +static const struct software_node_ref_args cs42l43_cs_refs[] = { + SOFTWARE_NODE_REFERENCE(&cs42l43_gpiochip_swnode, 0, GPIO_ACTIVE_LOW), + SOFTWARE_NODE_REFERENCE(&swnode_gpio_undefined), +}; + +static const struct property_entry cs42l43_cs_props[] = { + PROPERTY_ENTRY_REF_ARRAY("cs-gpios", cs42l43_cs_refs), + {} +}; + static int cs42l43_spi_tx(struct regmap *regmap, const u8 *buf, unsigned int len) { const u8 *end = buf + len; @@ -203,16 +230,111 @@ 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 (IS_ERR_OR_NULL(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_kmalloc(priv->dev, 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 void cs42l43_release_sw_node(void *data) +{ + software_node_unregister(&cs42l43_gpiochip_swnode); +} + 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); @@ -259,21 +381,70 @@ static int cs42l43_spi_probe(struct platform_device *pdev) if (is_of_node(fwnode)) { fwnode = fwnode_get_named_child_node(fwnode, "spi"); - ret = devm_add_action(priv->dev, cs42l43_release_of_node, fwnode); - if (ret) { - fwnode_handle_put(fwnode); + ret = devm_add_action_or_reset(priv->dev, cs42l43_release_of_node, fwnode); + if (ret) return ret; - } } - device_set_node(&priv->ctlr->dev, fwnode); + fwnode_property_read_u32(xu_fwnode, "01fa-sidecar-instances", &nsidecars); + + if (nsidecars) { + 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 = software_node_register(&cs42l43_gpiochip_swnode); + if (ret) + return dev_err_probe(priv->dev, ret, + "Failed to register gpio swnode\n"); + + ret = devm_add_action_or_reset(priv->dev, cs42l43_release_sw_node, NULL); + if (ret) + return ret; + + ret = device_create_managed_software_node(&priv->ctlr->dev, + cs42l43_cs_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) { - dev_err(priv->dev, "Failed to register SPI controller: %d\n", ret); + 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 ret; + return 0; } static const struct platform_device_id cs42l43_spi_id_table[] = { @@ -291,6 +462,7 @@ static struct platform_driver cs42l43_spi_driver = { }; 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>"); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index be3998104bfb..a29934422356 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -570,6 +570,7 @@ 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_controller_get_devdata(spi->controller); pdata = &dspi->pdata; @@ -661,7 +662,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) { @@ -984,6 +990,9 @@ 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); @@ -1013,6 +1022,9 @@ static void davinci_spi_remove(struct platform_device *pdev) spi_bitbang_stop(&dspi->bitbang); + /* 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); @@ -1027,7 +1039,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 d319dc357fef..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) @@ -871,7 +871,7 @@ 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); diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c index 5391bcac305c..4a5be813efa7 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; } @@ -315,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, @@ -326,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 0274c9295514..941ecc6f59f8 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 @@ -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) @@ -206,7 +208,7 @@ int dw_spi_check_status(struct dw_spi *dws, bool raw) 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) { @@ -349,7 +351,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) { @@ -421,10 +423,7 @@ static int dw_spi_transfer_one(struct spi_controller *host, 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 = roundup_pow_of_two(BITS_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 +439,7 @@ static int dw_spi_transfer_one(struct spi_controller *host, transfer->effective_speed_hz = dws->current_freq; /* Check if current transfer is a DMA transaction */ - if (host->can_dma && host->can_dma(host, spi, transfer)) - dws->dma_mapped = host->cur_msg_mapped; + dws->dma_mapped = spi_xfer_is_dma_mapped(host, spi, transfer); /* For poll mode just disable all interrupts */ dw_spi_mask_intr(dws, 0xff); @@ -679,7 +677,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; @@ -837,6 +835,20 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws) } /* + * 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,6 +894,10 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws) dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF); } +static const struct spi_controller_mem_caps dw_spi_mem_caps = { + .per_op_freq = true, +}; + int dw_spi_add_host(struct device *dev, struct dw_spi *dws) { struct spi_controller *host; @@ -929,8 +945,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) host->set_cs = dw_spi_set_cs; host->transfer_one = dw_spi_transfer_one; host->handle_err = dw_spi_handle_err; - if (dws->mem_ops.exec_op) + if (dws->mem_ops.exec_op) { host->mem_ops = &dws->mem_ops; + host->mem_caps = &dw_spi_mem_caps; + } host->max_speed_hz = dws->max_freq; host->flags = SPI_CONTROLLER_GPIO_SS; host->auto_runtime_pm = true; @@ -970,7 +988,7 @@ err_free_host: spi_controller_put(host); return ret; } -EXPORT_SYMBOL_NS_GPL(dw_spi_add_host, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_add_host, "SPI_DW_CORE"); void dw_spi_remove_host(struct dw_spi *dws) { @@ -985,7 +1003,7 @@ void dw_spi_remove_host(struct dw_spi *dws) free_irq(dws->irq, dws->host); } -EXPORT_SYMBOL_NS_GPL(dw_spi_remove_host, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_remove_host, "SPI_DW_CORE"); int dw_spi_suspend_host(struct dw_spi *dws) { @@ -998,14 +1016,14 @@ int dw_spi_suspend_host(struct dw_spi *dws) 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_host, "SPI_DW_CORE"); int dw_spi_resume_host(struct dw_spi *dws) { dw_spi_hw_init(&dws->host->dev, dws); return spi_controller_resume(dws->host); } -EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, SPI_DW_CORE); +EXPORT_SYMBOL_NS_GPL(dw_spi_resume_host, "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 f4c209e5f52b..b5bed02b7e50 100644 --- a/drivers/spi/spi-dw-dma.c +++ b/drivers/spi/spi-dw-dma.c @@ -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 cc74cbe03431..f0f576fac77a 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -320,7 +320,11 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) struct resource *mem; struct dw_spi *dws; int ret; - int num_cs; + + if (device_property_read_bool(&pdev->dev, "spi-slave")) { + dev_warn(&pdev->dev, "spi-slave is not yet supported\n"); + return -ENODEV; + } dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio), GFP_KERNEL); @@ -364,11 +368,8 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) &dws->reg_io_width)) dws->reg_io_width = 4; - num_cs = 4; - - device_property_read_u32(&pdev->dev, "num-cs", &num_cs); - - 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) { @@ -432,7 +433,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, @@ -444,4 +445,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..b32d6648a32e 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); /* @@ -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 6cafeee8ee2a..fc267c6437ae 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -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 */ diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index a1d60e51c053..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; @@ -575,46 +571,23 @@ static int ep93xx_spi_unprepare_hardware(struct spi_controller *host) return 0; } -static bool ep93xx_spi_dma_filter(struct dma_chan *chan, void *filter_param) +static int ep93xx_spi_setup_dma(struct device *dev, struct ep93xx_spi *espi) { - 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) -{ - 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; } @@ -647,18 +620,11 @@ static void ep93xx_spi_release_dma(struct ep93xx_spi *espi) static int ep93xx_spi_probe(struct platform_device *pdev) { struct spi_controller *host; - struct ep93xx_spi_info *info; 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 irq; @@ -713,12 +679,17 @@ static int ep93xx_spi_probe(struct platform_device *pdev) 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); + 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 host\n"); @@ -746,12 +717,19 @@ static void ep93xx_spi_remove(struct platform_device *pdev) 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-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c index 47c7a5c6257f..23ad1249f121 100644 --- a/drivers/spi/spi-fsl-cpm.c +++ b/drivers/spi/spi-fsl-cpm.c @@ -98,19 +98,13 @@ static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi) 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 __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; @@ -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) { @@ -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 38defdcf9370..067c954cb6ea 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -280,25 +280,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); } @@ -1003,9 +1003,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); @@ -1018,11 +1020,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; @@ -1068,7 +1078,10 @@ static int dspi_setup(struct spi_device *spi) 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); @@ -1458,10 +1471,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 ea647ee94da8..6a73eaa34cf7 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -835,7 +835,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 4fc2c56555b5..bb7a625db5b0 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -158,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-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 92a662d1b55c..40f5c8fdba76 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -82,12 +82,17 @@ #define TCR_RXMSK BIT(19) #define TCR_TXMSK BIT(18) +struct fsl_lpspi_devtype_data { + u8 prescale_max; +}; + struct lpspi_config { u8 bpw; u8 chip_select; u8 prescale; u16 mode; u32 speed_hz; + u32 effective_speed_hz; }; struct fsl_lpspi_data { @@ -119,10 +124,25 @@ struct fsl_lpspi_data { bool usedma; struct completion dma_rx_completion; struct completion dma_tx_completion; + + const struct fsl_lpspi_devtype_data *devtype_data; +}; + +/* + * ERR051608 fixed or not: + * https://www.nxp.com/docs/en/errata/i.MX93_1P87f.pdf + */ +static struct fsl_lpspi_devtype_data imx93_lpspi_devtype_data = { + .prescale_max = 1, +}; + +static struct fsl_lpspi_devtype_data imx7ulp_lpspi_devtype_data = { + .prescale_max = 7, }; 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,}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_lpspi_dt_ids); @@ -296,10 +316,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; if (!config.speed_hz) { dev_err(fsl_lpspi->dev, @@ -313,21 +336,26 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi) return -EINVAL; } - for (prescale = 0; prescale < 8; prescale++) { - scldiv = perclk_rate / config.speed_hz / (1 << prescale) - 2; - if (scldiv < 256) { + div = DIV_ROUND_UP(perclk_rate, config.speed_hz); + + 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; @@ -553,7 +581,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; @@ -594,9 +622,9 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller, 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); @@ -604,9 +632,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); @@ -726,6 +754,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; @@ -820,6 +850,7 @@ 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; @@ -828,6 +859,10 @@ static int fsl_lpspi_probe(struct platform_device *pdev) u32 temp; bool is_target; + 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, @@ -846,6 +881,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) 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"); + fsl_lpspi->devtype_data = devtype_data; init_completion(&fsl_lpspi->xfer_done); @@ -862,7 +898,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) 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); @@ -919,14 +955,10 @@ static int fsl_lpspi_probe(struct platform_device *pdev) 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) { @@ -957,16 +989,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; @@ -984,17 +1017,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 79bac30e79af..355e6a39fb41 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -522,9 +522,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)) @@ -652,7 +653,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; @@ -839,6 +840,10 @@ 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 int fsl_qspi_probe(struct platform_device *pdev) { struct spi_controller *ctlr; @@ -923,6 +928,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) 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); @@ -997,7 +1003,7 @@ static struct platform_driver fsl_qspi_driver = { .pm = &fsl_qspi_pm_ops, }, .probe = fsl_qspi_probe, - .remove_new = fsl_qspi_remove, + .remove = 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 97faf984801f..2f2082652a1a 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -249,8 +249,7 @@ 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_controller_get_devdata(spi->controller); struct fsl_spi_reg __iomem *reg_base; @@ -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; @@ -619,7 +618,7 @@ static struct spi_controller *fsl_spi_probe(struct device *dev, 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 host; @@ -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 @@ -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 37ef8c40b276..768d7482102a 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -604,6 +604,21 @@ static int spi_geni_prepare_message(struct spi_controller *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; @@ -622,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: @@ -632,19 +653,6 @@ 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); @@ -1108,27 +1116,31 @@ 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); + + ret = geni_icc_get(&mas->se, NULL); + if (ret) + return ret; + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 250); - pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; if (device_property_read_bool(&pdev->dev, "spi-slave")) spi->target = true; - ret = geni_icc_get(&mas->se, NULL); - if (ret) - goto spi_geni_probe_runtime_disable; /* 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 @@ -1144,36 +1156,11 @@ 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_controller(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_controller *spi = platform_get_drvdata(pdev); - struct spi_geni_master *mas = spi_controller_get_devdata(spi); - - /* Unregister _before_ disabling pm_runtime() so we stop transfers */ - spi_unregister_controller(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) @@ -1255,7 +1242,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 909cce109bba..4f192e013cd6 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -5,17 +5,17 @@ * 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/property.h> #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> #include <linux/spi/spi_gpio.h> - /* * This bitbanging SPI host driver should help make systems usable * when a native hardware SPI engine is not available, perhaps because @@ -236,11 +236,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 @@ -248,15 +256,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) @@ -326,29 +333,6 @@ 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_controller *host) -{ - host->dev.of_node = pdev->dev.of_node; - host->use_gpio_descriptors = true; - - return 0; -} -#else -static inline int spi_gpio_probe_dt(struct platform_device *pdev, - struct spi_controller *host) -{ - return 0; -} -#endif - static int spi_gpio_probe_pdata(struct platform_device *pdev, struct spi_controller *host) { @@ -389,19 +373,21 @@ static int spi_gpio_probe(struct platform_device *pdev) 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; host = devm_spi_alloc_host(dev, sizeof(*spi_gpio)); if (!host) return -ENOMEM; - if (pdev->dev.of_node) - status = spi_gpio_probe_dt(pdev, host); - else + 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; + if (status) + return status; + } spi_gpio = spi_controller_get_devdata(host); @@ -411,7 +397,8 @@ static int spi_gpio_probe(struct platform_device *pdev) 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_CS_HIGH | SPI_LSB_FIRST | SPI_MOSI_IDLE_LOW | + SPI_MOSI_IDLE_HIGH; if (!spi_gpio->mosi) { /* HW configuration without MOSI pin * @@ -436,6 +423,7 @@ static int spi_gpio_probe(struct platform_device *pdev) 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 (host->flags & SPI_CONTROLLER_NO_TX) { bb->txrx_word[SPI_MODE_0] = spi_gpio_spec_txrx_word_mode0; @@ -459,10 +447,16 @@ static int spi_gpio_probe(struct platform_device *pdev) 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, }; diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c index 35ef5e8e2ffd..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), @@ -483,6 +481,9 @@ static int hisi_spi_probe(struct platform_device *pdev) 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", &host->num_chipselect); if (ret) @@ -497,6 +498,7 @@ static int hisi_spi_probe(struct platform_device *pdev) 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); @@ -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 1301d14483d4..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 */ diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c index d8360f94d3b7..168ccf51f6d4 100644 --- a/drivers/spi/spi-img-spfi.c +++ b/drivers/spi/spi-img-spfi.c @@ -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 c3e5cee18bea..eeb7d082c247 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -3,6 +3,7 @@ // 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> @@ -13,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> @@ -71,7 +75,8 @@ 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); @@ -301,6 +306,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) @@ -407,7 +424,7 @@ static void spi_imx_buf_tx_swap(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 = ioread32be(spi_imx->base + MXC_CSPIRXDATA); if (spi_imx->rx_buf) { int n_bytes = spi_imx->target_burst % sizeof(val); @@ -436,13 +453,12 @@ static void mx53_ecspi_tx_target(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; - writel(val, spi_imx->base + MXC_CSPITXDATA); + iowrite32be(val, spi_imx->base + MXC_CSPITXDATA); } /* MX51 eCSPI */ @@ -649,9 +665,10 @@ 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 */ @@ -660,18 +677,8 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, ctrl |= (spi_imx->target_burst * 8 - 1) << MX51_ECSPI_CTRL_BL_OFFSET; else { - if (spi_imx->usedma) { - ctrl |= (spi_imx->bits_per_word - 1) - << MX51_ECSPI_CTRL_BL_OFFSET; - } else { - if (spi_imx->count >= MX51_ECSPI_CTRL_MAX_BURST) - ctrl |= (MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1) - << MX51_ECSPI_CTRL_BL_OFFSET; - else - ctrl |= (spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word, - BITS_PER_BYTE) * spi_imx->bits_per_word - 1) - << MX51_ECSPI_CTRL_BL_OFFSET; - } + ctrl |= (spi_imx->bits_per_word - 1) + << MX51_ECSPI_CTRL_BL_OFFSET; } /* set clock speed */ @@ -693,6 +700,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; } @@ -784,7 +834,7 @@ 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_HOST; unsigned int clk; @@ -888,7 +938,7 @@ 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_HOST; unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18; @@ -963,7 +1013,7 @@ 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_HOST; unsigned int clk; @@ -1060,7 +1110,7 @@ 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_targetmode = false, .devtype = IMX35_CSPI, @@ -1273,11 +1323,13 @@ static int spi_imx_setupxfer(struct spi_device *spi, /* * 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->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)) { @@ -1314,7 +1366,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, 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; } @@ -1405,7 +1457,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); @@ -1471,18 +1523,18 @@ static int spi_imx_dma_transfer(struct spi_imx_data *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); @@ -1501,7 +1553,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; @@ -1517,9 +1569,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; @@ -1620,12 +1672,30 @@ static int spi_imx_pio_transfer_target(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) { struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); - unsigned long hz_per_byte, byte_limit; spi_imx_setupxfer(spi, transfer); transfer->effective_speed_hz = spi_imx->spi_bus_clk; @@ -1644,15 +1714,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); @@ -1666,10 +1731,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) { @@ -1766,7 +1827,6 @@ 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->target_abort = spi_imx_target_abort; @@ -1880,8 +1940,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: @@ -1913,7 +1973,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; @@ -1934,7 +1994,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; @@ -1947,32 +2007,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 003a6d21c4c3..318b0768701e 100644 --- a/drivers/spi/spi-ingenic.c +++ b/drivers/spi/spi-ingenic.c @@ -16,6 +16,7 @@ #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) diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c index 4337ca51d7aa..4d9ffec900bb 100644 --- a/drivers/spi/spi-intel-pci.c +++ b/drivers/spi/spi-intel-pci.c @@ -86,6 +86,8 @@ static const struct pci_device_id intel_spi_pci_ids[] = { { PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0xa3a4), (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); @@ -94,6 +96,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..0974cca83a5d 100644 --- a/drivers/spi/spi-intel-platform.c +++ b/drivers/spi/spi-intel-platform.c @@ -28,6 +28,7 @@ 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 3e5dcf2b3c8a..b0dcdb6fb8fa 100644 --- a/drivers/spi/spi-intel.c +++ b/drivers/spi/spi-intel.c @@ -148,6 +148,8 @@ * @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 @@ -166,6 +168,8 @@ struct intel_spi { size_t pr_num; size_t chip0_size; bool locked; + bool protected; + bool bios_locked; bool swseq_reg; bool swseq_erase; u8 atomic_preopcode; @@ -1109,10 +1113,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 */ @@ -1247,8 +1254,10 @@ static void intel_spi_fill_partition(struct intel_spi *ispi, * 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 || intel_spi_is_protected(ispi, base, limit)) { part->mask_flags |= MTD_WRITEABLE; + ispi->protected = true; + } end = (limit << 12) + 4096; if (end > part->size) @@ -1390,6 +1399,9 @@ static int intel_spi_populate_chip(struct intel_spi *ispi) 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); @@ -1408,6 +1420,50 @@ static int intel_spi_populate_chip(struct intel_spi *ispi) 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 @@ -1448,6 +1504,7 @@ int intel_spi_probe(struct device *dev, struct resource *mem, 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..c5f35060dd63 100644 --- a/drivers/spi/spi-intel.h +++ b/drivers/spi/spi-intel.h @@ -13,6 +13,8 @@ struct resource; +extern const struct attribute_group *intel_spi_groups[]; + int intel_spi_probe(struct device *dev, struct resource *mem, const struct intel_spi_boardinfo *info); diff --git a/drivers/spi/spi-iproc-qspi.c b/drivers/spi/spi-iproc-qspi.c index 39ee2b43a516..392acc4026ab 100644 --- a/drivers/spi/spi-iproc-qspi.c +++ b/drivers/spi/spi-iproc-qspi.c @@ -138,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-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 18a46569ba46..60849e07f674 100644 --- a/drivers/spi/spi-lantiq-ssc.c +++ b/drivers/spi/spi-lantiq-ssc.c @@ -139,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 */ @@ -1029,7 +1029,7 @@ static void lantiq_ssc_remove(struct platform_device *pdev) 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 index 1cc1422ddba0..2cab79ad2b98 100644 --- a/drivers/spi/spi-ljca.c +++ b/drivers/spi/spi-ljca.c @@ -294,4 +294,4 @@ 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); +MODULE_IMPORT_NS("LJCA"); diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c index 3c0c24ed1f3d..e61e89b4119f 100644 --- a/drivers/spi/spi-lm70llp.c +++ b/drivers/spi/spi-lm70llp.c @@ -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 index f97800b6fd65..4fec226456d1 100644 --- a/drivers/spi/spi-loongson-core.c +++ b/drivers/spi/spi-loongson-core.c @@ -227,7 +227,7 @@ int loongson_spi_init_controller(struct device *dev, void __iomem *regs) return devm_spi_register_controller(dev, controller); } -EXPORT_SYMBOL_NS_GPL(loongson_spi_init_controller, SPI_LOONGSON_CORE); +EXPORT_SYMBOL_NS_GPL(loongson_spi_init_controller, "SPI_LOONGSON_CORE"); static int __maybe_unused loongson_spi_suspend(struct device *dev) { @@ -273,7 +273,7 @@ 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); +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 index 134cda0c13a5..cbcde153260e 100644 --- a/drivers/spi/spi-loongson-pci.c +++ b/drivers/spi/spi-loongson-pci.c @@ -19,12 +19,11 @@ static int loongson_spi_pci_register(struct pci_dev *pdev, if (ret < 0) return dev_err_probe(dev, ret, "cannot enable pci device\n"); - ret = pcim_iomap_regions(pdev, BIT(pci_bar), pci_name(pdev)); + 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"); - reg_base = pcim_iomap_table(pdev)[pci_bar]; - ret = loongson_spi_init_controller(dev, reg_base); if (ret) return dev_err_probe(dev, ret, "failed to initialize controller\n"); @@ -52,4 +51,4 @@ module_pci_driver(loongson_spi_pci_driver); MODULE_DESCRIPTION("Loongson spi pci driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SPI_LOONGSON_CORE); +MODULE_IMPORT_NS("SPI_LOONGSON_CORE"); diff --git a/drivers/spi/spi-loongson-plat.c b/drivers/spi/spi-loongson-plat.c index c066e5f5891e..64a7270f9a64 100644 --- a/drivers/spi/spi-loongson-plat.c +++ b/drivers/spi/spi-loongson-plat.c @@ -44,4 +44,4 @@ module_platform_driver(loongson_spi_plat_driver); MODULE_DESCRIPTION("Loongson spi platform driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SPI_LOONGSON_CORE); +MODULE_IMPORT_NS("SPI_LOONGSON_CORE"); diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index fee8893d2751..31a878d9458d 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -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, diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 17b8baf749e6..a9f0f47f4759 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -172,6 +172,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 +187,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); @@ -361,6 +374,9 @@ 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); + ret = spi_mem_check_op(op); if (ret) return ret; @@ -407,6 +423,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++; @@ -421,6 +438,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; @@ -432,6 +450,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; @@ -447,6 +466,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; @@ -525,6 +545,53 @@ 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. + * @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. + */ +u64 spi_mem_calc_op_duration(struct spi_mem_op *op) +{ + u64 ncycles = 0; + u32 ns_per_cycles; + + ns_per_cycles = 1000000000 / op->max_freq; + 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); + 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); + + return ncycles * ns_per_cycles; +} +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) { diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index fc75492e50ff..df74ad5060f8 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -514,7 +514,9 @@ static int meson_spicc_prepare_message(struct spi_controller *host, /* 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; } @@ -644,15 +646,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); @@ -670,9 +674,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; @@ -708,15 +712,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); @@ -734,8 +740,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; @@ -755,8 +761,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; @@ -846,7 +852,7 @@ static int meson_spicc_probe(struct platform_device *pdev) host->num_chipselect = 4; host->dev.of_node = pdev->dev.of_node; - host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH; + host->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LOOP; host->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | SPI_BPW_MASK(16) | @@ -943,7 +949,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 fd8b26dd4a79..ef7efeaeee97 100644 --- a/drivers/spi/spi-meson-spifc.c +++ b/drivers/spi/spi-meson-spifc.c @@ -429,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 03d125a71fd9..fa828fcaaef2 100644 --- a/drivers/spi/spi-microchip-core-qspi.c +++ b/drivers/spi/spi-microchip-core-qspi.c @@ -265,7 +265,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, + const struct spi_mem_op *op) { unsigned long clk_hz; u32 control, baud_rate_val = 0; @@ -274,15 +275,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 * op->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); + op->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); @@ -398,7 +400,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o if (err) goto error; - err = mchp_coreqspi_setup_clock(qspi, mem->spi); + err = mchp_coreqspi_setup_clock(qspi, mem->spi, op); if (err) goto error; @@ -456,6 +458,10 @@ error: static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { + struct mchp_coreqspi *qspi = spi_controller_get_devdata(mem->spi->controller); + unsigned long clk_hz; + u32 baud_rate_val; + if (!spi_mem_default_supports_op(mem, op)) return false; @@ -478,6 +484,14 @@ static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_ return false; } + clk_hz = clk_get_rate(qspi->clk); + if (!clk_hz) + return false; + + baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * op->max_freq); + if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER) + return false; + return true; } @@ -497,6 +511,10 @@ 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_probe(struct platform_device *pdev) { struct spi_controller *ctlr; @@ -539,6 +557,7 @@ static int mchp_coreqspi_probe(struct platform_device *pdev) 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; @@ -574,7 +593,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.c b/drivers/spi/spi-microchip-core.c index 634364c7cfe6..5b6af55855ef 100644 --- a/drivers/spi/spi-microchip-core.c +++ b/drivers/spi/spi-microchip-core.c @@ -21,7 +21,7 @@ #include <linux/spi/spi.h> #define MAX_LEN (0xffff) -#define MAX_CS (8) +#define MAX_CS (1) #define DEFAULT_FRAMESIZE (8) #define FIFO_DEPTH (32) #define CLK_GEN_MODE1_MAX (255) @@ -75,6 +75,7 @@ #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) @@ -89,6 +90,9 @@ #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) @@ -103,10 +107,11 @@ struct mchp_corespi { 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 pending; + int n_bytes; }; static inline u32 mchp_corespi_read(struct mchp_corespi *spi, unsigned int reg) @@ -130,113 +135,126 @@ static inline void mchp_corespi_disable(struct mchp_corespi *spi) static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi) { - u8 data; - int fifo_max, i = 0; + while (spi->rx_len >= spi->n_bytes && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)) { + u32 data = mchp_corespi_read(spi, REG_RX_DATA); - fifo_max = min(spi->rx_len, FIFO_DEPTH); + spi->rx_len -= spi->n_bytes; - 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) + continue; - if (spi->rx_buf) - *spi->rx_buf++ = data; - i++; + 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; } - 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); + u32 control = mchp_corespi_read(spi, REG_CONTROL); - control |= mask; - mchp_corespi_write(spi, REG_CONTROL, control); - - control |= CONTROL_ENABLE; + control |= INT_ENABLE_MASK; 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); + u32 control = mchp_corespi_read(spi, REG_CONTROL); - control |= CONTROL_ENABLE; + control &= ~INT_ENABLE_MASK; 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; + u32 lenpart; + u32 frames = mchp_corespi_read(spi, REG_FRAMESUP); /* - * Disable the SPI controller. Writes to transfer length have - * no effect when the controller is enabled. + * Writing to FRAMECNT in REG_CONTROL will reset the frame count, taking + * a shortcut requires an explicit clear. */ - mchp_corespi_disable(spi); + if (frames == len) { + mchp_corespi_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 a NOP + * 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 = 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); + mchp_corespi_write(spi, REG_FRAMESUP, len); } 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); + fifo_max = DIV_ROUND_UP(min(spi->tx_len, FIFO_DEPTH), spi->n_bytes); 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); + 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; + + mchp_corespi_write(spi, REG_TX_DATA, word); + if (spi->tx_buf) + spi->tx_buf += spi->n_bytes; i++; } - spi->tx_len -= i; - spi->pending += i; + spi->tx_len -= i * spi->n_bytes; } static inline void mchp_corespi_set_framesize(struct mchp_corespi *spi, int bt) { + u32 frame_size = mchp_corespi_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. */ - mchp_corespi_disable(spi); + control = mchp_corespi_read(spi, REG_CONTROL); + control &= ~CONTROL_ENABLE; + mchp_corespi_write(spi, REG_CONTROL, control); 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); } @@ -249,8 +267,18 @@ static void mchp_corespi_set_cs(struct spi_device *spi, bool disable) reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT); reg &= ~BIT(spi_get_chipselect(spi, 0)); reg |= !disable << spi_get_chipselect(spi, 0); + corespi->pending_slave_select = reg; - mchp_corespi_write(corespi, REG_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) + mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg); } static int mchp_corespi_setup(struct spi_device *spi) @@ -258,6 +286,9 @@ static int mchp_corespi_setup(struct spi_device *spi) struct mchp_corespi *corespi = 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 @@ -266,6 +297,7 @@ static int mchp_corespi_setup(struct spi_device *spi) if (spi->mode & SPI_CS_HIGH) { reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT); reg |= BIT(spi_get_chipselect(spi, 0)); + corespi->pending_slave_select = reg; mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg); } return 0; @@ -276,17 +308,13 @@ static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi * unsigned long clk_hz; u32 control = mchp_corespi_read(spi, REG_CONTROL); - control |= CONTROL_MASTER; + control &= ~CONTROL_ENABLE; + mchp_corespi_write(spi, REG_CONTROL, 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); - host->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 @@ -295,11 +323,16 @@ static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi * * 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_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; + mchp_corespi_enable_ints(spi); /* @@ -307,7 +340,8 @@ static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi * * select is relinquished to the hardware. SSELOUT is enabled too so we * can deal with active high targets. */ - mchp_corespi_write(spi, REG_SLAVE_SELECT, SSELOUT | SSEL_DIRECT); + spi->pending_slave_select = SSELOUT | SSEL_DIRECT; + mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select); control = mchp_corespi_read(spi, REG_CONTROL); @@ -321,8 +355,6 @@ 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; @@ -331,12 +363,12 @@ static inline void mchp_corespi_set_clk_gen(struct mchp_corespi *spi) 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; + u32 mode_val; + u32 control = mchp_corespi_read(spi, REG_CONTROL); switch (mode & SPI_MODE_X_MASK) { case SPI_MODE_0: @@ -354,12 +386,13 @@ static inline void mchp_corespi_set_mode(struct mchp_corespi *spi, unsigned int } /* - * Disable the SPI controller. Writes to the frame size have + * Disable the SPI controller. Writes to the frame protocol have * no effect when the controller is enabled. */ - mchp_corespi_disable(spi); - control = mchp_corespi_read(spi, REG_CONTROL); + control &= ~CONTROL_ENABLE; + mchp_corespi_write(spi, REG_CONTROL, control); + control &= ~(SPI_MODE_X_MASK << MODE_X_MASK_SHIFT); control |= mode_val; @@ -380,21 +413,18 @@ static irqreturn_t mchp_corespi_interrupt(int irq, void *dev_id) if (intfield == 0) return IRQ_NONE; - if (intfield & INT_TXDONE) { + if (intfield & INT_TXDONE) mchp_corespi_write(spi, REG_INT_CLEAR, INT_TXDONE); + if (intfield & INT_RXRDY) { + mchp_corespi_write(spi, REG_INT_CLEAR, INT_RXRDY); + 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 (!spi->rx_len && !spi->tx_len) + finalise = true; if (intfield & INT_RX_CHANNEL_OVERFLOW) { mchp_corespi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW); @@ -474,13 +504,17 @@ static int mchp_corespi_transfer_one(struct spi_controller *host, spi->rx_buf = xfer->rx_buf; spi->tx_len = xfer->len; spi->rx_len = xfer->len; - spi->pending = 0; + spi->n_bytes = roundup_pow_of_two(DIV_ROUND_UP(xfer->bits_per_word, BITS_PER_BYTE)); - mchp_corespi_set_xfer_size(spi, (spi->tx_len > FIFO_DEPTH) - ? FIFO_DEPTH : spi->tx_len); + mchp_corespi_set_framesize(spi, xfer->bits_per_word); - if (spi->tx_len) + mchp_corespi_write(spi, REG_COMMAND, COMMAND_RXFIFORST | COMMAND_TXFIFORST); + + mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select); + + while (spi->tx_len) mchp_corespi_write_fifo(spi); + return 1; } @@ -490,7 +524,6 @@ static int mchp_corespi_prepare_message(struct spi_controller *host, struct spi_device *spi_dev = msg->spi; struct mchp_corespi *spi = spi_controller_get_devdata(host); - mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE); mchp_corespi_set_mode(spi, spi_dev->mode); return 0; @@ -516,8 +549,9 @@ static int mchp_corespi_probe(struct platform_device *pdev) host->num_chipselect = num_cs; host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + host->use_gpio_descriptors = true; host->setup = mchp_corespi_setup; - host->bits_per_word_mask = SPI_BPW_MASK(8); + host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); host->transfer_one = mchp_corespi_transfer_one; host->prepare_message = mchp_corespi_prepare_message; host->set_cs = mchp_corespi_set_cs; @@ -588,7 +622,7 @@ static struct platform_driver mchp_corespi_driver = { .pm = MICROCHIP_SPI_PM_OPS, .of_match_table = of_match_ptr(mchp_corespi_dt_ids), }, - .remove_new = mchp_corespi_remove, + .remove = mchp_corespi_remove, }; module_platform_driver(mchp_corespi_driver); MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver"); diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index 28f06122edac..3bbeb8d5bfb8 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -107,7 +107,7 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, 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; @@ -325,7 +325,7 @@ static int mpc52xx_psc_spi_of_probe(struct platform_device *pdev) 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); diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index d5ac60c135c2..6d4dde15ac54 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -520,6 +520,7 @@ static void mpc52xx_spi_remove(struct platform_device *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); @@ -544,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-mt65xx.c b/drivers/spi/spi-mt65xx.c index e4cb22fe0075..197bf2dbe5de 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -743,61 +743,47 @@ 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_controller *host = dev_id; struct mtk_spi *mdata = spi_controller_get_devdata(host); - 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_transfer *xfer = mdata->cur_transfer; - if (!host->can_dma(host, 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) { + 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(host); - if (trans->tx_buf) { + if (xfer->tx_buf) { cnt = mdata->xfer_len / 4; iowrite32_rep(mdata->base + SPI_TX_DATA_REG, - trans->tx_buf + mdata->num_xfered, cnt); + 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, + xfer->tx_buf + (cnt * 4) + mdata->num_xfered, remainder); writel(reg_val, mdata->base + SPI_TX_DATA_REG); } @@ -809,21 +795,21 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) } 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); } } @@ -841,12 +827,33 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) mtk_spi_update_mdata_len(host); mtk_spi_setup_packet(host); - mtk_spi_setup_dma_addr(host, trans); + 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) { @@ -954,7 +961,7 @@ static int mtk_spi_mem_exec_op(struct spi_mem *mem, mtk_spi_reset(mdata); mtk_spi_hw_init(mem->spi->controller, mem->spi); - mtk_spi_prepare_transfer(mem->spi->controller, mem->spi->max_speed_hz); + mtk_spi_prepare_transfer(mem->spi->controller, op->max_freq); reg_val = readl(mdata->base + SPI_CFG3_IPM_REG); /* opcode byte len */ @@ -1115,6 +1122,10 @@ 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; @@ -1153,6 +1164,7 @@ static int mtk_spi_probe(struct platform_device *pdev) if (mdata->dev_comp->ipm_design) { mdata->dev = dev; host->mem_ops = &mtk_spi_mem_ops; + host->mem_caps = &mtk_spi_mem_caps; init_completion(&mdata->spimem_done); } @@ -1257,8 +1269,9 @@ 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), host); + 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"); @@ -1424,7 +1437,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 4e9053d03d5a..3770b8e096a4 100644 --- a/drivers/spi/spi-mt7621.c +++ b/drivers/spi/spi-mt7621.c @@ -52,6 +52,8 @@ #define MT7621_CPOL BIT(4) #define MT7621_LSB_FIRST BIT(3) +#define MT7621_NATIVE_CS_COUNT 2 + struct mt7621_spi { struct spi_controller *host; void __iomem *base; @@ -75,10 +77,11 @@ 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 host; @@ -94,7 +97,7 @@ static void mt7621_spi_set_cs(struct spi_device *spi, int enable) rs->pending_write = 0; - if (enable) + if (active) polar = BIT(cs); mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); } @@ -154,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) { @@ -243,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 *host, - 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(host); - 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; - } - - /* 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; + 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); } - /* Flush data and deassert CS */ - mt7621_spi_flush(rs); - mt7621_spi_set_cs(spi, 0); - -msg_done: - m->status = status; - spi_finalize_current_message(host); - return 0; } @@ -353,10 +344,14 @@ static int mt7621_spi_probe(struct platform_device *pdev) host->mode_bits = SPI_LSB_FIRST; host->flags = SPI_CONTROLLER_HALF_DUPLEX; host->setup = mt7621_spi_setup; - host->transfer_one_message = mt7621_spi_transfer_one_message; + 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->num_chipselect = 2; + 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); diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index 62b1c8995fa4..85ab5ce96c4d 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -998,7 +998,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 ddd98ddb7913..fdbea9dffb62 100644 --- a/drivers/spi/spi-mtk-snfi.c +++ b/drivers/spi/spi-mtk-snfi.c @@ -776,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, @@ -1187,7 +1187,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. @@ -1477,7 +1477,7 @@ static void mtk_snand_remove(struct platform_device *pdev) 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 bd988f53753e..c02c4204442f 100644 --- a/drivers/spi/spi-mux.c +++ b/drivers/spi/spi-mux.c @@ -68,6 +68,8 @@ static int spi_mux_select(struct spi_device *spi) priv->current_cs = spi_get_chipselect(spi, 0); + spi_setup(priv->spi); + return 0; } @@ -156,12 +158,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 60c9f3048ac9..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); @@ -397,7 +403,8 @@ static ssize_t mxic_spi_mem_dirmap_read(struct spi_mem_dirmap_desc *desc, 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); @@ -441,7 +448,8 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_mem_dirmap_desc *desc, 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); @@ -496,7 +504,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_dirmap_desc *desc) 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; @@ -514,11 +522,11 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, 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,6 +581,8 @@ 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) @@ -640,7 +650,7 @@ static int mxic_spi_transfer_one(struct spi_controller *host, /* 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, @@ -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 88cbe4f00cc3..43455305fdf4 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -381,6 +381,8 @@ static int mxs_spi_transfer_one(struct spi_controller *host, 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; @@ -477,7 +479,7 @@ 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_controller *host = dev_get_drvdata(dev); int ret; @@ -492,7 +494,7 @@ 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_controller *host = dev_get_drvdata(dev); int ret; @@ -512,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[] = { @@ -658,11 +659,11 @@ 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), }, }; diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index f3bb8bbc192f..958bab27a081 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -766,12 +766,12 @@ 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 a7feb20b06ee..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> @@ -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 88397f712a3b..bad6b30bab0e 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -57,13 +57,6 @@ #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 - /* Registers used by the driver */ #define FSPI_MCR0 0x00 #define FSPI_MCR0_AHB_TIMEOUT(x) ((x) << 24) @@ -263,9 +256,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 */ @@ -341,6 +331,7 @@ struct nxp_fspi_devtype_data { unsigned int txfifo; unsigned int ahb_buf_size; unsigned int quirks; + unsigned int lut_num; bool little_endian; }; @@ -349,6 +340,7 @@ static struct nxp_fspi_devtype_data lx2160a_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 */ }; @@ -357,6 +349,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 */ }; @@ -365,6 +358,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 */ }; @@ -373,6 +367,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 */ }; @@ -544,6 +548,8 @@ 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), @@ -588,8 +594,10 @@ 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[%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); @@ -697,9 +705,10 @@ 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; + unsigned long rate = op->max_freq; int ret; uint64_t size_kb; @@ -756,8 +765,7 @@ 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(f->memmap_phy + f->memmap_start, f->memmap_len); @@ -805,14 +813,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); @@ -875,7 +884,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 */ @@ -891,8 +900,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); @@ -922,7 +932,7 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) 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); /* @@ -1016,7 +1026,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); @@ -1091,11 +1101,17 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) 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; @@ -1134,6 +1150,10 @@ 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 = { + .per_op_freq = true, +}; + static int nxp_fspi_probe(struct platform_device *pdev) { struct spi_controller *ctlr; @@ -1231,6 +1251,7 @@ static int nxp_fspi_probe(struct platform_device *pdev) ctlr->bus_num = -1; ctlr->num_chipselect = NXP_FSPI_MAX_CHIPSELECT; ctlr->mem_ops = &nxp_fspi_mem_ops; + ctlr->mem_caps = &nxp_fspi_mem_caps; nxp_fspi_default_setup(f); @@ -1290,6 +1311,7 @@ static const struct of_device_id nxp_fspi_dt_ids[] = { { .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); @@ -1315,7 +1337,7 @@ static struct platform_driver nxp_fspi_driver = { .pm = &nxp_fspi_pm_ops, }, .probe = nxp_fspi_probe, - .remove_new = nxp_fspi_remove, + .remove = 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 6ea38f5e7d64..cba229920357 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -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); @@ -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-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 210a98d903fa..b9a91dbfeaef 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -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 ddf1c684bcc7..29c616e2c408 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 @@ -131,6 +133,7 @@ struct omap2_mcspi { unsigned int pin_dir:1; size_t max_xfer_len; u32 ref_clk_hz; + bool use_multi_mode; }; struct omap2_mcspi_cs { @@ -256,10 +259,15 @@ 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); @@ -283,7 +291,12 @@ static void omap2_mcspi_set_mode(struct spi_controller *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(ctlr, OMAP2_MCSPI_MODULCTRL, l); @@ -1175,13 +1188,6 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, 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(ctlr, 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; @@ -1204,8 +1210,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, unsigned count; if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && - ctlr->cur_msg_mapped && - ctlr->can_dma(ctlr, spi, t)) + spi_xfer_is_dma_mapped(ctlr, spi, t)) omap2_mcspi_set_fifo(spi, t, 1); omap2_mcspi_set_enable(spi, 1); @@ -1216,8 +1221,7 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, + OMAP2_MCSPI_TX0); if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && - ctlr->cur_msg_mapped && - ctlr->can_dma(ctlr, 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); @@ -1240,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(ctlr, 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)) @@ -1265,15 +1261,59 @@ static int omap2_mcspi_prepare_message(struct spi_controller *ctlr, 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; - /* Only a single channel can have the FORCE bit enabled + /* + * 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; + 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; + } + + /* Check if transfer asks to change the CS status after the transfer */ + if (!tr->cs_change) + mcspi->use_multi_mode = false; + + /* + * If at least one message is not compatible, switch back to single mode + * + * The bits_per_word of certain transfer can be different, but it will have no + * impact on the signal itself. + */ + if (!mcspi->use_multi_mode) + break; + } + + 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; @@ -1521,6 +1561,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev) } 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 @@ -1614,8 +1659,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 eee9ff4bfa5b..43bd9f21137f 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -18,7 +18,7 @@ #include <linux/of_address.h> #include <linux/clk.h> #include <linux/sizes.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #define DRIVER_NAME "orion_spi" @@ -846,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 cc18d320370f..fc98979eba48 100644 --- a/drivers/spi/spi-pci1xxxx.c +++ b/drivers/spi/spi-pci1xxxx.c @@ -6,6 +6,7 @@ #include <linux/bitfield.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/iopoll.h> #include <linux/irq.h> @@ -15,7 +16,7 @@ #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" @@ -567,7 +568,7 @@ error: static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr, struct spi_device *spi, struct spi_transfer *xfer) { - if (spi_ctlr->can_dma(spi_ctlr, spi, xfer) && spi_ctlr->cur_msg_mapped) + 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); diff --git a/drivers/spi/spi-pic32-sqi.c b/drivers/spi/spi-pic32-sqi.c index 3f1e5b27776b..fa0c1ee84532 100644 --- a/drivers/spi/spi-pic32-sqi.c +++ b/drivers/spi/spi-pic32-sqi.c @@ -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); } @@ -344,7 +344,7 @@ static int pic32_sqi_one_message(struct spi_controller *host, struct spi_transfer *xfer; struct pic32_sqi *sqi; int ret = 0, mode; - unsigned long timeout; + unsigned long time_left; u32 val; sqi = spi_controller_get_devdata(host); @@ -410,8 +410,8 @@ static int pic32_sqi_one_message(struct spi_controller *host, 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) { + 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; @@ -682,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 709edb70ad7d..369850d14313 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -498,7 +498,7 @@ static int pic32_spi_one_transfer(struct spi_controller *host, { struct pic32_spi *pic32s; bool dma_issued = false; - unsigned long timeout; + unsigned long time_left; int ret; pic32s = spi_controller_get_devdata(host); @@ -545,8 +545,8 @@ static int pic32_spi_one_transfer(struct spi_controller *host, } /* 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(host->dma_rx); @@ -859,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 de63cf0557ce..dd87cf4f70dd 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -899,7 +899,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) diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 942c3117ab3a..688cabcfbc52 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -20,23 +20,21 @@ * during SPI transfers by setting max_speed_hz via the device tree. */ -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/slab.h> +#include <linux/delay.h> #include <linux/errno.h> -#include <linux/wait.h> -#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.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/platform_device.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/wait.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> @@ -412,7 +410,11 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) } /* 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) { @@ -482,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 f2a856f6a99e..06711a62fa3d 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); @@ -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 = @@ -1209,42 +1174,19 @@ 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; @@ -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 = (uintptr_t)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_target = 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_target) controller = devm_spi_alloc_target(dev, sizeof(*drv_data)); else controller = devm_spi_alloc_host(dev, sizeof(*drv_data)); + if (!controller) + return dev_err_probe(dev, -ENOMEM, "cannot alloc spi_controller\n"); - 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; @@ -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); } } @@ -1613,8 +1427,6 @@ 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; @@ -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 49b775134485..3aeddada58e1 100644 --- a/drivers/spi/spi-qcom-qspi.c +++ b/drivers/spi/spi-qcom-qspi.c @@ -771,7 +771,7 @@ static int qcom_qspi_probe(struct platform_device *pdev) host->prepare_message = qcom_qspi_prepare_message; host->transfer_one = qcom_qspi_transfer_one; host->handle_err = qcom_qspi_handle_err; - if (of_property_read_bool(pdev->dev.of_node, "iommus")) + 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; @@ -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-qup.c b/drivers/spi/spi-qup.c index 2af63040ac6e..7d647edf6bc3 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -5,6 +5,8 @@ #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> @@ -16,8 +18,7 @@ #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 @@ -709,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->controller->can_dma && - spi->controller->can_dma(spi->controller, spi, xfer) && - spi->controller->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; @@ -1365,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 225f75550780..e71d3805b150 100644 --- a/drivers/spi/spi-rb4xx.c +++ b/drivers/spi/spi-rb4xx.c @@ -196,7 +196,7 @@ MODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match); static struct platform_driver rb4xx_spi_drv = { .probe = rb4xx_spi_probe, - .remove_new = rb4xx_spi_remove, + .remove = rb4xx_spi_remove, .driver = { .name = "rb4xx-spi", .of_match_table = of_match_ptr(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..cd0484041147 --- /dev/null +++ b/drivers/spi/spi-realtek-rtl-snand.c @@ -0,0 +1,419 @@ +// 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, + .cache_type = REGCACHE_NONE, + }; + 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-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c index 0d7fadcd4ed3..f3fe10eddb6a 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); @@ -490,20 +526,28 @@ static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op 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); - if (unlikely(mem->spi->max_speed_hz != sfc->frequency)) { - ret = clk_set_rate(sfc->clk, mem->spi->max_speed_hz); + ret = pm_runtime_get_sync(sfc->dev); + if (ret < 0) { + pm_runtime_put_noidle(sfc->dev); + return ret; + } + + 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,11 +558,17 @@ 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_mark_last_busy(sfc->dev); + pm_runtime_put_autosuspend(sfc->dev); + + return ret; } static int rockchip_sfc_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) @@ -535,6 +585,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; @@ -560,6 +614,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev) struct spi_controller *host; struct rockchip_sfc *sfc; int ret; + u32 i, val; host = devm_spi_alloc_host(&pdev->dev, sizeof(*sfc)); if (!host) @@ -567,6 +622,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev) 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; @@ -574,40 +630,35 @@ static int rockchip_sfc_probe(struct platform_device *pdev) 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); - } - - 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); - } + 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->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 +680,50 @@ 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); + + 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); - ret = spi_register_controller(host); + 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 = virt_to_phys(sfc->buffer); + } + + ret = devm_spi_register_controller(dev, host); if (ret) - goto err_irq; + goto err_register; - return 0; + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; +err_register: + 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 +734,84 @@ err_hclk: static void rockchip_sfc_remove(struct platform_device *pdev) { - struct spi_controller *host = platform_get_drvdata(pdev); struct rockchip_sfc *sfc = platform_get_drvdata(pdev); + struct spi_controller *host = sfc->host; spi_unregister_controller(host); + 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_mark_last_busy(dev); + 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 +822,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 e1ecd96c7858..1bc012fce7cb 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -192,7 +192,7 @@ struct rockchip_spi { u8 rsd; bool target_abort; - bool cs_inactive; /* spi target tansmition stop when cs inactive */ + 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 */ @@ -241,6 +241,20 @@ 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; + + /* + * 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) { /* Keep things powered as long as CS is asserted */ @@ -742,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 target_mode; + int ret; target_mode = of_property_read_bool(np, "spi-slave"); if (target_mode) - ctlr = spi_alloc_target(&pdev->dev, - sizeof(struct rockchip_spi)); + ctlr = spi_alloc_target(&pdev->dev, sizeof(struct rockchip_spi)); else - ctlr = spi_alloc_host(&pdev->dev, - sizeof(struct rockchip_spi)); + ctlr = spi_alloc_host(&pdev->dev, sizeof(struct rockchip_spi)); if (!ctlr) return -ENOMEM; @@ -769,21 +781,21 @@ 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_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_enabled(&pdev->dev, "spiclk"); if (IS_ERR(rs->spiclk)) { - dev_err(&pdev->dev, "Failed to get spi_pclk\n"); - ret = PTR_ERR(rs->spiclk); + ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->spiclk), + "Failed to get spi_pclk\n"); goto err_put_ctlr; } @@ -794,7 +806,7 @@ static int rockchip_spi_probe(struct platform_device *pdev) 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_put_ctlr; @@ -804,24 +816,22 @@ 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; + ret = dev_err_probe(&pdev->dev, -EINVAL, "Failed to get fifo length\n"); goto err_put_ctlr; } @@ -861,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; } @@ -945,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); @@ -963,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 */ @@ -1045,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 e11146932828..e0c66a24a3cb 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, @@ -95,16 +95,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 (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) + return -EOPNOTSUPP; return 0; } @@ -198,9 +198,16 @@ static int __maybe_unused rpcif_spi_resume(struct device *dev) static 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 diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 8e81f1a8623f..92faaf614f8e 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -24,7 +24,6 @@ #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,7 +1285,6 @@ 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; @@ -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); @@ -1437,7 +1427,7 @@ static 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", diff --git a/drivers/spi/spi-rzv2m-csi.c b/drivers/spi/spi-rzv2m-csi.c index 741e0f44c49c..7c0442883ac0 100644 --- a/drivers/spi/spi-rzv2m-csi.c +++ b/drivers/spi/spi-rzv2m-csi.c @@ -683,7 +683,7 @@ MODULE_DEVICE_TABLE(of, rzv2m_csi_match); static struct platform_driver rzv2m_csi_drv = { .probe = rzv2m_csi_probe, - .remove_new = rzv2m_csi_remove, + .remove = rzv2m_csi_remove, .driver = { .name = "rzv2m_csi", .of_match_table = rzv2m_csi_match, diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index f726d8670428..389275dbc003 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -245,7 +245,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"); @@ -258,7 +258,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"); @@ -950,7 +950,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata( struct spi_device *spi) { struct s3c64xx_spi_csinfo *cs; - struct device_node *target_np, *data_np = NULL; + struct device_node *target_np; u32 fb_delay = 0; target_np = spi->dev.of_node; @@ -963,7 +963,8 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata( if (!cs) return ERR_PTR(-ENOMEM); - data_np = of_get_child_by_name(target_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; @@ -971,7 +972,6 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_target_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; } @@ -1353,7 +1353,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); @@ -1637,6 +1637,7 @@ static const struct platform_device_id s3c64xx_spi_driver_ids[] = { }, { }, }; +MODULE_DEVICE_TABLE(platform, s3c64xx_spi_driver_ids); static const struct of_device_id s3c64xx_spi_dt_match[] = { { .compatible = "google,gs101-spi", @@ -1680,7 +1681,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 eecf9ea95ae3..1627aa66c965 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -7,13 +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.h> #include <linux/platform_data/sc18is602.h> +#include <linux/property.h> + #include <linux/gpio/consumer.h> enum chips { sc18is602, sc18is602b, sc18is603 }; @@ -236,9 +238,7 @@ 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_controller *host; @@ -251,8 +251,9 @@ static int sc18is602_probe(struct i2c_client *client) if (!host) return -ENOMEM; + device_set_node(&host->dev, dev_fwnode(dev)); + hw = spi_controller_get_devdata(host); - i2c_set_clientdata(client, hw); /* assert reset and then release */ hw->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); @@ -265,11 +266,7 @@ static int sc18is602_probe(struct i2c_client *client) hw->dev = dev; hw->ctrl = 0xff; - if (client->dev.of_node) - hw->id = (uintptr_t)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: @@ -278,28 +275,21 @@ static int sc18is602_probe(struct i2c_client *client) break; case sc18is603: host->num_chipselect = 2; - if (pdata) { + 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; } - host->bus_num = np ? -1 : client->adapter->nr; + 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->dev.of_node = np; host->min_speed_hz = hw->freq / 128; host->max_speed_hz = hw->freq / 4; @@ -314,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 @@ -334,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, diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 5d63aa1d28e2..93017faeb7b5 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -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 6f12e4fb2e2e..8a98c313548e 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -27,7 +27,7 @@ #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) @@ -1429,7 +1429,7 @@ static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend, 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", diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 3d560b154ad3..f66efaabcaca 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -183,7 +183,7 @@ static void sh_sci_spi_remove(struct platform_device *dev) 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 4b873d9a7602..130d7fc452fa 100644 --- a/drivers/spi/spi-sh.c +++ b/drivers/spi/spi-sh.c @@ -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 cfd17bbb2202..87bde2a207a3 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -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 f1ddf4c099a3..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) @@ -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) { @@ -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 a7c3b3923b4a..c4969f66a0ba 100644 --- a/drivers/spi/spi-sn-f-ospi.c +++ b/drivers/spi/spi-sn-f-ospi.c @@ -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); @@ -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; @@ -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.c b/drivers/spi/spi-sprd.c index 831ebae10fe0..ae794058b381 100644 --- a/drivers/spi/spi-sprd.c +++ b/drivers/spi/spi-sprd.c @@ -728,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); @@ -1072,7 +1072,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 e064025e2fd6..4cff976ab16f 100644 --- a/drivers/spi/spi-st-ssc4.c +++ b/drivers/spi/spi-st-ssc4.c @@ -449,7 +449,7 @@ static struct platform_driver spi_st_driver = { .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-qspi.c b/drivers/spi/spi-stm32-qspi.c index f1e922fd362a..540b6948b24d 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -349,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; @@ -653,9 +653,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"); @@ -676,10 +674,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"); } @@ -965,7 +963,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 e4e7ddb7524a..da3517d7102d 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -1057,7 +1057,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; @@ -2044,6 +2044,7 @@ static const struct stm32_spi_cfg stm32mp25_spi_cfg = { .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[] = { @@ -2355,7 +2356,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 11d8bd27b3e9..fcbe864c9b7d 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -206,7 +206,8 @@ static int sun4i_spi_transfer_one(struct spi_controller *host, struct spi_transfer *tfr) { struct sun4i_spi *sspi = spi_controller_get_devdata(host); - unsigned int mclk_rate, div, timeout; + unsigned int mclk_rate, div; + unsigned long time_left; unsigned int start, end, tx_time; unsigned int tx_len = 0; int ret = 0; @@ -327,10 +328,10 @@ static int sun4i_spi_transfer_one(struct spi_controller *host, 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) { + 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, @@ -534,7 +535,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 cd018ea1abf1..871dfd3e77be 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -277,7 +277,8 @@ static int sun6i_spi_transfer_one(struct spi_controller *host, struct spi_transfer *tfr) { struct sun6i_spi *sspi = spi_controller_get_devdata(host); - unsigned int div, div_cdr1, div_cdr2, timeout; + 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, nbits = 0; @@ -488,26 +489,26 @@ static int sun6i_spi_transfer_one(struct spi_controller *host, 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 (timeout && rx_len) { + if (time_left && rx_len) { /* * Even though RX on the peripheral side has finished * RX DMA might still be in flight */ - timeout = wait_for_completion_timeout(&sspi->dma_rx_done, - timeout); - if (!timeout) + 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) { + 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, @@ -809,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 4e481380c259..7fd4cc6f74c2 100644 --- a/drivers/spi/spi-sunplus-sp7021.c +++ b/drivers/spi/spi-sunplus-sp7021.c @@ -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 7cb4301a6fb2..eaf560487591 100644 --- a/drivers/spi/spi-synquacer.c +++ b/drivers/spi/spi-synquacer.c @@ -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 bc7cc4088eea..3822d7c8d8ed 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1518,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 9f6b9f89be5b..d5c8ee20b8e5 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -600,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 ed1393d159ae..fe452d03c1ee 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -542,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; @@ -1214,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 afbd64a217eb..08e49a876894 100644 --- a/drivers/spi/spi-tegra210-quad.c +++ b/drivers/spi/spi-tegra210-quad.c @@ -341,7 +341,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); } @@ -1724,7 +1724,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 0fe6899e78dd..a284d2794586 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -623,7 +623,7 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem, 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, @@ -658,6 +658,10 @@ static const struct spi_controller_mem_ops ti_qspi_mem_ops = { .adjust_op_size = ti_qspi_adjust_op_size, }; +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) { @@ -777,6 +781,7 @@ static int ti_qspi_probe(struct platform_device *pdev) 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)) host->num_chipselect = num_cs; @@ -824,22 +829,14 @@ static int ti_qspi_probe(struct platform_device *pdev) } - 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_host; } - 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_host; - } } qspi->fclk = devm_clk_get(&pdev->dev, "fck"); @@ -863,7 +860,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, @@ -931,7 +927,7 @@ static const struct dev_pm_ops ti_qspi_pm_ops = { static struct platform_driver ti_qspi_driver = { .probe = ti_qspi_probe, - .remove_new = ti_qspi_remove, + .remove = ti_qspi_remove, .driver = { .name = "ti-qspi", .pm = &ti_qspi_pm_ops, diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 271f3e7f834b..60fce5c73031 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -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 4a18cf896194..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 @@ -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-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c index 6b16a22cc3a4..a9aee2a6c7dc 100644 --- a/drivers/spi/spi-wpcm-fiu.c +++ b/drivers/spi/spi-wpcm-fiu.c @@ -378,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 @@ -387,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; } @@ -448,12 +448,10 @@ static int wpcm_fiu_probe(struct platform_device *pdev) 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)) @@ -462,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 63354dd3110f..3bd0149d8f4e 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 void 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; + + 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,13 +160,13 @@ 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; } @@ -133,12 +174,12 @@ static int spi_xcomm_txrx_bufs(struct spi_xcomm *spi_xcomm, } static int spi_xcomm_transfer_one(struct spi_controller *host, - struct spi_message *msg) + struct spi_message *msg) { 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_controller *host, 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; @@ -208,7 +248,7 @@ static int spi_xcomm_probe(struct i2c_client *i2c) struct spi_controller *host; int ret; - host = spi_alloc_host(&i2c->dev, sizeof(*spi_xcomm)); + host = devm_spi_alloc_host(&i2c->dev, sizeof(*spi_xcomm)); if (!host) return -ENOMEM; @@ -221,13 +261,12 @@ static int spi_xcomm_probe(struct i2c_client *i2c) host->flags = SPI_CONTROLLER_HALF_DUPLEX; host->transfer_one_message = spi_xcomm_transfer_one; host->dev.of_node = i2c->dev.of_node; - i2c_set_clientdata(i2c, host); ret = devm_spi_register_controller(&i2c->dev, host); if (ret < 0) - spi_controller_put(host); + 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 7795328427a6..ded709b2b459 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -524,7 +524,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 49302364b7bd..2fec18b68449 100644 --- a/drivers/spi/spi-xlp.c +++ b/drivers/spi/spi-xlp.c @@ -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; } diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c index 3c2cda315397..1b54d8f9f5ec 100644 --- a/drivers/spi/spi-xtensa-xtfpga.c +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -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 d6325c6be3d4..2bd25c75f881 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -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); @@ -379,12 +381,21 @@ static int zynq_qspi_setup_op(struct spi_device *spi) { 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); @@ -534,7 +545,7 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, 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 +580,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 +631,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 @@ -706,6 +721,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; @@ -763,7 +779,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 99524a3c9f38..d800d79f62a7 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -535,7 +535,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. @@ -553,12 +553,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; @@ -1033,6 +1033,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,6 +1061,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, { 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; @@ -1059,7 +1072,7 @@ static int zynqmp_qspi_exec_op(struct spi_mem *mem, 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; @@ -1077,8 +1090,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; } @@ -1104,8 +1119,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; } @@ -1173,8 +1190,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; } @@ -1206,6 +1224,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 @@ -1224,7 +1246,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) u32 num_cs; const struct qspi_platform_data *p_data; - ctlr = spi_alloc_host(&pdev->dev, sizeof(*xqspi)); + ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*xqspi)); if (!ctlr) return -ENOMEM; @@ -1238,30 +1260,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_ctlr; - } + 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_ctlr; - } + 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_ctlr; - } + 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_ctlr; - } + if (ret) + return dev_err_probe(dev, ret, "Unable to enable APB clock.\n"); ret = clk_prepare_enable(xqspi->refclk); if (ret) { @@ -1323,6 +1337,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; @@ -1341,13 +1356,12 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) clk_dis_all: 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_ctlr: - spi_controller_put(ctlr); return ret; } @@ -1371,6 +1385,7 @@ static void zynqmp_qspi_remove(struct platform_device *pdev) 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); @@ -1381,7 +1396,7 @@ 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 ff75838c1b5d..a7a4647717d4 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -312,7 +312,7 @@ static const struct attribute_group *spi_master_groups[] = { 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 +328,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 +371,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,19 +410,21 @@ 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); if (ret) @@ -597,10 +597,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; } @@ -685,10 +691,12 @@ static int __spi_add_device(struct spi_device *spi) * 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. */ - for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) { - status = spi_dev_check_cs(dev, spi, idx, spi, idx + 1); - if (status) - return status; + if (!spi_controller_is_target(ctlr)) { + for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) { + status = spi_dev_check_cs(dev, spi, idx, spi, idx + 1); + if (status) + return status; + } } /* Set the bus ID string */ @@ -822,14 +830,10 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr, proxy->controller_data = chip->controller_data; proxy->controller_state = NULL; /* - * spi->chip_select[i] gives the corresponding physical CS for logical CS i - * logical CS number is represented by setting the ith bit in spi->cs_index_mask - * So, for example, if spi->cs_index_mask = 0x01 then logical CS number is 0 and - * spi->chip_select[0] will give the physical CS. - * By default spi->chip_select[0] will hold the physical CS number so, set - * spi->cs_index_mask as 0x01. + * 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 = 0x01; + proxy->cs_index_mask = BIT(0); if (chip->swnode) { status = device_add_software_node(&proxy->dev, chip->swnode); @@ -862,15 +866,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); @@ -982,9 +989,6 @@ 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); } @@ -1022,20 +1026,45 @@ 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_CS_CNT_MAX; 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; - for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) { - if (spi->cs_index_mask & BIT(idx)) { - if (spi->controller->last_cs[idx] == spi_get_chipselect(spi, idx)) - last = true; - } + 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) { @@ -1072,31 +1101,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) 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. - */ - for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) { - if ((spi->cs_index_mask & BIT(idx)) && spi_get_csgpiod(spi, idx)) { - if (has_acpi_companion(&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); - } + 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 */ @@ -1205,12 +1212,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, @@ -1242,6 +1247,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; @@ -1256,6 +1262,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) { @@ -1269,12 +1277,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; } @@ -1285,24 +1297,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; } @@ -1312,12 +1321,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); } @@ -1327,12 +1333,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 */ @@ -1439,7 +1442,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; @@ -1613,8 +1616,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; @@ -1630,8 +1633,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; @@ -2052,7 +2055,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); @@ -2131,7 +2134,8 @@ static void __spi_unoptimize_message(struct spi_message *msg) */ static void spi_maybe_unoptimize_message(struct spi_message *msg) { - if (!msg->pre_optimized && msg->optimized) + if (!msg->pre_optimized && msg->optimized && + !msg->spi->controller->defer_optimize_message) __spi_unoptimize_message(msg); } @@ -2210,11 +2214,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. @@ -2222,20 +2223,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); - } + } while (--limit); - if (!list_empty(&ctlr->queue) || ctlr->busy) - ret = -EBUSY; - else - ctlr->running = false; - - spin_unlock_irqrestore(&ctlr->queue_lock, flags); - - return ret; + return -EBUSY; } static int spi_destroy_queue(struct spi_controller *ctlr) @@ -2428,7 +2427,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); @@ -2457,7 +2456,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi, nc, rc); return rc; } - if ((of_property_read_bool(nc, "parallel-memories")) && + 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; @@ -2574,7 +2573,7 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi, { struct spi_controller *ctlr = spi->controller; struct spi_device *ancillary; - int rc = 0; + int rc; /* Alloc an spi_device */ ancillary = spi_alloc_device(ctlr); @@ -2720,7 +2719,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; @@ -2819,7 +2818,7 @@ 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) { + device_match_acpi_handle(lookup.ctlr->dev.parent, parent_handle)) { /* Apple does not use _CRS but nested devices for SPI slaves */ acpi_spi_parse_apple_properties(adev, &lookup); } @@ -2872,9 +2871,6 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias, sizeof(spi->modalias)); - if (spi->irq < 0) - spi->irq = acpi_dev_gpio_irq_get(adev, 0); - acpi_device_set_enumerated(adev); adev->power.flags.ignore_parent = true; @@ -2929,7 +2925,7 @@ static void spi_controller_release(struct device *dev) kfree(ctlr); } -static struct class spi_master_class = { +static const struct class spi_master_class = { .name = "spi_master", .dev_release = spi_controller_release, .dev_groups = spi_master_groups, @@ -2937,21 +2933,10 @@ static struct class spi_master_class = { #ifdef CONFIG_SPI_SLAVE /** - * spi_slave_abort - abort the ongoing transfer request on an SPI slave + * spi_target_abort - abort the ongoing transfer request on an SPI slave * 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; @@ -3030,7 +3015,7 @@ static const struct attribute_group *spi_slave_groups[] = { NULL, }; -static struct class spi_slave_class = { +static const struct class spi_slave_class = { .name = "spi_slave", .dev_release = spi_controller_release, .dev_groups = spi_slave_groups, @@ -3252,9 +3237,9 @@ static int spi_controller_id_alloc(struct spi_controller *ctlr, int start, int e } /** - * 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, @@ -3324,7 +3309,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; @@ -3352,7 +3337,7 @@ int spi_register_controller(struct spi_controller *ctlr) 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)); /* @@ -3404,11 +3389,11 @@ static void devm_spi_unregister(struct device *dev, void *res) } /** - * devm_spi_register_controller - register managed SPI master or slave + * 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 @@ -3492,7 +3477,7 @@ void spi_unregister_controller(struct spi_controller *ctlr) /* * Release the last reference on the controller if its driver - * has not yet been converted to devm_spi_alloc_master/slave(). + * has not yet been converted to devm_spi_alloc_host/target(). */ if (!ctlr->devm_allocated) put_device(&ctlr->dev); @@ -3709,9 +3694,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. */ /* @@ -3725,12 +3707,8 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr, /* 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); @@ -3912,7 +3890,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 @@ -3931,6 +3909,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. @@ -4145,7 +4129,8 @@ 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))) @@ -4160,7 +4145,8 @@ 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))) @@ -4279,6 +4265,11 @@ static int __spi_optimize_message(struct spi_device *spi, 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; @@ -4309,6 +4300,13 @@ 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; @@ -4335,6 +4333,9 @@ EXPORT_SYMBOL_GPL(spi_optimize_message); */ void spi_unoptimize_message(struct spi_message *msg) { + if (msg->spi->controller->defer_optimize_message) + return; + __spi_unoptimize_message(msg); msg->pre_optimized = false; } @@ -4367,6 +4368,34 @@ 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); +} + +/** + * 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 + * + * spi_unoptimize_message() will automatically be called when the device is + * removed. + */ +int devm_spi_optimize_message(struct device *dev, struct spi_device *spi, + struct spi_message *msg) +{ + int ret; + + ret = spi_optimize_message(spi, msg); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, devm_spi_unoptimize_message, msg); +} +EXPORT_SYMBOL_GPL(devm_spi_optimize_message); + /** * spi_async - asynchronous SPI transfer * @spi: device with which data will be exchanged @@ -4417,8 +4446,6 @@ int spi_async(struct spi_device *spi, struct spi_message *message) spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags); - spi_maybe_unoptimize_message(message); - return ret; } EXPORT_SYMBOL_GPL(spi_async); @@ -4523,6 +4550,7 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message) wait_for_completion(&done); status = message->status; } + message->complete = NULL; message->context = NULL; return status; @@ -4808,7 +4836,7 @@ 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); } struct spi_controller *acpi_spi_find_controller_by_adev(struct acpi_device *adev) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 95fb5f1c91c1..58ae4304fdab 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -666,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); @@ -685,7 +685,6 @@ static const struct file_operations spidev_fops = { .compat_ioctl = spidev_compat_ioctl, .open = spidev_open, .release = spidev_release, - .llseek = no_llseek, }; /*-------------------------------------------------------------------------*/ @@ -699,17 +698,24 @@ 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 = /* cisco */ "spi-petra" }, + { .name = /* dh */ "dhcom-board" }, + { .name = /* elgin */ "jg10309-01" }, + { .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); @@ -730,10 +736,13 @@ static int spidev_of_check(struct device *dev) static const struct of_device_id spidev_dt_ids[] = { { .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 = "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 }, |