Commit fb02b9eb authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'spi/for-5.8' into spi-next

parents 0c0c5b8f 263b81dc
...@@ -26,6 +26,16 @@ Required properties: ...@@ -26,6 +26,16 @@ Required properties:
"brcm,spi-bcm-qspi", "brcm,spi-brcmstb-qspi" : MSPI+BSPI on BRCMSTB SoCs "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-qspi" : MSPI+BSPI on BRCMSTB SoCs
"brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs BRCMSTB SoCs
"brcm,spi-bcm7425-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm7429-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm7435-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm7216-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm7278-qspi", "brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
BRCMSTB SoCs
"brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi" : MSPI+BSPI on Cygnus, NSP "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi" : MSPI+BSPI on Cygnus, NSP
"brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi" : NS2 SoCs "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi" : NS2 SoCs
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/mikrotik,rb4xx-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MikroTik RB4xx series SPI master
maintainers:
- Gabor Juhos <juhosg@openwrt.org>
- Bert Vermeulen <bert@biot.com>
allOf:
- $ref: "spi-controller.yaml#"
properties:
compatible:
const: mikrotik,rb4xx-spi
reg:
maxItems: 1
required:
- compatible
- reg
examples:
- |
spi: spi@1f000000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "mikrotik,rb4xx-spi";
reg = <0x1f000000 0x10>;
};
...
\ No newline at end of file
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/renesas,rspi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas (Quad) Serial Peripheral Interface (RSPI/QSPI)
maintainers:
- Geert Uytterhoeven <geert+renesas@glider.be>
properties:
compatible:
oneOf:
- items:
- enum:
- renesas,rspi-sh7757 # SH7757
- const: renesas,rspi # Legacy SH
- items:
- enum:
- renesas,rspi-r7s72100 # RZ/A1H
- renesas,rspi-r7s9210 # RZ/A2
- const: renesas,rspi-rz # RZ/A
- items:
- enum:
- renesas,qspi-r8a7743 # RZ/G1M
- renesas,qspi-r8a7744 # RZ/G1N
- renesas,qspi-r8a7745 # RZ/G1E
- renesas,qspi-r8a77470 # RZ/G1C
- renesas,qspi-r8a7790 # R-Car H2
- renesas,qspi-r8a7791 # R-Car M2-W
- renesas,qspi-r8a7792 # R-Car V2H
- renesas,qspi-r8a7793 # R-Car M2-N
- renesas,qspi-r8a7794 # R-Car E2
- const: renesas,qspi # R-Car Gen2 and RZ/G1
reg:
maxItems: 1
interrupts:
oneOf:
- items:
- description: A combined interrupt
- items:
- description: Error interrupt (SPEI)
- description: Receive Interrupt (SPRI)
- description: Transmit Interrupt (SPTI)
interrupt-names:
oneOf:
- items:
- const: mux
- items:
- const: error
- const: rx
- const: tx
clocks:
maxItems: 1
power-domains:
maxItems: 1
resets:
maxItems: 1
dmas:
description:
Must contain a list of pairs of references to DMA specifiers, one for
transmission, and one for reception.
dma-names:
minItems: 2
maxItems: 4
items:
enum:
- tx
- rx
num-cs:
description: |
Total number of native chip selects.
Hardware limitations related to chip selects:
- When using GPIO chip selects, at least one native chip select must
be left unused, as it will be driven anyway.
minimum: 1
maximum: 2
default: 1
required:
- compatible
- reg
- interrupts
- clocks
- power-domains
- '#address-cells'
- '#size-cells'
allOf:
- $ref: spi-controller.yaml#
- if:
properties:
compatible:
contains:
enum:
- renesas,rspi-rz
then:
properties:
interrupts:
minItems: 3
required:
- interrupt-names
- if:
properties:
compatible:
contains:
enum:
- renesas,qspi
then:
required:
- resets
examples:
- |
#include <dt-bindings/clock/r8a7791-cpg-mssr.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/r8a7791-sysc.h>
qspi: spi@e6b10000 {
compatible = "renesas,qspi-r8a7791", "renesas,qspi";
reg = <0xe6b10000 0x2c>;
interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 917>;
dmas = <&dmac0 0x17>, <&dmac0 0x18>, <&dmac1 0x17>, <&dmac1 0x18>;
dma-names = "tx", "rx", "tx", "rx";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
resets = <&cpg 917>;
num-cs = <1>;
#address-cells = <1>;
#size-cells = <0>;
};
Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface.
Required properties:
- compatible : "snps,dw-apb-ssi" or "mscc,<soc>-spi", where soc is "ocelot" or
"jaguar2", or "amazon,alpine-dw-apb-ssi"
- reg : The register base for the controller. For "mscc,<soc>-spi", a second
register set is required (named ICPU_CFG:SPI_MST)
- interrupts : One interrupt, used by the controller.
- #address-cells : <1>, as required by generic SPI binding.
- #size-cells : <0>, also as required by generic SPI binding.
- clocks : phandles for the clocks, see the description of clock-names below.
The phandle for the "ssi_clk" is required. The phandle for the "pclk" clock
is optional. If a single clock is specified but no clock-name, it is the
"ssi_clk" clock. If both clocks are listed, the "ssi_clk" must be first.
Optional properties:
- clock-names : Contains the names of the clocks:
"ssi_clk", for the core clock used to generate the external SPI clock.
"pclk", the interface clock, required for register access. If a clock domain
used to enable this clock then it should be named "pclk_clkdomain".
- cs-gpios : Specifies the gpio pins to be used for chipselects.
- num-cs : The number of chipselects. If omitted, this will default to 4.
- reg-io-width : The I/O register width (in bytes) implemented by this
device. Supported values are 2 or 4 (the default).
Child nodes as per the generic SPI binding.
Example:
spi@fff00000 {
compatible = "snps,dw-apb-ssi";
reg = <0xfff00000 0x1000>;
interrupts = <0 154 4>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&spi_m_clk>;
num-cs = <2>;
cs-gpios = <&gpio0 13 0>,
<&gpio0 14 0>;
};
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/snps,dw-apb-ssi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface
maintainers:
- Mark Brown <broonie@kernel.org>
allOf:
- $ref: "spi-controller.yaml#"
- if:
properties:
compatible:
contains:
enum:
- mscc,ocelot-spi
- mscc,jaguar2-spi
then:
properties:
reg:
minItems: 2
properties:
compatible:
oneOf:
- description: Generic DW SPI Controller
enum:
- snps,dw-apb-ssi
- snps,dwc-ssi-1.01a
- description: Microsemi Ocelot/Jaguar2 SoC SPI Controller
items:
- enum:
- mscc,ocelot-spi
- mscc,jaguar2-spi
- const: snps,dw-apb-ssi
- description: Amazon Alpine SPI Controller
const: amazon,alpine-dw-apb-ssi
- description: Renesas RZ/N1 SPI Controller
items:
- const: renesas,rzn1-spi
- const: snps,dw-apb-ssi
- description: Intel Keem Bay SPI Controller
const: intel,keembay-ssi
reg:
minItems: 1
items:
- description: DW APB SSI controller memory mapped registers
- description: SPI MST region map
interrupts:
maxItems: 1
clocks:
minItems: 1
items:
- description: SPI Controller reference clock source
- description: APB interface clock source
clock-names:
minItems: 1
items:
- const: ssi_clk
- const: pclk
resets:
maxItems: 1
reset-names:
const: spi
reg-io-width:
$ref: /schemas/types.yaml#/definitions/uint32
description: I/O register width (in bytes) implemented by this device
default: 4
enum: [ 2, 4 ]
num-cs:
default: 4
minimum: 1
maximum: 4
dmas:
items:
- description: TX DMA Channel
- description: RX DMA Channel
dma-names:
items:
- const: tx
- const: rx
patternProperties:
"^.*@[0-9a-f]+$":
type: object
properties:
reg:
minimum: 0
maximum: 3
spi-rx-bus-width:
const: 1
spi-tx-bus-width:
const: 1
unevaluatedProperties: false
required:
- compatible
- reg
- "#address-cells"
- "#size-cells"
- interrupts
- clocks
examples:
- |
spi@fff00000 {
compatible = "snps,dw-apb-ssi";
reg = <0xfff00000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 154 4>;
clocks = <&spi_m_clk>;
num-cs = <2>;
cs-gpios = <&gpio0 13 0>,
<&gpio0 14 0>;
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/socionext,uniphier-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Socionext UniPhier SPI controller
description: |
UniPhier SoCs have SCSSI which supports SPI single channel.
maintainers:
- Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
- Keiji Hayashibara <hayashibara.keiji@socionext.com>
allOf:
- $ref: spi-controller.yaml#
properties:
"#address-cells": true
"#size-cells": true
compatible:
const: socionext,uniphier-scssi
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
resets:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
- resets
- "#address-cells"
- "#size-cells"
examples:
- |
spi0: spi@54006000 {
compatible = "socionext,uniphier-scssi";
reg = <0x54006000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 39 4>;
clocks = <&peri_clk 11>;
resets = <&peri_rst 11>;
};
Synopsys DesignWare SPI master
Required properties:
- compatible: should be "snps,designware-spi"
- #address-cells: see spi-bus.txt
- #size-cells: see spi-bus.txt
- reg: address and length of the spi master registers
- interrupts: should contain one interrupt
- clocks: spi clock phandle
- num-cs: see spi-bus.txt
Optional properties:
- cs-gpios: see spi-bus.txt
Example:
spi: spi@4020a000 {
compatible = "snps,designware-spi";
interrupts = <11 1>;
reg = <0x4020a000 0x1000>;
clocks = <&pclk>;
num-cs = <2>;
cs-gpios = <&banka 0 0>;
};
Device tree configuration for Renesas RSPI/QSPI driver
Required properties:
- compatible : For Renesas Serial Peripheral Interface on legacy SH:
"renesas,rspi-<soctype>", "renesas,rspi" as fallback.
For Renesas Serial Peripheral Interface on RZ/A:
"renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
For Quad Serial Peripheral Interface on R-Car Gen2 and
RZ/G1 devices:
"renesas,qspi-<soctype>", "renesas,qspi" as fallback.
Examples with soctypes are:
- "renesas,rspi-sh7757" (SH)
- "renesas,rspi-r7s72100" (RZ/A1H)
- "renesas,rspi-r7s9210" (RZ/A2)
- "renesas,qspi-r8a7743" (RZ/G1M)
- "renesas,qspi-r8a7744" (RZ/G1N)
- "renesas,qspi-r8a7745" (RZ/G1E)
- "renesas,qspi-r8a77470" (RZ/G1C)
- "renesas,qspi-r8a7790" (R-Car H2)
- "renesas,qspi-r8a7791" (R-Car M2-W)
- "renesas,qspi-r8a7792" (R-Car V2H)
- "renesas,qspi-r8a7793" (R-Car M2-N)
- "renesas,qspi-r8a7794" (R-Car E2)
- reg : Address start and address range size of the device
- interrupts : A list of interrupt-specifiers, one for each entry in
interrupt-names.
If interrupt-names is not present, an interrupt specifier
for a single muxed interrupt.
- interrupt-names : A list of interrupt names. Should contain (if present):
- "error" for SPEI,
- "rx" for SPRI,
- "tx" to SPTI,
- "mux" for a single muxed interrupt.
- num-cs : Number of chip selects. Some RSPI cores have more than 1.
- #address-cells : Must be <1>
- #size-cells : Must be <0>
Optional properties:
- clocks : Must contain a reference to the functional clock.
- dmas : Must contain a list of two references to DMA specifiers,
one for transmission, and one for reception.
- dma-names : Must contain a list of two DMA names, "tx" and "rx".
Pinctrl properties might be needed, too. See
Documentation/devicetree/bindings/pinctrl/renesas,*.
Examples:
spi0: spi@e800c800 {
compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
reg = <0xe800c800 0x24>;
interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>,
<0 239 IRQ_TYPE_LEVEL_HIGH>,
<0 240 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "error", "rx", "tx";
interrupt-parent = <&gic>;
num-cs = <1>;
#address-cells = <1>;
#size-cells = <0>;
};
spi: spi@e6b10000 {
compatible = "renesas,qspi-r8a7791", "renesas,qspi";
reg = <0 0xe6b10000 0 0x2c>;
interrupt-parent = <&gic>;
interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>;
num-cs = <1>;
#address-cells = <1>;
#size-cells = <0>;
dmas = <&dmac0 0x17>, <&dmac0 0x18>;
dma-names = "tx", "rx";
};
Socionext UniPhier SPI controller driver
UniPhier SoCs have SCSSI which supports SPI single channel.
Required properties:
- compatible: should be "socionext,uniphier-scssi"
- reg: address and length of the spi master registers
- #address-cells: must be <1>, see spi-bus.txt
- #size-cells: must be <0>, see spi-bus.txt
- interrupts: a single interrupt specifier
- pinctrl-names: should be "default"
- pinctrl-0: pin control state for the default mode
- clocks: a phandle to the clock for the device
- resets: a phandle to the reset control for the device
Example:
spi0: spi@54006000 {
compatible = "socionext,uniphier-scssi";
reg = <0x54006000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
interrupts = <0 39 4>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_spi0>;
clocks = <&peri_clk 11>;
resets = <&peri_rst 11>;
};
...@@ -29,7 +29,7 @@ modification to bootloader. ...@@ -29,7 +29,7 @@ modification to bootloader.
Example: Example:
For am4372: For am4372:
qspi: qspi@4b300000 { qspi: qspi@47900000 {
compatible = "ti,am4372-qspi"; compatible = "ti,am4372-qspi";
reg = <0x47900000 0x100>, <0x30000000 0x4000000>; reg = <0x47900000 0x100>, <0x30000000 0x4000000>;
reg-names = "qspi_base", "qspi_mmap"; reg-names = "qspi_base", "qspi_mmap";
......
...@@ -633,6 +633,8 @@ patternProperties: ...@@ -633,6 +633,8 @@ patternProperties:
description: Microsoft Corporation description: Microsoft Corporation
"^mikroe,.*": "^mikroe,.*":
description: MikroElektronika d.o.o. description: MikroElektronika d.o.o.
"^mikrotik,.*":
description: MikroTik
"^miniand,.*": "^miniand,.*":
description: Miniand Tech description: Miniand Tech
"^minix,.*": "^minix,.*":
......
...@@ -892,6 +892,11 @@ F: drivers/gpu/drm/amd/include/v9_structs.h ...@@ -892,6 +892,11 @@ F: drivers/gpu/drm/amd/include/v9_structs.h
F: drivers/gpu/drm/amd/include/vi_structs.h F: drivers/gpu/drm/amd/include/vi_structs.h
F: include/uapi/linux/kfd_ioctl.h F: include/uapi/linux/kfd_ioctl.h
AMD SPI DRIVER
M: Sanjay R Mehta <sanju.mehta@amd.com>
S: Maintained
F: drivers/spi/spi-amd.c
AMD MP2 I2C DRIVER AMD MP2 I2C DRIVER
M: Elie Morisse <syniurge@gmail.com> M: Elie Morisse <syniurge@gmail.com>
M: Nehal Shah <nehal-bakulchandra.shah@amd.com> M: Nehal Shah <nehal-bakulchandra.shah@amd.com>
......
...@@ -226,17 +226,20 @@ config SPI_DESIGNWARE ...@@ -226,17 +226,20 @@ config SPI_DESIGNWARE
help help
general driver for SPI controller core from DesignWare general driver for SPI controller core from DesignWare
if SPI_DESIGNWARE
config SPI_DW_DMA
bool "DMA support for DW SPI controller"
config SPI_DW_PCI config SPI_DW_PCI
tristate "PCI interface driver for DW SPI core" tristate "PCI interface driver for DW SPI core"
depends on SPI_DESIGNWARE && PCI depends on PCI
config SPI_DW_MID_DMA
bool "DMA support for DW SPI controller on Intel MID platform"
depends on SPI_DW_PCI && DW_DMAC_PCI
config SPI_DW_MMIO config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core" tristate "Memory-mapped io interface driver for DW SPI core"
depends on SPI_DESIGNWARE depends on HAS_IOMEM
endif
config SPI_DLN2 config SPI_DLN2
tristate "Diolan DLN-2 USB SPI adapter" tristate "Diolan DLN-2 USB SPI adapter"
...@@ -844,6 +847,7 @@ config SPI_TXX9 ...@@ -844,6 +847,7 @@ config SPI_TXX9
config SPI_UNIPHIER config SPI_UNIPHIER
tristate "Socionext UniPhier SPI Controller" tristate "Socionext UniPhier SPI Controller"
depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF
depends on HAS_IOMEM
help help
This enables a driver for the Socionext UniPhier SoC SCSSI SPI controller. This enables a driver for the Socionext UniPhier SoC SCSSI SPI controller.
...@@ -910,6 +914,12 @@ config SPI_ZYNQMP_GQSPI ...@@ -910,6 +914,12 @@ config SPI_ZYNQMP_GQSPI
help help
Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC. Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
config SPI_AMD
tristate "AMD SPI controller"
depends on SPI_MASTER || COMPILE_TEST
help
Enables SPI controller driver for AMD SoC.
# #
# Add new SPI master controllers in alphabetical order above this line # Add new SPI master controllers in alphabetical order above this line
# #
......
...@@ -36,9 +36,10 @@ obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o ...@@ -36,9 +36,10 @@ obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
obj-$(CONFIG_SPI_DLN2) += spi-dln2.o obj-$(CONFIG_SPI_DLN2) += spi-dln2.o
obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
spi-dw-y := spi-dw-core.o
spi-dw-$(CONFIG_SPI_DW_DMA) += spi-dw-dma.o
obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o obj-$(CONFIG_SPI_DW_PCI) += spi-dw-pci.o
spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
obj-$(CONFIG_SPI_EFM32) += spi-efm32.o obj-$(CONFIG_SPI_EFM32) += spi-efm32.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
obj-$(CONFIG_SPI_FALCON) += spi-falcon.o obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
...@@ -127,6 +128,7 @@ obj-$(CONFIG_SPI_XLP) += spi-xlp.o ...@@ -127,6 +128,7 @@ obj-$(CONFIG_SPI_XLP) += spi-xlp.o
obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o
obj-$(CONFIG_SPI_ZYNQ_QSPI) += spi-zynq-qspi.o obj-$(CONFIG_SPI_ZYNQ_QSPI) += spi-zynq-qspi.o
obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o
obj-$(CONFIG_SPI_AMD) += spi-amd.o
# SPI slave protocol handlers # SPI slave protocol handlers
obj-$(CONFIG_SPI_SLAVE_TIME) += spi-slave-time.o obj-$(CONFIG_SPI_SLAVE_TIME) += spi-slave-time.o
......
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
//
// AMD SPI controller driver
//
// Copyright (c) 2020, Advanced Micro Devices, Inc.
//
// Author: Sanjay R Mehta <sanju.mehta@amd.com>
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#define AMD_SPI_CTRL0_REG 0x00
#define AMD_SPI_EXEC_CMD BIT(16)
#define AMD_SPI_FIFO_CLEAR BIT(20)
#define AMD_SPI_BUSY BIT(31)
#define AMD_SPI_OPCODE_MASK 0xFF
#define AMD_SPI_ALT_CS_REG 0x1D
#define AMD_SPI_ALT_CS_MASK 0x3
#define AMD_SPI_FIFO_BASE 0x80
#define AMD_SPI_TX_COUNT_REG 0x48
#define AMD_SPI_RX_COUNT_REG 0x4B
#define AMD_SPI_STATUS_REG 0x4C
#define AMD_SPI_MEM_SIZE 200
/* M_CMD OP codes for SPI */
#define AMD_SPI_XFER_TX 1
#define AMD_SPI_XFER_RX 2
struct amd_spi {
void __iomem *io_remap_addr;
unsigned long io_base_addr;
u32 rom_addr;
u8 chip_select;
};
static inline u8 amd_spi_readreg8(struct spi_master *master, int idx)
{
struct amd_spi *amd_spi = spi_master_get_devdata(master);
return ioread8((u8 __iomem *)amd_spi->io_remap_addr + idx);
}
static inline void amd_spi_writereg8(struct spi_master *master, int idx,
u8 val)
{
struct amd_spi *amd_spi = spi_master_get_devdata(master);
iowrite8(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
}
static inline void amd_spi_setclear_reg8(struct spi_master *master, int idx,
u8 set, u8 clear)
{
u8 tmp = amd_spi_readreg8(master, idx);
tmp = (tmp & ~clear) | set;
amd_spi_writereg8(master, idx, tmp);
}
static inline u32 amd_spi_readreg32(struct spi_master *master, int idx)
{
struct amd_spi *amd_spi = spi_master_get_devdata(master);
return ioread32((u8 __iomem *)amd_spi->io_remap_addr + idx);
}
static inline void amd_spi_writereg32(struct spi_master *master, int idx,
u32 val)
{
struct amd_spi *amd_spi = spi_master_get_devdata(master);
iowrite32(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
}
static inline void amd_spi_setclear_reg32(struct spi_master *master, int idx,
u32 set, u32 clear)
{
u32 tmp = amd_spi_readreg32(master, idx);
tmp = (tmp & ~clear) | set;
amd_spi_writereg32(master, idx, tmp);
}
static void amd_spi_select_chip(struct spi_master *master)
{
struct amd_spi *amd_spi = spi_master_get_devdata(master);
u8 chip_select = amd_spi->chip_select;
amd_spi_setclear_reg8(master, AMD_SPI_ALT_CS_REG, chip_select,
AMD_SPI_ALT_CS_MASK);
}
static void amd_spi_clear_fifo_ptr(struct spi_master *master)
{
amd_spi_setclear_reg32(master, AMD_SPI_CTRL0_REG, AMD_SPI_FIFO_CLEAR,
AMD_SPI_FIFO_CLEAR);
}
static void amd_spi_set_opcode(struct spi_master *master, u8 cmd_opcode)
{
amd_spi_setclear_reg32(master, AMD_SPI_CTRL0_REG, cmd_opcode,
AMD_SPI_OPCODE_MASK);
}
static inline void amd_spi_set_rx_count(struct spi_master *master,
u8 rx_count)
{
amd_spi_setclear_reg8(master, AMD_SPI_RX_COUNT_REG, rx_count, 0xff);
}
static inline void amd_spi_set_tx_count(struct spi_master *master,
u8 tx_count)
{
amd_spi_setclear_reg8(master, AMD_SPI_TX_COUNT_REG, tx_count, 0xff);
}
static inline int amd_spi_busy_wait(struct amd_spi *amd_spi)
{
bool spi_busy;
int timeout = 100000;
/* poll for SPI bus to become idle */
spi_busy = (ioread32((u8 __iomem *)amd_spi->io_remap_addr +
AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY;
while (spi_busy) {
usleep_range(10, 20);
if (timeout-- < 0)
return -ETIMEDOUT;
spi_busy = (ioread32((u8 __iomem *)amd_spi->io_remap_addr +
AMD_SPI_CTRL0_REG) & AMD_SPI_BUSY) == AMD_SPI_BUSY;
}
return 0;
}
static void amd_spi_execute_opcode(struct spi_master *master)
{
struct amd_spi *amd_spi = spi_master_get_devdata(master);
/* Set ExecuteOpCode bit in the CTRL0 register */
amd_spi_setclear_reg32(master, AMD_SPI_CTRL0_REG, AMD_SPI_EXEC_CMD,
AMD_SPI_EXEC_CMD);
amd_spi_busy_wait(amd_spi);
}
static int amd_spi_master_setup(struct spi_device *spi)
{
struct spi_master *master = spi->master;
amd_spi_clear_fifo_ptr(master);
return 0;
}
static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
struct spi_master *master,
struct spi_message *message)
{
struct spi_transfer *xfer = NULL;
u8 cmd_opcode;
u8 *buf = NULL;
u32 m_cmd = 0;
u32 i = 0;
u32 tx_len = 0, rx_len = 0;
list_for_each_entry(xfer, &message->transfers,
transfer_list) {
if (xfer->rx_buf)
m_cmd = AMD_SPI_XFER_RX;
if (xfer->tx_buf)
m_cmd = AMD_SPI_XFER_TX;
if (m_cmd & AMD_SPI_XFER_TX) {
buf = (u8 *)xfer->tx_buf;
tx_len = xfer->len - 1;
cmd_opcode = *(u8 *)xfer->tx_buf;
buf++;
amd_spi_set_opcode(master, cmd_opcode);
/* Write data into the FIFO. */
for (i = 0; i < tx_len; i++) {
iowrite8(buf[i],
((u8 __iomem *)amd_spi->io_remap_addr +
AMD_SPI_FIFO_BASE + i));
}
amd_spi_set_tx_count(master, tx_len);
amd_spi_clear_fifo_ptr(master);
/* Execute command */
amd_spi_execute_opcode(master);
}
if (m_cmd & AMD_SPI_XFER_RX) {
/*
* Store no. of bytes to be received from
* FIFO
*/
rx_len = xfer->len;
buf = (u8 *)xfer->rx_buf;
amd_spi_set_rx_count(master, rx_len);
amd_spi_clear_fifo_ptr(master);
/* Execute command */
amd_spi_execute_opcode(master);
/* Read data from FIFO to receive buffer */
for (i = 0; i < rx_len; i++)
buf[i] = amd_spi_readreg8(master,
AMD_SPI_FIFO_BASE +
tx_len + i);
}
}
/* Update statistics */
message->actual_length = tx_len + rx_len + 1;
/* complete the transaction */
message->status = 0;
spi_finalize_current_message(master);
return 0;
}
static int amd_spi_master_transfer(struct spi_master *master,
struct spi_message *msg)
{
struct amd_spi *amd_spi = spi_master_get_devdata(master);
struct spi_device *spi = msg->spi;
amd_spi->chip_select = spi->chip_select;
amd_spi_select_chip(master);
/*
* Extract spi_transfers from the spi message and
* program the controller.
*/
amd_spi_fifo_xfer(amd_spi, master, msg);
return 0;
}
static int amd_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct spi_master *master;
struct amd_spi *amd_spi;
struct resource *res;
int err = 0;
/* Allocate storage for spi_master and driver private data */
master = spi_alloc_master(dev, sizeof(struct amd_spi));
if (!master) {
dev_err(dev, "Error allocating SPI master\n");
return -ENOMEM;
}
amd_spi = spi_master_get_devdata(master);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
amd_spi->io_remap_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(amd_spi->io_remap_addr)) {
err = PTR_ERR(amd_spi->io_remap_addr);
dev_err(dev, "error %d ioremap of SPI registers failed\n", err);
goto err_free_master;
}
dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr);
/* Initialize the spi_master fields */
master->bus_num = 0;
master->num_chipselect = 4;
master->mode_bits = 0;
master->flags = SPI_MASTER_HALF_DUPLEX;
master->setup = amd_spi_master_setup;
master->transfer_one_message = amd_spi_master_transfer;
/* Register the controller with SPI framework */
err = devm_spi_register_master(dev, master);
if (err) {
dev_err(dev, "error %d registering SPI controller\n", err);
goto err_free_master;
}
return 0;
err_free_master:
spi_master_put(master);
return err;
}
static const struct acpi_device_id spi_acpi_match[] = {
{ "AMDI0061", 0 },
{},
};
MODULE_DEVICE_TABLE(acpi, spi_acpi_match);
static struct platform_driver amd_spi_driver = {
.driver = {
.name = "amd_spi",
.acpi_match_table = ACPI_PTR(spi_acpi_match),
},
.probe = amd_spi_probe,
};
module_platform_driver(amd_spi_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Sanjay Mehta <sanju.mehta@amd.com>");
MODULE_DESCRIPTION("AMD SPI Master Controller Driver");
...@@ -276,11 +276,11 @@ static int a3700_spi_fifo_flush(struct a3700_spi *a3700_spi) ...@@ -276,11 +276,11 @@ static int a3700_spi_fifo_flush(struct a3700_spi *a3700_spi)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static int a3700_spi_init(struct a3700_spi *a3700_spi) static void a3700_spi_init(struct a3700_spi *a3700_spi)
{ {
struct spi_master *master = a3700_spi->master; struct spi_master *master = a3700_spi->master;
u32 val; u32 val;
int i, ret = 0; int i;
/* Reset SPI unit */ /* Reset SPI unit */
val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG); val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
...@@ -311,8 +311,6 @@ static int a3700_spi_init(struct a3700_spi *a3700_spi) ...@@ -311,8 +311,6 @@ static int a3700_spi_init(struct a3700_spi *a3700_spi)
/* Mask the interrupts and clear cause bits */ /* Mask the interrupts and clear cause bits */
spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0); spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0);
spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, ~0U); spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, ~0U);
return ret;
} }
static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id) static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id)
...@@ -886,9 +884,7 @@ static int a3700_spi_probe(struct platform_device *pdev) ...@@ -886,9 +884,7 @@ static int a3700_spi_probe(struct platform_device *pdev)
master->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk), master->min_speed_hz = DIV_ROUND_UP(clk_get_rate(spi->clk),
A3700_SPI_MAX_PRESCALE); A3700_SPI_MAX_PRESCALE);
ret = a3700_spi_init(spi); a3700_spi_init(spi);
if (ret)
goto error_clk;
ret = devm_request_irq(dev, spi->irq, a3700_spi_interrupt, 0, ret = devm_request_irq(dev, spi->irq, a3700_spi_interrupt, 0,
dev_name(dev), master); dev_name(dev), master);
......
...@@ -706,6 +706,7 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master, ...@@ -706,6 +706,7 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master,
static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
struct spi_transfer *xfer, struct spi_transfer *xfer,
u32 *plen) u32 *plen)
__must_hold(&as->lock)
{ {
struct atmel_spi *as = spi_master_get_devdata(master); struct atmel_spi *as = spi_master_get_devdata(master);
struct dma_chan *rxchan = master->dma_rx; struct dma_chan *rxchan = master->dma_rx;
......
...@@ -91,6 +91,7 @@ ...@@ -91,6 +91,7 @@
#define MSPI_MSPI_STATUS 0x020 #define MSPI_MSPI_STATUS 0x020
#define MSPI_CPTQP 0x024 #define MSPI_CPTQP 0x024
#define MSPI_SPCR3 0x028 #define MSPI_SPCR3 0x028
#define MSPI_REV 0x02c
#define MSPI_TXRAM 0x040 #define MSPI_TXRAM 0x040
#define MSPI_RXRAM 0x0c0 #define MSPI_RXRAM 0x0c0
#define MSPI_CDRAM 0x140 #define MSPI_CDRAM 0x140
...@@ -106,14 +107,22 @@ ...@@ -106,14 +107,22 @@
#define MSPI_SPCR2_SPE BIT(6) #define MSPI_SPCR2_SPE BIT(6)
#define MSPI_SPCR2_CONT_AFTER_CMD BIT(7) #define MSPI_SPCR2_CONT_AFTER_CMD BIT(7)
#define MSPI_SPCR3_FASTBR BIT(0)
#define MSPI_SPCR3_FASTDT BIT(1)
#define MSPI_SPCR3_SYSCLKSEL_MASK GENMASK(11, 10)
#define MSPI_SPCR3_SYSCLKSEL_27 (MSPI_SPCR3_SYSCLKSEL_MASK & \
~(BIT(10) | BIT(11)))
#define MSPI_SPCR3_SYSCLKSEL_108 (MSPI_SPCR3_SYSCLKSEL_MASK & \
BIT(11))
#define MSPI_MSPI_STATUS_SPIF BIT(0) #define MSPI_MSPI_STATUS_SPIF BIT(0)
#define INTR_BASE_BIT_SHIFT 0x02 #define INTR_BASE_BIT_SHIFT 0x02
#define INTR_COUNT 0x07 #define INTR_COUNT 0x07
#define NUM_CHIPSELECT 4 #define NUM_CHIPSELECT 4
#define QSPI_SPBR_MIN 8U
#define QSPI_SPBR_MAX 255U #define QSPI_SPBR_MAX 255U
#define MSPI_BASE_FREQ 27000000UL
#define OPCODE_DIOR 0xBB #define OPCODE_DIOR 0xBB
#define OPCODE_QIOR 0xEB #define OPCODE_QIOR 0xEB
...@@ -217,6 +226,9 @@ struct bcm_qspi { ...@@ -217,6 +226,9 @@ struct bcm_qspi {
struct bcm_qspi_dev_id *dev_ids; struct bcm_qspi_dev_id *dev_ids;
struct completion mspi_done; struct completion mspi_done;
struct completion bspi_done; struct completion bspi_done;
u8 mspi_maj_rev;
u8 mspi_min_rev;
bool mspi_spcr3_sysclk;
}; };
static inline bool has_bspi(struct bcm_qspi *qspi) static inline bool has_bspi(struct bcm_qspi *qspi)
...@@ -224,6 +236,36 @@ static inline bool has_bspi(struct bcm_qspi *qspi) ...@@ -224,6 +236,36 @@ static inline bool has_bspi(struct bcm_qspi *qspi)
return qspi->bspi_mode; return qspi->bspi_mode;
} }
/* hardware supports spcr3 and fast baud-rate */
static inline bool bcm_qspi_has_fastbr(struct bcm_qspi *qspi)
{
if (!has_bspi(qspi) &&
((qspi->mspi_maj_rev >= 1) &&
(qspi->mspi_min_rev >= 5)))
return true;
return false;
}
/* hardware supports sys clk 108Mhz */
static inline bool bcm_qspi_has_sysclk_108(struct bcm_qspi *qspi)
{
if (!has_bspi(qspi) && (qspi->mspi_spcr3_sysclk ||
((qspi->mspi_maj_rev >= 1) &&
(qspi->mspi_min_rev >= 6))))
return true;
return false;
}
static inline int bcm_qspi_spbr_min(struct bcm_qspi *qspi)
{
if (bcm_qspi_has_fastbr(qspi))
return 1;
else
return 8;
}
/* Read qspi controller register*/ /* Read qspi controller register*/
static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type, static inline u32 bcm_qspi_read(struct bcm_qspi *qspi, enum base_type type,
unsigned int offset) unsigned int offset)
...@@ -531,16 +573,39 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi, ...@@ -531,16 +573,39 @@ static void bcm_qspi_hw_set_parms(struct bcm_qspi *qspi,
if (xp->speed_hz) if (xp->speed_hz)
spbr = qspi->base_clk / (2 * xp->speed_hz); spbr = qspi->base_clk / (2 * xp->speed_hz);
spcr = clamp_val(spbr, QSPI_SPBR_MIN, QSPI_SPBR_MAX); spcr = clamp_val(spbr, bcm_qspi_spbr_min(qspi), QSPI_SPBR_MAX);
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spcr); bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, spcr);
spcr = MSPI_MASTER_BIT; if (!qspi->mspi_maj_rev)
/* legacy controller */
spcr = MSPI_MASTER_BIT;
else
spcr = 0;
/* for 16 bit the data should be zero */ /* for 16 bit the data should be zero */
if (xp->bits_per_word != 16) if (xp->bits_per_word != 16)
spcr |= xp->bits_per_word << 2; spcr |= xp->bits_per_word << 2;
spcr |= xp->mode & 3; spcr |= xp->mode & 3;
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_MSB, spcr); bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_MSB, spcr);
if (bcm_qspi_has_fastbr(qspi)) {
spcr = 0;
/* enable fastbr */
spcr |= MSPI_SPCR3_FASTBR;
if (bcm_qspi_has_sysclk_108(qspi)) {
/* SYSCLK_108 */
spcr |= MSPI_SPCR3_SYSCLKSEL_108;
qspi->base_clk = MSPI_BASE_FREQ * 4;
/* Change spbr as we changed sysclk */
bcm_qspi_write(qspi, MSPI, MSPI_SPCR0_LSB, 4);
}
bcm_qspi_write(qspi, MSPI, MSPI_SPCR3, spcr);
}
qspi->last_parms = *xp; qspi->last_parms = *xp;
} }
...@@ -1195,8 +1260,51 @@ static const struct spi_controller_mem_ops bcm_qspi_mem_ops = { ...@@ -1195,8 +1260,51 @@ static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
.exec_op = bcm_qspi_exec_mem_op, .exec_op = bcm_qspi_exec_mem_op,
}; };
struct bcm_qspi_data {
bool has_mspi_rev;
bool has_spcr3_sysclk;
};
static const struct bcm_qspi_data bcm_qspi_no_rev_data = {
.has_mspi_rev = false,
.has_spcr3_sysclk = false,
};
static const struct bcm_qspi_data bcm_qspi_rev_data = {
.has_mspi_rev = true,
.has_spcr3_sysclk = false,
};
static const struct bcm_qspi_data bcm_qspi_spcr3_data = {
.has_mspi_rev = true,
.has_spcr3_sysclk = true,
};
static const struct of_device_id bcm_qspi_of_match[] = { static const struct of_device_id bcm_qspi_of_match[] = {
{ .compatible = "brcm,spi-bcm-qspi" }, {
.compatible = "brcm,spi-bcm7425-qspi",
.data = &bcm_qspi_no_rev_data,
},
{
.compatible = "brcm,spi-bcm7429-qspi",
.data = &bcm_qspi_no_rev_data,
},
{
.compatible = "brcm,spi-bcm7435-qspi",
.data = &bcm_qspi_no_rev_data,
},
{
.compatible = "brcm,spi-bcm-qspi",
.data = &bcm_qspi_rev_data,
},
{
.compatible = "brcm,spi-bcm7216-qspi",
.data = &bcm_qspi_spcr3_data,
},
{
.compatible = "brcm,spi-bcm7278-qspi",
.data = &bcm_qspi_spcr3_data,
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, bcm_qspi_of_match); MODULE_DEVICE_TABLE(of, bcm_qspi_of_match);
...@@ -1204,12 +1312,15 @@ MODULE_DEVICE_TABLE(of, bcm_qspi_of_match); ...@@ -1204,12 +1312,15 @@ MODULE_DEVICE_TABLE(of, bcm_qspi_of_match);
int bcm_qspi_probe(struct platform_device *pdev, int bcm_qspi_probe(struct platform_device *pdev,
struct bcm_qspi_soc_intc *soc_intc) struct bcm_qspi_soc_intc *soc_intc)
{ {
const struct of_device_id *of_id = NULL;
const struct bcm_qspi_data *data;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct bcm_qspi *qspi; struct bcm_qspi *qspi;
struct spi_master *master; struct spi_master *master;
struct resource *res; struct resource *res;
int irq, ret = 0, num_ints = 0; int irq, ret = 0, num_ints = 0;
u32 val; u32 val;
u32 rev = 0;
const char *name = NULL; const char *name = NULL;
int num_irqs = ARRAY_SIZE(qspi_irq_tab); int num_irqs = ARRAY_SIZE(qspi_irq_tab);
...@@ -1217,9 +1328,12 @@ int bcm_qspi_probe(struct platform_device *pdev, ...@@ -1217,9 +1328,12 @@ int bcm_qspi_probe(struct platform_device *pdev,
if (!dev->of_node) if (!dev->of_node)
return -ENODEV; return -ENODEV;
if (!of_match_node(bcm_qspi_of_match, dev->of_node)) of_id = of_match_node(bcm_qspi_of_match, dev->of_node);
if (!of_id)
return -ENODEV; return -ENODEV;
data = of_id->data;
master = spi_alloc_master(dev, sizeof(struct bcm_qspi)); master = spi_alloc_master(dev, sizeof(struct bcm_qspi));
if (!master) { if (!master) {
dev_err(dev, "error allocating spi_master\n"); dev_err(dev, "error allocating spi_master\n");
...@@ -1352,7 +1466,19 @@ int bcm_qspi_probe(struct platform_device *pdev, ...@@ -1352,7 +1466,19 @@ int bcm_qspi_probe(struct platform_device *pdev,
} }
qspi->base_clk = clk_get_rate(qspi->clk); qspi->base_clk = clk_get_rate(qspi->clk);
qspi->max_speed_hz = qspi->base_clk / (QSPI_SPBR_MIN * 2);
if (data->has_mspi_rev) {
rev = bcm_qspi_read(qspi, MSPI, MSPI_REV);
/* some older revs do not have a MSPI_REV register */
if ((rev & 0xff) == 0xff)
rev = 0;
}
qspi->mspi_maj_rev = (rev >> 4) & 0xf;
qspi->mspi_min_rev = rev & 0xf;
qspi->mspi_spcr3_sysclk = data->has_spcr3_sysclk;
qspi->max_speed_hz = qspi->base_clk / (bcm_qspi_spbr_min(qspi) * 2);
bcm_qspi_hw_init(qspi); bcm_qspi_hw_init(qspi);
init_completion(&qspi->mspi_done); init_completion(&qspi->mspi_done);
......
...@@ -191,12 +191,12 @@ static void bcm2835_debugfs_remove(struct bcm2835_spi *bs) ...@@ -191,12 +191,12 @@ static void bcm2835_debugfs_remove(struct bcm2835_spi *bs)
} }
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned reg) static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned int reg)
{ {
return readl(bs->regs + reg); return readl(bs->regs + reg);
} }
static inline void bcm2835_wr(struct bcm2835_spi *bs, unsigned reg, u32 val) static inline void bcm2835_wr(struct bcm2835_spi *bs, unsigned int reg, u32 val)
{ {
writel(val, bs->regs + reg); writel(val, bs->regs + reg);
} }
...@@ -940,6 +940,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, ...@@ -940,6 +940,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
if (dma_mapping_error(ctlr->dma_tx->device->dev, bs->fill_tx_addr)) { if (dma_mapping_error(ctlr->dma_tx->device->dev, bs->fill_tx_addr)) {
dev_err(dev, "cannot map zero page - not using DMA mode\n"); dev_err(dev, "cannot map zero page - not using DMA mode\n");
bs->fill_tx_addr = 0; bs->fill_tx_addr = 0;
ret = -ENOMEM;
goto err_release; goto err_release;
} }
...@@ -949,6 +950,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, ...@@ -949,6 +950,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
DMA_MEM_TO_DEV, 0); DMA_MEM_TO_DEV, 0);
if (!bs->fill_tx_desc) { if (!bs->fill_tx_desc) {
dev_err(dev, "cannot prepare fill_tx_desc - not using DMA mode\n"); dev_err(dev, "cannot prepare fill_tx_desc - not using DMA mode\n");
ret = -ENOMEM;
goto err_release; goto err_release;
} }
...@@ -979,6 +981,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, ...@@ -979,6 +981,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
if (dma_mapping_error(ctlr->dma_rx->device->dev, bs->clear_rx_addr)) { if (dma_mapping_error(ctlr->dma_rx->device->dev, bs->clear_rx_addr)) {
dev_err(dev, "cannot map clear_rx_cs - not using DMA mode\n"); dev_err(dev, "cannot map clear_rx_cs - not using DMA mode\n");
bs->clear_rx_addr = 0; bs->clear_rx_addr = 0;
ret = -ENOMEM;
goto err_release; goto err_release;
} }
...@@ -989,6 +992,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, ...@@ -989,6 +992,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
DMA_MEM_TO_DEV, 0); DMA_MEM_TO_DEV, 0);
if (!bs->clear_rx_desc[i]) { if (!bs->clear_rx_desc[i]) {
dev_err(dev, "cannot prepare clear_rx_desc - not using DMA mode\n"); dev_err(dev, "cannot prepare clear_rx_desc - not using DMA mode\n");
ret = -ENOMEM;
goto err_release; goto err_release;
} }
...@@ -1376,17 +1380,26 @@ static int bcm2835_spi_remove(struct platform_device *pdev) ...@@ -1376,17 +1380,26 @@ static int bcm2835_spi_remove(struct platform_device *pdev)
spi_unregister_controller(ctlr); spi_unregister_controller(ctlr);
bcm2835_dma_release(ctlr, bs);
/* Clear FIFOs, and disable the HW block */ /* Clear FIFOs, and disable the HW block */
bcm2835_wr(bs, BCM2835_SPI_CS, bcm2835_wr(bs, BCM2835_SPI_CS,
BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX); BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
clk_disable_unprepare(bs->clk); clk_disable_unprepare(bs->clk);
bcm2835_dma_release(ctlr, bs);
return 0; return 0;
} }
static void bcm2835_spi_shutdown(struct platform_device *pdev)
{
int ret;
ret = bcm2835_spi_remove(pdev);
if (ret)
dev_err(&pdev->dev, "failed to shutdown\n");
}
static const struct of_device_id bcm2835_spi_match[] = { static const struct of_device_id bcm2835_spi_match[] = {
{ .compatible = "brcm,bcm2835-spi", }, { .compatible = "brcm,bcm2835-spi", },
{} {}
...@@ -1400,6 +1413,7 @@ static struct platform_driver bcm2835_spi_driver = { ...@@ -1400,6 +1413,7 @@ static struct platform_driver bcm2835_spi_driver = {
}, },
.probe = bcm2835_spi_probe, .probe = bcm2835_spi_probe,
.remove = bcm2835_spi_remove, .remove = bcm2835_spi_remove,
.shutdown = bcm2835_spi_shutdown,
}; };
module_platform_driver(bcm2835_spi_driver); module_platform_driver(bcm2835_spi_driver);
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -20,6 +19,7 @@ ...@@ -20,6 +19,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/reset.h>
#include "spi-dw.h" #include "spi-dw.h"
...@@ -30,6 +30,7 @@ struct dw_spi_mmio { ...@@ -30,6 +30,7 @@ struct dw_spi_mmio {
struct clk *clk; struct clk *clk;
struct clk *pclk; struct clk *pclk;
void *priv; void *priv;
struct reset_control *rstc;
}; };
#define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24 #define MSCC_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
...@@ -44,6 +45,13 @@ struct dw_spi_mmio { ...@@ -44,6 +45,13 @@ struct dw_spi_mmio {
#define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13) #define MSCC_SPI_MST_SW_MODE_SW_PIN_CTRL_MODE BIT(13)
#define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5) #define MSCC_SPI_MST_SW_MODE_SW_SPI_CS(x) (x << 5)
/*
* For Keem Bay, CTRLR0[31] is used to select controller mode.
* 0: SSI is slave
* 1: SSI is master
*/
#define KEEMBAY_CTRLR0_SSIC_IS_MST BIT(31)
struct dw_spi_mscc { struct dw_spi_mscc {
struct regmap *syscon; struct regmap *syscon;
void __iomem *spi_mst; void __iomem *spi_mst;
...@@ -106,6 +114,9 @@ static int dw_spi_mscc_init(struct platform_device *pdev, ...@@ -106,6 +114,9 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
dwsmmio->dws.set_cs = dw_spi_mscc_set_cs; dwsmmio->dws.set_cs = dw_spi_mscc_set_cs;
dwsmmio->priv = dwsmscc; dwsmmio->priv = dwsmscc;
/* Register hook to configure CTRLR0 */
dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
return 0; return 0;
} }
...@@ -128,6 +139,49 @@ static int dw_spi_alpine_init(struct platform_device *pdev, ...@@ -128,6 +139,49 @@ static int dw_spi_alpine_init(struct platform_device *pdev,
{ {
dwsmmio->dws.cs_override = 1; dwsmmio->dws.cs_override = 1;
/* Register hook to configure CTRLR0 */
dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
return 0;
}
static int dw_spi_dw_apb_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio)
{
/* Register hook to configure CTRLR0 */
dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
dw_spi_dma_setup_generic(&dwsmmio->dws);
return 0;
}
static int dw_spi_dwc_ssi_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio)
{
/* Register hook to configure CTRLR0 */
dwsmmio->dws.update_cr0 = dw_spi_update_cr0_v1_01a;
dw_spi_dma_setup_generic(&dwsmmio->dws);
return 0;
}
static u32 dw_spi_update_cr0_keembay(struct spi_controller *master,
struct spi_device *spi,
struct spi_transfer *transfer)
{
u32 cr0 = dw_spi_update_cr0_v1_01a(master, spi, transfer);
return cr0 | KEEMBAY_CTRLR0_SSIC_IS_MST;
}
static int dw_spi_keembay_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio)
{
/* Register hook to configure CTRLR0 */
dwsmmio->dws.update_cr0 = dw_spi_update_cr0_keembay;
return 0; return 0;
} }
...@@ -136,6 +190,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) ...@@ -136,6 +190,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
int (*init_func)(struct platform_device *pdev, int (*init_func)(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio); struct dw_spi_mmio *dwsmmio);
struct dw_spi_mmio *dwsmmio; struct dw_spi_mmio *dwsmmio;
struct resource *mem;
struct dw_spi *dws; struct dw_spi *dws;
int ret; int ret;
int num_cs; int num_cs;
...@@ -148,11 +203,11 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) ...@@ -148,11 +203,11 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
dws = &dwsmmio->dws; dws = &dwsmmio->dws;
/* Get basic io resource and map it */ /* Get basic io resource and map it */
dws->regs = devm_platform_ioremap_resource(pdev, 0); dws->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
if (IS_ERR(dws->regs)) { if (IS_ERR(dws->regs))
dev_err(&pdev->dev, "SPI region map failed\n");
return PTR_ERR(dws->regs); return PTR_ERR(dws->regs);
}
dws->paddr = mem->start;
dws->irq = platform_get_irq(pdev, 0); dws->irq = platform_get_irq(pdev, 0);
if (dws->irq < 0) if (dws->irq < 0)
...@@ -175,6 +230,14 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) ...@@ -175,6 +230,14 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
if (ret) if (ret)
goto out_clk; goto out_clk;
/* find an optional reset controller */
dwsmmio->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, "spi");
if (IS_ERR(dwsmmio->rstc)) {
ret = PTR_ERR(dwsmmio->rstc);
goto out_clk;
}
reset_control_deassert(dwsmmio->rstc);
dws->bus_num = pdev->id; dws->bus_num = pdev->id;
dws->max_freq = clk_get_rate(dwsmmio->clk); dws->max_freq = clk_get_rate(dwsmmio->clk);
...@@ -208,6 +271,8 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) ...@@ -208,6 +271,8 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
clk_disable_unprepare(dwsmmio->pclk); clk_disable_unprepare(dwsmmio->pclk);
out_clk: out_clk:
clk_disable_unprepare(dwsmmio->clk); clk_disable_unprepare(dwsmmio->clk);
reset_control_assert(dwsmmio->rstc);
return ret; return ret;
} }
...@@ -219,25 +284,30 @@ static int dw_spi_mmio_remove(struct platform_device *pdev) ...@@ -219,25 +284,30 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(dwsmmio->pclk); clk_disable_unprepare(dwsmmio->pclk);
clk_disable_unprepare(dwsmmio->clk); clk_disable_unprepare(dwsmmio->clk);
reset_control_assert(dwsmmio->rstc);
return 0; return 0;
} }
static const struct of_device_id dw_spi_mmio_of_match[] = { static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "snps,dw-apb-ssi", }, { .compatible = "snps,dw-apb-ssi", .data = dw_spi_dw_apb_init},
{ .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init}, { .compatible = "mscc,ocelot-spi", .data = dw_spi_mscc_ocelot_init},
{ .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init}, { .compatible = "mscc,jaguar2-spi", .data = dw_spi_mscc_jaguar2_init},
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init}, { .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
{ .compatible = "renesas,rzn1-spi", }, { .compatible = "renesas,rzn1-spi", .data = dw_spi_dw_apb_init},
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_dwc_ssi_init},
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init},
{ /* end of table */} { /* end of table */}
}; };
MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match); MODULE_DEVICE_TABLE(of, dw_spi_mmio_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id dw_spi_mmio_acpi_match[] = { static const struct acpi_device_id dw_spi_mmio_acpi_match[] = {
{"HISI0173", 0}, {"HISI0173", (kernel_ulong_t)dw_spi_dw_apb_init},
{}, {},
}; };
MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match); MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match);
#endif
static struct platform_driver dw_spi_mmio_driver = { static struct platform_driver dw_spi_mmio_driver = {
.probe = dw_spi_mmio_probe, .probe = dw_spi_mmio_probe,
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
* Copyright (c) 2009, 2014 Intel Corporation. * Copyright (c) 2009, 2014 Intel Corporation.
*/ */
#include <linux/interrupt.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -16,6 +15,15 @@ ...@@ -16,6 +15,15 @@
#define DRIVER_NAME "dw_spi_pci" #define DRIVER_NAME "dw_spi_pci"
/* HW info for MRST Clk Control Unit, 32b reg per controller */
#define MRST_SPI_CLK_BASE 100000000 /* 100m */
#define MRST_CLK_SPI_REG 0xff11d86c
#define CLK_SPI_BDIV_OFFSET 0
#define CLK_SPI_BDIV_MASK 0x00000007
#define CLK_SPI_CDIV_OFFSET 9
#define CLK_SPI_CDIV_MASK 0x00000e00
#define CLK_SPI_DISABLE_OFFSET 8
struct spi_pci_desc { struct spi_pci_desc {
int (*setup)(struct dw_spi *); int (*setup)(struct dw_spi *);
u16 num_cs; u16 num_cs;
...@@ -23,19 +31,55 @@ struct spi_pci_desc { ...@@ -23,19 +31,55 @@ struct spi_pci_desc {
u32 max_freq; u32 max_freq;
}; };
static int spi_mid_init(struct dw_spi *dws)
{
void __iomem *clk_reg;
u32 clk_cdiv;
clk_reg = ioremap(MRST_CLK_SPI_REG, 16);
if (!clk_reg)
return -ENOMEM;
/* Get SPI controller operating freq info */
clk_cdiv = readl(clk_reg + dws->bus_num * sizeof(u32));
clk_cdiv &= CLK_SPI_CDIV_MASK;
clk_cdiv >>= CLK_SPI_CDIV_OFFSET;
dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1);
iounmap(clk_reg);
/* Register hook to configure CTRLR0 */
dws->update_cr0 = dw_spi_update_cr0;
dw_spi_dma_setup_mfld(dws);
return 0;
}
static int spi_generic_init(struct dw_spi *dws)
{
/* Register hook to configure CTRLR0 */
dws->update_cr0 = dw_spi_update_cr0;
dw_spi_dma_setup_generic(dws);
return 0;
}
static struct spi_pci_desc spi_pci_mid_desc_1 = { static struct spi_pci_desc spi_pci_mid_desc_1 = {
.setup = dw_spi_mid_init, .setup = spi_mid_init,
.num_cs = 5, .num_cs = 5,
.bus_num = 0, .bus_num = 0,
}; };
static struct spi_pci_desc spi_pci_mid_desc_2 = { static struct spi_pci_desc spi_pci_mid_desc_2 = {
.setup = dw_spi_mid_init, .setup = spi_mid_init,
.num_cs = 2, .num_cs = 2,
.bus_num = 1, .bus_num = 1,
}; };
static struct spi_pci_desc spi_pci_ehl_desc = { static struct spi_pci_desc spi_pci_ehl_desc = {
.setup = spi_generic_init,
.num_cs = 2, .num_cs = 2,
.bus_num = -1, .bus_num = -1,
.max_freq = 100000000, .max_freq = 100000000,
......
...@@ -2,18 +2,21 @@ ...@@ -2,18 +2,21 @@
#ifndef DW_SPI_HEADER_H #ifndef DW_SPI_HEADER_H
#define DW_SPI_HEADER_H #define DW_SPI_HEADER_H
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/irqreturn.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
/* Register offsets */ /* Register offsets */
#define DW_SPI_CTRL0 0x00 #define DW_SPI_CTRLR0 0x00
#define DW_SPI_CTRL1 0x04 #define DW_SPI_CTRLR1 0x04
#define DW_SPI_SSIENR 0x08 #define DW_SPI_SSIENR 0x08
#define DW_SPI_MWCR 0x0c #define DW_SPI_MWCR 0x0c
#define DW_SPI_SER 0x10 #define DW_SPI_SER 0x10
#define DW_SPI_BAUDR 0x14 #define DW_SPI_BAUDR 0x14
#define DW_SPI_TXFLTR 0x18 #define DW_SPI_TXFTLR 0x18
#define DW_SPI_RXFLTR 0x1c #define DW_SPI_RXFTLR 0x1c
#define DW_SPI_TXFLR 0x20 #define DW_SPI_TXFLR 0x20
#define DW_SPI_RXFLR 0x24 #define DW_SPI_RXFLR 0x24
#define DW_SPI_SR 0x28 #define DW_SPI_SR 0x28
...@@ -57,6 +60,15 @@ ...@@ -57,6 +60,15 @@
#define SPI_SRL_OFFSET 11 #define SPI_SRL_OFFSET 11
#define SPI_CFS_OFFSET 12 #define SPI_CFS_OFFSET 12
/* Bit fields in CTRLR0 based on DWC_ssi_databook.pdf v1.01a */
#define DWC_SSI_CTRLR0_SRL_OFFSET 13
#define DWC_SSI_CTRLR0_TMOD_OFFSET 10
#define DWC_SSI_CTRLR0_TMOD_MASK GENMASK(11, 10)
#define DWC_SSI_CTRLR0_SCPOL_OFFSET 9
#define DWC_SSI_CTRLR0_SCPH_OFFSET 8
#define DWC_SSI_CTRLR0_FRF_OFFSET 6
#define DWC_SSI_CTRLR0_DFS_OFFSET 0
/* Bit fields in SR, 7 bits */ /* Bit fields in SR, 7 bits */
#define SR_MASK 0x7f /* cover 7 bits */ #define SR_MASK 0x7f /* cover 7 bits */
#define SR_BUSY (1 << 0) #define SR_BUSY (1 << 0)
...@@ -90,7 +102,7 @@ enum dw_ssi_type { ...@@ -90,7 +102,7 @@ enum dw_ssi_type {
struct dw_spi; struct dw_spi;
struct dw_spi_dma_ops { struct dw_spi_dma_ops {
int (*dma_init)(struct dw_spi *dws); int (*dma_init)(struct device *dev, struct dw_spi *dws);
void (*dma_exit)(struct dw_spi *dws); void (*dma_exit)(struct dw_spi *dws);
int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer); int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer);
bool (*can_dma)(struct spi_controller *master, struct spi_device *spi, bool (*can_dma)(struct spi_controller *master, struct spi_device *spi,
...@@ -114,6 +126,8 @@ struct dw_spi { ...@@ -114,6 +126,8 @@ struct dw_spi {
u16 bus_num; u16 bus_num;
u16 num_cs; /* supported slave numbers */ u16 num_cs; /* supported slave numbers */
void (*set_cs)(struct spi_device *spi, bool enable); void (*set_cs)(struct spi_device *spi, bool enable);
u32 (*update_cr0)(struct spi_controller *master, struct spi_device *spi,
struct spi_transfer *transfer);
/* Current message transfer state info */ /* Current message transfer state info */
size_t len; size_t len;
...@@ -124,24 +138,22 @@ struct dw_spi { ...@@ -124,24 +138,22 @@ struct dw_spi {
void *rx_end; void *rx_end;
int dma_mapped; int dma_mapped;
u8 n_bytes; /* current is a 1/2 bytes op */ u8 n_bytes; /* current is a 1/2 bytes op */
u32 dma_width;
irqreturn_t (*transfer_handler)(struct dw_spi *dws); irqreturn_t (*transfer_handler)(struct dw_spi *dws);
u32 current_freq; /* frequency in hz */ u32 current_freq; /* frequency in hz */
/* DMA info */ /* DMA info */
int dma_inited;
struct dma_chan *txchan; struct dma_chan *txchan;
u32 txburst;
struct dma_chan *rxchan; struct dma_chan *rxchan;
u32 rxburst;
unsigned long dma_chan_busy; unsigned long dma_chan_busy;
dma_addr_t dma_addr; /* phy address of the Data register */ dma_addr_t dma_addr; /* phy address of the Data register */
const struct dw_spi_dma_ops *dma_ops; const struct dw_spi_dma_ops *dma_ops;
void *dma_tx; struct completion dma_completion;
void *dma_rx;
/* Bus interface info */
void *priv;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs; struct dentry *debugfs;
struct debugfs_regset32 regset;
#endif #endif
}; };
...@@ -235,24 +247,28 @@ static inline void spi_shutdown_chip(struct dw_spi *dws) ...@@ -235,24 +247,28 @@ static inline void spi_shutdown_chip(struct dw_spi *dws)
spi_set_clk(dws, 0); spi_set_clk(dws, 0);
} }
/*
* Each SPI slave device to work with dw_api controller should
* has such a structure claiming its working mode (poll or PIO/DMA),
* which can be save in the "controller_data" member of the
* struct spi_device.
*/
struct dw_spi_chip {
u8 poll_mode; /* 1 for controller polling mode */
u8 type; /* SPI/SSP/MicroWire */
void (*cs_control)(u32 command);
};
extern void dw_spi_set_cs(struct spi_device *spi, bool enable); extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws); extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
extern void dw_spi_remove_host(struct dw_spi *dws); extern void dw_spi_remove_host(struct dw_spi *dws);
extern int dw_spi_suspend_host(struct dw_spi *dws); extern int dw_spi_suspend_host(struct dw_spi *dws);
extern int dw_spi_resume_host(struct dw_spi *dws); extern int dw_spi_resume_host(struct dw_spi *dws);
extern u32 dw_spi_update_cr0(struct spi_controller *master,
struct spi_device *spi,
struct spi_transfer *transfer);
extern u32 dw_spi_update_cr0_v1_01a(struct spi_controller *master,
struct spi_device *spi,
struct spi_transfer *transfer);
#ifdef CONFIG_SPI_DW_DMA
extern void dw_spi_dma_setup_mfld(struct dw_spi *dws);
extern void dw_spi_dma_setup_generic(struct dw_spi *dws);
#else
static inline void dw_spi_dma_setup_mfld(struct dw_spi *dws) {}
static inline void dw_spi_dma_setup_generic(struct dw_spi *dws) {}
#endif /* !CONFIG_SPI_DW_DMA */
/* platform related setup */
extern int dw_spi_mid_init(struct dw_spi *dws); /* Intel MID platforms */
#endif /* DW_SPI_HEADER_H */ #endif /* DW_SPI_HEADER_H */
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: GPL-2.0+
// //
// Copyright 2013 Freescale Semiconductor, Inc. // Copyright 2013 Freescale Semiconductor, Inc.
// Copyright 2020 NXP
// //
// Freescale DSPI driver // Freescale DSPI driver
// This file contains a driver for the Freescale DSPI // This file contains a driver for the Freescale DSPI
...@@ -26,6 +27,9 @@ ...@@ -26,6 +27,9 @@
#define SPI_MCR_CLR_TXF BIT(11) #define SPI_MCR_CLR_TXF BIT(11)
#define SPI_MCR_CLR_RXF BIT(10) #define SPI_MCR_CLR_RXF BIT(10)
#define SPI_MCR_XSPI BIT(3) #define SPI_MCR_XSPI BIT(3)
#define SPI_MCR_DIS_TXF BIT(13)
#define SPI_MCR_DIS_RXF BIT(12)
#define SPI_MCR_HALT BIT(0)
#define SPI_TCR 0x08 #define SPI_TCR 0x08
#define SPI_TCR_GET_TCNT(x) (((x) & GENMASK(31, 16)) >> 16) #define SPI_TCR_GET_TCNT(x) (((x) & GENMASK(31, 16)) >> 16)
...@@ -246,13 +250,33 @@ struct fsl_dspi { ...@@ -246,13 +250,33 @@ struct fsl_dspi {
static void dspi_native_host_to_dev(struct fsl_dspi *dspi, u32 *txdata) static void dspi_native_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
{ {
memcpy(txdata, dspi->tx, dspi->oper_word_size); switch (dspi->oper_word_size) {
case 1:
*txdata = *(u8 *)dspi->tx;
break;
case 2:
*txdata = *(u16 *)dspi->tx;
break;
case 4:
*txdata = *(u32 *)dspi->tx;
break;
}
dspi->tx += dspi->oper_word_size; dspi->tx += dspi->oper_word_size;
} }
static void dspi_native_dev_to_host(struct fsl_dspi *dspi, u32 rxdata) static void dspi_native_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
{ {
memcpy(dspi->rx, &rxdata, dspi->oper_word_size); switch (dspi->oper_word_size) {
case 1:
*(u8 *)dspi->rx = rxdata;
break;
case 2:
*(u16 *)dspi->rx = rxdata;
break;
case 4:
*(u32 *)dspi->rx = rxdata;
break;
}
dspi->rx += dspi->oper_word_size; dspi->rx += dspi->oper_word_size;
} }
...@@ -1417,6 +1441,24 @@ static int dspi_remove(struct platform_device *pdev) ...@@ -1417,6 +1441,24 @@ static int dspi_remove(struct platform_device *pdev)
return 0; return 0;
} }
static void dspi_shutdown(struct platform_device *pdev)
{
struct spi_controller *ctlr = platform_get_drvdata(pdev);
struct fsl_dspi *dspi = spi_controller_get_devdata(ctlr);
/* Disable RX and TX */
regmap_update_bits(dspi->regmap, SPI_MCR,
SPI_MCR_DIS_TXF | SPI_MCR_DIS_RXF,
SPI_MCR_DIS_TXF | SPI_MCR_DIS_RXF);
/* Stop Running */
regmap_update_bits(dspi->regmap, SPI_MCR, SPI_MCR_HALT, SPI_MCR_HALT);
dspi_release_dma(dspi);
clk_disable_unprepare(dspi->clk);
spi_unregister_controller(dspi->ctlr);
}
static struct platform_driver fsl_dspi_driver = { static struct platform_driver fsl_dspi_driver = {
.driver.name = DRIVER_NAME, .driver.name = DRIVER_NAME,
.driver.of_match_table = fsl_dspi_dt_ids, .driver.of_match_table = fsl_dspi_dt_ids,
...@@ -1424,6 +1466,7 @@ static struct platform_driver fsl_dspi_driver = { ...@@ -1424,6 +1466,7 @@ static struct platform_driver fsl_dspi_driver = {
.driver.pm = &dspi_pm, .driver.pm = &dspi_pm,
.probe = dspi_probe, .probe = dspi_probe,
.remove = dspi_remove, .remove = dspi_remove,
.shutdown = dspi_shutdown,
}; };
module_platform_driver(fsl_dspi_driver); module_platform_driver(fsl_dspi_driver);
......
...@@ -186,14 +186,13 @@ static bool fsl_lpspi_can_dma(struct spi_controller *controller, ...@@ -186,14 +186,13 @@ static bool fsl_lpspi_can_dma(struct spi_controller *controller,
bytes_per_word = fsl_lpspi_bytes_per_word(transfer->bits_per_word); bytes_per_word = fsl_lpspi_bytes_per_word(transfer->bits_per_word);
switch (bytes_per_word) switch (bytes_per_word) {
{ case 1:
case 1: case 2:
case 2: case 4:
case 4: break;
break; default:
default: return false;
return false;
} }
return true; return true;
...@@ -941,7 +940,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) ...@@ -941,7 +940,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
ret = pm_runtime_get_sync(fsl_lpspi->dev); ret = pm_runtime_get_sync(fsl_lpspi->dev);
if (ret < 0) { if (ret < 0) {
dev_err(fsl_lpspi->dev, "failed to enable clock\n"); dev_err(fsl_lpspi->dev, "failed to enable clock\n");
goto out_controller_put; goto out_pm_get;
} }
temp = readl(fsl_lpspi->base + IMX7ULP_PARAM); temp = readl(fsl_lpspi->base + IMX7ULP_PARAM);
...@@ -950,13 +949,15 @@ static int fsl_lpspi_probe(struct platform_device *pdev) ...@@ -950,13 +949,15 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller); ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller);
if (ret == -EPROBE_DEFER) if (ret == -EPROBE_DEFER)
goto out_controller_put; goto out_pm_get;
if (ret < 0) if (ret < 0)
dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret); dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret);
return 0; return 0;
out_pm_get:
pm_runtime_put_noidle(fsl_lpspi->dev);
out_controller_put: out_controller_put:
spi_controller_put(controller); spi_controller_put(controller);
......
...@@ -876,14 +876,15 @@ static int fsl_qspi_probe(struct platform_device *pdev) ...@@ -876,14 +876,15 @@ static int fsl_qspi_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"QuadSPI-memory"); "QuadSPI-memory");
q->ahb_addr = devm_ioremap_resource(dev, res); q->memmap_phy = res->start;
if (IS_ERR(q->ahb_addr)) { /* Since there are 4 cs, map size required is 4 times ahb_buf_size */
ret = PTR_ERR(q->ahb_addr); q->ahb_addr = devm_ioremap(dev, q->memmap_phy,
(q->devtype_data->ahb_buf_size * 4));
if (!q->ahb_addr) {
ret = -ENOMEM;
goto err_put_ctrl; goto err_put_ctrl;
} }
q->memmap_phy = res->start;
/* find the clocks */ /* find the clocks */
q->clk_en = devm_clk_get(dev, "qspi_en"); q->clk_en = devm_clk_get(dev, "qspi_en");
if (IS_ERR(q->clk_en)) { if (IS_ERR(q->clk_en)) {
......
...@@ -588,7 +588,7 @@ static void fsl_spi_grlib_probe(struct device *dev) ...@@ -588,7 +588,7 @@ static void fsl_spi_grlib_probe(struct device *dev)
pdata->cs_control = fsl_spi_grlib_cs_control; pdata->cs_control = fsl_spi_grlib_cs_control;
} }
static struct spi_master * fsl_spi_probe(struct device *dev, static struct spi_master *fsl_spi_probe(struct device *dev,
struct resource *mem, unsigned int irq) struct resource *mem, unsigned int irq)
{ {
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
......
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
#define HISI_SFC_V3XX_VERSION (0x1f8) #define HISI_SFC_V3XX_VERSION (0x1f8)
#define HISI_SFC_V3XX_INT_STAT (0x120)
#define HISI_SFC_V3XX_INT_STAT_PP_ERR BIT(2)
#define HISI_SFC_V3XX_INT_STAT_ADDR_IACCES BIT(5)
#define HISI_SFC_V3XX_INT_CLR (0x12c)
#define HISI_SFC_V3XX_INT_CLR_CLEAR (0xff)
#define HISI_SFC_V3XX_CMD_CFG (0x300) #define HISI_SFC_V3XX_CMD_CFG (0x300)
#define HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT (1 << 17) #define HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT (1 << 17)
#define HISI_SFC_V3XX_CMD_CFG_DUAL_IO (2 << 17) #define HISI_SFC_V3XX_CMD_CFG_DUAL_IO (2 << 17)
...@@ -163,7 +168,7 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host, ...@@ -163,7 +168,7 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host,
u8 chip_select) u8 chip_select)
{ {
int ret, len = op->data.nbytes; int ret, len = op->data.nbytes;
u32 config = 0; u32 int_stat, config = 0;
if (op->addr.nbytes) if (op->addr.nbytes)
config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK; config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK;
...@@ -228,6 +233,25 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host, ...@@ -228,6 +233,25 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host,
if (ret) if (ret)
return ret; return ret;
/*
* The interrupt status register indicates whether an error occurs
* after per operation. Check it, and clear the interrupts for
* next time judgement.
*/
int_stat = readl(host->regbase + HISI_SFC_V3XX_INT_STAT);
writel(HISI_SFC_V3XX_INT_CLR_CLEAR,
host->regbase + HISI_SFC_V3XX_INT_CLR);
if (int_stat & HISI_SFC_V3XX_INT_STAT_ADDR_IACCES) {
dev_err(host->dev, "fail to access protected address\n");
return -EIO;
}
if (int_stat & HISI_SFC_V3XX_INT_STAT_PP_ERR) {
dev_err(host->dev, "page program operation failed\n");
return -EIO;
}
if (op->data.dir == SPI_MEM_DATA_IN) if (op->data.dir == SPI_MEM_DATA_IN)
hisi_sfc_v3xx_read_databuf(host, op->data.buf.in, len); hisi_sfc_v3xx_read_databuf(host, op->data.buf.in, len);
......
...@@ -71,6 +71,7 @@ struct spi_imx_devtype_data { ...@@ -71,6 +71,7 @@ struct spi_imx_devtype_data {
void (*reset)(struct spi_imx_data *); void (*reset)(struct spi_imx_data *);
void (*setup_wml)(struct spi_imx_data *); void (*setup_wml)(struct spi_imx_data *);
void (*disable)(struct spi_imx_data *); void (*disable)(struct spi_imx_data *);
void (*disable_dma)(struct spi_imx_data *);
bool has_dmamode; bool has_dmamode;
bool has_slavemode; bool has_slavemode;
unsigned int fifo_size; unsigned int fifo_size;
...@@ -485,6 +486,11 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx) ...@@ -485,6 +486,11 @@ static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MX51_ECSPI_CTRL); writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
} }
static void mx51_disable_dma(struct spi_imx_data *spi_imx)
{
writel(0, spi_imx->base + MX51_ECSPI_DMA);
}
static void mx51_ecspi_disable(struct spi_imx_data *spi_imx) static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
{ {
u32 ctrl; u32 ctrl;
...@@ -987,6 +993,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = { ...@@ -987,6 +993,7 @@ static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.rx_available = mx51_ecspi_rx_available, .rx_available = mx51_ecspi_rx_available,
.reset = mx51_ecspi_reset, .reset = mx51_ecspi_reset,
.setup_wml = mx51_setup_wml, .setup_wml = mx51_setup_wml,
.disable_dma = mx51_disable_dma,
.fifo_size = 64, .fifo_size = 64,
.has_dmamode = true, .has_dmamode = true,
.dynamic_burst = true, .dynamic_burst = true,
...@@ -1001,6 +1008,7 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = { ...@@ -1001,6 +1008,7 @@ static struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
.prepare_transfer = mx51_ecspi_prepare_transfer, .prepare_transfer = mx51_ecspi_prepare_transfer,
.trigger = mx51_ecspi_trigger, .trigger = mx51_ecspi_trigger,
.rx_available = mx51_ecspi_rx_available, .rx_available = mx51_ecspi_rx_available,
.disable_dma = mx51_disable_dma,
.reset = mx51_ecspi_reset, .reset = mx51_ecspi_reset,
.fifo_size = 64, .fifo_size = 64,
.has_dmamode = true, .has_dmamode = true,
...@@ -1385,6 +1393,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, ...@@ -1385,6 +1393,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) { if (!desc_tx) {
dmaengine_terminate_all(master->dma_tx); dmaengine_terminate_all(master->dma_tx);
dmaengine_terminate_all(master->dma_rx);
return -EINVAL; return -EINVAL;
} }
...@@ -1498,6 +1507,7 @@ static int spi_imx_transfer(struct spi_device *spi, ...@@ -1498,6 +1507,7 @@ static int spi_imx_transfer(struct spi_device *spi,
struct spi_transfer *transfer) struct spi_transfer *transfer)
{ {
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master); struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
int ret;
/* flush rxfifo before transfer */ /* flush rxfifo before transfer */
while (spi_imx->devtype_data->rx_available(spi_imx)) while (spi_imx->devtype_data->rx_available(spi_imx))
...@@ -1506,10 +1516,23 @@ static int spi_imx_transfer(struct spi_device *spi, ...@@ -1506,10 +1516,23 @@ static int spi_imx_transfer(struct spi_device *spi,
if (spi_imx->slave_mode) if (spi_imx->slave_mode)
return spi_imx_pio_transfer_slave(spi, transfer); return spi_imx_pio_transfer_slave(spi, transfer);
if (spi_imx->usedma) /*
return spi_imx_dma_transfer(spi_imx, transfer); * fallback PIO mode if dma setup error happen, for example sdma
else * firmware may not be updated as ERR009165 required.
return spi_imx_pio_transfer(spi, transfer); */
if (spi_imx->usedma) {
ret = spi_imx_dma_transfer(spi_imx, transfer);
if (ret != -EINVAL)
return ret;
spi_imx->devtype_data->disable_dma(spi_imx);
spi_imx->usedma = false;
spi_imx->dynamic_burst = spi_imx->devtype_data->dynamic_burst;
dev_dbg(&spi->dev, "Fallback to PIO mode\n");
}
return spi_imx_pio_transfer(spi, transfer);
} }
static int spi_imx_setup(struct spi_device *spi) static int spi_imx_setup(struct spi_device *spi)
......
...@@ -108,15 +108,17 @@ static int spi_check_buswidth_req(struct spi_mem *mem, u8 buswidth, bool tx) ...@@ -108,15 +108,17 @@ static int spi_check_buswidth_req(struct spi_mem *mem, u8 buswidth, bool tx)
return 0; return 0;
case 2: case 2:
if ((tx && (mode & (SPI_TX_DUAL | SPI_TX_QUAD))) || if ((tx &&
(!tx && (mode & (SPI_RX_DUAL | SPI_RX_QUAD)))) (mode & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL))) ||
(!tx &&
(mode & (SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL))))
return 0; return 0;
break; break;
case 4: case 4:
if ((tx && (mode & SPI_TX_QUAD)) || if ((tx && (mode & (SPI_TX_QUAD | SPI_TX_OCTAL))) ||
(!tx && (mode & SPI_RX_QUAD))) (!tx && (mode & (SPI_RX_QUAD | SPI_RX_OCTAL))))
return 0; return 0;
break; break;
......
...@@ -391,7 +391,7 @@ static int mtk_nor_pp_unbuffered(struct mtk_nor *sp, ...@@ -391,7 +391,7 @@ static int mtk_nor_pp_unbuffered(struct mtk_nor *sp,
return mtk_nor_cmd_exec(sp, MTK_NOR_CMD_WRITE, 6 * BITS_PER_BYTE); return mtk_nor_cmd_exec(sp, MTK_NOR_CMD_WRITE, 6 * BITS_PER_BYTE);
} }
int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) static int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{ {
struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master); struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master);
int ret; int ret;
......
...@@ -17,10 +17,8 @@ ...@@ -17,10 +17,8 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/gpio.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define DRIVER_NAME "orion_spi" #define DRIVER_NAME "orion_spi"
...@@ -98,7 +96,6 @@ struct orion_spi { ...@@ -98,7 +96,6 @@ struct orion_spi {
struct clk *clk; struct clk *clk;
struct clk *axi_clk; struct clk *axi_clk;
const struct orion_spi_dev *devdata; const struct orion_spi_dev *devdata;
int unused_hw_gpio;
struct orion_child_options child[ORION_NUM_CHIPSELECTS]; struct orion_child_options child[ORION_NUM_CHIPSELECTS];
}; };
...@@ -325,20 +322,27 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -325,20 +322,27 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
static void orion_spi_set_cs(struct spi_device *spi, bool enable) static void orion_spi_set_cs(struct spi_device *spi, bool enable)
{ {
struct orion_spi *orion_spi; struct orion_spi *orion_spi;
int cs;
orion_spi = spi_master_get_devdata(spi->master); orion_spi = spi_master_get_devdata(spi->master);
if (gpio_is_valid(spi->cs_gpio)) /*
cs = orion_spi->unused_hw_gpio; * If this line is using a GPIO to control chip select, this internal
else * .set_cs() function will still be called, so we clear any previous
cs = spi->chip_select; * chip select. The CS we activate will not have any elecrical effect,
* as it is handled by a GPIO, but that doesn't matter. What we need
* is to deassert the old chip select and assert some other chip select.
*/
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK); orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK);
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG,
ORION_SPI_CS(cs)); ORION_SPI_CS(spi->chip_select));
/* Chip select logic is inverted from spi_set_cs */ /*
* Chip select logic is inverted from spi_set_cs(). For lines using a
* GPIO to do chip select SPI_CS_HIGH is enforced and inversion happens
* in the GPIO library, but we don't care about that, because in those
* cases we are dealing with an unused native CS anyways so the polarity
* doesn't matter.
*/
if (!enable) if (!enable)
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
else else
...@@ -503,9 +507,6 @@ static int orion_spi_transfer_one(struct spi_master *master, ...@@ -503,9 +507,6 @@ static int orion_spi_transfer_one(struct spi_master *master,
static int orion_spi_setup(struct spi_device *spi) static int orion_spi_setup(struct spi_device *spi)
{ {
if (gpio_is_valid(spi->cs_gpio)) {
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
}
return orion_spi_setup_transfer(spi, NULL); return orion_spi_setup_transfer(spi, NULL);
} }
...@@ -622,13 +623,13 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -622,13 +623,13 @@ static int orion_spi_probe(struct platform_device *pdev)
master->setup = orion_spi_setup; master->setup = orion_spi_setup;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
master->use_gpio_descriptors = true;
master->flags = SPI_MASTER_GPIO_SS; master->flags = SPI_MASTER_GPIO_SS;
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
spi = spi_master_get_devdata(master); spi = spi_master_get_devdata(master);
spi->master = master; spi->master = master;
spi->unused_hw_gpio = -1;
of_id = of_match_device(orion_spi_of_match_table, &pdev->dev); of_id = of_match_device(orion_spi_of_match_table, &pdev->dev);
devdata = (of_id) ? of_id->data : &orion_spi_dev_data; devdata = (of_id) ? of_id->data : &orion_spi_dev_data;
...@@ -683,7 +684,6 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -683,7 +684,6 @@ static int orion_spi_probe(struct platform_device *pdev)
for_each_available_child_of_node(pdev->dev.of_node, np) { for_each_available_child_of_node(pdev->dev.of_node, np) {
struct orion_direct_acc *dir_acc; struct orion_direct_acc *dir_acc;
u32 cs; u32 cs;
int cs_gpio;
/* Get chip-select number from the "reg" property */ /* Get chip-select number from the "reg" property */
status = of_property_read_u32(np, "reg", &cs); status = of_property_read_u32(np, "reg", &cs);
...@@ -694,44 +694,6 @@ static int orion_spi_probe(struct platform_device *pdev) ...@@ -694,44 +694,6 @@ static int orion_spi_probe(struct platform_device *pdev)
continue; continue;
} }
/*
* Initialize the CS GPIO:
* - properly request the actual GPIO signal
* - de-assert the logical signal so that all GPIO CS lines
* are inactive when probing for slaves
* - find an unused physical CS which will be driven for any
* slave which uses a CS GPIO
*/
cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", cs);
if (cs_gpio > 0) {
char *gpio_name;
int cs_flags;
if (spi->unused_hw_gpio == -1) {
dev_info(&pdev->dev,
"Selected unused HW CS#%d for any GPIO CSes\n",
cs);
spi->unused_hw_gpio = cs;
}
gpio_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
"%s-CS%d", dev_name(&pdev->dev), cs);
if (!gpio_name) {
status = -ENOMEM;
goto out_rel_axi_clk;
}
cs_flags = of_property_read_bool(np, "spi-cs-high") ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
status = devm_gpio_request_one(&pdev->dev, cs_gpio,
cs_flags, gpio_name);
if (status) {
dev_err(&pdev->dev,
"Can't request GPIO for CS %d\n", cs);
goto out_rel_axi_clk;
}
}
/* /*
* Check if an address is configured for this SPI device. If * Check if an address is configured for this SPI device. If
* not, the MBus mapping via the 'ranges' property in the 'soc' * not, the MBus mapping via the 'ranges' property in the 'soc'
......
...@@ -150,6 +150,7 @@ static const struct lpss_config lpss_platforms[] = { ...@@ -150,6 +150,7 @@ static const struct lpss_config lpss_platforms[] = {
.tx_threshold_hi = 48, .tx_threshold_hi = 48,
.cs_sel_shift = 8, .cs_sel_shift = 8,
.cs_sel_mask = 3 << 8, .cs_sel_mask = 3 << 8,
.cs_clk_stays_gated = true,
}, },
{ /* LPSS_CNL_SSP */ { /* LPSS_CNL_SSP */
.offset = 0x200, .offset = 0x200,
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/of.h>
#include <asm/mach-ath79/ar71xx_regs.h> #include <asm/mach-ath79/ar71xx_regs.h>
...@@ -150,6 +151,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev) ...@@ -150,6 +151,7 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
if (IS_ERR(ahb_clk)) if (IS_ERR(ahb_clk))
return PTR_ERR(ahb_clk); return PTR_ERR(ahb_clk);
master->dev.of_node = pdev->dev.of_node;
master->bus_num = 0; master->bus_num = 0;
master->num_chipselect = 3; master->num_chipselect = 3;
master->mode_bits = SPI_TX_DUAL; master->mode_bits = SPI_TX_DUAL;
...@@ -158,6 +160,11 @@ static int rb4xx_spi_probe(struct platform_device *pdev) ...@@ -158,6 +160,11 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
master->transfer_one = rb4xx_transfer_one; master->transfer_one = rb4xx_transfer_one;
master->set_cs = rb4xx_set_cs; master->set_cs = rb4xx_set_cs;
rbspi = spi_master_get_devdata(master);
rbspi->base = spi_base;
rbspi->clk = ahb_clk;
platform_set_drvdata(pdev, rbspi);
err = devm_spi_register_master(&pdev->dev, master); err = devm_spi_register_master(&pdev->dev, master);
if (err) { if (err) {
dev_err(&pdev->dev, "failed to register SPI master\n"); dev_err(&pdev->dev, "failed to register SPI master\n");
...@@ -168,11 +175,6 @@ static int rb4xx_spi_probe(struct platform_device *pdev) ...@@ -168,11 +175,6 @@ static int rb4xx_spi_probe(struct platform_device *pdev)
if (err) if (err)
return err; return err;
rbspi = spi_master_get_devdata(master);
rbspi->base = spi_base;
rbspi->clk = ahb_clk;
platform_set_drvdata(pdev, rbspi);
/* Enable SPI */ /* Enable SPI */
rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO); rb4xx_write(rbspi, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
...@@ -188,11 +190,18 @@ static int rb4xx_spi_remove(struct platform_device *pdev) ...@@ -188,11 +190,18 @@ static int rb4xx_spi_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct of_device_id rb4xx_spi_dt_match[] = {
{ .compatible = "mikrotik,rb4xx-spi" },
{ },
};
MODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match);
static struct platform_driver rb4xx_spi_drv = { static struct platform_driver rb4xx_spi_drv = {
.probe = rb4xx_spi_probe, .probe = rb4xx_spi_probe,
.remove = rb4xx_spi_remove, .remove = rb4xx_spi_remove,
.driver = { .driver = {
.name = "rb4xx-spi", .name = "rb4xx-spi",
.of_match_table = of_match_ptr(rb4xx_spi_dt_match),
}, },
}; };
......
This diff is collapsed.
...@@ -1398,7 +1398,7 @@ static int sh_msiof_spi_resume(struct device *dev) ...@@ -1398,7 +1398,7 @@ static int sh_msiof_spi_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend, static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend,
sh_msiof_spi_resume); sh_msiof_spi_resume);
#define DEV_PM_OPS &sh_msiof_spi_pm_ops #define DEV_PM_OPS (&sh_msiof_spi_pm_ops)
#else #else
#define DEV_PM_OPS NULL #define DEV_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM_SLEEP */
......
...@@ -319,7 +319,7 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr, ...@@ -319,7 +319,7 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr,
static void sprd_adi_set_wdt_rst_mode(struct sprd_adi *sadi) static void sprd_adi_set_wdt_rst_mode(struct sprd_adi *sadi)
{ {
#ifdef CONFIG_SPRD_WATCHDOG #if IS_ENABLED(CONFIG_SPRD_WATCHDOG)
u32 val; u32 val;
/* Set default watchdog reboot mode */ /* Set default watchdog reboot mode */
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/sizes.h> #include <linux/sizes.h>
...@@ -87,6 +88,7 @@ ...@@ -87,6 +88,7 @@
#define STM32_BUSY_TIMEOUT_US 100000 #define STM32_BUSY_TIMEOUT_US 100000
#define STM32_ABT_TIMEOUT_US 100000 #define STM32_ABT_TIMEOUT_US 100000
#define STM32_COMP_TIMEOUT_MS 1000 #define STM32_COMP_TIMEOUT_MS 1000
#define STM32_AUTOSUSPEND_DELAY -1
struct stm32_qspi_flash { struct stm32_qspi_flash {
struct stm32_qspi *qspi; struct stm32_qspi *qspi;
...@@ -431,10 +433,17 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -431,10 +433,17 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
int ret; int ret;
ret = pm_runtime_get_sync(qspi->dev);
if (ret < 0)
return ret;
mutex_lock(&qspi->lock); mutex_lock(&qspi->lock);
ret = stm32_qspi_send(mem, op); ret = stm32_qspi_send(mem, op);
mutex_unlock(&qspi->lock); mutex_unlock(&qspi->lock);
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return ret; return ret;
} }
...@@ -444,6 +453,7 @@ static int stm32_qspi_setup(struct spi_device *spi) ...@@ -444,6 +453,7 @@ static int stm32_qspi_setup(struct spi_device *spi)
struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl); struct stm32_qspi *qspi = spi_controller_get_devdata(ctrl);
struct stm32_qspi_flash *flash; struct stm32_qspi_flash *flash;
u32 presc; u32 presc;
int ret;
if (ctrl->busy) if (ctrl->busy)
return -EBUSY; return -EBUSY;
...@@ -451,6 +461,10 @@ static int stm32_qspi_setup(struct spi_device *spi) ...@@ -451,6 +461,10 @@ static int stm32_qspi_setup(struct spi_device *spi)
if (!spi->max_speed_hz) if (!spi->max_speed_hz)
return -EINVAL; return -EINVAL;
ret = pm_runtime_get_sync(qspi->dev);
if (ret < 0)
return ret;
presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1;
flash = &qspi->flash[spi->chip_select]; flash = &qspi->flash[spi->chip_select];
...@@ -467,6 +481,9 @@ static int stm32_qspi_setup(struct spi_device *spi) ...@@ -467,6 +481,9 @@ static int stm32_qspi_setup(struct spi_device *spi)
writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR);
mutex_unlock(&qspi->lock); mutex_unlock(&qspi->lock);
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return 0; return 0;
} }
...@@ -538,10 +555,15 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { ...@@ -538,10 +555,15 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = {
static void stm32_qspi_release(struct stm32_qspi *qspi) static void stm32_qspi_release(struct stm32_qspi *qspi)
{ {
pm_runtime_get_sync(qspi->dev);
/* disable qspi */ /* disable qspi */
writel_relaxed(0, qspi->io_base + QSPI_CR); writel_relaxed(0, qspi->io_base + QSPI_CR);
stm32_qspi_dma_free(qspi); stm32_qspi_dma_free(qspi);
mutex_destroy(&qspi->lock); mutex_destroy(&qspi->lock);
pm_runtime_put_noidle(qspi->dev);
pm_runtime_disable(qspi->dev);
pm_runtime_set_suspended(qspi->dev);
pm_runtime_dont_use_autosuspend(qspi->dev);
clk_disable_unprepare(qspi->clk); clk_disable_unprepare(qspi->clk);
} }
...@@ -643,9 +665,20 @@ static int stm32_qspi_probe(struct platform_device *pdev) ...@@ -643,9 +665,20 @@ static int stm32_qspi_probe(struct platform_device *pdev)
ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP; ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP;
ctrl->dev.of_node = dev->of_node; ctrl->dev.of_node = dev->of_node;
pm_runtime_set_autosuspend_delay(dev, STM32_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_get_noresume(dev);
ret = devm_spi_register_master(dev, ctrl); ret = devm_spi_register_master(dev, ctrl);
if (!ret) if (ret)
return 0; goto err_qspi_release;
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
err_qspi_release: err_qspi_release:
stm32_qspi_release(qspi); stm32_qspi_release(qspi);
...@@ -660,14 +693,28 @@ static int stm32_qspi_remove(struct platform_device *pdev) ...@@ -660,14 +693,28 @@ static int stm32_qspi_remove(struct platform_device *pdev)
struct stm32_qspi *qspi = platform_get_drvdata(pdev); struct stm32_qspi *qspi = platform_get_drvdata(pdev);
stm32_qspi_release(qspi); stm32_qspi_release(qspi);
return 0; return 0;
} }
static int __maybe_unused stm32_qspi_suspend(struct device *dev) static int __maybe_unused stm32_qspi_runtime_suspend(struct device *dev)
{ {
struct stm32_qspi *qspi = dev_get_drvdata(dev); struct stm32_qspi *qspi = dev_get_drvdata(dev);
clk_disable_unprepare(qspi->clk); clk_disable_unprepare(qspi->clk);
return 0;
}
static int __maybe_unused stm32_qspi_runtime_resume(struct device *dev)
{
struct stm32_qspi *qspi = dev_get_drvdata(dev);
return clk_prepare_enable(qspi->clk);
}
static int __maybe_unused stm32_qspi_suspend(struct device *dev)
{
pinctrl_pm_select_sleep_state(dev); pinctrl_pm_select_sleep_state(dev);
return 0; return 0;
...@@ -683,10 +730,17 @@ static int __maybe_unused stm32_qspi_resume(struct device *dev) ...@@ -683,10 +730,17 @@ static int __maybe_unused stm32_qspi_resume(struct device *dev)
writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR);
writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR);
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
return 0; return 0;
} }
static SIMPLE_DEV_PM_OPS(stm32_qspi_pm_ops, stm32_qspi_suspend, stm32_qspi_resume); static const struct dev_pm_ops stm32_qspi_pm_ops = {
SET_RUNTIME_PM_OPS(stm32_qspi_runtime_suspend,
stm32_qspi_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(stm32_qspi_suspend, stm32_qspi_resume)
};
static const struct of_device_id stm32_qspi_match[] = { static const struct of_device_id stm32_qspi_match[] = {
{.compatible = "st,stm32f469-qspi"}, {.compatible = "st,stm32f469-qspi"},
......
...@@ -811,7 +811,9 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id) ...@@ -811,7 +811,9 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
mask |= STM32F4_SPI_SR_TXE; mask |= STM32F4_SPI_SR_TXE;
} }
if (!spi->cur_usedma && spi->cur_comm == SPI_FULL_DUPLEX) { if (!spi->cur_usedma && (spi->cur_comm == SPI_FULL_DUPLEX ||
spi->cur_comm == SPI_SIMPLEX_RX ||
spi->cur_comm == SPI_3WIRE_RX)) {
/* TXE flag is set and is handled when RXNE flag occurs */ /* TXE flag is set and is handled when RXNE flag occurs */
sr &= ~STM32F4_SPI_SR_TXE; sr &= ~STM32F4_SPI_SR_TXE;
mask |= STM32F4_SPI_SR_RXNE | STM32F4_SPI_SR_OVR; mask |= STM32F4_SPI_SR_RXNE | STM32F4_SPI_SR_OVR;
...@@ -850,7 +852,7 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id) ...@@ -850,7 +852,7 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)
stm32f4_spi_read_rx(spi); stm32f4_spi_read_rx(spi);
if (spi->rx_len == 0) if (spi->rx_len == 0)
end = true; end = true;
else /* Load data for discontinuous mode */ else if (spi->tx_buf)/* Load data for discontinuous mode */
stm32f4_spi_write_tx(spi); stm32f4_spi_write_tx(spi);
} }
...@@ -1151,7 +1153,9 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi) ...@@ -1151,7 +1153,9 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi)
/* Enable the interrupts relative to the current communication mode */ /* Enable the interrupts relative to the current communication mode */
if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) { if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) {
cr2 |= STM32F4_SPI_CR2_TXEIE; cr2 |= STM32F4_SPI_CR2_TXEIE;
} else if (spi->cur_comm == SPI_FULL_DUPLEX) { } else if (spi->cur_comm == SPI_FULL_DUPLEX ||
spi->cur_comm == SPI_SIMPLEX_RX ||
spi->cur_comm == SPI_3WIRE_RX) {
/* In transmit-only mode, the OVR flag is set in the SR register /* In transmit-only mode, the OVR flag is set in the SR register
* since the received data are never read. Therefore set OVR * since the received data are never read. Therefore set OVR
* interrupt only when rx buffer is available. * interrupt only when rx buffer is available.
...@@ -1462,10 +1466,16 @@ static int stm32f4_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) ...@@ -1462,10 +1466,16 @@ static int stm32f4_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)
stm32_spi_set_bits(spi, STM32F4_SPI_CR1, stm32_spi_set_bits(spi, STM32F4_SPI_CR1,
STM32F4_SPI_CR1_BIDIMODE | STM32F4_SPI_CR1_BIDIMODE |
STM32F4_SPI_CR1_BIDIOE); STM32F4_SPI_CR1_BIDIOE);
} else if (comm_type == SPI_FULL_DUPLEX) { } else if (comm_type == SPI_FULL_DUPLEX ||
comm_type == SPI_SIMPLEX_RX) {
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1, stm32_spi_clr_bits(spi, STM32F4_SPI_CR1,
STM32F4_SPI_CR1_BIDIMODE | STM32F4_SPI_CR1_BIDIMODE |
STM32F4_SPI_CR1_BIDIOE); STM32F4_SPI_CR1_BIDIOE);
} else if (comm_type == SPI_3WIRE_RX) {
stm32_spi_set_bits(spi, STM32F4_SPI_CR1,
STM32F4_SPI_CR1_BIDIMODE);
stm32_spi_clr_bits(spi, STM32F4_SPI_CR1,
STM32F4_SPI_CR1_BIDIOE);
} else { } else {
return -EINVAL; return -EINVAL;
} }
...@@ -1906,6 +1916,7 @@ static int stm32_spi_probe(struct platform_device *pdev) ...@@ -1906,6 +1916,7 @@ static int stm32_spi_probe(struct platform_device *pdev)
master->prepare_message = stm32_spi_prepare_msg; master->prepare_message = stm32_spi_prepare_msg;
master->transfer_one = stm32_spi_transfer_one; master->transfer_one = stm32_spi_transfer_one;
master->unprepare_message = stm32_spi_unprepare_msg; master->unprepare_message = stm32_spi_unprepare_msg;
master->flags = SPI_MASTER_MUST_TX;
spi->dma_tx = dma_request_chan(spi->dev, "tx"); spi->dma_tx = dma_request_chan(spi->dev, "tx");
if (IS_ERR(spi->dma_tx)) { if (IS_ERR(spi->dma_tx)) {
......
...@@ -470,6 +470,7 @@ static int sun6i_spi_probe(struct platform_device *pdev) ...@@ -470,6 +470,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
master->max_speed_hz = 100 * 1000 * 1000; master->max_speed_hz = 100 * 1000 * 1000;
master->min_speed_hz = 3 * 1000; master->min_speed_hz = 3 * 1000;
master->use_gpio_descriptors = true;
master->set_cs = sun6i_spi_set_cs; master->set_cs = sun6i_spi_set_cs;
master->transfer_one = sun6i_spi_transfer_one; master->transfer_one = sun6i_spi_transfer_one;
master->num_chipselect = 4; master->num_chipselect = 4;
......
...@@ -1398,6 +1398,7 @@ static int tegra_spi_probe(struct platform_device *pdev) ...@@ -1398,6 +1398,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
ret = pm_runtime_get_sync(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret); dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
pm_runtime_put_noidle(&pdev->dev);
goto exit_pm_disable; goto exit_pm_disable;
} }
......
...@@ -491,6 +491,7 @@ static int tegra_sflash_probe(struct platform_device *pdev) ...@@ -491,6 +491,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
ret = pm_runtime_get_sync(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret); dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
pm_runtime_put_noidle(&pdev->dev);
goto exit_pm_disable; goto exit_pm_disable;
} }
......
...@@ -1118,6 +1118,7 @@ static int tegra_slink_probe(struct platform_device *pdev) ...@@ -1118,6 +1118,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
ret = pm_runtime_get_sync(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret); dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret);
pm_runtime_put_noidle(&pdev->dev);
goto exit_pm_disable; goto exit_pm_disable;
} }
tspi->def_command_reg = SLINK_M_S; tspi->def_command_reg = SLINK_M_S;
......
...@@ -659,8 +659,7 @@ static int uniphier_spi_probe(struct platform_device *pdev) ...@@ -659,8 +659,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
priv->master = master; priv->master = master;
priv->is_save_param = false; priv->is_save_param = false;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
priv->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->base)) { if (IS_ERR(priv->base)) {
ret = PTR_ERR(priv->base); ret = PTR_ERR(priv->base);
goto out_master_put; goto out_master_put;
...@@ -716,8 +715,10 @@ static int uniphier_spi_probe(struct platform_device *pdev) ...@@ -716,8 +715,10 @@ static int uniphier_spi_probe(struct platform_device *pdev)
master->dma_tx = dma_request_chan(&pdev->dev, "tx"); master->dma_tx = dma_request_chan(&pdev->dev, "tx");
if (IS_ERR_OR_NULL(master->dma_tx)) { if (IS_ERR_OR_NULL(master->dma_tx)) {
if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto out_disable_clk; goto out_disable_clk;
}
master->dma_tx = NULL; master->dma_tx = NULL;
dma_tx_burst = INT_MAX; dma_tx_burst = INT_MAX;
} else { } else {
...@@ -732,8 +733,10 @@ static int uniphier_spi_probe(struct platform_device *pdev) ...@@ -732,8 +733,10 @@ static int uniphier_spi_probe(struct platform_device *pdev)
master->dma_rx = dma_request_chan(&pdev->dev, "rx"); master->dma_rx = dma_request_chan(&pdev->dev, "rx");
if (IS_ERR_OR_NULL(master->dma_rx)) { if (IS_ERR_OR_NULL(master->dma_rx)) {
if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto out_disable_clk; goto out_disable_clk;
}
master->dma_rx = NULL; master->dma_rx = NULL;
dma_rx_burst = INT_MAX; dma_rx_burst = INT_MAX;
} else { } else {
......
...@@ -1023,7 +1023,8 @@ static int spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg) ...@@ -1023,7 +1023,8 @@ static int spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
void *tmp; void *tmp;
unsigned int max_tx, max_rx; unsigned int max_tx, max_rx;
if (ctlr->flags & (SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX)) { if ((ctlr->flags & (SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX))
&& !(msg->spi->mode & SPI_3WIRE)) {
max_tx = 0; max_tx = 0;
max_rx = 0; max_rx = 0;
...@@ -1075,7 +1076,7 @@ static int spi_transfer_wait(struct spi_controller *ctlr, ...@@ -1075,7 +1076,7 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
{ {
struct spi_statistics *statm = &ctlr->statistics; struct spi_statistics *statm = &ctlr->statistics;
struct spi_statistics *stats = &msg->spi->statistics; struct spi_statistics *stats = &msg->spi->statistics;
unsigned long long ms = 1; unsigned long long ms;
if (spi_controller_is_slave(ctlr)) { if (spi_controller_is_slave(ctlr)) {
if (wait_for_completion_interruptible(&ctlr->xfer_completion)) { if (wait_for_completion_interruptible(&ctlr->xfer_completion)) {
...@@ -1160,6 +1161,8 @@ int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer) ...@@ -1160,6 +1161,8 @@ int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer)
{ {
int delay; int delay;
might_sleep();
if (!_delay) if (!_delay)
return -EINVAL; return -EINVAL;
...@@ -3855,8 +3858,7 @@ static u8 *buf; ...@@ -3855,8 +3858,7 @@ static u8 *buf;
* is zero for success, else a negative errno status code. * is zero for success, else a negative errno status code.
* This call may only be used from a context that may sleep. * This call may only be used from a context that may sleep.
* *
* Parameters to this routine are always copied using a small buffer; * Parameters to this routine are always copied using a small buffer.
* portable code should never use this for more than 32 bytes.
* Performance-sensitive or bulk transfer code should instead use * Performance-sensitive or bulk transfer code should instead use
* spi_{async,sync}() calls with dma-safe buffers. * spi_{async,sync}() calls with dma-safe buffers.
* *
......
...@@ -62,7 +62,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS); ...@@ -62,7 +62,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \ #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
| SPI_NO_CS | SPI_READY | SPI_TX_DUAL \ | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
| SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD) | SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
| SPI_RX_QUAD | SPI_RX_OCTAL)
struct spidev_data { struct spidev_data {
dev_t devt; dev_t devt;
......
...@@ -52,7 +52,9 @@ $(OUTPUT)spidev_fdx: $(SPIDEV_FDX_IN) ...@@ -52,7 +52,9 @@ $(OUTPUT)spidev_fdx: $(SPIDEV_FDX_IN)
clean: clean:
rm -f $(ALL_PROGRAMS) rm -f $(ALL_PROGRAMS)
rm -rf $(OUTPUT)include/ rm -rf $(OUTPUT)include/
find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete
find $(if $(OUTPUT),$(OUTPUT),.) -name '\.*.o.d' -delete
find $(if $(OUTPUT),$(OUTPUT),.) -name '\.*.o.cmd' -delete
install: $(ALL_PROGRAMS) install: $(ALL_PROGRAMS)
install -d -m 755 $(DESTDIR)$(bindir); \ install -d -m 755 $(DESTDIR)$(bindir); \
......
...@@ -128,18 +128,22 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len) ...@@ -128,18 +128,22 @@ static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
.bits_per_word = bits, .bits_per_word = bits,
}; };
if (mode & SPI_TX_QUAD) if (mode & SPI_TX_OCTAL)
tr.tx_nbits = 8;
else if (mode & SPI_TX_QUAD)
tr.tx_nbits = 4; tr.tx_nbits = 4;
else if (mode & SPI_TX_DUAL) else if (mode & SPI_TX_DUAL)
tr.tx_nbits = 2; tr.tx_nbits = 2;
if (mode & SPI_RX_QUAD) if (mode & SPI_RX_OCTAL)
tr.rx_nbits = 8;
else if (mode & SPI_RX_QUAD)
tr.rx_nbits = 4; tr.rx_nbits = 4;
else if (mode & SPI_RX_DUAL) else if (mode & SPI_RX_DUAL)
tr.rx_nbits = 2; tr.rx_nbits = 2;
if (!(mode & SPI_LOOP)) { if (!(mode & SPI_LOOP)) {
if (mode & (SPI_TX_QUAD | SPI_TX_DUAL)) if (mode & (SPI_TX_OCTAL | SPI_TX_QUAD | SPI_TX_DUAL))
tr.rx_buf = 0; tr.rx_buf = 0;
else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL)) else if (mode & (SPI_RX_OCTAL | SPI_RX_QUAD | SPI_RX_DUAL))
tr.tx_buf = 0; tr.tx_buf = 0;
} }
...@@ -187,6 +191,7 @@ static void print_usage(const char *prog) ...@@ -187,6 +191,7 @@ static void print_usage(const char *prog)
" -R --ready slave pulls low to pause\n" " -R --ready slave pulls low to pause\n"
" -2 --dual dual transfer\n" " -2 --dual dual transfer\n"
" -4 --quad quad transfer\n" " -4 --quad quad transfer\n"
" -8 --octal octal transfer\n"
" -S --size transfer size\n" " -S --size transfer size\n"
" -I --iter iterations\n"); " -I --iter iterations\n");
exit(1); exit(1);
...@@ -213,13 +218,14 @@ static void parse_opts(int argc, char *argv[]) ...@@ -213,13 +218,14 @@ static void parse_opts(int argc, char *argv[])
{ "dual", 0, 0, '2' }, { "dual", 0, 0, '2' },
{ "verbose", 0, 0, 'v' }, { "verbose", 0, 0, 'v' },
{ "quad", 0, 0, '4' }, { "quad", 0, 0, '4' },
{ "octal", 0, 0, '8' },
{ "size", 1, 0, 'S' }, { "size", 1, 0, 'S' },
{ "iter", 1, 0, 'I' }, { "iter", 1, 0, 'I' },
{ NULL, 0, 0, 0 }, { NULL, 0, 0, 0 },
}; };
int c; int c;
c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:vS:I:", c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR248p:vS:I:",
lopts, NULL); lopts, NULL);
if (c == -1) if (c == -1)
...@@ -280,6 +286,9 @@ static void parse_opts(int argc, char *argv[]) ...@@ -280,6 +286,9 @@ static void parse_opts(int argc, char *argv[])
case '4': case '4':
mode |= SPI_TX_QUAD; mode |= SPI_TX_QUAD;
break; break;
case '8':
mode |= SPI_TX_OCTAL;
break;
case 'S': case 'S':
transfer_size = atoi(optarg); transfer_size = atoi(optarg);
break; break;
...@@ -295,6 +304,8 @@ static void parse_opts(int argc, char *argv[]) ...@@ -295,6 +304,8 @@ static void parse_opts(int argc, char *argv[])
mode |= SPI_RX_DUAL; mode |= SPI_RX_DUAL;
if (mode & SPI_TX_QUAD) if (mode & SPI_TX_QUAD)
mode |= SPI_RX_QUAD; mode |= SPI_RX_QUAD;
if (mode & SPI_TX_OCTAL)
mode |= SPI_RX_OCTAL;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment