aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/spi/amlogic,meson-gx-spicc.yaml75
-rw-r--r--Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt2
-rw-r--r--Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml5
-rw-r--r--Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml4
-rw-r--r--Documentation/driver-api/spi.rst4
-rw-r--r--drivers/firmware/xilinx/zynqmp.c7
-rw-r--r--drivers/spi/Kconfig9
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/atmel-quadspi.c34
-rw-r--r--drivers/spi/spi-aspeed-smc.c10
-rw-r--r--drivers/spi/spi-bcm-qspi.c5
-rw-r--r--drivers/spi/spi-bcm-qspi.h2
-rw-r--r--drivers/spi/spi-bcm63xx.c3
-rw-r--r--drivers/spi/spi-brcmstb-qspi.c4
-rw-r--r--drivers/spi/spi-cadence-quadspi.c7
-rw-r--r--drivers/spi/spi-fsl-cpm.c2
-rw-r--r--drivers/spi/spi-fsl-dspi.c36
-rw-r--r--drivers/spi/spi-gxp.c2
-rw-r--r--drivers/spi/spi-hisi-sfc-v3xx.c2
-rw-r--r--drivers/spi/spi-img-spfi.c3
-rw-r--r--drivers/spi/spi-imx.c8
-rw-r--r--drivers/spi/spi-intel.c2
-rw-r--r--drivers/spi/spi-iproc-qspi.c4
-rw-r--r--drivers/spi/spi-meson-spicc.c39
-rw-r--r--drivers/spi/spi-microchip-core.c9
-rw-r--r--drivers/spi/spi-mpc52xx.c2
-rw-r--r--drivers/spi/spi-mtk-nor.c7
-rw-r--r--drivers/spi/spi-mxic.c3
-rw-r--r--drivers/spi/spi-npcm-fiu.c4
-rw-r--r--drivers/spi/spi-nxp-fspi.c2
-rw-r--r--drivers/spi/spi-pci1xxxx.c397
-rw-r--r--drivers/spi/spi-pxa2xx.c195
-rw-r--r--drivers/spi/spi-tegra210-quad.c5
-rw-r--r--drivers/spi/spi-zynqmp-gqspi.c191
-rw-r--r--drivers/spi/spi.c70
-rw-r--r--include/linux/firmware/xlnx-zynqmp.h19
-rw-r--r--include/linux/pxa2xx_ssp.h1
-rw-r--r--include/linux/spi/spi-mem.h2
-rw-r--r--include/linux/spi/spi.h54
39 files changed, 952 insertions, 279 deletions
diff --git a/Documentation/devicetree/bindings/spi/amlogic,meson-gx-spicc.yaml b/Documentation/devicetree/bindings/spi/amlogic,meson-gx-spicc.yaml
index 0c10f7678178..53eb6562b979 100644
--- a/Documentation/devicetree/bindings/spi/amlogic,meson-gx-spicc.yaml
+++ b/Documentation/devicetree/bindings/spi/amlogic,meson-gx-spicc.yaml
@@ -10,9 +10,6 @@ title: Amlogic Meson SPI Communication Controller
maintainers:
- Neil Armstrong <[email protected]>
-allOf:
- - $ref: "spi-controller.yaml#"
-
description: |
The Meson SPICC is a generic SPI controller for general purpose Full-Duplex
communications with dedicated 16 words RX/TX PIO FIFOs.
@@ -43,31 +40,53 @@ properties:
minItems: 1
maxItems: 2
-if:
- properties:
- compatible:
- contains:
- enum:
- - amlogic,meson-g12a-spicc
-
-then:
- properties:
- clocks:
- minItems: 2
-
- clock-names:
- items:
- - const: core
- - const: pclk
-
-else:
- properties:
- clocks:
- maxItems: 1
-
- clock-names:
- items:
- - const: core
+allOf:
+ - $ref: "spi-controller.yaml#"
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - amlogic,meson-g12a-spicc
+
+ then:
+ properties:
+ clocks:
+ minItems: 2
+
+ clock-names:
+ items:
+ - const: core
+ - const: pclk
+
+ else:
+ properties:
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ items:
+ - const: core
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - amlogic,meson-gx-spicc
+
+ then:
+ properties:
+ pinctrl-0: true
+ pinctrl-1: true
+ pinctrl-2: true
+
+ pinctrl-names:
+ minItems: 1
+ items:
+ - const: default
+ - const: idle-high
+ - const: idle-low
required:
- compatible
diff --git a/Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt b/Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt
index c63ce4cc0a80..fb38e96d395f 100644
--- a/Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt
+++ b/Documentation/devicetree/bindings/spi/nuvoton,npcm-fiu.txt
@@ -51,7 +51,7 @@ fiu3: spi@c00000000 {
clocks = <&clk NPCM7XX_CLK_AHB>;
pinctrl-names = "default";
pinctrl-0 = <&spi3_pins>;
- spi-nor@0 {
+ flash@0 {
...
};
};
diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
index dca677f9e1b9..ead2cccf658f 100644
--- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
@@ -44,6 +44,11 @@ properties:
description:
Maximum SPI clocking speed of the device in Hz.
+ spi-cs-setup-ns:
+ description:
+ Delay in nanosecods to be introduced by the controller after CS is
+ asserted.
+
spi-rx-bus-width:
description:
Bus width to the SPI bus used for read transfers.
diff --git a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml
index 6bf0edc57f4a..546c416cdb55 100644
--- a/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml
@@ -14,7 +14,9 @@ allOf:
properties:
compatible:
- const: xlnx,zynqmp-qspi-1.0
+ enum:
+ - xlnx,versal-qspi-1.0
+ - xlnx,zynqmp-qspi-1.0
reg:
maxItems: 2
diff --git a/Documentation/driver-api/spi.rst b/Documentation/driver-api/spi.rst
index f64cb666498a..f28887045049 100644
--- a/Documentation/driver-api/spi.rst
+++ b/Documentation/driver-api/spi.rst
@@ -25,8 +25,8 @@ hardware, which may be as simple as a set of GPIO pins or as complex as
a pair of FIFOs connected to dual DMA engines on the other side of the
SPI shift register (maximizing throughput). Such drivers bridge between
whatever bus they sit on (often the platform bus) and SPI, and expose
-the SPI side of their device as a :c:type:`struct spi_master
-<spi_master>`. SPI devices are children of that master,
+the SPI side of their device as a :c:type:`struct spi_controller
+<spi_controller>`. SPI devices are children of that master,
represented as a :c:type:`struct spi_device <spi_device>` and
manufactured from :c:type:`struct spi_board_info
<spi_board_info>` descriptors which are usually provided by
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index ff5cabe70a2b..6bc6b6c84241 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -843,6 +843,13 @@ int zynqmp_pm_read_pggs(u32 index, u32 *value)
}
EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs);
+int zynqmp_pm_set_tapdelay_bypass(u32 index, u32 value)
+{
+ return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_TAPDELAY_BYPASS,
+ index, value, NULL);
+}
+EXPORT_SYMBOL_GPL(zynqmp_pm_set_tapdelay_bypass);
+
/**
* zynqmp_pm_set_boot_health_status() - PM API for setting healthy boot status
* @value: Status value to be written
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index d1bb62f7368b..cb7e3a8ef3a5 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -710,6 +710,15 @@ config SPI_ORION
This enables using the SPI master controller on the Orion
and MVEBU chips.
+config SPI_PCI1XXXX
+ tristate "PCI1XXXX SPI Bus support"
+ depends on PCI
+ help
+ Say "yes" to Enable the SPI Bus support for the PCI1xxxx card
+ This is a PCI to SPI Bus driver
+ This driver can be built as module. If so, the module will be
+ called as spi-pci1xxxx.
+
config SPI_PIC32
tristate "Microchip PIC32 series SPI"
depends on MACH_PIC32 || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 4b34e855c841..60d0b2f611f1 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o
obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o
obj-$(CONFIG_SPI_TI_QSPI) += spi-ti-qspi.o
obj-$(CONFIG_SPI_ORION) += spi-orion.o
+obj-$(CONFIG_SPI_PCI1XXXX) += spi-pci1xxxx.o
obj-$(CONFIG_SPI_PIC32) += spi-pic32.o
obj-$(CONFIG_SPI_PIC32_SQI) += spi-pic32-sqi.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o
diff --git a/drivers/spi/atmel-quadspi.c b/drivers/spi/atmel-quadspi.c
index 976a217e356d..70637e46290a 100644
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -510,6 +510,39 @@ static int atmel_qspi_setup(struct spi_device *spi)
return 0;
}
+static int atmel_qspi_set_cs_timing(struct spi_device *spi)
+{
+ struct spi_controller *ctrl = spi->master;
+ struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
+ unsigned long clk_rate;
+ u32 cs_setup;
+ 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;
+
+ cs_setup = 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(cs_setup);
+ atmel_qspi_write(aq->scr, aq, QSPI_SCR);
+
+ pm_runtime_mark_last_busy(ctrl->dev.parent);
+ pm_runtime_put_autosuspend(ctrl->dev.parent);
+
+ return 0;
+}
+
static void atmel_qspi_init(struct atmel_qspi *aq)
{
/* Reset the QSPI controller */
@@ -555,6 +588,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD;
ctrl->setup = atmel_qspi_setup;
+ ctrl->set_cs_timing = atmel_qspi_set_cs_timing;
ctrl->bus_num = -1;
ctrl->mem_ops = &atmel_qspi_mem_ops;
ctrl->num_chipselect = 1;
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index a334e89add86..710ff8cf121f 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -734,13 +734,11 @@ static int aspeed_spi_probe(struct platform_device *pdev)
aspi->data = data;
aspi->dev = dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- aspi->regs = devm_ioremap_resource(dev, res);
+ aspi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(aspi->regs))
return PTR_ERR(aspi->regs);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- aspi->ahb_base = devm_ioremap_resource(dev, res);
+ aspi->ahb_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
if (IS_ERR(aspi->ahb_base)) {
dev_err(dev, "missing AHB mapping window\n");
return PTR_ERR(aspi->ahb_base);
@@ -1163,7 +1161,7 @@ static const struct aspeed_spi_data ast2500_spi_data = {
static const struct aspeed_spi_data ast2600_fmc_data = {
.max_cs = 3,
.hastype = false,
- .mode_bits = SPI_RX_QUAD | SPI_RX_QUAD,
+ .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD,
.we0 = 16,
.ctl0 = CE0_CTRL_REG,
.timing = CE0_TIMING_COMPENSATION_REG,
@@ -1178,7 +1176,7 @@ static const struct aspeed_spi_data ast2600_fmc_data = {
static const struct aspeed_spi_data ast2600_spi_data = {
.max_cs = 2,
.hastype = false,
- .mode_bits = SPI_RX_QUAD | SPI_RX_QUAD,
+ .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD,
.we0 = 16,
.ctl0 = CE0_CTRL_REG,
.timing = CE0_TIMING_COMPENSATION_REG,
diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
index cad2d55dcd3d..0eee574d3e1f 100644
--- a/drivers/spi/spi-bcm-qspi.c
+++ b/drivers/spi/spi-bcm-qspi.c
@@ -1682,7 +1682,7 @@ qspi_probe_err:
/* probe function to be called by SoC specific platform driver probe */
EXPORT_SYMBOL_GPL(bcm_qspi_probe);
-int bcm_qspi_remove(struct platform_device *pdev)
+void bcm_qspi_remove(struct platform_device *pdev)
{
struct bcm_qspi *qspi = platform_get_drvdata(pdev);
@@ -1690,9 +1690,8 @@ int bcm_qspi_remove(struct platform_device *pdev)
bcm_qspi_hw_uninit(qspi);
clk_disable_unprepare(qspi->clk);
kfree(qspi->dev_ids);
-
- return 0;
}
+
/* function to be called by SoC specific platform driver remove() */
EXPORT_SYMBOL_GPL(bcm_qspi_remove);
diff --git a/drivers/spi/spi-bcm-qspi.h b/drivers/spi/spi-bcm-qspi.h
index 01aec6460108..3d7c359c0239 100644
--- a/drivers/spi/spi-bcm-qspi.h
+++ b/drivers/spi/spi-bcm-qspi.h
@@ -96,7 +96,7 @@ static inline u32 get_qspi_mask(int type)
/* The common driver functions to be called by the SoC platform driver */
int bcm_qspi_probe(struct platform_device *pdev,
struct bcm_qspi_soc_intc *soc_intc);
-int bcm_qspi_remove(struct platform_device *pdev);
+void bcm_qspi_remove(struct platform_device *pdev);
/* pm_ops used by the SoC platform driver called on PM suspend/resume */
extern const struct dev_pm_ops bcm_qspi_pm_ops;
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 80fa0ef8909c..3686d78c44a6 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -547,8 +547,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
bs->pdev = pdev;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- bs->regs = devm_ioremap_resource(&pdev->dev, r);
+ bs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
if (IS_ERR(bs->regs)) {
ret = PTR_ERR(bs->regs);
goto out_err;
diff --git a/drivers/spi/spi-brcmstb-qspi.c b/drivers/spi/spi-brcmstb-qspi.c
index 75e9b76dab1e..de362b35718f 100644
--- a/drivers/spi/spi-brcmstb-qspi.c
+++ b/drivers/spi/spi-brcmstb-qspi.c
@@ -23,7 +23,9 @@ static int brcmstb_qspi_probe(struct platform_device *pdev)
static int brcmstb_qspi_remove(struct platform_device *pdev)
{
- return bcm_qspi_remove(pdev);
+ bcm_qspi_remove(pdev);
+
+ return 0;
}
static struct platform_driver brcmstb_qspi_driver = {
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index 447230547945..4219113cf36b 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -1580,7 +1580,6 @@ static int cqspi_probe(struct platform_device *pdev)
struct spi_master *master;
struct resource *res_ahb;
struct cqspi_st *cqspi;
- struct resource *res;
int ret;
int irq;
@@ -1616,8 +1615,7 @@ static int cqspi_probe(struct platform_device *pdev)
}
/* Obtain and remap controller address. */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- cqspi->iobase = devm_ioremap_resource(dev, res);
+ cqspi->iobase = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(cqspi->iobase)) {
dev_err(dev, "Cannot remap controller address.\n");
ret = PTR_ERR(cqspi->iobase);
@@ -1625,8 +1623,7 @@ static int cqspi_probe(struct platform_device *pdev)
}
/* Obtain and remap AHB address. */
- res_ahb = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- cqspi->ahb_base = devm_ioremap_resource(dev, res_ahb);
+ cqspi->ahb_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res_ahb);
if (IS_ERR(cqspi->ahb_base)) {
dev_err(dev, "Cannot remap AHB address.\n");
ret = PTR_ERR(cqspi->ahb_base);
diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c
index ee905880769e..17a44d4f5021 100644
--- a/drivers/spi/spi-fsl-cpm.c
+++ b/drivers/spi/spi-fsl-cpm.c
@@ -333,7 +333,7 @@ int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
goto err_bds;
}
- mspi->dma_dummy_tx = dma_map_single(dev, empty_zero_page, PAGE_SIZE,
+ mspi->dma_dummy_tx = dma_map_single(dev, ZERO_PAGE(0), PAGE_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, mspi->dma_dummy_tx)) {
dev_err(dev, "unable to map dummy tx buffer\n");
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index a33e547b7d39..e419642eb10e 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -900,12 +900,31 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void dspi_assert_cs(struct spi_device *spi, bool *cs)
+{
+ if (!spi->cs_gpiod || *cs)
+ return;
+
+ gpiod_set_value_cansleep(spi->cs_gpiod, true);
+ *cs = true;
+}
+
+static void dspi_deassert_cs(struct spi_device *spi, bool *cs)
+{
+ if (!spi->cs_gpiod || !*cs)
+ return;
+
+ gpiod_set_value_cansleep(spi->cs_gpiod, false);
+ *cs = false;
+}
+
static int dspi_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *message)
{
struct fsl_dspi *dspi = spi_controller_get_devdata(ctlr);
struct spi_device *spi = message->spi;
struct spi_transfer *transfer;
+ bool cs = false;
int status = 0;
message->actual_length = 0;
@@ -914,9 +933,14 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
dspi->cur_transfer = transfer;
dspi->cur_msg = message;
dspi->cur_chip = spi_get_ctldata(spi);
+
+ dspi_assert_cs(spi, &cs);
+
/* Prepare command word for CMD FIFO */
- dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0) |
- SPI_PUSHR_CMD_PCS(spi->chip_select);
+ dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0);
+ if (!spi->cs_gpiod)
+ dspi->tx_cmd |= SPI_PUSHR_CMD_PCS(spi->chip_select);
+
if (list_is_last(&dspi->cur_transfer->transfer_list,
&dspi->cur_msg->transfers)) {
/* Leave PCS activated after last transfer when
@@ -964,6 +988,9 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
break;
spi_transfer_delay_exec(transfer);
+
+ if (!(dspi->tx_cmd & SPI_PUSHR_CMD_CONT))
+ dspi_deassert_cs(spi, &cs);
}
message->status = status;
@@ -981,6 +1008,7 @@ static int dspi_setup(struct spi_device *spi)
unsigned char pasc = 0, asc = 0;
struct chip_data *chip;
unsigned long clkrate;
+ bool cs = true;
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
@@ -1030,6 +1058,9 @@ static int dspi_setup(struct spi_device *spi)
chip->ctar_val |= SPI_CTAR_LSBFE;
}
+ gpiod_direction_output(spi->cs_gpiod, false);
+ dspi_deassert_cs(spi, &cs);
+
spi_set_ctldata(spi, chip);
return 0;
@@ -1248,6 +1279,7 @@ static int dspi_probe(struct platform_device *pdev)
ctlr->cleanup = dspi_cleanup;
ctlr->slave_abort = dspi_slave_abort;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
+ ctlr->use_gpio_descriptors = true;
pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
diff --git a/drivers/spi/spi-gxp.c b/drivers/spi/spi-gxp.c
index 15b110183839..c900c2f39b57 100644
--- a/drivers/spi/spi-gxp.c
+++ b/drivers/spi/spi-gxp.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0=or-later
+// SPDX-License-Identifier: GPL-2.0-or-later
/* Copyright (C) 2022 Hewlett-Packard Development Company, L.P. */
#include <linux/iopoll.h>
diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c
index d3a23b1c2a4c..f07d1045a30a 100644
--- a/drivers/spi/spi-hisi-sfc-v3xx.c
+++ b/drivers/spi/spi-hisi-sfc-v3xx.c
@@ -165,7 +165,7 @@ static int hisi_sfc_v3xx_adjust_op_size(struct spi_mem *mem,
}
/*
- * The controller only supports Standard SPI mode, Duall mode and
+ * The controller only supports Standard SPI mode, Dual mode and
* Quad mode. Double sanitize the ops here to avoid OOB access.
*/
static bool hisi_sfc_v3xx_supports_op(struct spi_mem *mem,
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index bfd12247f173..257046f843ff 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -540,8 +540,7 @@ static int img_spfi_probe(struct platform_device *pdev)
spfi->master = master;
spin_lock_init(&spfi->lock);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- spfi->regs = devm_ioremap_resource(spfi->dev, res);
+ spfi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(spfi->regs)) {
ret = PTR_ERR(spfi->regs);
goto put_spi;
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 30d82cc7300b..a4bda03d3a8e 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -77,7 +77,6 @@ struct spi_imx_devtype_data {
void (*reset)(struct spi_imx_data *spi_imx);
void (*setup_wml)(struct spi_imx_data *spi_imx);
void (*disable)(struct spi_imx_data *spi_imx);
- void (*disable_dma)(struct spi_imx_data *spi_imx);
bool has_dmamode;
bool has_slavemode;
unsigned int fifo_size;
@@ -497,11 +496,6 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
}
-static void mx51_disable_dma(struct spi_imx_data *spi_imx)
-{
- writel(0, spi_imx->base + MX51_ECSPI_DMA);
-}
-
static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
{
u32 ctrl;
@@ -1043,7 +1037,6 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.rx_available = mx51_ecspi_rx_available,
.reset = mx51_ecspi_reset,
.setup_wml = mx51_setup_wml,
- .disable_dma = mx51_disable_dma,
.fifo_size = 64,
.has_dmamode = true,
.dynamic_burst = true,
@@ -1058,7 +1051,6 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
.prepare_transfer = mx51_ecspi_prepare_transfer,
.trigger = mx51_ecspi_trigger,
.rx_available = mx51_ecspi_rx_available,
- .disable_dma = mx51_disable_dma,
.reset = mx51_ecspi_reset,
.fifo_size = 64,
.has_dmamode = true,
diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c
index 55f4ee2db002..605acb1bf4b0 100644
--- a/drivers/spi/spi-intel.c
+++ b/drivers/spi/spi-intel.c
@@ -114,7 +114,7 @@
#define ERASE_OPCODE_SHIFT 8
#define ERASE_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT)
#define ERASE_64K_OPCODE_SHIFT 16
-#define ERASE_64K_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT)
+#define ERASE_64K_OPCODE_MASK (0xff << ERASE_64K_OPCODE_SHIFT)
/* Flash descriptor fields */
#define FLVALSIG_MAGIC 0x0ff0a55a
diff --git a/drivers/spi/spi-iproc-qspi.c b/drivers/spi/spi-iproc-qspi.c
index de297dacfd57..91cf8eb7213c 100644
--- a/drivers/spi/spi-iproc-qspi.c
+++ b/drivers/spi/spi-iproc-qspi.c
@@ -129,7 +129,9 @@ static int bcm_iproc_probe(struct platform_device *pdev)
static int bcm_iproc_remove(struct platform_device *pdev)
{
- return bcm_qspi_remove(pdev);
+ bcm_qspi_remove(pdev);
+
+ return 0;
}
static const struct of_device_id bcm_iproc_of_match[] = {
diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c
index bad201510a99..ffea38e2339c 100644
--- a/drivers/spi/spi-meson-spicc.c
+++ b/drivers/spi/spi-meson-spicc.c
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/reset.h>
+#include <linux/pinctrl/consumer.h>
/*
* The Meson SPICC controller could support DMA based transfers, but is not
@@ -167,6 +168,9 @@ struct meson_spicc_device {
unsigned long tx_remain;
unsigned long rx_remain;
unsigned long xfer_remain;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_idle_high;
+ struct pinctrl_state *pins_idle_low;
};
#define pow2_clk_to_spicc(_div) container_of(_div, struct meson_spicc_device, pow2_div)
@@ -175,8 +179,22 @@ static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
{
u32 conf;
- if (!spicc->data->has_oen)
+ if (!spicc->data->has_oen) {
+ /* Try to get pinctrl states for idle high/low */
+ spicc->pins_idle_high = pinctrl_lookup_state(spicc->pinctrl,
+ "idle-high");
+ if (IS_ERR(spicc->pins_idle_high)) {
+ dev_warn(&spicc->pdev->dev, "can't get idle-high pinctrl\n");
+ spicc->pins_idle_high = NULL;
+ }
+ spicc->pins_idle_low = pinctrl_lookup_state(spicc->pinctrl,
+ "idle-low");
+ if (IS_ERR(spicc->pins_idle_low)) {
+ dev_warn(&spicc->pdev->dev, "can't get idle-low pinctrl\n");
+ spicc->pins_idle_low = NULL;
+ }
return;
+ }
conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0) |
SPICC_ENH_MOSI_OEN | SPICC_ENH_CLK_OEN | SPICC_ENH_CS_OEN;
@@ -441,6 +459,16 @@ static int meson_spicc_prepare_message(struct spi_master *master,
else
conf &= ~SPICC_POL;
+ if (!spicc->data->has_oen) {
+ if (spi->mode & SPI_CPOL) {
+ if (spicc->pins_idle_high)
+ pinctrl_select_state(spicc->pinctrl, spicc->pins_idle_high);
+ } else {
+ if (spicc->pins_idle_low)
+ pinctrl_select_state(spicc->pinctrl, spicc->pins_idle_low);
+ }
+ }
+
if (spi->mode & SPI_CPHA)
conf |= SPICC_PHA;
else
@@ -487,6 +515,9 @@ static int meson_spicc_unprepare_transfer(struct spi_master *master)
/* Set default configuration, keeping datarate field */
writel_relaxed(conf, spicc->base + SPICC_CONREG);
+ if (!spicc->data->has_oen)
+ pinctrl_select_default_state(&spicc->pdev->dev);
+
return 0;
}
@@ -798,6 +829,12 @@ static int meson_spicc_probe(struct platform_device *pdev)
goto out_core_clk;
}
+ spicc->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(spicc->pinctrl)) {
+ ret = PTR_ERR(spicc->pinctrl);
+ goto out_clk;
+ }
+
device_reset_optional(&pdev->dev);
master->num_chipselect = 4;
diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c
index d352844c798c..aeaa1da88f39 100644
--- a/drivers/spi/spi-microchip-core.c
+++ b/drivers/spi/spi-microchip-core.c
@@ -119,15 +119,6 @@ static inline void mchp_corespi_write(struct mchp_corespi *spi, unsigned int reg
writel(val, spi->regs + reg);
}
-static inline void mchp_corespi_enable(struct mchp_corespi *spi)
-{
- u32 control = mchp_corespi_read(spi, REG_CONTROL);
-
- control |= CONTROL_ENABLE;
-
- mchp_corespi_write(spi, REG_CONTROL, control);
-}
-
static inline void mchp_corespi_disable(struct mchp_corespi *spi)
{
u32 control = mchp_corespi_read(spi, REG_CONTROL);
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index cb075c1acbee..7b64e64c65cf 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -151,7 +151,7 @@ mpc52xx_spi_fsmstate_idle(int irq, struct mpc52xx_spi *ms, u8 status, u8 data)
int spr, sppr;
u8 ctrl1;
- if (status && (irq != NO_IRQ))
+ if (status && irq)
dev_err(&ms->master->dev, "spurious irq, status=0x%.2x\n",
status);
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
index d167699a1a96..58eca18b28b0 100644
--- a/drivers/spi/spi-mtk-nor.c
+++ b/drivers/spi/spi-mtk-nor.c
@@ -354,7 +354,7 @@ static int mtk_nor_dma_exec(struct mtk_nor *sp, u32 from, unsigned int length,
dma_addr_t dma_addr)
{
int ret = 0;
- ulong delay;
+ u32 delay, timeout;
u32 reg;
writel(from, sp->base + MTK_NOR_REG_DMA_FADR);
@@ -376,15 +376,16 @@ static int mtk_nor_dma_exec(struct mtk_nor *sp, u32 from, unsigned int length,
mtk_nor_rmw(sp, MTK_NOR_REG_DMA_CTL, MTK_NOR_DMA_START, 0);
delay = CLK_TO_US(sp, (length + 5) * BITS_PER_BYTE);
+ timeout = (delay + 1) * 100;
if (sp->has_irq) {
if (!wait_for_completion_timeout(&sp->op_done,
- (delay + 1) * 100))
+ usecs_to_jiffies(max(timeout, 10000U))))
ret = -ETIMEDOUT;
} else {
ret = readl_poll_timeout(sp->base + MTK_NOR_REG_DMA_CTL, reg,
!(reg & MTK_NOR_DMA_START), delay / 3,
- (delay + 1) * 100);
+ timeout);
}
if (ret < 0)
diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c
index 65be8e085ab8..a3dba17390eb 100644
--- a/drivers/spi/spi-mxic.c
+++ b/drivers/spi/spi-mxic.c
@@ -772,8 +772,7 @@ static int mxic_spi_probe(struct platform_device *pdev)
if (IS_ERR(mxic->send_dly_clk))
return PTR_ERR(mxic->send_dly_clk);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
- mxic->regs = devm_ioremap_resource(&pdev->dev, res);
+ mxic->regs = devm_platform_ioremap_resource_byname(pdev, "regs");
if (IS_ERR(mxic->regs))
return PTR_ERR(mxic->regs);
diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c
index 49f6424e35af..559d3a5b4062 100644
--- a/drivers/spi/spi-npcm-fiu.c
+++ b/drivers/spi/spi-npcm-fiu.c
@@ -699,7 +699,6 @@ static int npcm_fiu_probe(struct platform_device *pdev)
struct spi_controller *ctrl;
struct npcm_fiu_spi *fiu;
void __iomem *regbase;
- struct resource *res;
int id, ret;
ctrl = devm_spi_alloc_master(dev, sizeof(*fiu));
@@ -725,8 +724,7 @@ static int npcm_fiu_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fiu);
fiu->dev = dev;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
- regbase = devm_ioremap_resource(dev, res);
+ regbase = devm_platform_ioremap_resource_byname(pdev, "control");
if (IS_ERR(regbase))
return PTR_ERR(regbase);
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index d6a65a989ef8..1c1991a26c15 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -924,7 +924,7 @@ static int nxp_fspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
static void erratum_err050568(struct nxp_fspi *f)
{
- const struct soc_device_attribute ls1028a_soc_attr[] = {
+ static const struct soc_device_attribute ls1028a_soc_attr[] = {
{ .family = "QorIQ LS1028A" },
{ /* sentinel */ }
};
diff --git a/drivers/spi/spi-pci1xxxx.c b/drivers/spi/spi-pci1xxxx.c
new file mode 100644
index 000000000000..958503a4d911
--- /dev/null
+++ b/drivers/spi/spi-pci1xxxx.c
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0
+// PCI1xxxx SPI driver
+// Copyright (C) 2022 Microchip Technology Inc.
+// Authors: Tharun Kumar P <[email protected]>
+// Kumaravel Thiagarajan <[email protected]>
+
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#define DRV_NAME "spi-pci1xxxx"
+
+#define SYS_FREQ_DEFAULT (62500000)
+
+#define PCI1XXXX_SPI_MAX_CLOCK_HZ (30000000)
+#define PCI1XXXX_SPI_CLK_20MHZ (20000000)
+#define PCI1XXXX_SPI_CLK_15MHZ (15000000)
+#define PCI1XXXX_SPI_CLK_12MHZ (12000000)
+#define PCI1XXXX_SPI_CLK_10MHZ (10000000)
+#define PCI1XXXX_SPI_MIN_CLOCK_HZ (2000000)
+
+#define PCI1XXXX_SPI_BUFFER_SIZE (320)
+
+#define SPI_MST_CTL_DEVSEL_MASK (GENMASK(27, 25))
+#define SPI_MST_CTL_CMD_LEN_MASK (GENMASK(16, 8))
+#define SPI_MST_CTL_SPEED_MASK (GENMASK(7, 5))
+#define SPI_MSI_VECTOR_SEL_MASK (GENMASK(4, 4))
+
+#define SPI_MST_CTL_FORCE_CE (BIT(4))
+#define SPI_MST_CTL_MODE_SEL (BIT(2))
+#define SPI_MST_CTL_GO (BIT(0))
+
+#define SPI_MST1_ADDR_BASE (0x800)
+
+/* x refers to SPI Host Controller HW instance id in the below macros - 0 or 1 */
+
+#define SPI_MST_CMD_BUF_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x00)
+#define SPI_MST_RSP_BUF_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x200)
+#define SPI_MST_CTL_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x400)
+#define SPI_MST_EVENT_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x420)
+#define SPI_MST_EVENT_MASK_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x424)
+#define SPI_MST_PAD_CTL_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x460)
+#define SPIALERT_MST_DB_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x464)
+#define SPIALERT_MST_VAL_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x468)
+#define SPI_PCI_CTRL_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x480)
+
+#define PCI1XXXX_IRQ_FLAGS (IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE)
+#define SPI_MAX_DATA_LEN 320
+
+#define PCI1XXXX_SPI_TIMEOUT (msecs_to_jiffies(100))
+
+#define SPI_INTR BIT(8)
+#define SPI_FORCE_CE BIT(4)
+
+#define SPI_CHIP_SEL_COUNT 7
+#define VENDOR_ID_MCHP 0x1055
+
+struct pci1xxxx_spi_internal {
+ u8 hw_inst;
+ bool spi_xfer_in_progress;
+ int irq;
+ struct completion spi_xfer_done;
+ struct spi_master *spi_host;
+ struct pci1xxxx_spi *parent;
+ struct {
+ unsigned int dev_sel : 3;
+ unsigned int msi_vector_sel : 1;
+ } prev_val;
+};
+
+struct pci1xxxx_spi {
+ struct pci_dev *dev;
+ u8 total_hw_instances;
+ void __iomem *reg_base;
+ struct pci1xxxx_spi_internal *spi_int[];
+};
+
+static const struct pci_device_id pci1xxxx_spi_pci_id_table[] = {
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0001), 0, 0, 0x02},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0002), 0, 0, 0x01},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0003), 0, 0, 0x11},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0001), 0, 0, 0x02},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0002), 0, 0, 0x01},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0003), 0, 0, 0x11},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0001), 0, 0, 0x02},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0002), 0, 0, 0x01},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0003), 0, 0, 0x11},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0001), 0, 0, 0x02},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0002), 0, 0, 0x01},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0003), 0, 0, 0x11},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0001), 0, 0, 0x02},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0002), 0, 0, 0x01},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0003), 0, 0, 0x11},
+ { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01},
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, pci1xxxx_spi_pci_id_table);
+
+static void pci1xxxx_spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi->controller);
+ struct pci1xxxx_spi *par = p->parent;
+ u32 regval;
+
+ /* Set the DEV_SEL bits of the SPI_MST_CTL_REG */
+ regval = readl(par->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+ if (enable) {
+ regval &= ~SPI_MST_CTL_DEVSEL_MASK;
+ regval |= (spi->chip_select << 25);
+ writel(regval,
+ par->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+ } else {
+ regval &= ~(spi->chip_select << 25);
+ writel(regval,
+ par->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+
+ }
+}
+
+static u8 pci1xxxx_get_clock_div(u32 hz)
+{
+ u8 val = 0;
+
+ if (hz >= PCI1XXXX_SPI_MAX_CLOCK_HZ)
+ val = 2;
+ else if ((hz < PCI1XXXX_SPI_MAX_CLOCK_HZ) && (hz >= PCI1XXXX_SPI_CLK_20MHZ))
+ val = 3;
+ else if ((hz < PCI1XXXX_SPI_CLK_20MHZ) && (hz >= PCI1XXXX_SPI_CLK_15MHZ))
+ val = 4;
+ else if ((hz < PCI1XXXX_SPI_CLK_15MHZ) && (hz >= PCI1XXXX_SPI_CLK_12MHZ))
+ val = 5;
+ else if ((hz < PCI1XXXX_SPI_CLK_12MHZ) && (hz >= PCI1XXXX_SPI_CLK_10MHZ))
+ val = 6;
+ else if ((hz < PCI1XXXX_SPI_CLK_10MHZ) && (hz >= PCI1XXXX_SPI_MIN_CLOCK_HZ))
+ val = 7;
+ else
+ val = 2;
+
+ return val;
+}
+
+static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr,
+ struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi_ctlr);
+ int mode, len, loop_iter, transfer_len;
+ struct pci1xxxx_spi *par = p->parent;
+ unsigned long bytes_transfered;
+ unsigned long bytes_recvd;
+ unsigned long loop_count;
+ u8 *rx_buf, result;
+ const u8 *tx_buf;
+ u32 regval;
+ u8 clkdiv;
+
+ p->spi_xfer_in_progress = true;
+ mode = spi->mode;
+ clkdiv = pci1xxxx_get_clock_div(xfer->speed_hz);
+ tx_buf = xfer->tx_buf;
+ rx_buf = xfer->rx_buf;
+ transfer_len = xfer->len;
+ regval = readl(par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+ writel(regval, par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+
+ if (tx_buf) {
+ bytes_transfered = 0;
+ bytes_recvd = 0;
+ loop_count = transfer_len / SPI_MAX_DATA_LEN;
+ if (transfer_len % SPI_MAX_DATA_LEN != 0)
+ loop_count += 1;
+
+ for (loop_iter = 0; loop_iter < loop_count; loop_iter++) {
+ len = SPI_MAX_DATA_LEN;
+ if ((transfer_len % SPI_MAX_DATA_LEN != 0) &&
+ (loop_iter == loop_count - 1))
+ len = transfer_len % SPI_MAX_DATA_LEN;
+
+ reinit_completion(&p->spi_xfer_done);
+ memcpy_toio(par->reg_base + SPI_MST_CMD_BUF_OFFSET(p->hw_inst),
+ &tx_buf[bytes_transfered], len);
+ bytes_transfered += len;
+ regval = readl(par->reg_base +
+ SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+ regval &= ~(SPI_MST_CTL_MODE_SEL | SPI_MST_CTL_CMD_LEN_MASK |
+ SPI_MST_CTL_SPEED_MASK);
+
+ if (mode == SPI_MODE_3)
+ regval |= SPI_MST_CTL_MODE_SEL;
+ else
+ regval &= ~SPI_MST_CTL_MODE_SEL;
+
+ regval |= ((clkdiv << 5) | SPI_FORCE_CE | (len << 8));
+ regval &= ~SPI_MST_CTL_CMD_LEN_MASK;
+ writel(regval, par->reg_base +
+ SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+ regval = readl(par->reg_base +
+ SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+ regval |= SPI_MST_CTL_GO;
+ writel(regval, par->reg_base +
+ SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+
+ /* Wait for DMA_TERM interrupt */
+ result = wait_for_completion_timeout(&p->spi_xfer_done,
+ PCI1XXXX_SPI_TIMEOUT);
+ if (!result)
+ return -ETIMEDOUT;
+
+ if (rx_buf) {
+ memcpy_fromio(&rx_buf[bytes_recvd], par->reg_base +
+ SPI_MST_RSP_BUF_OFFSET(p->hw_inst), len);
+ bytes_recvd += len;
+ }
+ }
+ }
+
+ regval = readl(par->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+ regval &= ~SPI_FORCE_CE;
+ writel(regval, par->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
+ p->spi_xfer_in_progress = false;
+
+ return 0;
+}
+
+static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev)
+{
+ struct pci1xxxx_spi_internal *p = dev;
+ irqreturn_t spi_int_fired = IRQ_NONE;
+ u32 regval;
+
+ /* Clear the SPI GO_BIT Interrupt */
+ regval = readl(p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+ if (regval & SPI_INTR) {
+ /* Clear xfer_done */
+ complete(&p->spi_xfer_done);
+ spi_int_fired = IRQ_HANDLED;
+ }
+
+ writel(regval, p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
+
+ return spi_int_fired;
+}
+
+static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ u8 hw_inst_cnt, iter, start, only_sec_inst;
+ struct pci1xxxx_spi_internal *spi_sub_ptr;
+ struct device *dev = &pdev->dev;
+ struct pci1xxxx_spi *spi_bus;
+ struct spi_master *spi_host;
+ u32 regval;
+ int ret;
+
+ hw_inst_cnt = ent->driver_data & 0x0f;
+ start = (ent->driver_data & 0xf0) >> 4;
+ if (start == 1)
+ only_sec_inst = 1;
+ else
+ only_sec_inst = 0;
+
+ spi_bus = devm_kzalloc(&pdev->dev,
+ struct_size(spi_bus, spi_int, hw_inst_cnt),
+ GFP_KERNEL);
+ if (!spi_bus)
+ return -ENOMEM;
+
+ spi_bus->dev = pdev;
+ spi_bus->total_hw_instances = hw_inst_cnt;
+ pci_set_master(pdev);
+
+ for (iter = 0; iter < hw_inst_cnt; iter++) {
+ spi_bus->spi_int[iter] = devm_kzalloc(&pdev->dev,
+ sizeof(struct pci1xxxx_spi_internal),
+ GFP_KERNEL);
+ spi_sub_ptr = spi_bus->spi_int[iter];
+ spi_sub_ptr->spi_host = devm_spi_alloc_master(dev, sizeof(struct spi_master));
+ if (!spi_sub_ptr->spi_host)
+ return -ENOMEM;
+
+ spi_sub_ptr->parent = spi_bus;
+ spi_sub_ptr->spi_xfer_in_progress = false;
+
+ if (!iter) {
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return -ENOMEM;
+
+ ret = pci_request_regions(pdev, DRV_NAME);
+ if (ret)
+ return -ENOMEM;
+
+ spi_bus->reg_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
+ if (!spi_bus->reg_base) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = pci_alloc_irq_vectors(pdev, hw_inst_cnt, hw_inst_cnt,
+ PCI_IRQ_ALL_TYPES);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error allocating MSI vectors\n");
+ goto error;
+ }
+
+ init_completion(&spi_sub_ptr->spi_xfer_done);
+ /* Initialize Interrupts - SPI_INT */
+ regval = readl(spi_bus->reg_base +
+ SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
+ regval &= ~SPI_INTR;
+ writel(regval, spi_bus->reg_base +
+ SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
+ spi_sub_ptr->irq = pci_irq_vector(pdev, 0);
+
+ ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
+ pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
+ pci_name(pdev), spi_sub_ptr);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to request irq : %d",
+ spi_sub_ptr->irq);
+ ret = -ENODEV;
+ goto error;
+ }
+
+ /* This register is only applicable for 1st instance */
+ regval = readl(spi_bus->reg_base + SPI_PCI_CTRL_REG_OFFSET(0));
+ if (!only_sec_inst)
+ regval |= (BIT(4));
+ else
+ regval &= ~(BIT(4));
+
+ writel(regval, spi_bus->reg_base + SPI_PCI_CTRL_REG_OFFSET(0));
+ }
+
+ spi_sub_ptr->hw_inst = start++;
+
+ if (iter == 1) {
+ init_completion(&spi_sub_ptr->spi_xfer_done);
+ /* Initialize Interrupts - SPI_INT */
+ regval = readl(spi_bus->reg_base +
+ SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
+ regval &= ~SPI_INTR;
+ writel(regval, spi_bus->reg_base +
+ SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
+ spi_sub_ptr->irq = pci_irq_vector(pdev, iter);
+ ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
+ pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
+ pci_name(pdev), spi_sub_ptr);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to request irq : %d",
+ spi_sub_ptr->irq);
+ ret = -ENODEV;
+ goto error;
+ }
+ }
+
+ spi_host = spi_sub_ptr->spi_host;
+ spi_host->num_chipselect = SPI_CHIP_SEL_COUNT;
+ spi_host->mode_bits = SPI_MODE_0 | SPI_MODE_3 | SPI_RX_DUAL |
+ SPI_TX_DUAL | SPI_LOOP;
+ spi_host->transfer_one = pci1xxxx_spi_transfer_one;
+ spi_host->set_cs = pci1xxxx_spi_set_cs;
+ spi_host->bits_per_word_mask = SPI_BPW_MASK(8);
+ spi_host->max_speed_hz = PCI1XXXX_SPI_MAX_CLOCK_HZ;
+ spi_host->min_speed_hz = PCI1XXXX_SPI_MIN_CLOCK_HZ;
+ spi_host->flags = SPI_MASTER_MUST_TX;
+ spi_master_set_devdata(spi_host, spi_sub_ptr);
+ ret = devm_spi_register_master(dev, spi_host);
+ if (ret)
+ goto error;
+ }
+ pci_set_drvdata(pdev, spi_bus);
+
+ return 0;
+
+error:
+ pci_release_regions(pdev);
+ return ret;
+}
+
+static struct pci_driver pci1xxxx_spi_driver = {
+ .name = DRV_NAME,
+ .id_table = pci1xxxx_spi_pci_id_table,
+ .probe = pci1xxxx_spi_probe,
+};
+
+module_pci_driver(pci1xxxx_spi_driver);
+
+MODULE_DESCRIPTION("Microchip Technology Inc. pci1xxxx SPI bus driver");
+MODULE_AUTHOR("Tharun Kumar P<[email protected]>");
+MODULE_AUTHOR("Kumaravel Thiagarajan<[email protected]>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 2bf21c2e7a52..32cc82a89ec1 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -20,7 +20,6 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
-#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -1322,134 +1321,11 @@ static void cleanup(struct spi_device *spi)
kfree(chip);
}
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
- { "INT33C0", LPSS_LPT_SSP },
- { "INT33C1", LPSS_LPT_SSP },
- { "INT3430", LPSS_LPT_SSP },
- { "INT3431", LPSS_LPT_SSP },
- { "80860F0E", LPSS_BYT_SSP },
- { "8086228E", LPSS_BSW_SSP },
- { },
-};
-MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
-#endif
-
-/*
- * PCI IDs of compound devices that integrate both host controller and private
- * integrated DMA engine. Please note these are not used in module
- * autoloading and probing in this module but matching the LPSS SSP type.
- */
-static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
- /* SPT-LP */
- { PCI_VDEVICE(INTEL, 0x9d29), LPSS_SPT_SSP },
- { PCI_VDEVICE(INTEL, 0x9d2a), LPSS_SPT_SSP },
- /* SPT-H */
- { PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP },
- { PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP },
- /* KBL-H */
- { PCI_VDEVICE(INTEL, 0xa2a9), LPSS_SPT_SSP },
- { PCI_VDEVICE(INTEL, 0xa2aa), LPSS_SPT_SSP },
- /* CML-V */
- { PCI_VDEVICE(INTEL, 0xa3a9), LPSS_SPT_SSP },
- { PCI_VDEVICE(INTEL, 0xa3aa), LPSS_SPT_SSP },
- /* BXT A-Step */
- { PCI_VDEVICE(INTEL, 0x0ac2), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x0ac4), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x0ac6), LPSS_BXT_SSP },
- /* BXT B-Step */
- { PCI_VDEVICE(INTEL, 0x1ac2), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x1ac4), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x1ac6), LPSS_BXT_SSP },
- /* GLK */
- { PCI_VDEVICE(INTEL, 0x31c2), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x31c4), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x31c6), LPSS_BXT_SSP },
- /* ICL-LP */
- { PCI_VDEVICE(INTEL, 0x34aa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x34ab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x34fb), LPSS_CNL_SSP },
- /* EHL */
- { PCI_VDEVICE(INTEL, 0x4b2a), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x4b2b), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x4b37), LPSS_BXT_SSP },
- /* JSL */
- { PCI_VDEVICE(INTEL, 0x4daa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x4dab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x4dfb), LPSS_CNL_SSP },
- /* TGL-H */
- { PCI_VDEVICE(INTEL, 0x43aa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x43ab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x43fb), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x43fd), LPSS_CNL_SSP },
- /* ADL-P */
- { PCI_VDEVICE(INTEL, 0x51aa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x51ab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x51fb), LPSS_CNL_SSP },
- /* ADL-M */
- { PCI_VDEVICE(INTEL, 0x54aa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x54ab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x54fb), LPSS_CNL_SSP },
- /* APL */
- { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
- { PCI_VDEVICE(INTEL, 0x5ac6), LPSS_BXT_SSP },
- /* RPL-S */
- { PCI_VDEVICE(INTEL, 0x7a2a), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x7a2b), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x7a79), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x7a7b), LPSS_CNL_SSP },
- /* ADL-S */
- { PCI_VDEVICE(INTEL, 0x7aaa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x7aab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x7af9), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x7afb), LPSS_CNL_SSP },
- /* MTL-P */
- { PCI_VDEVICE(INTEL, 0x7e27), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x7e30), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x7e46), LPSS_CNL_SSP },
- /* CNL-LP */
- { PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x9dab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x9dfb), LPSS_CNL_SSP },
- /* CNL-H */
- { PCI_VDEVICE(INTEL, 0xa32a), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0xa32b), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0xa37b), LPSS_CNL_SSP },
- /* CML-LP */
- { PCI_VDEVICE(INTEL, 0x02aa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x02ab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x02fb), LPSS_CNL_SSP },
- /* CML-H */
- { PCI_VDEVICE(INTEL, 0x06aa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x06ab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0x06fb), LPSS_CNL_SSP },
- /* TGL-LP */
- { PCI_VDEVICE(INTEL, 0xa0aa), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0xa0ab), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0xa0de), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0xa0df), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0xa0fb), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0xa0fd), LPSS_CNL_SSP },
- { PCI_VDEVICE(INTEL, 0xa0fe), LPSS_CNL_SSP },
- { },
-};
-
-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);
-
-#ifdef CONFIG_PCI
-
static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
{
return param == chan->device->dev;
}
-#endif /* CONFIG_PCI */
-
static struct pxa2xx_spi_controller *
pxa2xx_spi_init_pdata(struct platform_device *pdev)
{
@@ -1458,46 +1334,51 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
struct device *parent = dev->parent;
struct ssp_device *ssp;
struct resource *res;
- struct pci_dev *pcidev = dev_is_pci(parent) ? to_pci_dev(parent) : NULL;
- const struct pci_device_id *pcidev_id = NULL;
- enum pxa_ssp_type type;
+ enum pxa_ssp_type type = SSP_UNDEFINED;
const void *match;
+ bool is_lpss_priv;
int status;
u64 uid;
- if (pcidev)
- pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, pcidev);
+ is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv");
- match = device_get_match_data(&pdev->dev);
+ match = device_get_match_data(dev);
if (match)
type = (enum pxa_ssp_type)match;
- else if (pcidev_id)
- type = (enum pxa_ssp_type)pcidev_id->driver_data;
- else
+ 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(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
ssp = &pdata->ssp;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ssp->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+ 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;
-#ifdef CONFIG_PCI
- if (pcidev_id) {
+ /* Platforms with iDMA 64-bit */
+ if (is_lpss_priv) {
pdata->tx_param = parent;
pdata->rx_param = parent;
pdata->dma_filter = pxa2xx_spi_idma_filter;
}
-#endif
- ssp->clk = devm_clk_get(&pdev->dev, NULL);
+ ssp->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ssp->clk))
return ERR_CAST(ssp->clk);
@@ -1506,7 +1387,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
return ERR_PTR(ssp->irq);
ssp->type = type;
- ssp->dev = &pdev->dev;
+ ssp->dev = dev;
status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid);
if (status)
@@ -1514,7 +1395,7 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
else
ssp->port_id = uid;
- pdata->is_slave = device_property_read_bool(&pdev->dev, "spi-slave");
+ pdata->is_slave = device_property_read_bool(dev, "spi-slave");
pdata->num_chipselect = 1;
pdata->enable_dma = true;
pdata->dma_burst_size = 1;
@@ -1807,7 +1688,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int pxa2xx_spi_suspend(struct device *dev)
{
struct driver_data *drv_data = dev_get_drvdata(dev);
@@ -1842,9 +1722,7 @@ static int pxa2xx_spi_resume(struct device *dev)
/* Start the queue running */
return spi_controller_resume(drv_data->controller);
}
-#endif
-#ifdef CONFIG_PM
static int pxa2xx_spi_runtime_suspend(struct device *dev)
{
struct driver_data *drv_data = dev_get_drvdata(dev);
@@ -1859,18 +1737,35 @@ static int pxa2xx_spi_runtime_resume(struct device *dev)
return clk_prepare_enable(drv_data->ssp->clk);
}
-#endif
static const struct dev_pm_ops pxa2xx_spi_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pxa2xx_spi_suspend, pxa2xx_spi_resume)
- SET_RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend,
- pxa2xx_spi_runtime_resume, NULL)
+ 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[] = {
+ { .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 = &pxa2xx_spi_pm_ops,
+ .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),
},
diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index c89592b21ffc..904972606bd4 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -1157,6 +1157,11 @@ static int tegra_qspi_combined_seq_xfer(struct tegra_qspi *tqspi,
msg->actual_length += xfer->len;
transfer_phase++;
}
+ if (!xfer->cs_change) {
+ tegra_qspi_transfer_end(spi);
+ spi_transfer_delay_exec(xfer);
+ }
+ ret = 0;
exit:
msg->status = ret;
diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c
index c760aac070e5..95ff15665d44 100644
--- a/drivers/spi/spi-zynqmp-gqspi.c
+++ b/drivers/spi/spi-zynqmp-gqspi.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
@@ -34,6 +35,7 @@
#define GQSPI_RXD_OFST 0x00000120
#define GQSPI_TX_THRESHOLD_OFST 0x00000128
#define GQSPI_RX_THRESHOLD_OFST 0x0000012C
+#define IOU_TAPDLY_BYPASS_OFST 0x0000003C
#define GQSPI_LPBK_DLY_ADJ_OFST 0x00000138
#define GQSPI_GEN_FIFO_OFST 0x00000140
#define GQSPI_SEL_OFST 0x00000144
@@ -48,6 +50,7 @@
#define GQSPI_QSPIDMA_DST_I_MASK_OFST 0x00000820
#define GQSPI_QSPIDMA_DST_ADDR_OFST 0x00000800
#define GQSPI_QSPIDMA_DST_ADDR_MSB_OFST 0x00000828
+#define GQSPI_DATA_DLY_ADJ_OFST 0x000001F8
/* GQSPI register bit masks */
#define GQSPI_SEL_MASK 0x00000001
@@ -136,11 +139,37 @@
#define GQSPI_MAX_NUM_CS 2 /* Maximum number of chip selects */
+#define GQSPI_USE_DATA_DLY 0x1
+#define GQSPI_USE_DATA_DLY_SHIFT 31
+#define GQSPI_DATA_DLY_ADJ_VALUE 0x2
+#define GQSPI_DATA_DLY_ADJ_SHIFT 28
+#define GQSPI_LPBK_DLY_ADJ_DLY_1 0x1
+#define GQSPI_LPBK_DLY_ADJ_DLY_1_SHIFT 0x3
+#define TAP_DLY_BYPASS_LQSPI_RX_VALUE 0x1
+#define TAP_DLY_BYPASS_LQSPI_RX_SHIFT 0x2
+
+/* set to differentiate versal from zynqmp, 1=versal, 0=zynqmp */
+#define QSPI_QUIRK_HAS_TAPDELAY BIT(0)
+
+#define GQSPI_FREQ_37_5MHZ 37500000
+#define GQSPI_FREQ_40MHZ 40000000
+#define GQSPI_FREQ_100MHZ 100000000
+#define GQSPI_FREQ_150MHZ 150000000
+
#define SPI_AUTOSUSPEND_TIMEOUT 3000
enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
/**
+ * struct qspi_platform_data - zynqmp qspi platform data structure
+ * @quirks: Flags is used to identify the platform
+ */
+struct qspi_platform_data {
+ u32 quirks;
+};
+
+/**
* struct zynqmp_qspi - Defines qspi driver instance
+ * @ctlr: Pointer to the spi controller information
* @regs: Virtual address of the QSPI controller registers
* @refclk: Pointer to the peripheral clock
* @pclk: Pointer to the APB clock
@@ -157,6 +186,9 @@ enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
* @genfifoentry: Used for storing the genfifoentry instruction.
* @mode: Defines the mode in which QSPI is operating
* @data_completion: completion structure
+ * @op_lock: Operational lock
+ * @speed_hz: Current SPI bus clock speed in hz
+ * @has_tapdelay: Used for tapdelay register available in qspi
*/
struct zynqmp_qspi {
struct spi_controller *ctlr;
@@ -177,6 +209,8 @@ struct zynqmp_qspi {
enum mode_type mode;
struct completion data_completion;
struct mutex op_lock;
+ u32 speed_hz;
+ bool has_tapdelay;
};
/**
@@ -250,6 +284,56 @@ static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
}
/**
+ * zynqmp_qspi_set_tapdelay: To configure qspi tap delays
+ * @xqspi: Pointer to the zynqmp_qspi structure
+ * @baudrateval: Buadrate to configure
+ */
+static void zynqmp_qspi_set_tapdelay(struct zynqmp_qspi *xqspi, u32 baudrateval)
+{
+ u32 tapdlybypass = 0, lpbkdlyadj = 0, datadlyadj = 0, clk_rate;
+ u32 reqhz = 0;
+
+ clk_rate = clk_get_rate(xqspi->refclk);
+ reqhz = (clk_rate / (GQSPI_BAUD_DIV_SHIFT << baudrateval));
+
+ if (!xqspi->has_tapdelay) {
+ if (reqhz <= GQSPI_FREQ_40MHZ) {
+ zynqmp_pm_set_tapdelay_bypass(PM_TAPDELAY_QSPI,
+ PM_TAPDELAY_BYPASS_ENABLE);
+ } else if (reqhz <= GQSPI_FREQ_100MHZ) {
+ zynqmp_pm_set_tapdelay_bypass(PM_TAPDELAY_QSPI,
+ PM_TAPDELAY_BYPASS_ENABLE);
+ lpbkdlyadj |= (GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK);
+ datadlyadj |= ((GQSPI_USE_DATA_DLY <<
+ GQSPI_USE_DATA_DLY_SHIFT)
+ | (GQSPI_DATA_DLY_ADJ_VALUE <<
+ GQSPI_DATA_DLY_ADJ_SHIFT));
+ } else if (reqhz <= GQSPI_FREQ_150MHZ) {
+ lpbkdlyadj |= GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK;
+ }
+ } else {
+ if (reqhz <= GQSPI_FREQ_37_5MHZ) {
+ tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
+ TAP_DLY_BYPASS_LQSPI_RX_SHIFT);
+ } else if (reqhz <= GQSPI_FREQ_100MHZ) {
+ tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE <<
+ TAP_DLY_BYPASS_LQSPI_RX_SHIFT);
+ lpbkdlyadj |= (GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK);
+ datadlyadj |= (GQSPI_USE_DATA_DLY <<
+ GQSPI_USE_DATA_DLY_SHIFT);
+ } else if (reqhz <= GQSPI_FREQ_150MHZ) {
+ lpbkdlyadj |= (GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK
+ | (GQSPI_LPBK_DLY_ADJ_DLY_1 <<
+ GQSPI_LPBK_DLY_ADJ_DLY_1_SHIFT));
+ }
+ zynqmp_gqspi_write(xqspi,
+ IOU_TAPDLY_BYPASS_OFST, tapdlybypass);
+ }
+ zynqmp_gqspi_write(xqspi, GQSPI_LPBK_DLY_ADJ_OFST, lpbkdlyadj);
+ zynqmp_gqspi_write(xqspi, GQSPI_DATA_DLY_ADJ_OFST, datadlyadj);
+}
+
+/**
* zynqmp_qspi_init_hw - Initialize the hardware
* @xqspi: Pointer to the zynqmp_qspi structure
*
@@ -264,12 +348,15 @@ static void zynqmp_gqspi_selectslave(struct zynqmp_qspi *instanceptr,
* - Enable manual slave select
* - Enable manual start
* - Deselect all the chip select lines
- * - Set the little endian mode of TX FIFO and
+ * - Set the little endian mode of TX FIFO
+ * - Set clock phase
+ * - Set clock polarity and
* - Enable the QSPI controller
*/
static void zynqmp_qspi_init_hw(struct zynqmp_qspi *xqspi)
{
- u32 config_reg;
+ u32 config_reg, baud_rate_val = 0;
+ ulong clk_rate;
/* Select the GQSPI mode */
zynqmp_gqspi_write(xqspi, GQSPI_SEL_OFST, GQSPI_SEL_MASK);
@@ -303,21 +390,37 @@ static void zynqmp_qspi_init_hw(struct zynqmp_qspi *xqspi)
config_reg |= GQSPI_CFG_WP_HOLD_MASK;
/* Clear pre-scalar by default */
config_reg &= ~GQSPI_CFG_BAUD_RATE_DIV_MASK;
- /* CPHA 0 */
- config_reg &= ~GQSPI_CFG_CLK_PHA_MASK;
- /* CPOL 0 */
- config_reg &= ~GQSPI_CFG_CLK_POL_MASK;
+ /* Set CPHA */
+ if (xqspi->ctlr->mode_bits & SPI_CPHA)
+ config_reg |= GQSPI_CFG_CLK_PHA_MASK;
+ else
+ config_reg &= ~GQSPI_CFG_CLK_PHA_MASK;
+ /* Set CPOL */
+ if (xqspi->ctlr->mode_bits & SPI_CPOL)
+ config_reg |= GQSPI_CFG_CLK_POL_MASK;
+ else
+ config_reg &= ~GQSPI_CFG_CLK_POL_MASK;
+
+ /* Set the clock frequency */
+ clk_rate = clk_get_rate(xqspi->refclk);
+ while ((baud_rate_val < GQSPI_BAUD_DIV_MAX) &&
+ (clk_rate /
+ (GQSPI_BAUD_DIV_SHIFT << baud_rate_val)) > xqspi->speed_hz)
+ baud_rate_val++;
+
+ config_reg &= ~GQSPI_CFG_BAUD_RATE_DIV_MASK;
+ config_reg |= (baud_rate_val << GQSPI_CFG_BAUD_RATE_DIV_SHIFT);
+
zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
+ /* Set the tapdelay for clock frequency */
+ zynqmp_qspi_set_tapdelay(xqspi, baud_rate_val);
+
/* Clear the TX and RX FIFO */
zynqmp_gqspi_write(xqspi, GQSPI_FIFO_CTRL_OFST,
GQSPI_FIFO_CTRL_RST_RX_FIFO_MASK |
GQSPI_FIFO_CTRL_RST_TX_FIFO_MASK |
GQSPI_FIFO_CTRL_RST_GEN_FIFO_MASK);
- /* Set by default to allow for high frequencies */
- zynqmp_gqspi_write(xqspi, GQSPI_LPBK_DLY_ADJ_OFST,
- zynqmp_gqspi_read(xqspi, GQSPI_LPBK_DLY_ADJ_OFST) |
- GQSPI_LPBK_DLY_ADJ_USE_LPBK_MASK);
/* Reset thresholds */
zynqmp_gqspi_write(xqspi, GQSPI_TX_THRESHOLD_OFST,
GQSPI_TX_FIFO_THRESHOLD_RESET_VAL);
@@ -455,30 +558,30 @@ static int zynqmp_qspi_config_op(struct zynqmp_qspi *xqspi,
struct spi_device *qspi)
{
ulong clk_rate;
- u32 config_reg, baud_rate_val = 0;
+ u32 config_reg, req_speed_hz, baud_rate_val = 0;
- /* Set the clock frequency */
- /* If req_hz == 0, default to lowest speed */
- clk_rate = clk_get_rate(xqspi->refclk);
+ req_speed_hz = qspi->max_speed_hz;
- while ((baud_rate_val < GQSPI_BAUD_DIV_MAX) &&
- (clk_rate /
- (GQSPI_BAUD_DIV_SHIFT << baud_rate_val)) > qspi->max_speed_hz)
- baud_rate_val++;
+ if (xqspi->speed_hz != req_speed_hz) {
+ xqspi->speed_hz = req_speed_hz;
- config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
+ /* Set the clock frequency */
+ /* If req_speed_hz == 0, default to lowest speed */
+ clk_rate = clk_get_rate(xqspi->refclk);
- /* Set the QSPI clock phase and clock polarity */
- config_reg &= (~GQSPI_CFG_CLK_PHA_MASK) & (~GQSPI_CFG_CLK_POL_MASK);
+ while ((baud_rate_val < GQSPI_BAUD_DIV_MAX) &&
+ (clk_rate /
+ (GQSPI_BAUD_DIV_SHIFT << baud_rate_val)) >
+ req_speed_hz)
+ baud_rate_val++;
- if (qspi->mode & SPI_CPHA)
- config_reg |= GQSPI_CFG_CLK_PHA_MASK;
- if (qspi->mode & SPI_CPOL)
- config_reg |= GQSPI_CFG_CLK_POL_MASK;
+ config_reg = zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST);
- config_reg &= ~GQSPI_CFG_BAUD_RATE_DIV_MASK;
- config_reg |= (baud_rate_val << GQSPI_CFG_BAUD_RATE_DIV_SHIFT);
- zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
+ config_reg &= ~GQSPI_CFG_BAUD_RATE_DIV_MASK;
+ config_reg |= (baud_rate_val << GQSPI_CFG_BAUD_RATE_DIV_SHIFT);
+ zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, config_reg);
+ zynqmp_qspi_set_tapdelay(xqspi, baud_rate_val);
+ }
return 0;
}
@@ -739,6 +842,8 @@ static irqreturn_t zynqmp_qspi_irq(int irq, void *dev_id)
/**
* zynqmp_qspi_setuprxdma - This function sets up the RX DMA operation
* @xqspi: xqspi is a pointer to the GQSPI instance.
+ *
+ * Return: 0 on success; error value otherwise.
*/
static int zynqmp_qspi_setuprxdma(struct zynqmp_qspi *xqspi)
{
@@ -823,6 +928,8 @@ static void zynqmp_qspi_write_op(struct zynqmp_qspi *xqspi, u8 tx_nbits,
* @rx_nbits: Receive buswidth.
* @genfifoentry: genfifoentry is pointer to the variable in which
* GENFIFO mask is returned to calling function
+ *
+ * Return: 0 on success; error value otherwise.
*/
static int zynqmp_qspi_read_op(struct zynqmp_qspi *xqspi, u8 rx_nbits,
u32 genfifoentry)
@@ -1087,6 +1194,16 @@ static const struct dev_pm_ops zynqmp_qspi_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(zynqmp_qspi_suspend, zynqmp_qspi_resume)
};
+static const struct qspi_platform_data versal_qspi_def = {
+ .quirks = QSPI_QUIRK_HAS_TAPDELAY,
+};
+
+static const struct of_device_id zynqmp_qspi_of_match[] = {
+ { .compatible = "xlnx,zynqmp-qspi-1.0"},
+ { .compatible = "xlnx,versal-qspi-1.0", .data = &versal_qspi_def },
+ { /* End of table */ }
+};
+
static const struct spi_controller_mem_ops zynqmp_qspi_mem_ops = {
.exec_op = zynqmp_qspi_exec_op,
};
@@ -1107,6 +1224,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
u32 num_cs;
+ const struct qspi_platform_data *p_data;
ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
if (!ctlr)
@@ -1117,6 +1235,10 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
xqspi->ctlr = ctlr;
platform_set_drvdata(pdev, xqspi);
+ p_data = of_device_get_match_data(&pdev->dev);
+ if (p_data && (p_data->quirks & QSPI_QUIRK_HAS_TAPDELAY))
+ xqspi->has_tapdelay = true;
+
xqspi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(xqspi->regs)) {
ret = PTR_ERR(xqspi->regs);
@@ -1164,6 +1286,11 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
goto clk_dis_all;
}
+ ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
+ SPI_TX_DUAL | SPI_TX_QUAD;
+ ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
+ xqspi->speed_hz = ctlr->max_speed_hz;
+
/* QSPI controller initializations */
zynqmp_qspi_init_hw(xqspi);
@@ -1199,10 +1326,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->setup = zynqmp_qspi_setup_op;
- ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
- ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
- SPI_TX_DUAL | SPI_TX_QUAD;
ctlr->dev.of_node = np;
ctlr->auto_runtime_pm = true;
@@ -1253,11 +1377,6 @@ static int zynqmp_qspi_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id zynqmp_qspi_of_match[] = {
- { .compatible = "xlnx,zynqmp-qspi-1.0", },
- { /* End of table */ }
-};
-
MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match);
static struct platform_driver zynqmp_qspi_driver = {
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 5f9aedd1f0b6..3cc7bb4d03de 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -127,10 +127,10 @@ do { \
unsigned int start; \
pcpu_stats = per_cpu_ptr(in, i); \
do { \
- start = u64_stats_fetch_begin_irq( \
+ start = u64_stats_fetch_begin( \
&pcpu_stats->syncp); \
inc = u64_stats_read(&pcpu_stats->field); \
- } while (u64_stats_fetch_retry_irq( \
+ } while (u64_stats_fetch_retry( \
&pcpu_stats->syncp, start)); \
ret += inc; \
} \
@@ -360,6 +360,18 @@ const struct spi_device_id *spi_get_device_id(const struct spi_device *sdev)
}
EXPORT_SYMBOL_GPL(spi_get_device_id);
+const void *spi_get_device_match_data(const struct spi_device *sdev)
+{
+ const void *match;
+
+ match = device_get_match_data(&sdev->dev);
+ if (match)
+ return match;
+
+ return (const void *)spi_get_device_id(sdev)->driver_data;
+}
+EXPORT_SYMBOL_GPL(spi_get_device_match_data);
+
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
@@ -2212,6 +2224,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
struct device_node *nc)
{
u32 value;
+ u16 cs_setup;
int rc;
/* Mode (clock phase/polarity/etc.) */
@@ -2297,6 +2310,11 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
if (!of_property_read_u32(nc, "spi-max-frequency", &value))
spi->max_speed_hz = value;
+ if (!of_property_read_u16(nc, "spi-cs-setup-ns", &cs_setup)) {
+ spi->cs_setup.value = cs_setup;
+ spi->cs_setup.unit = SPI_DELAY_UNIT_NSECS;
+ }
+
return 0;
}
@@ -2759,6 +2777,17 @@ int spi_slave_abort(struct spi_device *spi)
}
EXPORT_SYMBOL_GPL(spi_slave_abort);
+int spi_target_abort(struct spi_device *spi)
+{
+ struct spi_controller *ctlr = spi->controller;
+
+ if (spi_controller_is_target(ctlr) && ctlr->target_abort)
+ return ctlr->target_abort(ctlr);
+
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(spi_target_abort);
+
static ssize_t slave_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -3593,6 +3622,37 @@ static int __spi_validate_bits_per_word(struct spi_controller *ctlr,
}
/**
+ * spi_set_cs_timing - configure CS setup, hold, and inactive delays
+ * @spi: the device that requires specific CS timing configuration
+ *
+ * Return: zero on success, else a negative error code.
+ */
+static int spi_set_cs_timing(struct spi_device *spi)
+{
+ struct device *parent = spi->controller->dev.parent;
+ int status = 0;
+
+ if (spi->controller->set_cs_timing && !spi->cs_gpiod) {
+ if (spi->controller->auto_runtime_pm) {
+ status = pm_runtime_get_sync(parent);
+ if (status < 0) {
+ pm_runtime_put_noidle(parent);
+ dev_err(&spi->controller->dev, "Failed to power device: %d\n",
+ status);
+ return status;
+ }
+
+ status = spi->controller->set_cs_timing(spi);
+ pm_runtime_mark_last_busy(parent);
+ pm_runtime_put_autosuspend(parent);
+ } else {
+ status = spi->controller->set_cs_timing(spi);
+ }
+ }
+ return status;
+}
+
+/**
* spi_setup - setup SPI mode and clock rate
* @spi: the device whose settings are being modified
* Context: can sleep, and no requests are queued to the device
@@ -3688,6 +3748,12 @@ int spi_setup(struct spi_device *spi)
}
}
+ status = spi_set_cs_timing(spi);
+ if (status) {
+ mutex_unlock(&spi->controller->io_mutex);
+ return status;
+ }
+
if (spi->controller->auto_runtime_pm && spi->controller->set_cs) {
status = pm_runtime_resume_and_get(spi->controller->dev.parent);
if (status < 0) {
diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
index 76d2b3ebad84..fac37680ffe7 100644
--- a/include/linux/firmware/xlnx-zynqmp.h
+++ b/include/linux/firmware/xlnx-zynqmp.h
@@ -135,6 +135,7 @@ enum pm_ret_status {
};
enum pm_ioctl_id {
+ IOCTL_SET_TAPDELAY_BYPASS = 4,
IOCTL_SD_DLL_RESET = 6,
IOCTL_SET_SD_TAPDELAY = 7,
IOCTL_SET_PLL_FRAC_MODE = 8,
@@ -389,6 +390,18 @@ enum zynqmp_pm_shutdown_subtype {
ZYNQMP_PM_SHUTDOWN_SUBTYPE_SYSTEM = 2,
};
+enum tap_delay_signal_type {
+ PM_TAPDELAY_NAND_DQS_IN = 0,
+ PM_TAPDELAY_NAND_DQS_OUT = 1,
+ PM_TAPDELAY_QSPI = 2,
+ PM_TAPDELAY_MAX = 3,
+};
+
+enum tap_delay_bypass_ctrl {
+ PM_TAPDELAY_BYPASS_DISABLE = 0,
+ PM_TAPDELAY_BYPASS_ENABLE = 1,
+};
+
enum ospi_mux_select_type {
PM_OSPI_MUX_SEL_DMA = 0,
PM_OSPI_MUX_SEL_LINEAR = 1,
@@ -484,6 +497,7 @@ int zynqmp_pm_write_ggs(u32 index, u32 value);
int zynqmp_pm_read_ggs(u32 index, u32 *value);
int zynqmp_pm_write_pggs(u32 index, u32 value);
int zynqmp_pm_read_pggs(u32 index, u32 *value);
+int zynqmp_pm_set_tapdelay_bypass(u32 index, u32 value);
int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype);
int zynqmp_pm_set_boot_health_status(u32 value);
int zynqmp_pm_pinctrl_request(const u32 pin);
@@ -696,6 +710,11 @@ static inline int zynqmp_pm_read_pggs(u32 index, u32 *value)
return -ENODEV;
}
+static inline int zynqmp_pm_set_tapdelay_bypass(u32 index, u32 value)
+{
+ return -ENODEV;
+}
+
static inline int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)
{
return -ENODEV;
diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h
index a3fec2de512f..cd1973e6ac4b 100644
--- a/include/linux/pxa2xx_ssp.h
+++ b/include/linux/pxa2xx_ssp.h
@@ -229,6 +229,7 @@ enum pxa_ssp_type {
LPSS_SPT_SSP,
LPSS_BXT_SSP,
LPSS_CNL_SSP,
+ SSP_MAX
};
struct ssp_device {
diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h
index 2ba044d0d5e5..8e984d75f5b6 100644
--- a/include/linux/spi/spi-mem.h
+++ b/include/linux/spi/spi-mem.h
@@ -225,7 +225,7 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem)
/**
* struct spi_controller_mem_ops - SPI memory operations
* @adjust_op_size: shrink the data xfer of an operation to match controller's
- * limitations (can be alignment of max RX/TX size
+ * limitations (can be alignment or max RX/TX size
* limitations)
* @supports_op: check if an operation is supported by the controller
* @exec_op: execute a SPI memory operation
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index fbf8c0d95968..9a32495fbb1f 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -356,6 +356,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
* @max_speed_hz: Highest supported transfer speed
* @flags: other constraints relevant to this driver
* @slave: indicates that this is an SPI slave controller
+ * @target: indicates that this is an SPI target controller
* @devm_allocated: whether the allocation of this struct is devres-managed
* @max_transfer_size: function that returns the max transfer size for
* a &spi_device; may be %NULL, so the default %SIZE_MAX will be used.
@@ -440,6 +441,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
* @mem_caps: controller capabilities for the handling of memory operations.
* @unprepare_message: undo any work done by prepare_message().
* @slave_abort: abort the ongoing transfer request on an SPI slave controller
+ * @target_abort: abort the ongoing transfer request on an SPI target controller
* @cs_gpiods: Array of GPIO descs to use as chip select lines; one per CS
* number. Any individual value may be NULL for CS lines that
* are not GPIOs (driven by the SPI controller itself).
@@ -535,8 +537,12 @@ struct spi_controller {
/* Flag indicating if the allocation of this struct is devres-managed */
bool devm_allocated;
- /* Flag indicating this is an SPI slave controller */
- bool slave;
+ union {
+ /* Flag indicating this is an SPI slave controller */
+ bool slave;
+ /* Flag indicating this is an SPI target controller */
+ bool target;
+ };
/*
* on some hardware transfer / message size may be constrained
@@ -649,7 +655,10 @@ struct spi_controller {
struct spi_message *message);
int (*unprepare_message)(struct spi_controller *ctlr,
struct spi_message *message);
- int (*slave_abort)(struct spi_controller *ctlr);
+ union {
+ int (*slave_abort)(struct spi_controller *ctlr);
+ int (*target_abort)(struct spi_controller *ctlr);
+ };
/*
* These hooks are for drivers that use a generic implementation
@@ -727,6 +736,11 @@ static inline bool spi_controller_is_slave(struct spi_controller *ctlr)
return IS_ENABLED(CONFIG_SPI_SLAVE) && ctlr->slave;
}
+static inline bool spi_controller_is_target(struct spi_controller *ctlr)
+{
+ return IS_ENABLED(CONFIG_SPI_SLAVE) && ctlr->target;
+}
+
/* PM calls that need to be issued by the driver */
extern int spi_controller_suspend(struct spi_controller *ctlr);
extern int spi_controller_resume(struct spi_controller *ctlr);
@@ -763,6 +777,21 @@ static inline struct spi_controller *spi_alloc_slave(struct device *host,
return __spi_alloc_controller(host, size, true);
}
+static inline struct spi_controller *spi_alloc_host(struct device *dev,
+ unsigned int size)
+{
+ return __spi_alloc_controller(dev, size, false);
+}
+
+static inline struct spi_controller *spi_alloc_target(struct device *dev,
+ unsigned int size)
+{
+ if (!IS_ENABLED(CONFIG_SPI_SLAVE))
+ return NULL;
+
+ return __spi_alloc_controller(dev, size, true);
+}
+
struct spi_controller *__devm_spi_alloc_controller(struct device *dev,
unsigned int size,
bool slave);
@@ -782,6 +811,21 @@ static inline struct spi_controller *devm_spi_alloc_slave(struct device *dev,
return __devm_spi_alloc_controller(dev, size, true);
}
+static inline struct spi_controller *devm_spi_alloc_host(struct device *dev,
+ unsigned int size)
+{
+ return __devm_spi_alloc_controller(dev, size, false);
+}
+
+static inline struct spi_controller *devm_spi_alloc_target(struct device *dev,
+ unsigned int size)
+{
+ if (!IS_ENABLED(CONFIG_SPI_SLAVE))
+ return NULL;
+
+ return __devm_spi_alloc_controller(dev, size, true);
+}
+
extern int spi_register_controller(struct spi_controller *ctlr);
extern int devm_spi_register_controller(struct device *dev,
struct spi_controller *ctlr);
@@ -1141,6 +1185,7 @@ static inline void spi_message_free(struct spi_message *m)
extern int spi_setup(struct spi_device *spi);
extern int spi_async(struct spi_device *spi, struct spi_message *message);
extern int spi_slave_abort(struct spi_device *spi);
+extern int spi_target_abort(struct spi_device *spi);
static inline size_t
spi_max_message_size(struct spi_device *spi)
@@ -1514,6 +1559,9 @@ extern void spi_unregister_device(struct spi_device *spi);
extern const struct spi_device_id *
spi_get_device_id(const struct spi_device *sdev);
+extern const void *
+spi_get_device_match_data(const struct spi_device *sdev);
+
static inline bool
spi_transfer_is_last(struct spi_controller *ctlr, struct spi_transfer *xfer)
{