Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
fb02b9eb
Commit
fb02b9eb
authored
May 30, 2020
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/for-5.8' into spi-next
parents
0c0c5b8f
263b81dc
Changes
49
Hide whitespace changes
Inline
Side-by-side
Showing
49 changed files
with
2017 additions
and
570 deletions
+2017
-570
Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt
Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt
+10
-0
Documentation/devicetree/bindings/spi/mikrotik,rb4xx-spi.yaml
...mentation/devicetree/bindings/spi/mikrotik,rb4xx-spi.yaml
+36
-0
Documentation/devicetree/bindings/spi/renesas,rspi.yaml
Documentation/devicetree/bindings/spi/renesas,rspi.yaml
+144
-0
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt
+0
-41
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
+133
-0
Documentation/devicetree/bindings/spi/socionext,uniphier-spi.yaml
...ation/devicetree/bindings/spi/socionext,uniphier-spi.yaml
+57
-0
Documentation/devicetree/bindings/spi/spi-dw.txt
Documentation/devicetree/bindings/spi/spi-dw.txt
+0
-24
Documentation/devicetree/bindings/spi/spi-rspi.txt
Documentation/devicetree/bindings/spi/spi-rspi.txt
+0
-73
Documentation/devicetree/bindings/spi/spi-uniphier.txt
Documentation/devicetree/bindings/spi/spi-uniphier.txt
+0
-28
Documentation/devicetree/bindings/spi/ti_qspi.txt
Documentation/devicetree/bindings/spi/ti_qspi.txt
+1
-1
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/devicetree/bindings/vendor-prefixes.yaml
+2
-0
MAINTAINERS
MAINTAINERS
+5
-0
drivers/spi/Kconfig
drivers/spi/Kconfig
+16
-6
drivers/spi/Makefile
drivers/spi/Makefile
+4
-2
drivers/spi/spi-amd.c
drivers/spi/spi-amd.c
+315
-0
drivers/spi/spi-armada-3700.c
drivers/spi/spi-armada-3700.c
+3
-7
drivers/spi/spi-atmel.c
drivers/spi/spi-atmel.c
+1
-0
drivers/spi/spi-bcm-qspi.c
drivers/spi/spi-bcm-qspi.c
+132
-6
drivers/spi/spi-bcm2835.c
drivers/spi/spi-bcm2835.c
+18
-4
drivers/spi/spi-dw-core.c
drivers/spi/spi-dw-core.c
+94
-135
drivers/spi/spi-dw-dma.c
drivers/spi/spi-dw-dma.c
+480
-0
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-dw-mmio.c
+78
-8
drivers/spi/spi-dw-pci.c
drivers/spi/spi-dw-pci.c
+47
-3
drivers/spi/spi-dw.h
drivers/spi/spi-dw.h
+41
-25
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-dspi.c
+45
-2
drivers/spi/spi-fsl-lpspi.c
drivers/spi/spi-fsl-lpspi.c
+11
-10
drivers/spi/spi-fsl-qspi.c
drivers/spi/spi-fsl-qspi.c
+6
-5
drivers/spi/spi-fsl-spi.c
drivers/spi/spi-fsl-spi.c
+1
-1
drivers/spi/spi-hisi-sfc-v3xx.c
drivers/spi/spi-hisi-sfc-v3xx.c
+25
-1
drivers/spi/spi-imx.c
drivers/spi/spi-imx.c
+27
-4
drivers/spi/spi-mem.c
drivers/spi/spi-mem.c
+6
-4
drivers/spi/spi-mtk-nor.c
drivers/spi/spi-mtk-nor.c
+1
-1
drivers/spi/spi-orion.c
drivers/spi/spi-orion.c
+16
-54
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-pxa2xx.c
+1
-0
drivers/spi/spi-rb4xx.c
drivers/spi/spi-rb4xx.c
+14
-5
drivers/spi/spi-rockchip.c
drivers/spi/spi-rockchip.c
+134
-95
drivers/spi/spi-sh-msiof.c
drivers/spi/spi-sh-msiof.c
+1
-1
drivers/spi/spi-sprd-adi.c
drivers/spi/spi-sprd-adi.c
+1
-1
drivers/spi/spi-stm32-qspi.c
drivers/spi/spi-stm32-qspi.c
+58
-4
drivers/spi/spi-stm32.c
drivers/spi/spi-stm32.c
+15
-4
drivers/spi/spi-sun6i.c
drivers/spi/spi-sun6i.c
+1
-0
drivers/spi/spi-tegra114.c
drivers/spi/spi-tegra114.c
+1
-0
drivers/spi/spi-tegra20-sflash.c
drivers/spi/spi-tegra20-sflash.c
+1
-0
drivers/spi/spi-tegra20-slink.c
drivers/spi/spi-tegra20-slink.c
+1
-0
drivers/spi/spi-uniphier.c
drivers/spi/spi-uniphier.c
+7
-4
drivers/spi/spi.c
drivers/spi/spi.c
+6
-4
drivers/spi/spidev.c
drivers/spi/spidev.c
+2
-1
tools/spi/Makefile
tools/spi/Makefile
+3
-1
tools/spi/spidev_test.c
tools/spi/spidev_test.c
+16
-5
No files found.
Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt
View file @
fb02b9eb
...
...
@@ -26,6 +26,16 @@ Required properties:
"brcm,spi-bcm-qspi", "brcm,spi-brcmstb-qspi" : MSPI+BSPI on BRCMSTB SoCs
"brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm7425-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm7429-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm7435-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm7216-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm7278-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi" : MSPI+BSPI on Cygnus, NSP
"brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi" : NS2 SoCs
...
...
Documentation/devicetree/bindings/spi/mikrotik,rb4xx-spi.yaml
0 → 100644
View file @
fb02b9eb
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/spi/mikrotik,rb4xx-spi.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
MikroTik RB4xx series SPI master
maintainers
:
-
Gabor Juhos <juhosg@openwrt.org>
-
Bert Vermeulen <bert@biot.com>
allOf
:
-
$ref
:
"
spi-controller.yaml#"
properties
:
compatible
:
const
:
mikrotik,rb4xx-spi
reg
:
maxItems
:
1
required
:
-
compatible
-
reg
examples
:
-
|
spi: spi@1f000000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "mikrotik,rb4xx-spi";
reg = <0x1f000000 0x10>;
};
...
\ No newline at end of file
Documentation/devicetree/bindings/spi/renesas,rspi.yaml
0 → 100644
View file @
fb02b9eb
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/spi/renesas,rspi.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
Renesas (Quad) Serial Peripheral Interface (RSPI/QSPI)
maintainers
:
-
Geert Uytterhoeven <geert+renesas@glider.be>
properties
:
compatible
:
oneOf
:
-
items
:
-
enum
:
-
renesas,rspi-sh7757
# SH7757
-
const
:
renesas,rspi
# Legacy SH
-
items
:
-
enum
:
-
renesas,rspi-r7s72100
# RZ/A1H
-
renesas,rspi-r7s9210
# RZ/A2
-
const
:
renesas,rspi-rz
# RZ/A
-
items
:
-
enum
:
-
renesas,qspi-r8a7743
# RZ/G1M
-
renesas,qspi-r8a7744
# RZ/G1N
-
renesas,qspi-r8a7745
# RZ/G1E
-
renesas,qspi-r8a77470
# RZ/G1C
-
renesas,qspi-r8a7790
# R-Car H2
-
renesas,qspi-r8a7791
# R-Car M2-W
-
renesas,qspi-r8a7792
# R-Car V2H
-
renesas,qspi-r8a7793
# R-Car M2-N
-
renesas,qspi-r8a7794
# R-Car E2
-
const
:
renesas,qspi
# R-Car Gen2 and RZ/G1
reg
:
maxItems
:
1
interrupts
:
oneOf
:
-
items
:
-
description
:
A combined interrupt
-
items
:
-
description
:
Error interrupt (SPEI)
-
description
:
Receive Interrupt (SPRI)
-
description
:
Transmit Interrupt (SPTI)
interrupt-names
:
oneOf
:
-
items
:
-
const
:
mux
-
items
:
-
const
:
error
-
const
:
rx
-
const
:
tx
clocks
:
maxItems
:
1
power-domains
:
maxItems
:
1
resets
:
maxItems
:
1
dmas
:
description
:
Must contain a list of pairs of references to DMA specifiers, one for
transmission, and one for reception.
dma-names
:
minItems
:
2
maxItems
:
4
items
:
enum
:
-
tx
-
rx
num-cs
:
description
:
|
Total number of native chip selects.
Hardware limitations related to chip selects:
- When using GPIO chip selects, at least one native chip select must
be left unused, as it will be driven anyway.
minimum
:
1
maximum
:
2
default
:
1
required
:
-
compatible
-
reg
-
interrupts
-
clocks
-
power-domains
-
'
#address-cells'
-
'
#size-cells'
allOf
:
-
$ref
:
spi-controller.yaml#
-
if
:
properties
:
compatible
:
contains
:
enum
:
-
renesas,rspi-rz
then
:
properties
:
interrupts
:
minItems
:
3
required
:
-
interrupt-names
-
if
:
properties
:
compatible
:
contains
:
enum
:
-
renesas,qspi
then
:
required
:
-
resets
examples
:
-
|
#include <dt-bindings/clock/r8a7791-cpg-mssr.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7791-sysc.h>
qspi: spi@e6b10000 {
compatible = "renesas,qspi-r8a7791", "renesas,qspi";
reg = <0xe6b10000 0x2c>;
interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 917>;
dmas = <&dmac0 0x17>, <&dmac0 0x18>, <&dmac1 0x17>, <&dmac1 0x18>;
dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
resets = <&cpg 917>;
num-cs = <1>;
#address-cells = <1>;
#size-cells = <0>;
};
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.txt
deleted
100644 → 0
View file @
0c0c5b8f
Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface.
Required properties:
- compatible : "snps,dw-apb-ssi" or "mscc,<soc>-spi", where soc is "ocelot" or
"jaguar2", or "amazon,alpine-dw-apb-ssi"
- reg : The register base for the controller. For "mscc,<soc>-spi", a second
register set is required (named ICPU_CFG:SPI_MST)
- interrupts : One interrupt, used by the controller.
- #address-cells : <1>, as required by generic SPI binding.
- #size-cells : <0>, also as required by generic SPI binding.
- clocks : phandles for the clocks, see the description of clock-names below.
The phandle for the "ssi_clk" is required. The phandle for the "pclk" clock
is optional. If a single clock is specified but no clock-name, it is the
"ssi_clk" clock. If both clocks are listed, the "ssi_clk" must be first.
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. 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
device. Supported values are 2 or 4 (the default).
Child nodes as per the generic SPI binding.
Example:
spi@fff00000 {
compatible = "snps,dw-apb-ssi";
reg = <0xfff00000 0x1000>;
interrupts = <0 154 4>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&spi_m_clk>;
num-cs = <2>;
cs-gpios = <&gpio0 13 0>,
<&gpio0 14 0>;
};
Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
0 → 100644
View file @
fb02b9eb
# SPDX-License-Identifier: GPL-2.0-only
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/spi/snps,dw-apb-ssi.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface
maintainers
:
-
Mark Brown <broonie@kernel.org>
allOf
:
-
$ref
:
"
spi-controller.yaml#"
-
if
:
properties
:
compatible
:
contains
:
enum
:
-
mscc,ocelot-spi
-
mscc,jaguar2-spi
then
:
properties
:
reg
:
minItems
:
2
properties
:
compatible
:
oneOf
:
-
description
:
Generic DW SPI Controller
enum
:
-
snps,dw-apb-ssi
-
snps,dwc-ssi-1.01a
-
description
:
Microsemi Ocelot/Jaguar2 SoC SPI Controller
items
:
-
enum
:
-
mscc,ocelot-spi
-
mscc,jaguar2-spi
-
const
:
snps,dw-apb-ssi
-
description
:
Amazon Alpine SPI Controller
const
:
amazon,alpine-dw-apb-ssi
-
description
:
Renesas RZ/N1 SPI Controller
items
:
-
const
:
renesas,rzn1-spi
-
const
:
snps,dw-apb-ssi
-
description
:
Intel Keem Bay SPI Controller
const
:
intel,keembay-ssi
reg
:
minItems
:
1
items
:
-
description
:
DW APB SSI controller memory mapped registers
-
description
:
SPI MST region map
interrupts
:
maxItems
:
1
clocks
:
minItems
:
1
items
:
-
description
:
SPI Controller reference clock source
-
description
:
APB interface clock source
clock-names
:
minItems
:
1
items
:
-
const
:
ssi_clk
-
const
:
pclk
resets
:
maxItems
:
1
reset-names
:
const
:
spi
reg-io-width
:
$ref
:
/schemas/types.yaml#/definitions/uint32
description
:
I/O register width (in bytes) implemented by this device
default
:
4
enum
:
[
2
,
4
]
num-cs
:
default
:
4
minimum
:
1
maximum
:
4
dmas
:
items
:
-
description
:
TX DMA Channel
-
description
:
RX DMA Channel
dma-names
:
items
:
-
const
:
tx
-
const
:
rx
patternProperties
:
"
^.*@[0-9a-f]+$"
:
type
:
object
properties
:
reg
:
minimum
:
0
maximum
:
3
spi-rx-bus-width
:
const
:
1
spi-tx-bus-width
:
const
:
1
unevaluatedProperties
:
false
required
:
-
compatible
-
reg
-
"
#address-cells"
-
"
#size-cells"
-
interrupts
-
clocks
examples
:
-
|
spi@fff00000 {
compatible = "snps,dw-apb-ssi";
reg = <0xfff00000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 154 4>;
clocks = <&spi_m_clk>;
num-cs = <2>;
cs-gpios = <&gpio0 13 0>,
<&gpio0 14 0>;
};
...
Documentation/devicetree/bindings/spi/socionext,uniphier-spi.yaml
0 → 100644
View file @
fb02b9eb
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML
1.2
---
$id
:
http://devicetree.org/schemas/spi/socionext,uniphier-spi.yaml#
$schema
:
http://devicetree.org/meta-schemas/core.yaml#
title
:
Socionext UniPhier SPI controller
description
:
|
UniPhier SoCs have SCSSI which supports SPI single channel.
maintainers
:
-
Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
-
Keiji Hayashibara <hayashibara.keiji@socionext.com>
allOf
:
-
$ref
:
spi-controller.yaml#
properties
:
"
#address-cells"
:
true
"
#size-cells"
:
true
compatible
:
const
:
socionext,uniphier-scssi
reg
:
maxItems
:
1
interrupts
:
maxItems
:
1
clocks
:
maxItems
:
1
resets
:
maxItems
:
1
required
:
-
compatible
-
reg
-
interrupts
-
clocks
-
resets
-
"
#address-cells"
-
"
#size-cells"
examples
:
-
|
spi0: spi@54006000 {
compatible = "socionext,uniphier-scssi";
reg = <0x54006000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 39 4>;
clocks = <&peri_clk 11>;
resets = <&peri_rst 11>;
};
Documentation/devicetree/bindings/spi/spi-dw.txt
deleted
100644 → 0
View file @
0c0c5b8f
Synopsys DesignWare SPI master
Required properties:
- compatible: should be "snps,designware-spi"
- #address-cells: see spi-bus.txt
- #size-cells: see spi-bus.txt
- reg: address and length of the spi master registers
- interrupts: should contain one interrupt
- clocks: spi clock phandle
- num-cs: see spi-bus.txt
Optional properties:
- cs-gpios: see spi-bus.txt
Example:
spi: spi@4020a000 {
compatible = "snps,designware-spi";
interrupts = <11 1>;
reg = <0x4020a000 0x1000>;
clocks = <&pclk>;
num-cs = <2>;
cs-gpios = <&banka 0 0>;
};
Documentation/devicetree/bindings/spi/spi-rspi.txt
deleted
100644 → 0
View file @
0c0c5b8f
Device tree configuration for Renesas RSPI/QSPI driver
Required properties:
- compatible : For Renesas Serial Peripheral Interface on legacy SH:
"renesas,rspi-<soctype>", "renesas,rspi" as fallback.
For Renesas Serial Peripheral Interface on RZ/A:
"renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
For Quad Serial Peripheral Interface on R-Car Gen2 and
RZ/G1 devices:
"renesas,qspi-<soctype>", "renesas,qspi" as fallback.
Examples with soctypes are:
- "renesas,rspi-sh7757" (SH)
- "renesas,rspi-r7s72100" (RZ/A1H)
- "renesas,rspi-r7s9210" (RZ/A2)
- "renesas,qspi-r8a7743" (RZ/G1M)
- "renesas,qspi-r8a7744" (RZ/G1N)
- "renesas,qspi-r8a7745" (RZ/G1E)
- "renesas,qspi-r8a77470" (RZ/G1C)
- "renesas,qspi-r8a7790" (R-Car H2)
- "renesas,qspi-r8a7791" (R-Car M2-W)
- "renesas,qspi-r8a7792" (R-Car V2H)
- "renesas,qspi-r8a7793" (R-Car M2-N)
- "renesas,qspi-r8a7794" (R-Car E2)
- reg : Address start and address range size of the device
- interrupts : A list of interrupt-specifiers, one for each entry in
interrupt-names.
If interrupt-names is not present, an interrupt specifier
for a single muxed interrupt.
- interrupt-names : A list of interrupt names. Should contain (if present):
- "error" for SPEI,
- "rx" for SPRI,
- "tx" to SPTI,
- "mux" for a single muxed interrupt.
- num-cs : Number of chip selects. Some RSPI cores have more than 1.
- #address-cells : Must be <1>
- #size-cells : Must be <0>
Optional properties:
- clocks : Must contain a reference to the functional clock.
- 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".
Pinctrl properties might be needed, too. See
Documentation/devicetree/bindings/pinctrl/renesas,*.
Examples:
spi0: spi@e800c800 {
compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
reg = <0xe800c800 0x24>;
interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>,
<0 239 IRQ_TYPE_LEVEL_HIGH>,
<0 240 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "error", "rx", "tx";
interrupt-parent = <&gic>;
num-cs = <1>;
#address-cells = <1>;
#size-cells = <0>;
};
spi: spi@e6b10000 {
compatible = "renesas,qspi-r8a7791", "renesas,qspi";
reg = <0 0xe6b10000 0 0x2c>;
interrupt-parent = <&gic>;
interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>;
num-cs = <1>;
#address-cells = <1>;
#size-cells = <0>;
dmas = <&dmac0 0x17>, <&dmac0 0x18>;
dma-names = "tx", "rx";
};
Documentation/devicetree/bindings/spi/spi-uniphier.txt
deleted
100644 → 0
View file @
0c0c5b8f
Socionext UniPhier SPI controller driver
UniPhier SoCs have SCSSI which supports SPI single channel.
Required properties:
- compatible: should be "socionext,uniphier-scssi"
- reg: address and length of the spi master registers
- #address-cells: must be <1>, see spi-bus.txt
- #size-cells: must be <0>, see spi-bus.txt
- interrupts: a single interrupt specifier
- pinctrl-names: should be "default"
- pinctrl-0: pin control state for the default mode
- clocks: a phandle to the clock for the device
- resets: a phandle to the reset control for the device
Example:
spi0: spi@54006000 {
compatible = "socionext,uniphier-scssi";
reg = <0x54006000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 39 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spi0>;
clocks = <&peri_clk 11>;
resets = <&peri_rst 11>;
};
Documentation/devicetree/bindings/spi/ti_qspi.txt
View file @
fb02b9eb
...
...
@@ -29,7 +29,7 @@ modification to bootloader.
Example:
For am4372:
qspi: qspi@4
b3
00000 {
qspi: qspi@4
79
00000 {
compatible = "ti,am4372-qspi";
reg = <0x47900000 0x100>, <0x30000000 0x4000000>;
reg-names = "qspi_base", "qspi_mmap";
...
...
Documentation/devicetree/bindings/vendor-prefixes.yaml
View file @
fb02b9eb
...
...
@@ -633,6 +633,8 @@ patternProperties:
description
:
Microsoft Corporation
"
^mikroe,.*"
:
description
:
MikroElektronika d.o.o.
"
^mikrotik,.*"
:
description
:
MikroTik
"
^miniand,.*"
:
description
:
Miniand Tech
"
^minix,.*"
:
...
...
MAINTAINERS
View file @
fb02b9eb
...
...
@@ -892,6 +892,11 @@ F: drivers/gpu/drm/amd/include/v9_structs.h
F: drivers/gpu/drm/amd/include/vi_structs.h
F: include/uapi/linux/kfd_ioctl.h
AMD SPI DRIVER
M: Sanjay R Mehta <sanju.mehta@amd.com>
S: Maintained
F: drivers/spi/spi-amd.c
AMD MP2 I2C DRIVER
M: Elie Morisse <syniurge@gmail.com>
M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
...
...
drivers/spi/Kconfig
View file @
fb02b9eb
...
...
@@ -226,17 +226,20 @@ config SPI_DESIGNWARE
help
general driver for SPI controller core from DesignWare
if SPI_DESIGNWARE
config SPI_DW_DMA
bool "DMA support for DW SPI controller"
config SPI_DW_PCI
tristate "PCI interface driver for DW SPI core"
depends on SPI_DESIGNWARE && PCI
config SPI_DW_MID_DMA
bool "DMA support for DW SPI controller on Intel MID platform"
depends on SPI_DW_PCI && DW_DMAC_PCI
depends on PCI
config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core"
depends on SPI_DESIGNWARE
depends on HAS_IOMEM
endif
config SPI_DLN2
tristate "Diolan DLN-2 USB SPI adapter"
...
...
@@ -844,6 +847,7 @@ config SPI_TXX9
config SPI_UNIPHIER
tristate "Socionext UniPhier SPI Controller"
depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
depends on HAS_IOMEM
help
This enables a driver for the Socionext UniPhier SoC SCSSI SPI controller.
...
...
@@ -910,6 +914,12 @@ config SPI_ZYNQMP_GQSPI
help
Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
config SPI_AMD
tristate "AMD SPI controller"
depends on SPI_MASTER || COMPILE_TEST
help
Enables SPI controller driver for AMD SoC.
#
# Add new SPI master controllers in alphabetical order above this line
#
...
...
drivers/spi/Makefile
View file @
fb02b9eb
...
...
@@ -36,9 +36,10 @@ obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
obj-$(CONFIG_SPI_DAVINCI)
+=
spi-davinci.o
obj-$(CONFIG_SPI_DLN2)
+=
spi-dln2.o
obj-$(CONFIG_SPI_DESIGNWARE)
+=
spi-dw.o
spi-dw-y
:=
spi-dw-core.o
spi-dw-$(CONFIG_SPI_DW_DMA)
+=
spi-dw-dma.o
obj-$(CONFIG_SPI_DW_MMIO)
+=
spi-dw-mmio.o
obj-$(CONFIG_SPI_DW_PCI)
+=
spi-dw-midpci.o
spi-dw-midpci-objs
:=
spi-dw-pci.o spi-dw-mid.o
obj-$(CONFIG_SPI_DW_PCI)
+=
spi-dw-pci.o
obj-$(CONFIG_SPI_EFM32)
+=
spi-efm32.o
obj-$(CONFIG_SPI_EP93XX)
+=
spi-ep93xx.o
obj-$(CONFIG_SPI_FALCON)
+=
spi-falcon.o
...
...
@@ -127,6 +128,7 @@ obj-$(CONFIG_SPI_XLP) += spi-xlp.o
obj-$(CONFIG_SPI_XTENSA_XTFPGA)
+=
spi-xtensa-xtfpga.o
obj-$(CONFIG_SPI_ZYNQ_QSPI)
+=
spi-zynq-qspi.o
obj-$(CONFIG_SPI_ZYNQMP_GQSPI)
+=
spi-zynqmp-gqspi.o
obj-$(CONFIG_SPI_AMD)
+=
spi-amd.o
# SPI slave protocol handlers
obj-$(CONFIG_SPI_SLAVE_TIME)
+=
spi-slave-time.o
...
...
drivers/spi/spi-amd.c
0 → 100644
View file @
fb02b9eb
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
//
// AMD SPI controller driver
//
// Copyright (c) 2020, Advanced Micro Devices, Inc.
//
// Author: Sanjay R Mehta <sanju.mehta@amd.com>
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#define AMD_SPI_CTRL0_REG 0x00
#define AMD_SPI_EXEC_CMD BIT(16)
#define AMD_SPI_FIFO_CLEAR BIT(20)
#define AMD_SPI_BUSY BIT(31)
#define AMD_SPI_OPCODE_MASK 0xFF
#define AMD_SPI_ALT_CS_REG 0x1D
#define AMD_SPI_ALT_CS_MASK 0x3
#define AMD_SPI_FIFO_BASE 0x80
#define AMD_SPI_TX_COUNT_REG 0x48
#define AMD_SPI_RX_COUNT_REG 0x4B
#define AMD_SPI_STATUS_REG 0x4C
#define AMD_SPI_MEM_SIZE 200
/* M_CMD OP codes for SPI */
#define AMD_SPI_XFER_TX 1
#define AMD_SPI_XFER_RX 2
struct
amd_spi
{
void
__iomem
*
io_remap_addr
;
unsigned
long
io_base_addr
;
u32
rom_addr
;
u8
chip_select
;
};
static
inline
u8
amd_spi_readreg8
(
struct
spi_master
*
master
,
int
idx
)
{
struct
amd_spi
*
amd_spi
=
spi_master_get_devdata
(
master
);
return
ioread8
((
u8
__iomem
*
)
amd_spi
->
io_remap_addr
+
idx
);
}
static
inline
void
amd_spi_writereg8
(
struct
spi_master
*
master
,
int
idx
,
u8
val
)
{
struct
amd_spi
*
amd_spi
=
spi_master_get_devdata
(
master
);
iowrite8
(
val
,
((
u8
__iomem
*
)
amd_spi
->
io_remap_addr
+
idx
));
}
static
inline
void
amd_spi_setclear_reg8
(
struct
spi_master
*
master
,
int
idx
,
u8
set
,
u8
clear
)
{
u8
tmp
=
amd_spi_readreg8
(
master
,
idx
);
tmp
=
(
tmp
&
~
clear
)
|
set
;
amd_spi_writereg8
(
master
,
idx
,
tmp
);
}
static
inline
u32
amd_spi_readreg32
(
struct
spi_master
*
master
,
int
idx
)
{
struct
amd_spi
*
amd_spi
=
spi_master_get_devdata
(
master
);
return
ioread32
((
u8
__iomem
*
)
amd_spi
->
io_remap_addr
+
idx
);
}
static
inline
void
amd_spi_writereg32
(
struct
spi_master
*
master
,
int
idx
,
u32
val
)
{
struct
amd_spi
*
amd_spi
=
spi_master_get_devdata
(
master
);
iowrite32
(
val
,
((
u8
__iomem
*
)
amd_spi
->
io_remap_addr
+
idx
));
}
static
inline
void
amd_spi_setclear_reg32
(
struct
spi_master
*
master
,
int
idx
,
u32
set
,
u32
clear
)
{
u32
tmp
=
amd_spi_readreg32
(
master
,
idx
);
tmp
=
(
tmp
&
~
clear
)
|
set
;
amd_spi_writereg32
(
master
,
idx
,
tmp
);
}
static
void
amd_spi_select_chip
(
struct
spi_master
*
master
)
{
struct
amd_spi
*
amd_spi
=
spi_master_get_devdata
(
master
);
u8
chip_select
=
amd_spi
->
chip_select
;
amd_spi_setclear_reg8
(
master
,
AMD_SPI_ALT_CS_REG
,
chip_select
,
AMD_SPI_ALT_CS_MASK
);
}
static
void
amd_spi_clear_fifo_ptr
(
struct
spi_master
*
master
)
{
amd_spi_setclear_reg32
(
master
,
AMD_SPI_CTRL0_REG
,
AMD_SPI_FIFO_CLEAR
,
AMD_SPI_FIFO_CLEAR
);
}
static
void
amd_spi_set_opcode
(
struct
spi_master
*
master
,
u8
cmd_opcode
)
{
amd_spi_setclear_reg32
(
master
,
AMD_SPI_CTRL0_REG
,
cmd_opcode
,
AMD_SPI_OPCODE_MASK
);
}
static
inline
void
amd_spi_set_rx_count
(
struct
spi_master
*
master
,
u8
rx_count
)
{
amd_spi_setclear_reg8
(
master
,
AMD_SPI_RX_COUNT_REG
,
rx_count
,
0xff
);
}
static
inline
void
amd_spi_set_tx_count
(
struct
spi_master
*
master
,
u8
tx_count
)
{
amd_spi_setclear_reg8
(
master
,
AMD_SPI_TX_COUNT_REG
,
tx_count
,
0xff
);
}
static
inline
int
amd_spi_busy_wait
(
struct
amd_spi
*
amd_spi
)
{
bool
spi_busy
;
int
timeout
=
100000
;
/* poll for SPI bus to become idle */
spi_busy
=
(
ioread32
((
u8
__iomem
*
)
amd_spi
->
io_remap_addr
+
AMD_SPI_CTRL0_REG
)
&
AMD_SPI_BUSY
)
==
AMD_SPI_BUSY
;
while
(
spi_busy
)
{
usleep_range
(
10
,
20
);
if
(
timeout
--
<
0
)
return
-
ETIMEDOUT
;
spi_busy
=
(
ioread32
((
u8
__iomem
*
)
amd_spi
->
io_remap_addr
+
AMD_SPI_CTRL0_REG
)
&
AMD_SPI_BUSY
)
==
AMD_SPI_BUSY
;
}
return
0
;
}
static
void
amd_spi_execute_opcode
(
struct
spi_master
*
master
)
{
struct
amd_spi
*
amd_spi
=
spi_master_get_devdata
(
master
);
/* Set ExecuteOpCode bit in the CTRL0 register */
amd_spi_setclear_reg32
(
master
,
AMD_SPI_CTRL0_REG
,
AMD_SPI_EXEC_CMD
,
AMD_SPI_EXEC_CMD
);
amd_spi_busy_wait
(
amd_spi
);
}
static
int
amd_spi_master_setup
(
struct
spi_device
*
spi
)
{
struct
spi_master
*
master
=
spi
->
master
;
amd_spi_clear_fifo_ptr
(
master
);
return
0
;
}
static
inline
int
amd_spi_fifo_xfer
(
struct
amd_spi
*
amd_spi
,
struct
spi_master
*
master
,
struct
spi_message
*
message
)
{
struct
spi_transfer
*
xfer
=
NULL
;
u8
cmd_opcode
;
u8
*
buf
=
NULL
;
u32
m_cmd
=
0
;
u32
i
=
0
;
u32
tx_len
=
0
,
rx_len
=
0
;
list_for_each_entry
(
xfer
,
&
message
->
transfers
,
transfer_list
)
{
if
(
xfer
->
rx_buf
)
m_cmd
=
AMD_SPI_XFER_RX
;
if
(
xfer
->
tx_buf
)
m_cmd
=
AMD_SPI_XFER_TX
;
if
(
m_cmd
&
AMD_SPI_XFER_TX
)
{
buf
=
(
u8
*
)
xfer
->
tx_buf
;
tx_len
=
xfer
->
len
-
1
;
cmd_opcode
=
*
(
u8
*
)
xfer
->
tx_buf
;
buf
++
;
amd_spi_set_opcode
(
master
,
cmd_opcode
);
/* Write data into the FIFO. */
for
(
i
=
0
;
i
<
tx_len
;
i
++
)
{
iowrite8
(
buf
[
i
],
((
u8
__iomem
*
)
amd_spi
->
io_remap_addr
+
AMD_SPI_FIFO_BASE
+
i
));
}
amd_spi_set_tx_count
(
master
,
tx_len
);
amd_spi_clear_fifo_ptr
(
master
);
/* Execute command */
amd_spi_execute_opcode
(
master
);
}
if
(
m_cmd
&
AMD_SPI_XFER_RX
)
{
/*
* Store no. of bytes to be received from
* FIFO
*/
rx_len
=
xfer
->
len
;
buf
=
(
u8
*
)
xfer
->
rx_buf
;
amd_spi_set_rx_count
(
master
,
rx_len
);
amd_spi_clear_fifo_ptr
(
master
);
/* Execute command */
amd_spi_execute_opcode
(
master
);
/* Read data from FIFO to receive buffer */
for
(
i
=
0
;
i
<
rx_len
;
i
++
)
buf
[
i
]
=
amd_spi_readreg8
(
master
,
AMD_SPI_FIFO_BASE
+
tx_len
+
i
);
}
}
/* Update statistics */
message
->
actual_length
=
tx_len
+
rx_len
+
1
;
/* complete the transaction */
message
->
status
=
0
;
spi_finalize_current_message
(
master
);
return
0
;
}
static
int
amd_spi_master_transfer
(
struct
spi_master
*
master
,
struct
spi_message
*
msg
)
{
struct
amd_spi
*
amd_spi
=
spi_master_get_devdata
(
master
);
struct
spi_device
*
spi
=
msg
->
spi
;
amd_spi
->
chip_select
=
spi
->
chip_select
;
amd_spi_select_chip
(
master
);
/*
* Extract spi_transfers from the spi message and
* program the controller.
*/
amd_spi_fifo_xfer
(
amd_spi
,
master
,
msg
);
return
0
;
}
static
int
amd_spi_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
struct
spi_master
*
master
;
struct
amd_spi
*
amd_spi
;
struct
resource
*
res
;
int
err
=
0
;
/* Allocate storage for spi_master and driver private data */
master
=
spi_alloc_master
(
dev
,
sizeof
(
struct
amd_spi
));
if
(
!
master
)
{
dev_err
(
dev
,
"Error allocating SPI master
\n
"
);
return
-
ENOMEM
;
}
amd_spi
=
spi_master_get_devdata
(
master
);
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
amd_spi
->
io_remap_addr
=
devm_ioremap_resource
(
&
pdev
->
dev
,
res
);
if
(
IS_ERR
(
amd_spi
->
io_remap_addr
))
{
err
=
PTR_ERR
(
amd_spi
->
io_remap_addr
);
dev_err
(
dev
,
"error %d ioremap of SPI registers failed
\n
"
,
err
);
goto
err_free_master
;
}
dev_dbg
(
dev
,
"io_remap_address: %p
\n
"
,
amd_spi
->
io_remap_addr
);
/* Initialize the spi_master fields */
master
->
bus_num
=
0
;
master
->
num_chipselect
=
4
;
master
->
mode_bits
=
0
;
master
->
flags
=
SPI_MASTER_HALF_DUPLEX
;
master
->
setup
=
amd_spi_master_setup
;
master
->
transfer_one_message
=
amd_spi_master_transfer
;
/* Register the controller with SPI framework */
err
=
devm_spi_register_master
(
dev
,
master
);
if
(
err
)
{
dev_err
(
dev
,
"error %d registering SPI controller
\n
"
,
err
);
goto
err_free_master
;
}
return
0
;
err_free_master:
spi_master_put
(
master
);
return
err
;
}
static
const
struct
acpi_device_id
spi_acpi_match
[]
=
{
{
"AMDI0061"
,
0
},
{},
};
MODULE_DEVICE_TABLE
(
acpi
,
spi_acpi_match
);
static
struct
platform_driver
amd_spi_driver
=
{
.
driver
=
{
.
name
=
"amd_spi"
,
.
acpi_match_table
=
ACPI_PTR
(
spi_acpi_match
),
},
.
probe
=
amd_spi_probe
,
};
module_platform_driver
(
amd_spi_driver
);
MODULE_LICENSE
(
"Dual BSD/GPL"
);
MODULE_AUTHOR
(
"Sanjay Mehta <sanju.mehta@amd.com>"
);
MODULE_DESCRIPTION
(
"AMD SPI Master Controller Driver"
);
drivers/spi/spi-armada-3700.c
View file @
fb02b9eb
...
...
@@ -276,11 +276,11 @@ static int a3700_spi_fifo_flush(struct a3700_spi *a3700_spi)
return
-
ETIMEDOUT
;
}
static
int
a3700_spi_init
(
struct
a3700_spi
*
a3700_spi
)
static
void
a3700_spi_init
(
struct
a3700_spi
*
a3700_spi
)
{
struct
spi_master
*
master
=
a3700_spi
->
master
;
u32
val
;
int
i
,
ret
=
0
;
int
i
;
/* Reset SPI unit */
val
=
spireg_read
(
a3700_spi
,
A3700_SPI_IF_CFG_REG
);
...
...
@@ -311,8 +311,6 @@ static int a3700_spi_init(struct a3700_spi *a3700_spi)
/* Mask the interrupts and clear cause bits */
spireg_write
(
a3700_spi
,
A3700_SPI_INT_MASK_REG
,
0
);
spireg_write
(
a3700_spi
,
A3700_SPI_INT_STAT_REG
,
~
0U
);
return
ret
;
}
static
irqreturn_t
a3700_spi_interrupt
(
int
irq
,
void
*
dev_id
)
...
...
@@ -886,9 +884,7 @@ static int a3700_spi_probe(struct platform_device *pdev)
master
->
min_speed_hz
=
DIV_ROUND_UP
(
clk_get_rate
(
spi
->
clk
),
A3700_SPI_MAX_PRESCALE
);
ret
=
a3700_spi_init
(
spi
);
if
(
ret
)
goto
error_clk
;
a3700_spi_init
(
spi
);
ret
=
devm_request_irq
(
dev
,
spi
->
irq
,
a3700_spi_interrupt
,
0
,
dev_name
(
dev
),
master
);
...
...
drivers/spi/spi-atmel.c
View file @
fb02b9eb
...
...
@@ -706,6 +706,7 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master,
static
int
atmel_spi_next_xfer_dma_submit
(
struct
spi_master
*
master
,
struct
spi_transfer
*
xfer
,
u32
*
plen
)
__must_hold
(
&
as
->
lock
)
{
struct
atmel_spi
*
as
=
spi_master_get_devdata
(
master
);
struct
dma_chan
*
rxchan
=
master
->
dma_rx
;
...
...
drivers/spi/spi-bcm-qspi.c
View file @
fb02b9eb
...
...
@@ -91,6 +91,7 @@
#define MSPI_MSPI_STATUS 0x020
#define MSPI_CPTQP 0x024
#define MSPI_SPCR3 0x028
#define MSPI_REV 0x02c
#define MSPI_TXRAM 0x040
#define MSPI_RXRAM 0x0c0
#define MSPI_CDRAM 0x140
...
...
@@ -106,14 +107,22 @@
#define MSPI_SPCR2_SPE BIT(6)
#define MSPI_SPCR2_CONT_AFTER_CMD BIT(7)
#define MSPI_SPCR3_FASTBR BIT(0)
#define MSPI_SPCR3_FASTDT BIT(1)
#define MSPI_SPCR3_SYSCLKSEL_MASK GENMASK(11, 10)
#define MSPI_SPCR3_SYSCLKSEL_27 (MSPI_SPCR3_SYSCLKSEL_MASK & \
~(BIT(10) | BIT(11)))
#define MSPI_SPCR3_SYSCLKSEL_108 (MSPI_SPCR3_SYSCLKSEL_MASK & \
BIT(11))
#define MSPI_MSPI_STATUS_SPIF BIT(0)
#define INTR_BASE_BIT_SHIFT 0x02
#define INTR_COUNT 0x07
#define NUM_CHIPSELECT 4
#define QSPI_SPBR_MIN 8U
#define QSPI_SPBR_MAX 255U
#define MSPI_BASE_FREQ 27000000UL
#define OPCODE_DIOR 0xBB
#define OPCODE_QIOR 0xEB
...
...
@@ -217,6 +226,9 @@ struct bcm_qspi {
struct
bcm_qspi_dev_id
*
dev_ids
;
struct
completion
mspi_done
;
struct
completion
bspi_done
;
u8
mspi_maj_rev
;
u8
mspi_min_rev
;
bool
mspi_spcr3_sysclk
;
};
static
inline
bool
has_bspi
(
struct
bcm_qspi
*
qspi
)
...
...
@@ -224,6 +236,36 @@ static inline bool has_bspi(struct bcm_qspi *qspi)
return
qspi
->
bspi_mode
;
}
/* hardware supports spcr3 and fast baud-rate */
static
inline
bool
bcm_qspi_has_fastbr
(
struct
bcm_qspi
*
qspi
)
{
if
(
!
has_bspi
(
qspi
)
&&
((
qspi
->
mspi_maj_rev
>=
1
)
&&
(
qspi
->
mspi_min_rev
>=
5
)))
return
true
;
return
false
;
}
/* hardware supports sys clk 108Mhz */
static
inline
bool
bcm_qspi_has_sysclk_108
(
struct
bcm_qspi
*
qspi
)
{
if
(
!
has_bspi
(
qspi
)
&&
(
qspi
->
mspi_spcr3_sysclk
||
((
qspi
->
mspi_maj_rev
>=
1
)
&&
(
qspi
->
mspi_min_rev
>=
6
))))
return
true
;
return
false
;
}
static
inline
int
bcm_qspi_spbr_min
(
struct
bcm_qspi
*
qspi
)
{
if
(
bcm_qspi_has_fastbr
(
qspi
))
return
1
;
else
return
8
;
}
/* Read qspi controller register*/
static
inline
u32
bcm_qspi_read
(
struct
bcm_qspi
*
qspi
,
enum
base_type
type
,
unsigned
int
offset
)
...
...
@@ -531,16 +573,39 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
if
(
xp
->
speed_hz
)
spbr
=
qspi
->
base_clk
/
(
2
*
xp
->
speed_hz
);
spcr
=
clamp_val
(
spbr
,
QSPI_SPBR_MIN
,
QSPI_SPBR_MAX
);
spcr
=
clamp_val
(
spbr
,
bcm_qspi_spbr_min
(
qspi
)
,
QSPI_SPBR_MAX
);
bcm_qspi_write
(
qspi
,
MSPI
,
MSPI_SPCR0_LSB
,
spcr
);
spcr
=
MSPI_MASTER_BIT
;
if
(
!
qspi
->
mspi_maj_rev
)
/* legacy controller */
spcr
=
MSPI_MASTER_BIT
;
else
spcr
=
0
;
/* for 16 bit the data should be zero */
if
(
xp
->
bits_per_word
!=
16
)
spcr
|=
xp
->
bits_per_word
<<
2
;
spcr
|=
xp
->
mode
&
3
;
bcm_qspi_write
(
qspi
,
MSPI
,
MSPI_SPCR0_MSB
,
spcr
);
if
(
bcm_qspi_has_fastbr
(
qspi
))
{
spcr
=
0
;
/* enable fastbr */
spcr
|=
MSPI_SPCR3_FASTBR
;
if
(
bcm_qspi_has_sysclk_108
(
qspi
))
{
/* SYSCLK_108 */
spcr
|=
MSPI_SPCR3_SYSCLKSEL_108
;
qspi
->
base_clk
=
MSPI_BASE_FREQ
*
4
;
/* Change spbr as we changed sysclk */
bcm_qspi_write
(
qspi
,
MSPI
,
MSPI_SPCR0_LSB
,
4
);
}
bcm_qspi_write
(
qspi
,
MSPI
,
MSPI_SPCR3
,
spcr
);
}
qspi
->
last_parms
=
*
xp
;
}
...
...
@@ -1195,8 +1260,51 @@ static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
.
exec_op
=
bcm_qspi_exec_mem_op
,
};
struct
bcm_qspi_data
{
bool
has_mspi_rev
;
bool
has_spcr3_sysclk
;
};
static
const
struct
bcm_qspi_data
bcm_qspi_no_rev_data
=
{
.
has_mspi_rev
=
false
,
.
has_spcr3_sysclk
=
false
,
};
static
const
struct
bcm_qspi_data
bcm_qspi_rev_data
=
{
.
has_mspi_rev
=
true
,
.
has_spcr3_sysclk
=
false
,
};
static
const
struct
bcm_qspi_data
bcm_qspi_spcr3_data
=
{
.
has_mspi_rev
=
true
,
.
has_spcr3_sysclk
=
true
,
};
static
const
struct
of_device_id
bcm_qspi_of_match
[]
=
{
{
.
compatible
=
"brcm,spi-bcm-qspi"
},
{
.
compatible
=
"brcm,spi-bcm7425-qspi"
,
.
data
=
&
bcm_qspi_no_rev_data
,
},
{
.
compatible
=
"brcm,spi-bcm7429-qspi"
,
.
data
=
&
bcm_qspi_no_rev_data
,
},
{
.
compatible
=
"brcm,spi-bcm7435-qspi"
,
.
data
=
&
bcm_qspi_no_rev_data
,
},
{
.
compatible
=
"brcm,spi-bcm-qspi"
,
.
data
=
&
bcm_qspi_rev_data
,
},
{
.
compatible
=
"brcm,spi-bcm7216-qspi"
,
.
data
=
&
bcm_qspi_spcr3_data
,
},
{
.
compatible
=
"brcm,spi-bcm7278-qspi"
,
.
data
=
&
bcm_qspi_spcr3_data
,
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
bcm_qspi_of_match
);
...
...
@@ -1204,12 +1312,15 @@ MODULE_DEVICE_TABLE(of, bcm_qspi_of_match);
int
bcm_qspi_probe
(
struct
platform_device
*
pdev
,
struct
bcm_qspi_soc_intc
*
soc_intc
)
{
const
struct
of_device_id
*
of_id
=
NULL
;
const
struct
bcm_qspi_data
*
data
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
bcm_qspi
*
qspi
;
struct
spi_master
*
master
;
struct
resource
*
res
;
int
irq
,
ret
=
0
,
num_ints
=
0
;
u32
val
;
u32
rev
=
0
;
const
char
*
name
=
NULL
;
int
num_irqs
=
ARRAY_SIZE
(
qspi_irq_tab
);
...
...
@@ -1217,9 +1328,12 @@ int bcm_qspi_probe(struct platform_device *pdev,
if
(
!
dev
->
of_node
)
return
-
ENODEV
;
if
(
!
of_match_node
(
bcm_qspi_of_match
,
dev
->
of_node
))
of_id
=
of_match_node
(
bcm_qspi_of_match
,
dev
->
of_node
);
if
(
!
of_id
)
return
-
ENODEV
;
data
=
of_id
->
data
;
master
=
spi_alloc_master
(
dev
,
sizeof
(
struct
bcm_qspi
));
if
(
!
master
)
{
dev_err
(
dev
,
"error allocating spi_master
\n
"
);
...
...
@@ -1352,7 +1466,19 @@ int bcm_qspi_probe(struct platform_device *pdev,
}
qspi
->
base_clk
=
clk_get_rate
(
qspi
->
clk
);
qspi
->
max_speed_hz
=
qspi
->
base_clk
/
(
QSPI_SPBR_MIN
*
2
);
if
(
data
->
has_mspi_rev
)
{
rev
=
bcm_qspi_read
(
qspi
,
MSPI
,
MSPI_REV
);
/* some older revs do not have a MSPI_REV register */
if
((
rev
&
0xff
)
==
0xff
)
rev
=
0
;
}
qspi
->
mspi_maj_rev
=
(
rev
>>
4
)
&
0xf
;
qspi
->
mspi_min_rev
=
rev
&
0xf
;
qspi
->
mspi_spcr3_sysclk
=
data
->
has_spcr3_sysclk
;
qspi
->
max_speed_hz
=
qspi
->
base_clk
/
(
bcm_qspi_spbr_min
(
qspi
)
*
2
);
bcm_qspi_hw_init
(
qspi
);
init_completion
(
&
qspi
->
mspi_done
);
...
...
drivers/spi/spi-bcm2835.c
View file @
fb02b9eb
...
...
@@ -191,12 +191,12 @@ static void bcm2835_debugfs_remove(struct bcm2835_spi *bs)
}
#endif
/* CONFIG_DEBUG_FS */
static
inline
u32
bcm2835_rd
(
struct
bcm2835_spi
*
bs
,
unsigned
reg
)
static
inline
u32
bcm2835_rd
(
struct
bcm2835_spi
*
bs
,
unsigned
int
reg
)
{
return
readl
(
bs
->
regs
+
reg
);
}
static
inline
void
bcm2835_wr
(
struct
bcm2835_spi
*
bs
,
unsigned
reg
,
u32
val
)
static
inline
void
bcm2835_wr
(
struct
bcm2835_spi
*
bs
,
unsigned
int
reg
,
u32
val
)
{
writel
(
val
,
bs
->
regs
+
reg
);
}
...
...
@@ -940,6 +940,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
if
(
dma_mapping_error
(
ctlr
->
dma_tx
->
device
->
dev
,
bs
->
fill_tx_addr
))
{
dev_err
(
dev
,
"cannot map zero page - not using DMA mode
\n
"
);
bs
->
fill_tx_addr
=
0
;
ret
=
-
ENOMEM
;
goto
err_release
;
}
...
...
@@ -949,6 +950,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
DMA_MEM_TO_DEV
,
0
);
if
(
!
bs
->
fill_tx_desc
)
{
dev_err
(
dev
,
"cannot prepare fill_tx_desc - not using DMA mode
\n
"
);
ret
=
-
ENOMEM
;
goto
err_release
;
}
...
...
@@ -979,6 +981,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
if
(
dma_mapping_error
(
ctlr
->
dma_rx
->
device
->
dev
,
bs
->
clear_rx_addr
))
{
dev_err
(
dev
,
"cannot map clear_rx_cs - not using DMA mode
\n
"
);
bs
->
clear_rx_addr
=
0
;
ret
=
-
ENOMEM
;
goto
err_release
;
}
...
...
@@ -989,6 +992,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
DMA_MEM_TO_DEV
,
0
);
if
(
!
bs
->
clear_rx_desc
[
i
])
{
dev_err
(
dev
,
"cannot prepare clear_rx_desc - not using DMA mode
\n
"
);
ret
=
-
ENOMEM
;
goto
err_release
;
}
...
...
@@ -1376,17 +1380,26 @@ static int bcm2835_spi_remove(struct platform_device *pdev)
spi_unregister_controller
(
ctlr
);
bcm2835_dma_release
(
ctlr
,
bs
);
/* Clear FIFOs, and disable the HW block */
bcm2835_wr
(
bs
,
BCM2835_SPI_CS
,
BCM2835_SPI_CS_CLEAR_RX
|
BCM2835_SPI_CS_CLEAR_TX
);
clk_disable_unprepare
(
bs
->
clk
);
bcm2835_dma_release
(
ctlr
,
bs
);
return
0
;
}
static
void
bcm2835_spi_shutdown
(
struct
platform_device
*
pdev
)
{
int
ret
;
ret
=
bcm2835_spi_remove
(
pdev
);
if
(
ret
)
dev_err
(
&
pdev
->
dev
,
"failed to shutdown
\n
"
);
}
static
const
struct
of_device_id
bcm2835_spi_match
[]
=
{
{
.
compatible
=
"brcm,bcm2835-spi"
,
},
{}
...
...
@@ -1400,6 +1413,7 @@ static struct platform_driver bcm2835_spi_driver = {
},
.
probe
=
bcm2835_spi_probe
,
.
remove
=
bcm2835_spi_remove
,
.
shutdown
=
bcm2835_spi_shutdown
,
};
module_platform_driver
(
bcm2835_spi_driver
);
...
...
drivers/spi/spi-dw.c
→
drivers/spi/spi-dw
-core
.c
View file @
fb02b9eb
...
...
@@ -24,74 +24,34 @@ struct chip_data {
u8
tmode
;
/* TR/TO/RO/EEPROM */
u8
type
;
/* SPI/SSP/MicroWire */
u8
poll_mode
;
/* 1 means use poll mode */
u16
clk_div
;
/* baud rate divider */
u32
speed_hz
;
/* baud rate */
void
(
*
cs_control
)(
u32
command
);
};
#ifdef CONFIG_DEBUG_FS
#define SPI_REGS_BUFSIZE 1024
static
ssize_t
dw_spi_show_regs
(
struct
file
*
file
,
char
__user
*
user_buf
,
size_t
count
,
loff_t
*
ppos
)
{
struct
dw_spi
*
dws
=
file
->
private_data
;
char
*
buf
;
u32
len
=
0
;
ssize_t
ret
;
buf
=
kzalloc
(
SPI_REGS_BUFSIZE
,
GFP_KERNEL
);
if
(
!
buf
)
return
0
;
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"%s registers:
\n
"
,
dev_name
(
&
dws
->
master
->
dev
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"=================================
\n
"
);
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"CTRL0:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_CTRL0
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"CTRL1:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_CTRL1
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"SSIENR:
\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_SSIENR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"SER:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_SER
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"BAUDR:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_BAUDR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"TXFTLR:
\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_TXFLTR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"RXFTLR:
\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_RXFLTR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"TXFLR:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_TXFLR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"RXFLR:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_RXFLR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"SR:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_SR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"IMR:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_IMR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"ISR:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_ISR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"DMACR:
\t\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_DMACR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"DMATDLR:
\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_DMATDLR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"DMARDLR:
\t
0x%08x
\n
"
,
dw_readl
(
dws
,
DW_SPI_DMARDLR
));
len
+=
scnprintf
(
buf
+
len
,
SPI_REGS_BUFSIZE
-
len
,
"=================================
\n
"
);
ret
=
simple_read_from_buffer
(
user_buf
,
count
,
ppos
,
buf
,
len
);
kfree
(
buf
);
return
ret
;
#define DW_SPI_DBGFS_REG(_name, _off) \
{ \
.name = _name, \
.offset = _off, \
}
static
const
struct
file_operations
dw_spi_regs_ops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
simple_open
,
.
read
=
dw_spi_show_regs
,
.
llseek
=
default_llseek
,
static
const
struct
debugfs_reg32
dw_spi_dbgfs_regs
[]
=
{
DW_SPI_DBGFS_REG
(
"CTRLR0"
,
DW_SPI_CTRLR0
),
DW_SPI_DBGFS_REG
(
"CTRLR1"
,
DW_SPI_CTRLR1
),
DW_SPI_DBGFS_REG
(
"SSIENR"
,
DW_SPI_SSIENR
),
DW_SPI_DBGFS_REG
(
"SER"
,
DW_SPI_SER
),
DW_SPI_DBGFS_REG
(
"BAUDR"
,
DW_SPI_BAUDR
),
DW_SPI_DBGFS_REG
(
"TXFTLR"
,
DW_SPI_TXFTLR
),
DW_SPI_DBGFS_REG
(
"RXFTLR"
,
DW_SPI_RXFTLR
),
DW_SPI_DBGFS_REG
(
"TXFLR"
,
DW_SPI_TXFLR
),
DW_SPI_DBGFS_REG
(
"RXFLR"
,
DW_SPI_RXFLR
),
DW_SPI_DBGFS_REG
(
"SR"
,
DW_SPI_SR
),
DW_SPI_DBGFS_REG
(
"IMR"
,
DW_SPI_IMR
),
DW_SPI_DBGFS_REG
(
"ISR"
,
DW_SPI_ISR
),
DW_SPI_DBGFS_REG
(
"DMACR"
,
DW_SPI_DMACR
),
DW_SPI_DBGFS_REG
(
"DMATDLR"
,
DW_SPI_DMATDLR
),
DW_SPI_DBGFS_REG
(
"DMARDLR"
,
DW_SPI_DMARDLR
),
};
static
int
dw_spi_debugfs_init
(
struct
dw_spi
*
dws
)
...
...
@@ -103,8 +63,11 @@ static int dw_spi_debugfs_init(struct dw_spi *dws)
if
(
!
dws
->
debugfs
)
return
-
ENOMEM
;
debugfs_create_file
(
"registers"
,
S_IFREG
|
S_IRUGO
,
dws
->
debugfs
,
(
void
*
)
dws
,
&
dw_spi_regs_ops
);
dws
->
regset
.
regs
=
dw_spi_dbgfs_regs
;
dws
->
regset
.
nregs
=
ARRAY_SIZE
(
dw_spi_dbgfs_regs
);
dws
->
regset
.
base
=
dws
->
regs
;
debugfs_create_regset32
(
"registers"
,
0400
,
dws
->
debugfs
,
&
dws
->
regset
);
return
0
;
}
...
...
@@ -127,13 +90,16 @@ static inline void dw_spi_debugfs_remove(struct dw_spi *dws)
void
dw_spi_set_cs
(
struct
spi_device
*
spi
,
bool
enable
)
{
struct
dw_spi
*
dws
=
spi_controller_get_devdata
(
spi
->
controller
);
struct
chip_data
*
chip
=
spi_get_ctldata
(
spi
);
/* Chip select logic is inverted from spi_set_cs() */
if
(
chip
&&
chip
->
cs_control
)
chip
->
cs_control
(
!
enable
);
bool
cs_high
=
!!
(
spi
->
mode
&
SPI_CS_HIGH
);
if
(
!
enable
)
/*
* DW SPI controller demands any native CS being set in order to
* proceed with data transfer. So in order to activate the SPI
* communications we must set a corresponding bit in the Slave
* Enable register no matter whether the SPI core is configured to
* support active-high or active-low CS level.
*/
if
(
cs_high
==
enable
)
dw_writel
(
dws
,
DW_SPI_SER
,
BIT
(
spi
->
chip_select
));
else
if
(
dws
->
cs_override
)
dw_writel
(
dws
,
DW_SPI_SER
,
0
);
...
...
@@ -265,17 +231,56 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
return
dws
->
transfer_handler
(
dws
);
}
/* Must be called inside pump_transfers() */
static
int
poll_transfer
(
struct
dw_spi
*
dws
)
/* Configure CTRLR0 for DW_apb_ssi */
u32
dw_spi_update_cr0
(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
transfer
)
{
do
{
dw_writer
(
dws
);
dw_reader
(
dws
);
cpu_relax
();
}
while
(
dws
->
rx_end
>
dws
->
rx
);
struct
chip_data
*
chip
=
spi_get_ctldata
(
spi
);
u32
cr0
;
return
0
;
/* Default SPI mode is SCPOL = 0, SCPH = 0 */
cr0
=
(
transfer
->
bits_per_word
-
1
)
|
(
chip
->
type
<<
SPI_FRF_OFFSET
)
|
((((
spi
->
mode
&
SPI_CPOL
)
?
1
:
0
)
<<
SPI_SCOL_OFFSET
)
|
(((
spi
->
mode
&
SPI_CPHA
)
?
1
:
0
)
<<
SPI_SCPH_OFFSET
)
|
(((
spi
->
mode
&
SPI_LOOP
)
?
1
:
0
)
<<
SPI_SRL_OFFSET
))
|
(
chip
->
tmode
<<
SPI_TMOD_OFFSET
);
return
cr0
;
}
EXPORT_SYMBOL_GPL
(
dw_spi_update_cr0
);
/* Configure CTRLR0 for DWC_ssi */
u32
dw_spi_update_cr0_v1_01a
(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
transfer
)
{
struct
chip_data
*
chip
=
spi_get_ctldata
(
spi
);
u32
cr0
;
/* CTRLR0[ 4: 0] Data Frame Size */
cr0
=
(
transfer
->
bits_per_word
-
1
);
/* CTRLR0[ 7: 6] Frame Format */
cr0
|=
chip
->
type
<<
DWC_SSI_CTRLR0_FRF_OFFSET
;
/*
* SPI mode (SCPOL|SCPH)
* CTRLR0[ 8] Serial Clock Phase
* CTRLR0[ 9] Serial Clock Polarity
*/
cr0
|=
((
spi
->
mode
&
SPI_CPOL
)
?
1
:
0
)
<<
DWC_SSI_CTRLR0_SCPOL_OFFSET
;
cr0
|=
((
spi
->
mode
&
SPI_CPHA
)
?
1
:
0
)
<<
DWC_SSI_CTRLR0_SCPH_OFFSET
;
/* CTRLR0[11:10] Transfer Mode */
cr0
|=
chip
->
tmode
<<
DWC_SSI_CTRLR0_TMOD_OFFSET
;
/* CTRLR0[13] Shift Register Loop */
cr0
|=
((
spi
->
mode
&
SPI_LOOP
)
?
1
:
0
)
<<
DWC_SSI_CTRLR0_SRL_OFFSET
;
return
cr0
;
}
EXPORT_SYMBOL_GPL
(
dw_spi_update_cr0_v1_01a
);
static
int
dw_spi_transfer_one
(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
transfer
)
...
...
@@ -313,34 +318,11 @@ static int dw_spi_transfer_one(struct spi_controller *master,
spi_set_clk
(
dws
,
chip
->
clk_div
);
}
transfer
->
effective_speed_hz
=
dws
->
max_freq
/
chip
->
clk_div
;
dws
->
n_bytes
=
DIV_ROUND_UP
(
transfer
->
bits_per_word
,
BITS_PER_BYTE
);
dws
->
dma_width
=
DIV_ROUND_UP
(
transfer
->
bits_per_word
,
BITS_PER_BYTE
);
/* Default SPI mode is SCPOL = 0, SCPH = 0 */
cr0
=
(
transfer
->
bits_per_word
-
1
)
|
(
chip
->
type
<<
SPI_FRF_OFFSET
)
|
((((
spi
->
mode
&
SPI_CPOL
)
?
1
:
0
)
<<
SPI_SCOL_OFFSET
)
|
(((
spi
->
mode
&
SPI_CPHA
)
?
1
:
0
)
<<
SPI_SCPH_OFFSET
)
|
(((
spi
->
mode
&
SPI_LOOP
)
?
1
:
0
)
<<
SPI_SRL_OFFSET
))
|
(
chip
->
tmode
<<
SPI_TMOD_OFFSET
);
/*
* Adjust transfer mode if necessary. Requires platform dependent
* chipselect mechanism.
*/
if
(
chip
->
cs_control
)
{
if
(
dws
->
rx
&&
dws
->
tx
)
chip
->
tmode
=
SPI_TMOD_TR
;
else
if
(
dws
->
rx
)
chip
->
tmode
=
SPI_TMOD_RO
;
else
chip
->
tmode
=
SPI_TMOD_TO
;
cr0
&=
~
SPI_TMOD_MASK
;
cr0
|=
(
chip
->
tmode
<<
SPI_TMOD_OFFSET
);
}
dw_writel
(
dws
,
DW_SPI_CTRL0
,
cr0
);
cr0
=
dws
->
update_cr0
(
master
,
spi
,
transfer
);
dw_writel
(
dws
,
DW_SPI_CTRLR0
,
cr0
);
/* Check if current transfer is a DMA transaction */
if
(
master
->
can_dma
&&
master
->
can_dma
(
master
,
spi
,
transfer
))
...
...
@@ -359,9 +341,9 @@ static int dw_spi_transfer_one(struct spi_controller *master,
spi_enable_chip
(
dws
,
1
);
return
ret
;
}
}
else
if
(
!
chip
->
poll_mode
)
{
}
else
{
txlevel
=
min_t
(
u16
,
dws
->
fifo_len
/
2
,
dws
->
len
/
dws
->
n_bytes
);
dw_writel
(
dws
,
DW_SPI_TXF
LT
R
,
txlevel
);
dw_writel
(
dws
,
DW_SPI_TXF
TL
R
,
txlevel
);
/* Set the interrupt mask */
imask
|=
SPI_INT_TXEI
|
SPI_INT_TXOI
|
...
...
@@ -373,14 +355,8 @@ static int dw_spi_transfer_one(struct spi_controller *master,
spi_enable_chip
(
dws
,
1
);
if
(
dws
->
dma_mapped
)
{
ret
=
dws
->
dma_ops
->
dma_transfer
(
dws
,
transfer
);
if
(
ret
<
0
)
return
ret
;
}
if
(
chip
->
poll_mode
)
return
poll_transfer
(
dws
);
if
(
dws
->
dma_mapped
)
return
dws
->
dma_ops
->
dma_transfer
(
dws
,
transfer
);
return
1
;
}
...
...
@@ -399,7 +375,6 @@ static void dw_spi_handle_err(struct spi_controller *master,
/* This may be called twice for each spi dev */
static
int
dw_spi_setup
(
struct
spi_device
*
spi
)
{
struct
dw_spi_chip
*
chip_info
=
NULL
;
struct
chip_data
*
chip
;
/* Only alloc on first setup */
...
...
@@ -411,21 +386,6 @@ static int dw_spi_setup(struct spi_device *spi)
spi_set_ctldata
(
spi
,
chip
);
}
/*
* Protocol drivers may change the chip settings, so...
* if chip_info exists, use it
*/
chip_info
=
spi
->
controller_data
;
/* chip_info doesn't always exist */
if
(
chip_info
)
{
if
(
chip_info
->
cs_control
)
chip
->
cs_control
=
chip_info
->
cs_control
;
chip
->
poll_mode
=
chip_info
->
poll_mode
;
chip
->
type
=
chip_info
->
type
;
}
chip
->
tmode
=
SPI_TMOD_TR
;
return
0
;
...
...
@@ -452,11 +412,11 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
u32
fifo
;
for
(
fifo
=
1
;
fifo
<
256
;
fifo
++
)
{
dw_writel
(
dws
,
DW_SPI_TXF
LT
R
,
fifo
);
if
(
fifo
!=
dw_readl
(
dws
,
DW_SPI_TXF
LT
R
))
dw_writel
(
dws
,
DW_SPI_TXF
TL
R
,
fifo
);
if
(
fifo
!=
dw_readl
(
dws
,
DW_SPI_TXF
TL
R
))
break
;
}
dw_writel
(
dws
,
DW_SPI_TXF
LT
R
,
0
);
dw_writel
(
dws
,
DW_SPI_TXF
TL
R
,
0
);
dws
->
fifo_len
=
(
fifo
==
1
)
?
0
:
fifo
;
dev_dbg
(
dev
,
"Detected FIFO size: %u bytes
\n
"
,
dws
->
fifo_len
);
...
...
@@ -481,7 +441,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
dws
->
master
=
master
;
dws
->
type
=
SSI_MOTO_SPI
;
dws
->
dma_inited
=
0
;
dws
->
dma_addr
=
(
dma_addr_t
)(
dws
->
paddr
+
DW_SPI_DR
);
spin_lock_init
(
&
dws
->
buf_lock
);
...
...
@@ -517,12 +476,12 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
spi_hw_init
(
dev
,
dws
);
if
(
dws
->
dma_ops
&&
dws
->
dma_ops
->
dma_init
)
{
ret
=
dws
->
dma_ops
->
dma_init
(
dws
);
ret
=
dws
->
dma_ops
->
dma_init
(
d
ev
,
d
ws
);
if
(
ret
)
{
dev_warn
(
dev
,
"DMA init failed
\n
"
);
dws
->
dma_inited
=
0
;
}
else
{
master
->
can_dma
=
dws
->
dma_ops
->
can_dma
;
master
->
flags
|=
SPI_CONTROLLER_MUST_TX
;
}
}
...
...
drivers/spi/spi-dw-
mid
.c
→
drivers/spi/spi-dw-
dma
.c
View file @
fb02b9eb
// SPDX-License-Identifier: GPL-2.0-only
/*
* Special handling for DW
core on Intel MID platform
* Special handling for DW
DMA core
*
* Copyright (c) 2009, 2014 Intel Corporation.
*/
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/irqreturn.h>
#include <linux/jiffies.h>
#include <linux/pci.h>
#include <linux/platform_data/dma-dw.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
#include "spi-dw.h"
#ifdef CONFIG_SPI_DW_MID_DMA
#include <linux/pci.h>
#include <linux/platform_data/dma-dw.h>
#define WAIT_RETRIES 5
#define RX_BUSY 0
#define RX_BURST_LEVEL 16
#define TX_BUSY 1
#define TX_BURST_LEVEL 16
static
struct
dw_dma_slave
mid_dma_tx
=
{
.
dst_id
=
1
};
static
struct
dw_dma_slave
mid_dma_rx
=
{
.
src_id
=
0
};
static
bool
mid_spi_dma_chan_filter
(
struct
dma_chan
*
chan
,
void
*
param
)
static
bool
dw_spi_dma_chan_filter
(
struct
dma_chan
*
chan
,
void
*
param
)
{
struct
dw_dma_slave
*
s
=
param
;
...
...
@@ -35,11 +34,36 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
return
true
;
}
static
int
mid_spi_dma
_init
(
struct
dw_spi
*
dws
)
static
void
dw_spi_dma_maxburst
_init
(
struct
dw_spi
*
dws
)
{
struct
dma_slave_caps
caps
;
u32
max_burst
,
def_burst
;
int
ret
;
def_burst
=
dws
->
fifo_len
/
2
;
ret
=
dma_get_slave_caps
(
dws
->
rxchan
,
&
caps
);
if
(
!
ret
&&
caps
.
max_burst
)
max_burst
=
caps
.
max_burst
;
else
max_burst
=
RX_BURST_LEVEL
;
dws
->
rxburst
=
min
(
max_burst
,
def_burst
);
ret
=
dma_get_slave_caps
(
dws
->
txchan
,
&
caps
);
if
(
!
ret
&&
caps
.
max_burst
)
max_burst
=
caps
.
max_burst
;
else
max_burst
=
TX_BURST_LEVEL
;
dws
->
txburst
=
min
(
max_burst
,
def_burst
);
}
static
int
dw_spi_dma_init_mfld
(
struct
device
*
dev
,
struct
dw_spi
*
dws
)
{
struct
dw_dma_slave
dma_tx
=
{
.
dst_id
=
1
},
*
tx
=
&
dma_tx
;
struct
dw_dma_slave
dma_rx
=
{
.
src_id
=
0
},
*
rx
=
&
dma_rx
;
struct
pci_dev
*
dma_dev
;
struct
dw_dma_slave
*
tx
=
dws
->
dma_tx
;
struct
dw_dma_slave
*
rx
=
dws
->
dma_rx
;
dma_cap_mask_t
mask
;
/*
...
...
@@ -55,40 +79,71 @@ static int mid_spi_dma_init(struct dw_spi *dws)
/* 1. Init rx channel */
rx
->
dma_dev
=
&
dma_dev
->
dev
;
dws
->
rxchan
=
dma_request_channel
(
mask
,
mid
_spi_dma_chan_filter
,
rx
);
dws
->
rxchan
=
dma_request_channel
(
mask
,
dw
_spi_dma_chan_filter
,
rx
);
if
(
!
dws
->
rxchan
)
goto
err_exit
;
dws
->
master
->
dma_rx
=
dws
->
rxchan
;
/* 2. Init tx channel */
tx
->
dma_dev
=
&
dma_dev
->
dev
;
dws
->
txchan
=
dma_request_channel
(
mask
,
mid
_spi_dma_chan_filter
,
tx
);
dws
->
txchan
=
dma_request_channel
(
mask
,
dw
_spi_dma_chan_filter
,
tx
);
if
(
!
dws
->
txchan
)
goto
free_rxchan
;
dws
->
master
->
dma_rx
=
dws
->
rxchan
;
dws
->
master
->
dma_tx
=
dws
->
txchan
;
dws
->
dma_inited
=
1
;
init_completion
(
&
dws
->
dma_completion
);
dw_spi_dma_maxburst_init
(
dws
);
return
0
;
free_rxchan:
dma_release_channel
(
dws
->
rxchan
);
dws
->
rxchan
=
NULL
;
err_exit:
return
-
EBUSY
;
}
static
void
mid_spi_dma_exit
(
struct
dw_spi
*
dws
)
static
int
dw_spi_dma_init_generic
(
struct
device
*
dev
,
struct
dw_spi
*
dws
)
{
if
(
!
dws
->
dma_inited
)
return
;
dws
->
rxchan
=
dma_request_slave_channel
(
dev
,
"rx"
);
if
(
!
dws
->
rxchan
)
return
-
ENODEV
;
dmaengine_terminate_sync
(
dws
->
txchan
);
dma_release_channel
(
dws
->
txchan
);
dws
->
txchan
=
dma_request_slave_channel
(
dev
,
"tx"
);
if
(
!
dws
->
txchan
)
{
dma_release_channel
(
dws
->
rxchan
);
dws
->
rxchan
=
NULL
;
return
-
ENODEV
;
}
dmaengine_terminate_sync
(
dws
->
rxchan
);
dma_release_channel
(
dws
->
rxchan
);
dws
->
master
->
dma_rx
=
dws
->
rxchan
;
dws
->
master
->
dma_tx
=
dws
->
txchan
;
init_completion
(
&
dws
->
dma_completion
);
dw_spi_dma_maxburst_init
(
dws
);
return
0
;
}
static
void
dw_spi_dma_exit
(
struct
dw_spi
*
dws
)
{
if
(
dws
->
txchan
)
{
dmaengine_terminate_sync
(
dws
->
txchan
);
dma_release_channel
(
dws
->
txchan
);
}
if
(
dws
->
rxchan
)
{
dmaengine_terminate_sync
(
dws
->
rxchan
);
dma_release_channel
(
dws
->
rxchan
);
}
dw_writel
(
dws
,
DW_SPI_DMACR
,
0
);
}
static
irqreturn_t
d
ma_transf
er
(
struct
dw_spi
*
dws
)
static
irqreturn_t
d
w_spi_dma_transfer_handl
er
(
struct
dw_spi
*
dws
)
{
u16
irq_status
=
dw_readl
(
dws
,
DW_SPI_ISR
);
...
...
@@ -100,30 +155,78 @@ static irqreturn_t dma_transfer(struct dw_spi *dws)
dev_err
(
&
dws
->
master
->
dev
,
"%s: FIFO overrun/underrun
\n
"
,
__func__
);
dws
->
master
->
cur_msg
->
status
=
-
EIO
;
spi_finalize_current_transfer
(
dws
->
master
);
complete
(
&
dws
->
dma_completion
);
return
IRQ_HANDLED
;
}
static
bool
mid
_spi_can_dma
(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
static
bool
dw
_spi_can_dma
(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
{
struct
dw_spi
*
dws
=
spi_controller_get_devdata
(
master
);
if
(
!
dws
->
dma_inited
)
return
false
;
return
xfer
->
len
>
dws
->
fifo_len
;
}
static
enum
dma_slave_buswidth
convert_dma_width
(
u32
dma_width
)
{
if
(
dma_width
==
1
)
static
enum
dma_slave_buswidth
dw_spi_dma_convert_width
(
u8
n_bytes
)
{
if
(
n_bytes
==
1
)
return
DMA_SLAVE_BUSWIDTH_1_BYTE
;
else
if
(
dma_width
==
2
)
else
if
(
n_bytes
==
2
)
return
DMA_SLAVE_BUSWIDTH_2_BYTES
;
return
DMA_SLAVE_BUSWIDTH_UNDEFINED
;
}
static
int
dw_spi_dma_wait
(
struct
dw_spi
*
dws
,
struct
spi_transfer
*
xfer
)
{
unsigned
long
long
ms
;
ms
=
xfer
->
len
*
MSEC_PER_SEC
*
BITS_PER_BYTE
;
do_div
(
ms
,
xfer
->
effective_speed_hz
);
ms
+=
ms
+
200
;
if
(
ms
>
UINT_MAX
)
ms
=
UINT_MAX
;
ms
=
wait_for_completion_timeout
(
&
dws
->
dma_completion
,
msecs_to_jiffies
(
ms
));
if
(
ms
==
0
)
{
dev_err
(
&
dws
->
master
->
cur_msg
->
spi
->
dev
,
"DMA transaction timed out
\n
"
);
return
-
ETIMEDOUT
;
}
return
0
;
}
static
inline
bool
dw_spi_dma_tx_busy
(
struct
dw_spi
*
dws
)
{
return
!
(
dw_readl
(
dws
,
DW_SPI_SR
)
&
SR_TF_EMPT
);
}
static
int
dw_spi_dma_wait_tx_done
(
struct
dw_spi
*
dws
,
struct
spi_transfer
*
xfer
)
{
int
retry
=
WAIT_RETRIES
;
struct
spi_delay
delay
;
u32
nents
;
nents
=
dw_readl
(
dws
,
DW_SPI_TXFLR
);
delay
.
unit
=
SPI_DELAY_UNIT_SCK
;
delay
.
value
=
nents
*
dws
->
n_bytes
*
BITS_PER_BYTE
;
while
(
dw_spi_dma_tx_busy
(
dws
)
&&
retry
--
)
spi_delay_exec
(
&
delay
,
xfer
);
if
(
retry
<
0
)
{
dev_err
(
&
dws
->
master
->
dev
,
"Tx hanged up
\n
"
);
return
-
EIO
;
}
return
0
;
}
/*
* dws->dma_chan_busy is set before the dma transfer starts, callback for tx
* channel will clear a corresponding bit.
...
...
@@ -135,11 +238,13 @@ static void dw_spi_dma_tx_done(void *arg)
clear_bit
(
TX_BUSY
,
&
dws
->
dma_chan_busy
);
if
(
test_bit
(
RX_BUSY
,
&
dws
->
dma_chan_busy
))
return
;
spi_finalize_current_transfer
(
dws
->
master
);
dw_writel
(
dws
,
DW_SPI_DMACR
,
0
);
complete
(
&
dws
->
dma_completion
);
}
static
struct
dma_async_tx_descriptor
*
dw_spi_dma_prepare_tx
(
struct
dw_spi
*
dws
,
struct
spi_transfer
*
xfer
)
static
struct
dma_async_tx_descriptor
*
dw_spi_dma_prepare_tx
(
struct
dw_spi
*
dws
,
struct
spi_transfer
*
xfer
)
{
struct
dma_slave_config
txconf
;
struct
dma_async_tx_descriptor
*
txdesc
;
...
...
@@ -147,11 +252,12 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
if
(
!
xfer
->
tx_buf
)
return
NULL
;
memset
(
&
txconf
,
0
,
sizeof
(
txconf
));
txconf
.
direction
=
DMA_MEM_TO_DEV
;
txconf
.
dst_addr
=
dws
->
dma_addr
;
txconf
.
dst_maxburst
=
16
;
txconf
.
dst_maxburst
=
dws
->
txburst
;
txconf
.
src_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
txconf
.
dst_addr_width
=
convert_dma_width
(
dws
->
dma_width
);
txconf
.
dst_addr_width
=
dw_spi_dma_convert_width
(
dws
->
n_bytes
);
txconf
.
device_fc
=
false
;
dmaengine_slave_config
(
dws
->
txchan
,
&
txconf
);
...
...
@@ -170,6 +276,49 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
return
txdesc
;
}
static
inline
bool
dw_spi_dma_rx_busy
(
struct
dw_spi
*
dws
)
{
return
!!
(
dw_readl
(
dws
,
DW_SPI_SR
)
&
SR_RF_NOT_EMPT
);
}
static
int
dw_spi_dma_wait_rx_done
(
struct
dw_spi
*
dws
)
{
int
retry
=
WAIT_RETRIES
;
struct
spi_delay
delay
;
unsigned
long
ns
,
us
;
u32
nents
;
/*
* It's unlikely that DMA engine is still doing the data fetching, but
* if it's let's give it some reasonable time. The timeout calculation
* is based on the synchronous APB/SSI reference clock rate, on a
* number of data entries left in the Rx FIFO, times a number of clock
* periods normally needed for a single APB read/write transaction
* without PREADY signal utilized (which is true for the DW APB SSI
* controller).
*/
nents
=
dw_readl
(
dws
,
DW_SPI_RXFLR
);
ns
=
4U
*
NSEC_PER_SEC
/
dws
->
max_freq
*
nents
;
if
(
ns
<=
NSEC_PER_USEC
)
{
delay
.
unit
=
SPI_DELAY_UNIT_NSECS
;
delay
.
value
=
ns
;
}
else
{
us
=
DIV_ROUND_UP
(
ns
,
NSEC_PER_USEC
);
delay
.
unit
=
SPI_DELAY_UNIT_USECS
;
delay
.
value
=
clamp_val
(
us
,
0
,
USHRT_MAX
);
}
while
(
dw_spi_dma_rx_busy
(
dws
)
&&
retry
--
)
spi_delay_exec
(
&
delay
,
NULL
);
if
(
retry
<
0
)
{
dev_err
(
&
dws
->
master
->
dev
,
"Rx hanged up
\n
"
);
return
-
EIO
;
}
return
0
;
}
/*
* dws->dma_chan_busy is set before the dma transfer starts, callback for rx
* channel will clear a corresponding bit.
...
...
@@ -181,7 +330,9 @@ static void dw_spi_dma_rx_done(void *arg)
clear_bit
(
RX_BUSY
,
&
dws
->
dma_chan_busy
);
if
(
test_bit
(
TX_BUSY
,
&
dws
->
dma_chan_busy
))
return
;
spi_finalize_current_transfer
(
dws
->
master
);
dw_writel
(
dws
,
DW_SPI_DMACR
,
0
);
complete
(
&
dws
->
dma_completion
);
}
static
struct
dma_async_tx_descriptor
*
dw_spi_dma_prepare_rx
(
struct
dw_spi
*
dws
,
...
...
@@ -193,11 +344,12 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
if
(
!
xfer
->
rx_buf
)
return
NULL
;
memset
(
&
rxconf
,
0
,
sizeof
(
rxconf
));
rxconf
.
direction
=
DMA_DEV_TO_MEM
;
rxconf
.
src_addr
=
dws
->
dma_addr
;
rxconf
.
src_maxburst
=
16
;
rxconf
.
src_maxburst
=
dws
->
rxburst
;
rxconf
.
dst_addr_width
=
DMA_SLAVE_BUSWIDTH_4_BYTES
;
rxconf
.
src_addr_width
=
convert_dma_width
(
dws
->
dma_width
);
rxconf
.
src_addr_width
=
dw_spi_dma_convert_width
(
dws
->
n_bytes
);
rxconf
.
device_fc
=
false
;
dmaengine_slave_config
(
dws
->
rxchan
,
&
rxconf
);
...
...
@@ -216,12 +368,12 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
return
rxdesc
;
}
static
int
mid
_spi_dma_setup
(
struct
dw_spi
*
dws
,
struct
spi_transfer
*
xfer
)
static
int
dw
_spi_dma_setup
(
struct
dw_spi
*
dws
,
struct
spi_transfer
*
xfer
)
{
u16
dma_ctrl
=
0
;
u16
imr
=
0
,
dma_ctrl
=
0
;
dw_writel
(
dws
,
DW_SPI_DMARDLR
,
0xf
);
dw_writel
(
dws
,
DW_SPI_DMATDLR
,
0x10
);
dw_writel
(
dws
,
DW_SPI_DMARDLR
,
dws
->
rxburst
-
1
);
dw_writel
(
dws
,
DW_SPI_DMATDLR
,
dws
->
fifo_len
-
dws
->
txburst
);
if
(
xfer
->
tx_buf
)
dma_ctrl
|=
SPI_DMA_TDMAE
;
...
...
@@ -230,16 +382,23 @@ static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
dw_writel
(
dws
,
DW_SPI_DMACR
,
dma_ctrl
);
/* Set the interrupt mask */
spi_umask_intr
(
dws
,
SPI_INT_TXOI
|
SPI_INT_RXUI
|
SPI_INT_RXOI
);
if
(
xfer
->
tx_buf
)
imr
|=
SPI_INT_TXOI
;
if
(
xfer
->
rx_buf
)
imr
|=
SPI_INT_RXUI
|
SPI_INT_RXOI
;
spi_umask_intr
(
dws
,
imr
);
dws
->
transfer_handler
=
dma_transfer
;
reinit_completion
(
&
dws
->
dma_completion
);
dws
->
transfer_handler
=
dw_spi_dma_transfer_handler
;
return
0
;
}
static
int
mid
_spi_dma_transfer
(
struct
dw_spi
*
dws
,
struct
spi_transfer
*
xfer
)
static
int
dw
_spi_dma_transfer
(
struct
dw_spi
*
dws
,
struct
spi_transfer
*
xfer
)
{
struct
dma_async_tx_descriptor
*
txdesc
,
*
rxdesc
;
int
ret
;
/* Prepare the TX dma transfer */
txdesc
=
dw_spi_dma_prepare_tx
(
dws
,
xfer
);
...
...
@@ -260,10 +419,23 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
dma_async_issue_pending
(
dws
->
txchan
);
}
return
0
;
ret
=
dw_spi_dma_wait
(
dws
,
xfer
);
if
(
ret
)
return
ret
;
if
(
txdesc
&&
dws
->
master
->
cur_msg
->
status
==
-
EINPROGRESS
)
{
ret
=
dw_spi_dma_wait_tx_done
(
dws
,
xfer
);
if
(
ret
)
return
ret
;
}
if
(
rxdesc
&&
dws
->
master
->
cur_msg
->
status
==
-
EINPROGRESS
)
ret
=
dw_spi_dma_wait_rx_done
(
dws
);
return
ret
;
}
static
void
mid
_spi_dma_stop
(
struct
dw_spi
*
dws
)
static
void
dw
_spi_dma_stop
(
struct
dw_spi
*
dws
)
{
if
(
test_bit
(
TX_BUSY
,
&
dws
->
dma_chan_busy
))
{
dmaengine_terminate_sync
(
dws
->
txchan
);
...
...
@@ -273,50 +445,36 @@ static void mid_spi_dma_stop(struct dw_spi *dws)
dmaengine_terminate_sync
(
dws
->
rxchan
);
clear_bit
(
RX_BUSY
,
&
dws
->
dma_chan_busy
);
}
dw_writel
(
dws
,
DW_SPI_DMACR
,
0
);
}
static
const
struct
dw_spi_dma_ops
mid_dma
_ops
=
{
.
dma_init
=
mid_spi_dma_init
,
.
dma_exit
=
mid
_spi_dma_exit
,
.
dma_setup
=
mid
_spi_dma_setup
,
.
can_dma
=
mid
_spi_can_dma
,
.
dma_transfer
=
mid
_spi_dma_transfer
,
.
dma_stop
=
mid
_spi_dma_stop
,
static
const
struct
dw_spi_dma_ops
dw_spi_dma_mfld
_ops
=
{
.
dma_init
=
dw_spi_dma_init_mfld
,
.
dma_exit
=
dw
_spi_dma_exit
,
.
dma_setup
=
dw
_spi_dma_setup
,
.
can_dma
=
dw
_spi_can_dma
,
.
dma_transfer
=
dw
_spi_dma_transfer
,
.
dma_stop
=
dw
_spi_dma_stop
,
};
#endif
/* Some specific info for SPI0 controller on Intel MID */
/* HW info for MRST Clk Control Unit, 32b reg per controller */
#define MRST_SPI_CLK_BASE 100000000
/* 100m */
#define MRST_CLK_SPI_REG 0xff11d86c
#define CLK_SPI_BDIV_OFFSET 0
#define CLK_SPI_BDIV_MASK 0x00000007
#define CLK_SPI_CDIV_OFFSET 9
#define CLK_SPI_CDIV_MASK 0x00000e00
#define CLK_SPI_DISABLE_OFFSET 8
void
dw_spi_dma_setup_mfld
(
struct
dw_spi
*
dws
)
{
dws
->
dma_ops
=
&
dw_spi_dma_mfld_ops
;
}
EXPORT_SYMBOL_GPL
(
dw_spi_dma_setup_mfld
);
static
const
struct
dw_spi_dma_ops
dw_spi_dma_generic_ops
=
{
.
dma_init
=
dw_spi_dma_init_generic
,
.
dma_exit
=
dw_spi_dma_exit
,
.
dma_setup
=
dw_spi_dma_setup
,
.
can_dma
=
dw_spi_can_dma
,
.
dma_transfer
=
dw_spi_dma_transfer
,
.
dma_stop
=
dw_spi_dma_stop
,
};
int
dw_spi_mid_init
(
struct
dw_spi
*
dws
)
void
dw_spi_dma_setup_generic
(
struct
dw_spi
*
dws
)
{
void
__iomem
*
clk_reg
;
u32
clk_cdiv
;
clk_reg
=
ioremap
(
MRST_CLK_SPI_REG
,
16
);
if
(
!
clk_reg
)
return
-
ENOMEM
;
/* Get SPI controller operating freq info */
clk_cdiv
=
readl
(
clk_reg
+
dws
->
bus_num
*
sizeof
(
u32
));
clk_cdiv
&=
CLK_SPI_CDIV_MASK
;
clk_cdiv
>>=
CLK_SPI_CDIV_OFFSET
;
dws
->
max_freq
=
MRST_SPI_CLK_BASE
/
(
clk_cdiv
+
1
);
iounmap
(
clk_reg
);
#ifdef CONFIG_SPI_DW_MID_DMA
dws
->
dma_tx
=
&
mid_dma_tx
;
dws
->
dma_rx
=
&
mid_dma_rx
;
dws
->
dma_ops
=
&
mid_dma_ops
;
#endif
return
0
;
dws
->
dma_ops
=
&
dw_spi_dma_generic_ops
;
}
EXPORT_SYMBOL_GPL
(
dw_spi_dma_setup_generic
);
drivers/spi/spi-dw-mmio.c
View file @
fb02b9eb
...
...
@@ -7,7 +7,6 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
...
...
@@ -20,6 +19,7 @@
#include <linux/acpi.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include "spi-dw.h"
...
...
@@ -30,6 +30,7 @@ struct dw_spi_mmio {
struct
clk
*
clk
;
struct
clk
*
pclk
;
void
*
priv
;
struct
reset_control
*
rstc
;
};
#define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
...
...
@@ -44,6 +45,13 @@ struct dw_spi_mmio {
#define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13)
#define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5)
/*
* For Keem Bay, CTRLR0[31] is used to select controller mode.
* 0: SSI is slave
* 1: SSI is master
*/
#define KEEMBAY_CTRLR0_SSIC_IS_MST BIT(31)
struct
dw_spi_mscc
{
struct
regmap
*
syscon
;
void
__iomem
*
spi_mst
;
...
...
@@ -106,6 +114,9 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
dwsmmio
->
dws
.
set_cs
=
dw_spi_mscc_set_cs
;
dwsmmio
->
priv
=
dwsmscc
;
/* Register hook to configure CTRLR0 */
dwsmmio
->
dws
.
update_cr0
=
dw_spi_update_cr0
;
return
0
;
}
...
...
@@ -128,6 +139,49 @@ static int dw_spi_alpine_init(struct platform_device *pdev,
{
dwsmmio
->
dws
.
cs_override
=
1
;
/* Register hook to configure CTRLR0 */
dwsmmio
->
dws
.
update_cr0
=
dw_spi_update_cr0
;
return
0
;
}
static
int
dw_spi_dw_apb_init
(
struct
platform_device
*
pdev
,
struct
dw_spi_mmio
*
dwsmmio
)
{
/* Register hook to configure CTRLR0 */
dwsmmio
->
dws
.
update_cr0
=
dw_spi_update_cr0
;
dw_spi_dma_setup_generic
(
&
dwsmmio
->
dws
);
return
0
;
}
static
int
dw_spi_dwc_ssi_init
(
struct
platform_device
*
pdev
,
struct
dw_spi_mmio
*
dwsmmio
)
{
/* Register hook to configure CTRLR0 */
dwsmmio
->
dws
.
update_cr0
=
dw_spi_update_cr0_v1_01a
;
dw_spi_dma_setup_generic
(
&
dwsmmio
->
dws
);
return
0
;
}
static
u32
dw_spi_update_cr0_keembay
(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
transfer
)
{
u32
cr0
=
dw_spi_update_cr0_v1_01a
(
master
,
spi
,
transfer
);
return
cr0
|
KEEMBAY_CTRLR0_SSIC_IS_MST
;
}
static
int
dw_spi_keembay_init
(
struct
platform_device
*
pdev
,
struct
dw_spi_mmio
*
dwsmmio
)
{
/* Register hook to configure CTRLR0 */
dwsmmio
->
dws
.
update_cr0
=
dw_spi_update_cr0_keembay
;
return
0
;
}
...
...
@@ -136,6 +190,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
int
(
*
init_func
)(
struct
platform_device
*
pdev
,
struct
dw_spi_mmio
*
dwsmmio
);
struct
dw_spi_mmio
*
dwsmmio
;
struct
resource
*
mem
;
struct
dw_spi
*
dws
;
int
ret
;
int
num_cs
;
...
...
@@ -148,11 +203,11 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
dws
=
&
dwsmmio
->
dws
;
/* Get basic io resource and map it */
dws
->
regs
=
devm_platform_ioremap_resource
(
pdev
,
0
);
if
(
IS_ERR
(
dws
->
regs
))
{
dev_err
(
&
pdev
->
dev
,
"SPI region map failed
\n
"
);
dws
->
regs
=
devm_platform_get_and_ioremap_resource
(
pdev
,
0
,
&
mem
);
if
(
IS_ERR
(
dws
->
regs
))
return
PTR_ERR
(
dws
->
regs
);
}
dws
->
paddr
=
mem
->
start
;
dws
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
dws
->
irq
<
0
)
...
...
@@ -175,6 +230,14 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
if
(
ret
)
goto
out_clk
;
/* find an optional reset controller */
dwsmmio
->
rstc
=
devm_reset_control_get_optional_exclusive
(
&
pdev
->
dev
,
"spi"
);
if
(
IS_ERR
(
dwsmmio
->
rstc
))
{
ret
=
PTR_ERR
(
dwsmmio
->
rstc
);
goto
out_clk
;
}
reset_control_deassert
(
dwsmmio
->
rstc
);
dws
->
bus_num
=
pdev
->
id
;
dws
->
max_freq
=
clk_get_rate
(
dwsmmio
->
clk
);
...
...
@@ -208,6 +271,8 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
clk_disable_unprepare
(
dwsmmio
->
pclk
);
out_clk:
clk_disable_unprepare
(
dwsmmio
->
clk
);
reset_control_assert
(
dwsmmio
->
rstc
);
return
ret
;
}
...
...
@@ -219,25 +284,30 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
pm_runtime_disable
(
&
pdev
->
dev
);
clk_disable_unprepare
(
dwsmmio
->
pclk
);
clk_disable_unprepare
(
dwsmmio
->
clk
);
reset_control_assert
(
dwsmmio
->
rstc
);
return
0
;
}
static
const
struct
of_device_id
dw_spi_mmio_of_match
[]
=
{
{
.
compatible
=
"snps,dw-apb-ssi"
,
},
{
.
compatible
=
"snps,dw-apb-ssi"
,
.
data
=
dw_spi_dw_apb_init
},
{
.
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"
,
},
{
.
compatible
=
"renesas,rzn1-spi"
,
.
data
=
dw_spi_dw_apb_init
},
{
.
compatible
=
"snps,dwc-ssi-1.01a"
,
.
data
=
dw_spi_dwc_ssi_init
},
{
.
compatible
=
"intel,keembay-ssi"
,
.
data
=
dw_spi_keembay_init
},
{
/* end of table */
}
};
MODULE_DEVICE_TABLE
(
of
,
dw_spi_mmio_of_match
);
#ifdef CONFIG_ACPI
static
const
struct
acpi_device_id
dw_spi_mmio_acpi_match
[]
=
{
{
"HISI0173"
,
0
},
{
"HISI0173"
,
(
kernel_ulong_t
)
dw_spi_dw_apb_init
},
{},
};
MODULE_DEVICE_TABLE
(
acpi
,
dw_spi_mmio_acpi_match
);
#endif
static
struct
platform_driver
dw_spi_mmio_driver
=
{
.
probe
=
dw_spi_mmio_probe
,
...
...
drivers/spi/spi-dw-pci.c
View file @
fb02b9eb
...
...
@@ -5,7 +5,6 @@
* Copyright (c) 2009, 2014 Intel Corporation.
*/
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
...
...
@@ -16,6 +15,15 @@
#define DRIVER_NAME "dw_spi_pci"
/* HW info for MRST Clk Control Unit, 32b reg per controller */
#define MRST_SPI_CLK_BASE 100000000
/* 100m */
#define MRST_CLK_SPI_REG 0xff11d86c
#define CLK_SPI_BDIV_OFFSET 0
#define CLK_SPI_BDIV_MASK 0x00000007
#define CLK_SPI_CDIV_OFFSET 9
#define CLK_SPI_CDIV_MASK 0x00000e00
#define CLK_SPI_DISABLE_OFFSET 8
struct
spi_pci_desc
{
int
(
*
setup
)(
struct
dw_spi
*
);
u16
num_cs
;
...
...
@@ -23,19 +31,55 @@ struct spi_pci_desc {
u32
max_freq
;
};
static
int
spi_mid_init
(
struct
dw_spi
*
dws
)
{
void
__iomem
*
clk_reg
;
u32
clk_cdiv
;
clk_reg
=
ioremap
(
MRST_CLK_SPI_REG
,
16
);
if
(
!
clk_reg
)
return
-
ENOMEM
;
/* Get SPI controller operating freq info */
clk_cdiv
=
readl
(
clk_reg
+
dws
->
bus_num
*
sizeof
(
u32
));
clk_cdiv
&=
CLK_SPI_CDIV_MASK
;
clk_cdiv
>>=
CLK_SPI_CDIV_OFFSET
;
dws
->
max_freq
=
MRST_SPI_CLK_BASE
/
(
clk_cdiv
+
1
);
iounmap
(
clk_reg
);
/* Register hook to configure CTRLR0 */
dws
->
update_cr0
=
dw_spi_update_cr0
;
dw_spi_dma_setup_mfld
(
dws
);
return
0
;
}
static
int
spi_generic_init
(
struct
dw_spi
*
dws
)
{
/* Register hook to configure CTRLR0 */
dws
->
update_cr0
=
dw_spi_update_cr0
;
dw_spi_dma_setup_generic
(
dws
);
return
0
;
}
static
struct
spi_pci_desc
spi_pci_mid_desc_1
=
{
.
setup
=
dw_
spi_mid_init
,
.
setup
=
spi_mid_init
,
.
num_cs
=
5
,
.
bus_num
=
0
,
};
static
struct
spi_pci_desc
spi_pci_mid_desc_2
=
{
.
setup
=
dw_
spi_mid_init
,
.
setup
=
spi_mid_init
,
.
num_cs
=
2
,
.
bus_num
=
1
,
};
static
struct
spi_pci_desc
spi_pci_ehl_desc
=
{
.
setup
=
spi_generic_init
,
.
num_cs
=
2
,
.
bus_num
=
-
1
,
.
max_freq
=
100000000
,
...
...
drivers/spi/spi-dw.h
View file @
fb02b9eb
...
...
@@ -2,18 +2,21 @@
#ifndef DW_SPI_HEADER_H
#define DW_SPI_HEADER_H
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/irqreturn.h>
#include <linux/io.h>
#include <linux/scatterlist.h>
/* Register offsets */
#define DW_SPI_CTRL0 0x00
#define DW_SPI_CTRL1 0x04
#define DW_SPI_CTRL
R
0 0x00
#define DW_SPI_CTRL
R
1 0x04
#define DW_SPI_SSIENR 0x08
#define DW_SPI_MWCR 0x0c
#define DW_SPI_SER 0x10
#define DW_SPI_BAUDR 0x14
#define DW_SPI_TXF
LT
R 0x18
#define DW_SPI_RXF
LT
R 0x1c
#define DW_SPI_TXF
TL
R 0x18
#define DW_SPI_RXF
TL
R 0x1c
#define DW_SPI_TXFLR 0x20
#define DW_SPI_RXFLR 0x24
#define DW_SPI_SR 0x28
...
...
@@ -57,6 +60,15 @@
#define SPI_SRL_OFFSET 11
#define SPI_CFS_OFFSET 12
/* Bit fields in CTRLR0 based on DWC_ssi_databook.pdf v1.01a */
#define DWC_SSI_CTRLR0_SRL_OFFSET 13
#define DWC_SSI_CTRLR0_TMOD_OFFSET 10
#define DWC_SSI_CTRLR0_TMOD_MASK GENMASK(11, 10)
#define DWC_SSI_CTRLR0_SCPOL_OFFSET 9
#define DWC_SSI_CTRLR0_SCPH_OFFSET 8
#define DWC_SSI_CTRLR0_FRF_OFFSET 6
#define DWC_SSI_CTRLR0_DFS_OFFSET 0
/* Bit fields in SR, 7 bits */
#define SR_MASK 0x7f
/* cover 7 bits */
#define SR_BUSY (1 << 0)
...
...
@@ -90,7 +102,7 @@ enum dw_ssi_type {
struct
dw_spi
;
struct
dw_spi_dma_ops
{
int
(
*
dma_init
)(
struct
dw_spi
*
dws
);
int
(
*
dma_init
)(
struct
d
evice
*
dev
,
struct
d
w_spi
*
dws
);
void
(
*
dma_exit
)(
struct
dw_spi
*
dws
);
int
(
*
dma_setup
)(
struct
dw_spi
*
dws
,
struct
spi_transfer
*
xfer
);
bool
(
*
can_dma
)(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
...
...
@@ -114,6 +126,8 @@ struct dw_spi {
u16
bus_num
;
u16
num_cs
;
/* supported slave numbers */
void
(
*
set_cs
)(
struct
spi_device
*
spi
,
bool
enable
);
u32
(
*
update_cr0
)(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
transfer
);
/* Current message transfer state info */
size_t
len
;
...
...
@@ -124,24 +138,22 @@ struct dw_spi {
void
*
rx_end
;
int
dma_mapped
;
u8
n_bytes
;
/* current is a 1/2 bytes op */
u32
dma_width
;
irqreturn_t
(
*
transfer_handler
)(
struct
dw_spi
*
dws
);
u32
current_freq
;
/* frequency in hz */
/* DMA info */
int
dma_inited
;
struct
dma_chan
*
txchan
;
u32
txburst
;
struct
dma_chan
*
rxchan
;
u32
rxburst
;
unsigned
long
dma_chan_busy
;
dma_addr_t
dma_addr
;
/* phy address of the Data register */
const
struct
dw_spi_dma_ops
*
dma_ops
;
void
*
dma_tx
;
void
*
dma_rx
;
struct
completion
dma_completion
;
/* Bus interface info */
void
*
priv
;
#ifdef CONFIG_DEBUG_FS
struct
dentry
*
debugfs
;
struct
debugfs_regset32
regset
;
#endif
};
...
...
@@ -235,24 +247,28 @@ static inline void spi_shutdown_chip(struct dw_spi *dws)
spi_set_clk
(
dws
,
0
);
}
/*
* Each SPI slave device to work with dw_api controller should
* has such a structure claiming its working mode (poll or PIO/DMA),
* which can be save in the "controller_data" member of the
* struct spi_device.
*/
struct
dw_spi_chip
{
u8
poll_mode
;
/* 1 for controller polling mode */
u8
type
;
/* SPI/SSP/MicroWire */
void
(
*
cs_control
)(
u32
command
);
};
extern
void
dw_spi_set_cs
(
struct
spi_device
*
spi
,
bool
enable
);
extern
int
dw_spi_add_host
(
struct
device
*
dev
,
struct
dw_spi
*
dws
);
extern
void
dw_spi_remove_host
(
struct
dw_spi
*
dws
);
extern
int
dw_spi_suspend_host
(
struct
dw_spi
*
dws
);
extern
int
dw_spi_resume_host
(
struct
dw_spi
*
dws
);
extern
u32
dw_spi_update_cr0
(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
transfer
);
extern
u32
dw_spi_update_cr0_v1_01a
(
struct
spi_controller
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
transfer
);
#ifdef CONFIG_SPI_DW_DMA
extern
void
dw_spi_dma_setup_mfld
(
struct
dw_spi
*
dws
);
extern
void
dw_spi_dma_setup_generic
(
struct
dw_spi
*
dws
);
#else
static
inline
void
dw_spi_dma_setup_mfld
(
struct
dw_spi
*
dws
)
{}
static
inline
void
dw_spi_dma_setup_generic
(
struct
dw_spi
*
dws
)
{}
#endif
/* !CONFIG_SPI_DW_DMA */
/* platform related setup */
extern
int
dw_spi_mid_init
(
struct
dw_spi
*
dws
);
/* Intel MID platforms */
#endif
/* DW_SPI_HEADER_H */
drivers/spi/spi-fsl-dspi.c
View file @
fb02b9eb
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright 2013 Freescale Semiconductor, Inc.
// Copyright 2020 NXP
//
// Freescale DSPI driver
// This file contains a driver for the Freescale DSPI
...
...
@@ -26,6 +27,9 @@
#define SPI_MCR_CLR_TXF BIT(11)
#define SPI_MCR_CLR_RXF BIT(10)
#define SPI_MCR_XSPI BIT(3)
#define SPI_MCR_DIS_TXF BIT(13)
#define SPI_MCR_DIS_RXF BIT(12)
#define SPI_MCR_HALT BIT(0)
#define SPI_TCR 0x08
#define SPI_TCR_GET_TCNT(x) (((x) & GENMASK(31, 16)) >> 16)
...
...
@@ -246,13 +250,33 @@ struct fsl_dspi {
static
void
dspi_native_host_to_dev
(
struct
fsl_dspi
*
dspi
,
u32
*
txdata
)
{
memcpy
(
txdata
,
dspi
->
tx
,
dspi
->
oper_word_size
);
switch
(
dspi
->
oper_word_size
)
{
case
1
:
*
txdata
=
*
(
u8
*
)
dspi
->
tx
;
break
;
case
2
:
*
txdata
=
*
(
u16
*
)
dspi
->
tx
;
break
;
case
4
:
*
txdata
=
*
(
u32
*
)
dspi
->
tx
;
break
;
}
dspi
->
tx
+=
dspi
->
oper_word_size
;
}
static
void
dspi_native_dev_to_host
(
struct
fsl_dspi
*
dspi
,
u32
rxdata
)
{
memcpy
(
dspi
->
rx
,
&
rxdata
,
dspi
->
oper_word_size
);
switch
(
dspi
->
oper_word_size
)
{
case
1
:
*
(
u8
*
)
dspi
->
rx
=
rxdata
;
break
;
case
2
:
*
(
u16
*
)
dspi
->
rx
=
rxdata
;
break
;
case
4
:
*
(
u32
*
)
dspi
->
rx
=
rxdata
;
break
;
}
dspi
->
rx
+=
dspi
->
oper_word_size
;
}
...
...
@@ -1417,6 +1441,24 @@ static int dspi_remove(struct platform_device *pdev)
return
0
;
}
static
void
dspi_shutdown
(
struct
platform_device
*
pdev
)
{
struct
spi_controller
*
ctlr
=
platform_get_drvdata
(
pdev
);
struct
fsl_dspi
*
dspi
=
spi_controller_get_devdata
(
ctlr
);
/* Disable RX and TX */
regmap_update_bits
(
dspi
->
regmap
,
SPI_MCR
,
SPI_MCR_DIS_TXF
|
SPI_MCR_DIS_RXF
,
SPI_MCR_DIS_TXF
|
SPI_MCR_DIS_RXF
);
/* Stop Running */
regmap_update_bits
(
dspi
->
regmap
,
SPI_MCR
,
SPI_MCR_HALT
,
SPI_MCR_HALT
);
dspi_release_dma
(
dspi
);
clk_disable_unprepare
(
dspi
->
clk
);
spi_unregister_controller
(
dspi
->
ctlr
);
}
static
struct
platform_driver
fsl_dspi_driver
=
{
.
driver
.
name
=
DRIVER_NAME
,
.
driver
.
of_match_table
=
fsl_dspi_dt_ids
,
...
...
@@ -1424,6 +1466,7 @@ static struct platform_driver fsl_dspi_driver = {
.
driver
.
pm
=
&
dspi_pm
,
.
probe
=
dspi_probe
,
.
remove
=
dspi_remove
,
.
shutdown
=
dspi_shutdown
,
};
module_platform_driver
(
fsl_dspi_driver
);
...
...
drivers/spi/spi-fsl-lpspi.c
View file @
fb02b9eb
...
...
@@ -186,14 +186,13 @@ static bool fsl_lpspi_can_dma(struct spi_controller *controller,
bytes_per_word
=
fsl_lpspi_bytes_per_word
(
transfer
->
bits_per_word
);
switch
(
bytes_per_word
)
{
case
1
:
case
2
:
case
4
:
break
;
default:
return
false
;
switch
(
bytes_per_word
)
{
case
1
:
case
2
:
case
4
:
break
;
default:
return
false
;
}
return
true
;
...
...
@@ -941,7 +940,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
ret
=
pm_runtime_get_sync
(
fsl_lpspi
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
fsl_lpspi
->
dev
,
"failed to enable clock
\n
"
);
goto
out_
controller_pu
t
;
goto
out_
pm_ge
t
;
}
temp
=
readl
(
fsl_lpspi
->
base
+
IMX7ULP_PARAM
);
...
...
@@ -950,13 +949,15 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
ret
=
fsl_lpspi_dma_init
(
&
pdev
->
dev
,
fsl_lpspi
,
controller
);
if
(
ret
==
-
EPROBE_DEFER
)
goto
out_
controller_pu
t
;
goto
out_
pm_ge
t
;
if
(
ret
<
0
)
dev_err
(
&
pdev
->
dev
,
"dma setup error %d, use pio
\n
"
,
ret
);
return
0
;
out_pm_get:
pm_runtime_put_noidle
(
fsl_lpspi
->
dev
);
out_controller_put:
spi_controller_put
(
controller
);
...
...
drivers/spi/spi-fsl-qspi.c
View file @
fb02b9eb
...
...
@@ -876,14 +876,15 @@ static int fsl_qspi_probe(struct platform_device *pdev)
res
=
platform_get_resource_byname
(
pdev
,
IORESOURCE_MEM
,
"QuadSPI-memory"
);
q
->
ahb_addr
=
devm_ioremap_resource
(
dev
,
res
);
if
(
IS_ERR
(
q
->
ahb_addr
))
{
ret
=
PTR_ERR
(
q
->
ahb_addr
);
q
->
memmap_phy
=
res
->
start
;
/* Since there are 4 cs, map size required is 4 times ahb_buf_size */
q
->
ahb_addr
=
devm_ioremap
(
dev
,
q
->
memmap_phy
,
(
q
->
devtype_data
->
ahb_buf_size
*
4
));
if
(
!
q
->
ahb_addr
)
{
ret
=
-
ENOMEM
;
goto
err_put_ctrl
;
}
q
->
memmap_phy
=
res
->
start
;
/* find the clocks */
q
->
clk_en
=
devm_clk_get
(
dev
,
"qspi_en"
);
if
(
IS_ERR
(
q
->
clk_en
))
{
...
...
drivers/spi/spi-fsl-spi.c
View file @
fb02b9eb
...
...
@@ -588,7 +588,7 @@ static void fsl_spi_grlib_probe(struct device *dev)
pdata
->
cs_control
=
fsl_spi_grlib_cs_control
;
}
static
struct
spi_master
*
fsl_spi_probe
(
struct
device
*
dev
,
static
struct
spi_master
*
fsl_spi_probe
(
struct
device
*
dev
,
struct
resource
*
mem
,
unsigned
int
irq
)
{
struct
fsl_spi_platform_data
*
pdata
=
dev_get_platdata
(
dev
);
...
...
drivers/spi/spi-hisi-sfc-v3xx.c
View file @
fb02b9eb
...
...
@@ -17,6 +17,11 @@
#define HISI_SFC_V3XX_VERSION (0x1f8)
#define HISI_SFC_V3XX_INT_STAT (0x120)
#define HISI_SFC_V3XX_INT_STAT_PP_ERR BIT(2)
#define HISI_SFC_V3XX_INT_STAT_ADDR_IACCES BIT(5)
#define HISI_SFC_V3XX_INT_CLR (0x12c)
#define HISI_SFC_V3XX_INT_CLR_CLEAR (0xff)
#define HISI_SFC_V3XX_CMD_CFG (0x300)
#define HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT (1 << 17)
#define HISI_SFC_V3XX_CMD_CFG_DUAL_IO (2 << 17)
...
...
@@ -163,7 +168,7 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host,
u8
chip_select
)
{
int
ret
,
len
=
op
->
data
.
nbytes
;
u32
config
=
0
;
u32
int_stat
,
config
=
0
;
if
(
op
->
addr
.
nbytes
)
config
|=
HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK
;
...
...
@@ -228,6 +233,25 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host,
if
(
ret
)
return
ret
;
/*
* The interrupt status register indicates whether an error occurs
* after per operation. Check it, and clear the interrupts for
* next time judgement.
*/
int_stat
=
readl
(
host
->
regbase
+
HISI_SFC_V3XX_INT_STAT
);
writel
(
HISI_SFC_V3XX_INT_CLR_CLEAR
,
host
->
regbase
+
HISI_SFC_V3XX_INT_CLR
);
if
(
int_stat
&
HISI_SFC_V3XX_INT_STAT_ADDR_IACCES
)
{
dev_err
(
host
->
dev
,
"fail to access protected address
\n
"
);
return
-
EIO
;
}
if
(
int_stat
&
HISI_SFC_V3XX_INT_STAT_PP_ERR
)
{
dev_err
(
host
->
dev
,
"page program operation failed
\n
"
);
return
-
EIO
;
}
if
(
op
->
data
.
dir
==
SPI_MEM_DATA_IN
)
hisi_sfc_v3xx_read_databuf
(
host
,
op
->
data
.
buf
.
in
,
len
);
...
...
drivers/spi/spi-imx.c
View file @
fb02b9eb
...
...
@@ -71,6 +71,7 @@ struct spi_imx_devtype_data {
void
(
*
reset
)(
struct
spi_imx_data
*
);
void
(
*
setup_wml
)(
struct
spi_imx_data
*
);
void
(
*
disable
)(
struct
spi_imx_data
*
);
void
(
*
disable_dma
)(
struct
spi_imx_data
*
);
bool
has_dmamode
;
bool
has_slavemode
;
unsigned
int
fifo_size
;
...
...
@@ -485,6 +486,11 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
writel
(
reg
,
spi_imx
->
base
+
MX51_ECSPI_CTRL
);
}
static
void
mx51_disable_dma
(
struct
spi_imx_data
*
spi_imx
)
{
writel
(
0
,
spi_imx
->
base
+
MX51_ECSPI_DMA
);
}
static
void
mx51_ecspi_disable
(
struct
spi_imx_data
*
spi_imx
)
{
u32
ctrl
;
...
...
@@ -987,6 +993,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.
rx_available
=
mx51_ecspi_rx_available
,
.
reset
=
mx51_ecspi_reset
,
.
setup_wml
=
mx51_setup_wml
,
.
disable_dma
=
mx51_disable_dma
,
.
fifo_size
=
64
,
.
has_dmamode
=
true
,
.
dynamic_burst
=
true
,
...
...
@@ -1001,6 +1008,7 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
.
prepare_transfer
=
mx51_ecspi_prepare_transfer
,
.
trigger
=
mx51_ecspi_trigger
,
.
rx_available
=
mx51_ecspi_rx_available
,
.
disable_dma
=
mx51_disable_dma
,
.
reset
=
mx51_ecspi_reset
,
.
fifo_size
=
64
,
.
has_dmamode
=
true
,
...
...
@@ -1385,6 +1393,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
DMA_PREP_INTERRUPT
|
DMA_CTRL_ACK
);
if
(
!
desc_tx
)
{
dmaengine_terminate_all
(
master
->
dma_tx
);
dmaengine_terminate_all
(
master
->
dma_rx
);
return
-
EINVAL
;
}
...
...
@@ -1498,6 +1507,7 @@ static int spi_imx_transfer(struct spi_device *spi,
struct
spi_transfer
*
transfer
)
{
struct
spi_imx_data
*
spi_imx
=
spi_master_get_devdata
(
spi
->
master
);
int
ret
;
/* flush rxfifo before transfer */
while
(
spi_imx
->
devtype_data
->
rx_available
(
spi_imx
))
...
...
@@ -1506,10 +1516,23 @@ static int spi_imx_transfer(struct spi_device *spi,
if
(
spi_imx
->
slave_mode
)
return
spi_imx_pio_transfer_slave
(
spi
,
transfer
);
if
(
spi_imx
->
usedma
)
return
spi_imx_dma_transfer
(
spi_imx
,
transfer
);
else
return
spi_imx_pio_transfer
(
spi
,
transfer
);
/*
* fallback PIO mode if dma setup error happen, for example sdma
* firmware may not be updated as ERR009165 required.
*/
if
(
spi_imx
->
usedma
)
{
ret
=
spi_imx_dma_transfer
(
spi_imx
,
transfer
);
if
(
ret
!=
-
EINVAL
)
return
ret
;
spi_imx
->
devtype_data
->
disable_dma
(
spi_imx
);
spi_imx
->
usedma
=
false
;
spi_imx
->
dynamic_burst
=
spi_imx
->
devtype_data
->
dynamic_burst
;
dev_dbg
(
&
spi
->
dev
,
"Fallback to PIO mode
\n
"
);
}
return
spi_imx_pio_transfer
(
spi
,
transfer
);
}
static
int
spi_imx_setup
(
struct
spi_device
*
spi
)
...
...
drivers/spi/spi-mem.c
View file @
fb02b9eb
...
...
@@ -108,15 +108,17 @@ static int spi_check_buswidth_req(struct spi_mem *mem, u8 buswidth, bool tx)
return
0
;
case
2
:
if
((
tx
&&
(
mode
&
(
SPI_TX_DUAL
|
SPI_TX_QUAD
)))
||
(
!
tx
&&
(
mode
&
(
SPI_RX_DUAL
|
SPI_RX_QUAD
))))
if
((
tx
&&
(
mode
&
(
SPI_TX_DUAL
|
SPI_TX_QUAD
|
SPI_TX_OCTAL
)))
||
(
!
tx
&&
(
mode
&
(
SPI_RX_DUAL
|
SPI_RX_QUAD
|
SPI_RX_OCTAL
))))
return
0
;
break
;
case
4
:
if
((
tx
&&
(
mode
&
SPI_TX_QUAD
))
||
(
!
tx
&&
(
mode
&
SPI_RX_QUAD
)))
if
((
tx
&&
(
mode
&
(
SPI_TX_QUAD
|
SPI_TX_OCTAL
)
))
||
(
!
tx
&&
(
mode
&
(
SPI_RX_QUAD
|
SPI_RX_OCTAL
)
)))
return
0
;
break
;
...
...
drivers/spi/spi-mtk-nor.c
View file @
fb02b9eb
...
...
@@ -391,7 +391,7 @@ static int mtk_nor_pp_unbuffered(struct mtk_nor *sp,
return
mtk_nor_cmd_exec
(
sp
,
MTK_NOR_CMD_WRITE
,
6
*
BITS_PER_BYTE
);
}
int
mtk_nor_exec_op
(
struct
spi_mem
*
mem
,
const
struct
spi_mem_op
*
op
)
static
int
mtk_nor_exec_op
(
struct
spi_mem
*
mem
,
const
struct
spi_mem_op
*
op
)
{
struct
mtk_nor
*
sp
=
spi_controller_get_devdata
(
mem
->
spi
->
master
);
int
ret
;
...
...
drivers/spi/spi-orion.c
View file @
fb02b9eb
...
...
@@ -17,10 +17,8 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/sizes.h>
#include <linux/gpio.h>
#include <asm/unaligned.h>
#define DRIVER_NAME "orion_spi"
...
...
@@ -98,7 +96,6 @@ struct orion_spi {
struct
clk
*
clk
;
struct
clk
*
axi_clk
;
const
struct
orion_spi_dev
*
devdata
;
int
unused_hw_gpio
;
struct
orion_child_options
child
[
ORION_NUM_CHIPSELECTS
];
};
...
...
@@ -325,20 +322,27 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static
void
orion_spi_set_cs
(
struct
spi_device
*
spi
,
bool
enable
)
{
struct
orion_spi
*
orion_spi
;
int
cs
;
orion_spi
=
spi_master_get_devdata
(
spi
->
master
);
if
(
gpio_is_valid
(
spi
->
cs_gpio
))
cs
=
orion_spi
->
unused_hw_gpio
;
else
cs
=
spi
->
chip_select
;
/*
* If this line is using a GPIO to control chip select, this internal
* .set_cs() function will still be called, so we clear any previous
* chip select. The CS we activate will not have any elecrical effect,
* as it is handled by a GPIO, but that doesn't matter. What we need
* is to deassert the old chip select and assert some other chip select.
*/
orion_spi_clrbits
(
orion_spi
,
ORION_SPI_IF_CTRL_REG
,
ORION_SPI_CS_MASK
);
orion_spi_setbits
(
orion_spi
,
ORION_SPI_IF_CTRL_REG
,
ORION_SPI_CS
(
cs
));
ORION_SPI_CS
(
spi
->
chip_select
));
/* Chip select logic is inverted from spi_set_cs */
/*
* Chip select logic is inverted from spi_set_cs(). For lines using a
* GPIO to do chip select SPI_CS_HIGH is enforced and inversion happens
* in the GPIO library, but we don't care about that, because in those
* cases we are dealing with an unused native CS anyways so the polarity
* doesn't matter.
*/
if
(
!
enable
)
orion_spi_setbits
(
orion_spi
,
ORION_SPI_IF_CTRL_REG
,
0x1
);
else
...
...
@@ -503,9 +507,6 @@ static int orion_spi_transfer_one(struct spi_master *master,
static
int
orion_spi_setup
(
struct
spi_device
*
spi
)
{
if
(
gpio_is_valid
(
spi
->
cs_gpio
))
{
gpio_direction_output
(
spi
->
cs_gpio
,
!
(
spi
->
mode
&
SPI_CS_HIGH
));
}
return
orion_spi_setup_transfer
(
spi
,
NULL
);
}
...
...
@@ -622,13 +623,13 @@ static int orion_spi_probe(struct platform_device *pdev)
master
->
setup
=
orion_spi_setup
;
master
->
bits_per_word_mask
=
SPI_BPW_MASK
(
8
)
|
SPI_BPW_MASK
(
16
);
master
->
auto_runtime_pm
=
true
;
master
->
use_gpio_descriptors
=
true
;
master
->
flags
=
SPI_MASTER_GPIO_SS
;
platform_set_drvdata
(
pdev
,
master
);
spi
=
spi_master_get_devdata
(
master
);
spi
->
master
=
master
;
spi
->
unused_hw_gpio
=
-
1
;
of_id
=
of_match_device
(
orion_spi_of_match_table
,
&
pdev
->
dev
);
devdata
=
(
of_id
)
?
of_id
->
data
:
&
orion_spi_dev_data
;
...
...
@@ -683,7 +684,6 @@ static int orion_spi_probe(struct platform_device *pdev)
for_each_available_child_of_node
(
pdev
->
dev
.
of_node
,
np
)
{
struct
orion_direct_acc
*
dir_acc
;
u32
cs
;
int
cs_gpio
;
/* Get chip-select number from the "reg" property */
status
=
of_property_read_u32
(
np
,
"reg"
,
&
cs
);
...
...
@@ -694,44 +694,6 @@ static int orion_spi_probe(struct platform_device *pdev)
continue
;
}
/*
* Initialize the CS GPIO:
* - properly request the actual GPIO signal
* - de-assert the logical signal so that all GPIO CS lines
* are inactive when probing for slaves
* - find an unused physical CS which will be driven for any
* slave which uses a CS GPIO
*/
cs_gpio
=
of_get_named_gpio
(
pdev
->
dev
.
of_node
,
"cs-gpios"
,
cs
);
if
(
cs_gpio
>
0
)
{
char
*
gpio_name
;
int
cs_flags
;
if
(
spi
->
unused_hw_gpio
==
-
1
)
{
dev_info
(
&
pdev
->
dev
,
"Selected unused HW CS#%d for any GPIO CSes
\n
"
,
cs
);
spi
->
unused_hw_gpio
=
cs
;
}
gpio_name
=
devm_kasprintf
(
&
pdev
->
dev
,
GFP_KERNEL
,
"%s-CS%d"
,
dev_name
(
&
pdev
->
dev
),
cs
);
if
(
!
gpio_name
)
{
status
=
-
ENOMEM
;
goto
out_rel_axi_clk
;
}
cs_flags
=
of_property_read_bool
(
np
,
"spi-cs-high"
)
?
GPIOF_OUT_INIT_LOW
:
GPIOF_OUT_INIT_HIGH
;
status
=
devm_gpio_request_one
(
&
pdev
->
dev
,
cs_gpio
,
cs_flags
,
gpio_name
);
if
(
status
)
{
dev_err
(
&
pdev
->
dev
,
"Can't request GPIO for CS %d
\n
"
,
cs
);
goto
out_rel_axi_clk
;
}
}
/*
* Check if an address is configured for this SPI device. If
* not, the MBus mapping via the 'ranges' property in the 'soc'
...
...
drivers/spi/spi-pxa2xx.c
View file @
fb02b9eb
...
...
@@ -150,6 +150,7 @@ static const struct lpss_config lpss_platforms[] = {
.
tx_threshold_hi
=
48
,
.
cs_sel_shift
=
8
,
.
cs_sel_mask
=
3
<<
8
,
.
cs_clk_stays_gated
=
true
,
},
{
/* LPSS_CNL_SSP */
.
offset
=
0x200
,
...
...
drivers/spi/spi-rb4xx.c
View file @
fb02b9eb
...
...
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
#include <asm/mach-ath79/ar71xx_regs.h>
...
...
@@ -150,6 +151,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
if
(
IS_ERR
(
ahb_clk
))
return
PTR_ERR
(
ahb_clk
);
master
->
dev
.
of_node
=
pdev
->
dev
.
of_node
;
master
->
bus_num
=
0
;
master
->
num_chipselect
=
3
;
master
->
mode_bits
=
SPI_TX_DUAL
;
...
...
@@ -158,6 +160,11 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
master
->
transfer_one
=
rb4xx_transfer_one
;
master
->
set_cs
=
rb4xx_set_cs
;
rbspi
=
spi_master_get_devdata
(
master
);
rbspi
->
base
=
spi_base
;
rbspi
->
clk
=
ahb_clk
;
platform_set_drvdata
(
pdev
,
rbspi
);
err
=
devm_spi_register_master
(
&
pdev
->
dev
,
master
);
if
(
err
)
{
dev_err
(
&
pdev
->
dev
,
"failed to register SPI master
\n
"
);
...
...
@@ -168,11 +175,6 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
if
(
err
)
return
err
;
rbspi
=
spi_master_get_devdata
(
master
);
rbspi
->
base
=
spi_base
;
rbspi
->
clk
=
ahb_clk
;
platform_set_drvdata
(
pdev
,
rbspi
);
/* Enable SPI */
rb4xx_write
(
rbspi
,
AR71XX_SPI_REG_FS
,
AR71XX_SPI_FS_GPIO
);
...
...
@@ -188,11 +190,18 @@ static int rb4xx_spi_remove(struct platform_device *pdev)
return
0
;
}
static
const
struct
of_device_id
rb4xx_spi_dt_match
[]
=
{
{
.
compatible
=
"mikrotik,rb4xx-spi"
},
{
},
};
MODULE_DEVICE_TABLE
(
of
,
rb4xx_spi_dt_match
);
static
struct
platform_driver
rb4xx_spi_drv
=
{
.
probe
=
rb4xx_spi_probe
,
.
remove
=
rb4xx_spi_remove
,
.
driver
=
{
.
name
=
"rb4xx-spi"
,
.
of_match_table
=
of_match_ptr
(
rb4xx_spi_dt_match
),
},
};
...
...
drivers/spi/spi-rockchip.c
View file @
fb02b9eb
...
...
@@ -183,6 +183,8 @@ struct rockchip_spi {
u8
rsd
;
bool
cs_asserted
[
ROCKCHIP_SPI_MAX_CS_NUM
];
bool
slave_abort
;
};
static
inline
void
spi_enable_chip
(
struct
rockchip_spi
*
rs
,
bool
enable
)
...
...
@@ -219,8 +221,8 @@ static u32 get_fifo_len(struct rockchip_spi *rs)
static
void
rockchip_spi_set_cs
(
struct
spi_device
*
spi
,
bool
enable
)
{
struct
spi_
master
*
master
=
spi
->
mast
er
;
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctlr
=
spi
->
controll
er
;
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
bool
cs_asserted
=
!
enable
;
/* Return immediately for no-op */
...
...
@@ -244,10 +246,10 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
rs
->
cs_asserted
[
spi
->
chip_select
]
=
cs_asserted
;
}
static
void
rockchip_spi_handle_err
(
struct
spi_
master
*
maste
r
,
static
void
rockchip_spi_handle_err
(
struct
spi_
controller
*
ctl
r
,
struct
spi_message
*
msg
)
{
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
/* stop running spi transfer
* this also flushes both rx and tx fifos
...
...
@@ -258,10 +260,10 @@ static void rockchip_spi_handle_err(struct spi_master *master,
writel_relaxed
(
0
,
rs
->
regs
+
ROCKCHIP_SPI_IMR
);
if
(
atomic_read
(
&
rs
->
state
)
&
TXDMA
)
dmaengine_terminate_async
(
maste
r
->
dma_tx
);
dmaengine_terminate_async
(
ctl
r
->
dma_tx
);
if
(
atomic_read
(
&
rs
->
state
)
&
RXDMA
)
dmaengine_terminate_async
(
maste
r
->
dma_rx
);
dmaengine_terminate_async
(
ctl
r
->
dma_rx
);
}
static
void
rockchip_spi_pio_writer
(
struct
rockchip_spi
*
rs
)
...
...
@@ -319,8 +321,8 @@ static void rockchip_spi_pio_reader(struct rockchip_spi *rs)
static
irqreturn_t
rockchip_spi_isr
(
int
irq
,
void
*
dev_id
)
{
struct
spi_
master
*
maste
r
=
dev_id
;
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctl
r
=
dev_id
;
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
if
(
rs
->
tx_left
)
rockchip_spi_pio_writer
(
rs
);
...
...
@@ -329,7 +331,7 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)
if
(
!
rs
->
rx_left
)
{
spi_enable_chip
(
rs
,
false
);
writel_relaxed
(
0
,
rs
->
regs
+
ROCKCHIP_SPI_IMR
);
spi_finalize_current_transfer
(
maste
r
);
spi_finalize_current_transfer
(
ctl
r
);
}
return
IRQ_HANDLED
;
...
...
@@ -355,35 +357,35 @@ static int rockchip_spi_prepare_irq(struct rockchip_spi *rs,
static
void
rockchip_spi_dma_rxcb
(
void
*
data
)
{
struct
spi_
master
*
maste
r
=
data
;
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctl
r
=
data
;
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
int
state
=
atomic_fetch_andnot
(
RXDMA
,
&
rs
->
state
);
if
(
state
&
TXDMA
)
if
(
state
&
TXDMA
&&
!
rs
->
slave_abort
)
return
;
spi_enable_chip
(
rs
,
false
);
spi_finalize_current_transfer
(
maste
r
);
spi_finalize_current_transfer
(
ctl
r
);
}
static
void
rockchip_spi_dma_txcb
(
void
*
data
)
{
struct
spi_
master
*
maste
r
=
data
;
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctl
r
=
data
;
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
int
state
=
atomic_fetch_andnot
(
TXDMA
,
&
rs
->
state
);
if
(
state
&
RXDMA
)
if
(
state
&
RXDMA
&&
!
rs
->
slave_abort
)
return
;
/* Wait until the FIFO data completely. */
wait_for_idle
(
rs
);
spi_enable_chip
(
rs
,
false
);
spi_finalize_current_transfer
(
maste
r
);
spi_finalize_current_transfer
(
ctl
r
);
}
static
int
rockchip_spi_prepare_dma
(
struct
rockchip_spi
*
rs
,
struct
spi_
master
*
maste
r
,
struct
spi_transfer
*
xfer
)
struct
spi_
controller
*
ctl
r
,
struct
spi_transfer
*
xfer
)
{
struct
dma_async_tx_descriptor
*
rxdesc
,
*
txdesc
;
...
...
@@ -398,17 +400,17 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
.
src_maxburst
=
1
,
};
dmaengine_slave_config
(
maste
r
->
dma_rx
,
&
rxconf
);
dmaengine_slave_config
(
ctl
r
->
dma_rx
,
&
rxconf
);
rxdesc
=
dmaengine_prep_slave_sg
(
maste
r
->
dma_rx
,
ctl
r
->
dma_rx
,
xfer
->
rx_sg
.
sgl
,
xfer
->
rx_sg
.
nents
,
DMA_DEV_TO_MEM
,
DMA_PREP_INTERRUPT
);
if
(
!
rxdesc
)
return
-
EINVAL
;
rxdesc
->
callback
=
rockchip_spi_dma_rxcb
;
rxdesc
->
callback_param
=
maste
r
;
rxdesc
->
callback_param
=
ctl
r
;
}
txdesc
=
NULL
;
...
...
@@ -420,27 +422,27 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
.
dst_maxburst
=
rs
->
fifo_len
/
4
,
};
dmaengine_slave_config
(
maste
r
->
dma_tx
,
&
txconf
);
dmaengine_slave_config
(
ctl
r
->
dma_tx
,
&
txconf
);
txdesc
=
dmaengine_prep_slave_sg
(
maste
r
->
dma_tx
,
ctl
r
->
dma_tx
,
xfer
->
tx_sg
.
sgl
,
xfer
->
tx_sg
.
nents
,
DMA_MEM_TO_DEV
,
DMA_PREP_INTERRUPT
);
if
(
!
txdesc
)
{
if
(
rxdesc
)
dmaengine_terminate_sync
(
maste
r
->
dma_rx
);
dmaengine_terminate_sync
(
ctl
r
->
dma_rx
);
return
-
EINVAL
;
}
txdesc
->
callback
=
rockchip_spi_dma_txcb
;
txdesc
->
callback_param
=
maste
r
;
txdesc
->
callback_param
=
ctl
r
;
}
/* rx must be started before tx due to spi instinct */
if
(
rxdesc
)
{
atomic_or
(
RXDMA
,
&
rs
->
state
);
dmaengine_submit
(
rxdesc
);
dma_async_issue_pending
(
maste
r
->
dma_rx
);
dma_async_issue_pending
(
ctl
r
->
dma_rx
);
}
spi_enable_chip
(
rs
,
true
);
...
...
@@ -448,7 +450,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
if
(
txdesc
)
{
atomic_or
(
TXDMA
,
&
rs
->
state
);
dmaengine_submit
(
txdesc
);
dma_async_issue_pending
(
maste
r
->
dma_tx
);
dma_async_issue_pending
(
ctl
r
->
dma_tx
);
}
/* 1 means the transfer is in progress */
...
...
@@ -457,7 +459,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
static
void
rockchip_spi_config
(
struct
rockchip_spi
*
rs
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
,
bool
use_dma
)
bool
use_dma
,
bool
slave_mode
)
{
u32
cr0
=
CR0_FRF_SPI
<<
CR0_FRF_OFFSET
|
CR0_BHT_8BIT
<<
CR0_BHT_OFFSET
...
...
@@ -466,6 +468,10 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
u32
cr1
;
u32
dmacr
=
0
;
if
(
slave_mode
)
cr0
|=
CR0_OPM_SLAVE
<<
CR0_OPM_OFFSET
;
rs
->
slave_abort
=
false
;
cr0
|=
rs
->
rsd
<<
CR0_RSD_OFFSET
;
cr0
|=
(
spi
->
mode
&
0x3U
)
<<
CR0_SCPH_OFFSET
;
if
(
spi
->
mode
&
SPI_LSB_FIRST
)
...
...
@@ -493,7 +499,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
break
;
default:
/* we only whitelist 4, 8 and 16 bit words in
*
maste
r->bits_per_word_mask, so this shouldn't
*
ctl
r->bits_per_word_mask, so this shouldn't
* happen
*/
unreachable
();
...
...
@@ -535,12 +541,22 @@ static size_t rockchip_spi_max_transfer_size(struct spi_device *spi)
return
ROCKCHIP_SPI_MAX_TRANLEN
;
}
static
int
rockchip_spi_slave_abort
(
struct
spi_controller
*
ctlr
)
{
struct
rockchip_spi
*
rs
=
spi_controller_get_devdata
(
ctlr
);
rs
->
slave_abort
=
true
;
complete
(
&
ctlr
->
xfer_completion
);
return
0
;
}
static
int
rockchip_spi_transfer_one
(
struct
spi_
master
*
maste
r
,
struct
spi_
controller
*
ctl
r
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
{
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
bool
use_dma
;
WARN_ON
(
readl_relaxed
(
rs
->
regs
+
ROCKCHIP_SPI_SSIENR
)
&&
...
...
@@ -558,21 +574,21 @@ static int rockchip_spi_transfer_one(
rs
->
n_bytes
=
xfer
->
bits_per_word
<=
8
?
1
:
2
;
use_dma
=
master
->
can_dma
?
master
->
can_dma
(
maste
r
,
spi
,
xfer
)
:
false
;
use_dma
=
ctlr
->
can_dma
?
ctlr
->
can_dma
(
ctl
r
,
spi
,
xfer
)
:
false
;
rockchip_spi_config
(
rs
,
spi
,
xfer
,
use_dma
);
rockchip_spi_config
(
rs
,
spi
,
xfer
,
use_dma
,
ctlr
->
slave
);
if
(
use_dma
)
return
rockchip_spi_prepare_dma
(
rs
,
maste
r
,
xfer
);
return
rockchip_spi_prepare_dma
(
rs
,
ctl
r
,
xfer
);
return
rockchip_spi_prepare_irq
(
rs
,
xfer
);
}
static
bool
rockchip_spi_can_dma
(
struct
spi_
master
*
maste
r
,
static
bool
rockchip_spi_can_dma
(
struct
spi_
controller
*
ctl
r
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
{
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
unsigned
int
bytes_per_word
=
xfer
->
bits_per_word
<=
8
?
1
:
2
;
/* if the numbor of spi words to transfer is less than the fifo
...
...
@@ -586,44 +602,55 @@ static int rockchip_spi_probe(struct platform_device *pdev)
{
int
ret
;
struct
rockchip_spi
*
rs
;
struct
spi_
master
*
maste
r
;
struct
spi_
controller
*
ctl
r
;
struct
resource
*
mem
;
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
u32
rsd_nsecs
;
bool
slave_mode
;
slave_mode
=
of_property_read_bool
(
np
,
"spi-slave"
);
if
(
slave_mode
)
ctlr
=
spi_alloc_slave
(
&
pdev
->
dev
,
sizeof
(
struct
rockchip_spi
));
else
ctlr
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
struct
rockchip_spi
));
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
struct
rockchip_spi
));
if
(
!
master
)
if
(
!
ctlr
)
return
-
ENOMEM
;
platform_set_drvdata
(
pdev
,
maste
r
);
platform_set_drvdata
(
pdev
,
ctl
r
);
rs
=
spi_master_get_devdata
(
master
);
rs
=
spi_controller_get_devdata
(
ctlr
);
ctlr
->
slave
=
slave_mode
;
/* Get basic io resource and map it */
mem
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
rs
->
regs
=
devm_ioremap_resource
(
&
pdev
->
dev
,
mem
);
if
(
IS_ERR
(
rs
->
regs
))
{
ret
=
PTR_ERR
(
rs
->
regs
);
goto
err_put_
maste
r
;
goto
err_put_
ctl
r
;
}
rs
->
apb_pclk
=
devm_clk_get
(
&
pdev
->
dev
,
"apb_pclk"
);
if
(
IS_ERR
(
rs
->
apb_pclk
))
{
dev_err
(
&
pdev
->
dev
,
"Failed to get apb_pclk
\n
"
);
ret
=
PTR_ERR
(
rs
->
apb_pclk
);
goto
err_put_
maste
r
;
goto
err_put_
ctl
r
;
}
rs
->
spiclk
=
devm_clk_get
(
&
pdev
->
dev
,
"spiclk"
);
if
(
IS_ERR
(
rs
->
spiclk
))
{
dev_err
(
&
pdev
->
dev
,
"Failed to get spi_pclk
\n
"
);
ret
=
PTR_ERR
(
rs
->
spiclk
);
goto
err_put_
maste
r
;
goto
err_put_
ctl
r
;
}
ret
=
clk_prepare_enable
(
rs
->
apb_pclk
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to enable apb_pclk
\n
"
);
goto
err_put_
maste
r
;
goto
err_put_
ctl
r
;
}
ret
=
clk_prepare_enable
(
rs
->
spiclk
);
...
...
@@ -639,7 +666,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
goto
err_disable_spiclk
;
ret
=
devm_request_threaded_irq
(
&
pdev
->
dev
,
ret
,
rockchip_spi_isr
,
NULL
,
IRQF_ONESHOT
,
dev_name
(
&
pdev
->
dev
),
maste
r
);
IRQF_ONESHOT
,
dev_name
(
&
pdev
->
dev
),
ctl
r
);
if
(
ret
)
goto
err_disable_spiclk
;
...
...
@@ -673,78 +700,90 @@ static int rockchip_spi_probe(struct platform_device *pdev)
pm_runtime_set_active
(
&
pdev
->
dev
);
pm_runtime_enable
(
&
pdev
->
dev
);
master
->
auto_runtime_pm
=
true
;
master
->
bus_num
=
pdev
->
id
;
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_LOOP
|
SPI_LSB_FIRST
;
master
->
num_chipselect
=
ROCKCHIP_SPI_MAX_CS_NUM
;
master
->
dev
.
of_node
=
pdev
->
dev
.
of_node
;
master
->
bits_per_word_mask
=
SPI_BPW_MASK
(
16
)
|
SPI_BPW_MASK
(
8
)
|
SPI_BPW_MASK
(
4
);
master
->
min_speed_hz
=
rs
->
freq
/
BAUDR_SCKDV_MAX
;
master
->
max_speed_hz
=
min
(
rs
->
freq
/
BAUDR_SCKDV_MIN
,
MAX_SCLK_OUT
);
master
->
set_cs
=
rockchip_spi_set_cs
;
master
->
transfer_one
=
rockchip_spi_transfer_one
;
master
->
max_transfer_size
=
rockchip_spi_max_transfer_size
;
master
->
handle_err
=
rockchip_spi_handle_err
;
master
->
flags
=
SPI_MASTER_GPIO_SS
;
master
->
dma_tx
=
dma_request_chan
(
rs
->
dev
,
"tx"
);
if
(
IS_ERR
(
master
->
dma_tx
))
{
ctlr
->
auto_runtime_pm
=
true
;
ctlr
->
bus_num
=
pdev
->
id
;
ctlr
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_LOOP
|
SPI_LSB_FIRST
;
if
(
slave_mode
)
{
ctlr
->
mode_bits
|=
SPI_NO_CS
;
ctlr
->
slave_abort
=
rockchip_spi_slave_abort
;
}
else
{
ctlr
->
flags
=
SPI_MASTER_GPIO_SS
;
ctlr
->
max_native_cs
=
ROCKCHIP_SPI_MAX_CS_NUM
;
/*
* rk spi0 has two native cs, spi1..5 one cs only
* if num-cs is missing in the dts, default to 1
*/
if
(
of_property_read_u16
(
np
,
"num-cs"
,
&
ctlr
->
num_chipselect
))
ctlr
->
num_chipselect
=
1
;
ctlr
->
use_gpio_descriptors
=
true
;
}
ctlr
->
dev
.
of_node
=
pdev
->
dev
.
of_node
;
ctlr
->
bits_per_word_mask
=
SPI_BPW_MASK
(
16
)
|
SPI_BPW_MASK
(
8
)
|
SPI_BPW_MASK
(
4
);
ctlr
->
min_speed_hz
=
rs
->
freq
/
BAUDR_SCKDV_MAX
;
ctlr
->
max_speed_hz
=
min
(
rs
->
freq
/
BAUDR_SCKDV_MIN
,
MAX_SCLK_OUT
);
ctlr
->
set_cs
=
rockchip_spi_set_cs
;
ctlr
->
transfer_one
=
rockchip_spi_transfer_one
;
ctlr
->
max_transfer_size
=
rockchip_spi_max_transfer_size
;
ctlr
->
handle_err
=
rockchip_spi_handle_err
;
ctlr
->
dma_tx
=
dma_request_chan
(
rs
->
dev
,
"tx"
);
if
(
IS_ERR
(
ctlr
->
dma_tx
))
{
/* Check tx to see if we need defer probing driver */
if
(
PTR_ERR
(
maste
r
->
dma_tx
)
==
-
EPROBE_DEFER
)
{
if
(
PTR_ERR
(
ctl
r
->
dma_tx
)
==
-
EPROBE_DEFER
)
{
ret
=
-
EPROBE_DEFER
;
goto
err_disable_pm_runtime
;
}
dev_warn
(
rs
->
dev
,
"Failed to request TX DMA channel
\n
"
);
maste
r
->
dma_tx
=
NULL
;
ctl
r
->
dma_tx
=
NULL
;
}
maste
r
->
dma_rx
=
dma_request_chan
(
rs
->
dev
,
"rx"
);
if
(
IS_ERR
(
maste
r
->
dma_rx
))
{
if
(
PTR_ERR
(
maste
r
->
dma_rx
)
==
-
EPROBE_DEFER
)
{
ctl
r
->
dma_rx
=
dma_request_chan
(
rs
->
dev
,
"rx"
);
if
(
IS_ERR
(
ctl
r
->
dma_rx
))
{
if
(
PTR_ERR
(
ctl
r
->
dma_rx
)
==
-
EPROBE_DEFER
)
{
ret
=
-
EPROBE_DEFER
;
goto
err_free_dma_tx
;
}
dev_warn
(
rs
->
dev
,
"Failed to request RX DMA channel
\n
"
);
maste
r
->
dma_rx
=
NULL
;
ctl
r
->
dma_rx
=
NULL
;
}
if
(
master
->
dma_tx
&&
maste
r
->
dma_rx
)
{
if
(
ctlr
->
dma_tx
&&
ctl
r
->
dma_rx
)
{
rs
->
dma_addr_tx
=
mem
->
start
+
ROCKCHIP_SPI_TXDR
;
rs
->
dma_addr_rx
=
mem
->
start
+
ROCKCHIP_SPI_RXDR
;
maste
r
->
can_dma
=
rockchip_spi_can_dma
;
ctl
r
->
can_dma
=
rockchip_spi_can_dma
;
}
ret
=
devm_spi_register_
master
(
&
pdev
->
dev
,
maste
r
);
ret
=
devm_spi_register_
controller
(
&
pdev
->
dev
,
ctl
r
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to register
mast
er
\n
"
);
dev_err
(
&
pdev
->
dev
,
"Failed to register
controll
er
\n
"
);
goto
err_free_dma_rx
;
}
return
0
;
err_free_dma_rx:
if
(
maste
r
->
dma_rx
)
dma_release_channel
(
maste
r
->
dma_rx
);
if
(
ctl
r
->
dma_rx
)
dma_release_channel
(
ctl
r
->
dma_rx
);
err_free_dma_tx:
if
(
maste
r
->
dma_tx
)
dma_release_channel
(
maste
r
->
dma_tx
);
if
(
ctl
r
->
dma_tx
)
dma_release_channel
(
ctl
r
->
dma_tx
);
err_disable_pm_runtime:
pm_runtime_disable
(
&
pdev
->
dev
);
err_disable_spiclk:
clk_disable_unprepare
(
rs
->
spiclk
);
err_disable_apbclk:
clk_disable_unprepare
(
rs
->
apb_pclk
);
err_put_
maste
r:
spi_
master_put
(
maste
r
);
err_put_
ctl
r:
spi_
controller_put
(
ctl
r
);
return
ret
;
}
static
int
rockchip_spi_remove
(
struct
platform_device
*
pdev
)
{
struct
spi_
master
*
master
=
spi_mast
er_get
(
platform_get_drvdata
(
pdev
));
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctlr
=
spi_controll
er_get
(
platform_get_drvdata
(
pdev
));
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
pm_runtime_get_sync
(
&
pdev
->
dev
);
...
...
@@ -755,12 +794,12 @@ static int rockchip_spi_remove(struct platform_device *pdev)
pm_runtime_disable
(
&
pdev
->
dev
);
pm_runtime_set_suspended
(
&
pdev
->
dev
);
if
(
maste
r
->
dma_tx
)
dma_release_channel
(
maste
r
->
dma_tx
);
if
(
maste
r
->
dma_rx
)
dma_release_channel
(
maste
r
->
dma_rx
);
if
(
ctl
r
->
dma_tx
)
dma_release_channel
(
ctl
r
->
dma_tx
);
if
(
ctl
r
->
dma_rx
)
dma_release_channel
(
ctl
r
->
dma_rx
);
spi_
master_put
(
maste
r
);
spi_
controller_put
(
ctl
r
);
return
0
;
}
...
...
@@ -769,9 +808,9 @@ static int rockchip_spi_remove(struct platform_device *pdev)
static
int
rockchip_spi_suspend
(
struct
device
*
dev
)
{
int
ret
;
struct
spi_
master
*
maste
r
=
dev_get_drvdata
(
dev
);
struct
spi_
controller
*
ctl
r
=
dev_get_drvdata
(
dev
);
ret
=
spi_
master_suspend
(
maste
r
);
ret
=
spi_
controller_suspend
(
ctl
r
);
if
(
ret
<
0
)
return
ret
;
...
...
@@ -787,8 +826,8 @@ static int rockchip_spi_suspend(struct device *dev)
static
int
rockchip_spi_resume
(
struct
device
*
dev
)
{
int
ret
;
struct
spi_
master
*
maste
r
=
dev_get_drvdata
(
dev
);
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctl
r
=
dev_get_drvdata
(
dev
);
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
pinctrl_pm_select_default_state
(
dev
);
...
...
@@ -796,7 +835,7 @@ static int rockchip_spi_resume(struct device *dev)
if
(
ret
<
0
)
return
ret
;
ret
=
spi_
master_resume
(
maste
r
);
ret
=
spi_
controller_resume
(
ctl
r
);
if
(
ret
<
0
)
{
clk_disable_unprepare
(
rs
->
spiclk
);
clk_disable_unprepare
(
rs
->
apb_pclk
);
...
...
@@ -809,8 +848,8 @@ static int rockchip_spi_resume(struct device *dev)
#ifdef CONFIG_PM
static
int
rockchip_spi_runtime_suspend
(
struct
device
*
dev
)
{
struct
spi_
master
*
maste
r
=
dev_get_drvdata
(
dev
);
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctl
r
=
dev_get_drvdata
(
dev
);
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
clk_disable_unprepare
(
rs
->
spiclk
);
clk_disable_unprepare
(
rs
->
apb_pclk
);
...
...
@@ -821,8 +860,8 @@ static int rockchip_spi_runtime_suspend(struct device *dev)
static
int
rockchip_spi_runtime_resume
(
struct
device
*
dev
)
{
int
ret
;
struct
spi_
master
*
maste
r
=
dev_get_drvdata
(
dev
);
struct
rockchip_spi
*
rs
=
spi_
master_get_devdata
(
maste
r
);
struct
spi_
controller
*
ctl
r
=
dev_get_drvdata
(
dev
);
struct
rockchip_spi
*
rs
=
spi_
controller_get_devdata
(
ctl
r
);
ret
=
clk_prepare_enable
(
rs
->
apb_pclk
);
if
(
ret
<
0
)
...
...
drivers/spi/spi-sh-msiof.c
View file @
fb02b9eb
...
...
@@ -1398,7 +1398,7 @@ static int sh_msiof_spi_resume(struct device *dev)
static
SIMPLE_DEV_PM_OPS
(
sh_msiof_spi_pm_ops
,
sh_msiof_spi_suspend
,
sh_msiof_spi_resume
);
#define DEV_PM_OPS
&sh_msiof_spi_pm_ops
#define DEV_PM_OPS
(&sh_msiof_spi_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif
/* CONFIG_PM_SLEEP */
...
...
drivers/spi/spi-sprd-adi.c
View file @
fb02b9eb
...
...
@@ -319,7 +319,7 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr,
static
void
sprd_adi_set_wdt_rst_mode
(
struct
sprd_adi
*
sadi
)
{
#if
def CONFIG_SPRD_WATCHDOG
#if
IS_ENABLED(CONFIG_SPRD_WATCHDOG)
u32
val
;
/* Set default watchdog reboot mode */
...
...
drivers/spi/spi-stm32-qspi.c
View file @
fb02b9eb
...
...
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/sizes.h>
...
...
@@ -87,6 +88,7 @@
#define STM32_BUSY_TIMEOUT_US 100000
#define STM32_ABT_TIMEOUT_US 100000
#define STM32_COMP_TIMEOUT_MS 1000
#define STM32_AUTOSUSPEND_DELAY -1
struct
stm32_qspi_flash
{
struct
stm32_qspi
*
qspi
;
...
...
@@ -431,10 +433,17 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
struct
stm32_qspi
*
qspi
=
spi_controller_get_devdata
(
mem
->
spi
->
master
);
int
ret
;
ret
=
pm_runtime_get_sync
(
qspi
->
dev
);
if
(
ret
<
0
)
return
ret
;
mutex_lock
(
&
qspi
->
lock
);
ret
=
stm32_qspi_send
(
mem
,
op
);
mutex_unlock
(
&
qspi
->
lock
);
pm_runtime_mark_last_busy
(
qspi
->
dev
);
pm_runtime_put_autosuspend
(
qspi
->
dev
);
return
ret
;
}
...
...
@@ -444,6 +453,7 @@ static int stm32_qspi_setup(struct spi_device *spi)
struct
stm32_qspi
*
qspi
=
spi_controller_get_devdata
(
ctrl
);
struct
stm32_qspi_flash
*
flash
;
u32
presc
;
int
ret
;
if
(
ctrl
->
busy
)
return
-
EBUSY
;
...
...
@@ -451,6 +461,10 @@ static int stm32_qspi_setup(struct spi_device *spi)
if
(
!
spi
->
max_speed_hz
)
return
-
EINVAL
;
ret
=
pm_runtime_get_sync
(
qspi
->
dev
);
if
(
ret
<
0
)
return
ret
;
presc
=
DIV_ROUND_UP
(
qspi
->
clk_rate
,
spi
->
max_speed_hz
)
-
1
;
flash
=
&
qspi
->
flash
[
spi
->
chip_select
];
...
...
@@ -467,6 +481,9 @@ static int stm32_qspi_setup(struct spi_device *spi)
writel_relaxed
(
qspi
->
dcr_reg
,
qspi
->
io_base
+
QSPI_DCR
);
mutex_unlock
(
&
qspi
->
lock
);
pm_runtime_mark_last_busy
(
qspi
->
dev
);
pm_runtime_put_autosuspend
(
qspi
->
dev
);
return
0
;
}
...
...
@@ -538,10 +555,15 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = {
static
void
stm32_qspi_release
(
struct
stm32_qspi
*
qspi
)
{
pm_runtime_get_sync
(
qspi
->
dev
);
/* disable qspi */
writel_relaxed
(
0
,
qspi
->
io_base
+
QSPI_CR
);
stm32_qspi_dma_free
(
qspi
);
mutex_destroy
(
&
qspi
->
lock
);
pm_runtime_put_noidle
(
qspi
->
dev
);
pm_runtime_disable
(
qspi
->
dev
);
pm_runtime_set_suspended
(
qspi
->
dev
);
pm_runtime_dont_use_autosuspend
(
qspi
->
dev
);
clk_disable_unprepare
(
qspi
->
clk
);
}
...
...
@@ -643,9 +665,20 @@ static int stm32_qspi_probe(struct platform_device *pdev)
ctrl
->
num_chipselect
=
STM32_QSPI_MAX_NORCHIP
;
ctrl
->
dev
.
of_node
=
dev
->
of_node
;
pm_runtime_set_autosuspend_delay
(
dev
,
STM32_AUTOSUSPEND_DELAY
);
pm_runtime_use_autosuspend
(
dev
);
pm_runtime_set_active
(
dev
);
pm_runtime_enable
(
dev
);
pm_runtime_get_noresume
(
dev
);
ret
=
devm_spi_register_master
(
dev
,
ctrl
);
if
(
!
ret
)
return
0
;
if
(
ret
)
goto
err_qspi_release
;
pm_runtime_mark_last_busy
(
dev
);
pm_runtime_put_autosuspend
(
dev
);
return
0
;
err_qspi_release:
stm32_qspi_release
(
qspi
);
...
...
@@ -660,14 +693,28 @@ static int stm32_qspi_remove(struct platform_device *pdev)
struct
stm32_qspi
*
qspi
=
platform_get_drvdata
(
pdev
);
stm32_qspi_release
(
qspi
);
return
0
;
}
static
int
__maybe_unused
stm32_qspi_suspend
(
struct
device
*
dev
)
static
int
__maybe_unused
stm32_qspi_
runtime_
suspend
(
struct
device
*
dev
)
{
struct
stm32_qspi
*
qspi
=
dev_get_drvdata
(
dev
);
clk_disable_unprepare
(
qspi
->
clk
);
return
0
;
}
static
int
__maybe_unused
stm32_qspi_runtime_resume
(
struct
device
*
dev
)
{
struct
stm32_qspi
*
qspi
=
dev_get_drvdata
(
dev
);
return
clk_prepare_enable
(
qspi
->
clk
);
}
static
int
__maybe_unused
stm32_qspi_suspend
(
struct
device
*
dev
)
{
pinctrl_pm_select_sleep_state
(
dev
);
return
0
;
...
...
@@ -683,10 +730,17 @@ static int __maybe_unused stm32_qspi_resume(struct device *dev)
writel_relaxed
(
qspi
->
cr_reg
,
qspi
->
io_base
+
QSPI_CR
);
writel_relaxed
(
qspi
->
dcr_reg
,
qspi
->
io_base
+
QSPI_DCR
);
pm_runtime_mark_last_busy
(
qspi
->
dev
);
pm_runtime_put_autosuspend
(
qspi
->
dev
);
return
0
;
}
static
SIMPLE_DEV_PM_OPS
(
stm32_qspi_pm_ops
,
stm32_qspi_suspend
,
stm32_qspi_resume
);
static
const
struct
dev_pm_ops
stm32_qspi_pm_ops
=
{
SET_RUNTIME_PM_OPS
(
stm32_qspi_runtime_suspend
,
stm32_qspi_runtime_resume
,
NULL
)
SET_SYSTEM_SLEEP_PM_OPS
(
stm32_qspi_suspend
,
stm32_qspi_resume
)
};
static
const
struct
of_device_id
stm32_qspi_match
[]
=
{
{.
compatible
=
"st,stm32f469-qspi"
},
...
...
drivers/spi/spi-stm32.c
View file @
fb02b9eb
...
...
@@ -811,7 +811,9 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
mask
|=
STM32F4_SPI_SR_TXE
;
}
if
(
!
spi
->
cur_usedma
&&
spi
->
cur_comm
==
SPI_FULL_DUPLEX
)
{
if
(
!
spi
->
cur_usedma
&&
(
spi
->
cur_comm
==
SPI_FULL_DUPLEX
||
spi
->
cur_comm
==
SPI_SIMPLEX_RX
||
spi
->
cur_comm
==
SPI_3WIRE_RX
))
{
/* TXE flag is set and is handled when RXNE flag occurs */
sr
&=
~
STM32F4_SPI_SR_TXE
;
mask
|=
STM32F4_SPI_SR_RXNE
|
STM32F4_SPI_SR_OVR
;
...
...
@@ -850,7 +852,7 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
stm32f4_spi_read_rx
(
spi
);
if
(
spi
->
rx_len
==
0
)
end
=
true
;
else
/* Load data for discontinuous mode */
else
if
(
spi
->
tx_buf
)
/* Load data for discontinuous mode */
stm32f4_spi_write_tx
(
spi
);
}
...
...
@@ -1151,7 +1153,9 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi)
/* Enable the interrupts relative to the current communication mode */
if
(
spi
->
cur_comm
==
SPI_SIMPLEX_TX
||
spi
->
cur_comm
==
SPI_3WIRE_TX
)
{
cr2
|=
STM32F4_SPI_CR2_TXEIE
;
}
else
if
(
spi
->
cur_comm
==
SPI_FULL_DUPLEX
)
{
}
else
if
(
spi
->
cur_comm
==
SPI_FULL_DUPLEX
||
spi
->
cur_comm
==
SPI_SIMPLEX_RX
||
spi
->
cur_comm
==
SPI_3WIRE_RX
)
{
/* In transmit-only mode, the OVR flag is set in the SR register
* since the received data are never read. Therefore set OVR
* interrupt only when rx buffer is available.
...
...
@@ -1462,10 +1466,16 @@ static int stm32f4_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
stm32_spi_set_bits
(
spi
,
STM32F4_SPI_CR1
,
STM32F4_SPI_CR1_BIDIMODE
|
STM32F4_SPI_CR1_BIDIOE
);
}
else
if
(
comm_type
==
SPI_FULL_DUPLEX
)
{
}
else
if
(
comm_type
==
SPI_FULL_DUPLEX
||
comm_type
==
SPI_SIMPLEX_RX
)
{
stm32_spi_clr_bits
(
spi
,
STM32F4_SPI_CR1
,
STM32F4_SPI_CR1_BIDIMODE
|
STM32F4_SPI_CR1_BIDIOE
);
}
else
if
(
comm_type
==
SPI_3WIRE_RX
)
{
stm32_spi_set_bits
(
spi
,
STM32F4_SPI_CR1
,
STM32F4_SPI_CR1_BIDIMODE
);
stm32_spi_clr_bits
(
spi
,
STM32F4_SPI_CR1
,
STM32F4_SPI_CR1_BIDIOE
);
}
else
{
return
-
EINVAL
;
}
...
...
@@ -1906,6 +1916,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
master
->
prepare_message
=
stm32_spi_prepare_msg
;
master
->
transfer_one
=
stm32_spi_transfer_one
;
master
->
unprepare_message
=
stm32_spi_unprepare_msg
;
master
->
flags
=
SPI_MASTER_MUST_TX
;
spi
->
dma_tx
=
dma_request_chan
(
spi
->
dev
,
"tx"
);
if
(
IS_ERR
(
spi
->
dma_tx
))
{
...
...
drivers/spi/spi-sun6i.c
View file @
fb02b9eb
...
...
@@ -470,6 +470,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
master
->
max_speed_hz
=
100
*
1000
*
1000
;
master
->
min_speed_hz
=
3
*
1000
;
master
->
use_gpio_descriptors
=
true
;
master
->
set_cs
=
sun6i_spi_set_cs
;
master
->
transfer_one
=
sun6i_spi_transfer_one
;
master
->
num_chipselect
=
4
;
...
...
drivers/spi/spi-tegra114.c
View file @
fb02b9eb
...
...
@@ -1398,6 +1398,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
ret
=
pm_runtime_get_sync
(
&
pdev
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"pm runtime get failed, e = %d
\n
"
,
ret
);
pm_runtime_put_noidle
(
&
pdev
->
dev
);
goto
exit_pm_disable
;
}
...
...
drivers/spi/spi-tegra20-sflash.c
View file @
fb02b9eb
...
...
@@ -491,6 +491,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
ret
=
pm_runtime_get_sync
(
&
pdev
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"pm runtime get failed, e = %d
\n
"
,
ret
);
pm_runtime_put_noidle
(
&
pdev
->
dev
);
goto
exit_pm_disable
;
}
...
...
drivers/spi/spi-tegra20-slink.c
View file @
fb02b9eb
...
...
@@ -1118,6 +1118,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
ret
=
pm_runtime_get_sync
(
&
pdev
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"pm runtime get failed, e = %d
\n
"
,
ret
);
pm_runtime_put_noidle
(
&
pdev
->
dev
);
goto
exit_pm_disable
;
}
tspi
->
def_command_reg
=
SLINK_M_S
;
...
...
drivers/spi/spi-uniphier.c
View file @
fb02b9eb
...
...
@@ -659,8 +659,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
priv
->
master
=
master
;
priv
->
is_save_param
=
false
;
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
priv
->
base
=
devm_ioremap_resource
(
&
pdev
->
dev
,
res
);
priv
->
base
=
devm_platform_get_and_ioremap_resource
(
pdev
,
0
,
&
res
);
if
(
IS_ERR
(
priv
->
base
))
{
ret
=
PTR_ERR
(
priv
->
base
);
goto
out_master_put
;
...
...
@@ -716,8 +715,10 @@ static int uniphier_spi_probe(struct platform_device *pdev)
master
->
dma_tx
=
dma_request_chan
(
&
pdev
->
dev
,
"tx"
);
if
(
IS_ERR_OR_NULL
(
master
->
dma_tx
))
{
if
(
PTR_ERR
(
master
->
dma_tx
)
==
-
EPROBE_DEFER
)
if
(
PTR_ERR
(
master
->
dma_tx
)
==
-
EPROBE_DEFER
)
{
ret
=
-
EPROBE_DEFER
;
goto
out_disable_clk
;
}
master
->
dma_tx
=
NULL
;
dma_tx_burst
=
INT_MAX
;
}
else
{
...
...
@@ -732,8 +733,10 @@ static int uniphier_spi_probe(struct platform_device *pdev)
master
->
dma_rx
=
dma_request_chan
(
&
pdev
->
dev
,
"rx"
);
if
(
IS_ERR_OR_NULL
(
master
->
dma_rx
))
{
if
(
PTR_ERR
(
master
->
dma_rx
)
==
-
EPROBE_DEFER
)
if
(
PTR_ERR
(
master
->
dma_rx
)
==
-
EPROBE_DEFER
)
{
ret
=
-
EPROBE_DEFER
;
goto
out_disable_clk
;
}
master
->
dma_rx
=
NULL
;
dma_rx_burst
=
INT_MAX
;
}
else
{
...
...
drivers/spi/spi.c
View file @
fb02b9eb
...
...
@@ -1023,7 +1023,8 @@ static int spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
void
*
tmp
;
unsigned
int
max_tx
,
max_rx
;
if
(
ctlr
->
flags
&
(
SPI_CONTROLLER_MUST_RX
|
SPI_CONTROLLER_MUST_TX
))
{
if
((
ctlr
->
flags
&
(
SPI_CONTROLLER_MUST_RX
|
SPI_CONTROLLER_MUST_TX
))
&&
!
(
msg
->
spi
->
mode
&
SPI_3WIRE
))
{
max_tx
=
0
;
max_rx
=
0
;
...
...
@@ -1075,7 +1076,7 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
{
struct
spi_statistics
*
statm
=
&
ctlr
->
statistics
;
struct
spi_statistics
*
stats
=
&
msg
->
spi
->
statistics
;
unsigned
long
long
ms
=
1
;
unsigned
long
long
ms
;
if
(
spi_controller_is_slave
(
ctlr
))
{
if
(
wait_for_completion_interruptible
(
&
ctlr
->
xfer_completion
))
{
...
...
@@ -1160,6 +1161,8 @@ int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer)
{
int
delay
;
might_sleep
();
if
(
!
_delay
)
return
-
EINVAL
;
...
...
@@ -3855,8 +3858,7 @@ static u8 *buf;
* is zero for success, else a negative errno status code.
* This call may only be used from a context that may sleep.
*
* Parameters to this routine are always copied using a small buffer;
* portable code should never use this for more than 32 bytes.
* Parameters to this routine are always copied using a small buffer.
* Performance-sensitive or bulk transfer code should instead use
* spi_{async,sync}() calls with dma-safe buffers.
*
...
...
drivers/spi/spidev.c
View file @
fb02b9eb
...
...
@@ -62,7 +62,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
| SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
| SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)
| SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
| SPI_RX_QUAD | SPI_RX_OCTAL)
struct
spidev_data
{
dev_t
devt
;
...
...
tools/spi/Makefile
View file @
fb02b9eb
...
...
@@ -52,7 +52,9 @@ $(OUTPUT)spidev_fdx: $(SPIDEV_FDX_IN)
clean
:
rm
-f
$(ALL_PROGRAMS)
rm
-rf
$(OUTPUT)
include/
find
$(
if
$(OUTPUT)
,
$(OUTPUT)
,.
)
-name
'*.o'
-delete
-o
-name
'\.*.d'
-delete
find
$(
if
$(OUTPUT)
,
$(OUTPUT)
,.
)
-name
'*.o'
-delete
find
$(
if
$(OUTPUT)
,
$(OUTPUT)
,.
)
-name
'\.*.o.d'
-delete
find
$(
if
$(OUTPUT)
,
$(OUTPUT)
,.
)
-name
'\.*.o.cmd'
-delete
install
:
$(ALL_PROGRAMS)
install
-d
-m
755
$(DESTDIR)$(bindir)
;
\
...
...
tools/spi/spidev_test.c
View file @
fb02b9eb
...
...
@@ -128,18 +128,22 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
.
bits_per_word
=
bits
,
};
if
(
mode
&
SPI_TX_QUAD
)
if
(
mode
&
SPI_TX_OCTAL
)
tr
.
tx_nbits
=
8
;
else
if
(
mode
&
SPI_TX_QUAD
)
tr
.
tx_nbits
=
4
;
else
if
(
mode
&
SPI_TX_DUAL
)
tr
.
tx_nbits
=
2
;
if
(
mode
&
SPI_RX_QUAD
)
if
(
mode
&
SPI_RX_OCTAL
)
tr
.
rx_nbits
=
8
;
else
if
(
mode
&
SPI_RX_QUAD
)
tr
.
rx_nbits
=
4
;
else
if
(
mode
&
SPI_RX_DUAL
)
tr
.
rx_nbits
=
2
;
if
(
!
(
mode
&
SPI_LOOP
))
{
if
(
mode
&
(
SPI_TX_QUAD
|
SPI_TX_DUAL
))
if
(
mode
&
(
SPI_TX_
OCTAL
|
SPI_TX_
QUAD
|
SPI_TX_DUAL
))
tr
.
rx_buf
=
0
;
else
if
(
mode
&
(
SPI_RX_QUAD
|
SPI_RX_DUAL
))
else
if
(
mode
&
(
SPI_RX_
OCTAL
|
SPI_RX_
QUAD
|
SPI_RX_DUAL
))
tr
.
tx_buf
=
0
;
}
...
...
@@ -187,6 +191,7 @@ static void print_usage(const char *prog)
" -R --ready slave pulls low to pause
\n
"
" -2 --dual dual transfer
\n
"
" -4 --quad quad transfer
\n
"
" -8 --octal octal transfer
\n
"
" -S --size transfer size
\n
"
" -I --iter iterations
\n
"
);
exit
(
1
);
...
...
@@ -213,13 +218,14 @@ static void parse_opts(int argc, char *argv[])
{
"dual"
,
0
,
0
,
'2'
},
{
"verbose"
,
0
,
0
,
'v'
},
{
"quad"
,
0
,
0
,
'4'
},
{
"octal"
,
0
,
0
,
'8'
},
{
"size"
,
1
,
0
,
'S'
},
{
"iter"
,
1
,
0
,
'I'
},
{
NULL
,
0
,
0
,
0
},
};
int
c
;
c
=
getopt_long
(
argc
,
argv
,
"D:s:d:b:i:o:lHOLC3NR24p:vS:I:"
,
c
=
getopt_long
(
argc
,
argv
,
"D:s:d:b:i:o:lHOLC3NR24
8
p:vS:I:"
,
lopts
,
NULL
);
if
(
c
==
-
1
)
...
...
@@ -280,6 +286,9 @@ static void parse_opts(int argc, char *argv[])
case
'4'
:
mode
|=
SPI_TX_QUAD
;
break
;
case
'8'
:
mode
|=
SPI_TX_OCTAL
;
break
;
case
'S'
:
transfer_size
=
atoi
(
optarg
);
break
;
...
...
@@ -295,6 +304,8 @@ static void parse_opts(int argc, char *argv[])
mode
|=
SPI_RX_DUAL
;
if
(
mode
&
SPI_TX_QUAD
)
mode
|=
SPI_RX_QUAD
;
if
(
mode
&
SPI_TX_OCTAL
)
mode
|=
SPI_RX_OCTAL
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment