spi: Updates for v6.17

This release is almost entirely driver work, mostly new drivers with the
 usual smattering of per driver updates anf fixes, with only trivial
 changes in the core.  Highlights include:
 
  - Quite a bit of maintainence work on the STM32 and Qualcomm drivers.
  - Usage of the newly added devm_dma_request_chan() in the ateml driver,
    pulling in the relevant dmaengine change.
  - Cleanups of our usage of the PM autosuspend functions, this pulls in
    some PM core changes on a shared tag.
  - Support for ADI sigma-delta triggers, Amlogic SPISG, Mediatek MT6991
    and MT8196, Renesas RZ/V2H(P) and SOPHGO SG2042.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmiHa5MACgkQJNaLcl1U
 h9DSlAf/YyxtmieKVcrWN9vsfNM6tHWOxLshxoIpkWoab5uVdoLsHQSQzzB76Taz
 mBeJAaf0ipLV9b6b9Cl2rZEwWJPg+l3o3KXAbQSQ7bMV/4vUhsFDkXO/nnPd6EmK
 ta20i7UpuRKvW55MrzbkJ0+bU1kTVrMxDBR/CJQuF0U+TOUaytpIsZ54nfJ5facq
 W4bMNwzpqcxoyk5iR1xQxsu4phPkcL6tQ1XF3MlcTOEOmLxPXNPZX+WDoRYEAuCo
 8M6+YyFMFlEgeQGplDhPb3O/KCTdQOhOGXSs0UpeiVVXV6Ozl23GG47wPC79HWRV
 +pAPQ8FfUnNDHw0IAaHc9WyF+FVhKQ==
 =yjWy
 -----END PGP SIGNATURE-----

Merge tag 'spi-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi updates from Mark Brown:
 "This release is almost entirely driver work, mostly new drivers with
  the usual smattering of per driver updates anf fixes, with only
  trivial changes in the core. Highlights include:

   - Quite a bit of maintainence work on the STM32 and Qualcomm drivers

   - Usage of the newly added devm_dma_request_chan() in the ateml
     driver, pulling in the relevant dmaengine change

   - Cleanups of our usage of the PM autosuspend functions, this pulls
     in some PM core changes on a shared tag

   - Support for ADI sigma-delta triggers, Amlogic SPISG, Mediatek
     MT6991 and MT8196, Renesas RZ/V2H(P) and SOPHGO SG2042"

* tag 'spi-v6.17' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (62 commits)
  spi: SPISG: Fix less than zero comparison on a u32 variable
  spi: intel: Allow writeable MTD partition with module param
  spi: Add driver for the RZ/V2H(P) RSPI IP
  spi: dt-bindings: Document the RZ/V2H(P) RSPI
  MAINTAINERS: Add an entry for Amlogic spi driver
  spi: Add Amlogic SPISG driver
  spi: dt-bindings: Add binding document of Amlogic SPISG controller
  spi: spi-sg2044-nor: Add SPI-NOR controller for SG2042
  spi: spi-sg2044-nor: Add configurable chip_info
  spi: dt-bindings: spi-sg2044-nor: Change SOPHGO SG2042
  spi: spi-qpic-snand: simplify bad block marker duplication
  spi: spidev: Add an entry for the ABB spi sensors
  dt-bindings: trivial-devices: Document ABB sensors
  spi: stm32-ospi: Fix NULL vs IS_ERR() bug in stm32_ospi_get_resources()
  spi: gpio: Use explicit 'unsigned int' for parameter types
  spi: dt-bindings: spi-mux: Drop "spi-max-frequency" as required
  spi: st: Switch from CONFIG_PM_SLEEP guards to pm_sleep_ptr()
  spi: rspi: Convert to DEFINE_SIMPLE_DEV_PM_OPS()
  spi: sh-msiof: Convert to DEFINE_SIMPLE_DEV_PM_OPS()
  spi: xilinx: Fix block comment style and minor cleanups
  ...
This commit is contained in:
Linus Torvalds 2025-07-28 23:03:09 -07:00
commit 0262163136
56 changed files with 2963 additions and 545 deletions

View File

@ -0,0 +1,59 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2025 Amlogic, Inc. All rights reserved
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/amlogic,a4-spisg.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic SPI Scatter-Gather Controller
maintainers:
- Xianwei Zhao <xianwei.zhao@amlogic.com>
- Sunny Luo <sunny.luo@amlogic.com>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
const: amlogic,a4-spisg
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 2
clock-names:
items:
- const: core
- const: pclk
resets:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
spi@50000 {
compatible = "amlogic,a4-spisg";
reg = <0x50000 0x38>;
interrupts = <GIC_SPI 183 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clkc 37>,
<&clkc 93>;
clock-names = "core", "pclk";
#address-cells = <1>;
#size-cells = <0>;
};

View File

@ -23,6 +23,7 @@ properties:
- fsl,ls2080a-dspi
- fsl,ls2085a-dspi
- fsl,lx2160a-dspi
- nxp,s32g2-dspi
- items:
- enum:
- fsl,ls1012a-dspi
@ -37,6 +38,9 @@ properties:
- items:
- const: fsl,lx2160a-dspi
- const: fsl,ls2085a-dspi
- items:
- const: nxp,s32g3-dspi
- const: nxp,s32g2-dspi
reg:
maxItems: 1
@ -114,3 +118,17 @@ examples:
spi-cs-hold-delay-ns = <50>;
};
};
# S32G3 in target mode
- |
spi@401d4000 {
compatible = "nxp,s32g3-dspi", "nxp,s32g2-dspi";
reg = <0x401d4000 0x1000>;
interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks 26>;
clock-names = "dspi";
spi-num-chipselects = <8>;
bus-num = <0>;
dmas = <&edma0 0 7>, <&edma0 0 8>;
dma-names = "tx", "rx";
spi-slave;
};

View File

@ -0,0 +1,102 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/marvell,orion-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell Orion SPI controller
maintainers:
- Andrew Lunn <andrew@lunn.ch>
- Gregory CLEMENT <gregory.clement@bootlin.com>
allOf:
- $ref: /schemas/spi/spi-controller.yaml#
properties:
compatible:
oneOf:
- enum:
- marvell,orion-spi
- marvell,armada-380-spi # For ap80x and cp11x
- items:
- enum:
- marvell,armada-370-spi
- marvell,armada-375-spi
- marvell,armada-380-spi
- marvell,armada-390-spi
- marvell,armada-xp-spi
- const: marvell,orion-spi
cell-index:
description: Instance id for the SPI controller
deprecated: true
reg:
minItems: 1
items:
- description: control registers
- description: CS0 MBUS target/attribute registers for direct mode
- description: CS1 MBUS target/attribute registers for direct mode
- description: CS2 MBUS target/attribute registers for direct mode
- description: CS3 MBUS target/attribute registers for direct mode
- description: CS4 MBUS target/attribute registers for direct mode
- description: CS5 MBUS target/attribute registers for direct mode
- description: CS6 MBUS target/attribute registers for direct mode
- description: CS7 MBUS target/attribute registers for direct mode
clocks:
minItems: 1
maxItems: 2
clock-names:
items:
- const: core
- const: axi
interrupts:
maxItems: 1
required:
- compatible
- reg
- clocks
unevaluatedProperties: false
examples:
- |
spi@10600 {
compatible = "marvell,orion-spi";
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
reg = <0x10600 0x28>;
clocks = <&coreclk 0>;
interrupts = <23>;
};
- |
#define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16))
bus {
#address-cells = <2>;
#size-cells = <1>;
spi@10600 {
compatible = "marvell,orion-spi";
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
reg = <MBUS_ID(0xf0, 0x01) 0x10600 0x28>, /* control */
<MBUS_ID(0x01, 0x1e) 0 0xffffffff>, /* CS0 */
<MBUS_ID(0x01, 0x5e) 0 0xffffffff>, /* CS1 */
<MBUS_ID(0x01, 0x9e) 0 0xffffffff>, /* CS2 */
<MBUS_ID(0x01, 0xde) 0 0xffffffff>, /* CS3 */
<MBUS_ID(0x01, 0x1f) 0 0xffffffff>, /* CS4 */
<MBUS_ID(0x01, 0x5f) 0 0xffffffff>, /* CS5 */
<MBUS_ID(0x01, 0x9f) 0 0xffffffff>, /* CS6 */
<MBUS_ID(0x01, 0xdf) 0 0xffffffff>; /* CS7 */
clocks = <&coreclk 0>;
interrupts = <23>;
};
};

View File

@ -39,6 +39,10 @@ properties:
- mediatek,mt7988-spi-single
- mediatek,mt8188-spi-ipm
- const: mediatek,spi-ipm
- items:
- enum:
- mediatek,mt8196-spi
- const: mediatek,mt6991-spi
- items:
- enum:
- mediatek,mt2701-spi
@ -46,6 +50,7 @@ properties:
- mediatek,mt6589-spi
- mediatek,mt6765-spi
- mediatek,mt6893-spi
- mediatek,mt6991-spi
- mediatek,mt7622-spi
- mediatek,mt8135-spi
- mediatek,mt8173-spi

View File

@ -24,6 +24,9 @@ properties:
interrupts:
maxItems: 1
clocks:
maxItems: 1
dmas:
maxItems: 1

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/nxp,lpc3220-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP LPC3220 SPI controller
maintainers:
- Frank Li <Frank.Li@nxp.com>
properties:
compatible:
enum:
- nxp,lpc3220-spi
reg:
maxItems: 1
clocks:
maxItems: 1
allOf:
- $ref: spi-controller.yaml#
unevaluatedProperties: false
required:
- compatible
- reg
- clocks
examples:
- |
#include <dt-bindings/clock/lpc32xx-clock.h>
spi@20088000 {
compatible = "nxp,lpc3220-spi";
reg = <0x20088000 0x1000>;
clocks = <&clk LPC32XX_CLK_SPI1>;
#address-cells = <1>;
#size-cells = <0>;
};

View File

@ -0,0 +1,96 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/renesas,rzv2h-rspi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/V2H(P) Renesas Serial Peripheral Interface (RSPI)
maintainers:
- Fabrizio Castro <fabrizio.castro.jz@renesas.com>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
const: renesas,r9a09g057-rspi # RZ/V2H(P)
reg:
maxItems: 1
interrupts:
items:
- description: Idle Interrupt
- description: Error Interrupt
- description: Communication End Interrupt
- description: Receive Buffer Full Interrupt
- description: Transmit Buffer Empty Interrupt
interrupt-names:
items:
- const: idle
- const: error
- const: end
- const: rx
- const: tx
clocks:
maxItems: 3
clock-names:
items:
- const: pclk
- const: pclk_sfr
- const: tclk
resets:
maxItems: 2
reset-names:
items:
- const: presetn
- const: tresetn
power-domains:
maxItems: 1
required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
- clock-names
- resets
- reset-names
- power-domains
- '#address-cells'
- '#size-cells'
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/renesas-cpg-mssr.h>
spi@12800800 {
compatible = "renesas,r9a09g057-rspi";
reg = <0x12800800 0x400>;
interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 113 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 504 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 505 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "idle", "error", "end", "rx", "tx";
clocks = <&cpg CPG_MOD 0x5a>,
<&cpg CPG_MOD 0x5b>,
<&cpg CPG_MOD 0x5c>;
clock-names = "pclk", "pclk_sfr", "tclk";
resets = <&cpg 0x7f>, <&cpg 0x80>;
reset-names = "presetn", "tresetn";
power-domains = <&cpg>;
#address-cells = <1>;
#size-cells = <0>;
};

View File

@ -46,7 +46,6 @@ properties:
required:
- compatible
- reg
- spi-max-frequency
- mux-controls
unevaluatedProperties: false

View File

@ -1,79 +0,0 @@
Marvell Orion SPI device
Required properties:
- compatible : should be on of the following:
- "marvell,orion-spi" for the Orion, mv78x00, Kirkwood and Dove SoCs
- "marvell,armada-370-spi", for the Armada 370 SoCs
- "marvell,armada-375-spi", for the Armada 375 SoCs
- "marvell,armada-380-spi", for the Armada 38x SoCs
- "marvell,armada-390-spi", for the Armada 39x SoCs
- "marvell,armada-xp-spi", for the Armada XP SoCs
- reg : offset and length of the register set for the device.
This property can optionally have additional entries to configure
the SPI direct access mode that some of the Marvell SoCs support
additionally to the normal indirect access (PIO) mode. The values
for the MBus "target" and "attribute" are defined in the Marvell
SoC "Functional Specifications" Manual in the chapter "Marvell
Core Processor Address Decoding".
The eight register sets following the control registers refer to
chip-select lines 0 through 7 respectively.
- cell-index : Which of multiple SPI controllers is this.
- clocks : pointers to the reference clocks for this device, the first
one is the one used for the clock on the spi bus, the
second one is optional and is the clock used for the
functional part of the controller
Optional properties:
- interrupts : Is currently not used.
- clock-names : names of used clocks, mandatory if the second clock is
used, the name must be "core", and "axi" (the latter
is only for Armada 7K/8K).
Example:
spi@10600 {
compatible = "marvell,orion-spi";
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
reg = <0x10600 0x28>;
interrupts = <23>;
};
Example with SPI direct mode support (optionally):
spi0: spi@10600 {
compatible = "marvell,orion-spi";
#address-cells = <1>;
#size-cells = <0>;
cell-index = <0>;
reg = <MBUS_ID(0xf0, 0x01) 0x10600 0x28>, /* control */
<MBUS_ID(0x01, 0x1e) 0 0xffffffff>, /* CS0 */
<MBUS_ID(0x01, 0x5e) 0 0xffffffff>, /* CS1 */
<MBUS_ID(0x01, 0x9e) 0 0xffffffff>, /* CS2 */
<MBUS_ID(0x01, 0xde) 0 0xffffffff>, /* CS3 */
<MBUS_ID(0x01, 0x1f) 0 0xffffffff>, /* CS4 */
<MBUS_ID(0x01, 0x5f) 0 0xffffffff>, /* CS5 */
<MBUS_ID(0x01, 0x9f) 0 0xffffffff>, /* CS6 */
<MBUS_ID(0x01, 0xdf) 0 0xffffffff>; /* CS7 */
interrupts = <23>;
};
To enable the direct mode, the board specific 'ranges' property in the
'soc' node needs to add the entries for the desired SPI controllers
and its chip-selects that are used in the direct mode instead of PIO
mode. Here an example for this (SPI controller 0, device 1 and SPI
controller 1, device 2 are used in direct mode. All other SPI device
are used in the default indirect (PIO) mode):
soc {
/*
* Enable the SPI direct access by configuring an entry
* here in the board-specific ranges property
*/
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000>, /* internal regs */
<MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>, /* BootROM */
<MBUS_ID(0x01, 0x5e) 0 0 0xf1100000 0x10000>, /* SPI0-DEV1 */
<MBUS_ID(0x01, 0x9a) 0 0 0xf1110000 0x10000>; /* SPI1-DEV2 */
For further information on the MBus bindings, please see the MBus
DT documentation:
Documentation/devicetree/bindings/bus/mvebu-mbus.txt

View File

@ -115,6 +115,7 @@ properties:
maxItems: 4
st,spi-midi-ns:
deprecated: true
description: |
Only for STM32H7, (Master Inter-Data Idleness) minimum time
delay in nanoseconds inserted between two consecutive data frames.

View File

@ -14,12 +14,9 @@ allOf:
properties:
compatible:
oneOf:
- const: sophgo,sg2044-spifmc-nor
- items:
- enum:
- sophgo,sg2042-spifmc-nor
- const: sophgo,sg2044-spifmc-nor
enum:
- sophgo,sg2042-spifmc-nor
- sophgo,sg2044-spifmc-nor
reg:
maxItems: 1

View File

@ -18,6 +18,38 @@ maintainers:
allOf:
- $ref: spi-controller.yaml#
- if:
properties:
compatible:
contains:
const: st,stm32f4-spi
then:
properties:
st,spi-midi-ns: false
sram: false
dmas:
maxItems: 2
dma-names:
items:
- const: rx
- const: tx
- if:
properties:
compatible:
contains:
const: st,stm32mp25-spi
then:
properties:
sram: false
dmas:
maxItems: 2
dma-names:
items:
- const: rx
- const: tx
properties:
compatible:
@ -41,16 +73,28 @@ properties:
dmas:
description: |
DMA specifiers for tx and rx dma. DMA fifo mode must be used. See
the STM32 DMA controllers bindings Documentation/devicetree/bindings/dma/stm32/*.yaml.
DMA specifiers for tx and rx channels. DMA fifo mode must be used. See
the STM32 DMA bindings Documentation/devicetree/bindings/dma/stm32/st,*dma.yaml
minItems: 2
items:
- description: rx DMA channel
- description: tx DMA channel
- description: rxm2m MDMA channel
dma-names:
minItems: 2
items:
- const: rx
- const: tx
- const: rxm2m
sram:
$ref: /schemas/types.yaml#/definitions/phandle
description: |
Phandles to a reserved SRAM region which is used as temporary
storage memory between DMA and MDMA engines.
The region should be defined as child node of the AHB SRAM node
as per the generic bindings in Documentation/devicetree/bindings/sram/sram.yaml
access-controllers:
minItems: 1

View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (c) 2025 Analog Devices, Inc.
# Copyright (c) 2025 BayLibre, SAS
%YAML 1.2
---
$id: http://devicetree.org/schemas/trigger-source/adi,util-sigma-delta-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices Util Sigma-Delta SPI IP Core
maintainers:
- David Lechner <dlechner@baylibre.com>
description:
The Util Sigma-Delta SPI is an FPGA IP core from Analog Devices that provides
a SPI offload trigger from the RDY signal of the combined DOUT/RDY pin of
the sigma-delta family of ADCs.
https://analogdevicesinc.github.io/hdl/library/util_sigma_delta_spi/index.html
properties:
compatible:
const: adi,util-sigma-delta-spi
reg:
maxItems: 1
clocks:
maxItems: 1
'#trigger-source-cells':
const: 0
required:
- compatible
- reg
- clocks
- '#trigger-source-cells'
additionalProperties: false
examples:
- |
trigger@40000 {
reg = <0x40000 0x1000>;
compatible = "adi,util-sigma-delta-spi";
clocks = <&clk 0>;
#trigger-source-cells = <0>;
};

View File

@ -30,6 +30,8 @@ properties:
items:
# Entries are sorted alphanumerically by the compatible
- enum:
# ABB register based spi sensors
- abb,spi-sensor
# Acbel fsg032 power supply
- acbel,fsg032
# SMBus/I2C Digital Temperature Sensor in 6-Pin SOT with SMBus Alert and Over Temperature Pin

View File

@ -1308,6 +1308,15 @@ S: Maintained
F: Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
F: drivers/rtc/rtc-amlogic-a4.c
AMLOGIC SPISG DRIVER
M: Sunny Luo <sunny.luo@amlogic.com>
M: Xianwei Zhao <xianwei.zhao@amlogic.com>
L: linux-amlogic@lists.infradead.org
L: linux-spi@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/spi/amlogic,a4-spisg.yaml
F: drivers/spi/spi-amlogic-spisg.c
AMPHENOL CHIPCAP 2 DRIVER
M: Javier Carrasco <javier.carrasco.cruz@gmail.com>
L: linux-hwmon@vger.kernel.org
@ -23432,7 +23441,7 @@ F: include/linux/mtd/spi-nor.h
SPI OFFLOAD
R: David Lechner <dlechner@baylibre.com>
F: drivers/spi/spi-offload-trigger-pwm.c
F: drivers/spi/spi-offload-trigger-*.c
F: drivers/spi/spi-offload.c
F: include/linux/spi/offload/
K: spi_offload
@ -25253,6 +25262,11 @@ W: https://github.com/srcres258/linux-doc
T: git git://github.com/srcres258/linux-doc.git doc-zh-tw
F: Documentation/translations/zh_TW/
TRIGGER SOURCE - ADI UTIL SIGMA DELTA SPI
M: David Lechner <dlechner@baylibre.com>
S: Maintained
F: Documentation/devicetree/bindings/trigger-source/adi,util-sigma-delta-spi.yaml
TRIGGER SOURCE - PWM
M: David Lechner <dlechner@baylibre.com>
S: Maintained

View File

@ -926,6 +926,36 @@ void dma_release_channel(struct dma_chan *chan)
}
EXPORT_SYMBOL_GPL(dma_release_channel);
static void dmaenginem_release_channel(void *chan)
{
dma_release_channel(chan);
}
/**
* devm_dma_request_chan - try to allocate an exclusive slave channel
* @dev: pointer to client device structure
* @name: slave channel name
*
* Returns pointer to appropriate DMA channel on success or an error pointer.
*
* The operation is managed and will be undone on driver detach.
*/
struct dma_chan *devm_dma_request_chan(struct device *dev, const char *name)
{
struct dma_chan *chan = dma_request_chan(dev, name);
int ret = 0;
if (!IS_ERR(chan))
ret = devm_add_action_or_reset(dev, dmaenginem_release_channel, chan);
if (ret)
return ERR_PTR(ret);
return chan;
}
EXPORT_SYMBOL_GPL(devm_dma_request_chan);
/**
* dmaengine_get - register interest in dma_channels
*/

View File

@ -1379,7 +1379,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip);
int cwperpage, bad_block_byte, ret;
bool wide_bus;
int ecc_mode = 1;
int ecc_mode = ECC_MODE_8BIT;
/* controller only supports 512 bytes data steps */
ecc->size = NANDC_STEP_SIZE;
@ -1400,7 +1400,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
if (ecc->strength >= 8) {
/* 8 bit ECC defaults to BCH ECC on all platforms */
host->bch_enabled = true;
ecc_mode = 1;
ecc_mode = ECC_MODE_8BIT;
if (wide_bus) {
host->ecc_bytes_hw = 14;
@ -1420,7 +1420,7 @@ static int qcom_nand_attach_chip(struct nand_chip *chip)
if (nandc->props->ecc_modes & ECC_BCH_4BIT) {
/* BCH */
host->bch_enabled = true;
ecc_mode = 0;
ecc_mode = ECC_MODE_4BIT;
if (wide_bus) {
host->ecc_bytes_hw = 8;

View File

@ -99,6 +99,15 @@ config SPI_AMLOGIC_SPIFC_A1
This enables master mode support for the SPIFC (SPI flash
controller) available in Amlogic A1 (A113L SoC).
config SPI_AMLOGIC_SPISG
tristate "Amlogic SPISG controller"
depends on COMMON_CLK
depends on ARCH_MESON || COMPILE_TEST
help
This enables master mode support for the SPISG (SPI scatter-gather
communication controller), which is available on platforms such as
Amlogic A4 SoCs.
config SPI_APPLE
tristate "Apple SoC SPI Controller platform driver"
depends on ARCH_APPLE || COMPILE_TEST
@ -647,10 +656,10 @@ config SPI_FSL_SPI
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select REGMAP_MMIO
depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || M5441x || COMPILE_TEST
depends on ARCH_MXC || ARCH_NXP || M5441x || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
mode. VF610, LS1021A and ColdFire platforms uses the controller.
mode. S32, VF610, LS1021A and ColdFire platforms uses the controller.
config SPI_FSL_ESPI
tristate "Freescale eSPI controller"
@ -923,6 +932,14 @@ config SPI_RSPI
help
SPI driver for Renesas RSPI and QSPI blocks.
config SPI_RZV2H_RSPI
tristate "Renesas RZ/V2H RSPI controller"
depends on ARCH_RENESAS || COMPILE_TEST
help
RSPI driver for the Renesas RZ/V2H Serial Peripheral Interface (RSPI).
RSPI supports both SPI host and SPI target roles. This option only
enables the SPI host role.
config SPI_RZV2M_CSI
tristate "Renesas RZ/V2M CSI controller"
depends on ARCH_RENESAS || COMPILE_TEST
@ -1355,6 +1372,11 @@ if SPI_OFFLOAD
comment "SPI Offload triggers"
config SPI_OFFLOAD_TRIGGER_ADI_UTIL_SD
tristate "SPI offload trigger using ADI sigma-delta utility"
help
SPI offload trigger from ADI sigma-delta utility FPGA IP block.
config SPI_OFFLOAD_TRIGGER_PWM
tristate "SPI offload trigger using PWM"
depends on PWM

View File

@ -20,6 +20,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o
obj-$(CONFIG_SPI_ALTERA_CORE) += spi-altera-core.o
obj-$(CONFIG_SPI_ALTERA_DFL) += spi-altera-dfl.o
obj-$(CONFIG_SPI_AMLOGIC_SPIFC_A1) += spi-amlogic-spifc-a1.o
obj-$(CONFIG_SPI_AMLOGIC_SPISG) += spi-amlogic-spisg.o
obj-$(CONFIG_SPI_APPLE) += spi-apple.o
obj-$(CONFIG_SPI_AR934X) += spi-ar934x.o
obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o
@ -126,6 +127,7 @@ obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o
obj-$(CONFIG_SPI_REALTEK_SNAND) += spi-realtek-rtl-snand.o
obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_RZV2H_RSPI) += spi-rzv2h-rspi.o
obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o
obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o
obj-$(CONFIG_SPI_SC18IS602) += spi-sc18is602.o
@ -170,3 +172,4 @@ obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL) += spi-slave-system-control.o
# SPI offload triggers
obj-$(CONFIG_SPI_OFFLOAD_TRIGGER_PWM) += spi-offload-trigger-pwm.o
obj-$(CONFIG_SPI_OFFLOAD_TRIGGER_ADI_UTIL_SD) += spi-offload-trigger-adi-util-sigma-delta.o

View File

@ -965,7 +965,6 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
err = aq->ops->transfer(mem, op, offset);
pm_runtime_put:
pm_runtime_mark_last_busy(&aq->pdev->dev);
pm_runtime_put_autosuspend(&aq->pdev->dev);
return err;
}
@ -1168,7 +1167,6 @@ static int atmel_qspi_setup(struct spi_device *spi)
aq->scr |= QSPI_SCR_SCBR(scbr);
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
pm_runtime_mark_last_busy(ctrl->dev.parent);
pm_runtime_put_autosuspend(ctrl->dev.parent);
return 0;
@ -1230,7 +1228,6 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi)
aq->mr |= QSPI_MR_DLYBCT(cs_hold) | QSPI_MR_DLYCS(cs_inactive);
atmel_qspi_write(aq->mr, aq, QSPI_MR);
pm_runtime_mark_last_busy(ctrl->dev.parent);
pm_runtime_put_autosuspend(ctrl->dev.parent);
return 0;
@ -1285,18 +1282,21 @@ static int atmel_qspi_dma_init(struct spi_controller *ctrl)
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
int ret;
aq->rx_chan = dma_request_chan(&aq->pdev->dev, "rx");
aq->rx_chan = devm_dma_request_chan(&aq->pdev->dev, "rx");
if (IS_ERR(aq->rx_chan)) {
ret = dev_err_probe(&aq->pdev->dev, PTR_ERR(aq->rx_chan),
"RX DMA channel is not available\n");
goto null_rx_chan;
aq->rx_chan = NULL;
return ret;
}
aq->tx_chan = dma_request_chan(&aq->pdev->dev, "tx");
aq->tx_chan = devm_dma_request_chan(&aq->pdev->dev, "tx");
if (IS_ERR(aq->tx_chan)) {
ret = dev_err_probe(&aq->pdev->dev, PTR_ERR(aq->tx_chan),
"TX DMA channel is not available\n");
goto release_rx_chan;
aq->rx_chan = NULL;
aq->tx_chan = NULL;
return ret;
}
ctrl->dma_rx = aq->rx_chan;
@ -1307,21 +1307,6 @@ static int atmel_qspi_dma_init(struct spi_controller *ctrl)
dma_chan_name(aq->tx_chan), dma_chan_name(aq->rx_chan));
return 0;
release_rx_chan:
dma_release_channel(aq->rx_chan);
aq->tx_chan = NULL;
null_rx_chan:
aq->rx_chan = NULL;
return ret;
}
static void atmel_qspi_dma_release(struct atmel_qspi *aq)
{
if (aq->rx_chan)
dma_release_channel(aq->rx_chan);
if (aq->tx_chan)
dma_release_channel(aq->tx_chan);
}
static const struct atmel_qspi_ops atmel_qspi_ops = {
@ -1426,14 +1411,13 @@ static int atmel_qspi_probe(struct platform_device *pdev)
/* Request the IRQ */
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
err = irq;
goto dma_release;
}
if (irq < 0)
return irq;
err = devm_request_irq(&pdev->dev, irq, atmel_qspi_interrupt,
0, dev_name(&pdev->dev), aq);
if (err)
goto dma_release;
return err;
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
pm_runtime_use_autosuspend(&pdev->dev);
@ -1442,22 +1426,15 @@ static int atmel_qspi_probe(struct platform_device *pdev)
err = atmel_qspi_init(aq);
if (err)
goto dma_release;
return err;
err = spi_register_controller(ctrl);
if (err)
goto dma_release;
return err;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
dma_release:
if (aq->caps->has_dma)
atmel_qspi_dma_release(aq);
return err;
}
static int atmel_qspi_sama7g5_suspend(struct atmel_qspi *aq)
@ -1507,9 +1484,6 @@ static void atmel_qspi_remove(struct platform_device *pdev)
ret = pm_runtime_get_sync(&pdev->dev);
if (ret >= 0) {
if (aq->caps->has_dma)
atmel_qspi_dma_release(aq);
if (aq->caps->has_gclk) {
ret = atmel_qspi_sama7g5_suspend(aq);
if (ret)
@ -1582,7 +1556,6 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev)
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;

View File

@ -0,0 +1,888 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Amlogic SPI communication Scatter-Gather Controller
*
* Copyright (C) 2025 Amlogic, Inc. All rights reserved
*
* Author: Sunny Luo <sunny.luo@amlogic.com>
* Author: Xianwei Zhao <xianwei.zhao@amlogic.com>
*/
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/reset.h>
#include <linux/regmap.h>
/* Register Map */
#define SPISG_REG_CFG_READY 0x00
#define SPISG_REG_CFG_SPI 0x04
#define CFG_BUS64_EN BIT(0)
#define CFG_SLAVE_EN BIT(1)
#define CFG_SLAVE_SELECT GENMASK(3, 2)
#define CFG_SFLASH_WP BIT(4)
#define CFG_SFLASH_HD BIT(5)
/* start on vsync rising */
#define CFG_HW_POS BIT(6)
/* start on vsync falling */
#define CFG_HW_NEG BIT(7)
#define SPISG_REG_CFG_START 0x08
#define CFG_BLOCK_NUM GENMASK(19, 0)
#define CFG_BLOCK_SIZE GENMASK(22, 20)
#define CFG_DATA_COMMAND BIT(23)
#define CFG_OP_MODE GENMASK(25, 24)
#define CFG_RXD_MODE GENMASK(27, 26)
#define CFG_TXD_MODE GENMASK(29, 28)
#define CFG_EOC BIT(30)
#define CFG_PEND BIT(31)
#define SPISG_REG_CFG_BUS 0x0C
#define CFG_CLK_DIV GENMASK(7, 0)
#define CLK_DIV_WIDTH 8
#define CFG_RX_TUNING GENMASK(11, 8)
#define CFG_TX_TUNING GENMASK(15, 12)
#define CFG_CS_SETUP GENMASK(19, 16)
#define CFG_LANE GENMASK(21, 20)
#define CFG_HALF_DUPLEX BIT(22)
#define CFG_B_L_ENDIAN BIT(23)
#define CFG_DC_MODE BIT(24)
#define CFG_NULL_CTL BIT(25)
#define CFG_DUMMY_CTL BIT(26)
#define CFG_READ_TURN GENMASK(28, 27)
#define CFG_KEEP_SS BIT(29)
#define CFG_CPHA BIT(30)
#define CFG_CPOL BIT(31)
#define SPISG_REG_PIO_TX_DATA_L 0x10
#define SPISG_REG_PIO_TX_DATA_H 0x14
#define SPISG_REG_PIO_RX_DATA_L 0x18
#define SPISG_REG_PIO_RX_DATA_H 0x1C
#define SPISG_REG_MEM_TX_ADDR_L 0x10
#define SPISG_REG_MEM_TX_ADDR_H 0x14
#define SPISG_REG_MEM_RX_ADDR_L 0x18
#define SPISG_REG_MEM_RX_ADDR_H 0x1C
#define SPISG_REG_DESC_LIST_L 0x20
#define SPISG_REG_DESC_LIST_H 0x24
#define LIST_DESC_PENDING BIT(31)
#define SPISG_REG_DESC_CURRENT_L 0x28
#define SPISG_REG_DESC_CURRENT_H 0x2c
#define SPISG_REG_IRQ_STS 0x30
#define SPISG_REG_IRQ_ENABLE 0x34
#define IRQ_RCH_DESC_EOC BIT(0)
#define IRQ_RCH_DESC_INVALID BIT(1)
#define IRQ_RCH_DESC_RESP BIT(2)
#define IRQ_RCH_DATA_RESP BIT(3)
#define IRQ_WCH_DESC_EOC BIT(4)
#define IRQ_WCH_DESC_INVALID BIT(5)
#define IRQ_WCH_DESC_RESP BIT(6)
#define IRQ_WCH_DATA_RESP BIT(7)
#define IRQ_DESC_ERR BIT(8)
#define IRQ_SPI_READY BIT(9)
#define IRQ_DESC_DONE BIT(10)
#define IRQ_DESC_CHAIN_DONE BIT(11)
#define SPISG_MAX_REG 0x40
#define SPISG_BLOCK_MAX 0x100000
#define SPISG_OP_MODE_WRITE_CMD 0
#define SPISG_OP_MODE_READ_STS 1
#define SPISG_OP_MODE_WRITE 2
#define SPISG_OP_MODE_READ 3
#define SPISG_DATA_MODE_NONE 0
#define SPISG_DATA_MODE_PIO 1
#define SPISG_DATA_MODE_MEM 2
#define SPISG_DATA_MODE_SG 3
#define SPISG_CLK_DIV_MAX 256
/* recommended by specification */
#define SPISG_CLK_DIV_MIN 4
#define DIV_NUM (SPISG_CLK_DIV_MAX - SPISG_CLK_DIV_MIN + 1)
#define SPISG_PCLK_RATE_MIN 24000000
#define SPISG_SINGLE_SPI 0
#define SPISG_DUAL_SPI 1
#define SPISG_QUAD_SPI 2
struct spisg_sg_link {
#define LINK_ADDR_VALID BIT(0)
#define LINK_ADDR_EOC BIT(1)
#define LINK_ADDR_IRQ BIT(2)
#define LINK_ADDR_ACT GENMASK(5, 3)
#define LINK_ADDR_RING BIT(6)
#define LINK_ADDR_LEN GENMASK(31, 8)
u32 addr;
u32 addr1;
};
struct spisg_descriptor {
u32 cfg_start;
u32 cfg_bus;
u64 tx_paddr;
u64 rx_paddr;
};
struct spisg_descriptor_extra {
struct spisg_sg_link *tx_ccsg;
struct spisg_sg_link *rx_ccsg;
int tx_ccsg_len;
int rx_ccsg_len;
};
struct spisg_device {
struct spi_controller *controller;
struct platform_device *pdev;
struct regmap *map;
struct clk *core;
struct clk *pclk;
struct clk *sclk;
struct clk_div_table *tbl;
struct completion completion;
u32 status;
u32 speed_hz;
u32 effective_speed_hz;
u32 bytes_per_word;
u32 cfg_spi;
u32 cfg_start;
u32 cfg_bus;
};
static int spi_delay_to_sclk(u32 slck_speed_hz, struct spi_delay *delay)
{
s32 ns;
if (!delay)
return 0;
if (delay->unit == SPI_DELAY_UNIT_SCK)
return delay->value;
ns = spi_delay_to_ns(delay, NULL);
if (ns < 0)
return 0;
return DIV_ROUND_UP_ULL(slck_speed_hz * ns, NSEC_PER_SEC);
}
static inline u32 aml_spisg_sem_down_read(struct spisg_device *spisg)
{
u32 ret;
regmap_read(spisg->map, SPISG_REG_CFG_READY, &ret);
if (ret)
regmap_write(spisg->map, SPISG_REG_CFG_READY, 0);
return ret;
}
static inline void aml_spisg_sem_up_write(struct spisg_device *spisg)
{
regmap_write(spisg->map, SPISG_REG_CFG_READY, 1);
}
static int aml_spisg_set_speed(struct spisg_device *spisg, uint speed_hz)
{
u32 cfg_bus;
if (!speed_hz || speed_hz == spisg->speed_hz)
return 0;
spisg->speed_hz = speed_hz;
clk_set_rate(spisg->sclk, speed_hz);
/* Store the div for the descriptor mode */
regmap_read(spisg->map, SPISG_REG_CFG_BUS, &cfg_bus);
spisg->cfg_bus &= ~CFG_CLK_DIV;
spisg->cfg_bus |= cfg_bus & CFG_CLK_DIV;
spisg->effective_speed_hz = clk_get_rate(spisg->sclk);
dev_dbg(&spisg->pdev->dev,
"desired speed %dHz, effective speed %dHz\n",
speed_hz, spisg->effective_speed_hz);
return 0;
}
static bool aml_spisg_can_dma(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *xfer)
{
return true;
}
static void aml_spisg_sg_xlate(struct sg_table *sgt, struct spisg_sg_link *ccsg)
{
struct scatterlist *sg;
int i;
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
ccsg->addr = FIELD_PREP(LINK_ADDR_VALID, 1) |
FIELD_PREP(LINK_ADDR_RING, 0) |
FIELD_PREP(LINK_ADDR_EOC, sg_is_last(sg)) |
FIELD_PREP(LINK_ADDR_LEN, sg_dma_len(sg));
ccsg->addr1 = (u32)sg_dma_address(sg);
ccsg++;
}
}
static int nbits_to_lane[] = {
SPISG_SINGLE_SPI,
SPISG_SINGLE_SPI,
SPISG_DUAL_SPI,
-EINVAL,
SPISG_QUAD_SPI
};
static int aml_spisg_setup_transfer(struct spisg_device *spisg,
struct spi_transfer *xfer,
struct spisg_descriptor *desc,
struct spisg_descriptor_extra *exdesc)
{
int block_size, blocks;
struct device *dev = &spisg->pdev->dev;
struct spisg_sg_link *ccsg;
int ccsg_len;
dma_addr_t paddr;
int ret;
memset(desc, 0, sizeof(*desc));
if (exdesc)
memset(exdesc, 0, sizeof(*exdesc));
aml_spisg_set_speed(spisg, xfer->speed_hz);
xfer->effective_speed_hz = spisg->effective_speed_hz;
desc->cfg_start = spisg->cfg_start;
desc->cfg_bus = spisg->cfg_bus;
block_size = xfer->bits_per_word >> 3;
blocks = xfer->len / block_size;
desc->cfg_start |= FIELD_PREP(CFG_EOC, 0);
desc->cfg_bus |= FIELD_PREP(CFG_KEEP_SS, !xfer->cs_change);
desc->cfg_bus |= FIELD_PREP(CFG_NULL_CTL, 0);
if (xfer->tx_buf || xfer->tx_dma) {
desc->cfg_bus |= FIELD_PREP(CFG_LANE, nbits_to_lane[xfer->tx_nbits]);
desc->cfg_start |= FIELD_PREP(CFG_OP_MODE, SPISG_OP_MODE_WRITE);
}
if (xfer->rx_buf || xfer->rx_dma) {
desc->cfg_bus |= FIELD_PREP(CFG_LANE, nbits_to_lane[xfer->rx_nbits]);
desc->cfg_start |= FIELD_PREP(CFG_OP_MODE, SPISG_OP_MODE_READ);
}
if (FIELD_GET(CFG_OP_MODE, desc->cfg_start) == SPISG_OP_MODE_READ_STS) {
desc->cfg_start |= FIELD_PREP(CFG_BLOCK_SIZE, blocks) |
FIELD_PREP(CFG_BLOCK_NUM, 1);
} else {
blocks = min_t(int, blocks, SPISG_BLOCK_MAX);
desc->cfg_start |= FIELD_PREP(CFG_BLOCK_SIZE, block_size & 0x7) |
FIELD_PREP(CFG_BLOCK_NUM, blocks);
}
if (xfer->tx_sg.nents && xfer->tx_sg.sgl) {
ccsg_len = xfer->tx_sg.nents * sizeof(struct spisg_sg_link);
ccsg = kzalloc(ccsg_len, GFP_KERNEL | GFP_DMA);
if (!ccsg) {
dev_err(dev, "alloc tx_ccsg failed\n");
return -ENOMEM;
}
aml_spisg_sg_xlate(&xfer->tx_sg, ccsg);
paddr = dma_map_single(dev, (void *)ccsg,
ccsg_len, DMA_TO_DEVICE);
ret = dma_mapping_error(dev, paddr);
if (ret) {
kfree(ccsg);
dev_err(dev, "tx ccsg map failed\n");
return ret;
}
desc->tx_paddr = paddr;
desc->cfg_start |= FIELD_PREP(CFG_TXD_MODE, SPISG_DATA_MODE_SG);
exdesc->tx_ccsg = ccsg;
exdesc->tx_ccsg_len = ccsg_len;
dma_sync_sgtable_for_device(spisg->controller->cur_tx_dma_dev,
&xfer->tx_sg, DMA_TO_DEVICE);
} else if (xfer->tx_buf || xfer->tx_dma) {
paddr = xfer->tx_dma;
if (!paddr) {
paddr = dma_map_single(dev, (void *)xfer->tx_buf,
xfer->len, DMA_TO_DEVICE);
ret = dma_mapping_error(dev, paddr);
if (ret) {
dev_err(dev, "tx buf map failed\n");
return ret;
}
}
desc->tx_paddr = paddr;
desc->cfg_start |= FIELD_PREP(CFG_TXD_MODE, SPISG_DATA_MODE_MEM);
}
if (xfer->rx_sg.nents && xfer->rx_sg.sgl) {
ccsg_len = xfer->rx_sg.nents * sizeof(struct spisg_sg_link);
ccsg = kzalloc(ccsg_len, GFP_KERNEL | GFP_DMA);
if (!ccsg) {
dev_err(dev, "alloc rx_ccsg failed\n");
return -ENOMEM;
}
aml_spisg_sg_xlate(&xfer->rx_sg, ccsg);
paddr = dma_map_single(dev, (void *)ccsg,
ccsg_len, DMA_TO_DEVICE);
ret = dma_mapping_error(dev, paddr);
if (ret) {
kfree(ccsg);
dev_err(dev, "rx ccsg map failed\n");
return ret;
}
desc->rx_paddr = paddr;
desc->cfg_start |= FIELD_PREP(CFG_RXD_MODE, SPISG_DATA_MODE_SG);
exdesc->rx_ccsg = ccsg;
exdesc->rx_ccsg_len = ccsg_len;
dma_sync_sgtable_for_device(spisg->controller->cur_rx_dma_dev,
&xfer->rx_sg, DMA_FROM_DEVICE);
} else if (xfer->rx_buf || xfer->rx_dma) {
paddr = xfer->rx_dma;
if (!paddr) {
paddr = dma_map_single(dev, xfer->rx_buf,
xfer->len, DMA_FROM_DEVICE);
ret = dma_mapping_error(dev, paddr);
if (ret) {
dev_err(dev, "rx buf map failed\n");
return ret;
}
}
desc->rx_paddr = paddr;
desc->cfg_start |= FIELD_PREP(CFG_RXD_MODE, SPISG_DATA_MODE_MEM);
}
return 0;
}
static void aml_spisg_cleanup_transfer(struct spisg_device *spisg,
struct spi_transfer *xfer,
struct spisg_descriptor *desc,
struct spisg_descriptor_extra *exdesc)
{
struct device *dev = &spisg->pdev->dev;
if (desc->tx_paddr) {
if (FIELD_GET(CFG_TXD_MODE, desc->cfg_start) == SPISG_DATA_MODE_SG) {
dma_unmap_single(dev, (dma_addr_t)desc->tx_paddr,
exdesc->tx_ccsg_len, DMA_TO_DEVICE);
kfree(exdesc->tx_ccsg);
dma_sync_sgtable_for_cpu(spisg->controller->cur_tx_dma_dev,
&xfer->tx_sg, DMA_TO_DEVICE);
} else if (!xfer->tx_dma) {
dma_unmap_single(dev, (dma_addr_t)desc->tx_paddr,
xfer->len, DMA_TO_DEVICE);
}
}
if (desc->rx_paddr) {
if (FIELD_GET(CFG_RXD_MODE, desc->cfg_start) == SPISG_DATA_MODE_SG) {
dma_unmap_single(dev, (dma_addr_t)desc->rx_paddr,
exdesc->rx_ccsg_len, DMA_TO_DEVICE);
kfree(exdesc->rx_ccsg);
dma_sync_sgtable_for_cpu(spisg->controller->cur_rx_dma_dev,
&xfer->rx_sg, DMA_FROM_DEVICE);
} else if (!xfer->rx_dma) {
dma_unmap_single(dev, (dma_addr_t)desc->rx_paddr,
xfer->len, DMA_FROM_DEVICE);
}
}
}
static void aml_spisg_setup_null_desc(struct spisg_device *spisg,
struct spisg_descriptor *desc,
u32 n_sclk)
{
/* unit is the last xfer sclk */
desc->cfg_start = spisg->cfg_start;
desc->cfg_bus = spisg->cfg_bus;
desc->cfg_start |= FIELD_PREP(CFG_OP_MODE, SPISG_OP_MODE_WRITE) |
FIELD_PREP(CFG_BLOCK_SIZE, 1) |
FIELD_PREP(CFG_BLOCK_NUM, DIV_ROUND_UP(n_sclk, 8));
desc->cfg_bus |= FIELD_PREP(CFG_NULL_CTL, 1);
}
static void aml_spisg_pending(struct spisg_device *spisg,
dma_addr_t desc_paddr,
bool trig,
bool irq_en)
{
u32 desc_l, desc_h, cfg_spi, irq_enable;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
desc_l = (u64)desc_paddr & 0xffffffff;
desc_h = (u64)desc_paddr >> 32;
#else
desc_l = desc_paddr & 0xffffffff;
desc_h = 0;
#endif
cfg_spi = spisg->cfg_spi;
if (trig)
cfg_spi |= CFG_HW_POS;
else
desc_h |= LIST_DESC_PENDING;
irq_enable = IRQ_RCH_DESC_INVALID | IRQ_RCH_DESC_RESP |
IRQ_RCH_DATA_RESP | IRQ_WCH_DESC_INVALID |
IRQ_WCH_DESC_RESP | IRQ_WCH_DATA_RESP |
IRQ_DESC_ERR | IRQ_DESC_CHAIN_DONE;
regmap_write(spisg->map, SPISG_REG_IRQ_ENABLE, irq_en ? irq_enable : 0);
regmap_write(spisg->map, SPISG_REG_CFG_SPI, cfg_spi);
regmap_write(spisg->map, SPISG_REG_DESC_LIST_L, desc_l);
regmap_write(spisg->map, SPISG_REG_DESC_LIST_H, desc_h);
}
static irqreturn_t aml_spisg_irq(int irq, void *data)
{
struct spisg_device *spisg = (void *)data;
u32 sts;
spisg->status = 0;
regmap_read(spisg->map, SPISG_REG_IRQ_STS, &sts);
regmap_write(spisg->map, SPISG_REG_IRQ_STS, sts);
if (sts & (IRQ_RCH_DESC_INVALID |
IRQ_RCH_DESC_RESP |
IRQ_RCH_DATA_RESP |
IRQ_WCH_DESC_INVALID |
IRQ_WCH_DESC_RESP |
IRQ_WCH_DATA_RESP |
IRQ_DESC_ERR))
spisg->status = sts;
else if (sts & IRQ_DESC_CHAIN_DONE)
spisg->status = 0;
else
return IRQ_NONE;
complete(&spisg->completion);
return IRQ_HANDLED;
}
static int aml_spisg_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
struct spisg_device *spisg = spi_controller_get_devdata(ctlr);
struct device *dev = &spisg->pdev->dev;
unsigned long long ms = 0;
struct spi_transfer *xfer;
struct spisg_descriptor *descs, *desc;
struct spisg_descriptor_extra *exdescs, *exdesc;
dma_addr_t descs_paddr;
int desc_num = 1, descs_len;
u32 cs_hold_in_sclk = 0;
int ret = -EIO;
if (!aml_spisg_sem_down_read(spisg)) {
spi_finalize_current_message(ctlr);
dev_err(dev, "controller busy\n");
return -EBUSY;
}
/* calculate the desc num for all xfer */
list_for_each_entry(xfer, &msg->transfers, transfer_list)
desc_num++;
/* alloc descriptor/extra-descriptor table */
descs = kcalloc(desc_num, sizeof(*desc) + sizeof(*exdesc),
GFP_KERNEL | GFP_DMA);
if (!descs) {
spi_finalize_current_message(ctlr);
aml_spisg_sem_up_write(spisg);
return -ENOMEM;
}
descs_len = sizeof(*desc) * desc_num;
exdescs = (struct spisg_descriptor_extra *)(descs + desc_num);
/* config descriptor for each xfer */
desc = descs;
exdesc = exdescs;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
ret = aml_spisg_setup_transfer(spisg, xfer, desc, exdesc);
if (ret) {
dev_err(dev, "config descriptor failed\n");
goto end;
}
/* calculate cs-setup delay with the first xfer speed */
if (list_is_first(&xfer->transfer_list, &msg->transfers))
desc->cfg_bus |= FIELD_PREP(CFG_CS_SETUP,
spi_delay_to_sclk(xfer->effective_speed_hz, &msg->spi->cs_setup));
/* calculate cs-hold delay with the last xfer speed */
if (list_is_last(&xfer->transfer_list, &msg->transfers))
cs_hold_in_sclk =
spi_delay_to_sclk(xfer->effective_speed_hz, &msg->spi->cs_hold);
desc++;
exdesc++;
ms += DIV_ROUND_UP_ULL(8LL * MSEC_PER_SEC * xfer->len,
xfer->effective_speed_hz);
}
if (cs_hold_in_sclk)
/* additional null-descriptor to achieve the cs-hold delay */
aml_spisg_setup_null_desc(spisg, desc, cs_hold_in_sclk);
else
desc--;
desc->cfg_bus |= FIELD_PREP(CFG_KEEP_SS, 0);
desc->cfg_start |= FIELD_PREP(CFG_EOC, 1);
/* some tolerances */
ms += ms + 20;
if (ms > UINT_MAX)
ms = UINT_MAX;
descs_paddr = dma_map_single(dev, (void *)descs,
descs_len, DMA_TO_DEVICE);
ret = dma_mapping_error(dev, descs_paddr);
if (ret) {
dev_err(dev, "desc table map failed\n");
goto end;
}
reinit_completion(&spisg->completion);
aml_spisg_pending(spisg, descs_paddr, false, true);
if (wait_for_completion_timeout(&spisg->completion,
spi_controller_is_target(spisg->controller) ?
MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(ms)))
ret = spisg->status ? -EIO : 0;
else
ret = -ETIMEDOUT;
dma_unmap_single(dev, descs_paddr, descs_len, DMA_TO_DEVICE);
end:
desc = descs;
exdesc = exdescs;
list_for_each_entry(xfer, &msg->transfers, transfer_list)
aml_spisg_cleanup_transfer(spisg, xfer, desc++, exdesc++);
kfree(descs);
if (!ret)
msg->actual_length = msg->frame_length;
msg->status = ret;
spi_finalize_current_message(ctlr);
aml_spisg_sem_up_write(spisg);
return ret;
}
static int aml_spisg_prepare_message(struct spi_controller *ctlr,
struct spi_message *message)
{
struct spisg_device *spisg = spi_controller_get_devdata(ctlr);
struct spi_device *spi = message->spi;
if (!spi->bits_per_word || spi->bits_per_word % 8) {
dev_err(&spisg->pdev->dev, "invalid wordlen %d\n", spi->bits_per_word);
return -EINVAL;
}
spisg->bytes_per_word = spi->bits_per_word >> 3;
spisg->cfg_spi &= ~CFG_SLAVE_SELECT;
spisg->cfg_spi |= FIELD_PREP(CFG_SLAVE_SELECT, spi_get_chipselect(spi, 0));
spisg->cfg_bus &= ~(CFG_CPOL | CFG_CPHA | CFG_B_L_ENDIAN | CFG_HALF_DUPLEX);
spisg->cfg_bus |= FIELD_PREP(CFG_CPOL, !!(spi->mode & SPI_CPOL)) |
FIELD_PREP(CFG_CPHA, !!(spi->mode & SPI_CPHA)) |
FIELD_PREP(CFG_B_L_ENDIAN, !!(spi->mode & SPI_LSB_FIRST)) |
FIELD_PREP(CFG_HALF_DUPLEX, !!(spi->mode & SPI_3WIRE));
return 0;
}
static int aml_spisg_setup(struct spi_device *spi)
{
if (!spi->controller_state)
spi->controller_state = spi_controller_get_devdata(spi->controller);
return 0;
}
static void aml_spisg_cleanup(struct spi_device *spi)
{
spi->controller_state = NULL;
}
static int aml_spisg_target_abort(struct spi_controller *ctlr)
{
struct spisg_device *spisg = spi_controller_get_devdata(ctlr);
spisg->status = 0;
regmap_write(spisg->map, SPISG_REG_DESC_LIST_H, 0);
complete(&spisg->completion);
return 0;
}
static int aml_spisg_clk_init(struct spisg_device *spisg, void __iomem *base)
{
struct device *dev = &spisg->pdev->dev;
struct clk_init_data init;
struct clk_divider *div;
struct clk_div_table *tbl;
char name[32];
int ret, i;
spisg->core = devm_clk_get_enabled(dev, "core");
if (IS_ERR_OR_NULL(spisg->core)) {
dev_err(dev, "core clock request failed\n");
return PTR_ERR(spisg->core);
}
spisg->pclk = devm_clk_get_enabled(dev, "pclk");
if (IS_ERR_OR_NULL(spisg->pclk)) {
dev_err(dev, "pclk clock request failed\n");
return PTR_ERR(spisg->pclk);
}
clk_set_min_rate(spisg->pclk, SPISG_PCLK_RATE_MIN);
clk_disable_unprepare(spisg->pclk);
tbl = devm_kzalloc(dev, sizeof(struct clk_div_table) * (DIV_NUM + 1), GFP_KERNEL);
if (!tbl)
return -ENOMEM;
for (i = 0; i < DIV_NUM; i++) {
tbl[i].val = i + SPISG_CLK_DIV_MIN - 1;
tbl[i].div = i + SPISG_CLK_DIV_MIN;
}
spisg->tbl = tbl;
div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
if (!div)
return -ENOMEM;
div->flags = CLK_DIVIDER_ROUND_CLOSEST;
div->reg = base + SPISG_REG_CFG_BUS;
div->shift = __bf_shf(CFG_CLK_DIV);
div->width = CLK_DIV_WIDTH;
div->table = tbl;
/* Register value should not be outside of the table */
regmap_update_bits(spisg->map, SPISG_REG_CFG_BUS, CFG_CLK_DIV,
FIELD_PREP(CFG_CLK_DIV, SPISG_CLK_DIV_MIN - 1));
/* Register clk-divider */
snprintf(name, sizeof(name), "%s_div", dev_name(dev));
init.name = name;
init.ops = &clk_divider_ops;
init.flags = CLK_SET_RATE_PARENT;
init.parent_data = &(const struct clk_parent_data) {
.fw_name = "pclk",
};
init.num_parents = 1;
div->hw.init = &init;
ret = devm_clk_hw_register(dev, &div->hw);
if (ret) {
dev_err(dev, "clock registration failed\n");
return ret;
}
spisg->sclk = devm_clk_hw_get_clk(dev, &div->hw, NULL);
if (IS_ERR_OR_NULL(spisg->sclk)) {
dev_err(dev, "get clock failed\n");
return PTR_ERR(spisg->sclk);
}
clk_prepare_enable(spisg->sclk);
return 0;
}
static int aml_spisg_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
struct spisg_device *spisg;
struct device *dev = &pdev->dev;
void __iomem *base;
int ret, irq;
const struct regmap_config aml_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = SPISG_MAX_REG,
};
if (of_property_read_bool(dev->of_node, "spi-slave"))
ctlr = spi_alloc_target(dev, sizeof(*spisg));
else
ctlr = spi_alloc_host(dev, sizeof(*spisg));
if (!ctlr)
return dev_err_probe(dev, -ENOMEM, "controller allocation failed\n");
spisg = spi_controller_get_devdata(ctlr);
spisg->controller = ctlr;
spisg->pdev = pdev;
platform_set_drvdata(pdev, spisg);
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return dev_err_probe(dev, PTR_ERR(base), "resource ioremap failed\n");
spisg->map = devm_regmap_init_mmio(dev, base, &aml_regmap_config);
if (IS_ERR(spisg->map))
return dev_err_probe(dev, PTR_ERR(spisg->map), "regmap init failed\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
goto out_controller;
}
ret = device_reset_optional(dev);
if (ret)
return dev_err_probe(dev, ret, "reset dev failed\n");
ret = aml_spisg_clk_init(spisg, base);
if (ret)
return dev_err_probe(dev, ret, "clock init failed\n");
spisg->cfg_spi = 0;
spisg->cfg_start = 0;
spisg->cfg_bus = 0;
spisg->cfg_spi = FIELD_PREP(CFG_SFLASH_WP, 1) |
FIELD_PREP(CFG_SFLASH_HD, 1);
if (spi_controller_is_target(ctlr)) {
spisg->cfg_spi |= FIELD_PREP(CFG_SLAVE_EN, 1);
spisg->cfg_bus = FIELD_PREP(CFG_TX_TUNING, 0xf);
}
/* default pending */
spisg->cfg_start = FIELD_PREP(CFG_PEND, 1);
pm_runtime_set_active(&spisg->pdev->dev);
pm_runtime_enable(&spisg->pdev->dev);
pm_runtime_resume_and_get(&spisg->pdev->dev);
ctlr->num_chipselect = 4;
ctlr->dev.of_node = pdev->dev.of_node;
ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST |
SPI_3WIRE | SPI_TX_QUAD | SPI_RX_QUAD;
ctlr->max_speed_hz = 1000 * 1000 * 100;
ctlr->min_speed_hz = 1000 * 10;
ctlr->setup = aml_spisg_setup;
ctlr->cleanup = aml_spisg_cleanup;
ctlr->prepare_message = aml_spisg_prepare_message;
ctlr->transfer_one_message = aml_spisg_transfer_one_message;
ctlr->target_abort = aml_spisg_target_abort;
ctlr->can_dma = aml_spisg_can_dma;
ctlr->max_dma_len = SPISG_BLOCK_MAX;
ctlr->auto_runtime_pm = true;
dma_set_max_seg_size(&pdev->dev, SPISG_BLOCK_MAX);
ret = devm_request_irq(&pdev->dev, irq, aml_spisg_irq, 0, NULL, spisg);
if (ret) {
dev_err(&pdev->dev, "irq request failed\n");
goto out_clk;
}
ret = devm_spi_register_controller(dev, ctlr);
if (ret) {
dev_err(&pdev->dev, "spi controller registration failed\n");
goto out_clk;
}
init_completion(&spisg->completion);
pm_runtime_put(&spisg->pdev->dev);
return 0;
out_clk:
if (spisg->core)
clk_disable_unprepare(spisg->core);
clk_disable_unprepare(spisg->pclk);
out_controller:
spi_controller_put(ctlr);
return ret;
}
static void aml_spisg_remove(struct platform_device *pdev)
{
struct spisg_device *spisg = platform_get_drvdata(pdev);
if (!pm_runtime_suspended(&pdev->dev)) {
pinctrl_pm_select_sleep_state(&spisg->pdev->dev);
clk_disable_unprepare(spisg->core);
clk_disable_unprepare(spisg->pclk);
}
}
static int spisg_suspend_runtime(struct device *dev)
{
struct spisg_device *spisg = dev_get_drvdata(dev);
pinctrl_pm_select_sleep_state(&spisg->pdev->dev);
clk_disable_unprepare(spisg->sclk);
clk_disable_unprepare(spisg->core);
return 0;
}
static int spisg_resume_runtime(struct device *dev)
{
struct spisg_device *spisg = dev_get_drvdata(dev);
clk_prepare_enable(spisg->core);
clk_prepare_enable(spisg->sclk);
pinctrl_pm_select_default_state(&spisg->pdev->dev);
return 0;
}
static const struct dev_pm_ops amlogic_spisg_pm_ops = {
.runtime_suspend = spisg_suspend_runtime,
.runtime_resume = spisg_resume_runtime,
};
static const struct of_device_id amlogic_spisg_of_match[] = {
{
.compatible = "amlogic,a4-spisg",
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, amlogic_spisg_of_match);
static struct platform_driver amlogic_spisg_driver = {
.probe = aml_spisg_probe,
.remove = aml_spisg_remove,
.driver = {
.name = "amlogic-spisg",
.of_match_table = amlogic_spisg_of_match,
.pm = &amlogic_spisg_pm_ops,
},
};
module_platform_driver(amlogic_spisg_driver);
MODULE_DESCRIPTION("Amlogic SPI Scatter-Gather Controller driver");
MODULE_AUTHOR("Sunny Luo <sunny.luo@amlogic.com>");
MODULE_LICENSE("GPL");

View File

@ -1469,7 +1469,6 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
ret = cqspi_mem_process(mem, op);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
if (ret)
@ -1970,7 +1969,6 @@ static int cqspi_probe(struct platform_device *pdev)
goto probe_setup_failed;
}
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;

View File

@ -662,7 +662,6 @@ static int cdns_spi_probe(struct platform_device *pdev)
/* Set to default valid value */
ctlr->max_speed_hz = xspi->clk_rate / 4;
xspi->speed_hz = ctlr->max_speed_hz;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
} else {
ctlr->mode_bits |= SPI_NO_CS;

View File

@ -94,8 +94,9 @@ struct falcon_sflash {
struct spi_controller *host;
};
int falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t,
unsigned long flags)
static int
falcon_sflash_xfer(struct spi_device *spi, struct spi_transfer *t,
unsigned long flags)
{
struct device *dev = &spi->dev;
struct falcon_sflash *priv = spi_controller_get_devdata(spi->controller);

View File

@ -24,6 +24,7 @@
#define SPI_MCR 0x00
#define SPI_MCR_HOST BIT(31)
#define SPI_MCR_MTFE BIT(26)
#define SPI_MCR_PCSIS(x) ((x) << 16)
#define SPI_MCR_CLR_TXF BIT(11)
#define SPI_MCR_CLR_RXF BIT(10)
@ -35,8 +36,9 @@
#define SPI_TCR 0x08
#define SPI_TCR_GET_TCNT(x) (((x) & GENMASK(31, 16)) >> 16)
#define SPI_CTAR(x) (0x0c + (((x) & GENMASK(1, 0)) * 4))
#define SPI_CTAR(x) (0x0c + (((x) & GENMASK(2, 0)) * 4))
#define SPI_CTAR_FMSZ(x) (((x) << 27) & GENMASK(30, 27))
#define SPI_CTAR_DBR BIT(31)
#define SPI_CTAR_CPOL BIT(26)
#define SPI_CTAR_CPHA BIT(25)
#define SPI_CTAR_LSBFE BIT(24)
@ -93,12 +95,14 @@
#define SPI_TXFR1 0x40
#define SPI_TXFR2 0x44
#define SPI_TXFR3 0x48
#define SPI_TXFR4 0x4C
#define SPI_RXFR0 0x7c
#define SPI_RXFR1 0x80
#define SPI_RXFR2 0x84
#define SPI_RXFR3 0x88
#define SPI_RXFR4 0x8C
#define SPI_CTARE(x) (0x11c + (((x) & GENMASK(1, 0)) * 4))
#define SPI_CTARE(x) (0x11c + (((x) & GENMASK(2, 0)) * 4))
#define SPI_CTARE_FMSZE(x) (((x) & 0x1) << 16)
#define SPI_CTARE_DTCP(x) ((x) & 0x7ff)
@ -109,6 +113,8 @@
#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
#define SPI_25MHZ 25000000
struct chip_data {
u32 ctar_val;
};
@ -122,6 +128,7 @@ struct fsl_dspi_devtype_data {
enum dspi_trans_mode trans_mode;
u8 max_clock_factor;
int fifo_size;
const struct regmap_config *regmap;
};
enum {
@ -135,6 +142,102 @@ enum {
LX2160A,
MCF5441X,
VF610,
S32G,
S32G_TARGET,
};
static const struct regmap_range dspi_yes_ranges[] = {
regmap_reg_range(SPI_MCR, SPI_MCR),
regmap_reg_range(SPI_TCR, SPI_CTAR(3)),
regmap_reg_range(SPI_SR, SPI_TXFR3),
regmap_reg_range(SPI_RXFR0, SPI_RXFR3),
regmap_reg_range(SPI_CTARE(0), SPI_CTARE(3)),
regmap_reg_range(SPI_SREX, SPI_SREX),
};
static const struct regmap_range s32g_dspi_yes_ranges[] = {
regmap_reg_range(SPI_MCR, SPI_MCR),
regmap_reg_range(SPI_TCR, SPI_CTAR(5)),
regmap_reg_range(SPI_SR, SPI_TXFR4),
regmap_reg_range(SPI_RXFR0, SPI_RXFR4),
regmap_reg_range(SPI_CTARE(0), SPI_CTARE(5)),
regmap_reg_range(SPI_SREX, SPI_SREX),
};
static const struct regmap_access_table dspi_access_table = {
.yes_ranges = dspi_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(dspi_yes_ranges),
};
static const struct regmap_access_table s32g_dspi_access_table = {
.yes_ranges = s32g_dspi_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(s32g_dspi_yes_ranges),
};
static const struct regmap_range dspi_volatile_ranges[] = {
regmap_reg_range(SPI_MCR, SPI_TCR),
regmap_reg_range(SPI_SR, SPI_SR),
regmap_reg_range(SPI_PUSHR, SPI_RXFR4),
regmap_reg_range(SPI_SREX, SPI_SREX),
};
static const struct regmap_access_table dspi_volatile_table = {
.yes_ranges = dspi_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(dspi_volatile_ranges),
};
enum {
DSPI_REGMAP,
S32G_DSPI_REGMAP,
DSPI_XSPI_REGMAP,
S32G_DSPI_XSPI_REGMAP,
DSPI_PUSHR,
};
static const struct regmap_config dspi_regmap_config[] = {
[DSPI_REGMAP] = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = SPI_RXFR3,
.volatile_table = &dspi_volatile_table,
.rd_table = &dspi_access_table,
.wr_table = &dspi_access_table,
},
[S32G_DSPI_REGMAP] = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = SPI_RXFR4,
.volatile_table = &dspi_volatile_table,
.wr_table = &s32g_dspi_access_table,
.rd_table = &s32g_dspi_access_table,
},
[DSPI_XSPI_REGMAP] = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = SPI_SREX,
.volatile_table = &dspi_volatile_table,
.rd_table = &dspi_access_table,
.wr_table = &dspi_access_table,
},
[S32G_DSPI_XSPI_REGMAP] = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = SPI_SREX,
.volatile_table = &dspi_volatile_table,
.wr_table = &s32g_dspi_access_table,
.rd_table = &s32g_dspi_access_table,
},
[DSPI_PUSHR] = {
.name = "pushr",
.reg_bits = 16,
.val_bits = 16,
.reg_stride = 2,
.max_register = 0x2,
},
};
static const struct fsl_dspi_devtype_data devtype_data[] = {
@ -142,55 +245,77 @@ static const struct fsl_dspi_devtype_data devtype_data[] = {
.trans_mode = DSPI_DMA_MODE,
.max_clock_factor = 2,
.fifo_size = 4,
.regmap = &dspi_regmap_config[DSPI_REGMAP],
},
[LS1021A] = {
/* Has A-011218 DMA erratum */
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
.regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS1012A] = {
/* Has A-011218 DMA erratum */
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 16,
.regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS1028A] = {
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
.regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS1043A] = {
/* Has A-011218 DMA erratum */
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 16,
.regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS1046A] = {
/* Has A-011218 DMA erratum */
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 16,
.regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS2080A] = {
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
.regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LS2085A] = {
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
.regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[LX2160A] = {
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 8,
.fifo_size = 4,
.regmap = &dspi_regmap_config[DSPI_XSPI_REGMAP],
},
[MCF5441X] = {
.trans_mode = DSPI_DMA_MODE,
.max_clock_factor = 8,
.fifo_size = 16,
.regmap = &dspi_regmap_config[DSPI_REGMAP],
},
[S32G] = {
.trans_mode = DSPI_XSPI_MODE,
.max_clock_factor = 1,
.fifo_size = 5,
.regmap = &dspi_regmap_config[S32G_DSPI_XSPI_REGMAP],
},
[S32G_TARGET] = {
.trans_mode = DSPI_DMA_MODE,
.max_clock_factor = 1,
.fifo_size = 5,
.regmap = &dspi_regmap_config[S32G_DSPI_REGMAP],
},
};
@ -225,6 +350,7 @@ struct fsl_dspi {
const void *tx;
void *rx;
u16 tx_cmd;
bool mtf_enabled;
const struct fsl_dspi_devtype_data *devtype_data;
struct completion xfer_done;
@ -247,6 +373,12 @@ struct fsl_dspi {
void (*dev_to_host)(struct fsl_dspi *dspi, u32 rxdata);
};
static bool is_s32g_dspi(struct fsl_dspi *data)
{
return data->devtype_data == &devtype_data[S32G] ||
data->devtype_data == &devtype_data[S32G_TARGET];
}
static void dspi_native_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
{
switch (dspi->oper_word_size) {
@ -595,7 +727,7 @@ static void dspi_release_dma(struct fsl_dspi *dspi)
}
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
unsigned long clkrate)
unsigned long clkrate, bool mtf_enabled)
{
/* Valid baud rate pre-scaler values */
int pbr_tbl[4] = {2, 3, 5, 7};
@ -612,7 +744,13 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
for (i = 0; i < ARRAY_SIZE(brs); i++)
for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) {
scale = brs[i] * pbr_tbl[j];
if (mtf_enabled) {
/* In MTF mode DBR=1 so frequency is doubled */
scale = (brs[i] * pbr_tbl[j]) / 2;
} else {
scale = brs[i] * pbr_tbl[j];
}
if (scale >= scale_needed) {
if (scale < minscale) {
minscale = scale;
@ -746,8 +884,12 @@ static void dspi_setup_accel(struct fsl_dspi *dspi)
struct spi_transfer *xfer = dspi->cur_transfer;
bool odd = !!(dspi->len & 1);
/* No accel for frames not multiple of 8 bits at the moment */
if (xfer->bits_per_word % 8)
/*
* No accel for DMA transfers or frames not multiples of 8 bits at the
* moment.
*/
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE ||
xfer->bits_per_word % 8)
goto no_accel;
if (!odd && dspi->len <= dspi->devtype_data->fifo_size * 2) {
@ -756,10 +898,7 @@ static void dspi_setup_accel(struct fsl_dspi *dspi)
dspi->oper_bits_per_word = 8;
} else {
/* Start off with maximum supported by hardware */
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
dspi->oper_bits_per_word = 32;
else
dspi->oper_bits_per_word = 16;
dspi->oper_bits_per_word = 32;
/*
* And go down only if the buffer can't be sent with
@ -1027,6 +1166,20 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
return status;
}
static int dspi_set_mtf(struct fsl_dspi *dspi)
{
if (spi_controller_is_target(dspi->ctlr))
return 0;
if (dspi->mtf_enabled)
regmap_update_bits(dspi->regmap, SPI_MCR, SPI_MCR_MTFE,
SPI_MCR_MTFE);
else
regmap_update_bits(dspi->regmap, SPI_MCR, SPI_MCR_MTFE, 0);
return 0;
}
static int dspi_setup(struct spi_device *spi)
{
struct fsl_dspi *dspi = spi_controller_get_devdata(spi->controller);
@ -1085,7 +1238,16 @@ static int dspi_setup(struct spi_device *spi)
cs_sck_delay, sck_cs_delay);
clkrate = clk_get_rate(dspi->clk);
hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
if (is_s32g_dspi(dspi) && spi->max_speed_hz > SPI_25MHZ)
dspi->mtf_enabled = true;
else
dspi->mtf_enabled = false;
dspi_set_mtf(dspi);
hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate,
dspi->mtf_enabled);
/* Set PCS to SCK delay scale values */
ns_delay_scale(&pcssck, &cssck, cs_sck_delay, clkrate);
@ -1107,6 +1269,9 @@ static int dspi_setup(struct spi_device *spi)
SPI_CTAR_PBR(pbr) |
SPI_CTAR_BR(br);
if (dspi->mtf_enabled)
chip->ctar_val |= SPI_CTAR_DBR;
if (spi->mode & SPI_LSB_FIRST)
chip->ctar_val |= SPI_CTAR_LSBFE;
}
@ -1160,112 +1325,14 @@ static const struct of_device_id fsl_dspi_dt_ids[] = {
}, {
.compatible = "fsl,lx2160a-dspi",
.data = &devtype_data[LX2160A],
}, {
.compatible = "nxp,s32g2-dspi",
.data = &devtype_data[S32G],
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids);
#ifdef CONFIG_PM_SLEEP
static int dspi_suspend(struct device *dev)
{
struct fsl_dspi *dspi = dev_get_drvdata(dev);
if (dspi->irq)
disable_irq(dspi->irq);
spi_controller_suspend(dspi->ctlr);
clk_disable_unprepare(dspi->clk);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int dspi_resume(struct device *dev)
{
struct fsl_dspi *dspi = dev_get_drvdata(dev);
int ret;
pinctrl_pm_select_default_state(dev);
ret = clk_prepare_enable(dspi->clk);
if (ret)
return ret;
spi_controller_resume(dspi->ctlr);
if (dspi->irq)
enable_irq(dspi->irq);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
static const struct regmap_range dspi_yes_ranges[] = {
regmap_reg_range(SPI_MCR, SPI_MCR),
regmap_reg_range(SPI_TCR, SPI_CTAR(3)),
regmap_reg_range(SPI_SR, SPI_TXFR3),
regmap_reg_range(SPI_RXFR0, SPI_RXFR3),
regmap_reg_range(SPI_CTARE(0), SPI_CTARE(3)),
regmap_reg_range(SPI_SREX, SPI_SREX),
};
static const struct regmap_access_table dspi_access_table = {
.yes_ranges = dspi_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(dspi_yes_ranges),
};
static const struct regmap_range dspi_volatile_ranges[] = {
regmap_reg_range(SPI_MCR, SPI_TCR),
regmap_reg_range(SPI_SR, SPI_SR),
regmap_reg_range(SPI_PUSHR, SPI_RXFR3),
};
static const struct regmap_access_table dspi_volatile_table = {
.yes_ranges = dspi_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(dspi_volatile_ranges),
};
static const struct regmap_config dspi_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0x88,
.volatile_table = &dspi_volatile_table,
.rd_table = &dspi_access_table,
.wr_table = &dspi_access_table,
};
static const struct regmap_range dspi_xspi_volatile_ranges[] = {
regmap_reg_range(SPI_MCR, SPI_TCR),
regmap_reg_range(SPI_SR, SPI_SR),
regmap_reg_range(SPI_PUSHR, SPI_RXFR3),
regmap_reg_range(SPI_SREX, SPI_SREX),
};
static const struct regmap_access_table dspi_xspi_volatile_table = {
.yes_ranges = dspi_xspi_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(dspi_xspi_volatile_ranges),
};
static const struct regmap_config dspi_xspi_regmap_config[] = {
{
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0x13c,
.volatile_table = &dspi_xspi_volatile_table,
.rd_table = &dspi_access_table,
.wr_table = &dspi_access_table,
},
{
.name = "pushr",
.reg_bits = 16,
.val_bits = 16,
.reg_stride = 2,
.max_register = 0x2,
},
};
static int dspi_init(struct fsl_dspi *dspi)
{
unsigned int mcr;
@ -1301,6 +1368,50 @@ static int dspi_init(struct fsl_dspi *dspi)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int dspi_suspend(struct device *dev)
{
struct fsl_dspi *dspi = dev_get_drvdata(dev);
if (dspi->irq)
disable_irq(dspi->irq);
spi_controller_suspend(dspi->ctlr);
clk_disable_unprepare(dspi->clk);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int dspi_resume(struct device *dev)
{
struct fsl_dspi *dspi = dev_get_drvdata(dev);
int ret;
pinctrl_pm_select_default_state(dev);
ret = clk_prepare_enable(dspi->clk);
if (ret)
return ret;
spi_controller_resume(dspi->ctlr);
ret = dspi_init(dspi);
if (ret) {
dev_err(dev, "failed to initialize dspi during resume\n");
return ret;
}
dspi_set_mtf(dspi);
if (dspi->irq)
enable_irq(dspi->irq);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
static int dspi_target_abort(struct spi_controller *host)
{
struct fsl_dspi *dspi = spi_controller_get_devdata(host);
@ -1325,7 +1436,6 @@ static int dspi_target_abort(struct spi_controller *host)
static int dspi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const struct regmap_config *regmap_config;
struct fsl_dspi_platform_data *pdata;
struct spi_controller *ctlr;
int ret, cs_num, bus_num = -1;
@ -1338,7 +1448,10 @@ static int dspi_probe(struct platform_device *pdev)
if (!dspi)
return -ENOMEM;
ctlr = spi_alloc_host(&pdev->dev, 0);
if (of_property_read_bool(np, "spi-slave"))
ctlr = spi_alloc_target(&pdev->dev, 0);
else
ctlr = spi_alloc_host(&pdev->dev, 0);
if (!ctlr)
return -ENOMEM;
@ -1377,9 +1490,6 @@ static int dspi_probe(struct platform_device *pdev)
of_property_read_u32(np, "bus-num", &bus_num);
ctlr->bus_num = bus_num;
if (of_property_read_bool(np, "spi-slave"))
ctlr->target = true;
dspi->devtype_data = of_device_get_match_data(&pdev->dev);
if (!dspi->devtype_data) {
dev_err(&pdev->dev, "can't get devtype_data\n");
@ -1397,6 +1507,9 @@ static int dspi_probe(struct platform_device *pdev)
dspi->pushr_tx = 0;
}
if (spi_controller_is_target(ctlr) && is_s32g_dspi(dspi))
dspi->devtype_data = &devtype_data[S32G_TARGET];
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
else
@ -1408,11 +1521,8 @@ static int dspi_probe(struct platform_device *pdev)
goto out_ctlr_put;
}
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
regmap_config = &dspi_xspi_regmap_config[0];
else
regmap_config = &dspi_regmap_config;
dspi->regmap = devm_regmap_init_mmio(&pdev->dev, base, regmap_config);
dspi->regmap = devm_regmap_init_mmio(&pdev->dev, base,
dspi->devtype_data->regmap);
if (IS_ERR(dspi->regmap)) {
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
PTR_ERR(dspi->regmap));
@ -1423,7 +1533,7 @@ static int dspi_probe(struct platform_device *pdev)
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE) {
dspi->regmap_pushr = devm_regmap_init_mmio(
&pdev->dev, base + SPI_PUSHR,
&dspi_xspi_regmap_config[1]);
&dspi_regmap_config[DSPI_PUSHR]);
if (IS_ERR(dspi->regmap_pushr)) {
dev_err(&pdev->dev,
"failed to init pushr regmap: %ld\n",

View File

@ -513,7 +513,6 @@ static int fsl_espi_setup(struct spi_device *spi)
fsl_espi_setup_transfer(spi, NULL);
pm_runtime_mark_last_busy(espi->dev);
pm_runtime_put_autosuspend(espi->dev);
return 0;
@ -726,7 +725,6 @@ static int fsl_espi_probe(struct device *dev, struct resource *mem,
dev_info(dev, "irq = %u\n", irq);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;

View File

@ -233,7 +233,6 @@ static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller)
struct fsl_lpspi_data *fsl_lpspi =
spi_controller_get_devdata(controller);
pm_runtime_mark_last_busy(fsl_lpspi->dev);
pm_runtime_put_autosuspend(fsl_lpspi->dev);
return 0;
@ -966,7 +965,6 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
goto free_dma;
}
pm_runtime_mark_last_busy(fsl_lpspi->dev);
pm_runtime_put_autosuspend(fsl_lpspi->dev);
return 0;

View File

@ -104,7 +104,7 @@ static inline int getmiso(const struct spi_device *spi)
*/
static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha0(spi, nsecs, 0, flags, word, bits);
@ -113,7 +113,7 @@ static u32 spi_gpio_txrx_word_mode0(struct spi_device *spi,
}
static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha1(spi, nsecs, 0, flags, word, bits);
@ -122,7 +122,7 @@ static u32 spi_gpio_txrx_word_mode1(struct spi_device *spi,
}
static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha0(spi, nsecs, 1, flags, word, bits);
@ -131,7 +131,7 @@ static u32 spi_gpio_txrx_word_mode2(struct spi_device *spi,
}
static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
if (unlikely(spi->mode & SPI_LSB_FIRST))
return bitbang_txrx_le_cpha1(spi, nsecs, 1, flags, word, bits);
@ -150,7 +150,7 @@ static u32 spi_gpio_txrx_word_mode3(struct spi_device *spi,
*/
static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
@ -160,7 +160,7 @@ static u32 spi_gpio_spec_txrx_word_mode0(struct spi_device *spi,
}
static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
@ -170,7 +170,7 @@ static u32 spi_gpio_spec_txrx_word_mode1(struct spi_device *spi,
}
static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))
@ -180,7 +180,7 @@ static u32 spi_gpio_spec_txrx_word_mode2(struct spi_device *spi,
}
static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits, unsigned flags)
unsigned int nsecs, u32 word, u8 bits, unsigned int flags)
{
flags = spi->controller->flags;
if (unlikely(spi->mode & SPI_LSB_FIRST))

View File

@ -1748,7 +1748,6 @@ spi_imx_prepare_message(struct spi_controller *controller, struct spi_message *m
ret = spi_imx->devtype_data->prepare_message(spi_imx, msg);
if (ret) {
pm_runtime_mark_last_busy(spi_imx->dev);
pm_runtime_put_autosuspend(spi_imx->dev);
}
@ -1760,7 +1759,6 @@ spi_imx_unprepare_message(struct spi_controller *controller, struct spi_message
{
struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
pm_runtime_mark_last_busy(spi_imx->dev);
pm_runtime_put_autosuspend(spi_imx->dev);
return 0;
}
@ -1933,7 +1931,6 @@ static int spi_imx_probe(struct platform_device *pdev)
goto out_register_controller;
}
pm_runtime_mark_last_busy(spi_imx->dev);
pm_runtime_put_autosuspend(spi_imx->dev);
return ret;

View File

@ -189,6 +189,11 @@ struct intel_spi_mem_op {
static bool writeable;
module_param(writeable, bool, 0);
MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)");
static bool ignore_protection_status;
module_param(ignore_protection_status, bool, 0);
MODULE_PARM_DESC(
ignore_protection_status,
"Do not block SPI flash chip write access even if it is write-protected (default=0)");
static void intel_spi_dump_regs(struct intel_spi *ispi)
{
@ -1248,13 +1253,15 @@ static void intel_spi_fill_partition(struct intel_spi *ispi,
continue;
/*
* If any of the regions have protection bits set, make the
* whole partition read-only to be on the safe side.
* If any of the regions have protection bits set and
* the ignore protection status parameter is not set,
* make the whole partition read-only to be on the safe side.
*
* Also if the user did not ask the chip to be writeable
* mask the bit too.
*/
if (!writeable || intel_spi_is_protected(ispi, base, limit)) {
if (!writeable || (!ignore_protection_status &&
intel_spi_is_protected(ispi, base, limit))) {
part->mask_flags |= MTD_WRITEABLE;
ispi->protected = true;
}

View File

@ -194,7 +194,7 @@ static inline void mchp_coreqspi_read_op(struct mchp_coreqspi *qspi)
}
}
static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word)
static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi)
{
u32 control, data;
@ -222,6 +222,87 @@ static inline void mchp_coreqspi_write_op(struct mchp_coreqspi *qspi, bool word)
}
}
static inline void mchp_coreqspi_write_read_op(struct mchp_coreqspi *qspi)
{
u32 control, data;
qspi->rx_len = qspi->tx_len;
control = readl_relaxed(qspi->regs + REG_CONTROL);
control |= CONTROL_FLAGSX4;
writel_relaxed(control, qspi->regs + REG_CONTROL);
while (qspi->tx_len >= 4) {
while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL)
;
data = qspi->txbuf ? *((u32 *)qspi->txbuf) : 0xaa;
if (qspi->txbuf)
qspi->txbuf += 4;
qspi->tx_len -= 4;
writel_relaxed(data, qspi->regs + REG_X4_TX_DATA);
/*
* The rx FIFO is twice the size of the tx FIFO, so there is
* no requirement to block transmission if receive data is not
* ready, and it is fine to let the tx FIFO completely fill
* without reading anything from the rx FIFO. Once the tx FIFO
* has been filled and becomes non-full due to a transmission
* occurring there will always be something to receive.
* IOW, this is safe as TX_FIFO_SIZE + 4 < 2 * TX_FIFO_SIZE
*/
if (qspi->rx_len >= 4) {
if (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXAVAILABLE) {
data = readl_relaxed(qspi->regs + REG_X4_RX_DATA);
*(u32 *)qspi->rxbuf = data;
qspi->rxbuf += 4;
qspi->rx_len -= 4;
}
}
}
/*
* Since transmission is not being blocked by clearing the rx FIFO,
* loop here until all received data "leaked" by the loop above has
* been dealt with.
*/
while (qspi->rx_len >= 4) {
while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY)
;
data = readl_relaxed(qspi->regs + REG_X4_RX_DATA);
*(u32 *)qspi->rxbuf = data;
qspi->rxbuf += 4;
qspi->rx_len -= 4;
}
/*
* Since rx_len and tx_len must be < 4 bytes at this point, there's no
* concern about overflowing the rx or tx FIFOs any longer. It's
* therefore safe to loop over the remainder of the transmit data before
* handling the remaining receive data.
*/
if (!qspi->tx_len)
return;
control &= ~CONTROL_FLAGSX4;
writel_relaxed(control, qspi->regs + REG_CONTROL);
while (qspi->tx_len--) {
while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_TXFIFOFULL)
;
data = qspi->txbuf ? *qspi->txbuf : 0xaa;
qspi->txbuf++;
writel_relaxed(data, qspi->regs + REG_TX_DATA);
}
while (qspi->rx_len--) {
while (readl_relaxed(qspi->regs + REG_STATUS) & STATUS_RXFIFOEMPTY)
;
data = readl_relaxed(qspi->regs + REG_RX_DATA);
*qspi->rxbuf++ = (data & 0xFF);
}
}
static void mchp_coreqspi_enable_ints(struct mchp_coreqspi *qspi)
{
u32 mask = IEN_TXDONE |
@ -266,7 +347,7 @@ static irqreturn_t mchp_coreqspi_isr(int irq, void *dev_id)
}
static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi,
const struct spi_mem_op *op)
u32 max_freq)
{
unsigned long clk_hz;
u32 control, baud_rate_val = 0;
@ -275,11 +356,11 @@ static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_devi
if (!clk_hz)
return -EINVAL;
baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * op->max_freq);
baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * max_freq);
if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER) {
dev_err(&spi->dev,
"could not configure the clock for spi clock %d Hz & system clock %ld Hz\n",
op->max_freq, clk_hz);
max_freq, clk_hz);
return -EINVAL;
}
@ -367,23 +448,13 @@ static inline void mchp_coreqspi_config_op(struct mchp_coreqspi *qspi, const str
writel_relaxed(frames, qspi->regs + REG_FRAMES);
}
static int mchp_qspi_wait_for_ready(struct spi_mem *mem)
static int mchp_coreqspi_wait_for_ready(struct mchp_coreqspi *qspi)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata
(mem->spi->controller);
u32 status;
int ret;
ret = readl_poll_timeout(qspi->regs + REG_STATUS, status,
return readl_poll_timeout(qspi->regs + REG_STATUS, status,
(status & STATUS_READY), 0,
TIMEOUT_MS);
if (ret) {
dev_err(&mem->spi->dev,
"Timeout waiting on QSPI ready.\n");
return -ETIMEDOUT;
}
return ret;
}
static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
@ -396,11 +467,13 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
int err, i;
mutex_lock(&qspi->op_lock);
err = mchp_qspi_wait_for_ready(mem);
if (err)
err = mchp_coreqspi_wait_for_ready(qspi);
if (err) {
dev_err(&mem->spi->dev, "Timeout waiting on QSPI ready.\n");
goto error;
}
err = mchp_coreqspi_setup_clock(qspi, mem->spi, op);
err = mchp_coreqspi_setup_clock(qspi, mem->spi, op->max_freq);
if (err)
goto error;
@ -415,7 +488,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
qspi->rxbuf = NULL;
qspi->tx_len = op->cmd.nbytes;
qspi->rx_len = 0;
mchp_coreqspi_write_op(qspi, false);
mchp_coreqspi_write_op(qspi);
}
qspi->txbuf = &opaddr[0];
@ -426,7 +499,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
qspi->rxbuf = NULL;
qspi->tx_len = op->addr.nbytes;
qspi->rx_len = 0;
mchp_coreqspi_write_op(qspi, false);
mchp_coreqspi_write_op(qspi);
}
if (op->data.nbytes) {
@ -435,7 +508,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
qspi->rxbuf = NULL;
qspi->rx_len = 0;
qspi->tx_len = op->data.nbytes;
mchp_coreqspi_write_op(qspi, true);
mchp_coreqspi_write_op(qspi);
} else {
qspi->txbuf = NULL;
qspi->rxbuf = (u8 *)op->data.buf.in;
@ -515,6 +588,109 @@ static const struct spi_controller_mem_caps mchp_coreqspi_mem_caps = {
.per_op_freq = true,
};
static int mchp_coreqspi_unprepare_message(struct spi_controller *ctlr, struct spi_message *m)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
/*
* This delay is required for the driver to function correctly,
* but no explanation has been determined for why it is required.
*/
udelay(750);
mutex_unlock(&qspi->op_lock);
return 0;
}
static int mchp_coreqspi_prepare_message(struct spi_controller *ctlr, struct spi_message *m)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
struct spi_transfer *t = NULL;
u32 control, frames;
u32 total_bytes = 0, cmd_bytes = 0, idle_cycles = 0;
int ret;
bool quad = false, dual = false;
mutex_lock(&qspi->op_lock);
ret = mchp_coreqspi_wait_for_ready(qspi);
if (ret) {
mutex_unlock(&qspi->op_lock);
dev_err(&ctlr->dev, "Timeout waiting on QSPI ready.\n");
return ret;
}
ret = mchp_coreqspi_setup_clock(qspi, m->spi, m->spi->max_speed_hz);
if (ret) {
mutex_unlock(&qspi->op_lock);
return ret;
}
control = readl_relaxed(qspi->regs + REG_CONTROL);
control &= ~(CONTROL_MODE12_MASK | CONTROL_MODE0);
writel_relaxed(control, qspi->regs + REG_CONTROL);
reinit_completion(&qspi->data_completion);
list_for_each_entry(t, &m->transfers, transfer_list) {
total_bytes += t->len;
if (!cmd_bytes && !(t->tx_buf && t->rx_buf))
cmd_bytes = t->len;
if (!t->rx_buf)
cmd_bytes = total_bytes;
if (t->tx_nbits == SPI_NBITS_QUAD || t->rx_nbits == SPI_NBITS_QUAD)
quad = true;
else if (t->tx_nbits == SPI_NBITS_DUAL || t->rx_nbits == SPI_NBITS_DUAL)
dual = true;
}
control = readl_relaxed(qspi->regs + REG_CONTROL);
if (quad) {
control |= (CONTROL_MODE0 | CONTROL_MODE12_EX_RW);
} else if (dual) {
control &= ~CONTROL_MODE0;
control |= CONTROL_MODE12_FULL;
} else {
control &= ~(CONTROL_MODE12_MASK | CONTROL_MODE0);
}
writel_relaxed(control, qspi->regs + REG_CONTROL);
frames = total_bytes & BYTESUPPER_MASK;
writel_relaxed(frames, qspi->regs + REG_FRAMESUP);
frames = total_bytes & BYTESLOWER_MASK;
frames |= cmd_bytes << FRAMES_CMDBYTES_SHIFT;
frames |= idle_cycles << FRAMES_IDLE_SHIFT;
control = readl_relaxed(qspi->regs + REG_CONTROL);
if (control & CONTROL_MODE12_MASK)
frames |= (1 << FRAMES_SHIFT);
frames |= FRAMES_FLAGWORD;
writel_relaxed(frames, qspi->regs + REG_FRAMES);
return 0;
};
static int mchp_coreqspi_transfer_one(struct spi_controller *ctlr, struct spi_device *spi,
struct spi_transfer *t)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata(ctlr);
qspi->tx_len = t->len;
if (t->tx_buf)
qspi->txbuf = (u8 *)t->tx_buf;
if (!t->rx_buf) {
mchp_coreqspi_write_op(qspi);
} else {
qspi->rxbuf = (u8 *)t->rx_buf;
qspi->rx_len = t->len;
mchp_coreqspi_write_read_op(qspi);
}
return 0;
}
static int mchp_coreqspi_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
@ -562,6 +738,12 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_TX_DUAL | SPI_TX_QUAD;
ctlr->dev.of_node = np;
ctlr->min_speed_hz = clk_get_rate(qspi->clk) / 30;
ctlr->prepare_message = mchp_coreqspi_prepare_message;
ctlr->unprepare_message = mchp_coreqspi_unprepare_message;
ctlr->transfer_one = mchp_coreqspi_transfer_one;
ctlr->num_chipselect = 2;
ctlr->use_gpio_descriptors = true;
ret = devm_spi_register_controller(&pdev->dev, ctlr);
if (ret)

