Merge branch 'spi-5.5' into spi-next
commit
ca4196aa10
|
@ -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>;
|
||||||
|
};
|
||||||
|
|
|
@ -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"
|
|
@ -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:
|
Optional properties:
|
||||||
- clock-names : Contains the names of the clocks:
|
- clock-names : Contains the names of the clocks:
|
||||||
"ssi_clk", for the core clock used to generate the external SPI clock.
|
"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.
|
- cs-gpios : Specifies the gpio pins to be used for chipselects.
|
||||||
- num-cs : The number of chipselects. If omitted, this will default to 4.
|
- 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
|
- 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>;
|
|
||||||
};
|
|
|
@ -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>;
|
|
||||||
...
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -9,6 +9,7 @@ Required properties:
|
||||||
|
|
||||||
Optional properties:
|
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:
|
Example:
|
||||||
axi_quad_spi@41e00000 {
|
axi_quad_spi@41e00000 {
|
||||||
|
@ -17,5 +18,6 @@ Example:
|
||||||
interrupts = <0 31 1>;
|
interrupts = <0 31 1>;
|
||||||
reg = <0x41e00000 0x10000>;
|
reg = <0x41e00000 0x10000>;
|
||||||
xlnx,num-ss-bits = <0x1>;
|
xlnx,num-ss-bits = <0x1>;
|
||||||
|
xlnx,num-transfer-bits = <32>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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->use_count--;
|
||||||
ssp->label = NULL;
|
ssp->label = NULL;
|
||||||
} else
|
} else
|
||||||
dev_err(&ssp->pdev->dev, "device already free\n");
|
dev_err(ssp->dev, "device already free\n");
|
||||||
mutex_unlock(&ssp_lock);
|
mutex_unlock(&ssp_lock);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(pxa_ssp_free);
|
EXPORT_SYMBOL(pxa_ssp_free);
|
||||||
|
@ -118,7 +118,7 @@ static int pxa_ssp_probe(struct platform_device *pdev)
|
||||||
if (ssp == NULL)
|
if (ssp == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ssp->pdev = pdev;
|
ssp->dev = dev;
|
||||||
|
|
||||||
ssp->clk = devm_clk_get(dev, NULL);
|
ssp->clk = devm_clk_get(dev, NULL);
|
||||||
if (IS_ERR(ssp->clk))
|
if (IS_ERR(ssp->clk))
|
||||||
|
|
|
@ -39,24 +39,24 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
|
||||||
.len = 2,
|
.len = 2,
|
||||||
.cs_change = 1,
|
.cs_change = 1,
|
||||||
.delay_usecs = adis->data->write_delay,
|
.delay_usecs = adis->data->write_delay,
|
||||||
.cs_change_delay = adis->data->cs_change_delay,
|
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||||
}, {
|
}, {
|
||||||
.tx_buf = adis->tx + 2,
|
.tx_buf = adis->tx + 2,
|
||||||
.bits_per_word = 8,
|
.bits_per_word = 8,
|
||||||
.len = 2,
|
.len = 2,
|
||||||
.cs_change = 1,
|
.cs_change = 1,
|
||||||
.delay_usecs = adis->data->write_delay,
|
.delay_usecs = adis->data->write_delay,
|
||||||
.cs_change_delay = adis->data->cs_change_delay,
|
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||||
}, {
|
}, {
|
||||||
.tx_buf = adis->tx + 4,
|
.tx_buf = adis->tx + 4,
|
||||||
.bits_per_word = 8,
|
.bits_per_word = 8,
|
||||||
.len = 2,
|
.len = 2,
|
||||||
.cs_change = 1,
|
.cs_change = 1,
|
||||||
.delay_usecs = adis->data->write_delay,
|
.delay_usecs = adis->data->write_delay,
|
||||||
.cs_change_delay = adis->data->cs_change_delay,
|
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||||
}, {
|
}, {
|
||||||
.tx_buf = adis->tx + 6,
|
.tx_buf = adis->tx + 6,
|
||||||
.bits_per_word = 8,
|
.bits_per_word = 8,
|
||||||
|
@ -139,16 +139,16 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
|
||||||
.len = 2,
|
.len = 2,
|
||||||
.cs_change = 1,
|
.cs_change = 1,
|
||||||
.delay_usecs = adis->data->write_delay,
|
.delay_usecs = adis->data->write_delay,
|
||||||
.cs_change_delay = adis->data->cs_change_delay,
|
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||||
}, {
|
}, {
|
||||||
.tx_buf = adis->tx + 2,
|
.tx_buf = adis->tx + 2,
|
||||||
.bits_per_word = 8,
|
.bits_per_word = 8,
|
||||||
.len = 2,
|
.len = 2,
|
||||||
.cs_change = 1,
|
.cs_change = 1,
|
||||||
.delay_usecs = adis->data->read_delay,
|
.delay_usecs = adis->data->read_delay,
|
||||||
.cs_change_delay = adis->data->cs_change_delay,
|
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||||
}, {
|
}, {
|
||||||
.tx_buf = adis->tx + 4,
|
.tx_buf = adis->tx + 4,
|
||||||
.rx_buf = adis->rx,
|
.rx_buf = adis->rx,
|
||||||
|
@ -156,8 +156,8 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
|
||||||
.len = 2,
|
.len = 2,
|
||||||
.cs_change = 1,
|
.cs_change = 1,
|
||||||
.delay_usecs = adis->data->read_delay,
|
.delay_usecs = adis->data->read_delay,
|
||||||
.cs_change_delay = adis->data->cs_change_delay,
|
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||||
}, {
|
}, {
|
||||||
.rx_buf = adis->rx + 2,
|
.rx_buf = adis->rx + 2,
|
||||||
.bits_per_word = 8,
|
.bits_per_word = 8,
|
||||||
|
|
|
@ -80,6 +80,7 @@ config SPI_ARMADA_3700
|
||||||
config SPI_ATMEL
|
config SPI_ATMEL
|
||||||
tristate "Atmel SPI Controller"
|
tristate "Atmel SPI Controller"
|
||||||
depends on ARCH_AT91 || COMPILE_TEST
|
depends on ARCH_AT91 || COMPILE_TEST
|
||||||
|
depends on OF
|
||||||
help
|
help
|
||||||
This selects a driver for the Atmel SPI Controller, present on
|
This selects a driver for the Atmel SPI Controller, present on
|
||||||
many AT91 ARM chips.
|
many AT91 ARM chips.
|
||||||
|
|
|
@ -132,7 +132,7 @@ static int at91_usart_spi_configure_dma(struct spi_controller *ctlr,
|
||||||
dma_cap_zero(mask);
|
dma_cap_zero(mask);
|
||||||
dma_cap_set(DMA_SLAVE, 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_OR_NULL(ctlr->dma_tx)) {
|
||||||
if (IS_ERR(ctlr->dma_tx)) {
|
if (IS_ERR(ctlr->dma_tx)) {
|
||||||
err = PTR_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;
|
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_OR_NULL(ctlr->dma_rx)) {
|
||||||
if (IS_ERR(ctlr->dma_rx)) {
|
if (IS_ERR(ctlr->dma_rx)) {
|
||||||
err = PTR_ERR(ctlr->dma_rx);
|
err = PTR_ERR(ctlr->dma_rx);
|
||||||
|
|
|
@ -222,37 +222,13 @@
|
||||||
| SPI_BF(name, value))
|
| SPI_BF(name, value))
|
||||||
|
|
||||||
/* Register access macros */
|
/* 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) \
|
#define spi_readl(port, reg) \
|
||||||
readl_relaxed((port)->regs + SPI_##reg)
|
readl_relaxed((port)->regs + SPI_##reg)
|
||||||
#define spi_writel(port, reg, value) \
|
#define spi_writel(port, reg, value) \
|
||||||
writel_relaxed((value), (port)->regs + SPI_##reg)
|
writel_relaxed((value), (port)->regs + SPI_##reg)
|
||||||
|
|
||||||
#define spi_readw(port, reg) \
|
|
||||||
readw_relaxed((port)->regs + SPI_##reg)
|
|
||||||
#define spi_writew(port, reg, value) \
|
#define spi_writew(port, reg, value) \
|
||||||
writew_relaxed((value), (port)->regs + SPI_##reg)
|
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
|
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
|
||||||
* cache operations; better heuristics consider wordsize and bitrate.
|
* cache operations; better heuristics consider wordsize and bitrate.
|
||||||
*/
|
*/
|
||||||
|
@ -299,16 +275,16 @@ struct atmel_spi {
|
||||||
|
|
||||||
bool use_dma;
|
bool use_dma;
|
||||||
bool use_pdc;
|
bool use_pdc;
|
||||||
bool use_cs_gpios;
|
|
||||||
|
|
||||||
bool keep_cs;
|
bool keep_cs;
|
||||||
|
|
||||||
u32 fifo_size;
|
u32 fifo_size;
|
||||||
|
u8 native_cs_free;
|
||||||
|
u8 native_cs_for_gpio;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Controller-specific per-slave state */
|
/* Controller-specific per-slave state */
|
||||||
struct atmel_spi_device {
|
struct atmel_spi_device {
|
||||||
struct gpio_desc *npcs_pin;
|
|
||||||
u32 csr;
|
u32 csr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -335,11 +311,9 @@ static bool atmel_spi_is_v2(struct atmel_spi *as)
|
||||||
* transmitted") Not so! Workaround uses nCSx pins as GPIOs; or newer
|
* transmitted") Not so! Workaround uses nCSx pins as GPIOs; or newer
|
||||||
* controllers have CSAAT and friends.
|
* controllers have CSAAT and friends.
|
||||||
*
|
*
|
||||||
* Since the CSAAT functionality is a bit weird on newer controllers as
|
* Even controller newer than ar91rm9200, using GPIOs can make sens as
|
||||||
* well, we use GPIO to control nCSx pins on all controllers, updating
|
* it lets us support active-high chipselects despite the controller's
|
||||||
* MR.PCS to avoid confusing the controller. Using GPIOs also lets us
|
* belief that only active-low devices/systems exists.
|
||||||
* 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
|
* However, at91rm9200 has a second erratum whereby nCS0 doesn't work
|
||||||
* right when driven with GPIO. ("Mode Fault does not allow more than one
|
* right when driven with GPIO. ("Mode Fault does not allow more than one
|
||||||
|
@ -351,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)
|
static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct atmel_spi_device *asd = spi->controller_state;
|
struct atmel_spi_device *asd = spi->controller_state;
|
||||||
|
int chip_select;
|
||||||
u32 mr;
|
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)) {
|
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
|
/* 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
|
* on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS
|
||||||
*/
|
*/
|
||||||
spi_writel(as, CSR0, asd->csr);
|
spi_writel(as, CSR0, asd->csr);
|
||||||
if (as->caps.has_wdrbt) {
|
if (as->caps.has_wdrbt) {
|
||||||
spi_writel(as, MR,
|
spi_writel(as, MR,
|
||||||
SPI_BF(PCS, ~(0x01 << spi->chip_select))
|
SPI_BF(PCS, ~(0x01 << chip_select))
|
||||||
| SPI_BIT(WDRBT)
|
| SPI_BIT(WDRBT)
|
||||||
| SPI_BIT(MODFDIS)
|
| SPI_BIT(MODFDIS)
|
||||||
| SPI_BIT(MSTR));
|
| SPI_BIT(MSTR));
|
||||||
} else {
|
} else {
|
||||||
spi_writel(as, MR,
|
spi_writel(as, MR,
|
||||||
SPI_BF(PCS, ~(0x01 << spi->chip_select))
|
SPI_BF(PCS, ~(0x01 << chip_select))
|
||||||
| SPI_BIT(MODFDIS)
|
| SPI_BIT(MODFDIS)
|
||||||
| SPI_BIT(MSTR));
|
| SPI_BIT(MSTR));
|
||||||
}
|
}
|
||||||
|
|
||||||
mr = spi_readl(as, MR);
|
mr = spi_readl(as, MR);
|
||||||
if (as->use_cs_gpios)
|
if (spi->cs_gpiod)
|
||||||
gpiod_set_value(asd->npcs_pin, 1);
|
gpiod_set_value(spi->cs_gpiod, 1);
|
||||||
} else {
|
} else {
|
||||||
u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
|
u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
|
||||||
int i;
|
int i;
|
||||||
|
@ -389,9 +369,9 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
|
||||||
}
|
}
|
||||||
|
|
||||||
mr = spi_readl(as, MR);
|
mr = spi_readl(as, MR);
|
||||||
mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
|
mr = SPI_BFINS(PCS, ~(1 << chip_select), mr);
|
||||||
if (as->use_cs_gpios && spi->chip_select != 0)
|
if (spi->cs_gpiod)
|
||||||
gpiod_set_value(asd->npcs_pin, 1);
|
gpiod_set_value(spi->cs_gpiod, 1);
|
||||||
spi_writel(as, MR, mr);
|
spi_writel(as, MR, mr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,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)
|
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;
|
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
|
/* only deactivate *this* device; sometimes transfers to
|
||||||
* another device may be active when this routine is called.
|
* another device may be active when this routine is called.
|
||||||
*/
|
*/
|
||||||
mr = spi_readl(as, MR);
|
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);
|
mr = SPI_BFINS(PCS, 0xf, mr);
|
||||||
spi_writel(as, MR, mr);
|
spi_writel(as, MR, mr);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(&spi->dev, "DEactivate NPCS, mr %08x\n", 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));
|
spi_writel(as, CR, SPI_BIT(LASTXFER));
|
||||||
else if (atmel_spi_is_v2(as) || spi->chip_select != 0)
|
else
|
||||||
gpiod_set_value(asd->npcs_pin, 0);
|
gpiod_set_value(spi->cs_gpiod, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock)
|
static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock)
|
||||||
|
@ -526,7 +511,7 @@ static int atmel_spi_configure_dma(struct spi_master *master,
|
||||||
dma_cap_zero(mask);
|
dma_cap_zero(mask);
|
||||||
dma_cap_set(DMA_SLAVE, 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)) {
|
if (IS_ERR(master->dma_tx)) {
|
||||||
err = PTR_ERR(master->dma_tx);
|
err = PTR_ERR(master->dma_tx);
|
||||||
if (err == -EPROBE_DEFER) {
|
if (err == -EPROBE_DEFER) {
|
||||||
|
@ -843,6 +828,12 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
|
||||||
{
|
{
|
||||||
u32 scbr, csr;
|
u32 scbr, csr;
|
||||||
unsigned long bus_hz;
|
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. */
|
/* v1 chips start out at half the peripheral bus speed. */
|
||||||
bus_hz = as->spi_clk;
|
bus_hz = as->spi_clk;
|
||||||
|
@ -871,9 +862,9 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
|
||||||
xfer->speed_hz, scbr, bus_hz);
|
xfer->speed_hz, scbr, bus_hz);
|
||||||
return -EINVAL;
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1172,40 +1163,105 @@ atmel_spi_pdc_interrupt(int irq, void *dev_id)
|
||||||
return ret;
|
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)
|
static int atmel_spi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct atmel_spi *as;
|
struct atmel_spi *as;
|
||||||
struct atmel_spi_device *asd;
|
struct atmel_spi_device *asd;
|
||||||
u32 csr;
|
u32 csr;
|
||||||
unsigned int bits = spi->bits_per_word;
|
unsigned int bits = spi->bits_per_word;
|
||||||
|
int chip_select;
|
||||||
|
int word_delay_csr;
|
||||||
|
|
||||||
as = spi_master_get_devdata(spi->master);
|
as = spi_master_get_devdata(spi->master);
|
||||||
|
|
||||||
/* see notes above re chipselect */
|
/* see notes above re chipselect */
|
||||||
if (!atmel_spi_is_v2(as)
|
if (!spi->cs_gpiod && (spi->mode & SPI_CS_HIGH)) {
|
||||||
&& spi->chip_select == 0
|
dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n");
|
||||||
&& (spi->mode & SPI_CS_HIGH)) {
|
|
||||||
dev_dbg(&spi->dev, "setup: can't be active-high\n");
|
|
||||||
return -EINVAL;
|
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);
|
csr = SPI_BF(BITS, bits - 8);
|
||||||
if (spi->mode & SPI_CPOL)
|
if (spi->mode & SPI_CPOL)
|
||||||
csr |= SPI_BIT(CPOL);
|
csr |= SPI_BIT(CPOL);
|
||||||
if (!(spi->mode & SPI_CPHA))
|
if (!(spi->mode & SPI_CPHA))
|
||||||
csr |= SPI_BIT(NCPHA);
|
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);
|
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
|
/* DLYBCT adds delays between words. This is useful for slow devices
|
||||||
* that need a bit of time to setup the next transfer.
|
* that need a bit of time to setup the next transfer.
|
||||||
*/
|
*/
|
||||||
csr |= SPI_BF(DLYBCT,
|
csr |= SPI_BF(DLYBCT, word_delay_csr);
|
||||||
(as->spi_clk / 1000000 * spi->word_delay_usecs) >> 5);
|
|
||||||
|
|
||||||
asd = spi->controller_state;
|
asd = spi->controller_state;
|
||||||
if (!asd) {
|
if (!asd) {
|
||||||
|
@ -1213,21 +1269,6 @@ static int atmel_spi_setup(struct spi_device *spi)
|
||||||
if (!asd)
|
if (!asd)
|
||||||
return -ENOMEM;
|
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;
|
spi->controller_state = asd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1238,7 +1279,7 @@ static int atmel_spi_setup(struct spi_device *spi)
|
||||||
bits, spi->mode, spi->chip_select, csr);
|
bits, spi->mode, spi->chip_select, csr);
|
||||||
|
|
||||||
if (!atmel_spi_is_v2(as))
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1367,8 +1408,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||||
&& as->use_pdc)
|
&& as->use_pdc)
|
||||||
atmel_spi_dma_unmap_xfer(master, xfer);
|
atmel_spi_dma_unmap_xfer(master, xfer);
|
||||||
|
|
||||||
if (xfer->delay_usecs)
|
spi_transfer_delay_exec(xfer);
|
||||||
udelay(xfer->delay_usecs);
|
|
||||||
|
|
||||||
if (xfer->cs_change) {
|
if (xfer->cs_change) {
|
||||||
if (list_is_last(&xfer->transfer_list,
|
if (list_is_last(&xfer->transfer_list,
|
||||||
|
@ -1523,7 +1563,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
|
||||||
master->dev.of_node = pdev->dev.of_node;
|
master->dev.of_node = pdev->dev.of_node;
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = master->dev.of_node ? 0 : 4;
|
master->num_chipselect = 4;
|
||||||
master->setup = atmel_spi_setup;
|
master->setup = atmel_spi_setup;
|
||||||
master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
|
master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
|
||||||
master->transfer_one_message = atmel_spi_transfer_one_message;
|
master->transfer_one_message = atmel_spi_transfer_one_message;
|
||||||
|
@ -1551,19 +1591,6 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
atmel_get_caps(as);
|
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_dma = false;
|
||||||
as->use_pdc = false;
|
as->use_pdc = false;
|
||||||
if (as->caps.has_dma_support) {
|
if (as->caps.has_dma_support) {
|
||||||
|
@ -1771,20 +1798,18 @@ static const struct dev_pm_ops atmel_spi_pm_ops = {
|
||||||
#define ATMEL_SPI_PM_OPS NULL
|
#define ATMEL_SPI_PM_OPS NULL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_OF)
|
|
||||||
static const struct of_device_id atmel_spi_dt_ids[] = {
|
static const struct of_device_id atmel_spi_dt_ids[] = {
|
||||||
{ .compatible = "atmel,at91rm9200-spi" },
|
{ .compatible = "atmel,at91rm9200-spi" },
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
|
MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct platform_driver atmel_spi_driver = {
|
static struct platform_driver atmel_spi_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "atmel_spi",
|
.name = "atmel_spi",
|
||||||
.pm = ATMEL_SPI_PM_OPS,
|
.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,
|
.probe = atmel_spi_probe,
|
||||||
.remove = atmel_spi_remove,
|
.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,
|
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 spi_clk = clk_get_rate(spi_engine->ref_clk);
|
||||||
unsigned int t;
|
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)
|
if (delay == 0)
|
||||||
return;
|
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_cs(p, dry, spi, true);
|
||||||
|
|
||||||
spi_engine_gen_xfer(p, dry, xfer);
|
spi_engine_gen_xfer(p, dry, xfer);
|
||||||
spi_engine_gen_sleep(p, dry, spi_engine, clk_div,
|
spi_engine_gen_sleep(p, dry, spi_engine, clk_div, xfer);
|
||||||
xfer->delay_usecs);
|
|
||||||
|
|
||||||
cs_change = xfer->cs_change;
|
cs_change = xfer->cs_change;
|
||||||
if (list_is_last(&xfer->transfer_list, &msg->transfers))
|
if (list_is_last(&xfer->transfer_list, &msg->transfers))
|
||||||
|
|
|
@ -803,6 +803,7 @@ static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
from = op->addr.val;
|
from = op->addr.val;
|
||||||
|
if (!spi->cs_gpiod)
|
||||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||||
bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
|
bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
|
||||||
|
|
||||||
|
@ -882,6 +883,7 @@ static int bcm_qspi_transfer_one(struct spi_master *master,
|
||||||
int slots;
|
int slots;
|
||||||
unsigned long timeo = msecs_to_jiffies(100);
|
unsigned long timeo = msecs_to_jiffies(100);
|
||||||
|
|
||||||
|
if (!spi->cs_gpiod)
|
||||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||||
qspi->trans_pos.trans = trans;
|
qspi->trans_pos.trans = trans;
|
||||||
qspi->trans_pos.byte = 0;
|
qspi->trans_pos.byte = 0;
|
||||||
|
@ -1234,6 +1236,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
||||||
master->cleanup = bcm_qspi_cleanup;
|
master->cleanup = bcm_qspi_cleanup;
|
||||||
master->dev.of_node = dev->of_node;
|
master->dev.of_node = dev->of_node;
|
||||||
master->num_chipselect = NUM_CHIPSELECT;
|
master->num_chipselect = NUM_CHIPSELECT;
|
||||||
|
master->use_gpio_descriptors = true;
|
||||||
|
|
||||||
qspi->big_endian = of_device_is_big_endian(dev->of_node);
|
qspi->big_endian = of_device_is_big_endian(dev->of_node);
|
||||||
|
|
||||||
|
|
|
@ -291,8 +291,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
|
||||||
|
|
||||||
msg->actual_length += t->len;
|
msg->actual_length += t->len;
|
||||||
|
|
||||||
if (t->delay_usecs)
|
spi_transfer_delay_exec(t);
|
||||||
udelay(t->delay_usecs);
|
|
||||||
|
|
||||||
if (t->cs_change)
|
if (t->cs_change)
|
||||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
|
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 */
|
/* 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");
|
dev_err(&spi->dev, "unable to keep CS asserted after transfer\n");
|
||||||
status = -EINVAL;
|
status = -EINVAL;
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
|
@ -119,8 +119,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
|
||||||
*rx_buf++ = (u8)v;
|
*rx_buf++ = (u8)v;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xfer->delay_usecs)
|
spi_transfer_delay_exec(xfer);
|
||||||
udelay(xfer->delay_usecs);
|
|
||||||
|
|
||||||
return xfer->len;
|
return xfer->len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,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,ocelot-spi", .data = dw_spi_mscc_ocelot_init},
|
||||||
{ .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
|
{ .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
|
||||||
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
|
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
|
||||||
|
{ .compatible = "renesas,rzn1-spi", },
|
||||||
{ /* end of table */}
|
{ /* end of table */}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/module.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 = {
|
static struct spi_pci_desc spi_pci_ehl_desc = {
|
||||||
.num_cs = 1,
|
.num_cs = 2,
|
||||||
.bus_num = -1,
|
.bus_num = -1,
|
||||||
.max_freq = 100000000,
|
.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 */
|
/* Get basic io resource and map it */
|
||||||
dws->paddr = pci_resource_start(pdev, pci_bar);
|
dws->paddr = pci_resource_start(pdev, pci_bar);
|
||||||
|
pci_set_master(pdev);
|
||||||
|
|
||||||
ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev));
|
ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev));
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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->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,
|
* 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;
|
return ret;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
pci_free_irq_vectors(pdev);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dw_spi_add_host(&pdev->dev, dws);
|
ret = dw_spi_add_host(&pdev->dev, dws);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
pci_free_irq_vectors(pdev);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* PCI hook and SPI hook use the same drv data */
|
/* PCI hook and SPI hook use the same drv data */
|
||||||
pci_set_drvdata(pdev, dws);
|
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",
|
dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n",
|
||||||
pdev->vendor, pdev->device);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +114,11 @@ static void spi_pci_remove(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct dw_spi *dws = pci_get_drvdata(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);
|
dw_spi_remove_host(dws);
|
||||||
|
pci_free_irq_vectors(pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
|
|
@ -494,6 +494,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||||
master->dev.of_node = dev->of_node;
|
master->dev.of_node = dev->of_node;
|
||||||
master->dev.fwnode = dev->fwnode;
|
master->dev.fwnode = dev->fwnode;
|
||||||
master->flags = SPI_MASTER_GPIO_SS;
|
master->flags = SPI_MASTER_GPIO_SS;
|
||||||
|
master->auto_runtime_pm = true;
|
||||||
|
|
||||||
if (dws->set_cs)
|
if (dws->set_cs)
|
||||||
master->set_cs = dws->set_cs;
|
master->set_cs = dws->set_cs;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/gpio.h>
|
|
||||||
|
|
||||||
/* Register offsets */
|
/* Register offsets */
|
||||||
#define DW_SPI_CTRL0 0x00
|
#define DW_SPI_CTRL0 0x00
|
||||||
|
|
|
@ -377,7 +377,7 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
|
||||||
|
|
||||||
m->actual_length += t->len;
|
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;
|
spi_flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,7 @@ enum dspi_trans_mode {
|
||||||
struct fsl_dspi_devtype_data {
|
struct fsl_dspi_devtype_data {
|
||||||
enum dspi_trans_mode trans_mode;
|
enum dspi_trans_mode trans_mode;
|
||||||
u8 max_clock_factor;
|
u8 max_clock_factor;
|
||||||
|
bool ptp_sts_supported;
|
||||||
bool xspi_mode;
|
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 = {
|
static const struct fsl_dspi_devtype_data ls1021a_v1_data = {
|
||||||
.trans_mode = DSPI_TCFQ_MODE,
|
.trans_mode = DSPI_TCFQ_MODE,
|
||||||
.max_clock_factor = 8,
|
.max_clock_factor = 8,
|
||||||
|
.ptp_sts_supported = true,
|
||||||
.xspi_mode = true,
|
.xspi_mode = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct fsl_dspi_devtype_data ls2085a_data = {
|
static const struct fsl_dspi_devtype_data ls2085a_data = {
|
||||||
.trans_mode = DSPI_TCFQ_MODE,
|
.trans_mode = DSPI_TCFQ_MODE,
|
||||||
.max_clock_factor = 8,
|
.max_clock_factor = 8,
|
||||||
|
.ptp_sts_supported = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct fsl_dspi_devtype_data coldfire_data = {
|
static const struct fsl_dspi_devtype_data coldfire_data = {
|
||||||
|
@ -654,6 +657,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
|
||||||
u16 spi_tcnt;
|
u16 spi_tcnt;
|
||||||
u32 spi_tcr;
|
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
|
/* Get transfer counter (in number of SPI transfers). It was
|
||||||
* reset to 0 when transfer(s) were started.
|
* reset to 0 when transfer(s) were started.
|
||||||
*/
|
*/
|
||||||
|
@ -672,6 +678,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
|
||||||
/* Success! */
|
/* Success! */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
|
||||||
|
dspi->tx, !dspi->irq);
|
||||||
|
|
||||||
if (trans_mode == DSPI_EOQ_MODE)
|
if (trans_mode == DSPI_EOQ_MODE)
|
||||||
dspi_eoq_write(dspi);
|
dspi_eoq_write(dspi);
|
||||||
else if (trans_mode == DSPI_TCFQ_MODE)
|
else if (trans_mode == DSPI_TCFQ_MODE)
|
||||||
|
@ -779,6 +788,9 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
|
||||||
SPI_FRAME_EBITS(transfer->bits_per_word) |
|
SPI_FRAME_EBITS(transfer->bits_per_word) |
|
||||||
SPI_CTARE_DTCP(1));
|
SPI_CTARE_DTCP(1));
|
||||||
|
|
||||||
|
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
|
||||||
|
dspi->tx, !dspi->irq);
|
||||||
|
|
||||||
trans_mode = dspi->devtype_data->trans_mode;
|
trans_mode = dspi->devtype_data->trans_mode;
|
||||||
switch (trans_mode) {
|
switch (trans_mode) {
|
||||||
case DSPI_EOQ_MODE:
|
case DSPI_EOQ_MODE:
|
||||||
|
@ -815,8 +827,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
|
||||||
dev_err(&dspi->pdev->dev,
|
dev_err(&dspi->pdev->dev,
|
||||||
"Waiting for transfer to complete failed!\n");
|
"Waiting for transfer to complete failed!\n");
|
||||||
|
|
||||||
if (transfer->delay_usecs)
|
spi_transfer_delay_exec(transfer);
|
||||||
udelay(transfer->delay_usecs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -1006,6 +1017,25 @@ static void dspi_init(struct fsl_dspi *dspi)
|
||||||
SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1));
|
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)
|
static int dspi_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
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->dev.of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
ctlr->cleanup = dspi_cleanup;
|
ctlr->cleanup = dspi_cleanup;
|
||||||
|
ctlr->slave_abort = dspi_slave_abort;
|
||||||
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
||||||
|
|
||||||
pdata = dev_get_platdata(&pdev->dev);
|
pdata = dev_get_platdata(&pdev->dev);
|
||||||
|
@ -1135,6 +1166,7 @@ static int dspi_probe(struct platform_device *pdev)
|
||||||
init_waitqueue_head(&dspi->waitq);
|
init_waitqueue_head(&dspi->waitq);
|
||||||
|
|
||||||
poll_mode:
|
poll_mode:
|
||||||
|
|
||||||
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
|
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
|
||||||
ret = dspi_request_dma(dspi, res->start);
|
ret = dspi_request_dma(dspi, res->start);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -1146,6 +1178,8 @@ poll_mode:
|
||||||
ctlr->max_speed_hz =
|
ctlr->max_speed_hz =
|
||||||
clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor;
|
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);
|
platform_set_drvdata(pdev, ctlr);
|
||||||
|
|
||||||
ret = spi_register_controller(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);
|
ret = fsl_espi_bufs(spi, trans);
|
||||||
|
|
||||||
if (trans->delay_usecs)
|
spi_transfer_delay_exec(trans);
|
||||||
udelay(trans->delay_usecs);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -437,6 +436,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
|
||||||
struct spi_message *m)
|
struct spi_message *m)
|
||||||
{
|
{
|
||||||
unsigned int delay_usecs = 0, rx_nbits = 0;
|
unsigned int delay_usecs = 0, rx_nbits = 0;
|
||||||
|
unsigned int delay_nsecs = 0, delay_nsecs1 = 0;
|
||||||
struct spi_transfer *t, trans = {};
|
struct spi_transfer *t, trans = {};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -445,8 +445,16 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||||
if (t->delay_usecs > delay_usecs)
|
if (t->delay_usecs) {
|
||||||
|
if (t->delay_usecs > delay_usecs) {
|
||||||
delay_usecs = t->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)
|
if (t->rx_nbits > rx_nbits)
|
||||||
rx_nbits = t->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.len = m->frame_length;
|
||||||
trans.speed_hz = t->speed_hz;
|
trans.speed_hz = t->speed_hz;
|
||||||
trans.bits_per_word = t->bits_per_word;
|
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;
|
trans.rx_nbits = rx_nbits;
|
||||||
|
|
||||||
if (trans.len)
|
if (trans.len)
|
||||||
|
|
|
@ -675,7 +675,7 @@ static int fsl_lpspi_dma_init(struct device *dev,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Prepare for TX DMA: */
|
/* 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)) {
|
if (IS_ERR(controller->dma_tx)) {
|
||||||
ret = PTR_ERR(controller->dma_tx);
|
ret = PTR_ERR(controller->dma_tx);
|
||||||
dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
|
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: */
|
/* 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)) {
|
if (IS_ERR(controller->dma_rx)) {
|
||||||
ret = PTR_ERR(controller->dma_rx);
|
ret = PTR_ERR(controller->dma_rx);
|
||||||
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
|
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
|
||||||
|
|
|
@ -68,6 +68,11 @@
|
||||||
#define QUADSPI_FLSHCR_TCSH_MASK GENMASK(11, 8)
|
#define QUADSPI_FLSHCR_TCSH_MASK GENMASK(11, 8)
|
||||||
#define QUADSPI_FLSHCR_TDH_MASK GENMASK(17, 16)
|
#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 0x1c
|
||||||
#define QUADSPI_BUF3CR_ALLMST_MASK BIT(31)
|
#define QUADSPI_BUF3CR_ALLMST_MASK BIT(31)
|
||||||
#define QUADSPI_BUF3CR_ADATSZ(x) ((x) << 8)
|
#define QUADSPI_BUF3CR_ADATSZ(x) ((x) << 8)
|
||||||
|
@ -195,6 +200,7 @@
|
||||||
struct fsl_qspi_devtype_data {
|
struct fsl_qspi_devtype_data {
|
||||||
unsigned int rxfifo;
|
unsigned int rxfifo;
|
||||||
unsigned int txfifo;
|
unsigned int txfifo;
|
||||||
|
int invalid_mstrid;
|
||||||
unsigned int ahb_buf_size;
|
unsigned int ahb_buf_size;
|
||||||
unsigned int quirks;
|
unsigned int quirks;
|
||||||
bool little_endian;
|
bool little_endian;
|
||||||
|
@ -203,6 +209,7 @@ struct fsl_qspi_devtype_data {
|
||||||
static const struct fsl_qspi_devtype_data vybrid_data = {
|
static const struct fsl_qspi_devtype_data vybrid_data = {
|
||||||
.rxfifo = SZ_128,
|
.rxfifo = SZ_128,
|
||||||
.txfifo = SZ_64,
|
.txfifo = SZ_64,
|
||||||
|
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||||
.ahb_buf_size = SZ_1K,
|
.ahb_buf_size = SZ_1K,
|
||||||
.quirks = QUADSPI_QUIRK_SWAP_ENDIAN,
|
.quirks = QUADSPI_QUIRK_SWAP_ENDIAN,
|
||||||
.little_endian = true,
|
.little_endian = true,
|
||||||
|
@ -211,6 +218,7 @@ static const struct fsl_qspi_devtype_data vybrid_data = {
|
||||||
static const struct fsl_qspi_devtype_data imx6sx_data = {
|
static const struct fsl_qspi_devtype_data imx6sx_data = {
|
||||||
.rxfifo = SZ_128,
|
.rxfifo = SZ_128,
|
||||||
.txfifo = SZ_512,
|
.txfifo = SZ_512,
|
||||||
|
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||||
.ahb_buf_size = SZ_1K,
|
.ahb_buf_size = SZ_1K,
|
||||||
.quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618,
|
.quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618,
|
||||||
.little_endian = true,
|
.little_endian = true,
|
||||||
|
@ -219,6 +227,7 @@ static const struct fsl_qspi_devtype_data imx6sx_data = {
|
||||||
static const struct fsl_qspi_devtype_data imx7d_data = {
|
static const struct fsl_qspi_devtype_data imx7d_data = {
|
||||||
.rxfifo = SZ_128,
|
.rxfifo = SZ_128,
|
||||||
.txfifo = SZ_512,
|
.txfifo = SZ_512,
|
||||||
|
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||||
.ahb_buf_size = SZ_1K,
|
.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,
|
QUADSPI_QUIRK_USE_TDH_SETTING,
|
||||||
|
@ -228,6 +237,7 @@ static const struct fsl_qspi_devtype_data imx7d_data = {
|
||||||
static const struct fsl_qspi_devtype_data imx6ul_data = {
|
static const struct fsl_qspi_devtype_data imx6ul_data = {
|
||||||
.rxfifo = SZ_128,
|
.rxfifo = SZ_128,
|
||||||
.txfifo = SZ_512,
|
.txfifo = SZ_512,
|
||||||
|
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||||
.ahb_buf_size = SZ_1K,
|
.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,
|
QUADSPI_QUIRK_USE_TDH_SETTING,
|
||||||
|
@ -237,6 +247,7 @@ static const struct fsl_qspi_devtype_data imx6ul_data = {
|
||||||
static const struct fsl_qspi_devtype_data ls1021a_data = {
|
static const struct fsl_qspi_devtype_data ls1021a_data = {
|
||||||
.rxfifo = SZ_128,
|
.rxfifo = SZ_128,
|
||||||
.txfifo = SZ_64,
|
.txfifo = SZ_64,
|
||||||
|
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||||
.ahb_buf_size = SZ_1K,
|
.ahb_buf_size = SZ_1K,
|
||||||
.quirks = 0,
|
.quirks = 0,
|
||||||
.little_endian = false,
|
.little_endian = false,
|
||||||
|
@ -246,6 +257,7 @@ static const struct fsl_qspi_devtype_data ls2080a_data = {
|
||||||
.rxfifo = SZ_128,
|
.rxfifo = SZ_128,
|
||||||
.txfifo = SZ_64,
|
.txfifo = SZ_64,
|
||||||
.ahb_buf_size = SZ_1K,
|
.ahb_buf_size = SZ_1K,
|
||||||
|
.invalid_mstrid = 0x0,
|
||||||
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_BASE_INTERNAL,
|
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_BASE_INTERNAL,
|
||||||
.little_endian = true,
|
.little_endian = true,
|
||||||
};
|
};
|
||||||
|
@ -633,6 +645,7 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
||||||
void __iomem *base = q->iobase;
|
void __iomem *base = q->iobase;
|
||||||
u32 addr_offset = 0;
|
u32 addr_offset = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
int invalid_mstrid = q->devtype_data->invalid_mstrid;
|
||||||
|
|
||||||
mutex_lock(&q->lock);
|
mutex_lock(&q->lock);
|
||||||
|
|
||||||
|
@ -656,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,
|
qspi_writel(q, QUADSPI_SPTRCLR_BFPTRC | QUADSPI_SPTRCLR_IPPTRC,
|
||||||
base + QUADSPI_SPTRCLR);
|
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);
|
fsl_qspi_prepare_lut(q, op);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -416,8 +416,7 @@ static int fsl_spi_do_one_msg(struct spi_master *master,
|
||||||
}
|
}
|
||||||
m->actual_length += t->len;
|
m->actual_length += t->len;
|
||||||
|
|
||||||
if (t->delay_usecs)
|
spi_transfer_delay_exec(t);
|
||||||
udelay(t->delay_usecs);
|
|
||||||
|
|
||||||
if (cs_change) {
|
if (cs_change) {
|
||||||
ndelay(nsecs);
|
ndelay(nsecs);
|
||||||
|
|
|
@ -362,9 +362,6 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
||||||
struct spi_gpio *spi_gpio;
|
struct spi_gpio *spi_gpio;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct spi_bitbang *bb;
|
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));
|
master = spi_alloc_master(dev, sizeof(*spi_gpio));
|
||||||
if (!master)
|
if (!master)
|
||||||
|
@ -376,7 +373,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (of_id)
|
if (pdev->dev.of_node)
|
||||||
status = spi_gpio_probe_dt(pdev, master);
|
status = spi_gpio_probe_dt(pdev, master);
|
||||||
else
|
else
|
||||||
status = spi_gpio_probe_pdata(pdev, master);
|
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);
|
dma_release_channel(spfi->tx_ch);
|
||||||
if (spfi->rx_ch)
|
if (spfi->rx_ch)
|
||||||
dma_release_channel(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");
|
dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n");
|
||||||
} else {
|
} else {
|
||||||
master->dma_tx = spfi->tx_ch;
|
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;
|
spi_imx->wml = spi_imx->devtype_data->fifo_size / 2;
|
||||||
|
|
||||||
/* Prepare for TX DMA: */
|
/* 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)) {
|
if (IS_ERR(master->dma_tx)) {
|
||||||
ret = PTR_ERR(master->dma_tx);
|
ret = PTR_ERR(master->dma_tx);
|
||||||
dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
|
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 : */
|
/* 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)) {
|
if (IS_ERR(master->dma_rx)) {
|
||||||
ret = PTR_ERR(master->dma_rx);
|
ret = PTR_ERR(master->dma_rx);
|
||||||
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
|
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 device *dev = &pdev->dev;
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct resource *res;
|
|
||||||
struct lantiq_ssc_spi *spi;
|
struct lantiq_ssc_spi *spi;
|
||||||
const struct lantiq_ssc_hwcfg *hwcfg;
|
const struct lantiq_ssc_hwcfg *hwcfg;
|
||||||
const struct of_device_id *match;
|
const struct of_device_id *match;
|
||||||
|
@ -812,12 +811,6 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
hwcfg = match->data;
|
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);
|
rx_irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME);
|
||||||
if (rx_irq < 0)
|
if (rx_irq < 0)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
@ -839,8 +832,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
||||||
spi->dev = dev;
|
spi->dev = dev;
|
||||||
spi->hwcfg = hwcfg;
|
spi->hwcfg = hwcfg;
|
||||||
platform_set_drvdata(pdev, spi);
|
platform_set_drvdata(pdev, spi);
|
||||||
|
spi->regbase = devm_platform_ioremap_resource(pdev, 0);
|
||||||
spi->regbase = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(spi->regbase)) {
|
if (IS_ERR(spi->regbase)) {
|
||||||
err = PTR_ERR(spi->regbase);
|
err = PTR_ERR(spi->regbase);
|
||||||
goto err_master_put;
|
goto err_master_put;
|
||||||
|
|
|
@ -298,12 +298,18 @@ static struct spi_test spi_tests[] = {
|
||||||
{
|
{
|
||||||
.tx_buf = TX(0),
|
.tx_buf = TX(0),
|
||||||
.rx_buf = RX(0),
|
.rx_buf = RX(0),
|
||||||
.delay_usecs = 1000,
|
.delay = {
|
||||||
|
.value = 1000,
|
||||||
|
.unit = SPI_DELAY_UNIT_USECS,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.tx_buf = TX(0),
|
.tx_buf = TX(0),
|
||||||
.rx_buf = RX(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 *
|
unsigned long long nbits = (unsigned long long)BITS_PER_BYTE *
|
||||||
xfer->len;
|
xfer->len;
|
||||||
|
|
||||||
delay_usecs += xfer->delay_usecs;
|
delay_usecs += xfer->delay.value;
|
||||||
if (!xfer->speed_hz)
|
if (!xfer->speed_hz)
|
||||||
continue;
|
continue;
|
||||||
estimated_time += div_u64(nbits * NSEC_PER_SEC, xfer->speed_hz);
|
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))
|
if (!spi_mem_internal_supports_op(mem, op))
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
|
|
||||||
if (ctlr->mem_ops) {
|
if (ctlr->mem_ops && !mem->spi->cs_gpiod) {
|
||||||
ret = spi_mem_access_start(mem);
|
ret = spi_mem_access_start(mem);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -311,8 +311,7 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
|
||||||
break;
|
break;
|
||||||
m->actual_length += t->len;
|
m->actual_length += t->len;
|
||||||
|
|
||||||
if (t->delay_usecs)
|
spi_transfer_delay_exec(t);
|
||||||
udelay(t->delay_usecs);
|
|
||||||
|
|
||||||
if (cs_change)
|
if (cs_change)
|
||||||
mpc512x_psc_spi_deactivate_cs(spi);
|
mpc512x_psc_spi_deactivate_cs(spi);
|
||||||
|
|
|
@ -234,8 +234,7 @@ static void mpc52xx_psc_spi_work(struct work_struct *work)
|
||||||
break;
|
break;
|
||||||
m->actual_length += t->len;
|
m->actual_length += t->len;
|
||||||
|
|
||||||
if (t->delay_usecs)
|
spi_transfer_delay_exec(t);
|
||||||
udelay(t->delay_usecs);
|
|
||||||
|
|
||||||
if (cs_change)
|
if (cs_change)
|
||||||
mpc52xx_psc_spi_deactivate_cs(spi);
|
mpc52xx_psc_spi_deactivate_cs(spi);
|
||||||
|
|
|
@ -139,7 +139,6 @@ static const struct mtk_spi_compatible mt8183_compat = {
|
||||||
* supplies it.
|
* supplies it.
|
||||||
*/
|
*/
|
||||||
static const struct mtk_chip_config mtk_default_chip_info = {
|
static const struct mtk_chip_config mtk_default_chip_info = {
|
||||||
.cs_pol = 0,
|
|
||||||
.sample_sel = 0,
|
.sample_sel = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -230,10 +229,12 @@ static int mtk_spi_prepare_message(struct spi_master *master,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mdata->dev_comp->enhance_timing) {
|
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;
|
reg_val |= SPI_CMD_CS_POL;
|
||||||
else
|
else
|
||||||
reg_val &= ~SPI_CMD_CS_POL;
|
reg_val &= ~SPI_CMD_CS_POL;
|
||||||
|
|
||||||
if (chip_config->sample_sel)
|
if (chip_config->sample_sel)
|
||||||
reg_val |= SPI_CMD_SAMPLE_SEL;
|
reg_val |= SPI_CMD_SAMPLE_SEL;
|
||||||
else
|
else
|
||||||
|
@ -264,6 +265,9 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
|
||||||
u32 reg_val;
|
u32 reg_val;
|
||||||
struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
|
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);
|
reg_val = readl(mdata->base + SPI_CMD_REG);
|
||||||
if (!enable) {
|
if (!enable) {
|
||||||
reg_val |= SPI_CMD_PAUSE_EN;
|
reg_val |= SPI_CMD_PAUSE_EN;
|
||||||
|
@ -619,7 +623,6 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct mtk_spi *mdata;
|
struct mtk_spi *mdata;
|
||||||
const struct of_device_id *of_id;
|
const struct of_device_id *of_id;
|
||||||
struct resource *res;
|
|
||||||
int i, irq, ret, addr_bits;
|
int i, irq, ret, addr_bits;
|
||||||
|
|
||||||
master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
|
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 = spi_master_get_devdata(master);
|
||||||
mdata->dev_comp = of_id->data;
|
mdata->dev_comp = of_id->data;
|
||||||
|
|
||||||
|
if (mdata->dev_comp->enhance_timing)
|
||||||
|
master->mode_bits |= SPI_CS_HIGH;
|
||||||
|
|
||||||
if (mdata->dev_comp->must_tx)
|
if (mdata->dev_comp->must_tx)
|
||||||
master->flags = SPI_MASTER_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);
|
platform_set_drvdata(pdev, master);
|
||||||
|
mdata->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
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);
|
|
||||||
if (IS_ERR(mdata->base)) {
|
if (IS_ERR(mdata->base)) {
|
||||||
ret = PTR_ERR(mdata->base);
|
ret = PTR_ERR(mdata->base);
|
||||||
goto err_put_master;
|
goto err_put_master;
|
||||||
|
|
|
@ -346,7 +346,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
|
||||||
if (op->addr.nbytes > 7)
|
if (op->addr.nbytes > 7)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return spi_mem_default_supports_op(mem, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mxic_spi_mem_exec_op(struct spi_mem *mem,
|
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)
|
static irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct npcm_pspi *priv = dev_id;
|
struct npcm_pspi *priv = dev_id;
|
||||||
u16 val;
|
|
||||||
u8 stat;
|
u8 stat;
|
||||||
|
|
||||||
stat = ioread8(priv->base + NPCM_PSPI_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 (priv->tx_buf) {
|
||||||
if (stat & NPCM_PSPI_STAT_RBF) {
|
if (stat & NPCM_PSPI_STAT_RBF) {
|
||||||
val = ioread8(NPCM_PSPI_DATA + priv->base);
|
ioread8(NPCM_PSPI_DATA + priv->base);
|
||||||
if (priv->tx_bytes == 0) {
|
if (priv->tx_bytes == 0) {
|
||||||
npcm_pspi_disable(priv);
|
npcm_pspi_disable(priv);
|
||||||
complete(&priv->xfer_done);
|
complete(&priv->xfer_done);
|
||||||
|
|
|
@ -1027,7 +1027,7 @@ static int nxp_fspi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ctlr->dev.of_node = np;
|
ctlr->dev.of_node = np;
|
||||||
|
|
||||||
ret = spi_register_controller(ctlr);
|
ret = devm_spi_register_controller(&pdev->dev, ctlr);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_destroy_mutex;
|
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)
|
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);
|
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||||
|
|
||||||
/* Always do at least 16 bits */
|
/* Always do at least 16 bits */
|
||||||
|
@ -146,7 +146,7 @@ static int spi100k_read_data(struct spi_master *master, int len)
|
||||||
udelay(1000);
|
udelay(1000);
|
||||||
|
|
||||||
dataL = readw(spi100k->base + SPI_RX_LSB);
|
dataL = readw(spi100k->base + SPI_RX_LSB);
|
||||||
dataH = readw(spi100k->base + SPI_RX_MSB);
|
readw(spi100k->base + SPI_RX_MSB);
|
||||||
spi100k_disable_clock(master);
|
spi100k_disable_clock(master);
|
||||||
|
|
||||||
return dataL;
|
return dataL;
|
||||||
|
@ -321,8 +321,7 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->delay_usecs)
|
spi_transfer_delay_exec(t);
|
||||||
udelay(t->delay_usecs);
|
|
||||||
|
|
||||||
/* ignore the "leave it on after last xfer" hint */
|
/* ignore the "leave it on after last xfer" hint */
|
||||||
|
|
||||||
|
|
|
@ -397,13 +397,11 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
|
||||||
{
|
{
|
||||||
struct omap2_mcspi *mcspi;
|
struct omap2_mcspi *mcspi;
|
||||||
struct omap2_mcspi_dma *mcspi_dma;
|
struct omap2_mcspi_dma *mcspi_dma;
|
||||||
|
struct dma_async_tx_descriptor *tx;
|
||||||
|
|
||||||
mcspi = spi_master_get_devdata(spi->master);
|
mcspi = spi_master_get_devdata(spi->master);
|
||||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
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,
|
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
|
||||||
|
@ -417,10 +415,8 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
|
||||||
} else {
|
} else {
|
||||||
/* FIXME: fall back to PIO? */
|
/* FIXME: fall back to PIO? */
|
||||||
}
|
}
|
||||||
}
|
|
||||||
dma_async_issue_pending(mcspi_dma->dma_tx);
|
dma_async_issue_pending(mcspi_dma->dma_tx);
|
||||||
omap2_mcspi_set_dma_req(spi, 0, 1);
|
omap2_mcspi_set_dma_req(spi, 0, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
|
@ -439,6 +435,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
int word_len, element_count;
|
int word_len, element_count;
|
||||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||||
void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
||||||
|
struct dma_async_tx_descriptor *tx;
|
||||||
|
|
||||||
mcspi = spi_master_get_devdata(spi->master);
|
mcspi = spi_master_get_devdata(spi->master);
|
||||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||||
|
@ -462,8 +459,6 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
else /* word_len <= 32 */
|
else /* word_len <= 32 */
|
||||||
element_count = count >> 2;
|
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);
|
||||||
|
|
||||||
|
@ -488,21 +483,16 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
nb_sizes = 1;
|
nb_sizes = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents,
|
ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, 0, nb_sizes,
|
||||||
0, nb_sizes,
|
sizes, sg_out, out_mapped_nents, GFP_KERNEL);
|
||||||
sizes,
|
|
||||||
sg_out, out_mapped_nents,
|
|
||||||
GFP_KERNEL);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&spi->dev, "sg_split failed\n");
|
dev_err(&spi->dev, "sg_split failed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx,
|
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, sg_out[0],
|
||||||
sg_out[0],
|
out_mapped_nents[0], DMA_DEV_TO_MEM,
|
||||||
out_mapped_nents[0],
|
|
||||||
DMA_DEV_TO_MEM,
|
|
||||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||||
if (tx) {
|
if (tx) {
|
||||||
tx->callback = omap2_mcspi_rx_callback;
|
tx->callback = omap2_mcspi_rx_callback;
|
||||||
|
@ -511,7 +501,6 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
} else {
|
} else {
|
||||||
/* FIXME: fall back to PIO? */
|
/* FIXME: fall back to PIO? */
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
dma_async_issue_pending(mcspi_dma->dma_rx);
|
dma_async_issue_pending(mcspi_dma->dma_rx);
|
||||||
omap2_mcspi_set_dma_req(spi, 1, 1);
|
omap2_mcspi_set_dma_req(spi, 1, 1);
|
||||||
|
|
|
@ -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)
|
if (orion_spi_write_read_8bit(spi, &tx, &rx) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
count--;
|
count--;
|
||||||
if (xfer->word_delay_usecs)
|
spi_delay_exec(&xfer->word_delay, xfer);
|
||||||
udelay(xfer->word_delay_usecs);
|
|
||||||
} while (count);
|
} while (count);
|
||||||
} else if (word_len == 16) {
|
} else if (word_len == 16) {
|
||||||
const u16 *tx = xfer->tx_buf;
|
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)
|
if (orion_spi_write_read_16bit(spi, &tx, &rx) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
count -= 2;
|
count -= 2;
|
||||||
if (xfer->word_delay_usecs)
|
spi_delay_exec(&xfer->word_delay, xfer);
|
||||||
udelay(xfer->word_delay_usecs);
|
|
||||||
} while (count);
|
} while (count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -606,25 +606,30 @@ static void pic32_spi_cleanup(struct spi_device *spi)
|
||||||
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
|
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;
|
struct spi_master *master = pic32s->master;
|
||||||
dma_cap_mask_t mask;
|
int ret = 0;
|
||||||
|
|
||||||
dma_cap_zero(mask);
|
master->dma_rx = dma_request_chan(dev, "spi-rx");
|
||||||
dma_cap_set(DMA_SLAVE, mask);
|
if (IS_ERR(master->dma_rx)) {
|
||||||
|
if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER)
|
||||||
master->dma_rx = dma_request_slave_channel_compat(mask, NULL, NULL,
|
ret = -EPROBE_DEFER;
|
||||||
dev, "spi-rx");
|
else
|
||||||
if (!master->dma_rx) {
|
|
||||||
dev_warn(dev, "RX channel not found.\n");
|
dev_warn(dev, "RX channel not found.\n");
|
||||||
|
|
||||||
|
master->dma_rx = NULL;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
master->dma_tx = dma_request_slave_channel_compat(mask, NULL, NULL,
|
master->dma_tx = dma_request_chan(dev, "spi-tx");
|
||||||
dev, "spi-tx");
|
if (IS_ERR(master->dma_tx)) {
|
||||||
if (!master->dma_tx) {
|
if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER)
|
||||||
|
ret = -EPROBE_DEFER;
|
||||||
|
else
|
||||||
dev_warn(dev, "TX channel not found.\n");
|
dev_warn(dev, "TX channel not found.\n");
|
||||||
|
|
||||||
|
master->dma_tx = NULL;
|
||||||
goto out_err;
|
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 */
|
/* DMA chnls allocated and prepared */
|
||||||
set_bit(PIC32F_DMA_PREP, &pic32s->flags);
|
set_bit(PIC32F_DMA_PREP, &pic32s->flags);
|
||||||
|
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
if (master->dma_rx)
|
if (master->dma_rx) {
|
||||||
dma_release_channel(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);
|
dma_release_channel(master->dma_tx);
|
||||||
|
master->dma_tx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pic32_spi_dma_unprep(struct pic32_spi *pic32s)
|
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;
|
master->unprepare_transfer_hardware = pic32_spi_unprepare_hardware;
|
||||||
|
|
||||||
/* optional DMA support */
|
/* 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))
|
if (test_bit(PIC32F_DMA_PREP, &pic32s->flags))
|
||||||
master->can_dma = pic32_spi_can_dma;
|
master->can_dma = pic32_spi_can_dma;
|
||||||
|
|
||||||
|
|
|
@ -485,12 +485,11 @@ static void giveback(struct pl022 *pl022)
|
||||||
struct spi_transfer, transfer_list);
|
struct spi_transfer, transfer_list);
|
||||||
|
|
||||||
/* Delay if requested before any change in chip select */
|
/* Delay if requested before any change in chip select */
|
||||||
if (last_transfer->delay_usecs)
|
|
||||||
/*
|
/*
|
||||||
* FIXME: This runs in interrupt context.
|
* FIXME: This runs in interrupt context.
|
||||||
* Is this really smart?
|
* Is this really smart?
|
||||||
*/
|
*/
|
||||||
udelay(last_transfer->delay_usecs);
|
spi_transfer_delay_exec(last_transfer);
|
||||||
|
|
||||||
if (!last_transfer->cs_change) {
|
if (!last_transfer->cs_change) {
|
||||||
struct spi_message *next_msg;
|
struct spi_message *next_msg;
|
||||||
|
@ -1159,7 +1158,7 @@ static int pl022_dma_autoprobe(struct pl022 *pl022)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* automatically configure DMA channels from platform, normally using DT */
|
/* 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)) {
|
if (IS_ERR(chan)) {
|
||||||
err = PTR_ERR(chan);
|
err = PTR_ERR(chan);
|
||||||
goto err_no_rxchan;
|
goto err_no_rxchan;
|
||||||
|
@ -1167,7 +1166,7 @@ static int pl022_dma_autoprobe(struct pl022 *pl022)
|
||||||
|
|
||||||
pl022->dma_rx_channel = chan;
|
pl022->dma_rx_channel = chan;
|
||||||
|
|
||||||
chan = dma_request_slave_channel_reason(dev, "tx");
|
chan = dma_request_chan(dev, "tx");
|
||||||
if (IS_ERR(chan)) {
|
if (IS_ERR(chan)) {
|
||||||
err = PTR_ERR(chan);
|
err = PTR_ERR(chan);
|
||||||
goto err_no_txchan;
|
goto err_no_txchan;
|
||||||
|
@ -1401,12 +1400,11 @@ static void pump_transfers(unsigned long data)
|
||||||
previous = list_entry(transfer->transfer_list.prev,
|
previous = list_entry(transfer->transfer_list.prev,
|
||||||
struct spi_transfer,
|
struct spi_transfer,
|
||||||
transfer_list);
|
transfer_list);
|
||||||
if (previous->delay_usecs)
|
|
||||||
/*
|
/*
|
||||||
* FIXME: This runs in interrupt context.
|
* FIXME: This runs in interrupt context.
|
||||||
* Is this really smart?
|
* Is this really smart?
|
||||||
*/
|
*/
|
||||||
udelay(previous->delay_usecs);
|
spi_transfer_delay_exec(previous);
|
||||||
|
|
||||||
/* Reselect chip select only if cs_change was requested */
|
/* Reselect chip select only if cs_change was requested */
|
||||||
if (previous->cs_change)
|
if (previous->cs_change)
|
||||||
|
@ -1520,8 +1518,7 @@ static void do_polling_transfer(struct pl022 *pl022)
|
||||||
previous =
|
previous =
|
||||||
list_entry(transfer->transfer_list.prev,
|
list_entry(transfer->transfer_list.prev,
|
||||||
struct spi_transfer, transfer_list);
|
struct spi_transfer, transfer_list);
|
||||||
if (previous->delay_usecs)
|
spi_transfer_delay_exec(previous);
|
||||||
udelay(previous->delay_usecs);
|
|
||||||
if (previous->cs_change)
|
if (previous->cs_change)
|
||||||
pl022_cs_control(pl022, SSP_CHIP_SELECT);
|
pl022_cs_control(pl022, SSP_CHIP_SELECT);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -4,27 +4,29 @@
|
||||||
* Copyright (C) 2013, Intel Corporation
|
* Copyright (C) 2013, Intel Corporation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/init.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/module.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/ioport.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/err.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/interrupt.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
|
#include <linux/of.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/platform_device.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/pxa2xx_spi.h>
|
||||||
#include <linux/spi/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"
|
#include "spi-pxa2xx.h"
|
||||||
|
|
||||||
|
@ -1480,11 +1482,13 @@ MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match);
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#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;
|
unsigned int devid;
|
||||||
int port_id = -1;
|
int port_id = -1;
|
||||||
|
|
||||||
|
adev = ACPI_COMPANION(dev);
|
||||||
if (adev && adev->pnp.unique_id &&
|
if (adev && adev->pnp.unique_id &&
|
||||||
!kstrtouint(adev->pnp.unique_id, 0, &devid))
|
!kstrtouint(adev->pnp.unique_id, 0, &devid))
|
||||||
port_id = devid;
|
port_id = devid;
|
||||||
|
@ -1493,7 +1497,7 @@ static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
|
||||||
|
|
||||||
#else /* !CONFIG_ACPI */
|
#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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1514,34 +1518,22 @@ static struct pxa2xx_spi_controller *
|
||||||
pxa2xx_spi_init_pdata(struct platform_device *pdev)
|
pxa2xx_spi_init_pdata(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct pxa2xx_spi_controller *pdata;
|
struct pxa2xx_spi_controller *pdata;
|
||||||
struct acpi_device *adev;
|
|
||||||
struct ssp_device *ssp;
|
struct ssp_device *ssp;
|
||||||
struct resource *res;
|
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 pci_device_id *pcidev_id = NULL;
|
||||||
const struct of_device_id *of_id = NULL;
|
|
||||||
enum pxa_ssp_type type;
|
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)
|
match = device_get_match_data(&pdev->dev);
|
||||||
of_id = of_match_device(pdev->dev.driver->of_match_table,
|
if (match)
|
||||||
&pdev->dev);
|
type = (enum pxa_ssp_type)match;
|
||||||
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;
|
|
||||||
else if (pcidev_id)
|
else if (pcidev_id)
|
||||||
type = (enum pxa_ssp_type)pcidev_id->driver_data;
|
type = (enum pxa_ssp_type)pcidev_id->driver_data;
|
||||||
else if (of_id)
|
|
||||||
type = (enum pxa_ssp_type)of_id->data;
|
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1560,19 +1552,25 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
|
||||||
|
|
||||||
#ifdef CONFIG_PCI
|
#ifdef CONFIG_PCI
|
||||||
if (pcidev_id) {
|
if (pcidev_id) {
|
||||||
pdata->tx_param = pdev->dev.parent;
|
pdata->tx_param = parent;
|
||||||
pdata->rx_param = pdev->dev.parent;
|
pdata->rx_param = parent;
|
||||||
pdata->dma_filter = pxa2xx_spi_idma_filter;
|
pdata->dma_filter = pxa2xx_spi_idma_filter;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ssp->clk = devm_clk_get(&pdev->dev, NULL);
|
ssp->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
ssp->irq = platform_get_irq(pdev, 0);
|
if (IS_ERR(ssp->clk))
|
||||||
ssp->type = type;
|
return NULL;
|
||||||
ssp->pdev = pdev;
|
|
||||||
ssp->port_id = pxa2xx_spi_get_port_id(adev);
|
|
||||||
|
|
||||||
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->num_chipselect = 1;
|
||||||
pdata->enable_dma = true;
|
pdata->enable_dma = true;
|
||||||
pdata->dma_burst_size = 1;
|
pdata->dma_burst_size = 1;
|
||||||
|
|
|
@ -932,11 +932,11 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* allocate dma resources, if available */
|
/* 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))
|
if (IS_ERR(master->dma_rx))
|
||||||
return PTR_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)) {
|
if (IS_ERR(master->dma_tx)) {
|
||||||
ret = PTR_ERR(master->dma_tx);
|
ret = PTR_ERR(master->dma_tx);
|
||||||
goto err_tx;
|
goto err_tx;
|
||||||
|
|
|
@ -1154,15 +1154,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
if (!is_polling(sdd)) {
|
if (!is_polling(sdd)) {
|
||||||
/* Acquire DMA channels */
|
/* Acquire DMA channels */
|
||||||
sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
|
sdd->rx_dma.ch = dma_request_chan(&pdev->dev, "rx");
|
||||||
"rx");
|
|
||||||
if (IS_ERR(sdd->rx_dma.ch)) {
|
if (IS_ERR(sdd->rx_dma.ch)) {
|
||||||
dev_err(&pdev->dev, "Failed to get RX DMA channel\n");
|
dev_err(&pdev->dev, "Failed to get RX DMA channel\n");
|
||||||
ret = PTR_ERR(sdd->rx_dma.ch);
|
ret = PTR_ERR(sdd->rx_dma.ch);
|
||||||
goto err_disable_io_clk;
|
goto err_disable_io_clk;
|
||||||
}
|
}
|
||||||
sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
|
sdd->tx_dma.ch = dma_request_chan(&pdev->dev, "tx");
|
||||||
"tx");
|
|
||||||
if (IS_ERR(sdd->tx_dma.ch)) {
|
if (IS_ERR(sdd->tx_dma.ch)) {
|
||||||
dev_err(&pdev->dev, "Failed to get TX DMA channel\n");
|
dev_err(&pdev->dev, "Failed to get TX DMA channel\n");
|
||||||
ret = PTR_ERR(sdd->tx_dma.ch);
|
ret = PTR_ERR(sdd->tx_dma.ch);
|
||||||
|
|
|
@ -211,8 +211,7 @@ static int sc18is602_transfer_one(struct spi_master *master,
|
||||||
}
|
}
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
if (t->delay_usecs)
|
spi_transfer_delay_exec(t);
|
||||||
udelay(t->delay_usecs);
|
|
||||||
}
|
}
|
||||||
m->status = status;
|
m->status = status;
|
||||||
spi_finalize_current_message(master);
|
spi_finalize_current_message(master);
|
||||||
|
|
|
@ -190,8 +190,7 @@ static int hspi_transfer_one_message(struct spi_controller *ctlr,
|
||||||
|
|
||||||
msg->actual_length += t->len;
|
msg->actual_length += t->len;
|
||||||
|
|
||||||
if (t->delay_usecs)
|
spi_transfer_delay_exec(t);
|
||||||
udelay(t->delay_usecs);
|
|
||||||
|
|
||||||
if (cs_change) {
|
if (cs_change) {
|
||||||
ndelay(nsecs);
|
ndelay(nsecs);
|
||||||
|
|
|
@ -368,7 +368,6 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct spi_controller *ctlr;
|
struct spi_controller *ctlr;
|
||||||
struct mtk_spi_slave *mdata;
|
struct mtk_spi_slave *mdata;
|
||||||
struct resource *res;
|
|
||||||
int irq, ret;
|
int irq, ret;
|
||||||
|
|
||||||
ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata));
|
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);
|
platform_set_drvdata(pdev, ctlr);
|
||||||
|
|
||||||
init_completion(&mdata->xfer_done);
|
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->dev = &pdev->dev;
|
||||||
|
mdata->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
mdata->base = devm_ioremap_resource(&pdev->dev, res);
|
|
||||||
if (IS_ERR(mdata->base)) {
|
if (IS_ERR(mdata->base)) {
|
||||||
ret = PTR_ERR(mdata->base);
|
ret = PTR_ERR(mdata->base);
|
||||||
goto err_put_ctlr;
|
goto err_put_ctlr;
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
|
|
||||||
/* Bits definitions for register REG_WDG_CTRL */
|
/* Bits definitions for register REG_WDG_CTRL */
|
||||||
#define BIT_WDG_RUN BIT(1)
|
#define BIT_WDG_RUN BIT(1)
|
||||||
|
#define BIT_WDG_NEW BIT(2)
|
||||||
#define BIT_WDG_RST BIT(3)
|
#define BIT_WDG_RST BIT(3)
|
||||||
|
|
||||||
/* Registers definitions for PMIC */
|
/* Registers definitions for PMIC */
|
||||||
|
@ -383,6 +384,10 @@ static int sprd_adi_restart_handler(struct notifier_block *this,
|
||||||
/* Unlock the watchdog */
|
/* Unlock the watchdog */
|
||||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, WDG_UNLOCK_KEY);
|
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. */
|
/* Load the watchdog timeout value, 50ms is always enough. */
|
||||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_LOW,
|
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_LOW,
|
||||||
WDG_LOAD_VAL & WDG_LOAD_MASK);
|
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;
|
val |= BIT_WDG_RUN | BIT_WDG_RST;
|
||||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val);
|
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);
|
mdelay(1000);
|
||||||
|
|
||||||
dev_emerg(sadi->dev, "Unable to restart system\n");
|
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);
|
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;
|
u16 word_delay, interval;
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
|
if (d->unit != SPI_DELAY_UNIT_SCK)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
val = readl_relaxed(ss->base + SPRD_SPI_CTL7);
|
val = readl_relaxed(ss->base + SPRD_SPI_CTL7);
|
||||||
val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX);
|
val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX);
|
||||||
/* Set default chip selection, clock phase and clock polarity */
|
/* 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:
|
* formula as below per datasheet:
|
||||||
* interval time (source clock cycles) = interval * 4 + 10.
|
* 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);
|
SPRD_SPI_MAX_DELAY_CYCLE);
|
||||||
interval = DIV_ROUND_UP(word_delay - 10, 4);
|
interval = DIV_ROUND_UP(word_delay - 10, 4);
|
||||||
ss->word_delay = interval * 4 + 10;
|
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;
|
val &= ~SPRD_SPI_DATA_LINE2_EN;
|
||||||
|
|
||||||
writel_relaxed(val, ss->base + SPRD_SPI_CTL7);
|
writel_relaxed(val, ss->base + SPRD_SPI_CTL7);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sprd_spi_setup_transfer(struct spi_device *sdev,
|
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);
|
struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller);
|
||||||
u8 bits_per_word = t->bits_per_word;
|
u8 bits_per_word = t->bits_per_word;
|
||||||
u32 val, mode = 0;
|
u32 val, mode = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
ss->len = t->len;
|
ss->len = t->len;
|
||||||
ss->tx_buf = t->tx_buf;
|
ss->tx_buf = t->tx_buf;
|
||||||
ss->rx_buf = t->rx_buf;
|
ss->rx_buf = t->rx_buf;
|
||||||
|
|
||||||
ss->hw_mode = sdev->mode;
|
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 */
|
/* Set tansfer speed and valid bits */
|
||||||
sprd_spi_set_speed(ss, t->speed_hz);
|
sprd_spi_set_speed(ss, t->speed_hz);
|
||||||
|
|
|
@ -381,6 +381,7 @@ static int spi_st_probe(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
clk_disable:
|
clk_disable:
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
clk_disable_unprepare(spi_st->clk);
|
clk_disable_unprepare(spi_st->clk);
|
||||||
put_master:
|
put_master:
|
||||||
spi_master_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_master *master = platform_get_drvdata(pdev);
|
||||||
struct spi_st *spi_st = spi_master_get_devdata(master);
|
struct spi_st *spi_st = spi_master_get_devdata(master);
|
||||||
|
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
clk_disable_unprepare(spi_st->clk);
|
clk_disable_unprepare(spi_st->clk);
|
||||||
|
|
||||||
pinctrl_pm_select_sleep_state(&pdev->dev);
|
pinctrl_pm_select_sleep_state(&pdev->dev);
|
||||||
|
|
|
@ -666,8 +666,7 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi,
|
||||||
dma_addr_t dma_phys;
|
dma_addr_t dma_phys;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dma_chan = dma_request_slave_channel_reason(tspi->dev,
|
dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx");
|
||||||
dma_to_memory ? "rx" : "tx");
|
|
||||||
if (IS_ERR(dma_chan)) {
|
if (IS_ERR(dma_chan)) {
|
||||||
ret = PTR_ERR(dma_chan);
|
ret = PTR_ERR(dma_chan);
|
||||||
if (ret != -EPROBE_DEFER)
|
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);
|
dma_release_channel(dma_chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly,
|
static int tegra_spi_set_hw_cs_timing(struct spi_device *spi,
|
||||||
u8 hold_dly, u8 inactive_dly)
|
struct spi_delay *setup,
|
||||||
|
struct spi_delay *hold,
|
||||||
|
struct spi_delay *inactive)
|
||||||
{
|
{
|
||||||
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
||||||
|
u8 setup_dly, hold_dly, inactive_dly;
|
||||||
u32 setup_hold;
|
u32 setup_hold;
|
||||||
u32 spi_cs_timing;
|
u32 spi_cs_timing;
|
||||||
u32 inactive_cycles;
|
u32 inactive_cycles;
|
||||||
u8 cs_state;
|
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);
|
setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
|
||||||
hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
|
hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
|
||||||
if (setup_dly && hold_dly) {
|
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;
|
tspi->spi_cs_timing2 = spi_cs_timing;
|
||||||
tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2);
|
tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
|
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;
|
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)
|
static void tegra_spi_transfer_end(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
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:
|
complete_xfer:
|
||||||
if (ret < 0 || skip) {
|
if (ret < 0 || skip) {
|
||||||
tegra_spi_transfer_end(spi);
|
tegra_spi_transfer_end(spi);
|
||||||
tegra_spi_transfer_delay(xfer->delay_usecs);
|
spi_transfer_delay_exec(xfer);
|
||||||
goto exit;
|
goto exit;
|
||||||
} else if (list_is_last(&xfer->transfer_list,
|
} else if (list_is_last(&xfer->transfer_list,
|
||||||
&msg->transfers)) {
|
&msg->transfers)) {
|
||||||
|
@ -1106,11 +1112,11 @@ complete_xfer:
|
||||||
tspi->cs_control = spi;
|
tspi->cs_control = spi;
|
||||||
else {
|
else {
|
||||||
tegra_spi_transfer_end(spi);
|
tegra_spi_transfer_end(spi);
|
||||||
tegra_spi_transfer_delay(xfer->delay_usecs);
|
spi_transfer_delay_exec(xfer);
|
||||||
}
|
}
|
||||||
} else if (xfer->cs_change) {
|
} else if (xfer->cs_change) {
|
||||||
tegra_spi_transfer_end(spi);
|
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;
|
goto exit;
|
||||||
}
|
}
|
||||||
msg->actual_length += xfer->len;
|
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,
|
tegra_sflash_writel(tsd, tsd->def_command_reg,
|
||||||
SPI_COMMAND);
|
SPI_COMMAND);
|
||||||
udelay(xfer->delay_usecs);
|
spi_transfer_delay_exec(xfer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
|
@ -599,8 +599,7 @@ static int tegra_slink_init_dma_param(struct tegra_slink_data *tspi,
|
||||||
int ret;
|
int ret;
|
||||||
struct dma_slave_config dma_sconfig;
|
struct dma_slave_config dma_sconfig;
|
||||||
|
|
||||||
dma_chan = dma_request_slave_channel_reason(tspi->dev,
|
dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx");
|
||||||
dma_to_memory ? "rx" : "tx");
|
|
||||||
if (IS_ERR(dma_chan)) {
|
if (IS_ERR(dma_chan)) {
|
||||||
ret = PTR_ERR(dma_chan);
|
ret = PTR_ERR(dma_chan);
|
||||||
if (ret != -EPROBE_DEFER)
|
if (ret != -EPROBE_DEFER)
|
||||||
|
@ -1073,7 +1072,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
||||||
ret = clk_enable(tspi->clk);
|
ret = clk_enable(tspi->clk);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "Clock enable failed %d\n", ret);
|
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);
|
spi_irq = platform_get_irq(pdev, 0);
|
||||||
|
@ -1146,6 +1145,8 @@ exit_free_irq:
|
||||||
free_irq(spi_irq, tspi);
|
free_irq(spi_irq, tspi);
|
||||||
exit_clk_disable:
|
exit_clk_disable:
|
||||||
clk_disable(tspi->clk);
|
clk_disable(tspi->clk);
|
||||||
|
exit_clk_unprepare:
|
||||||
|
clk_unprepare(tspi->clk);
|
||||||
exit_free_master:
|
exit_free_master:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1159,6 +1160,7 @@ static int tegra_slink_remove(struct platform_device *pdev)
|
||||||
free_irq(tspi->irq, tspi);
|
free_irq(tspi->irq, tspi);
|
||||||
|
|
||||||
clk_disable(tspi->clk);
|
clk_disable(tspi->clk);
|
||||||
|
clk_unprepare(tspi->clk);
|
||||||
|
|
||||||
if (tspi->tx_dma_chan)
|
if (tspi->tx_dma_chan)
|
||||||
tegra_slink_deinit_dma_param(tspi, false);
|
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",
|
"%s:data->current_msg->actual_length=%d\n",
|
||||||
__func__, data->current_msg->actual_length);
|
__func__, data->current_msg->actual_length);
|
||||||
|
|
||||||
/* check for delay */
|
spi_transfer_delay_exec(data->cur_trans);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock(&data->lock);
|
spin_lock(&data->lock);
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/machine.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
|
|
||||||
#define SPI_FIFO_SIZE 4
|
#define SPI_FIFO_SIZE 4
|
||||||
|
@ -79,7 +80,7 @@ struct txx9spi {
|
||||||
void __iomem *membase;
|
void __iomem *membase;
|
||||||
int baseclk;
|
int baseclk;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
int last_chipselect;
|
struct gpio_desc *last_chipselect;
|
||||||
int last_chipselect_val;
|
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,
|
static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
|
||||||
int on, unsigned int cs_delay)
|
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) {
|
if (on) {
|
||||||
/* deselect the chip with cs_change hint in last transfer */
|
/* deselect the chip with cs_change hint in last transfer */
|
||||||
if (c->last_chipselect >= 0)
|
if (c->last_chipselect)
|
||||||
gpio_set_value(c->last_chipselect,
|
gpiod_set_value(c->last_chipselect,
|
||||||
!c->last_chipselect_val);
|
!c->last_chipselect_val);
|
||||||
c->last_chipselect = spi->chip_select;
|
c->last_chipselect = spi->cs_gpiod;
|
||||||
c->last_chipselect_val = val;
|
c->last_chipselect_val = on;
|
||||||
} else {
|
} else {
|
||||||
c->last_chipselect = -1;
|
c->last_chipselect = NULL;
|
||||||
ndelay(cs_delay); /* CS Hold Time */
|
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 */
|
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)
|
if (!spi->max_speed_hz)
|
||||||
return -EINVAL;
|
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 */
|
/* deselect chip */
|
||||||
spin_lock(&c->lock);
|
spin_lock(&c->lock);
|
||||||
txx9spi_cs_func(spi, c, 0, (NSEC_PER_SEC / 2) / spi->max_speed_hz);
|
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;
|
len -= count * wsize;
|
||||||
}
|
}
|
||||||
m->actual_length += t->len;
|
m->actual_length += t->len;
|
||||||
if (t->delay_usecs)
|
spi_transfer_delay_exec(t);
|
||||||
udelay(t->delay_usecs);
|
|
||||||
|
|
||||||
if (!cs_change)
|
if (!cs_change)
|
||||||
continue;
|
continue;
|
||||||
|
@ -320,6 +316,47 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
|
||||||
return 0;
|
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)
|
static int txx9spi_probe(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
|
@ -373,12 +410,14 @@ static int txx9spi_probe(struct platform_device *dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
c->last_chipselect = -1;
|
c->last_chipselect = NULL;
|
||||||
|
|
||||||
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
|
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
|
||||||
(unsigned long long)res->start, irq,
|
(unsigned long long)res->start, irq,
|
||||||
(c->baseclk + 500000) / 1000000);
|
(c->baseclk + 500000) / 1000000);
|
||||||
|
|
||||||
|
gpiod_add_lookup_table(&txx9spi_cs_gpio_table);
|
||||||
|
|
||||||
/* the spi->mode bits understood by this driver: */
|
/* the spi->mode bits understood by this driver: */
|
||||||
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
|
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->transfer = txx9spi_transfer;
|
||||||
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
|
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
|
||||||
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
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);
|
ret = devm_spi_register_master(&dev->dev, master);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
@ -188,8 +188,7 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
|
||||||
}
|
}
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
if (t->delay_usecs)
|
spi_transfer_delay_exec(t);
|
||||||
udelay(t->delay_usecs);
|
|
||||||
|
|
||||||
is_first = false;
|
is_first = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,7 +391,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
||||||
struct xilinx_spi *xspi;
|
struct xilinx_spi *xspi;
|
||||||
struct xspi_platform_data *pdata;
|
struct xspi_platform_data *pdata;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret, num_cs = 0, bits_per_word = 8;
|
int ret, num_cs = 0, bits_per_word;
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
u8 i;
|
u8 i;
|
||||||
|
@ -403,6 +403,11 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
||||||
} else {
|
} else {
|
||||||
of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
|
of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
|
||||||
&num_cs);
|
&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) {
|
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)
|
static int xtfpga_spi_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct xtfpga_spi *xspi;
|
struct xtfpga_spi *xspi;
|
||||||
struct resource *mem;
|
|
||||||
int ret;
|
int ret;
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
|
|
||||||
|
@ -97,14 +96,7 @@ static int xtfpga_spi_probe(struct platform_device *pdev)
|
||||||
xspi->bitbang.master = master;
|
xspi->bitbang.master = master;
|
||||||
xspi->bitbang.chipselect = xtfpga_spi_chipselect;
|
xspi->bitbang.chipselect = xtfpga_spi_chipselect;
|
||||||
xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
|
xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
|
||||||
|
xspi->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||||
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);
|
|
||||||
if (IS_ERR(xspi->regs)) {
|
if (IS_ERR(xspi->regs)) {
|
||||||
ret = PTR_ERR(xspi->regs);
|
ret = PTR_ERR(xspi->regs);
|
||||||
goto err;
|
goto err;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/module.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_BDRATE_MASK GENMASK(5, 3) /* Baud Rate Mask */
|
||||||
#define ZYNQ_QSPI_CONFIG_CPHA_MASK BIT(2) /* Clock Phase Control */
|
#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_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_FWIDTH_MASK GENMASK(7, 6) /* FIFO width */
|
||||||
#define ZYNQ_QSPI_CONFIG_MSTREN_MASK BIT(0) /* Master Mode */
|
#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
|
* These are the values used in the calculation of baud rate divisor and
|
||||||
* setting the slave select.
|
* setting the slave select.
|
||||||
*/
|
*/
|
||||||
#define ZYNQ_QSPI_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */
|
#define ZYNQ_QSPI_CONFIG_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_CONFIG_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift */
|
||||||
#define ZYNQ_QSPI_SS_SHIFT 10 /* Slave Select field shift in CR */
|
#define ZYNQ_QSPI_CONFIG_PCS BIT(10) /* Peripheral Chip Select */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* QSPI Interrupt Registers bit Masks
|
* QSPI Interrupt Registers bit Masks
|
||||||
|
@ -99,9 +97,9 @@
|
||||||
* It is named Linear Configuration but it controls other modes when not in
|
* It is named Linear Configuration but it controls other modes when not in
|
||||||
* linear mode also.
|
* linear mode also.
|
||||||
*/
|
*/
|
||||||
#define ZYNQ_QSPI_LCFG_TWO_MEM_MASK BIT(30) /* LQSPI Two memories Mask */
|
#define ZYNQ_QSPI_LCFG_TWO_MEM BIT(30) /* LQSPI Two memories */
|
||||||
#define ZYNQ_QSPI_LCFG_SEP_BUS_MASK BIT(29) /* LQSPI Separate bus Mask */
|
#define ZYNQ_QSPI_LCFG_SEP_BUS BIT(29) /* LQSPI Separate bus */
|
||||||
#define ZYNQ_QSPI_LCFG_U_PAGE_MASK BIT(28) /* LQSPI Upper Page Mask */
|
#define ZYNQ_QSPI_LCFG_U_PAGE BIT(28) /* LQSPI Upper Page */
|
||||||
|
|
||||||
#define ZYNQ_QSPI_LCFG_DUMMY_SHIFT 8
|
#define ZYNQ_QSPI_LCFG_DUMMY_SHIFT 8
|
||||||
|
|
||||||
|
@ -116,8 +114,8 @@
|
||||||
*/
|
*/
|
||||||
#define ZYNQ_QSPI_MODEBITS (SPI_CPOL | SPI_CPHA)
|
#define ZYNQ_QSPI_MODEBITS (SPI_CPOL | SPI_CPHA)
|
||||||
|
|
||||||
/* Default number of chip selects */
|
/* Maximum number of chip selects */
|
||||||
#define ZYNQ_QSPI_DEFAULT_NUM_CS 1
|
#define ZYNQ_QSPI_MAX_NUM_CS 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct zynq_qspi - Defines qspi driver instance
|
* 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
|
* zynq_qspi_init_hw - Initialize the hardware
|
||||||
* @xqspi: Pointer to the zynq_qspi structure
|
* @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
|
* The default settings of the QSPI controller's configurable parameters on
|
||||||
* reset are
|
* 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
|
* - Set the little endian mode of TX FIFO and
|
||||||
* - Enable the QSPI controller
|
* - 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;
|
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);
|
zynq_qspi_write(xqspi, ZYNQ_QSPI_IDIS_OFFSET, ZYNQ_QSPI_IXR_ALL_MASK);
|
||||||
|
|
||||||
/* Disable linear mode as the boot loader may have used it */
|
/* 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 */
|
/* Clear the RX FIFO */
|
||||||
while (zynq_qspi_read(xqspi, ZYNQ_QSPI_STATUS_OFFSET) &
|
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)
|
static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
|
||||||
{
|
{
|
||||||
struct spi_controller *ctrl = spi->master;
|
struct spi_controller *ctlr = spi->master;
|
||||||
struct zynq_qspi *xqspi = spi_controller_get_devdata(ctrl);
|
struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr);
|
||||||
u32 config_reg;
|
u32 config_reg;
|
||||||
|
|
||||||
config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_CONFIG_OFFSET);
|
/* Select the lower (CS0) or upper (CS1) memory */
|
||||||
if (assert) {
|
if (ctlr->num_chipselect > 1) {
|
||||||
/* Select the slave */
|
config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET);
|
||||||
config_reg &= ~ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
|
if (!spi->chip_select)
|
||||||
config_reg |= (((~(BIT(spi->chip_select))) <<
|
config_reg &= ~ZYNQ_QSPI_LCFG_U_PAGE;
|
||||||
ZYNQ_QSPI_SS_SHIFT) &
|
else
|
||||||
ZYNQ_QSPI_CONFIG_SSCTRL_MASK);
|
config_reg |= ZYNQ_QSPI_LCFG_U_PAGE;
|
||||||
} else {
|
|
||||||
config_reg |= ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
|
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);
|
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
|
* 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)) >
|
(clk_get_rate(xqspi->refclk) / (2 << baud_rate_val)) >
|
||||||
spi->max_speed_hz)
|
spi->max_speed_hz)
|
||||||
baud_rate_val++;
|
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_CPOL_MASK;
|
||||||
|
|
||||||
config_reg &= ~ZYNQ_QSPI_CONFIG_BDRATE_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);
|
zynq_qspi_write(xqspi, ZYNQ_QSPI_CONFIG_OFFSET, config_reg);
|
||||||
|
|
||||||
return 0;
|
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)
|
static int zynq_qspi_setup_op(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct spi_controller *ctrl = spi->master;
|
struct spi_controller *ctlr = spi->master;
|
||||||
struct zynq_qspi *qspi = spi_controller_get_devdata(ctrl);
|
struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr);
|
||||||
|
|
||||||
if (ctrl->busy)
|
if (ctlr->busy)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
clk_enable(qspi->refclk);
|
clk_enable(qspi->refclk);
|
||||||
|
@ -663,9 +674,6 @@ static int zynq_qspi_probe(struct platform_device *pdev)
|
||||||
goto clk_dis_pclk;
|
goto clk_dis_pclk;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* QSPI controller initializations */
|
|
||||||
zynq_qspi_init_hw(xqspi);
|
|
||||||
|
|
||||||
xqspi->irq = platform_get_irq(pdev, 0);
|
xqspi->irq = platform_get_irq(pdev, 0);
|
||||||
if (xqspi->irq <= 0) {
|
if (xqspi->irq <= 0) {
|
||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
|
@ -681,10 +689,14 @@ static int zynq_qspi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ret = of_property_read_u32(np, "num-cs",
|
ret = of_property_read_u32(np, "num-cs",
|
||||||
&num_cs);
|
&num_cs);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
ctlr->num_chipselect = ZYNQ_QSPI_DEFAULT_NUM_CS;
|
ctlr->num_chipselect = 1;
|
||||||
else
|
} 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->num_chipselect = num_cs;
|
||||||
|
}
|
||||||
|
|
||||||
ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
|
ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
|
||||||
SPI_TX_DUAL | SPI_TX_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->setup = zynq_qspi_setup_op;
|
||||||
ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
|
ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
|
||||||
ctlr->dev.of_node = np;
|
ctlr->dev.of_node = np;
|
||||||
|
|
||||||
|
/* QSPI controller initializations */
|
||||||
|
zynq_qspi_init_hw(xqspi, ctlr->num_chipselect);
|
||||||
|
|
||||||
ret = devm_spi_register_controller(&pdev->dev, ctlr);
|
ret = devm_spi_register_controller(&pdev->dev, ctlr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "spi_register_master failed\n");
|
dev_err(&pdev->dev, "spi_register_master failed\n");
|
||||||
|
|
|
@ -92,7 +92,7 @@ static ssize_t driver_override_store(struct device *dev,
|
||||||
if (len) {
|
if (len) {
|
||||||
spi->driver_override = driver_override;
|
spi->driver_override = driver_override;
|
||||||
} else {
|
} else {
|
||||||
/* Emptry string, disable driver override */
|
/* Empty string, disable driver override */
|
||||||
spi->driver_override = NULL;
|
spi->driver_override = NULL;
|
||||||
kfree(driver_override);
|
kfree(driver_override);
|
||||||
}
|
}
|
||||||
|
@ -469,7 +469,7 @@ static LIST_HEAD(board_list);
|
||||||
static LIST_HEAD(spi_controller_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
|
* spi_controller list, and their matching process
|
||||||
* also used to protect object of type struct idr
|
* 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)
|
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)
|
if (spi->mode & SPI_CS_HIGH)
|
||||||
enable = !enable;
|
enable = !enable;
|
||||||
|
|
||||||
|
@ -800,6 +809,11 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
|
||||||
} else if (spi->controller->set_cs) {
|
} else if (spi->controller->set_cs) {
|
||||||
spi->controller->set_cs(spi, !enable);
|
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
|
#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,
|
int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
|
||||||
struct spi_transfer *xfer)
|
|
||||||
{
|
{
|
||||||
u32 delay = xfer->cs_change_delay;
|
u32 delay = _delay->value;
|
||||||
u32 unit = xfer->cs_change_delay_unit;
|
u32 unit = _delay->unit;
|
||||||
u32 hz;
|
u32 hz;
|
||||||
|
|
||||||
/* return early on "fast" mode - for everything but USECS */
|
if (!delay)
|
||||||
if (!delay && unit != SPI_DELAY_UNIT_USECS)
|
return 0;
|
||||||
return;
|
|
||||||
|
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
case SPI_DELAY_UNIT_USECS:
|
case SPI_DELAY_UNIT_USECS:
|
||||||
/* for compatibility use default of 10us */
|
|
||||||
if (!delay)
|
|
||||||
delay = 10000;
|
|
||||||
else
|
|
||||||
delay *= 1000;
|
delay *= 1000;
|
||||||
break;
|
break;
|
||||||
case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
|
case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
|
||||||
break;
|
break;
|
||||||
case SPI_DELAY_UNIT_SCK:
|
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
|
/* if there is no effective speed know, then approximate
|
||||||
* by underestimating with half the requested hz
|
* by underestimating with half the requested hz
|
||||||
*/
|
*/
|
||||||
hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
|
hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
|
||||||
|
if (!hz)
|
||||||
|
return -EINVAL;
|
||||||
delay *= DIV_ROUND_UP(1000000000, hz);
|
delay *= DIV_ROUND_UP(1000000000, hz);
|
||||||
break;
|
break;
|
||||||
default:
|
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,
|
dev_err_once(&msg->spi->dev,
|
||||||
"Use of unsupported delay unit %i, using default of 10us\n",
|
"Use of unsupported delay unit %i, using default of 10us\n",
|
||||||
xfer->cs_change_delay_unit);
|
unit);
|
||||||
delay = 10000;
|
_spi_transfer_delay_ns(10000);
|
||||||
}
|
}
|
||||||
/* now sleep for the requested amount of time */
|
|
||||||
_spi_transfer_delay_ns(delay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1171,6 +1222,11 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
|
||||||
spi_statistics_add_transfer_stats(statm, xfer, ctlr);
|
spi_statistics_add_transfer_stats(statm, xfer, ctlr);
|
||||||
spi_statistics_add_transfer_stats(stats, xfer, ctlr);
|
spi_statistics_add_transfer_stats(stats, xfer, ctlr);
|
||||||
|
|
||||||
|
if (!ctlr->ptp_sts_supported) {
|
||||||
|
xfer->ptp_sts_word_pre = 0;
|
||||||
|
ptp_read_system_prets(xfer->ptp_sts);
|
||||||
|
}
|
||||||
|
|
||||||
if (xfer->tx_buf || xfer->rx_buf) {
|
if (xfer->tx_buf || xfer->rx_buf) {
|
||||||
reinit_completion(&ctlr->xfer_completion);
|
reinit_completion(&ctlr->xfer_completion);
|
||||||
|
|
||||||
|
@ -1197,13 +1253,17 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
|
||||||
xfer->len);
|
xfer->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ctlr->ptp_sts_supported) {
|
||||||
|
ptp_read_system_postts(xfer->ptp_sts);
|
||||||
|
xfer->ptp_sts_word_post = xfer->len;
|
||||||
|
}
|
||||||
|
|
||||||
trace_spi_transfer_stop(msg, xfer);
|
trace_spi_transfer_stop(msg, xfer);
|
||||||
|
|
||||||
if (msg->status != -EINPROGRESS)
|
if (msg->status != -EINPROGRESS)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (xfer->delay_usecs)
|
spi_transfer_delay_exec(xfer);
|
||||||
_spi_transfer_delay_ns(xfer->delay_usecs * 1000);
|
|
||||||
|
|
||||||
if (xfer->cs_change) {
|
if (xfer->cs_change) {
|
||||||
if (list_is_last(&xfer->transfer_list,
|
if (list_is_last(&xfer->transfer_list,
|
||||||
|
@ -1265,6 +1325,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
|
||||||
*/
|
*/
|
||||||
static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
|
static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
|
||||||
{
|
{
|
||||||
|
struct spi_transfer *xfer;
|
||||||
struct spi_message *msg;
|
struct spi_message *msg;
|
||||||
bool was_busy = false;
|
bool was_busy = false;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -1391,6 +1452,13 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) {
|
||||||
|
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||||
|
xfer->ptp_sts_word_pre = 0;
|
||||||
|
ptp_read_system_prets(xfer->ptp_sts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = ctlr->transfer_one_message(ctlr, msg);
|
ret = ctlr->transfer_one_message(ctlr, msg);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&ctlr->dev,
|
dev_err(&ctlr->dev,
|
||||||
|
@ -1418,6 +1486,99 @@ static void spi_pump_messages(struct kthread_work *work)
|
||||||
__spi_pump_messages(ctlr, true);
|
__spi_pump_messages(ctlr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spi_take_timestamp_pre - helper for drivers to collect the beginning of the
|
||||||
|
* TX timestamp for the requested byte from the SPI
|
||||||
|
* transfer. The frequency with which this function
|
||||||
|
* must be called (once per word, once for the whole
|
||||||
|
* transfer, once per batch of words etc) is arbitrary
|
||||||
|
* as long as the @tx buffer offset is greater than or
|
||||||
|
* equal to the requested byte at the time of the
|
||||||
|
* call. The timestamp is only taken once, at the
|
||||||
|
* first such call. It is assumed that the driver
|
||||||
|
* advances its @tx buffer pointer monotonically.
|
||||||
|
* @ctlr: Pointer to the spi_controller structure of the driver
|
||||||
|
* @xfer: Pointer to the transfer being timestamped
|
||||||
|
* @tx: Pointer to the current word within the xfer->tx_buf that the driver is
|
||||||
|
* preparing to transmit right now.
|
||||||
|
* @irqs_off: If true, will disable IRQs and preemption for the duration of the
|
||||||
|
* transfer, for less jitter in time measurement. Only compatible
|
||||||
|
* with PIO drivers. If true, must follow up with
|
||||||
|
* spi_take_timestamp_post or otherwise system will crash.
|
||||||
|
* WARNING: for fully predictable results, the CPU frequency must
|
||||||
|
* also be under control (governor).
|
||||||
|
*/
|
||||||
|
void spi_take_timestamp_pre(struct spi_controller *ctlr,
|
||||||
|
struct spi_transfer *xfer,
|
||||||
|
const void *tx, bool irqs_off)
|
||||||
|
{
|
||||||
|
u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8);
|
||||||
|
|
||||||
|
if (!xfer->ptp_sts)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (xfer->timestamped_pre)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tx < (xfer->tx_buf + xfer->ptp_sts_word_pre * bytes_per_word))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Capture the resolution of the timestamp */
|
||||||
|
xfer->ptp_sts_word_pre = (tx - xfer->tx_buf) / bytes_per_word;
|
||||||
|
|
||||||
|
xfer->timestamped_pre = true;
|
||||||
|
|
||||||
|
if (irqs_off) {
|
||||||
|
local_irq_save(ctlr->irq_flags);
|
||||||
|
preempt_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ptp_read_system_prets(xfer->ptp_sts);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(spi_take_timestamp_pre);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* spi_take_timestamp_post - helper for drivers to collect the end of the
|
||||||
|
* TX timestamp for the requested byte from the SPI
|
||||||
|
* transfer. Can be called with an arbitrary
|
||||||
|
* frequency: only the first call where @tx exceeds
|
||||||
|
* or is equal to the requested word will be
|
||||||
|
* timestamped.
|
||||||
|
* @ctlr: Pointer to the spi_controller structure of the driver
|
||||||
|
* @xfer: Pointer to the transfer being timestamped
|
||||||
|
* @tx: Pointer to the current word within the xfer->tx_buf that the driver has
|
||||||
|
* just transmitted.
|
||||||
|
* @irqs_off: If true, will re-enable IRQs and preemption for the local CPU.
|
||||||
|
*/
|
||||||
|
void spi_take_timestamp_post(struct spi_controller *ctlr,
|
||||||
|
struct spi_transfer *xfer,
|
||||||
|
const void *tx, bool irqs_off)
|
||||||
|
{
|
||||||
|
u8 bytes_per_word = DIV_ROUND_UP(xfer->bits_per_word, 8);
|
||||||
|
|
||||||
|
if (!xfer->ptp_sts)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (xfer->timestamped_post)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (tx < (xfer->tx_buf + xfer->ptp_sts_word_post * bytes_per_word))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ptp_read_system_postts(xfer->ptp_sts);
|
||||||
|
|
||||||
|
if (irqs_off) {
|
||||||
|
local_irq_restore(ctlr->irq_flags);
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Capture the resolution of the timestamp */
|
||||||
|
xfer->ptp_sts_word_post = (tx - xfer->tx_buf) / bytes_per_word;
|
||||||
|
|
||||||
|
xfer->timestamped_post = true;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(spi_take_timestamp_post);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_set_thread_rt - set the controller to pump at realtime priority
|
* spi_set_thread_rt - set the controller to pump at realtime priority
|
||||||
* @ctlr: controller to boost priority of
|
* @ctlr: controller to boost priority of
|
||||||
|
@ -1503,6 +1664,7 @@ EXPORT_SYMBOL_GPL(spi_get_next_queued_message);
|
||||||
*/
|
*/
|
||||||
void spi_finalize_current_message(struct spi_controller *ctlr)
|
void spi_finalize_current_message(struct spi_controller *ctlr)
|
||||||
{
|
{
|
||||||
|
struct spi_transfer *xfer;
|
||||||
struct spi_message *mesg;
|
struct spi_message *mesg;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1511,6 +1673,13 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
|
||||||
mesg = ctlr->cur_msg;
|
mesg = ctlr->cur_msg;
|
||||||
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
|
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
|
||||||
|
|
||||||
|
if (!ctlr->ptp_sts_supported && !ctlr->transfer_one) {
|
||||||
|
list_for_each_entry(xfer, &mesg->transfers, transfer_list) {
|
||||||
|
ptp_read_system_postts(xfer->ptp_sts);
|
||||||
|
xfer->ptp_sts_word_post = xfer->len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spi_unmap_msg(ctlr, mesg);
|
spi_unmap_msg(ctlr, mesg);
|
||||||
|
|
||||||
if (ctlr->cur_msg_prepared && ctlr->unprepare_message) {
|
if (ctlr->cur_msg_prepared && ctlr->unprepare_message) {
|
||||||
|
@ -2872,10 +3041,11 @@ struct spi_replaced_transfers *spi_replace_transfers(
|
||||||
/* add to list */
|
/* add to list */
|
||||||
list_add(&xfer->transfer_list, rxfer->replaced_after);
|
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) {
|
if (i) {
|
||||||
xfer->cs_change = false;
|
xfer->cs_change = false;
|
||||||
xfer->delay_usecs = 0;
|
xfer->delay_usecs = 0;
|
||||||
|
xfer->delay.value = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3092,7 +3262,29 @@ int spi_setup(struct spi_device *spi)
|
||||||
if (spi->controller->setup)
|
if (spi->controller->setup)
|
||||||
status = spi->controller->setup(spi);
|
status = spi->controller->setup(spi);
|
||||||
|
|
||||||
|
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);
|
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) {
|
if (spi->rt && !spi->controller->rt) {
|
||||||
spi->controller->rt = true;
|
spi->controller->rt = true;
|
||||||
|
@ -3115,18 +3307,71 @@ EXPORT_SYMBOL_GPL(spi_setup);
|
||||||
/**
|
/**
|
||||||
* spi_set_cs_timing - configure CS setup, hold, and inactive delays
|
* spi_set_cs_timing - configure CS setup, hold, and inactive delays
|
||||||
* @spi: the device that requires specific CS timing configuration
|
* @spi: the device that requires specific CS timing configuration
|
||||||
* @setup: CS setup time in terms of clock count
|
* @setup: CS setup time specified via @spi_delay
|
||||||
* @hold: CS hold time in terms of clock count
|
* @hold: CS hold time specified via @spi_delay
|
||||||
* @inactive_dly: CS inactive delay between transfers in terms of clock count
|
* @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,
|
int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup,
|
||||||
u8 inactive_dly)
|
struct spi_delay *hold, struct spi_delay *inactive)
|
||||||
{
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
if (spi->controller->set_cs_timing)
|
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);
|
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)
|
static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
||||||
{
|
{
|
||||||
struct spi_controller *ctlr = spi->controller;
|
struct spi_controller *ctlr = spi->controller;
|
||||||
|
@ -3262,8 +3507,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xfer->word_delay_usecs < spi->word_delay_usecs)
|
if (_spi_xfer_word_delay_update(xfer, spi))
|
||||||
xfer->word_delay_usecs = spi->word_delay_usecs;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
message->status = -EINPROGRESS;
|
message->status = -EINPROGRESS;
|
||||||
|
@ -3274,6 +3519,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
||||||
static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
||||||
{
|
{
|
||||||
struct spi_controller *ctlr = spi->controller;
|
struct spi_controller *ctlr = spi->controller;
|
||||||
|
struct spi_transfer *xfer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some controllers do not support doing regular SPI transfers. Return
|
* Some controllers do not support doing regular SPI transfers. Return
|
||||||
|
@ -3289,6 +3535,13 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
|
||||||
|
|
||||||
trace_spi_message_submit(message);
|
trace_spi_message_submit(message);
|
||||||
|
|
||||||
|
if (!ctlr->ptp_sts_supported) {
|
||||||
|
list_for_each_entry(xfer, &message->transfers, transfer_list) {
|
||||||
|
xfer->ptp_sts_word_pre = 0;
|
||||||
|
ptp_read_system_prets(xfer->ptp_sts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ctlr->transfer(spi, message);
|
return ctlr->transfer(spi, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -265,9 +265,11 @@ static int spidev_message(struct spidev_data *spidev,
|
||||||
k_tmp->tx_nbits = u_tmp->tx_nbits;
|
k_tmp->tx_nbits = u_tmp->tx_nbits;
|
||||||
k_tmp->rx_nbits = u_tmp->rx_nbits;
|
k_tmp->rx_nbits = u_tmp->rx_nbits;
|
||||||
k_tmp->bits_per_word = u_tmp->bits_per_word;
|
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->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)
|
if (!k_tmp->speed_hz)
|
||||||
k_tmp->speed_hz = spidev->speed_hz;
|
k_tmp->speed_hz = spidev->speed_hz;
|
||||||
#ifdef VERBOSE
|
#ifdef VERBOSE
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
/* Board specific platform_data */
|
/* Board specific platform_data */
|
||||||
struct mtk_chip_config {
|
struct mtk_chip_config {
|
||||||
u32 cs_pol;
|
|
||||||
u32 sample_sel;
|
u32 sample_sel;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -206,7 +206,7 @@ enum pxa_ssp_type {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssp_device {
|
struct ssp_device {
|
||||||
struct platform_device *pdev;
|
struct device *dev;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
|
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/ptp_clock_kernel.h>
|
||||||
|
|
||||||
struct dma_chan;
|
struct dma_chan;
|
||||||
struct property_entry;
|
struct property_entry;
|
||||||
|
@ -89,6 +90,22 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
|
||||||
#define SPI_STATISTICS_INCREMENT_FIELD(stats, field) \
|
#define SPI_STATISTICS_INCREMENT_FIELD(stats, field) \
|
||||||
SPI_STATISTICS_ADD_TO_FIELD(stats, field, 1)
|
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
|
* struct spi_device - Controller side proxy for an SPI slave device
|
||||||
* @dev: Driver model representation of the device.
|
* @dev: Driver model representation of the device.
|
||||||
|
@ -123,7 +140,7 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
|
||||||
* the spi_master.
|
* the spi_master.
|
||||||
* @cs_gpiod: gpio descriptor of the chipselect line (optional, NULL when
|
* @cs_gpiod: gpio descriptor of the chipselect line (optional, NULL when
|
||||||
* not using a GPIO line)
|
* 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
|
* words of a transfer
|
||||||
*
|
*
|
||||||
* @statistics: statistics for the spi_device
|
* @statistics: statistics for the spi_device
|
||||||
|
@ -173,7 +190,7 @@ struct spi_device {
|
||||||
const char *driver_override;
|
const char *driver_override;
|
||||||
int cs_gpio; /* LEGACY: chip select gpio */
|
int cs_gpio; /* LEGACY: chip select gpio */
|
||||||
struct gpio_desc *cs_gpiod; /* chip select gpio desc */
|
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 */
|
/* the statistics */
|
||||||
struct spi_statistics statistics;
|
struct spi_statistics statistics;
|
||||||
|
@ -390,6 +407,11 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
||||||
* controller has native support for memory like operations.
|
* controller has native support for memory like operations.
|
||||||
* @unprepare_message: undo any work done by prepare_message().
|
* @unprepare_message: undo any work done by prepare_message().
|
||||||
* @slave_abort: abort the ongoing transfer request on an SPI slave controller
|
* @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_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
|
* 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
|
* are not GPIOs (driven by the SPI controller itself). Use the cs_gpiods
|
||||||
|
@ -409,6 +431,12 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
||||||
* @fw_translate_cs: If the boot firmware uses different numbering scheme
|
* @fw_translate_cs: If the boot firmware uses different numbering scheme
|
||||||
* what Linux expects, this optional hook can be used to translate
|
* what Linux expects, this optional hook can be used to translate
|
||||||
* between the two.
|
* between the two.
|
||||||
|
* @ptp_sts_supported: If the driver sets this to true, it must provide a
|
||||||
|
* time snapshot in @spi_transfer->ptp_sts as close as possible to the
|
||||||
|
* moment in time when @spi_transfer->ptp_sts_word_pre and
|
||||||
|
* @spi_transfer->ptp_sts_word_post were transmitted.
|
||||||
|
* If the driver does not set this, the SPI core takes the snapshot as
|
||||||
|
* close to the driver hand-over as possible.
|
||||||
*
|
*
|
||||||
* Each SPI controller can communicate with one or more @spi_device
|
* Each SPI controller can communicate with one or more @spi_device
|
||||||
* children. These make a small bus, sharing MOSI, MISO and SCK signals
|
* children. These make a small bus, sharing MOSI, MISO and SCK signals
|
||||||
|
@ -502,8 +530,8 @@ struct spi_controller {
|
||||||
* to configure specific CS timing through spi_set_cs_timing() after
|
* to configure specific CS timing through spi_set_cs_timing() after
|
||||||
* spi_setup().
|
* spi_setup().
|
||||||
*/
|
*/
|
||||||
void (*set_cs_timing)(struct spi_device *spi, u8 setup_clk_cycles,
|
int (*set_cs_timing)(struct spi_device *spi, struct spi_delay *setup,
|
||||||
u8 hold_clk_cycles, u8 inactive_clk_cycles);
|
struct spi_delay *hold, struct spi_delay *inactive);
|
||||||
|
|
||||||
/* bidirectional bulk transfers
|
/* bidirectional bulk transfers
|
||||||
*
|
*
|
||||||
|
@ -587,6 +615,11 @@ struct spi_controller {
|
||||||
/* Optimized handlers for SPI memory-like operations. */
|
/* Optimized handlers for SPI memory-like operations. */
|
||||||
const struct spi_controller_mem_ops *mem_ops;
|
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 */
|
/* gpio chip select */
|
||||||
int *cs_gpios;
|
int *cs_gpios;
|
||||||
struct gpio_desc **cs_gpiods;
|
struct gpio_desc **cs_gpiods;
|
||||||
|
@ -604,6 +637,15 @@ struct spi_controller {
|
||||||
void *dummy_tx;
|
void *dummy_tx;
|
||||||
|
|
||||||
int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);
|
int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver sets this field to indicate it is able to snapshot SPI
|
||||||
|
* transfers (needed e.g. for reading the time of POSIX clocks)
|
||||||
|
*/
|
||||||
|
bool ptp_sts_supported;
|
||||||
|
|
||||||
|
/* Interrupt enable state during PTP system timestamping */
|
||||||
|
unsigned long irq_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void *spi_controller_get_devdata(struct spi_controller *ctlr)
|
static inline void *spi_controller_get_devdata(struct spi_controller *ctlr)
|
||||||
|
@ -644,6 +686,14 @@ extern struct spi_message *spi_get_next_queued_message(struct spi_controller *ct
|
||||||
extern void spi_finalize_current_message(struct spi_controller *ctlr);
|
extern void spi_finalize_current_message(struct spi_controller *ctlr);
|
||||||
extern void spi_finalize_current_transfer(struct spi_controller *ctlr);
|
extern void spi_finalize_current_transfer(struct spi_controller *ctlr);
|
||||||
|
|
||||||
|
/* Helper calls for driver to timestamp transfer */
|
||||||
|
void spi_take_timestamp_pre(struct spi_controller *ctlr,
|
||||||
|
struct spi_transfer *xfer,
|
||||||
|
const void *tx, bool irqs_off);
|
||||||
|
void spi_take_timestamp_post(struct spi_controller *ctlr,
|
||||||
|
struct spi_transfer *xfer,
|
||||||
|
const void *tx, bool irqs_off);
|
||||||
|
|
||||||
/* the spi driver core manages memory for the spi_controller classdev */
|
/* the spi driver core manages memory for the spi_controller classdev */
|
||||||
extern struct spi_controller *__spi_alloc_controller(struct device *host,
|
extern struct spi_controller *__spi_alloc_controller(struct device *host,
|
||||||
unsigned int size, bool slave);
|
unsigned int size, bool slave);
|
||||||
|
@ -739,13 +789,13 @@ extern void spi_res_release(struct spi_controller *ctlr,
|
||||||
* @cs_change: affects chipselect after this transfer completes
|
* @cs_change: affects chipselect after this transfer completes
|
||||||
* @cs_change_delay: delay between cs deassert and assert when
|
* @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 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
|
* @delay_usecs: microseconds to delay after this transfer before
|
||||||
* (optionally) changing the chipselect status, then starting
|
* (optionally) changing the chipselect status, then starting
|
||||||
* the next transfer or completing this @spi_message.
|
* the next transfer or completing this @spi_message.
|
||||||
* @word_delay_usecs: microseconds 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.
|
|
||||||
* @word_delay: clock cycles to inter word delay after each word size
|
|
||||||
* (set by bits_per_word) transmission.
|
* (set by bits_per_word) transmission.
|
||||||
* @effective_speed_hz: the effective SCK-speed that was used to
|
* @effective_speed_hz: the effective SCK-speed that was used to
|
||||||
* transfer this transfer. Set to 0 if the spi bus driver does
|
* transfer this transfer. Set to 0 if the spi bus driver does
|
||||||
|
@ -753,6 +803,35 @@ extern void spi_res_release(struct spi_controller *ctlr,
|
||||||
* @transfer_list: transfers are sequenced through @spi_message.transfers
|
* @transfer_list: transfers are sequenced through @spi_message.transfers
|
||||||
* @tx_sg: Scatterlist for transmit, currently not for client use
|
* @tx_sg: Scatterlist for transmit, currently not for client use
|
||||||
* @rx_sg: Scatterlist for receive, currently not for client use
|
* @rx_sg: Scatterlist for receive, currently not for client use
|
||||||
|
* @ptp_sts_word_pre: The word (subject to bits_per_word semantics) offset
|
||||||
|
* within @tx_buf for which the SPI device is requesting that the time
|
||||||
|
* snapshot for this transfer begins. Upon completing the SPI transfer,
|
||||||
|
* this value may have changed compared to what was requested, depending
|
||||||
|
* on the available snapshotting resolution (DMA transfer,
|
||||||
|
* @ptp_sts_supported is false, etc).
|
||||||
|
* @ptp_sts_word_post: See @ptp_sts_word_post. The two can be equal (meaning
|
||||||
|
* that a single byte should be snapshotted).
|
||||||
|
* If the core takes care of the timestamp (if @ptp_sts_supported is false
|
||||||
|
* for this controller), it will set @ptp_sts_word_pre to 0, and
|
||||||
|
* @ptp_sts_word_post to the length of the transfer. This is done
|
||||||
|
* purposefully (instead of setting to spi_transfer->len - 1) to denote
|
||||||
|
* that a transfer-level snapshot taken from within the driver may still
|
||||||
|
* be of higher quality.
|
||||||
|
* @ptp_sts: Pointer to a memory location held by the SPI slave device where a
|
||||||
|
* PTP system timestamp structure may lie. If drivers use PIO or their
|
||||||
|
* hardware has some sort of assist for retrieving exact transfer timing,
|
||||||
|
* they can (and should) assert @ptp_sts_supported and populate this
|
||||||
|
* structure using the ptp_read_system_*ts helper functions.
|
||||||
|
* The timestamp must represent the time at which the SPI slave device has
|
||||||
|
* processed the word, i.e. the "pre" timestamp should be taken before
|
||||||
|
* transmitting the "pre" word, and the "post" timestamp after receiving
|
||||||
|
* transmit confirmation from the controller for the "post" word.
|
||||||
|
* @timestamped_pre: Set by the SPI controller driver to denote it has acted
|
||||||
|
* upon the @ptp_sts request. Not set when the SPI core has taken care of
|
||||||
|
* the task. SPI device drivers are free to print a warning if this comes
|
||||||
|
* back unset and they need the better resolution.
|
||||||
|
* @timestamped_post: See above. The reason why both exist is that these
|
||||||
|
* booleans are also used to keep state in the core SPI logic.
|
||||||
*
|
*
|
||||||
* SPI transfers always write the same number of bytes as they read.
|
* SPI transfers always write the same number of bytes as they read.
|
||||||
* Protocol drivers should always provide @rx_buf and/or @tx_buf.
|
* Protocol drivers should always provide @rx_buf and/or @tx_buf.
|
||||||
|
@ -830,18 +909,22 @@ struct spi_transfer {
|
||||||
#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */
|
#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */
|
||||||
#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */
|
#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */
|
||||||
u8 bits_per_word;
|
u8 bits_per_word;
|
||||||
u8 word_delay_usecs;
|
|
||||||
u16 delay_usecs;
|
u16 delay_usecs;
|
||||||
u16 cs_change_delay;
|
struct spi_delay delay;
|
||||||
u8 cs_change_delay_unit;
|
struct spi_delay cs_change_delay;
|
||||||
#define SPI_DELAY_UNIT_USECS 0
|
struct spi_delay word_delay;
|
||||||
#define SPI_DELAY_UNIT_NSECS 1
|
|
||||||
#define SPI_DELAY_UNIT_SCK 2
|
|
||||||
u32 speed_hz;
|
u32 speed_hz;
|
||||||
u16 word_delay;
|
|
||||||
|
|
||||||
u32 effective_speed_hz;
|
u32 effective_speed_hz;
|
||||||
|
|
||||||
|
unsigned int ptp_sts_word_pre;
|
||||||
|
unsigned int ptp_sts_word_post;
|
||||||
|
|
||||||
|
struct ptp_system_timestamp *ptp_sts;
|
||||||
|
|
||||||
|
bool timestamped_pre;
|
||||||
|
bool timestamped_post;
|
||||||
|
|
||||||
struct list_head transfer_list;
|
struct list_head transfer_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -935,6 +1018,20 @@ spi_transfer_del(struct spi_transfer *t)
|
||||||
list_del(&t->transfer_list);
|
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
|
* spi_message_init_with_transfers - Initialize spi_message and append transfers
|
||||||
* @m: spi_message to be initialized
|
* @m: spi_message to be initialized
|
||||||
|
@ -982,7 +1079,10 @@ static inline void spi_message_free(struct spi_message *m)
|
||||||
kfree(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_setup(struct spi_device *spi);
|
||||||
extern int spi_async(struct spi_device *spi, struct spi_message *message);
|
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 */
|
/* 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) ||
|
if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) ||
|
||||||
(mmp_sspa_read_reg(sspa, SSPA_RXSP) & 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");
|
"can't change hardware dai format: stream is in use\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,11 +52,11 @@ struct ssp_priv {
|
||||||
|
|
||||||
static void dump_registers(struct ssp_device *ssp)
|
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, SSCR0), pxa_ssp_read_reg(ssp, SSCR1),
|
||||||
pxa_ssp_read_reg(ssp, SSTO));
|
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, SSPSP), pxa_ssp_read_reg(ssp, SSSR),
|
||||||
pxa_ssp_read_reg(ssp, SSACD));
|
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;
|
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",
|
"pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n",
|
||||||
cpu_dai->id, clk_id, freq);
|
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);
|
ssacd |= (0x6 << 4);
|
||||||
|
|
||||||
dev_dbg(&ssp->pdev->dev,
|
dev_dbg(ssp->dev,
|
||||||
"Using SSACDD %x to supply %uHz\n",
|
"Using SSACDD %x to supply %uHz\n",
|
||||||
val, freq);
|
val, freq);
|
||||||
break;
|
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.
|
* - complain loudly and fail if they've not been set up yet.
|
||||||
*/
|
*/
|
||||||
if ((sscr0 & SSCR0_MOD) && !ttsa) {
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue