summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-intel.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-12-13 23:54:31 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2022-12-13 23:54:31 +0300
commitd0f3ad23cf4f4046e88eef92c608d43cad9e4f7e (patch)
treef22a64cac48017fab350b4a954652f687a952a5d /drivers/spi/spi-intel.c
parentc5589c436d4646e0dc23f64264db8e04cf67c88f (diff)
parent3cf241c3d56ff19f5192cb42a025bc6582b6e8fa (diff)
downloadlinux-d0f3ad23cf4f4046e88eef92c608d43cad9e4f7e.tar.xz
Merge tag 'spi-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown: "A busy enough release, but not for the core which has only seen very small updates. The biggest addition is the readdition of support for detailed configuration of the timings around chip selects. That had been removed for lack of use but there's been applications found for it on Atmel systems. Otherwise the updates are mostly feature additions and cleanups to existing drivers. Summary: - Provide a helper for getting device match data in a way that abstracts away which firmware interface is being used. - Re-add the spi_set_cs_timing() API for detailed configuration of the timing around chip select and support it on Atmel. - Support for MediaTek MT7986, Microchip PCI1xxxx, Nuvoton WPCM450 FIU and Socionext F_OSPI" * tag 'spi-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (66 commits) spi: dt-bindings: Convert Synquacer SPI to DT schema spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode spi: spi-mtk-nor: Add recovery mechanism for dma read timeout spi: spi-fsl-lpspi: add num-cs binding for lpspi spi: spi-fsl-lpspi: support multiple cs for lpspi spi: mtk-snfi: Add snfi support for MT7986 IC spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE spi: cadence-quadspi: Add minimum operable clock rate warning to baudrate divisor calculation spi: microchip: pci1xxxx: Add suspend and resume support for PCI1XXXX SPI driver spi: dt-bindings: nuvoton,wpcm450-fiu: Fix warning in example (missing reg property) spi: dt-bindings: nuvoton,wpcm450-fiu: Fix error in example (bogus include) spi: mediatek: Enable irq when pdata is ready spi: spi-mtk-nor: Unify write buffer on/off spi: intel: Add support for SFDP opcode spi: intel: Take possible chip address into account in intel_spi_read/write_reg() spi: intel: Implement adjust_op_size() spi: intel: Use ->replacement_op in intel_spi_hw_cycle() spi: cadence: Drop obsolete dependency on COMPILE_TEST spi: Add Nuvoton WPCM450 Flash Interface Unit (FIU) bindings spi: wpcm-fiu: Add direct map support ...
Diffstat (limited to 'drivers/spi/spi-intel.c')
-rw-r--r--drivers/spi/spi-intel.c78
1 files changed, 40 insertions, 38 deletions
diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c
index 3ac73691fbb5..f619212b0d5c 100644
--- a/drivers/spi/spi-intel.c
+++ b/drivers/spi/spi-intel.c
@@ -33,6 +33,7 @@
#define HSFSTS_CTL_FCYCLE_WRITE (0x02 << HSFSTS_CTL_FCYCLE_SHIFT)
#define HSFSTS_CTL_FCYCLE_ERASE (0x03 << HSFSTS_CTL_FCYCLE_SHIFT)
#define HSFSTS_CTL_FCYCLE_ERASE_64K (0x04 << HSFSTS_CTL_FCYCLE_SHIFT)
+#define HSFSTS_CTL_FCYCLE_RDSFDP (0x05 << HSFSTS_CTL_FCYCLE_SHIFT)
#define HSFSTS_CTL_FCYCLE_RDID (0x06 << HSFSTS_CTL_FCYCLE_SHIFT)
#define HSFSTS_CTL_FCYCLE_WRSR (0x07 << HSFSTS_CTL_FCYCLE_SHIFT)
#define HSFSTS_CTL_FCYCLE_RDSR (0x08 << HSFSTS_CTL_FCYCLE_SHIFT)
@@ -352,34 +353,21 @@ static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode, int optype)
return 0;
}
-static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, size_t len)
+static int intel_spi_hw_cycle(struct intel_spi *ispi,
+ const struct intel_spi_mem_op *iop, size_t len)
{
u32 val, status;
int ret;
- val = readl(ispi->base + HSFSTS_CTL);
- val &= ~(HSFSTS_CTL_FCYCLE_MASK | HSFSTS_CTL_FDBC_MASK);
-
- switch (opcode) {
- case SPINOR_OP_RDID:
- val |= HSFSTS_CTL_FCYCLE_RDID;
- break;
- case SPINOR_OP_WRSR:
- val |= HSFSTS_CTL_FCYCLE_WRSR;
- break;
- case SPINOR_OP_RDSR:
- val |= HSFSTS_CTL_FCYCLE_RDSR;
- break;
- default:
- return -EINVAL;
- }
-
- if (len > INTEL_SPI_FIFO_SZ)
+ if (!iop->replacement_op)
return -EINVAL;
+ val = readl(ispi->base + HSFSTS_CTL);
+ val &= ~(HSFSTS_CTL_FCYCLE_MASK | HSFSTS_CTL_FDBC_MASK);
val |= (len - 1) << HSFSTS_CTL_FDBC_SHIFT;
val |= HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE;
val |= HSFSTS_CTL_FGO;
+ val |= iop->replacement_op;
writel(val, ispi->base + HSFSTS_CTL);
ret = intel_spi_wait_hw_busy(ispi);
@@ -406,9 +394,6 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len,
if (ret < 0)
return ret;
- if (len > INTEL_SPI_FIFO_SZ)
- return -EINVAL;
-
/*
* Always clear it after each SW sequencer operation regardless
* of whether it is successful or not.
@@ -473,17 +458,18 @@ static int intel_spi_read_reg(struct intel_spi *ispi, const struct spi_mem *mem,
const struct intel_spi_mem_op *iop,
const struct spi_mem_op *op)
{
+ u32 addr = intel_spi_chip_addr(ispi, mem) + op->addr.val;
size_t nbytes = op->data.nbytes;
u8 opcode = op->cmd.opcode;
int ret;
- writel(intel_spi_chip_addr(ispi, mem), ispi->base + FADDR);
+ writel(addr, ispi->base + FADDR);
if (ispi->swseq_reg)
ret = intel_spi_sw_cycle(ispi, opcode, nbytes,
OPTYPE_READ_NO_ADDR);
else
- ret = intel_spi_hw_cycle(ispi, opcode, nbytes);
+ ret = intel_spi_hw_cycle(ispi, iop, nbytes);
if (ret)
return ret;
@@ -495,6 +481,7 @@ static int intel_spi_write_reg(struct intel_spi *ispi, const struct spi_mem *mem
const struct intel_spi_mem_op *iop,
const struct spi_mem_op *op)
{
+ u32 addr = intel_spi_chip_addr(ispi, mem) + op->addr.val;
size_t nbytes = op->data.nbytes;
u8 opcode = op->cmd.opcode;
int ret;
@@ -538,7 +525,7 @@ static int intel_spi_write_reg(struct intel_spi *ispi, const struct spi_mem *mem
if (opcode == SPINOR_OP_WRDI)
return 0;
- writel(intel_spi_chip_addr(ispi, mem), ispi->base + FADDR);
+ writel(addr, ispi->base + FADDR);
/* Write the value beforehand */
ret = intel_spi_write_block(ispi, op->data.buf.out, nbytes);
@@ -548,7 +535,7 @@ static int intel_spi_write_reg(struct intel_spi *ispi, const struct spi_mem *mem
if (ispi->swseq_reg)
return intel_spi_sw_cycle(ispi, opcode, nbytes,
OPTYPE_WRITE_NO_ADDR);
- return intel_spi_hw_cycle(ispi, opcode, nbytes);
+ return intel_spi_hw_cycle(ispi, iop, nbytes);
}
static int intel_spi_read(struct intel_spi *ispi, const struct spi_mem *mem,
@@ -713,6 +700,12 @@ static int intel_spi_erase(struct intel_spi *ispi, const struct spi_mem *mem,
return 0;
}
+static int intel_spi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+ op->data.nbytes = clamp_val(op->data.nbytes, 0, INTEL_SPI_FIFO_SZ);
+ return 0;
+}
+
static bool intel_spi_cmp_mem_op(const struct intel_spi_mem_op *iop,
const struct spi_mem_op *op)
{
@@ -853,6 +846,7 @@ static ssize_t intel_spi_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs
}
static const struct spi_controller_mem_ops intel_spi_mem_ops = {
+ .adjust_op_size = intel_spi_adjust_op_size,
.supports_op = intel_spi_supports_mem_op,
.exec_op = intel_spi_exec_mem_op,
.get_name = intel_spi_get_name,
@@ -912,18 +906,26 @@ static const struct spi_controller_mem_ops intel_spi_mem_ops = {
*/
#define INTEL_SPI_GENERIC_OPS \
/* Status register operations */ \
- INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 1), \
- SPI_MEM_OP_NO_ADDR, \
- INTEL_SPI_OP_DATA_IN(1), \
- intel_spi_read_reg), \
- INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), \
- SPI_MEM_OP_NO_ADDR, \
- INTEL_SPI_OP_DATA_IN(1), \
- intel_spi_read_reg), \
- INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1), \
- SPI_MEM_OP_NO_ADDR, \
- INTEL_SPI_OP_DATA_OUT(1), \
- intel_spi_write_reg), \
+ INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 1), \
+ SPI_MEM_OP_NO_ADDR, \
+ INTEL_SPI_OP_DATA_IN(1), \
+ intel_spi_read_reg, \
+ HSFSTS_CTL_FCYCLE_RDID), \
+ INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1), \
+ SPI_MEM_OP_NO_ADDR, \
+ INTEL_SPI_OP_DATA_IN(1), \
+ intel_spi_read_reg, \
+ HSFSTS_CTL_FCYCLE_RDSR), \
+ INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_WRSR, 1), \
+ SPI_MEM_OP_NO_ADDR, \
+ INTEL_SPI_OP_DATA_OUT(1), \
+ intel_spi_write_reg, \
+ HSFSTS_CTL_FCYCLE_WRSR), \
+ INTEL_SPI_MEM_OP_REPL(SPI_MEM_OP_CMD(SPINOR_OP_RDSFDP, 1), \
+ INTEL_SPI_OP_ADDR(3), \
+ INTEL_SPI_OP_DATA_IN(1), \
+ intel_spi_read_reg, \
+ HSFSTS_CTL_FCYCLE_RDSFDP), \
/* Normal read */ \
INTEL_SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ, 1), \
INTEL_SPI_OP_ADDR(3), \