View File

@ -220,6 +220,14 @@ static const struct mtk_spi_compatible mt6893_compat = {
.no_need_unprepare = true,
};
static const struct mtk_spi_compatible mt6991_compat = {
.need_pad_sel = true,
.must_tx = true,
.enhance_timing = true,
.dma_ext = true,
.ipm_design = true,
};
/*
* A piece of default chip info unless the platform
* supplies it.
@ -245,6 +253,9 @@ static const struct of_device_id mtk_spi_of_match[] = {
{ .compatible = "mediatek,mt6765-spi",
.data = (void *)&mt6765_compat,
},
{ .compatible = "mediatek,mt6991-spi",
.data = (void *)&mt6991_compat,
},
{ .compatible = "mediatek,mt7622-spi",
.data = (void *)&mt7622_compat,
},

View File

@ -918,7 +918,6 @@ static int mtk_nor_probe(struct platform_device *pdev)
if (ret < 0)
goto err_probe;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
dev_info(&pdev->dev, "spi frequency: %d Hz\n", sp->spi_freq);

View File

@ -968,7 +968,6 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
/* Invalidate the data in the AHB buffer. */
nxp_fspi_invalid(f);
pm_runtime_mark_last_busy(f->dev);
pm_runtime_put_autosuspend(f->dev);
return err;

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2025 Analog Devices Inc.
* Copyright (C) 2025 BayLibre, SAS
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/spi/offload/provider.h>
static bool adi_util_sigma_delta_match(struct spi_offload_trigger *trigger,
enum spi_offload_trigger_type type,
u64 *args, u32 nargs)
{
return type == SPI_OFFLOAD_TRIGGER_DATA_READY && nargs == 0;
}
static const struct spi_offload_trigger_ops adi_util_sigma_delta_ops = {
.match = adi_util_sigma_delta_match,
};
static int adi_util_sigma_delta_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct spi_offload_trigger_info info = {
.fwnode = dev_fwnode(dev),
.ops = &adi_util_sigma_delta_ops,
};
struct clk *clk;
clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk))
return dev_err_probe(dev, PTR_ERR(clk), "Failed to get clock\n");
return devm_spi_offload_trigger_register(dev, &info);
}
static const struct of_device_id adi_util_sigma_delta_of_match_table[] = {
{ .compatible = "adi,util-sigma-delta-spi", },
{ }
};
MODULE_DEVICE_TABLE(of, adi_util_sigma_delta_of_match_table);
static struct platform_driver adi_util_sigma_delta_driver = {
.probe = adi_util_sigma_delta_probe,
.driver = {
.name = "adi-util-sigma-delta-spi",
.of_match_table = adi_util_sigma_delta_of_match_table,
},
};
module_platform_driver(adi_util_sigma_delta_driver);
MODULE_AUTHOR("David Lechner <dlechner@baylibre.com>");
MODULE_DESCRIPTION("ADI Sigma-Delta SPI offload trigger utility driver");
MODULE_LICENSE("GPL");

View File

@ -272,7 +272,6 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
mcspi_write_chconf0(spi, l);
pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
}
}
@ -1102,7 +1101,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
if (ret && initial_setup)
omap2_mcspi_cleanup(spi);
pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
return ret;
@ -1379,7 +1377,6 @@ static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
omap2_mcspi_set_mode(ctlr);
pm_runtime_mark_last_busy(mcspi->dev);
pm_runtime_put_autosuspend(mcspi->dev);
return 0;
}

View File

@ -23,6 +23,7 @@
#define SYS_FREQ_DEFAULT (62500000)
#define PCI1XXXX_SPI_MAX_CLOCK_HZ (30000000)
#define PCI1XXXX_SPI_CLK_25MHZ (25000000)
#define PCI1XXXX_SPI_CLK_20MHZ (20000000)
#define PCI1XXXX_SPI_CLK_15MHZ (15000000)
#define PCI1XXXX_SPI_CLK_12MHZ (12000000)
@ -96,8 +97,8 @@
#define SPI_DMA_CH1_DONE_INT BIT(1)
#define SPI_DMA_CH0_ABORT_INT BIT(16)
#define SPI_DMA_CH1_ABORT_INT BIT(17)
#define SPI_DMA_DONE_INT_MASK (SPI_DMA_CH0_DONE_INT | SPI_DMA_CH1_DONE_INT)
#define SPI_DMA_ABORT_INT_MASK (SPI_DMA_CH0_ABORT_INT | SPI_DMA_CH1_ABORT_INT)
#define SPI_DMA_DONE_INT_MASK(x) (1 << (x))
#define SPI_DMA_ABORT_INT_MASK(x) (1 << (16 + (x)))
#define DMA_CH_CONTROL_LIE BIT(3)
#define DMA_CH_CONTROL_RIE BIT(4)
#define DMA_INTR_EN (DMA_CH_CONTROL_RIE | DMA_CH_CONTROL_LIE)
@ -131,12 +132,15 @@
#define SPI_SUSPEND_CONFIG 0x101
#define SPI_RESUME_CONFIG 0x203
#define NUM_VEC_PER_INST 3
struct pci1xxxx_spi_internal {
u8 hw_inst;
u8 clkdiv;
int irq;
int irq[NUM_VEC_PER_INST];
int mode;
bool spi_xfer_in_progress;
atomic_t dma_completion_count;
void *rx_buf;
bool dma_aborted_rd;
u32 bytes_recvd;
@ -160,8 +164,10 @@ struct pci1xxxx_spi {
u8 dev_rev;
void __iomem *reg_base;
void __iomem *dma_offset_bar;
/* lock to safely access the DMA registers in isr */
spinlock_t dma_reg_lock;
/* lock to safely access the DMA RD registers in isr */
spinlock_t dma_rd_reg_lock;
/* lock to safely access the DMA RD registers in isr */
spinlock_t dma_wr_reg_lock;
bool can_dma;
struct pci1xxxx_spi_internal *spi_int[] __counted_by(total_hw_instances);
};
@ -192,6 +198,9 @@ static const struct pci_device_id pci1xxxx_spi_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, pci1xxxx_spi_pci_id_table);
static irqreturn_t pci1xxxx_spi_isr_dma_rd(int irq, void *dev);
static irqreturn_t pci1xxxx_spi_isr_dma_wr(int irq, void *dev);
static int pci1xxxx_set_sys_lock(struct pci1xxxx_spi *par)
{
writel(SPI_SYSLOCK, par->reg_base + SPI_SYSLOCK_REG);
@ -212,13 +221,16 @@ static void pci1xxxx_release_sys_lock(struct pci1xxxx_spi *par)
writel(0x0, par->reg_base + SPI_SYSLOCK_REG);
}
static int pci1xxxx_check_spi_can_dma(struct pci1xxxx_spi *spi_bus, int irq)
static int pci1xxxx_check_spi_can_dma(struct pci1xxxx_spi *spi_bus, int hw_inst, int num_vector)
{
struct pci_dev *pdev = spi_bus->dev;
u32 pf_num;
u32 regval;
int ret;
if (num_vector != hw_inst * NUM_VEC_PER_INST)
return -EOPNOTSUPP;
/*
* DEV REV Registers is a system register, HW Syslock bit
* should be acquired before accessing the register
@ -246,16 +258,6 @@ static int pci1xxxx_check_spi_can_dma(struct pci1xxxx_spi *spi_bus, int irq)
if (spi_bus->dev_rev < 0xC0 || pf_num)
return -EOPNOTSUPP;
/*
* DMA Supported only with MSI Interrupts
* One of the SPI instance's MSI vector address and data
* is used for DMA Interrupt
*/
if (!irq_get_msi_desc(irq)) {
dev_warn(&pdev->dev, "Error MSI Interrupt not supported, will operate in PIO mode\n");
return -EOPNOTSUPP;
}
spi_bus->dma_offset_bar = pcim_iomap(pdev, 2, pci_resource_len(pdev, 2));
if (!spi_bus->dma_offset_bar) {
dev_warn(&pdev->dev, "Error failed to map dma bar, will operate in PIO mode\n");
@ -272,29 +274,91 @@ static int pci1xxxx_check_spi_can_dma(struct pci1xxxx_spi *spi_bus, int irq)
return 0;
}
static int pci1xxxx_spi_dma_init(struct pci1xxxx_spi *spi_bus, int irq)
static void pci1xxxx_spi_dma_config(struct pci1xxxx_spi *spi_bus)
{
struct pci1xxxx_spi_internal *spi_sub_ptr;
u8 iter, irq_index;
struct msi_msg msi;
u32 regval;
u16 data;
irq_index = spi_bus->total_hw_instances;
for (iter = 0; iter < spi_bus->total_hw_instances; iter++) {
spi_sub_ptr = spi_bus->spi_int[iter];
get_cached_msi_msg(spi_sub_ptr->irq[1], &msi);
if (iter == 0) {
writel(msi.address_hi, spi_bus->dma_offset_bar +
SPI_DMA_INTR_IMWR_WDONE_HIGH);
writel(msi.address_hi, spi_bus->dma_offset_bar +
SPI_DMA_INTR_IMWR_WABORT_HIGH);
writel(msi.address_hi, spi_bus->dma_offset_bar +
SPI_DMA_INTR_IMWR_RDONE_HIGH);
writel(msi.address_hi, spi_bus->dma_offset_bar +
SPI_DMA_INTR_IMWR_RABORT_HIGH);
writel(msi.address_lo, spi_bus->dma_offset_bar +
SPI_DMA_INTR_IMWR_WDONE_LOW);
writel(msi.address_lo, spi_bus->dma_offset_bar +
SPI_DMA_INTR_IMWR_WABORT_LOW);
writel(msi.address_lo, spi_bus->dma_offset_bar +
SPI_DMA_INTR_IMWR_RDONE_LOW);
writel(msi.address_lo, spi_bus->dma_offset_bar +
SPI_DMA_INTR_IMWR_RABORT_LOW);
writel(0, spi_bus->dma_offset_bar + SPI_DMA_INTR_WR_IMWR_DATA);
writel(0, spi_bus->dma_offset_bar + SPI_DMA_INTR_RD_IMWR_DATA);
}
regval = readl(spi_bus->dma_offset_bar + SPI_DMA_INTR_WR_IMWR_DATA);
data = msi.data + irq_index;
writel((regval | (data << (iter * 16))), spi_bus->dma_offset_bar +
SPI_DMA_INTR_WR_IMWR_DATA);
regval = readl(spi_bus->dma_offset_bar + SPI_DMA_INTR_WR_IMWR_DATA);
irq_index++;
data = msi.data + irq_index;
regval = readl(spi_bus->dma_offset_bar + SPI_DMA_INTR_RD_IMWR_DATA);
writel(regval | (data << (iter * 16)), spi_bus->dma_offset_bar +
SPI_DMA_INTR_RD_IMWR_DATA);
regval = readl(spi_bus->dma_offset_bar + SPI_DMA_INTR_RD_IMWR_DATA);
irq_index++;
}
}
static int pci1xxxx_spi_dma_init(struct pci1xxxx_spi *spi_bus, int hw_inst, int num_vector)
{
struct pci1xxxx_spi_internal *spi_sub_ptr;
u8 iter, irq_index;
int ret;
ret = pci1xxxx_check_spi_can_dma(spi_bus, irq);
irq_index = hw_inst;
ret = pci1xxxx_check_spi_can_dma(spi_bus, hw_inst, num_vector);
if (ret)
return ret;
spin_lock_init(&spi_bus->dma_reg_lock);
get_cached_msi_msg(irq, &msi);
spin_lock_init(&spi_bus->dma_rd_reg_lock);
spin_lock_init(&spi_bus->dma_wr_reg_lock);
writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_WR_ENGINE_EN);
writel(SPI_DMA_ENGINE_EN, spi_bus->dma_offset_bar + SPI_DMA_GLOBAL_RD_ENGINE_EN);
writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WDONE_HIGH);
writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WABORT_HIGH);
writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RDONE_HIGH);
writel(msi.address_hi, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RABORT_HIGH);
writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WDONE_LOW);
writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_WABORT_LOW);
writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RDONE_LOW);
writel(msi.address_lo, spi_bus->dma_offset_bar + SPI_DMA_INTR_IMWR_RABORT_LOW);
writel(msi.data, spi_bus->dma_offset_bar + SPI_DMA_INTR_WR_IMWR_DATA);
writel(msi.data, spi_bus->dma_offset_bar + SPI_DMA_INTR_RD_IMWR_DATA);
for (iter = 0; iter < hw_inst; iter++) {
spi_sub_ptr = spi_bus->spi_int[iter];
spi_sub_ptr->irq[1] = pci_irq_vector(spi_bus->dev, irq_index);
ret = devm_request_irq(&spi_bus->dev->dev, spi_sub_ptr->irq[1],
pci1xxxx_spi_isr_dma_wr, PCI1XXXX_IRQ_FLAGS,
pci_name(spi_bus->dev), spi_sub_ptr);
if (ret < 0)
return ret;
irq_index++;
spi_sub_ptr->irq[2] = pci_irq_vector(spi_bus->dev, irq_index);
ret = devm_request_irq(&spi_bus->dev->dev, spi_sub_ptr->irq[2],
pci1xxxx_spi_isr_dma_rd, PCI1XXXX_IRQ_FLAGS,
pci_name(spi_bus->dev), spi_sub_ptr);
if (ret < 0)
return ret;
irq_index++;
}
pci1xxxx_spi_dma_config(spi_bus);
dma_set_max_seg_size(&spi_bus->dev->dev, PCI1XXXX_SPI_BUFFER_SIZE);
spi_bus->can_dma = true;
return 0;
@ -318,12 +382,14 @@ static void pci1xxxx_spi_set_cs(struct spi_device *spi, bool enable)
writel(regval, par->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
}
static u8 pci1xxxx_get_clock_div(u32 hz)
static u8 pci1xxxx_get_clock_div(struct pci1xxxx_spi *par, u32 hz)
{
u8 val = 0;
if (hz >= PCI1XXXX_SPI_MAX_CLOCK_HZ)
val = 2;
else if (par->dev_rev >= 0xC0 && hz >= PCI1XXXX_SPI_CLK_25MHZ)
val = 1;
else if ((hz < PCI1XXXX_SPI_MAX_CLOCK_HZ) && (hz >= PCI1XXXX_SPI_CLK_20MHZ))
val = 3;
else if ((hz < PCI1XXXX_SPI_CLK_20MHZ) && (hz >= PCI1XXXX_SPI_CLK_15MHZ))
@ -398,13 +464,14 @@ static void pci1xxxx_spi_setup(struct pci1xxxx_spi *par, u8 hw_inst, u32 mode,
writel(regval, par->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst));
}
static void pci1xxxx_start_spi_xfer(struct pci1xxxx_spi_internal *p, u8 hw_inst)
static void pci1xxxx_start_spi_xfer(struct pci1xxxx_spi_internal *p)
{
u32 regval;
regval = readl(p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst));
atomic_set(&p->dma_completion_count, 0);
regval = readl(p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
regval |= SPI_MST_CTL_GO;
writel(regval, p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(hw_inst));
writel(regval, p->parent->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst));
}
static int pci1xxxx_spi_transfer_with_io(struct spi_controller *spi_ctlr,
@ -423,7 +490,7 @@ static int pci1xxxx_spi_transfer_with_io(struct spi_controller *spi_ctlr,
p->spi_xfer_in_progress = true;
p->bytes_recvd = 0;
clkdiv = pci1xxxx_get_clock_div(xfer->speed_hz);
clkdiv = pci1xxxx_get_clock_div(par, xfer->speed_hz);
tx_buf = xfer->tx_buf;
rx_buf = xfer->rx_buf;
transfer_len = xfer->len;
@ -448,7 +515,7 @@ static int pci1xxxx_spi_transfer_with_io(struct spi_controller *spi_ctlr,
&tx_buf[bytes_transfered], len);
bytes_transfered += len;
pci1xxxx_spi_setup(par, p->hw_inst, spi->mode, clkdiv, len);
pci1xxxx_start_spi_xfer(p, p->hw_inst);
pci1xxxx_start_spi_xfer(p);
/* Wait for DMA_TERM interrupt */
result = wait_for_completion_timeout(&p->spi_xfer_done,
@ -474,7 +541,6 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr,
{
struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi_ctlr);
struct pci1xxxx_spi *par = p->parent;
dma_addr_t rx_dma_addr = 0;
dma_addr_t tx_dma_addr = 0;
int ret = 0;
u32 regval;
@ -483,6 +549,7 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr,
p->tx_sgl = xfer->tx_sg.sgl;
p->rx_sgl = xfer->rx_sg.sgl;
p->rx_buf = xfer->rx_buf;
atomic_set(&p->dma_completion_count, 1);
regval = readl(par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
writel(regval, par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
@ -492,20 +559,16 @@ static int pci1xxxx_spi_transfer_with_dma(struct spi_controller *spi_ctlr,
}
p->xfer = xfer;
p->mode = spi->mode;
p->clkdiv = pci1xxxx_get_clock_div(xfer->speed_hz);
p->clkdiv = pci1xxxx_get_clock_div(par, xfer->speed_hz);
p->bytes_recvd = 0;
p->rx_buf = xfer->rx_buf;
regval = readl(par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
writel(regval, par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
tx_dma_addr = sg_dma_address(p->tx_sgl);
rx_dma_addr = sg_dma_address(p->rx_sgl);
p->tx_sgl_len = sg_dma_len(p->tx_sgl);
p->rx_sgl_len = sg_dma_len(p->rx_sgl);
pci1xxxx_spi_setup(par, p->hw_inst, p->mode, p->clkdiv, p->tx_sgl_len);
pci1xxxx_spi_setup_dma_to_io(p, (tx_dma_addr), p->tx_sgl_len);
if (rx_dma_addr)
pci1xxxx_spi_setup_dma_from_io(p, rx_dma_addr, p->rx_sgl_len);
writel(p->hw_inst, par->dma_offset_bar + SPI_DMA_RD_DOORBELL_REG);
reinit_completion(&p->spi_xfer_done);
@ -595,83 +658,111 @@ static irqreturn_t pci1xxxx_spi_isr_io(int irq, void *dev)
return spi_int_fired;
}
static void pci1xxxx_spi_setup_next_dma_transfer(struct pci1xxxx_spi_internal *p)
static void pci1xxxx_spi_setup_next_dma_to_io_transfer(struct pci1xxxx_spi_internal *p)
{
dma_addr_t tx_dma_addr = 0;
dma_addr_t rx_dma_addr = 0;
u32 prev_len;
p->tx_sgl = sg_next(p->tx_sgl);
if (p->rx_sgl)
p->rx_sgl = sg_next(p->rx_sgl);
if (!p->tx_sgl) {
/* Clear xfer_done */
complete(&p->spi_xfer_done);
} else {
if (p->tx_sgl) {
tx_dma_addr = sg_dma_address(p->tx_sgl);
prev_len = p->tx_sgl_len;
p->tx_sgl_len = sg_dma_len(p->tx_sgl);
pci1xxxx_spi_setup_dma_to_io(p, tx_dma_addr, p->tx_sgl_len);
writel(p->hw_inst, p->parent->dma_offset_bar + SPI_DMA_RD_DOORBELL_REG);
if (prev_len != p->tx_sgl_len)
pci1xxxx_spi_setup(p->parent,
p->hw_inst, p->mode, p->clkdiv, p->tx_sgl_len);
pci1xxxx_spi_setup_dma_to_io(p, tx_dma_addr, p->tx_sgl_len);
if (p->rx_sgl) {
rx_dma_addr = sg_dma_address(p->rx_sgl);
p->rx_sgl_len = sg_dma_len(p->rx_sgl);
pci1xxxx_spi_setup_dma_from_io(p, rx_dma_addr, p->rx_sgl_len);
}
writel(p->hw_inst, p->parent->dma_offset_bar + SPI_DMA_RD_DOORBELL_REG);
}
}
static irqreturn_t pci1xxxx_spi_isr_dma(int irq, void *dev)
static void pci1xxxx_spi_setup_next_dma_from_io_transfer(struct pci1xxxx_spi_internal *p)
{
dma_addr_t rx_dma_addr = 0;
if (p->rx_sgl) {
rx_dma_addr = sg_dma_address(p->rx_sgl);
p->rx_sgl_len = sg_dma_len(p->rx_sgl);
pci1xxxx_spi_setup_dma_from_io(p, rx_dma_addr, p->rx_sgl_len);
writel(p->hw_inst, p->parent->dma_offset_bar + SPI_DMA_WR_DOORBELL_REG);
}
}
static irqreturn_t pci1xxxx_spi_isr_dma_rd(int irq, void *dev)
{
struct pci1xxxx_spi_internal *p = dev;
irqreturn_t spi_int_fired = IRQ_NONE;
unsigned long flags;
u32 regval;
spin_lock_irqsave(&p->parent->dma_reg_lock, flags);
/* Clear the DMA RD INT and start spi xfer*/
regval = readl(p->parent->dma_offset_bar + SPI_DMA_INTR_RD_STS);
if (regval & SPI_DMA_DONE_INT_MASK) {
if (regval & SPI_DMA_CH0_DONE_INT)
pci1xxxx_start_spi_xfer(p, SPI0);
if (regval & SPI_DMA_CH1_DONE_INT)
pci1xxxx_start_spi_xfer(p, SPI1);
spi_int_fired = IRQ_HANDLED;
if (regval) {
if (regval & SPI_DMA_DONE_INT_MASK(p->hw_inst)) {
/* Start the SPI transfer only if both DMA read and write are completed */
if (atomic_inc_return(&p->dma_completion_count) == 2)
pci1xxxx_start_spi_xfer(p);
spi_int_fired = IRQ_HANDLED;
}
if (regval & SPI_DMA_ABORT_INT_MASK(p->hw_inst)) {
p->dma_aborted_rd = true;
spi_int_fired = IRQ_HANDLED;
}
spin_lock_irqsave(&p->parent->dma_rd_reg_lock, flags);
writel((SPI_DMA_DONE_INT_MASK(p->hw_inst) | SPI_DMA_ABORT_INT_MASK(p->hw_inst)),
p->parent->dma_offset_bar + SPI_DMA_INTR_RD_CLR);
spin_unlock_irqrestore(&p->parent->dma_rd_reg_lock, flags);
}
if (regval & SPI_DMA_ABORT_INT_MASK) {
p->dma_aborted_rd = true;
spi_int_fired = IRQ_HANDLED;
}
writel(regval, p->parent->dma_offset_bar + SPI_DMA_INTR_RD_CLR);
return spi_int_fired;
}
static irqreturn_t pci1xxxx_spi_isr_dma_wr(int irq, void *dev)
{
struct pci1xxxx_spi_internal *p = dev;
irqreturn_t spi_int_fired = IRQ_NONE;
unsigned long flags;
u32 regval;
/* Clear the DMA WR INT */
regval = readl(p->parent->dma_offset_bar + SPI_DMA_INTR_WR_STS);
if (regval & SPI_DMA_DONE_INT_MASK) {
if (regval & SPI_DMA_CH0_DONE_INT)
pci1xxxx_spi_setup_next_dma_transfer(p->parent->spi_int[SPI0]);
if (regval) {
if (regval & SPI_DMA_DONE_INT_MASK(p->hw_inst)) {
spi_int_fired = IRQ_HANDLED;
if (sg_is_last(p->rx_sgl)) {
complete(&p->spi_xfer_done);
} else {
p->rx_sgl = sg_next(p->rx_sgl);
if (atomic_inc_return(&p->dma_completion_count) == 2)
pci1xxxx_start_spi_xfer(p);
}
if (regval & SPI_DMA_CH1_DONE_INT)
pci1xxxx_spi_setup_next_dma_transfer(p->parent->spi_int[SPI1]);
}
if (regval & SPI_DMA_ABORT_INT_MASK(p->hw_inst)) {
p->dma_aborted_wr = true;
spi_int_fired = IRQ_HANDLED;
}
spin_lock_irqsave(&p->parent->dma_wr_reg_lock, flags);
writel((SPI_DMA_DONE_INT_MASK(p->hw_inst) | SPI_DMA_ABORT_INT_MASK(p->hw_inst)),
p->parent->dma_offset_bar + SPI_DMA_INTR_WR_CLR);
spin_unlock_irqrestore(&p->parent->dma_wr_reg_lock, flags);
}
return spi_int_fired;
}
spi_int_fired = IRQ_HANDLED;
}
if (regval & SPI_DMA_ABORT_INT_MASK) {
p->dma_aborted_wr = true;
spi_int_fired = IRQ_HANDLED;
}
writel(regval, p->parent->dma_offset_bar + SPI_DMA_INTR_WR_CLR);
spin_unlock_irqrestore(&p->parent->dma_reg_lock, flags);
static irqreturn_t pci1xxxx_spi_isr_dma(int irq, void *dev)
{
struct pci1xxxx_spi_internal *p = dev;
irqreturn_t spi_int_fired = IRQ_NONE;
u32 regval;
/* Clear the SPI GO_BIT Interrupt */
regval = readl(p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
if (regval & SPI_INTR) {
writel(p->hw_inst, p->parent->dma_offset_bar + SPI_DMA_WR_DOORBELL_REG);
pci1xxxx_spi_setup_next_dma_from_io_transfer(p);
pci1xxxx_spi_setup_next_dma_to_io_transfer(p);
spi_int_fired = IRQ_HANDLED;
writel(regval, p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
}
writel(regval, p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst));
return spi_int_fired;
}
@ -761,7 +852,7 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
if (!spi_bus->reg_base)
return -EINVAL;
num_vector = pci_alloc_irq_vectors(pdev, 1, hw_inst_cnt,
num_vector = pci_alloc_irq_vectors(pdev, 1, hw_inst_cnt * NUM_VEC_PER_INST,
PCI_IRQ_INTX | PCI_IRQ_MSI);
if (num_vector < 0) {
dev_err(&pdev->dev, "Error allocating MSI vectors\n");
@ -775,27 +866,23 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
regval &= ~SPI_INTR;
writel(regval, spi_bus->reg_base +
SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
spi_sub_ptr->irq = pci_irq_vector(pdev, 0);
spi_sub_ptr->irq[0] = pci_irq_vector(pdev, 0);
if (num_vector >= hw_inst_cnt)
ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq[0],
pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
pci_name(pdev), spi_sub_ptr);
else
ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq[0],
pci1xxxx_spi_shared_isr,
PCI1XXXX_IRQ_FLAGS | IRQF_SHARED,
pci_name(pdev), spi_bus);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to request irq : %d",
spi_sub_ptr->irq);
spi_sub_ptr->irq[0]);
return -ENODEV;
}
ret = pci1xxxx_spi_dma_init(spi_bus, spi_sub_ptr->irq);
if (ret && ret != -EOPNOTSUPP)
return ret;
/* This register is only applicable for 1st instance */
regval = readl(spi_bus->reg_base + SPI_PCI_CTRL_REG_OFFSET(0));
if (!only_sec_inst)
@ -817,13 +904,13 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
writel(regval, spi_bus->reg_base +
SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst));
if (num_vector >= hw_inst_cnt) {
spi_sub_ptr->irq = pci_irq_vector(pdev, iter);
ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq,
spi_sub_ptr->irq[0] = pci_irq_vector(pdev, iter);
ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq[0],
pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS,
pci_name(pdev), spi_sub_ptr);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to request irq : %d",
spi_sub_ptr->irq);
spi_sub_ptr->irq[0]);
return -ENODEV;
}
}
@ -846,6 +933,10 @@ static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *
if (ret)
return ret;
}
ret = pci1xxxx_spi_dma_init(spi_bus, hw_inst_cnt, num_vector);
if (ret && ret != -EOPNOTSUPP)
return ret;
pci_set_drvdata(pdev, spi_bus);
return 0;

View File

@ -59,12 +59,6 @@
#define OOB_BUF_SIZE 128
#define ecceng_to_qspi(eng) container_of(eng, struct qpic_spi_nand, ecc_eng)
struct qpic_snand_op {
u32 cmd_reg;
u32 addr1_reg;
u32 addr2_reg;
};
struct snandc_read_status {
__le32 snandc_flash;
__le32 snandc_buffer;
@ -283,9 +277,22 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
goto err_free_ecc_cfg;
}
if (ecc_cfg->strength != 4) {
switch (ecc_cfg->strength) {
case 4:
ecc_cfg->ecc_mode = ECC_MODE_4BIT;
ecc_cfg->ecc_bytes_hw = 7;
ecc_cfg->spare_bytes = 4;
break;
case 8:
ecc_cfg->ecc_mode = ECC_MODE_8BIT;
ecc_cfg->ecc_bytes_hw = 13;
ecc_cfg->spare_bytes = 2;
break;
default:
dev_err(snandc->dev,
"only 4 bits ECC strength is supported\n");
"only 4 or 8 bits ECC strength is supported\n");
ret = -EOPNOTSUPP;
goto err_free_ecc_cfg;
}
@ -302,8 +309,6 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
nand->ecc.ctx.priv = ecc_cfg;
snandc->qspi->mtd = mtd;
ecc_cfg->ecc_bytes_hw = 7;
ecc_cfg->spare_bytes = 4;
ecc_cfg->bbm_size = 1;
ecc_cfg->bch_enabled = true;
ecc_cfg->bytes = ecc_cfg->ecc_bytes_hw + ecc_cfg->spare_bytes + ecc_cfg->bbm_size;
@ -365,7 +370,7 @@ static int qcom_spi_ecc_init_ctx_pipelined(struct nand_device *nand)
FIELD_PREP(ECC_SW_RESET, 0) |
FIELD_PREP(ECC_NUM_DATA_BYTES_MASK, ecc_cfg->cw_data) |
FIELD_PREP(ECC_FORCE_CLK_OPEN, 1) |
FIELD_PREP(ECC_MODE_MASK, 0) |
FIELD_PREP(ECC_MODE_MASK, ecc_cfg->ecc_mode) |
FIELD_PREP(ECC_PARITY_SIZE_BYTES_BCH_MASK, ecc_cfg->ecc_bytes_hw);
ecc_cfg->ecc_buf_cfg = FIELD_PREP(NUM_STEPS_MASK, 0x203);
@ -608,10 +613,16 @@ static int qcom_spi_read_last_cw(struct qcom_nand_controller *snandc,
bbpos = mtd->writesize - ecc_cfg->cw_size * (num_cw - 1);
if (snandc->data_buffer[bbpos] == 0xff)
snandc->data_buffer[bbpos + 1] = 0xff;
if (snandc->data_buffer[bbpos] != 0xff)
snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos];
/*
* TODO: The SPINAND code expects two bad block marker bytes
* at the beginning of the OOB area, but the OOB layout used by
* the driver has only one. Duplicate that for now in order to
* avoid certain blocks to be marked as bad.
*
* This can be removed once single-byte bad block marker support
* gets implemented in the SPINAND code.
*/
snandc->data_buffer[bbpos + 1] = snandc->data_buffer[bbpos];
memcpy(op->data.buf.in, snandc->data_buffer + bbpos, op->data.nbytes);
@ -851,7 +862,7 @@ static int qcom_spi_read_page_ecc(struct qcom_nand_controller *snandc,
int data_size, oob_size;
if (i == (num_cw - 1)) {
data_size = 512 - ((num_cw - 1) << 2);
data_size = NANDC_STEP_SIZE - ((num_cw - 1) << 2);
oob_size = (num_cw << 2) + ecc_cfg->ecc_bytes_hw +
ecc_cfg->spare_bytes;
} else {
@ -1310,7 +1321,6 @@ static int qcom_spi_write_page(struct qcom_nand_controller *snandc,
static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
const struct spi_mem_op *op)
{
struct qpic_snand_op s_op = {};
u32 cmd;
int ret, opcode;
@ -1318,34 +1328,24 @@ static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
if (ret < 0)
return ret;
s_op.cmd_reg = cmd;
s_op.addr1_reg = op->addr.val;
s_op.addr2_reg = 0;
opcode = op->cmd.opcode;
switch (opcode) {
case SPINAND_WRITE_EN:
return 0;
case SPINAND_PROGRAM_EXECUTE:
s_op.addr1_reg = op->addr.val << 16;
s_op.addr2_reg = op->addr.val >> 16 & 0xff;
snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
snandc->qspi->addr1 = cpu_to_le32(op->addr.val << 16);
snandc->qspi->addr2 = cpu_to_le32(op->addr.val >> 16 & 0xff);
snandc->qspi->cmd = cpu_to_le32(cmd);
return qcom_spi_program_execute(snandc, op);
case SPINAND_READ:
s_op.addr1_reg = (op->addr.val << 16);
s_op.addr2_reg = op->addr.val >> 16 & 0xff;
snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg);
snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
snandc->qspi->addr1 = cpu_to_le32(op->addr.val << 16);
snandc->qspi->addr2 = cpu_to_le32(op->addr.val >> 16 & 0xff);
snandc->qspi->cmd = cpu_to_le32(cmd);
return 0;
case SPINAND_ERASE:
s_op.addr2_reg = (op->addr.val >> 16) & 0xffff;
s_op.addr1_reg = op->addr.val;
snandc->qspi->addr1 = cpu_to_le32(s_op.addr1_reg << 16);
snandc->qspi->addr2 = cpu_to_le32(s_op.addr2_reg);
snandc->qspi->addr1 = cpu_to_le32(op->addr.val << 16);
snandc->qspi->addr2 = cpu_to_le32(op->addr.val >> 16 & 0xffff);
snandc->qspi->cmd = cpu_to_le32(cmd);
return qcom_spi_block_erase(snandc);
default:
@ -1357,10 +1357,10 @@ static int qcom_spi_send_cmdaddr(struct qcom_nand_controller *snandc,
qcom_clear_read_regs(snandc);
qcom_clear_bam_transaction(snandc);
snandc->regs->cmd = cpu_to_le32(s_op.cmd_reg);
snandc->regs->cmd = cpu_to_le32(cmd);
snandc->regs->exec = cpu_to_le32(1);
snandc->regs->addr0 = cpu_to_le32(s_op.addr1_reg);
snandc->regs->addr1 = cpu_to_le32(s_op.addr2_reg);
snandc->regs->addr0 = cpu_to_le32(op->addr.val);
snandc->regs->addr1 = cpu_to_le32(0);
qcom_write_reg_dma(snandc, &snandc->regs->cmd, NAND_FLASH_CMD, 3, NAND_BAM_NEXT_SGL);
qcom_write_reg_dma(snandc, &snandc->regs->exec, NAND_EXEC_CMD, 1, NAND_BAM_NEXT_SGL);

View File

@ -565,7 +565,6 @@ static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op
ret = rockchip_sfc_xfer_done(sfc, 100000);
out:
pm_runtime_mark_last_busy(sfc->dev);
pm_runtime_put_autosuspend(sfc->dev);
return ret;
@ -712,7 +711,6 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
if (ret)
goto err_register;
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@ -799,7 +797,6 @@ static int rockchip_sfc_resume(struct device *dev)
rockchip_sfc_init(sfc);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;

View File

@ -1404,7 +1404,6 @@ static const struct platform_device_id spi_driver_ids[] = {
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
#ifdef CONFIG_PM_SLEEP
static int rspi_suspend(struct device *dev)
{
struct rspi_data *rspi = dev_get_drvdata(dev);
@ -1419,11 +1418,7 @@ static int rspi_resume(struct device *dev)
return spi_controller_resume(rspi->ctlr);
}
static SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume);
#define DEV_PM_OPS &rspi_pm_ops
#else
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static DEFINE_SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume);
static struct platform_driver rspi_driver = {
.probe = rspi_probe,
@ -1431,7 +1426,7 @@ static struct platform_driver rspi_driver = {
.id_table = spi_driver_ids,
.driver = {
.name = "renesas_spi",
.pm = DEV_PM_OPS,
.pm = pm_sleep_ptr(&rspi_pm_ops),
.of_match_table = of_match_ptr(rspi_of_match),
},
};

View File

@ -0,0 +1,466 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Renesas RZ/V2H Renesas Serial Peripheral Interface (RSPI)
*
* Copyright (C) 2025 Renesas Electronics Corporation
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/limits.h>
#include <linux/log2.h>
#include <linux/math.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/reset.h>
#include <linux/spi/spi.h>
#include <linux/wait.h>
/* Registers */
#define RSPI_SPDR 0x00
#define RSPI_SPCR 0x08
#define RSPI_SSLP 0x10
#define RSPI_SPBR 0x11
#define RSPI_SPSCR 0x13
#define RSPI_SPCMD 0x14
#define RSPI_SPDCR2 0x44
#define RSPI_SPSR 0x52
#define RSPI_SPSRC 0x6a
#define RSPI_SPFCR 0x6c
/* Register SPCR */
#define RSPI_SPCR_MSTR BIT(30)
#define RSPI_SPCR_SPRIE BIT(17)
#define RSPI_SPCR_SCKASE BIT(12)
#define RSPI_SPCR_SPE BIT(0)
/* Register SPBR */
#define RSPI_SPBR_SPR_MIN 0
#define RSPI_SPBR_SPR_MAX 255
/* Register SPCMD */
#define RSPI_SPCMD_SSLA GENMASK(25, 24)
#define RSPI_SPCMD_SPB GENMASK(20, 16)
#define RSPI_SPCMD_LSBF BIT(12)
#define RSPI_SPCMD_SSLKP BIT(7)
#define RSPI_SPCMD_BRDV GENMASK(3, 2)
#define RSPI_SPCMD_CPOL BIT(1)
#define RSPI_SPCMD_CPHA BIT(0)
#define RSPI_SPCMD_BRDV_MIN 0
#define RSPI_SPCMD_BRDV_MAX 3
/* Register SPDCR2 */
#define RSPI_SPDCR2_TTRG GENMASK(11, 8)
#define RSPI_SPDCR2_RTRG GENMASK(3, 0)
#define RSPI_FIFO_SIZE 16
/* Register SPSR */
#define RSPI_SPSR_SPRF BIT(15)
/* Register RSPI_SPSRC */
#define RSPI_SPSRC_CLEAR 0xfd80
#define RSPI_RESET_NUM 2
#define RSPI_CLK_NUM 3
struct rzv2h_rspi_priv {
struct reset_control_bulk_data resets[RSPI_RESET_NUM];
struct spi_controller *controller;
void __iomem *base;
struct clk *tclk;
wait_queue_head_t wait;
unsigned int bytes_per_word;
u32 freq;
u16 status;
};
#define RZV2H_RSPI_TX(func, type) \
static inline void rzv2h_rspi_tx_##type(struct rzv2h_rspi_priv *rspi, \
const void *txbuf, \
unsigned int index) { \
type buf = 0; \
\
if (txbuf) \
buf = ((type *)txbuf)[index]; \
\
func(buf, rspi->base + RSPI_SPDR); \
}
#define RZV2H_RSPI_RX(func, type) \
static inline void rzv2h_rspi_rx_##type(struct rzv2h_rspi_priv *rspi, \
void *rxbuf, \
unsigned int index) { \
type buf = func(rspi->base + RSPI_SPDR); \
\
if (rxbuf) \
((type *)rxbuf)[index] = buf; \
}
RZV2H_RSPI_TX(writel, u32)
RZV2H_RSPI_TX(writew, u16)
RZV2H_RSPI_TX(writeb, u8)
RZV2H_RSPI_RX(readl, u32)
RZV2H_RSPI_RX(readw, u16)
RZV2H_RSPI_RX(readl, u8)
static void rzv2h_rspi_reg_rmw(const struct rzv2h_rspi_priv *rspi,
int reg_offs, u32 bit_mask, u32 value)
{
u32 tmp;
value <<= __ffs(bit_mask);
tmp = (readl(rspi->base + reg_offs) & ~bit_mask) | value;
writel(tmp, rspi->base + reg_offs);
}
static inline void rzv2h_rspi_spe_disable(const struct rzv2h_rspi_priv *rspi)
{
rzv2h_rspi_reg_rmw(rspi, RSPI_SPCR, RSPI_SPCR_SPE, 0);
}
static inline void rzv2h_rspi_spe_enable(const struct rzv2h_rspi_priv *rspi)
{
rzv2h_rspi_reg_rmw(rspi, RSPI_SPCR, RSPI_SPCR_SPE, 1);
}
static inline void rzv2h_rspi_clear_fifos(const struct rzv2h_rspi_priv *rspi)
{
writeb(1, rspi->base + RSPI_SPFCR);
}
static inline void rzv2h_rspi_clear_all_irqs(struct rzv2h_rspi_priv *rspi)
{
writew(RSPI_SPSRC_CLEAR, rspi->base + RSPI_SPSRC);
rspi->status = 0;
}
static irqreturn_t rzv2h_rx_irq_handler(int irq, void *data)
{
struct rzv2h_rspi_priv *rspi = data;
rspi->status = readw(rspi->base + RSPI_SPSR);
wake_up(&rspi->wait);
return IRQ_HANDLED;
}
static inline int rzv2h_rspi_wait_for_interrupt(struct rzv2h_rspi_priv *rspi,
u32 wait_mask)
{
return wait_event_timeout(rspi->wait, (rspi->status & wait_mask),
HZ) == 0 ? -ETIMEDOUT : 0;
}
static void rzv2h_rspi_send(struct rzv2h_rspi_priv *rspi, const void *txbuf,
unsigned int index)
{
switch (rspi->bytes_per_word) {
case 4:
rzv2h_rspi_tx_u32(rspi, txbuf, index);
break;
case 2:
rzv2h_rspi_tx_u16(rspi, txbuf, index);
break;
default:
rzv2h_rspi_tx_u8(rspi, txbuf, index);
}
}
static int rzv2h_rspi_receive(struct rzv2h_rspi_priv *rspi, void *rxbuf,
unsigned int index)
{
int ret;
ret = rzv2h_rspi_wait_for_interrupt(rspi, RSPI_SPSR_SPRF);
if (ret)
return ret;
switch (rspi->bytes_per_word) {
case 4:
rzv2h_rspi_rx_u32(rspi, rxbuf, index);
break;
case 2:
rzv2h_rspi_rx_u16(rspi, rxbuf, index);
break;
default:
rzv2h_rspi_rx_u8(rspi, rxbuf, index);
}
return 0;
}
static int rzv2h_rspi_transfer_one(struct spi_controller *controller,
struct spi_device *spi,
struct spi_transfer *transfer)
{
struct rzv2h_rspi_priv *rspi = spi_controller_get_devdata(controller);
unsigned int words_to_transfer, i;
int ret = 0;
transfer->effective_speed_hz = rspi->freq;
words_to_transfer = transfer->len / rspi->bytes_per_word;
for (i = 0; i < words_to_transfer; i++) {
rzv2h_rspi_clear_all_irqs(rspi);
rzv2h_rspi_send(rspi, transfer->tx_buf, i);
ret = rzv2h_rspi_receive(rspi, transfer->rx_buf, i);
if (ret)
break;
}
rzv2h_rspi_clear_all_irqs(rspi);
if (ret)
transfer->error = SPI_TRANS_FAIL_IO;
spi_finalize_current_transfer(controller);
return ret;
}
static inline u32 rzv2h_rspi_calc_bitrate(unsigned long tclk_rate, u8 spr,
u8 brdv)
{
return DIV_ROUND_UP(tclk_rate, (2 * (spr + 1) * (1 << brdv)));
}
static u32 rzv2h_rspi_setup_clock(struct rzv2h_rspi_priv *rspi, u32 hz)
{
unsigned long tclk_rate;
int spr;
u8 brdv;
/*
* From the manual:
* Bit rate = f(RSPI_n_TCLK)/(2*(n+1)*2^(N))
*
* Where:
* * RSPI_n_TCLK is fixed to 200MHz on V2H
* * n = SPR - is RSPI_SPBR.SPR (from 0 to 255)
* * N = BRDV - is RSPI_SPCMD.BRDV (from 0 to 3)
*/
tclk_rate = clk_get_rate(rspi->tclk);
for (brdv = RSPI_SPCMD_BRDV_MIN; brdv <= RSPI_SPCMD_BRDV_MAX; brdv++) {
spr = DIV_ROUND_UP(tclk_rate, hz * (1 << (brdv + 1)));
spr--;
if (spr >= RSPI_SPBR_SPR_MIN && spr <= RSPI_SPBR_SPR_MAX)
goto clock_found;
}
return 0;
clock_found:
rzv2h_rspi_reg_rmw(rspi, RSPI_SPCMD, RSPI_SPCMD_BRDV, brdv);
writeb(spr, rspi->base + RSPI_SPBR);
return rzv2h_rspi_calc_bitrate(tclk_rate, spr, brdv);
}
static int rzv2h_rspi_prepare_message(struct spi_controller *ctlr,
struct spi_message *message)
{
struct rzv2h_rspi_priv *rspi = spi_controller_get_devdata(ctlr);
const struct spi_device *spi = message->spi;
struct spi_transfer *xfer;
u32 speed_hz = U32_MAX;
u8 bits_per_word;
u32 conf32;
u16 conf16;
/* Make sure SPCR.SPE is 0 before amending the configuration */
rzv2h_rspi_spe_disable(rspi);
/* Configure the device to work in "host" mode */
conf32 = RSPI_SPCR_MSTR;
/* Auto-stop function */
conf32 |= RSPI_SPCR_SCKASE;
/* SPI receive buffer full interrupt enable */
conf32 |= RSPI_SPCR_SPRIE;
writel(conf32, rspi->base + RSPI_SPCR);
/* Use SPCMD0 only */
writeb(0x0, rspi->base + RSPI_SPSCR);
/* Setup mode */
conf32 = FIELD_PREP(RSPI_SPCMD_CPOL, !!(spi->mode & SPI_CPOL));
conf32 |= FIELD_PREP(RSPI_SPCMD_CPHA, !!(spi->mode & SPI_CPHA));
conf32 |= FIELD_PREP(RSPI_SPCMD_LSBF, !!(spi->mode & SPI_LSB_FIRST));
conf32 |= FIELD_PREP(RSPI_SPCMD_SSLKP, 1);
conf32 |= FIELD_PREP(RSPI_SPCMD_SSLA, spi_get_chipselect(spi, 0));
writel(conf32, rspi->base + RSPI_SPCMD);
if (spi->mode & SPI_CS_HIGH)
writeb(BIT(spi_get_chipselect(spi, 0)), rspi->base + RSPI_SSLP);
else
writeb(0, rspi->base + RSPI_SSLP);
/* Setup FIFO thresholds */
conf16 = FIELD_PREP(RSPI_SPDCR2_TTRG, RSPI_FIFO_SIZE - 1);
conf16 |= FIELD_PREP(RSPI_SPDCR2_RTRG, 0);
writew(conf16, rspi->base + RSPI_SPDCR2);
rzv2h_rspi_clear_fifos(rspi);
list_for_each_entry(xfer, &message->transfers, transfer_list) {
if (!xfer->speed_hz)
continue;
speed_hz = min(xfer->speed_hz, speed_hz);
bits_per_word = xfer->bits_per_word;
}
if (speed_hz == U32_MAX)
return -EINVAL;
rspi->bytes_per_word = roundup_pow_of_two(BITS_TO_BYTES(bits_per_word));
rzv2h_rspi_reg_rmw(rspi, RSPI_SPCMD, RSPI_SPCMD_SPB, bits_per_word - 1);
rspi->freq = rzv2h_rspi_setup_clock(rspi, speed_hz);
if (!rspi->freq)
return -EINVAL;
rzv2h_rspi_spe_enable(rspi);
return 0;
}
static int rzv2h_rspi_unprepare_message(struct spi_controller *ctlr,
struct spi_message *message)
{
struct rzv2h_rspi_priv *rspi = spi_controller_get_devdata(ctlr);
rzv2h_rspi_spe_disable(rspi);
return 0;
}
static int rzv2h_rspi_probe(struct platform_device *pdev)
{
struct spi_controller *controller;
struct device *dev = &pdev->dev;
struct rzv2h_rspi_priv *rspi;
struct clk_bulk_data *clks;
unsigned long tclk_rate;
int irq_rx, ret, i;
controller = devm_spi_alloc_host(dev, sizeof(*rspi));
if (!controller)
return -ENOMEM;
rspi = spi_controller_get_devdata(controller);
platform_set_drvdata(pdev, rspi);
rspi->controller = controller;
rspi->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(rspi->base))
return PTR_ERR(rspi->base);
ret = devm_clk_bulk_get_all_enabled(dev, &clks);
if (ret != RSPI_CLK_NUM)
return dev_err_probe(dev, ret >= 0 ? -EINVAL : ret,
"cannot get clocks\n");
for (i = 0; i < RSPI_CLK_NUM; i++) {
if (!strcmp(clks[i].id, "tclk")) {
rspi->tclk = clks[i].clk;
break;
}
}
if (!rspi->tclk)
return dev_err_probe(dev, -EINVAL, "Failed to get tclk\n");
tclk_rate = clk_get_rate(rspi->tclk);
rspi->resets[0].id = "presetn";
rspi->resets[1].id = "tresetn";
ret = devm_reset_control_bulk_get_exclusive(dev, RSPI_RESET_NUM,
rspi->resets);
if (ret)
return dev_err_probe(dev, ret, "cannot get resets\n");
irq_rx = platform_get_irq_byname(pdev, "rx");
if (irq_rx < 0)
return dev_err_probe(dev, irq_rx, "cannot get IRQ 'rx'\n");
ret = reset_control_bulk_deassert(RSPI_RESET_NUM, rspi->resets);
if (ret)
return dev_err_probe(dev, ret, "failed to deassert resets\n");
init_waitqueue_head(&rspi->wait);
ret = devm_request_irq(dev, irq_rx, rzv2h_rx_irq_handler, 0,
dev_name(dev), rspi);
if (ret) {
dev_err(dev, "cannot request `rx` IRQ\n");
goto quit_resets;
}
controller->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH |
SPI_LSB_FIRST;
controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
controller->prepare_message = rzv2h_rspi_prepare_message;
controller->unprepare_message = rzv2h_rspi_unprepare_message;
controller->num_chipselect = 4;
controller->transfer_one = rzv2h_rspi_transfer_one;
controller->min_speed_hz = rzv2h_rspi_calc_bitrate(tclk_rate,
RSPI_SPBR_SPR_MAX,
RSPI_SPCMD_BRDV_MAX);
controller->max_speed_hz = rzv2h_rspi_calc_bitrate(tclk_rate,
RSPI_SPBR_SPR_MIN,
RSPI_SPCMD_BRDV_MIN);
device_set_node(&controller->dev, dev_fwnode(dev));
ret = spi_register_controller(controller);
if (ret) {
dev_err(dev, "register controller failed\n");
goto quit_resets;
}
return 0;
quit_resets:
reset_control_bulk_assert(RSPI_RESET_NUM, rspi->resets);
return ret;
}
static void rzv2h_rspi_remove(struct platform_device *pdev)
{
struct rzv2h_rspi_priv *rspi = platform_get_drvdata(pdev);
spi_unregister_controller(rspi->controller);
reset_control_bulk_assert(RSPI_RESET_NUM, rspi->resets);
}
static const struct of_device_id rzv2h_rspi_match[] = {
{ .compatible = "renesas,r9a09g057-rspi" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rzv2h_rspi_match);
static struct platform_driver rzv2h_rspi_drv = {
.probe = rzv2h_rspi_probe,
.remove = rzv2h_rspi_remove,
.driver = {
.name = "rzv2h_rspi",
.of_match_table = rzv2h_rspi_match,
},
};
module_platform_driver(rzv2h_rspi_drv);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>");
MODULE_DESCRIPTION("Renesas RZ/V2H(P) Serial Peripheral Interface Driver");

View File

@ -1045,14 +1045,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
}
}
pm_runtime_mark_last_busy(&sdd->pdev->dev);
pm_runtime_put_autosuspend(&sdd->pdev->dev);
s3c64xx_spi_set_cs(spi, false);
return 0;
setup_exit:
pm_runtime_mark_last_busy(&sdd->pdev->dev);
pm_runtime_put_autosuspend(&sdd->pdev->dev);
/* setup() returns with device de-selected */
s3c64xx_spi_set_cs(spi, false);
@ -1384,7 +1382,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\n",
mem_res, sdd->fifo_depth);
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;

