Commit 0805c6fb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'spi-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi updates from Mark Brown:
 "The big update this time around is some excellent work from David
  Jander who went through the fast path and really eliminated overheads,
  meaning that we are seeing a huge reduction in the time spent between
  transfers for single threaded clients.

  Benchmarking has been coming out at about a halving of overhead which
  is clearly visible in system level usage that stresses SPI like some
  CAN and IIO applications, especially with small transfers. Thanks to
  David for taking the time to drill down into this and push the work
  upstream.

  Otherwise there's been a bunch of new device support and the usual
  updates.

   - Optimisation of the fast path, particularly around the number and
     types of locking operations, from David Jander.

   - Support for Arbel NPCM845, HP GXP, Intel Meteor Lake and Thunder
     Bay, MediaTek MT8188 and MT8365, Microchip FPGAs, nVidia Tegra 241
     and Samsung Exynos Auto v9 and 4210"

* tag 'spi-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (97 commits)
  MAINTAINERS: add spi support to GXP
  spi: dt-bindings: add documentation for hpe,gxp-spifi
  spi: spi-gxp: Add support for HPE GXP SoCs
  spi: a3700: support BE for AC5 SPI driver
  spi/panel: dt-bindings: drop CPHA and CPOL from common properties
  spi: bcm2835: enable shared interrupt support
  spi: dt-bindings: spi-controller: correct example indentation
  spi: dt-bindings: qcom,spi-geni-qcom: allow three interconnects
  spi: npcm-fiu: Add NPCM8XX support
  dt-binding: spi: Add npcm845 compatible to npcm-fiu document
  spi: npcm-fiu: Modify direct read dummy configuration
  spi: atmel: remove #ifdef CONFIG_{PM, SLEEP}
  spi: dt-bindings: Add compatible for MediaTek MT8188
  spi: dt-bindings: mediatek,spi-mtk-nor: Update bindings for nor flash
  spi: dt-bindings: atmel,at91rm9200-spi: convert to json-schema
  spi: tegra20-slink: fix UAF in tegra_slink_remove()
  spi: Fix simplification of devm_spi_register_controller
  spi: microchip-core: switch to use dev_err_probe()
  spi: microchip-core: switch to use devm_spi_alloc_master()
  spi: microchip-core: fix UAF in mchp_corespi_remove()
  ...
parents 416e05e5 69243df9
...@@ -21,6 +21,9 @@ properties: ...@@ -21,6 +21,9 @@ properties:
enable-gpios: true enable-gpios: true
port: true port: true
spi-cpha: true
spi-cpol: true
required: required:
- compatible - compatible
- enable-gpios - enable-gpios
......
...@@ -42,6 +42,9 @@ properties: ...@@ -42,6 +42,9 @@ properties:
panel-height-mm: panel-height-mm:
description: physical panel height [mm] description: physical panel height [mm]
spi-cpha: true
spi-cpol: true
required: required:
- compatible - compatible
- reg - reg
......
...@@ -23,6 +23,9 @@ properties: ...@@ -23,6 +23,9 @@ properties:
backlight: true backlight: true
port: true port: true
spi-cpha: true
spi-cpol: true
required: required:
- compatible - compatible
- reg - reg
......
...@@ -28,6 +28,9 @@ properties: ...@@ -28,6 +28,9 @@ properties:
backlight: true backlight: true
port: true port: true
spi-cpha: true
spi-cpol: true
required: required:
- compatible - compatible
- port - port
......
...@@ -13,6 +13,7 @@ properties: ...@@ -13,6 +13,7 @@ properties:
compatible: compatible:
items: items:
- enum: - enum:
- renesas,r9a07g043-ssi # RZ/G2UL
- renesas,r9a07g044-ssi # RZ/G2{L,LC} - renesas,r9a07g044-ssi # RZ/G2{L,LC}
- renesas,r9a07g054-ssi # RZ/V2L - renesas,r9a07g054-ssi # RZ/V2L
- const: renesas,rz-ssi - const: renesas,rz-ssi
...@@ -50,7 +51,7 @@ properties: ...@@ -50,7 +51,7 @@ properties:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
description: description:
The first cell represents a phandle to dmac The first cell represents a phandle to dmac.
The second cell specifies the encoded MID/RID values of the SSI port The second cell specifies the encoded MID/RID values of the SSI port
connected to the DMA client and the slave channel configuration connected to the DMA client and the slave channel configuration
parameters. parameters.
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2022 Microchip Technology, Inc. and its subsidiaries
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/atmel,at91rm9200-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atmel SPI device
maintainers:
- Tudor Ambarus <tudor.ambarus@microchip.com>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
oneOf:
- const: atmel,at91rm9200-spi
- items:
- const: microchip,sam9x60-spi
- const: atmel,at91rm9200-spi
reg:
maxItems: 1
interrupts:
maxItems: 1
clock-names:
contains:
const: spi_clk
clocks:
maxItems: 1
atmel,fifo-size:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Maximum number of data the RX and TX FIFOs can store for FIFO
capable SPI controllers.
enum: [ 16, 32 ]
required:
- compatible
- reg
- interrupts
- clock-names
- clocks
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi1: spi@fffcc000 {
compatible = "atmel,at91rm9200-spi";
reg = <0xfffcc000 0x4000>;
interrupts = <13 IRQ_TYPE_LEVEL_HIGH 5>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&spi1_clk>;
clock-names = "spi_clk";
cs-gpios = <&pioB 3 GPIO_ACTIVE_HIGH>;
atmel,fifo-size = <32>;
mmc@0 {
compatible = "mmc-spi-slot";
reg = <0>;
gpios = <&pioC 4 GPIO_ACTIVE_HIGH>; /* CD */
spi-max-frequency = <25000000>;
};
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/hpe,gxp-spifi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: HPE GXP spi controller flash interface
maintainers:
- Nick Hawkins <nick.hawkins@hpe.com>
- Jean-Marie Verdun <verdun@hpe.com>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
const: hpe,gxp-spifi
reg:
items:
- description: cfg registers
- description: data registers
- description: mapped memory
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
unevaluatedProperties: false
examples:
- |
spi@200 {
compatible = "hpe,gxp-spifi";
reg = <0x200 0x80>, <0xc000 0x100>, <0x38000000 0x800000>;
interrupts = <20>;
interrupt-parent = <&vic0>;
#address-cells = <1>;
#size-cells = <0>;
flash@0 {
reg = <0>;
compatible = "jedec,spi-nor";
};
flash@1 {
reg = <1>;
compatible = "jedec,spi-nor";
};
};
...@@ -18,6 +18,7 @@ properties: ...@@ -18,6 +18,7 @@ properties:
- items: - items:
- enum: - enum:
- mediatek,mt7629-spi - mediatek,mt7629-spi
- mediatek,mt8365-spi
- const: mediatek,mt7622-spi - const: mediatek,mt7622-spi
- items: - items:
- enum: - enum:
...@@ -33,6 +34,7 @@ properties: ...@@ -33,6 +34,7 @@ properties:
- items: - items:
- enum: - enum:
- mediatek,mt7986-spi-ipm - mediatek,mt7986-spi-ipm
- mediatek,mt8188-spi-ipm
- const: mediatek,spi-ipm - const: mediatek,spi-ipm
- items: - items:
- enum: - enum:
......
...@@ -23,6 +23,10 @@ allOf: ...@@ -23,6 +23,10 @@ allOf:
properties: properties:
compatible: compatible:
oneOf: oneOf:
- enum:
- mediatek,mt8173-nor
- mediatek,mt8186-nor
- mediatek,mt8192-nor
- items: - items:
- enum: - enum:
- mediatek,mt2701-nor - mediatek,mt2701-nor
...@@ -30,13 +34,13 @@ properties: ...@@ -30,13 +34,13 @@ properties:
- mediatek,mt7622-nor - mediatek,mt7622-nor
- mediatek,mt7623-nor - mediatek,mt7623-nor
- mediatek,mt7629-nor - mediatek,mt7629-nor
- mediatek,mt8186-nor
- mediatek,mt8192-nor
- mediatek,mt8195-nor - mediatek,mt8195-nor
- enum:
- mediatek,mt8173-nor
- items:
- const: mediatek,mt8173-nor - const: mediatek,mt8173-nor
- items:
- enum:
- mediatek,mt8188-nor
- const: mediatek,mt8186-nor
reg: reg:
maxItems: 1 maxItems: 1
...@@ -64,7 +68,6 @@ properties: ...@@ -64,7 +68,6 @@ properties:
required: required:
- compatible - compatible
- reg - reg
- interrupts
- clocks - clocks
- clock-names - clock-names
......
...@@ -6,8 +6,13 @@ The NPCM7XX supports three FIU modules, ...@@ -6,8 +6,13 @@ The NPCM7XX supports three FIU modules,
FIU0 and FIUx supports two chip selects, FIU0 and FIUx supports two chip selects,
FIU3 support four chip select. FIU3 support four chip select.
The NPCM8XX supports four FIU modules,
FIU0 and FIUx supports two chip selects,
FIU1 and FIU3 supports four chip selects.
Required properties: Required properties:
- compatible : "nuvoton,npcm750-fiu" for the NPCM7XX BMC - compatible : "nuvoton,npcm750-fiu" for Poleg NPCM7XX BMC
"nuvoton,npcm845-fiu" for Arbel NPCM8XX BMC
- #address-cells : should be 1. - #address-cells : should be 1.
- #size-cells : should be 0. - #size-cells : should be 0.
- reg : the first contains the register location and length, - reg : the first contains the register location and length,
...@@ -30,6 +35,12 @@ Aliases: ...@@ -30,6 +35,12 @@ Aliases:
fiu1 represent fiu 3 controller fiu1 represent fiu 3 controller
fiu2 represent fiu x controller fiu2 represent fiu x controller
In the NPCM8XX BMC:
fiu0 represent fiu 0 controller
fiu1 represent fiu 1 controller
fiu2 represent fiu 3 controller
fiu3 represent fiu x controller
Example: Example:
fiu3: spi@c00000000 { fiu3: spi@c00000000 {
compatible = "nuvoton,npcm750-fiu"; compatible = "nuvoton,npcm750-fiu";
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/nvidia,tegra210-quad-peripheral-props.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Peripheral properties for Tegra Quad SPI Controller
maintainers:
- Thierry Reding <thierry.reding@gmail.com>
- Jonathan Hunter <jonathanh@nvidia.com>
properties:
nvidia,tx-clk-tap-delay:
description:
Delays the clock going out to device with this tap value.
Tap value varies based on platform design trace lengths from Tegra
QSPI to corresponding slave device.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 31
nvidia,rx-clk-tap-delay:
description:
Delays the clock coming in from the device with this tap value.
Tap value varies based on platform design trace lengths from Tegra
QSPI to corresponding slave device.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
unevaluatedProperties: true
...@@ -20,6 +20,7 @@ properties: ...@@ -20,6 +20,7 @@ properties:
- nvidia,tegra186-qspi - nvidia,tegra186-qspi
- nvidia,tegra194-qspi - nvidia,tegra194-qspi
- nvidia,tegra234-qspi - nvidia,tegra234-qspi
- nvidia,tegra241-qspi
reg: reg:
maxItems: 1 maxItems: 1
...@@ -57,27 +58,6 @@ patternProperties: ...@@ -57,27 +58,6 @@ patternProperties:
spi-tx-bus-width: spi-tx-bus-width:
enum: [1, 2, 4] enum: [1, 2, 4]
nvidia,tx-clk-tap-delay:
description:
Delays the clock going out to device with this tap value.
Tap value varies based on platform design trace lengths from Tegra
QSPI to corresponding slave device.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 31
nvidia,rx-clk-tap-delay:
description:
Delays the clock coming in from the device with this tap value.
Tap value varies based on platform design trace lengths from Tegra
QSPI to corresponding slave device.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 255
required:
- reg
required: required:
- compatible - compatible
- reg - reg
......
...@@ -45,12 +45,15 @@ properties: ...@@ -45,12 +45,15 @@ properties:
- const: rx - const: rx
interconnects: interconnects:
maxItems: 2 minItems: 2
maxItems: 3
interconnect-names: interconnect-names:
minItems: 2
items: items:
- const: qup-core - const: qup-core
- const: qup-config - const: qup-config
- const: qup-memory
interrupts: interrupts:
maxItems: 1 maxItems: 1
......
...@@ -20,7 +20,9 @@ properties: ...@@ -20,7 +20,9 @@ properties:
- samsung,s3c2443-spi # for S3C2443, S3C2416 and S3C2450 - samsung,s3c2443-spi # for S3C2443, S3C2416 and S3C2450
- samsung,s3c6410-spi - samsung,s3c6410-spi
- samsung,s5pv210-spi # for S5PV210 and S5PC110 - samsung,s5pv210-spi # for S5PV210 and S5PC110
- samsung,exynos4210-spi
- samsung,exynos5433-spi - samsung,exynos5433-spi
- samsung,exynosautov9-spi
- tesla,fsd-spi - tesla,fsd-spi
- const: samsung,exynos7-spi - const: samsung,exynos7-spi
deprecated: true deprecated: true
...@@ -85,7 +87,9 @@ allOf: ...@@ -85,7 +87,9 @@ allOf:
properties: properties:
compatible: compatible:
contains: contains:
const: samsung,exynos5433-spi enum:
- samsung,exynos5433-spi
- samsung,exynosautov9-spi
then: then:
properties: properties:
clocks: clocks:
......
...@@ -61,6 +61,8 @@ properties: ...@@ -61,6 +61,8 @@ properties:
- const: snps,dw-apb-ssi - const: snps,dw-apb-ssi
- description: Intel Keem Bay SPI Controller - description: Intel Keem Bay SPI Controller
const: intel,keembay-ssi const: intel,keembay-ssi
- description: Intel Thunder Bay SPI Controller
const: intel,thunderbay-ssi
- description: Baikal-T1 SPI Controller - description: Baikal-T1 SPI Controller
const: baikal,bt1-ssi const: baikal,bt1-ssi
- description: Baikal-T1 System Boot SPI Controller - description: Baikal-T1 System Boot SPI Controller
...@@ -124,9 +126,16 @@ properties: ...@@ -124,9 +126,16 @@ properties:
rx-sample-delay-ns: rx-sample-delay-ns:
default: 0 default: 0
description: Default value of the rx-sample-delay-ns property. description: |
Default value of the rx-sample-delay-ns property.
This value will be used if the property is not explicitly defined This value will be used if the property is not explicitly defined
for a SPI slave device. See below. for a SPI slave device.
SPI Rx sample delay offset, unit is nanoseconds.
The delay from the default sample time before the actual sample of the
rxd input signal occurs. The "rx_sample_delay" is an optional feature
of the designware controller, and the upper limit is also subject to
controller configuration.
patternProperties: patternProperties:
"^.*@[0-9a-f]+$": "^.*@[0-9a-f]+$":
...@@ -136,19 +145,6 @@ patternProperties: ...@@ -136,19 +145,6 @@ patternProperties:
minimum: 0 minimum: 0
maximum: 3 maximum: 3
spi-rx-bus-width:
const: 1
spi-tx-bus-width:
const: 1
rx-sample-delay-ns:
description: SPI Rx sample delay offset, unit is nanoseconds.
The delay from the default sample time before the actual
sample of the rxd input signal occurs. The "rx_sample_delay"
is an optional feature of the designware controller, and the
upper limit is also subject to controller configuration.
unevaluatedProperties: false unevaluatedProperties: false
required: required:
......
...@@ -49,6 +49,13 @@ properties: ...@@ -49,6 +49,13 @@ properties:
enum: [ 0, 1 ] enum: [ 0, 1 ]
default: 0 default: 0
required:
- compatible
- reg
- interrupts
- clock-names
- clocks
unevaluatedProperties: false unevaluatedProperties: false
examples: examples:
......
...@@ -95,6 +95,17 @@ patternProperties: ...@@ -95,6 +95,17 @@ patternProperties:
type: object type: object
$ref: spi-peripheral-props.yaml $ref: spi-peripheral-props.yaml
properties:
spi-cpha:
$ref: /schemas/types.yaml#/definitions/flag
description:
The device requires shifted clock phase (CPHA) mode.
spi-cpol:
$ref: /schemas/types.yaml#/definitions/flag
description:
The device requires inverse clock polarity (CPOL) mode.
required: required:
- compatible - compatible
- reg - reg
...@@ -139,9 +150,9 @@ examples: ...@@ -139,9 +150,9 @@ examples:
}; };
flash@2 { flash@2 {
compatible = "jedec,spi-nor"; compatible = "jedec,spi-nor";
spi-max-frequency = <50000000>; spi-max-frequency = <50000000>;
reg = <2>, <3>; reg = <2>, <3>;
stacked-memories = /bits/ 64 <0x10000000 0x10000000>; stacked-memories = /bits/ 64 <0x10000000 0x10000000>;
}; };
}; };
...@@ -34,16 +34,6 @@ properties: ...@@ -34,16 +34,6 @@ properties:
description: description:
The device requires 3-wire mode. The device requires 3-wire mode.
spi-cpha:
$ref: /schemas/types.yaml#/definitions/flag
description:
The device requires shifted clock phase (CPHA) mode.
spi-cpol:
$ref: /schemas/types.yaml#/definitions/flag
description:
The device requires inverse clock polarity (CPOL) mode.
spi-cs-high: spi-cs-high:
$ref: /schemas/types.yaml#/definitions/flag $ref: /schemas/types.yaml#/definitions/flag
description: description:
...@@ -71,6 +61,11 @@ properties: ...@@ -71,6 +61,11 @@ properties:
description: description:
Delay, in microseconds, after a read transfer. Delay, in microseconds, after a read transfer.
rx-sample-delay-ns:
description: SPI Rx sample delay offset, unit is nanoseconds.
The delay from the default sample time before the actual
sample of the rxd input signal occurs.
spi-tx-bus-width: spi-tx-bus-width:
description: description:
Bus width to the SPI bus used for write transfers. Bus width to the SPI bus used for write transfers.
...@@ -112,5 +107,6 @@ properties: ...@@ -112,5 +107,6 @@ properties:
allOf: allOf:
- $ref: cdns,qspi-nor-peripheral-props.yaml# - $ref: cdns,qspi-nor-peripheral-props.yaml#
- $ref: samsung,spi-peripheral-props.yaml# - $ref: samsung,spi-peripheral-props.yaml#
- $ref: nvidia,tegra210-quad-peripheral-props.yaml#
additionalProperties: true additionalProperties: true
...@@ -30,6 +30,13 @@ properties: ...@@ -30,6 +30,13 @@ properties:
clocks: clocks:
maxItems: 2 maxItems: 2
required:
- compatible
- reg
- interrupts
- clock-names
- clocks
unevaluatedProperties: false unevaluatedProperties: false
examples: examples:
......
Atmel SPI device
Required properties:
- compatible : should be "atmel,at91rm9200-spi" or "microchip,sam9x60-spi".
- reg: Address and length of the register set for the device
- interrupts: Should contain spi interrupt
- cs-gpios: chipselects (optional for SPI controller version >= 2 with the
Chip Select Active After Transfer feature).
- clock-names: tuple listing input clock names.
Required elements: "spi_clk"
- clocks: phandles to input clocks.
Optional properties:
- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO
capable SPI controllers.
Example:
spi1: spi@fffcc000 {
compatible = "atmel,at91rm9200-spi";
reg = <0xfffcc000 0x4000>;
interrupts = <13 4 5>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&spi1_clk>;
clock-names = "spi_clk";
cs-gpios = <&pioB 3 0>;
atmel,fifo-size = <32>;
mmc-slot@0 {
compatible = "mmc-spi-slot";
reg = <0>;
gpios = <&pioC 4 0>; /* CD */
spi-max-frequency = <25000000>;
};
};
...@@ -2147,11 +2147,13 @@ M: Jean-Marie Verdun <verdun@hpe.com> ...@@ -2147,11 +2147,13 @@ M: Jean-Marie Verdun <verdun@hpe.com>
M: Nick Hawkins <nick.hawkins@hpe.com> M: Nick Hawkins <nick.hawkins@hpe.com>
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/arm/hpe,gxp.yaml F: Documentation/devicetree/bindings/arm/hpe,gxp.yaml
F: Documentation/devicetree/bindings/spi/hpe,gxp-spi.yaml
F: Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml F: Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
F: arch/arm/boot/dts/hpe-bmc* F: arch/arm/boot/dts/hpe-bmc*
F: arch/arm/boot/dts/hpe-gxp* F: arch/arm/boot/dts/hpe-gxp*
F: arch/arm/mach-hpe/ F: arch/arm/mach-hpe/
F: drivers/clocksource/timer-gxp.c F: drivers/clocksource/timer-gxp.c
F: drivers/spi/spi-gxp.c
F: drivers/watchdog/gxp-wdt.c F: drivers/watchdog/gxp-wdt.c
ARM/IGEP MACHINE SUPPORT ARM/IGEP MACHINE SUPPORT
...@@ -17332,6 +17334,7 @@ F: drivers/clk/microchip/clk-mpfs.c ...@@ -17332,6 +17334,7 @@ F: drivers/clk/microchip/clk-mpfs.c
F: drivers/mailbox/mailbox-mpfs.c F: drivers/mailbox/mailbox-mpfs.c
F: drivers/pci/controller/pcie-microchip-host.c F: drivers/pci/controller/pcie-microchip-host.c
F: drivers/soc/microchip/ F: drivers/soc/microchip/
F: drivers/spi/spi-microchip-core.c
F: include/soc/microchip/mpfs.h F: include/soc/microchip/mpfs.h
RNBD BLOCK DRIVERS RNBD BLOCK DRIVERS
......
...@@ -371,6 +371,13 @@ config SPI_FSL_QUADSPI ...@@ -371,6 +371,13 @@ config SPI_FSL_QUADSPI
This controller does not support generic SPI messages. It only This controller does not support generic SPI messages. It only
supports the high-level SPI memory interface. supports the high-level SPI memory interface.
config SPI_GXP
tristate "GXP SPI driver"
depends on ARCH_HPE || COMPILE_TEST
help
This enables support for the driver for GXP bus attached SPI
controllers.
config SPI_HISI_KUNPENG config SPI_HISI_KUNPENG
tristate "HiSilicon SPI Controller for Kunpeng SoCs" tristate "HiSilicon SPI Controller for Kunpeng SoCs"
depends on (ARM64 && ACPI) || COMPILE_TEST depends on (ARM64 && ACPI) || COMPILE_TEST
...@@ -575,6 +582,15 @@ config SPI_MESON_SPIFC ...@@ -575,6 +582,15 @@ config SPI_MESON_SPIFC
This enables master mode support for the SPIFC (SPI flash This enables master mode support for the SPIFC (SPI flash
controller) available in Amlogic Meson SoCs. controller) available in Amlogic Meson SoCs.
config SPI_MICROCHIP_CORE
tristate "Microchip FPGA SPI controllers"
depends on SPI_MASTER
help
This enables the SPI driver for Microchip FPGA SPI controllers.
Say Y or M here if you want to use the "hard" controllers on
PolarFire SoC.
If built as a module, it will be called spi-microchip-core.
config SPI_MT65XX config SPI_MT65XX
tristate "MediaTek SPI controller" tristate "MediaTek SPI controller"
depends on ARCH_MEDIATEK || COMPILE_TEST depends on ARCH_MEDIATEK || COMPILE_TEST
......
...@@ -57,6 +57,7 @@ obj-$(CONFIG_SPI_FSL_LPSPI) += spi-fsl-lpspi.o ...@@ -57,6 +57,7 @@ obj-$(CONFIG_SPI_FSL_LPSPI) += spi-fsl-lpspi.o
obj-$(CONFIG_SPI_FSL_QUADSPI) += spi-fsl-qspi.o obj-$(CONFIG_SPI_FSL_QUADSPI) += spi-fsl-qspi.o
obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
obj-$(CONFIG_SPI_GPIO) += spi-gpio.o obj-$(CONFIG_SPI_GPIO) += spi-gpio.o
obj-$(CONFIG_SPI_GXP) += spi-gxp.o
obj-$(CONFIG_SPI_HISI_KUNPENG) += spi-hisi-kunpeng.o obj-$(CONFIG_SPI_HISI_KUNPENG) += spi-hisi-kunpeng.o
obj-$(CONFIG_SPI_HISI_SFC_V3XX) += spi-hisi-sfc-v3xx.o obj-$(CONFIG_SPI_HISI_SFC_V3XX) += spi-hisi-sfc-v3xx.o
obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o
...@@ -71,6 +72,7 @@ obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o ...@@ -71,6 +72,7 @@ obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o
obj-$(CONFIG_SPI_MESON_SPICC) += spi-meson-spicc.o obj-$(CONFIG_SPI_MESON_SPICC) += spi-meson-spicc.o
obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
obj-$(CONFIG_SPI_MICROCHIP_CORE) += spi-microchip-core.o
obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi-mem.h> #include <linux/spi/spi-mem.h>
/* QSPI register offsets */ /* QSPI register offsets */
...@@ -285,7 +286,7 @@ static bool atmel_qspi_supports_op(struct spi_mem *mem, ...@@ -285,7 +286,7 @@ static bool atmel_qspi_supports_op(struct spi_mem *mem,
/* special case not supported by hardware */ /* special case not supported by hardware */
if (op->addr.nbytes == 2 && op->cmd.buswidth != op->addr.buswidth && if (op->addr.nbytes == 2 && op->cmd.buswidth != op->addr.buswidth &&
op->dummy.nbytes == 0) op->dummy.nbytes == 0)
return false; return false;
return true; return true;
...@@ -417,9 +418,13 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -417,9 +418,13 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
if (op->addr.val + op->data.nbytes > aq->mmap_size) if (op->addr.val + op->data.nbytes > aq->mmap_size)
return -ENOTSUPP; return -ENOTSUPP;
err = pm_runtime_resume_and_get(&aq->pdev->dev);
if (err < 0)
return err;
err = atmel_qspi_set_cfg(aq, op, &offset); err = atmel_qspi_set_cfg(aq, op, &offset);
if (err) if (err)
return err; goto pm_runtime_put;
/* Skip to the final steps if there is no data */ /* Skip to the final steps if there is no data */
if (op->data.nbytes) { if (op->data.nbytes) {
...@@ -441,7 +446,7 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -441,7 +446,7 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
/* Poll INSTRuction End status */ /* Poll INSTRuction End status */
sr = atmel_qspi_read(aq, QSPI_SR); sr = atmel_qspi_read(aq, QSPI_SR);
if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED) if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
return err; goto pm_runtime_put;
/* Wait for INSTRuction End interrupt */ /* Wait for INSTRuction End interrupt */
reinit_completion(&aq->cmd_completion); reinit_completion(&aq->cmd_completion);
...@@ -452,6 +457,9 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -452,6 +457,9 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
err = -ETIMEDOUT; err = -ETIMEDOUT;
atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IDR); atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IDR);
pm_runtime_put:
pm_runtime_mark_last_busy(&aq->pdev->dev);
pm_runtime_put_autosuspend(&aq->pdev->dev);
return err; return err;
} }
...@@ -472,6 +480,7 @@ static int atmel_qspi_setup(struct spi_device *spi) ...@@ -472,6 +480,7 @@ static int atmel_qspi_setup(struct spi_device *spi)
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
unsigned long src_rate; unsigned long src_rate;
u32 scbr; u32 scbr;
int ret;
if (ctrl->busy) if (ctrl->busy)
return -EBUSY; return -EBUSY;
...@@ -488,9 +497,16 @@ static int atmel_qspi_setup(struct spi_device *spi) ...@@ -488,9 +497,16 @@ static int atmel_qspi_setup(struct spi_device *spi)
if (scbr > 0) if (scbr > 0)
scbr--; scbr--;
ret = pm_runtime_resume_and_get(ctrl->dev.parent);
if (ret < 0)
return ret;
aq->scr = QSPI_SCR_SCBR(scbr); aq->scr = QSPI_SCR_SCBR(scbr);
atmel_qspi_write(aq->scr, aq, QSPI_SCR); atmel_qspi_write(aq->scr, aq, QSPI_SCR);
pm_runtime_mark_last_busy(ctrl->dev.parent);
pm_runtime_put_autosuspend(ctrl->dev.parent);
return 0; return 0;
} }
...@@ -621,11 +637,24 @@ static int atmel_qspi_probe(struct platform_device *pdev) ...@@ -621,11 +637,24 @@ static int atmel_qspi_probe(struct platform_device *pdev)
if (err) if (err)
goto disable_qspick; goto disable_qspick;
pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
atmel_qspi_init(aq); atmel_qspi_init(aq);
err = spi_register_controller(ctrl); err = spi_register_controller(ctrl);
if (err) if (err) {
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
goto disable_qspick; goto disable_qspick;
}
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0; return 0;
...@@ -641,9 +670,18 @@ static int atmel_qspi_remove(struct platform_device *pdev) ...@@ -641,9 +670,18 @@ static int atmel_qspi_remove(struct platform_device *pdev)
{ {
struct spi_controller *ctrl = platform_get_drvdata(pdev); struct spi_controller *ctrl = platform_get_drvdata(pdev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
int ret;
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0)
return ret;
spi_unregister_controller(ctrl); spi_unregister_controller(ctrl);
atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR); atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
clk_disable_unprepare(aq->qspick); clk_disable_unprepare(aq->qspick);
clk_disable_unprepare(aq->pclk); clk_disable_unprepare(aq->pclk);
return 0; return 0;
...@@ -653,10 +691,19 @@ static int __maybe_unused atmel_qspi_suspend(struct device *dev) ...@@ -653,10 +691,19 @@ static int __maybe_unused atmel_qspi_suspend(struct device *dev)
{ {
struct spi_controller *ctrl = dev_get_drvdata(dev); struct spi_controller *ctrl = dev_get_drvdata(dev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
int ret;
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR); atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
clk_disable_unprepare(aq->qspick);
clk_disable_unprepare(aq->pclk); pm_runtime_mark_last_busy(dev);
pm_runtime_force_suspend(dev);
clk_unprepare(aq->qspick);
clk_unprepare(aq->pclk);
return 0; return 0;
} }
...@@ -665,19 +712,54 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev) ...@@ -665,19 +712,54 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev)
{ {
struct spi_controller *ctrl = dev_get_drvdata(dev); struct spi_controller *ctrl = dev_get_drvdata(dev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl); struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
int ret;
clk_prepare_enable(aq->pclk); clk_prepare(aq->pclk);
clk_prepare_enable(aq->qspick); clk_prepare(aq->qspick);
ret = pm_runtime_force_resume(dev);
if (ret < 0)
return ret;
atmel_qspi_init(aq); atmel_qspi_init(aq);
atmel_qspi_write(aq->scr, aq, QSPI_SCR); atmel_qspi_write(aq->scr, aq, QSPI_SCR);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
}
static int __maybe_unused atmel_qspi_runtime_suspend(struct device *dev)
{
struct spi_controller *ctrl = dev_get_drvdata(dev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
clk_disable(aq->qspick);
clk_disable(aq->pclk);
return 0; return 0;
} }
static SIMPLE_DEV_PM_OPS(atmel_qspi_pm_ops, atmel_qspi_suspend, static int __maybe_unused atmel_qspi_runtime_resume(struct device *dev)
atmel_qspi_resume); {
struct spi_controller *ctrl = dev_get_drvdata(dev);
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
int ret;
ret = clk_enable(aq->pclk);
if (ret)
return ret;
return clk_enable(aq->qspick);
}
static const struct dev_pm_ops __maybe_unused atmel_qspi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(atmel_qspi_suspend, atmel_qspi_resume)
SET_RUNTIME_PM_OPS(atmel_qspi_runtime_suspend,
atmel_qspi_runtime_resume, NULL)
};
static const struct atmel_qspi_caps atmel_sama5d2_qspi_caps = {}; static const struct atmel_qspi_caps atmel_sama5d2_qspi_caps = {};
...@@ -704,7 +786,7 @@ static struct platform_driver atmel_qspi_driver = { ...@@ -704,7 +786,7 @@ static struct platform_driver atmel_qspi_driver = {
.driver = { .driver = {
.name = "atmel_qspi", .name = "atmel_qspi",
.of_match_table = atmel_qspi_dt_ids, .of_match_table = atmel_qspi_dt_ids,
.pm = &atmel_qspi_pm_ops, .pm = pm_ptr(&atmel_qspi_pm_ops),
}, },
.probe = atmel_qspi_probe, .probe = atmel_qspi_probe,
.remove = atmel_qspi_remove, .remove = atmel_qspi_remove,
......
...@@ -128,9 +128,9 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) ...@@ -128,9 +128,9 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
struct spi_master *master; struct spi_master *master;
struct altera_spi *hw; struct altera_spi *hw;
void __iomem *base; void __iomem *base;
int err = -ENODEV; int err;
master = spi_alloc_master(dev, sizeof(struct altera_spi)); master = devm_spi_alloc_master(dev, sizeof(struct altera_spi));
if (!master) if (!master)
return -ENOMEM; return -ENOMEM;
...@@ -159,10 +159,9 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) ...@@ -159,10 +159,9 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
altera_spi_init_master(master); altera_spi_init_master(master);
err = devm_spi_register_master(dev, master); err = devm_spi_register_master(dev, master);
if (err) { if (err)
dev_err(dev, "%s failed to register spi master %d\n", __func__, err); return dev_err_probe(dev, err, "%s failed to register spi master\n",
goto exit; __func__);
}
if (dfl_dev->revision == FME_FEATURE_REV_MAX10_SPI_N5010) if (dfl_dev->revision == FME_FEATURE_REV_MAX10_SPI_N5010)
strscpy(board_info.modalias, "m10-n5010", SPI_NAME_SIZE); strscpy(board_info.modalias, "m10-n5010", SPI_NAME_SIZE);
...@@ -179,9 +178,6 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) ...@@ -179,9 +178,6 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
} }
return 0; return 0;
exit:
spi_master_put(master);
return err;
} }
static const struct dfl_device_id dfl_spi_altera_ids[] = { static const struct dfl_device_id dfl_spi_altera_ids[] = {
......
...@@ -40,14 +40,23 @@ ...@@ -40,14 +40,23 @@
#define AMD_SPI_XFER_TX 1 #define AMD_SPI_XFER_TX 1
#define AMD_SPI_XFER_RX 2 #define AMD_SPI_XFER_RX 2
/**
* enum amd_spi_versions - SPI controller versions
* @AMD_SPI_V1: AMDI0061 hardware version
* @AMD_SPI_V2: AMDI0062 hardware version
*/
enum amd_spi_versions { enum amd_spi_versions {
AMD_SPI_V1 = 1, /* AMDI0061 */ AMD_SPI_V1 = 1,
AMD_SPI_V2, /* AMDI0062 */ AMD_SPI_V2,
}; };
/**
* struct amd_spi - SPI driver instance
* @io_remap_addr: Start address of the SPI controller registers
* @version: SPI controller hardware version
*/
struct amd_spi { struct amd_spi {
void __iomem *io_remap_addr; void __iomem *io_remap_addr;
unsigned long io_base_addr;
enum amd_spi_versions version; enum amd_spi_versions version;
}; };
...@@ -281,22 +290,19 @@ static int amd_spi_probe(struct platform_device *pdev) ...@@ -281,22 +290,19 @@ static int amd_spi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct spi_master *master; struct spi_master *master;
struct amd_spi *amd_spi; struct amd_spi *amd_spi;
int err = 0; int err;
/* Allocate storage for spi_master and driver private data */ /* Allocate storage for spi_master and driver private data */
master = spi_alloc_master(dev, sizeof(struct amd_spi)); master = devm_spi_alloc_master(dev, sizeof(struct amd_spi));
if (!master) { if (!master)
dev_err(dev, "Error allocating SPI master\n"); return dev_err_probe(dev, -ENOMEM, "Error allocating SPI master\n");
return -ENOMEM;
}
amd_spi = spi_master_get_devdata(master); amd_spi = spi_master_get_devdata(master);
amd_spi->io_remap_addr = devm_platform_ioremap_resource(pdev, 0); amd_spi->io_remap_addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(amd_spi->io_remap_addr)) { if (IS_ERR(amd_spi->io_remap_addr))
err = PTR_ERR(amd_spi->io_remap_addr); return dev_err_probe(dev, PTR_ERR(amd_spi->io_remap_addr),
dev_err(dev, "error %d ioremap of SPI registers failed\n", err); "ioremap of SPI registers failed\n");
goto err_free_master;
}
dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr); dev_dbg(dev, "io_remap_address: %p\n", amd_spi->io_remap_addr);
amd_spi->version = (enum amd_spi_versions) device_get_match_data(dev); amd_spi->version = (enum amd_spi_versions) device_get_match_data(dev);
...@@ -313,17 +319,10 @@ static int amd_spi_probe(struct platform_device *pdev) ...@@ -313,17 +319,10 @@ static int amd_spi_probe(struct platform_device *pdev)
/* Register the controller with SPI framework */ /* Register the controller with SPI framework */
err = devm_spi_register_master(dev, master); err = devm_spi_register_master(dev, master);
if (err) { if (err)
dev_err(dev, "error %d registering SPI controller\n", err); return dev_err_probe(dev, err, "error registering SPI controller\n");
goto err_free_master;
}
return 0; return 0;
err_free_master:
spi_master_put(master);
return err;
} }
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
......
...@@ -497,7 +497,7 @@ static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi) ...@@ -497,7 +497,7 @@ static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi)
while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) { while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) {
val = *(u32 *)a3700_spi->tx_buf; val = *(u32 *)a3700_spi->tx_buf;
spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val); spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, cpu_to_le32(val));
a3700_spi->buf_len -= 4; a3700_spi->buf_len -= 4;
a3700_spi->tx_buf += 4; a3700_spi->tx_buf += 4;
} }
...@@ -519,7 +519,7 @@ static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi) ...@@ -519,7 +519,7 @@ static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi)
while (!a3700_is_rfifo_empty(a3700_spi) && a3700_spi->buf_len) { while (!a3700_is_rfifo_empty(a3700_spi) && a3700_spi->buf_len) {
val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG); val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG);
if (a3700_spi->buf_len >= 4) { if (a3700_spi->buf_len >= 4) {
val = le32_to_cpu(val);
memcpy(a3700_spi->rx_buf, &val, 4); memcpy(a3700_spi->rx_buf, &val, 4);
a3700_spi->buf_len -= 4; a3700_spi->buf_len -= 4;
......
...@@ -1631,7 +1631,6 @@ static int atmel_spi_remove(struct platform_device *pdev) ...@@ -1631,7 +1631,6 @@ static int atmel_spi_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int atmel_spi_runtime_suspend(struct device *dev) static int atmel_spi_runtime_suspend(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_master *master = dev_get_drvdata(dev);
...@@ -1653,7 +1652,6 @@ static int atmel_spi_runtime_resume(struct device *dev) ...@@ -1653,7 +1652,6 @@ static int atmel_spi_runtime_resume(struct device *dev)
return clk_prepare_enable(as->clk); return clk_prepare_enable(as->clk);
} }
#ifdef CONFIG_PM_SLEEP
static int atmel_spi_suspend(struct device *dev) static int atmel_spi_suspend(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_master *master = dev_get_drvdata(dev);
...@@ -1693,17 +1691,12 @@ static int atmel_spi_resume(struct device *dev) ...@@ -1693,17 +1691,12 @@ static int atmel_spi_resume(struct device *dev)
/* Start the queue running */ /* Start the queue running */
return spi_master_resume(master); return spi_master_resume(master);
} }
#endif
static const struct dev_pm_ops atmel_spi_pm_ops = { static const struct dev_pm_ops atmel_spi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(atmel_spi_suspend, atmel_spi_resume) SYSTEM_SLEEP_PM_OPS(atmel_spi_suspend, atmel_spi_resume)
SET_RUNTIME_PM_OPS(atmel_spi_runtime_suspend, RUNTIME_PM_OPS(atmel_spi_runtime_suspend,
atmel_spi_runtime_resume, NULL) atmel_spi_runtime_resume, NULL)
}; };
#define ATMEL_SPI_PM_OPS (&atmel_spi_pm_ops)
#else
#define ATMEL_SPI_PM_OPS NULL
#endif
static const struct of_device_id atmel_spi_dt_ids[] = { static const struct of_device_id atmel_spi_dt_ids[] = {
{ .compatible = "atmel,at91rm9200-spi" }, { .compatible = "atmel,at91rm9200-spi" },
...@@ -1715,7 +1708,7 @@ MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids); ...@@ -1715,7 +1708,7 @@ MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
static struct platform_driver atmel_spi_driver = { static struct platform_driver atmel_spi_driver = {
.driver = { .driver = {
.name = "atmel_spi", .name = "atmel_spi",
.pm = ATMEL_SPI_PM_OPS, .pm = pm_ptr(&atmel_spi_pm_ops),
.of_match_table = atmel_spi_dt_ids, .of_match_table = atmel_spi_dt_ids,
}, },
.probe = atmel_spi_probe, .probe = atmel_spi_probe,
......
...@@ -372,6 +372,10 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id) ...@@ -372,6 +372,10 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
struct bcm2835_spi *bs = dev_id; struct bcm2835_spi *bs = dev_id;
u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
/* Bail out early if interrupts are not enabled */
if (!(cs & BCM2835_SPI_CS_INTR))
return IRQ_NONE;
/* /*
* An interrupt is signaled either if DONE is set (TX FIFO empty) * An interrupt is signaled either if DONE is set (TX FIFO empty)
* or if RXR is set (RX FIFO >= ¾ full). * or if RXR is set (RX FIFO >= ¾ full).
...@@ -1369,8 +1373,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev) ...@@ -1369,8 +1373,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
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);
err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0, err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt,
dev_name(&pdev->dev), bs); IRQF_SHARED, dev_name(&pdev->dev), bs);
if (err) { if (err) {
dev_err(&pdev->dev, "could not request IRQ: %d\n", err); dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
goto out_dma_release; goto out_dma_release;
......
...@@ -307,8 +307,9 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi) ...@@ -307,8 +307,9 @@ static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
if (spi->mode & SPI_LOOP) if (spi->mode & SPI_LOOP)
cr0 |= DW_HSSI_CTRLR0_SRL; cr0 |= DW_HSSI_CTRLR0_SRL;
if (dws->caps & DW_SPI_CAP_KEEMBAY_MST) /* CTRLR0[31] MST */
cr0 |= DW_HSSI_CTRLR0_KEEMBAY_MST; if (dw_spi_ver_is_ge(dws, HSSI, 102A))
cr0 |= DW_HSSI_CTRLR0_MST;
} }
return cr0; return cr0;
...@@ -942,7 +943,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -942,7 +943,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
if (dws->dma_ops && dws->dma_ops->dma_init) { if (dws->dma_ops && dws->dma_ops->dma_init) {
ret = dws->dma_ops->dma_init(dev, dws); ret = dws->dma_ops->dma_init(dev, dws);
if (ret) { if (ret == -EPROBE_DEFER) {
goto err_free_irq;
} else if (ret) {
dev_warn(dev, "DMA init failed\n"); dev_warn(dev, "DMA init failed\n");
} else { } else {
master->can_dma = dws->dma_ops->can_dma; master->can_dma = dws->dma_ops->can_dma;
...@@ -963,6 +966,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) ...@@ -963,6 +966,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
if (dws->dma_ops && dws->dma_ops->dma_exit) if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws); dws->dma_ops->dma_exit(dws);
dw_spi_enable_chip(dws, 0); dw_spi_enable_chip(dws, 0);
err_free_irq:
free_irq(dws->irq, master); free_irq(dws->irq, master);
err_free_master: err_free_master:
spi_controller_put(master); spi_controller_put(master);
......
...@@ -139,15 +139,20 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws) ...@@ -139,15 +139,20 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws) static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
{ {
dws->rxchan = dma_request_slave_channel(dev, "rx"); int ret;
if (!dws->rxchan)
return -ENODEV;
dws->txchan = dma_request_slave_channel(dev, "tx"); dws->rxchan = dma_request_chan(dev, "rx");
if (!dws->txchan) { if (IS_ERR(dws->rxchan)) {
dma_release_channel(dws->rxchan); ret = PTR_ERR(dws->rxchan);
dws->rxchan = NULL; dws->rxchan = NULL;
return -ENODEV; goto err_exit;
}
dws->txchan = dma_request_chan(dev, "tx");
if (IS_ERR(dws->txchan)) {
ret = PTR_ERR(dws->txchan);
dws->txchan = NULL;
goto free_rxchan;
} }
dws->master->dma_rx = dws->rxchan; dws->master->dma_rx = dws->rxchan;
...@@ -160,6 +165,12 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws) ...@@ -160,6 +165,12 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
dw_spi_dma_sg_burst_init(dws); dw_spi_dma_sg_burst_init(dws);
return 0; return 0;
free_rxchan:
dma_release_channel(dws->rxchan);
dws->rxchan = NULL;
err_exit:
return ret;
} }
static void dw_spi_dma_exit(struct dw_spi *dws) static void dw_spi_dma_exit(struct dw_spi *dws)
......
...@@ -214,11 +214,10 @@ static int dw_spi_hssi_init(struct platform_device *pdev, ...@@ -214,11 +214,10 @@ static int dw_spi_hssi_init(struct platform_device *pdev,
return 0; return 0;
} }
static int dw_spi_keembay_init(struct platform_device *pdev, static int dw_spi_intel_init(struct platform_device *pdev,
struct dw_spi_mmio *dwsmmio) struct dw_spi_mmio *dwsmmio)
{ {
dwsmmio->dws.ip = DW_HSSI_ID; dwsmmio->dws.ip = DW_HSSI_ID;
dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST;
return 0; return 0;
} }
...@@ -349,7 +348,8 @@ static const struct of_device_id dw_spi_mmio_of_match[] = { ...@@ -349,7 +348,8 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .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", .data = dw_spi_pssi_init}, { .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init},
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init}, { .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
{ .compatible = "intel,keembay-ssi", .data = dw_spi_keembay_init}, { .compatible = "intel,keembay-ssi", .data = dw_spi_intel_init},
{ .compatible = "intel,thunderbay-ssi", .data = dw_spi_intel_init},
{ .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init}, { .compatible = "microchip,sparx5-spi", dw_spi_mscc_sparx5_init},
{ .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init}, { .compatible = "canaan,k210-spi", dw_spi_canaan_k210_init},
{ /* end of table */} { /* end of table */}
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
((_dws)->ip == DW_ ## _ip ## _ID) ((_dws)->ip == DW_ ## _ip ## _ID)
#define __dw_spi_ver_cmp(_dws, _ip, _ver, _op) \ #define __dw_spi_ver_cmp(_dws, _ip, _ver, _op) \
(dw_spi_ip_is(_dws, _ip) && (_dws)->ver _op DW_ ## _ip ## _ver) (dw_spi_ip_is(_dws, _ip) && (_dws)->ver _op DW_ ## _ip ## _ ## _ver)
#define dw_spi_ver_is(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, ==) #define dw_spi_ver_is(_dws, _ip, _ver) __dw_spi_ver_cmp(_dws, _ip, _ver, ==)
...@@ -31,8 +31,7 @@ ...@@ -31,8 +31,7 @@
/* DW SPI controller capabilities */ /* DW SPI controller capabilities */
#define DW_SPI_CAP_CS_OVERRIDE BIT(0) #define DW_SPI_CAP_CS_OVERRIDE BIT(0)
#define DW_SPI_CAP_KEEMBAY_MST BIT(1) #define DW_SPI_CAP_DFS32 BIT(1)
#define DW_SPI_CAP_DFS32 BIT(2)
/* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */ /* Register offsets (Generic for both DWC APB SSI and DWC SSI IP-cores) */
#define DW_SPI_CTRLR0 0x00 #define DW_SPI_CTRLR0 0x00
...@@ -94,13 +93,7 @@ ...@@ -94,13 +93,7 @@
#define DW_HSSI_CTRLR0_SCPOL BIT(9) #define DW_HSSI_CTRLR0_SCPOL BIT(9)
#define DW_HSSI_CTRLR0_TMOD_MASK GENMASK(11, 10) #define DW_HSSI_CTRLR0_TMOD_MASK GENMASK(11, 10)
#define DW_HSSI_CTRLR0_SRL BIT(13) #define DW_HSSI_CTRLR0_SRL BIT(13)
#define DW_HSSI_CTRLR0_MST BIT(31)
/*
* For Keem Bay, CTRLR0[31] is used to select controller mode.
* 0: SSI is slave
* 1: SSI is master
*/
#define DW_HSSI_CTRLR0_KEEMBAY_MST BIT(31)
/* Bit fields in CTRLR1 */ /* Bit fields in CTRLR1 */
#define DW_SPI_NDF_MASK GENMASK(15, 0) #define DW_SPI_NDF_MASK GENMASK(15, 0)
......
...@@ -24,8 +24,7 @@ ...@@ -24,8 +24,7 @@
#define FSI2SPI_IRQ 0x20 #define FSI2SPI_IRQ 0x20
#define SPI_FSI_BASE 0x70000 #define SPI_FSI_BASE 0x70000
#define SPI_FSI_INIT_TIMEOUT_MS 1000 #define SPI_FSI_TIMEOUT_MS 1000
#define SPI_FSI_STATUS_TIMEOUT_MS 100
#define SPI_FSI_MAX_RX_SIZE 8 #define SPI_FSI_MAX_RX_SIZE 8
#define SPI_FSI_MAX_TX_SIZE 40 #define SPI_FSI_MAX_TX_SIZE 40
...@@ -299,6 +298,7 @@ static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq) ...@@ -299,6 +298,7 @@ static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq)
static int fsi_spi_transfer_data(struct fsi_spi *ctx, static int fsi_spi_transfer_data(struct fsi_spi *ctx,
struct spi_transfer *transfer) struct spi_transfer *transfer)
{ {
int loops;
int rc = 0; int rc = 0;
unsigned long end; unsigned long end;
u64 status = 0ULL; u64 status = 0ULL;
...@@ -317,9 +317,10 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, ...@@ -317,9 +317,10 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx,
if (rc) if (rc)
return rc; return rc;
end = jiffies + msecs_to_jiffies(SPI_FSI_STATUS_TIMEOUT_MS); loops = 0;
end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS);
do { do {
if (time_after(jiffies, end)) if (loops++ && time_after(jiffies, end))
return -ETIMEDOUT; return -ETIMEDOUT;
rc = fsi_spi_status(ctx, &status, "TX"); rc = fsi_spi_status(ctx, &status, "TX");
...@@ -335,9 +336,10 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, ...@@ -335,9 +336,10 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx,
u8 *rx = transfer->rx_buf; u8 *rx = transfer->rx_buf;
while (transfer->len > recv) { while (transfer->len > recv) {
end = jiffies + msecs_to_jiffies(SPI_FSI_STATUS_TIMEOUT_MS); loops = 0;
end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS);
do { do {
if (time_after(jiffies, end)) if (loops++ && time_after(jiffies, end))
return -ETIMEDOUT; return -ETIMEDOUT;
rc = fsi_spi_status(ctx, &status, "RX"); rc = fsi_spi_status(ctx, &status, "RX");
...@@ -359,6 +361,7 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, ...@@ -359,6 +361,7 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx,
static int fsi_spi_transfer_init(struct fsi_spi *ctx) static int fsi_spi_transfer_init(struct fsi_spi *ctx)
{ {
int loops = 0;
int rc; int rc;
bool reset = false; bool reset = false;
unsigned long end; unsigned long end;
...@@ -369,9 +372,9 @@ static int fsi_spi_transfer_init(struct fsi_spi *ctx) ...@@ -369,9 +372,9 @@ static int fsi_spi_transfer_init(struct fsi_spi *ctx)
SPI_FSI_CLOCK_CFG_SCK_NO_DEL | SPI_FSI_CLOCK_CFG_SCK_NO_DEL |
FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 19); FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 19);
end = jiffies + msecs_to_jiffies(SPI_FSI_INIT_TIMEOUT_MS); end = jiffies + msecs_to_jiffies(SPI_FSI_TIMEOUT_MS);
do { do {
if (time_after(jiffies, end)) if (loops++ && time_after(jiffies, end))
return -ETIMEDOUT; return -ETIMEDOUT;
rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, &status); rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, &status);
......
// SPDX-License-Identifier: GPL-2.0=or-later
/* Copyright (C) 2022 Hewlett-Packard Development Company, L.P. */
#include <linux/iopoll.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#define GXP_SPI0_MAX_CHIPSELECT 2
#define GXP_SPI_SLEEP_TIME 1
#define GXP_SPI_TIMEOUT (130 * 1000000 / GXP_SPI_SLEEP_TIME)
#define MANUAL_MODE 0
#define DIRECT_MODE 1
#define SPILDAT_LEN 256
#define OFFSET_SPIMCFG 0x0
#define OFFSET_SPIMCTRL 0x4
#define OFFSET_SPICMD 0x5
#define OFFSET_SPIDCNT 0x6
#define OFFSET_SPIADDR 0x8
#define OFFSET_SPIINTSTS 0xc
#define SPIMCTRL_START 0x01
#define SPIMCTRL_BUSY 0x02
#define SPIMCTRL_DIR 0x08
struct gxp_spi;
struct gxp_spi_chip {
struct gxp_spi *spifi;
u32 cs;
};
struct gxp_spi_data {
u32 max_cs;
u32 mode_bits;
};
struct gxp_spi {
const struct gxp_spi_data *data;
void __iomem *reg_base;
void __iomem *dat_base;
void __iomem *dir_base;
struct device *dev;
struct gxp_spi_chip chips[GXP_SPI0_MAX_CHIPSELECT];
};
static void gxp_spi_set_mode(struct gxp_spi *spifi, int mode)
{
u8 value;
void __iomem *reg_base = spifi->reg_base;
value = readb(reg_base + OFFSET_SPIMCTRL);
if (mode == MANUAL_MODE) {
writeb(0x55, reg_base + OFFSET_SPICMD);
writeb(0xaa, reg_base + OFFSET_SPICMD);
value &= ~0x30;
} else {
value |= 0x30;
}
writeb(value, reg_base + OFFSET_SPIMCTRL);
}
static int gxp_spi_read_reg(struct gxp_spi_chip *chip, const struct spi_mem_op *op)
{
int ret;
struct gxp_spi *spifi = chip->spifi;
void __iomem *reg_base = spifi->reg_base;
u32 value;
value = readl(reg_base + OFFSET_SPIMCFG);
value &= ~(1 << 24);
value |= (chip->cs << 24);
value &= ~(0x07 << 16);
value &= ~(0x1f << 19);
writel(value, reg_base + OFFSET_SPIMCFG);
writel(0, reg_base + OFFSET_SPIADDR);
writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);
writew(op->data.nbytes, reg_base + OFFSET_SPIDCNT);
value = readb(reg_base + OFFSET_SPIMCTRL);
value &= ~SPIMCTRL_DIR;
value |= SPIMCTRL_START;
writeb(value, reg_base + OFFSET_SPIMCTRL);
ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,
!(value & SPIMCTRL_BUSY),
GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);
if (ret) {
dev_warn(spifi->dev, "read reg busy time out\n");
return ret;
}
memcpy_fromio(op->data.buf.in, spifi->dat_base, op->data.nbytes);
return ret;
}
static int gxp_spi_write_reg(struct gxp_spi_chip *chip, const struct spi_mem_op *op)
{
int ret;
struct gxp_spi *spifi = chip->spifi;
void __iomem *reg_base = spifi->reg_base;
u32 value;
value = readl(reg_base + OFFSET_SPIMCFG);
value &= ~(1 << 24);
value |= (chip->cs << 24);
value &= ~(0x07 << 16);
value &= ~(0x1f << 19);
writel(value, reg_base + OFFSET_SPIMCFG);
writel(0, reg_base + OFFSET_SPIADDR);
writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);
memcpy_toio(spifi->dat_base, op->data.buf.in, op->data.nbytes);
writew(op->data.nbytes, reg_base + OFFSET_SPIDCNT);
value = readb(reg_base + OFFSET_SPIMCTRL);
value |= SPIMCTRL_DIR;
value |= SPIMCTRL_START;
writeb(value, reg_base + OFFSET_SPIMCTRL);
ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,
!(value & SPIMCTRL_BUSY),
GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);
if (ret)
dev_warn(spifi->dev, "write reg busy time out\n");
return ret;
}
static ssize_t gxp_spi_read(struct gxp_spi_chip *chip, const struct spi_mem_op *op)
{
struct gxp_spi *spifi = chip->spifi;
u32 offset = op->addr.val;
if (chip->cs == 0)
offset += 0x4000000;
memcpy_fromio(op->data.buf.in, spifi->dir_base + offset, op->data.nbytes);
return 0;
}
static ssize_t gxp_spi_write(struct gxp_spi_chip *chip, const struct spi_mem_op *op)
{
struct gxp_spi *spifi = chip->spifi;
void __iomem *reg_base = spifi->reg_base;
u32 write_len;
u32 value;
int ret;
write_len = op->data.nbytes;
if (write_len > SPILDAT_LEN)
write_len = SPILDAT_LEN;
value = readl(reg_base + OFFSET_SPIMCFG);
value &= ~(1 << 24);
value |= (chip->cs << 24);
value &= ~(0x07 << 16);
value |= (op->addr.nbytes << 16);
value &= ~(0x1f << 19);
writel(value, reg_base + OFFSET_SPIMCFG);
writel(op->addr.val, reg_base + OFFSET_SPIADDR);
writeb(op->cmd.opcode, reg_base + OFFSET_SPICMD);
writew(write_len, reg_base + OFFSET_SPIDCNT);
memcpy_toio(spifi->dat_base, op->data.buf.in, write_len);
value = readb(reg_base + OFFSET_SPIMCTRL);
value |= SPIMCTRL_DIR;
value |= SPIMCTRL_START;
writeb(value, reg_base + OFFSET_SPIMCTRL);
ret = readb_poll_timeout(reg_base + OFFSET_SPIMCTRL, value,
!(value & SPIMCTRL_BUSY),
GXP_SPI_SLEEP_TIME, GXP_SPI_TIMEOUT);
if (ret) {
dev_warn(spifi->dev, "write busy time out\n");
return ret;
}
return write_len;
}
static int do_gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct gxp_spi *spifi = spi_controller_get_devdata(mem->spi->master);
struct gxp_spi_chip *chip = &spifi->chips[mem->spi->chip_select];
int ret;
if (op->data.dir == SPI_MEM_DATA_IN) {
if (!op->addr.nbytes)
ret = gxp_spi_read_reg(chip, op);
else
ret = gxp_spi_read(chip, op);
} else {
if (!op->addr.nbytes)
ret = gxp_spi_write_reg(chip, op);
else
ret = gxp_spi_write(chip, op);
}
return ret;
}
static int gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
int ret;
ret = do_gxp_exec_mem_op(mem, op);
if (ret)
dev_err(&mem->spi->dev, "operation failed: %d", ret);
return ret;
}
static const struct spi_controller_mem_ops gxp_spi_mem_ops = {
.exec_op = gxp_exec_mem_op,
};
static int gxp_spi_setup(struct spi_device *spi)
{
struct gxp_spi *spifi = spi_controller_get_devdata(spi->master);
unsigned int cs = spi->chip_select;
struct gxp_spi_chip *chip = &spifi->chips[cs];
chip->spifi = spifi;
chip->cs = cs;
gxp_spi_set_mode(spifi, MANUAL_MODE);
return 0;
}
static int gxp_spifi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct gxp_spi_data *data;
struct spi_controller *ctlr;
struct gxp_spi *spifi;
struct resource *res;
int ret;
data = of_device_get_match_data(&pdev->dev);
ctlr = devm_spi_alloc_master(dev, sizeof(*spifi));
if (!ctlr)
return -ENOMEM;
spifi = spi_controller_get_devdata(ctlr);
platform_set_drvdata(pdev, spifi);
spifi->data = data;
spifi->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spifi->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(spifi->reg_base))
return PTR_ERR(spifi->reg_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
spifi->dat_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(spifi->dat_base))
return PTR_ERR(spifi->dat_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
spifi->dir_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(spifi->dir_base))
return PTR_ERR(spifi->dir_base);
ctlr->mode_bits = data->mode_bits;
ctlr->bus_num = pdev->id;
ctlr->mem_ops = &gxp_spi_mem_ops;
ctlr->setup = gxp_spi_setup;
ctlr->num_chipselect = data->max_cs;
ctlr->dev.of_node = dev->of_node;
ret = devm_spi_register_controller(dev, ctlr);
if (ret) {
return dev_err_probe(&pdev->dev, ret,
"failed to register spi controller\n");
}
return 0;
}
static const struct gxp_spi_data gxp_spifi_data = {
.max_cs = 2,
.mode_bits = 0,
};
static const struct of_device_id gxp_spifi_match[] = {
{.compatible = "hpe,gxp-spifi", .data = &gxp_spifi_data },
{ /* null */ }
};
MODULE_DEVICE_TABLE(of, gxp_spifi_match);
static struct platform_driver gxp_spifi_driver = {
.probe = gxp_spifi_probe,
.driver = {
.name = "gxp-spifi",
.of_match_table = gxp_spifi_match,
},
};
module_platform_driver(gxp_spifi_driver);
MODULE_DESCRIPTION("HPE GXP SPI Flash Interface driver");
MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");
MODULE_LICENSE("GPL");
...@@ -74,6 +74,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = { ...@@ -74,6 +74,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0xa0a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0xa1a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0xa224), (unsigned long)&bxt_info },
......
...@@ -1236,8 +1236,8 @@ static int intel_spi_populate_chip(struct intel_spi *ispi) ...@@ -1236,8 +1236,8 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
return -ENOMEM; return -ENOMEM;
pdata->nr_parts = 1; pdata->nr_parts = 1;
pdata->parts = devm_kcalloc(ispi->dev, sizeof(*pdata->parts), pdata->parts = devm_kcalloc(ispi->dev, pdata->nr_parts,
pdata->nr_parts, GFP_KERNEL); sizeof(*pdata->parts), GFP_KERNEL);
if (!pdata->parts) if (!pdata->parts)
return -ENOMEM; return -ENOMEM;
......
This diff is collapsed.
...@@ -37,12 +37,6 @@ struct mpc52xx_psc_spi { ...@@ -37,12 +37,6 @@ struct mpc52xx_psc_spi {
struct mpc52xx_psc_fifo __iomem *fifo; struct mpc52xx_psc_fifo __iomem *fifo;
unsigned int irq; unsigned int irq;
u8 bits_per_word; u8 bits_per_word;
u8 busy;
struct work_struct work;
struct list_head queue;
spinlock_t lock;
struct completion done; struct completion done;
}; };
...@@ -198,69 +192,53 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, ...@@ -198,69 +192,53 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
return 0; return 0;
} }
static void mpc52xx_psc_spi_work(struct work_struct *work) int mpc52xx_psc_spi_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *m)
{ {
struct mpc52xx_psc_spi *mps = struct spi_device *spi;
container_of(work, struct mpc52xx_psc_spi, work); struct spi_transfer *t = NULL;
unsigned cs_change;
spin_lock_irq(&mps->lock); int status;
mps->busy = 1;
while (!list_empty(&mps->queue)) { spi = m->spi;
struct spi_message *m; cs_change = 1;
struct spi_device *spi; status = 0;
struct spi_transfer *t = NULL; list_for_each_entry (t, &m->transfers, transfer_list) {
unsigned cs_change; if (t->bits_per_word || t->speed_hz) {
int status; status = mpc52xx_psc_spi_transfer_setup(spi, t);
if (status < 0)
m = container_of(mps->queue.next, struct spi_message, queue);
list_del_init(&m->queue);
spin_unlock_irq(&mps->lock);
spi = m->spi;
cs_change = 1;
status = 0;
list_for_each_entry (t, &m->transfers, transfer_list) {
if (t->bits_per_word || t->speed_hz) {
status = mpc52xx_psc_spi_transfer_setup(spi, t);
if (status < 0)
break;
}
if (cs_change)
mpc52xx_psc_spi_activate_cs(spi);
cs_change = t->cs_change;
status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
if (status)
break; break;
m->actual_length += t->len; }
spi_transfer_delay_exec(t); if (cs_change)
mpc52xx_psc_spi_activate_cs(spi);
cs_change = t->cs_change;
if (cs_change) status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
mpc52xx_psc_spi_deactivate_cs(spi); if (status)
} break;
m->actual_length += t->len;
m->status = status; spi_transfer_delay_exec(t);
if (m->complete)
m->complete(m->context);
if (status || !cs_change) if (cs_change)
mpc52xx_psc_spi_deactivate_cs(spi); mpc52xx_psc_spi_deactivate_cs(spi);
}
mpc52xx_psc_spi_transfer_setup(spi, NULL); m->status = status;
if (status || !cs_change)
mpc52xx_psc_spi_deactivate_cs(spi);
spin_lock_irq(&mps->lock); mpc52xx_psc_spi_transfer_setup(spi, NULL);
}
mps->busy = 0; spi_finalize_current_message(ctlr);
spin_unlock_irq(&mps->lock);
return 0;
} }
static int mpc52xx_psc_spi_setup(struct spi_device *spi) static int mpc52xx_psc_spi_setup(struct spi_device *spi)
{ {
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc52xx_psc_spi_cs *cs = spi->controller_state; struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
unsigned long flags;
if (spi->bits_per_word%8) if (spi->bits_per_word%8)
return -EINVAL; return -EINVAL;
...@@ -275,28 +253,6 @@ static int mpc52xx_psc_spi_setup(struct spi_device *spi) ...@@ -275,28 +253,6 @@ static int mpc52xx_psc_spi_setup(struct spi_device *spi)
cs->bits_per_word = spi->bits_per_word; cs->bits_per_word = spi->bits_per_word;
cs->speed_hz = spi->max_speed_hz; cs->speed_hz = spi->max_speed_hz;
spin_lock_irqsave(&mps->lock, flags);
if (!mps->busy)
mpc52xx_psc_spi_deactivate_cs(spi);
spin_unlock_irqrestore(&mps->lock, flags);
return 0;
}
static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
struct spi_message *m)
{
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
unsigned long flags;
m->actual_length = 0;
m->status = -EINPROGRESS;
spin_lock_irqsave(&mps->lock, flags);
list_add_tail(&m->queue, &mps->queue);
schedule_work(&mps->work);
spin_unlock_irqrestore(&mps->lock, flags);
return 0; return 0;
} }
...@@ -391,7 +347,7 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, ...@@ -391,7 +347,7 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
master->num_chipselect = pdata->max_chipselect; master->num_chipselect = pdata->max_chipselect;
} }
master->setup = mpc52xx_psc_spi_setup; master->setup = mpc52xx_psc_spi_setup;
master->transfer = mpc52xx_psc_spi_transfer; master->transfer_one_message = mpc52xx_psc_spi_transfer_one_message;
master->cleanup = mpc52xx_psc_spi_cleanup; master->cleanup = mpc52xx_psc_spi_cleanup;
master->dev.of_node = dev->of_node; master->dev.of_node = dev->of_node;
...@@ -415,10 +371,7 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, ...@@ -415,10 +371,7 @@ static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
goto free_irq; goto free_irq;
} }
spin_lock_init(&mps->lock);
init_completion(&mps->done); init_completion(&mps->done);
INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
INIT_LIST_HEAD(&mps->queue);
ret = spi_register_master(master); ret = spi_register_master(master);
if (ret < 0) if (ret < 0)
...@@ -470,7 +423,6 @@ static int mpc52xx_psc_spi_of_remove(struct platform_device *op) ...@@ -470,7 +423,6 @@ static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
struct spi_master *master = spi_master_get(platform_get_drvdata(op)); struct spi_master *master = spi_master_get(platform_get_drvdata(op));
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master); struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
flush_work(&mps->work);
spi_unregister_master(master); spi_unregister_master(master);
free_irq(mps->irq, mps); free_irq(mps->irq, mps);
if (mps->psc) if (mps->psc)
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#define NPCM_FIU_UMA_DR1 0x34 #define NPCM_FIU_UMA_DR1 0x34
#define NPCM_FIU_UMA_DR2 0x38 #define NPCM_FIU_UMA_DR2 0x38
#define NPCM_FIU_UMA_DR3 0x3C #define NPCM_FIU_UMA_DR3 0x3C
#define NPCM_FIU_CFG 0x78
#define NPCM_FIU_MAX_REG_LIMIT 0x80 #define NPCM_FIU_MAX_REG_LIMIT 0x80
/* FIU Direct Read Configuration Register */ /* FIU Direct Read Configuration Register */
...@@ -151,6 +152,9 @@ ...@@ -151,6 +152,9 @@
#define NPCM_FIU_UMA_DR3_RB13 GENMASK(15, 8) #define NPCM_FIU_UMA_DR3_RB13 GENMASK(15, 8)
#define NPCM_FIU_UMA_DR3_RB12 GENMASK(7, 0) #define NPCM_FIU_UMA_DR3_RB12 GENMASK(7, 0)
/* FIU Configuration Register */
#define NPCM_FIU_CFG_FIU_FIX BIT(31)
/* FIU Read Mode */ /* FIU Read Mode */
enum { enum {
DRD_SINGLE_WIRE_MODE = 0, DRD_SINGLE_WIRE_MODE = 0,
...@@ -187,6 +191,7 @@ enum { ...@@ -187,6 +191,7 @@ enum {
FIU0 = 0, FIU0 = 0,
FIU3, FIU3,
FIUX, FIUX,
FIU1,
}; };
struct npcm_fiu_info { struct npcm_fiu_info {
...@@ -214,6 +219,21 @@ static const struct fiu_data npcm7xx_fiu_data = { ...@@ -214,6 +219,21 @@ static const struct fiu_data npcm7xx_fiu_data = {
.fiu_max = 3, .fiu_max = 3,
}; };
static const struct npcm_fiu_info npxm8xx_fiu_info[] = {
{.name = "FIU0", .fiu_id = FIU0,
.max_map_size = MAP_SIZE_128MB, .max_cs = 2},
{.name = "FIU3", .fiu_id = FIU3,
.max_map_size = MAP_SIZE_128MB, .max_cs = 4},
{.name = "FIUX", .fiu_id = FIUX,
.max_map_size = MAP_SIZE_16MB, .max_cs = 2},
{.name = "FIU1", .fiu_id = FIU1,
.max_map_size = MAP_SIZE_16MB, .max_cs = 4} };
static const struct fiu_data npxm8xx_fiu_data = {
.npcm_fiu_data_info = npxm8xx_fiu_info,
.fiu_max = 4,
};
struct npcm_fiu_spi; struct npcm_fiu_spi;
struct npcm_fiu_chip { struct npcm_fiu_chip {
...@@ -252,8 +272,7 @@ static void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu, ...@@ -252,8 +272,7 @@ static void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu,
fiu->drd_op.addr.buswidth = op->addr.buswidth; fiu->drd_op.addr.buswidth = op->addr.buswidth;
regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
NPCM_FIU_DRD_CFG_DBW, NPCM_FIU_DRD_CFG_DBW,
((op->dummy.nbytes * ilog2(op->addr.buswidth)) / BITS_PER_BYTE) op->dummy.nbytes << NPCM_FIU_DRD_DBW_SHIFT);
<< NPCM_FIU_DRD_DBW_SHIFT);
fiu->drd_op.dummy.nbytes = op->dummy.nbytes; fiu->drd_op.dummy.nbytes = op->dummy.nbytes;
regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG,
NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode); NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode);
...@@ -625,6 +644,10 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) ...@@ -625,6 +644,10 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc)
regmap_update_bits(gcr_regmap, NPCM7XX_INTCR3_OFFSET, regmap_update_bits(gcr_regmap, NPCM7XX_INTCR3_OFFSET,
NPCM7XX_INTCR3_FIU_FIX, NPCM7XX_INTCR3_FIU_FIX,
NPCM7XX_INTCR3_FIU_FIX); NPCM7XX_INTCR3_FIU_FIX);
} else {
regmap_update_bits(fiu->regmap, NPCM_FIU_CFG,
NPCM_FIU_CFG_FIU_FIX,
NPCM_FIU_CFG_FIU_FIX);
} }
if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) { if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) {
...@@ -665,6 +688,7 @@ static const struct spi_controller_mem_ops npcm_fiu_mem_ops = { ...@@ -665,6 +688,7 @@ static const struct spi_controller_mem_ops npcm_fiu_mem_ops = {
static const struct of_device_id npcm_fiu_dt_ids[] = { static const struct of_device_id npcm_fiu_dt_ids[] = {
{ .compatible = "nuvoton,npcm750-fiu", .data = &npcm7xx_fiu_data }, { .compatible = "nuvoton,npcm750-fiu", .data = &npcm7xx_fiu_data },
{ .compatible = "nuvoton,npcm845-fiu", .data = &npxm8xx_fiu_data },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -1404,6 +1404,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { ...@@ -1404,6 +1404,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
{ PCI_VDEVICE(INTEL, 0x7aab), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x7aab), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x7af9), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x7af9), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x7afb), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x7afb), LPSS_CNL_SSP },
/* MTL-P */
{ PCI_VDEVICE(INTEL, 0x7e27), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x7e30), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x7e46), LPSS_CNL_SSP },
/* CNL-LP */ /* CNL-LP */
{ PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x9daa), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x9dab), LPSS_CNL_SSP }, { PCI_VDEVICE(INTEL, 0x9dab), LPSS_CNL_SSP },
......
This diff is collapsed.
...@@ -73,11 +73,8 @@ struct spi_sh_data { ...@@ -73,11 +73,8 @@ struct spi_sh_data {
void __iomem *addr; void __iomem *addr;
int irq; int irq;
struct spi_master *master; struct spi_master *master;
struct list_head queue;
struct work_struct ws;
unsigned long cr1; unsigned long cr1;
wait_queue_head_t wait; wait_queue_head_t wait;
spinlock_t lock;
int width; int width;
}; };
...@@ -271,47 +268,39 @@ static int spi_sh_receive(struct spi_sh_data *ss, struct spi_message *mesg, ...@@ -271,47 +268,39 @@ static int spi_sh_receive(struct spi_sh_data *ss, struct spi_message *mesg,
return 0; return 0;
} }
static void spi_sh_work(struct work_struct *work) static int spi_sh_transfer_one_message(struct spi_controller *ctlr,
struct spi_message *mesg)
{ {
struct spi_sh_data *ss = container_of(work, struct spi_sh_data, ws); struct spi_sh_data *ss = spi_controller_get_devdata(ctlr);
struct spi_message *mesg;
struct spi_transfer *t; struct spi_transfer *t;
unsigned long flags;
int ret; int ret;
pr_debug("%s: enter\n", __func__); pr_debug("%s: enter\n", __func__);
spin_lock_irqsave(&ss->lock, flags); spi_sh_clear_bit(ss, SPI_SH_SSA, SPI_SH_CR1);
while (!list_empty(&ss->queue)) {
mesg = list_entry(ss->queue.next, struct spi_message, queue);
list_del_init(&mesg->queue);
spin_unlock_irqrestore(&ss->lock, flags);
list_for_each_entry(t, &mesg->transfers, transfer_list) {
pr_debug("tx_buf = %p, rx_buf = %p\n",
t->tx_buf, t->rx_buf);
pr_debug("len = %d, delay.value = %d\n",
t->len, t->delay.value);
if (t->tx_buf) {
ret = spi_sh_send(ss, mesg, t);
if (ret < 0)
goto error;
}
if (t->rx_buf) {
ret = spi_sh_receive(ss, mesg, t);
if (ret < 0)
goto error;
}
mesg->actual_length += t->len;
}
spin_lock_irqsave(&ss->lock, flags);
mesg->status = 0; list_for_each_entry(t, &mesg->transfers, transfer_list) {
if (mesg->complete) pr_debug("tx_buf = %p, rx_buf = %p\n",
mesg->complete(mesg->context); t->tx_buf, t->rx_buf);
pr_debug("len = %d, delay.value = %d\n",
t->len, t->delay.value);
if (t->tx_buf) {
ret = spi_sh_send(ss, mesg, t);
if (ret < 0)
goto error;
}
if (t->rx_buf) {
ret = spi_sh_receive(ss, mesg, t);
if (ret < 0)
goto error;
}
mesg->actual_length += t->len;
} }
mesg->status = 0;
spi_finalize_current_message(ctlr);
clear_fifo(ss); clear_fifo(ss);
spi_sh_set_bit(ss, SPI_SH_SSD, SPI_SH_CR1); spi_sh_set_bit(ss, SPI_SH_SSD, SPI_SH_CR1);
udelay(100); udelay(100);
...@@ -321,12 +310,11 @@ static void spi_sh_work(struct work_struct *work) ...@@ -321,12 +310,11 @@ static void spi_sh_work(struct work_struct *work)
clear_fifo(ss); clear_fifo(ss);
spin_unlock_irqrestore(&ss->lock, flags); return 0;
return;
error: error:
mesg->status = ret; mesg->status = ret;
spi_finalize_current_message(ctlr);
if (mesg->complete) if (mesg->complete)
mesg->complete(mesg->context); mesg->complete(mesg->context);
...@@ -334,6 +322,7 @@ static void spi_sh_work(struct work_struct *work) ...@@ -334,6 +322,7 @@ static void spi_sh_work(struct work_struct *work)
SPI_SH_CR1); SPI_SH_CR1);
clear_fifo(ss); clear_fifo(ss);
return ret;
} }
static int spi_sh_setup(struct spi_device *spi) static int spi_sh_setup(struct spi_device *spi)
...@@ -355,29 +344,6 @@ static int spi_sh_setup(struct spi_device *spi) ...@@ -355,29 +344,6 @@ static int spi_sh_setup(struct spi_device *spi)
return 0; return 0;
} }
static int spi_sh_transfer(struct spi_device *spi, struct spi_message *mesg)
{
struct spi_sh_data *ss = spi_master_get_devdata(spi->master);
unsigned long flags;
pr_debug("%s: enter\n", __func__);
pr_debug("\tmode = %02x\n", spi->mode);
spin_lock_irqsave(&ss->lock, flags);
mesg->actual_length = 0;
mesg->status = -EINPROGRESS;
spi_sh_clear_bit(ss, SPI_SH_SSA, SPI_SH_CR1);
list_add_tail(&mesg->queue, &ss->queue);
schedule_work(&ss->ws);
spin_unlock_irqrestore(&ss->lock, flags);
return 0;
}
static void spi_sh_cleanup(struct spi_device *spi) static void spi_sh_cleanup(struct spi_device *spi)
{ {
struct spi_sh_data *ss = spi_master_get_devdata(spi->master); struct spi_sh_data *ss = spi_master_get_devdata(spi->master);
...@@ -416,7 +382,6 @@ static int spi_sh_remove(struct platform_device *pdev) ...@@ -416,7 +382,6 @@ static int spi_sh_remove(struct platform_device *pdev)
struct spi_sh_data *ss = platform_get_drvdata(pdev); struct spi_sh_data *ss = platform_get_drvdata(pdev);
spi_unregister_master(ss->master); spi_unregister_master(ss->master);
flush_work(&ss->ws);
free_irq(ss->irq, ss); free_irq(ss->irq, ss);
return 0; return 0;
...@@ -467,9 +432,6 @@ static int spi_sh_probe(struct platform_device *pdev) ...@@ -467,9 +432,6 @@ static int spi_sh_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "ioremap error.\n"); dev_err(&pdev->dev, "ioremap error.\n");
return -ENOMEM; return -ENOMEM;
} }
INIT_LIST_HEAD(&ss->queue);
spin_lock_init(&ss->lock);
INIT_WORK(&ss->ws, spi_sh_work);
init_waitqueue_head(&ss->wait); init_waitqueue_head(&ss->wait);
ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss); ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss);
...@@ -481,7 +443,7 @@ static int spi_sh_probe(struct platform_device *pdev) ...@@ -481,7 +443,7 @@ static int spi_sh_probe(struct platform_device *pdev)
master->num_chipselect = 2; master->num_chipselect = 2;
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->setup = spi_sh_setup; master->setup = spi_sh_setup;
master->transfer = spi_sh_transfer; master->transfer_one_message = spi_sh_transfer_one_message;
master->cleanup = spi_sh_cleanup; master->cleanup = spi_sh_cleanup;
ret = spi_register_master(master); ret = spi_register_master(master);
......
...@@ -427,6 +427,44 @@ static int sifive_spi_remove(struct platform_device *pdev) ...@@ -427,6 +427,44 @@ static int sifive_spi_remove(struct platform_device *pdev)
return 0; return 0;
} }
static int sifive_spi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sifive_spi *spi = spi_master_get_devdata(master);
int ret;
ret = spi_master_suspend(master);
if (ret)
return ret;
/* Disable all the interrupts just in case */
sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
clk_disable_unprepare(spi->clk);
return ret;
}
static int sifive_spi_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sifive_spi *spi = spi_master_get_devdata(master);
int ret;
ret = clk_prepare_enable(spi->clk);
if (ret)
return ret;
ret = spi_master_resume(master);
if (ret)
clk_disable_unprepare(spi->clk);
return ret;
}
static DEFINE_SIMPLE_DEV_PM_OPS(sifive_spi_pm_ops,
sifive_spi_suspend, sifive_spi_resume);
static const struct of_device_id sifive_spi_of_match[] = { static const struct of_device_id sifive_spi_of_match[] = {
{ .compatible = "sifive,spi0", }, { .compatible = "sifive,spi0", },
{} {}
...@@ -438,6 +476,7 @@ static struct platform_driver sifive_spi_driver = { ...@@ -438,6 +476,7 @@ static struct platform_driver sifive_spi_driver = {
.remove = sifive_spi_remove, .remove = sifive_spi_remove,
.driver = { .driver = {
.name = SIFIVE_SPI_DRIVER_NAME, .name = SIFIVE_SPI_DRIVER_NAME,
.pm = &sifive_spi_pm_ops,
.of_match_table = sifive_spi_of_match, .of_match_table = sifive_spi_of_match,
}, },
}; };
......
...@@ -299,8 +299,7 @@ static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi) ...@@ -299,8 +299,7 @@ static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
STM32_BUSY_TIMEOUT_US); STM32_BUSY_TIMEOUT_US);
} }
static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi)
const struct spi_mem_op *op)
{ {
u32 cr, sr; u32 cr, sr;
int err = 0; int err = 0;
...@@ -331,8 +330,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, ...@@ -331,8 +330,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi,
return err; return err;
} }
static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi, static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi)
const struct spi_mem_op *op)
{ {
u32 cr; u32 cr;
...@@ -349,7 +347,7 @@ static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi, ...@@ -349,7 +347,7 @@ static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi,
return 0; return 0;
} }
static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth) static int stm32_qspi_get_mode(u8 buswidth)
{ {
if (buswidth == 4) if (buswidth == 4)
return CCR_BUSWIDTH_4; return CCR_BUSWIDTH_4;
...@@ -382,11 +380,11 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -382,11 +380,11 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
ccr = qspi->fmode; ccr = qspi->fmode;
ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode); ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode);
ccr |= FIELD_PREP(CCR_IMODE_MASK, ccr |= FIELD_PREP(CCR_IMODE_MASK,
stm32_qspi_get_mode(qspi, op->cmd.buswidth)); stm32_qspi_get_mode(op->cmd.buswidth));
if (op->addr.nbytes) { if (op->addr.nbytes) {
ccr |= FIELD_PREP(CCR_ADMODE_MASK, ccr |= FIELD_PREP(CCR_ADMODE_MASK,
stm32_qspi_get_mode(qspi, op->addr.buswidth)); stm32_qspi_get_mode(op->addr.buswidth));
ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1); ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1);
} }
...@@ -396,7 +394,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -396,7 +394,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
if (op->data.nbytes) { if (op->data.nbytes) {
ccr |= FIELD_PREP(CCR_DMODE_MASK, ccr |= FIELD_PREP(CCR_DMODE_MASK,
stm32_qspi_get_mode(qspi, op->data.buswidth)); stm32_qspi_get_mode(op->data.buswidth));
} }
writel_relaxed(ccr, qspi->io_base + QSPI_CCR); writel_relaxed(ccr, qspi->io_base + QSPI_CCR);
...@@ -405,7 +403,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -405,7 +403,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR); writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR);
if (qspi->fmode == CCR_FMODE_APM) if (qspi->fmode == CCR_FMODE_APM)
err_poll_status = stm32_qspi_wait_poll_status(qspi, op); err_poll_status = stm32_qspi_wait_poll_status(qspi);
err = stm32_qspi_tx(qspi, op); err = stm32_qspi_tx(qspi, op);
...@@ -420,7 +418,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -420,7 +418,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op)
goto abort; goto abort;
/* wait end of tx in indirect mode */ /* wait end of tx in indirect mode */
err = stm32_qspi_wait_cmd(qspi, op); err = stm32_qspi_wait_cmd(qspi);
if (err) if (err)
goto abort; goto abort;
......
...@@ -783,6 +783,7 @@ static int __maybe_unused synquacer_spi_resume(struct device *dev) ...@@ -783,6 +783,7 @@ static int __maybe_unused synquacer_spi_resume(struct device *dev)
ret = synquacer_spi_enable(master); ret = synquacer_spi_enable(master);
if (ret) { if (ret) {
clk_disable_unprepare(sspi->clk);
dev_err(dev, "failed to enable spi (%d)\n", ret); dev_err(dev, "failed to enable spi (%d)\n", ret);
return ret; return ret;
} }
......
...@@ -1136,7 +1136,7 @@ static int tegra_slink_probe(struct platform_device *pdev) ...@@ -1136,7 +1136,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
static int tegra_slink_remove(struct platform_device *pdev) static int tegra_slink_remove(struct platform_device *pdev)
{ {
struct spi_master *master = platform_get_drvdata(pdev); struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct tegra_slink_data *tspi = spi_master_get_devdata(master); struct tegra_slink_data *tspi = spi_master_get_devdata(master);
spi_unregister_master(master); spi_unregister_master(master);
...@@ -1151,6 +1151,7 @@ static int tegra_slink_remove(struct platform_device *pdev) ...@@ -1151,6 +1151,7 @@ static int tegra_slink_remove(struct platform_device *pdev)
if (tspi->rx_dma_chan) if (tspi->rx_dma_chan)
tegra_slink_deinit_dma_param(tspi, true); tegra_slink_deinit_dma_param(tspi, true);
spi_master_put(master);
return 0; return 0;
} }
......
...@@ -37,6 +37,16 @@ ...@@ -37,6 +37,16 @@
#define QSPI_RX_EN BIT(12) #define QSPI_RX_EN BIT(12)
#define QSPI_CS_SW_VAL BIT(20) #define QSPI_CS_SW_VAL BIT(20)
#define QSPI_CS_SW_HW BIT(21) #define QSPI_CS_SW_HW BIT(21)
#define QSPI_CS_POL_INACTIVE(n) (1 << (22 + (n)))
#define QSPI_CS_POL_INACTIVE_MASK (0xF << 22)
#define QSPI_CS_SEL_0 (0 << 26)
#define QSPI_CS_SEL_1 (1 << 26)
#define QSPI_CS_SEL_2 (2 << 26)
#define QSPI_CS_SEL_3 (3 << 26)
#define QSPI_CS_SEL_MASK (3 << 26)
#define QSPI_CS_SEL(x) (((x) & 0x3) << 26)
#define QSPI_CONTROL_MODE_0 (0 << 28) #define QSPI_CONTROL_MODE_0 (0 << 28)
#define QSPI_CONTROL_MODE_3 (3 << 28) #define QSPI_CONTROL_MODE_3 (3 << 28)
#define QSPI_CONTROL_MODE_MASK (3 << 28) #define QSPI_CONTROL_MODE_MASK (3 << 28)
...@@ -154,6 +164,7 @@ ...@@ -154,6 +164,7 @@
struct tegra_qspi_soc_data { struct tegra_qspi_soc_data {
bool has_dma; bool has_dma;
bool cmb_xfer_capable; bool cmb_xfer_capable;
unsigned int cs_count;
}; };
struct tegra_qspi_client_data { struct tegra_qspi_client_data {
...@@ -812,6 +823,7 @@ static u32 tegra_qspi_setup_transfer_one(struct spi_device *spi, struct spi_tran ...@@ -812,6 +823,7 @@ static u32 tegra_qspi_setup_transfer_one(struct spi_device *spi, struct spi_tran
tegra_qspi_mask_clear_irq(tqspi); tegra_qspi_mask_clear_irq(tqspi);
command1 = tqspi->def_command1_reg; command1 = tqspi->def_command1_reg;
command1 |= QSPI_CS_SEL(spi->chip_select);
command1 |= QSPI_BIT_LENGTH(bits_per_word - 1); command1 |= QSPI_BIT_LENGTH(bits_per_word - 1);
command1 &= ~QSPI_CONTROL_MODE_MASK; command1 &= ~QSPI_CONTROL_MODE_MASK;
...@@ -941,10 +953,11 @@ static int tegra_qspi_setup(struct spi_device *spi) ...@@ -941,10 +953,11 @@ static int tegra_qspi_setup(struct spi_device *spi)
/* keep default cs state to inactive */ /* keep default cs state to inactive */
val = tqspi->def_command1_reg; val = tqspi->def_command1_reg;
val |= QSPI_CS_SEL(spi->chip_select);
if (spi->mode & SPI_CS_HIGH) if (spi->mode & SPI_CS_HIGH)
val &= ~QSPI_CS_SW_VAL; val &= ~QSPI_CS_POL_INACTIVE(spi->chip_select);
else else
val |= QSPI_CS_SW_VAL; val |= QSPI_CS_POL_INACTIVE(spi->chip_select);
tqspi->def_command1_reg = val; tqspi->def_command1_reg = val;
tegra_qspi_writel(tqspi, tqspi->def_command1_reg, QSPI_COMMAND1); tegra_qspi_writel(tqspi, tqspi->def_command1_reg, QSPI_COMMAND1);
...@@ -1425,16 +1438,25 @@ static irqreturn_t tegra_qspi_isr_thread(int irq, void *context_data) ...@@ -1425,16 +1438,25 @@ static irqreturn_t tegra_qspi_isr_thread(int irq, void *context_data)
static struct tegra_qspi_soc_data tegra210_qspi_soc_data = { static struct tegra_qspi_soc_data tegra210_qspi_soc_data = {
.has_dma = true, .has_dma = true,
.cmb_xfer_capable = false, .cmb_xfer_capable = false,
.cs_count = 1,
}; };
static struct tegra_qspi_soc_data tegra186_qspi_soc_data = { static struct tegra_qspi_soc_data tegra186_qspi_soc_data = {
.has_dma = true, .has_dma = true,
.cmb_xfer_capable = true, .cmb_xfer_capable = true,
.cs_count = 1,
}; };
static struct tegra_qspi_soc_data tegra234_qspi_soc_data = { static struct tegra_qspi_soc_data tegra234_qspi_soc_data = {
.has_dma = false, .has_dma = false,
.cmb_xfer_capable = true, .cmb_xfer_capable = true,
.cs_count = 1,
};
static struct tegra_qspi_soc_data tegra241_qspi_soc_data = {
.has_dma = false,
.cmb_xfer_capable = true,
.cs_count = 4,
}; };
static const struct of_device_id tegra_qspi_of_match[] = { static const struct of_device_id tegra_qspi_of_match[] = {
...@@ -1450,6 +1472,9 @@ static const struct of_device_id tegra_qspi_of_match[] = { ...@@ -1450,6 +1472,9 @@ static const struct of_device_id tegra_qspi_of_match[] = {
}, { }, {
.compatible = "nvidia,tegra234-qspi", .compatible = "nvidia,tegra234-qspi",
.data = &tegra234_qspi_soc_data, .data = &tegra234_qspi_soc_data,
}, {
.compatible = "nvidia,tegra241-qspi",
.data = &tegra241_qspi_soc_data,
}, },
{} {}
}; };
...@@ -1467,6 +1492,9 @@ static const struct acpi_device_id tegra_qspi_acpi_match[] = { ...@@ -1467,6 +1492,9 @@ static const struct acpi_device_id tegra_qspi_acpi_match[] = {
}, { }, {
.id = "NVDA1413", .id = "NVDA1413",
.driver_data = (kernel_ulong_t)&tegra234_qspi_soc_data, .driver_data = (kernel_ulong_t)&tegra234_qspi_soc_data,
}, {
.id = "NVDA1513",
.driver_data = (kernel_ulong_t)&tegra241_qspi_soc_data,
}, },
{} {}
}; };
...@@ -1506,6 +1534,7 @@ static int tegra_qspi_probe(struct platform_device *pdev) ...@@ -1506,6 +1534,7 @@ static int tegra_qspi_probe(struct platform_device *pdev)
spin_lock_init(&tqspi->lock); spin_lock_init(&tqspi->lock);
tqspi->soc_data = device_get_match_data(&pdev->dev); tqspi->soc_data = device_get_match_data(&pdev->dev);
master->num_chipselect = tqspi->soc_data->cs_count;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tqspi->base = devm_ioremap_resource(&pdev->dev, r); tqspi->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(tqspi->base)) if (IS_ERR(tqspi->base))
......
...@@ -57,7 +57,6 @@ struct ti_qspi { ...@@ -57,7 +57,6 @@ struct ti_qspi {
void *rx_bb_addr; void *rx_bb_addr;
struct dma_chan *rx_chan; struct dma_chan *rx_chan;
u32 spi_max_frequency;
u32 cmd; u32 cmd;
u32 dc; u32 dc;
...@@ -140,37 +139,19 @@ static inline void ti_qspi_write(struct ti_qspi *qspi, ...@@ -140,37 +139,19 @@ static inline void ti_qspi_write(struct ti_qspi *qspi,
static int ti_qspi_setup(struct spi_device *spi) static int ti_qspi_setup(struct spi_device *spi)
{ {
struct ti_qspi *qspi = spi_master_get_devdata(spi->master); struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; int ret;
int clk_div = 0, ret;
u32 clk_ctrl_reg, clk_rate, clk_mask;
if (spi->master->busy) { if (spi->master->busy) {
dev_dbg(qspi->dev, "master busy doing other transfers\n"); dev_dbg(qspi->dev, "master busy doing other transfers\n");
return -EBUSY; return -EBUSY;
} }
if (!qspi->spi_max_frequency) { if (!qspi->master->max_speed_hz) {
dev_err(qspi->dev, "spi max frequency not defined\n"); dev_err(qspi->dev, "spi max frequency not defined\n");
return -EINVAL; return -EINVAL;
} }
clk_rate = clk_get_rate(qspi->fclk); spi->max_speed_hz = min(spi->max_speed_hz, qspi->master->max_speed_hz);
clk_div = DIV_ROUND_UP(clk_rate, qspi->spi_max_frequency) - 1;
if (clk_div < 0) {
dev_dbg(qspi->dev, "clock divider < 0, using /1 divider\n");
return -EINVAL;
}
if (clk_div > QSPI_CLK_DIV_MAX) {
dev_dbg(qspi->dev, "clock divider >%d , using /%d divider\n",
QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1);
return -EINVAL;
}
dev_dbg(qspi->dev, "hz: %d, clock divider %d\n",
qspi->spi_max_frequency, clk_div);
ret = pm_runtime_resume_and_get(qspi->dev); ret = pm_runtime_resume_and_get(qspi->dev);
if (ret < 0) { if (ret < 0) {
...@@ -178,18 +159,6 @@ static int ti_qspi_setup(struct spi_device *spi) ...@@ -178,18 +159,6 @@ static int ti_qspi_setup(struct spi_device *spi)
return ret; return ret;
} }
clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG);
clk_ctrl_reg &= ~QSPI_CLK_EN;
/* disable SCLK */
ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG);
/* enable SCLK */
clk_mask = QSPI_CLK_EN | clk_div;
ti_qspi_write(qspi, clk_mask, QSPI_SPI_CLOCK_CNTRL_REG);
ctx_reg->clkctrl = clk_mask;
pm_runtime_mark_last_busy(qspi->dev); pm_runtime_mark_last_busy(qspi->dev);
ret = pm_runtime_put_autosuspend(qspi->dev); ret = pm_runtime_put_autosuspend(qspi->dev);
if (ret < 0) { if (ret < 0) {
...@@ -200,6 +169,37 @@ static int ti_qspi_setup(struct spi_device *spi) ...@@ -200,6 +169,37 @@ static int ti_qspi_setup(struct spi_device *spi)
return 0; return 0;
} }
static void ti_qspi_setup_clk(struct ti_qspi *qspi, u32 speed_hz)
{
struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
int clk_div;
u32 clk_ctrl_reg, clk_rate, clk_ctrl_new;
clk_rate = clk_get_rate(qspi->fclk);
clk_div = DIV_ROUND_UP(clk_rate, speed_hz) - 1;
clk_div = clamp(clk_div, 0, QSPI_CLK_DIV_MAX);
dev_dbg(qspi->dev, "hz: %d, clock divider %d\n", speed_hz, clk_div);
pm_runtime_resume_and_get(qspi->dev);
clk_ctrl_new = QSPI_CLK_EN | clk_div;
if (ctx_reg->clkctrl != clk_ctrl_new) {
clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG);
clk_ctrl_reg &= ~QSPI_CLK_EN;
/* disable SCLK */
ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG);
/* enable SCLK */
ti_qspi_write(qspi, clk_ctrl_new, QSPI_SPI_CLOCK_CNTRL_REG);
ctx_reg->clkctrl = clk_ctrl_new;
}
pm_runtime_mark_last_busy(qspi->dev);
pm_runtime_put_autosuspend(qspi->dev);
}
static void ti_qspi_restore_ctx(struct ti_qspi *qspi) static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
{ {
struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
...@@ -623,8 +623,10 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem, ...@@ -623,8 +623,10 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
mutex_lock(&qspi->list_lock); mutex_lock(&qspi->list_lock);
if (!qspi->mmap_enabled || qspi->current_cs != mem->spi->chip_select) if (!qspi->mmap_enabled || qspi->current_cs != mem->spi->chip_select) {
ti_qspi_setup_clk(qspi, mem->spi->max_speed_hz);
ti_qspi_enable_memory_map(mem->spi); ti_qspi_enable_memory_map(mem->spi);
}
ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth, ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
op->addr.nbytes, op->dummy.nbytes); op->addr.nbytes, op->dummy.nbytes);
...@@ -701,6 +703,7 @@ static int ti_qspi_start_transfer_one(struct spi_master *master, ...@@ -701,6 +703,7 @@ static int ti_qspi_start_transfer_one(struct spi_master *master,
wlen = t->bits_per_word >> 3; wlen = t->bits_per_word >> 3;
transfer_len_words = min(t->len / wlen, frame_len_words); transfer_len_words = min(t->len / wlen, frame_len_words);
ti_qspi_setup_clk(qspi, t->speed_hz);
ret = qspi_transfer_msg(qspi, t, transfer_len_words * wlen); ret = qspi_transfer_msg(qspi, t, transfer_len_words * wlen);
if (ret) { if (ret) {
dev_dbg(qspi->dev, "transfer message failed\n"); dev_dbg(qspi->dev, "transfer message failed\n");
...@@ -851,7 +854,7 @@ static int ti_qspi_probe(struct platform_device *pdev) ...@@ -851,7 +854,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
if (!of_property_read_u32(np, "spi-max-frequency", &max_freq)) if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
qspi->spi_max_frequency = max_freq; master->max_speed_hz = max_freq;
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask); dma_cap_set(DMA_MEMCPY, mask);
......
...@@ -455,35 +455,10 @@ static void pch_spi_reset(struct spi_master *master) ...@@ -455,35 +455,10 @@ static void pch_spi_reset(struct spi_master *master)
static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
{ {
struct spi_transfer *transfer;
struct pch_spi_data *data = spi_master_get_devdata(pspi->master); struct pch_spi_data *data = spi_master_get_devdata(pspi->master);
int retval; int retval;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&data->lock, flags);
/* validate Tx/Rx buffers and Transfer length */
list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
if (!transfer->tx_buf && !transfer->rx_buf) {
dev_err(&pspi->dev,
"%s Tx and Rx buffer NULL\n", __func__);
retval = -EINVAL;
goto err_return_spinlock;
}
if (!transfer->len) {
dev_err(&pspi->dev, "%s Transfer length invalid\n",
__func__);
retval = -EINVAL;
goto err_return_spinlock;
}
dev_dbg(&pspi->dev,
"%s Tx/Rx buffer valid. Transfer length valid\n",
__func__);
}
spin_unlock_irqrestore(&data->lock, flags);
/* We won't process any messages if we have been asked to terminate */ /* We won't process any messages if we have been asked to terminate */
if (data->status == STATUS_EXITING) { if (data->status == STATUS_EXITING) {
dev_err(&pspi->dev, "%s status = STATUS_EXITING.\n", __func__); dev_err(&pspi->dev, "%s status = STATUS_EXITING.\n", __func__);
...@@ -518,10 +493,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) ...@@ -518,10 +493,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
err_out: err_out:
dev_dbg(&pspi->dev, "%s RETURN=%d\n", __func__, retval); dev_dbg(&pspi->dev, "%s RETURN=%d\n", __func__, retval);
return retval; return retval;
err_return_spinlock:
dev_dbg(&pspi->dev, "%s RETURN=%d\n", __func__, retval);
spin_unlock_irqrestore(&data->lock, flags);
return retval;
} }
static inline void pch_spi_select_chip(struct pch_spi_data *data, static inline void pch_spi_select_chip(struct pch_spi_data *data,
...@@ -1365,6 +1336,7 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev) ...@@ -1365,6 +1336,7 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
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->max_speed_hz = PCH_MAX_BAUDRATE; master->max_speed_hz = PCH_MAX_BAUDRATE;
master->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX;
data->board_dat = board_dat; data->board_dat = board_dat;
data->plat_dev = plat_dev; data->plat_dev = plat_dev;
......
...@@ -134,6 +134,8 @@ ...@@ -134,6 +134,8 @@
#define GQSPI_DMA_UNALIGN 0x3 #define GQSPI_DMA_UNALIGN 0x3
#define GQSPI_DEFAULT_NUM_CS 1 /* Default number of chip selects */ #define GQSPI_DEFAULT_NUM_CS 1 /* Default number of chip selects */
#define GQSPI_MAX_NUM_CS 2 /* Maximum number of chip selects */
#define SPI_AUTOSUSPEND_TIMEOUT 3000 #define SPI_AUTOSUSPEND_TIMEOUT 3000
enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA}; enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
...@@ -363,8 +365,13 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) ...@@ -363,8 +365,13 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
genfifoentry |= GQSPI_GENFIFO_MODE_SPI; genfifoentry |= GQSPI_GENFIFO_MODE_SPI;
if (!is_high) { if (!is_high) {
xqspi->genfifobus = GQSPI_GENFIFO_BUS_LOWER; if (!qspi->chip_select) {
xqspi->genfifocs = GQSPI_GENFIFO_CS_LOWER; xqspi->genfifobus = GQSPI_GENFIFO_BUS_LOWER;
xqspi->genfifocs = GQSPI_GENFIFO_CS_LOWER;
} else {
xqspi->genfifobus = GQSPI_GENFIFO_BUS_UPPER;
xqspi->genfifocs = GQSPI_GENFIFO_CS_UPPER;
}
genfifoentry |= xqspi->genfifobus; genfifoentry |= xqspi->genfifobus;
genfifoentry |= xqspi->genfifocs; genfifoentry |= xqspi->genfifocs;
genfifoentry |= GQSPI_GENFIFO_CS_SETUP; genfifoentry |= GQSPI_GENFIFO_CS_SETUP;
...@@ -1099,6 +1106,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) ...@@ -1099,6 +1106,7 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
struct zynqmp_qspi *xqspi; struct zynqmp_qspi *xqspi;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
u32 num_cs;
ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); ctlr = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
if (!ctlr) if (!ctlr)
...@@ -1176,8 +1184,19 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) ...@@ -1176,8 +1184,19 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
if (ret) if (ret)
goto clk_dis_all; goto clk_dis_all;
ret = of_property_read_u32(np, "num-cs", &num_cs);
if (ret < 0) {
ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS;
} else if (num_cs > GQSPI_MAX_NUM_CS) {
ret = -EINVAL;
dev_err(&pdev->dev, "only %d chip selects are available\n",
GQSPI_MAX_NUM_CS);
goto clk_dis_all;
} else {
ctlr->num_chipselect = num_cs;
}
ctlr->bits_per_word_mask = SPI_BPW_MASK(8); ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->num_chipselect = GQSPI_DEFAULT_NUM_CS;
ctlr->mem_ops = &zynqmp_qspi_mem_ops; ctlr->mem_ops = &zynqmp_qspi_mem_ops;
ctlr->setup = zynqmp_qspi_setup_op; ctlr->setup = zynqmp_qspi_setup_op;
ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2; ctlr->max_speed_hz = clk_get_rate(xqspi->refclk) / 2;
......
This diff is collapsed.
This diff is collapsed.
...@@ -417,6 +417,7 @@ int main(int argc, char *argv[]) ...@@ -417,6 +417,7 @@ int main(int argc, char *argv[])
{ {
int ret = 0; int ret = 0;
int fd; int fd;
uint32_t request;
parse_opts(argc, argv); parse_opts(argc, argv);
...@@ -430,13 +431,23 @@ int main(int argc, char *argv[]) ...@@ -430,13 +431,23 @@ int main(int argc, char *argv[])
/* /*
* spi mode * spi mode
*/ */
/* WR is make a request to assign 'mode' */
request = mode;
ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode); ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1) if (ret == -1)
pabort("can't set spi mode"); pabort("can't set spi mode");
/* RD is read what mode the device actually is in */
ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode); ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1) if (ret == -1)
pabort("can't get spi mode"); pabort("can't get spi mode");
/* Drivers can reject some mode bits without returning an error.
* Read the current value to identify what mode it is in, and if it
* differs from the requested mode, warn the user.
*/
if (request != mode)
printf("WARNING device does not support requested mode 0x%x\n",
request);
/* /*
* bits per word * bits per word
......
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