mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-08 14:13:53 +00:00
Merge remote-tracking branch 'spi/for-6.3' into spi-next
This commit is contained in:
commit
de82c25dab
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Allwinner A10 SPI Controller
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml"
|
||||
- $ref: spi-controller.yaml
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Allwinner A31 SPI Controller
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml"
|
||||
- $ref: spi-controller.yaml
|
||||
|
||||
maintainers:
|
||||
- Chen-Yu Tsai <wens@csie.org>
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright 2019 BayLibre, SAS
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/spi/amlogic,meson-gx-spicc.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/spi/amlogic,meson-gx-spicc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic Meson SPI Communication Controller
|
||||
|
||||
@ -41,7 +41,7 @@ properties:
|
||||
maxItems: 2
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
@ -100,17 +100,17 @@ unevaluatedProperties: false
|
||||
examples:
|
||||
- |
|
||||
spi@c1108d80 {
|
||||
compatible = "amlogic,meson-gx-spicc";
|
||||
reg = <0xc1108d80 0x80>;
|
||||
interrupts = <112>;
|
||||
clocks = <&clk81>;
|
||||
clock-names = "core";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "amlogic,meson-gx-spicc";
|
||||
reg = <0xc1108d80 0x80>;
|
||||
interrupts = <112>;
|
||||
clocks = <&clk81>;
|
||||
clock-names = "core";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
display@0 {
|
||||
compatible = "lg,lg4573";
|
||||
spi-max-frequency = <1000000>;
|
||||
reg = <0>;
|
||||
};
|
||||
display@0 {
|
||||
compatible = "lg,lg4573";
|
||||
spi-max-frequency = <1000000>;
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright 2019 BayLibre, SAS
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/spi/amlogic,meson6-spifc.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/spi/amlogic,meson6-spifc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic Meson SPI Flash Controller
|
||||
|
||||
@ -11,7 +11,7 @@ maintainers:
|
||||
- Neil Armstrong <neil.armstrong@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
description: |
|
||||
The Meson SPIFC is a controller optimized for communication with SPI
|
||||
@ -40,15 +40,15 @@ unevaluatedProperties: false
|
||||
examples:
|
||||
- |
|
||||
spi@c1108c80 {
|
||||
compatible = "amlogic,meson6-spifc";
|
||||
reg = <0xc1108c80 0x80>;
|
||||
clocks = <&clk81>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "amlogic,meson6-spifc";
|
||||
reg = <0xc1108c80 0x80>;
|
||||
clocks = <&clk81>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
flash: flash@0 {
|
||||
compatible = "spansion,m25p80", "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <40000000>;
|
||||
};
|
||||
flash: flash@0 {
|
||||
compatible = "spansion,m25p80", "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <40000000>;
|
||||
};
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ description: |
|
||||
SPI) of the AST2400, AST2500 and AST2600 SOCs.
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -60,23 +60,23 @@ examples:
|
||||
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
flash@0 {
|
||||
reg = < 0 >;
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <50000000>;
|
||||
spi-rx-bus-width = <2>;
|
||||
reg = < 0 >;
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <50000000>;
|
||||
spi-rx-bus-width = <2>;
|
||||
};
|
||||
|
||||
flash@1 {
|
||||
reg = < 1 >;
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <50000000>;
|
||||
spi-rx-bus-width = <2>;
|
||||
reg = < 1 >;
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <50000000>;
|
||||
spi-rx-bus-width = <2>;
|
||||
};
|
||||
|
||||
flash@2 {
|
||||
reg = < 2 >;
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <50000000>;
|
||||
spi-rx-bus-width = <2>;
|
||||
reg = < 2 >;
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <50000000>;
|
||||
spi-rx-bus-width = <2>;
|
||||
};
|
||||
};
|
||||
|
134
Documentation/devicetree/bindings/spi/brcm,bcm63xx-hsspi.yaml
Normal file
134
Documentation/devicetree/bindings/spi/brcm,bcm63xx-hsspi.yaml
Normal file
@ -0,0 +1,134 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/brcm,bcm63xx-hsspi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Broadcom Broadband SoC High Speed SPI controller
|
||||
|
||||
maintainers:
|
||||
- William Zhang <william.zhang@broadcom.com>
|
||||
- Kursad Oney <kursad.oney@broadcom.com>
|
||||
- Jonas Gorski <jonas.gorski@gmail.com>
|
||||
|
||||
description: |
|
||||
Broadcom Broadband SoC supports High Speed SPI master controller since the
|
||||
early MIPS based chips such as BCM6328 and BCM63268. This initial rev 1.0
|
||||
controller was carried over to recent ARM based chips, such as BCM63138,
|
||||
BCM4908 and BCM6858. The old MIPS based chip should continue to use the
|
||||
brcm,bcm6328-hsspi compatible string. The recent ARM based chip is required to
|
||||
use the brcm,bcmbca-hsspi-v1.0 as part of its compatible string list as
|
||||
defined below to match the specific chip along with ip revision info.
|
||||
|
||||
This rev 1.0 controller has a limitation that can not keep the chip select line
|
||||
active between the SPI transfers within the same SPI message. This can
|
||||
terminate the transaction to some SPI devices prematurely. The issue can be
|
||||
worked around by either the controller's prepend mode or using the dummy chip
|
||||
select workaround. Driver automatically picks the suitable mode based on
|
||||
transfer type so it is transparent to the user.
|
||||
|
||||
The newer SoCs such as BCM6756, BCM4912 and BCM6855 include an updated SPI
|
||||
controller rev 1.1 that add the capability to allow the driver to control chip
|
||||
select explicitly. This solves the issue in the old controller.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: brcm,bcm6328-hsspi
|
||||
- items:
|
||||
- enum:
|
||||
- brcm,bcm47622-hsspi
|
||||
- brcm,bcm4908-hsspi
|
||||
- brcm,bcm63138-hsspi
|
||||
- brcm,bcm63146-hsspi
|
||||
- brcm,bcm63148-hsspi
|
||||
- brcm,bcm63158-hsspi
|
||||
- brcm,bcm63178-hsspi
|
||||
- brcm,bcm6846-hsspi
|
||||
- brcm,bcm6856-hsspi
|
||||
- brcm,bcm6858-hsspi
|
||||
- brcm,bcm6878-hsspi
|
||||
- const: brcm,bcmbca-hsspi-v1.0
|
||||
- items:
|
||||
- enum:
|
||||
- brcm,bcm4912-hsspi
|
||||
- brcm,bcm6756-hsspi
|
||||
- brcm,bcm6813-hsspi
|
||||
- brcm,bcm6855-hsspi
|
||||
- const: brcm,bcmbca-hsspi-v1.1
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: main registers
|
||||
- description: miscellaneous control registers
|
||||
minItems: 1
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: hsspi
|
||||
- const: spim-ctrl
|
||||
minItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: SPI master reference clock
|
||||
- description: SPI master pll clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: hsspi
|
||||
- const: pll
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: spi-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- brcm,bcm6328-hsspi
|
||||
- brcm,bcmbca-hsspi-v1.0
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
reg-names:
|
||||
maxItems: 1
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
reg-names:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
required:
|
||||
- reg-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
spi@ff801000 {
|
||||
compatible = "brcm,bcm6756-hsspi", "brcm,bcmbca-hsspi-v1.1";
|
||||
reg = <0xff801000 0x1000>,
|
||||
<0xff802610 0x4>;
|
||||
reg-names = "hsspi", "spim-ctrl";
|
||||
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&hsspi>, <&hsspi_pll>;
|
||||
clock-names = "hsspi", "pll";
|
||||
num-cs = <8>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
@ -99,98 +99,98 @@ required:
|
||||
examples:
|
||||
- | # BRCMSTB SoC: SPI Master (MSPI+BSPI) for SPI-NOR access
|
||||
spi@f03e3400 {
|
||||
compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-bcm-qspi";
|
||||
reg = <0xf03e3400 0x188>, <0xf03e3200 0x50>, <0xf03e0920 0x4>;
|
||||
reg-names = "mspi", "bspi", "cs_reg";
|
||||
interrupts = <0x5>, <0x6>, <0x1>, <0x2>, <0x3>, <0x4>, <0x0>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupt-names = "mspi_done",
|
||||
"mspi_halted",
|
||||
"spi_lr_fullness_reached",
|
||||
"spi_lr_session_aborted",
|
||||
"spi_lr_impatient",
|
||||
"spi_lr_session_done",
|
||||
"spi_lr_overread";
|
||||
clocks = <&hif_spi>;
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x0>;
|
||||
compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-bcm-qspi";
|
||||
reg = <0xf03e3400 0x188>, <0xf03e3200 0x50>, <0xf03e0920 0x4>;
|
||||
reg-names = "mspi", "bspi", "cs_reg";
|
||||
interrupts = <0x5>, <0x6>, <0x1>, <0x2>, <0x3>, <0x4>, <0x0>;
|
||||
interrupt-parent = <&gic>;
|
||||
interrupt-names = "mspi_done",
|
||||
"mspi_halted",
|
||||
"spi_lr_fullness_reached",
|
||||
"spi_lr_session_aborted",
|
||||
"spi_lr_impatient",
|
||||
"spi_lr_session_done",
|
||||
"spi_lr_overread";
|
||||
clocks = <&hif_spi>;
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x0>;
|
||||
|
||||
flash@0 {
|
||||
#size-cells = <0x2>;
|
||||
#address-cells = <0x2>;
|
||||
compatible = "m25p80";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <0x2625a00>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
};
|
||||
flash@0 {
|
||||
#size-cells = <0x2>;
|
||||
#address-cells = <0x2>;
|
||||
compatible = "m25p80";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <0x2625a00>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
};
|
||||
};
|
||||
- | # BRCMSTB SoC: MSPI master for any SPI device
|
||||
spi@f0416000 {
|
||||
clocks = <&upg_fixed>;
|
||||
compatible = "brcm,spi-brcmstb-mspi", "brcm,spi-bcm-qspi";
|
||||
reg = <0xf0416000 0x180>;
|
||||
reg-names = "mspi";
|
||||
interrupts = <0x14>;
|
||||
interrupt-parent = <&irq0_aon_intc>;
|
||||
interrupt-names = "mspi_done";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&upg_fixed>;
|
||||
compatible = "brcm,spi-brcmstb-mspi", "brcm,spi-bcm-qspi";
|
||||
reg = <0xf0416000 0x180>;
|
||||
reg-names = "mspi";
|
||||
interrupts = <0x14>;
|
||||
interrupt-parent = <&irq0_aon_intc>;
|
||||
interrupt-names = "mspi_done";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
- | # iProc SoC
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
spi@18027200 {
|
||||
compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi";
|
||||
reg = <0x18027200 0x184>,
|
||||
<0x18027000 0x124>,
|
||||
<0x1811c408 0x004>,
|
||||
<0x180273a0 0x01c>;
|
||||
reg-names = "mspi", "bspi", "intr_regs", "intr_status_reg";
|
||||
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "mspi_done",
|
||||
"mspi_halted",
|
||||
"spi_lr_fullness_reached",
|
||||
"spi_lr_session_aborted",
|
||||
"spi_lr_impatient",
|
||||
"spi_lr_session_done";
|
||||
clocks = <&iprocmed>;
|
||||
num-cs = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "brcm,spi-nsp-qspi", "brcm,spi-bcm-qspi";
|
||||
reg = <0x18027200 0x184>,
|
||||
<0x18027000 0x124>,
|
||||
<0x1811c408 0x004>,
|
||||
<0x180273a0 0x01c>;
|
||||
reg-names = "mspi", "bspi", "intr_regs", "intr_status_reg";
|
||||
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "mspi_done",
|
||||
"mspi_halted",
|
||||
"spi_lr_fullness_reached",
|
||||
"spi_lr_session_aborted",
|
||||
"spi_lr_impatient",
|
||||
"spi_lr_session_done";
|
||||
clocks = <&iprocmed>;
|
||||
num-cs = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
- | # NS2 SoC
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
spi@66470200 {
|
||||
compatible = "brcm,spi-ns2-qspi", "brcm,spi-bcm-qspi";
|
||||
reg = <0x66470200 0x184>,
|
||||
<0x66470000 0x124>,
|
||||
<0x67017408 0x004>,
|
||||
<0x664703a0 0x01c>;
|
||||
reg-names = "mspi", "bspi", "intr_regs", "intr_status_reg";
|
||||
interrupts = <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "spi_l1_intr";
|
||||
clocks = <&iprocmed>;
|
||||
num-cs = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "brcm,spi-ns2-qspi", "brcm,spi-bcm-qspi";
|
||||
reg = <0x66470200 0x184>,
|
||||
<0x66470000 0x124>,
|
||||
<0x67017408 0x004>,
|
||||
<0x664703a0 0x01c>;
|
||||
reg-names = "mspi", "bspi", "intr_regs", "intr_status_reg";
|
||||
interrupts = <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "spi_l1_intr";
|
||||
clocks = <&iprocmed>;
|
||||
num-cs = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
flash@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "m25p80";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <12500000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
};
|
||||
flash@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "m25p80";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <12500000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
};
|
||||
};
|
||||
|
@ -47,7 +47,7 @@ properties:
|
||||
cdns,fifo-depth:
|
||||
description:
|
||||
Size of the data FIFO in words.
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [ 128, 256 ]
|
||||
default: 128
|
||||
|
||||
@ -103,21 +103,21 @@ unevaluatedProperties: false
|
||||
examples:
|
||||
- |
|
||||
qspi: spi@ff705000 {
|
||||
compatible = "cdns,qspi-nor";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0xff705000 0x1000>,
|
||||
<0xffa00000 0x1000>;
|
||||
interrupts = <0 151 4>;
|
||||
clocks = <&qspi_clk>;
|
||||
cdns,fifo-depth = <128>;
|
||||
cdns,fifo-width = <4>;
|
||||
cdns,trigger-address = <0x00000000>;
|
||||
resets = <&rst 0x1>, <&rst 0x2>;
|
||||
reset-names = "qspi", "qspi-ocp";
|
||||
compatible = "cdns,qspi-nor";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0xff705000 0x1000>,
|
||||
<0xffa00000 0x1000>;
|
||||
interrupts = <0 151 4>;
|
||||
clocks = <&qspi_clk>;
|
||||
cdns,fifo-depth = <128>;
|
||||
cdns,fifo-width = <4>;
|
||||
cdns,trigger-address = <0x00000000>;
|
||||
resets = <&rst 0x1>, <&rst 0x2>;
|
||||
reset-names = "qspi", "qspi-ocp";
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0x0>;
|
||||
};
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0x0>;
|
||||
};
|
||||
};
|
||||
|
@ -2,8 +2,8 @@
|
||||
# Copyright 2020-21 Cadence
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/spi/cdns,xspi.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/spi/cdns,xspi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cadence XSPI Controller
|
||||
|
||||
@ -16,7 +16,7 @@ description: |
|
||||
read/write access to slaves such as SPI-NOR flash.
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Han Xu <han.xu@nxp.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Shawn Guo <shawnguo@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/spi/spi-controller.yaml#"
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Leilk Liu <leilk.liu@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/spi/spi-controller.yaml#"
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -18,14 +18,12 @@ description: |
|
||||
using the accompanying ECC engine. There should be only one spi
|
||||
slave device following generic spi bindings.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt7622-snand
|
||||
- mediatek,mt7629-snand
|
||||
- mediatek,mt7986-snand
|
||||
|
||||
reg:
|
||||
items:
|
||||
@ -36,19 +34,20 @@ properties:
|
||||
- description: NFI interrupt
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: clock used for the controller
|
||||
- description: clock used for the SPI bus
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: nfi_clk
|
||||
- const: pad_clk
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
nand-ecc-engine:
|
||||
description: device-tree node of the accompanying ECC engine.
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
mediatek,rx-latch-latency-ns:
|
||||
description: Data read latch latency, unit is nanoseconds.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -57,6 +56,43 @@ required:
|
||||
- clock-names
|
||||
- nand-ecc-engine
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt7622-snand
|
||||
- mediatek,mt7629-snand
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: clock used for the controller
|
||||
- description: clock used for the SPI bus
|
||||
clock-names:
|
||||
items:
|
||||
- const: nfi_clk
|
||||
- const: pad_clk
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt7986-snand
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: clock used for the controller
|
||||
- description: clock used for the SPI bus
|
||||
- description: clock used for the AHB bus
|
||||
clock-names:
|
||||
items:
|
||||
- const: nfi_clk
|
||||
- const: pad_clk
|
||||
- const: nfi_hclk
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Leilk Liu <leilk.liu@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/spi/spi-controller.yaml#"
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -11,7 +11,7 @@ maintainers:
|
||||
- Bert Vermeulen <bert@biot.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Marek Vasut <marex@denx.de>
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/spi/spi-controller.yaml#"
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -11,7 +11,7 @@ maintainers:
|
||||
- Jonathan Hunter <jonathanh@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -74,25 +74,25 @@ examples:
|
||||
#include <dt-bindings/reset/tegra210-car.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
spi@70410000 {
|
||||
compatible = "nvidia,tegra210-qspi";
|
||||
reg = <0x70410000 0x1000>;
|
||||
interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car TEGRA210_CLK_QSPI>,
|
||||
<&tegra_car TEGRA210_CLK_QSPI_PM>;
|
||||
clock-names = "qspi", "qspi_out";
|
||||
resets = <&tegra_car 211>;
|
||||
dmas = <&apbdma 5>, <&apbdma 5>;
|
||||
dma-names = "rx", "tx";
|
||||
compatible = "nvidia,tegra210-qspi";
|
||||
reg = <0x70410000 0x1000>;
|
||||
interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&tegra_car TEGRA210_CLK_QSPI>,
|
||||
<&tegra_car TEGRA210_CLK_QSPI_PM>;
|
||||
clock-names = "qspi", "qspi_out";
|
||||
resets = <&tegra_car 211>;
|
||||
dmas = <&apbdma 5>, <&apbdma 5>;
|
||||
dma-names = "rx", "tx";
|
||||
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <104000000>;
|
||||
spi-tx-bus-width = <2>;
|
||||
spi-rx-bus-width = <2>;
|
||||
nvidia,tx-clk-tap-delay = <0>;
|
||||
nvidia,rx-clk-tap-delay = <0>;
|
||||
};
|
||||
flash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <104000000>;
|
||||
spi-tx-bus-width = <2>;
|
||||
spi-rx-bus-width = <2>;
|
||||
nvidia,tx-clk-tap-delay = <0>;
|
||||
nvidia,rx-clk-tap-delay = <0>;
|
||||
};
|
||||
};
|
||||
|
@ -1,9 +1,8 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/spi/qcom,spi-qcom-qspi.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/spi/qcom,spi-qcom-qspi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Quad Serial Peripheral Interface (QSPI)
|
||||
|
||||
@ -53,6 +52,11 @@ properties:
|
||||
- const: qspi-config
|
||||
- const: qspi-memory
|
||||
|
||||
operating-points-v2: true
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -88,7 +92,6 @@ examples:
|
||||
spi-tx-bus-width = <2>;
|
||||
spi-rx-bus-width = <2>;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -11,7 +11,7 @@ maintainers:
|
||||
- Birger Koblitz <mail@birger-koblitz.de>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -141,15 +141,15 @@ examples:
|
||||
#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>;
|
||||
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>;
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Mark Brown <broonie@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -1,33 +0,0 @@
|
||||
Binding for Broadcom BCM6328 High Speed SPI controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must contain of "brcm,bcm6328-hsspi".
|
||||
- reg: Base address and size of the controllers memory area.
|
||||
- interrupts: Interrupt for the SPI block.
|
||||
- clocks: phandles of the SPI clock and the PLL clock.
|
||||
- clock-names: must be "hsspi", "pll".
|
||||
- #address-cells: <1>, as required by generic SPI binding.
|
||||
- #size-cells: <0>, also as required by generic SPI binding.
|
||||
|
||||
Optional properties:
|
||||
- num-cs: some controllers have less than 8 cs signals. Defaults to 8
|
||||
if absent.
|
||||
|
||||
Child nodes as per the generic SPI binding.
|
||||
|
||||
Example:
|
||||
|
||||
spi@10001000 {
|
||||
compatible = "brcm,bcm6328-hsspi";
|
||||
reg = <0x10001000 0x600>;
|
||||
|
||||
interrupts = <29>;
|
||||
|
||||
clocks = <&clkctl 9>, <&hsspi_pll>;
|
||||
clock-names = "hsspi", "pll";
|
||||
|
||||
num-cs = <2>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Michal Simek <michal.simek@xilinx.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Anson Huang <Anson.Huang@nxp.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/spi/spi-controller.yaml#"
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -14,7 +14,7 @@ description:
|
||||
dedicated GPIO lines.
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/spi/spi-controller.yaml#"
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -41,7 +41,7 @@ properties:
|
||||
num-chipselects:
|
||||
description: Number of chipselect lines. Should be <0> if a single device
|
||||
with no chip select is connected.
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
# Deprecated properties
|
||||
gpio-sck: false
|
||||
|
@ -30,8 +30,8 @@ description: |
|
||||
+------------+
|
||||
|
||||
allOf:
|
||||
- $ref: "/schemas/spi/spi-controller.yaml#"
|
||||
- $ref: "/schemas/spi/spi-peripheral-props.yaml#"
|
||||
- $ref: /schemas/spi/spi-controller.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
maintainers:
|
||||
- Chris Packham <chris.packham@alliedtelesis.co.nz>
|
||||
|
@ -11,7 +11,7 @@ maintainers:
|
||||
- Kuldeep Singh <singh.kuldeep87k@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -49,6 +49,16 @@ properties:
|
||||
Delay in nanoseconds to be introduced by the controller after CS is
|
||||
asserted.
|
||||
|
||||
spi-cs-hold-delay-ns:
|
||||
description:
|
||||
Delay in nanoseconds to be introduced by the controller before CS is
|
||||
de-asserted.
|
||||
|
||||
spi-cs-inactive-delay-ns:
|
||||
description:
|
||||
Delay in nanoseconds to be introduced by the controller after CS is
|
||||
de-asserted.
|
||||
|
||||
spi-rx-bus-width:
|
||||
description:
|
||||
Bus width to the SPI bus used for read transfers.
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Linus Walleij <linus.walleij@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
# We need a select here so we don't match all nodes with 'arm,primecell'
|
||||
select:
|
||||
@ -45,7 +45,7 @@ properties:
|
||||
description: delay in ms following transfer completion before the
|
||||
runtime power management system suspends the device. A setting of 0
|
||||
indicates no delay and the device will be suspended immediately.
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
pl022,rt:
|
||||
description: indicates the controller should run the message pump with realtime
|
||||
@ -81,7 +81,7 @@ patternProperties:
|
||||
properties:
|
||||
pl022,interface:
|
||||
description: SPI interface type
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 0 # SPI
|
||||
- 1 # Texas Instruments Synchronous Serial Frame Format
|
||||
@ -89,7 +89,7 @@ patternProperties:
|
||||
|
||||
pl022,com-mode:
|
||||
description: Specifies the transfer mode
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 0 # interrupt mode
|
||||
- 1 # polling mode
|
||||
@ -98,30 +98,30 @@ patternProperties:
|
||||
|
||||
pl022,rx-level-trig:
|
||||
description: Rx FIFO watermark level
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 4
|
||||
|
||||
pl022,tx-level-trig:
|
||||
description: Tx FIFO watermark level
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 4
|
||||
|
||||
pl022,ctrl-len:
|
||||
description: Microwire interface - Control length
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0x03
|
||||
maximum: 0x1f
|
||||
|
||||
pl022,wait-state:
|
||||
description: Microwire interface - Wait state
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
|
||||
pl022,duplex:
|
||||
description: Microwire interface - Full/Half duplex
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
|
||||
required:
|
||||
|
@ -11,7 +11,7 @@ description:
|
||||
as flash and display controllers using the SPI communication interface.
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
@ -12,7 +12,7 @@ maintainers:
|
||||
- Palmer Dabbelt <palmer@sifive.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -51,14 +51,14 @@ properties:
|
||||
sifive,fifo-depth:
|
||||
description:
|
||||
Depth of hardware queues; defaults to 8
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [8]
|
||||
default: 8
|
||||
|
||||
sifive,max-bits-per-word:
|
||||
description:
|
||||
Maximum bits per word; defaults to 8
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7, 8]
|
||||
default: 8
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
STMicroelectronics SSC (SPI) Controller
|
||||
---------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : "st,comms-ssc4-spi"
|
||||
- reg : Offset and length of the device's register set
|
||||
- interrupts : The interrupt specifier
|
||||
- clock-names : Must contain "ssc"
|
||||
- clocks : Must contain an entry for each name in clock-names
|
||||
See ../clk/*
|
||||
- pinctrl-names : Uses "default", can use "sleep" if provided
|
||||
See ../pinctrl/pinctrl-bindings.txt
|
||||
|
||||
Optional properties:
|
||||
- cs-gpios : List of GPIO chip selects
|
||||
See ../spi/spi-bus.txt
|
||||
|
||||
Child nodes represent devices on the SPI bus
|
||||
See ../spi/spi-bus.txt
|
||||
|
||||
Example:
|
||||
spi@9840000 {
|
||||
compatible = "st,comms-ssc4-spi";
|
||||
reg = <0x9840000 0x110>;
|
||||
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
|
||||
clock-names = "ssc";
|
||||
pinctrl-0 = <&pinctrl_spi0_default>;
|
||||
pinctrl-names = "default";
|
||||
cs-gpios = <&pio17 5 0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
st95hf@0{
|
||||
compatible = "st,st95hf";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: Sunplus sp7021 SPI controller
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml"
|
||||
- $ref: spi-controller.yaml
|
||||
|
||||
maintainers:
|
||||
- Li-hao Kuo <lhjeff911@gmail.com>
|
||||
@ -59,9 +59,9 @@ unevaluatedProperties: false
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
spi@9C002D80 {
|
||||
spi@9c002d80 {
|
||||
compatible = "sunplus,sp7021-spi";
|
||||
reg = <0x9C002D80 0x80>, <0x9C002E00 0x80>;
|
||||
reg = <0x9c002d80 0x80>, <0x9c002e00 0x80>;
|
||||
reg-names = "master", "slave";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupt-names = "dma_w",
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Michal Simek <michal.simek@xilinx.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -10,7 +10,7 @@ maintainers:
|
||||
- Michal Simek <michal.simek@xilinx.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -1,9 +1,8 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/spi/sprd,spi-adi.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
$id: http://devicetree.org/schemas/spi/sprd,spi-adi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Spreadtrum ADI controller
|
||||
|
||||
|
61
Documentation/devicetree/bindings/spi/st,ssc-spi.yaml
Normal file
61
Documentation/devicetree/bindings/spi/st,ssc-spi.yaml
Normal file
@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/st,ssc-spi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: STMicroelectronics SSC SPI Controller
|
||||
|
||||
description: |
|
||||
The STMicroelectronics SSC SPI controller can be found on STi platforms
|
||||
and it used to communicate with external devices using the
|
||||
Serial Peripheral Interface.
|
||||
|
||||
maintainers:
|
||||
- Patrice Chotard <patrice.chotard@foss.st.com>
|
||||
|
||||
allOf:
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: st,comms-ssc4-spi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: ssc
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/stih407-clks.h>
|
||||
spi@9840000 {
|
||||
compatible = "st,comms-ssc4-spi";
|
||||
reg = <0x9840000 0x110>;
|
||||
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
|
||||
clock-names = "ssc";
|
||||
pinctrl-0 = <&pinctrl_spi0_default>;
|
||||
pinctrl-names = "default";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
...
|
@ -11,7 +11,7 @@ maintainers:
|
||||
- Patrice Chotard <patrice.chotard@foss.st.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -17,7 +17,7 @@ maintainers:
|
||||
- Fabrice Gasnier <fabrice.gasnier@foss.st.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
@ -84,18 +84,17 @@ examples:
|
||||
#include <dt-bindings/clock/stm32mp1-clks.h>
|
||||
#include <dt-bindings/reset/stm32mp1-resets.h>
|
||||
spi@4000b000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "st,stm32h7-spi";
|
||||
reg = <0x4000b000 0x400>;
|
||||
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&rcc SPI2_K>;
|
||||
resets = <&rcc SPI2_R>;
|
||||
dmas = <&dmamux1 0 39 0x400 0x05>,
|
||||
<&dmamux1 1 40 0x400 0x05>;
|
||||
dma-names = "rx", "tx";
|
||||
cs-gpios = <&gpioa 11 0>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "st,stm32h7-spi";
|
||||
reg = <0x4000b000 0x400>;
|
||||
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&rcc SPI2_K>;
|
||||
resets = <&rcc SPI2_R>;
|
||||
dmas = <&dmamux1 0 39 0x400 0x05>,
|
||||
<&dmamux1 1 40 0x400 0x05>;
|
||||
dma-names = "rx", "tx";
|
||||
cs-gpios = <&gpioa 11 0>;
|
||||
};
|
||||
|
||||
...
|
||||
|
@ -11,7 +11,7 @@ description:
|
||||
memory devices.
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
maintainers:
|
||||
- Michal Simek <michal.simek@xilinx.com>
|
||||
|
@ -65,6 +65,8 @@ properties:
|
||||
- capella,cm3232
|
||||
# CM3323: Ambient Light Sensor
|
||||
- capella,cm3323
|
||||
# Cisco SPI Petra
|
||||
- cisco,spi-petra
|
||||
# High-Precision Digital Thermometer
|
||||
- dallas,ds1631
|
||||
# Total-Elapsed-Time Recorder with Alarm
|
||||
@ -169,6 +171,8 @@ properties:
|
||||
- isil,isl29030
|
||||
# Intersil ISL68137 Digital Output Configurable PWM Controller
|
||||
- isil,isl68137
|
||||
# Linear Technology LTC2488
|
||||
- lineartechnology,ltc2488
|
||||
# 5 Bit Programmable, Pulse-Width Modulator
|
||||
- maxim,ds1050
|
||||
# 10 kOhm digital potentiometer with I2C interface
|
||||
@ -227,6 +231,8 @@ properties:
|
||||
- memsic,mxc6655
|
||||
# Menlo on-board CPLD trivial SPI device
|
||||
- menlo,m53cpld
|
||||
# Micron SPI NOR Authenta
|
||||
- micron,spi-authenta
|
||||
# Microchip differential I2C ADC, 1 Channel, 18 bit
|
||||
- microchip,mcp3421
|
||||
# Microchip differential I2C ADC, 2 Channel, 18 bit
|
||||
@ -305,10 +311,14 @@ properties:
|
||||
- pulsedlight,lidar-lite-v2
|
||||
# Renesas ISL29501 time-of-flight sensor
|
||||
- renesas,isl29501
|
||||
# Rohm DH2228FV
|
||||
- rohm,dh2228fv
|
||||
# S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power)
|
||||
- samsung,24ad0xd1
|
||||
# Samsung Exynos SoC SATA PHY I2C device
|
||||
- samsung,exynos-sataphy-i2c
|
||||
# Semtech sx1301 baseband processor
|
||||
- semtech,sx1301
|
||||
# Sensirion low power multi-pixel gas sensor with I2C interface
|
||||
- sensirion,sgpc3
|
||||
# Sensirion multi-pixel gas sensor with I2C interface
|
||||
@ -323,6 +333,10 @@ properties:
|
||||
- sensortek,stk8ba50
|
||||
# SGX Sensortech VZ89X Sensors
|
||||
- sgx,vz89x
|
||||
# Silicon Labs EM3581 Zigbee SoC with SPI interface
|
||||
- silabs,em3581
|
||||
# Silicon Labs SI3210 Programmable CMOS SLIC/CODEC with SPI interface
|
||||
- silabs,si3210
|
||||
# Relative Humidity and Temperature Sensors
|
||||
- silabs,si7020
|
||||
# Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply
|
||||
|
@ -141,15 +141,15 @@ field. Below is a sample configuration using the PXA255 NSSP.
|
||||
::
|
||||
|
||||
static struct pxa2xx_spi_chip cs8415a_chip_info = {
|
||||
.tx_threshold = 8, /* SSP hardward FIFO threshold */
|
||||
.rx_threshold = 8, /* SSP hardward FIFO threshold */
|
||||
.tx_threshold = 8, /* SSP hardware FIFO threshold */
|
||||
.rx_threshold = 8, /* SSP hardware FIFO threshold */
|
||||
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
|
||||
.timeout = 235, /* See Intel documentation */
|
||||
};
|
||||
|
||||
static struct pxa2xx_spi_chip cs8405a_chip_info = {
|
||||
.tx_threshold = 8, /* SSP hardward FIFO threshold */
|
||||
.rx_threshold = 8, /* SSP hardward FIFO threshold */
|
||||
.tx_threshold = 8, /* SSP hardware FIFO threshold */
|
||||
.rx_threshold = 8, /* SSP hardware FIFO threshold */
|
||||
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
|
||||
.timeout = 235, /* See Intel documentation */
|
||||
};
|
||||
@ -157,7 +157,7 @@ field. Below is a sample configuration using the PXA255 NSSP.
|
||||
static struct spi_board_info streetracer_spi_board_info[] __initdata = {
|
||||
{
|
||||
.modalias = "cs8415a", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 3686400, /* Run SSP as fast a possbile */
|
||||
.max_speed_hz = 3686400, /* Run SSP as fast a possible */
|
||||
.bus_num = 2, /* Framework bus number */
|
||||
.chip_select = 0, /* Framework chip select */
|
||||
.platform_data = NULL; /* No spi_driver specific config */
|
||||
@ -166,7 +166,7 @@ field. Below is a sample configuration using the PXA255 NSSP.
|
||||
},
|
||||
{
|
||||
.modalias = "cs8405a", /* Name of spi_driver for this device */
|
||||
.max_speed_hz = 3686400, /* Run SSP as fast a possbile */
|
||||
.max_speed_hz = 3686400, /* Run SSP as fast a possible */
|
||||
.bus_num = 2, /* Framework bus number */
|
||||
.chip_select = 1, /* Framework chip select */
|
||||
.controller_data = &cs8405a_chip_info, /* Master chip config */
|
||||
|
@ -57,7 +57,7 @@ devices might share the same SI/SO pin.
|
||||
The bitbanger routine in this driver (lm70_txrx) is called back from
|
||||
the bound "hwmon/lm70" protocol driver through its sysfs hook, using a
|
||||
spi_write_then_read() call. It performs Mode 0 (SPI/Microwire) bitbanging.
|
||||
The lm70 driver then inteprets the resulting digital temperature value
|
||||
The lm70 driver then interprets the resulting digital temperature value
|
||||
and exports it through sysfs.
|
||||
|
||||
A "gotcha": National Semiconductor's LM70 LLP eval board circuit schematic
|
||||
|
@ -105,7 +105,7 @@ find isn't necessarily helpful. The four modes combine two mode bits:
|
||||
- CPHA indicates the clock phase used to sample data; CPHA=0 says
|
||||
sample on the leading edge, CPHA=1 means the trailing edge.
|
||||
|
||||
Since the signal needs to stablize before it's sampled, CPHA=0
|
||||
Since the signal needs to stabilize before it's sampled, CPHA=0
|
||||
implies that its data is written half a clock before the first
|
||||
clock edge. The chipselect may have made it become available.
|
||||
|
||||
|
12
MAINTAINERS
12
MAINTAINERS
@ -2925,6 +2925,7 @@ M: Patrice Chotard <patrice.chotard@foss.st.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
W: http://www.stlinux.com
|
||||
F: Documentation/devicetree/bindings/spi/st,ssc-spi.yaml
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-st.txt
|
||||
F: arch/arm/boot/dts/sti*
|
||||
F: arch/arm/mach-sti/
|
||||
@ -4299,6 +4300,17 @@ L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/phy/broadcom/phy-brcm-usb*
|
||||
|
||||
BROADCOM Broadband SoC High Speed SPI Controller DRIVER
|
||||
M: William Zhang <william.zhang@broadcom.com>
|
||||
M: Kursad Oney <kursad.oney@broadcom.com>
|
||||
M: Jonas Gorski <jonas.gorski@gmail.com>
|
||||
R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
|
||||
L: linux-spi@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/spi/brcm,bcm63xx-hsspi.yaml
|
||||
F: drivers/spi/spi-bcm63xx-hsspi.c
|
||||
F: drivers/spi/spi-bcmbca-hsspi.c
|
||||
|
||||
BROADCOM ETHERNET PHY DRIVERS
|
||||
M: Florian Fainelli <f.fainelli@gmail.com>
|
||||
R: Broadcom internal kernel review list <bcm-kernel-feedback-list@broadcom.com>
|
||||
|
@ -199,6 +199,15 @@ config SPI_BCM_QSPI
|
||||
based platforms. This driver works for both SPI master for SPI NOR
|
||||
flash device as well as MSPI device.
|
||||
|
||||
config SPI_BCMBCA_HSSPI
|
||||
tristate "Broadcom BCMBCA HS SPI controller driver"
|
||||
depends on ARCH_BCMBCA || COMPILE_TEST
|
||||
help
|
||||
This enables support for the High Speed SPI controller present on
|
||||
newer Broadcom BCMBCA SoCs. These SoCs include an updated SPI controller
|
||||
that adds the capability to allow the driver to control chip select
|
||||
explicitly.
|
||||
|
||||
config SPI_BITBANG
|
||||
tristate "Utilities for Bitbanging SPI masters"
|
||||
help
|
||||
@ -247,7 +256,7 @@ config SPI_CADENCE_XSPI
|
||||
Enable support for the Cadence XSPI Flash controller.
|
||||
|
||||
Cadence XSPI is a specialized controller for connecting an SPI
|
||||
Flash over upto 8bit wide bus. Enable this option if you have a
|
||||
Flash over up to 8-bit wide bus. Enable this option if you have a
|
||||
device with a Cadence XSPI controller and want to access the
|
||||
Flash as an MTD device.
|
||||
|
||||
@ -295,7 +304,6 @@ config SPI_DW_BT1
|
||||
tristate "Baikal-T1 SPI driver for DW SPI core"
|
||||
depends on MIPS_BAIKAL_T1 || COMPILE_TEST
|
||||
select MULTIPLEXER
|
||||
select MUX_MMIO
|
||||
help
|
||||
Baikal-T1 SoC is equipped with three DW APB SSI-based MMIO SPI
|
||||
controllers. Two of them are pretty much normal: with IRQ, DMA,
|
||||
@ -448,19 +456,19 @@ config SPI_INTEL
|
||||
tristate
|
||||
|
||||
config SPI_INTEL_PCI
|
||||
tristate "Intel PCH/PCU SPI flash PCI driver (DANGEROUS)"
|
||||
tristate "Intel PCH/PCU SPI flash PCI driver"
|
||||
depends on PCI
|
||||
depends on X86 || COMPILE_TEST
|
||||
depends on SPI_MEM
|
||||
select SPI_INTEL
|
||||
help
|
||||
This enables PCI support for the Intel PCH/PCU SPI controller in
|
||||
master mode. This controller is present in modern Intel hardware
|
||||
and is used to hold BIOS and other persistent settings. Using
|
||||
this driver it is possible to upgrade BIOS directly from Linux.
|
||||
|
||||
Say N here unless you know what you are doing. Overwriting the
|
||||
SPI flash may render the system unbootable.
|
||||
master mode. This controller is used to hold BIOS and other
|
||||
persistent settings. Controllers present in modern Intel hardware
|
||||
only work in hardware sequencing mode, this means that the
|
||||
controller exposes a subset of operations that makes it safer to
|
||||
use. Using this driver it is possible to upgrade BIOS directly
|
||||
from Linux.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called spi-intel-pci.
|
||||
@ -472,10 +480,11 @@ config SPI_INTEL_PLATFORM
|
||||
select SPI_INTEL
|
||||
help
|
||||
This enables platform support for the Intel PCH/PCU SPI
|
||||
controller in master mode. This controller is present in modern
|
||||
Intel hardware and is used to hold BIOS and other persistent
|
||||
settings. Using this driver it is possible to upgrade BIOS
|
||||
directly from Linux.
|
||||
controller in master mode that is used to hold BIOS and other
|
||||
persistent settings. Most of these controllers work in
|
||||
software sequencing mode, which means that the controller
|
||||
exposes the low level SPI-NOR opcodes to the software. Using
|
||||
this driver it is possible to upgrade BIOS directly from Linux.
|
||||
|
||||
Say N here unless you know what you are doing. Overwriting the
|
||||
SPI flash may render the system unbootable.
|
||||
@ -1166,9 +1175,6 @@ config SPI_SPIDEV
|
||||
help
|
||||
This supports user mode SPI protocol drivers.
|
||||
|
||||
Note that this application programming interface is EXPERIMENTAL
|
||||
and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes.
|
||||
|
||||
config SPI_LOOPBACK_TEST
|
||||
tristate "spi loopback test framework support"
|
||||
depends on m
|
||||
|
@ -30,6 +30,7 @@ obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
|
||||
obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm2835aux.o
|
||||
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
|
||||
obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
|
||||
obj-$(CONFIG_SPI_BCMBCA_HSSPI) += spi-bcmbca-hsspi.o
|
||||
obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o
|
||||
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
|
||||
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
|
||||
|
@ -406,7 +406,7 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
|
||||
|
||||
static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
||||
{
|
||||
struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->master);
|
||||
struct atmel_qspi *aq = spi_controller_get_devdata(mem->spi->controller);
|
||||
u32 sr, offset;
|
||||
int err;
|
||||
|
||||
@ -476,7 +476,7 @@ static const struct spi_controller_mem_ops atmel_qspi_mem_ops = {
|
||||
|
||||
static int atmel_qspi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct spi_controller *ctrl = spi->master;
|
||||
struct spi_controller *ctrl = spi->controller;
|
||||
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
|
||||
unsigned long src_rate;
|
||||
u32 scbr;
|
||||
@ -512,7 +512,7 @@ static int atmel_qspi_setup(struct spi_device *spi)
|
||||
|
||||
static int atmel_qspi_set_cs_timing(struct spi_device *spi)
|
||||
{
|
||||
struct spi_controller *ctrl = spi->master;
|
||||
struct spi_controller *ctrl = spi->controller;
|
||||
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
|
||||
unsigned long clk_rate;
|
||||
u32 cs_setup;
|
||||
@ -582,7 +582,7 @@ static int atmel_qspi_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int irq, err = 0;
|
||||
|
||||
ctrl = devm_spi_alloc_master(&pdev->dev, sizeof(*aq));
|
||||
ctrl = devm_spi_alloc_host(&pdev->dev, sizeof(*aq));
|
||||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#define ALTERA_SPI_TXDATA 4
|
||||
#define ALTERA_SPI_STATUS 8
|
||||
#define ALTERA_SPI_CONTROL 12
|
||||
#define ALTERA_SPI_SLAVE_SEL 20
|
||||
#define ALTERA_SPI_TARGET_SEL 20
|
||||
|
||||
#define ALTERA_SPI_STATUS_ROE_MSK 0x8
|
||||
#define ALTERA_SPI_STATUS_TOE_MSK 0x10
|
||||
@ -67,7 +67,7 @@ static int altr_spi_readl(struct altera_spi *hw, unsigned int reg,
|
||||
|
||||
static inline struct altera_spi *altera_spi_to_hw(struct spi_device *sdev)
|
||||
{
|
||||
return spi_master_get_devdata(sdev->master);
|
||||
return spi_controller_get_devdata(sdev->controller);
|
||||
}
|
||||
|
||||
static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
|
||||
@ -77,9 +77,9 @@ static void altera_spi_set_cs(struct spi_device *spi, bool is_high)
|
||||
if (is_high) {
|
||||
hw->imr &= ~ALTERA_SPI_CONTROL_SSO_MSK;
|
||||
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
|
||||
altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL, 0);
|
||||
altr_spi_writel(hw, ALTERA_SPI_TARGET_SEL, 0);
|
||||
} else {
|
||||
altr_spi_writel(hw, ALTERA_SPI_SLAVE_SEL,
|
||||
altr_spi_writel(hw, ALTERA_SPI_TARGET_SEL,
|
||||
BIT(spi->chip_select));
|
||||
hw->imr |= ALTERA_SPI_CONTROL_SSO_MSK;
|
||||
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
|
||||
@ -139,10 +139,10 @@ static void altera_spi_rx_word(struct altera_spi *hw)
|
||||
hw->count++;
|
||||
}
|
||||
|
||||
static int altera_spi_txrx(struct spi_master *master,
|
||||
static int altera_spi_txrx(struct spi_controller *host,
|
||||
struct spi_device *spi, struct spi_transfer *t)
|
||||
{
|
||||
struct altera_spi *hw = spi_master_get_devdata(master);
|
||||
struct altera_spi *hw = spi_controller_get_devdata(host);
|
||||
u32 val;
|
||||
|
||||
hw->tx = t->tx_buf;
|
||||
@ -175,15 +175,15 @@ static int altera_spi_txrx(struct spi_master *master,
|
||||
|
||||
altera_spi_rx_word(hw);
|
||||
}
|
||||
spi_finalize_current_transfer(master);
|
||||
spi_finalize_current_transfer(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
irqreturn_t altera_spi_irq(int irq, void *dev)
|
||||
{
|
||||
struct spi_master *master = dev;
|
||||
struct altera_spi *hw = spi_master_get_devdata(master);
|
||||
struct spi_controller *host = dev;
|
||||
struct altera_spi *hw = spi_controller_get_devdata(host);
|
||||
|
||||
altera_spi_rx_word(hw);
|
||||
|
||||
@ -194,20 +194,20 @@ irqreturn_t altera_spi_irq(int irq, void *dev)
|
||||
hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK;
|
||||
altr_spi_writel(hw, ALTERA_SPI_CONTROL, hw->imr);
|
||||
|
||||
spi_finalize_current_transfer(master);
|
||||
spi_finalize_current_transfer(host);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(altera_spi_irq);
|
||||
|
||||
void altera_spi_init_master(struct spi_master *master)
|
||||
void altera_spi_init_host(struct spi_controller *host)
|
||||
{
|
||||
struct altera_spi *hw = spi_master_get_devdata(master);
|
||||
struct altera_spi *hw = spi_controller_get_devdata(host);
|
||||
u32 val;
|
||||
|
||||
master->transfer_one = altera_spi_txrx;
|
||||
master->set_cs = altera_spi_set_cs;
|
||||
host->transfer_one = altera_spi_txrx;
|
||||
host->set_cs = altera_spi_set_cs;
|
||||
|
||||
/* program defaults into the registers */
|
||||
hw->imr = 0; /* disable spi interrupts */
|
||||
@ -217,6 +217,6 @@ void altera_spi_init_master(struct spi_master *master)
|
||||
if (val & ALTERA_SPI_STATUS_RRDY_MSK)
|
||||
altr_spi_readl(hw, ALTERA_SPI_RXDATA, &val); /* flush rxdata */
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(altera_spi_init_master);
|
||||
EXPORT_SYMBOL_GPL(altera_spi_init_host);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -104,20 +104,20 @@ static const struct regmap_config indirect_regbus_cfg = {
|
||||
.reg_read = indirect_bus_reg_read,
|
||||
};
|
||||
|
||||
static void config_spi_master(void __iomem *base, struct spi_master *master)
|
||||
static void config_spi_host(void __iomem *base, struct spi_controller *host)
|
||||
{
|
||||
u64 v;
|
||||
|
||||
v = readq(base + SPI_CORE_PARAMETER);
|
||||
|
||||
master->mode_bits = SPI_CS_HIGH;
|
||||
host->mode_bits = SPI_CS_HIGH;
|
||||
if (FIELD_GET(CLK_POLARITY, v))
|
||||
master->mode_bits |= SPI_CPOL;
|
||||
host->mode_bits |= SPI_CPOL;
|
||||
if (FIELD_GET(CLK_PHASE, v))
|
||||
master->mode_bits |= SPI_CPHA;
|
||||
host->mode_bits |= SPI_CPHA;
|
||||
|
||||
master->num_chipselect = FIELD_GET(NUM_CHIPSELECT, v);
|
||||
master->bits_per_word_mask =
|
||||
host->num_chipselect = FIELD_GET(NUM_CHIPSELECT, v);
|
||||
host->bits_per_word_mask =
|
||||
SPI_BPW_RANGE_MASK(1, FIELD_GET(DATA_WIDTH, v));
|
||||
}
|
||||
|
||||
@ -125,18 +125,18 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
|
||||
{
|
||||
struct spi_board_info board_info = { 0 };
|
||||
struct device *dev = &dfl_dev->dev;
|
||||
struct spi_master *master;
|
||||
struct spi_controller *host;
|
||||
struct altera_spi *hw;
|
||||
void __iomem *base;
|
||||
int err;
|
||||
|
||||
master = devm_spi_alloc_master(dev, sizeof(struct altera_spi));
|
||||
if (!master)
|
||||
host = devm_spi_alloc_host(dev, sizeof(struct altera_spi));
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
|
||||
master->bus_num = -1;
|
||||
host->bus_num = -1;
|
||||
|
||||
hw = spi_master_get_devdata(master);
|
||||
hw = spi_controller_get_devdata(host);
|
||||
|
||||
hw->dev = dev;
|
||||
|
||||
@ -145,10 +145,10 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
config_spi_master(base, master);
|
||||
config_spi_host(base, host);
|
||||
dev_dbg(dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__,
|
||||
master->num_chipselect, master->bits_per_word_mask,
|
||||
master->mode_bits);
|
||||
host->num_chipselect, host->bits_per_word_mask,
|
||||
host->mode_bits);
|
||||
|
||||
hw->regmap = devm_regmap_init(dev, NULL, base, &indirect_regbus_cfg);
|
||||
if (IS_ERR(hw->regmap))
|
||||
@ -156,11 +156,11 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
|
||||
|
||||
hw->irq = -EINVAL;
|
||||
|
||||
altera_spi_init_master(master);
|
||||
altera_spi_init_host(host);
|
||||
|
||||
err = devm_spi_register_master(dev, master);
|
||||
err = devm_spi_register_controller(dev, host);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err, "%s failed to register spi master\n",
|
||||
return dev_err_probe(dev, err, "%s failed to register spi host\n",
|
||||
__func__);
|
||||
|
||||
if (dfl_dev->revision == FME_FEATURE_REV_MAX10_SPI_N5010)
|
||||
@ -172,7 +172,7 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
|
||||
board_info.bus_num = 0;
|
||||
board_info.chip_select = 0;
|
||||
|
||||
if (!spi_new_device(master, &board_info)) {
|
||||
if (!spi_new_device(host, &board_info)) {
|
||||
dev_err(dev, "%s failed to create SPI device: %s\n",
|
||||
__func__, board_info.modalias);
|
||||
}
|
||||
|
@ -39,16 +39,16 @@ static int altera_spi_probe(struct platform_device *pdev)
|
||||
struct altera_spi_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
enum altera_spi_type type = ALTERA_SPI_TYPE_UNKNOWN;
|
||||
struct altera_spi *hw;
|
||||
struct spi_master *master;
|
||||
struct spi_controller *host;
|
||||
int err = -ENODEV;
|
||||
u16 i;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(struct altera_spi));
|
||||
if (!master)
|
||||
host = spi_alloc_host(&pdev->dev, sizeof(struct altera_spi));
|
||||
if (!host)
|
||||
return err;
|
||||
|
||||
/* setup the master state. */
|
||||
master->bus_num = -1;
|
||||
/* setup the host state. */
|
||||
host->bus_num = -1;
|
||||
|
||||
if (pdata) {
|
||||
if (pdata->num_chipselect > ALTERA_SPI_MAX_CS) {
|
||||
@ -59,18 +59,18 @@ static int altera_spi_probe(struct platform_device *pdev)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
master->num_chipselect = pdata->num_chipselect;
|
||||
master->mode_bits = pdata->mode_bits;
|
||||
master->bits_per_word_mask = pdata->bits_per_word_mask;
|
||||
host->num_chipselect = pdata->num_chipselect;
|
||||
host->mode_bits = pdata->mode_bits;
|
||||
host->bits_per_word_mask = pdata->bits_per_word_mask;
|
||||
} else {
|
||||
master->num_chipselect = 16;
|
||||
master->mode_bits = SPI_CS_HIGH;
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
|
||||
host->num_chipselect = 16;
|
||||
host->mode_bits = SPI_CS_HIGH;
|
||||
host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
|
||||
}
|
||||
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
host->dev.of_node = pdev->dev.of_node;
|
||||
|
||||
hw = spi_master_get_devdata(master);
|
||||
hw = spi_controller_get_devdata(host);
|
||||
hw->dev = &pdev->dev;
|
||||
|
||||
if (platid)
|
||||
@ -107,24 +107,24 @@ static int altera_spi_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
altera_spi_init_master(master);
|
||||
altera_spi_init_host(host);
|
||||
|
||||
/* irq is optional */
|
||||
hw->irq = platform_get_irq(pdev, 0);
|
||||
if (hw->irq >= 0) {
|
||||
err = devm_request_irq(&pdev->dev, hw->irq, altera_spi_irq, 0,
|
||||
pdev->name, master);
|
||||
pdev->name, host);
|
||||
if (err)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = devm_spi_register_master(&pdev->dev, master);
|
||||
err = devm_spi_register_controller(&pdev->dev, host);
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
if (pdata) {
|
||||
for (i = 0; i < pdata->num_devices; i++) {
|
||||
if (!spi_new_device(master, pdata->devices + i))
|
||||
if (!spi_new_device(host, pdata->devices + i))
|
||||
dev_warn(&pdev->dev,
|
||||
"unable to create SPI device: %s\n",
|
||||
pdata->devices[i].modalias);
|
||||
@ -135,7 +135,7 @@ static int altera_spi_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
spi_master_put(master);
|
||||
spi_controller_put(host);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ static inline int ar934x_spi_clk_div(struct ar934x_spi *sp, unsigned int freq)
|
||||
|
||||
static int ar934x_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct ar934x_spi *sp = spi_controller_get_devdata(spi->master);
|
||||
struct ar934x_spi *sp = spi_controller_get_devdata(spi->controller);
|
||||
|
||||
if ((spi->max_speed_hz == 0) ||
|
||||
(spi->max_speed_hz > (sp->clk_freq / 2))) {
|
||||
@ -74,10 +74,10 @@ static int ar934x_spi_setup(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ar934x_spi_transfer_one_message(struct spi_controller *master,
|
||||
static int ar934x_spi_transfer_one_message(struct spi_controller *ctlr,
|
||||
struct spi_message *m)
|
||||
{
|
||||
struct ar934x_spi *sp = spi_controller_get_devdata(master);
|
||||
struct ar934x_spi *sp = spi_controller_get_devdata(ctlr);
|
||||
struct spi_transfer *t = NULL;
|
||||
struct spi_device *spi = m->spi;
|
||||
unsigned long trx_done, trx_cur;
|
||||
@ -150,7 +150,7 @@ static int ar934x_spi_transfer_one_message(struct spi_controller *master,
|
||||
|
||||
msg_done:
|
||||
m->status = stat;
|
||||
spi_finalize_current_message(master);
|
||||
spi_finalize_current_message(ctlr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -183,7 +183,7 @@ static int ar934x_spi_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||
ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(*sp));
|
||||
if (!ctlr) {
|
||||
dev_info(&pdev->dev, "failed to allocate spi controller\n");
|
||||
ret = -ENOMEM;
|
||||
|
@ -100,7 +100,7 @@
|
||||
#define A3700_SPI_CLK_CAPT_EDGE BIT(7)
|
||||
|
||||
struct a3700_spi {
|
||||
struct spi_master *master;
|
||||
struct spi_controller *host;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
unsigned int irq;
|
||||
@ -174,7 +174,7 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
|
||||
val |= A3700_SPI_ADDR_PIN;
|
||||
break;
|
||||
default:
|
||||
dev_err(&a3700_spi->master->dev, "wrong pin mode %u", pin_mode);
|
||||
dev_err(&a3700_spi->host->dev, "wrong pin mode %u", pin_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -278,7 +278,7 @@ static int a3700_spi_fifo_flush(struct a3700_spi *a3700_spi)
|
||||
|
||||
static void a3700_spi_init(struct a3700_spi *a3700_spi)
|
||||
{
|
||||
struct spi_master *master = a3700_spi->master;
|
||||
struct spi_controller *host = a3700_spi->host;
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
@ -295,14 +295,14 @@ static void a3700_spi_init(struct a3700_spi *a3700_spi)
|
||||
|
||||
/* Disable AUTO_CS and deactivate all chip-selects */
|
||||
a3700_spi_auto_cs_unset(a3700_spi);
|
||||
for (i = 0; i < master->num_chipselect; i++)
|
||||
for (i = 0; i < host->num_chipselect; i++)
|
||||
a3700_spi_deactivate_cs(a3700_spi, i);
|
||||
|
||||
/* Enable FIFO mode */
|
||||
a3700_spi_fifo_mode_set(a3700_spi, true);
|
||||
|
||||
/* Set SPI mode */
|
||||
a3700_spi_mode_set(a3700_spi, master->mode_bits);
|
||||
a3700_spi_mode_set(a3700_spi, host->mode_bits);
|
||||
|
||||
/* Reset counters */
|
||||
spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0);
|
||||
@ -315,11 +315,11 @@ static void a3700_spi_init(struct a3700_spi *a3700_spi)
|
||||
|
||||
static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_master *master = dev_id;
|
||||
struct spi_controller *host = dev_id;
|
||||
struct a3700_spi *a3700_spi;
|
||||
u32 cause;
|
||||
|
||||
a3700_spi = spi_master_get_devdata(master);
|
||||
a3700_spi = spi_controller_get_devdata(host);
|
||||
|
||||
/* Get interrupt causes */
|
||||
cause = spireg_read(a3700_spi, A3700_SPI_INT_STAT_REG);
|
||||
@ -344,7 +344,7 @@ static bool a3700_spi_wait_completion(struct spi_device *spi)
|
||||
unsigned int ctrl_reg;
|
||||
unsigned long timeout_jiffies;
|
||||
|
||||
a3700_spi = spi_master_get_devdata(spi->master);
|
||||
a3700_spi = spi_controller_get_devdata(spi->controller);
|
||||
|
||||
/* SPI interrupt is edge-triggered, which means an interrupt will
|
||||
* be generated only when detecting a specific status bit changed
|
||||
@ -393,7 +393,7 @@ static bool a3700_spi_transfer_wait(struct spi_device *spi,
|
||||
{
|
||||
struct a3700_spi *a3700_spi;
|
||||
|
||||
a3700_spi = spi_master_get_devdata(spi->master);
|
||||
a3700_spi = spi_controller_get_devdata(spi->controller);
|
||||
a3700_spi->wait_mask = bit_mask;
|
||||
|
||||
return a3700_spi_wait_completion(spi);
|
||||
@ -417,7 +417,7 @@ static void a3700_spi_transfer_setup(struct spi_device *spi,
|
||||
{
|
||||
struct a3700_spi *a3700_spi;
|
||||
|
||||
a3700_spi = spi_master_get_devdata(spi->master);
|
||||
a3700_spi = spi_controller_get_devdata(spi->controller);
|
||||
|
||||
a3700_spi_clock_set(a3700_spi, xfer->speed_hz);
|
||||
|
||||
@ -434,7 +434,7 @@ static void a3700_spi_transfer_setup(struct spi_device *spi,
|
||||
|
||||
static void a3700_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
struct a3700_spi *a3700_spi = spi_master_get_devdata(spi->master);
|
||||
struct a3700_spi *a3700_spi = spi_controller_get_devdata(spi->controller);
|
||||
|
||||
if (!enable)
|
||||
a3700_spi_activate_cs(a3700_spi, spi->chip_select);
|
||||
@ -565,10 +565,10 @@ static void a3700_spi_transfer_abort_fifo(struct a3700_spi *a3700_spi)
|
||||
spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
|
||||
}
|
||||
|
||||
static int a3700_spi_prepare_message(struct spi_master *master,
|
||||
static int a3700_spi_prepare_message(struct spi_controller *host,
|
||||
struct spi_message *message)
|
||||
{
|
||||
struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
|
||||
struct a3700_spi *a3700_spi = spi_controller_get_devdata(host);
|
||||
struct spi_device *spi = message->spi;
|
||||
int ret;
|
||||
|
||||
@ -588,11 +588,11 @@ static int a3700_spi_prepare_message(struct spi_master *master,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a3700_spi_transfer_one_fifo(struct spi_master *master,
|
||||
static int a3700_spi_transfer_one_fifo(struct spi_controller *host,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
|
||||
struct a3700_spi *a3700_spi = spi_controller_get_devdata(host);
|
||||
int ret = 0, timeout = A3700_SPI_TIMEOUT;
|
||||
unsigned int nbits = 0, byte_len;
|
||||
u32 val;
|
||||
@ -732,16 +732,16 @@ static int a3700_spi_transfer_one_fifo(struct spi_master *master,
|
||||
error:
|
||||
a3700_spi_transfer_abort_fifo(a3700_spi);
|
||||
out:
|
||||
spi_finalize_current_transfer(master);
|
||||
spi_finalize_current_transfer(host);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int a3700_spi_transfer_one_full_duplex(struct spi_master *master,
|
||||
static int a3700_spi_transfer_one_full_duplex(struct spi_controller *host,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
|
||||
struct a3700_spi *a3700_spi = spi_controller_get_devdata(host);
|
||||
u32 val;
|
||||
|
||||
/* Disable FIFO mode */
|
||||
@ -777,27 +777,27 @@ static int a3700_spi_transfer_one_full_duplex(struct spi_master *master,
|
||||
|
||||
}
|
||||
|
||||
spi_finalize_current_transfer(master);
|
||||
spi_finalize_current_transfer(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a3700_spi_transfer_one(struct spi_master *master,
|
||||
static int a3700_spi_transfer_one(struct spi_controller *host,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
a3700_spi_transfer_setup(spi, xfer);
|
||||
|
||||
if (xfer->tx_buf && xfer->rx_buf)
|
||||
return a3700_spi_transfer_one_full_duplex(master, spi, xfer);
|
||||
return a3700_spi_transfer_one_full_duplex(host, spi, xfer);
|
||||
|
||||
return a3700_spi_transfer_one_fifo(master, spi, xfer);
|
||||
return a3700_spi_transfer_one_fifo(host, spi, xfer);
|
||||
}
|
||||
|
||||
static int a3700_spi_unprepare_message(struct spi_master *master,
|
||||
static int a3700_spi_unprepare_message(struct spi_controller *host,
|
||||
struct spi_message *message)
|
||||
{
|
||||
struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
|
||||
struct a3700_spi *a3700_spi = spi_controller_get_devdata(host);
|
||||
|
||||
clk_disable(a3700_spi->clk);
|
||||
|
||||
@ -815,14 +815,14 @@ static int a3700_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *of_node = dev->of_node;
|
||||
struct spi_master *master;
|
||||
struct spi_controller *host;
|
||||
struct a3700_spi *spi;
|
||||
u32 num_cs = 0;
|
||||
int irq, ret = 0;
|
||||
|
||||
master = spi_alloc_master(dev, sizeof(*spi));
|
||||
if (!master) {
|
||||
dev_err(dev, "master allocation failed\n");
|
||||
host = spi_alloc_host(dev, sizeof(*spi));
|
||||
if (!host) {
|
||||
dev_err(dev, "host allocation failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@ -833,23 +833,23 @@ static int a3700_spi_probe(struct platform_device *pdev)
|
||||
goto error;
|
||||
}
|
||||
|
||||
master->bus_num = pdev->id;
|
||||
master->dev.of_node = of_node;
|
||||
master->mode_bits = SPI_MODE_3;
|
||||
master->num_chipselect = num_cs;
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(32);
|
||||
master->prepare_message = a3700_spi_prepare_message;
|
||||
master->transfer_one = a3700_spi_transfer_one;
|
||||
master->unprepare_message = a3700_spi_unprepare_message;
|
||||
master->set_cs = a3700_spi_set_cs;
|
||||
master->mode_bits |= (SPI_RX_DUAL | SPI_TX_DUAL |
|
||||
host->bus_num = pdev->id;
|
||||
host->dev.of_node = of_node;
|
||||
host->mode_bits = SPI_MODE_3;
|
||||
host->num_chipselect = num_cs;
|
||||
host->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(32);
|
||||
host->prepare_message = a3700_spi_prepare_message;
|
||||
host->transfer_one = a3700_spi_transfer_one;
|
||||
host->unprepare_message = a3700_spi_unprepare_message;
|
||||
host->set_cs = a3700_spi_set_cs;
|
||||
host->mode_bits |= (SPI_RX_DUAL | SPI_TX_DUAL |
|
||||
SPI_RX_QUAD | SPI_TX_QUAD);
|
||||
|
||||
platform_set_drvdata(pdev, master);
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
spi = spi_master_get_devdata(master);
|
||||
spi = spi_controller_get_devdata(host);
|
||||
|
||||
spi->master = master;
|
||||
spi->host = host;
|
||||
|
||||
spi->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(spi->base)) {
|
||||
@ -878,23 +878,23 @@ static int a3700_spi_probe(struct platform_device *pdev)
|
||||
goto error;
|
||||
}
|
||||
|
||||
master->max_speed_hz = min_t(unsigned long, A3700_SPI_MAX_SPEED_HZ,
|
||||
host->max_speed_hz = min_t(unsigned long, A3700_SPI_MAX_SPEED_HZ,
|
||||
clk_get_rate(spi->clk));
|
||||
master->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk),
|
||||
host->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk),
|
||||
A3700_SPI_MAX_PRESCALE);
|
||||
|
||||
a3700_spi_init(spi);
|
||||
|
||||
ret = devm_request_irq(dev, spi->irq, a3700_spi_interrupt, 0,
|
||||
dev_name(dev), master);
|
||||
dev_name(dev), host);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not request IRQ: %d\n", ret);
|
||||
goto error_clk;
|
||||
}
|
||||
|
||||
ret = devm_spi_register_master(dev, master);
|
||||
ret = devm_spi_register_controller(dev, host);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register master\n");
|
||||
dev_err(dev, "Failed to register host\n");
|
||||
goto error_clk;
|
||||
}
|
||||
|
||||
@ -903,15 +903,15 @@ static int a3700_spi_probe(struct platform_device *pdev)
|
||||
error_clk:
|
||||
clk_unprepare(spi->clk);
|
||||
error:
|
||||
spi_master_put(master);
|
||||
spi_controller_put(host);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int a3700_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct a3700_spi *spi = spi_master_get_devdata(master);
|
||||
struct spi_controller *host = platform_get_drvdata(pdev);
|
||||
struct a3700_spi *spi = spi_controller_get_devdata(host);
|
||||
|
||||
clk_unprepare(spi->clk);
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
#define US_CR_TXEN BIT(6)
|
||||
#define US_CR_TXDIS BIT(7)
|
||||
|
||||
#define US_MR_SPI_MASTER 0x0E
|
||||
#define US_MR_SPI_HOST 0x0E
|
||||
#define US_MR_CHRL GENMASK(7, 6)
|
||||
#define US_MR_CPHA BIT(8)
|
||||
#define US_MR_CPOL BIT(16)
|
||||
@ -61,7 +61,7 @@
|
||||
#define US_OVRE_RXRDY_IRQS (US_IR_OVRE | US_IR_RXRDY)
|
||||
|
||||
#define US_INIT \
|
||||
(US_MR_SPI_MASTER | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT)
|
||||
(US_MR_SPI_HOST | US_MR_CHRL | US_MR_CLKO | US_MR_WRDBT)
|
||||
#define US_DMA_MIN_BYTES 16
|
||||
#define US_DMA_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
||||
@ -104,7 +104,7 @@ struct at91_usart_spi {
|
||||
static void dma_callback(void *data)
|
||||
{
|
||||
struct spi_controller *ctlr = data;
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
|
||||
|
||||
at91_usart_spi_writel(aus, IER, US_IR_RXRDY);
|
||||
aus->current_rx_remaining_bytes = 0;
|
||||
@ -115,7 +115,7 @@ static bool at91_usart_spi_can_dma(struct spi_controller *ctrl,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctrl);
|
||||
|
||||
return aus->use_dma && xfer->len >= US_DMA_MIN_BYTES;
|
||||
}
|
||||
@ -216,7 +216,7 @@ static void at91_usart_spi_stop_dma(struct spi_controller *ctlr)
|
||||
static int at91_usart_spi_dma_transfer(struct spi_controller *ctlr,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
|
||||
struct dma_chan *rxchan = ctlr->dma_rx;
|
||||
struct dma_chan *txchan = ctlr->dma_tx;
|
||||
struct dma_async_tx_descriptor *rxdesc;
|
||||
@ -334,7 +334,7 @@ at91_usart_spi_set_xfer_speed(struct at91_usart_spi *aus,
|
||||
static irqreturn_t at91_usart_spi_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_controller *controller = dev_id;
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(controller);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(controller);
|
||||
|
||||
spin_lock(&aus->lock);
|
||||
at91_usart_spi_read_status(aus);
|
||||
@ -359,7 +359,7 @@ static irqreturn_t at91_usart_spi_interrupt(int irq, void *dev_id)
|
||||
|
||||
static int at91_usart_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(spi->controller);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(spi->controller);
|
||||
u32 *ausd = spi->controller_state;
|
||||
unsigned int mr = at91_usart_spi_readl(aus, MR);
|
||||
|
||||
@ -399,7 +399,7 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
|
||||
unsigned long dma_timeout = 0;
|
||||
int ret = 0;
|
||||
|
||||
@ -444,7 +444,7 @@ static int at91_usart_spi_transfer_one(struct spi_controller *ctlr,
|
||||
static int at91_usart_spi_prepare_message(struct spi_controller *ctlr,
|
||||
struct spi_message *message)
|
||||
{
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
|
||||
struct spi_device *spi = message->spi;
|
||||
u32 *ausd = spi->controller_state;
|
||||
|
||||
@ -458,7 +458,7 @@ static int at91_usart_spi_prepare_message(struct spi_controller *ctlr,
|
||||
static int at91_usart_spi_unprepare_message(struct spi_controller *ctlr,
|
||||
struct spi_message *message)
|
||||
{
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
|
||||
|
||||
at91_usart_spi_writel(aus, CR, US_RESET | US_DISABLE);
|
||||
at91_usart_spi_writel(aus, IDR, US_OVRE_RXRDY_IRQS);
|
||||
@ -515,7 +515,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(clk);
|
||||
|
||||
ret = -ENOMEM;
|
||||
controller = spi_alloc_master(&pdev->dev, sizeof(*aus));
|
||||
controller = spi_alloc_host(&pdev->dev, sizeof(*aus));
|
||||
if (!controller)
|
||||
goto at91_usart_spi_probe_fail;
|
||||
|
||||
@ -539,7 +539,7 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
|
||||
US_MAX_CLK_DIV);
|
||||
platform_set_drvdata(pdev, controller);
|
||||
|
||||
aus = spi_master_get_devdata(controller);
|
||||
aus = spi_controller_get_devdata(controller);
|
||||
|
||||
aus->dev = &pdev->dev;
|
||||
aus->regs = devm_ioremap_resource(&pdev->dev, regs);
|
||||
@ -574,9 +574,9 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&aus->lock);
|
||||
init_completion(&aus->xfer_completion);
|
||||
|
||||
ret = devm_spi_register_master(&pdev->dev, controller);
|
||||
ret = devm_spi_register_controller(&pdev->dev, controller);
|
||||
if (ret)
|
||||
goto at91_usart_fail_register_master;
|
||||
goto at91_usart_fail_register_controller;
|
||||
|
||||
dev_info(&pdev->dev,
|
||||
"AT91 USART SPI Controller version 0x%x at %pa (irq %d)\n",
|
||||
@ -585,19 +585,19 @@ static int at91_usart_spi_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
at91_usart_fail_register_master:
|
||||
at91_usart_fail_register_controller:
|
||||
at91_usart_spi_release_dma(controller);
|
||||
at91_usart_fail_dma:
|
||||
clk_disable_unprepare(clk);
|
||||
at91_usart_spi_probe_fail:
|
||||
spi_master_put(controller);
|
||||
spi_controller_put(controller);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__maybe_unused static int at91_usart_spi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_controller *ctlr = dev_get_drvdata(dev);
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
|
||||
|
||||
clk_disable_unprepare(aus->clk);
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
@ -608,7 +608,7 @@ __maybe_unused static int at91_usart_spi_runtime_suspend(struct device *dev)
|
||||
__maybe_unused static int at91_usart_spi_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_get_drvdata(dev);
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctrl);
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
@ -633,7 +633,7 @@ __maybe_unused static int at91_usart_spi_suspend(struct device *dev)
|
||||
__maybe_unused static int at91_usart_spi_resume(struct device *dev)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_get_drvdata(dev);
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctrl);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctrl);
|
||||
int ret;
|
||||
|
||||
if (!pm_runtime_suspended(dev)) {
|
||||
@ -650,7 +650,7 @@ __maybe_unused static int at91_usart_spi_resume(struct device *dev)
|
||||
static int at91_usart_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_controller *ctlr = platform_get_drvdata(pdev);
|
||||
struct at91_usart_spi *aus = spi_master_get_devdata(ctlr);
|
||||
struct at91_usart_spi *aus = spi_controller_get_devdata(ctlr);
|
||||
|
||||
at91_usart_spi_release_dma(ctlr);
|
||||
clk_disable_unprepare(aus->clk);
|
||||
|
@ -58,7 +58,7 @@ static inline void ath79_spi_wr(struct ath79_spi *sp, unsigned int reg, u32 val)
|
||||
|
||||
static inline struct ath79_spi *ath79_spidev_to_sp(struct spi_device *spi)
|
||||
{
|
||||
return spi_master_get_devdata(spi->master);
|
||||
return spi_controller_get_devdata(spi->controller);
|
||||
}
|
||||
|
||||
static inline void ath79_spi_delay(struct ath79_spi *sp, unsigned int nsecs)
|
||||
@ -120,7 +120,7 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned int nsecs,
|
||||
else
|
||||
out = ioc & ~AR71XX_SPI_IOC_DO;
|
||||
|
||||
/* setup MSB (to slave) on trailing edge */
|
||||
/* setup MSB (to target) on trailing edge */
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out);
|
||||
ath79_spi_delay(sp, nsecs);
|
||||
ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, out | AR71XX_SPI_IOC_CLK);
|
||||
@ -168,28 +168,28 @@ static const struct spi_controller_mem_ops ath79_mem_ops = {
|
||||
|
||||
static int ath79_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct spi_controller *host;
|
||||
struct ath79_spi *sp;
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*sp));
|
||||
if (master == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate spi master\n");
|
||||
host = spi_alloc_host(&pdev->dev, sizeof(*sp));
|
||||
if (host == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate spi host\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sp = spi_master_get_devdata(master);
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
sp = spi_controller_get_devdata(host);
|
||||
host->dev.of_node = pdev->dev.of_node;
|
||||
platform_set_drvdata(pdev, sp);
|
||||
|
||||
master->use_gpio_descriptors = true;
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
|
||||
master->flags = SPI_MASTER_GPIO_SS;
|
||||
master->num_chipselect = 3;
|
||||
master->mem_ops = &ath79_mem_ops;
|
||||
host->use_gpio_descriptors = true;
|
||||
host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
|
||||
host->flags = SPI_MASTER_GPIO_SS;
|
||||
host->num_chipselect = 3;
|
||||
host->mem_ops = &ath79_mem_ops;
|
||||
|
||||
sp->bitbang.master = master;
|
||||
sp->bitbang.master = host;
|
||||
sp->bitbang.chipselect = ath79_spi_chipselect;
|
||||
sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
|
||||
sp->bitbang.flags = SPI_CS_HIGH;
|
||||
@ -197,18 +197,18 @@ static int ath79_spi_probe(struct platform_device *pdev)
|
||||
sp->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(sp->base)) {
|
||||
ret = PTR_ERR(sp->base);
|
||||
goto err_put_master;
|
||||
goto err_put_host;
|
||||
}
|
||||
|
||||
sp->clk = devm_clk_get(&pdev->dev, "ahb");
|
||||
if (IS_ERR(sp->clk)) {
|
||||
ret = PTR_ERR(sp->clk);
|
||||
goto err_put_master;
|
||||
goto err_put_host;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(sp->clk);
|
||||
if (ret)
|
||||
goto err_put_master;
|
||||
goto err_put_host;
|
||||
|
||||
rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
|
||||
if (!rate) {
|
||||
@ -231,8 +231,8 @@ static int ath79_spi_probe(struct platform_device *pdev)
|
||||
ath79_spi_disable(sp);
|
||||
err_clk_disable:
|
||||
clk_disable_unprepare(sp->clk);
|
||||
err_put_master:
|
||||
spi_master_put(sp->bitbang.master);
|
||||
err_put_host:
|
||||
spi_controller_put(host);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -244,7 +244,7 @@ static int ath79_spi_remove(struct platform_device *pdev)
|
||||
spi_bitbang_stop(&sp->bitbang);
|
||||
ath79_spi_disable(sp);
|
||||
clk_disable_unprepare(sp->clk);
|
||||
spi_master_put(sp->bitbang.master);
|
||||
spi_controller_put(sp->bitbang.master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -358,7 +358,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
|
||||
u32 csr;
|
||||
|
||||
/* Make sure clock polarity is correct */
|
||||
for (i = 0; i < spi->master->num_chipselect; i++) {
|
||||
for (i = 0; i < spi->controller->num_chipselect; i++) {
|
||||
csr = spi_readl(as, CSR0 + 4 * i);
|
||||
if ((csr ^ cpol) & SPI_BIT(CPOL))
|
||||
spi_writel(as, CSR0 + 4 * i,
|
||||
@ -419,11 +419,11 @@ static inline bool atmel_spi_use_dma(struct atmel_spi *as,
|
||||
return as->use_dma && xfer->len >= DMA_MIN_BYTES;
|
||||
}
|
||||
|
||||
static bool atmel_spi_can_dma(struct spi_master *master,
|
||||
static bool atmel_spi_can_dma(struct spi_controller *host,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
|
||||
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5))
|
||||
return atmel_spi_use_dma(as, xfer) &&
|
||||
@ -435,7 +435,7 @@ static bool atmel_spi_can_dma(struct spi_master *master,
|
||||
|
||||
static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(as->pdev);
|
||||
struct spi_controller *host = platform_get_drvdata(as->pdev);
|
||||
struct dma_slave_config slave_config;
|
||||
int err = 0;
|
||||
|
||||
@ -467,21 +467,21 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
|
||||
* So we'd rather write only one data at the time. Hence the transmit
|
||||
* path works the same whether FIFOs are available (and enabled) or not.
|
||||
*/
|
||||
if (dmaengine_slave_config(master->dma_tx, &slave_config)) {
|
||||
if (dmaengine_slave_config(host->dma_tx, &slave_config)) {
|
||||
dev_err(&as->pdev->dev,
|
||||
"failed to configure tx dma channel\n");
|
||||
err = -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This driver configures the spi controller for master mode (MSTR bit
|
||||
* This driver configures the spi controller for host mode (MSTR bit
|
||||
* set to '1' in the Mode Register).
|
||||
* So according to the datasheet, when FIFOs are available (and
|
||||
* enabled), the Receive FIFO operates in Single Data Mode.
|
||||
* So the receive path works the same whether FIFOs are available (and
|
||||
* enabled) or not.
|
||||
*/
|
||||
if (dmaengine_slave_config(master->dma_rx, &slave_config)) {
|
||||
if (dmaengine_slave_config(host->dma_rx, &slave_config)) {
|
||||
dev_err(&as->pdev->dev,
|
||||
"failed to configure rx dma channel\n");
|
||||
err = -EINVAL;
|
||||
@ -490,22 +490,22 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, u8 bits_per_word)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int atmel_spi_configure_dma(struct spi_master *master,
|
||||
static int atmel_spi_configure_dma(struct spi_controller *host,
|
||||
struct atmel_spi *as)
|
||||
{
|
||||
struct device *dev = &as->pdev->dev;
|
||||
int err;
|
||||
|
||||
master->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
err = PTR_ERR(master->dma_tx);
|
||||
host->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(host->dma_tx)) {
|
||||
err = PTR_ERR(host->dma_tx);
|
||||
dev_dbg(dev, "No TX DMA channel, DMA is disabled\n");
|
||||
goto error_clear;
|
||||
}
|
||||
|
||||
master->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(master->dma_rx)) {
|
||||
err = PTR_ERR(master->dma_rx);
|
||||
host->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(host->dma_rx)) {
|
||||
err = PTR_ERR(host->dma_rx);
|
||||
/*
|
||||
* No reason to check EPROBE_DEFER here since we have already
|
||||
* requested tx channel.
|
||||
@ -520,45 +520,45 @@ static int atmel_spi_configure_dma(struct spi_master *master,
|
||||
|
||||
dev_info(&as->pdev->dev,
|
||||
"Using %s (tx) and %s (rx) for DMA transfers\n",
|
||||
dma_chan_name(master->dma_tx),
|
||||
dma_chan_name(master->dma_rx));
|
||||
dma_chan_name(host->dma_tx),
|
||||
dma_chan_name(host->dma_rx));
|
||||
|
||||
return 0;
|
||||
error:
|
||||
if (!IS_ERR(master->dma_rx))
|
||||
dma_release_channel(master->dma_rx);
|
||||
if (!IS_ERR(master->dma_tx))
|
||||
dma_release_channel(master->dma_tx);
|
||||
if (!IS_ERR(host->dma_rx))
|
||||
dma_release_channel(host->dma_rx);
|
||||
if (!IS_ERR(host->dma_tx))
|
||||
dma_release_channel(host->dma_tx);
|
||||
error_clear:
|
||||
master->dma_tx = master->dma_rx = NULL;
|
||||
host->dma_tx = host->dma_rx = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void atmel_spi_stop_dma(struct spi_master *master)
|
||||
static void atmel_spi_stop_dma(struct spi_controller *host)
|
||||
{
|
||||
if (master->dma_rx)
|
||||
dmaengine_terminate_all(master->dma_rx);
|
||||
if (master->dma_tx)
|
||||
dmaengine_terminate_all(master->dma_tx);
|
||||
if (host->dma_rx)
|
||||
dmaengine_terminate_all(host->dma_rx);
|
||||
if (host->dma_tx)
|
||||
dmaengine_terminate_all(host->dma_tx);
|
||||
}
|
||||
|
||||
static void atmel_spi_release_dma(struct spi_master *master)
|
||||
static void atmel_spi_release_dma(struct spi_controller *host)
|
||||
{
|
||||
if (master->dma_rx) {
|
||||
dma_release_channel(master->dma_rx);
|
||||
master->dma_rx = NULL;
|
||||
if (host->dma_rx) {
|
||||
dma_release_channel(host->dma_rx);
|
||||
host->dma_rx = NULL;
|
||||
}
|
||||
if (master->dma_tx) {
|
||||
dma_release_channel(master->dma_tx);
|
||||
master->dma_tx = NULL;
|
||||
if (host->dma_tx) {
|
||||
dma_release_channel(host->dma_tx);
|
||||
host->dma_tx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function is called by the DMA driver from tasklet context */
|
||||
static void dma_callback(void *data)
|
||||
{
|
||||
struct spi_master *master = data;
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct spi_controller *host = data;
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
|
||||
if (is_vmalloc_addr(as->current_transfer->rx_buf) &&
|
||||
IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
|
||||
@ -571,13 +571,13 @@ static void dma_callback(void *data)
|
||||
/*
|
||||
* Next transfer using PIO without FIFO.
|
||||
*/
|
||||
static void atmel_spi_next_xfer_single(struct spi_master *master,
|
||||
static void atmel_spi_next_xfer_single(struct spi_controller *host,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
unsigned long xfer_pos = xfer->len - as->current_remaining_bytes;
|
||||
|
||||
dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_pio\n");
|
||||
dev_vdbg(host->dev.parent, "atmel_spi_next_xfer_pio\n");
|
||||
|
||||
/* Make sure data is not remaining in RDR */
|
||||
spi_readl(as, RDR);
|
||||
@ -591,7 +591,7 @@ static void atmel_spi_next_xfer_single(struct spi_master *master,
|
||||
else
|
||||
spi_writel(as, TDR, *(u8 *)(xfer->tx_buf + xfer_pos));
|
||||
|
||||
dev_dbg(master->dev.parent,
|
||||
dev_dbg(host->dev.parent,
|
||||
" start pio xfer %p: len %u tx %p rx %p bitpw %d\n",
|
||||
xfer, xfer->len, xfer->tx_buf, xfer->rx_buf,
|
||||
xfer->bits_per_word);
|
||||
@ -603,10 +603,10 @@ static void atmel_spi_next_xfer_single(struct spi_master *master,
|
||||
/*
|
||||
* Next transfer using PIO with FIFO.
|
||||
*/
|
||||
static void atmel_spi_next_xfer_fifo(struct spi_master *master,
|
||||
static void atmel_spi_next_xfer_fifo(struct spi_controller *host,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
u32 current_remaining_data, num_data;
|
||||
u32 offset = xfer->len - as->current_remaining_bytes;
|
||||
const u16 *words = (const u16 *)((u8 *)xfer->tx_buf + offset);
|
||||
@ -614,7 +614,7 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,
|
||||
u16 td0, td1;
|
||||
u32 fifomr;
|
||||
|
||||
dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_fifo\n");
|
||||
dev_vdbg(host->dev.parent, "atmel_spi_next_xfer_fifo\n");
|
||||
|
||||
/* Compute the number of data to transfer in the current iteration */
|
||||
current_remaining_data = ((xfer->bits_per_word > 8) ?
|
||||
@ -658,7 +658,7 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,
|
||||
num_data--;
|
||||
}
|
||||
|
||||
dev_dbg(master->dev.parent,
|
||||
dev_dbg(host->dev.parent,
|
||||
" start fifo xfer %p: len %u tx %p rx %p bitpw %d\n",
|
||||
xfer, xfer->len, xfer->tx_buf, xfer->rx_buf,
|
||||
xfer->bits_per_word);
|
||||
@ -673,32 +673,32 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,
|
||||
/*
|
||||
* Next transfer using PIO.
|
||||
*/
|
||||
static void atmel_spi_next_xfer_pio(struct spi_master *master,
|
||||
static void atmel_spi_next_xfer_pio(struct spi_controller *host,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
|
||||
if (as->fifo_size)
|
||||
atmel_spi_next_xfer_fifo(master, xfer);
|
||||
atmel_spi_next_xfer_fifo(host, xfer);
|
||||
else
|
||||
atmel_spi_next_xfer_single(master, xfer);
|
||||
atmel_spi_next_xfer_single(host, xfer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Submit next transfer for DMA.
|
||||
*/
|
||||
static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||
static int atmel_spi_next_xfer_dma_submit(struct spi_controller *host,
|
||||
struct spi_transfer *xfer,
|
||||
u32 *plen)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct dma_chan *rxchan = master->dma_rx;
|
||||
struct dma_chan *txchan = master->dma_tx;
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
struct dma_chan *rxchan = host->dma_rx;
|
||||
struct dma_chan *txchan = host->dma_tx;
|
||||
struct dma_async_tx_descriptor *rxdesc;
|
||||
struct dma_async_tx_descriptor *txdesc;
|
||||
dma_cookie_t cookie;
|
||||
|
||||
dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\n");
|
||||
dev_vdbg(host->dev.parent, "atmel_spi_next_xfer_dma_submit\n");
|
||||
|
||||
/* Check that the channels are available */
|
||||
if (!rxchan || !txchan)
|
||||
@ -749,7 +749,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||
if (!txdesc)
|
||||
goto err_dma;
|
||||
|
||||
dev_dbg(master->dev.parent,
|
||||
dev_dbg(host->dev.parent,
|
||||
" start dma xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
|
||||
xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma,
|
||||
xfer->rx_buf, (unsigned long long)xfer->rx_dma);
|
||||
@ -759,7 +759,7 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||
|
||||
/* Put the callback on the RX transfer only, that should finish last */
|
||||
rxdesc->callback = dma_callback;
|
||||
rxdesc->callback_param = master;
|
||||
rxdesc->callback_param = host;
|
||||
|
||||
/* Submit and fire RX and TX with TX last so we're ready to read! */
|
||||
cookie = rxdesc->tx_submit(rxdesc);
|
||||
@ -775,12 +775,12 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||
|
||||
err_dma:
|
||||
spi_writel(as, IDR, SPI_BIT(OVRES));
|
||||
atmel_spi_stop_dma(master);
|
||||
atmel_spi_stop_dma(host);
|
||||
err_exit:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void atmel_spi_next_xfer_data(struct spi_master *master,
|
||||
static void atmel_spi_next_xfer_data(struct spi_controller *host,
|
||||
struct spi_transfer *xfer,
|
||||
dma_addr_t *tx_dma,
|
||||
dma_addr_t *rx_dma,
|
||||
@ -788,8 +788,8 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
|
||||
{
|
||||
*rx_dma = xfer->rx_dma + xfer->len - *plen;
|
||||
*tx_dma = xfer->tx_dma + xfer->len - *plen;
|
||||
if (*plen > master->max_dma_len)
|
||||
*plen = master->max_dma_len;
|
||||
if (*plen > host->max_dma_len)
|
||||
*plen = host->max_dma_len;
|
||||
}
|
||||
|
||||
static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
|
||||
@ -844,17 +844,17 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
|
||||
* Submit next transfer for PDC.
|
||||
* lock is held, spi irq is blocked
|
||||
*/
|
||||
static void atmel_spi_pdc_next_xfer(struct spi_master *master,
|
||||
static void atmel_spi_pdc_next_xfer(struct spi_controller *host,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
u32 len;
|
||||
dma_addr_t tx_dma, rx_dma;
|
||||
|
||||
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
|
||||
|
||||
len = as->current_remaining_bytes;
|
||||
atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
|
||||
atmel_spi_next_xfer_data(host, xfer, &tx_dma, &rx_dma, &len);
|
||||
as->current_remaining_bytes -= len;
|
||||
|
||||
spi_writel(as, RPR, rx_dma);
|
||||
@ -865,7 +865,7 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
|
||||
spi_writel(as, RCR, len);
|
||||
spi_writel(as, TCR, len);
|
||||
|
||||
dev_dbg(&master->dev,
|
||||
dev_dbg(&host->dev,
|
||||
" start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
|
||||
xfer, xfer->len, xfer->tx_buf,
|
||||
(unsigned long long)xfer->tx_dma, xfer->rx_buf,
|
||||
@ -873,7 +873,7 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
|
||||
|
||||
if (as->current_remaining_bytes) {
|
||||
len = as->current_remaining_bytes;
|
||||
atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
|
||||
atmel_spi_next_xfer_data(host, xfer, &tx_dma, &rx_dma, &len);
|
||||
as->current_remaining_bytes -= len;
|
||||
|
||||
spi_writel(as, RNPR, rx_dma);
|
||||
@ -884,7 +884,7 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
|
||||
spi_writel(as, RNCR, len);
|
||||
spi_writel(as, TNCR, len);
|
||||
|
||||
dev_dbg(&master->dev,
|
||||
dev_dbg(&host->dev,
|
||||
" next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
|
||||
xfer, xfer->len, xfer->tx_buf,
|
||||
(unsigned long long)xfer->tx_dma, xfer->rx_buf,
|
||||
@ -944,14 +944,14 @@ atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
|
||||
static void atmel_spi_dma_unmap_xfer(struct spi_controller *host,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
if (xfer->tx_dma != INVALID_DMA_ADDRESS)
|
||||
dma_unmap_single(master->dev.parent, xfer->tx_dma,
|
||||
dma_unmap_single(host->dev.parent, xfer->tx_dma,
|
||||
xfer->len, DMA_TO_DEVICE);
|
||||
if (xfer->rx_dma != INVALID_DMA_ADDRESS)
|
||||
dma_unmap_single(master->dev.parent, xfer->rx_dma,
|
||||
dma_unmap_single(host->dev.parent, xfer->rx_dma,
|
||||
xfer->len, DMA_FROM_DEVICE);
|
||||
}
|
||||
|
||||
@ -1039,8 +1039,8 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
|
||||
static irqreturn_t
|
||||
atmel_spi_pio_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_master *master = dev_id;
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct spi_controller *host = dev_id;
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
u32 status, pending, imr;
|
||||
struct spi_transfer *xfer;
|
||||
int ret = IRQ_NONE;
|
||||
@ -1052,7 +1052,7 @@ atmel_spi_pio_interrupt(int irq, void *dev_id)
|
||||
if (pending & SPI_BIT(OVRES)) {
|
||||
ret = IRQ_HANDLED;
|
||||
spi_writel(as, IDR, SPI_BIT(OVRES));
|
||||
dev_warn(master->dev.parent, "overrun\n");
|
||||
dev_warn(host->dev.parent, "overrun\n");
|
||||
|
||||
/*
|
||||
* When we get an overrun, we disregard the current
|
||||
@ -1097,8 +1097,8 @@ atmel_spi_pio_interrupt(int irq, void *dev_id)
|
||||
static irqreturn_t
|
||||
atmel_spi_pdc_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_master *master = dev_id;
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct spi_controller *host = dev_id;
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
u32 status, pending, imr;
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
@ -1152,12 +1152,12 @@ static int atmel_word_delay_csr(struct spi_device *spi, struct atmel_spi *as)
|
||||
static void initialize_native_cs_for_gpio(struct atmel_spi *as)
|
||||
{
|
||||
int i;
|
||||
struct spi_master *master = platform_get_drvdata(as->pdev);
|
||||
struct spi_controller *host = platform_get_drvdata(as->pdev);
|
||||
|
||||
if (!as->native_cs_free)
|
||||
return; /* already initialized */
|
||||
|
||||
if (!master->cs_gpiods)
|
||||
if (!host->cs_gpiods)
|
||||
return; /* No CS GPIO */
|
||||
|
||||
/*
|
||||
@ -1170,7 +1170,7 @@ static void initialize_native_cs_for_gpio(struct atmel_spi *as)
|
||||
i = 1;
|
||||
|
||||
for (; i < 4; i++)
|
||||
if (master->cs_gpiods[i])
|
||||
if (host->cs_gpiods[i])
|
||||
as->native_cs_free |= BIT(i);
|
||||
|
||||
if (as->native_cs_free)
|
||||
@ -1186,7 +1186,7 @@ static int atmel_spi_setup(struct spi_device *spi)
|
||||
int chip_select;
|
||||
int word_delay_csr;
|
||||
|
||||
as = spi_master_get_devdata(spi->master);
|
||||
as = spi_controller_get_devdata(spi->controller);
|
||||
|
||||
/* see notes above re chipselect */
|
||||
if (!spi->cs_gpiod && (spi->mode & SPI_CS_HIGH)) {
|
||||
@ -1254,7 +1254,7 @@ static int atmel_spi_setup(struct spi_device *spi)
|
||||
|
||||
static void atmel_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(spi->master);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(spi->controller);
|
||||
/* the core doesn't really pass us enable/disable, but CS HIGH vs CS LOW
|
||||
* since we already have routines for activate/deactivate translate
|
||||
* high/low to active/inactive
|
||||
@ -1269,7 +1269,7 @@ static void atmel_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
|
||||
}
|
||||
|
||||
static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
static int atmel_spi_one_transfer(struct spi_controller *host,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
@ -1281,7 +1281,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
int ret;
|
||||
unsigned long dma_timeout;
|
||||
|
||||
as = spi_master_get_devdata(master);
|
||||
as = spi_controller_get_devdata(host);
|
||||
|
||||
asd = spi->controller_state;
|
||||
bits = (asd->csr >> 4) & 0xf;
|
||||
@ -1295,7 +1295,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
* DMA map early, for performance (empties dcache ASAP) and
|
||||
* better fault reporting.
|
||||
*/
|
||||
if ((!master->cur_msg->is_dma_mapped)
|
||||
if ((!host->cur_msg->is_dma_mapped)
|
||||
&& as->use_pdc) {
|
||||
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
|
||||
return -ENOMEM;
|
||||
@ -1311,11 +1311,11 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
|
||||
if (as->use_pdc) {
|
||||
atmel_spi_lock(as);
|
||||
atmel_spi_pdc_next_xfer(master, xfer);
|
||||
atmel_spi_pdc_next_xfer(host, xfer);
|
||||
atmel_spi_unlock(as);
|
||||
} else if (atmel_spi_use_dma(as, xfer)) {
|
||||
len = as->current_remaining_bytes;
|
||||
ret = atmel_spi_next_xfer_dma_submit(master,
|
||||
ret = atmel_spi_next_xfer_dma_submit(host,
|
||||
xfer, &len);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev,
|
||||
@ -1329,7 +1329,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
}
|
||||
} else {
|
||||
atmel_spi_lock(as);
|
||||
atmel_spi_next_xfer_pio(master, xfer);
|
||||
atmel_spi_next_xfer_pio(host, xfer);
|
||||
atmel_spi_unlock(as);
|
||||
}
|
||||
|
||||
@ -1346,7 +1346,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
|
||||
if (as->done_status) {
|
||||
if (as->use_pdc) {
|
||||
dev_warn(master->dev.parent,
|
||||
dev_warn(host->dev.parent,
|
||||
"overrun (%u/%u remaining)\n",
|
||||
spi_readl(as, TCR), spi_readl(as, RCR));
|
||||
|
||||
@ -1362,7 +1362,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
if (spi_readl(as, SR) & SPI_BIT(TXEMPTY))
|
||||
break;
|
||||
if (!timeout)
|
||||
dev_warn(master->dev.parent,
|
||||
dev_warn(host->dev.parent,
|
||||
"timeout waiting for TXEMPTY");
|
||||
while (spi_readl(as, SR) & SPI_BIT(RDRF))
|
||||
spi_readl(as, RDR);
|
||||
@ -1371,13 +1371,13 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
spi_readl(as, SR);
|
||||
|
||||
} else if (atmel_spi_use_dma(as, xfer)) {
|
||||
atmel_spi_stop_dma(master);
|
||||
atmel_spi_stop_dma(host);
|
||||
}
|
||||
}
|
||||
|
||||
if (!master->cur_msg->is_dma_mapped
|
||||
if (!host->cur_msg->is_dma_mapped
|
||||
&& as->use_pdc)
|
||||
atmel_spi_dma_unmap_xfer(master, xfer);
|
||||
atmel_spi_dma_unmap_xfer(host, xfer);
|
||||
|
||||
if (as->use_pdc)
|
||||
atmel_spi_disable_pdc_transfer(as);
|
||||
@ -1440,7 +1440,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
struct spi_master *master;
|
||||
struct spi_controller *host;
|
||||
struct atmel_spi *as;
|
||||
|
||||
/* Select default pin state */
|
||||
@ -1459,29 +1459,29 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(clk);
|
||||
|
||||
/* setup spi core then atmel-specific driver state */
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*as));
|
||||
if (!master)
|
||||
host = spi_alloc_host(&pdev->dev, sizeof(*as));
|
||||
if (!host)
|
||||
return -ENOMEM;
|
||||
|
||||
/* the spi->mode bits understood by this driver: */
|
||||
master->use_gpio_descriptors = true;
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
master->bus_num = pdev->id;
|
||||
master->num_chipselect = 4;
|
||||
master->setup = atmel_spi_setup;
|
||||
master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX |
|
||||
host->use_gpio_descriptors = true;
|
||||
host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
||||
host->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
|
||||
host->dev.of_node = pdev->dev.of_node;
|
||||
host->bus_num = pdev->id;
|
||||
host->num_chipselect = 4;
|
||||
host->setup = atmel_spi_setup;
|
||||
host->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX |
|
||||
SPI_MASTER_GPIO_SS);
|
||||
master->transfer_one = atmel_spi_one_transfer;
|
||||
master->set_cs = atmel_spi_set_cs;
|
||||
master->cleanup = atmel_spi_cleanup;
|
||||
master->auto_runtime_pm = true;
|
||||
master->max_dma_len = SPI_MAX_DMA_XFER;
|
||||
master->can_dma = atmel_spi_can_dma;
|
||||
platform_set_drvdata(pdev, master);
|
||||
host->transfer_one = atmel_spi_one_transfer;
|
||||
host->set_cs = atmel_spi_set_cs;
|
||||
host->cleanup = atmel_spi_cleanup;
|
||||
host->auto_runtime_pm = true;
|
||||
host->max_dma_len = SPI_MAX_DMA_XFER;
|
||||
host->can_dma = atmel_spi_can_dma;
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
as = spi_master_get_devdata(master);
|
||||
as = spi_controller_get_devdata(host);
|
||||
|
||||
spin_lock_init(&as->lock);
|
||||
|
||||
@ -1502,7 +1502,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
as->use_dma = false;
|
||||
as->use_pdc = false;
|
||||
if (as->caps.has_dma_support) {
|
||||
ret = atmel_spi_configure_dma(master, as);
|
||||
ret = atmel_spi_configure_dma(host, as);
|
||||
if (ret == 0) {
|
||||
as->use_dma = true;
|
||||
} else if (ret == -EPROBE_DEFER) {
|
||||
@ -1532,7 +1532,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
if (!as->use_dma)
|
||||
dev_info(master->dev.parent,
|
||||
dev_info(host->dev.parent,
|
||||
" can not allocate dma coherent memory\n");
|
||||
}
|
||||
|
||||
@ -1541,10 +1541,10 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
|
||||
if (as->use_pdc) {
|
||||
ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pdc_interrupt,
|
||||
0, dev_name(&pdev->dev), master);
|
||||
0, dev_name(&pdev->dev), host);
|
||||
} else {
|
||||
ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pio_interrupt,
|
||||
0, dev_name(&pdev->dev), master);
|
||||
0, dev_name(&pdev->dev), host);
|
||||
}
|
||||
if (ret)
|
||||
goto out_unmap_regs;
|
||||
@ -1569,7 +1569,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = devm_spi_register_master(&pdev->dev, master);
|
||||
ret = devm_spi_register_controller(&pdev->dev, host);
|
||||
if (ret)
|
||||
goto out_free_dma;
|
||||
|
||||
@ -1585,28 +1585,28 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
|
||||
if (as->use_dma)
|
||||
atmel_spi_release_dma(master);
|
||||
atmel_spi_release_dma(host);
|
||||
|
||||
spi_writel(as, CR, SPI_BIT(SWRST));
|
||||
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
|
||||
clk_disable_unprepare(clk);
|
||||
out_free_irq:
|
||||
out_unmap_regs:
|
||||
spi_master_put(master);
|
||||
spi_controller_put(host);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int atmel_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct spi_controller *host = platform_get_drvdata(pdev);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
/* reset the hardware and block queue progress */
|
||||
if (as->use_dma) {
|
||||
atmel_spi_stop_dma(master);
|
||||
atmel_spi_release_dma(master);
|
||||
atmel_spi_stop_dma(host);
|
||||
atmel_spi_release_dma(host);
|
||||
if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) {
|
||||
dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER,
|
||||
as->addr_tx_bbuf,
|
||||
@ -1633,8 +1633,8 @@ static int atmel_spi_remove(struct platform_device *pdev)
|
||||
|
||||
static int atmel_spi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct spi_controller *host = dev_get_drvdata(dev);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
|
||||
clk_disable_unprepare(as->clk);
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
@ -1644,8 +1644,8 @@ static int atmel_spi_runtime_suspend(struct device *dev)
|
||||
|
||||
static int atmel_spi_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct spi_controller *host = dev_get_drvdata(dev);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
@ -1654,11 +1654,11 @@ static int atmel_spi_runtime_resume(struct device *dev)
|
||||
|
||||
static int atmel_spi_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct spi_controller *host = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
/* Stop the queue running */
|
||||
ret = spi_master_suspend(master);
|
||||
ret = spi_controller_suspend(host);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1670,8 +1670,8 @@ static int atmel_spi_suspend(struct device *dev)
|
||||
|
||||
static int atmel_spi_resume(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct spi_controller *host = dev_get_drvdata(dev);
|
||||
struct atmel_spi *as = spi_controller_get_devdata(host);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(as->clk);
|
||||
@ -1689,7 +1689,7 @@ static int atmel_spi_resume(struct device *dev)
|
||||
}
|
||||
|
||||
/* Start the queue running */
|
||||
return spi_master_resume(master);
|
||||
return spi_controller_resume(host);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops atmel_spi_pm_ops = {
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
#include <linux/mtd/spi-nor.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
@ -57,6 +59,7 @@
|
||||
#define PINGPONG_CMD_SS_SHIFT 12
|
||||
|
||||
#define HSSPI_PINGPONG_STATUS_REG(x) (0x84 + (x) * 0x40)
|
||||
#define HSSPI_PINGPONG_STATUS_SRC_BUSY BIT(1)
|
||||
|
||||
#define HSSPI_PROFILE_CLK_CTRL_REG(x) (0x100 + (x) * 0x20)
|
||||
#define CLK_CTRL_FREQ_CTRL_MASK 0x0000ffff
|
||||
@ -92,15 +95,42 @@
|
||||
|
||||
#define HSSPI_MAX_PREPEND_LEN 15
|
||||
|
||||
#define HSSPI_MAX_SYNC_CLOCK 30000000
|
||||
/*
|
||||
* Some chip require 30MHz but other require 25MHz. Use smaller value to cover
|
||||
* both cases.
|
||||
*/
|
||||
#define HSSPI_MAX_SYNC_CLOCK 25000000
|
||||
|
||||
#define HSSPI_SPI_MAX_CS 8
|
||||
#define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */
|
||||
#define HSSPI_POLL_STATUS_TIMEOUT_MS 100
|
||||
|
||||
#define HSSPI_WAIT_MODE_POLLING 0
|
||||
#define HSSPI_WAIT_MODE_INTR 1
|
||||
#define HSSPI_WAIT_MODE_MAX HSSPI_WAIT_MODE_INTR
|
||||
|
||||
/*
|
||||
* Default transfer mode is auto. If the msg is prependable, use the prepend
|
||||
* mode. If not, falls back to use the dummy cs workaround mode but limit the
|
||||
* clock to 25MHz to make sure it works in all board design.
|
||||
*/
|
||||
#define HSSPI_XFER_MODE_AUTO 0
|
||||
#define HSSPI_XFER_MODE_PREPEND 1
|
||||
#define HSSPI_XFER_MODE_DUMMYCS 2
|
||||
#define HSSPI_XFER_MODE_MAX HSSPI_XFER_MODE_DUMMYCS
|
||||
|
||||
#define bcm63xx_prepend_printk_on_checkfail(bs, fmt, ...) \
|
||||
do { \
|
||||
if (bs->xfer_mode == HSSPI_XFER_MODE_AUTO) \
|
||||
dev_dbg(&bs->pdev->dev, fmt, ##__VA_ARGS__); \
|
||||
else if (bs->xfer_mode == HSSPI_XFER_MODE_PREPEND) \
|
||||
dev_err(&bs->pdev->dev, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
struct bcm63xx_hsspi {
|
||||
struct completion done;
|
||||
struct mutex bus_mutex;
|
||||
|
||||
struct mutex msg_mutex;
|
||||
struct platform_device *pdev;
|
||||
struct clk *clk;
|
||||
struct clk *pll_clk;
|
||||
@ -109,8 +139,289 @@ struct bcm63xx_hsspi {
|
||||
|
||||
u32 speed_hz;
|
||||
u8 cs_polarity;
|
||||
u32 wait_mode;
|
||||
u32 xfer_mode;
|
||||
u32 prepend_cnt;
|
||||
u8 *prepend_buf;
|
||||
};
|
||||
|
||||
static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_get_drvdata(dev);
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
|
||||
|
||||
return sprintf(buf, "%d\n", bs->wait_mode);
|
||||
}
|
||||
|
||||
static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_get_drvdata(dev);
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
|
||||
u32 val;
|
||||
|
||||
if (kstrtou32(buf, 10, &val))
|
||||
return -EINVAL;
|
||||
|
||||
if (val > HSSPI_WAIT_MODE_MAX) {
|
||||
dev_warn(dev, "invalid wait mode %u\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&bs->msg_mutex);
|
||||
bs->wait_mode = val;
|
||||
/* clear interrupt status to avoid spurious int on next transfer */
|
||||
if (val == HSSPI_WAIT_MODE_INTR)
|
||||
__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
|
||||
mutex_unlock(&bs->msg_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(wait_mode);
|
||||
|
||||
static ssize_t xfer_mode_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_get_drvdata(dev);
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
|
||||
|
||||
return sprintf(buf, "%d\n", bs->xfer_mode);
|
||||
}
|
||||
|
||||
static ssize_t xfer_mode_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_get_drvdata(dev);
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
|
||||
u32 val;
|
||||
|
||||
if (kstrtou32(buf, 10, &val))
|
||||
return -EINVAL;
|
||||
|
||||
if (val > HSSPI_XFER_MODE_MAX) {
|
||||
dev_warn(dev, "invalid xfer mode %u\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&bs->msg_mutex);
|
||||
bs->xfer_mode = val;
|
||||
mutex_unlock(&bs->msg_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(xfer_mode);
|
||||
|
||||
static struct attribute *bcm63xx_hsspi_attrs[] = {
|
||||
&dev_attr_wait_mode.attr,
|
||||
&dev_attr_xfer_mode.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group bcm63xx_hsspi_group = {
|
||||
.attrs = bcm63xx_hsspi_attrs,
|
||||
};
|
||||
|
||||
static void bcm63xx_hsspi_set_clk(struct bcm63xx_hsspi *bs,
|
||||
struct spi_device *spi, int hz);
|
||||
|
||||
static size_t bcm63xx_hsspi_max_message_size(struct spi_device *spi)
|
||||
{
|
||||
return HSSPI_BUFFER_LEN - HSSPI_OPCODE_LEN;
|
||||
}
|
||||
|
||||
static int bcm63xx_hsspi_wait_cmd(struct bcm63xx_hsspi *bs)
|
||||
{
|
||||
unsigned long limit;
|
||||
u32 reg = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (bs->wait_mode == HSSPI_WAIT_MODE_INTR) {
|
||||
if (wait_for_completion_timeout(&bs->done, HZ) == 0)
|
||||
rc = 1;
|
||||
} else {
|
||||
/* polling mode checks for status busy bit */
|
||||
limit = jiffies + msecs_to_jiffies(HSSPI_POLL_STATUS_TIMEOUT_MS);
|
||||
|
||||
while (!time_after(jiffies, limit)) {
|
||||
reg = __raw_readl(bs->regs + HSSPI_PINGPONG_STATUS_REG(0));
|
||||
if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
|
||||
cpu_relax();
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
if (rc)
|
||||
dev_err(&bs->pdev->dev, "transfer timed out!\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool bcm63xx_prepare_prepend_transfer(struct spi_master *master,
|
||||
struct spi_message *msg,
|
||||
struct spi_transfer *t_prepend)
|
||||
{
|
||||
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
|
||||
bool tx_only = false;
|
||||
struct spi_transfer *t;
|
||||
|
||||
/*
|
||||
* Multiple transfers within a message may be combined into one transfer
|
||||
* to the controller using its prepend feature. A SPI message is prependable
|
||||
* only if the following are all true:
|
||||
* 1. One or more half duplex write transfer in single bit mode
|
||||
* 2. Optional full duplex read/write at the end
|
||||
* 3. No delay and cs_change between transfers
|
||||
*/
|
||||
bs->prepend_cnt = 0;
|
||||
list_for_each_entry(t, &msg->transfers, transfer_list) {
|
||||
if ((spi_delay_to_ns(&t->delay, t) > 0) || t->cs_change) {
|
||||
bcm63xx_prepend_printk_on_checkfail(bs,
|
||||
"Delay or cs change not supported in prepend mode!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
tx_only = false;
|
||||
if (t->tx_buf && !t->rx_buf) {
|
||||
tx_only = true;
|
||||
if (bs->prepend_cnt + t->len >
|
||||
(HSSPI_BUFFER_LEN - HSSPI_OPCODE_LEN)) {
|
||||
bcm63xx_prepend_printk_on_checkfail(bs,
|
||||
"exceed max buf len, abort prepending transfers!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t->tx_nbits > SPI_NBITS_SINGLE &&
|
||||
!list_is_last(&t->transfer_list, &msg->transfers)) {
|
||||
bcm63xx_prepend_printk_on_checkfail(bs,
|
||||
"multi-bit prepend buf not supported!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t->tx_nbits == SPI_NBITS_SINGLE) {
|
||||
memcpy(bs->prepend_buf + bs->prepend_cnt, t->tx_buf, t->len);
|
||||
bs->prepend_cnt += t->len;
|
||||
}
|
||||
} else {
|
||||
if (!list_is_last(&t->transfer_list, &msg->transfers)) {
|
||||
bcm63xx_prepend_printk_on_checkfail(bs,
|
||||
"rx/tx_rx transfer not supported when it is not last one!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (list_is_last(&t->transfer_list, &msg->transfers)) {
|
||||
memcpy(t_prepend, t, sizeof(struct spi_transfer));
|
||||
|
||||
if (tx_only && t->tx_nbits == SPI_NBITS_SINGLE) {
|
||||
/*
|
||||
* if the last one is also a single bit tx only transfer, merge
|
||||
* all of them into one single tx transfer
|
||||
*/
|
||||
t_prepend->len = bs->prepend_cnt;
|
||||
t_prepend->tx_buf = bs->prepend_buf;
|
||||
bs->prepend_cnt = 0;
|
||||
} else {
|
||||
/*
|
||||
* if the last one is not a tx only transfer or dual tx xfer, all
|
||||
* the previous transfers are sent through prepend bytes and
|
||||
* make sure it does not exceed the max prepend len
|
||||
*/
|
||||
if (bs->prepend_cnt > HSSPI_MAX_PREPEND_LEN) {
|
||||
bcm63xx_prepend_printk_on_checkfail(bs,
|
||||
"exceed max prepend len, abort prepending transfers!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int bcm63xx_hsspi_do_prepend_txrx(struct spi_device *spi,
|
||||
struct spi_transfer *t)
|
||||
{
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
|
||||
unsigned int chip_select = spi->chip_select;
|
||||
u16 opcode = 0, val;
|
||||
const u8 *tx = t->tx_buf;
|
||||
u8 *rx = t->rx_buf;
|
||||
u32 reg = 0;
|
||||
|
||||
/*
|
||||
* shouldn't happen as we set the max_message_size in the probe.
|
||||
* but check it again in case some driver does not honor the max size
|
||||
*/
|
||||
if (t->len + bs->prepend_cnt > (HSSPI_BUFFER_LEN - HSSPI_OPCODE_LEN)) {
|
||||
dev_warn(&bs->pdev->dev,
|
||||
"Prepend message large than fifo size len %d prepend %d\n",
|
||||
t->len, bs->prepend_cnt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bcm63xx_hsspi_set_clk(bs, spi, t->speed_hz);
|
||||
|
||||
if (tx && rx)
|
||||
opcode = HSSPI_OP_READ_WRITE;
|
||||
else if (tx)
|
||||
opcode = HSSPI_OP_WRITE;
|
||||
else if (rx)
|
||||
opcode = HSSPI_OP_READ;
|
||||
|
||||
if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
|
||||
(opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) {
|
||||
opcode |= HSSPI_OP_MULTIBIT;
|
||||
|
||||
if (t->rx_nbits == SPI_NBITS_DUAL) {
|
||||
reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
|
||||
reg |= bs->prepend_cnt << MODE_CTRL_MULTIDATA_RD_STRT_SHIFT;
|
||||
}
|
||||
if (t->tx_nbits == SPI_NBITS_DUAL) {
|
||||
reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
|
||||
reg |= bs->prepend_cnt << MODE_CTRL_MULTIDATA_WR_STRT_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
reg |= bs->prepend_cnt << MODE_CTRL_PREPENDBYTE_CNT_SHIFT;
|
||||
__raw_writel(reg | 0xff,
|
||||
bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
|
||||
|
||||
reinit_completion(&bs->done);
|
||||
if (bs->prepend_cnt)
|
||||
memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, bs->prepend_buf,
|
||||
bs->prepend_cnt);
|
||||
if (tx)
|
||||
memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN + bs->prepend_cnt, tx,
|
||||
t->len);
|
||||
|
||||
*(__be16 *)(&val) = cpu_to_be16(opcode | t->len);
|
||||
__raw_writew(val, bs->fifo);
|
||||
/* enable interrupt */
|
||||
if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
|
||||
__raw_writel(HSSPI_PINGx_CMD_DONE(0), bs->regs + HSSPI_INT_MASK_REG);
|
||||
|
||||
/* start the transfer */
|
||||
reg = chip_select << PINGPONG_CMD_SS_SHIFT |
|
||||
chip_select << PINGPONG_CMD_PROFILE_SHIFT |
|
||||
PINGPONG_COMMAND_START_NOW;
|
||||
__raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
|
||||
|
||||
if (bcm63xx_hsspi_wait_cmd(bs))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (rx)
|
||||
memcpy_fromio(rx, bs->fifo, t->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned int cs,
|
||||
bool active)
|
||||
{
|
||||
@ -158,14 +469,16 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
|
||||
{
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
|
||||
unsigned int chip_select = spi->chip_select;
|
||||
u16 opcode = 0;
|
||||
u16 opcode = 0, val;
|
||||
int pending = t->len;
|
||||
int step_size = HSSPI_BUFFER_LEN;
|
||||
const u8 *tx = t->tx_buf;
|
||||
u8 *rx = t->rx_buf;
|
||||
u32 reg = 0;
|
||||
|
||||
bcm63xx_hsspi_set_clk(bs, spi, t->speed_hz);
|
||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, true);
|
||||
if (!t->cs_off)
|
||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, true);
|
||||
|
||||
if (tx && rx)
|
||||
opcode = HSSPI_OP_READ_WRITE;
|
||||
@ -178,11 +491,16 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
|
||||
step_size -= HSSPI_OPCODE_LEN;
|
||||
|
||||
if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
|
||||
(opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL))
|
||||
(opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) {
|
||||
opcode |= HSSPI_OP_MULTIBIT;
|
||||
|
||||
__raw_writel(1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT |
|
||||
1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT | 0xff,
|
||||
if (t->rx_nbits == SPI_NBITS_DUAL)
|
||||
reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
|
||||
if (t->tx_nbits == SPI_NBITS_DUAL)
|
||||
reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
|
||||
}
|
||||
|
||||
__raw_writel(reg | 0xff,
|
||||
bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
|
||||
|
||||
while (pending > 0) {
|
||||
@ -194,22 +512,21 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
|
||||
tx += curr_step;
|
||||
}
|
||||
|
||||
__raw_writew(opcode | curr_step, bs->fifo);
|
||||
*(__be16 *)(&val) = cpu_to_be16(opcode | curr_step);
|
||||
__raw_writew(val, bs->fifo);
|
||||
|
||||
/* enable interrupt */
|
||||
__raw_writel(HSSPI_PINGx_CMD_DONE(0),
|
||||
bs->regs + HSSPI_INT_MASK_REG);
|
||||
if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
|
||||
__raw_writel(HSSPI_PINGx_CMD_DONE(0),
|
||||
bs->regs + HSSPI_INT_MASK_REG);
|
||||
|
||||
/* start the transfer */
|
||||
__raw_writel(!chip_select << PINGPONG_CMD_SS_SHIFT |
|
||||
chip_select << PINGPONG_CMD_PROFILE_SHIFT |
|
||||
PINGPONG_COMMAND_START_NOW,
|
||||
bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
|
||||
reg = !chip_select << PINGPONG_CMD_SS_SHIFT |
|
||||
chip_select << PINGPONG_CMD_PROFILE_SHIFT |
|
||||
PINGPONG_COMMAND_START_NOW;
|
||||
__raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
|
||||
|
||||
if (wait_for_completion_timeout(&bs->done, HZ) == 0) {
|
||||
dev_err(&bs->pdev->dev, "transfer timed out!\n");
|
||||
if (bcm63xx_hsspi_wait_cmd(bs))
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (rx) {
|
||||
memcpy_fromio(rx, bs->fifo, curr_step);
|
||||
@ -259,17 +576,17 @@ static int bcm63xx_hsspi_setup(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
|
||||
static int bcm63xx_hsspi_do_dummy_cs_txrx(struct spi_device *spi,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
|
||||
struct spi_transfer *t;
|
||||
struct spi_device *spi = msg->spi;
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(spi->master);
|
||||
int status = -EINVAL;
|
||||
int dummy_cs;
|
||||
u32 reg;
|
||||
bool keep_cs = false;
|
||||
struct spi_transfer *t;
|
||||
|
||||
/* This controller does not support keeping CS active during idle.
|
||||
/*
|
||||
* This controller does not support keeping CS active during idle.
|
||||
* To work around this, we use the following ugly hack:
|
||||
*
|
||||
* a. Invert the target chip select's polarity so it will be active.
|
||||
@ -287,6 +604,21 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
|
||||
bcm63xx_hsspi_set_cs(bs, dummy_cs, true);
|
||||
|
||||
list_for_each_entry(t, &msg->transfers, transfer_list) {
|
||||
/*
|
||||
* We are here because one of reasons below:
|
||||
* a. Message is not prependable and in default auto xfer mode. This mean
|
||||
* we fallback to dummy cs mode at maximum 25MHz safe clock rate.
|
||||
* b. User set to use the dummy cs mode.
|
||||
*/
|
||||
if (bs->xfer_mode == HSSPI_XFER_MODE_AUTO) {
|
||||
if (t->speed_hz > HSSPI_MAX_SYNC_CLOCK) {
|
||||
t->speed_hz = HSSPI_MAX_SYNC_CLOCK;
|
||||
dev_warn_once(&bs->pdev->dev,
|
||||
"Force to dummy cs mode. Reduce the speed to %dHz",
|
||||
t->speed_hz);
|
||||
}
|
||||
}
|
||||
|
||||
status = bcm63xx_hsspi_do_txrx(spi, t);
|
||||
if (status)
|
||||
break;
|
||||
@ -295,23 +627,85 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
|
||||
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (t->cs_change)
|
||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
|
||||
/* use existing cs change logic from spi_transfer_one_message */
|
||||
if (t->cs_change) {
|
||||
if (list_is_last(&t->transfer_list, &msg->transfers)) {
|
||||
keep_cs = true;
|
||||
} else {
|
||||
if (!t->cs_off)
|
||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
|
||||
|
||||
spi_transfer_cs_change_delay_exec(msg, t);
|
||||
|
||||
if (!list_next_entry(t, transfer_list)->cs_off)
|
||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, true);
|
||||
}
|
||||
} else if (!list_is_last(&t->transfer_list, &msg->transfers) &&
|
||||
t->cs_off != list_next_entry(t, transfer_list)->cs_off) {
|
||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, t->cs_off);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&bs->bus_mutex);
|
||||
reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
|
||||
reg &= ~GLOBAL_CTRL_CS_POLARITY_MASK;
|
||||
reg |= bs->cs_polarity;
|
||||
__raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
|
||||
mutex_unlock(&bs->bus_mutex);
|
||||
bcm63xx_hsspi_set_cs(bs, dummy_cs, false);
|
||||
if (status || !keep_cs)
|
||||
bcm63xx_hsspi_set_cs(bs, spi->chip_select, false);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct bcm63xx_hsspi *bs = spi_master_get_devdata(master);
|
||||
struct spi_device *spi = msg->spi;
|
||||
int status = -EINVAL;
|
||||
bool prependable = false;
|
||||
struct spi_transfer t_prepend;
|
||||
|
||||
mutex_lock(&bs->msg_mutex);
|
||||
|
||||
if (bs->xfer_mode != HSSPI_XFER_MODE_DUMMYCS)
|
||||
prependable = bcm63xx_prepare_prepend_transfer(master, msg, &t_prepend);
|
||||
|
||||
if (prependable) {
|
||||
status = bcm63xx_hsspi_do_prepend_txrx(spi, &t_prepend);
|
||||
msg->actual_length = (t_prepend.len + bs->prepend_cnt);
|
||||
} else {
|
||||
if (bs->xfer_mode == HSSPI_XFER_MODE_PREPEND) {
|
||||
dev_err(&bs->pdev->dev,
|
||||
"User sets prepend mode but msg not prependable! Abort transfer\n");
|
||||
status = -EINVAL;
|
||||
} else
|
||||
status = bcm63xx_hsspi_do_dummy_cs_txrx(spi, msg);
|
||||
}
|
||||
|
||||
mutex_unlock(&bs->msg_mutex);
|
||||
msg->status = status;
|
||||
spi_finalize_current_message(master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool bcm63xx_hsspi_mem_supports_op(struct spi_mem *mem,
|
||||
const struct spi_mem_op *op)
|
||||
{
|
||||
if (!spi_mem_default_supports_op(mem, op))
|
||||
return false;
|
||||
|
||||
/* Controller doesn't support spi mem dual io mode */
|
||||
if ((op->cmd.opcode == SPINOR_OP_READ_1_2_2) ||
|
||||
(op->cmd.opcode == SPINOR_OP_READ_1_2_2_4B) ||
|
||||
(op->cmd.opcode == SPINOR_OP_READ_1_2_2_DTR) ||
|
||||
(op->cmd.opcode == SPINOR_OP_READ_1_2_2_DTR_4B))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct spi_controller_mem_ops bcm63xx_hsspi_mem_ops = {
|
||||
.supports_op = bcm63xx_hsspi_mem_supports_op,
|
||||
};
|
||||
|
||||
static irqreturn_t bcm63xx_hsspi_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct bcm63xx_hsspi *bs = (struct bcm63xx_hsspi *)dev_id;
|
||||
@ -398,10 +792,18 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
|
||||
bs->regs = regs;
|
||||
bs->speed_hz = rate;
|
||||
bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
|
||||
bs->wait_mode = HSSPI_WAIT_MODE_POLLING;
|
||||
bs->prepend_buf = devm_kzalloc(dev, HSSPI_BUFFER_LEN, GFP_KERNEL);
|
||||
if (!bs->prepend_buf) {
|
||||
ret = -ENOMEM;
|
||||
goto out_put_master;
|
||||
}
|
||||
|
||||
mutex_init(&bs->bus_mutex);
|
||||
mutex_init(&bs->msg_mutex);
|
||||
init_completion(&bs->done);
|
||||
|
||||
master->mem_ops = &bcm63xx_hsspi_mem_ops;
|
||||
master->dev.of_node = dev->of_node;
|
||||
if (!dev->of_node)
|
||||
master->bus_num = HSSPI_BUS_NUM;
|
||||
@ -415,6 +817,9 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
|
||||
master->num_chipselect = num_cs;
|
||||
master->setup = bcm63xx_hsspi_setup;
|
||||
master->transfer_one_message = bcm63xx_hsspi_transfer_one;
|
||||
master->max_transfer_size = bcm63xx_hsspi_max_message_size;
|
||||
master->max_message_size = bcm63xx_hsspi_max_message_size;
|
||||
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
|
||||
SPI_RX_DUAL | SPI_TX_DUAL;
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||
@ -434,21 +839,33 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
|
||||
__raw_writel(reg | GLOBAL_CTRL_CLK_GATE_SSOFF,
|
||||
bs->regs + HSSPI_GLOBAL_CTRL_REG);
|
||||
|
||||
ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
|
||||
pdev->name, bs);
|
||||
if (irq > 0) {
|
||||
ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
|
||||
pdev->name, bs);
|
||||
|
||||
if (ret)
|
||||
goto out_put_master;
|
||||
if (ret)
|
||||
goto out_put_master;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "couldn't register sysfs group\n");
|
||||
goto out_pm_disable;
|
||||
}
|
||||
|
||||
/* register and we are done */
|
||||
ret = devm_spi_register_master(dev, master);
|
||||
if (ret)
|
||||
goto out_pm_disable;
|
||||
goto out_sysgroup_disable;
|
||||
|
||||
dev_info(dev, "Broadcom 63XX High Speed SPI Controller driver");
|
||||
|
||||
return 0;
|
||||
|
||||
out_sysgroup_disable:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
|
||||
out_pm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
out_put_master:
|
||||
@ -470,6 +887,7 @@ static int bcm63xx_hsspi_remove(struct platform_device *pdev)
|
||||
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
|
||||
clk_disable_unprepare(bs->pll_clk);
|
||||
clk_disable_unprepare(bs->clk);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -516,6 +934,7 @@ static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
|
||||
|
||||
static const struct of_device_id bcm63xx_hsspi_of_match[] = {
|
||||
{ .compatible = "brcm,bcm6328-hsspi", },
|
||||
{ .compatible = "brcm,bcmbca-hsspi-v1.0", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm63xx_hsspi_of_match);
|
||||
|
654
drivers/spi/spi-bcmbca-hsspi.c
Normal file
654
drivers/spi/spi-bcmbca-hsspi.c
Normal file
@ -0,0 +1,654 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Broadcom BCMBCA High Speed SPI Controller driver
|
||||
*
|
||||
* Copyright 2000-2010 Broadcom Corporation
|
||||
* Copyright 2012-2013 Jonas Gorski <jogo@openwrt.org>
|
||||
* Copyright 2019-2022 Broadcom Ltd
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spi/spi-mem.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define HSSPI_GLOBAL_CTRL_REG 0x0
|
||||
#define GLOBAL_CTRL_CS_POLARITY_SHIFT 0
|
||||
#define GLOBAL_CTRL_CS_POLARITY_MASK 0x000000ff
|
||||
#define GLOBAL_CTRL_PLL_CLK_CTRL_SHIFT 8
|
||||
#define GLOBAL_CTRL_PLL_CLK_CTRL_MASK 0x0000ff00
|
||||
#define GLOBAL_CTRL_CLK_GATE_SSOFF BIT(16)
|
||||
#define GLOBAL_CTRL_CLK_POLARITY BIT(17)
|
||||
#define GLOBAL_CTRL_MOSI_IDLE BIT(18)
|
||||
|
||||
#define HSSPI_GLOBAL_EXT_TRIGGER_REG 0x4
|
||||
|
||||
#define HSSPI_INT_STATUS_REG 0x8
|
||||
#define HSSPI_INT_STATUS_MASKED_REG 0xc
|
||||
#define HSSPI_INT_MASK_REG 0x10
|
||||
|
||||
#define HSSPI_PINGx_CMD_DONE(i) BIT((i * 8) + 0)
|
||||
#define HSSPI_PINGx_RX_OVER(i) BIT((i * 8) + 1)
|
||||
#define HSSPI_PINGx_TX_UNDER(i) BIT((i * 8) + 2)
|
||||
#define HSSPI_PINGx_POLL_TIMEOUT(i) BIT((i * 8) + 3)
|
||||
#define HSSPI_PINGx_CTRL_INVAL(i) BIT((i * 8) + 4)
|
||||
|
||||
#define HSSPI_INT_CLEAR_ALL 0xff001f1f
|
||||
|
||||
#define HSSPI_PINGPONG_COMMAND_REG(x) (0x80 + (x) * 0x40)
|
||||
#define PINGPONG_CMD_COMMAND_MASK 0xf
|
||||
#define PINGPONG_COMMAND_NOOP 0
|
||||
#define PINGPONG_COMMAND_START_NOW 1
|
||||
#define PINGPONG_COMMAND_START_TRIGGER 2
|
||||
#define PINGPONG_COMMAND_HALT 3
|
||||
#define PINGPONG_COMMAND_FLUSH 4
|
||||
#define PINGPONG_CMD_PROFILE_SHIFT 8
|
||||
#define PINGPONG_CMD_SS_SHIFT 12
|
||||
|
||||
#define HSSPI_PINGPONG_STATUS_REG(x) (0x84 + (x) * 0x40)
|
||||
#define HSSPI_PINGPONG_STATUS_SRC_BUSY BIT(1)
|
||||
|
||||
#define HSSPI_PROFILE_CLK_CTRL_REG(x) (0x100 + (x) * 0x20)
|
||||
#define CLK_CTRL_FREQ_CTRL_MASK 0x0000ffff
|
||||
#define CLK_CTRL_SPI_CLK_2X_SEL BIT(14)
|
||||
#define CLK_CTRL_ACCUM_RST_ON_LOOP BIT(15)
|
||||
#define CLK_CTRL_CLK_POLARITY BIT(16)
|
||||
|
||||
#define HSSPI_PROFILE_SIGNAL_CTRL_REG(x) (0x104 + (x) * 0x20)
|
||||
#define SIGNAL_CTRL_LATCH_RISING BIT(12)
|
||||
#define SIGNAL_CTRL_LAUNCH_RISING BIT(13)
|
||||
#define SIGNAL_CTRL_ASYNC_INPUT_PATH BIT(16)
|
||||
|
||||
#define HSSPI_PROFILE_MODE_CTRL_REG(x) (0x108 + (x) * 0x20)
|
||||
#define MODE_CTRL_MULTIDATA_RD_STRT_SHIFT 8
|
||||
#define MODE_CTRL_MULTIDATA_WR_STRT_SHIFT 12
|
||||
#define MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT 16
|
||||
#define MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT 18
|
||||
#define MODE_CTRL_MODE_3WIRE BIT(20)
|
||||
#define MODE_CTRL_PREPENDBYTE_CNT_SHIFT 24
|
||||
|
||||
#define HSSPI_FIFO_REG(x) (0x200 + (x) * 0x200)
|
||||
|
||||
#define HSSPI_OP_MULTIBIT BIT(11)
|
||||
#define HSSPI_OP_CODE_SHIFT 13
|
||||
#define HSSPI_OP_SLEEP (0 << HSSPI_OP_CODE_SHIFT)
|
||||
#define HSSPI_OP_READ_WRITE (1 << HSSPI_OP_CODE_SHIFT)
|
||||
#define HSSPI_OP_WRITE (2 << HSSPI_OP_CODE_SHIFT)
|
||||
#define HSSPI_OP_READ (3 << HSSPI_OP_CODE_SHIFT)
|
||||
#define HSSPI_OP_SETIRQ (4 << HSSPI_OP_CODE_SHIFT)
|
||||
|
||||
#define HSSPI_BUFFER_LEN 512
|
||||
#define HSSPI_OPCODE_LEN 2
|
||||
|
||||
#define HSSPI_MAX_PREPEND_LEN 15
|
||||
|
||||
#define HSSPI_MAX_SYNC_CLOCK 30000000
|
||||
|
||||
#define HSSPI_SPI_MAX_CS 8
|
||||
#define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */
|
||||
#define HSSPI_POLL_STATUS_TIMEOUT_MS 100
|
||||
|
||||
#define HSSPI_WAIT_MODE_POLLING 0
|
||||
#define HSSPI_WAIT_MODE_INTR 1
|
||||
#define HSSPI_WAIT_MODE_MAX HSSPI_WAIT_MODE_INTR
|
||||
|
||||
#define SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT 0
|
||||
#define SPIM_CTRL_CS_OVERRIDE_SEL_MASK 0xff
|
||||
#define SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT 8
|
||||
#define SPIM_CTRL_CS_OVERRIDE_VAL_MASK 0xff
|
||||
|
||||
struct bcmbca_hsspi {
|
||||
struct completion done;
|
||||
struct mutex bus_mutex;
|
||||
struct mutex msg_mutex;
|
||||
struct platform_device *pdev;
|
||||
struct clk *clk;
|
||||
struct clk *pll_clk;
|
||||
void __iomem *regs;
|
||||
void __iomem *spim_ctrl;
|
||||
u8 __iomem *fifo;
|
||||
u32 speed_hz;
|
||||
u8 cs_polarity;
|
||||
u32 wait_mode;
|
||||
};
|
||||
|
||||
static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_get_drvdata(dev);
|
||||
struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
|
||||
|
||||
return sprintf(buf, "%d\n", bs->wait_mode);
|
||||
}
|
||||
|
||||
static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct spi_controller *ctrl = dev_get_drvdata(dev);
|
||||
struct bcmbca_hsspi *bs = spi_master_get_devdata(ctrl);
|
||||
u32 val;
|
||||
|
||||
if (kstrtou32(buf, 10, &val))
|
||||
return -EINVAL;
|
||||
|
||||
if (val > HSSPI_WAIT_MODE_MAX) {
|
||||
dev_warn(dev, "invalid wait mode %u\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&bs->msg_mutex);
|
||||
bs->wait_mode = val;
|
||||
/* clear interrupt status to avoid spurious int on next transfer */
|
||||
if (val == HSSPI_WAIT_MODE_INTR)
|
||||
__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
|
||||
mutex_unlock(&bs->msg_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(wait_mode);
|
||||
|
||||
static struct attribute *bcmbca_hsspi_attrs[] = {
|
||||
&dev_attr_wait_mode.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group bcmbca_hsspi_group = {
|
||||
.attrs = bcmbca_hsspi_attrs,
|
||||
};
|
||||
|
||||
static void bcmbca_hsspi_set_cs(struct bcmbca_hsspi *bs, unsigned int cs,
|
||||
bool active)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* No cs orerriden needed for SS7 internal cs on pcm based voice dev */
|
||||
if (cs == 7)
|
||||
return;
|
||||
|
||||
mutex_lock(&bs->bus_mutex);
|
||||
|
||||
reg = __raw_readl(bs->spim_ctrl);
|
||||
if (active)
|
||||
reg |= BIT(cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
|
||||
else
|
||||
reg &= ~BIT(cs + SPIM_CTRL_CS_OVERRIDE_SEL_SHIFT);
|
||||
|
||||
__raw_writel(reg, bs->spim_ctrl);
|
||||
|
||||
mutex_unlock(&bs->bus_mutex);
|
||||
}
|
||||
|
||||
static void bcmbca_hsspi_set_clk(struct bcmbca_hsspi *bs,
|
||||
struct spi_device *spi, int hz)
|
||||
{
|
||||
unsigned int profile = spi->chip_select;
|
||||
u32 reg;
|
||||
|
||||
reg = DIV_ROUND_UP(2048, DIV_ROUND_UP(bs->speed_hz, hz));
|
||||
__raw_writel(CLK_CTRL_ACCUM_RST_ON_LOOP | reg,
|
||||
bs->regs + HSSPI_PROFILE_CLK_CTRL_REG(profile));
|
||||
|
||||
reg = __raw_readl(bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
|
||||
if (hz > HSSPI_MAX_SYNC_CLOCK)
|
||||
reg |= SIGNAL_CTRL_ASYNC_INPUT_PATH;
|
||||
else
|
||||
reg &= ~SIGNAL_CTRL_ASYNC_INPUT_PATH;
|
||||
__raw_writel(reg, bs->regs + HSSPI_PROFILE_SIGNAL_CTRL_REG(profile));
|
||||
|
||||
mutex_lock(&bs->bus_mutex);
|
||||
/* setup clock polarity */
|
||||
reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
|
||||
reg &= ~GLOBAL_CTRL_CLK_POLARITY;
|
||||
if (spi->mode & SPI_CPOL)
|
||||
reg |= GLOBAL_CTRL_CLK_POLARITY;
|
||||
__raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
|
||||
|
||||
mutex_unlock(&bs->bus_mutex);
|
||||
}
|
||||
|
||||
static int bcmbca_hsspi_wait_cmd(struct bcmbca_hsspi *bs, unsigned int cs)
|
||||
{
|
||||
unsigned long limit;
|
||||
u32 reg = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (bs->wait_mode == HSSPI_WAIT_MODE_INTR) {
|
||||
if (wait_for_completion_timeout(&bs->done, HZ) == 0)
|
||||
rc = 1;
|
||||
} else {
|
||||
limit = jiffies + msecs_to_jiffies(HSSPI_POLL_STATUS_TIMEOUT_MS);
|
||||
|
||||
while (!time_after(jiffies, limit)) {
|
||||
reg = __raw_readl(bs->regs + HSSPI_PINGPONG_STATUS_REG(0));
|
||||
if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
|
||||
cpu_relax();
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (reg & HSSPI_PINGPONG_STATUS_SRC_BUSY)
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
if (rc)
|
||||
dev_err(&bs->pdev->dev, "transfer timed out!\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int bcmbca_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
|
||||
unsigned int chip_select = spi->chip_select;
|
||||
u16 opcode = 0, val;
|
||||
int pending = t->len;
|
||||
int step_size = HSSPI_BUFFER_LEN;
|
||||
const u8 *tx = t->tx_buf;
|
||||
u8 *rx = t->rx_buf;
|
||||
u32 reg = 0, cs_act = 0;
|
||||
|
||||
bcmbca_hsspi_set_clk(bs, spi, t->speed_hz);
|
||||
|
||||
if (tx && rx)
|
||||
opcode = HSSPI_OP_READ_WRITE;
|
||||
else if (tx)
|
||||
opcode = HSSPI_OP_WRITE;
|
||||
else if (rx)
|
||||
opcode = HSSPI_OP_READ;
|
||||
|
||||
if (opcode != HSSPI_OP_READ)
|
||||
step_size -= HSSPI_OPCODE_LEN;
|
||||
|
||||
if ((opcode == HSSPI_OP_READ && t->rx_nbits == SPI_NBITS_DUAL) ||
|
||||
(opcode == HSSPI_OP_WRITE && t->tx_nbits == SPI_NBITS_DUAL)) {
|
||||
opcode |= HSSPI_OP_MULTIBIT;
|
||||
|
||||
if (t->rx_nbits == SPI_NBITS_DUAL)
|
||||
reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
|
||||
if (t->tx_nbits == SPI_NBITS_DUAL)
|
||||
reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
|
||||
}
|
||||
|
||||
__raw_writel(reg | 0xff,
|
||||
bs->regs + HSSPI_PROFILE_MODE_CTRL_REG(chip_select));
|
||||
|
||||
while (pending > 0) {
|
||||
int curr_step = min_t(int, step_size, pending);
|
||||
|
||||
reinit_completion(&bs->done);
|
||||
if (tx) {
|
||||
memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
|
||||
tx += curr_step;
|
||||
}
|
||||
|
||||
*(__be16 *)(&val) = cpu_to_be16(opcode | curr_step);
|
||||
__raw_writew(val, bs->fifo);
|
||||
|
||||
/* enable interrupt */
|
||||
if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
|
||||
__raw_writel(HSSPI_PINGx_CMD_DONE(0),
|
||||
bs->regs + HSSPI_INT_MASK_REG);
|
||||
|
||||
if (!cs_act) {
|
||||
/* must apply cs signal as close as the cmd starts */
|
||||
bcmbca_hsspi_set_cs(bs, chip_select, true);
|
||||
cs_act = 1;
|
||||
}
|
||||
|
||||
reg = chip_select << PINGPONG_CMD_SS_SHIFT |
|
||||
chip_select << PINGPONG_CMD_PROFILE_SHIFT |
|
||||
PINGPONG_COMMAND_START_NOW;
|
||||
__raw_writel(reg, bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
|
||||
|
||||
if (bcmbca_hsspi_wait_cmd(bs, spi->chip_select))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
pending -= curr_step;
|
||||
|
||||
if (rx) {
|
||||
memcpy_fromio(rx, bs->fifo, curr_step);
|
||||
rx += curr_step;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcmbca_hsspi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct bcmbca_hsspi *bs = spi_master_get_devdata(spi->master);
|
||||
u32 reg;
|
||||
|
||||
reg = __raw_readl(bs->regs +
|
||||
HSSPI_PROFILE_SIGNAL_CTRL_REG(spi->chip_select));
|
||||
reg &= ~(SIGNAL_CTRL_LAUNCH_RISING | SIGNAL_CTRL_LATCH_RISING);
|
||||
if (spi->mode & SPI_CPHA)
|
||||
reg |= SIGNAL_CTRL_LAUNCH_RISING;
|
||||
else
|
||||
reg |= SIGNAL_CTRL_LATCH_RISING;
|
||||
__raw_writel(reg, bs->regs +
|
||||
HSSPI_PROFILE_SIGNAL_CTRL_REG(spi->chip_select));
|
||||
|
||||
mutex_lock(&bs->bus_mutex);
|
||||
reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
|
||||
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
reg |= BIT(spi->chip_select);
|
||||
else
|
||||
reg &= ~BIT(spi->chip_select);
|
||||
__raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
|
||||
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
bs->cs_polarity |= BIT(spi->chip_select);
|
||||
else
|
||||
bs->cs_polarity &= ~BIT(spi->chip_select);
|
||||
|
||||
reg = __raw_readl(bs->spim_ctrl);
|
||||
reg &= ~BIT(spi->chip_select + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
reg |= BIT(spi->chip_select + SPIM_CTRL_CS_OVERRIDE_VAL_SHIFT);
|
||||
__raw_writel(reg, bs->spim_ctrl);
|
||||
|
||||
mutex_unlock(&bs->bus_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcmbca_hsspi_transfer_one(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
|
||||
struct spi_transfer *t;
|
||||
struct spi_device *spi = msg->spi;
|
||||
int status = -EINVAL;
|
||||
bool keep_cs = false;
|
||||
|
||||
mutex_lock(&bs->msg_mutex);
|
||||
list_for_each_entry(t, &msg->transfers, transfer_list) {
|
||||
status = bcmbca_hsspi_do_txrx(spi, t, msg);
|
||||
if (status)
|
||||
break;
|
||||
|
||||
spi_transfer_delay_exec(t);
|
||||
|
||||
if (t->cs_change) {
|
||||
if (list_is_last(&t->transfer_list, &msg->transfers)) {
|
||||
keep_cs = true;
|
||||
} else {
|
||||
if (!t->cs_off)
|
||||
bcmbca_hsspi_set_cs(bs, spi->chip_select, false);
|
||||
|
||||
spi_transfer_cs_change_delay_exec(msg, t);
|
||||
|
||||
if (!list_next_entry(t, transfer_list)->cs_off)
|
||||
bcmbca_hsspi_set_cs(bs, spi->chip_select, true);
|
||||
}
|
||||
} else if (!list_is_last(&t->transfer_list, &msg->transfers) &&
|
||||
t->cs_off != list_next_entry(t, transfer_list)->cs_off) {
|
||||
bcmbca_hsspi_set_cs(bs, spi->chip_select, t->cs_off);
|
||||
}
|
||||
|
||||
msg->actual_length += t->len;
|
||||
}
|
||||
|
||||
mutex_unlock(&bs->msg_mutex);
|
||||
|
||||
if (status || !keep_cs)
|
||||
bcmbca_hsspi_set_cs(bs, spi->chip_select, false);
|
||||
|
||||
msg->status = status;
|
||||
spi_finalize_current_message(master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t bcmbca_hsspi_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct bcmbca_hsspi *bs = (struct bcmbca_hsspi *)dev_id;
|
||||
|
||||
if (__raw_readl(bs->regs + HSSPI_INT_STATUS_MASKED_REG) == 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
|
||||
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
|
||||
|
||||
complete(&bs->done);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int bcmbca_hsspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct bcmbca_hsspi *bs;
|
||||
struct resource *res_mem;
|
||||
void __iomem *spim_ctrl;
|
||||
void __iomem *regs;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk *clk, *pll_clk = NULL;
|
||||
int irq, ret;
|
||||
u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hsspi");
|
||||
if (!res_mem)
|
||||
return -EINVAL;
|
||||
regs = devm_ioremap_resource(dev, res_mem);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spim-ctrl");
|
||||
if (!res_mem)
|
||||
return -EINVAL;
|
||||
spim_ctrl = devm_ioremap_resource(dev, res_mem);
|
||||
if (IS_ERR(spim_ctrl))
|
||||
return PTR_ERR(spim_ctrl);
|
||||
|
||||
clk = devm_clk_get(dev, "hsspi");
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
if (!rate) {
|
||||
pll_clk = devm_clk_get(dev, "pll");
|
||||
|
||||
if (IS_ERR(pll_clk)) {
|
||||
ret = PTR_ERR(pll_clk);
|
||||
goto out_disable_clk;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(pll_clk);
|
||||
if (ret)
|
||||
goto out_disable_clk;
|
||||
|
||||
rate = clk_get_rate(pll_clk);
|
||||
if (!rate) {
|
||||
ret = -EINVAL;
|
||||
goto out_disable_pll_clk;
|
||||
}
|
||||
}
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*bs));
|
||||
if (!master) {
|
||||
ret = -ENOMEM;
|
||||
goto out_disable_pll_clk;
|
||||
}
|
||||
|
||||
bs = spi_master_get_devdata(master);
|
||||
bs->pdev = pdev;
|
||||
bs->clk = clk;
|
||||
bs->pll_clk = pll_clk;
|
||||
bs->regs = regs;
|
||||
bs->spim_ctrl = spim_ctrl;
|
||||
bs->speed_hz = rate;
|
||||
bs->fifo = (u8 __iomem *) (bs->regs + HSSPI_FIFO_REG(0));
|
||||
bs->wait_mode = HSSPI_WAIT_MODE_POLLING;
|
||||
|
||||
mutex_init(&bs->bus_mutex);
|
||||
mutex_init(&bs->msg_mutex);
|
||||
init_completion(&bs->done);
|
||||
|
||||
master->dev.of_node = dev->of_node;
|
||||
if (!dev->of_node)
|
||||
master->bus_num = HSSPI_BUS_NUM;
|
||||
|
||||
of_property_read_u32(dev->of_node, "num-cs", &num_cs);
|
||||
if (num_cs > 8) {
|
||||
dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n",
|
||||
num_cs);
|
||||
num_cs = HSSPI_SPI_MAX_CS;
|
||||
}
|
||||
master->num_chipselect = num_cs;
|
||||
master->setup = bcmbca_hsspi_setup;
|
||||
master->transfer_one_message = bcmbca_hsspi_transfer_one;
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
|
||||
SPI_RX_DUAL | SPI_TX_DUAL;
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||
master->auto_runtime_pm = true;
|
||||
|
||||
platform_set_drvdata(pdev, master);
|
||||
|
||||
/* Initialize the hardware */
|
||||
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
|
||||
|
||||
/* clean up any pending interrupts */
|
||||
__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
|
||||
|
||||
/* read out default CS polarities */
|
||||
reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG);
|
||||
bs->cs_polarity = reg & GLOBAL_CTRL_CS_POLARITY_MASK;
|
||||
__raw_writel(reg | GLOBAL_CTRL_CLK_GATE_SSOFF,
|
||||
bs->regs + HSSPI_GLOBAL_CTRL_REG);
|
||||
|
||||
if (irq > 0) {
|
||||
ret = devm_request_irq(dev, irq, bcmbca_hsspi_interrupt, IRQF_SHARED,
|
||||
pdev->name, bs);
|
||||
if (ret)
|
||||
goto out_put_master;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "couldn't register sysfs group\n");
|
||||
goto out_pm_disable;
|
||||
}
|
||||
|
||||
/* register and we are done */
|
||||
ret = devm_spi_register_master(dev, master);
|
||||
if (ret)
|
||||
goto out_sysgroup_disable;
|
||||
|
||||
dev_info(dev, "Broadcom BCMBCA High Speed SPI Controller driver");
|
||||
|
||||
return 0;
|
||||
|
||||
out_sysgroup_disable:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
|
||||
out_pm_disable:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
out_put_master:
|
||||
spi_master_put(master);
|
||||
out_disable_pll_clk:
|
||||
clk_disable_unprepare(pll_clk);
|
||||
out_disable_clk:
|
||||
clk_disable_unprepare(clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bcmbca_hsspi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
|
||||
|
||||
/* reset the hardware and block queue progress */
|
||||
__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
|
||||
clk_disable_unprepare(bs->pll_clk);
|
||||
clk_disable_unprepare(bs->clk);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &bcmbca_hsspi_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int bcmbca_hsspi_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
|
||||
|
||||
spi_master_suspend(master);
|
||||
clk_disable_unprepare(bs->pll_clk);
|
||||
clk_disable_unprepare(bs->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcmbca_hsspi_resume(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct bcmbca_hsspi *bs = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(bs->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (bs->pll_clk) {
|
||||
ret = clk_prepare_enable(bs->pll_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(bs->clk);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
spi_master_resume(master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(bcmbca_hsspi_pm_ops, bcmbca_hsspi_suspend,
|
||||
bcmbca_hsspi_resume);
|
||||
|
||||
static const struct of_device_id bcmbca_hsspi_of_match[] = {
|
||||
{ .compatible = "brcm,bcmbca-hsspi-v1.1", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, bcmbca_hsspi_of_match);
|
||||
|
||||
static struct platform_driver bcmbca_hsspi_driver = {
|
||||
.driver = {
|
||||
.name = "bcmbca-hsspi",
|
||||
.pm = &bcmbca_hsspi_pm_ops,
|
||||
.of_match_table = bcmbca_hsspi_of_match,
|
||||
},
|
||||
.probe = bcmbca_hsspi_probe,
|
||||
.remove = bcmbca_hsspi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(bcmbca_hsspi_driver);
|
||||
|
||||
MODULE_ALIAS("platform:bcmbca_hsspi");
|
||||
MODULE_DESCRIPTION("Broadcom BCMBCA High Speed SPI Controller driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -84,6 +84,7 @@ struct cqspi_st {
|
||||
u32 trigger_address;
|
||||
u32 wr_delay;
|
||||
bool use_direct_mode;
|
||||
bool use_direct_mode_wr;
|
||||
struct cqspi_flash_pdata f_pdata[CQSPI_MAX_CHIPSELECT];
|
||||
bool use_dma_read;
|
||||
u32 pd_dev_id;
|
||||
@ -531,6 +532,17 @@ static int cqspi_command_read(struct cqspi_flash_pdata *f_pdata,
|
||||
/* 0 means 1 byte. */
|
||||
reg |= (((n_rx - 1) & CQSPI_REG_CMDCTRL_RD_BYTES_MASK)
|
||||
<< CQSPI_REG_CMDCTRL_RD_BYTES_LSB);
|
||||
|
||||
/* setup ADDR BIT field */
|
||||
if (op->addr.nbytes) {
|
||||
reg |= (0x1 << CQSPI_REG_CMDCTRL_ADDR_EN_LSB);
|
||||
reg |= ((op->addr.nbytes - 1) &
|
||||
CQSPI_REG_CMDCTRL_ADD_BYTES_MASK)
|
||||
<< CQSPI_REG_CMDCTRL_ADD_BYTES_LSB;
|
||||
|
||||
writel(op->addr.val, reg_base + CQSPI_REG_CMDADDRESS);
|
||||
}
|
||||
|
||||
status = cqspi_exec_flash_cmd(cqspi, reg);
|
||||
if (status)
|
||||
return status;
|
||||
@ -549,6 +561,9 @@ static int cqspi_command_read(struct cqspi_flash_pdata *f_pdata,
|
||||
memcpy(rxbuf, ®, read_len);
|
||||
}
|
||||
|
||||
/* Reset CMD_CTRL Reg once command read completes */
|
||||
writel(0, reg_base + CQSPI_REG_CMDCTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -613,7 +628,12 @@ static int cqspi_command_write(struct cqspi_flash_pdata *f_pdata,
|
||||
}
|
||||
}
|
||||
|
||||
return cqspi_exec_flash_cmd(cqspi, reg);
|
||||
ret = cqspi_exec_flash_cmd(cqspi, reg);
|
||||
|
||||
/* Reset CMD_CTRL Reg once command write completes */
|
||||
writel(0, reg_base + CQSPI_REG_CMDCTRL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata,
|
||||
@ -937,6 +957,12 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata,
|
||||
reg = readl(reg_base + CQSPI_REG_WR_COMPLETION_CTRL);
|
||||
reg |= CQSPI_REG_WR_DISABLE_AUTO_POLL;
|
||||
writel(reg, reg_base + CQSPI_REG_WR_COMPLETION_CTRL);
|
||||
/*
|
||||
* DAC mode require auto polling as flash needs to be polled
|
||||
* for write completion in case of bubble in SPI transaction
|
||||
* due to slow CPU/DMA master.
|
||||
*/
|
||||
cqspi->use_direct_mode_wr = false;
|
||||
}
|
||||
|
||||
reg = readl(reg_base + CQSPI_REG_SIZE);
|
||||
@ -1222,7 +1248,7 @@ static ssize_t cqspi_write(struct cqspi_flash_pdata *f_pdata,
|
||||
* data.
|
||||
*/
|
||||
if (!op->cmd.dtr && cqspi->use_direct_mode &&
|
||||
((to + len) <= cqspi->ahb_size)) {
|
||||
cqspi->use_direct_mode_wr && ((to + len) <= cqspi->ahb_size)) {
|
||||
memcpy_toio(cqspi->ahb_base + to, buf, len);
|
||||
return cqspi_wait_idle(cqspi);
|
||||
}
|
||||
@ -1333,7 +1359,13 @@ static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
|
||||
cqspi_configure(f_pdata, mem->spi->max_speed_hz);
|
||||
|
||||
if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
|
||||
if (!op->addr.nbytes)
|
||||
/*
|
||||
* Performing reads in DAC mode forces to read minimum 4 bytes
|
||||
* which is unsupported on some flash devices during register
|
||||
* reads, prefer STIG mode for such small reads.
|
||||
*/
|
||||
if (!op->addr.nbytes ||
|
||||
op->data.nbytes <= CQSPI_STIG_DATA_LEN_MAX)
|
||||
return cqspi_command_read(f_pdata, op);
|
||||
|
||||
return cqspi_read(f_pdata, op);
|
||||
@ -1692,8 +1724,10 @@ static int cqspi_probe(struct platform_device *pdev)
|
||||
cqspi->master_ref_clk_hz);
|
||||
if (ddata->hwcaps_mask & CQSPI_SUPPORTS_OCTAL)
|
||||
master->mode_bits |= SPI_RX_OCTAL | SPI_TX_OCTAL;
|
||||
if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE))
|
||||
if (!(ddata->quirks & CQSPI_DISABLE_DAC_MODE)) {
|
||||
cqspi->use_direct_mode = true;
|
||||
cqspi->use_direct_mode_wr = true;
|
||||
}
|
||||
if (ddata->quirks & CQSPI_SUPPORT_EXTERNAL_DMA)
|
||||
cqspi->use_dma_read = true;
|
||||
if (ddata->quirks & CQSPI_NO_SUPPORT_WR_COMPLETION)
|
||||
|
@ -87,6 +87,8 @@ struct spi_geni_master {
|
||||
struct completion cs_done;
|
||||
struct completion cancel_done;
|
||||
struct completion abort_done;
|
||||
struct completion tx_reset_done;
|
||||
struct completion rx_reset_done;
|
||||
unsigned int oversampling;
|
||||
spinlock_t lock;
|
||||
int irq;
|
||||
@ -95,6 +97,8 @@ struct spi_geni_master {
|
||||
struct dma_chan *tx;
|
||||
struct dma_chan *rx;
|
||||
int cur_xfer_mode;
|
||||
dma_addr_t tx_se_dma;
|
||||
dma_addr_t rx_se_dma;
|
||||
};
|
||||
|
||||
static int get_spi_clk_cfg(unsigned int speed_hz,
|
||||
@ -129,23 +133,27 @@ static int get_spi_clk_cfg(unsigned int speed_hz,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void handle_fifo_timeout(struct spi_master *spi,
|
||||
static void handle_se_timeout(struct spi_master *spi,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||
unsigned long time_left;
|
||||
struct geni_se *se = &mas->se;
|
||||
const struct spi_transfer *xfer;
|
||||
|
||||
spin_lock_irq(&mas->lock);
|
||||
reinit_completion(&mas->cancel_done);
|
||||
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
if (mas->cur_xfer_mode == GENI_SE_FIFO)
|
||||
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
|
||||
xfer = mas->cur_xfer;
|
||||
mas->cur_xfer = NULL;
|
||||
geni_se_cancel_m_cmd(se);
|
||||
spin_unlock_irq(&mas->lock);
|
||||
|
||||
time_left = wait_for_completion_timeout(&mas->cancel_done, HZ);
|
||||
if (time_left)
|
||||
return;
|
||||
goto unmap_if_dma;
|
||||
|
||||
spin_lock_irq(&mas->lock);
|
||||
reinit_completion(&mas->abort_done);
|
||||
@ -162,6 +170,39 @@ static void handle_fifo_timeout(struct spi_master *spi,
|
||||
*/
|
||||
mas->abort_failed = true;
|
||||
}
|
||||
|
||||
unmap_if_dma:
|
||||
if (mas->cur_xfer_mode == GENI_SE_DMA) {
|
||||
if (xfer) {
|
||||
if (xfer->tx_buf && mas->tx_se_dma) {
|
||||
spin_lock_irq(&mas->lock);
|
||||
reinit_completion(&mas->tx_reset_done);
|
||||
writel(1, se->base + SE_DMA_TX_FSM_RST);
|
||||
spin_unlock_irq(&mas->lock);
|
||||
time_left = wait_for_completion_timeout(&mas->tx_reset_done, HZ);
|
||||
if (!time_left)
|
||||
dev_err(mas->dev, "DMA TX RESET failed\n");
|
||||
geni_se_tx_dma_unprep(se, mas->tx_se_dma, xfer->len);
|
||||
}
|
||||
if (xfer->rx_buf && mas->rx_se_dma) {
|
||||
spin_lock_irq(&mas->lock);
|
||||
reinit_completion(&mas->rx_reset_done);
|
||||
writel(1, se->base + SE_DMA_RX_FSM_RST);
|
||||
spin_unlock_irq(&mas->lock);
|
||||
time_left = wait_for_completion_timeout(&mas->rx_reset_done, HZ);
|
||||
if (!time_left)
|
||||
dev_err(mas->dev, "DMA RX RESET failed\n");
|
||||
geni_se_rx_dma_unprep(se, mas->rx_se_dma, xfer->len);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This can happen if a timeout happened and we had to wait
|
||||
* for lock in this function because isr was holding the lock
|
||||
* and handling transfer completion at that time.
|
||||
*/
|
||||
dev_warn(mas->dev, "Cancel/Abort on completed SPI transfer\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_gpi_timeout(struct spi_master *spi, struct spi_message *msg)
|
||||
@ -178,7 +219,8 @@ static void spi_geni_handle_err(struct spi_master *spi, struct spi_message *msg)
|
||||
|
||||
switch (mas->cur_xfer_mode) {
|
||||
case GENI_SE_FIFO:
|
||||
handle_fifo_timeout(spi, msg);
|
||||
case GENI_SE_DMA:
|
||||
handle_se_timeout(spi, msg);
|
||||
break;
|
||||
case GENI_GPI_DMA:
|
||||
handle_gpi_timeout(spi, msg);
|
||||
@ -250,6 +292,8 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
|
||||
}
|
||||
|
||||
mas->cs_flag = set_flag;
|
||||
/* set xfer_mode to FIFO to complete cs_done in isr */
|
||||
mas->cur_xfer_mode = GENI_SE_FIFO;
|
||||
reinit_completion(&mas->cs_done);
|
||||
if (set_flag)
|
||||
geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0);
|
||||
@ -260,7 +304,7 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
|
||||
time_left = wait_for_completion_timeout(&mas->cs_done, HZ);
|
||||
if (!time_left) {
|
||||
dev_warn(mas->dev, "Timeout setting chip select\n");
|
||||
handle_fifo_timeout(spi, NULL);
|
||||
handle_se_timeout(spi, NULL);
|
||||
}
|
||||
|
||||
exit:
|
||||
@ -482,8 +526,12 @@ static bool geni_can_dma(struct spi_controller *ctlr,
|
||||
{
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(slv->master);
|
||||
|
||||
/* check if dma is supported */
|
||||
return mas->cur_xfer_mode != GENI_SE_FIFO;
|
||||
/*
|
||||
* Return true if transfer needs to be mapped prior to
|
||||
* calling transfer_one which is the case only for GPI_DMA.
|
||||
* For SE_DMA mode, map/unmap is done in geni_se_*x_dma_prep.
|
||||
*/
|
||||
return mas->cur_xfer_mode == GENI_GPI_DMA;
|
||||
}
|
||||
|
||||
static int spi_geni_prepare_message(struct spi_master *spi,
|
||||
@ -494,6 +542,7 @@ static int spi_geni_prepare_message(struct spi_master *spi,
|
||||
|
||||
switch (mas->cur_xfer_mode) {
|
||||
case GENI_SE_FIFO:
|
||||
case GENI_SE_DMA:
|
||||
if (spi_geni_is_abort_still_pending(mas))
|
||||
return -EBUSY;
|
||||
ret = setup_fifo_params(spi_msg->spi, spi);
|
||||
@ -597,7 +646,7 @@ static int spi_geni_init(struct spi_geni_master *mas)
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* in case of failure to get dma channel, we can still do the
|
||||
* in case of failure to get gpi dma channel, we can still do the
|
||||
* FIFO mode, so fallthrough
|
||||
*/
|
||||
dev_warn(mas->dev, "FIFO mode disabled, but couldn't get DMA, fall back to FIFO mode\n");
|
||||
@ -716,12 +765,12 @@ static void geni_spi_handle_rx(struct spi_geni_master *mas)
|
||||
mas->rx_rem_bytes -= rx_bytes;
|
||||
}
|
||||
|
||||
static void setup_fifo_xfer(struct spi_transfer *xfer,
|
||||
static int setup_se_xfer(struct spi_transfer *xfer,
|
||||
struct spi_geni_master *mas,
|
||||
u16 mode, struct spi_master *spi)
|
||||
{
|
||||
u32 m_cmd = 0;
|
||||
u32 len;
|
||||
u32 len, fifo_size;
|
||||
struct geni_se *se = &mas->se;
|
||||
int ret;
|
||||
|
||||
@ -748,7 +797,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
|
||||
/* Speed and bits per word can be overridden per transfer */
|
||||
ret = geni_spi_set_clock_and_bw(mas, xfer->speed_hz);
|
||||
if (ret)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
mas->tx_rem_bytes = 0;
|
||||
mas->rx_rem_bytes = 0;
|
||||
@ -772,17 +821,50 @@ static void setup_fifo_xfer(struct spi_transfer *xfer,
|
||||
mas->rx_rem_bytes = xfer->len;
|
||||
}
|
||||
|
||||
/* Select transfer mode based on transfer length */
|
||||
fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / mas->cur_bits_per_word;
|
||||
mas->cur_xfer_mode = (len <= fifo_size) ? GENI_SE_FIFO : GENI_SE_DMA;
|
||||
geni_se_select_mode(se, mas->cur_xfer_mode);
|
||||
|
||||
/*
|
||||
* Lock around right before we start the transfer since our
|
||||
* interrupt could come in at any time now.
|
||||
*/
|
||||
spin_lock_irq(&mas->lock);
|
||||
geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION);
|
||||
if (m_cmd & SPI_TX_ONLY) {
|
||||
|
||||
if (mas->cur_xfer_mode == GENI_SE_DMA) {
|
||||
if (m_cmd & SPI_RX_ONLY) {
|
||||
ret = geni_se_rx_dma_prep(se, xfer->rx_buf,
|
||||
xfer->len, &mas->rx_se_dma);
|
||||
if (ret) {
|
||||
dev_err(mas->dev, "Failed to setup Rx dma %d\n", ret);
|
||||
mas->rx_se_dma = 0;
|
||||
goto unlock_and_return;
|
||||
}
|
||||
}
|
||||
if (m_cmd & SPI_TX_ONLY) {
|
||||
ret = geni_se_tx_dma_prep(se, (void *)xfer->tx_buf,
|
||||
xfer->len, &mas->tx_se_dma);
|
||||
if (ret) {
|
||||
dev_err(mas->dev, "Failed to setup Tx dma %d\n", ret);
|
||||
mas->tx_se_dma = 0;
|
||||
if (m_cmd & SPI_RX_ONLY) {
|
||||
/* Unmap rx buffer if duplex transfer */
|
||||
geni_se_rx_dma_unprep(se, mas->rx_se_dma, xfer->len);
|
||||
mas->rx_se_dma = 0;
|
||||
}
|
||||
goto unlock_and_return;
|
||||
}
|
||||
}
|
||||
} else if (m_cmd & SPI_TX_ONLY) {
|
||||
if (geni_spi_handle_tx(mas))
|
||||
writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
}
|
||||
|
||||
unlock_and_return:
|
||||
spin_unlock_irq(&mas->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_geni_transfer_one(struct spi_master *spi,
|
||||
@ -790,6 +872,7 @@ static int spi_geni_transfer_one(struct spi_master *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||
int ret;
|
||||
|
||||
if (spi_geni_is_abort_still_pending(mas))
|
||||
return -EBUSY;
|
||||
@ -798,9 +881,12 @@ static int spi_geni_transfer_one(struct spi_master *spi,
|
||||
if (!xfer->len)
|
||||
return 0;
|
||||
|
||||
if (mas->cur_xfer_mode == GENI_SE_FIFO) {
|
||||
setup_fifo_xfer(xfer, mas, slv->mode, spi);
|
||||
return 1;
|
||||
if (mas->cur_xfer_mode == GENI_SE_FIFO || mas->cur_xfer_mode == GENI_SE_DMA) {
|
||||
ret = setup_se_xfer(xfer, mas, slv->mode, spi);
|
||||
/* SPI framework expects +ve ret code to wait for transfer complete */
|
||||
if (!ret)
|
||||
ret = 1;
|
||||
return ret;
|
||||
}
|
||||
return setup_gsi_xfer(xfer, mas, slv, spi);
|
||||
}
|
||||
@ -823,39 +909,70 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
|
||||
|
||||
spin_lock(&mas->lock);
|
||||
|
||||
if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
|
||||
geni_spi_handle_rx(mas);
|
||||
if (mas->cur_xfer_mode == GENI_SE_FIFO) {
|
||||
if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN))
|
||||
geni_spi_handle_rx(mas);
|
||||
|
||||
if (m_irq & M_TX_FIFO_WATERMARK_EN)
|
||||
geni_spi_handle_tx(mas);
|
||||
if (m_irq & M_TX_FIFO_WATERMARK_EN)
|
||||
geni_spi_handle_tx(mas);
|
||||
|
||||
if (m_irq & M_CMD_DONE_EN) {
|
||||
if (mas->cur_xfer) {
|
||||
if (m_irq & M_CMD_DONE_EN) {
|
||||
if (mas->cur_xfer) {
|
||||
spi_finalize_current_transfer(spi);
|
||||
mas->cur_xfer = NULL;
|
||||
/*
|
||||
* If this happens, then a CMD_DONE came before all the
|
||||
* Tx buffer bytes were sent out. This is unusual, log
|
||||
* this condition and disable the WM interrupt to
|
||||
* prevent the system from stalling due an interrupt
|
||||
* storm.
|
||||
*
|
||||
* If this happens when all Rx bytes haven't been
|
||||
* received, log the condition. The only known time
|
||||
* this can happen is if bits_per_word != 8 and some
|
||||
* registers that expect xfer lengths in num spi_words
|
||||
* weren't written correctly.
|
||||
*/
|
||||
if (mas->tx_rem_bytes) {
|
||||
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n",
|
||||
mas->tx_rem_bytes, mas->cur_bits_per_word);
|
||||
}
|
||||
if (mas->rx_rem_bytes)
|
||||
dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n",
|
||||
mas->rx_rem_bytes, mas->cur_bits_per_word);
|
||||
} else {
|
||||
complete(&mas->cs_done);
|
||||
}
|
||||
}
|
||||
} else if (mas->cur_xfer_mode == GENI_SE_DMA) {
|
||||
const struct spi_transfer *xfer = mas->cur_xfer;
|
||||
u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT);
|
||||
u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT);
|
||||
|
||||
if (dma_tx_status)
|
||||
writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR);
|
||||
if (dma_rx_status)
|
||||
writel(dma_rx_status, se->base + SE_DMA_RX_IRQ_CLR);
|
||||
if (dma_tx_status & TX_DMA_DONE)
|
||||
mas->tx_rem_bytes = 0;
|
||||
if (dma_rx_status & RX_DMA_DONE)
|
||||
mas->rx_rem_bytes = 0;
|
||||
if (dma_tx_status & TX_RESET_DONE)
|
||||
complete(&mas->tx_reset_done);
|
||||
if (dma_rx_status & RX_RESET_DONE)
|
||||
complete(&mas->rx_reset_done);
|
||||
if (!mas->tx_rem_bytes && !mas->rx_rem_bytes && xfer) {
|
||||
if (xfer->tx_buf && mas->tx_se_dma) {
|
||||
geni_se_tx_dma_unprep(se, mas->tx_se_dma, xfer->len);
|
||||
mas->tx_se_dma = 0;
|
||||
}
|
||||
if (xfer->rx_buf && mas->rx_se_dma) {
|
||||
geni_se_rx_dma_unprep(se, mas->rx_se_dma, xfer->len);
|
||||
mas->rx_se_dma = 0;
|
||||
}
|
||||
spi_finalize_current_transfer(spi);
|
||||
mas->cur_xfer = NULL;
|
||||
/*
|
||||
* If this happens, then a CMD_DONE came before all the
|
||||
* Tx buffer bytes were sent out. This is unusual, log
|
||||
* this condition and disable the WM interrupt to
|
||||
* prevent the system from stalling due an interrupt
|
||||
* storm.
|
||||
*
|
||||
* If this happens when all Rx bytes haven't been
|
||||
* received, log the condition. The only known time
|
||||
* this can happen is if bits_per_word != 8 and some
|
||||
* registers that expect xfer lengths in num spi_words
|
||||
* weren't written correctly.
|
||||
*/
|
||||
if (mas->tx_rem_bytes) {
|
||||
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n",
|
||||
mas->tx_rem_bytes, mas->cur_bits_per_word);
|
||||
}
|
||||
if (mas->rx_rem_bytes)
|
||||
dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n",
|
||||
mas->rx_rem_bytes, mas->cur_bits_per_word);
|
||||
} else {
|
||||
complete(&mas->cs_done);
|
||||
}
|
||||
}
|
||||
|
||||
@ -949,6 +1066,8 @@ static int spi_geni_probe(struct platform_device *pdev)
|
||||
init_completion(&mas->cs_done);
|
||||
init_completion(&mas->cancel_done);
|
||||
init_completion(&mas->abort_done);
|
||||
init_completion(&mas->tx_reset_done);
|
||||
init_completion(&mas->rx_reset_done);
|
||||
spin_lock_init(&mas->lock);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 250);
|
||||
|
@ -60,12 +60,12 @@ static int intel_spi_pci_probe(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
static const struct pci_device_id intel_spi_pci_ids[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02a4), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x06a4), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x18e0), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x19e0), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x1bca), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x34a4), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x38a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
|
||||
@ -75,11 +75,14 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x9d24), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x9da4), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2a4), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa324), (unsigned long)&cnl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa3a4), (unsigned long)&cnl_info },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, intel_spi_pci_ids);
|
||||
|
@ -104,7 +104,7 @@
|
||||
#define BXT_PR 0x84
|
||||
#define BXT_SSFSTS_CTL 0xa0
|
||||
#define BXT_FREG_NUM 12
|
||||
#define BXT_PR_NUM 6
|
||||
#define BXT_PR_NUM 5
|
||||
|
||||
#define CNL_PR 0x84
|
||||
#define CNL_FREG_NUM 6
|
||||
|
@ -71,6 +71,11 @@ module_param(check_ranges, int, 0644);
|
||||
MODULE_PARM_DESC(check_ranges,
|
||||
"checks rx_buffer pattern are valid");
|
||||
|
||||
static unsigned int delay_ms = 100;
|
||||
module_param(delay_ms, uint, 0644);
|
||||
MODULE_PARM_DESC(delay_ms,
|
||||
"delay between tests, in milliseconds (default: 100)");
|
||||
|
||||
/* the actual tests to execute */
|
||||
static struct spi_test spi_tests[] = {
|
||||
{
|
||||
@ -1098,7 +1103,8 @@ int spi_test_run_tests(struct spi_device *spi,
|
||||
* detect the individual tests when using a logic analyzer
|
||||
* we also add scheduling to avoid potential spi_timeouts...
|
||||
*/
|
||||
mdelay(100);
|
||||
if (delay_ms)
|
||||
mdelay(delay_ms);
|
||||
schedule();
|
||||
}
|
||||
|
||||
|
@ -325,7 +325,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
|
||||
if (!spi_mem_internal_supports_op(mem, op))
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (ctlr->mem_ops && !mem->spi->cs_gpiod) {
|
||||
if (ctlr->mem_ops && ctlr->mem_ops->exec_op && !mem->spi->cs_gpiod) {
|
||||
ret = spi_mem_access_start(mem);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -195,6 +195,8 @@
|
||||
#define DATA_READ_MODE_X4 2
|
||||
#define DATA_READ_MODE_DUAL 5
|
||||
#define DATA_READ_MODE_QUAD 6
|
||||
#define DATA_READ_LATCH_LAT GENMASK(9, 8)
|
||||
#define DATA_READ_LATCH_LAT_S 8
|
||||
#define PG_LOAD_CUSTOM_EN BIT(7)
|
||||
#define DATARD_CUSTOM_EN BIT(6)
|
||||
#define CS_DESELECT_CYC_S 0
|
||||
@ -205,6 +207,9 @@
|
||||
|
||||
#define SNF_DLY_CTL3 0x548
|
||||
#define SFCK_SAM_DLY_S 0
|
||||
#define SFCK_SAM_DLY GENMASK(5, 0)
|
||||
#define SFCK_SAM_DLY_TOTAL 9
|
||||
#define SFCK_SAM_DLY_RANGE 47
|
||||
|
||||
#define SNF_STA_CTL1 0x550
|
||||
#define CUS_PG_DONE BIT(28)
|
||||
@ -297,6 +302,7 @@ struct mtk_snand {
|
||||
struct device *dev;
|
||||
struct clk *nfi_clk;
|
||||
struct clk *pad_clk;
|
||||
struct clk *nfi_hclk;
|
||||
void __iomem *nfi_base;
|
||||
int irq;
|
||||
struct completion op_done;
|
||||
@ -1339,7 +1345,16 @@ static int mtk_snand_enable_clk(struct mtk_snand *ms)
|
||||
dev_err(ms->dev, "unable to enable pad clk\n");
|
||||
goto err1;
|
||||
}
|
||||
ret = clk_prepare_enable(ms->nfi_hclk);
|
||||
if (ret) {
|
||||
dev_err(ms->dev, "unable to enable nfi hclk\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
clk_disable_unprepare(ms->pad_clk);
|
||||
err1:
|
||||
clk_disable_unprepare(ms->nfi_clk);
|
||||
return ret;
|
||||
@ -1347,6 +1362,7 @@ static int mtk_snand_enable_clk(struct mtk_snand *ms)
|
||||
|
||||
static void mtk_snand_disable_clk(struct mtk_snand *ms)
|
||||
{
|
||||
clk_disable_unprepare(ms->nfi_hclk);
|
||||
clk_disable_unprepare(ms->pad_clk);
|
||||
clk_disable_unprepare(ms->nfi_clk);
|
||||
}
|
||||
@ -1357,6 +1373,8 @@ static int mtk_snand_probe(struct platform_device *pdev)
|
||||
const struct of_device_id *dev_id;
|
||||
struct spi_controller *ctlr;
|
||||
struct mtk_snand *ms;
|
||||
unsigned long spi_freq;
|
||||
u32 val = 0;
|
||||
int ret;
|
||||
|
||||
dev_id = of_match_node(mtk_snand_ids, np);
|
||||
@ -1401,6 +1419,13 @@ static int mtk_snand_probe(struct platform_device *pdev)
|
||||
goto release_ecc;
|
||||
}
|
||||
|
||||
ms->nfi_hclk = devm_clk_get_optional(&pdev->dev, "nfi_hclk");
|
||||
if (IS_ERR(ms->nfi_hclk)) {
|
||||
ret = PTR_ERR(ms->nfi_hclk);
|
||||
dev_err(&pdev->dev, "unable to get nfi_hclk, err = %d\n", ret);
|
||||
goto release_ecc;
|
||||
}
|
||||
|
||||
ret = mtk_snand_enable_clk(ms);
|
||||
if (ret)
|
||||
goto release_ecc;
|
||||
@ -1428,10 +1453,22 @@ static int mtk_snand_probe(struct platform_device *pdev)
|
||||
// switch to SNFI mode
|
||||
nfi_write32(ms, SNF_CFG, SPI_MODE);
|
||||
|
||||
ret = of_property_read_u32(np, "rx-sample-delay-ns", &val);
|
||||
if (!ret)
|
||||
nfi_rmw32(ms, SNF_DLY_CTL3, SFCK_SAM_DLY,
|
||||
val * SFCK_SAM_DLY_RANGE / SFCK_SAM_DLY_TOTAL);
|
||||
|
||||
ret = of_property_read_u32(np, "mediatek,rx-latch-latency-ns", &val);
|
||||
if (!ret) {
|
||||
spi_freq = clk_get_rate(ms->pad_clk);
|
||||
val = DIV_ROUND_CLOSEST(val, NSEC_PER_SEC / spi_freq);
|
||||
nfi_rmw32(ms, SNF_MISC_CTL, DATA_READ_LATCH_LAT,
|
||||
val << DATA_READ_LATCH_LAT_S);
|
||||
}
|
||||
|
||||
// setup an initial page format for ops matching page_cache_op template
|
||||
// before ECC is called.
|
||||
ret = mtk_snand_setup_pagefmt(ms, ms->caps->sector_size,
|
||||
ms->caps->spare_sizes[0]);
|
||||
ret = mtk_snand_setup_pagefmt(ms, SZ_2K, SZ_64);
|
||||
if (ret) {
|
||||
dev_err(ms->dev, "failed to set initial page format\n");
|
||||
goto disable_clk;
|
||||
|
@ -2091,7 +2091,6 @@ pl022_platform_data_dt_get(struct device *dev)
|
||||
return NULL;
|
||||
|
||||
pd->bus_id = -1;
|
||||
pd->enable_dma = 1;
|
||||
of_property_read_u32(np, "pl022,autosuspend-delay",
|
||||
&pd->autosuspend_delay);
|
||||
pd->rt = of_property_read_bool(np, "pl022,rt");
|
||||
|
@ -472,10 +472,9 @@ static int synquacer_spi_transfer_one(struct spi_master *master,
|
||||
read_fifo(sspi);
|
||||
}
|
||||
|
||||
if (status < 0) {
|
||||
dev_err(sspi->dev, "failed to transfer. status: 0x%x\n",
|
||||
status);
|
||||
return status;
|
||||
if (status == 0) {
|
||||
dev_err(sspi->dev, "failed to transfer. Timeout.\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -83,7 +83,7 @@ struct xilinx_spi {
|
||||
void __iomem *regs; /* virt. address of the control registers */
|
||||
|
||||
int irq;
|
||||
|
||||
bool force_irq; /* force irq to setup master inhibit */
|
||||
u8 *rx_ptr; /* pointer in the Tx buffer */
|
||||
const u8 *tx_ptr; /* pointer in the Rx buffer */
|
||||
u8 bytes_per_word;
|
||||
@ -248,7 +248,8 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
xspi->rx_ptr = t->rx_buf;
|
||||
remaining_words = t->len / xspi->bytes_per_word;
|
||||
|
||||
if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) {
|
||||
if (xspi->irq >= 0 &&
|
||||
(xspi->force_irq || remaining_words > xspi->buffer_size)) {
|
||||
u32 isr;
|
||||
use_irq = true;
|
||||
/* Inhibit irq to avoid spurious irqs on tx_empty*/
|
||||
@ -393,6 +394,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int ret, num_cs = 0, bits_per_word;
|
||||
struct spi_master *master;
|
||||
bool force_irq = false;
|
||||
u32 tmp;
|
||||
u8 i;
|
||||
|
||||
@ -400,6 +402,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
||||
if (pdata) {
|
||||
num_cs = pdata->num_chipselect;
|
||||
bits_per_word = pdata->bits_per_word;
|
||||
force_irq = pdata->force_irq;
|
||||
} else {
|
||||
of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
|
||||
&num_cs);
|
||||
@ -477,6 +480,8 @@ static int xilinx_spi_probe(struct platform_device *pdev)
|
||||
dev_name(&pdev->dev), xspi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xspi->force_irq = force_irq;
|
||||
}
|
||||
|
||||
/* SPI controller initializations */
|
||||
|
@ -604,7 +604,7 @@ static void spi_dev_set_name(struct spi_device *spi)
|
||||
}
|
||||
|
||||
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->controller->dev),
|
||||
spi->chip_select);
|
||||
spi_get_chipselect(spi, 0));
|
||||
}
|
||||
|
||||
static int spi_dev_check(struct device *dev, void *data)
|
||||
@ -613,7 +613,7 @@ static int spi_dev_check(struct device *dev, void *data)
|
||||
struct spi_device *new_spi = data;
|
||||
|
||||
if (spi->controller == new_spi->controller &&
|
||||
spi->chip_select == new_spi->chip_select)
|
||||
spi_get_chipselect(spi, 0) == spi_get_chipselect(new_spi, 0))
|
||||
return -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
@ -638,7 +638,7 @@ static int __spi_add_device(struct spi_device *spi)
|
||||
status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
|
||||
if (status) {
|
||||
dev_err(dev, "chipselect %d already in use\n",
|
||||
spi->chip_select);
|
||||
spi_get_chipselect(spi, 0));
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -649,7 +649,7 @@ static int __spi_add_device(struct spi_device *spi)
|
||||
}
|
||||
|
||||
if (ctlr->cs_gpiods)
|
||||
spi->cs_gpiod = ctlr->cs_gpiods[spi->chip_select];
|
||||
spi_set_csgpiod(spi, 0, ctlr->cs_gpiods[spi_get_chipselect(spi, 0)]);
|
||||
|
||||
/*
|
||||
* Drivers may modify this initial i/o setup, but will
|
||||
@ -692,8 +692,8 @@ int spi_add_device(struct spi_device *spi)
|
||||
int status;
|
||||
|
||||
/* Chipselects are numbered 0..max; validate. */
|
||||
if (spi->chip_select >= ctlr->num_chipselect) {
|
||||
dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
|
||||
if (spi_get_chipselect(spi, 0) >= ctlr->num_chipselect) {
|
||||
dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, 0),
|
||||
ctlr->num_chipselect);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -714,8 +714,8 @@ static int spi_add_device_locked(struct spi_device *spi)
|
||||
struct device *dev = ctlr->dev.parent;
|
||||
|
||||
/* Chipselects are numbered 0..max; validate. */
|
||||
if (spi->chip_select >= ctlr->num_chipselect) {
|
||||
dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
|
||||
if (spi_get_chipselect(spi, 0) >= ctlr->num_chipselect) {
|
||||
dev_err(dev, "cs%d >= max %d\n", spi_get_chipselect(spi, 0),
|
||||
ctlr->num_chipselect);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -761,7 +761,7 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr,
|
||||
|
||||
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
|
||||
|
||||
proxy->chip_select = chip->chip_select;
|
||||
spi_set_chipselect(proxy, 0, chip->chip_select);
|
||||
proxy->max_speed_hz = chip->max_speed_hz;
|
||||
proxy->mode = chip->mode;
|
||||
proxy->irq = chip->irq;
|
||||
@ -970,24 +970,23 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
|
||||
* Avoid calling into the driver (or doing delays) if the chip select
|
||||
* isn't actually changing from the last time this was called.
|
||||
*/
|
||||
if (!force && ((enable && spi->controller->last_cs == spi->chip_select) ||
|
||||
(!enable && spi->controller->last_cs != spi->chip_select)) &&
|
||||
if (!force && ((enable && spi->controller->last_cs == spi_get_chipselect(spi, 0)) ||
|
||||
(!enable && spi->controller->last_cs != spi_get_chipselect(spi, 0))) &&
|
||||
(spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH)))
|
||||
return;
|
||||
|
||||
trace_spi_set_cs(spi, activate);
|
||||
|
||||
spi->controller->last_cs = enable ? spi->chip_select : -1;
|
||||
spi->controller->last_cs = enable ? spi_get_chipselect(spi, 0) : -1;
|
||||
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
|
||||
|
||||
if ((spi->cs_gpiod || !spi->controller->set_cs_timing) && !activate) {
|
||||
if ((spi_get_csgpiod(spi, 0) || !spi->controller->set_cs_timing) && !activate)
|
||||
spi_delay_exec(&spi->cs_hold, NULL);
|
||||
}
|
||||
|
||||
if (spi->mode & SPI_CS_HIGH)
|
||||
enable = !enable;
|
||||
|
||||
if (spi->cs_gpiod) {
|
||||
if (spi_get_csgpiod(spi, 0)) {
|
||||
if (!(spi->mode & SPI_NO_CS)) {
|
||||
/*
|
||||
* Historically ACPI has no means of the GPIO polarity and
|
||||
@ -1000,10 +999,10 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
|
||||
* into account.
|
||||
*/
|
||||
if (has_acpi_companion(&spi->dev))
|
||||
gpiod_set_value_cansleep(spi->cs_gpiod, !enable);
|
||||
gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), !enable);
|
||||
else
|
||||
/* Polarity handled by GPIO library */
|
||||
gpiod_set_value_cansleep(spi->cs_gpiod, activate);
|
||||
gpiod_set_value_cansleep(spi_get_csgpiod(spi, 0), activate);
|
||||
}
|
||||
/* Some SPI masters need both GPIO CS & slave_select */
|
||||
if ((spi->controller->flags & SPI_MASTER_GPIO_SS) &&
|
||||
@ -1013,7 +1012,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
|
||||
spi->controller->set_cs(spi, !enable);
|
||||
}
|
||||
|
||||
if (spi->cs_gpiod || !spi->controller->set_cs_timing) {
|
||||
if (spi_get_csgpiod(spi, 0) || !spi->controller->set_cs_timing) {
|
||||
if (activate)
|
||||
spi_delay_exec(&spi->cs_setup, NULL);
|
||||
else
|
||||
@ -1484,6 +1483,13 @@ static void _spi_transfer_cs_change_delay(struct spi_message *msg,
|
||||
}
|
||||
}
|
||||
|
||||
void spi_transfer_cs_change_delay_exec(struct spi_message *msg,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
_spi_transfer_cs_change_delay(msg, xfer);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_transfer_cs_change_delay_exec);
|
||||
|
||||
/*
|
||||
* spi_transfer_one_message - Default implementation of transfer_one_message()
|
||||
*
|
||||
@ -1921,7 +1927,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr,
|
||||
/* Capture the resolution of the timestamp */
|
||||
xfer->ptp_sts_word_post = progress;
|
||||
|
||||
xfer->timestamped = true;
|
||||
xfer->timestamped = 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(spi_take_timestamp_post);
|
||||
|
||||
@ -2220,11 +2226,26 @@ void spi_flush_queue(struct spi_controller *ctlr)
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static void of_spi_parse_dt_cs_delay(struct device_node *nc,
|
||||
struct spi_delay *delay, const char *prop)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
if (!of_property_read_u32(nc, prop, &value)) {
|
||||
if (value > U16_MAX) {
|
||||
delay->value = DIV_ROUND_UP(value, 1000);
|
||||
delay->unit = SPI_DELAY_UNIT_USECS;
|
||||
} else {
|
||||
delay->value = value;
|
||||
delay->unit = SPI_DELAY_UNIT_NSECS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
|
||||
struct device_node *nc)
|
||||
{
|
||||
u32 value;
|
||||
u16 cs_setup;
|
||||
int rc;
|
||||
|
||||
/* Mode (clock phase/polarity/etc.) */
|
||||
@ -2304,16 +2325,16 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
|
||||
nc, rc);
|
||||
return rc;
|
||||
}
|
||||
spi->chip_select = value;
|
||||
spi_set_chipselect(spi, 0, value);
|
||||
|
||||
/* Device speed */
|
||||
if (!of_property_read_u32(nc, "spi-max-frequency", &value))
|
||||
spi->max_speed_hz = value;
|
||||
|
||||
if (!of_property_read_u16(nc, "spi-cs-setup-delay-ns", &cs_setup)) {
|
||||
spi->cs_setup.value = cs_setup;
|
||||
spi->cs_setup.unit = SPI_DELAY_UNIT_NSECS;
|
||||
}
|
||||
/* Device CS delays */
|
||||
of_spi_parse_dt_cs_delay(nc, &spi->cs_setup, "spi-cs-setup-delay-ns");
|
||||
of_spi_parse_dt_cs_delay(nc, &spi->cs_hold, "spi-cs-hold-delay-ns");
|
||||
of_spi_parse_dt_cs_delay(nc, &spi->cs_inactive, "spi-cs-inactive-delay-ns");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2423,7 +2444,7 @@ struct spi_device *spi_new_ancillary_device(struct spi_device *spi,
|
||||
strscpy(ancillary->modalias, "dummy", sizeof(ancillary->modalias));
|
||||
|
||||
/* Use provided chip-select for ancillary device */
|
||||
ancillary->chip_select = chip_select;
|
||||
spi_set_chipselect(ancillary, 0, chip_select);
|
||||
|
||||
/* Take over SPI mode/speed from SPI main device */
|
||||
ancillary->max_speed_hz = spi->max_speed_hz;
|
||||
@ -2670,7 +2691,7 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
|
||||
spi->mode |= lookup.mode;
|
||||
spi->irq = lookup.irq;
|
||||
spi->bits_per_word = lookup.bits_per_word;
|
||||
spi->chip_select = lookup.chip_select;
|
||||
spi_set_chipselect(spi, 0, lookup.chip_select);
|
||||
|
||||
return spi;
|
||||
}
|
||||
@ -3051,15 +3072,14 @@ static int spi_controller_check_ops(struct spi_controller *ctlr)
|
||||
* The controller may implement only the high-level SPI-memory like
|
||||
* operations if it does not support regular SPI transfers, and this is
|
||||
* valid use case.
|
||||
* If ->mem_ops is NULL, we request that at least one of the
|
||||
* ->transfer_xxx() method be implemented.
|
||||
* If ->mem_ops or ->mem_ops->exec_op is NULL, we request that at least
|
||||
* one of the ->transfer_xxx() method be implemented.
|
||||
*/
|
||||
if (ctlr->mem_ops) {
|
||||
if (!ctlr->mem_ops->exec_op)
|
||||
return -EINVAL;
|
||||
} else if (!ctlr->transfer && !ctlr->transfer_one &&
|
||||
if (!ctlr->mem_ops || (ctlr->mem_ops && !ctlr->mem_ops->exec_op)) {
|
||||
if (!ctlr->transfer && !ctlr->transfer_one &&
|
||||
!ctlr->transfer_one_message) {
|
||||
return -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -3632,7 +3652,7 @@ static int spi_set_cs_timing(struct spi_device *spi)
|
||||
struct device *parent = spi->controller->dev.parent;
|
||||
int status = 0;
|
||||
|
||||
if (spi->controller->set_cs_timing && !spi->cs_gpiod) {
|
||||
if (spi->controller->set_cs_timing && !spi_get_csgpiod(spi, 0)) {
|
||||
if (spi->controller->auto_runtime_pm) {
|
||||
status = pm_runtime_get_sync(parent);
|
||||
if (status < 0) {
|
||||
@ -3837,7 +3857,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
||||
* cs_change is set for each transfer.
|
||||
*/
|
||||
if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) ||
|
||||
spi->cs_gpiod)) {
|
||||
spi_get_csgpiod(spi, 0))) {
|
||||
size_t maxsize;
|
||||
int ret;
|
||||
|
||||
|
@ -115,8 +115,6 @@ spidev_sync(struct spidev_data *spidev, struct spi_message *message)
|
||||
else
|
||||
status = spidev_sync_unlocked(spi, message);
|
||||
|
||||
mutex_unlock(&spidev->spi_lock);
|
||||
|
||||
mutex_unlock(&spidev->spi_lock);
|
||||
return status;
|
||||
}
|
||||
@ -713,6 +711,8 @@ static const struct spi_device_id spidev_spi_ids[] = {
|
||||
{ .name = "m53cpld" },
|
||||
{ .name = "spi-petra" },
|
||||
{ .name = "spi-authenta" },
|
||||
{ .name = "em3581" },
|
||||
{ .name = "si3210" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, spidev_spi_ids);
|
||||
@ -731,14 +731,16 @@ static int spidev_of_check(struct device *dev)
|
||||
}
|
||||
|
||||
static const struct of_device_id spidev_dt_ids[] = {
|
||||
{ .compatible = "rohm,dh2228fv", .data = &spidev_of_check },
|
||||
{ .compatible = "lineartechnology,ltc2488", .data = &spidev_of_check },
|
||||
{ .compatible = "semtech,sx1301", .data = &spidev_of_check },
|
||||
{ .compatible = "lwn,bk4", .data = &spidev_of_check },
|
||||
{ .compatible = "dh,dhcom-board", .data = &spidev_of_check },
|
||||
{ .compatible = "menlo,m53cpld", .data = &spidev_of_check },
|
||||
{ .compatible = "cisco,spi-petra", .data = &spidev_of_check },
|
||||
{ .compatible = "dh,dhcom-board", .data = &spidev_of_check },
|
||||
{ .compatible = "lineartechnology,ltc2488", .data = &spidev_of_check },
|
||||
{ .compatible = "lwn,bk4", .data = &spidev_of_check },
|
||||
{ .compatible = "menlo,m53cpld", .data = &spidev_of_check },
|
||||
{ .compatible = "micron,spi-authenta", .data = &spidev_of_check },
|
||||
{ .compatible = "rohm,dh2228fv", .data = &spidev_of_check },
|
||||
{ .compatible = "semtech,sx1301", .data = &spidev_of_check },
|
||||
{ .compatible = "silabs,em3581", .data = &spidev_of_check },
|
||||
{ .compatible = "silabs,si3210", .data = &spidev_of_check },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
/**
|
||||
* struct altera_spi_platform_data - Platform data of the Altera SPI driver
|
||||
* @mode_bits: Mode bits of SPI master.
|
||||
* @mode_bits: Mode bits of SPI host.
|
||||
* @num_chipselect: Number of chipselects.
|
||||
* @bits_per_word_mask: bitmask of supported bits_per_word for transfers.
|
||||
* @num_devices: Number of devices that shall be added when the driver
|
||||
@ -46,5 +46,5 @@ struct altera_spi {
|
||||
};
|
||||
|
||||
extern irqreturn_t altera_spi_irq(int irq, void *dev);
|
||||
extern void altera_spi_init_master(struct spi_master *master);
|
||||
extern void altera_spi_init_host(struct spi_controller *host);
|
||||
#endif /* __LINUX_SPI_ALTERA_H */
|
||||
|
@ -26,6 +26,7 @@ struct spi_controller;
|
||||
struct spi_transfer;
|
||||
struct spi_controller_mem_ops;
|
||||
struct spi_controller_mem_caps;
|
||||
struct spi_message;
|
||||
|
||||
/*
|
||||
* INTERFACES between SPI master-side drivers and SPI slave protocol handlers,
|
||||
@ -119,6 +120,8 @@ struct spi_delay {
|
||||
|
||||
extern int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer);
|
||||
extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer);
|
||||
extern void spi_transfer_cs_change_delay_exec(struct spi_message *msg,
|
||||
struct spi_transfer *xfer);
|
||||
|
||||
/**
|
||||
* struct spi_device - Controller side proxy for an SPI slave device
|
||||
@ -263,7 +266,25 @@ static inline void *spi_get_drvdata(struct spi_device *spi)
|
||||
return dev_get_drvdata(&spi->dev);
|
||||
}
|
||||
|
||||
struct spi_message;
|
||||
static inline u8 spi_get_chipselect(struct spi_device *spi, u8 idx)
|
||||
{
|
||||
return spi->chip_select;
|
||||
}
|
||||
|
||||
static inline void spi_set_chipselect(struct spi_device *spi, u8 idx, u8 chipselect)
|
||||
{
|
||||
spi->chip_select = chipselect;
|
||||
}
|
||||
|
||||
static inline struct gpio_desc *spi_get_csgpiod(struct spi_device *spi, u8 idx)
|
||||
{
|
||||
return spi->cs_gpiod;
|
||||
}
|
||||
|
||||
static inline void spi_set_csgpiod(struct spi_device *spi, u8 idx, struct gpio_desc *csgpiod)
|
||||
{
|
||||
spi->cs_gpiod = csgpiod;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct spi_driver - Host side "protocol" driver
|
||||
@ -1001,6 +1022,9 @@ struct spi_transfer {
|
||||
void *rx_buf;
|
||||
unsigned len;
|
||||
|
||||
#define SPI_TRANS_FAIL_NO_START BIT(0)
|
||||
u16 error;
|
||||
|
||||
dma_addr_t tx_dma;
|
||||
dma_addr_t rx_dma;
|
||||
struct sg_table tx_sg;
|
||||
@ -1011,6 +1035,7 @@ struct spi_transfer {
|
||||
unsigned cs_change:1;
|
||||
unsigned tx_nbits:3;
|
||||
unsigned rx_nbits:3;
|
||||
unsigned timestamped:1;
|
||||
#define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */
|
||||
#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */
|
||||
#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */
|
||||
@ -1027,12 +1052,7 @@ struct spi_transfer {
|
||||
|
||||
struct ptp_system_timestamp *ptp_sts;
|
||||
|
||||
bool timestamped;
|
||||
|
||||
struct list_head transfer_list;
|
||||
|
||||
#define SPI_TRANS_FAIL_NO_START BIT(0)
|
||||
u16 error;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -15,6 +15,7 @@ struct xspi_platform_data {
|
||||
u8 bits_per_word;
|
||||
struct spi_board_info *devices;
|
||||
u8 num_devices;
|
||||
bool force_irq;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_SPI_XILINX_SPI_H */
|
||||
|
Loading…
Reference in New Issue
Block a user