Merge branch 'spi-5.5' into spi-next
This commit is contained in:
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:
|
||||
- clock-names : Contains the names of the clocks:
|
||||
"ssi_clk", for the core clock used to generate the external SPI clock.
|
||||
"pclk", the interface clock, required for register access.
|
||||
"pclk", the interface clock, required for register access. If a clock domain
|
||||
used to enable this clock then it should be named "pclk_clkdomain".
|
||||
- cs-gpios : Specifies the gpio pins to be used for chipselects.
|
||||
- num-cs : The number of chipselects. If omitted, this will default to 4.
|
||||
- reg-io-width : The I/O register width (in bytes) implemented by this
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
SiFive SPI controller Device Tree Bindings
|
||||
------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "sifive,<chip>-spi" and "sifive,spi<version>".
|
||||
Supported compatible strings are:
|
||||
"sifive,fu540-c000-spi" for the SiFive SPI v0 as integrated
|
||||
onto the SiFive FU540 chip, and "sifive,spi0" for the SiFive
|
||||
SPI v0 IP block with no chip integration tweaks.
|
||||
Please refer to sifive-blocks-ip-versioning.txt for details
|
||||
- reg : Physical base address and size of SPI registers map
|
||||
A second (optional) range can indicate memory mapped flash
|
||||
- interrupts : Must contain one entry
|
||||
- interrupt-parent : Must be core interrupt controller
|
||||
- clocks : Must reference the frequency given to the controller
|
||||
- #address-cells : Must be '1', indicating which CS to use
|
||||
- #size-cells : Must be '0'
|
||||
|
||||
Optional properties:
|
||||
- sifive,fifo-depth : Depth of hardware queues; defaults to 8
|
||||
- sifive,max-bits-per-word : Maximum bits per word; defaults to 8
|
||||
|
||||
SPI RTL that corresponds to the IP block version numbers can be found here:
|
||||
https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/spi
|
||||
|
||||
Example:
|
||||
spi: spi@10040000 {
|
||||
compatible = "sifive,fu540-c000-spi", "sifive,spi0";
|
||||
reg = <0x0 0x10040000 0x0 0x1000 0x0 0x20000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <51>;
|
||||
clocks = <&tlclk>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
sifive,fifo-depth = <8>;
|
||||
sifive,max-bits-per-word = <8>;
|
||||
};
|
|
@ -0,0 +1,86 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/spi-sifive.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: SiFive SPI controller
|
||||
|
||||
maintainers:
|
||||
- Pragnesh Patel <pragnesh.patel@sifive.com>
|
||||
- Paul Walmsley <paul.walmsley@sifive.com>
|
||||
- Palmer Dabbelt <palmer@sifive.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: sifive,fu540-c000-spi
|
||||
- const: sifive,spi0
|
||||
|
||||
description:
|
||||
Should be "sifive,<chip>-spi" and "sifive,spi<version>".
|
||||
Supported compatible strings are -
|
||||
"sifive,fu540-c000-spi" for the SiFive SPI v0 as integrated
|
||||
onto the SiFive FU540 chip, and "sifive,spi0" for the SiFive
|
||||
SPI v0 IP block with no chip integration tweaks.
|
||||
Please refer to sifive-blocks-ip-versioning.txt for details
|
||||
|
||||
SPI RTL that corresponds to the IP block version numbers can be found here -
|
||||
https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/spi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
description:
|
||||
Physical base address and size of SPI registers map
|
||||
A second (optional) range can indicate memory mapped flash
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
description:
|
||||
Must reference the frequency given to the controller
|
||||
|
||||
sifive,fifo-depth:
|
||||
description:
|
||||
Depth of hardware queues; defaults to 8
|
||||
allOf:
|
||||
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
- enum: [ 8 ]
|
||||
- default: 8
|
||||
|
||||
sifive,max-bits-per-word:
|
||||
description:
|
||||
Maximum bits per word; defaults to 8
|
||||
allOf:
|
||||
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
- enum: [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
|
||||
- default: 8
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi: spi@10040000 {
|
||||
compatible = "sifive,fu540-c000-spi", "sifive,spi0";
|
||||
reg = <0x0 0x10040000 0x0 0x1000 0x0 0x20000000 0x0 0x10000000>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <51>;
|
||||
clocks = <&tlclk>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
sifive,fifo-depth = <8>;
|
||||
sifive,max-bits-per-word = <8>;
|
||||
};
|
||||
|
||||
...
|
|
@ -1,47 +0,0 @@
|
|||
* STMicroelectronics Quad Serial Peripheral Interface(QSPI)
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "st,stm32f469-qspi"
|
||||
- reg: the first contains the register location and length.
|
||||
the second contains the memory mapping address and length
|
||||
- reg-names: should contain the reg names "qspi" "qspi_mm"
|
||||
- interrupts: should contain the interrupt for the device
|
||||
- clocks: the phandle of the clock needed by the QSPI controller
|
||||
- A pinctrl must be defined to set pins in mode of operation for QSPI transfer
|
||||
|
||||
Optional properties:
|
||||
- resets: must contain the phandle to the reset controller.
|
||||
|
||||
A spi flash (NOR/NAND) must be a child of spi node and could have some
|
||||
properties. Also see jedec,spi-nor.txt.
|
||||
|
||||
Required properties:
|
||||
- reg: chip-Select number (QSPI controller may connect 2 flashes)
|
||||
- spi-max-frequency: max frequency of spi bus
|
||||
|
||||
Optional properties:
|
||||
- spi-rx-bus-width: see ./spi-bus.txt for the description
|
||||
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
|
||||
Documentation/devicetree/bindings/dma/dma.txt.
|
||||
- dma-names: DMA request names should include "tx" and "rx" if present.
|
||||
|
||||
Example:
|
||||
|
||||
qspi: spi@a0001000 {
|
||||
compatible = "st,stm32f469-qspi";
|
||||
reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>;
|
||||
reg-names = "qspi", "qspi_mm";
|
||||
interrupts = <91>;
|
||||
resets = <&rcc STM32F4_AHB3_RESET(QSPI)>;
|
||||
clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_qspi0>;
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-rx-bus-width = <4>;
|
||||
spi-max-frequency = <108000000>;
|
||||
...
|
||||
};
|
||||
};
|
|
@ -8,7 +8,8 @@ Required properties:
|
|||
number.
|
||||
|
||||
Optional properties:
|
||||
- xlnx,num-ss-bits : Number of chip selects used.
|
||||
- xlnx,num-ss-bits : Number of chip selects used.
|
||||
- xlnx,num-transfer-bits : Number of bits per transfer. This will be 8 if not specified
|
||||
|
||||
Example:
|
||||
axi_quad_spi@41e00000 {
|
||||
|
@ -17,5 +18,6 @@ Example:
|
|||
interrupts = <0 31 1>;
|
||||
reg = <0x41e00000 0x10000>;
|
||||
xlnx,num-ss-bits = <0x1>;
|
||||
xlnx,num-transfer-bits = <32>;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/st,stm32-qspi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics STM32 Quad Serial Peripheral Interface (QSPI) bindings
|
||||
|
||||
maintainers:
|
||||
- Christophe Kerello <christophe.kerello@st.com>
|
||||
- Patrice Chotard <patrice.chotard@st.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: st,stm32f469-qspi
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: registers
|
||||
- description: memory mapping
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: qspi
|
||||
- const: qspi_mm
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: tx DMA channel
|
||||
- description: rx DMA channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- clocks
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/stm32mp1-clks.h>
|
||||
#include <dt-bindings/reset/stm32mp1-resets.h>
|
||||
spi@58003000 {
|
||||
compatible = "st,stm32f469-qspi";
|
||||
reg = <0x58003000 0x1000>, <0x70000000 0x10000000>;
|
||||
reg-names = "qspi", "qspi_mm";
|
||||
interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&mdma1 22 0x10 0x100002 0x0 0x0>,
|
||||
<&mdma1 22 0x10 0x100008 0x0 0x0>;
|
||||
dma-names = "tx", "rx";
|
||||
clocks = <&rcc QSPI_K>;
|
||||
resets = <&rcc QSPI_R>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-rx-bus-width = <4>;
|
||||
spi-max-frequency = <108000000>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -89,7 +89,7 @@ void pxa_ssp_free(struct ssp_device *ssp)
|
|||
ssp->use_count--;
|
||||
ssp->label = NULL;
|
||||
} else
|
||||
dev_err(&ssp->pdev->dev, "device already free\n");
|
||||
dev_err(ssp->dev, "device already free\n");
|
||||
mutex_unlock(&ssp_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(pxa_ssp_free);
|
||||
|
@ -118,7 +118,7 @@ static int pxa_ssp_probe(struct platform_device *pdev)
|
|||
if (ssp == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ssp->pdev = pdev;
|
||||
ssp->dev = dev;
|
||||
|
||||
ssp->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(ssp->clk))
|
||||
|
|
|
@ -39,24 +39,24 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
|
|||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->write_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 2,
|
||||
.bits_per_word = 8,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->write_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 4,
|
||||
.bits_per_word = 8,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->write_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 6,
|
||||
.bits_per_word = 8,
|
||||
|
@ -139,16 +139,16 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
|
|||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->write_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 2,
|
||||
.bits_per_word = 8,
|
||||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->read_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.tx_buf = adis->tx + 4,
|
||||
.rx_buf = adis->rx,
|
||||
|
@ -156,8 +156,8 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
|
|||
.len = 2,
|
||||
.cs_change = 1,
|
||||
.delay_usecs = adis->data->read_delay,
|
||||
.cs_change_delay = adis->data->cs_change_delay,
|
||||
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
|
||||
.cs_change_delay.value = adis->data->cs_change_delay,
|
||||
.cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
|
||||
}, {
|
||||
.rx_buf = adis->rx + 2,
|
||||
.bits_per_word = 8,
|
||||
|
|
|
@ -80,6 +80,7 @@ config SPI_ARMADA_3700
|
|||
config SPI_ATMEL
|
||||
tristate "Atmel SPI Controller"
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
depends on OF
|
||||
help
|
||||
This selects a driver for the Atmel SPI Controller, present on
|
||||
many AT91 ARM chips.
|
||||
|
@ -143,7 +144,7 @@ config SPI_BCM63XX
|
|||
tristate "Broadcom BCM63xx SPI controller"
|
||||
depends on BCM63XX || COMPILE_TEST
|
||||
help
|
||||
Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
|
||||
Enable support for the SPI controller on the Broadcom BCM63xx SoCs.
|
||||
|
||||
config SPI_BCM63XX_HSSPI
|
||||
tristate "Broadcom BCM63XX HS SPI controller driver"
|
||||
|
@ -234,11 +235,11 @@ config SPI_DLN2
|
|||
tristate "Diolan DLN-2 USB SPI adapter"
|
||||
depends on MFD_DLN2
|
||||
help
|
||||
If you say yes to this option, support will be included for Diolan
|
||||
DLN2, a USB to SPI interface.
|
||||
If you say yes to this option, support will be included for Diolan
|
||||
DLN2, a USB to SPI interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called spi-dln2.
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called spi-dln2.
|
||||
|
||||
config SPI_EFM32
|
||||
tristate "EFM32 SPI controller"
|
||||
|
@ -747,10 +748,10 @@ config SPI_SYNQUACER
|
|||
It also supports the new dual-bit and quad-bit SPI protocol.
|
||||
|
||||
config SPI_MXIC
|
||||
tristate "Macronix MX25F0A SPI controller"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
This selects the Macronix MX25F0A SPI controller driver.
|
||||
tristate "Macronix MX25F0A SPI controller"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
This selects the Macronix MX25F0A SPI controller driver.
|
||||
|
||||
config SPI_MXS
|
||||
tristate "Freescale MXS SPI controller"
|
||||
|
|
|
@ -132,7 +132,7 @@ static int at91_usart_spi_configure_dma(struct spi_controller *ctlr,
|
|||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
ctlr->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
ctlr->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR_OR_NULL(ctlr->dma_tx)) {
|
||||
if (IS_ERR(ctlr->dma_tx)) {
|
||||
err = PTR_ERR(ctlr->dma_tx);
|
||||
|
@ -145,7 +145,7 @@ static int at91_usart_spi_configure_dma(struct spi_controller *ctlr,
|
|||
goto at91_usart_spi_error_clear;
|
||||
}
|
||||
|
||||
ctlr->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
ctlr->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR_OR_NULL(ctlr->dma_rx)) {
|
||||
if (IS_ERR(ctlr->dma_rx)) {
|
||||
err = PTR_ERR(ctlr->dma_rx);
|
||||
|
|
|
@ -222,37 +222,13 @@
|
|||
| SPI_BF(name, value))
|
||||
|
||||
/* Register access macros */
|
||||
#ifdef CONFIG_AVR32
|
||||
#define spi_readl(port, reg) \
|
||||
__raw_readl((port)->regs + SPI_##reg)
|
||||
#define spi_writel(port, reg, value) \
|
||||
__raw_writel((value), (port)->regs + SPI_##reg)
|
||||
|
||||
#define spi_readw(port, reg) \
|
||||
__raw_readw((port)->regs + SPI_##reg)
|
||||
#define spi_writew(port, reg, value) \
|
||||
__raw_writew((value), (port)->regs + SPI_##reg)
|
||||
|
||||
#define spi_readb(port, reg) \
|
||||
__raw_readb((port)->regs + SPI_##reg)
|
||||
#define spi_writeb(port, reg, value) \
|
||||
__raw_writeb((value), (port)->regs + SPI_##reg)
|
||||
#else
|
||||
#define spi_readl(port, reg) \
|
||||
readl_relaxed((port)->regs + SPI_##reg)
|
||||
#define spi_writel(port, reg, value) \
|
||||
writel_relaxed((value), (port)->regs + SPI_##reg)
|
||||
|
||||
#define spi_readw(port, reg) \
|
||||
readw_relaxed((port)->regs + SPI_##reg)
|
||||
#define spi_writew(port, reg, value) \
|
||||
writew_relaxed((value), (port)->regs + SPI_##reg)
|
||||
|
||||
#define spi_readb(port, reg) \
|
||||
readb_relaxed((port)->regs + SPI_##reg)
|
||||
#define spi_writeb(port, reg, value) \
|
||||
writeb_relaxed((value), (port)->regs + SPI_##reg)
|
||||
#endif
|
||||
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
|
||||
* cache operations; better heuristics consider wordsize and bitrate.
|
||||
*/
|
||||
|
@ -299,16 +275,16 @@ struct atmel_spi {
|
|||
|
||||
bool use_dma;
|
||||
bool use_pdc;
|
||||
bool use_cs_gpios;
|
||||
|
||||
bool keep_cs;
|
||||
|
||||
u32 fifo_size;
|
||||
u8 native_cs_free;
|
||||
u8 native_cs_for_gpio;
|
||||
};
|
||||
|
||||
/* Controller-specific per-slave state */
|
||||
struct atmel_spi_device {
|
||||
struct gpio_desc *npcs_pin;
|
||||
u32 csr;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
* controllers have CSAAT and friends.
|
||||
*
|
||||
* Since the CSAAT functionality is a bit weird on newer controllers as
|
||||
* well, we use GPIO to control nCSx pins on all controllers, updating
|
||||
* MR.PCS to avoid confusing the controller. Using GPIOs also lets us
|
||||
* support active-high chipselects despite the controller's belief that
|
||||
* only active-low devices/systems exists.
|
||||
* Even controller newer than ar91rm9200, using GPIOs can make sens as
|
||||
* it lets us support active-high chipselects despite the controller's
|
||||
* belief that only active-low devices/systems exists.
|
||||
*
|
||||
* However, at91rm9200 has a second erratum whereby nCS0 doesn't work
|
||||
* right when driven with GPIO. ("Mode Fault does not allow more than one
|
||||
|
@ -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)
|
||||
{
|
||||
struct atmel_spi_device *asd = spi->controller_state;
|
||||
int chip_select;
|
||||
u32 mr;
|
||||
|
||||
if (spi->cs_gpiod)
|
||||
chip_select = as->native_cs_for_gpio;
|
||||
else
|
||||
chip_select = spi->chip_select;
|
||||
|
||||
if (atmel_spi_is_v2(as)) {
|
||||
spi_writel(as, CSR0 + 4 * spi->chip_select, asd->csr);
|
||||
spi_writel(as, CSR0 + 4 * chip_select, asd->csr);
|
||||
/* For the low SPI version, there is a issue that PDC transfer
|
||||
* on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS
|
||||
*/
|
||||
spi_writel(as, CSR0, asd->csr);
|
||||
if (as->caps.has_wdrbt) {
|
||||
spi_writel(as, MR,
|
||||
SPI_BF(PCS, ~(0x01 << spi->chip_select))
|
||||
SPI_BF(PCS, ~(0x01 << chip_select))
|
||||
| SPI_BIT(WDRBT)
|
||||
| SPI_BIT(MODFDIS)
|
||||
| SPI_BIT(MSTR));
|
||||
} else {
|
||||
spi_writel(as, MR,
|
||||
SPI_BF(PCS, ~(0x01 << spi->chip_select))
|
||||
SPI_BF(PCS, ~(0x01 << chip_select))
|
||||
| SPI_BIT(MODFDIS)
|
||||
| SPI_BIT(MSTR));
|
||||
}
|
||||
|
||||
mr = spi_readl(as, MR);
|
||||
if (as->use_cs_gpios)
|
||||
gpiod_set_value(asd->npcs_pin, 1);
|
||||
if (spi->cs_gpiod)
|
||||
gpiod_set_value(spi->cs_gpiod, 1);
|
||||
} else {
|
||||
u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
|
||||
int i;
|
||||
|
@ -389,9 +369,9 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
|
|||
}
|
||||
|
||||
mr = spi_readl(as, MR);
|
||||
mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
|
||||
if (as->use_cs_gpios && spi->chip_select != 0)
|
||||
gpiod_set_value(asd->npcs_pin, 1);
|
||||
mr = SPI_BFINS(PCS, ~(1 << chip_select), mr);
|
||||
if (spi->cs_gpiod)
|
||||
gpiod_set_value(spi->cs_gpiod, 1);
|
||||
spi_writel(as, MR, mr);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
struct atmel_spi_device *asd = spi->controller_state;
|
||||
int chip_select;
|
||||
u32 mr;
|
||||
|
||||
if (spi->cs_gpiod)
|
||||
chip_select = as->native_cs_for_gpio;
|
||||
else
|
||||
chip_select = spi->chip_select;
|
||||
|
||||
/* only deactivate *this* device; sometimes transfers to
|
||||
* another device may be active when this routine is called.
|
||||
*/
|
||||
mr = spi_readl(as, MR);
|
||||
if (~SPI_BFEXT(PCS, mr) & (1 << spi->chip_select)) {
|
||||
if (~SPI_BFEXT(PCS, mr) & (1 << chip_select)) {
|
||||
mr = SPI_BFINS(PCS, 0xf, mr);
|
||||
spi_writel(as, MR, mr);
|
||||
}
|
||||
|
||||
dev_dbg(&spi->dev, "DEactivate NPCS, mr %08x\n", mr);
|
||||
|
||||
if (!as->use_cs_gpios)
|
||||
if (!spi->cs_gpiod)
|
||||
spi_writel(as, CR, SPI_BIT(LASTXFER));
|
||||
else if (atmel_spi_is_v2(as) || spi->chip_select != 0)
|
||||
gpiod_set_value(asd->npcs_pin, 0);
|
||||
else
|
||||
gpiod_set_value(spi->cs_gpiod, 0);
|
||||
}
|
||||
|
||||
static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock)
|
||||
|
@ -526,7 +511,7 @@ static int atmel_spi_configure_dma(struct spi_master *master,
|
|||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
master->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
err = PTR_ERR(master->dma_tx);
|
||||
if (err == -EPROBE_DEFER) {
|
||||
|
@ -843,6 +828,12 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
|
|||
{
|
||||
u32 scbr, csr;
|
||||
unsigned long bus_hz;
|
||||
int chip_select;
|
||||
|
||||
if (spi->cs_gpiod)
|
||||
chip_select = as->native_cs_for_gpio;
|
||||
else
|
||||
chip_select = spi->chip_select;
|
||||
|
||||
/* v1 chips start out at half the peripheral bus speed. */
|
||||
bus_hz = as->spi_clk;
|
||||
|
@ -871,9 +862,9 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
|
|||
xfer->speed_hz, scbr, bus_hz);
|
||||
return -EINVAL;
|
||||
}
|
||||
csr = spi_readl(as, CSR0 + 4 * spi->chip_select);
|
||||
csr = spi_readl(as, CSR0 + 4 * chip_select);
|
||||
csr = SPI_BFINS(SCBR, scbr, csr);
|
||||
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
|
||||
spi_writel(as, CSR0 + 4 * chip_select, csr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1172,40 +1163,105 @@ atmel_spi_pdc_interrupt(int irq, void *dev_id)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_word_delay_csr(struct spi_device *spi, struct atmel_spi *as)
|
||||
{
|
||||
struct spi_delay *delay = &spi->word_delay;
|
||||
u32 value = delay->value;
|
||||
|
||||
switch (delay->unit) {
|
||||
case SPI_DELAY_UNIT_NSECS:
|
||||
value /= 1000;
|
||||
break;
|
||||
case SPI_DELAY_UNIT_USECS:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return (as->spi_clk / 1000000 * value) >> 5;
|
||||
}
|
||||
|
||||
static void initialize_native_cs_for_gpio(struct atmel_spi *as)
|
||||
{
|
||||
int i;
|
||||
struct spi_master *master = platform_get_drvdata(as->pdev);
|
||||
|
||||
if (!as->native_cs_free)
|
||||
return; /* already initialized */
|
||||
|
||||
if (!master->cs_gpiods)
|
||||
return; /* No CS GPIO */
|
||||
|
||||
/*
|
||||
* On the first version of the controller (AT91RM9200), CS0
|
||||
* can't be used associated with GPIO
|
||||
*/
|
||||
if (atmel_spi_is_v2(as))
|
||||
i = 0;
|
||||
else
|
||||
i = 1;
|
||||
|
||||
for (; i < 4; i++)
|
||||
if (master->cs_gpiods[i])
|
||||
as->native_cs_free |= BIT(i);
|
||||
|
||||
if (as->native_cs_free)
|
||||
as->native_cs_for_gpio = ffs(as->native_cs_free);
|
||||
}
|
||||
|
||||
static int atmel_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct atmel_spi *as;
|
||||
struct atmel_spi_device *asd;
|
||||
u32 csr;
|
||||
unsigned int bits = spi->bits_per_word;
|
||||
int chip_select;
|
||||
int word_delay_csr;
|
||||
|
||||
as = spi_master_get_devdata(spi->master);
|
||||
|
||||
/* see notes above re chipselect */
|
||||
if (!atmel_spi_is_v2(as)
|
||||
&& spi->chip_select == 0
|
||||
&& (spi->mode & SPI_CS_HIGH)) {
|
||||
dev_dbg(&spi->dev, "setup: can't be active-high\n");
|
||||
if (!spi->cs_gpiod && (spi->mode & SPI_CS_HIGH)) {
|
||||
dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Setup() is called during spi_register_controller(aka
|
||||
* spi_register_master) but after all membmers of the cs_gpiod
|
||||
* array have been filled, so we can looked for which native
|
||||
* CS will be free for using with GPIO
|
||||
*/
|
||||
initialize_native_cs_for_gpio(as);
|
||||
|
||||
if (spi->cs_gpiod && as->native_cs_free) {
|
||||
dev_err(&spi->dev,
|
||||
"No native CS available to support this GPIO CS\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (spi->cs_gpiod)
|
||||
chip_select = as->native_cs_for_gpio;
|
||||
else
|
||||
chip_select = spi->chip_select;
|
||||
|
||||
csr = SPI_BF(BITS, bits - 8);
|
||||
if (spi->mode & SPI_CPOL)
|
||||
csr |= SPI_BIT(CPOL);
|
||||
if (!(spi->mode & SPI_CPHA))
|
||||
csr |= SPI_BIT(NCPHA);
|
||||
if (!as->use_cs_gpios)
|
||||
csr |= SPI_BIT(CSAAT);
|
||||
|
||||
/* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
|
||||
*/
|
||||
if (!spi->cs_gpiod)
|
||||
csr |= SPI_BIT(CSAAT);
|
||||
csr |= SPI_BF(DLYBS, 0);
|
||||
|
||||
word_delay_csr = atmel_word_delay_csr(spi, as);
|
||||
if (word_delay_csr < 0)
|
||||
return word_delay_csr;
|
||||
|
||||
/* DLYBCT adds delays between words. This is useful for slow devices
|
||||
* that need a bit of time to setup the next transfer.
|
||||
*/
|
||||
csr |= SPI_BF(DLYBCT,
|
||||
(as->spi_clk / 1000000 * spi->word_delay_usecs) >> 5);
|
||||
csr |= SPI_BF(DLYBCT, word_delay_csr);
|
||||
|
||||
asd = spi->controller_state;
|
||||
if (!asd) {
|
||||
|
@ -1213,21 +1269,6 @@ static int atmel_spi_setup(struct spi_device *spi)
|
|||
if (!asd)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* If use_cs_gpios is true this means that we have "cs-gpios"
|
||||
* defined in the device tree node so we should have
|
||||
* gotten the GPIO lines from the device tree inside the
|
||||
* SPI core. Warn if this is not the case but continue since
|
||||
* CS GPIOs are after all optional.
|
||||
*/
|
||||
if (as->use_cs_gpios) {
|
||||
if (!spi->cs_gpiod) {
|
||||
dev_err(&spi->dev,
|
||||
"host claims to use CS GPIOs but no CS found in DT by the SPI core\n");
|
||||
}
|
||||
asd->npcs_pin = spi->cs_gpiod;
|
||||
}
|
||||
|
||||
spi->controller_state = asd;
|
||||
}
|
||||
|
||||
|
@ -1238,7 +1279,7 @@ static int atmel_spi_setup(struct spi_device *spi)
|
|||
bits, spi->mode, spi->chip_select, csr);
|
||||
|
||||
if (!atmel_spi_is_v2(as))
|
||||
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
|
||||
spi_writel(as, CSR0 + 4 * chip_select, csr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1367,8 +1408,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
|||
&& as->use_pdc)
|
||||
atmel_spi_dma_unmap_xfer(master, xfer);
|
||||
|
||||
if (xfer->delay_usecs)
|
||||
udelay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
|
||||
if (xfer->cs_change) {
|
||||
if (list_is_last(&xfer->transfer_list,
|
||||
|
@ -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->dev.of_node = pdev->dev.of_node;
|
||||
master->bus_num = pdev->id;
|
||||
master->num_chipselect = master->dev.of_node ? 0 : 4;
|
||||
master->num_chipselect = 4;
|
||||
master->setup = atmel_spi_setup;
|
||||
master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
|
||||
master->transfer_one_message = atmel_spi_transfer_one_message;
|
||||
|
@ -1551,19 +1591,6 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
|||
|
||||
atmel_get_caps(as);
|
||||
|
||||
/*
|
||||
* If there are chip selects in the device tree, those will be
|
||||
* discovered by the SPI core when registering the SPI master
|
||||
* and assigned to each SPI device.
|
||||
*/
|
||||
as->use_cs_gpios = true;
|
||||
if (atmel_spi_is_v2(as) &&
|
||||
pdev->dev.of_node &&
|
||||
!of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) {
|
||||
as->use_cs_gpios = false;
|
||||
master->num_chipselect = 4;
|
||||
}
|
||||
|
||||
as->use_dma = false;
|
||||
as->use_pdc = false;
|
||||
if (as->caps.has_dma_support) {
|
||||
|
@ -1771,20 +1798,18 @@ static const struct dev_pm_ops atmel_spi_pm_ops = {
|
|||
#define ATMEL_SPI_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id atmel_spi_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91rm9200-spi" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver atmel_spi_driver = {
|
||||
.driver = {
|
||||
.name = "atmel_spi",
|
||||
.pm = ATMEL_SPI_PM_OPS,
|
||||
.of_match_table = of_match_ptr(atmel_spi_dt_ids),
|
||||
.of_match_table = atmel_spi_dt_ids,
|
||||
},
|
||||
.probe = atmel_spi_probe,
|
||||
.remove = atmel_spi_remove,
|
||||
|
|
|
@ -163,10 +163,21 @@ static void spi_engine_gen_xfer(struct spi_engine_program *p, bool dry,
|
|||
}
|
||||
|
||||
static void spi_engine_gen_sleep(struct spi_engine_program *p, bool dry,
|
||||
struct spi_engine *spi_engine, unsigned int clk_div, unsigned int delay)
|
||||
struct spi_engine *spi_engine, unsigned int clk_div,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
unsigned int spi_clk = clk_get_rate(spi_engine->ref_clk);
|
||||
unsigned int t;
|
||||
int delay;
|
||||
|
||||
if (xfer->delay_usecs) {
|
||||
delay = xfer->delay_usecs;
|
||||
} else {
|
||||
delay = spi_delay_to_ns(&xfer->delay, xfer);
|
||||
if (delay < 0)
|
||||
return;
|
||||
delay /= 1000;
|
||||
}
|
||||
|
||||
if (delay == 0)
|
||||
return;
|
||||
|
@ -218,8 +229,7 @@ static int spi_engine_compile_message(struct spi_engine *spi_engine,
|
|||
spi_engine_gen_cs(p, dry, spi, true);
|
||||
|
||||
spi_engine_gen_xfer(p, dry, xfer);
|
||||
spi_engine_gen_sleep(p, dry, spi_engine, clk_div,
|
||||
xfer->delay_usecs);
|
||||
spi_engine_gen_sleep(p, dry, spi_engine, clk_div, xfer);
|
||||
|
||||
cs_change = xfer->cs_change;
|
||||
if (list_is_last(&xfer->transfer_list, &msg->transfers))
|
||||
|
|
|
@ -803,7 +803,8 @@ static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
|
|||
return -EIO;
|
||||
|
||||
from = op->addr.val;
|
||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||
if (!spi->cs_gpiod)
|
||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||
bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
|
||||
|
||||
/*
|
||||
|
@ -882,7 +883,8 @@ static int bcm_qspi_transfer_one(struct spi_master *master,
|
|||
int slots;
|
||||
unsigned long timeo = msecs_to_jiffies(100);
|
||||
|
||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||
if (!spi->cs_gpiod)
|
||||
bcm_qspi_chip_select(qspi, spi->chip_select);
|
||||
qspi->trans_pos.trans = trans;
|
||||
qspi->trans_pos.byte = 0;
|
||||
|
||||
|
@ -1234,6 +1236,7 @@ int bcm_qspi_probe(struct platform_device *pdev,
|
|||
master->cleanup = bcm_qspi_cleanup;
|
||||
master->dev.of_node = dev->of_node;
|
||||
master->num_chipselect = NUM_CHIPSELECT;
|
||||
master->use_gpio_descriptors = true;
|
||||
|
||||
qspi->big_endian = of_device_is_big_endian(dev->of_node);
|
||||
|
||||
|
|
|
@ -291,8 +291,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
|
|||
|
||||
msg->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (t->cs_change)
|
||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
|
||||
|
|
|
@ -368,7 +368,7 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
|
|||
}
|
||||
|
||||
/* CS will be deasserted directly after transfer */
|
||||
if (t->delay_usecs) {
|
||||
if (t->delay_usecs || t->delay.value) {
|
||||
dev_err(&spi->dev, "unable to keep CS asserted after transfer\n");
|
||||
status = -EINVAL;
|
||||
goto exit;
|
||||
|
|
|
@ -119,8 +119,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
|
|||
*rx_buf++ = (u8)v;
|
||||
}
|
||||
|
||||
if (xfer->delay_usecs)
|
||||
udelay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
|
||||
return xfer->len;
|
||||
}
|
||||
|
|
|
@ -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,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
|
||||
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
|
||||
{ .compatible = "renesas,rzn1-spi", },
|
||||
{ /* end of table */}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -35,7 +36,7 @@ static struct spi_pci_desc spi_pci_mid_desc_2 = {
|
|||
};
|
||||
|
||||
static struct spi_pci_desc spi_pci_ehl_desc = {
|
||||
.num_cs = 1,
|
||||
.num_cs = 2,
|
||||
.bus_num = -1,
|
||||
.max_freq = 100000000,
|
||||
};
|
||||
|
@ -57,13 +58,18 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
/* Get basic io resource and map it */
|
||||
dws->paddr = pci_resource_start(pdev, pci_bar);
|
||||
pci_set_master(pdev);
|
||||
|
||||
ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dws->regs = pcim_iomap_table(pdev)[pci_bar];
|
||||
dws->irq = pdev->irq;
|
||||
dws->irq = pci_irq_vector(pdev, 0);
|
||||
|
||||
/*
|
||||
* Specific handling for platforms, like dma setup,
|
||||
|
@ -80,12 +86,15 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
return ret;
|
||||
}
|
||||
} else {
|
||||
pci_free_irq_vectors(pdev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = dw_spi_add_host(&pdev->dev, dws);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
pci_free_irq_vectors(pdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* PCI hook and SPI hook use the same drv data */
|
||||
pci_set_drvdata(pdev, dws);
|
||||
|
@ -93,6 +102,11 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n",
|
||||
pdev->vendor, pdev->device);
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_put_autosuspend(&pdev->dev);
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -100,7 +114,11 @@ static void spi_pci_remove(struct pci_dev *pdev)
|
|||
{
|
||||
struct dw_spi *dws = pci_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_forbid(&pdev->dev);
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
|
||||
dw_spi_remove_host(dws);
|
||||
pci_free_irq_vectors(pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -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.fwnode = dev->fwnode;
|
||||
master->flags = SPI_MASTER_GPIO_SS;
|
||||
master->auto_runtime_pm = true;
|
||||
|
||||
if (dws->set_cs)
|
||||
master->set_cs = dws->set_cs;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include <linux/io.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
/* Register offsets */
|
||||
#define DW_SPI_CTRL0 0x00
|
||||
|
|
|
@ -377,7 +377,7 @@ static int falcon_sflash_xfer_one(struct spi_master *master,
|
|||
|
||||
m->actual_length += t->len;
|
||||
|
||||
WARN_ON(t->delay_usecs || t->cs_change);
|
||||
WARN_ON(t->delay_usecs || t->delay.value || t->cs_change);
|
||||
spi_flags = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@ enum dspi_trans_mode {
|
|||
struct fsl_dspi_devtype_data {
|
||||
enum dspi_trans_mode trans_mode;
|
||||
u8 max_clock_factor;
|
||||
bool ptp_sts_supported;
|
||||
bool xspi_mode;
|
||||
};
|
||||
|
||||
|
@ -140,12 +141,14 @@ static const struct fsl_dspi_devtype_data vf610_data = {
|
|||
static const struct fsl_dspi_devtype_data ls1021a_v1_data = {
|
||||
.trans_mode = DSPI_TCFQ_MODE,
|
||||
.max_clock_factor = 8,
|
||||
.ptp_sts_supported = true,
|
||||
.xspi_mode = true,
|
||||
};
|
||||
|
||||
static const struct fsl_dspi_devtype_data ls2085a_data = {
|
||||
.trans_mode = DSPI_TCFQ_MODE,
|
||||
.max_clock_factor = 8,
|
||||
.ptp_sts_supported = true,
|
||||
};
|
||||
|
||||
static const struct fsl_dspi_devtype_data coldfire_data = {
|
||||
|
@ -654,6 +657,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
|
|||
u16 spi_tcnt;
|
||||
u32 spi_tcr;
|
||||
|
||||
spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer,
|
||||
dspi->tx - dspi->bytes_per_word, !dspi->irq);
|
||||
|
||||
/* Get transfer counter (in number of SPI transfers). It was
|
||||
* reset to 0 when transfer(s) were started.
|
||||
*/
|
||||
|
@ -672,6 +678,9 @@ static int dspi_rxtx(struct fsl_dspi *dspi)
|
|||
/* Success! */
|
||||
return 0;
|
||||
|
||||
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
|
||||
dspi->tx, !dspi->irq);
|
||||
|
||||
if (trans_mode == DSPI_EOQ_MODE)
|
||||
dspi_eoq_write(dspi);
|
||||
else if (trans_mode == DSPI_TCFQ_MODE)
|
||||
|
@ -779,6 +788,9 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
|
|||
SPI_FRAME_EBITS(transfer->bits_per_word) |
|
||||
SPI_CTARE_DTCP(1));
|
||||
|
||||
spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
|
||||
dspi->tx, !dspi->irq);
|
||||
|
||||
trans_mode = dspi->devtype_data->trans_mode;
|
||||
switch (trans_mode) {
|
||||
case DSPI_EOQ_MODE:
|
||||
|
@ -815,8 +827,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
|
|||
dev_err(&dspi->pdev->dev,
|
||||
"Waiting for transfer to complete failed!\n");
|
||||
|
||||
if (transfer->delay_usecs)
|
||||
udelay(transfer->delay_usecs);
|
||||
spi_transfer_delay_exec(transfer);
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -1006,6 +1017,25 @@ static void dspi_init(struct fsl_dspi *dspi)
|
|||
SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1));
|
||||
}
|
||||
|
||||
static int dspi_slave_abort(struct spi_master *master)
|
||||
{
|
||||
struct fsl_dspi *dspi = spi_master_get_devdata(master);
|
||||
|
||||
/*
|
||||
* Terminate all pending DMA transactions for the SPI working
|
||||
* in SLAVE mode.
|
||||
*/
|
||||
dmaengine_terminate_sync(dspi->dma->chan_rx);
|
||||
dmaengine_terminate_sync(dspi->dma->chan_tx);
|
||||
|
||||
/* Clear the internal DSPI RX and TX FIFO buffers */
|
||||
regmap_update_bits(dspi->regmap, SPI_MCR,
|
||||
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
|
||||
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
@ -1030,6 +1060,7 @@ static int dspi_probe(struct platform_device *pdev)
|
|||
ctlr->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
ctlr->cleanup = dspi_cleanup;
|
||||
ctlr->slave_abort = dspi_slave_abort;
|
||||
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
@ -1135,6 +1166,7 @@ static int dspi_probe(struct platform_device *pdev)
|
|||
init_waitqueue_head(&dspi->waitq);
|
||||
|
||||
poll_mode:
|
||||
|
||||
if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
|
||||
ret = dspi_request_dma(dspi, res->start);
|
||||
if (ret < 0) {
|
||||
|
@ -1146,6 +1178,8 @@ poll_mode:
|
|||
ctlr->max_speed_hz =
|
||||
clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor;
|
||||
|
||||
ctlr->ptp_sts_supported = dspi->devtype_data->ptp_sts_supported;
|
||||
|
||||
platform_set_drvdata(pdev, ctlr);
|
||||
|
||||
ret = spi_register_controller(ctlr);
|
||||
|
|
|
@ -427,8 +427,7 @@ static int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans)
|
|||
|
||||
ret = fsl_espi_bufs(spi, trans);
|
||||
|
||||
if (trans->delay_usecs)
|
||||
udelay(trans->delay_usecs);
|
||||
spi_transfer_delay_exec(trans);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -437,6 +436,7 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
|
|||
struct spi_message *m)
|
||||
{
|
||||
unsigned int delay_usecs = 0, rx_nbits = 0;
|
||||
unsigned int delay_nsecs = 0, delay_nsecs1 = 0;
|
||||
struct spi_transfer *t, trans = {};
|
||||
int ret;
|
||||
|
||||
|
@ -445,8 +445,16 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
|
|||
goto out;
|
||||
|
||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||
if (t->delay_usecs > delay_usecs)
|
||||
delay_usecs = t->delay_usecs;
|
||||
if (t->delay_usecs) {
|
||||
if (t->delay_usecs > delay_usecs) {
|
||||
delay_usecs = t->delay_usecs;
|
||||
delay_nsecs = delay_usecs * 1000;
|
||||
}
|
||||
} else {
|
||||
delay_nsecs1 = spi_delay_to_ns(&t->delay, t);
|
||||
if (delay_nsecs1 > delay_nsecs)
|
||||
delay_nsecs = delay_nsecs1;
|
||||
}
|
||||
if (t->rx_nbits > rx_nbits)
|
||||
rx_nbits = t->rx_nbits;
|
||||
}
|
||||
|
@ -457,7 +465,8 @@ static int fsl_espi_do_one_msg(struct spi_master *master,
|
|||
trans.len = m->frame_length;
|
||||
trans.speed_hz = t->speed_hz;
|
||||
trans.bits_per_word = t->bits_per_word;
|
||||
trans.delay_usecs = delay_usecs;
|
||||
trans.delay.value = delay_nsecs;
|
||||
trans.delay.unit = SPI_DELAY_UNIT_NSECS;
|
||||
trans.rx_nbits = rx_nbits;
|
||||
|
||||
if (trans.len)
|
||||
|
|
|
@ -675,7 +675,7 @@ static int fsl_lpspi_dma_init(struct device *dev,
|
|||
int ret;
|
||||
|
||||
/* Prepare for TX DMA: */
|
||||
controller->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
controller->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(controller->dma_tx)) {
|
||||
ret = PTR_ERR(controller->dma_tx);
|
||||
dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
|
||||
|
@ -684,7 +684,7 @@ static int fsl_lpspi_dma_init(struct device *dev,
|
|||
}
|
||||
|
||||
/* Prepare for RX DMA: */
|
||||
controller->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
controller->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(controller->dma_rx)) {
|
||||
ret = PTR_ERR(controller->dma_rx);
|
||||
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
|
||||
|
@ -779,7 +779,7 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_id)
|
|||
|
||||
if (temp_SR & SR_FCF && (temp_IER & IER_FCIE)) {
|
||||
writel(SR_FCF, fsl_lpspi->base + IMX7ULP_SR);
|
||||
complete(&fsl_lpspi->xfer_done);
|
||||
complete(&fsl_lpspi->xfer_done);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,11 @@
|
|||
#define QUADSPI_FLSHCR_TCSH_MASK GENMASK(11, 8)
|
||||
#define QUADSPI_FLSHCR_TDH_MASK GENMASK(17, 16)
|
||||
|
||||
#define QUADSPI_BUF0CR 0x10
|
||||
#define QUADSPI_BUF1CR 0x14
|
||||
#define QUADSPI_BUF2CR 0x18
|
||||
#define QUADSPI_BUFXCR_INVALID_MSTRID 0xe
|
||||
|
||||
#define QUADSPI_BUF3CR 0x1c
|
||||
#define QUADSPI_BUF3CR_ALLMST_MASK BIT(31)
|
||||
#define QUADSPI_BUF3CR_ADATSZ(x) ((x) << 8)
|
||||
|
@ -195,6 +200,7 @@
|
|||
struct fsl_qspi_devtype_data {
|
||||
unsigned int rxfifo;
|
||||
unsigned int txfifo;
|
||||
int invalid_mstrid;
|
||||
unsigned int ahb_buf_size;
|
||||
unsigned int quirks;
|
||||
bool little_endian;
|
||||
|
@ -203,6 +209,7 @@ struct fsl_qspi_devtype_data {
|
|||
static const struct fsl_qspi_devtype_data vybrid_data = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_64,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = QUADSPI_QUIRK_SWAP_ENDIAN,
|
||||
.little_endian = true,
|
||||
|
@ -211,6 +218,7 @@ static const struct fsl_qspi_devtype_data vybrid_data = {
|
|||
static const struct fsl_qspi_devtype_data imx6sx_data = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_512,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = QUADSPI_QUIRK_4X_INT_CLK | QUADSPI_QUIRK_TKT245618,
|
||||
.little_endian = true,
|
||||
|
@ -219,6 +227,7 @@ static const struct fsl_qspi_devtype_data imx6sx_data = {
|
|||
static const struct fsl_qspi_devtype_data imx7d_data = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_512,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
|
||||
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 = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_512,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
|
||||
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 = {
|
||||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_64,
|
||||
.invalid_mstrid = QUADSPI_BUFXCR_INVALID_MSTRID,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.quirks = 0,
|
||||
.little_endian = false,
|
||||
|
@ -246,6 +257,7 @@ static const struct fsl_qspi_devtype_data ls2080a_data = {
|
|||
.rxfifo = SZ_128,
|
||||
.txfifo = SZ_64,
|
||||
.ahb_buf_size = SZ_1K,
|
||||
.invalid_mstrid = 0x0,
|
||||
.quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_BASE_INTERNAL,
|
||||
.little_endian = true,
|
||||
};
|
||||
|
@ -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;
|
||||
u32 addr_offset = 0;
|
||||
int err = 0;
|
||||
int invalid_mstrid = q->devtype_data->invalid_mstrid;
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -416,8 +416,7 @@ static int fsl_spi_do_one_msg(struct spi_master *master,
|
|||
}
|
||||
m->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (cs_change) {
|
||||
ndelay(nsecs);
|
||||
|
|
|
@ -362,9 +362,6 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
|||
struct spi_gpio *spi_gpio;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct spi_bitbang *bb;
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
of_id = of_match_device(spi_gpio_dt_ids, &pdev->dev);
|
||||
|
||||
master = spi_alloc_master(dev, sizeof(*spi_gpio));
|
||||
if (!master)
|
||||
|
@ -376,7 +373,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
|||
return status;
|
||||
}
|
||||
|
||||
if (of_id)
|
||||
if (pdev->dev.of_node)
|
||||
status = spi_gpio_probe_dt(pdev, master);
|
||||
else
|
||||
status = spi_gpio_probe_pdata(pdev, master);
|
||||
|
|
|
@ -673,6 +673,8 @@ static int img_spfi_probe(struct platform_device *pdev)
|
|||
dma_release_channel(spfi->tx_ch);
|
||||
if (spfi->rx_ch)
|
||||
dma_release_channel(spfi->rx_ch);
|
||||
spfi->tx_ch = NULL;
|
||||
spfi->rx_ch = NULL;
|
||||
dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n");
|
||||
} else {
|
||||
master->dma_tx = spfi->tx_ch;
|
||||
|
|
|
@ -1272,7 +1272,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
|
|||
spi_imx->wml = spi_imx->devtype_data->fifo_size / 2;
|
||||
|
||||
/* Prepare for TX DMA: */
|
||||
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
master->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
ret = PTR_ERR(master->dma_tx);
|
||||
dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
|
||||
|
@ -1281,7 +1281,7 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
|
|||
}
|
||||
|
||||
/* Prepare for RX : */
|
||||
master->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
master->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(master->dma_rx)) {
|
||||
ret = PTR_ERR(master->dma_rx);
|
||||
dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
|
||||
|
|
|
@ -797,7 +797,6 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct spi_master *master;
|
||||
struct resource *res;
|
||||
struct lantiq_ssc_spi *spi;
|
||||
const struct lantiq_ssc_hwcfg *hwcfg;
|
||||
const struct of_device_id *match;
|
||||
|
@ -812,12 +811,6 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
|||
}
|
||||
hwcfg = match->data;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "failed to get resources\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
rx_irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME);
|
||||
if (rx_irq < 0)
|
||||
return -ENXIO;
|
||||
|
@ -839,8 +832,7 @@ static int lantiq_ssc_probe(struct platform_device *pdev)
|
|||
spi->dev = dev;
|
||||
spi->hwcfg = hwcfg;
|
||||
platform_set_drvdata(pdev, spi);
|
||||
|
||||
spi->regbase = devm_ioremap_resource(dev, res);
|
||||
spi->regbase = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(spi->regbase)) {
|
||||
err = PTR_ERR(spi->regbase);
|
||||
goto err_master_put;
|
||||
|
|
|
@ -298,12 +298,18 @@ static struct spi_test spi_tests[] = {
|
|||
{
|
||||
.tx_buf = TX(0),
|
||||
.rx_buf = RX(0),
|
||||
.delay_usecs = 1000,
|
||||
.delay = {
|
||||
.value = 1000,
|
||||
.unit = SPI_DELAY_UNIT_USECS,
|
||||
},
|
||||
},
|
||||
{
|
||||
.tx_buf = TX(0),
|
||||
.rx_buf = RX(0),
|
||||
.delay_usecs = 1000,
|
||||
.delay = {
|
||||
.value = 1000,
|
||||
.unit = SPI_DELAY_UNIT_USECS,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -537,7 +543,7 @@ static int spi_test_check_elapsed_time(struct spi_device *spi,
|
|||
unsigned long long nbits = (unsigned long long)BITS_PER_BYTE *
|
||||
xfer->len;
|
||||
|
||||
delay_usecs += xfer->delay_usecs;
|
||||
delay_usecs += xfer->delay.value;
|
||||
if (!xfer->speed_hz)
|
||||
continue;
|
||||
estimated_time += div_u64(nbits * NSEC_PER_SEC, xfer->speed_hz);
|
||||
|
|
|
@ -286,7 +286,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
|||
if (!spi_mem_internal_supports_op(mem, op))
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (ctlr->mem_ops) {
|
||||
if (ctlr->mem_ops && !mem->spi->cs_gpiod) {
|
||||
ret = spi_mem_access_start(mem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
@ -311,8 +311,7 @@ static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
|
|||
break;
|
||||
m->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (cs_change)
|
||||
mpc512x_psc_spi_deactivate_cs(spi);
|
||||
|
|
|
@ -234,8 +234,7 @@ static void mpc52xx_psc_spi_work(struct work_struct *work)
|
|||
break;
|
||||
m->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (cs_change)
|
||||
mpc52xx_psc_spi_deactivate_cs(spi);
|
||||
|
|
|
@ -139,7 +139,6 @@ static const struct mtk_spi_compatible mt8183_compat = {
|
|||
* supplies it.
|
||||
*/
|
||||
static const struct mtk_chip_config mtk_default_chip_info = {
|
||||
.cs_pol = 0,
|
||||
.sample_sel = 0,
|
||||
};
|
||||
|
||||
|
@ -230,10 +229,12 @@ static int mtk_spi_prepare_message(struct spi_master *master,
|
|||
#endif
|
||||
|
||||
if (mdata->dev_comp->enhance_timing) {
|
||||
if (chip_config->cs_pol)
|
||||
/* set CS polarity */
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
reg_val |= SPI_CMD_CS_POL;
|
||||
else
|
||||
reg_val &= ~SPI_CMD_CS_POL;
|
||||
|
||||
if (chip_config->sample_sel)
|
||||
reg_val |= SPI_CMD_SAMPLE_SEL;
|
||||
else
|
||||
|
@ -264,6 +265,9 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
|
|||
u32 reg_val;
|
||||
struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
|
||||
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
enable = !enable;
|
||||
|
||||
reg_val = readl(mdata->base + SPI_CMD_REG);
|
||||
if (!enable) {
|
||||
reg_val |= SPI_CMD_PAUSE_EN;
|
||||
|
@ -619,7 +623,6 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
|||
struct spi_master *master;
|
||||
struct mtk_spi *mdata;
|
||||
const struct of_device_id *of_id;
|
||||
struct resource *res;
|
||||
int i, irq, ret, addr_bits;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
|
||||
|
@ -647,6 +650,10 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
|||
|
||||
mdata = spi_master_get_devdata(master);
|
||||
mdata->dev_comp = of_id->data;
|
||||
|
||||
if (mdata->dev_comp->enhance_timing)
|
||||
master->mode_bits |= SPI_CS_HIGH;
|
||||
|
||||
if (mdata->dev_comp->must_tx)
|
||||
master->flags = SPI_MASTER_MUST_TX;
|
||||
|
||||
|
@ -682,15 +689,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
platform_set_drvdata(pdev, master);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&pdev->dev, "failed to determine base address\n");
|
||||
goto err_put_master;
|
||||
}
|
||||
|
||||
mdata->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
mdata->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mdata->base)) {
|
||||
ret = PTR_ERR(mdata->base);
|
||||
goto err_put_master;
|
||||
|
|
|
@ -346,7 +346,7 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem,
|
|||
if (op->addr.nbytes > 7)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return spi_mem_default_supports_op(mem, op);
|
||||
}
|
||||
|
||||
static int mxic_spi_mem_exec_op(struct spi_mem *mem,
|
||||
|
|
|
@ -293,7 +293,6 @@ static void npcm_pspi_reset_hw(struct npcm_pspi *priv)
|
|||
static irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct npcm_pspi *priv = dev_id;
|
||||
u16 val;
|
||||
u8 stat;
|
||||
|
||||
stat = ioread8(priv->base + NPCM_PSPI_STAT);
|
||||
|
@ -303,7 +302,7 @@ static irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
|
|||
|
||||
if (priv->tx_buf) {
|
||||
if (stat & NPCM_PSPI_STAT_RBF) {
|
||||
val = ioread8(NPCM_PSPI_DATA + priv->base);
|
||||
ioread8(NPCM_PSPI_DATA + priv->base);
|
||||
if (priv->tx_bytes == 0) {
|
||||
npcm_pspi_disable(priv);
|
||||
complete(&priv->xfer_done);
|
||||
|
|
|
@ -1027,7 +1027,7 @@ static int nxp_fspi_probe(struct platform_device *pdev)
|
|||
|
||||
ctlr->dev.of_node = np;
|
||||
|
||||
ret = spi_register_controller(ctlr);
|
||||
ret = devm_spi_register_controller(&pdev->dev, ctlr);
|
||||
if (ret)
|
||||
goto err_destroy_mutex;
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
|
|||
|
||||
static int spi100k_read_data(struct spi_master *master, int len)
|
||||
{
|
||||
int dataH, dataL;
|
||||
int dataL;
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
/* Always do at least 16 bits */
|
||||
|
@ -146,7 +146,7 @@ static int spi100k_read_data(struct spi_master *master, int len)
|
|||
udelay(1000);
|
||||
|
||||
dataL = readw(spi100k->base + SPI_RX_LSB);
|
||||
dataH = readw(spi100k->base + SPI_RX_MSB);
|
||||
readw(spi100k->base + SPI_RX_MSB);
|
||||
spi100k_disable_clock(master);
|
||||
|
||||
return dataL;
|
||||
|
@ -321,8 +321,7 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
|
|||
}
|
||||
}
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
/* ignore the "leave it on after last xfer" hint */
|
||||
|
||||
|
|
|
@ -397,30 +397,26 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
|
|||
{
|
||||
struct omap2_mcspi *mcspi;
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
|
||||
mcspi = spi_master_get_devdata(spi->master);
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
|
||||
if (mcspi_dma->dma_tx) {
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
|
||||
|
||||
dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
|
||||
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
|
||||
xfer->tx_sg.nents,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_tx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
|
||||
xfer->tx_sg.nents,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_tx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
dma_async_issue_pending(mcspi_dma->dma_tx);
|
||||
omap2_mcspi_set_dma_req(spi, 0, 1);
|
||||
|
||||
}
|
||||
|
||||
static unsigned
|
||||
|
@ -439,6 +435,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
|||
int word_len, element_count;
|
||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||
void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
|
||||
mcspi = spi_master_get_devdata(spi->master);
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
|
@ -462,55 +459,47 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
|||
else /* word_len <= 32 */
|
||||
element_count = count >> 2;
|
||||
|
||||
if (mcspi_dma->dma_rx) {
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
|
||||
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
|
||||
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
|
||||
|
||||
/*
|
||||
* Reduce DMA transfer length by one more if McSPI is
|
||||
* configured in turbo mode.
|
||||
*/
|
||||
if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
|
||||
transfer_reduction += es;
|
||||
|
||||
if (transfer_reduction) {
|
||||
/* Split sgl into two. The second sgl won't be used. */
|
||||
sizes[0] = count - transfer_reduction;
|
||||
sizes[1] = transfer_reduction;
|
||||
nb_sizes = 2;
|
||||
} else {
|
||||
/*
|
||||
* Reduce DMA transfer length by one more if McSPI is
|
||||
* configured in turbo mode.
|
||||
* Don't bother splitting the sgl. This essentially
|
||||
* clones the original sgl.
|
||||
*/
|
||||
if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
|
||||
transfer_reduction += es;
|
||||
sizes[0] = count;
|
||||
nb_sizes = 1;
|
||||
}
|
||||
|
||||
if (transfer_reduction) {
|
||||
/* Split sgl into two. The second sgl won't be used. */
|
||||
sizes[0] = count - transfer_reduction;
|
||||
sizes[1] = transfer_reduction;
|
||||
nb_sizes = 2;
|
||||
} else {
|
||||
/*
|
||||
* Don't bother splitting the sgl. This essentially
|
||||
* clones the original sgl.
|
||||
*/
|
||||
sizes[0] = count;
|
||||
nb_sizes = 1;
|
||||
}
|
||||
ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, 0, nb_sizes,
|
||||
sizes, sg_out, out_mapped_nents, GFP_KERNEL);
|
||||
|
||||
ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents,
|
||||
0, nb_sizes,
|
||||
sizes,
|
||||
sg_out, out_mapped_nents,
|
||||
GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "sg_split failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "sg_split failed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx,
|
||||
sg_out[0],
|
||||
out_mapped_nents[0],
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_rx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, sg_out[0],
|
||||
out_mapped_nents[0], DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_rx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
|
||||
dma_async_issue_pending(mcspi_dma->dma_rx);
|
||||
|
|
|
@ -467,8 +467,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
|
|||
if (orion_spi_write_read_8bit(spi, &tx, &rx) < 0)
|
||||
goto out;
|
||||
count--;
|
||||
if (xfer->word_delay_usecs)
|
||||
udelay(xfer->word_delay_usecs);
|
||||
spi_delay_exec(&xfer->word_delay, xfer);
|
||||
} while (count);
|
||||
} else if (word_len == 16) {
|
||||
const u16 *tx = xfer->tx_buf;
|
||||
|
@ -478,8 +477,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
|
|||
if (orion_spi_write_read_16bit(spi, &tx, &rx) < 0)
|
||||
goto out;
|
||||
count -= 2;
|
||||
if (xfer->word_delay_usecs)
|
||||
udelay(xfer->word_delay_usecs);
|
||||
spi_delay_exec(&xfer->word_delay, xfer);
|
||||
} while (count);
|
||||
}
|
||||
|
||||
|
|
|
@ -606,25 +606,30 @@ static void pic32_spi_cleanup(struct spi_device *spi)
|
|||
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
|
||||
}
|
||||
|
||||
static void pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
|
||||
static int pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
|
||||
{
|
||||
struct spi_master *master = pic32s->master;
|
||||
dma_cap_mask_t mask;
|
||||
int ret = 0;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
master->dma_rx = dma_request_chan(dev, "spi-rx");
|
||||
if (IS_ERR(master->dma_rx)) {
|
||||
if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER)
|
||||
ret = -EPROBE_DEFER;
|
||||
else
|
||||
dev_warn(dev, "RX channel not found.\n");
|
||||
|
||||
master->dma_rx = dma_request_slave_channel_compat(mask, NULL, NULL,
|
||||
dev, "spi-rx");
|
||||
if (!master->dma_rx) {
|
||||
dev_warn(dev, "RX channel not found.\n");
|
||||
master->dma_rx = NULL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
master->dma_tx = dma_request_slave_channel_compat(mask, NULL, NULL,
|
||||
dev, "spi-tx");
|
||||
if (!master->dma_tx) {
|
||||
dev_warn(dev, "TX channel not found.\n");
|
||||
master->dma_tx = dma_request_chan(dev, "spi-tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER)
|
||||
ret = -EPROBE_DEFER;
|
||||
else
|
||||
dev_warn(dev, "TX channel not found.\n");
|
||||
|
||||
master->dma_tx = NULL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
|
@ -634,14 +639,20 @@ static void pic32_spi_dma_prep(struct pic32_spi *pic32s, struct device *dev)
|
|||
/* DMA chnls allocated and prepared */
|
||||
set_bit(PIC32F_DMA_PREP, &pic32s->flags);
|
||||
|
||||
return;
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
if (master->dma_rx)
|
||||
if (master->dma_rx) {
|
||||
dma_release_channel(master->dma_rx);
|
||||
master->dma_rx = NULL;
|
||||
}
|
||||
|
||||
if (master->dma_tx)
|
||||
if (master->dma_tx) {
|
||||
dma_release_channel(master->dma_tx);
|
||||
master->dma_tx = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pic32_spi_dma_unprep(struct pic32_spi *pic32s)
|
||||
|
@ -776,7 +787,10 @@ static int pic32_spi_probe(struct platform_device *pdev)
|
|||
master->unprepare_transfer_hardware = pic32_spi_unprepare_hardware;
|
||||
|
||||
/* optional DMA support */
|
||||
pic32_spi_dma_prep(pic32s, &pdev->dev);
|
||||
ret = pic32_spi_dma_prep(pic32s, &pdev->dev);
|
||||
if (ret)
|
||||
goto err_bailout;
|
||||
|
||||
if (test_bit(PIC32F_DMA_PREP, &pic32s->flags))
|
||||
master->can_dma = pic32_spi_can_dma;
|
||||
|
||||
|
|
|
@ -485,12 +485,11 @@ static void giveback(struct pl022 *pl022)
|
|||
struct spi_transfer, transfer_list);
|
||||
|
||||
/* Delay if requested before any change in chip select */
|
||||
if (last_transfer->delay_usecs)
|
||||
/*
|
||||
* FIXME: This runs in interrupt context.
|
||||
* Is this really smart?
|
||||
*/
|
||||
udelay(last_transfer->delay_usecs);
|
||||
/*
|
||||
* FIXME: This runs in interrupt context.
|
||||
* Is this really smart?
|
||||
*/
|
||||
spi_transfer_delay_exec(last_transfer);
|
||||
|
||||
if (!last_transfer->cs_change) {
|
||||
struct spi_message *next_msg;
|
||||
|
@ -1159,7 +1158,7 @@ static int pl022_dma_autoprobe(struct pl022 *pl022)
|
|||
int err;
|
||||
|
||||
/* automatically configure DMA channels from platform, normally using DT */
|
||||
chan = dma_request_slave_channel_reason(dev, "rx");
|
||||
chan = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(chan)) {
|
||||
err = PTR_ERR(chan);
|
||||
goto err_no_rxchan;
|
||||
|
@ -1167,7 +1166,7 @@ static int pl022_dma_autoprobe(struct pl022 *pl022)
|
|||
|
||||
pl022->dma_rx_channel = chan;
|
||||
|
||||
chan = dma_request_slave_channel_reason(dev, "tx");
|
||||
chan = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(chan)) {
|
||||
err = PTR_ERR(chan);
|
||||
goto err_no_txchan;
|
||||
|
@ -1401,12 +1400,11 @@ static void pump_transfers(unsigned long data)
|
|||
previous = list_entry(transfer->transfer_list.prev,
|
||||
struct spi_transfer,
|
||||
transfer_list);
|
||||
if (previous->delay_usecs)
|
||||
/*
|
||||
* FIXME: This runs in interrupt context.
|
||||
* Is this really smart?
|
||||
*/
|
||||
udelay(previous->delay_usecs);
|
||||
/*
|
||||
* FIXME: This runs in interrupt context.
|
||||
* Is this really smart?
|
||||
*/
|
||||
spi_transfer_delay_exec(previous);
|
||||
|
||||
/* Reselect chip select only if cs_change was requested */
|
||||
if (previous->cs_change)
|
||||
|
@ -1520,8 +1518,7 @@ static void do_polling_transfer(struct pl022 *pl022)
|
|||
previous =
|
||||
list_entry(transfer->transfer_list.prev,
|
||||
struct spi_transfer, transfer_list);
|
||||
if (previous->delay_usecs)
|
||||
udelay(previous->delay_usecs);
|
||||
spi_transfer_delay_exec(previous);
|
||||
if (previous->cs_change)
|
||||
pl022_cs_control(pl022, SSP_CHIP_SELECT);
|
||||
} else {
|
||||
|
|
|
@ -4,27 +4,29 @@
|
|||
* Copyright (C) 2013, Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include "spi-pxa2xx.h"
|
||||
|
||||
|
@ -1480,11 +1482,13 @@ MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match);
|
|||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
|
||||
static int pxa2xx_spi_get_port_id(struct device *dev)
|
||||
{
|
||||
struct acpi_device *adev;
|
||||
unsigned int devid;
|
||||
int port_id = -1;
|
||||
|
||||
adev = ACPI_COMPANION(dev);
|
||||
if (adev && adev->pnp.unique_id &&
|
||||
!kstrtouint(adev->pnp.unique_id, 0, &devid))
|
||||
port_id = devid;
|
||||
|
@ -1493,7 +1497,7 @@ static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
|
|||
|
||||
#else /* !CONFIG_ACPI */
|
||||
|
||||
static int pxa2xx_spi_get_port_id(struct acpi_device *adev)
|
||||
static int pxa2xx_spi_get_port_id(struct device *dev)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
@ -1514,34 +1518,22 @@ static struct pxa2xx_spi_controller *
|
|||
pxa2xx_spi_init_pdata(struct platform_device *pdev)
|
||||
{
|
||||
struct pxa2xx_spi_controller *pdata;
|
||||
struct acpi_device *adev;
|
||||
struct ssp_device *ssp;
|
||||
struct resource *res;
|
||||
const struct acpi_device_id *adev_id = NULL;
|
||||
struct device *parent = pdev->dev.parent;
|
||||
struct pci_dev *pcidev = dev_is_pci(parent) ? to_pci_dev(parent) : NULL;
|
||||
const struct pci_device_id *pcidev_id = NULL;
|
||||
const struct of_device_id *of_id = NULL;
|
||||
enum pxa_ssp_type type;
|
||||
const void *match;
|
||||
|
||||
adev = ACPI_COMPANION(&pdev->dev);
|
||||
if (pcidev)
|
||||
pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match, pcidev);
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
of_id = of_match_device(pdev->dev.driver->of_match_table,
|
||||
&pdev->dev);
|
||||
else if (dev_is_pci(pdev->dev.parent))
|
||||
pcidev_id = pci_match_id(pxa2xx_spi_pci_compound_match,
|
||||
to_pci_dev(pdev->dev.parent));
|
||||
else if (adev)
|
||||
adev_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
|
||||
&pdev->dev);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
if (adev_id)
|
||||
type = (enum pxa_ssp_type)adev_id->driver_data;
|
||||
match = device_get_match_data(&pdev->dev);
|
||||
if (match)
|
||||
type = (enum pxa_ssp_type)match;
|
||||
else if (pcidev_id)
|
||||
type = (enum pxa_ssp_type)pcidev_id->driver_data;
|
||||
else if (of_id)
|
||||
type = (enum pxa_ssp_type)of_id->data;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
|
@ -1560,19 +1552,25 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
|
|||
|
||||
#ifdef CONFIG_PCI
|
||||
if (pcidev_id) {
|
||||
pdata->tx_param = pdev->dev.parent;
|
||||
pdata->rx_param = pdev->dev.parent;
|
||||
pdata->tx_param = parent;
|
||||
pdata->rx_param = parent;
|
||||
pdata->dma_filter = pxa2xx_spi_idma_filter;
|
||||
}
|
||||
#endif
|
||||
|
||||
ssp->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
ssp->irq = platform_get_irq(pdev, 0);
|
||||
ssp->type = type;
|
||||
ssp->pdev = pdev;
|
||||
ssp->port_id = pxa2xx_spi_get_port_id(adev);
|
||||
if (IS_ERR(ssp->clk))
|
||||
return NULL;
|
||||
|
||||
pdata->is_slave = of_property_read_bool(pdev->dev.of_node, "spi-slave");
|
||||
ssp->irq = platform_get_irq(pdev, 0);
|
||||
if (ssp->irq < 0)
|
||||
return NULL;
|
||||
|
||||
ssp->type = type;
|
||||
ssp->dev = &pdev->dev;
|
||||
ssp->port_id = pxa2xx_spi_get_port_id(&pdev->dev);
|
||||
|
||||
pdata->is_slave = device_property_read_bool(&pdev->dev, "spi-slave");
|
||||
pdata->num_chipselect = 1;
|
||||
pdata->enable_dma = true;
|
||||
pdata->dma_burst_size = 1;
|
||||
|
|
|
@ -932,11 +932,11 @@ static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
|
|||
int ret;
|
||||
|
||||
/* allocate dma resources, if available */
|
||||
master->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
master->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(master->dma_rx))
|
||||
return PTR_ERR(master->dma_rx);
|
||||
|
||||
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
master->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
ret = PTR_ERR(master->dma_tx);
|
||||
goto err_tx;
|
||||
|
|
|
@ -1154,15 +1154,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
|
||||
if (!is_polling(sdd)) {
|
||||
/* Acquire DMA channels */
|
||||
sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
|
||||
"rx");
|
||||
sdd->rx_dma.ch = dma_request_chan(&pdev->dev, "rx");
|
||||
if (IS_ERR(sdd->rx_dma.ch)) {
|
||||
dev_err(&pdev->dev, "Failed to get RX DMA channel\n");
|
||||
ret = PTR_ERR(sdd->rx_dma.ch);
|
||||
goto err_disable_io_clk;
|
||||
}
|
||||
sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
|
||||
"tx");
|
||||
sdd->tx_dma.ch = dma_request_chan(&pdev->dev, "tx");
|
||||
if (IS_ERR(sdd->tx_dma.ch)) {
|
||||
dev_err(&pdev->dev, "Failed to get TX DMA channel\n");
|
||||
ret = PTR_ERR(sdd->tx_dma.ch);
|
||||
|
|
|
@ -211,8 +211,7 @@ static int sc18is602_transfer_one(struct spi_master *master,
|
|||
}
|
||||
status = 0;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
}
|
||||
m->status = status;
|
||||
spi_finalize_current_message(master);
|
||||
|
|
|
@ -190,8 +190,7 @@ static int hspi_transfer_one_message(struct spi_controller *ctlr,
|
|||
|
||||
msg->actual_length += t->len;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (cs_change) {
|
||||
ndelay(nsecs);
|
||||
|
|
|
@ -368,7 +368,6 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct spi_controller *ctlr;
|
||||
struct mtk_spi_slave *mdata;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
|
||||
ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata));
|
||||
|
@ -392,17 +391,8 @@ static int mtk_spi_slave_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, ctlr);
|
||||
|
||||
init_completion(&mdata->xfer_done);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&pdev->dev, "failed to determine base address\n");
|
||||
goto err_put_ctlr;
|
||||
}
|
||||
|
||||
mdata->dev = &pdev->dev;
|
||||
|
||||
mdata->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
mdata->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mdata->base)) {
|
||||
ret = PTR_ERR(mdata->base);
|
||||
goto err_put_ctlr;
|
||||
|
|
|
@ -77,6 +77,7 @@
|
|||
|
||||
/* Bits definitions for register REG_WDG_CTRL */
|
||||
#define BIT_WDG_RUN BIT(1)
|
||||
#define BIT_WDG_NEW BIT(2)
|
||||
#define BIT_WDG_RST BIT(3)
|
||||
|
||||
/* Registers definitions for PMIC */
|
||||
|
@ -383,6 +384,10 @@ static int sprd_adi_restart_handler(struct notifier_block *this,
|
|||
/* Unlock the watchdog */
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, WDG_UNLOCK_KEY);
|
||||
|
||||
sprd_adi_read(sadi, sadi->slave_pbase + REG_WDG_CTRL, &val);
|
||||
val |= BIT_WDG_NEW;
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val);
|
||||
|
||||
/* Load the watchdog timeout value, 50ms is always enough. */
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_LOW,
|
||||
WDG_LOAD_VAL & WDG_LOAD_MASK);
|
||||
|
@ -393,6 +398,9 @@ static int sprd_adi_restart_handler(struct notifier_block *this,
|
|||
val |= BIT_WDG_RUN | BIT_WDG_RST;
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val);
|
||||
|
||||
/* Lock the watchdog */
|
||||
sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, ~WDG_UNLOCK_KEY);
|
||||
|
||||
mdelay(1000);
|
||||
|
||||
dev_emerg(sadi->dev, "Unable to restart system\n");
|
||||
|
|
|
@ -669,11 +669,15 @@ static void sprd_spi_set_speed(struct sprd_spi *ss, u32 speed_hz)
|
|||
writel_relaxed(clk_div, ss->base + SPRD_SPI_CLKD);
|
||||
}
|
||||
|
||||
static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
|
||||
static int sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
|
||||
{
|
||||
struct spi_delay *d = &t->word_delay;
|
||||
u16 word_delay, interval;
|
||||
u32 val;
|
||||
|
||||
if (d->unit != SPI_DELAY_UNIT_SCK)
|
||||
return -EINVAL;
|
||||
|
||||
val = readl_relaxed(ss->base + SPRD_SPI_CTL7);
|
||||
val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX);
|
||||
/* Set default chip selection, clock phase and clock polarity */
|
||||
|
@ -686,7 +690,7 @@ static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
|
|||
* formula as below per datasheet:
|
||||
* interval time (source clock cycles) = interval * 4 + 10.
|
||||
*/
|
||||
word_delay = clamp_t(u16, t->word_delay, SPRD_SPI_MIN_DELAY_CYCLE,
|
||||
word_delay = clamp_t(u16, d->value, SPRD_SPI_MIN_DELAY_CYCLE,
|
||||
SPRD_SPI_MAX_DELAY_CYCLE);
|
||||
interval = DIV_ROUND_UP(word_delay - 10, 4);
|
||||
ss->word_delay = interval * 4 + 10;
|
||||
|
@ -711,6 +715,8 @@ static void sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
|
|||
val &= ~SPRD_SPI_DATA_LINE2_EN;
|
||||
|
||||
writel_relaxed(val, ss->base + SPRD_SPI_CTL7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_spi_setup_transfer(struct spi_device *sdev,
|
||||
|
@ -719,13 +725,16 @@ static int sprd_spi_setup_transfer(struct spi_device *sdev,
|
|||
struct sprd_spi *ss = spi_controller_get_devdata(sdev->controller);
|
||||
u8 bits_per_word = t->bits_per_word;
|
||||
u32 val, mode = 0;
|
||||
int ret;
|
||||
|
||||
ss->len = t->len;
|
||||
ss->tx_buf = t->tx_buf;
|
||||
ss->rx_buf = t->rx_buf;
|
||||
|
||||
ss->hw_mode = sdev->mode;
|
||||
sprd_spi_init_hw(ss, t);
|
||||
ret = sprd_spi_init_hw(ss, t);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set tansfer speed and valid bits */
|
||||
sprd_spi_set_speed(ss, t->speed_hz);
|
||||
|
|
|
@ -381,6 +381,7 @@ static int spi_st_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
clk_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
clk_disable_unprepare(spi_st->clk);
|
||||
put_master:
|
||||
spi_master_put(master);
|
||||
|
@ -392,6 +393,8 @@ static int spi_st_remove(struct platform_device *pdev)
|
|||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct spi_st *spi_st = spi_master_get_devdata(master);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
clk_disable_unprepare(spi_st->clk);
|
||||
|
||||
pinctrl_pm_select_sleep_state(&pdev->dev);
|
||||
|
|
|
@ -666,8 +666,7 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi,
|
|||
dma_addr_t dma_phys;
|
||||
int ret;
|
||||
|
||||
dma_chan = dma_request_slave_channel_reason(tspi->dev,
|
||||
dma_to_memory ? "rx" : "tx");
|
||||
dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx");
|
||||
if (IS_ERR(dma_chan)) {
|
||||
ret = PTR_ERR(dma_chan);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
|
@ -723,15 +722,31 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
|
|||
dma_release_channel(dma_chan);
|
||||
}
|
||||
|
||||
static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly,
|
||||
u8 hold_dly, u8 inactive_dly)
|
||||
static int tegra_spi_set_hw_cs_timing(struct spi_device *spi,
|
||||
struct spi_delay *setup,
|
||||
struct spi_delay *hold,
|
||||
struct spi_delay *inactive)
|
||||
{
|
||||
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
||||
u8 setup_dly, hold_dly, inactive_dly;
|
||||
u32 setup_hold;
|
||||
u32 spi_cs_timing;
|
||||
u32 inactive_cycles;
|
||||
u8 cs_state;
|
||||
|
||||
if ((setup && setup->unit != SPI_DELAY_UNIT_SCK) ||
|
||||
(hold && hold->unit != SPI_DELAY_UNIT_SCK) ||
|
||||
(inactive && inactive->unit != SPI_DELAY_UNIT_SCK)) {
|
||||
dev_err(&spi->dev,
|
||||
"Invalid delay unit %d, should be SPI_DELAY_UNIT_SCK\n",
|
||||
SPI_DELAY_UNIT_SCK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
setup_dly = setup ? setup->value : 0;
|
||||
hold_dly = hold ? hold->value : 0;
|
||||
inactive_dly = inactive ? inactive->value : 0;
|
||||
|
||||
setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
|
||||
hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
|
||||
if (setup_dly && hold_dly) {
|
||||
|
@ -758,6 +773,8 @@ static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly,
|
|||
tspi->spi_cs_timing2 = spi_cs_timing;
|
||||
tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
|
||||
|
@ -984,17 +1001,6 @@ static int tegra_spi_setup(struct spi_device *spi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_spi_transfer_delay(int delay)
|
||||
{
|
||||
if (!delay)
|
||||
return;
|
||||
|
||||
if (delay >= 1000)
|
||||
mdelay(delay / 1000);
|
||||
|
||||
udelay(delay % 1000);
|
||||
}
|
||||
|
||||
static void tegra_spi_transfer_end(struct spi_device *spi)
|
||||
{
|
||||
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
|
||||
|
@ -1098,7 +1104,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
|
|||
complete_xfer:
|
||||
if (ret < 0 || skip) {
|
||||
tegra_spi_transfer_end(spi);
|
||||
tegra_spi_transfer_delay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
goto exit;
|
||||
} else if (list_is_last(&xfer->transfer_list,
|
||||
&msg->transfers)) {
|
||||
|
@ -1106,11 +1112,11 @@ complete_xfer:
|
|||
tspi->cs_control = spi;
|
||||
else {
|
||||
tegra_spi_transfer_end(spi);
|
||||
tegra_spi_transfer_delay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
}
|
||||
} else if (xfer->cs_change) {
|
||||
tegra_spi_transfer_end(spi);
|
||||
tegra_spi_transfer_delay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -341,10 +341,11 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master,
|
|||
goto exit;
|
||||
}
|
||||
msg->actual_length += xfer->len;
|
||||
if (xfer->cs_change && xfer->delay_usecs) {
|
||||
if (xfer->cs_change &&
|
||||
(xfer->delay_usecs || xfer->delay.value)) {
|
||||
tegra_sflash_writel(tsd, tsd->def_command_reg,
|
||||
SPI_COMMAND);
|
||||
udelay(xfer->delay_usecs);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
|
|
|
@ -599,8 +599,7 @@ static int tegra_slink_init_dma_param(struct tegra_slink_data *tspi,
|
|||
int ret;
|
||||
struct dma_slave_config dma_sconfig;
|
||||
|
||||
dma_chan = dma_request_slave_channel_reason(tspi->dev,
|
||||
dma_to_memory ? "rx" : "tx");
|
||||
dma_chan = dma_request_chan(tspi->dev, dma_to_memory ? "rx" : "tx");
|
||||
if (IS_ERR(dma_chan)) {
|
||||
ret = PTR_ERR(dma_chan);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
|
@ -1073,7 +1072,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
|||
ret = clk_enable(tspi->clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Clock enable failed %d\n", ret);
|
||||
goto exit_free_master;
|
||||
goto exit_clk_unprepare;
|
||||
}
|
||||
|
||||
spi_irq = platform_get_irq(pdev, 0);
|
||||
|
@ -1146,6 +1145,8 @@ exit_free_irq:
|
|||
free_irq(spi_irq, tspi);
|
||||
exit_clk_disable:
|
||||
clk_disable(tspi->clk);
|
||||
exit_clk_unprepare:
|
||||
clk_unprepare(tspi->clk);
|
||||
exit_free_master:
|
||||
spi_master_put(master);
|
||||
return ret;
|
||||
|
@ -1159,6 +1160,7 @@ static int tegra_slink_remove(struct platform_device *pdev)
|
|||
free_irq(tspi->irq, tspi);
|
||||
|
||||
clk_disable(tspi->clk);
|
||||
clk_unprepare(tspi->clk);
|
||||
|
||||
if (tspi->tx_dma_chan)
|
||||
tegra_slink_deinit_dma_param(tspi, false);
|
||||
|
|
|
@ -1229,12 +1229,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
|
|||
"%s:data->current_msg->actual_length=%d\n",
|
||||
__func__, data->current_msg->actual_length);
|
||||
|
||||
/* check for delay */
|
||||
if (data->cur_trans->delay_usecs) {
|
||||
dev_dbg(&data->master->dev, "%s:delay in usec=%d\n",
|
||||
__func__, data->cur_trans->delay_usecs);
|
||||
udelay(data->cur_trans->delay_usecs);
|
||||
}
|
||||
spi_transfer_delay_exec(data->cur_trans);
|
||||
|
||||
spin_lock(&data->lock);
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
|
||||
#define SPI_FIFO_SIZE 4
|
||||
|
@ -79,7 +80,7 @@ struct txx9spi {
|
|||
void __iomem *membase;
|
||||
int baseclk;
|
||||
struct clk *clk;
|
||||
int last_chipselect;
|
||||
struct gpio_desc *last_chipselect;
|
||||
int last_chipselect_val;
|
||||
};
|
||||
|
||||
|
@ -95,20 +96,22 @@ static void txx9spi_wr(struct txx9spi *c, u32 val, int reg)
|
|||
static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
|
||||
int on, unsigned int cs_delay)
|
||||
{
|
||||
int val = (spi->mode & SPI_CS_HIGH) ? on : !on;
|
||||
|
||||
/*
|
||||
* The GPIO descriptor will track polarity inversion inside
|
||||
* gpiolib.
|
||||
*/
|
||||
if (on) {
|
||||
/* deselect the chip with cs_change hint in last transfer */
|
||||
if (c->last_chipselect >= 0)
|
||||
gpio_set_value(c->last_chipselect,
|
||||
if (c->last_chipselect)
|
||||
gpiod_set_value(c->last_chipselect,
|
||||
!c->last_chipselect_val);
|
||||
c->last_chipselect = spi->chip_select;
|
||||
c->last_chipselect_val = val;
|
||||
c->last_chipselect = spi->cs_gpiod;
|
||||
c->last_chipselect_val = on;
|
||||
} else {
|
||||
c->last_chipselect = -1;
|
||||
c->last_chipselect = NULL;
|
||||
ndelay(cs_delay); /* CS Hold Time */
|
||||
}
|
||||
gpio_set_value(spi->chip_select, val);
|
||||
gpiod_set_value(spi->cs_gpiod, on);
|
||||
ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */
|
||||
}
|
||||
|
||||
|
@ -119,12 +122,6 @@ static int txx9spi_setup(struct spi_device *spi)
|
|||
if (!spi->max_speed_hz)
|
||||
return -EINVAL;
|
||||
|
||||
if (gpio_direction_output(spi->chip_select,
|
||||
!(spi->mode & SPI_CS_HIGH))) {
|
||||
dev_err(&spi->dev, "Cannot setup GPIO for chipselect.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* deselect chip */
|
||||
spin_lock(&c->lock);
|
||||
txx9spi_cs_func(spi, c, 0, (NSEC_PER_SEC / 2) / spi->max_speed_hz);
|
||||
|
@ -248,8 +245,7 @@ static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m)
|
|||
len -= count * wsize;
|
||||
}
|
||||
m->actual_length += t->len;
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (!cs_change)
|
||||
continue;
|
||||
|
@ -320,6 +316,47 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Chip select uses GPIO only, further the driver is using the chip select
|
||||
* numer (from the device tree "reg" property, and this can only come from
|
||||
* device tree since this i MIPS and there is no way to pass platform data) as
|
||||
* the GPIO number. As the platform has only one GPIO controller (the txx9 GPIO
|
||||
* chip) it is thus using the chip select number as an offset into that chip.
|
||||
* This chip has a maximum of 16 GPIOs 0..15 and this is what all platforms
|
||||
* register.
|
||||
*
|
||||
* We modernized this behaviour by explicitly converting that offset to an
|
||||
* offset on the GPIO chip using a GPIO descriptor machine table of the same
|
||||
* size as the txx9 GPIO chip with a 1-to-1 mapping of chip select to GPIO
|
||||
* offset.
|
||||
*
|
||||
* This is admittedly a hack, but it is countering the hack of using "reg" to
|
||||
* contain a GPIO offset when it should be using "cs-gpios" as the SPI bindings
|
||||
* state.
|
||||
*/
|
||||
static struct gpiod_lookup_table txx9spi_cs_gpio_table = {
|
||||
.dev_id = "spi0",
|
||||
.table = {
|
||||
GPIO_LOOKUP_IDX("TXx9", 0, "cs", 0, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 1, "cs", 1, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 2, "cs", 2, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 3, "cs", 3, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 4, "cs", 4, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 5, "cs", 5, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 6, "cs", 6, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 7, "cs", 7, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 8, "cs", 8, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 9, "cs", 9, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 10, "cs", 10, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 11, "cs", 11, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 12, "cs", 12, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 13, "cs", 13, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 14, "cs", 14, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("TXx9", 15, "cs", 15, GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static int txx9spi_probe(struct platform_device *dev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
|
@ -373,12 +410,14 @@ static int txx9spi_probe(struct platform_device *dev)
|
|||
if (ret)
|
||||
goto exit;
|
||||
|
||||
c->last_chipselect = -1;
|
||||
c->last_chipselect = NULL;
|
||||
|
||||
dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
|
||||
(unsigned long long)res->start, irq,
|
||||
(c->baseclk + 500000) / 1000000);
|
||||
|
||||
gpiod_add_lookup_table(&txx9spi_cs_gpio_table);
|
||||
|
||||
/* the spi->mode bits understood by this driver: */
|
||||
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
|
||||
|
||||
|
@ -387,6 +426,7 @@ static int txx9spi_probe(struct platform_device *dev)
|
|||
master->transfer = txx9spi_transfer;
|
||||
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||
master->use_gpio_descriptors = true;
|
||||
|
||||
ret = devm_spi_register_master(&dev->dev, master);
|
||||
if (ret)
|
||||
|
|
|
@ -188,8 +188,7 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
|
|||
}
|
||||
status = 0;
|
||||
|
||||
if (t->delay_usecs)
|
||||
udelay(t->delay_usecs);
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
is_first = false;
|
||||
}
|
||||
|
|
|
@ -391,7 +391,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
|||
struct xilinx_spi *xspi;
|
||||
struct xspi_platform_data *pdata;
|
||||
struct resource *res;
|
||||
int ret, num_cs = 0, bits_per_word = 8;
|
||||
int ret, num_cs = 0, bits_per_word;
|
||||
struct spi_master *master;
|
||||
u32 tmp;
|
||||
u8 i;
|
||||
|
@ -403,6 +403,11 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
|||
} else {
|
||||
of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
|
||||
&num_cs);
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"xlnx,num-transfer-bits",
|
||||
&bits_per_word);
|
||||
if (ret)
|
||||
bits_per_word = 8;
|
||||
}
|
||||
|
||||
if (!num_cs) {
|
||||
|
|
|
@ -80,7 +80,6 @@ static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on)
|
|||
static int xtfpga_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct xtfpga_spi *xspi;
|
||||
struct resource *mem;
|
||||
int ret;
|
||||
struct spi_master *master;
|
||||
|
||||
|
@ -97,14 +96,7 @@ static int xtfpga_spi_probe(struct platform_device *pdev)
|
|||
xspi->bitbang.master = master;
|
||||
xspi->bitbang.chipselect = xtfpga_spi_chipselect;
|
||||
xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!mem) {
|
||||
dev_err(&pdev->dev, "No memory resource\n");
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
xspi->regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
xspi->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(xspi->regs)) {
|
||||
ret = PTR_ERR(xspi->regs);
|
||||
goto err;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -51,7 +50,6 @@
|
|||
#define ZYNQ_QSPI_CONFIG_BDRATE_MASK GENMASK(5, 3) /* Baud Rate Mask */
|
||||
#define ZYNQ_QSPI_CONFIG_CPHA_MASK BIT(2) /* Clock Phase Control */
|
||||
#define ZYNQ_QSPI_CONFIG_CPOL_MASK BIT(1) /* Clock Polarity Control */
|
||||
#define ZYNQ_QSPI_CONFIG_SSCTRL_MASK BIT(10) /* Slave Select Mask */
|
||||
#define ZYNQ_QSPI_CONFIG_FWIDTH_MASK GENMASK(7, 6) /* FIFO width */
|
||||
#define ZYNQ_QSPI_CONFIG_MSTREN_MASK BIT(0) /* Master Mode */
|
||||
|
||||
|
@ -61,9 +59,9 @@
|
|||
* These are the values used in the calculation of baud rate divisor and
|
||||
* setting the slave select.
|
||||
*/
|
||||
#define ZYNQ_QSPI_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */
|
||||
#define ZYNQ_QSPI_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift in CR */
|
||||
#define ZYNQ_QSPI_SS_SHIFT 10 /* Slave Select field shift in CR */
|
||||
#define ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX GENMASK(2, 0) /* Baud rate maximum */
|
||||
#define ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT 3 /* Baud rate divisor shift */
|
||||
#define ZYNQ_QSPI_CONFIG_PCS BIT(10) /* Peripheral Chip Select */
|
||||
|
||||
/*
|
||||
* QSPI Interrupt Registers bit Masks
|
||||
|
@ -99,9 +97,9 @@
|
|||
* It is named Linear Configuration but it controls other modes when not in
|
||||
* linear mode also.
|
||||
*/
|
||||
#define ZYNQ_QSPI_LCFG_TWO_MEM_MASK BIT(30) /* LQSPI Two memories Mask */
|
||||
#define ZYNQ_QSPI_LCFG_SEP_BUS_MASK BIT(29) /* LQSPI Separate bus Mask */
|
||||
#define ZYNQ_QSPI_LCFG_U_PAGE_MASK BIT(28) /* LQSPI Upper Page Mask */
|
||||
#define ZYNQ_QSPI_LCFG_TWO_MEM BIT(30) /* LQSPI Two memories */
|
||||
#define ZYNQ_QSPI_LCFG_SEP_BUS BIT(29) /* LQSPI Separate bus */
|
||||
#define ZYNQ_QSPI_LCFG_U_PAGE BIT(28) /* LQSPI Upper Page */
|
||||
|
||||
#define ZYNQ_QSPI_LCFG_DUMMY_SHIFT 8
|
||||
|
||||
|
@ -116,8 +114,8 @@
|
|||
*/
|
||||
#define ZYNQ_QSPI_MODEBITS (SPI_CPOL | SPI_CPHA)
|
||||
|
||||
/* Default number of chip selects */
|
||||
#define ZYNQ_QSPI_DEFAULT_NUM_CS 1
|
||||
/* Maximum number of chip selects */
|
||||
#define ZYNQ_QSPI_MAX_NUM_CS 2
|
||||
|
||||
/**
|
||||
* struct zynq_qspi - Defines qspi driver instance
|
||||
|
@ -161,6 +159,7 @@ static inline void zynq_qspi_write(struct zynq_qspi *xqspi, u32 offset,
|
|||
/**
|
||||
* zynq_qspi_init_hw - Initialize the hardware
|
||||
* @xqspi: Pointer to the zynq_qspi structure
|
||||
* @num_cs: Number of connected CS (to enable dual memories if needed)
|
||||
*
|
||||
* The default settings of the QSPI controller's configurable parameters on
|
||||
* reset are
|
||||
|
@ -178,7 +177,7 @@ static inline void zynq_qspi_write(struct zynq_qspi *xqspi, u32 offset,
|
|||
* - Set the little endian mode of TX FIFO and
|
||||
* - Enable the QSPI controller
|
||||
*/
|
||||
static void zynq_qspi_init_hw(struct zynq_qspi *xqspi)
|
||||
static void zynq_qspi_init_hw(struct zynq_qspi *xqspi, unsigned int num_cs)
|
||||
{
|
||||
u32 config_reg;
|
||||
|
||||
|
@ -186,7 +185,12 @@ static void zynq_qspi_init_hw(struct zynq_qspi *xqspi)
|
|||
zynq_qspi_write(xqspi, ZYNQ_QSPI_IDIS_OFFSET, ZYNQ_QSPI_IXR_ALL_MASK);
|
||||
|
||||
/* Disable linear mode as the boot loader may have used it */
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET, 0);
|
||||
config_reg = 0;
|
||||
/* At the same time, enable dual mode if more than 1 CS is available */
|
||||
if (num_cs > 1)
|
||||
config_reg |= ZYNQ_QSPI_LCFG_TWO_MEM;
|
||||
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET, config_reg);
|
||||
|
||||
/* Clear the RX FIFO */
|
||||
while (zynq_qspi_read(xqspi, ZYNQ_QSPI_STATUS_OFFSET) &
|
||||
|
@ -284,21 +288,28 @@ static void zynq_qspi_txfifo_op(struct zynq_qspi *xqspi, unsigned int size)
|
|||
*/
|
||||
static void zynq_qspi_chipselect(struct spi_device *spi, bool assert)
|
||||
{
|
||||
struct spi_controller *ctrl = spi->master;
|
||||
struct zynq_qspi *xqspi = spi_controller_get_devdata(ctrl);
|
||||
struct spi_controller *ctlr = spi->master;
|
||||
struct zynq_qspi *xqspi = spi_controller_get_devdata(ctlr);
|
||||
u32 config_reg;
|
||||
|
||||
config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_CONFIG_OFFSET);
|
||||
if (assert) {
|
||||
/* Select the slave */
|
||||
config_reg &= ~ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
|
||||
config_reg |= (((~(BIT(spi->chip_select))) <<
|
||||
ZYNQ_QSPI_SS_SHIFT) &
|
||||
ZYNQ_QSPI_CONFIG_SSCTRL_MASK);
|
||||
} else {
|
||||
config_reg |= ZYNQ_QSPI_CONFIG_SSCTRL_MASK;
|
||||
/* Select the lower (CS0) or upper (CS1) memory */
|
||||
if (ctlr->num_chipselect > 1) {
|
||||
config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET);
|
||||
if (!spi->chip_select)
|
||||
config_reg &= ~ZYNQ_QSPI_LCFG_U_PAGE;
|
||||
else
|
||||
config_reg |= ZYNQ_QSPI_LCFG_U_PAGE;
|
||||
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_LINEAR_CFG_OFFSET, config_reg);
|
||||
}
|
||||
|
||||
/* Ground the line to assert the CS */
|
||||
config_reg = zynq_qspi_read(xqspi, ZYNQ_QSPI_CONFIG_OFFSET);
|
||||
if (assert)
|
||||
config_reg &= ~ZYNQ_QSPI_CONFIG_PCS;
|
||||
else
|
||||
config_reg |= ZYNQ_QSPI_CONFIG_PCS;
|
||||
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_CONFIG_OFFSET, config_reg);
|
||||
}
|
||||
|
||||
|
@ -332,7 +343,7 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
|
|||
* ----------------
|
||||
* 111 - divide by 256
|
||||
*/
|
||||
while ((baud_rate_val < ZYNQ_QSPI_BAUD_DIV_MAX) &&
|
||||
while ((baud_rate_val < ZYNQ_QSPI_CONFIG_BAUD_DIV_MAX) &&
|
||||
(clk_get_rate(xqspi->refclk) / (2 << baud_rate_val)) >
|
||||
spi->max_speed_hz)
|
||||
baud_rate_val++;
|
||||
|
@ -348,7 +359,7 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
|
|||
config_reg |= ZYNQ_QSPI_CONFIG_CPOL_MASK;
|
||||
|
||||
config_reg &= ~ZYNQ_QSPI_CONFIG_BDRATE_MASK;
|
||||
config_reg |= (baud_rate_val << ZYNQ_QSPI_BAUD_DIV_SHIFT);
|
||||
config_reg |= (baud_rate_val << ZYNQ_QSPI_CONFIG_BAUD_DIV_SHIFT);
|
||||
zynq_qspi_write(xqspi, ZYNQ_QSPI_CONFIG_OFFSET, config_reg);
|
||||
|
||||
return 0;
|
||||
|
@ -365,10 +376,10 @@ static int zynq_qspi_config_op(struct zynq_qspi *xqspi, struct spi_device *spi)
|
|||
*/
|
||||
static int zynq_qspi_setup_op(struct spi_device *spi)
|
||||
{
|
||||
struct spi_controller *ctrl = spi->master;
|
||||
struct zynq_qspi *qspi = spi_controller_get_devdata(ctrl);
|
||||
struct spi_controller *ctlr = spi->master;
|
||||
struct zynq_qspi *qspi = spi_controller_get_devdata(ctlr);
|
||||
|
||||
if (ctrl->busy)
|
||||
if (ctlr->busy)
|
||||
return -EBUSY;
|
||||
|
||||
clk_enable(qspi->refclk);
|
||||
|
@ -663,9 +674,6 @@ static int zynq_qspi_probe(struct platform_device *pdev)
|
|||
goto clk_dis_pclk;
|
||||
}
|
||||
|
||||
/* QSPI controller initializations */
|
||||
zynq_qspi_init_hw(xqspi);
|
||||
|
||||
xqspi->irq = platform_get_irq(pdev, 0);
|
||||
if (xqspi->irq <= 0) {
|
||||
ret = -ENXIO;
|
||||
|
@ -681,10 +689,14 @@ static int zynq_qspi_probe(struct platform_device *pdev)
|
|||
|
||||
ret = of_property_read_u32(np, "num-cs",
|
||||
&num_cs);
|
||||
if (ret < 0)
|
||||
ctlr->num_chipselect = ZYNQ_QSPI_DEFAULT_NUM_CS;
|
||||
else
|
||||
if (ret < 0) {
|
||||
ctlr->num_chipselect = 1;
|
||||
} else if (num_cs > ZYNQ_QSPI_MAX_NUM_CS) {
|
||||
dev_err(&pdev->dev, "only 2 chip selects are available\n");
|
||||
goto remove_master;
|
||||
} else {
|
||||
ctlr->num_chipselect = num_cs;
|
||||
}
|
||||
|
||||
ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
|
||||
SPI_TX_DUAL | SPI_TX_QUAD;
|
||||
|
@ -692,6 +704,10 @@ static int zynq_qspi_probe(struct platform_device *pdev)
|
|||
ctlr->setup = zynq_qspi_setup_op;
|
||||
ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
|
||||
ctlr->dev.of_node = np;
|
||||
|
||||
/* QSPI controller initializations */
|
||||
zynq_qspi_init_hw(xqspi, ctlr->num_chipselect);
|
||||
|
||||
ret = devm_spi_register_controller(&pdev->dev, ctlr);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "spi_register_master failed\n");
|
||||
|
|
|
@ -92,7 +92,7 @@ static ssize_t driver_override_store(struct device *dev,
|
|||
if (len) {
|
||||
spi->driver_override = driver_override;
|
||||
} else {
|
||||
/* Emptry string, disable driver override */
|
||||
/* Empty string, disable driver override */
|
||||
spi->driver_override = NULL;
|
||||
kfree(driver_override);
|
||||
}
|
||||
|
@ -469,7 +469,7 @@ static LIST_HEAD(board_list);
|
|||
static LIST_HEAD(spi_controller_list);
|
||||
|
||||
/*
|
||||
* Used to protect add/del opertion for board_info list and
|
||||
* Used to protect add/del operation for board_info list and
|
||||
* spi_controller list, and their matching process
|
||||
* also used to protect object of type struct idr
|
||||
*/
|
||||
|
@ -775,6 +775,15 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
|||
|
||||
static void spi_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
bool enable1 = enable;
|
||||
|
||||
if (!spi->controller->set_cs_timing) {
|
||||
if (enable1)
|
||||
spi_delay_exec(&spi->controller->cs_setup, NULL);
|
||||
else
|
||||
spi_delay_exec(&spi->controller->cs_hold, NULL);
|
||||
}
|
||||
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
enable = !enable;
|
||||
|
||||
|
@ -800,6 +809,11 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
|
|||
} else if (spi->controller->set_cs) {
|
||||
spi->controller->set_cs(spi, !enable);
|
||||
}
|
||||
|
||||
if (!spi->controller->set_cs_timing) {
|
||||
if (!enable1)
|
||||
spi_delay_exec(&spi->controller->cs_inactive, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
|
@ -1106,42 +1120,79 @@ static void _spi_transfer_delay_ns(u32 ns)
|
|||
}
|
||||
}
|
||||
|
||||
static void _spi_transfer_cs_change_delay(struct spi_message *msg,
|
||||
struct spi_transfer *xfer)
|
||||
int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
|
||||
{
|
||||
u32 delay = xfer->cs_change_delay;
|
||||
u32 unit = xfer->cs_change_delay_unit;
|
||||
u32 delay = _delay->value;
|
||||
u32 unit = _delay->unit;
|
||||
u32 hz;
|
||||
|
||||
/* return early on "fast" mode - for everything but USECS */
|
||||
if (!delay && unit != SPI_DELAY_UNIT_USECS)
|
||||
return;
|
||||
if (!delay)
|
||||
return 0;
|
||||
|
||||
switch (unit) {
|
||||
case SPI_DELAY_UNIT_USECS:
|
||||
/* for compatibility use default of 10us */
|
||||
if (!delay)
|
||||
delay = 10000;
|
||||
else
|
||||
delay *= 1000;
|
||||
delay *= 1000;
|
||||
break;
|
||||
case SPI_DELAY_UNIT_NSECS: /* nothing to do here */
|
||||
break;
|
||||
case SPI_DELAY_UNIT_SCK:
|
||||
/* clock cycles need to be obtained from spi_transfer */
|
||||
if (!xfer)
|
||||
return -EINVAL;
|
||||
/* if there is no effective speed know, then approximate
|
||||
* by underestimating with half the requested hz
|
||||
*/
|
||||
hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
|
||||
if (!hz)
|
||||
return -EINVAL;
|
||||
delay *= DIV_ROUND_UP(1000000000, hz);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_delay_to_ns);
|
||||
|
||||
int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer)
|
||||
{
|
||||
int delay;
|
||||
|
||||
if (!_delay)
|
||||
return -EINVAL;
|
||||
|
||||
delay = spi_delay_to_ns(_delay, xfer);
|
||||
if (delay < 0)
|
||||
return delay;
|
||||
|
||||
_spi_transfer_delay_ns(delay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_delay_exec);
|
||||
|
||||
static void _spi_transfer_cs_change_delay(struct spi_message *msg,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
u32 delay = xfer->cs_change_delay.value;
|
||||
u32 unit = xfer->cs_change_delay.unit;
|
||||
int ret;
|
||||
|
||||
/* return early on "fast" mode - for everything but USECS */
|
||||
if (!delay) {
|
||||
if (unit == SPI_DELAY_UNIT_USECS)
|
||||
_spi_transfer_delay_ns(10000);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = spi_delay_exec(&xfer->cs_change_delay, xfer);
|
||||
if (ret) {
|
||||
dev_err_once(&msg->spi->dev,
|
||||
"Use of unsupported delay unit %i, using default of 10us\n",
|
||||
xfer->cs_change_delay_unit);
|
||||
delay = 10000;
|
||||
unit);
|
||||
_spi_transfer_delay_ns(10000);
|
||||
}
|
||||
/* now sleep for the requested amount of time */
|
||||
_spi_transfer_delay_ns(delay);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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(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) {
|
||||
reinit_completion(&ctlr->xfer_completion);
|
||||
|
||||
|
@ -1197,13 +1253,17 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
|
|||
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);
|
||||
|
||||
if (msg->status != -EINPROGRESS)
|
||||
goto out;
|
||||
|
||||
if (xfer->delay_usecs)
|
||||
_spi_transfer_delay_ns(xfer->delay_usecs * 1000);
|
||||
spi_transfer_delay_exec(xfer);
|
||||
|
||||
if (xfer->cs_change) {
|
||||
if (list_is_last(&xfer->transfer_list,
|
||||
|
@ -1265,6 +1325,7 @@ EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
|
|||
*/
|
||||
static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
|
||||
{
|
||||
struct spi_transfer *xfer;
|
||||
struct spi_message *msg;
|
||||
bool was_busy = false;
|
||||
unsigned long flags;
|
||||
|
@ -1391,6 +1452,13 @@ static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
|
|||
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);
|
||||
if (ret) {
|
||||
dev_err(&ctlr->dev,
|
||||
|
@ -1418,6 +1486,99 @@ static void spi_pump_messages(struct kthread_work *work)
|
|||
__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
|
||||
* @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)
|
||||
{
|
||||
struct spi_transfer *xfer;
|
||||
struct spi_message *mesg;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
@ -1511,6 +1673,13 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
|
|||
mesg = ctlr->cur_msg;
|
||||
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);
|
||||
|
||||
if (ctlr->cur_msg_prepared && ctlr->unprepare_message) {
|
||||
|
@ -2872,10 +3041,11 @@ struct spi_replaced_transfers *spi_replace_transfers(
|
|||
/* add to list */
|
||||
list_add(&xfer->transfer_list, rxfer->replaced_after);
|
||||
|
||||
/* clear cs_change and delay_usecs for all but the last */
|
||||
/* clear cs_change and delay for all but the last */
|
||||
if (i) {
|
||||
xfer->cs_change = false;
|
||||
xfer->delay_usecs = 0;
|
||||
xfer->delay.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3092,7 +3262,29 @@ int spi_setup(struct spi_device *spi)
|
|||
if (spi->controller->setup)
|
||||
status = spi->controller->setup(spi);
|
||||
|
||||
spi_set_cs(spi, false);
|
||||
if (spi->controller->auto_runtime_pm && spi->controller->set_cs) {
|
||||
status = pm_runtime_get_sync(spi->controller->dev.parent);
|
||||
if (status < 0) {
|
||||
pm_runtime_put_noidle(spi->controller->dev.parent);
|
||||
dev_err(&spi->controller->dev, "Failed to power device: %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* We do not want to return positive value from pm_runtime_get,
|
||||
* there are many instances of devices calling spi_setup() and
|
||||
* checking for a non-zero return value instead of a negative
|
||||
* return value.
|
||||
*/
|
||||
status = 0;
|
||||
|
||||
spi_set_cs(spi, false);
|
||||
pm_runtime_mark_last_busy(spi->controller->dev.parent);
|
||||
pm_runtime_put_autosuspend(spi->controller->dev.parent);
|
||||
} else {
|
||||
spi_set_cs(spi, false);
|
||||
}
|
||||
|
||||
if (spi->rt && !spi->controller->rt) {
|
||||
spi->controller->rt = true;
|
||||
|
@ -3115,18 +3307,71 @@ EXPORT_SYMBOL_GPL(spi_setup);
|
|||
/**
|
||||
* spi_set_cs_timing - configure CS setup, hold, and inactive delays
|
||||
* @spi: the device that requires specific CS timing configuration
|
||||
* @setup: CS setup time in terms of clock count
|
||||
* @hold: CS hold time in terms of clock count
|
||||
* @inactive_dly: CS inactive delay between transfers in terms of clock count
|
||||
* @setup: CS setup time specified via @spi_delay
|
||||
* @hold: CS hold time specified via @spi_delay
|
||||
* @inactive: CS inactive delay between transfers specified via @spi_delay
|
||||
*
|
||||
* Return: zero on success, else a negative error code.
|
||||
*/
|
||||
void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold,
|
||||
u8 inactive_dly)
|
||||
int spi_set_cs_timing(struct spi_device *spi, struct spi_delay *setup,
|
||||
struct spi_delay *hold, struct spi_delay *inactive)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (spi->controller->set_cs_timing)
|
||||
spi->controller->set_cs_timing(spi, setup, hold, inactive_dly);
|
||||
return spi->controller->set_cs_timing(spi, setup, hold,
|
||||
inactive);
|
||||
|
||||
if ((setup && setup->unit == SPI_DELAY_UNIT_SCK) ||
|
||||
(hold && hold->unit == SPI_DELAY_UNIT_SCK) ||
|
||||
(inactive && inactive->unit == SPI_DELAY_UNIT_SCK)) {
|
||||
dev_err(&spi->dev,
|
||||
"Clock-cycle delays for CS not supported in SW mode\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
len = sizeof(struct spi_delay);
|
||||
|
||||
/* copy delays to controller */
|
||||
if (setup)
|
||||
memcpy(&spi->controller->cs_setup, setup, len);
|
||||
else
|
||||
memset(&spi->controller->cs_setup, 0, len);
|
||||
|
||||
if (hold)
|
||||
memcpy(&spi->controller->cs_hold, hold, len);
|
||||
else
|
||||
memset(&spi->controller->cs_hold, 0, len);
|
||||
|
||||
if (inactive)
|
||||
memcpy(&spi->controller->cs_inactive, inactive, len);
|
||||
else
|
||||
memset(&spi->controller->cs_inactive, 0, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_set_cs_timing);
|
||||
|
||||
static int _spi_xfer_word_delay_update(struct spi_transfer *xfer,
|
||||
struct spi_device *spi)
|
||||
{
|
||||
int delay1, delay2;
|
||||
|
||||
delay1 = spi_delay_to_ns(&xfer->word_delay, xfer);
|
||||
if (delay1 < 0)
|
||||
return delay1;
|
||||
|
||||
delay2 = spi_delay_to_ns(&spi->word_delay, xfer);
|
||||
if (delay2 < 0)
|
||||
return delay2;
|
||||
|
||||
if (delay1 < delay2)
|
||||
memcpy(&xfer->word_delay, &spi->word_delay,
|
||||
sizeof(xfer->word_delay));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
||||
{
|
||||
struct spi_controller *ctlr = spi->controller;
|
||||
|
@ -3262,8 +3507,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (xfer->word_delay_usecs < spi->word_delay_usecs)
|
||||
xfer->word_delay_usecs = spi->word_delay_usecs;
|
||||
if (_spi_xfer_word_delay_update(xfer, spi))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
message->status = -EINPROGRESS;
|
||||
|
@ -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)
|
||||
{
|
||||
struct spi_controller *ctlr = spi->controller;
|
||||
struct spi_transfer *xfer;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -265,9 +265,11 @@ static int spidev_message(struct spidev_data *spidev,
|
|||
k_tmp->tx_nbits = u_tmp->tx_nbits;
|
||||
k_tmp->rx_nbits = u_tmp->rx_nbits;
|
||||
k_tmp->bits_per_word = u_tmp->bits_per_word;
|
||||
k_tmp->delay_usecs = u_tmp->delay_usecs;
|
||||
k_tmp->delay.value = u_tmp->delay_usecs;
|
||||
k_tmp->delay.unit = SPI_DELAY_UNIT_USECS;
|
||||
k_tmp->speed_hz = u_tmp->speed_hz;
|
||||
k_tmp->word_delay_usecs = u_tmp->word_delay_usecs;
|
||||
k_tmp->word_delay.value = u_tmp->word_delay_usecs;
|
||||
k_tmp->word_delay.unit = SPI_DELAY_UNIT_USECS;
|
||||
if (!k_tmp->speed_hz)
|
||||
k_tmp->speed_hz = spidev->speed_hz;
|
||||
#ifdef VERBOSE
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
/* Board specific platform_data */
|
||||
struct mtk_chip_config {
|
||||
u32 cs_pol;
|
||||
u32 sample_sel;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -206,7 +206,7 @@ enum pxa_ssp_type {
|
|||
};
|
||||
|
||||
struct ssp_device {
|
||||
struct platform_device *pdev;
|
||||
struct device *dev;
|
||||
struct list_head node;
|
||||
|
||||
struct clk *clk;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/completion.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
struct dma_chan;
|
||||
struct property_entry;
|
||||
|
@ -89,6 +90,22 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
|
|||
#define SPI_STATISTICS_INCREMENT_FIELD(stats, field) \
|
||||
SPI_STATISTICS_ADD_TO_FIELD(stats, field, 1)
|
||||
|
||||
/**
|
||||
* struct spi_delay - SPI delay information
|
||||
* @value: Value for the delay
|
||||
* @unit: Unit for the delay
|
||||
*/
|
||||
struct spi_delay {
|
||||
#define SPI_DELAY_UNIT_USECS 0
|
||||
#define SPI_DELAY_UNIT_NSECS 1
|
||||
#define SPI_DELAY_UNIT_SCK 2
|
||||
u16 value;
|
||||
u8 unit;
|
||||
};
|
||||
|
||||
extern int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer);
|
||||
extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer);
|
||||
|
||||
/**
|
||||
* struct spi_device - Controller side proxy for an SPI slave device
|
||||
* @dev: Driver model representation of the device.
|
||||
|
@ -123,7 +140,7 @@ void spi_statistics_add_transfer_stats(struct spi_statistics *stats,
|
|||
* the spi_master.
|
||||
* @cs_gpiod: gpio descriptor of the chipselect line (optional, NULL when
|
||||
* not using a GPIO line)
|
||||
* @word_delay_usecs: microsecond delay to be inserted between consecutive
|
||||
* @word_delay: delay to be inserted between consecutive
|
||||
* words of a transfer
|
||||
*
|
||||
* @statistics: statistics for the spi_device
|
||||
|
@ -173,7 +190,7 @@ struct spi_device {
|
|||
const char *driver_override;
|
||||
int cs_gpio; /* LEGACY: chip select gpio */
|
||||
struct gpio_desc *cs_gpiod; /* chip select gpio desc */
|
||||
uint8_t word_delay_usecs; /* inter-word delay */
|
||||
struct spi_delay word_delay; /* inter-word delay */
|
||||
|
||||
/* the statistics */
|
||||
struct spi_statistics statistics;
|
||||
|
@ -390,6 +407,11 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
|||
* controller has native support for memory like operations.
|
||||
* @unprepare_message: undo any work done by prepare_message().
|
||||
* @slave_abort: abort the ongoing transfer request on an SPI slave controller
|
||||
* @cs_setup: delay to be introduced by the controller after CS is asserted
|
||||
* @cs_hold: delay to be introduced by the controller before CS is deasserted
|
||||
* @cs_inactive: delay to be introduced by the controller after CS is
|
||||
* deasserted. If @cs_change_delay is used from @spi_transfer, then the
|
||||
* two delays will be added up.
|
||||
* @cs_gpios: LEGACY: array of GPIO descs to use as chip select lines; one per
|
||||
* CS number. Any individual value may be -ENOENT for CS lines that
|
||||
* are not GPIOs (driven by the SPI controller itself). Use the cs_gpiods
|
||||
|
@ -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
|
||||
* what Linux expects, this optional hook can be used to translate
|
||||
* 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
|
||||
* 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
|
||||
* spi_setup().
|
||||
*/
|
||||
void (*set_cs_timing)(struct spi_device *spi, u8 setup_clk_cycles,
|
||||
u8 hold_clk_cycles, u8 inactive_clk_cycles);
|
||||
int (*set_cs_timing)(struct spi_device *spi, struct spi_delay *setup,
|
||||
struct spi_delay *hold, struct spi_delay *inactive);
|
||||
|
||||
/* bidirectional bulk transfers
|
||||
*
|
||||
|
@ -587,6 +615,11 @@ struct spi_controller {
|
|||
/* Optimized handlers for SPI memory-like operations. */
|
||||
const struct spi_controller_mem_ops *mem_ops;
|
||||
|
||||
/* CS delays */
|
||||
struct spi_delay cs_setup;
|
||||
struct spi_delay cs_hold;
|
||||
struct spi_delay cs_inactive;
|
||||
|
||||
/* gpio chip select */
|
||||
int *cs_gpios;
|
||||
struct gpio_desc **cs_gpiods;
|
||||
|
@ -604,6 +637,15 @@ struct spi_controller {
|
|||
void *dummy_tx;
|
||||
|
||||
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)
|
||||
|
@ -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_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 */
|
||||
extern struct spi_controller *__spi_alloc_controller(struct device *host,
|
||||
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_delay: delay between cs deassert and assert when
|
||||
* @cs_change is set and @spi_transfer is not the last in @spi_message
|
||||
* @cs_change_delay_unit: unit of cs_change_delay
|
||||
* @delay: delay to be introduced after this transfer before
|
||||
* (optionally) changing the chipselect status, then starting
|
||||
* the next transfer or completing this @spi_message.
|
||||
* @delay_usecs: microseconds to delay after this transfer before
|
||||
* (optionally) changing the chipselect status, then starting
|
||||
* the next transfer or completing this @spi_message.
|
||||
* @word_delay_usecs: microseconds to inter word delay after each word size
|
||||
* (set by bits_per_word) transmission.
|
||||
* @word_delay: clock cycles to inter word delay after each word size
|
||||
* @word_delay: inter word delay to be introduced after each word size
|
||||
* (set by bits_per_word) transmission.
|
||||
* @effective_speed_hz: the effective SCK-speed that was used to
|
||||
* transfer this transfer. Set to 0 if the spi bus driver does
|
||||
|
@ -753,6 +803,35 @@ extern void spi_res_release(struct spi_controller *ctlr,
|
|||
* @transfer_list: transfers are sequenced through @spi_message.transfers
|
||||
* @tx_sg: Scatterlist for transmit, 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.
|
||||
* 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_QUAD 0x04 /* 4bits transfer */
|
||||
u8 bits_per_word;
|
||||
u8 word_delay_usecs;
|
||||
u16 delay_usecs;
|
||||
u16 cs_change_delay;
|
||||
u8 cs_change_delay_unit;
|
||||
#define SPI_DELAY_UNIT_USECS 0
|
||||
#define SPI_DELAY_UNIT_NSECS 1
|
||||
#define SPI_DELAY_UNIT_SCK 2
|
||||
struct spi_delay delay;
|
||||
struct spi_delay cs_change_delay;
|
||||
struct spi_delay word_delay;
|
||||
u32 speed_hz;
|
||||
u16 word_delay;
|
||||
|
||||
u32 effective_speed_hz;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
@ -935,6 +1018,20 @@ spi_transfer_del(struct spi_transfer *t)
|
|||
list_del(&t->transfer_list);
|
||||
}
|
||||
|
||||
static inline int
|
||||
spi_transfer_delay_exec(struct spi_transfer *t)
|
||||
{
|
||||
struct spi_delay d;
|
||||
|
||||
if (t->delay_usecs) {
|
||||
d.value = t->delay_usecs;
|
||||
d.unit = SPI_DELAY_UNIT_USECS;
|
||||
return spi_delay_exec(&d, NULL);
|
||||
}
|
||||
|
||||
return spi_delay_exec(&t->delay, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* spi_message_init_with_transfers - Initialize spi_message and append transfers
|
||||
* @m: spi_message to be initialized
|
||||
|
@ -982,7 +1079,10 @@ static inline void spi_message_free(struct spi_message *m)
|
|||
kfree(m);
|
||||
}
|
||||
|
||||
extern void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold, u8 inactive_dly);
|
||||
extern int spi_set_cs_timing(struct spi_device *spi,
|
||||
struct spi_delay *setup,
|
||||
struct spi_delay *hold,
|
||||
struct spi_delay *inactive);
|
||||
|
||||
extern int spi_setup(struct spi_device *spi);
|
||||
extern int spi_async(struct spi_device *spi, struct spi_message *message);
|
||||
|
|
|
@ -177,7 +177,7 @@ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
|
|||
/* we can only change the settings if the port is not in use */
|
||||
if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) ||
|
||||
(mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) {
|
||||
dev_err(&sspa->pdev->dev,
|
||||
dev_err(sspa->dev,
|
||||
"can't change hardware dai format: stream is in use\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -52,11 +52,11 @@ struct ssp_priv {
|
|||
|
||||
static void dump_registers(struct ssp_device *ssp)
|
||||
{
|
||||
dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n",
|
||||
dev_dbg(ssp->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n",
|
||||
pxa_ssp_read_reg(ssp, SSCR0), pxa_ssp_read_reg(ssp, SSCR1),
|
||||
pxa_ssp_read_reg(ssp, SSTO));
|
||||
|
||||
dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n",
|
||||
dev_dbg(ssp->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n",
|
||||
pxa_ssp_read_reg(ssp, SSPSP), pxa_ssp_read_reg(ssp, SSSR),
|
||||
pxa_ssp_read_reg(ssp, SSACD));
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
|
|||
clk_id = PXA_SSP_CLK_EXT;
|
||||
}
|
||||
|
||||
dev_dbg(&ssp->pdev->dev,
|
||||
dev_dbg(ssp->dev,
|
||||
"pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n",
|
||||
cpu_dai->id, clk_id, freq);
|
||||
|
||||
|
@ -316,7 +316,7 @@ static int pxa_ssp_set_pll(struct ssp_priv *priv, unsigned int freq)
|
|||
|
||||
ssacd |= (0x6 << 4);
|
||||
|
||||
dev_dbg(&ssp->pdev->dev,
|
||||
dev_dbg(ssp->dev,
|
||||
"Using SSACDD %x to supply %uHz\n",
|
||||
val, freq);
|
||||
break;
|
||||
|
@ -687,7 +687,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
|
|||
* - complain loudly and fail if they've not been set up yet.
|
||||
*/
|
||||
if ((sscr0 & SSCR0_MOD) && !ttsa) {
|
||||
dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
|
||||
dev_err(ssp->dev, "No TDM timeslot configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue