mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 08:20:52 +07:00
spi: Updates for v5.5
Lots of stuff going on in the core for SPI this time around, the two big changes both being around time in different forms: - A rework of delay times from Alexandru Ardelean which makes the ways in which they are specified more consistent between drivers so that what's available to clients is less dependent on the hardware implementation. - Support for PTP timestamping of transfers from Vladimir Oltean, useful for use with precision clocks with SPI control interfaces. - Big cleanups for the Atmel, PXA2xx and Zynq QSPI drivers. -----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAl3b1ogTHGJyb29uaWVA a2VybmVsLm9yZwAKCRAk1otyXVSH0NBpB/0Rh81T/xG0moEM6qyCqjriD8rQKfA7 l7r7pNPCXCTPnVe2mfSLrlu6ETi8tG1iVYGPSEQmo5JnlgpoOvr0SVvQMej0ceB+ jn3H31JgfvryMr99AFEsRN8N6GkY1dLlTV/5edKRTkut++tqlYD/G99bn3K7IlxW oN8le+fCDuF78mWGDEdClwuZ5ZDiZtWbRu01Q6ooVVZz3XLlLZPtgKH2qlwoVJ9r cuwnE2e3wce5Hq/JwAFnG2pUYIjKNd00/VxK640pU1dJ/LeqekH0Xe4ZoCr4X0zE 8c+srra1yefAiDIPNG0v+exZePuu53tbEJylVVefOlrGCTa+nbJBioH3 =+5en -----END PGP SIGNATURE----- Merge tag 'spi-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi updates from Mark Brown: "Lots of stuff going on in the core for SPI this time around, the two big changes both being around time in different forms: - A rework of delay times from Alexandru Ardelean which makes the ways in which they are specified more consistent between drivers so that what's available to clients is less dependent on the hardware implementation. - Support for PTP timestamping of transfers from Vladimir Oltean, useful for use with precision clocks with SPI control interfaces. - Big cleanups for the Atmel, PXA2xx and Zynq QSPI drivers" * tag 'spi-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (119 commits) dt-bindings: spi: Convert stm32 QSPI bindings to json-schema spi: pic32: Retire dma_request_slave_channel_compat() spi: Fix Kconfig indentation spi: mediatek: add SPI_CS_HIGH support spi: st-ssc4: add missed pm_runtime_disable spi: tegra20-slink: add missed clk_unprepare spi: tegra20-slink: Use dma_request_chan() directly for channel request spi: tegra114: Use dma_request_chan() directly for channel request spi: s3c64xx: Use dma_request_chan() directly for channel request spi: qup: Use dma_request_chan() directly for channel request spi: pl022: Use dma_request_chan() directly for channel request spi: imx: Use dma_request_chan() directly for channel request spi: fsl-lpspi: Use dma_request_chan() directly for channel request spi: atmel: Use dma_request_chan() directly for channel request spi: at91-usart: Use dma_request_chan() directly for channel request spi: fsl-cpm: Correct the free:ing spi: Fix regression to return zero on success instead of positive value spi: pxa2xx: Add missed security checks spi: nxp-fspi: Use devm API to fix missed unregistration of controller spi: omap2-mcspi: Remove redundant checks ...
This commit is contained in:
commit
a86f69d334
57
Documentation/devicetree/bindings/spi/renesas,hspi.yaml
Normal file
57
Documentation/devicetree/bindings/spi/renesas,hspi.yaml
Normal file
@ -0,0 +1,57 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/renesas,hspi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas HSPI
|
||||
|
||||
maintainers:
|
||||
- Geert Uytterhoeven <geert+renesas@glider.be>
|
||||
|
||||
allOf:
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,hspi-r8a7778 # R-Car M1A
|
||||
- renesas,hspi-r8a7779 # R-Car H1
|
||||
- const: renesas,hspi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- '#address-cells'
|
||||
- '#size-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7778-clock.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
hspi0: spi@fffc7000 {
|
||||
compatible = "renesas,hspi-r8a7778", "renesas,hspi";
|
||||
reg = <0xfffc7000 0x18>;
|
||||
interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp0_clks R8A7778_CLK_HSPI>;
|
||||
power-domains = <&cpg_clocks>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
11
Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt
Normal file
11
Documentation/devicetree/bindings/spi/renesas,rzn1-spi.txt
Normal file
@ -0,0 +1,11 @@
|
||||
Renesas RZ/N1 SPI Controller
|
||||
|
||||
This controller is based on the Synopsys DW Synchronous Serial Interface and
|
||||
inherits all properties defined in snps,dw-apb-ssi.txt except for the
|
||||
compatible property.
|
||||
|
||||
Required properties:
|
||||
- compatible : The device specific string followed by the generic RZ/N1 string.
|
||||
Therefore it must be one of:
|
||||
"renesas,r9a06g032-spi", "renesas,rzn1-spi"
|
||||
"renesas,r9a06g033-spi", "renesas,rzn1-spi"
|
159
Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml
Normal file
159
Documentation/devicetree/bindings/spi/renesas,sh-msiof.yaml
Normal file
@ -0,0 +1,159 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/renesas,sh-msiof.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas MSIOF SPI controller
|
||||
|
||||
maintainers:
|
||||
- Geert Uytterhoeven <geert+renesas@glider.be>
|
||||
|
||||
allOf:
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: renesas,msiof-sh73a0 # SH-Mobile AG5
|
||||
- const: renesas,sh-mobile-msiof # generic SH-Mobile compatible
|
||||
# device
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,msiof-r8a7743 # RZ/G1M
|
||||
- renesas,msiof-r8a7744 # RZ/G1N
|
||||
- renesas,msiof-r8a7745 # RZ/G1E
|
||||
- renesas,msiof-r8a77470 # RZ/G1C
|
||||
- renesas,msiof-r8a7790 # R-Car H2
|
||||
- renesas,msiof-r8a7791 # R-Car M2-W
|
||||
- renesas,msiof-r8a7792 # R-Car V2H
|
||||
- renesas,msiof-r8a7793 # R-Car M2-N
|
||||
- renesas,msiof-r8a7794 # R-Car E2
|
||||
- const: renesas,rcar-gen2-msiof # generic R-Car Gen2 and RZ/G1
|
||||
# compatible device
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,msiof-r8a774a1 # RZ/G2M
|
||||
- renesas,msiof-r8a774b1 # RZ/G2N
|
||||
- renesas,msiof-r8a774c0 # RZ/G2E
|
||||
- renesas,msiof-r8a7795 # R-Car H3
|
||||
- renesas,msiof-r8a7796 # R-Car M3-W
|
||||
- renesas,msiof-r8a77965 # R-Car M3-N
|
||||
- renesas,msiof-r8a77970 # R-Car V3M
|
||||
- renesas,msiof-r8a77980 # R-Car V3H
|
||||
- renesas,msiof-r8a77990 # R-Car E3
|
||||
- renesas,msiof-r8a77995 # R-Car D3
|
||||
- const: renesas,rcar-gen3-msiof # generic R-Car Gen3 and RZ/G2
|
||||
# compatible device
|
||||
- items:
|
||||
- const: renesas,sh-msiof # deprecated
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
oneOf:
|
||||
- items:
|
||||
- description: CPU and DMA engine registers
|
||||
- items:
|
||||
- description: CPU registers
|
||||
- description: DMA engine registers
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
num-cs:
|
||||
description: |
|
||||
Total number of chip selects (default is 1).
|
||||
Up to 3 native chip selects are supported:
|
||||
0: MSIOF_SYNC
|
||||
1: MSIOF_SS1
|
||||
2: MSIOF_SS2
|
||||
Hardware limitations related to chip selects:
|
||||
- Native chip selects are always deasserted in between transfers
|
||||
that are part of the same message. Use cs-gpios to work around
|
||||
this.
|
||||
- All slaves using native chip selects must use the same spi-cs-high
|
||||
configuration. Use cs-gpios to work around this.
|
||||
- When using GPIO chip selects, at least one native chip select must
|
||||
be left unused, as it will be driven anyway.
|
||||
minimum: 1
|
||||
maximum: 3
|
||||
default: 1
|
||||
|
||||
dmas:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
|
||||
dma-names:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
enum: [ tx, rx ]
|
||||
|
||||
renesas,dtdl:
|
||||
description: delay sync signal (setup) in transmit mode.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum:
|
||||
- 0 # no bit delay
|
||||
- 50 # 0.5-clock-cycle delay
|
||||
- 100 # 1-clock-cycle delay
|
||||
- 150 # 1.5-clock-cycle delay
|
||||
- 200 # 2-clock-cycle delay
|
||||
|
||||
renesas,syncdl:
|
||||
description: delay sync signal (hold) in transmit mode
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- enum:
|
||||
- 0 # no bit delay
|
||||
- 50 # 0.5-clock-cycle delay
|
||||
- 100 # 1-clock-cycle delay
|
||||
- 150 # 1.5-clock-cycle delay
|
||||
- 200 # 2-clock-cycle delay
|
||||
- 300 # 3-clock-cycle delay
|
||||
|
||||
renesas,tx-fifo-size:
|
||||
# deprecated for soctype-specific bindings
|
||||
description: |
|
||||
Override the default TX fifo size. Unit is words. Ignored if 0.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- maxItems: 1
|
||||
default: 64
|
||||
|
||||
renesas,rx-fifo-size:
|
||||
# deprecated for soctype-specific bindings
|
||||
description: |
|
||||
Override the default RX fifo size. Unit is words. Ignored if 0.
|
||||
allOf:
|
||||
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||
- maxItems: 1
|
||||
default: 64
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- '#address-cells'
|
||||
- '#size-cells'
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r8a7791-clock.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
msiof0: spi@e6e20000 {
|
||||
compatible = "renesas,msiof-r8a7791", "renesas,rcar-gen2-msiof";
|
||||
reg = <0 0xe6e20000 0 0x0064>;
|
||||
interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
|
||||
dmas = <&dmac0 0x51>, <&dmac0 0x52>;
|
||||
dma-names = "tx", "rx";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
@ -1,26 +0,0 @@
|
||||
Renesas HSPI.
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,hspi-<soctype>", "renesas,hspi" as fallback.
|
||||
Examples with soctypes are:
|
||||
- "renesas,hspi-r8a7778" (R-Car M1)
|
||||
- "renesas,hspi-r8a7779" (R-Car H1)
|
||||
- reg : Offset and length of the register set for the device
|
||||
- interrupts : Interrupt specifier
|
||||
- #address-cells : Must be <1>
|
||||
- #size-cells : Must be <0>
|
||||
|
||||
Pinctrl properties might be needed, too. See
|
||||
Documentation/devicetree/bindings/pinctrl/renesas,*.
|
||||
|
||||
Example:
|
||||
|
||||
hspi0: spi@fffc7000 {
|
||||
compatible = "renesas,hspi-r8a7778", "renesas,hspi";
|
||||
reg = <0xfffc7000 0x18>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
@ -1,105 +0,0 @@
|
||||
Renesas MSIOF spi controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,msiof-r8a7743" (RZ/G1M)
|
||||
"renesas,msiof-r8a7744" (RZ/G1N)
|
||||
"renesas,msiof-r8a7745" (RZ/G1E)
|
||||
"renesas,msiof-r8a77470" (RZ/G1C)
|
||||
"renesas,msiof-r8a774a1" (RZ/G2M)
|
||||
"renesas,msiof-r8a774c0" (RZ/G2E)
|
||||
"renesas,msiof-r8a7790" (R-Car H2)
|
||||
"renesas,msiof-r8a7791" (R-Car M2-W)
|
||||
"renesas,msiof-r8a7792" (R-Car V2H)
|
||||
"renesas,msiof-r8a7793" (R-Car M2-N)
|
||||
"renesas,msiof-r8a7794" (R-Car E2)
|
||||
"renesas,msiof-r8a7795" (R-Car H3)
|
||||
"renesas,msiof-r8a7796" (R-Car M3-W)
|
||||
"renesas,msiof-r8a77965" (R-Car M3-N)
|
||||
"renesas,msiof-r8a77970" (R-Car V3M)
|
||||
"renesas,msiof-r8a77980" (R-Car V3H)
|
||||
"renesas,msiof-r8a77990" (R-Car E3)
|
||||
"renesas,msiof-r8a77995" (R-Car D3)
|
||||
"renesas,msiof-sh73a0" (SH-Mobile AG5)
|
||||
"renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device)
|
||||
"renesas,rcar-gen2-msiof" (generic R-Car Gen2 and RZ/G1 compatible device)
|
||||
"renesas,rcar-gen3-msiof" (generic R-Car Gen3 and RZ/G2 compatible device)
|
||||
"renesas,sh-msiof" (deprecated)
|
||||
|
||||
When compatible with the generic version, nodes
|
||||
must list the SoC-specific version corresponding
|
||||
to the platform first followed by the generic
|
||||
version.
|
||||
|
||||
- reg : A list of offsets and lengths of the register sets for
|
||||
the device.
|
||||
If only one register set is present, it is to be used
|
||||
by both the CPU and the DMA engine.
|
||||
If two register sets are present, the first is to be
|
||||
used by the CPU, and the second is to be used by the
|
||||
DMA engine.
|
||||
- interrupts : Interrupt specifier
|
||||
- #address-cells : Must be <1>
|
||||
- #size-cells : Must be <0>
|
||||
|
||||
Optional properties:
|
||||
- clocks : Must contain a reference to the functional clock.
|
||||
- num-cs : Total number of chip selects (default is 1).
|
||||
Up to 3 native chip selects are supported:
|
||||
0: MSIOF_SYNC
|
||||
1: MSIOF_SS1
|
||||
2: MSIOF_SS2
|
||||
Hardware limitations related to chip selects:
|
||||
- Native chip selects are always deasserted in
|
||||
between transfers that are part of the same
|
||||
message. Use cs-gpios to work around this.
|
||||
- All slaves using native chip selects must use the
|
||||
same spi-cs-high configuration. Use cs-gpios to
|
||||
work around this.
|
||||
- When using GPIO chip selects, at least one native
|
||||
chip select must be left unused, as it will be
|
||||
driven anyway.
|
||||
- dmas : Must contain a list of two references to DMA
|
||||
specifiers, one for transmission, and one for
|
||||
reception.
|
||||
- dma-names : Must contain a list of two DMA names, "tx" and "rx".
|
||||
- spi-slave : Empty property indicating the SPI controller is used
|
||||
in slave mode.
|
||||
- renesas,dtdl : delay sync signal (setup) in transmit mode.
|
||||
Must contain one of the following values:
|
||||
0 (no bit delay)
|
||||
50 (0.5-clock-cycle delay)
|
||||
100 (1-clock-cycle delay)
|
||||
150 (1.5-clock-cycle delay)
|
||||
200 (2-clock-cycle delay)
|
||||
|
||||
- renesas,syncdl : delay sync signal (hold) in transmit mode.
|
||||
Must contain one of the following values:
|
||||
0 (no bit delay)
|
||||
50 (0.5-clock-cycle delay)
|
||||
100 (1-clock-cycle delay)
|
||||
150 (1.5-clock-cycle delay)
|
||||
200 (2-clock-cycle delay)
|
||||
300 (3-clock-cycle delay)
|
||||
|
||||
Optional properties, deprecated for soctype-specific bindings:
|
||||
- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
|
||||
(default is 64)
|
||||
- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
|
||||
(default is 64)
|
||||
|
||||
Pinctrl properties might be needed, too. See
|
||||
Documentation/devicetree/bindings/pinctrl/renesas,*.
|
||||
|
||||
Example:
|
||||
|
||||
msiof0: spi@e6e20000 {
|
||||
compatible = "renesas,msiof-r8a7791",
|
||||
"renesas,rcar-gen2-msiof";
|
||||
reg = <0 0xe6e20000 0 0x0064>;
|
||||
interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
|
||||
dmas = <&dmac0 0x51>, <&dmac0 0x52>;
|
||||
dma-names = "tx", "rx";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
@ -16,7 +16,8 @@ Required properties:
|
||||
Optional properties:
|
||||
- clock-names : Contains the names of the clocks:
|
||||
"ssi_clk", for the core clock used to generate the external SPI clock.
|
||||
"pclk", the interface clock, required for register access.
|
||||
"pclk", the interface clock, required for register access. If a clock domain
|
||||
used to enable this clock then it should be named "pclk_clkdomain".
|
||||
- cs-gpios : Specifies the gpio pins to be used for chipselects.
|
||||
- num-cs : The number of chipselects. If omitted, this will default to 4.
|
||||
- reg-io-width : The I/O register width (in bytes) implemented by this
|
||||
|
@ -1,37 +0,0 @@
|
||||
SiFive SPI controller Device Tree Bindings
|
||||
------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "sifive,<chip>-spi" and "sifive,spi<version>".
|
||||
Supported compatible strings are:
|
||||
"sifive,fu540-c000-spi" for the SiFive SPI v0 as integrated
|
||||
onto the SiFive FU540 chip, and "sifive,spi0" for the SiFive
|
||||
SPI v0 IP block with no chip integration tweaks.
|
||||
Please refer to sifive-blocks-ip-versioning.txt for details
|
||||
- reg : Physical base address and size of SPI registers map
|
||||
A second (optional) range can indicate memory mapped flash
|
||||
- interrupts : Must contain one entry
|
||||
- interrupt-parent : Must be core interrupt controller
|
||||
- clocks : Must reference the frequency given to the controller
|
||||
- #address-cells : Must be '1', indicating which CS to use
|
||||
- #size-cells : Must be '0'
|
||||
|
||||
Optional properties:
|
||||
- sifive,fifo-depth : Depth of hardware queues; defaults to 8
|
||||
- sifive,max-bits-per-word : Maximum bits per word; defaults to 8
|
||||
|
||||
SPI RTL that corresponds to the IP block version numbers can be found here:
|
||||
https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/spi
|
||||
|
||||
Example:
|
||||
spi: spi@10040000 {
|
||||
compatible = "sifive,fu540-c000-spi", "sifive,spi0";
|
||||
reg = <0x0 0x10040000 0x0 0x1000 0x0 0x20000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <51>;
|
||||
clocks = <&tlclk>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
sifive,fifo-depth = <8>;
|
||||
sifive,max-bits-per-word = <8>;
|
||||
};
|
86
Documentation/devicetree/bindings/spi/spi-sifive.yaml
Normal file
86
Documentation/devicetree/bindings/spi/spi-sifive.yaml
Normal file
@ -0,0 +1,86 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/spi-sifive.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: SiFive SPI controller
|
||||
|
||||
maintainers:
|
||||
- Pragnesh Patel <pragnesh.patel@sifive.com>
|
||||
- Paul Walmsley <paul.walmsley@sifive.com>
|
||||
- Palmer Dabbelt <palmer@sifive.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: sifive,fu540-c000-spi
|
||||
- const: sifive,spi0
|
||||
|
||||
description:
|
||||
Should be "sifive,<chip>-spi" and "sifive,spi<version>".
|
||||
Supported compatible strings are -
|
||||
"sifive,fu540-c000-spi" for the SiFive SPI v0 as integrated
|
||||
onto the SiFive FU540 chip, and "sifive,spi0" for the SiFive
|
||||
SPI v0 IP block with no chip integration tweaks.
|
||||
Please refer to sifive-blocks-ip-versioning.txt for details
|
||||
|
||||
SPI RTL that corresponds to the IP block version numbers can be found here -
|
||||
https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/spi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
description:
|
||||
Physical base address and size of SPI registers map
|
||||
A second (optional) range can indicate memory mapped flash
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
description:
|
||||
Must reference the frequency given to the controller
|
||||
|
||||
sifive,fifo-depth:
|
||||
description:
|
||||
Depth of hardware queues; defaults to 8
|
||||
allOf:
|
||||
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
- enum: [ 8 ]
|
||||
- default: 8
|
||||
|
||||
sifive,max-bits-per-word:
|
||||
description:
|
||||
Maximum bits per word; defaults to 8
|
||||
allOf:
|
||||
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
- enum: [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
|
||||
- default: 8
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi: spi@10040000 {
|
||||
compatible = "sifive,fu540-c000-spi", "sifive,spi0";
|
||||
reg = <0x0 0x10040000 0x0 0x1000 0x0 0x20000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <51>;
|
||||
clocks = <&tlclk>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
sifive,fifo-depth = <8>;
|
||||
sifive,max-bits-per-word = <8>;
|
||||
};
|
||||
|
||||
...
|
@ -1,47 +0,0 @@
|
||||
* STMicroelectronics Quad Serial Peripheral Interface(QSPI)
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "st,stm32f469-qspi"
|
||||
- reg: the first contains the register location and length.
|
||||
the second contains the memory mapping address and length
|
||||
- reg-names: should contain the reg names "qspi" "qspi_mm"
|
||||
- interrupts: should contain the interrupt for the device
|
||||
- clocks: the phandle of the clock needed by the QSPI controller
|
||||
- A pinctrl must be defined to set pins in mode of operation for QSPI transfer
|
||||
|
||||
Optional properties:
|
||||
- resets: must contain the phandle to the reset controller.
|
||||
|
||||
A spi flash (NOR/NAND) must be a child of spi node and could have some
|
||||
properties. Also see jedec,spi-nor.txt.
|
||||
|
||||
Required properties:
|
||||
- reg: chip-Select number (QSPI controller may connect 2 flashes)
|
||||
- spi-max-frequency: max frequency of spi bus
|
||||
|
||||
Optional properties:
|
||||
- spi-rx-bus-width: see ./spi-bus.txt for the description
|
||||
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
- dma-names: DMA request names should include "tx" and "rx" if present.
|
||||
|
||||
Example:
|
||||
|
||||
qspi: spi@a0001000 {
|
||||
compatible = "st,stm32f469-qspi";
|
||||
reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>;
|
||||
reg-names = "qspi", "qspi_mm";
|
||||
interrupts = <91>;
|
||||
resets = <&rcc STM32F4_AHB3_RESET(QSPI)>;
|
||||
clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_qspi0>;
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-rx-bus-width = <4>;
|
||||
spi-max-frequency = <108000000>;
|
||||
...
|
||||
};
|
||||
};
|
@ -8,7 +8,8 @@ Required properties:
|
||||
number.
|
||||
|
||||
Optional properties:
|
||||
- xlnx,num-ss-bits : Number of chip selects used.
|
||||
- xlnx,num-ss-bits : Number of chip selects used.
|
||||
- xlnx,num-transfer-bits : Number of bits per transfer. This will be 8 if not specified
|
||||
|
||||
Example:
|
||||
axi_quad_spi@41e00000 {
|
||||
@ -17,5 +18,6 @@ Example:
|
||||
interrupts = <0 31 1>;
|
||||
reg = <0x41e00000 0x10000>;
|
||||
xlnx,num-ss-bits = <0x1>;
|
||||
xlnx,num-transfer-bits = <32>;
|
||||
};
|
||||
|
||||
|
83
Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml
Normal file
83
Documentation/devicetree/bindings/spi/st,stm32-qspi.yaml
Normal file
@ -0,0 +1,83 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/st,stm32-qspi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics STM32 Quad Serial Peripheral Interface (QSPI) bindings
|
||||
|
||||
maintainers:
|
||||
- Christophe Kerello <christophe.kerello@st.com>
|
||||
- Patrice Chotard <patrice.chotard@st.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: st,stm32f469-qspi
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: registers
|
||||
- description: memory mapping
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: qspi
|
||||
- const: qspi_mm
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: tx DMA channel
|
||||
- description: rx DMA channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- clocks
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/stm32mp1-clks.h>
|
||||
#include <dt-bindings/reset/stm32mp1-resets.h>
|
||||
spi@58003000 {
|
||||
compatible = "st,stm32f469-qspi";
|
||||
reg = <0x58003000 0x1000>, <0x70000000 0x10000000>;
|
||||
reg-names = "qspi", "qspi_mm";
|
||||
interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&mdma1 22 0x10 0x100002 0x0 0x0>,
|
||||
<&mdma1 22 0x10 0x100008 0x0 0x0>;
|
||||
dma-names = "tx", "rx";
|
||||
clocks = <&rcc QSPI_K>;
|
||||
resets = <&rcc QSPI_R>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-rx-bus-width = <4>;
|
||||
spi-max-frequency = <108000000>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -89,7 +89,7 @@ void pxa_ssp_free(struct ssp_device *ssp)
|
||||
ssp->use_count--;
|
||||
ssp->label = NULL;
|
||||
} else
|
||||
dev_err(&ssp->pdev->dev, "device already free\n");
|
||||
dev_err(ssp->dev, "device already free\n");
|
||||
mutex_unlock(&ssp_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa_ssp_free);
|
||||
@ -118,7 +118,7 @@ static int pxa_ssp_probe(struct platform_device *pdev)
|
||||
if (ssp == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ssp->pdev = pdev;
|
||||
ssp->dev = dev;
|
||||
|
||||
ssp->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(ssp->clk))
|
||||
|
@ -39,24 +39,24 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->write_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 2,
|
||||
.bits_per_word = 8,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->write_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 4,
|
||||
.bits_per_word = 8,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->write_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 6,
|
||||
.bits_per_word = 8,
|
||||
@ -139,16 +139,16 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->write_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 2,
|
||||
.bits_per_word = 8,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->read_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 4,
|
||||
.rx_buf = adis->rx,
|
||||
@ -156,8 +156,8 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->read_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.rx_buf = adis->rx + 2,
|
||||
.bits_per_word = 8,
|
||||
|
@ -80,6 +80,7 @@ config SPI_ARMADA_3700
|
||||
config SPI_ATMEL
|
||||
tristate "Atmel SPI Controller"
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
This selects a driver for the Atmel SPI Controller, present on
|
||||
many AT91 ARM chips.
|
||||
@ -143,7 +144,7 @@ config SPI_BCM63XX
|
||||
tristate "Broadcom BCM63xx SPI controller"
|
||||
depends on BCM63XX || COMPILE_TEST
|
||||
help
|
||||
Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
|
||||
Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
|
||||
|
||||
config SPI_BCM63XX_HSSPI
|
||||
tristate "Broadcom BCM63XX HS SPI controller driver"
|
||||
@ -234,11 +235,11 @@ config SPI_DLN2
|
||||
tristate "Diolan DLN-2 USB SPI adapter"
|
||||
depends on MFD_DLN2
|
||||
help
|
||||
If you say yes to this option, support will be included for Diolan
|
||||
DLN2, a USB to SPI interface.
|
||||
If you say yes to this option, support will be included for Diolan
|
||||
DLN2, a USB to SPI interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called spi-dln2.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called spi-dln2.
|
||||
|
||||
config SPI_EFM32
|
||||
tristate "EFM32 SPI controller"
|
||||
@ -747,10 +748,10 @@ config SPI_SYNQUACER
|
||||
It also supports the new dual-bit and quad-bit SPI protocol.
|
||||
|
||||
config SPI_MXIC
|
||||
tristate "Macronix MX25F0A SPI controller"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
This selects the Macronix MX25F0A SPI controller driver.
|
||||
tristate "Macronix MX25F0A SPI controller"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
This selects the Macronix MX25F0A SPI controller driver.
|
||||
|
||||
config SPI_MXS
|
||||
tristate "Freescale MXS SPI controller"
|
||||
|
@ -132,7 +132,7 @@ static int at91_usart_spi_configure_dma(struct spi_controller *ctlr,
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
ctlr->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
ctlr->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR_OR_NULL(ctlr->dma_tx)) {
|
||||
if (IS_ERR(ctlr->dma_tx)) {
|
||||
err = PTR_ERR(ctlr->dma_tx);
|
||||
@ -145,7 +145,7 @@ static int at91_usart_spi_configure_dma(struct spi_controller *ctlr,
|
||||
goto at91_usart_spi_error_clear;
|
||||
}
|
||||
|
||||
ctlr->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
ctlr->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR_OR_NULL(ctlr->dma_rx)) {
|
||||
if (IS_ERR(ctlr->dma_rx)) {
|
||||
err = PTR_ERR(ctlr->dma_rx);
|
||||
|
@ -222,37 +222,13 @@
|
||||
| SPI_BF(name, value))
|
||||
|
||||
/* Register access macros */
|
||||
#ifdef CONFIG_AVR32
|
||||
#define spi_readl(port, reg) \
|
||||
__raw_readl((port)->regs + SPI_##reg)
|
||||
#define spi_writel(port, reg, value) \
|
||||
__raw_writel((value), (port)->regs + SPI_##reg)
|
||||
|
||||
#define spi_readw(port, reg) \
|
||||
__raw_readw((port)->regs + SPI_##reg)
|
||||
#define spi_writew(port, reg, value) \
|
||||
__raw_writew((value), (port)->regs + SPI_##reg)
|
||||
|
||||
#define spi_readb(port, reg) \
|
||||
__raw_readb((port)->regs + SPI_##reg)
|
||||
#define spi_writeb(port, reg, value) \
|
||||
__raw_writeb((value), (port)->regs + SPI_##reg)
|
||||
#else
|
||||
#define spi_readl(port, reg) \
|
||||
readl_relaxed((port)->regs + SPI_##reg)
|
||||
#define spi_writel(port, reg, value) \
|
||||
writel_relaxed((value), (port)->regs + SPI_##reg)
|
||||
|
||||
#define spi_readw(port, reg) \
|
||||
readw_relaxed((port)->regs + SPI_##reg)
|
||||
#define spi_writew(port, reg, value) \
|
||||
writew_relaxed((value), (port)->regs + SPI_##reg)
|
||||
|
||||
#define spi_readb(port, reg) \
|
||||
readb_relaxed((port)->regs + SPI_##reg)
|
||||
#define spi_writeb(port, reg, value) \
|
||||
writeb_relaxed((value), (port)->regs + SPI_##reg)
|
||||
#endif
|
||||
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
|
||||
* cache operations; better heuristics consider wordsize and bitrate.
|
||||
*/
|
||||
@ -299,17 +275,16 @@ struct atmel_spi {
|
||||
|
||||
bool use_dma;
|
||||
bool use_pdc;
|
||||
bool use_cs_gpios;
|
||||
|
||||
bool keep_cs;
|
||||
bool cs_active;
|
||||
|
||||
u32 fifo_size;
|
||||
u8 native_cs_free;
|
||||
u8 native_cs_for_gpio;
|
||||
};
|
||||
|
||||
/* Controller-specific per-slave state */
|
||||
struct atmel_spi_device {
|
||||
struct gpio_desc *npcs_pin;
|
||||
u32 csr;
|
||||
};
|
||||
|
||||
@ -336,11 +311,9 @@ static bool atmel_spi_is_v2(struct atmel_spi *as)
|
||||
* transmitted") Not so! Workaround uses nCSx pins as GPIOs; or newer
|
||||
* controllers have CSAAT and friends.
|
||||
*
|
||||
* Since the CSAAT functionality is a bit weird on newer controllers as
|
||||
* well, we use GPIO to control nCSx pins on all controllers, updating
|
||||
* MR.PCS to avoid confusing the controller. Using GPIOs also lets us
|
||||
* support active-high chipselects despite the controller's belief that
|
||||
* only active-low devices/systems exists.
|
||||
* Even controller newer than ar91rm9200, using GPIOs can make sens as
|
||||
* it lets us support active-high chipselects despite the controller's
|
||||
* belief that only active-low devices/systems exists.
|
||||
*
|
||||
* However, at91rm9200 has a second erratum whereby nCS0 doesn't work
|
||||
* right when driven with GPIO. ("Mode Fault does not allow more than one
|
||||
@ -352,30 +325,36 @@ static bool atmel_spi_is_v2(struct atmel_spi *as)
|
||||
static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
|
||||
{
|
||||
struct atmel_spi_device *asd = spi->controller_state;
|
||||
int chip_select;
|
||||
u32 mr;
|
||||
|
||||
if (spi->cs_gpiod)
|
||||
chip_select = as->native_cs_for_gpio;
|
||||
else
|
||||
chip_select = spi->chip_select;
|
||||
|
||||
if (atmel_spi_is_v2(as)) {
|
||||
spi_writel(as, CSR0 + 4 * spi->chip_select, asd->csr);
|
||||
spi_writel(as, CSR0 + 4 * chip_select, asd->csr);
|
||||
/* For the low SPI version, there is a issue that PDC transfer
|
||||
* on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS
|
||||
*/
|
||||
spi_writel(as, CSR0, asd->csr);
|
||||
if (as->caps.has_wdrbt) {
|
||||
spi_writel(as, MR,
|
||||
SPI_BF(PCS, ~(0x01 << spi->chip_select))
|
||||
SPI_BF(PCS, ~(0x01 << chip_select))
|
||||
| SPI_BIT(WDRBT)
|
||||
| SPI_BIT(MODFDIS)
|
||||
| SPI_BIT(MSTR));
|
||||
} else {
|
||||
spi_writel(as, MR,
|
||||
SPI_BF(PCS, ~(0x01 << spi->chip_select))
|
||||
SPI_BF(PCS, ~(0x01 << chip_select))
|
||||
| SPI_BIT(MODFDIS)
|
||||
| SPI_BIT(MSTR));
|
||||
}
|
||||
|
||||
mr = spi_readl(as, MR);
|
||||
if (as->use_cs_gpios)
|
||||
gpiod_set_value(asd->npcs_pin, 1);
|
||||
if (spi->cs_gpiod)
|
||||
gpiod_set_value(spi->cs_gpiod, 1);
|
||||
} else {
|
||||
u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
|
||||
int i;
|
||||
@ -390,9 +369,9 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
|
||||
}
|
||||
|
||||
mr = spi_readl(as, MR);
|
||||
mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
|
||||
if (as->use_cs_gpios && spi->chip_select != 0)
|
||||
gpiod_set_value(asd->npcs_pin, 1);
|
||||
mr = SPI_BFINS(PCS, ~(1 << chip_select), mr);
|
||||
if (spi->cs_gpiod)
|
||||
gpiod_set_value(spi->cs_gpiod, 1);
|
||||
spi_writel(as, MR, mr);
|
||||
}
|
||||
|
||||
@ -401,24 +380,29 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
|
||||
|
||||
static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
|
||||
{
|
||||
struct atmel_spi_device *asd = spi->controller_state;
|
||||
int chip_select;
|
||||
u32 mr;
|
||||
|
||||
if (spi->cs_gpiod)
|
||||
chip_select = as->native_cs_for_gpio;
|
||||
else
|
||||
chip_select = spi->chip_select;
|
||||
|
||||
/* only deactivate *this* device; sometimes transfers to
|
||||
* another device may be active when this routine is called.
|
||||
*/
|
||||
mr = spi_readl(as, MR);
|
||||
if (~SPI_BFEXT(PCS, mr) & (1 << spi->chip_select)) {
|
||||
if (~SPI_BFEXT(PCS, mr) & (1 << chip_select)) {
|
||||
mr = SPI_BFINS(PCS, 0xf, mr);
|
||||
spi_writel(as, MR, mr);
|
||||
}
|
||||
|
||||
dev_dbg(&spi->dev, "DEactivate NPCS, mr %08x\n", mr);
|
||||
|
||||
if (!as->use_cs_gpios)
|
||||
if (!spi->cs_gpiod)
|
||||
spi_writel(as, CR, SPI_BIT(LASTXFER));
|
||||
else if (atmel_spi_is_v2(as) || spi->chip_select != 0)
|
||||
gpiod_set_value(asd->npcs_pin, 0);
|
||||
else
|
||||
gpiod_set_value(spi->cs_gpiod, 0);
|
||||
}
|
||||
|
||||
static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock)
|
||||
@ -527,7 +511,7 @@ static int atmel_spi_configure_dma(struct spi_master *master,
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
master->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
err = PTR_ERR(master->dma_tx);
|
||||
if (err == -EPROBE_DEFER) {
|
||||
@ -844,6 +828,12 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
|
||||
{
|
||||
u32 scbr, csr;
|
||||
unsigned long bus_hz;
|
||||
int chip_select;
|
||||
|
||||
if (spi->cs_gpiod)
|
||||
chip_select = as->native_cs_for_gpio;
|
||||
else
|
||||
chip_select = spi->chip_select;
|
||||
|
||||
/* v1 chips start out at half the peripheral bus speed. */
|
||||
bus_hz = as->spi_clk;
|
||||
@ -872,9 +862,9 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
|
||||
xfer->speed_hz, scbr, bus_hz);
|
||||
return -EINVAL;
|
||||
}
|
||||
csr = spi_readl(as, CSR0 + 4 * spi->chip_select);
|
||||
csr = spi_readl(as, CSR0 + 4 * chip_select);
|
||||
csr = SPI_BFINS(SCBR, scbr, csr);
|
||||
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
|
||||
spi_writel(as, CSR0 + 4 * chip_select, csr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1173,40 +1163,105 @@ atmel_spi_pdc_interrupt(int irq, void *dev_id)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_word_delay_csr(struct spi_device *spi, struct atmel_spi *as)
|
||||
{
|
||||
struct spi_delay *delay = &spi->word_delay;
|
||||
u32 value = delay->value;
|
||||
|
||||
switch (delay->unit) {
|
||||
case SPI_DELAY_UNIT_NSECS:
|
||||
value /= 1000;
|
||||
break;
|
||||
case SPI_DELAY_UNIT_USECS:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return (as->spi_clk / 1000000 * value) >> 5;
|
||||
}
|
||||
|
||||
static void initialize_native_cs_for_gpio(struct atmel_spi *as)
|
||||
{
|
||||
int i;
|
||||
struct spi_master *master = platform_get_drvdata(as->pdev);
|
||||
|
||||
if (!as->native_cs_free)
|
||||
return; /* already initialized */
|
||||
|
||||
if (!master->cs_gpiods)
|
||||
return; /* No CS GPIO */
|
||||
|
||||
/*
|
||||
* On the first version of the controller (AT91RM9200), CS0
|
||||
* can't be used associated with GPIO
|
||||
*/
|
||||
if (atmel_spi_is_v2(as))
|
||||
i = 0;
|
||||
else
|
||||
i = 1;
|
||||
|
||||
for (; i < 4; i++)
|
||||
if (master->cs_gpiods[i])
|
||||
as->native_cs_free |= BIT(i);
|
||||
|
||||
if (as->native_cs_free)
|
||||
as->native_cs_for_gpio = ffs(as->native_cs_free);
|
||||
}
|
||||
|
||||
static int atmel_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct atmel_spi *as;
|
||||
struct atmel_spi_device *asd;
|
||||
u32 csr;
|
||||
unsigned int bits = spi->bits_per_word;
|
||||
int chip_select;
|
||||
int word_delay_csr;
|
||||
|
||||
as = spi_master_get_devdata(spi->master);
|
||||
|
||||
/* see notes above re chipselect */
|
||||
if (!atmel_spi_is_v2(as)
|
||||
&& spi->chip_select == 0
|
||||
&& (spi->mode & SPI_CS_HIGH)) {
|
||||
dev_dbg(&spi->dev, "setup: can't be active-high\n");
|
||||
if (!spi->cs_gpiod && (spi->mode & SPI_CS_HIGH)) {
|
||||
dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Setup() is called during spi_register_controller(aka
|
||||
* spi_register_master) but after all membmers of the cs_gpiod
|
||||
* array have been filled, so we can looked for which native
|
||||
* CS will be free for using with GPIO
|
||||
*/
|
||||
initialize_native_cs_for_gpio(as);
|
||||
|
||||
if (spi->cs_gpiod && as->native_cs_free) {
|
||||
dev_err(&spi->dev,
|
||||
"No native CS available to support this GPIO CS\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (spi->cs_gpiod)
|
||||
chip_select = as->native_cs_for_gpio;
|
||||
else
|
||||
chip_select = spi->chip_select;
|
||||
|
||||
csr = SPI_BF(BITS, bits - 8);
|
||||
if (spi->mode & SPI_CPOL)
|
||||
csr |= SPI_BIT(CPOL);
|
||||
if (!(spi->mode & SPI_CPHA))
|
||||
csr |= SPI_BIT(NCPHA);
|
||||
if (!as->use_cs_gpios)
|
||||
csr |= SPI_BIT(CSAAT);
|
||||
|
||||
/* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
|
||||
*/
|
||||
if (!spi->cs_gpiod)
|
||||
csr |= SPI_BIT(CSAAT);
|
||||
csr |= SPI_BF(DLYBS, 0);
|
||||
|
||||
word_delay_csr = atmel_word_delay_csr(spi, as);
|
||||
if (word_delay_csr < 0)
|
||||
return word_delay_csr;
|
||||
|
||||
/* DLYBCT adds delays between words. This is useful for slow devices
|
||||
* that need a bit of time to setup the next transfer.
|
||||
*/
|
||||
csr |= SPI_BF(DLYBCT,
|
||||
(as->spi_clk / 1000000 * spi->word_delay_usecs) >> 5);
|
||||
csr |= SPI_BF(DLYBCT, word_delay_csr);
|
||||
|
||||
asd = spi->controller_state;
|
||||
if (!asd) {
|
||||
@ -1214,21 +1269,6 @@ static int atmel_spi_setup(struct spi_device *spi)
|
||||
if (!asd)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* If use_cs_gpios is true this means that we have "cs-gpios"
|
||||
* defined in the device tree node so we should have
|
||||
* gotten the GPIO lines from the device tree inside the
|
||||
* SPI core. Warn if this is not the case but continue since
|
||||
* CS GPIOs are after all optional.
|
||||
*/
|
||||
if (as->use_cs_gpios) {
|
||||
if (!spi->cs_gpiod) {
|
||||
dev_err(&spi->dev,
|
||||
"host claims to use CS GPIOs but no CS found in DT by the SPI core\n");
|
||||
}
|
||||
asd->npcs_pin = spi->cs_gpiod;
|
||||
}
|
||||
|
||||
spi->controller_state = asd;
|
||||
}
|
||||
|
||||
@ -1239,7 +1279,7 @@ static int atmel_spi_setup(struct spi_device *spi)
|
||||
bits, spi->mode, spi->chip_select, csr);
|
||||
|
||||
if (!atmel_spi_is_v2(as))
|
||||
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
|
||||
spi_writel(as, CSR0 + 4 * chip_select, csr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1368,19 +1408,16 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
&& as->use_pdc)
|
||||
atmel_spi_dma_unmap_xfer(master, xfer);
|
||||
|
||||
if (xfer->delay_usecs)
|
||||
udelay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
|
||||
if (xfer->cs_change) {
|
||||
if (list_is_last(&xfer->transfer_list,
|
||||
&msg->transfers)) {
|
||||
as->keep_cs = true;
|
||||
} else {
|
||||
as->cs_active = !as->cs_active;
|
||||
if (as->cs_active)
|
||||
cs_activate(as, msg->spi);
|
||||
else
|
||||
cs_deactivate(as, msg->spi);
|
||||
cs_deactivate(as, msg->spi);
|
||||
udelay(10);
|
||||
cs_activate(as, msg->spi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1403,7 +1440,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
|
||||
atmel_spi_lock(as);
|
||||
cs_activate(as, spi);
|
||||
|
||||
as->cs_active = true;
|
||||
as->keep_cs = false;
|
||||
|
||||
msg->status = 0;
|
||||
@ -1527,7 +1563,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
master->bus_num = pdev->id;
|
||||
master->num_chipselect = master->dev.of_node ? 0 : 4;
|
||||
master->num_chipselect = 4;
|
||||
master->setup = atmel_spi_setup;
|
||||
master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
|
||||
master->transfer_one_message = atmel_spi_transfer_one_message;
|
||||
@ -1555,19 +1591,6 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
|
||||
atmel_get_caps(as);
|
||||
|
||||
/*
|
||||
* If there are chip selects in the device tree, those will be
|
||||
* discovered by the SPI core when registering the SPI master
|
||||
* and assigned to each SPI device.
|
||||
*/
|
||||
as->use_cs_gpios = true;
|
||||
if (atmel_spi_is_v2(as) &&
|
||||
pdev->dev.of_node &&
|
||||
!of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) {
|
||||
as->use_cs_gpios = false;
|
||||
master->num_chipselect = 4;
|
||||
}
|
||||
|
||||
as->use_dma = false;
|
||||
as->use_pdc = false;
|
||||
if (as->caps.has_dma_support) {
|
||||
@ -1775,20 +1798,18 @@ static const struct dev_pm_ops atmel_spi_pm_ops = {
|
||||
#define ATMEL_SPI_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id atmel_spi_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91rm9200-spi" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver atmel_spi_driver = {
|
||||
.driver = {
|
||||
.name = "atmel_spi",
|
||||
.pm = ATMEL_SPI_PM_OPS,
|
||||
.of_match_table = of_match_ptr(atmel_spi_dt_ids),
|
||||
.of_match_table = atmel_spi_dt_ids,
|
||||
},
|
||||
.probe = atmel_spi_probe,
|
||||
.remove = atmel_spi_remove,
|
||||
|
@ -163,10 +163,21 @@ static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
|
||||
}
|
||||
|
||||
static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
|
||||
struct spi_engine *spi_engine, unsigned int clk_div, unsigned int delay)
|
||||
struct spi_engine *spi_engine, unsigned int clk_div,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
unsigned int spi_clk = clk_get_rate(spi_engine->ref_clk);
|
||||
unsigned int t;
|
||||
int delay;
|
||||
|
||||
if (xfer->delay_usecs) {
|
||||
delay = xfer->delay_usecs;
|
||||
} else {
|
||||
delay = spi_delay_to_ns(&xfer->delay, xfer);
|
||||
if (delay < 0)
|
||||
return;
|
||||
delay /= 1000;
|
||||
}
|
||||
|
||||
if (delay == 0)
|
||||
return;
|
||||
@ -218,8 +229,7 @@ static int spi_engine_compile_message(struct spi_engine *spi_engine,
|
||||
spi_engine_gen_cs(p, dry, spi, true);
|
||||
|
||||
spi_engine_gen_xfer(p, dry, xfer);
|
||||
spi_engine_gen_sleep(p, dry, spi_engine, clk_div,
|
||||
xfer->delay_usecs);
|
||||
spi_engine_gen_sleep(p, dry, spi_engine, clk_div, xfer);
|
||||
|
||||
cs_change = xfer->cs_change;
|
||||
if (list_is_last(&xfer->transfer_list, &msg->transfers))
|
||||
|
@ -803,7 +803,8 @@ static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
|
||||
return -EIO;
|
||||
|
||||
from = op->addr.val;
|
||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||
if (!spi->cs_gpiod)
|
||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
|
||||
|
||||
/*
|
||||
@ -882,7 +883,8 @@ static int bcm_qspi_transfer_one(struct spi_master *master,
|
||||
int slots;
|
||||
unsigned long timeo = msecs_to_jiffies(100);
|
||||
|
||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||
if (!spi->cs_gpiod)
|
||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||
qspi->trans_pos.trans = trans;
|
||||
qspi->trans_pos.byte = 0;
|
||||
|
||||
@ -1234,6 +1236,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||
master->cleanup = bcm_qspi_cleanup;
|
||||
master->dev.of_node = dev->of_node;
|
||||
master->num_chipselect = NUM_CHIPSELECT;
|
||||
master->use_gpio_descriptors = true;
|
||||
|
||||
qspi->big_endian = of_device_is_big_endian(dev->of_node);
|
||||
|
||||
|
@ -1248,7 +1248,7 @@ static int bcm2835_spi_setup(struct spi_device *spi)
|
||||
/*
|
||||
* Retrieve the corresponding GPIO line used for CS.
|
||||
* The inversion semantics will be handled by the GPIO core
|
||||
* code, so we pass GPIOS_OUT_LOW for "unasserted" and
|
||||
* code, so we pass GPIOD_OUT_LOW for "unasserted" and
|
||||
* the correct flag for inversion semantics. The SPI_CS_HIGH
|
||||
* on spi->mode cannot be checked for polarity in this case
|
||||
* as the flag use_gpio_descriptors enforces SPI_CS_HIGH.
|
||||
|
@ -291,8 +291,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
|
||||
|
||||
msg->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (t->cs_change)
|
||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
|
||||
|
@ -368,7 +368,7 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
|
||||
}
|
||||
|
||||
/* CS will be deasserted directly after transfer */
|
||||
if (t->delay_usecs) {
|
||||
if (t->delay_usecs || t->delay.value) {
|
||||
dev_err(&spi->dev, "unable to keep CS asserted after transfer\n");
|
||||
status = -EINVAL;
|
||||
goto exit;
|
||||
|
@ -119,8 +119,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
|
||||
*rx_buf++ = (u8)v;
|
||||
}
|
||||
|
||||
if (xfer->delay_usecs)
|
||||
udelay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
|
||||
return xfer->len;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/scatterlist.h>
|
||||
@ -193,6 +194,8 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = dw_spi_add_host(&pdev->dev, dws);
|
||||
if (ret)
|
||||
goto out;
|
||||
@ -201,6 +204,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
out:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
clk_disable_unprepare(dwsmmio->pclk);
|
||||
out_clk:
|
||||
clk_disable_unprepare(dwsmmio->clk);
|
||||
@ -212,6 +216,7 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
|
||||
struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
|
||||
|
||||
dw_spi_remove_host(&dwsmmio->dws);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
clk_disable_unprepare(dwsmmio->pclk);
|
||||
clk_disable_unprepare(dwsmmio->clk);
|
||||
|
||||
@ -223,6 +228,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
|
||||
{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init},
|
||||
{ .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
|
||||
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
|
||||
{ .compatible = "renesas,rzn1-spi", },
|
||||
{ /* end of table */}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/module.h>
|
||||
@ -35,7 +36,7 @@ static struct spi_pci_desc spi_pci_mid_desc_2 = {
|
||||
};
|
||||
|
||||
static struct spi_pci_desc spi_pci_ehl_desc = {
|
||||
.num_cs = 1,
|
||||
.num_cs = 2,
|
||||
.bus_num = -1,
|
||||
.max_freq = 100000000,
|
||||
};
|
||||
@ -57,13 +58,18 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
/* Get basic io resource and map it */
|
||||
dws->paddr = pci_resource_start(pdev, pci_bar);
|
||||
pci_set_master(pdev);
|
||||
|
||||
ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dws->regs = pcim_iomap_table(pdev)[pci_bar];
|
||||
dws->irq = pdev->irq;
|
||||
dws->irq = pci_irq_vector(pdev, 0);
|
||||
|
||||
/*
|
||||
* Specific handling for platforms, like dma setup,
|
||||
@ -80,12 +86,15 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
pci_free_irq_vectors(pdev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = dw_spi_add_host(&pdev->dev, dws);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
pci_free_irq_vectors(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* PCI hook and SPI hook use the same drv data */
|
||||
pci_set_drvdata(pdev, dws);
|
||||
@ -93,6 +102,11 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n",
|
||||
pdev->vendor, pdev->device);
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -100,7 +114,11 @@ static void spi_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct dw_spi *dws = pci_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_forbid(&pdev->dev);
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
|
||||
dw_spi_remove_host(dws);
|
||||
pci_free_irq_vectors(pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -308,7 +308,8 @@ static int dw_spi_transfer_one(struct spi_controller *master,
|
||||
cr0 = (transfer->bits_per_word - 1)
|
||||
| (chip->type << SPI_FRF_OFFSET)
|
||||
| ((((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET) |
|
||||
(((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET))
|
||||
(((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET) |
|
||||
(((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET))
|
||||
| (chip->tmode << SPI_TMOD_OFFSET);
|
||||
|
||||
/*
|
||||
@ -493,6 +494,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||
master->dev.of_node = dev->of_node;
|
||||
master->dev.fwnode = dev->fwnode;
|
||||
master->flags = SPI_MASTER_GPIO_SS;
|
||||
master->auto_runtime_pm = true;
|
||||
|
||||
if (dws->set_cs)
|
||||
master->set_cs = dws->set_cs;
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
/* Register offsets */
|
||||
#define DW_SPI_CTRL0 0x00
|
||||
|
@ -377,7 +377,7 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
|
||||
|
||||
m->actual_length += t->len;
|
||||
|
||||
WARN_ON(t->delay_usecs || t->cs_change);
|
||||
WARN_ON(t->delay_usecs || t->delay.value || t->cs_change);
|
||||
spi_flags = 0;
|
||||
}
|
||||
|
||||
|
@ -392,7 +392,8 @@ void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
|
||||
dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE);
|
||||
dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
|
||||
cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
|
||||
cpm_muram_free(cpm_muram_offset(mspi->pram));
|
||||
if (!(mspi->flags & SPI_CPM1))
|
||||
cpm_muram_free(cpm_muram_offset(mspi->pram));
|
||||
fsl_spi_free_dummy_rx();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsl_spi_cpm_free);
|
||||
|
@ -129,6 +129,7 @@ enum dspi_trans_mode {
|
||||
struct fsl_dspi_devtype_data {
|
||||
enum dspi_trans_mode trans_mode;
|
||||
u8 max_clock_factor;
|
||||
bool ptp_sts_supported;
|
||||
bool xspi_mode;
|
||||
};
|
||||
|
||||
@ -140,12 +141,14 @@ static const struct fsl_dspi_devtype_data vf610_data = {
|
||||
static const struct fsl_dspi_devtype_data ls1021a_v1_data = {
|
||||
.trans_mode = DSPI_TCFQ_MODE,
|
||||
.max_clock_factor = 8,
|
||||
.ptp_sts_supported = true,
|
||||
.xspi_mode = true,
|
||||
};
|
||||
|
||||
static const struct fsl_dspi_devtype_data ls2085a_data = {
|
||||
.trans_mode = DSPI_TCFQ_MODE,
|
||||
.max_clock_factor = 8,
|
||||
.ptp_sts_supported = true,
|
||||
};
|
||||
|
||||
static const struct fsl_dspi_devtype_data coldfire_data = {
|
||||
@ -654,6 +657,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
|
||||
u16 spi_tcnt;
|
||||
u32 spi_tcr;
|
||||
|
||||
spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer,
|
||||
dspi->tx - dspi->bytes_per_word, !dspi->irq);
|
||||
|
||||
/* Get transfer counter (in number of SPI transfers). It was
|
||||
* reset to 0 when transfer(s) were started.
|
||||
*/
|
||||
@ -672,6 +678,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
|
||||
/* Success! */
|
||||
return 0;
|
||||
|
||||
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
|
||||
dspi->tx, !dspi->irq);
|
||||
|
||||
if (trans_mode == DSPI_EOQ_MODE)
|
||||
dspi_eoq_write(dspi);
|
||||
else if (trans_mode == DSPI_TCFQ_MODE)
|
||||
@ -707,7 +716,7 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
|
||||
regmap_read(dspi->regmap, SPI_SR, &spi_sr);
|
||||
regmap_write(dspi->regmap, SPI_SR, spi_sr);
|
||||
|
||||
if (!(spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)))
|
||||
if (!(spi_sr & SPI_SR_EOQF))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (dspi_rxtx(dspi) == 0) {
|
||||
@ -779,6 +788,9 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
|
||||
SPI_FRAME_EBITS(transfer->bits_per_word) |
|
||||
SPI_CTARE_DTCP(1));
|
||||
|
||||
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
|
||||
dspi->tx, !dspi->irq);
|
||||
|
||||
trans_mode = dspi->devtype_data->trans_mode;
|
||||
switch (trans_mode) {
|
||||
case DSPI_EOQ_MODE:
|
||||
@ -815,8 +827,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
|
||||
dev_err(&dspi->pdev->dev,
|
||||
"Waiting for transfer to complete failed!\n");
|
||||
|
||||
if (transfer->delay_usecs)
|
||||
udelay(transfer->delay_usecs);
|
||||
spi_transfer_delay_exec(transfer);
|
||||
}
|
||||
|
||||
out:
|
||||
@ -1006,6 +1017,25 @@ static void dspi_init(struct fsl_dspi *dspi)
|
||||
SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1));
|
||||
}
|
||||
|
||||
static int dspi_slave_abort(struct spi_master *master)
|
||||
{
|
||||
struct fsl_dspi *dspi = spi_master_get_devdata(master);
|
||||
|
||||
/*
|
||||
* Terminate all pending DMA transactions for the SPI working
|
||||
* in SLAVE mode.
|
||||
*/
|
||||
dmaengine_terminate_sync(dspi->dma->chan_rx);
|
||||
dmaengine_terminate_sync(dspi->dma->chan_tx);
|
||||
|
||||
/* Clear the internal DSPI RX and TX FIFO buffers */
|
||||
regmap_update_bits(dspi->regmap, SPI_MCR,
|
||||
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
|
||||
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
@ -1030,6 +1060,7 @@ static int dspi_probe(struct platform_device *pdev)
|
||||
ctlr->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
ctlr->cleanup = dspi_cleanup;
|
||||
ctlr->slave_abort = dspi_slave_abort;
|
||||
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
@ -1114,6 +1145,9 @@ static int dspi_probe(struct platform_device *pdev)
|
||||
|
||||
dspi_init(dspi);
|
||||
|
||||
if (dspi->devtype_data->trans_mode == DSPI_TCFQ_MODE)
|
||||
goto poll_mode;
|
||||
|
||||
dspi->irq = platform_get_irq(pdev, 0);
|
||||
if (dspi->irq <= 0) {
|
||||
dev_info(&pdev->dev,
|
||||
@ -1132,6 +1166,7 @@ static int dspi_probe(struct platform_device *pdev)
|
||||
init_waitqueue_head(&dspi->waitq);
|
||||
|
||||
poll_mode:
|
||||
|
||||
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
|
||||
ret = dspi_request_dma(dspi, res->start);
|
||||
if (ret < 0) {
|
||||
@ -1143,6 +1178,8 @@ static int dspi_probe(struct platform_device *pdev)
|
||||
ctlr->max_speed_hz =
|
||||
clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor;
|
||||
|
||||
ctlr->ptp_sts_supported = dspi->devtype_data->ptp_sts_supported;
|
||||
|
||||
platform_set_drvdata(pdev, ctlr);
|
||||
|
||||
ret = spi_register_controller(ctlr);
|
||||
|
@ -427,8 +427,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
|
||||
|
||||
ret = fsl_espi_bufs(spi, trans);
|
||||
|
||||
if (trans->delay_usecs)
|
||||
udelay(trans->delay_usecs);
|
||||
spi_transfer_delay_exec(trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -437,6 +436,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
|
||||
struct spi_message *m)
|
||||
{
|
||||
unsigned int delay_usecs = 0, rx_nbits = 0;
|
||||
unsigned int delay_nsecs = 0, delay_nsecs1 = 0;
|
||||
struct spi_transfer *t, trans = {};
|
||||
int ret;
|
||||
|
||||
@ -445,8 +445,16 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||
if (t->delay_usecs > delay_usecs)
|
||||
delay_usecs = t->delay_usecs;
|
||||
if (t->delay_usecs) {
|
||||
if (t->delay_usecs > delay_usecs) {
|
||||
delay_usecs = t->delay_usecs;
|
||||
delay_nsecs = delay_usecs * 1000;
|
||||
}
|
||||
} else {
|
||||
delay_nsecs1 = spi_delay_to_ns(&t->delay, t);
|
||||
if (delay_nsecs1 > delay_nsecs)
|
||||
delay_nsecs = delay_nsecs1;
|
||||
}
|
||||
if (t->rx_nbits > rx_nbits)
|
||||
rx_nbits = t->rx_nbits;
|
||||
}
|
||||
@ -457,7 +465,8 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
|
||||
trans.len = m->frame_length;
|
||||
trans.speed_hz = t->speed_hz;
|
||||
trans.bits_per_word = t->bits_per_word;
|
||||
trans.delay_usecs = delay_usecs;
|
||||
trans.delay.value = delay_nsecs;
|
||||
trans.delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
trans.rx_nbits = rx_nbits;
|
||||
|
||||
if (trans.len)
|
||||
|
@ -675,7 +675,7 @@ static int fsl_lpspi_dma_init(struct device *dev,
|
||||
int ret;
|
||||
|
||||
/* Prepare for TX DMA: */
|
||||
controller->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
controller->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(controller->dma_tx)) {
|
||||
ret = PTR_ERR(controller->dma_tx);
|
||||
dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
|
||||
@ -684,7 +684,7 @@ static int fsl_lpspi_dma_init(struct device *dev,
|
||||
}
|
||||
|
||||
/* Prepare for RX DMA: */
|
||||
controller->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
controller->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(controller->dma_rx)) {
|
||||
ret = PTR_ERR(controller->dma_rx);
|
||||
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
|
||||
@ -779,7 +779,7 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
|
||||
|
||||
if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) {
|
||||
writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
|
||||
complete(&fsl_lpspi->xfer_done);
|
||||
complete(&fsl_lpspi->xfer_done);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -938,7 +938,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
|
||||
ret = pm_runtime_get_sync(fsl_lpspi->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(fsl_lpspi->dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
goto out_controller_put;
|
||||
}
|
||||
|
||||
temp = readl(fsl_lpspi->base + IMX7ULP_PARAM);
|
||||
|
@ -63,6 +63,16 @@
|
||||
#define QUADSPI_IPCR 0x08
|
||||
#define QUADSPI_IPCR_SEQID(x) ((x) << 24)
|
||||
|
||||
#define QUADSPI_FLSHCR 0x0c
|
||||
#define QUADSPI_FLSHCR_TCSS_MASK GENMASK(3, 0)
|
||||
#define QUADSPI_FLSHCR_TCSH_MASK GENMASK(11, 8)
|
||||
#define QUADSPI_FLSHCR_TDH_MASK GENMASK(17, 16)
|
||||
|
||||
#define QUADSPI_BUF0CR 0x10
|
||||
#define QUADSPI_BUF1CR 0x14
|
||||
#define QUADSPI_BUF2CR 0x18
|
||||
#define QUADSPI_BUFXCR_INVALID_MSTRID 0xe
|
||||
|
||||
#define QUADSPI_BUF3CR 0x1c
|
||||
#define QUADSPI_BUF3CR_ALLMST_MASK BIT(31)
|
||||
#define QUADSPI_BUF3CR_ADATSZ(x) ((x) << 8)
|
||||
@ -95,6 +105,9 @@
|
||||
#define QUADSPI_FR 0x160
|
||||
#define QUADSPI_FR_TFF_MASK BIT(0)
|
||||
|
||||
#define QUADSPI_RSER 0x164
|
||||
#define QUADSPI_RSER_TFIE BIT(0)
|
||||
|
||||
#define QUADSPI_SPTRCLR 0x16c
|
||||
#define QUADSPI_SPTRCLR_IPPTRC BIT(8)
|
||||
#define QUADSPI_SPTRCLR_BFPTRC BIT(0)
|
||||
@ -112,9 +125,6 @@
|
||||
#define QUADSPI_LCKER_LOCK BIT(0)
|
||||
#define QUADSPI_LCKER_UNLOCK BIT(1)
|
||||
|
||||
#define QUADSPI_RSER 0x164
|
||||
#define QUADSPI_RSER_TFIE BIT(0)
|
||||
|
||||
#define QUADSPI_LUT_BASE 0x310
|
||||
#define QUADSPI_LUT_OFFSET (SEQID_LUT * 4 * 4)
|
||||
#define QUADSPI_LUT_REG(idx) \
|
||||
@ -181,9 +191,16 @@
|
||||
*/
|
||||
#define QUADSPI_QUIRK_BASE_INTERNAL BIT(4)
|
||||
|
||||
/*
|
||||
* Controller uses TDH bits in register QUADSPI_FLSHCR.
|
||||
* They need to be set in accordance with the DDR/SDR mode.
|
||||
*/
|
||||
#define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5)
|
||||
|
||||
struct fsl_qspi_devtype_data {
|
||||
unsigned int rxfifo;
|
||||
unsigned int txfifo;
|
||||
int invalid_mstrid;
|
||||
unsigned int ahb_buf_size;
|
||||
unsigned int quirks;
|
||||
bool little_endian;
|
||||
@ -192,6 +209,7 @@ struct fsl_qspi_devtype_data {
|
||||
static const struct fsl_qspi_devtype_data vybrid_data = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_64,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = QUADSPI_QUIRK_SWAP_ENDIAN,
|
||||
.little_endian = true,
|
||||
@ -200,6 +218,7 @@ static const struct fsl_qspi_devtype_data vybrid_data = {
|
||||
static const struct fsl_qspi_devtype_data imx6sx_data = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_512,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618,
|
||||
.little_endian = true,
|
||||
@ -208,22 +227,27 @@ static const struct fsl_qspi_devtype_data imx6sx_data = {
|
||||
static const struct fsl_qspi_devtype_data imx7d_data = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_512,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK,
|
||||
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
|
||||
QUADSPI_QUIRK_USE_TDH_SETTING,
|
||||
.little_endian = true,
|
||||
};
|
||||
|
||||
static const struct fsl_qspi_devtype_data imx6ul_data = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_512,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK,
|
||||
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
|
||||
QUADSPI_QUIRK_USE_TDH_SETTING,
|
||||
.little_endian = true,
|
||||
};
|
||||
|
||||
static const struct fsl_qspi_devtype_data ls1021a_data = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_64,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = 0,
|
||||
.little_endian = false,
|
||||
@ -233,6 +257,7 @@ static const struct fsl_qspi_devtype_data ls2080a_data = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_64,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.invalid_mstrid = 0x0,
|
||||
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_BASE_INTERNAL,
|
||||
.little_endian = true,
|
||||
};
|
||||
@ -275,6 +300,11 @@ static inline int needs_amba_base_offset(struct fsl_qspi *q)
|
||||
return !(q->devtype_data->quirks & QUADSPI_QUIRK_BASE_INTERNAL);
|
||||
}
|
||||
|
||||
static inline int needs_tdh_setting(struct fsl_qspi *q)
|
||||
{
|
||||
return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING;
|
||||
}
|
||||
|
||||
/*
|
||||
* An IC bug makes it necessary to rearrange the 32-bit data.
|
||||
* Later chips, such as IMX6SLX, have fixed this bug.
|
||||
@ -615,6 +645,7 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
||||
void __iomem *base = q->iobase;
|
||||
u32 addr_offset = 0;
|
||||
int err = 0;
|
||||
int invalid_mstrid = q->devtype_data->invalid_mstrid;
|
||||
|
||||
mutex_lock(&q->lock);
|
||||
|
||||
@ -638,6 +669,10 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
||||
qspi_writel(q, QUADSPI_SPTRCLR_BFPTRC | QUADSPI_SPTRCLR_IPPTRC,
|
||||
base + QUADSPI_SPTRCLR);
|
||||
|
||||
qspi_writel(q, invalid_mstrid, base + QUADSPI_BUF0CR);
|
||||
qspi_writel(q, invalid_mstrid, base + QUADSPI_BUF1CR);
|
||||
qspi_writel(q, invalid_mstrid, base + QUADSPI_BUF2CR);
|
||||
|
||||
fsl_qspi_prepare_lut(q, op);
|
||||
|
||||
/*
|
||||
@ -710,6 +745,16 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
|
||||
qspi_writel(q, QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
|
||||
base + QUADSPI_MCR);
|
||||
|
||||
/*
|
||||
* Previous boot stages (BootROM, bootloader) might have used DDR
|
||||
* mode and did not clear the TDH bits. As we currently use SDR mode
|
||||
* only, clear the TDH bits if necessary.
|
||||
*/
|
||||
if (needs_tdh_setting(q))
|
||||
qspi_writel(q, qspi_readl(q, base + QUADSPI_FLSHCR) &
|
||||
~QUADSPI_FLSHCR_TDH_MASK,
|
||||
base + QUADSPI_FLSHCR);
|
||||
|
||||
reg = qspi_readl(q, base + QUADSPI_SMPR);
|
||||
qspi_writel(q, reg & ~(QUADSPI_SMPR_FSDLY_MASK
|
||||
| QUADSPI_SMPR_FSPHS_MASK
|
||||
|
@ -416,8 +416,7 @@ static int fsl_spi_do_one_msg(struct spi_master *master,
|
||||
}
|
||||
m->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (cs_change) {
|
||||
ndelay(nsecs);
|
||||
|
@ -362,19 +362,18 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
||||
struct spi_gpio *spi_gpio;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct spi_bitbang *bb;
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
of_id = of_match_device(spi_gpio_dt_ids, &pdev->dev);
|
||||
|
||||
master = spi_alloc_master(dev, sizeof(*spi_gpio));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
||||
status = devm_add_action_or_reset(&pdev->dev, spi_gpio_put, master);
|
||||
if (status)
|
||||
if (status) {
|
||||
spi_master_put(master);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (of_id)
|
||||
if (pdev->dev.of_node)
|
||||
status = spi_gpio_probe_dt(pdev, master);
|
||||
else
|
||||
status = spi_gpio_probe_pdata(pdev, master);
|
||||
|
@ -673,6 +673,8 @@ static int img_spfi_probe(struct platform_device *pdev)
|
||||
dma_release_channel(spfi->tx_ch);
|
||||
if (spfi->rx_ch)
|
||||
dma_release_channel(spfi->rx_ch);
|
||||
spfi->tx_ch = NULL;
|
||||
spfi->rx_ch = NULL;
|
||||
dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n");
|
||||
} else {
|
||||
master->dma_tx = spfi->tx_ch;
|
||||
|
@ -1272,7 +1272,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
|
||||
spi_imx->wml = spi_imx->devtype_data->fifo_size / 2;
|
||||
|
||||
/* Prepare for TX DMA: */
|
||||
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
master->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
ret = PTR_ERR(master->dma_tx);
|
||||
dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
|
||||
@ -1281,7 +1281,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
|
||||
}
|
||||
|
||||
/* Prepare for RX : */
|
||||
master->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
master->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(master->dma_rx)) {
|
||||
ret = PTR_ERR(master->dma_rx);
|
||||
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
|
||||
|
@ -797,7 +797,6 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct spi_master *master;
|
||||
struct resource *res;
|
||||
struct lantiq_ssc_spi *spi;
|
||||
const struct lantiq_ssc_hwcfg *hwcfg;
|
||||
const struct of_device_id *match;
|
||||
@ -812,12 +811,6 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
||||
}
|
||||
hwcfg = match->data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "failed to get resources\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rx_irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME);
|
||||
if (rx_irq < 0)
|
||||
return -ENXIO;
|
||||
@ -839,8 +832,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
||||
spi->dev = dev;
|
||||
spi->hwcfg = hwcfg;
|
||||
platform_set_drvdata(pdev, spi);
|
||||
|
||||
spi->regbase = devm_ioremap_resource(dev, res);
|
||||
spi->regbase = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(spi->regbase)) {
|
||||
err = PTR_ERR(spi->regbase);
|
||||
goto err_master_put;
|
||||
|
@ -298,12 +298,18 @@ static struct spi_test spi_tests[] = {
|
||||
{
|
||||
.tx_buf = TX(0),
|
||||
.rx_buf = RX(0),
|
||||
.delay_usecs = 1000,
|
||||
.delay = {
|
||||
.value = 1000,
|
||||
.unit = SPI_DELAY_UNIT_USECS,
|
||||
},
|
||||
},
|
||||
{
|
||||
.tx_buf = TX(0),
|
||||
.rx_buf = RX(0),
|
||||
.delay_usecs = 1000,
|
||||
.delay = {
|
||||
.value = 1000,
|
||||
.unit = SPI_DELAY_UNIT_USECS,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -537,7 +543,7 @@ static int spi_test_check_elapsed_time(struct spi_device *spi,
|
||||
unsigned long long nbits = (unsigned long long)BITS_PER_BYTE *
|
||||
xfer->len;
|
||||
|
||||
delay_usecs += xfer->delay_usecs;
|
||||
delay_usecs += xfer->delay.value;
|
||||
if (!xfer->speed_hz)
|
||||
continue;
|
||||
estimated_time += div_u64(nbits * NSEC_PER_SEC, xfer->speed_hz);
|
||||
|
@ -286,7 +286,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
||||
if (!spi_mem_internal_supports_op(mem, op))
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (ctlr->mem_ops) {
|
||||
if (ctlr->mem_ops && !mem->spi->cs_gpiod) {
|
||||
ret = spi_mem_access_start(mem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -311,8 +311,7 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
|
||||
break;
|
||||
m->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (cs_change)
|
||||
mpc512x_psc_spi_deactivate_cs(spi);
|
||||
|
@ -234,8 +234,7 @@ static void mpc52xx_psc_spi_work(struct work_struct *work)
|
||||
break;
|
||||
m->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (cs_change)
|
||||
mpc52xx_psc_spi_deactivate_cs(spi);
|
||||
|
@ -139,7 +139,6 @@ static const struct mtk_spi_compatible mt8183_compat = {
|
||||
* supplies it.
|
||||
*/
|
||||
static const struct mtk_chip_config mtk_default_chip_info = {
|
||||
.cs_pol = 0,
|
||||
.sample_sel = 0,
|
||||
};
|
||||
|
||||
@ -230,10 +229,12 @@ static int mtk_spi_prepare_message(struct spi_master *master,
|
||||
#endif
|
||||
|
||||
if (mdata->dev_comp->enhance_timing) {
|
||||
if (chip_config->cs_pol)
|
||||
/* set CS polarity */
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
reg_val |= SPI_CMD_CS_POL;
|
||||
else
|
||||
reg_val &= ~SPI_CMD_CS_POL;
|
||||
|
||||
if (chip_config->sample_sel)
|
||||
reg_val |= SPI_CMD_SAMPLE_SEL;
|
||||
else
|
||||
@ -264,6 +265,9 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
u32 reg_val;
|
||||
struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
|
||||
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
enable = !enable;
|
||||
|
||||
reg_val = readl(mdata->base + SPI_CMD_REG);
|
||||
if (!enable) {
|
||||
reg_val |= SPI_CMD_PAUSE_EN;
|
||||
@ -619,7 +623,6 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
||||
struct spi_master *master;
|
||||
struct mtk_spi *mdata;
|
||||
const struct of_device_id *of_id;
|
||||
struct resource *res;
|
||||
int i, irq, ret, addr_bits;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
|
||||
@ -647,6 +650,10 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
||||
|
||||
mdata = spi_master_get_devdata(master);
|
||||
mdata->dev_comp = of_id->data;
|
||||
|
||||
if (mdata->dev_comp->enhance_timing)
|
||||
master->mode_bits |= SPI_CS_HIGH;
|
||||
|
||||
if (mdata->dev_comp->must_tx)
|
||||
master->flags = SPI_MASTER_MUST_TX;
|
||||
|
||||
@ -682,15 +689,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, master);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&pdev->dev, "failed to determine base address\n");
|
||||
goto err_put_master;
|
||||
}
|
||||
|
||||
mdata->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
mdata->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mdata->base)) {
|
||||
ret = PTR_ERR(mdata->base);
|
||||
goto err_put_master;
|
||||
|
@ -145,8 +145,8 @@
|
||||
#define LWR_SUSP_CTRL_EN BIT(31)
|
||||
|
||||
#define DMAS_CTRL 0x9c
|
||||
#define DMAS_CTRL_DIR_READ BIT(31)
|
||||
#define DMAS_CTRL_EN BIT(30)
|
||||
#define DMAS_CTRL_EN BIT(31)
|
||||
#define DMAS_CTRL_DIR_READ BIT(30)
|
||||
|
||||
#define DATA_STROB 0xa0
|
||||
#define DATA_STROB_EDO_EN BIT(2)
|
||||
@ -275,7 +275,7 @@ static void mxic_spi_hw_init(struct mxic_spi *mxic)
|
||||
writel(0, mxic->regs + HC_EN);
|
||||
writel(0, mxic->regs + LRD_CFG);
|
||||
writel(0, mxic->regs + LRD_CTRL);
|
||||
writel(HC_CFG_NIO(1) | HC_CFG_TYPE(0, HC_CFG_TYPE_SPI_NAND) |
|
||||
writel(HC_CFG_NIO(1) | HC_CFG_TYPE(0, HC_CFG_TYPE_SPI_NOR) |
|
||||
HC_CFG_SLV_ACT(0) | HC_CFG_MAN_CS_EN | HC_CFG_IDLE_SIO_LVL(1),
|
||||
mxic->regs + HC_CFG);
|
||||
}
|
||||
@ -346,7 +346,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
|
||||
if (op->addr.nbytes > 7)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return spi_mem_default_supports_op(mem, op);
|
||||
}
|
||||
|
||||
static int mxic_spi_mem_exec_op(struct spi_mem *mem,
|
||||
|
@ -293,7 +293,6 @@ static void npcm_pspi_reset_hw(struct npcm_pspi *priv)
|
||||
static irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct npcm_pspi *priv = dev_id;
|
||||
u16 val;
|
||||
u8 stat;
|
||||
|
||||
stat = ioread8(priv->base + NPCM_PSPI_STAT);
|
||||
@ -303,7 +302,7 @@ static irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
|
||||
|
||||
if (priv->tx_buf) {
|
||||
if (stat & NPCM_PSPI_STAT_RBF) {
|
||||
val = ioread8(NPCM_PSPI_DATA + priv->base);
|
||||
ioread8(NPCM_PSPI_DATA + priv->base);
|
||||
if (priv->tx_bytes == 0) {
|
||||
npcm_pspi_disable(priv);
|
||||
complete(&priv->xfer_done);
|
||||
|
@ -1027,7 +1027,7 @@ static int nxp_fspi_probe(struct platform_device *pdev)
|
||||
|
||||
ctlr->dev.of_node = np;
|
||||
|
||||
ret = spi_register_controller(ctlr);
|
||||
ret = devm_spi_register_controller(&pdev->dev, ctlr);
|
||||
if (ret)
|
||||
goto err_destroy_mutex;
|
||||
|
||||
|
@ -128,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
|
||||
|
||||
static int spi100k_read_data(struct spi_master *master, int len)
|
||||
{
|
||||
int dataH, dataL;
|
||||
int dataL;
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
/* Always do at least 16 bits */
|
||||
@ -146,7 +146,7 @@ static int spi100k_read_data(struct spi_master *master, int len)
|
||||
udelay(1000);
|
||||
|
||||
dataL = readw(spi100k->base + SPI_RX_LSB);
|
||||
dataH = readw(spi100k->base + SPI_RX_MSB);
|
||||
readw(spi100k->base + SPI_RX_MSB);
|
||||
spi100k_disable_clock(master);
|
||||
|
||||
return dataL;
|
||||
@ -321,8 +321,7 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
|
||||
}
|
||||
}
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
/* ignore the "leave it on after last xfer" hint */
|
||||
|
||||
|
@ -397,30 +397,26 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
|
||||
{
|
||||
struct omap2_mcspi *mcspi;
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
|
||||
mcspi = spi_master_get_devdata(spi->master);
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
|
||||
if (mcspi_dma->dma_tx) {
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
|
||||
|
||||
dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
|
||||
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
|
||||
xfer->tx_sg.nents,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_tx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
|
||||
xfer->tx_sg.nents,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_tx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
dma_async_issue_pending(mcspi_dma->dma_tx);
|
||||
omap2_mcspi_set_dma_req(spi, 0, 1);
|
||||
|
||||
}
|
||||
|
||||
static unsigned
|
||||
@ -439,6 +435,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||
int word_len, element_count;
|
||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||
void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
|
||||
mcspi = spi_master_get_devdata(spi->master);
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
@ -462,55 +459,47 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||
else /* word_len <= 32 */
|
||||
element_count = count >> 2;
|
||||
|
||||
if (mcspi_dma->dma_rx) {
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
|
||||
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
|
||||
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
|
||||
|
||||
/*
|
||||
* Reduce DMA transfer length by one more if McSPI is
|
||||
* configured in turbo mode.
|
||||
*/
|
||||
if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
|
||||
transfer_reduction += es;
|
||||
|
||||
if (transfer_reduction) {
|
||||
/* Split sgl into two. The second sgl won't be used. */
|
||||
sizes[0] = count - transfer_reduction;
|
||||
sizes[1] = transfer_reduction;
|
||||
nb_sizes = 2;
|
||||
} else {
|
||||
/*
|
||||
* Reduce DMA transfer length by one more if McSPI is
|
||||
* configured in turbo mode.
|
||||
* Don't bother splitting the sgl. This essentially
|
||||
* clones the original sgl.
|
||||
*/
|
||||
if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
|
||||
transfer_reduction += es;
|
||||
sizes[0] = count;
|
||||
nb_sizes = 1;
|
||||
}
|
||||
|
||||
if (transfer_reduction) {
|
||||
/* Split sgl into two. The second sgl won't be used. */
|
||||
sizes[0] = count - transfer_reduction;
|
||||
sizes[1] = transfer_reduction;
|
||||
nb_sizes = 2;
|
||||
} else {
|
||||
/*
|
||||
* Don't bother splitting the sgl. This essentially
|
||||
* clones the original sgl.
|
||||
*/
|
||||
sizes[0] = count;
|
||||
nb_sizes = 1;
|
||||
}
|
||||
ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, 0, nb_sizes,
|
||||
sizes, sg_out, out_mapped_nents, GFP_KERNEL);
|
||||
|
||||
ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents,
|
||||
0, nb_sizes,
|
||||
sizes,
|
||||
sg_out, out_mapped_nents,
|
||||
GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "sg_split failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "sg_split failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx,
|
||||
sg_out[0],
|
||||
out_mapped_nents[0],
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_rx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, sg_out[0],
|
||||
out_mapped_nents[0], DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_rx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
|
||||
dma_async_issue_pending(mcspi_dma->dma_rx);
|
||||
|
@ -467,8 +467,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
if (orion_spi_write_read_8bit(spi, &tx, &rx) < 0)
|
||||
goto out;
|
||||
count--;
|
||||
if (xfer->word_delay_usecs)
|
||||
udelay(xfer->word_delay_usecs);
|
||||
spi_delay_exec(&xfer->word_delay, xfer);
|
||||
} while (count);
|
||||
} else if (word_len == 16) {
|
||||
const u16 *tx = xfer->tx_buf;
|
||||
@ -478,8 +477,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
if (orion_spi_write_read_16bit(spi, &tx, &rx) < 0)
|
||||
goto out;
|
||||
count -= 2;
|
||||
if (xfer->word_delay_usecs)
|
||||
udelay(xfer->word_delay_usecs);
|
||||
spi_delay_exec(&xfer->word_delay, xfer);
|
||||
} while (count);
|
||||
}
|
||||
|
||||
@ -772,9 +770,6 @@ static int orion_spi_probe(struct platform_device *pdev)
|
||||
if (status < 0)
|
||||
goto out_rel_pm;
|
||||
|
||||
pm_runtime_mark_last_busy(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
status = spi_register_master(master);
|
||||
if (status < 0)
|
||||
|
@ -606,25 +606,30 @@ static void pic32_spi_cleanup(struct spi_device *spi)
|
||||
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
|
||||
}
|
||||
|
||||
static void pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
|
||||
static int pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
|
||||
{
|
||||
struct spi_master *master = pic32s->master;
|
||||
dma_cap_mask_t mask;
|
||||
int ret = 0;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
master->dma_rx = dma_request_chan(dev, "spi-rx");
|
||||
if (IS_ERR(master->dma_rx)) {
|
||||
if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER)
|
||||
ret = -EPROBE_DEFER;
|
||||
else
|
||||
dev_warn(dev, "RX channel not found.\n");
|
||||
|
||||
master->dma_rx = dma_request_slave_channel_compat(mask, NULL, NULL,
|
||||
dev, "spi-rx");
|
||||
if (!master->dma_rx) {
|
||||
dev_warn(dev, "RX channel not found.\n");
|
||||
master->dma_rx = NULL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
master->dma_tx = dma_request_slave_channel_compat(mask, NULL, NULL,
|
||||
dev, "spi-tx");
|
||||
if (!master->dma_tx) {
|
||||
dev_warn(dev, "TX channel not found.\n");
|
||||
master->dma_tx = dma_request_chan(dev, "spi-tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER)
|
||||
ret = -EPROBE_DEFER;
|
||||
else
|
||||
dev_warn(dev, "TX channel not found.\n");
|
||||
|
||||
master->dma_tx = NULL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
@ -634,14 +639,20 @@ static void pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
|
||||
/* DMA chnls allocated and prepared */
|
||||
set_bit(PIC32F_DMA_PREP, &pic32s->flags);
|
||||
|
||||
return;
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
if (master->dma_rx)
|
||||
if (master->dma_rx) {
|
||||
dma_release_channel(master->dma_rx);
|
||||
master->dma_rx = NULL;
|
||||
}
|
||||
|
||||
if (master->dma_tx)
|
||||
if (master->dma_tx) {
|
||||
dma_release_channel(master->dma_tx);
|
||||
master->dma_tx = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pic32_spi_dma_unprep(struct pic32_spi *pic32s)
|
||||
@ -776,7 +787,10 @@ static int pic32_spi_probe(struct platform_device *pdev)
|
||||
master->unprepare_transfer_hardware = pic32_spi_unprepare_hardware;
|
||||
|
||||
/* optional DMA support */
|
||||
pic32_spi_dma_prep(pic32s, &pdev->dev);
|
||||
ret = pic32_spi_dma_prep(pic32s, &pdev->dev);
|
||||
if (ret)
|
||||
goto err_bailout;
|
||||
|
||||
if (test_bit(PIC32F_DMA_PREP, &pic32s->flags))
|
||||
master->can_dma = pic32_spi_can_dma;
|
||||
|
||||
|
@ -485,12 +485,11 @@ static void giveback(struct pl022 *pl022)
|
||||
struct spi_transfer, transfer_list);
|
||||
|
||||
/* Delay if requested before any change in chip select */
|
||||
if (last_transfer->delay_usecs)
|
||||
/*
|
||||
* FIXME: This runs in interrupt context.
|
||||
* Is this really smart?
|
||||
*/
|
||||
udelay(last_transfer->delay_usecs);
|
||||
/*
|
||||
* FIXME: This runs in interrupt context.
|
||||
* Is this really smart?
|
||||
*/
|
||||
spi_transfer_delay_exec(last_transfer);
|
||||
|
||||
if (!last_transfer->cs_change) {
|
||||
struct spi_message *next_msg;
|
||||
@ -1159,7 +1158,7 @@ static int pl022_dma_autoprobe(struct pl022 *pl022)
|
||||
int err;
|
||||
|
||||
/* automatically configure DMA channels from platform, normally using DT */
|
||||
chan = dma_request_slave_channel_reason(dev, "rx");
|
||||
chan = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(chan)) {
|
||||
err = PTR_ERR(chan);
|
||||
goto err_no_rxchan;
|
||||
@ -1167,7 +1166,7 @@ static int pl022_dma_autoprobe(struct pl022 *pl022)
|
||||
|
||||
pl022->dma_rx_channel = chan;
|
||||
|
||||
chan = dma_request_slave_channel_reason(dev, "tx");
|
||||
chan = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(chan)) {
|
||||
err = PTR_ERR(chan);
|
||||
goto err_no_txchan;
|
||||
@ -1401,12 +1400,11 @@ static void pump_transfers(unsigned long data)
|
||||
previous = list_entry(transfer->transfer_list.prev,
|
||||
struct spi_transfer,
|
||||
transfer_list);
|
||||
if (previous->delay_usecs)
|
||||
/*
|
||||
* FIXME: This runs in interrupt context.
|
||||
* Is this really smart?
|
||||
*/
|
||||
udelay(previous->delay_usecs);
|
||||
/*
|
||||
* FIXME: This runs in interrupt context.
|
||||
* Is this really smart?
|
||||
*/
|
||||
spi_transfer_delay_exec(previous);
|
||||
|
||||
/* Reselect chip select only if cs_change was requested */
|
||||
if (previous->cs_change)
|
||||
@ -1520,8 +1518,7 @@ static void do_polling_transfer(struct pl022 *pl022)
|
||||
previous =
|
||||
list_entry(transfer->transfer_list.prev,
|
||||
struct spi_transfer, transfer_list);
|
||||
if (previous->delay_usecs)
|
||||
udelay(previous->delay_usecs);
|
||||
spi_transfer_delay_exec(previous);
|
||||
if (previous->cs_change)
|
||||
pl022_cs_control(pl022, SSP_CHIP_SELECT);
|
||||
} else {
|
||||
|
@ -4,27 +4,29 @@
|
||||
* Copyright (C) 2013, Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include "spi-pxa2xx.h"
|
||||
|
||||
@ -1457,6 +1459,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x02aa), LPSS_CNL_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x02ab), LPSS_CNL_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x02fb), LPSS_CNL_SSP },
|
||||
/* CML-H */
|
||||
{ PCI_VDEVICE(INTEL, 0x06aa), LPSS_CNL_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x06ab), LPSS_CNL_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x06fb), LPSS_CNL_SSP },
|
||||
/* TGL-LP */
|
||||
{ PCI_VDEVICE(INTEL, 0xa0aa), LPSS_CNL_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0xa0ab), LPSS_CNL_SSP },
|
||||
@ -1476,11 +1482,13 @@ MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
|
||||
static int pxa2xx_spi_get_port_id(struct device *dev)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
unsigned int devid;
|
||||
int port_id = -1;
|
||||
|
||||
adev = ACPI_COMPANION(dev);
|
||||
if (adev && adev->pnp.unique_id &&
|
||||
!kstrtouint(adev->pnp.unique_id, 0, &devid))
|
||||
port_id = devid;
|
||||
@ -1489,7 +1497,7 @@ static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
|
||||
|
||||
#else /* !CONFIG_ACPI */
|
||||
|
||||
static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
|
||||
static int pxa2xx_spi_get_port_id(struct device *dev)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -1510,34 +1518,22 @@ static struct pxa2xx_spi_controller *
|
||||
pxa2xx_spi_init_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct pxa2xx_spi_controller *pdata;
|
||||
struct acpi_device *adev;
|
||||
struct ssp_device *ssp;
|
||||
struct resource *res;
|
||||
const struct acpi_device_id *adev_id = NULL;
|
||||
struct device *parent = pdev->dev.parent;
|
||||
struct pci_dev *pcidev = dev_is_pci(parent) ? to_pci_dev(parent) : NULL;
|
||||
const struct pci_device_id *pcidev_id = NULL;
|
||||
const struct of_device_id *of_id = NULL;
|
||||
enum pxa_ssp_type type;
|
||||
const void *match;
|
||||
|
||||
adev = ACPI_COMPANION(&pdev->dev);
|
||||
if (pcidev)
|
||||
pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, pcidev);
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
of_id = of_match_device(pdev->dev.driver->of_match_table,
|
||||
&pdev->dev);
|
||||
else if (dev_is_pci(pdev->dev.parent))
|
||||
pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match,
|
||||
to_pci_dev(pdev->dev.parent));
|
||||
else if (adev)
|
||||
adev_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
|
||||
&pdev->dev);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (adev_id)
|
||||
type = (enum pxa_ssp_type)adev_id->driver_data;
|
||||
match = device_get_match_data(&pdev->dev);
|
||||
if (match)
|
||||
type = (enum pxa_ssp_type)match;
|
||||
else if (pcidev_id)
|
||||
type = (enum pxa_ssp_type)pcidev_id->driver_data;
|
||||
else if (of_id)
|
||||
type = (enum pxa_ssp_type)of_id->data;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
@ -1545,32 +1541,36 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
|
||||
if (!pdata)
|
||||
return NULL;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
ssp = &pdata->ssp;
|
||||
|
||||
ssp->phys_base = res->start;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
ssp->mmio_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(ssp->mmio_base))
|
||||
return NULL;
|
||||
|
||||
ssp->phys_base = res->start;
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
if (pcidev_id) {
|
||||
pdata->tx_param = pdev->dev.parent;
|
||||
pdata->rx_param = pdev->dev.parent;
|
||||
pdata->tx_param = parent;
|
||||
pdata->rx_param = parent;
|
||||
pdata->dma_filter = pxa2xx_spi_idma_filter;
|
||||
}
|
||||
#endif
|
||||
|
||||
ssp->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
ssp->irq = platform_get_irq(pdev, 0);
|
||||
ssp->type = type;
|
||||
ssp->pdev = pdev;
|
||||
ssp->port_id = pxa2xx_spi_get_port_id(adev);
|
||||
if (IS_ERR(ssp->clk))
|
||||
return NULL;
|
||||
|
||||
pdata->is_slave = of_property_read_bool(pdev->dev.of_node, "spi-slave");
|
||||
ssp->irq = platform_get_irq(pdev, 0);
|
||||
if (ssp->irq < 0)
|
||||
return NULL;
|
||||
|
||||
ssp->type = type;
|
||||
ssp->dev = &pdev->dev;
|
||||
ssp->port_id = pxa2xx_spi_get_port_id(&pdev->dev);
|
||||
|
||||
pdata->is_slave = device_property_read_bool(&pdev->dev, "spi-slave");
|
||||
pdata->num_chipselect = 1;
|
||||
pdata->enable_dma = true;
|
||||
pdata->dma_burst_size = 1;
|
||||
@ -1602,6 +1602,11 @@ static int pxa2xx_spi_fw_translate_cs(struct spi_controller *controller,
|
||||
return cs;
|
||||
}
|
||||
|
||||
static size_t pxa2xx_spi_max_dma_transfer_size(struct spi_device *spi)
|
||||
{
|
||||
return MAX_DMA_LEN;
|
||||
}
|
||||
|
||||
static int pxa2xx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -1707,6 +1712,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
||||
} else {
|
||||
controller->can_dma = pxa2xx_spi_can_dma;
|
||||
controller->max_dma_len = MAX_DMA_LEN;
|
||||
controller->max_transfer_size =
|
||||
pxa2xx_spi_max_dma_transfer_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -932,11 +932,11 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
|
||||
int ret;
|
||||
|
||||
/* allocate dma resources, if available */
|
||||
master->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
master->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(master->dma_rx))
|
||||
return PTR_ERR(master->dma_rx);
|
||||
|
||||
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
master->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
ret = PTR_ERR(master->dma_tx);
|
||||
goto err_tx;
|
||||
|
@ -1257,9 +1257,9 @@ static int rspi_probe(struct platform_device *pdev)
|
||||
ctlr->flags = ops->flags;
|
||||
ctlr->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
ret = platform_get_irq_byname(pdev, "rx");
|
||||
ret = platform_get_irq_byname_optional(pdev, "rx");
|
||||
if (ret < 0) {
|
||||
ret = platform_get_irq_byname(pdev, "mux");
|
||||
ret = platform_get_irq_byname_optional(pdev, "mux");
|
||||
if (ret < 0)
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret >= 0)
|
||||
@ -1270,10 +1270,6 @@ static int rspi_probe(struct platform_device *pdev)
|
||||
if (ret >= 0)
|
||||
rspi->tx_irq = ret;
|
||||
}
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "platform_get_irq error\n");
|
||||
goto error2;
|
||||
}
|
||||
|
||||
if (rspi->rx_irq == rspi->tx_irq) {
|
||||
/* Single multiplexed interrupt */
|
||||
|
@ -1154,15 +1154,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
||||
|
||||
if (!is_polling(sdd)) {
|
||||
/* Acquire DMA channels */
|
||||
sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
|
||||
"rx");
|
||||
sdd->rx_dma.ch = dma_request_chan(&pdev->dev, "rx");
|
||||
if (IS_ERR(sdd->rx_dma.ch)) {
|
||||
dev_err(&pdev->dev, "Failed to get RX DMA channel\n");
|
||||
ret = PTR_ERR(sdd->rx_dma.ch);
|
||||
goto err_disable_io_clk;
|
||||
}
|
||||
sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
|
||||
"tx");
|
||||
sdd->tx_dma.ch = dma_request_chan(&pdev->dev, "tx");
|
||||
if (IS_ERR(sdd->tx_dma.ch)) {
|
||||
dev_err(&pdev->dev, "Failed to get TX DMA channel\n");
|
||||
ret = PTR_ERR(sdd->tx_dma.ch);
|
||||
|
@ -211,8 +211,7 @@ static int sc18is602_transfer_one(struct spi_master *master,
|
||||
}
|
||||
status = 0;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
}
|
||||
m->status = status;
|
||||
spi_finalize_current_message(master);
|
||||
|
@ -190,8 +190,7 @@ static int hspi_transfer_one_message(struct spi_controller *ctlr,
|
||||
|
||||
msg->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (cs_change) {
|
||||
ndelay(nsecs);
|
||||
|
@ -357,14 +357,14 @@ static int sifive_spi_probe(struct platform_device *pdev)
|
||||
if (!cs_bits) {
|
||||
dev_err(&pdev->dev, "Could not auto probe CS lines\n");
|
||||
ret = -EINVAL;
|
||||
goto put_master;
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
num_cs = ilog2(cs_bits) + 1;
|
||||
if (num_cs > SIFIVE_SPI_MAX_CS) {
|
||||
dev_err(&pdev->dev, "Invalid number of spi slaves\n");
|
||||
ret = -EINVAL;
|
||||
goto put_master;
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
/* Define our master */
|
||||
@ -393,7 +393,7 @@ static int sifive_spi_probe(struct platform_device *pdev)
|
||||
dev_name(&pdev->dev), spi);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Unable to bind to interrupt\n");
|
||||
goto put_master;
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "mapped; irq=%d, cs=%d\n",
|
||||
@ -402,11 +402,13 @@ static int sifive_spi_probe(struct platform_device *pdev)
|
||||
ret = devm_spi_register_master(&pdev->dev, master);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "spi_register_master failed\n");
|
||||
goto put_master;
|
||||
goto disable_clk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
disable_clk:
|
||||
clk_disable_unprepare(spi->clk);
|
||||
put_master:
|
||||
spi_master_put(master);
|
||||
|
||||
@ -420,6 +422,7 @@ static int sifive_spi_remove(struct platform_device *pdev)
|
||||
|
||||
/* Disable all the interrupts just in case */
|
||||
sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
|
||||
clk_disable_unprepare(spi->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -368,7 +368,6 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_controller *ctlr;
|
||||
struct mtk_spi_slave *mdata;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
|
||||
ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata));
|
||||
@ -392,17 +391,8 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, ctlr);
|
||||
|
||||
init_completion(&mdata->xfer_done);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&pdev->dev, "failed to determine base address\n");
|
||||
goto err_put_ctlr;
|
||||
}
|
||||
|
||||
mdata->dev = &pdev->dev;
|
||||
|
||||
mdata->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
mdata->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mdata->base)) {
|
||||
ret = PTR_ERR(mdata->base);
|
||||
goto err_put_ctlr;
|
||||
|
@ -77,6 +77,7 @@
|
||||
|
||||
/* Bits definitions for register REG_WDG_CTRL */
|
||||
#define BIT_WDG_RUN BIT(1)
|
||||
#define BIT_WDG_NEW BIT(2)
|
||||
#define BIT_WDG_RST BIT(3)
|
||||
|
||||
/* Registers definitions for PMIC */
|
||||
@ -383,6 +384,10 @@ static int sprd_adi_restart_handler(struct notifier_block *this,
|
||||
/* Unlock the watchdog */
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, WDG_UNLOCK_KEY);
|
||||
|
||||
sprd_adi_read(sadi, sadi->slave_pbase + REG_WDG_CTRL, &val);
|
||||
val |= BIT_WDG_NEW;
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val);
|
||||
|
||||
/* Load the watchdog timeout value, 50ms is always enough. */
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_LOW,
|
||||
WDG_LOAD_VAL & WDG_LOAD_MASK);
|
||||
@ -393,6 +398,9 @@ static int sprd_adi_restart_handler(struct notifier_block *this,
|
||||
val |= BIT_WDG_RUN | BIT_WDG_RST;
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val);
|
||||
|
||||
/* Lock the watchdog */
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, ~WDG_UNLOCK_KEY);
|
||||
|
||||
mdelay(1000);
|
||||
|
||||
dev_emerg(sadi->dev, "Unable to restart system\n");
|
||||
|
@ -669,11 +669,15 @@ static void sprd_spi_set_speed(struct sprd_spi *ss, u32 speed_hz)
|
||||
writel_relaxed(clk_div, ss->base + SPRD_SPI_CLKD);
|
||||
}
|
||||
|
||||
static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
|
||||
static int sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
|
||||
{
|
||||
struct spi_delay *d = &t->word_delay;
|
||||
u16 word_delay, interval;
|
||||
u32 val;
|
||||
|
||||
if (d->unit != SPI_DELAY_UNIT_SCK)
|
||||
return -EINVAL;
|
||||
|
||||
val = readl_relaxed(ss->base + SPRD_SPI_CTL7);
|
||||
val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX);
|
||||
/* Set default chip selection, clock phase and clock polarity */
|
||||
@ -686,7 +690,7 @@ static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
|
||||
* formula as below per datasheet:
|
||||
* interval time (source clock cycles) = interval * 4 + 10.
|
||||
*/
|
||||
word_delay = clamp_t(u16, t->word_delay, SPRD_SPI_MIN_DELAY_CYCLE,
|
||||
word_delay = clamp_t(u16, d->value, SPRD_SPI_MIN_DELAY_CYCLE,
|
||||
SPRD_SPI_MAX_DELAY_CYCLE);
|
||||
interval = DIV_ROUND_UP(word_delay - 10, 4);
|
||||
ss->word_delay = interval * 4 + 10;
|
||||
@ -711,6 +715,8 @@ static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
|
||||
val &= ~SPRD_SPI_DATA_LINE2_EN;
|
||||
|
||||
writel_relaxed(val, ss->base + SPRD_SPI_CTL7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_spi_setup_transfer(struct spi_device *sdev,
|
||||
@ -719,13 +725,16 @@ static int sprd_spi_setup_transfer(struct spi_device *sdev,
|
||||
struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller);
|
||||
u8 bits_per_word = t->bits_per_word;
|
||||
u32 val, mode = 0;
|
||||
int ret;
|
||||
|
||||
ss->len = t->len;
|
||||
ss->tx_buf = t->tx_buf;
|
||||
ss->rx_buf = t->rx_buf;
|
||||
|
||||
ss->hw_mode = sdev->mode;
|
||||
sprd_spi_init_hw(ss, t);
|
||||
ret = sprd_spi_init_hw(ss, t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set tansfer speed and valid bits */
|
||||
sprd_spi_set_speed(ss, t->speed_hz);
|
||||
|
@ -381,6 +381,7 @@ static int spi_st_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
clk_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
clk_disable_unprepare(spi_st->clk);
|
||||
put_master:
|
||||
spi_master_put(master);
|
||||
@ -392,6 +393,8 @@ static int spi_st_remove(struct platform_device *pdev)
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct spi_st *spi_st = spi_master_get_devdata(master);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
clk_disable_unprepare(spi_st->clk);
|
||||
|
||||
pinctrl_pm_select_sleep_state(&pdev->dev);
|
||||
|
@ -528,7 +528,6 @@ static void stm32_qspi_release(struct stm32_qspi *qspi)
|
||||
stm32_qspi_dma_free(qspi);
|
||||
mutex_destroy(&qspi->lock);
|
||||
clk_disable_unprepare(qspi->clk);
|
||||
spi_master_put(qspi->ctrl);
|
||||
}
|
||||
|
||||
static int stm32_qspi_probe(struct platform_device *pdev)
|
||||
@ -626,6 +625,8 @@ static int stm32_qspi_probe(struct platform_device *pdev)
|
||||
|
||||
err:
|
||||
stm32_qspi_release(qspi);
|
||||
spi_master_put(qspi->ctrl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -666,8 +666,7 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi,
|
||||
dma_addr_t dma_phys;
|
||||
int ret;
|
||||
|
||||
dma_chan = dma_request_slave_channel_reason(tspi->dev,
|
||||
dma_to_memory ? "rx" : "tx");
|
||||
dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx");
|
||||
if (IS_ERR(dma_chan)) {
|
||||
ret = PTR_ERR(dma_chan);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
@ -723,15 +722,31 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
|
||||
dma_release_channel(dma_chan);
|
||||
}
|
||||
|
||||
static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly,
|
||||
u8 hold_dly, u8 inactive_dly)
|
||||
static int tegra_spi_set_hw_cs_timing(struct spi_device *spi,
|
||||
struct spi_delay *setup,
|
||||
struct spi_delay *hold,
|
||||
struct spi_delay *inactive)
|
||||
{
|
||||
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
||||
u8 setup_dly, hold_dly, inactive_dly;
|
||||
u32 setup_hold;
|
||||
u32 spi_cs_timing;
|
||||
u32 inactive_cycles;
|
||||
u8 cs_state;
|
||||
|
||||
if ((setup && setup->unit != SPI_DELAY_UNIT_SCK) ||
|
||||
(hold && hold->unit != SPI_DELAY_UNIT_SCK) ||
|
||||
(inactive && inactive->unit != SPI_DELAY_UNIT_SCK)) {
|
||||
dev_err(&spi->dev,
|
||||
"Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n",
|
||||
SPI_DELAY_UNIT_SCK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
setup_dly = setup ? setup->value : 0;
|
||||
hold_dly = hold ? hold->value : 0;
|
||||
inactive_dly = inactive ? inactive->value : 0;
|
||||
|
||||
setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
|
||||
hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
|
||||
if (setup_dly && hold_dly) {
|
||||
@ -758,6 +773,8 @@ static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly,
|
||||
tspi->spi_cs_timing2 = spi_cs_timing;
|
||||
tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
|
||||
@ -984,17 +1001,6 @@ static int tegra_spi_setup(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_spi_transfer_delay(int delay)
|
||||
{
|
||||
if (!delay)
|
||||
return;
|
||||
|
||||
if (delay >= 1000)
|
||||
mdelay(delay / 1000);
|
||||
|
||||
udelay(delay % 1000);
|
||||
}
|
||||
|
||||
static void tegra_spi_transfer_end(struct spi_device *spi)
|
||||
{
|
||||
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
||||
@ -1098,7 +1104,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
|
||||
complete_xfer:
|
||||
if (ret < 0 || skip) {
|
||||
tegra_spi_transfer_end(spi);
|
||||
tegra_spi_transfer_delay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
goto exit;
|
||||
} else if (list_is_last(&xfer->transfer_list,
|
||||
&msg->transfers)) {
|
||||
@ -1106,11 +1112,11 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
|
||||
tspi->cs_control = spi;
|
||||
else {
|
||||
tegra_spi_transfer_end(spi);
|
||||
tegra_spi_transfer_delay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
}
|
||||
} else if (xfer->cs_change) {
|
||||
tegra_spi_transfer_end(spi);
|
||||
tegra_spi_transfer_delay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -341,10 +341,11 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master,
|
||||
goto exit;
|
||||
}
|
||||
msg->actual_length += xfer->len;
|
||||
if (xfer->cs_change && xfer->delay_usecs) {
|
||||
if (xfer->cs_change &&
|
||||
(xfer->delay_usecs || xfer->delay.value)) {
|
||||
tegra_sflash_writel(tsd, tsd->def_command_reg,
|
||||
SPI_COMMAND);
|
||||
udelay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
|
@ -599,8 +599,7 @@ static int tegra_slink_init_dma_param(struct tegra_slink_data *tspi,
|
||||
int ret;
|
||||
struct dma_slave_config dma_sconfig;
|
||||
|
||||
dma_chan = dma_request_slave_channel_reason(tspi->dev,
|
||||
dma_to_memory ? "rx" : "tx");
|
||||
dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx");
|
||||
if (IS_ERR(dma_chan)) {
|
||||
ret = PTR_ERR(dma_chan);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
@ -1073,7 +1072,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
||||
ret = clk_enable(tspi->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Clock enable failed %d\n", ret);
|
||||
goto exit_free_master;
|
||||
goto exit_clk_unprepare;
|
||||
}
|
||||
|
||||
spi_irq = platform_get_irq(pdev, 0);
|
||||
@ -1146,6 +1145,8 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
||||
free_irq(spi_irq, tspi);
|
||||
exit_clk_disable:
|
||||
clk_disable(tspi->clk);
|
||||
exit_clk_unprepare:
|
||||
clk_unprepare(tspi->clk);
|
||||
exit_free_master:
|
||||
spi_master_put(master);
|
||||
return ret;
|
||||
@ -1159,6 +1160,7 @@ static int tegra_slink_remove(struct platform_device *pdev)
|
||||
free_irq(tspi->irq, tspi);
|
||||
|
||||
clk_disable(tspi->clk);
|
||||
clk_unprepare(tspi->clk);
|
||||
|
||||
if (tspi->tx_dma_chan)
|
||||
tegra_slink_deinit_dma_param(tspi, false);
|
||||
|
@ -1229,12 +1229,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
|
||||
"%s:data->current_msg->actual_length=%d\n",
|
||||
__func__, data->current_msg->actual_length);
|
||||
|
||||
/* check for delay */
|
||||
if (data->cur_trans->delay_usecs) {
|
||||
dev_dbg(&data->master->dev, "%s:delay in usec=%d\n",
|
||||
__func__, data->cur_trans->delay_usecs);
|
||||
udelay(data->cur_trans->delay_usecs);
|
||||
}
|
||||
spi_transfer_delay_exec(data->cur_trans);
|
||||
|
||||
spin_lock(&data->lock);
|
||||
|
||||
|
@ -26,7 +26,8 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
|
||||
#define SPI_FIFO_SIZE 4
|
||||
@ -79,7 +80,7 @@ struct txx9spi {
|
||||
void __iomem *membase;
|
||||
int baseclk;
|
||||
struct clk *clk;
|
||||
int last_chipselect;
|
||||
struct gpio_desc *last_chipselect;
|
||||
int last_chipselect_val;
|
||||
};
|
||||
|
||||
@ -95,20 +96,22 @@ static void txx9spi_wr(struct txx9spi *c, u32 val, int reg)
|
||||
static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
|
||||
int on, unsigned int cs_delay)
|
||||
{
|
||||
int val = (spi->mode & SPI_CS_HIGH) ? on : !on;
|
||||
|
||||
/*
|
||||
* The GPIO descriptor will track polarity inversion inside
|
||||
* gpiolib.
|
||||
*/
|
||||
if (on) {
|
||||
/* deselect the chip with cs_change hint in last transfer */
|
||||
if (c->last_chipselect >= 0)
|
||||
gpio_set_value(c->last_chipselect,
|
||||
if (c->last_chipselect)
|
||||
gpiod_set_value(c->last_chipselect,
|
||||
!c->last_chipselect_val);
|
||||
c->last_chipselect = spi->chip_select;
|
||||
c->last_chipselect_val = val;
|
||||
c->last_chipselect = spi->cs_gpiod;
|
||||
c->last_chipselect_val = on;
|
||||
} else {
|
||||
c->last_chipselect = -1;
|
||||
c->last_chipselect = NULL;
|
||||
ndelay(cs_delay); /* CS Hold Time */
|
||||
}
|
||||
gpio_set_value(spi->chip_select, val);
|
||||
gpiod_set_value(spi->cs_gpiod, on);
|
||||
ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */
|
||||
}
|
||||
|
||||
@ -119,12 +122,6 @@ static int txx9spi_setup(struct spi_device *spi)
|
||||
if (!spi->max_speed_hz)
|
||||
return -EINVAL;
|
||||
|
||||
if (gpio_direction_output(spi->chip_select,
|
||||
!(spi->mode & SPI_CS_HIGH))) {
|
||||
dev_err(&spi->dev, "Cannot setup GPIO for chipselect.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* deselect chip */
|
||||
spin_lock(&c->lock);
|
||||
txx9spi_cs_func(spi, c, 0, (NSEC_PER_SEC / 2) / spi->max_speed_hz);
|
||||
@ -248,8 +245,7 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m)
|
||||
len -= count * wsize;
|
||||
}
|
||||
m->actual_length += t->len;
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (!cs_change)
|
||||
continue;
|
||||
@ -320,6 +316,47 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Chip select uses GPIO only, further the driver is using the chip select
|
||||
* numer (from the device tree "reg" property, and this can only come from
|
||||
* device tree since this i MIPS and there is no way to pass platform data) as
|
||||
* the GPIO number. As the platform has only one GPIO controller (the txx9 GPIO
|
||||
* chip) it is thus using the chip select number as an offset into that chip.
|
||||
* This chip has a maximum of 16 GPIOs 0..15 and this is what all platforms
|
||||
* register.
|
||||
*
|
||||
* We modernized this behaviour by explicitly converting that offset to an
|
||||
* offset on the GPIO chip using a GPIO descriptor machine table of the same
|
||||
* size as the txx9 GPIO chip with a 1-to-1 mapping of chip select to GPIO
|
||||
* offset.
|
||||
*
|
||||
* This is admittedly a hack, but it is countering the hack of using "reg" to
|
||||
* contain a GPIO offset when it should be using "cs-gpios" as the SPI bindings
|
||||
* state.
|
||||
*/
|
||||
static struct gpiod_lookup_table txx9spi_cs_gpio_table = {
|
||||
.dev_id = "spi0",
|
||||
.table = {
|
||||
GPIO_LOOKUP_IDX("TXx9", 0, "cs", 0, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 1, "cs", 1, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 2, "cs", 2, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 3, "cs", 3, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 4, "cs", 4, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 5, "cs", 5, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 6, "cs", 6, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 7, "cs", 7, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 8, "cs", 8, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 9, "cs", 9, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 10, "cs", 10, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 11, "cs", 11, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 12, "cs", 12, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 13, "cs", 13, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 14, "cs", 14, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 15, "cs", 15, GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static int txx9spi_probe(struct platform_device *dev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
@ -373,12 +410,14 @@ static int txx9spi_probe(struct platform_device *dev)
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
c->last_chipselect = -1;
|
||||
c->last_chipselect = NULL;
|
||||
|
||||
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
|
||||
(unsigned long long)res->start, irq,
|
||||
(c->baseclk + 500000) / 1000000);
|
||||
|
||||
gpiod_add_lookup_table(&txx9spi_cs_gpio_table);
|
||||
|
||||
/* the spi->mode bits understood by this driver: */
|
||||
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
|
||||
|
||||
@ -387,6 +426,7 @@ static int txx9spi_probe(struct platform_device *dev)
|
||||
master->transfer = txx9spi_transfer;
|
||||
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||
master->use_gpio_descriptors = true;
|
||||
|
||||
ret = devm_spi_register_master(&dev->dev, master);
|
||||
if (ret)
|
||||
|
@ -188,8 +188,7 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
|
||||
}
|
||||
status = 0;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
is_first = false;
|
||||
}
|
||||
|
@ -391,7 +391,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
||||
struct xilinx_spi *xspi;
|
||||
struct xspi_platform_data *pdata;
|
||||
struct resource *res;
|
||||
int ret, num_cs = 0, bits_per_word = 8;
|
||||
int ret, num_cs = 0, bits_per_word;
|
||||
struct spi_master *master;
|
||||
u32 tmp;
|
||||
u8 i;
|
||||
@ -403,6 +403,11 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
||||
} else {
|
||||
of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
|
||||
&num_cs);
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"xlnx,num-transfer-bits",
|
||||
&bits_per_word);
|
||||
if (ret)
|
||||
bits_per_word = 8;
|
||||
}
|
||||
|
||||
if (!num_cs) {
|
||||
|
@ -80,7 +80,6 @@ static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on)
|
||||
static int xtfpga_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct xtfpga_spi *xspi;
|
||||
struct resource *mem;
|
||||
int ret;
|
||||
struct spi_master *master;
|
||||
|
||||
@ -97,14 +96,7 @@ static int xtfpga_spi_probe(struct platform_device *pdev)
|
||||
xspi->bitbang.master = master;
|
||||
xspi->bitbang.chipselect = xtfpga_spi_chipselect;
|
||||
xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "No memory resource\n");
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
xspi->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
xspi->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(xspi->regs)) {
|
||||
ret = PTR_ERR(xspi->regs);
|
||||
goto err;
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
@ -51,7 +50,6 @@
|
||||
#define ZYNQ_QSPI_CONFIG_BDRATE_MASK GENMASK(5, 3) /* Baud Rate Mask */
|
||||
#define ZYNQ_QSPI_CONFIG_CPHA_MASK BIT(2) /* Clock Phase Control */
|
||||
#define ZYNQ_QSPI_CONFIG_CPOL_MASK BIT(1) /* Clock Polarity Control */
|
||||
#define ZYNQ_QSPI_CONFIG_SSCTRL_MASK BIT(10) /* Slave Select Mask */
|
||||
#define ZYNQ_QSPI_CONFIG_FWIDTH_MASK GENMASK(7, 6) /* FIFO width */
|
||||
#define ZYNQ_QSPI_CONFIG_MSTREN_MASK BIT(0) /* Master Mode */
|
||||
|
||||
@ -61,9 +59,9 @@
|
||||
* These are the values used in the calculation of baud rate divisor and
|
||||
* setting the slave select.
|
||||
*/
|
||||
#define ZYNQ_QSPI_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */
|
||||
#define ZYNQ_QSPI_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift in CR */
|
||||
#define ZYNQ_QSPI_SS_SHIFT 10 /* Slave Select field shift in CR */
|
||||
#define ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */
|
||||
#define ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift */
|
||||
#define ZYNQ_QSPI_CONFIG_PCS BIT(10) /* Peripheral Chip Select */
|
||||
|
||||
/*
|
||||
* QSPI Interrupt Registers bit Masks
|
||||
@ -99,9 +97,9 @@
|
||||
* It is named Linear Configuration but it controls other modes when not in
|
||||
* linear mode also.
|
||||
*/
|
||||
#define ZYNQ_QSPI_LCFG_TWO_MEM_MASK BIT(30) /* LQSPI Two memories Mask */
|
||||
#define ZYNQ_QSPI_LCFG_SEP_BUS_MASK BIT(29) /* LQSPI Separate bus Mask */
|
||||
#define ZYNQ_QSPI_LCFG_U_PAGE_MASK BIT(28) /* LQSPI Upper Page Mask */
|
||||
#define ZYNQ_QSPI_LCFG_TWO_MEM BIT(30) /* LQSPI Two memories */
|
||||
#define ZYNQ_QSPI_LCFG_SEP_BUS BIT(29) /* LQSPI Separate bus */
|
||||
#define ZYNQ_QSPI_LCFG_U_PAGE BIT(28) /* LQSPI Upper Page */
|
||||
|
||||
#define ZYNQ_QSPI_LCFG_DUMMY_SHIFT 8
|
||||
|
||||
@ -116,8 +114,8 @@
|
||||
*/
|
||||
#define ZYNQ_QSPI_MODEBITS (SPI_CPOL | SPI_CPHA)
|
||||
|
||||
/* Default number of chip selects */
|
||||
#define ZYNQ_QSPI_DEFAULT_NUM_CS 1
|
||||
/* Maximum number of chip selects */
|
||||
#define ZYNQ_QSPI_MAX_NUM_CS 2
|
||||
|
||||
/**
|
||||
* struct zynq_qspi - Defines qspi driver instance
|
||||
@ -161,6 +159,7 @@ static inline void zynq_qspi_write(struct zynq_qspi *xqspi, u32 offset,
|
||||
/**
|
||||
* zynq_qspi_init_hw - Initialize the hardware
|
||||
* @xqspi: Pointer to the zynq_qspi structure
|
||||
* @num_cs: Number of connected CS (to enable dual memories if needed)
|
||||
*
|
||||
* The default settings of the QSPI controller's configurable parameters on
|
||||
* reset are
|
||||
@ -178,7 +177,7 @@ static inline void zynq_qspi_write(struct zynq_qspi *xqspi, u32 offset,
|
||||
* - Set the little endian mode of TX FIFO and
|
||||
* - Enable the QSPI controller
|
||||
*/
|
||||
static void zynq_qspi_init_hw(struct zynq_qspi *xqspi)
|
||||
static void zynq_qspi_init_hw(struct zynq_qspi *xqspi, unsigned int num_cs)
|
||||
{
|
||||
u32 config_reg;
|
||||
|
||||
@ -186,7 +185,12 @@ static void zynq_qspi_init_hw(struct zynq_qspi *xqspi)
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_IDIS_OFFSET, ZYNQ_QSPI_IXR_ALL_MASK);
|
||||
|
||||
/* Disable linear mode as the boot loader may have used it */
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET, 0);
|
||||
config_reg = 0;
|
||||
/* At the same time, enable dual mode if more than 1 CS is available */
|
||||
if (num_cs > 1)
|
||||
config_reg |= ZYNQ_QSPI_LCFG_TWO_MEM;
|
||||
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET, config_reg);
|
||||
|
||||
/* Clear the RX FIFO */
|
||||
while (zynq_qspi_read(xqspi, ZYNQ_QSPI_STATUS_OFFSET) &
|
||||
@ -284,21 +288,28 @@ static void zynq_qspi_txfifo_op(struct zynq_qspi *xqspi, unsigned int size)
|
||||
*/
|
||||
static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
|
||||
{
|
||||
struct spi_controller *ctrl = spi->master;
|
||||
struct zynq_qspi *xqspi = spi_controller_get_devdata(ctrl);
|
||||
struct spi_controller *ctlr = spi->master;
|
||||
struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr);
|
||||
u32 config_reg;
|
||||
|
||||
config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_CONFIG_OFFSET);
|
||||
if (assert) {
|
||||
/* Select the slave */
|
||||
config_reg &= ~ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
|
||||
config_reg |= (((~(BIT(spi->chip_select))) <<
|
||||
ZYNQ_QSPI_SS_SHIFT) &
|
||||
ZYNQ_QSPI_CONFIG_SSCTRL_MASK);
|
||||
} else {
|
||||
config_reg |= ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
|
||||
/* Select the lower (CS0) or upper (CS1) memory */
|
||||
if (ctlr->num_chipselect > 1) {
|
||||
config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET);
|
||||
if (!spi->chip_select)
|
||||
config_reg &= ~ZYNQ_QSPI_LCFG_U_PAGE;
|
||||
else
|
||||
config_reg |= ZYNQ_QSPI_LCFG_U_PAGE;
|
||||
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET, config_reg);
|
||||
}
|
||||
|
||||
/* Ground the line to assert the CS */
|
||||
config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_CONFIG_OFFSET);
|
||||
if (assert)
|
||||
config_reg &= ~ZYNQ_QSPI_CONFIG_PCS;
|
||||
else
|
||||
config_reg |= ZYNQ_QSPI_CONFIG_PCS;
|
||||
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_CONFIG_OFFSET, config_reg);
|
||||
}
|
||||
|
||||
@ -332,7 +343,7 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
|
||||
* ----------------
|
||||
* 111 - divide by 256
|
||||
*/
|
||||
while ((baud_rate_val < ZYNQ_QSPI_BAUD_DIV_MAX) &&
|
||||
while ((baud_rate_val < ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX) &&
|
||||
(clk_get_rate(xqspi->refclk) / (2 << baud_rate_val)) >
|
||||
spi->max_speed_hz)
|
||||
baud_rate_val++;
|
||||
@ -348,7 +359,7 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
|
||||
config_reg |= ZYNQ_QSPI_CONFIG_CPOL_MASK;
|
||||
|
||||
config_reg &= ~ZYNQ_QSPI_CONFIG_BDRATE_MASK;
|
||||
config_reg |= (baud_rate_val << ZYNQ_QSPI_BAUD_DIV_SHIFT);
|
||||
config_reg |= (baud_rate_val << ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT);
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_CONFIG_OFFSET, config_reg);
|
||||
|
||||
return 0;
|
||||
@ -365,10 +376,10 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
|
||||
*/
|
||||
static int zynq_qspi_setup_op(struct spi_device *spi)
|
||||
{
|
||||
struct spi_controller *ctrl = spi->master;
|
||||
struct zynq_qspi *qspi = spi_controller_get_devdata(ctrl);
|
||||
struct spi_controller *ctlr = spi->master;
|
||||
struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr);
|
||||
|
||||
if (ctrl->busy)
|
||||
if (ctlr->busy)
|
||||
return -EBUSY;
|
||||
|
||||
clk_enable(qspi->refclk);
|
||||
@ -663,9 +674,6 @@ static int zynq_qspi_probe(struct platform_device *pdev)
|
||||
goto clk_dis_pclk;
|
||||
}
|
||||
|
||||
/* QSPI controller initializations */
|
||||
zynq_qspi_init_hw(xqspi);
|
||||
|
||||
xqspi->irq = platform_get_irq(pdev, 0);
|
||||
if (xqspi->irq <= 0) {
|
||||
ret = -ENXIO;
|
||||
@ -681,10 +689,14 @@ static int zynq_qspi_probe(struct platform_device *pdev)
|
||||
|
||||
ret = of_property_read_u32(np, "num-cs",
|
||||
&num_cs);
|
||||
if (ret < 0)
|
||||
ctlr->num_chipselect = ZYNQ_QSPI_DEFAULT_NUM_CS;
|
||||
else
|
||||
if (ret < 0) {
|
||||
ctlr->num_chipselect = 1;
|
||||
} else if (num_cs > ZYNQ_QSPI_MAX_NUM_CS) {
|
||||
dev_err(&pdev->dev, "only 2 chip selects are available\n");
|
||||
goto remove_master;
|
||||
} else {
|
||||
ctlr->num_chipselect = num_cs;
|
||||
}
|
||||
|
||||
ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
|
||||
SPI_TX_DUAL | SPI_TX_QUAD;
|
||||
@ -692,6 +704,10 @@ static int zynq_qspi_probe(struct platform_device *pdev)
|
||||
ctlr->setup = zynq_qspi_setup_op;
|
||||
ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
|
||||
ctlr->dev.of_node = np;
|
||||
|
||||
/* QSPI controller initializations */
|
||||
zynq_qspi_init_hw(xqspi, ctlr->num_chipselect);
|
||||
|
||||
ret = devm_spi_register_controller(&pdev->dev, ctlr);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "spi_register_master failed\n");
|
||||
|
@ -92,7 +92,7 @@ static ssize_t driver_override_store(struct device *dev,
|
||||
if (len) {
|
||||
spi->driver_override = driver_override;
|
||||
} else {
|
||||
/* Emptry string, disable driver override */
|
||||
/* Empty string, disable driver override */
|
||||
spi->driver_override = NULL;
|
||||
kfree(driver_override);
|
||||
}
|
||||
@ -469,7 +469,7 @@ static LIST_HEAD(board_list);
|
||||
static LIST_HEAD(spi_controller_list);
|
||||
|
||||
/*
|
||||
* Used to protect add/del opertion for board_info list and
|
||||
* Used to protect add/del operation for board_info list and
|
||||
* spi_controller list, and their matching process
|
||||
* also used to protect object of type struct idr
|
||||
*/
|
||||
@ -775,6 +775,15 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
||||
|
||||
static void spi_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
bool enable1 = enable;
|
||||
|
||||
if (!spi->controller->set_cs_timing) {
|
||||
if (enable1)
|
||||
spi_delay_exec(&spi->controller->cs_setup, NULL);
|
||||
else
|
||||
spi_delay_exec(&spi->controller->cs_hold, NULL);
|
||||
}
|
||||
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
enable = !enable;
|
||||
|
||||
@ -800,6 +809,11 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
|
||||
} else if (spi->controller->set_cs) {
|
||||
spi->controller->set_cs(spi, !enable);
|
||||
}
|
||||
|
||||
if (!spi->controller->set_cs_timing) {
|
||||
if (!enable1)
|
||||
spi_delay_exec(&spi->controller->cs_inactive, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
@ -1106,42 +1120,79 @@ static void _spi_transfer_delay_ns(u32 ns)
|
||||
}
|
||||
}
|
||||
|
||||
static void _spi_transfer_cs_change_delay(struct spi_message *msg,
|
||||
struct spi_transfer *xfer)
|
||||
int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
|
||||
{
|
||||
u32 delay = xfer->cs_change_delay;
|
||||
u32 unit = xfer->cs_change_delay_unit;
|
||||
u32 delay = _delay->value;
|
||||
u32 unit = _delay->unit;
|
||||
u32 hz;
|
||||
|
||||
/* return early on "fast" mode - for everything but USECS */
|
||||
if (!delay && unit != SPI_DELAY_UNIT_USECS)
|
||||
return;
|
||||
if (!delay)
|
||||
return 0;
|
||||
|
||||
switch (unit) {
|
||||
case SPI_DELAY_UNIT_USECS:
|
||||
/* for compatibility use default of 10us */
|
||||
if (!delay)
|
||||
delay = 10000;
|
||||
else
|
||||
delay *= 1000;
|
||||
delay *= 1000;
|
||||
break;
|
||||
case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
|
||||
break;
|
||||
case SPI_DELAY_UNIT_SCK:
|
||||
/* clock cycles need to be obtained from spi_transfer */
|
||||
if (!xfer)
|
||||
return -EINVAL;
|
||||
/* if there is no effective speed know, then approximate
|
||||
* by underestimating with half the requested hz
|
||||
*/
|
||||
hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
|
||||
if (!hz)
|
||||
return -EINVAL;
|
||||
delay *= DIV_ROUND_UP(1000000000, hz);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_delay_to_ns);
|
||||
|
||||
int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer)
|
||||
{
|
||||
int delay;
|
||||
|
||||
if (!_delay)
|
||||
return -EINVAL;
|
||||
|
||||
delay = spi_delay_to_ns(_delay, xfer);
|
||||
if (delay < 0)
|
||||
return delay;
|
||||
|
||||
_spi_transfer_delay_ns(delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_delay_exec);
|
||||
|
||||
static void _spi_transfer_cs_change_delay(struct spi_message *msg,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
u32 delay = xfer->cs_change_delay.value;
|
||||
u32 unit = xfer->cs_change_delay.unit;
|
||||
int ret;
|
||||
|
||||
/* return early on "fast" mode - for everything but USECS */
|
||||
if (!delay) {
|
||||
if (unit == SPI_DELAY_UNIT_USECS)
|
||||
_spi_transfer_delay_ns(10000);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = spi_delay_exec(&xfer->cs_change_delay, xfer);
|
||||
if (ret) {
|
||||
dev_err_once(&msg->spi->dev,
|
||||
"Use of unsupported delay unit %i, using default of 10us\n",
|
||||
xfer->cs_change_delay_unit);
|
||||
delay = 10000;
|
||||
unit);
|
||||
_spi_transfer_delay_ns(10000);
|
||||
}
|
||||
/* now sleep for the requested amount of time */
|
||||
_spi_transfer_delay_ns(delay);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1212,8 +1263,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
|
||||
if (msg->status != -EINPROGRESS)
|
||||
goto out;
|
||||
|
||||
if (xfer->delay_usecs)
|
||||
_spi_transfer_delay_ns(xfer->delay_usecs * 1000);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
|
||||
if (xfer->cs_change) {
|
||||
if (list_is_last(&xfer->transfer_list,
|
||||
@ -1830,15 +1880,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
|
||||
spi->mode |= SPI_3WIRE;
|
||||
if (of_property_read_bool(nc, "spi-lsb-first"))
|
||||
spi->mode |= SPI_LSB_FIRST;
|
||||
|
||||
/*
|
||||
* For descriptors associated with the device, polarity inversion is
|
||||
* handled in the gpiolib, so all chip selects are "active high" in
|
||||
* the logical sense, the gpiolib will invert the line if need be.
|
||||
*/
|
||||
if (ctlr->use_gpio_descriptors)
|
||||
spi->mode |= SPI_CS_HIGH;
|
||||
else if (of_property_read_bool(nc, "spi-cs-high"))
|
||||
if (of_property_read_bool(nc, "spi-cs-high"))
|
||||
spi->mode |= SPI_CS_HIGH;
|
||||
|
||||
/* Device DUAL/QUAD mode */
|
||||
@ -1902,6 +1944,15 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
|
||||
}
|
||||
spi->chip_select = value;
|
||||
|
||||
/*
|
||||
* For descriptors associated with the device, polarity inversion is
|
||||
* handled in the gpiolib, so all gpio chip selects are "active high"
|
||||
* in the logical sense, the gpiolib will invert the line if need be.
|
||||
*/
|
||||
if ((ctlr->use_gpio_descriptors) && ctlr->cs_gpiods &&
|
||||
ctlr->cs_gpiods[spi->chip_select])
|
||||
spi->mode |= SPI_CS_HIGH;
|
||||
|
||||
/* Device speed */
|
||||
rc = of_property_read_u32(nc, "spi-max-frequency", &value);
|
||||
if (rc) {
|
||||
@ -2990,10 +3041,11 @@ struct spi_replaced_transfers *spi_replace_transfers(
|
||||
/* add to list */
|
||||
list_add(&xfer->transfer_list, rxfer->replaced_after);
|
||||
|
||||
/* clear cs_change and delay_usecs for all but the last */
|
||||
/* clear cs_change and delay for all but the last */
|
||||
if (i) {
|
||||
xfer->cs_change = false;
|
||||
xfer->delay_usecs = 0;
|
||||
xfer->delay.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3210,7 +3262,29 @@ int spi_setup(struct spi_device *spi)
|
||||
if (spi->controller->setup)
|
||||
status = spi->controller->setup(spi);
|
||||
|
||||
spi_set_cs(spi, false);
|
||||
if (spi->controller->auto_runtime_pm && spi->controller->set_cs) {
|
||||
status = pm_runtime_get_sync(spi->controller->dev.parent);
|
||||
if (status < 0) {
|
||||
pm_runtime_put_noidle(spi->controller->dev.parent);
|
||||
dev_err(&spi->controller->dev, "Failed to power device: %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* We do not want to return positive value from pm_runtime_get,
|
||||
* there are many instances of devices calling spi_setup() and
|
||||
* checking for a non-zero return value instead of a negative
|
||||
* return value.
|
||||
*/
|
||||
status = 0;
|
||||
|
||||
spi_set_cs(spi, false);
|
||||
pm_runtime_mark_last_busy(spi->controller->dev.parent);
|
||||
pm_runtime_put_autosuspend(spi->controller->dev.parent);
|
||||
} else {
|
||||
spi_set_cs(spi, false);
|
||||
}
|
||||
|
||||
if (spi->rt && !spi->controller->rt) {
|
||||
spi->controller->rt = true;
|
||||
@ -3233,18 +3307,71 @@ EXPORT_SYMBOL_GPL(spi_setup);
|
||||
/**
|
||||
* spi_set_cs_timing - configure CS setup, hold, and inactive delays
|
||||
* @spi: the device that requires specific CS timing configuration
|
||||
* @setup: CS setup time in terms of clock count
|
||||
* @hold: CS hold time in terms of clock count
|
||||
* @inactive_dly: CS inactive delay between transfers in terms of clock count
|
||||
* @setup: CS setup time specified via @spi_delay
|
||||
* @hold: CS hold time specified via @spi_delay
|
||||
* @inactive: CS inactive delay between transfers specified via @spi_delay
|
||||
*
|
||||
* Return: zero on success, else a negative error code.
|
||||
*/
|
||||
void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold,
|
||||
u8 inactive_dly)
|
||||
int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup,
|
||||
struct spi_delay *hold, struct spi_delay *inactive)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (spi->controller->set_cs_timing)
|
||||
spi->controller->set_cs_timing(spi, setup, hold, inactive_dly);
|
||||
return spi->controller->set_cs_timing(spi, setup, hold,
|
||||
inactive);
|
||||
|
||||
if ((setup && setup->unit == SPI_DELAY_UNIT_SCK) ||
|
||||
(hold && hold->unit == SPI_DELAY_UNIT_SCK) ||
|
||||
(inactive && inactive->unit == SPI_DELAY_UNIT_SCK)) {
|
||||
dev_err(&spi->dev,
|
||||
"Clock-cycle delays for CS not supported in SW mode\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
len = sizeof(struct spi_delay);
|
||||
|
||||
/* copy delays to controller */
|
||||
if (setup)
|
||||
memcpy(&spi->controller->cs_setup, setup, len);
|
||||
else
|
||||
memset(&spi->controller->cs_setup, 0, len);
|
||||
|
||||
if (hold)
|
||||
memcpy(&spi->controller->cs_hold, hold, len);
|
||||
else
|
||||
memset(&spi->controller->cs_hold, 0, len);
|
||||
|
||||
if (inactive)
|
||||
memcpy(&spi->controller->cs_inactive, inactive, len);
|
||||
else
|
||||
memset(&spi->controller->cs_inactive, 0, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_set_cs_timing);
|
||||
|
||||
static int _spi_xfer_word_delay_update(struct spi_transfer *xfer,
|
||||
struct spi_device *spi)
|
||||
{
|
||||
int delay1, delay2;
|
||||
|
||||
delay1 = spi_delay_to_ns(&xfer->word_delay, xfer);
|
||||
if (delay1 < 0)
|
||||
return delay1;
|
||||
|
||||
delay2 = spi_delay_to_ns(&spi->word_delay, xfer);
|
||||
if (delay2 < 0)
|
||||
return delay2;
|
||||
|
||||
if (delay1 < delay2)
|
||||
memcpy(&xfer->word_delay, &spi->word_delay,
|
||||
sizeof(xfer->word_delay));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
||||
{
|
||||
struct spi_controller *ctlr = spi->controller;
|
||||
@ -3380,8 +3507,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (xfer->word_delay_usecs < spi->word_delay_usecs)
|
||||
xfer->word_delay_usecs = spi->word_delay_usecs;
|
||||
if (_spi_xfer_word_delay_update(xfer, spi))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
message->status = -EINPROGRESS;
|
||||
|
@ -265,9 +265,11 @@ static int spidev_message(struct spidev_data *spidev,
|
||||
k_tmp->tx_nbits = u_tmp->tx_nbits;
|
||||
k_tmp->rx_nbits = u_tmp->rx_nbits;
|
||||
k_tmp->bits_per_word = u_tmp->bits_per_word;
|
||||
k_tmp->delay_usecs = u_tmp->delay_usecs;
|
||||
k_tmp->delay.value = u_tmp->delay_usecs;
|
||||
k_tmp->delay.unit = SPI_DELAY_UNIT_USECS;
|
||||
k_tmp->speed_hz = u_tmp->speed_hz;
|
||||
k_tmp->word_delay_usecs = u_tmp->word_delay_usecs;
|
||||
k_tmp->word_delay.value = u_tmp->word_delay_usecs;
|
||||
k_tmp->word_delay.unit = SPI_DELAY_UNIT_USECS;
|
||||
if (!k_tmp->speed_hz)
|
||||
k_tmp->speed_hz = spidev->speed_hz;
|
||||
#ifdef VERBOSE
|
||||
@ -627,6 +629,9 @@ static int spidev_release(struct inode *inode, struct file *filp)
|
||||
if (dofree)
|
||||
kfree(spidev);
|
||||
}
|
||||
#ifdef CONFIG_SPI_SLAVE
|
||||
spi_slave_abort(spidev->spi);
|
||||
#endif
|
||||
mutex_unlock(&device_list_lock);
|
||||
|
||||
return 0;
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
/* Board specific platform_data */
|
||||
struct mtk_chip_config {
|
||||
u32 cs_pol;
|
||||
u32 sample_sel;
|
||||
};
|
||||
#endif
|
||||
|
@ -206,7 +206,7 @@ enum pxa_ssp_type {
|
||||
};
|
||||
|
||||
struct ssp_device {
|
||||
struct platform_device *pdev;
|
||||
struct device *dev;
|
||||
struct list_head node;
|
||||
|
||||
struct clk *clk;
|
||||
|
@ -90,6 +90,22 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
|
||||
#define SPI_STATISTICS_INCREMENT_FIELD(stats, field) \
|
||||
SPI_STATISTICS_ADD_TO_FIELD(stats, field, 1)
|
||||
|
||||
/**
|
||||
* struct spi_delay - SPI delay information
|
||||
* @value: Value for the delay
|
||||
* @unit: Unit for the delay
|
||||
*/
|
||||
struct spi_delay {
|
||||
#define SPI_DELAY_UNIT_USECS 0
|
||||
#define SPI_DELAY_UNIT_NSECS 1
|
||||
#define SPI_DELAY_UNIT_SCK 2
|
||||
u16 value;
|
||||
u8 unit;
|
||||
};
|
||||
|
||||
extern int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer);
|
||||
extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer);
|
||||
|
||||
/**
|
||||
* struct spi_device - Controller side proxy for an SPI slave device
|
||||
* @dev: Driver model representation of the device.
|
||||
@ -124,7 +140,7 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
|
||||
* the spi_master.
|
||||
* @cs_gpiod: gpio descriptor of the chipselect line (optional, NULL when
|
||||
* not using a GPIO line)
|
||||
* @word_delay_usecs: microsecond delay to be inserted between consecutive
|
||||
* @word_delay: delay to be inserted between consecutive
|
||||
* words of a transfer
|
||||
*
|
||||
* @statistics: statistics for the spi_device
|
||||
@ -174,7 +190,7 @@ struct spi_device {
|
||||
const char *driver_override;
|
||||
int cs_gpio; /* LEGACY: chip select gpio */
|
||||
struct gpio_desc *cs_gpiod; /* chip select gpio desc */
|
||||
uint8_t word_delay_usecs; /* inter-word delay */
|
||||
struct spi_delay word_delay; /* inter-word delay */
|
||||
|
||||
/* the statistics */
|
||||
struct spi_statistics statistics;
|
||||
@ -391,6 +407,11 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
||||
* controller has native support for memory like operations.
|
||||
* @unprepare_message: undo any work done by prepare_message().
|
||||
* @slave_abort: abort the ongoing transfer request on an SPI slave controller
|
||||
* @cs_setup: delay to be introduced by the controller after CS is asserted
|
||||
* @cs_hold: delay to be introduced by the controller before CS is deasserted
|
||||
* @cs_inactive: delay to be introduced by the controller after CS is
|
||||
* deasserted. If @cs_change_delay is used from @spi_transfer, then the
|
||||
* two delays will be added up.
|
||||
* @cs_gpios: LEGACY: array of GPIO descs to use as chip select lines; one per
|
||||
* CS number. Any individual value may be -ENOENT for CS lines that
|
||||
* are not GPIOs (driven by the SPI controller itself). Use the cs_gpiods
|
||||
@ -509,8 +530,8 @@ struct spi_controller {
|
||||
* to configure specific CS timing through spi_set_cs_timing() after
|
||||
* spi_setup().
|
||||
*/
|
||||
void (*set_cs_timing)(struct spi_device *spi, u8 setup_clk_cycles,
|
||||
u8 hold_clk_cycles, u8 inactive_clk_cycles);
|
||||
int (*set_cs_timing)(struct spi_device *spi, struct spi_delay *setup,
|
||||
struct spi_delay *hold, struct spi_delay *inactive);
|
||||
|
||||
/* bidirectional bulk transfers
|
||||
*
|
||||
@ -594,6 +615,11 @@ struct spi_controller {
|
||||
/* Optimized handlers for SPI memory-like operations. */
|
||||
const struct spi_controller_mem_ops *mem_ops;
|
||||
|
||||
/* CS delays */
|
||||
struct spi_delay cs_setup;
|
||||
struct spi_delay cs_hold;
|
||||
struct spi_delay cs_inactive;
|
||||
|
||||
/* gpio chip select */
|
||||
int *cs_gpios;
|
||||
struct gpio_desc **cs_gpiods;
|
||||
@ -763,13 +789,13 @@ extern void spi_res_release(struct spi_controller *ctlr,
|
||||
* @cs_change: affects chipselect after this transfer completes
|
||||
* @cs_change_delay: delay between cs deassert and assert when
|
||||
* @cs_change is set and @spi_transfer is not the last in @spi_message
|
||||
* @cs_change_delay_unit: unit of cs_change_delay
|
||||
* @delay: delay to be introduced after this transfer before
|
||||
* (optionally) changing the chipselect status, then starting
|
||||
* the next transfer or completing this @spi_message.
|
||||
* @delay_usecs: microseconds to delay after this transfer before
|
||||
* (optionally) changing the chipselect status, then starting
|
||||
* the next transfer or completing this @spi_message.
|
||||
* @word_delay_usecs: microseconds to inter word delay after each word size
|
||||
* (set by bits_per_word) transmission.
|
||||
* @word_delay: clock cycles to inter word delay after each word size
|
||||
* @word_delay: inter word delay to be introduced after each word size
|
||||
* (set by bits_per_word) transmission.
|
||||
* @effective_speed_hz: the effective SCK-speed that was used to
|
||||
* transfer this transfer. Set to 0 if the spi bus driver does
|
||||
@ -883,15 +909,11 @@ struct spi_transfer {
|
||||
#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */
|
||||
#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */
|
||||
u8 bits_per_word;
|
||||
u8 word_delay_usecs;
|
||||
u16 delay_usecs;
|
||||
u16 cs_change_delay;
|
||||
u8 cs_change_delay_unit;
|
||||
#define SPI_DELAY_UNIT_USECS 0
|
||||
#define SPI_DELAY_UNIT_NSECS 1
|
||||
#define SPI_DELAY_UNIT_SCK 2
|
||||
struct spi_delay delay;
|
||||
struct spi_delay cs_change_delay;
|
||||
struct spi_delay word_delay;
|
||||
u32 speed_hz;
|
||||
u16 word_delay;
|
||||
|
||||
u32 effective_speed_hz;
|
||||
|
||||
@ -996,6 +1018,20 @@ spi_transfer_del(struct spi_transfer *t)
|
||||
list_del(&t->transfer_list);
|
||||
}
|
||||
|
||||
static inline int
|
||||
spi_transfer_delay_exec(struct spi_transfer *t)
|
||||
{
|
||||
struct spi_delay d;
|
||||
|
||||
if (t->delay_usecs) {
|
||||
d.value = t->delay_usecs;
|
||||
d.unit = SPI_DELAY_UNIT_USECS;
|
||||
return spi_delay_exec(&d, NULL);
|
||||
}
|
||||
|
||||
return spi_delay_exec(&t->delay, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_message_init_with_transfers - Initialize spi_message and append transfers
|
||||
* @m: spi_message to be initialized
|
||||
@ -1043,7 +1079,10 @@ static inline void spi_message_free(struct spi_message *m)
|
||||
kfree(m);
|
||||
}
|
||||
|
||||
extern void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold, u8 inactive_dly);
|
||||
extern int spi_set_cs_timing(struct spi_device *spi,
|
||||
struct spi_delay *setup,
|
||||
struct spi_delay *hold,
|
||||
struct spi_delay *inactive);
|
||||
|
||||
extern int spi_setup(struct spi_device *spi);
|
||||
extern int spi_async(struct spi_device *spi, struct spi_message *message);
|
||||
|
@ -177,7 +177,7 @@ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
||||
/* we can only change the settings if the port is not in use */
|
||||
if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) ||
|
||||
(mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) {
|
||||
dev_err(&sspa->pdev->dev,
|
||||
dev_err(sspa->dev,
|
||||
"can't change hardware dai format: stream is in use\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -52,11 +52,11 @@ struct ssp_priv {
|
||||
|
||||
static void dump_registers(struct ssp_device *ssp)
|
||||
{
|
||||
dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n",
|
||||
dev_dbg(ssp->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n",
|
||||
pxa_ssp_read_reg(ssp, SSCR0), pxa_ssp_read_reg(ssp, SSCR1),
|
||||
pxa_ssp_read_reg(ssp, SSTO));
|
||||
|
||||
dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n",
|
||||
dev_dbg(ssp->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n",
|
||||
pxa_ssp_read_reg(ssp, SSPSP), pxa_ssp_read_reg(ssp, SSSR),
|
||||
pxa_ssp_read_reg(ssp, SSACD));
|
||||
}
|
||||
@ -223,7 +223,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
|
||||
clk_id = PXA_SSP_CLK_EXT;
|
||||
}
|
||||
|
||||
dev_dbg(&ssp->pdev->dev,
|
||||
dev_dbg(ssp->dev,
|
||||
"pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n",
|
||||
cpu_dai->id, clk_id, freq);
|
||||
|
||||
@ -316,7 +316,7 @@ static int pxa_ssp_set_pll(struct ssp_priv *priv, unsigned int freq)
|
||||
|
||||
ssacd |= (0x6 << 4);
|
||||
|
||||
dev_dbg(&ssp->pdev->dev,
|
||||
dev_dbg(ssp->dev,
|
||||
"Using SSACDD %x to supply %uHz\n",
|
||||
val, freq);
|
||||
break;
|
||||
@ -687,7 +687,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
|
||||
* - complain loudly and fail if they've not been set up yet.
|
||||
*/
|
||||
if ((sscr0 & SSCR0_MOD) && !ttsa) {
|
||||
dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
|
||||
dev_err(ssp->dev, "No TDM timeslot configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user