aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-10-04 19:36:53 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-10-04 19:36:53 -0700
commit2bca25eaeba6190efbfcb38ed169bd7ee43b5aaf (patch)
tree93e087ddb705c95c3e8f4570c95859eb5f2c4ca0
parentMerge tag 'regulator-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator (diff)
parentspi: Ensure that sg_table won't be used after being freed (diff)
downloadwireguard-linux-2bca25eaeba6190efbfcb38ed169bd7ee43b5aaf.tar.xz
wireguard-linux-2bca25eaeba6190efbfcb38ed169bd7ee43b5aaf.zip
Merge tag 'spi-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown: "With the exception of some refactoring to fix long standing issues where we weren't handling cache syncs properly for messages which had PIO and DMA transfers going to the same page correctly there has been no work on the core this time around, and it's also been quite a quiet release for the drivers too: - Fix cache syncs for cases where we have DMA and PIO transfers in the same message going to the same page - Update the fsl_spi driver to use transfer_one() rather than a custom transfer function - Support for configuring transfer speeds with the AMD SPI controller - Support for a second chip select and 64K erase on Intel SPI - Support for Microchip coreQSPI, Nuvoton NPCM845, NXP i.MX93, and Rockchip RK3128 and RK3588" * tag 'spi-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (73 commits) spi: Ensure that sg_table won't be used after being freed spi: spi-gxp: Use devm_platform_ioremap_resource() spi: s3c64xx: Fix large transfers with DMA spi: Split transfers larger than max size spi: Fix cache corruption due to DMA/PIO overlap spi: Save current RX and TX DMA devices spi: mt65xx: Add dma max segment size declaration spi: migrate mt7621 text bindings to YAML spi: renesas,sh-msiof: Add r8a779g0 support spi: spi-fsl-qspi: Use devm_platform_ioremap_resource_byname() spi: spi-fsl-lpspi: Use devm_platform_get_and_ioremap_resource() spi: spi-fsl-dspi: Use devm_platform_get_and_ioremap_resource() spi/omap100k:Fix PM disable depth imbalance in omap1_spi100k_probe spi: dw: Fix PM disable depth imbalance in dw_spi_bt1_probe spi: cadence-quadspi: Fix PM disable depth imbalance in cqspi_probe spi: s3c24xx: Switch to use devm_spi_alloc_master() spi: xilinx: Switch to use devm_spi_alloc_master() spi: img-spfi: using pm_runtime_resume_and_get instead of pm_runtime_get_sync spi: aspeed: Remove redundant dev_err call spi: spi-mpc52xx: switch to using gpiod API ...
-rw-r--r--Documentation/devicetree/bindings/display/panel/kingdisplay,kd035g6-54nt.yaml2
-rw-r--r--Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml2
-rw-r--r--Documentation/devicetree/bindings/display/panel/samsung,s6e63m0.yaml4
-rw-r--r--Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml15
-rw-r--r--Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt3
-rw-r--r--Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml3
-rw-r--r--Documentation/devicetree/bindings/spi/ralink,mt7621-spi.yaml61
-rw-r--r--Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml14
-rw-r--r--Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml1
-rw-r--r--Documentation/devicetree/bindings/spi/spi-controller.yaml5
-rw-r--r--Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml14
-rw-r--r--Documentation/devicetree/bindings/spi/spi-mt7621.txt26
-rw-r--r--Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml5
-rw-r--r--Documentation/devicetree/bindings/spi/spi-rockchip.yaml5
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/spi/Kconfig9
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-amd.c183
-rw-r--r--drivers/spi/spi-aspeed-smc.c4
-rw-r--r--drivers/spi/spi-cadence-quadspi.c3
-rw-r--r--drivers/spi/spi-cadence-xspi.c4
-rw-r--r--drivers/spi/spi-dw-bt1.c4
-rw-r--r--drivers/spi/spi-dw-core.c2
-rw-r--r--drivers/spi/spi-fsl-dspi.c3
-rw-r--r--drivers/spi/spi-fsl-lpspi.c10
-rw-r--r--drivers/spi/spi-fsl-qspi.c3
-rw-r--r--drivers/spi/spi-fsl-spi.c157
-rw-r--r--drivers/spi/spi-gxp.c10
-rw-r--r--drivers/spi/spi-img-spfi.c6
-rw-r--r--drivers/spi/spi-intel.c164
-rw-r--r--drivers/spi/spi-loopback-test.c27
-rw-r--r--drivers/spi/spi-meson-spicc.c8
-rw-r--r--drivers/spi/spi-microchip-core-qspi.c600
-rw-r--r--drivers/spi/spi-microchip-core.c4
-rw-r--r--drivers/spi/spi-mpc52xx.c35
-rw-r--r--drivers/spi/spi-mt65xx.c5
-rw-r--r--drivers/spi/spi-mt7621.c42
-rw-r--r--drivers/spi/spi-npcm-pspi.c1
-rw-r--r--drivers/spi/spi-nxp-fspi.c8
-rw-r--r--drivers/spi/spi-omap-100k.c1
-rw-r--r--drivers/spi/spi-omap2-mcspi.c4
-rw-r--r--drivers/spi/spi-pxa2xx.c4
-rw-r--r--drivers/spi/spi-qup.c21
-rw-r--r--drivers/spi/spi-s3c24xx.c24
-rw-r--r--drivers/spi/spi-s3c64xx.c13
-rw-r--r--drivers/spi/spi-sh-msiof.c1
-rw-r--r--drivers/spi/spi-stm32-qspi.c125
-rw-r--r--drivers/spi/spi-xilinx.c20
-rw-r--r--drivers/spi/spi-xtensa-xtfpga.c16
-rw-r--r--drivers/spi/spi.c157
-rw-r--r--include/linux/spi/spi.h6
51 files changed, 1430 insertions, 416 deletions
diff --git a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd035g6-54nt.yaml b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd035g6-54nt.yaml
index 2a2756d19681..b4be9bd8ddde 100644
--- a/Documentation/devicetree/bindings/display/panel/kingdisplay,kd035g6-54nt.yaml
+++ b/Documentation/devicetree/bindings/display/panel/kingdisplay,kd035g6-54nt.yaml
@@ -23,6 +23,8 @@ properties:
reg: true
reset-gpios: true
+ spi-3wire: true
+
required:
- compatible
- power-supply
diff --git a/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml
index 817a9bed7d5a..ebdca5f5a001 100644
--- a/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml
+++ b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml
@@ -24,6 +24,8 @@ properties:
reg: true
reset-gpios: true
+ spi-3wire: true
+
required:
- compatible
- power-supply
diff --git a/Documentation/devicetree/bindings/display/panel/samsung,s6e63m0.yaml b/Documentation/devicetree/bindings/display/panel/samsung,s6e63m0.yaml
index 940f7f88526f..6f1fc7469f07 100644
--- a/Documentation/devicetree/bindings/display/panel/samsung,s6e63m0.yaml
+++ b/Documentation/devicetree/bindings/display/panel/samsung,s6e63m0.yaml
@@ -24,6 +24,10 @@ properties:
default-brightness: true
max-brightness: true
+ spi-3wire: true
+ spi-cpha: true
+ spi-cpol: true
+
vdd3-supply:
description: VDD regulator
diff --git a/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml
index 7326c0a28d16..1051690e3753 100644
--- a/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml
+++ b/Documentation/devicetree/bindings/spi/microchip,mpfs-spi.yaml
@@ -4,7 +4,11 @@
$id: http://devicetree.org/schemas/spi/microchip,mpfs-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Microchip MPFS {Q,}SPI Controller Device Tree Bindings
+title: Microchip FPGA {Q,}SPI Controllers
+
+description:
+ SPI and QSPI controllers on Microchip PolarFire SoC and the "soft"/
+ fabric IP cores they are based on
maintainers:
- Conor Dooley <conor.dooley@microchip.com>
@@ -14,9 +18,12 @@ allOf:
properties:
compatible:
- enum:
- - microchip,mpfs-spi
- - microchip,mpfs-qspi
+ oneOf:
+ - items:
+ - const: microchip,mpfs-qspi
+ - const: microchip,coreqspi-rtl-v2
+ - const: microchip,coreqspi-rtl-v2 #FPGA QSPI
+ - const: microchip,mpfs-spi
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt b/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt
index b98203ca656d..a4e72e52af59 100644
--- a/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt
+++ b/Documentation/devicetree/bindings/spi/nuvoton,npcm-pspi.txt
@@ -3,7 +3,8 @@ Nuvoton NPCM Peripheral Serial Peripheral Interface(PSPI) controller driver
Nuvoton NPCM7xx SOC support two PSPI channels.
Required properties:
- - compatible : "nuvoton,npcm750-pspi" for NPCM7XX BMC
+ - compatible : "nuvoton,npcm750-pspi" for Poleg NPCM7XX.
+ "nuvoton,npcm845-pspi" for Arbel NPCM8XX.
- #address-cells : should be 1. see spi-bus.txt
- #size-cells : should be 0. see spi-bus.txt
- specifies physical base address and size of the register.
diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml
index 24e0c2181d25..2c3cada75339 100644
--- a/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml
+++ b/Documentation/devicetree/bindings/spi/nvidia,tegra210-quad-peripheral-props.yaml
@@ -29,5 +29,4 @@ properties:
minimum: 0
maximum: 255
-unevaluatedProperties: true
-
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/spi/ralink,mt7621-spi.yaml b/Documentation/devicetree/bindings/spi/ralink,mt7621-spi.yaml
new file mode 100644
index 000000000000..22879f7dcb77
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/ralink,mt7621-spi.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/ralink,mt7621-spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+maintainers:
+ - Sergio Paracuellos <sergio.paracuellos@gmail.com>
+
+title: Mediatek MT7621/MT7628 SPI controller
+
+allOf:
+ - $ref: /schemas/spi/spi-controller.yaml#
+
+properties:
+ compatible:
+ const: ralink,mt7621-spi
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: spi
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ const: spi
+
+required:
+ - compatible
+ - reg
+ - resets
+ - "#address-cells"
+ - "#size-cells"
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/mt7621-clk.h>
+ #include <dt-bindings/reset/mt7621-reset.h>
+
+ spi@b00 {
+ compatible = "ralink,mt7621-spi";
+ reg = <0xb00 0x100>;
+ clocks = <&sysc MT7621_CLK_SPI>;
+ clock-names = "spi";
+ resets = <&sysc MT7621_RST_SPI>;
+ reset-names = "spi";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_pins>;
+ };
diff --git a/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml b/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml
index 5de710adfa63..491a695a2deb 100644
--- a/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml
+++ b/Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml
@@ -47,10 +47,16 @@ properties:
- renesas,msiof-r8a77980 # R-Car V3H
- renesas,msiof-r8a77990 # R-Car E3
- renesas,msiof-r8a77995 # R-Car D3
- - renesas,msiof-r8a779a0 # R-Car V3U
- const: renesas,rcar-gen3-msiof # generic R-Car Gen3 and RZ/G2
# compatible device
- items:
+ - enum:
+ - renesas,msiof-r8a779a0 # R-Car V3U
+ - renesas,msiof-r8a779f0 # R-Car S4-8
+ - renesas,msiof-r8a779g0 # R-Car V4H
+ - const: renesas,rcar-gen4-msiof # generic R-Car Gen4
+ # compatible device
+ - items:
- const: renesas,sh-msiof # deprecated
reg:
@@ -69,6 +75,12 @@ properties:
clocks:
maxItems: 1
+ power-domains:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
num-cs:
description: |
Total number of chip selects (default is 1).
diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
index 37c3c272407d..d33b72fabc5d 100644
--- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
+++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
@@ -104,7 +104,6 @@ properties:
const: spi
reg-io-width:
- $ref: /schemas/types.yaml#/definitions/uint32
description: I/O register width (in bytes) implemented by this device
default: 4
enum: [ 2, 4 ]
diff --git a/Documentation/devicetree/bindings/spi/spi-controller.yaml b/Documentation/devicetree/bindings/spi/spi-controller.yaml
index 655713fba7e2..01042a7f382e 100644
--- a/Documentation/devicetree/bindings/spi/spi-controller.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-controller.yaml
@@ -96,6 +96,11 @@ patternProperties:
$ref: spi-peripheral-props.yaml
properties:
+ spi-3wire:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ The device requires 3-wire mode.
+
spi-cpha:
$ref: /schemas/types.yaml#/definitions/flag
description:
diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml b/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml
index 1d46877fe46a..8b44284d30c6 100644
--- a/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-fsl-lpspi.yaml
@@ -19,7 +19,9 @@ properties:
- fsl,imx7ulp-spi
- fsl,imx8qxp-spi
- items:
- - const: fsl,imx8ulp-spi
+ - enum:
+ - fsl,imx8ulp-spi
+ - fsl,imx93-spi
- const: fsl,imx7ulp-spi
reg:
maxItems: 1
@@ -37,6 +39,16 @@ properties:
- const: per
- const: ipg
+ dmas:
+ items:
+ - description: TX DMA Channel
+ - description: RX DMA Channel
+
+ dma-names:
+ items:
+ - const: tx
+ - const: rx
+
fsl,spi-only-use-cs1-sel:
description:
spi common code does not support use of CS signals discontinuously.
diff --git a/Documentation/devicetree/bindings/spi/spi-mt7621.txt b/Documentation/devicetree/bindings/spi/spi-mt7621.txt
deleted file mode 100644
index d5baec0fa56e..000000000000
--- a/Documentation/devicetree/bindings/spi/spi-mt7621.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-Binding for MTK SPI controller (MT7621 MIPS)
-
-Required properties:
-- compatible: Should be one of the following:
- - "ralink,mt7621-spi": for mt7621/mt7628/mt7688 platforms
-- #address-cells: should be 1.
-- #size-cells: should be 0.
-- reg: Address and length of the register set for the device
-- resets: phandle to the reset controller asserting this device in
- reset
- See ../reset/reset.txt for details.
-
-Optional properties:
-- cs-gpios: see spi-bus.txt.
-
-Example:
-
-- SoC Specific Portion:
-spi0: spi@b00 {
- compatible = "ralink,mt7621-spi";
- reg = <0xb00 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- resets = <&rstctrl 18>;
- reset-names = "spi";
-};
diff --git a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
index a4abe1588005..dca677f9e1b9 100644
--- a/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml
@@ -29,11 +29,6 @@ properties:
description:
Chip select used by the device.
- spi-3wire:
- $ref: /schemas/types.yaml#/definitions/flag
- description:
- The device requires 3-wire mode.
-
spi-cs-high:
$ref: /schemas/types.yaml#/definitions/flag
description:
diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml
index 52a78a2e362e..66e49947b703 100644
--- a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml
+++ b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml
@@ -27,6 +27,7 @@ properties:
- items:
- enum:
- rockchip,px30-spi
+ - rockchip,rk3128-spi
- rockchip,rk3188-spi
- rockchip,rk3288-spi
- rockchip,rk3308-spi
@@ -34,6 +35,7 @@ properties:
- rockchip,rk3368-spi
- rockchip,rk3399-spi
- rockchip,rk3568-spi
+ - rockchip,rk3588-spi
- rockchip,rv1126-spi
- const: rockchip,rk3066-spi
@@ -80,6 +82,9 @@ properties:
where the "sleep" configuration may describe the state
the pins should be in during system suspend.
+ power-domains:
+ maxItems: 1
+
required:
- compatible
- reg
diff --git a/MAINTAINERS b/MAINTAINERS
index ce066179edc3..8656ab794786 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17568,6 +17568,7 @@ F: drivers/mailbox/mailbox-mpfs.c
F: drivers/pci/controller/pcie-microchip-host.c
F: drivers/rtc/rtc-mpfs.c
F: drivers/soc/microchip/
+F: drivers/spi/spi-microchip-core-qspi.c
F: drivers/spi/spi-microchip-core.c
F: drivers/usb/musb/mpfs.c
F: include/soc/microchip/mpfs.h
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index e32f6a2058ae..d1bb62f7368b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -591,6 +591,15 @@ config SPI_MICROCHIP_CORE
PolarFire SoC.
If built as a module, it will be called spi-microchip-core.
+config SPI_MICROCHIP_CORE_QSPI
+ tristate "Microchip FPGA QSPI controllers"
+ depends on SPI_MASTER
+ help
+ This enables the QSPI driver for Microchip FPGA QSPI controllers.
+ Say Y or M here if you want to use the QSPI controllers on
+ PolarFire SoC.
+ If built as a module, it will be called spi-microchip-core-qspi.
+
config SPI_MT65XX
tristate "MediaTek SPI controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 15d2f3835e45..4b34e855c841 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o
obj-$(CONFIG_SPI_MESON_SPICC) += spi-meson-spicc.o
obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
obj-$(CONFIG_SPI_MICROCHIP_CORE) += spi-microchip-core.o
+obj-$(CONFIG_SPI_MICROCHIP_CORE_QSPI) += spi-microchip-core-qspi.o
obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o
diff --git a/drivers/spi/spi-amd.c b/drivers/spi/spi-amd.c
index 08df4f8d0531..e23121456c70 100644
--- a/drivers/spi/spi-amd.c
+++ b/drivers/spi/spi-amd.c
@@ -36,9 +36,17 @@
#define AMD_SPI_FIFO_SIZE 70
#define AMD_SPI_MEM_SIZE 200
-/* M_CMD OP codes for SPI */
-#define AMD_SPI_XFER_TX 1
-#define AMD_SPI_XFER_RX 2
+#define AMD_SPI_ENA_REG 0x20
+#define AMD_SPI_ALT_SPD_SHIFT 20
+#define AMD_SPI_ALT_SPD_MASK GENMASK(23, AMD_SPI_ALT_SPD_SHIFT)
+#define AMD_SPI_SPI100_SHIFT 0
+#define AMD_SPI_SPI100_MASK GENMASK(AMD_SPI_SPI100_SHIFT, AMD_SPI_SPI100_SHIFT)
+#define AMD_SPI_SPEED_REG 0x6C
+#define AMD_SPI_SPD7_SHIFT 8
+#define AMD_SPI_SPD7_MASK GENMASK(13, AMD_SPI_SPD7_SHIFT)
+
+#define AMD_SPI_MAX_HZ 100000000
+#define AMD_SPI_MIN_HZ 800000
/**
* enum amd_spi_versions - SPI controller versions
@@ -50,14 +58,41 @@ enum amd_spi_versions {
AMD_SPI_V2,
};
+enum amd_spi_speed {
+ F_66_66MHz,
+ F_33_33MHz,
+ F_22_22MHz,
+ F_16_66MHz,
+ F_100MHz,
+ F_800KHz,
+ SPI_SPD7,
+ F_50MHz = 0x4,
+ F_4MHz = 0x32,
+ F_3_17MHz = 0x3F
+};
+
+/**
+ * struct amd_spi_freq - Matches device speed with values to write in regs
+ * @speed_hz: Device frequency
+ * @enable_val: Value to be written to "enable register"
+ * @spd7_val: Some frequencies requires to have a value written at SPISPEED register
+ */
+struct amd_spi_freq {
+ u32 speed_hz;
+ u32 enable_val;
+ u32 spd7_val;
+};
+
/**
* struct amd_spi - SPI driver instance
* @io_remap_addr: Start address of the SPI controller registers
* @version: SPI controller hardware version
+ * @speed_hz: Device frequency
*/
struct amd_spi {
void __iomem *io_remap_addr;
enum amd_spi_versions version;
+ unsigned int speed_hz;
};
static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx)
@@ -189,65 +224,125 @@ static int amd_spi_master_setup(struct spi_device *spi)
return 0;
}
+static const struct amd_spi_freq amd_spi_freq[] = {
+ { AMD_SPI_MAX_HZ, F_100MHz, 0},
+ { 66660000, F_66_66MHz, 0},
+ { 50000000, SPI_SPD7, F_50MHz},
+ { 33330000, F_33_33MHz, 0},
+ { 22220000, F_22_22MHz, 0},
+ { 16660000, F_16_66MHz, 0},
+ { 4000000, SPI_SPD7, F_4MHz},
+ { 3170000, SPI_SPD7, F_3_17MHz},
+ { AMD_SPI_MIN_HZ, F_800KHz, 0},
+};
+
+static int 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;
+
+ amd_spi->speed_hz = amd_spi_freq[i].speed_hz;
+
+ alt_spd = (amd_spi_freq[i].enable_val << AMD_SPI_ALT_SPD_SHIFT)
+ & AMD_SPI_ALT_SPD_MASK;
+ amd_spi_setclear_reg32(amd_spi, AMD_SPI_ENA_REG, alt_spd,
+ AMD_SPI_ALT_SPD_MASK);
+
+ if (amd_spi->speed_hz == AMD_SPI_MAX_HZ)
+ amd_spi_setclear_reg32(amd_spi, AMD_SPI_ENA_REG, 1,
+ AMD_SPI_SPI100_MASK);
+
+ if (amd_spi_freq[i].spd7_val) {
+ spd7_val = (amd_spi_freq[i].spd7_val << AMD_SPI_SPD7_SHIFT)
+ & AMD_SPI_SPD7_MASK;
+ amd_spi_setclear_reg32(amd_spi, AMD_SPI_SPEED_REG, spd7_val,
+ AMD_SPI_SPD7_MASK);
+ }
+
+ return 0;
+}
+
static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
struct spi_master *master,
struct spi_message *message)
{
struct spi_transfer *xfer = NULL;
- u8 cmd_opcode;
+ struct spi_device *spi = message->spi;
+ u8 cmd_opcode = 0, fifo_pos = AMD_SPI_FIFO_BASE;
u8 *buf = NULL;
- u32 m_cmd = 0;
u32 i = 0;
u32 tx_len = 0, rx_len = 0;
list_for_each_entry(xfer, &message->transfers,
transfer_list) {
- if (xfer->rx_buf)
- m_cmd = AMD_SPI_XFER_RX;
- if (xfer->tx_buf)
- m_cmd = AMD_SPI_XFER_TX;
+ if (xfer->speed_hz)
+ amd_set_spi_freq(amd_spi, xfer->speed_hz);
+ else
+ amd_set_spi_freq(amd_spi, spi->max_speed_hz);
- if (m_cmd & AMD_SPI_XFER_TX) {
+ if (xfer->tx_buf) {
buf = (u8 *)xfer->tx_buf;
- tx_len = xfer->len - 1;
- cmd_opcode = *(u8 *)xfer->tx_buf;
- buf++;
- amd_spi_set_opcode(amd_spi, cmd_opcode);
+ if (!tx_len) {
+ cmd_opcode = *(u8 *)xfer->tx_buf;
+ buf++;
+ xfer->len--;
+ }
+ tx_len += xfer->len;
/* Write data into the FIFO. */
- for (i = 0; i < tx_len; i++) {
- iowrite8(buf[i], ((u8 __iomem *)amd_spi->io_remap_addr +
- AMD_SPI_FIFO_BASE + i));
- }
+ for (i = 0; i < xfer->len; i++)
+ amd_spi_writereg8(amd_spi, fifo_pos + i, buf[i]);
- amd_spi_set_tx_count(amd_spi, tx_len);
- amd_spi_clear_fifo_ptr(amd_spi);
- /* Execute command */
- amd_spi_execute_opcode(amd_spi);
- }
- if (m_cmd & AMD_SPI_XFER_RX) {
- /*
- * Store no. of bytes to be received from
- * FIFO
- */
- rx_len = xfer->len;
- buf = (u8 *)xfer->rx_buf;
- amd_spi_set_rx_count(amd_spi, rx_len);
- amd_spi_clear_fifo_ptr(amd_spi);
- /* Execute command */
- amd_spi_execute_opcode(amd_spi);
- amd_spi_busy_wait(amd_spi);
- /* Read data from FIFO to receive buffer */
- for (i = 0; i < rx_len; i++)
- buf[i] = amd_spi_readreg8(amd_spi, AMD_SPI_FIFO_BASE + tx_len + i);
+ fifo_pos += xfer->len;
}
+
+ /* Store no. of bytes to be received from FIFO */
+ if (xfer->rx_buf)
+ rx_len += xfer->len;
+ }
+
+ if (!buf) {
+ message->status = -EINVAL;
+ goto fin_msg;
+ }
+
+ amd_spi_set_opcode(amd_spi, cmd_opcode);
+ amd_spi_set_tx_count(amd_spi, tx_len);
+ amd_spi_set_rx_count(amd_spi, rx_len);
+
+ /* Execute command */
+ message->status = amd_spi_execute_opcode(amd_spi);
+ if (message->status)
+ goto fin_msg;
+
+ if (rx_len) {
+ message->status = amd_spi_busy_wait(amd_spi);
+ if (message->status)
+ goto fin_msg;
+
+ list_for_each_entry(xfer, &message->transfers, transfer_list)
+ if (xfer->rx_buf) {
+ buf = (u8 *)xfer->rx_buf;
+ /* Read data from FIFO to receive buffer */
+ for (i = 0; i < xfer->len; i++)
+ buf[i] = amd_spi_readreg8(amd_spi, fifo_pos + i);
+ fifo_pos += xfer->len;
+ }
}
/* Update statistics */
message->actual_length = tx_len + rx_len + 1;
- /* complete the transaction */
- message->status = 0;
+fin_msg:
switch (amd_spi->version) {
case AMD_SPI_V1:
break;
@@ -260,7 +355,7 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
spi_finalize_current_message(master);
- return 0;
+ return message->status;
}
static int amd_spi_master_transfer(struct spi_master *master,
@@ -275,9 +370,7 @@ static int amd_spi_master_transfer(struct spi_master *master,
* Extract spi_transfers from the spi message and
* program the controller.
*/
- amd_spi_fifo_xfer(amd_spi, master, msg);
-
- return 0;
+ return amd_spi_fifo_xfer(amd_spi, master, msg);
}
static size_t amd_spi_max_transfer_size(struct spi_device *spi)
@@ -312,6 +405,8 @@ static int amd_spi_probe(struct platform_device *pdev)
master->num_chipselect = 4;
master->mode_bits = 0;
master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->max_speed_hz = AMD_SPI_MAX_HZ;
+ master->min_speed_hz = AMD_SPI_MIN_HZ;
master->setup = amd_spi_master_setup;
master->transfer_one_message = amd_spi_master_transfer;
master->max_transfer_size = amd_spi_max_transfer_size;
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index 3e891bf22470..a334e89add86 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -736,10 +736,8 @@ static int aspeed_spi_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
aspi->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(aspi->regs)) {
- dev_err(dev, "missing AHB register window\n");
+ 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);
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index e12ab5b43f34..447230547945 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -1645,7 +1645,7 @@ static int cqspi_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
- return ret;
+ goto probe_pm_failed;
ret = clk_prepare_enable(cqspi->clk);
if (ret) {
@@ -1740,6 +1740,7 @@ probe_reset_failed:
clk_disable_unprepare(cqspi->clk);
probe_clk_failed:
pm_runtime_put_sync(dev);
+probe_pm_failed:
pm_runtime_disable(dev);
return ret;
}
diff --git a/drivers/spi/spi-cadence-xspi.c b/drivers/spi/spi-cadence-xspi.c
index 3ab19be83095..9e187f9c6c95 100644
--- a/drivers/spi/spi-cadence-xspi.c
+++ b/drivers/spi/spi-cadence-xspi.c
@@ -565,10 +565,8 @@ static int cdns_xspi_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sdma");
cdns_xspi->sdmabase = devm_ioremap_resource(dev, res);
- if (IS_ERR(cdns_xspi->sdmabase)) {
- dev_err(dev, "Failed to remap SDMA address\n");
+ 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");
diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c
index c06553416123..3fb89dee595e 100644
--- a/drivers/spi/spi-dw-bt1.c
+++ b/drivers/spi/spi-dw-bt1.c
@@ -293,8 +293,10 @@ static int dw_spi_bt1_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
ret = dw_spi_add_host(&pdev->dev, dws);
- if (ret)
+ if (ret) {
+ pm_runtime_disable(&pdev->dev);
goto err_disable_clk;
+ }
platform_set_drvdata(pdev, dwsbt1);
diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index f87d97ccd2d6..99edddf9958b 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -955,7 +955,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
ret = spi_register_controller(master);
if (ret) {
- dev_err(&master->dev, "problem registering spi master\n");
+ dev_err_probe(dev, ret, "problem registering spi master\n");
goto err_dma_exit;
}
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index fd004c9db9dc..a33e547b7d39 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -1294,8 +1294,7 @@ static int dspi_probe(struct platform_device *pdev)
else
ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(&pdev->dev, res);
+ base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base)) {
ret = PTR_ERR(base);
goto out_ctlr_put;
diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c
index 19b1f3d881b0..e8c1c8a4c6c8 100644
--- a/drivers/spi/spi-fsl-lpspi.c
+++ b/drivers/spi/spi-fsl-lpspi.c
@@ -855,8 +855,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
init_completion(&fsl_lpspi->xfer_done);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- fsl_lpspi->base = devm_ioremap_resource(&pdev->dev, res);
+ fsl_lpspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(fsl_lpspi->base)) {
ret = PTR_ERR(fsl_lpspi->base);
goto out_controller_put;
@@ -912,7 +911,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
ret = devm_spi_register_controller(&pdev->dev, controller);
if (ret < 0) {
- dev_err_probe(&pdev->dev, ret, "spi_register_controller error: %i\n", ret);
+ dev_err_probe(&pdev->dev, ret, "spi_register_controller error\n");
goto free_dma;
}
@@ -947,11 +946,8 @@ static int fsl_lpspi_remove(struct platform_device *pdev)
static int __maybe_unused fsl_lpspi_suspend(struct device *dev)
{
- int ret;
-
pinctrl_pm_select_sleep_state(dev);
- ret = pm_runtime_force_suspend(dev);
- return ret;
+ return pm_runtime_force_suspend(dev);
}
static int __maybe_unused fsl_lpspi_resume(struct device *dev)
diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
index 46ae46a944c5..85cc71ba624a 100644
--- a/drivers/spi/spi-fsl-qspi.c
+++ b/drivers/spi/spi-fsl-qspi.c
@@ -867,8 +867,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, q);
/* find the resources */
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI");
- q->iobase = devm_ioremap_resource(dev, res);
+ q->iobase = devm_platform_ioremap_resource_byname(pdev, "QuadSPI");
if (IS_ERR(q->iobase)) {
ret = PTR_ERR(q->iobase);
goto err_put_ctrl;
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index bdf94cc7be1a..731624f157fc 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -111,32 +111,6 @@ static void fsl_spi_change_mode(struct spi_device *spi)
local_irq_restore(flags);
}
-static void fsl_spi_chipselect(struct spi_device *spi, int value)
-{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
- struct fsl_spi_platform_data *pdata;
- struct spi_mpc8xxx_cs *cs = spi->controller_state;
-
- pdata = spi->dev.parent->parent->platform_data;
-
- if (value == BITBANG_CS_INACTIVE) {
- if (pdata->cs_control)
- pdata->cs_control(spi, false);
- }
-
- if (value == BITBANG_CS_ACTIVE) {
- mpc8xxx_spi->rx_shift = cs->rx_shift;
- mpc8xxx_spi->tx_shift = cs->tx_shift;
- mpc8xxx_spi->get_rx = cs->get_rx;
- mpc8xxx_spi->get_tx = cs->get_tx;
-
- fsl_spi_change_mode(spi);
-
- if (pdata->cs_control)
- pdata->cs_control(spi, true);
- }
-}
-
static void fsl_spi_qe_cpu_set_shifts(u32 *rx_shift, u32 *tx_shift,
int bits_per_word, int msb_first)
{
@@ -354,15 +328,11 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
return mpc8xxx_spi->count;
}
-static int fsl_spi_do_one_msg(struct spi_master *master,
- struct spi_message *m)
+static int fsl_spi_prepare_message(struct spi_controller *ctlr,
+ struct spi_message *m)
{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
- struct spi_device *spi = m->spi;
- struct spi_transfer *t, *first;
- unsigned int cs_change;
- const int nsecs = 50;
- int status, last_bpw;
+ struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(ctlr);
+ struct spi_transfer *t;
/*
* In CPU mode, optimize large byte transfers to use larger
@@ -378,62 +348,30 @@ static int fsl_spi_do_one_msg(struct spi_master *master,
t->bits_per_word = 16;
}
}
+ return 0;
+}
- /* Don't allow changes if CS is active */
- cs_change = 1;
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (cs_change)
- first = t;
- cs_change = t->cs_change;
- if (first->speed_hz != t->speed_hz) {
- dev_err(&spi->dev,
- "speed_hz cannot change while CS is active\n");
- return -EINVAL;
- }
- }
-
- last_bpw = -1;
- cs_change = 1;
- status = -EINVAL;
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (cs_change || last_bpw != t->bits_per_word)
- status = fsl_spi_setup_transfer(spi, t);
- if (status < 0)
- break;
- last_bpw = t->bits_per_word;
-
- if (cs_change) {
- fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE);
- ndelay(nsecs);
- }
- cs_change = t->cs_change;
- if (t->len)
- status = fsl_spi_bufs(spi, t, m->is_dma_mapped);
- if (status) {
- status = -EMSGSIZE;
- break;
- }
- m->actual_length += t->len;
-
- spi_transfer_delay_exec(t);
-
- if (cs_change) {
- ndelay(nsecs);
- fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
- ndelay(nsecs);
- }
- }
+static int fsl_spi_transfer_one(struct spi_controller *controller,
+ struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ int status;
- m->status = status;
+ status = fsl_spi_setup_transfer(spi, t);
+ if (status < 0)
+ return status;
+ if (t->len)
+ status = fsl_spi_bufs(spi, t, !!t->tx_dma || !!t->rx_dma);
+ if (status > 0)
+ return -EMSGSIZE;
- if (status || !cs_change) {
- ndelay(nsecs);
- fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
- }
+ return status;
+}
- fsl_spi_setup_transfer(spi, NULL);
- spi_finalize_current_message(master);
- return 0;
+static int fsl_spi_unprepare_message(struct spi_controller *controller,
+ struct spi_message *msg)
+{
+ return fsl_spi_setup_transfer(msg->spi, NULL);
}
static int fsl_spi_setup(struct spi_device *spi)
@@ -482,9 +420,6 @@ static int fsl_spi_setup(struct spi_device *spi)
return retval;
}
- /* Initialize chipselect - might be active for SPI_CS_HIGH mode */
- fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
-
return 0;
}
@@ -557,9 +492,7 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
u32 slvsel;
u16 cs = spi->chip_select;
- if (spi->cs_gpiod) {
- gpiod_set_value(spi->cs_gpiod, on);
- } else if (cs < mpc8xxx_spi->native_chipselects) {
+ if (cs < mpc8xxx_spi->native_chipselects) {
slvsel = mpc8xxx_spi_read_reg(&reg_base->slvsel);
slvsel = on ? (slvsel | (1 << cs)) : (slvsel & ~(1 << cs));
mpc8xxx_spi_write_reg(&reg_base->slvsel, slvsel);
@@ -568,7 +501,6 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on)
static void fsl_spi_grlib_probe(struct device *dev)
{
- struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct spi_master *master = dev_get_drvdata(dev);
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
struct fsl_spi_reg __iomem *reg_base = mpc8xxx_spi->reg_base;
@@ -588,7 +520,18 @@ static void fsl_spi_grlib_probe(struct device *dev)
mpc8xxx_spi_write_reg(&reg_base->slvsel, 0xffffffff);
}
master->num_chipselect = mpc8xxx_spi->native_chipselects;
- pdata->cs_control = fsl_spi_grlib_cs_control;
+ master->set_cs = fsl_spi_grlib_cs_control;
+}
+
+static void fsl_spi_cs_control(struct spi_device *spi, bool on)
+{
+ struct device *dev = spi->dev.parent->parent;
+ struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
+ struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
+
+ if (WARN_ON_ONCE(!pinfo->immr_spi_cs))
+ return;
+ iowrite32be(on ? 0 : SPI_BOOT_SEL_BIT, pinfo->immr_spi_cs);
}
static struct spi_master *fsl_spi_probe(struct device *dev,
@@ -613,8 +556,11 @@ static struct spi_master *fsl_spi_probe(struct device *dev,
master->setup = fsl_spi_setup;
master->cleanup = fsl_spi_cleanup;
- master->transfer_one_message = fsl_spi_do_one_msg;
+ master->prepare_message = fsl_spi_prepare_message;
+ master->transfer_one = fsl_spi_transfer_one;
+ master->unprepare_message = fsl_spi_unprepare_message;
master->use_gpio_descriptors = true;
+ master->set_cs = fsl_spi_cs_control;
mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->max_bits_per_word = 32;
@@ -688,21 +634,6 @@ err:
return ERR_PTR(ret);
}
-static void fsl_spi_cs_control(struct spi_device *spi, bool on)
-{
- if (spi->cs_gpiod) {
- gpiod_set_value(spi->cs_gpiod, on);
- } else {
- struct device *dev = spi->dev.parent->parent;
- struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
- struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
-
- if (WARN_ON_ONCE(!pinfo->immr_spi_cs))
- return;
- iowrite32be(on ? 0 : SPI_BOOT_SEL_BIT, pinfo->immr_spi_cs);
- }
-}
-
static int of_fsl_spi_probe(struct platform_device *ofdev)
{
struct device *dev = &ofdev->dev;
@@ -744,12 +675,10 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
ret = gpiod_count(dev, "cs");
if (ret < 0)
ret = 0;
- if (ret == 0 && !spisel_boot) {
+ if (ret == 0 && !spisel_boot)
pdata->max_chipselect = 1;
- } else {
+ else
pdata->max_chipselect = ret + spisel_boot;
- pdata->cs_control = fsl_spi_cs_control;
- }
}
ret = of_address_to_resource(np, 0, &mem);
diff --git a/drivers/spi/spi-gxp.c b/drivers/spi/spi-gxp.c
index 9ea355f7d64f..15b110183839 100644
--- a/drivers/spi/spi-gxp.c
+++ b/drivers/spi/spi-gxp.c
@@ -254,7 +254,6 @@ static int gxp_spifi_probe(struct platform_device *pdev)
const struct gxp_spi_data *data;
struct spi_controller *ctlr;
struct gxp_spi *spifi;
- struct resource *res;
int ret;
data = of_device_get_match_data(&pdev->dev);
@@ -269,18 +268,15 @@ static int gxp_spifi_probe(struct platform_device *pdev)
spifi->data = data;
spifi->dev = dev;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- spifi->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ spifi->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(spifi->reg_base))
return PTR_ERR(spifi->reg_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- spifi->dat_base = devm_ioremap_resource(&pdev->dev, res);
+ spifi->dat_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(spifi->dat_base))
return PTR_ERR(spifi->dat_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- spifi->dir_base = devm_ioremap_resource(&pdev->dev, res);
+ spifi->dir_base = devm_platform_ioremap_resource(pdev, 2);
if (IS_ERR(spifi->dir_base))
return PTR_ERR(spifi->dir_base);
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index 71376b6df89d..bfd12247f173 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -730,11 +730,9 @@ static int img_spfi_resume(struct device *dev)
struct img_spfi *spfi = spi_master_get_devdata(master);
int ret;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
return ret;
- }
spfi_reset(spfi);
pm_runtime_put(dev);
diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c
index 66063687ae27..55f4ee2db002 100644
--- a/drivers/spi/spi-intel.c
+++ b/drivers/spi/spi-intel.c
@@ -116,6 +116,22 @@
#define ERASE_64K_OPCODE_SHIFT 16
#define ERASE_64K_OPCODE_MASK (0xff << ERASE_OPCODE_SHIFT)
+/* Flash descriptor fields */
+#define FLVALSIG_MAGIC 0x0ff0a55a
+#define FLMAP0_NC_MASK GENMASK(9, 8)
+#define FLMAP0_NC_SHIFT 8
+#define FLMAP0_FCBA_MASK GENMASK(7, 0)
+
+#define FLCOMP_C0DEN_MASK GENMASK(3, 0)
+#define FLCOMP_C0DEN_512K 0x00
+#define FLCOMP_C0DEN_1M 0x01
+#define FLCOMP_C0DEN_2M 0x02
+#define FLCOMP_C0DEN_4M 0x03
+#define FLCOMP_C0DEN_8M 0x04
+#define FLCOMP_C0DEN_16M 0x05
+#define FLCOMP_C0DEN_32M 0x06
+#define FLCOMP_C0DEN_64M 0x07
+
#define INTEL_SPI_TIMEOUT 5000 /* ms */
#define INTEL_SPI_FIFO_SZ 64
@@ -129,6 +145,7 @@
* @master: Pointer to the SPI controller structure
* @nregions: Maximum number of regions
* @pr_num: Maximum number of protected range registers
+ * @chip0_size: Size of the first flash chip in bytes
* @locked: Is SPI setting locked
* @swseq_reg: Use SW sequencer in register reads/writes
* @swseq_erase: Use SW sequencer in erase operation
@@ -146,6 +163,7 @@ struct intel_spi {
struct spi_controller *master;
size_t nregions;
size_t pr_num;
+ size_t chip0_size;
bool locked;
bool swseq_reg;
bool swseq_erase;
@@ -158,6 +176,7 @@ struct intel_spi_mem_op {
struct spi_mem_op mem_op;
u32 replacement_op;
int (*exec_op)(struct intel_spi *ispi,
+ const struct spi_mem *mem,
const struct intel_spi_mem_op *iop,
const struct spi_mem_op *op);
};
@@ -441,7 +460,16 @@ static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, size_t len,
return 0;
}
-static int intel_spi_read_reg(struct intel_spi *ispi,
+static u32 intel_spi_chip_addr(const struct intel_spi *ispi,
+ const struct spi_mem *mem)
+{
+ /* Pick up the correct start address */
+ if (!mem)
+ return 0;
+ return mem->spi->chip_select == 1 ? ispi->chip0_size : 0;
+}
+
+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)
{
@@ -449,8 +477,7 @@ static int intel_spi_read_reg(struct intel_spi *ispi,
u8 opcode = op->cmd.opcode;
int ret;
- /* Address of the first chip */
- writel(0, ispi->base + FADDR);
+ writel(intel_spi_chip_addr(ispi, mem), ispi->base + FADDR);
if (ispi->swseq_reg)
ret = intel_spi_sw_cycle(ispi, opcode, nbytes,
@@ -464,7 +491,7 @@ static int intel_spi_read_reg(struct intel_spi *ispi,
return intel_spi_read_block(ispi, op->data.buf.in, nbytes);
}
-static int intel_spi_write_reg(struct intel_spi *ispi,
+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)
{
@@ -511,7 +538,7 @@ static int intel_spi_write_reg(struct intel_spi *ispi,
if (opcode == SPINOR_OP_WRDI)
return 0;
- writel(0, ispi->base + FADDR);
+ writel(intel_spi_chip_addr(ispi, mem), ispi->base + FADDR);
/* Write the value beforehand */
ret = intel_spi_write_block(ispi, op->data.buf.out, nbytes);
@@ -524,13 +551,13 @@ static int intel_spi_write_reg(struct intel_spi *ispi,
return intel_spi_hw_cycle(ispi, opcode, nbytes);
}
-static int intel_spi_read(struct intel_spi *ispi,
+static int intel_spi_read(struct intel_spi *ispi, const struct spi_mem *mem,
const struct intel_spi_mem_op *iop,
const struct spi_mem_op *op)
{
- void *read_buf = op->data.buf.in;
+ u32 addr = intel_spi_chip_addr(ispi, mem) + op->addr.val;
size_t block_size, nbytes = op->data.nbytes;
- u32 addr = op->addr.val;
+ void *read_buf = op->data.buf.in;
u32 val, status;
int ret;
@@ -585,13 +612,13 @@ static int intel_spi_read(struct intel_spi *ispi,
return 0;
}
-static int intel_spi_write(struct intel_spi *ispi,
+static int intel_spi_write(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 block_size, nbytes = op->data.nbytes;
const void *write_buf = op->data.buf.out;
- u32 addr = op->addr.val;
u32 val, status;
int ret;
@@ -648,12 +675,12 @@ static int intel_spi_write(struct intel_spi *ispi,
return 0;
}
-static int intel_spi_erase(struct intel_spi *ispi,
+static int intel_spi_erase(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;
u8 opcode = op->cmd.opcode;
- u32 addr = op->addr.val;
u32 val, status;
int ret;
@@ -765,7 +792,7 @@ static int intel_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *o
if (!iop)
return -EOPNOTSUPP;
- return iop->exec_op(ispi, iop, op);
+ return iop->exec_op(ispi, mem, iop, op);
}
static const char *intel_spi_get_name(struct spi_mem *mem)
@@ -805,7 +832,7 @@ static ssize_t intel_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs,
op.data.nbytes = len;
op.data.buf.in = buf;
- ret = iop->exec_op(ispi, iop, &op);
+ ret = iop->exec_op(ispi, desc->mem, iop, &op);
return ret ? ret : len;
}
@@ -821,7 +848,7 @@ static ssize_t intel_spi_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs
op.data.nbytes = len;
op.data.buf.out = buf;
- ret = iop->exec_op(ispi, iop, &op);
+ ret = iop->exec_op(ispi, desc->mem, iop, &op);
return ret ? ret : len;
}
@@ -1073,6 +1100,7 @@ static int intel_spi_init(struct intel_spi *ispi)
ispi->pregs = ispi->base + CNL_PR;
ispi->nregions = CNL_FREG_NUM;
ispi->pr_num = CNL_PR_NUM;
+ erase_64k = true;
break;
default:
@@ -1226,10 +1254,98 @@ static void intel_spi_fill_partition(struct intel_spi *ispi,
}
}
+static int intel_spi_read_desc(struct intel_spi *ispi)
+{
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_READ, 0),
+ SPI_MEM_OP_ADDR(3, 0, 0),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_IN(0, NULL, 0));
+ u32 buf[2], nc, fcba, flcomp;
+ ssize_t ret;
+
+ op.addr.val = 0x10;
+ op.data.buf.in = buf;
+ op.data.nbytes = sizeof(buf);
+
+ ret = intel_spi_read(ispi, NULL, NULL, &op);
+ if (ret) {
+ dev_warn(ispi->dev, "failed to read descriptor\n");
+ return ret;
+ }
+
+ dev_dbg(ispi->dev, "FLVALSIG=0x%08x\n", buf[0]);
+ dev_dbg(ispi->dev, "FLMAP0=0x%08x\n", buf[1]);
+
+ if (buf[0] != FLVALSIG_MAGIC) {
+ dev_warn(ispi->dev, "descriptor signature not valid\n");
+ return -ENODEV;
+ }
+
+ fcba = (buf[1] & FLMAP0_FCBA_MASK) << 4;
+ dev_dbg(ispi->dev, "FCBA=%#x\n", fcba);
+
+ op.addr.val = fcba;
+ op.data.buf.in = &flcomp;
+ op.data.nbytes = sizeof(flcomp);
+
+ ret = intel_spi_read(ispi, NULL, NULL, &op);
+ if (ret) {
+ dev_warn(ispi->dev, "failed to read FLCOMP\n");
+ return -ENODEV;
+ }
+
+ dev_dbg(ispi->dev, "FLCOMP=0x%08x\n", flcomp);
+
+ switch (flcomp & FLCOMP_C0DEN_MASK) {
+ case FLCOMP_C0DEN_512K:
+ ispi->chip0_size = SZ_512K;
+ break;
+ case FLCOMP_C0DEN_1M:
+ ispi->chip0_size = SZ_1M;
+ break;
+ case FLCOMP_C0DEN_2M:
+ ispi->chip0_size = SZ_2M;
+ break;
+ case FLCOMP_C0DEN_4M:
+ ispi->chip0_size = SZ_4M;
+ break;
+ case FLCOMP_C0DEN_8M:
+ ispi->chip0_size = SZ_8M;
+ break;
+ case FLCOMP_C0DEN_16M:
+ ispi->chip0_size = SZ_16M;
+ break;
+ case FLCOMP_C0DEN_32M:
+ ispi->chip0_size = SZ_32M;
+ break;
+ case FLCOMP_C0DEN_64M:
+ ispi->chip0_size = SZ_64M;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(ispi->dev, "chip0 size %zd KB\n", ispi->chip0_size / SZ_1K);
+
+ nc = (buf[1] & FLMAP0_NC_MASK) >> FLMAP0_NC_SHIFT;
+ if (!nc)
+ ispi->master->num_chipselect = 1;
+ else if (nc == 1)
+ ispi->master->num_chipselect = 2;
+ else
+ return -EINVAL;
+
+ dev_dbg(ispi->dev, "%u flash components found\n",
+ ispi->master->num_chipselect);
+ return 0;
+}
+
static int intel_spi_populate_chip(struct intel_spi *ispi)
{
struct flash_platform_data *pdata;
struct spi_board_info chip;
+ int ret;
pdata = devm_kzalloc(ispi->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -1247,7 +1363,23 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
snprintf(chip.modalias, 8, "spi-nor");
chip.platform_data = pdata;
- return spi_new_device(ispi->master, &chip) ? 0 : -ENODEV;
+ if (!spi_new_device(ispi->master, &chip))
+ return -ENODEV;
+
+ /* Add the second chip if present */
+ if (ispi->master->num_chipselect < 2)
+ return 0;
+
+ ret = intel_spi_read_desc(ispi);
+ if (ret)
+ return ret;
+
+ chip.platform_data = NULL;
+ chip.chip_select = 1;
+
+ if (!spi_new_device(ispi->master, &chip))
+ return -ENODEV;
+ return 0;
}
/**
diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c
index 4d4f77a186a9..dd7de8fa37d0 100644
--- a/drivers/spi/spi-loopback-test.c
+++ b/drivers/spi/spi-loopback-test.c
@@ -313,6 +313,33 @@ static struct spi_test spi_tests[] = {
},
},
},
+ {
+ .description = "three tx+rx transfers with overlapping cache lines",
+ .fill_option = FILL_COUNT_8,
+ /*
+ * This should be large enough for the controller driver to
+ * choose to transfer it with DMA.
+ */
+ .iterate_len = { 512, -1 },
+ .iterate_transfer_mask = BIT(1),
+ .transfer_count = 3,
+ .transfers = {
+ {
+ .len = 1,
+ .tx_buf = TX(0),
+ .rx_buf = RX(0),
+ },
+ {
+ .tx_buf = TX(1),
+ .rx_buf = RX(1),
+ },
+ {
+ .len = 1,
+ .tx_buf = TX(513),
+ .rx_buf = RX(513),
+ },
+ },
+ },
{ /* end of tests sequence */ }
};
diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c
index e4cb52e1fe26..bad201510a99 100644
--- a/drivers/spi/spi-meson-spicc.c
+++ b/drivers/spi/spi-meson-spicc.c
@@ -537,7 +537,7 @@ static unsigned long meson_spicc_pow2_recalc_rate(struct clk_hw *hw,
struct clk_divider *divider = to_clk_divider(hw);
struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);
- if (!spicc->master->cur_msg || !spicc->master->busy)
+ if (!spicc->master->cur_msg)
return 0;
return clk_divider_ops.recalc_rate(hw, parent_rate);
@@ -549,7 +549,7 @@ static int meson_spicc_pow2_determine_rate(struct clk_hw *hw,
struct clk_divider *divider = to_clk_divider(hw);
struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);
- if (!spicc->master->cur_msg || !spicc->master->busy)
+ if (!spicc->master->cur_msg)
return -EINVAL;
return clk_divider_ops.determine_rate(hw, req);
@@ -561,13 +561,13 @@ static int meson_spicc_pow2_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_divider *divider = to_clk_divider(hw);
struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);
- if (!spicc->master->cur_msg || !spicc->master->busy)
+ if (!spicc->master->cur_msg)
return -EINVAL;
return clk_divider_ops.set_rate(hw, rate, parent_rate);
}
-const struct clk_ops meson_spicc_pow2_clk_ops = {
+static const struct clk_ops meson_spicc_pow2_clk_ops = {
.recalc_rate = meson_spicc_pow2_recalc_rate,
.determine_rate = meson_spicc_pow2_determine_rate,
.set_rate = meson_spicc_pow2_set_rate,
diff --git a/drivers/spi/spi-microchip-core-qspi.c b/drivers/spi/spi-microchip-core-qspi.c
new file mode 100644
index 000000000000..19a6a46829f6
--- /dev/null
+++ b/drivers/spi/spi-microchip-core-qspi.c
@@ -0,0 +1,600 @@
+// SPDX-License-Identifier: (GPL-2.0)
+/*
+ * Microchip coreQSPI QSPI controller driver
+ *
+ * Copyright (C) 2018-2022 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Naga Sureshkumar Relli <nagasuresh.relli@microchip.com>
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+
+/*
+ * QSPI Control register mask defines
+ */
+#define CONTROL_ENABLE BIT(0)
+#define CONTROL_MASTER BIT(1)
+#define CONTROL_XIP BIT(2)
+#define CONTROL_XIPADDR BIT(3)
+#define CONTROL_CLKIDLE BIT(10)
+#define CONTROL_SAMPLE_MASK GENMASK(12, 11)
+#define CONTROL_MODE0 BIT(13)
+#define CONTROL_MODE12_MASK GENMASK(15, 14)
+#define CONTROL_MODE12_EX_RO BIT(14)
+#define CONTROL_MODE12_EX_RW BIT(15)
+#define CONTROL_MODE12_FULL GENMASK(15, 14)
+#define CONTROL_FLAGSX4 BIT(16)
+#define CONTROL_CLKRATE_MASK GENMASK(27, 24)
+#define CONTROL_CLKRATE_SHIFT 24
+
+/*
+ * QSPI Frames register mask defines
+ */
+#define FRAMES_TOTALBYTES_MASK GENMASK(15, 0)
+#define FRAMES_CMDBYTES_MASK GENMASK(24, 16)
+#define FRAMES_CMDBYTES_SHIFT 16
+#define FRAMES_SHIFT 25
+#define FRAMES_IDLE_MASK GENMASK(29, 26)
+#define FRAMES_IDLE_SHIFT 26
+#define FRAMES_FLAGBYTE BIT(30)
+#define FRAMES_FLAGWORD BIT(31)
+
+/*
+ * QSPI Interrupt Enable register mask defines
+ */
+#define IEN_TXDONE BIT(0)
+#define IEN_RXDONE BIT(1)
+#define IEN_RXAVAILABLE BIT(2)
+#define IEN_TXAVAILABLE BIT(3)
+#define IEN_RXFIFOEMPTY BIT(4)
+#define IEN_TXFIFOFULL BIT(5)
+
+/*
+ * QSPI Status register mask defines
+ */
+#define STATUS_TXDONE BIT(0)
+#define STATUS_RXDONE BIT(1)
+#define STATUS_RXAVAILABLE BIT(2)
+#define STATUS_TXAVAILABLE BIT(3)
+#define STATUS_RXFIFOEMPTY BIT(4)
+#define STATUS_TXFIFOFULL BIT(5)
+#define STATUS_READY BIT(7)
+#define STATUS_FLAGSX4 BIT(8)
+#define STATUS_MASK GENMASK(8, 0)
+
+#define BYTESUPPER_MASK GENMASK(31, 16)
+#define BYTESLOWER_MASK GENMASK(15, 0)
+
+#define MAX_DIVIDER 16
+#define MIN_DIVIDER 0
+#define MAX_DATA_CMD_LEN 256
+
+/* QSPI ready time out value */
+#define TIMEOUT_MS 500
+
+/*
+ * QSPI Register offsets.
+ */
+#define REG_CONTROL (0x00)
+#define REG_FRAMES (0x04)
+#define REG_IEN (0x0c)
+#define REG_STATUS (0x10)
+#define REG_DIRECT_ACCESS (0x14)
+#define REG_UPPER_ACCESS (0x18)
+#define REG_RX_DATA (0x40)
+#define REG_TX_DATA (0x44)
+#define REG_X4_RX_DATA (0x48)
+#define REG_X4_TX_DATA (0x4c)
+#define REG_FRAMESUP (0x50)
+
+/**
+ * struct mchp_coreqspi - Defines qspi driver instance
+ * @regs: Virtual address of the QSPI controller registers
+ * @clk: QSPI Operating clock
+ * @data_completion: completion structure
+ * @op_lock: lock access to the device
+ * @txbuf: TX buffer
+ * @rxbuf: RX buffer
+ * @irq: IRQ number
+ * @tx_len: Number of bytes left to transfer
+ * @rx_len: Number of bytes left to receive
+ */
+struct mchp_coreqspi {
+ void __iomem *regs;
+ struct clk *clk;
+ struct completion data_completion;
+ struct mutex op_lock; /* lock access to the device */
+ u8 *txbuf;
+ u8 *rxbuf;
+ int irq;
+ int tx_len;
+ int rx_len;
+};
+
+static int mchp_coreqspi_set_mode(struct mchp_coreqspi *qspi, const struct spi_mem_op *op)
+{
+ u32 control = readl_relaxed(qspi->regs + REG_CONTROL);
+
+ /*
+ * The operating mode can be configured based on the command that needs to be send.
+ * bits[15:14]: Sets whether multiple bit SPI operates in normal, extended or full modes.
+ * 00: Normal (single DQ0 TX and single DQ1 RX lines)
+ * 01: Extended RO (command and address bytes on DQ0 only)
+ * 10: Extended RW (command byte on DQ0 only)
+ * 11: Full. (command and address are on all DQ lines)
+ * bit[13]: Sets whether multiple bit SPI uses 2 or 4 bits of data
+ * 0: 2-bits (BSPI)
+ * 1: 4-bits (QSPI)
+ */
+ if (op->data.buswidth == 4 || op->data.buswidth == 2) {
+ control &= ~CONTROL_MODE12_MASK;
+ if (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || op->addr.buswidth == 0))
+ control |= CONTROL_MODE12_EX_RO;
+ else if (op->cmd.buswidth == 1)
+ control |= CONTROL_MODE12_EX_RW;
+ else
+ control |= CONTROL_MODE12_FULL;
+
+ control |= CONTROL_MODE0;
+ } else {
+ control &= ~(CONTROL_MODE12_MASK |
+ CONTROL_MODE0);
+ }
+
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ return 0;
+}
+
+static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi)
+{
+ u32 control, data;
+
+ if (!qspi->rx_len)
+ return;
+
+ control = readl_relaxed(qspi->regs + REG_CONTROL);
+
+ /*
+ * Read 4-bytes from the SPI FIFO in single transaction and then read
+ * the reamaining data byte wise.
+ */
+ control |= CONTROL_FLAGSX4;
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ while (qspi->rx_len >= 4) {
+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY)
+ ;
+ data = readl_relaxed(qspi->regs + REG_X4_RX_DATA);
+ *(u32 *)qspi->rxbuf = data;
+ qspi->rxbuf += 4;
+ qspi->rx_len -= 4;
+ }
+
+ control &= ~CONTROL_FLAGSX4;
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ while (qspi->rx_len--) {
+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY)
+ ;
+ data = readl_relaxed(qspi->regs + REG_RX_DATA);
+ *qspi->rxbuf++ = (data & 0xFF);
+ }
+}
+
+static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word)
+{
+ u32 control, data;
+
+ control = readl_relaxed(qspi->regs + REG_CONTROL);
+ control |= CONTROL_FLAGSX4;
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ while (qspi->tx_len >= 4) {
+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL)
+ ;
+ data = *(u32 *)qspi->txbuf;
+ qspi->txbuf += 4;
+ qspi->tx_len -= 4;
+ writel_relaxed(data, qspi->regs + REG_X4_TX_DATA);
+ }
+
+ control &= ~CONTROL_FLAGSX4;
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ while (qspi->tx_len--) {
+ while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL)
+ ;
+ data = *qspi->txbuf++;
+ writel_relaxed(data, qspi->regs + REG_TX_DATA);
+ }
+}
+
+static void mchp_coreqspi_enable_ints(struct mchp_coreqspi *qspi)
+{
+ u32 mask = IEN_TXDONE |
+ IEN_RXDONE |
+ IEN_RXAVAILABLE;
+
+ writel_relaxed(mask, qspi->regs + REG_IEN);
+}
+
+static void mchp_coreqspi_disable_ints(struct mchp_coreqspi *qspi)
+{
+ writel_relaxed(0, qspi->regs + REG_IEN);
+}
+
+static irqreturn_t mchp_coreqspi_isr(int irq, void *dev_id)
+{
+ struct mchp_coreqspi *qspi = (struct mchp_coreqspi *)dev_id;
+ irqreturn_t ret = IRQ_NONE;
+ int intfield = readl_relaxed(qspi->regs + REG_STATUS) & STATUS_MASK;
+
+ if (intfield == 0)
+ return ret;
+
+ if (intfield & IEN_TXDONE) {
+ writel_relaxed(IEN_TXDONE, qspi->regs + REG_STATUS);
+ ret = IRQ_HANDLED;
+ }
+
+ if (intfield & IEN_RXAVAILABLE) {
+ writel_relaxed(IEN_RXAVAILABLE, qspi->regs + REG_STATUS);
+ mchp_coreqspi_read_op(qspi);
+ ret = IRQ_HANDLED;
+ }
+
+ if (intfield & IEN_RXDONE) {
+ writel_relaxed(IEN_RXDONE, qspi->regs + REG_STATUS);
+ complete(&qspi->data_completion);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi)
+{
+ unsigned long clk_hz;
+ u32 control, baud_rate_val = 0;
+
+ clk_hz = clk_get_rate(qspi->clk);
+ if (!clk_hz)
+ return -EINVAL;
+
+ baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * spi->max_speed_hz);
+ 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);
+ return -EINVAL;
+ }
+
+ control = readl_relaxed(qspi->regs + REG_CONTROL);
+ control |= baud_rate_val << CONTROL_CLKRATE_SHIFT;
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+ control = readl_relaxed(qspi->regs + REG_CONTROL);
+
+ if ((spi->mode & SPI_CPOL) && (spi->mode & SPI_CPHA))
+ control |= CONTROL_CLKIDLE;
+ else
+ control &= ~CONTROL_CLKIDLE;
+
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ return 0;
+}
+
+static int mchp_coreqspi_setup_op(struct spi_device *spi_dev)
+{
+ struct spi_controller *ctlr = spi_dev->master;
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
+ u32 control = readl_relaxed(qspi->regs + REG_CONTROL);
+
+ control |= (CONTROL_MASTER | CONTROL_ENABLE);
+ control &= ~CONTROL_CLKIDLE;
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+
+ return 0;
+}
+
+static inline void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, const struct spi_mem_op *op)
+{
+ u32 idle_cycles = 0;
+ int total_bytes, cmd_bytes, frames, ctrl;
+
+ cmd_bytes = op->cmd.nbytes + op->addr.nbytes;
+ total_bytes = cmd_bytes + op->data.nbytes;
+
+ /*
+ * As per the coreQSPI IP spec,the number of command and data bytes are
+ * controlled by the frames register for each SPI sequence. This supports
+ * the SPI flash memory read and writes sequences as below. so configure
+ * the cmd and total bytes accordingly.
+ * ---------------------------------------------------------------------
+ * TOTAL BYTES | CMD BYTES | What happens |
+ * ______________________________________________________________________
+ * | | |
+ * 1 | 1 | The SPI core will transmit a single byte |
+ * | | and receive data is discarded |
+ * | | |
+ * 1 | 0 | The SPI core will transmit a single byte |
+ * | | and return a single byte |
+ * | | |
+ * 10 | 4 | The SPI core will transmit 4 command |
+ * | | bytes discarding the receive data and |
+ * | | transmits 6 dummy bytes returning the 6 |
+ * | | received bytes and return a single byte |
+ * | | |
+ * 10 | 10 | The SPI core will transmit 10 command |
+ * | | |
+ * 10 | 0 | The SPI core will transmit 10 command |
+ * | | bytes and returning 10 received bytes |
+ * ______________________________________________________________________
+ */
+ if (!(op->data.dir == SPI_MEM_DATA_IN))
+ cmd_bytes = total_bytes;
+
+ frames = total_bytes & BYTESUPPER_MASK;
+ writel_relaxed(frames, qspi->regs + REG_FRAMESUP);
+ frames = total_bytes & BYTESLOWER_MASK;
+ frames |= cmd_bytes << FRAMES_CMDBYTES_SHIFT;
+
+ if (op->dummy.buswidth)
+ idle_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth;
+
+ frames |= idle_cycles << FRAMES_IDLE_SHIFT;
+ ctrl = readl_relaxed(qspi->regs + REG_CONTROL);
+
+ if (ctrl & CONTROL_MODE12_MASK)
+ frames |= (1 << FRAMES_SHIFT);
+
+ frames |= FRAMES_FLAGWORD;
+ writel_relaxed(frames, qspi->regs + REG_FRAMES);
+}
+
+static int mchp_qspi_wait_for_ready(struct spi_mem *mem)
+{
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata
+ (mem->spi->master);
+ u32 status;
+ int ret;
+
+ ret = readl_poll_timeout(qspi->regs + REG_STATUS, status,
+ (status & STATUS_READY), 0,
+ TIMEOUT_MS);
+ if (ret) {
+ dev_err(&mem->spi->dev,
+ "Timeout waiting on QSPI ready.\n");
+ return -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ struct mchp_coreqspi *qspi = spi_controller_get_devdata
+ (mem->spi->master);
+ u32 address = op->addr.val;
+ u8 opcode = op->cmd.opcode;
+ u8 opaddr[5];
+ int err, i;
+
+ mutex_lock(&qspi->op_lock);
+ err = mchp_qspi_wait_for_ready(mem);
+ if (err)
+ goto error;
+
+ err = mchp_coreqspi_setup_clock(qspi, mem->spi);
+ if (err)
+ goto error;
+
+ err = mchp_coreqspi_set_mode(qspi, op);
+ if (err)
+ goto error;
+
+ reinit_completion(&qspi->data_completion);
+ mchp_coreqspi_config_op(qspi, op);
+ if (op->cmd.opcode) {
+ qspi->txbuf = &opcode;
+ qspi->rxbuf = NULL;
+ qspi->tx_len = op->cmd.nbytes;
+ qspi->rx_len = 0;
+ mchp_coreqspi_write_op(qspi, false);
+ }
+
+ qspi->txbuf = &opaddr[0];
+ if (op->addr.nbytes) {
+ for (i = 0; i < op->addr.nbytes; i++)
+ qspi->txbuf[i] = address >> (8 * (op->addr.nbytes - i - 1));
+
+ qspi->rxbuf = NULL;
+ qspi->tx_len = op->addr.nbytes;
+ qspi->rx_len = 0;
+ mchp_coreqspi_write_op(qspi, false);
+ }
+
+ if (op->data.nbytes) {
+ if (op->data.dir == SPI_MEM_DATA_OUT) {
+ qspi->txbuf = (u8 *)op->data.buf.out;
+ qspi->rxbuf = NULL;
+ qspi->rx_len = 0;
+ qspi->tx_len = op->data.nbytes;
+ mchp_coreqspi_write_op(qspi, true);
+ } else {
+ qspi->txbuf = NULL;
+ qspi->rxbuf = (u8 *)op->data.buf.in;
+ qspi->rx_len = op->data.nbytes;
+ qspi->tx_len = 0;
+ }
+ }
+
+ mchp_coreqspi_enable_ints(qspi);
+
+ if (!wait_for_completion_timeout(&qspi->data_completion, msecs_to_jiffies(1000)))
+ err = -ETIMEDOUT;
+
+error:
+ mutex_unlock(&qspi->op_lock);
+ mchp_coreqspi_disable_ints(qspi);
+
+ return err;
+}
+
+static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ if (!spi_mem_default_supports_op(mem, op))
+ return false;
+
+ if ((op->data.buswidth == 4 || op->data.buswidth == 2) &&
+ (op->cmd.buswidth == 1 && (op->addr.buswidth == 1 || op->addr.buswidth == 0))) {
+ /*
+ * If the command and address are on DQ0 only, then this
+ * controller doesn't support sending data on dual and
+ * quad lines. but it supports reading data on dual and
+ * quad lines with same configuration as command and
+ * address on DQ0.
+ * i.e. The control register[15:13] :EX_RO(read only) is
+ * meant only for the command and address are on DQ0 but
+ * not to write data, it is just to read.
+ * Ex: 0x34h is Quad Load Program Data which is not
+ * supported. Then the spi-mem layer will iterate over
+ * each command and it will chose the supported one.
+ */
+ if (op->data.dir == SPI_MEM_DATA_OUT)
+ return false;
+ }
+
+ return true;
+}
+
+static int mchp_coreqspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+ if (op->data.dir == SPI_MEM_DATA_OUT || op->data.dir == SPI_MEM_DATA_IN) {
+ if (op->data.nbytes > MAX_DATA_CMD_LEN)
+ op->data.nbytes = MAX_DATA_CMD_LEN;
+ }
+
+ return 0;
+}
+
+static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = {
+ .adjust_op_size = mchp_coreqspi_adjust_op_size,
+ .supports_op = mchp_coreqspi_supports_op,
+ .exec_op = mchp_coreqspi_exec_op,
+};
+
+static int mchp_coreqspi_probe(struct platform_device *pdev)
+{
+ struct spi_controller *ctlr;
+ struct mchp_coreqspi *qspi;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*qspi));
+ if (!ctlr)
+ return dev_err_probe(&pdev->dev, -ENOMEM,
+ "unable to allocate master for QSPI controller\n");
+
+ qspi = spi_controller_get_devdata(ctlr);
+ platform_set_drvdata(pdev, qspi);
+
+ qspi->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(qspi->regs))
+ return dev_err_probe(&pdev->dev, PTR_ERR(qspi->regs),
+ "failed to map registers\n");
+
+ qspi->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(qspi->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(qspi->clk),
+ "could not get clock\n");
+
+ ret = clk_prepare_enable(qspi->clk);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to enable clock\n");
+
+ init_completion(&qspi->data_completion);
+ mutex_init(&qspi->op_lock);
+
+ qspi->irq = platform_get_irq(pdev, 0);
+ if (qspi->irq < 0) {
+ ret = qspi->irq;
+ goto out;
+ }
+
+ ret = devm_request_irq(&pdev->dev, qspi->irq, mchp_coreqspi_isr,
+ IRQF_SHARED, pdev->name, qspi);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed %d\n", ret);
+ goto out;
+ }
+
+ ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
+ ctlr->mem_ops = &mchp_coreqspi_mem_ops;
+ ctlr->setup = mchp_coreqspi_setup_op;
+ ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
+ SPI_TX_DUAL | SPI_TX_QUAD;
+ ctlr->dev.of_node = np;
+
+ ret = devm_spi_register_controller(&pdev->dev, ctlr);
+ if (ret) {
+ dev_err_probe(&pdev->dev, ret,
+ "spi_register_controller failed\n");
+ goto out;
+ }
+
+ return 0;
+
+out:
+ clk_disable_unprepare(qspi->clk);
+
+ return ret;
+}
+
+static int mchp_coreqspi_remove(struct platform_device *pdev)
+{
+ struct mchp_coreqspi *qspi = platform_get_drvdata(pdev);
+ u32 control = readl_relaxed(qspi->regs + REG_CONTROL);
+
+ mchp_coreqspi_disable_ints(qspi);
+ control &= ~CONTROL_ENABLE;
+ writel_relaxed(control, qspi->regs + REG_CONTROL);
+ clk_disable_unprepare(qspi->clk);
+
+ return 0;
+}
+
+static const struct of_device_id mchp_coreqspi_of_match[] = {
+ { .compatible = "microchip,coreqspi-rtl-v2" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mchp_coreqspi_of_match);
+
+static struct platform_driver mchp_coreqspi_driver = {
+ .probe = mchp_coreqspi_probe,
+ .driver = {
+ .name = "microchip,coreqspi",
+ .of_match_table = mchp_coreqspi_of_match,
+ },
+ .remove = mchp_coreqspi_remove,
+};
+module_platform_driver(mchp_coreqspi_driver);
+
+MODULE_AUTHOR("Naga Sureshkumar Relli <nagasuresh.relli@microchip.com");
+MODULE_DESCRIPTION("Microchip coreQSPI QSPI controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-microchip-core.c b/drivers/spi/spi-microchip-core.c
index ce4385330b19..d352844c798c 100644
--- a/drivers/spi/spi-microchip-core.c
+++ b/drivers/spi/spi-microchip-core.c
@@ -548,12 +548,12 @@ static int mchp_corespi_probe(struct platform_device *pdev)
IRQF_SHARED, dev_name(&pdev->dev), master);
if (ret)
return dev_err_probe(&pdev->dev, ret,
- "could not request irq: %d\n", ret);
+ "could not request irq\n");
spi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(spi->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk),
- "could not get clk: %d\n", ret);
+ "could not get clk\n");
ret = clk_prepare_enable(spi->clk);
if (ret)
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index bc5e36fd4288..cb075c1acbee 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -11,13 +11,14 @@
*/
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/of_platform.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/io.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -89,7 +90,7 @@ struct mpc52xx_spi {
const u8 *tx_buf;
int cs_change;
int gpio_cs_count;
- unsigned int *gpio_cs;
+ struct gpio_desc **gpio_cs;
};
/*
@@ -101,9 +102,10 @@ static void mpc52xx_spi_chipsel(struct mpc52xx_spi *ms, int value)
if (ms->gpio_cs_count > 0) {
cs = ms->message->spi->chip_select;
- gpio_set_value(ms->gpio_cs[cs], value ? 0 : 1);
- } else
+ gpiod_set_value(ms->gpio_cs[cs], value);
+ } else {
out_8(ms->regs + SPI_PORTDATA, value ? 0 : 0x08);
+ }
}
/*
@@ -385,10 +387,10 @@ static int mpc52xx_spi_probe(struct platform_device *op)
{
struct spi_master *master;
struct mpc52xx_spi *ms;
+ struct gpio_desc *gpio_cs;
void __iomem *regs;
u8 ctrl1;
int rc, i = 0;
- int gpio_cs;
/* MMIO registers */
dev_dbg(&op->dev, "probing mpc5200 SPI device\n");
@@ -438,7 +440,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
ms->irq1 = irq_of_parse_and_map(op->dev.of_node, 1);
ms->state = mpc52xx_spi_fsmstate_idle;
ms->ipb_freq = mpc5xxx_get_bus_frequency(&op->dev);
- ms->gpio_cs_count = of_gpio_count(op->dev.of_node);
+ ms->gpio_cs_count = gpiod_count(&op->dev, NULL);
if (ms->gpio_cs_count > 0) {
master->num_chipselect = ms->gpio_cs_count;
ms->gpio_cs = kmalloc_array(ms->gpio_cs_count,
@@ -450,23 +452,16 @@ static int mpc52xx_spi_probe(struct platform_device *op)
}
for (i = 0; i < ms->gpio_cs_count; i++) {
- gpio_cs = of_get_gpio(op->dev.of_node, i);
- if (!gpio_is_valid(gpio_cs)) {
- dev_err(&op->dev,
- "could not parse the gpio field in oftree\n");
- rc = -ENODEV;
- goto err_gpio;
- }
-
- rc = gpio_request(gpio_cs, dev_name(&op->dev));
+ gpio_cs = gpiod_get_index(&op->dev,
+ NULL, i, GPIOD_OUT_LOW);
+ rc = PTR_ERR_OR_ZERO(gpio_cs);
if (rc) {
dev_err(&op->dev,
- "can't request spi cs gpio #%d on gpio line %d\n",
- i, gpio_cs);
+ "failed to get spi cs gpio #%d: %d\n",
+ i, rc);
goto err_gpio;
}
- gpio_direction_output(gpio_cs, 1);
ms->gpio_cs[i] = gpio_cs;
}
}
@@ -507,7 +502,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
dev_err(&ms->master->dev, "initialization failed\n");
err_gpio:
while (i-- > 0)
- gpio_free(ms->gpio_cs[i]);
+ gpiod_put(ms->gpio_cs[i]);
kfree(ms->gpio_cs);
err_alloc_gpio:
@@ -528,7 +523,7 @@ static int mpc52xx_spi_remove(struct platform_device *op)
free_irq(ms->irq1, ms);
for (i = 0; i < ms->gpio_cs_count; i++)
- gpio_free(ms->gpio_cs[i]);
+ gpiod_put(ms->gpio_cs[i]);
kfree(ms->gpio_cs);
spi_unregister_master(master);
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 0a3b9f7eed30..11aeae7fe7fc 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -1184,6 +1184,11 @@ static int mtk_spi_probe(struct platform_device *pdev)
if (!dev->dma_mask)
dev->dma_mask = &dev->coherent_dma_mask;
+ if (mdata->dev_comp->ipm_design)
+ dma_set_max_seg_size(dev, SZ_16M);
+ else
+ dma_set_max_seg_size(dev, SZ_256K);
+
ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
IRQF_TRIGGER_NONE, dev_name(dev), master);
if (ret)
diff --git a/drivers/spi/spi-mt7621.c b/drivers/spi/spi-mt7621.c
index b4b9b7309b5e..c4cc8e2f85e2 100644
--- a/drivers/spi/spi-mt7621.c
+++ b/drivers/spi/spi-mt7621.c
@@ -55,7 +55,6 @@ struct mt7621_spi {
void __iomem *base;
unsigned int sys_freq;
unsigned int speed;
- struct clk *clk;
int pending_write;
};
@@ -327,7 +326,6 @@ static int mt7621_spi_probe(struct platform_device *pdev)
struct spi_controller *master;
struct mt7621_spi *rs;
void __iomem *base;
- int status = 0;
struct clk *clk;
int ret;
@@ -339,21 +337,14 @@ static int mt7621_spi_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
- clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(clk)) {
- dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n",
- status);
- return PTR_ERR(clk);
- }
-
- status = clk_prepare_enable(clk);
- if (status)
- return status;
+ clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk),
+ "unable to get SYS clock\n");
master = devm_spi_alloc_master(&pdev->dev, sizeof(*rs));
if (!master) {
dev_info(&pdev->dev, "master allocation failed\n");
- clk_disable_unprepare(clk);
return -ENOMEM;
}
@@ -369,38 +360,18 @@ static int mt7621_spi_probe(struct platform_device *pdev)
rs = spi_controller_get_devdata(master);
rs->base = base;
- rs->clk = clk;
rs->master = master;
- rs->sys_freq = clk_get_rate(rs->clk);
+ rs->sys_freq = clk_get_rate(clk);
rs->pending_write = 0;
dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
ret = device_reset(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "SPI reset failed!\n");
- clk_disable_unprepare(clk);
return ret;
}
- ret = spi_register_controller(master);
- if (ret)
- clk_disable_unprepare(clk);
-
- return ret;
-}
-
-static int mt7621_spi_remove(struct platform_device *pdev)
-{
- struct spi_controller *master;
- struct mt7621_spi *rs;
-
- master = dev_get_drvdata(&pdev->dev);
- rs = spi_controller_get_devdata(master);
-
- spi_unregister_controller(master);
- clk_disable_unprepare(rs->clk);
-
- return 0;
+ return devm_spi_register_controller(&pdev->dev, master);
}
MODULE_ALIAS("platform:" DRIVER_NAME);
@@ -411,7 +382,6 @@ static struct platform_driver mt7621_spi_driver = {
.of_match_table = mt7621_spi_match,
},
.probe = mt7621_spi_probe,
- .remove = mt7621_spi_remove,
};
module_platform_driver(mt7621_spi_driver);
diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c
index 1668a347e003..7f2e4d1b0d43 100644
--- a/drivers/spi/spi-npcm-pspi.c
+++ b/drivers/spi/spi-npcm-pspi.c
@@ -443,6 +443,7 @@ static int npcm_pspi_remove(struct platform_device *pdev)
static const struct of_device_id npcm_pspi_match[] = {
{ .compatible = "nuvoton,npcm750-pspi", .data = NULL },
+ { .compatible = "nuvoton,npcm845-pspi", .data = NULL },
{}
};
MODULE_DEVICE_TABLE(of, npcm_pspi_match);
diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 2b0301fc971c..d6a65a989ef8 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -588,7 +588,7 @@ static int nxp_fspi_clk_prep_enable(struct nxp_fspi *f)
{
int ret;
- if (is_acpi_node(f->dev->fwnode))
+ if (is_acpi_node(dev_fwnode(f->dev)))
return 0;
ret = clk_prepare_enable(f->clk_en);
@@ -606,7 +606,7 @@ static int nxp_fspi_clk_prep_enable(struct nxp_fspi *f)
static int nxp_fspi_clk_disable_unprep(struct nxp_fspi *f)
{
- if (is_acpi_node(f->dev->fwnode))
+ if (is_acpi_node(dev_fwnode(f->dev)))
return 0;
clk_disable_unprepare(f->clk);
@@ -1100,7 +1100,7 @@ static int nxp_fspi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, f);
/* find the resources - configuration register address space */
- if (is_acpi_node(f->dev->fwnode))
+ if (is_acpi_node(dev_fwnode(f->dev)))
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
else
res = platform_get_resource_byname(pdev,
@@ -1113,7 +1113,7 @@ static int nxp_fspi_probe(struct platform_device *pdev)
}
/* find the resources - controller memory mapped space */
- if (is_acpi_node(f->dev->fwnode))
+ if (is_acpi_node(dev_fwnode(f->dev)))
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
else
res = platform_get_resource_byname(pdev,
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 20b047172965..061f7394e5b9 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -412,6 +412,7 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
return status;
err_fck:
+ pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(spi100k->fck);
err_ick:
clk_disable_unprepare(spi100k->ick);
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index c42e59df38fe..6ba9b0d7710b 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -1509,10 +1509,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
}
status = platform_get_irq(pdev, 0);
- if (status == -EPROBE_DEFER)
- goto free_master;
if (status < 0) {
- dev_err(&pdev->dev, "no irq resource found\n");
+ dev_err_probe(&pdev->dev, status, "no irq resource found\n");
goto free_master;
}
init_completion(&mcspi->txdone);
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index c8e079d7e541..2bf21c2e7a52 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -1856,10 +1856,8 @@ static int pxa2xx_spi_runtime_suspend(struct device *dev)
static int pxa2xx_spi_runtime_resume(struct device *dev)
{
struct driver_data *drv_data = dev_get_drvdata(dev);
- int status;
- status = clk_prepare_enable(drv_data->ssp->clk);
- return status;
+ return clk_prepare_enable(drv_data->ssp->clk);
}
#endif
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index 00d6084306b4..7d89510dc3f0 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -1198,8 +1198,10 @@ static int spi_qup_pm_resume_runtime(struct device *device)
return ret;
ret = clk_prepare_enable(controller->cclk);
- if (ret)
+ if (ret) {
+ clk_disable_unprepare(controller->iclk);
return ret;
+ }
/* Disable clocks auto gaiting */
config = readl_relaxed(controller->base + QUP_CONFIG);
@@ -1245,14 +1247,25 @@ static int spi_qup_resume(struct device *device)
return ret;
ret = clk_prepare_enable(controller->cclk);
- if (ret)
+ if (ret) {
+ clk_disable_unprepare(controller->iclk);
return ret;
+ }
ret = spi_qup_set_state(controller, QUP_STATE_RESET);
if (ret)
- return ret;
+ goto disable_clk;
- return spi_master_resume(master);
+ ret = spi_master_resume(master);
+ if (ret)
+ goto disable_clk;
+
+ return 0;
+
+disable_clk:
+ clk_disable_unprepare(controller->cclk);
+ clk_disable_unprepare(controller->iclk);
+ return ret;
}
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c
index 660aa866af06..ef25b5e93900 100644
--- a/drivers/spi/spi-s3c24xx.c
+++ b/drivers/spi/spi-s3c24xx.c
@@ -449,7 +449,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
struct spi_master *master;
int err = 0;
- master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
if (master == NULL) {
dev_err(&pdev->dev, "No memory for spi_master\n");
return -ENOMEM;
@@ -463,8 +463,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
if (pdata == NULL) {
dev_err(&pdev->dev, "No platform data supplied\n");
- err = -ENOENT;
- goto err_no_pdata;
+ return -ENOENT;
}
platform_set_drvdata(pdev, hw);
@@ -499,29 +498,24 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
/* find and map our resources */
hw->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(hw->regs)) {
- err = PTR_ERR(hw->regs);
- goto err_no_pdata;
- }
+ if (IS_ERR(hw->regs))
+ return PTR_ERR(hw->regs);
hw->irq = platform_get_irq(pdev, 0);
- if (hw->irq < 0) {
- err = -ENOENT;
- goto err_no_pdata;
- }
+ if (hw->irq < 0)
+ return -ENOENT;
err = devm_request_irq(&pdev->dev, hw->irq, s3c24xx_spi_irq, 0,
pdev->name, hw);
if (err) {
dev_err(&pdev->dev, "Cannot claim IRQ\n");
- goto err_no_pdata;
+ return err;
}
hw->clk = devm_clk_get(&pdev->dev, "spi");
if (IS_ERR(hw->clk)) {
dev_err(&pdev->dev, "No clock for device\n");
- err = PTR_ERR(hw->clk);
- goto err_no_pdata;
+ return PTR_ERR(hw->clk);
}
s3c24xx_spi_initialsetup(hw);
@@ -539,8 +533,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
err_register:
clk_disable(hw->clk);
- err_no_pdata:
- spi_master_put(hw->master);
return err;
}
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 7f346866614a..71d324ec9a70 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -84,6 +84,7 @@
#define S3C64XX_SPI_ST_TX_FIFORDY (1<<0)
#define S3C64XX_SPI_PACKET_CNT_EN (1<<16)
+#define S3C64XX_SPI_PACKET_CNT_MASK GENMASK(15, 0)
#define S3C64XX_SPI_PND_TX_UNDERRUN_CLR (1<<4)
#define S3C64XX_SPI_PND_TX_OVERRUN_CLR (1<<3)
@@ -389,8 +390,8 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
if (sdd->rx_dma.ch && sdd->tx_dma.ch) {
dma_release_channel(sdd->rx_dma.ch);
dma_release_channel(sdd->tx_dma.ch);
- sdd->rx_dma.ch = 0;
- sdd->tx_dma.ch = 0;
+ sdd->rx_dma.ch = NULL;
+ sdd->tx_dma.ch = NULL;
}
return 0;
@@ -711,6 +712,13 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
return 0;
}
+static size_t s3c64xx_spi_max_transfer_size(struct spi_device *spi)
+{
+ struct spi_controller *ctlr = spi->controller;
+
+ return ctlr->can_dma ? S3C64XX_SPI_PACKET_CNT_MASK : SIZE_MAX;
+}
+
static int s3c64xx_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
@@ -1152,6 +1160,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
master->prepare_message = s3c64xx_spi_prepare_message;
master->transfer_one = s3c64xx_spi_transfer_one;
+ master->max_transfer_size = s3c64xx_spi_max_transfer_size;
master->num_chipselect = sci->num_cs;
master->use_gpio_descriptors = true;
master->dma_alignment = 8;
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index d0012b30410c..9bca3d076f05 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -1085,6 +1085,7 @@ static const struct of_device_id sh_msiof_match[] = {
{ .compatible = "renesas,rcar-gen2-msiof", .data = &rcar_gen2_data },
{ .compatible = "renesas,msiof-r8a7796", .data = &rcar_gen3_data },
{ .compatible = "renesas,rcar-gen3-msiof", .data = &rcar_gen3_data },
+ { .compatible = "renesas,rcar-gen4-msiof", .data = &rcar_gen3_data },
{ .compatible = "renesas,sh-msiof", .data = &sh_data }, /* Deprecated */
{},
};
diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c
index f3fe92300639..9131660c1afb 100644
--- a/drivers/spi/spi-stm32-qspi.c
+++ b/drivers/spi/spi-stm32-qspi.c
@@ -15,6 +15,7 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
@@ -355,10 +356,10 @@ static int stm32_qspi_get_mode(u8 buswidth)
return buswidth;
}
-static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
+static int stm32_qspi_send(struct spi_device *spi, const struct spi_mem_op *op)
{
- struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
- struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select];
+ struct stm32_qspi *qspi = spi_controller_get_devdata(spi->master);
+ struct stm32_qspi_flash *flash = &qspi->flash[spi->chip_select];
u32 ccr, cr;
int timeout, err = 0, err_poll_status = 0;
@@ -465,7 +466,7 @@ static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *
qspi->fmode = CCR_FMODE_APM;
qspi->status_timeout = timeout_ms;
- ret = stm32_qspi_send(mem, op);
+ ret = stm32_qspi_send(mem->spi, op);
mutex_unlock(&qspi->lock);
pm_runtime_mark_last_busy(qspi->dev);
@@ -489,7 +490,7 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
else
qspi->fmode = CCR_FMODE_INDW;
- ret = stm32_qspi_send(mem, op);
+ ret = stm32_qspi_send(mem->spi, op);
mutex_unlock(&qspi->lock);
pm_runtime_mark_last_busy(qspi->dev);
@@ -545,7 +546,7 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc,
else
qspi->fmode = CCR_FMODE_INDR;
- ret = stm32_qspi_send(desc->mem, &op);
+ ret = stm32_qspi_send(desc->mem->spi, &op);
mutex_unlock(&qspi->lock);
pm_runtime_mark_last_busy(qspi->dev);
@@ -554,12 +555,96 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc,
return ret ?: len;
}
+static int stm32_qspi_transfer_one_message(struct spi_controller *ctrl,
+ struct spi_message *msg)
+{
+ struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl);
+ struct spi_transfer *transfer;
+ struct spi_device *spi = msg->spi;
+ struct spi_mem_op op;
+ int ret = 0;
+
+ if (!spi->cs_gpiod)
+ return -EOPNOTSUPP;
+
+ ret = pm_runtime_resume_and_get(qspi->dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&qspi->lock);
+
+ gpiod_set_value_cansleep(spi->cs_gpiod, true);
+
+ list_for_each_entry(transfer, &msg->transfers, transfer_list) {
+ u8 dummy_bytes = 0;
+
+ memset(&op, 0, sizeof(op));
+
+ dev_dbg(qspi->dev, "tx_buf:%p tx_nbits:%d rx_buf:%p rx_nbits:%d len:%d dummy_data:%d\n",
+ transfer->tx_buf, transfer->tx_nbits,
+ transfer->rx_buf, transfer->rx_nbits,
+ transfer->len, transfer->dummy_data);
+
+ /*
+ * QSPI hardware supports dummy bytes transfer.
+ * If current transfer is dummy byte, merge it with the next
+ * transfer in order to take into account QSPI block constraint
+ */
+ if (transfer->dummy_data) {
+ op.dummy.buswidth = transfer->tx_nbits;
+ op.dummy.nbytes = transfer->len;
+ dummy_bytes = transfer->len;
+
+ /* if happens, means that message is not correctly built */
+ if (list_is_last(&transfer->transfer_list, &msg->transfers)) {
+ ret = -EINVAL;
+ goto end_of_transfer;
+ }
+
+ transfer = list_next_entry(transfer, transfer_list);
+ }
+
+ op.data.nbytes = transfer->len;
+
+ if (transfer->rx_buf) {
+ qspi->fmode = CCR_FMODE_INDR;
+ op.data.buswidth = transfer->rx_nbits;
+ op.data.dir = SPI_MEM_DATA_IN;
+ op.data.buf.in = transfer->rx_buf;
+ } else {
+ qspi->fmode = CCR_FMODE_INDW;
+ op.data.buswidth = transfer->tx_nbits;
+ op.data.dir = SPI_MEM_DATA_OUT;
+ op.data.buf.out = transfer->tx_buf;
+ }
+
+ ret = stm32_qspi_send(spi, &op);
+ if (ret)
+ goto end_of_transfer;
+
+ msg->actual_length += transfer->len + dummy_bytes;
+ }
+
+end_of_transfer:
+ gpiod_set_value_cansleep(spi->cs_gpiod, false);
+
+ mutex_unlock(&qspi->lock);
+
+ msg->status = ret;
+ spi_finalize_current_message(ctrl);
+
+ pm_runtime_mark_last_busy(qspi->dev);
+ pm_runtime_put_autosuspend(qspi->dev);
+
+ return ret;
+}
+
static int stm32_qspi_setup(struct spi_device *spi)
{
struct spi_controller *ctrl = spi->master;
struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl);
struct stm32_qspi_flash *flash;
- u32 presc;
+ u32 presc, mode;
int ret;
if (ctrl->busy)
@@ -568,6 +653,16 @@ static int stm32_qspi_setup(struct spi_device *spi)
if (!spi->max_speed_hz)
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)) {
+ dev_err(qspi->dev, "spi-rx-bus-width\\/spi-tx-bus-width\\/cs-gpios\n");
+ dev_err(qspi->dev, "configuration not supported\n");
+
+ return -EINVAL;
+ }
+
ret = pm_runtime_resume_and_get(qspi->dev);
if (ret < 0)
return ret;
@@ -580,6 +675,16 @@ static int stm32_qspi_setup(struct spi_device *spi)
mutex_lock(&qspi->lock);
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
+ */
+ if (mode == (SPI_TX_OCTAL | SPI_RX_OCTAL)) {
+ qspi->cr_reg |= CR_DFM;
+ dev_dbg(qspi->dev, "Dual flash mode enable");
+ }
+
writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR);
/* set dcr fsize to max address */
@@ -741,11 +846,13 @@ static int stm32_qspi_probe(struct platform_device *pdev)
mutex_init(&qspi->lock);
- ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD
- | SPI_TX_DUAL | SPI_TX_QUAD;
+ ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_OCTAL
+ | SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_OCTAL;
ctrl->setup = stm32_qspi_setup;
ctrl->bus_num = -1;
ctrl->mem_ops = &stm32_qspi_mem_ops;
+ ctrl->use_gpio_descriptors = true;
+ ctrl->transfer_one_message = stm32_qspi_transfer_one_message;
ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP;
ctrl->dev.of_node = dev->of_node;
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 523edfdf5dcd..7377d3b81302 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -421,7 +421,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
return -EINVAL;
}
- master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
if (!master)
return -ENODEV;
@@ -439,10 +439,8 @@ static int xilinx_spi_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xspi->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(xspi->regs)) {
- ret = PTR_ERR(xspi->regs);
- goto put_master;
- }
+ if (IS_ERR(xspi->regs))
+ return PTR_ERR(xspi->regs);
master->bus_num = pdev->id;
master->num_chipselect = num_cs;
@@ -472,14 +470,13 @@ static int xilinx_spi_probe(struct platform_device *pdev)
xspi->irq = platform_get_irq(pdev, 0);
if (xspi->irq < 0 && xspi->irq != -ENXIO) {
- ret = xspi->irq;
- goto put_master;
+ return xspi->irq;
} else if (xspi->irq >= 0) {
/* Register for SPI Interrupt */
ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
dev_name(&pdev->dev), xspi);
if (ret)
- goto put_master;
+ return ret;
}
/* SPI controller initializations */
@@ -488,7 +485,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
ret = spi_bitbang_start(&xspi->bitbang);
if (ret) {
dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");
- goto put_master;
+ return ret;
}
dev_info(&pdev->dev, "at %pR, irq=%d\n", res, xspi->irq);
@@ -500,11 +497,6 @@ static int xilinx_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
return 0;
-
-put_master:
- spi_master_put(master);
-
- return ret;
}
static int xilinx_spi_remove(struct platform_device *pdev)
diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c
index fc2b5eb7d614..2fa7608f94cd 100644
--- a/drivers/spi/spi-xtensa-xtfpga.c
+++ b/drivers/spi/spi-xtensa-xtfpga.c
@@ -83,7 +83,7 @@ static int xtfpga_spi_probe(struct platform_device *pdev)
int ret;
struct spi_master *master;
- master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi));
+ master = devm_spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi));
if (!master)
return -ENOMEM;
@@ -97,30 +97,24 @@ static int xtfpga_spi_probe(struct platform_device *pdev)
xspi->bitbang.chipselect = xtfpga_spi_chipselect;
xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
xspi->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(xspi->regs)) {
- ret = PTR_ERR(xspi->regs);
- goto err;
- }
+ if (IS_ERR(xspi->regs))
+ return PTR_ERR(xspi->regs);
xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
usleep_range(1000, 2000);
if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) {
dev_err(&pdev->dev, "Device stuck in busy state\n");
- ret = -EBUSY;
- goto err;
+ return -EBUSY;
}
ret = spi_bitbang_start(&xspi->bitbang);
if (ret < 0) {
dev_err(&pdev->dev, "spi_bitbang_start failed\n");
- goto err;
+ return ret;
}
platform_set_drvdata(pdev, master);
return 0;
-err:
- spi_master_put(master);
- return ret;
}
static int xtfpga_spi_remove(struct platform_device *pdev)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 30e82f968639..5f9aedd1f0b6 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -753,7 +753,7 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr,
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
- strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
+ strscpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
@@ -1010,9 +1010,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
}
#ifdef CONFIG_HAS_DMA
-int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
- struct sg_table *sgt, void *buf, size_t len,
- enum dma_data_direction dir)
+static int spi_map_buf_attrs(struct spi_controller *ctlr, struct device *dev,
+ struct sg_table *sgt, void *buf, size_t len,
+ enum dma_data_direction dir, unsigned long attrs)
{
const bool vmalloced_buf = is_vmalloc_addr(buf);
unsigned int max_seg_size = dma_get_max_seg_size(dev);
@@ -1078,28 +1078,41 @@ int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
sg = sg_next(sg);
}
- ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
- if (!ret)
- ret = -ENOMEM;
+ ret = dma_map_sgtable(dev, sgt, dir, attrs);
if (ret < 0) {
sg_free_table(sgt);
return ret;
}
- sgt->nents = ret;
-
return 0;
}
-void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev,
- struct sg_table *sgt, enum dma_data_direction dir)
+int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
+ struct sg_table *sgt, void *buf, size_t len,
+ enum dma_data_direction dir)
+{
+ return spi_map_buf_attrs(ctlr, dev, sgt, buf, len, dir, 0);
+}
+
+static void spi_unmap_buf_attrs(struct spi_controller *ctlr,
+ struct device *dev, struct sg_table *sgt,
+ enum dma_data_direction dir,
+ unsigned long attrs)
{
if (sgt->orig_nents) {
- dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
+ 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,
+ struct sg_table *sgt, enum dma_data_direction dir)
+{
+ spi_unmap_buf_attrs(ctlr, dev, sgt, dir, 0);
+}
+
static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
{
struct device *tx_dev, *rx_dev;
@@ -1124,29 +1137,37 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
rx_dev = ctlr->dev.parent;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ /* The sync is done before each transfer. */
+ unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC;
+
if (!ctlr->can_dma(ctlr, msg->spi, xfer))
continue;
if (xfer->tx_buf != NULL) {
- ret = spi_map_buf(ctlr, tx_dev, &xfer->tx_sg,
- (void *)xfer->tx_buf, xfer->len,
- DMA_TO_DEVICE);
+ ret = spi_map_buf_attrs(ctlr, tx_dev, &xfer->tx_sg,
+ (void *)xfer->tx_buf,
+ xfer->len, DMA_TO_DEVICE,
+ attrs);
if (ret != 0)
return ret;
}
if (xfer->rx_buf != NULL) {
- ret = spi_map_buf(ctlr, rx_dev, &xfer->rx_sg,
- xfer->rx_buf, xfer->len,
- DMA_FROM_DEVICE);
+ ret = spi_map_buf_attrs(ctlr, rx_dev, &xfer->rx_sg,
+ xfer->rx_buf, xfer->len,
+ DMA_FROM_DEVICE, attrs);
if (ret != 0) {
- spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg,
- DMA_TO_DEVICE);
+ spi_unmap_buf_attrs(ctlr, tx_dev,
+ &xfer->tx_sg, DMA_TO_DEVICE,
+ attrs);
+
return ret;
}
}
}
+ ctlr->cur_rx_dma_dev = rx_dev;
+ ctlr->cur_tx_dma_dev = tx_dev;
ctlr->cur_msg_mapped = true;
return 0;
@@ -1154,38 +1175,60 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg)
{
+ struct device *rx_dev = ctlr->cur_rx_dma_dev;
+ struct device *tx_dev = ctlr->cur_tx_dma_dev;
struct spi_transfer *xfer;
- struct device *tx_dev, *rx_dev;
if (!ctlr->cur_msg_mapped || !ctlr->can_dma)
return 0;
- if (ctlr->dma_tx)
- tx_dev = ctlr->dma_tx->device->dev;
- else if (ctlr->dma_map_dev)
- tx_dev = ctlr->dma_map_dev;
- else
- tx_dev = ctlr->dev.parent;
-
- if (ctlr->dma_rx)
- rx_dev = ctlr->dma_rx->device->dev;
- else if (ctlr->dma_map_dev)
- rx_dev = ctlr->dma_map_dev;
- else
- rx_dev = ctlr->dev.parent;
-
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;
- spi_unmap_buf(ctlr, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
- spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
+ 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);
}
ctlr->cur_msg_mapped = false;
return 0;
}
+
+static void spi_dma_sync_for_device(struct spi_controller *ctlr,
+ struct spi_transfer *xfer)
+{
+ 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)
+ dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
+ if (xfer->rx_sg.orig_nents)
+ dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
+}
+
+static void spi_dma_sync_for_cpu(struct spi_controller *ctlr,
+ struct spi_transfer *xfer)
+{
+ 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)
+ dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
+ if (xfer->tx_sg.orig_nents)
+ dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
+}
#else /* !CONFIG_HAS_DMA */
static inline int __spi_map_msg(struct spi_controller *ctlr,
struct spi_message *msg)
@@ -1198,6 +1241,16 @@ static inline int __spi_unmap_msg(struct spi_controller *ctlr,
{
return 0;
}
+
+static void spi_dma_sync_for_device(struct spi_controller *ctrl,
+ struct spi_transfer *xfer)
+{
+}
+
+static void spi_dma_sync_for_cpu(struct spi_controller *ctrl,
+ struct spi_transfer *xfer)
+{
+}
#endif /* !CONFIG_HAS_DMA */
static inline int spi_unmap_msg(struct spi_controller *ctlr,
@@ -1435,7 +1488,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
struct spi_statistics __percpu *statm = ctlr->pcpu_statistics;
struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics;
- spi_set_cs(msg->spi, true, false);
+ xfer = list_first_entry(&msg->transfers, struct spi_transfer, transfer_list);
+ spi_set_cs(msg->spi, !xfer->cs_off, false);
SPI_STATISTICS_INCREMENT_FIELD(statm, messages);
SPI_STATISTICS_INCREMENT_FIELD(stats, messages);
@@ -1455,8 +1509,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
reinit_completion(&ctlr->xfer_completion);
fallback_pio:
+ spi_dma_sync_for_device(ctlr, xfer);
ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
if (ret < 0) {
+ spi_dma_sync_for_cpu(ctlr, xfer);
+
if (ctlr->cur_msg_mapped &&
(xfer->error & SPI_TRANS_FAIL_NO_START)) {
__spi_unmap_msg(ctlr, msg);
@@ -1479,6 +1536,8 @@ fallback_pio:
if (ret < 0)
msg->status = ret;
}
+
+ spi_dma_sync_for_cpu(ctlr, xfer);
} else {
if (xfer->len)
dev_err(&msg->spi->dev,
@@ -1503,10 +1562,15 @@ fallback_pio:
&msg->transfers)) {
keep_cs = true;
} else {
- spi_set_cs(msg->spi, false, false);
+ if (!xfer->cs_off)
+ spi_set_cs(msg->spi, false, false);
_spi_transfer_cs_change_delay(msg, xfer);
- spi_set_cs(msg->spi, true, false);
+ if (!list_next_entry(xfer, transfer_list)->cs_off)
+ spi_set_cs(msg->spi, true, false);
}
+ } else if (!list_is_last(&xfer->transfer_list, &msg->transfers) &&
+ xfer->cs_off != list_next_entry(xfer, transfer_list)->cs_off) {
+ spi_set_cs(msg->spi, xfer->cs_off, false);
}
msg->actual_length += xfer->len;
@@ -1587,6 +1651,15 @@ static int __spi_pump_transfer_message(struct spi_controller *ctlr,
trace_spi_message_start(msg);
+ ret = spi_split_transfers_maxsize(ctlr, msg,
+ spi_max_transfer_size(msg->spi),
+ GFP_KERNEL | GFP_DMA);
+ if (ret) {
+ msg->status = ret;
+ spi_finalize_current_message(ctlr);
+ return ret;
+ }
+
if (ctlr->prepare_message) {
ret = ctlr->prepare_message(ctlr, msg);
if (ret) {
@@ -2329,7 +2402,7 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
goto err_out;
}
- strlcpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias));
+ strscpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias));
/* Use provided chip-select for ancillary device */
ancillary->chip_select = chip_select;
@@ -2725,7 +2798,7 @@ static ssize_t slave_store(struct device *dev, struct device_attribute *attr,
if (!spi)
return -ENOMEM;
- strlcpy(spi->modalias, name, sizeof(spi->modalias));
+ strscpy(spi->modalias, name, sizeof(spi->modalias));
rc = spi_add_device(spi);
if (rc) {
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index f089ee1ead58..fbf8c0d95968 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -378,6 +378,8 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
* @cleanup: frees controller-specific state
* @can_dma: determine whether this controller supports DMA
* @dma_map_dev: device which can be used for DMA mapping
+ * @cur_rx_dma_dev: device which is currently used for RX DMA mapping
+ * @cur_tx_dma_dev: device which is currently used for TX DMA mapping
* @queued: whether this controller is providing an internal message queue
* @kworker: pointer to thread struct for message pump
* @pump_messages: work struct for scheduling work to the message pump
@@ -610,6 +612,8 @@ struct spi_controller {
struct spi_device *spi,
struct spi_transfer *xfer);
struct device *dma_map_dev;
+ struct device *cur_rx_dma_dev;
+ struct device *cur_tx_dma_dev;
/*
* These hooks are for drivers that want to use the generic
@@ -848,6 +852,7 @@ struct spi_res {
* @bits_per_word: select a bits_per_word other than the device default
* for this transfer. If 0 the default (from @spi_device) is used.
* @dummy_data: indicates transfer is dummy bytes transfer.
+ * @cs_off: performs the transfer with chipselect off.
* @cs_change: affects chipselect after this transfer completes
* @cs_change_delay: delay between cs deassert and assert when
* @cs_change is set and @spi_transfer is not the last in @spi_message
@@ -958,6 +963,7 @@ struct spi_transfer {
struct sg_table rx_sg;
unsigned dummy_data:1;
+ unsigned cs_off:1;
unsigned cs_change:1;
unsigned tx_nbits:3;
unsigned rx_nbits:3;