View File

@ -84,12 +84,18 @@
#define SPIFMC_MAX_READ_SIZE 0x10000
struct sg204x_spifmc_chip_info {
bool has_opt_reg;
u32 rd_fifo_int_trigger_level;
};
struct sg2044_spifmc {
struct spi_controller *ctrl;
void __iomem *io_base;
struct device *dev;
struct mutex lock;
struct clk *clk;
const struct sg204x_spifmc_chip_info *chip_info;
};
static int sg2044_spifmc_wait_int(struct sg2044_spifmc *spifmc, u8 int_type)
@ -139,7 +145,7 @@ static ssize_t sg2044_spifmc_read_64k(struct sg2044_spifmc *spifmc,
reg = sg2044_spifmc_init_reg(spifmc);
reg |= (op->addr.nbytes + op->dummy.nbytes) << SPIFMC_TRAN_CSR_ADDR_BYTES_SHIFT;
reg |= SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE;
reg |= spifmc->chip_info->rd_fifo_int_trigger_level;
reg |= SPIFMC_TRAN_CSR_WITH_CMD;
reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX;
@ -335,7 +341,8 @@ static ssize_t sg2044_spifmc_trans_reg(struct sg2044_spifmc *spifmc,
reg |= SPIFMC_TRAN_CSR_TRAN_MODE_RX;
reg |= SPIFMC_TRAN_CSR_TRAN_MODE_TX;
writel(SPIFMC_OPT_DISABLE_FIFO_FLUSH, spifmc->io_base + SPIFMC_OPT);
if (spifmc->chip_info->has_opt_reg)
writel(SPIFMC_OPT_DISABLE_FIFO_FLUSH, spifmc->io_base + SPIFMC_OPT);
} else {
/*
* If write values to the Status Register,
@ -457,6 +464,11 @@ static int sg2044_spifmc_probe(struct platform_device *pdev)
ret = devm_mutex_init(dev, &spifmc->lock);
if (ret)
return ret;
spifmc->chip_info = device_get_match_data(&pdev->dev);
if (!spifmc->chip_info) {
dev_err(&pdev->dev, "Failed to get specific chip info\n");
return -EINVAL;
}
sg2044_spifmc_init(spifmc);
sg2044_spifmc_init_reg(spifmc);
@ -468,8 +480,19 @@ static int sg2044_spifmc_probe(struct platform_device *pdev)
return 0;
}
static const struct sg204x_spifmc_chip_info sg2044_chip_info = {
.has_opt_reg = true,
.rd_fifo_int_trigger_level = SPIFMC_TRAN_CSR_FIFO_TRG_LVL_8_BYTE,
};
static const struct sg204x_spifmc_chip_info sg2042_chip_info = {
.has_opt_reg = false,
.rd_fifo_int_trigger_level = SPIFMC_TRAN_CSR_FIFO_TRG_LVL_1_BYTE,
};
static const struct of_device_id sg2044_spifmc_match[] = {
{ .compatible = "sophgo,sg2044-spifmc-nor" },
{ .compatible = "sophgo,sg2044-spifmc-nor", .data = &sg2044_chip_info },
{ .compatible = "sophgo,sg2042-spifmc-nor", .data = &sg2042_chip_info },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sg2044_spifmc_match);

View File

@ -1320,7 +1320,6 @@ static const struct platform_device_id spi_driver_ids[] = {
};
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
#ifdef CONFIG_PM_SLEEP
static int sh_msiof_spi_suspend(struct device *dev)
{
struct sh_msiof_spi_priv *p = dev_get_drvdata(dev);
@ -1335,12 +1334,8 @@ static int sh_msiof_spi_resume(struct device *dev)
return spi_controller_resume(p->ctlr);
}
static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend,
sh_msiof_spi_resume);
#define DEV_PM_OPS (&sh_msiof_spi_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static DEFINE_SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend,
sh_msiof_spi_resume);
static struct platform_driver sh_msiof_spi_drv = {
.probe = sh_msiof_spi_probe,
@ -1348,7 +1343,7 @@ static struct platform_driver sh_msiof_spi_drv = {
.id_table = spi_driver_ids,
.driver = {
.name = "spi_sh_msiof",
.pm = DEV_PM_OPS,
.pm = pm_sleep_ptr(&sh_msiof_spi_pm_ops),
.of_match_table = of_match_ptr(sh_msiof_match),
},
};

View File

@ -982,7 +982,6 @@ static int sprd_spi_probe(struct platform_device *pdev)
if (ret)
goto err_rpm_put;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;

View File

@ -378,8 +378,7 @@ static void spi_st_remove(struct platform_device *pdev)
pinctrl_pm_select_sleep_state(&pdev->dev);
}
#ifdef CONFIG_PM
static int spi_st_runtime_suspend(struct device *dev)
static int __maybe_unused spi_st_runtime_suspend(struct device *dev)
{
struct spi_controller *host = dev_get_drvdata(dev);
struct spi_st *spi_st = spi_controller_get_devdata(host);
@ -392,7 +391,7 @@ static int spi_st_runtime_suspend(struct device *dev)
return 0;
}
static int spi_st_runtime_resume(struct device *dev)
static int __maybe_unused spi_st_runtime_resume(struct device *dev)
{
struct spi_controller *host = dev_get_drvdata(dev);
struct spi_st *spi_st = spi_controller_get_devdata(host);
@ -403,10 +402,8 @@ static int spi_st_runtime_resume(struct device *dev)
return ret;
}
#endif
#ifdef CONFIG_PM_SLEEP
static int spi_st_suspend(struct device *dev)
static int __maybe_unused spi_st_suspend(struct device *dev)
{
struct spi_controller *host = dev_get_drvdata(dev);
int ret;
@ -418,7 +415,7 @@ static int spi_st_suspend(struct device *dev)
return pm_runtime_force_suspend(dev);
}
static int spi_st_resume(struct device *dev)
static int __maybe_unused spi_st_resume(struct device *dev)
{
struct spi_controller *host = dev_get_drvdata(dev);
int ret;
@ -429,7 +426,6 @@ static int spi_st_resume(struct device *dev)
return pm_runtime_force_resume(dev);
}
#endif
static const struct dev_pm_ops spi_st_pm = {
SET_SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume)
@ -445,7 +441,7 @@ MODULE_DEVICE_TABLE(of, stm_spi_match);
static struct platform_driver spi_st_driver = {
.driver = {
.name = "spi-st",
.pm = &spi_st_pm,
.pm = pm_sleep_ptr(&spi_st_pm),
.of_match_table = of_match_ptr(stm_spi_match),
},
.probe = spi_st_probe,

View File

@ -547,7 +547,6 @@ static int stm32_ospi_poll_status(struct spi_mem *mem,
ret = stm32_ospi_send(mem->spi, op);
mutex_unlock(&ospi->lock);
pm_runtime_mark_last_busy(ospi->dev);
pm_runtime_put_autosuspend(ospi->dev);
return ret;
@ -571,7 +570,6 @@ static int stm32_ospi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
ret = stm32_ospi_send(mem->spi, op);
mutex_unlock(&ospi->lock);
pm_runtime_mark_last_busy(ospi->dev);
pm_runtime_put_autosuspend(ospi->dev);
return ret;
@ -628,7 +626,6 @@ static ssize_t stm32_ospi_dirmap_read(struct spi_mem_dirmap_desc *desc,
ret = stm32_ospi_send(desc->mem->spi, &op);
mutex_unlock(&ospi->lock);
pm_runtime_mark_last_busy(ospi->dev);
pm_runtime_put_autosuspend(ospi->dev);
return ret ?: len;
@ -713,7 +710,6 @@ static int stm32_ospi_transfer_one_message(struct spi_controller *ctrl,
msg->status = ret;
spi_finalize_current_message(ctrl);
pm_runtime_mark_last_busy(ospi->dev);
pm_runtime_put_autosuspend(ospi->dev);
return ret;
@ -750,7 +746,6 @@ static int stm32_ospi_setup(struct spi_device *spi)
mutex_unlock(&ospi->lock);
pm_runtime_mark_last_busy(ospi->dev);
pm_runtime_put_autosuspend(ospi->dev);
return 0;
@ -771,9 +766,7 @@ static int stm32_ospi_get_resources(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct stm32_ospi *ospi = platform_get_drvdata(pdev);
struct resource *res;
struct reserved_mem *rmem = NULL;
struct device_node *node;
struct resource *res, _res;
int ret;
ospi->regs_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
@ -825,18 +818,14 @@ static int stm32_ospi_get_resources(struct platform_device *pdev)
goto err_dma;
}
node = of_parse_phandle(dev->of_node, "memory-region", 0);
if (node)
rmem = of_reserved_mem_lookup(node);
of_node_put(node);
if (rmem) {
ospi->mm_size = rmem->size;
ospi->mm_base = devm_ioremap(dev, rmem->base, rmem->size);
if (!ospi->mm_base) {
dev_err(dev, "unable to map memory region: %pa+%pa\n",
&rmem->base, &rmem->size);
ret = -ENOMEM;
res = &_res;
ret = of_reserved_mem_region_to_resource(dev->of_node, 0, res);
if (!ret) {
ospi->mm_size = resource_size(res);
ospi->mm_base = devm_ioremap_resource(dev, res);
if (IS_ERR(ospi->mm_base)) {
dev_err(dev, "unable to map memory region: %pR\n", res);
ret = PTR_ERR(ospi->mm_base);
goto err_dma;
}
@ -953,7 +942,6 @@ static int stm32_ospi_probe(struct platform_device *pdev)
goto err_pm_resume;
}
pm_runtime_mark_last_busy(ospi->dev);
pm_runtime_put_autosuspend(ospi->dev);
return 0;
@ -1032,7 +1020,6 @@ static int __maybe_unused stm32_ospi_resume(struct device *dev)
writel_relaxed(ospi->cr_reg, regs_base + OSPI_CR);
writel_relaxed(ospi->dcr_reg, regs_base + OSPI_DCR1);
pm_runtime_mark_last_busy(ospi->dev);
pm_runtime_put_autosuspend(ospi->dev);
return 0;

View File

@ -463,7 +463,6 @@ static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *
ret = stm32_qspi_send(mem->spi, op);
mutex_unlock(&qspi->lock);
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return ret;
@ -487,7 +486,6 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
ret = stm32_qspi_send(mem->spi, op);
mutex_unlock(&qspi->lock);
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return ret;
@ -543,7 +541,6 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc,
ret = stm32_qspi_send(desc->mem->spi, &op);
mutex_unlock(&qspi->lock);
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return ret ?: len;
@ -627,7 +624,6 @@ static int stm32_qspi_transfer_one_message(struct spi_controller *ctrl,
msg->status = ret;
spi_finalize_current_message(ctrl);
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return ret;
@ -684,7 +680,6 @@ static int stm32_qspi_setup(struct spi_device *spi)
writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR);
mutex_unlock(&qspi->lock);
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return 0;
@ -858,7 +853,6 @@ static int stm32_qspi_probe(struct platform_device *pdev)
if (ret)
goto err_pm_runtime_free;
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@ -938,7 +932,6 @@ static int __maybe_unused stm32_qspi_resume(struct device *dev)
writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR);
writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;

View File

@ -9,7 +9,9 @@
#include <linux/debugfs.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/genalloc.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/module.h>
@ -154,6 +156,9 @@
/* STM32H7_SPI_I2SCFGR bit fields */
#define STM32H7_SPI_I2SCFGR_I2SMOD BIT(0)
/* STM32MP25_SPICFG2 bit fields */
#define STM32MP25_SPI_CFG2_RDIOM BIT(13)
/* STM32MP25 SPI registers bit fields */
#define STM32MP25_SPI_HWCFGR1 0x3F0
@ -222,6 +227,7 @@ struct stm32_spi_reg {
* @rx: SPI RX data register
* @tx: SPI TX data register
* @fullcfg: SPI full or limited feature set register
* @rdy_en: SPI ready feature register
*/
struct stm32_spi_regspec {
const struct stm32_spi_reg en;
@ -235,6 +241,7 @@ struct stm32_spi_regspec {
const struct stm32_spi_reg rx;
const struct stm32_spi_reg tx;
const struct stm32_spi_reg fullcfg;
const struct stm32_spi_reg rdy_en;
};
struct stm32_spi;
@ -276,7 +283,7 @@ struct stm32_spi_cfg {
int (*config)(struct stm32_spi *spi);
void (*set_bpw)(struct stm32_spi *spi);
int (*set_mode)(struct stm32_spi *spi, unsigned int comm_type);
void (*set_data_idleness)(struct stm32_spi *spi, u32 length);
void (*set_data_idleness)(struct stm32_spi *spi, struct spi_transfer *xfer);
int (*set_number_of_data)(struct stm32_spi *spi, u32 length);
void (*write_tx)(struct stm32_spi *spi);
void (*read_rx)(struct stm32_spi *spi);
@ -323,6 +330,11 @@ struct stm32_spi_cfg {
* @dma_rx: dma channel for RX transfer
* @phys_addr: SPI registers physical base address
* @device_mode: the controller is configured as SPI device
* @sram_pool: SRAM pool for DMA transfers
* @sram_rx_buf_size: size of SRAM buffer for RX transfer
* @sram_rx_buf: SRAM buffer for RX transfer
* @sram_dma_rx_buf: SRAM buffer physical address for RX transfer
* @mdma_rx: MDMA channel for RX transfer
*/
struct stm32_spi {
struct device *dev;
@ -357,6 +369,12 @@ struct stm32_spi {
dma_addr_t phys_addr;
bool device_mode;
struct gen_pool *sram_pool;
size_t sram_rx_buf_size;
void *sram_rx_buf;
dma_addr_t sram_dma_rx_buf;
struct dma_chan *mdma_rx;
};
static const struct stm32_spi_regspec stm32fx_spi_regspec = {
@ -415,6 +433,8 @@ static const struct stm32_spi_regspec stm32mp25_spi_regspec = {
.tx = { STM32H7_SPI_TXDR },
.fullcfg = { STM32MP25_SPI_HWCFGR1, STM32MP25_SPI_HWCFGR1_FULLCFG },
.rdy_en = { STM32H7_SPI_CFG2, STM32MP25_SPI_CFG2_RDIOM },
};
static inline void stm32_spi_set_bits(struct stm32_spi *spi,
@ -878,8 +898,11 @@ static void stm32h7_spi_disable(struct stm32_spi *spi)
if (spi->cur_usedma && spi->dma_tx)
dmaengine_terminate_async(spi->dma_tx);
if (spi->cur_usedma && spi->dma_rx)
if (spi->cur_usedma && spi->dma_rx) {
dmaengine_terminate_async(spi->dma_rx);
if (spi->mdma_rx)
dmaengine_terminate_async(spi->mdma_rx);
}
stm32_spi_clr_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_SPE);
@ -1091,10 +1114,13 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
}
if (sr & STM32H7_SPI_SR_EOT) {
dev_dbg(spi->dev, "End of transfer\n");
if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
stm32h7_spi_read_rxfifo(spi);
if (!spi->cur_usedma ||
(spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX))
(spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) ||
(spi->mdma_rx && (spi->cur_comm == SPI_SIMPLEX_RX ||
spi->cur_comm == SPI_FULL_DUPLEX)))
end = true;
}
@ -1111,6 +1137,11 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
spin_unlock_irqrestore(&spi->lock, flags);
if (end) {
if (spi->cur_usedma && spi->mdma_rx) {
dmaengine_pause(spi->dma_rx);
/* Wait for callback */
return IRQ_HANDLED;
}
stm32h7_spi_disable(spi);
spi_finalize_current_transfer(ctrl);
}
@ -1172,15 +1203,21 @@ static int stm32_spi_prepare_msg(struct spi_controller *ctrl,
else
clrb |= spi->cfg->regs->cs_high.mask;
dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d\n",
if (spi_dev->mode & SPI_READY)
setb |= spi->cfg->regs->rdy_en.mask;
else
clrb |= spi->cfg->regs->rdy_en.mask;
dev_dbg(spi->dev, "cpol=%d cpha=%d lsb_first=%d cs_high=%d rdy=%d\n",
!!(spi_dev->mode & SPI_CPOL),
!!(spi_dev->mode & SPI_CPHA),
!!(spi_dev->mode & SPI_LSB_FIRST),
!!(spi_dev->mode & SPI_CS_HIGH));
!!(spi_dev->mode & SPI_CS_HIGH),
!!(spi_dev->mode & SPI_READY));
spin_lock_irqsave(&spi->lock, flags);
/* CPOL, CPHA and LSB FIRST bits have common register */
/* CPOL, CPHA, LSB FIRST, CS_HIGH and RDY_EN bits have common register */
if (clrb || setb)
writel_relaxed(
(readl_relaxed(spi->base + spi->cfg->regs->cpol.reg) &
@ -1410,6 +1447,8 @@ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi)
/* Enable the interrupts */
if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX)
ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE;
if (spi->mdma_rx && (spi->cur_comm == SPI_SIMPLEX_RX || spi->cur_comm == SPI_FULL_DUPLEX))
ier |= STM32H7_SPI_IER_EOTIE;
stm32_spi_set_bits(spi, STM32H7_SPI_IER, ier);
@ -1419,6 +1458,121 @@ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi)
stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART);
}
/**
* stm32_spi_prepare_rx_dma_mdma_chaining - Prepare RX DMA and MDMA chaining
* @spi: pointer to the spi controller data structure
* @xfer: pointer to the spi transfer
* @rx_dma_conf: pointer to the DMA configuration for RX channel
* @rx_dma_desc: pointer to the RX DMA descriptor
* @rx_mdma_desc: pointer to the RX MDMA descriptor
*
* It must return 0 if the chaining is possible or an error code if not.
*/
static int stm32_spi_prepare_rx_dma_mdma_chaining(struct stm32_spi *spi,
struct spi_transfer *xfer,
struct dma_slave_config *rx_dma_conf,
struct dma_async_tx_descriptor **rx_dma_desc,
struct dma_async_tx_descriptor **rx_mdma_desc)
{
struct dma_async_tx_descriptor *_mdma_desc = *rx_mdma_desc;
struct dma_async_tx_descriptor *_dma_desc = *rx_dma_desc;
struct dma_slave_config rx_mdma_conf = {0};
u32 sram_period, nents = 0, spi_s_len;
struct sg_table dma_sgt, mdma_sgt;
struct scatterlist *spi_s, *s;
dma_addr_t dma_buf;
int i, ret;
sram_period = spi->sram_rx_buf_size / 2;
/* Configure MDMA RX channel */
rx_mdma_conf.direction = rx_dma_conf->direction;
rx_mdma_conf.src_addr = spi->sram_dma_rx_buf;
rx_mdma_conf.peripheral_config = rx_dma_conf->peripheral_config;
rx_mdma_conf.peripheral_size = rx_dma_conf->peripheral_size;
dmaengine_slave_config(spi->mdma_rx, &rx_mdma_conf);
/* Count the number of entries needed */
for_each_sg(xfer->rx_sg.sgl, spi_s, xfer->rx_sg.nents, i)
if (sg_dma_len(spi_s) > sram_period)
nents += DIV_ROUND_UP(sg_dma_len(spi_s), sram_period);
else
nents++;
/* Prepare DMA slave_sg DBM transfer DEV_TO_MEM (RX>MEM=SRAM) */
ret = sg_alloc_table(&dma_sgt, nents, GFP_ATOMIC);
if (ret)
return ret;
spi_s = xfer->rx_sg.sgl;
spi_s_len = sg_dma_len(spi_s);
dma_buf = spi->sram_dma_rx_buf;
for_each_sg(dma_sgt.sgl, s, dma_sgt.nents, i) {
size_t bytes = min_t(size_t, spi_s_len, sram_period);
sg_dma_len(s) = bytes;
sg_dma_address(s) = dma_buf;
spi_s_len -= bytes;
if (!spi_s_len && sg_next(spi_s)) {
spi_s = sg_next(spi_s);
spi_s_len = sg_dma_len(spi_s);
dma_buf = spi->sram_dma_rx_buf;
} else { /* DMA configured in DBM: it will swap between the SRAM periods */
if (i & 1)
dma_buf += sram_period;
else
dma_buf = spi->sram_dma_rx_buf;
}
}
_dma_desc = dmaengine_prep_slave_sg(spi->dma_rx, dma_sgt.sgl,
dma_sgt.nents, rx_dma_conf->direction,
DMA_PREP_INTERRUPT);
sg_free_table(&dma_sgt);
if (!_dma_desc)
return -EINVAL;
/* Prepare MDMA slave_sg transfer MEM_TO_MEM (SRAM>DDR) */
ret = sg_alloc_table(&mdma_sgt, nents, GFP_ATOMIC);
if (ret) {
_dma_desc = NULL;
return ret;
}
spi_s = xfer->rx_sg.sgl;
spi_s_len = sg_dma_len(spi_s);
dma_buf = sg_dma_address(spi_s);
for_each_sg(mdma_sgt.sgl, s, mdma_sgt.nents, i) {
size_t bytes = min_t(size_t, spi_s_len, sram_period);
sg_dma_len(s) = bytes;
sg_dma_address(s) = dma_buf;
spi_s_len -= bytes;
if (!spi_s_len && sg_next(spi_s)) {
spi_s = sg_next(spi_s);
spi_s_len = sg_dma_len(spi_s);
dma_buf = sg_dma_address(spi_s);
} else {
dma_buf += bytes;
}
}
_mdma_desc = dmaengine_prep_slave_sg(spi->mdma_rx, mdma_sgt.sgl,
mdma_sgt.nents, rx_mdma_conf.direction,
DMA_PREP_INTERRUPT);
sg_free_table(&mdma_sgt);
if (!_mdma_desc) {
_dma_desc = NULL;
return -EINVAL;
}
return 0;
}
/**
* stm32_spi_transfer_one_dma - transfer a single spi_transfer using DMA
* @spi: pointer to the spi controller data structure
@ -1430,38 +1584,43 @@ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi)
static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
struct spi_transfer *xfer)
{
struct dma_async_tx_descriptor *rx_mdma_desc = NULL, *rx_dma_desc = NULL;
struct dma_async_tx_descriptor *tx_dma_desc = NULL;
struct dma_slave_config tx_dma_conf, rx_dma_conf;
struct dma_async_tx_descriptor *tx_dma_desc, *rx_dma_desc;
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&spi->lock, flags);
rx_dma_desc = NULL;
if (spi->rx_buf && spi->dma_rx) {
stm32_spi_dma_config(spi, spi->dma_rx, &rx_dma_conf, DMA_DEV_TO_MEM);
dmaengine_slave_config(spi->dma_rx, &rx_dma_conf);
if (spi->mdma_rx) {
rx_dma_conf.peripheral_size = 1;
dmaengine_slave_config(spi->dma_rx, &rx_dma_conf);
/* Enable Rx DMA request */
stm32_spi_set_bits(spi, spi->cfg->regs->dma_rx_en.reg,
spi->cfg->regs->dma_rx_en.mask);
rx_dma_desc = dmaengine_prep_slave_sg(
spi->dma_rx, xfer->rx_sg.sgl,
xfer->rx_sg.nents,
rx_dma_conf.direction,
DMA_PREP_INTERRUPT);
ret = stm32_spi_prepare_rx_dma_mdma_chaining(spi, xfer, &rx_dma_conf,
&rx_dma_desc, &rx_mdma_desc);
if (ret) { /* RX DMA MDMA chaining not possible, fallback to DMA only */
rx_dma_conf.peripheral_config = 0;
rx_dma_desc = NULL;
}
}
if (!rx_dma_desc) {
dmaengine_slave_config(spi->dma_rx, &rx_dma_conf);
rx_dma_desc = dmaengine_prep_slave_sg(spi->dma_rx, xfer->rx_sg.sgl,
xfer->rx_sg.nents,
rx_dma_conf.direction,
DMA_PREP_INTERRUPT);
}
}
tx_dma_desc = NULL;
if (spi->tx_buf && spi->dma_tx) {
stm32_spi_dma_config(spi, spi->dma_tx, &tx_dma_conf, DMA_MEM_TO_DEV);
dmaengine_slave_config(spi->dma_tx, &tx_dma_conf);
tx_dma_desc = dmaengine_prep_slave_sg(
spi->dma_tx, xfer->tx_sg.sgl,
xfer->tx_sg.nents,
tx_dma_conf.direction,
DMA_PREP_INTERRUPT);
tx_dma_desc = dmaengine_prep_slave_sg(spi->dma_tx, xfer->tx_sg.sgl,
xfer->tx_sg.nents,
tx_dma_conf.direction,
DMA_PREP_INTERRUPT);
}
if ((spi->tx_buf && spi->dma_tx && !tx_dma_desc) ||
@ -1472,9 +1631,25 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
goto dma_desc_error;
if (rx_dma_desc) {
rx_dma_desc->callback = spi->cfg->dma_rx_cb;
rx_dma_desc->callback_param = spi;
if (rx_mdma_desc) {
rx_mdma_desc->callback = spi->cfg->dma_rx_cb;
rx_mdma_desc->callback_param = spi;
} else {
rx_dma_desc->callback = spi->cfg->dma_rx_cb;
rx_dma_desc->callback_param = spi;
}
/* Enable Rx DMA request */
stm32_spi_set_bits(spi, spi->cfg->regs->dma_rx_en.reg,
spi->cfg->regs->dma_rx_en.mask);
if (rx_mdma_desc) {
if (dma_submit_error(dmaengine_submit(rx_mdma_desc))) {
dev_err(spi->dev, "Rx MDMA submit failed\n");
goto dma_desc_error;
}
/* Enable Rx MDMA channel */
dma_async_issue_pending(spi->mdma_rx);
}
if (dma_submit_error(dmaengine_submit(rx_dma_desc))) {
dev_err(spi->dev, "Rx DMA submit failed\n");
goto dma_desc_error;
@ -1509,6 +1684,8 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
return 1;
dma_submit_error:
if (spi->mdma_rx)
dmaengine_terminate_sync(spi->mdma_rx);
if (spi->dma_rx)
dmaengine_terminate_sync(spi->dma_rx);
@ -1520,6 +1697,9 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
dev_info(spi->dev, "DMA issue: fall back to irq transfer\n");
if (spi->sram_rx_buf)
memset(spi->sram_rx_buf, 0, spi->sram_rx_buf_size);
spi->cur_usedma = false;
return spi->cfg->transfer_one_irq(spi);
}
@ -1702,11 +1882,26 @@ static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
* stm32h7_spi_data_idleness - configure minimum time delay inserted between two
* consecutive data frames in host mode
* @spi: pointer to the spi controller data structure
* @len: transfer len
* @xfer: pointer to spi transfer
*/
static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len)
static void stm32h7_spi_data_idleness(struct stm32_spi *spi, struct spi_transfer *xfer)
{
u32 cfg2_clrb = 0, cfg2_setb = 0;
u32 len = xfer->len;
u32 spi_delay_ns;
spi_delay_ns = spi_delay_to_ns(&xfer->word_delay, xfer);
if (spi->cur_midi != 0) {
dev_warn(spi->dev, "st,spi-midi-ns DT property is deprecated\n");
if (spi_delay_ns) {
dev_warn(spi->dev, "Overriding st,spi-midi-ns with word_delay_ns %d\n",
spi_delay_ns);
spi->cur_midi = spi_delay_ns;
}
} else {
spi->cur_midi = spi_delay_ns;
}
cfg2_clrb |= STM32H7_SPI_CFG2_MIDI;
if ((len > 1) && (spi->cur_midi > 0)) {
@ -1768,6 +1963,13 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
spi->cur_bpw = transfer->bits_per_word;
spi->cfg->set_bpw(spi);
if (spi_dev->mode & SPI_READY && spi->cur_bpw < 8) {
writel_relaxed(readl_relaxed(spi->base + spi->cfg->regs->rdy_en.reg) &
~spi->cfg->regs->rdy_en.mask,
spi->base + spi->cfg->regs->rdy_en.reg);
dev_dbg(spi->dev, "RDY logic disabled as bits per word < 8\n");
}
/* Update spi->cur_speed with real clock speed */
if (STM32_SPI_HOST_MODE(spi)) {
mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz,
@ -1790,7 +1992,7 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
spi->cur_comm = comm_type;
if (STM32_SPI_HOST_MODE(spi) && spi->cfg->set_data_idleness)
spi->cfg->set_data_idleness(spi, transfer->len);
spi->cfg->set_data_idleness(spi, transfer);
if (spi->cur_bpw <= 8)
nb_words = transfer->len;
@ -1871,6 +2073,9 @@ static int stm32_spi_unprepare_msg(struct spi_controller *ctrl,
spi->cfg->disable(spi);
if (spi->sram_rx_buf)
memset(spi->sram_rx_buf, 0, spi->sram_rx_buf_size);
return 0;
}
@ -2069,9 +2274,15 @@ static int stm32_spi_probe(struct platform_device *pdev)
struct resource *res;
struct reset_control *rst;
struct device_node *np = pdev->dev.of_node;
const struct stm32_spi_cfg *cfg;
bool device_mode;
int ret;
const struct stm32_spi_cfg *cfg = of_device_get_match_data(&pdev->dev);
cfg = of_device_get_match_data(&pdev->dev);
if (!cfg) {
dev_err(&pdev->dev, "Failed to get match data for platform\n");
return -ENODEV;
}
device_mode = of_property_read_bool(np, "spi-slave");
if (!cfg->has_device_mode && device_mode) {
@ -2179,7 +2390,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
ctrl->auto_runtime_pm = true;
ctrl->bus_num = pdev->id;
ctrl->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST |
SPI_3WIRE;
SPI_3WIRE | SPI_READY;
ctrl->bits_per_word_mask = spi->cfg->get_bpw_mask(spi);
ctrl->max_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_min;
ctrl->min_speed_hz = spi->clk_rate / spi->cfg->baud_rate_div_max;
@ -2219,6 +2430,33 @@ static int stm32_spi_probe(struct platform_device *pdev)
if (spi->dma_tx || spi->dma_rx)
ctrl->can_dma = stm32_spi_can_dma;
spi->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
if (spi->sram_pool) {
spi->sram_rx_buf_size = gen_pool_size(spi->sram_pool);
dev_info(&pdev->dev, "SRAM pool: %zu KiB for RX DMA/MDMA chaining\n",
spi->sram_rx_buf_size / 1024);
spi->sram_rx_buf = gen_pool_dma_zalloc(spi->sram_pool, spi->sram_rx_buf_size,
&spi->sram_dma_rx_buf);
if (!spi->sram_rx_buf) {
dev_err(&pdev->dev, "failed to allocate SRAM buffer\n");
} else {
spi->mdma_rx = dma_request_chan(spi->dev, "rxm2m");
if (IS_ERR(spi->mdma_rx)) {
ret = PTR_ERR(spi->mdma_rx);
spi->mdma_rx = NULL;
if (ret == -EPROBE_DEFER) {
goto err_pool_free;
} else {
gen_pool_free(spi->sram_pool,
(unsigned long)spi->sram_rx_buf,
spi->sram_rx_buf_size);
dev_warn(&pdev->dev,
"failed to request rx mdma channel, DMA only\n");
}
}
}
}
pm_runtime_set_autosuspend_delay(&pdev->dev,
STM32_SPI_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(&pdev->dev);
@ -2233,7 +2471,6 @@ static int stm32_spi_probe(struct platform_device *pdev)
goto err_pm_disable;
}
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
dev_info(&pdev->dev, "driver initialized (%s mode)\n",
@ -2246,6 +2483,13 @@ static int stm32_spi_probe(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
if (spi->mdma_rx)
dma_release_channel(spi->mdma_rx);
err_pool_free:
if (spi->sram_pool)
gen_pool_free(spi->sram_pool, (unsigned long)spi->sram_rx_buf,
spi->sram_rx_buf_size);
err_dma_release:
if (spi->dma_tx)
dma_release_channel(spi->dma_tx);
@ -2276,6 +2520,11 @@ static void stm32_spi_remove(struct platform_device *pdev)
dma_release_channel(ctrl->dma_tx);
if (ctrl->dma_rx)
dma_release_channel(ctrl->dma_rx);
if (spi->mdma_rx)
dma_release_channel(spi->mdma_rx);
if (spi->sram_rx_buf)
gen_pool_free(spi->sram_pool, (unsigned long)spi->sram_rx_buf,
spi->sram_rx_buf_size);
clk_disable_unprepare(spi->clk);
@ -2342,7 +2591,6 @@ static int __maybe_unused stm32_spi_resume(struct device *dev)
spi->cfg->config(spi);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;

View File

@ -158,7 +158,6 @@ static int ti_qspi_setup(struct spi_device *spi)
return ret;
}
pm_runtime_mark_last_busy(qspi->dev);
ret = pm_runtime_put_autosuspend(qspi->dev);
if (ret < 0) {
dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n");
@ -195,7 +194,6 @@ static void ti_qspi_setup_clk(struct ti_qspi *qspi, u32 speed_hz)
ctx_reg->clkctrl = clk_ctrl_new;
}
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
}

View File

@ -89,8 +89,8 @@ struct xilinx_spi {
u8 bytes_per_word;
int buffer_size; /* buffer size in words */
u32 cs_inactive; /* Level of the CS pins when inactive*/
unsigned int (*read_fn)(void __iomem *);
void (*write_fn)(u32, void __iomem *);
unsigned int (*read_fn)(void __iomem *addr);
void (*write_fn)(u32 val, void __iomem *addr);
};
static void xspi_write32(u32 val, void __iomem *addr)
@ -251,6 +251,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
if (xspi->irq >= 0 &&
(xspi->force_irq || remaining_words > xspi->buffer_size)) {
u32 isr;
use_irq = true;
/* Inhibit irq to avoid spurious irqs on tx_empty*/
cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);

View File

@ -1330,7 +1330,6 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
goto clk_dis_all;
}
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;

View File

@ -1723,7 +1723,6 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
static void spi_idle_runtime_pm(struct spi_controller *ctlr)
{
if (ctlr->auto_runtime_pm) {
pm_runtime_mark_last_busy(ctlr->dev.parent);
pm_runtime_put_autosuspend(ctlr->dev.parent);
}
}
@ -3856,7 +3855,6 @@ static int spi_set_cs_timing(struct spi_device *spi)
}
status = spi->controller->set_cs_timing(spi);
pm_runtime_mark_last_busy(parent);
pm_runtime_put_autosuspend(parent);
} else {
status = spi->controller->set_cs_timing(spi);
@ -3991,7 +3989,6 @@ int spi_setup(struct spi_device *spi)
status = 0;
spi_set_cs(spi, false, true);
pm_runtime_mark_last_busy(spi->controller->dev.parent);
pm_runtime_put_autosuspend(spi->controller->dev.parent);
} else {
spi_set_cs(spi, false, true);

View File

@ -703,6 +703,7 @@ static const struct class spidev_class = {
* spidev_dt_ids array below. Both arrays are kept in the same ordering.
*/
static const struct spi_device_id spidev_spi_ids[] = {
{ .name = /* abb */ "spi-sensor" },
{ .name = /* cisco */ "spi-petra" },
{ .name = /* dh */ "dhcom-board" },
{ .name = /* elgin */ "jg10309-01" },
@ -735,6 +736,7 @@ static int spidev_of_check(struct device *dev)
}
static const struct of_device_id spidev_dt_ids[] = {
{ .compatible = "abb,spi-sensor", .data = &spidev_of_check },
{ .compatible = "cisco,spi-petra", .data = &spidev_of_check },
{ .compatible = "dh,dhcom-board", .data = &spidev_of_check },
{ .compatible = "elgin,jg10309-01", .data = &spidev_of_check },

View File

@ -1524,6 +1524,7 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
struct dma_chan *dma_request_chan(struct device *dev, const char *name);
struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask);
struct dma_chan *devm_dma_request_chan(struct device *dev, const char *name);
void dma_release_channel(struct dma_chan *chan);
int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps);
@ -1560,6 +1561,12 @@ static inline struct dma_chan *dma_request_chan_by_mask(
{
return ERR_PTR(-ENODEV);
}
static inline struct dma_chan *devm_dma_request_chan(struct device *dev, const char *name)
{
return ERR_PTR(-ENODEV);
}
static inline void dma_release_channel(struct dma_chan *chan)
{
}

View File

@ -101,6 +101,8 @@
#define ECC_SW_RESET BIT(1)
#define ECC_MODE 4
#define ECC_MODE_MASK GENMASK(5, 4)
#define ECC_MODE_4BIT 0
#define ECC_MODE_8BIT 1
#define ECC_PARITY_SIZE_BYTES_BCH 8
#define ECC_PARITY_SIZE_BYTES_BCH_MASK GENMASK(12, 8)
#define ECC_NUM_DATA_BYTES 16