mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge remote-tracking branch 'spi/for-5.14' into spi-next
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
Renesas RZ/N1 SPI Controller
|
||||
|
||||
This controller is based on the Synopsys DW Synchronous Serial Interface and
|
||||
inherits all properties defined in snps,dw-apb-ssi.txt except for the
|
||||
compatible property.
|
||||
|
||||
Required properties:
|
||||
- compatible : The device specific string followed by the generic RZ/N1 string.
|
||||
Therefore it must be one of:
|
||||
"renesas,r9a06g032-spi", "renesas,rzn1-spi"
|
||||
"renesas,r9a06g033-spi", "renesas,rzn1-spi"
|
||||
@@ -67,6 +67,12 @@ properties:
|
||||
const: baikal,bt1-sys-ssi
|
||||
- description: Canaan Kendryte K210 SoS SPI Controller
|
||||
const: canaan,k210-spi
|
||||
- description: Renesas RZ/N1 SPI Controller
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r9a06g032-spi # RZ/N1D
|
||||
- renesas,r9a06g033-spi # RZ/N1S
|
||||
- const: renesas,rzn1-spi # RZ/N1
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
Cadence SPI controller Device Tree Bindings
|
||||
-------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "cdns,spi-r1p6" or "xlnx,zynq-spi-r1p6".
|
||||
- reg : Physical base address and size of SPI registers map.
|
||||
- interrupts : Property with a value describing the interrupt
|
||||
number.
|
||||
- clock-names : List of input clock names - "ref_clk", "pclk"
|
||||
(See clock bindings for details).
|
||||
- clocks : Clock phandles (see clock bindings for details).
|
||||
|
||||
Optional properties:
|
||||
- num-cs : Number of chip selects used.
|
||||
If a decoder is used, this will be the number of
|
||||
chip selects after the decoder.
|
||||
- is-decoded-cs : Flag to indicate whether decoder is used or not.
|
||||
|
||||
Example:
|
||||
|
||||
spi@e0007000 {
|
||||
compatible = "xlnx,zynq-spi-r1p6";
|
||||
clock-names = "ref_clk", "pclk";
|
||||
clocks = <&clkc 26>, <&clkc 35>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 49 4>;
|
||||
num-cs = <4>;
|
||||
is-decoded-cs = <0>;
|
||||
reg = <0xe0007000 0x1000>;
|
||||
} ;
|
||||
66
Documentation/devicetree/bindings/spi/spi-cadence.yaml
Normal file
66
Documentation/devicetree/bindings/spi/spi-cadence.yaml
Normal file
@@ -0,0 +1,66 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/spi-cadence.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cadence SPI controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Michal Simek <michal.simek@xilinx.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- cdns,spi-r1p6
|
||||
- xlnx,zynq-spi-r1p6
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref_clk
|
||||
- const: pclk
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
num-cs:
|
||||
description: |
|
||||
Number of chip selects used. If a decoder is used,
|
||||
this will be the number of chip selects after the
|
||||
decoder.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 4
|
||||
default: 4
|
||||
|
||||
is-decoded-cs:
|
||||
description: |
|
||||
Flag to indicate whether decoder is used or not.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [ 0, 1 ]
|
||||
default: 0
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi@e0007000 {
|
||||
compatible = "xlnx,zynq-spi-r1p6";
|
||||
clock-names = "ref_clk", "pclk";
|
||||
clocks = <&clkc 26>, <&clkc 35>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 49 4>;
|
||||
num-cs = <4>;
|
||||
is-decoded-cs = <0>;
|
||||
reg = <0xe0007000 0x1000>;
|
||||
};
|
||||
...
|
||||
@@ -114,8 +114,11 @@ patternProperties:
|
||||
Compatible of the SPI device.
|
||||
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 256
|
||||
minItems: 1
|
||||
maxItems: 256
|
||||
items:
|
||||
minimum: 0
|
||||
maximum: 256
|
||||
description:
|
||||
Chip select used by the device.
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ properties:
|
||||
- rockchip,rk3328-spi
|
||||
- rockchip,rk3368-spi
|
||||
- rockchip,rk3399-spi
|
||||
- rockchip,rv1126-spi
|
||||
- const: rockchip,rk3066-spi
|
||||
|
||||
reg:
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
Xilinx SPI controller Device Tree Bindings
|
||||
-------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "xlnx,xps-spi-2.00.a", "xlnx,xps-spi-2.00.b" or "xlnx,axi-quad-spi-1.00.a"
|
||||
- reg : Physical base address and size of SPI registers map.
|
||||
- interrupts : Property with a value describing the interrupt
|
||||
number.
|
||||
|
||||
Optional properties:
|
||||
- xlnx,num-ss-bits : Number of chip selects used.
|
||||
- xlnx,num-transfer-bits : Number of bits per transfer. This will be 8 if not specified
|
||||
|
||||
Example:
|
||||
axi_quad_spi@41e00000 {
|
||||
compatible = "xlnx,xps-spi-2.00.a";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 31 1>;
|
||||
reg = <0x41e00000 0x10000>;
|
||||
xlnx,num-ss-bits = <0x1>;
|
||||
xlnx,num-transfer-bits = <32>;
|
||||
};
|
||||
|
||||
57
Documentation/devicetree/bindings/spi/spi-xilinx.yaml
Normal file
57
Documentation/devicetree/bindings/spi/spi-xilinx.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/spi-xilinx.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Xilinx SPI controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Michal Simek <michal.simek@xilinx.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- xlnx,xps-spi-2.00.a
|
||||
- xlnx,xps-spi-2.00.b
|
||||
- xlnx,axi-quad-spi-1.00.a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
xlnx,num-ss-bits:
|
||||
description: Number of chip selects used.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 32
|
||||
|
||||
xlnx,num-transfer-bits:
|
||||
description: Number of bits per transfer. This will be 8 if not specified.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [8, 16, 32]
|
||||
default: 8
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi0: spi@41e00000 {
|
||||
compatible = "xlnx,xps-spi-2.00.a";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 31 1>;
|
||||
reg = <0x41e00000 0x10000>;
|
||||
xlnx,num-ss-bits = <0x1>;
|
||||
xlnx,num-transfer-bits = <32>;
|
||||
};
|
||||
...
|
||||
@@ -1,25 +0,0 @@
|
||||
Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings
|
||||
-------------------------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "xlnx,zynqmp-qspi-1.0".
|
||||
- reg : Physical base address and size of GQSPI registers map.
|
||||
- interrupts : Property with a value describing the interrupt
|
||||
number.
|
||||
- clock-names : List of input clock names - "ref_clk", "pclk"
|
||||
(See clock bindings for details).
|
||||
- clocks : Clock phandles (see clock bindings for details).
|
||||
|
||||
Optional properties:
|
||||
- num-cs : Number of chip selects used.
|
||||
|
||||
Example:
|
||||
qspi: spi@ff0f0000 {
|
||||
compatible = "xlnx,zynqmp-qspi-1.0";
|
||||
clock-names = "ref_clk", "pclk";
|
||||
clocks = <&misc_clk &misc_clk>;
|
||||
interrupts = <0 15 4>;
|
||||
interrupt-parent = <&gic>;
|
||||
num-cs = <1>;
|
||||
reg = <0x0 0xff0f0000 0x1000>,<0x0 0xc0000000 0x8000000>;
|
||||
};
|
||||
51
Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml
Normal file
51
Documentation/devicetree/bindings/spi/spi-zynqmp-qspi.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/spi-zynqmp-qspi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Xilinx Zynq UltraScale+ MPSoC GQSPI controller Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Michal Simek <michal.simek@xilinx.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "spi-controller.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: xlnx,zynqmp-qspi-1.0
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref_clk
|
||||
- const: pclk
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/xlnx-zynqmp-clk.h>
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
qspi: spi@ff0f0000 {
|
||||
compatible = "xlnx,zynqmp-qspi-1.0";
|
||||
clocks = <&zynqmp_clk QSPI_REF>, <&zynqmp_clk LPD_LSBUS>;
|
||||
clock-names = "ref_clk", "pclk";
|
||||
interrupts = <0 15 4>;
|
||||
interrupt-parent = <&gic>;
|
||||
reg = <0x0 0xff0f0000 0x0 0x1000>,
|
||||
<0x0 0xc0000000 0x0 0x8000000>;
|
||||
};
|
||||
};
|
||||
@@ -2,43 +2,47 @@
|
||||
PXA2xx SPI on SSP driver HOWTO
|
||||
==============================
|
||||
|
||||
This a mini howto on the pxa2xx_spi driver. The driver turns a PXA2xx
|
||||
synchronous serial port into a SPI master controller
|
||||
This a mini HOWTO on the pxa2xx_spi driver. The driver turns a PXA2xx
|
||||
synchronous serial port into an SPI master controller
|
||||
(see Documentation/spi/spi-summary.rst). The driver has the following features
|
||||
|
||||
- Support for any PXA2xx SSP
|
||||
- Support for any PXA2xx and compatible SSP.
|
||||
- SSP PIO and SSP DMA data transfers.
|
||||
- External and Internal (SSPFRM) chip selects.
|
||||
- Per slave device (chip) configuration.
|
||||
- Full suspend, freeze, resume support.
|
||||
|
||||
The driver is built around a "spi_message" fifo serviced by workqueue and a
|
||||
tasklet. The workqueue, "pump_messages", drives message fifo and the tasklet
|
||||
(pump_transfer) is responsible for queuing SPI transactions and setting up and
|
||||
launching the dma/interrupt driven transfers.
|
||||
The driver is built around a &struct spi_message FIFO serviced by kernel
|
||||
thread. The kernel thread, spi_pump_messages(), drives message FIFO and
|
||||
is responsible for queuing SPI transactions and setting up and launching
|
||||
the DMA or interrupt driven transfers.
|
||||
|
||||
Declaring PXA2xx Master Controllers
|
||||
-----------------------------------
|
||||
Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a
|
||||
"platform device". The master configuration is passed to the driver via a table
|
||||
found in include/linux/spi/pxa2xx_spi.h::
|
||||
Typically, for a legacy platform, an SPI master is defined in the
|
||||
arch/.../mach-*/board-*.c as a "platform device". The master configuration
|
||||
is passed to the driver via a table found in include/linux/spi/pxa2xx_spi.h::
|
||||
|
||||
struct pxa2xx_spi_controller {
|
||||
u16 num_chipselect;
|
||||
u8 enable_dma;
|
||||
...
|
||||
};
|
||||
|
||||
The "pxa2xx_spi_controller.num_chipselect" field is used to determine the number of
|
||||
slave device (chips) attached to this SPI master.
|
||||
|
||||
The "pxa2xx_spi_controller.enable_dma" field informs the driver that SSP DMA should
|
||||
be used. This caused the driver to acquire two DMA channels: rx_channel and
|
||||
tx_channel. The rx_channel has a higher DMA service priority the tx_channel.
|
||||
be used. This caused the driver to acquire two DMA channels: Rx channel and
|
||||
Tx channel. The Rx channel has a higher DMA service priority than the Tx channel.
|
||||
See the "PXA2xx Developer Manual" section "DMA Controller".
|
||||
|
||||
For the new platforms the description of the controller and peripheral devices
|
||||
comes from Device Tree or ACPI.
|
||||
|
||||
NSSP MASTER SAMPLE
|
||||
------------------
|
||||
Below is a sample configuration using the PXA255 NSSP::
|
||||
Below is a sample configuration using the PXA255 NSSP for a legacy platform::
|
||||
|
||||
static struct resource pxa_spi_nssp_resources[] = {
|
||||
[0] = {
|
||||
@@ -79,9 +83,10 @@ Below is a sample configuration using the PXA255 NSSP::
|
||||
|
||||
Declaring Slave Devices
|
||||
-----------------------
|
||||
Typically each SPI slave (chip) is defined in the arch/.../mach-*/board-*.c
|
||||
using the "spi_board_info" structure found in "linux/spi/spi.h". See
|
||||
"Documentation/spi/spi-summary.rst" for additional information.
|
||||
Typically, for a legacy platform, each SPI slave (chip) is defined in the
|
||||
arch/.../mach-*/board-*.c using the "spi_board_info" structure found in
|
||||
"linux/spi/spi.h". See "Documentation/spi/spi-summary.rst" for additional
|
||||
information.
|
||||
|
||||
Each slave device attached to the PXA must provide slave specific configuration
|
||||
information via the structure "pxa2xx_spi_chip" found in
|
||||
@@ -101,9 +106,9 @@ device. All fields are optional.
|
||||
};
|
||||
|
||||
The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are
|
||||
used to configure the SSP hardware fifo. These fields are critical to the
|
||||
used to configure the SSP hardware FIFO. These fields are critical to the
|
||||
performance of pxa2xx_spi driver and misconfiguration will result in rx
|
||||
fifo overruns (especially in PIO mode transfers). Good default values are::
|
||||
FIFO overruns (especially in PIO mode transfers). Good default values are::
|
||||
|
||||
.tx_threshold = 8,
|
||||
.rx_threshold = 8,
|
||||
@@ -118,7 +123,7 @@ use a value of 8. The driver will determine a reasonable default if
|
||||
dma_burst_size == 0.
|
||||
|
||||
The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle
|
||||
trailing bytes in the SSP receiver fifo. The correct value for this field is
|
||||
trailing bytes in the SSP receiver FIFO. The correct value for this field is
|
||||
dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
|
||||
slave device. Please note that the PXA2xx SSP 1 does not support trailing byte
|
||||
timeouts and must busy-wait any trailing bytes.
|
||||
@@ -131,19 +136,19 @@ testing.
|
||||
The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific
|
||||
function for asserting/deasserting a slave device chip select. If the field is
|
||||
NULL, the pxa2xx_spi master controller driver assumes that the SSP port is
|
||||
configured to use SSPFRM instead.
|
||||
configured to use GPIO or SSPFRM instead.
|
||||
|
||||
NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the
|
||||
chipselect is dropped after each spi_transfer. Most devices need chip select
|
||||
asserted around the complete message. Use SSPFRM as a GPIO (through cs_control)
|
||||
asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor)
|
||||
to accommodate these chips.
|
||||
|
||||
|
||||
NSSP SLAVE SAMPLE
|
||||
-----------------
|
||||
The pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the
|
||||
"spi_board_info.controller_data" field. Below is a sample configuration using
|
||||
the PXA255 NSSP.
|
||||
For a legacy platform or in some other cases, the pxa2xx_spi_chip structure
|
||||
is passed to the pxa2xx_spi driver in the "spi_board_info.controller_data"
|
||||
field. Below is a sample configuration using the PXA255 NSSP.
|
||||
|
||||
::
|
||||
|
||||
@@ -212,7 +217,9 @@ DMA and PIO I/O Support
|
||||
-----------------------
|
||||
The pxa2xx_spi driver supports both DMA and interrupt driven PIO message
|
||||
transfers. The driver defaults to PIO mode and DMA transfers must be enabled
|
||||
by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure. The DMA
|
||||
by setting the "enable_dma" flag in the "pxa2xx_spi_controller" structure.
|
||||
For the newer platforms, that are known to support DMA, the driver will enable
|
||||
it automatically and try it first with a possible fallback to PIO. The DMA
|
||||
mode supports both coherent and stream based DMA mappings.
|
||||
|
||||
The following logic is used to determine the type of I/O to be used on
|
||||
@@ -236,5 +243,4 @@ a per "spi_transfer" basis::
|
||||
|
||||
THANKS TO
|
||||
---------
|
||||
|
||||
David Brownell and others for mentoring the development of this driver.
|
||||
|
||||
@@ -473,20 +473,26 @@ static int spinand_erase_op(struct spinand_device *spinand,
|
||||
return spi_mem_exec_op(spinand->spimem, &op);
|
||||
}
|
||||
|
||||
static int spinand_wait(struct spinand_device *spinand, u8 *s)
|
||||
static int spinand_wait(struct spinand_device *spinand,
|
||||
unsigned long initial_delay_us,
|
||||
unsigned long poll_delay_us,
|
||||
u8 *s)
|
||||
{
|
||||
unsigned long timeo = jiffies + msecs_to_jiffies(400);
|
||||
struct spi_mem_op op = SPINAND_GET_FEATURE_OP(REG_STATUS,
|
||||
spinand->scratchbuf);
|
||||
u8 status;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = spinand_read_status(spinand, &status);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = spi_mem_poll_status(spinand->spimem, &op, STATUS_BUSY, 0,
|
||||
initial_delay_us,
|
||||
poll_delay_us,
|
||||
SPINAND_WAITRDY_TIMEOUT_MS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(status & STATUS_BUSY))
|
||||
goto out;
|
||||
} while (time_before(jiffies, timeo));
|
||||
status = *spinand->scratchbuf;
|
||||
if (!(status & STATUS_BUSY))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Extra read, just in case the STATUS_READY bit has changed
|
||||
@@ -526,7 +532,10 @@ static int spinand_reset_op(struct spinand_device *spinand)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return spinand_wait(spinand, NULL);
|
||||
return spinand_wait(spinand,
|
||||
SPINAND_RESET_INITIAL_DELAY_US,
|
||||
SPINAND_RESET_POLL_DELAY_US,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
|
||||
@@ -549,7 +558,10 @@ static int spinand_read_page(struct spinand_device *spinand,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spinand_wait(spinand, &status);
|
||||
ret = spinand_wait(spinand,
|
||||
SPINAND_READ_INITIAL_DELAY_US,
|
||||
SPINAND_READ_POLL_DELAY_US,
|
||||
&status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -585,7 +597,10 @@ static int spinand_write_page(struct spinand_device *spinand,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spinand_wait(spinand, &status);
|
||||
ret = spinand_wait(spinand,
|
||||
SPINAND_WRITE_INITIAL_DELAY_US,
|
||||
SPINAND_WRITE_POLL_DELAY_US,
|
||||
&status);
|
||||
if (!ret && (status & STATUS_PROG_FAILED))
|
||||
return -EIO;
|
||||
|
||||
@@ -768,7 +783,11 @@ static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = spinand_wait(spinand, &status);
|
||||
ret = spinand_wait(spinand,
|
||||
SPINAND_ERASE_INITIAL_DELAY_US,
|
||||
SPINAND_ERASE_POLL_DELAY_US,
|
||||
&status);
|
||||
|
||||
if (!ret && (status & STATUS_ERASE_FAILED))
|
||||
ret = -EIO;
|
||||
|
||||
|
||||
@@ -806,6 +806,7 @@ config SPI_STM32_QSPI
|
||||
tristate "STMicroelectronics STM32 QUAD SPI controller"
|
||||
depends on ARCH_STM32 || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on SPI_MEM
|
||||
help
|
||||
This enables support for the Quad SPI controller in master mode.
|
||||
This driver does not support generic SPI. The implementation only
|
||||
|
||||
@@ -148,10 +148,8 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)
|
||||
|
||||
base = devm_ioremap_resource(dev, &dfl_dev->mmio_res);
|
||||
|
||||
if (IS_ERR(base)) {
|
||||
dev_err(dev, "%s get mem resource fail!\n", __func__);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
}
|
||||
|
||||
config_spi_master(base, master);
|
||||
dev_dbg(dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__,
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_data/spi-ath79.h>
|
||||
|
||||
#define DRV_NAME "ath79-spi"
|
||||
|
||||
@@ -138,7 +137,6 @@ static int ath79_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct ath79_spi *sp;
|
||||
struct ath79_spi_platform_data *pdata;
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
|
||||
@@ -152,15 +150,10 @@ static int ath79_spi_probe(struct platform_device *pdev)
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
platform_set_drvdata(pdev, sp);
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
master->use_gpio_descriptors = true;
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
|
||||
master->flags = SPI_MASTER_GPIO_SS;
|
||||
if (pdata) {
|
||||
master->bus_num = pdata->bus_num;
|
||||
master->num_chipselect = pdata->num_chipselect;
|
||||
}
|
||||
master->num_chipselect = 3;
|
||||
|
||||
sp->bitbang.master = master;
|
||||
sp->bitbang.chipselect = ath79_spi_chipselect;
|
||||
|
||||
@@ -700,7 +700,6 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master,
|
||||
static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||
struct spi_transfer *xfer,
|
||||
u32 *plen)
|
||||
__must_hold(&as->lock)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
struct dma_chan *rxchan = master->dma_rx;
|
||||
@@ -716,8 +715,6 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||
if (!rxchan || !txchan)
|
||||
return -ENODEV;
|
||||
|
||||
/* release lock for DMA operations */
|
||||
atmel_spi_unlock(as);
|
||||
|
||||
*plen = xfer->len;
|
||||
|
||||
@@ -786,15 +783,12 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
|
||||
rxchan->device->device_issue_pending(rxchan);
|
||||
txchan->device->device_issue_pending(txchan);
|
||||
|
||||
/* take back lock */
|
||||
atmel_spi_lock(as);
|
||||
return 0;
|
||||
|
||||
err_dma:
|
||||
spi_writel(as, IDR, SPI_BIT(OVRES));
|
||||
atmel_spi_stop_dma(master);
|
||||
err_exit:
|
||||
atmel_spi_lock(as);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -863,7 +857,6 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
|
||||
* lock is held, spi irq is blocked
|
||||
*/
|
||||
static void atmel_spi_pdc_next_xfer(struct spi_master *master,
|
||||
struct spi_message *msg,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
@@ -879,12 +872,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
|
||||
spi_writel(as, RPR, rx_dma);
|
||||
spi_writel(as, TPR, tx_dma);
|
||||
|
||||
if (msg->spi->bits_per_word > 8)
|
||||
if (xfer->bits_per_word > 8)
|
||||
len >>= 1;
|
||||
spi_writel(as, RCR, len);
|
||||
spi_writel(as, TCR, len);
|
||||
|
||||
dev_dbg(&msg->spi->dev,
|
||||
dev_dbg(&master->dev,
|
||||
" start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
|
||||
xfer, xfer->len, xfer->tx_buf,
|
||||
(unsigned long long)xfer->tx_dma, xfer->rx_buf,
|
||||
@@ -898,12 +891,12 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
|
||||
spi_writel(as, RNPR, rx_dma);
|
||||
spi_writel(as, TNPR, tx_dma);
|
||||
|
||||
if (msg->spi->bits_per_word > 8)
|
||||
if (xfer->bits_per_word > 8)
|
||||
len >>= 1;
|
||||
spi_writel(as, RNCR, len);
|
||||
spi_writel(as, TNCR, len);
|
||||
|
||||
dev_dbg(&msg->spi->dev,
|
||||
dev_dbg(&master->dev,
|
||||
" next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n",
|
||||
xfer, xfer->len, xfer->tx_buf,
|
||||
(unsigned long long)xfer->tx_dma, xfer->rx_buf,
|
||||
@@ -1054,8 +1047,6 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
|
||||
|
||||
/* Interrupt
|
||||
*
|
||||
* No need for locking in this Interrupt handler: done_status is the
|
||||
* only information modified.
|
||||
*/
|
||||
static irqreturn_t
|
||||
atmel_spi_pio_interrupt(int irq, void *dev_id)
|
||||
@@ -1273,12 +1264,28 @@ static int atmel_spi_setup(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
struct atmel_spi *as = spi_master_get_devdata(spi->master);
|
||||
/* the core doesn't really pass us enable/disable, but CS HIGH vs CS LOW
|
||||
* since we already have routines for activate/deactivate translate
|
||||
* high/low to active/inactive
|
||||
*/
|
||||
enable = (!!(spi->mode & SPI_CS_HIGH) == enable);
|
||||
|
||||
if (enable) {
|
||||
cs_activate(as, spi);
|
||||
} else {
|
||||
cs_deactivate(as, spi);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
struct spi_message *msg,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct atmel_spi *as;
|
||||
struct spi_device *spi = msg->spi;
|
||||
u8 bits;
|
||||
u32 len;
|
||||
struct atmel_spi_device *asd;
|
||||
@@ -1288,11 +1295,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
|
||||
as = spi_master_get_devdata(master);
|
||||
|
||||
if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
|
||||
dev_dbg(&spi->dev, "missing rx or tx buf\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
asd = spi->controller_state;
|
||||
bits = (asd->csr >> 4) & 0xf;
|
||||
if (bits != xfer->bits_per_word - 8) {
|
||||
@@ -1305,13 +1307,13 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
* DMA map early, for performance (empties dcache ASAP) and
|
||||
* better fault reporting.
|
||||
*/
|
||||
if ((!msg->is_dma_mapped)
|
||||
if ((!master->cur_msg_mapped)
|
||||
&& as->use_pdc) {
|
||||
if (atmel_spi_dma_map_xfer(as, xfer) < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
atmel_spi_set_xfer_speed(as, msg->spi, xfer);
|
||||
atmel_spi_set_xfer_speed(as, spi, xfer);
|
||||
|
||||
as->done_status = 0;
|
||||
as->current_transfer = xfer;
|
||||
@@ -1320,7 +1322,9 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
reinit_completion(&as->xfer_completion);
|
||||
|
||||
if (as->use_pdc) {
|
||||
atmel_spi_pdc_next_xfer(master, msg, xfer);
|
||||
atmel_spi_lock(as);
|
||||
atmel_spi_pdc_next_xfer(master, xfer);
|
||||
atmel_spi_unlock(as);
|
||||
} else if (atmel_spi_use_dma(as, xfer)) {
|
||||
len = as->current_remaining_bytes;
|
||||
ret = atmel_spi_next_xfer_dma_submit(master,
|
||||
@@ -1328,21 +1332,21 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
if (ret) {
|
||||
dev_err(&spi->dev,
|
||||
"unable to use DMA, fallback to PIO\n");
|
||||
atmel_spi_next_xfer_pio(master, xfer);
|
||||
as->done_status = ret;
|
||||
break;
|
||||
} else {
|
||||
as->current_remaining_bytes -= len;
|
||||
if (as->current_remaining_bytes < 0)
|
||||
as->current_remaining_bytes = 0;
|
||||
}
|
||||
} else {
|
||||
atmel_spi_lock(as);
|
||||
atmel_spi_next_xfer_pio(master, xfer);
|
||||
atmel_spi_unlock(as);
|
||||
}
|
||||
|
||||
/* interrupts are disabled, so free the lock for schedule */
|
||||
atmel_spi_unlock(as);
|
||||
dma_timeout = wait_for_completion_timeout(&as->xfer_completion,
|
||||
SPI_DMA_TIMEOUT);
|
||||
atmel_spi_lock(as);
|
||||
if (WARN_ON(dma_timeout == 0)) {
|
||||
dev_err(&spi->dev, "spi transfer timeout\n");
|
||||
as->done_status = -EIO;
|
||||
@@ -1381,90 +1385,16 @@ static int atmel_spi_one_transfer(struct spi_master *master,
|
||||
} else if (atmel_spi_use_dma(as, xfer)) {
|
||||
atmel_spi_stop_dma(master);
|
||||
}
|
||||
|
||||
if (!msg->is_dma_mapped
|
||||
&& as->use_pdc)
|
||||
atmel_spi_dma_unmap_xfer(master, xfer);
|
||||
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
/* only update length if no error */
|
||||
msg->actual_length += xfer->len;
|
||||
}
|
||||
|
||||
if (!msg->is_dma_mapped
|
||||
if (!master->cur_msg_mapped
|
||||
&& as->use_pdc)
|
||||
atmel_spi_dma_unmap_xfer(master, xfer);
|
||||
|
||||
spi_transfer_delay_exec(xfer);
|
||||
|
||||
if (xfer->cs_change) {
|
||||
if (list_is_last(&xfer->transfer_list,
|
||||
&msg->transfers)) {
|
||||
as->keep_cs = true;
|
||||
} else {
|
||||
cs_deactivate(as, msg->spi);
|
||||
udelay(10);
|
||||
cs_activate(as, msg->spi);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_spi_transfer_one_message(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct atmel_spi *as;
|
||||
struct spi_transfer *xfer;
|
||||
struct spi_device *spi = msg->spi;
|
||||
int ret = 0;
|
||||
|
||||
as = spi_master_get_devdata(master);
|
||||
|
||||
dev_dbg(&spi->dev, "new message %p submitted for %s\n",
|
||||
msg, dev_name(&spi->dev));
|
||||
|
||||
atmel_spi_lock(as);
|
||||
cs_activate(as, spi);
|
||||
|
||||
as->keep_cs = false;
|
||||
|
||||
msg->status = 0;
|
||||
msg->actual_length = 0;
|
||||
|
||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||
trace_spi_transfer_start(msg, xfer);
|
||||
|
||||
ret = atmel_spi_one_transfer(master, msg, xfer);
|
||||
if (ret)
|
||||
goto msg_done;
|
||||
|
||||
trace_spi_transfer_stop(msg, xfer);
|
||||
}
|
||||
|
||||
if (as->use_pdc)
|
||||
atmel_spi_disable_pdc_transfer(as);
|
||||
|
||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||
dev_dbg(&spi->dev,
|
||||
" xfer %p: len %u tx %p/%pad rx %p/%pad\n",
|
||||
xfer, xfer->len,
|
||||
xfer->tx_buf, &xfer->tx_dma,
|
||||
xfer->rx_buf, &xfer->rx_dma);
|
||||
}
|
||||
|
||||
msg_done:
|
||||
if (!as->keep_cs)
|
||||
cs_deactivate(as, msg->spi);
|
||||
|
||||
atmel_spi_unlock(as);
|
||||
|
||||
msg->status = as->done_status;
|
||||
spi_finalize_current_message(spi->master);
|
||||
|
||||
return ret;
|
||||
return as->done_status;
|
||||
}
|
||||
|
||||
static void atmel_spi_cleanup(struct spi_device *spi)
|
||||
@@ -1554,7 +1484,8 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
master->num_chipselect = 4;
|
||||
master->setup = atmel_spi_setup;
|
||||
master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
|
||||
master->transfer_one_message = atmel_spi_transfer_one_message;
|
||||
master->transfer_one = atmel_spi_one_transfer;
|
||||
master->set_cs = atmel_spi_set_cs;
|
||||
master->cleanup = atmel_spi_cleanup;
|
||||
master->auto_runtime_pm = true;
|
||||
master->max_dma_len = SPI_MAX_DMA_XFER;
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
#define BCM2835_SPI_FIFO_SIZE 64
|
||||
#define BCM2835_SPI_FIFO_SIZE_3_4 48
|
||||
#define BCM2835_SPI_DMA_MIN_LENGTH 96
|
||||
#define BCM2835_SPI_NUM_CS 24 /* raise as necessary */
|
||||
#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
|
||||
| SPI_NO_CS | SPI_3WIRE)
|
||||
|
||||
@@ -96,8 +95,6 @@ MODULE_PARM_DESC(polling_limit_us,
|
||||
* @rx_prologue: bytes received without DMA if first RX sglist entry's
|
||||
* length is not a multiple of 4 (to overcome hardware limitation)
|
||||
* @tx_spillover: whether @tx_prologue spills over to second TX sglist entry
|
||||
* @prepare_cs: precalculated CS register value for ->prepare_message()
|
||||
* (uses slave-specific clock polarity and phase settings)
|
||||
* @debugfs_dir: the debugfs directory - neede to remove debugfs when
|
||||
* unloading the module
|
||||
* @count_transfer_polling: count of how often polling mode is used
|
||||
@@ -107,7 +104,7 @@ MODULE_PARM_DESC(polling_limit_us,
|
||||
* These are counted as well in @count_transfer_polling and
|
||||
* @count_transfer_irq
|
||||
* @count_transfer_dma: count how often dma mode is used
|
||||
* @chip_select: SPI slave currently selected
|
||||
* @slv: SPI slave currently selected
|
||||
* (used by bcm2835_spi_dma_tx_done() to write @clear_rx_cs)
|
||||
* @tx_dma_active: whether a TX DMA descriptor is in progress
|
||||
* @rx_dma_active: whether a RX DMA descriptor is in progress
|
||||
@@ -115,11 +112,6 @@ MODULE_PARM_DESC(polling_limit_us,
|
||||
* @fill_tx_desc: preallocated TX DMA descriptor used for RX-only transfers
|
||||
* (cyclically copies from zero page to TX FIFO)
|
||||
* @fill_tx_addr: bus address of zero page
|
||||
* @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers
|
||||
* (cyclically clears RX FIFO by writing @clear_rx_cs to CS register)
|
||||
* @clear_rx_addr: bus address of @clear_rx_cs
|
||||
* @clear_rx_cs: precalculated CS register value to clear RX FIFO
|
||||
* (uses slave-specific clock polarity and phase settings)
|
||||
*/
|
||||
struct bcm2835_spi {
|
||||
void __iomem *regs;
|
||||
@@ -134,7 +126,6 @@ struct bcm2835_spi {
|
||||
int tx_prologue;
|
||||
int rx_prologue;
|
||||
unsigned int tx_spillover;
|
||||
u32 prepare_cs[BCM2835_SPI_NUM_CS];
|
||||
|
||||
struct dentry *debugfs_dir;
|
||||
u64 count_transfer_polling;
|
||||
@@ -142,14 +133,28 @@ struct bcm2835_spi {
|
||||
u64 count_transfer_irq_after_polling;
|
||||
u64 count_transfer_dma;
|
||||
|
||||
u8 chip_select;
|
||||
struct bcm2835_spidev *slv;
|
||||
unsigned int tx_dma_active;
|
||||
unsigned int rx_dma_active;
|
||||
struct dma_async_tx_descriptor *fill_tx_desc;
|
||||
dma_addr_t fill_tx_addr;
|
||||
struct dma_async_tx_descriptor *clear_rx_desc[BCM2835_SPI_NUM_CS];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct bcm2835_spidev - BCM2835 SPI slave
|
||||
* @prepare_cs: precalculated CS register value for ->prepare_message()
|
||||
* (uses slave-specific clock polarity and phase settings)
|
||||
* @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers
|
||||
* (cyclically clears RX FIFO by writing @clear_rx_cs to CS register)
|
||||
* @clear_rx_addr: bus address of @clear_rx_cs
|
||||
* @clear_rx_cs: precalculated CS register value to clear RX FIFO
|
||||
* (uses slave-specific clock polarity and phase settings)
|
||||
*/
|
||||
struct bcm2835_spidev {
|
||||
u32 prepare_cs;
|
||||
struct dma_async_tx_descriptor *clear_rx_desc;
|
||||
dma_addr_t clear_rx_addr;
|
||||
u32 clear_rx_cs[BCM2835_SPI_NUM_CS] ____cacheline_aligned;
|
||||
u32 clear_rx_cs ____cacheline_aligned;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
@@ -624,8 +629,7 @@ static void bcm2835_spi_dma_tx_done(void *data)
|
||||
|
||||
/* busy-wait for TX FIFO to empty */
|
||||
while (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE))
|
||||
bcm2835_wr(bs, BCM2835_SPI_CS,
|
||||
bs->clear_rx_cs[bs->chip_select]);
|
||||
bcm2835_wr(bs, BCM2835_SPI_CS, bs->slv->clear_rx_cs);
|
||||
|
||||
bs->tx_dma_active = false;
|
||||
smp_wmb();
|
||||
@@ -646,18 +650,18 @@ static void bcm2835_spi_dma_tx_done(void *data)
|
||||
/**
|
||||
* bcm2835_spi_prepare_sg() - prepare and submit DMA descriptor for sglist
|
||||
* @ctlr: SPI master controller
|
||||
* @spi: SPI slave
|
||||
* @tfr: SPI transfer
|
||||
* @bs: BCM2835 SPI controller
|
||||
* @slv: BCM2835 SPI slave
|
||||
* @is_tx: whether to submit DMA descriptor for TX or RX sglist
|
||||
*
|
||||
* Prepare and submit a DMA descriptor for the TX or RX sglist of @tfr.
|
||||
* Return 0 on success or a negative error number.
|
||||
*/
|
||||
static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *tfr,
|
||||
struct bcm2835_spi *bs,
|
||||
struct bcm2835_spidev *slv,
|
||||
bool is_tx)
|
||||
{
|
||||
struct dma_chan *chan;
|
||||
@@ -697,7 +701,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
|
||||
} else if (!tfr->rx_buf) {
|
||||
desc->callback = bcm2835_spi_dma_tx_done;
|
||||
desc->callback_param = ctlr;
|
||||
bs->chip_select = spi->chip_select;
|
||||
bs->slv = slv;
|
||||
}
|
||||
|
||||
/* submit it to DMA-engine */
|
||||
@@ -709,8 +713,8 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
|
||||
/**
|
||||
* bcm2835_spi_transfer_one_dma() - perform SPI transfer using DMA engine
|
||||
* @ctlr: SPI master controller
|
||||
* @spi: SPI slave
|
||||
* @tfr: SPI transfer
|
||||
* @slv: BCM2835 SPI slave
|
||||
* @cs: CS register
|
||||
*
|
||||
* For *bidirectional* transfers (both tx_buf and rx_buf are non-%NULL), set up
|
||||
@@ -754,8 +758,8 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr,
|
||||
* performed at the end of an RX-only transfer.
|
||||
*/
|
||||
static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *tfr,
|
||||
struct bcm2835_spidev *slv,
|
||||
u32 cs)
|
||||
{
|
||||
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
|
||||
@@ -773,7 +777,7 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
|
||||
|
||||
/* setup tx-DMA */
|
||||
if (bs->tx_buf) {
|
||||
ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, true);
|
||||
ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, true);
|
||||
} else {
|
||||
cookie = dmaengine_submit(bs->fill_tx_desc);
|
||||
ret = dma_submit_error(cookie);
|
||||
@@ -799,9 +803,9 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr,
|
||||
* this saves 10us or more.
|
||||
*/
|
||||
if (bs->rx_buf) {
|
||||
ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, false);
|
||||
ret = bcm2835_spi_prepare_sg(ctlr, tfr, bs, slv, false);
|
||||
} else {
|
||||
cookie = dmaengine_submit(bs->clear_rx_desc[spi->chip_select]);
|
||||
cookie = dmaengine_submit(slv->clear_rx_desc);
|
||||
ret = dma_submit_error(cookie);
|
||||
}
|
||||
if (ret) {
|
||||
@@ -850,8 +854,6 @@ static bool bcm2835_spi_can_dma(struct spi_controller *ctlr,
|
||||
static void bcm2835_dma_release(struct spi_controller *ctlr,
|
||||
struct bcm2835_spi *bs)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (ctlr->dma_tx) {
|
||||
dmaengine_terminate_sync(ctlr->dma_tx);
|
||||
|
||||
@@ -870,17 +872,6 @@ static void bcm2835_dma_release(struct spi_controller *ctlr,
|
||||
|
||||
if (ctlr->dma_rx) {
|
||||
dmaengine_terminate_sync(ctlr->dma_rx);
|
||||
|
||||
for (i = 0; i < BCM2835_SPI_NUM_CS; i++)
|
||||
if (bs->clear_rx_desc[i])
|
||||
dmaengine_desc_free(bs->clear_rx_desc[i]);
|
||||
|
||||
if (bs->clear_rx_addr)
|
||||
dma_unmap_single(ctlr->dma_rx->device->dev,
|
||||
bs->clear_rx_addr,
|
||||
sizeof(bs->clear_rx_cs),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
dma_release_channel(ctlr->dma_rx);
|
||||
ctlr->dma_rx = NULL;
|
||||
}
|
||||
@@ -892,7 +883,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
|
||||
struct dma_slave_config slave_config;
|
||||
const __be32 *addr;
|
||||
dma_addr_t dma_reg_base;
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
/* base address in dma-space */
|
||||
addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL);
|
||||
@@ -972,35 +963,6 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
|
||||
if (ret)
|
||||
goto err_config;
|
||||
|
||||
bs->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
|
||||
bs->clear_rx_cs,
|
||||
sizeof(bs->clear_rx_cs),
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(ctlr->dma_rx->device->dev, bs->clear_rx_addr)) {
|
||||
dev_err(dev, "cannot map clear_rx_cs - not using DMA mode\n");
|
||||
bs->clear_rx_addr = 0;
|
||||
ret = -ENOMEM;
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
for (i = 0; i < BCM2835_SPI_NUM_CS; i++) {
|
||||
bs->clear_rx_desc[i] = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
|
||||
bs->clear_rx_addr + i * sizeof(u32),
|
||||
sizeof(u32), 0,
|
||||
DMA_MEM_TO_DEV, 0);
|
||||
if (!bs->clear_rx_desc[i]) {
|
||||
dev_err(dev, "cannot prepare clear_rx_desc - not using DMA mode\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
ret = dmaengine_desc_set_reuse(bs->clear_rx_desc[i]);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot reuse clear_rx_desc - not using DMA mode\n");
|
||||
goto err_release;
|
||||
}
|
||||
}
|
||||
|
||||
/* all went well, so set can_dma */
|
||||
ctlr->can_dma = bcm2835_spi_can_dma;
|
||||
|
||||
@@ -1082,9 +1044,10 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
|
||||
struct spi_transfer *tfr)
|
||||
{
|
||||
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
|
||||
struct bcm2835_spidev *slv = spi_get_ctldata(spi);
|
||||
unsigned long spi_hz, clk_hz, cdiv;
|
||||
unsigned long hz_per_byte, byte_limit;
|
||||
u32 cs = bs->prepare_cs[spi->chip_select];
|
||||
u32 cs = slv->prepare_cs;
|
||||
|
||||
/* set clock */
|
||||
spi_hz = tfr->speed_hz;
|
||||
@@ -1133,7 +1096,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
|
||||
* this 1 idle clock cycle pattern but runs the spi clock without gaps
|
||||
*/
|
||||
if (ctlr->can_dma && bcm2835_spi_can_dma(ctlr, spi, tfr))
|
||||
return bcm2835_spi_transfer_one_dma(ctlr, spi, tfr, cs);
|
||||
return bcm2835_spi_transfer_one_dma(ctlr, tfr, slv, cs);
|
||||
|
||||
/* run in interrupt-mode */
|
||||
return bcm2835_spi_transfer_one_irq(ctlr, spi, tfr, cs, true);
|
||||
@@ -1144,6 +1107,7 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
|
||||
{
|
||||
struct spi_device *spi = msg->spi;
|
||||
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
|
||||
struct bcm2835_spidev *slv = spi_get_ctldata(spi);
|
||||
int ret;
|
||||
|
||||
if (ctlr->can_dma) {
|
||||
@@ -1162,7 +1126,7 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
|
||||
* Set up clock polarity before spi_transfer_one_message() asserts
|
||||
* chip select to avoid a gratuitous clock signal edge.
|
||||
*/
|
||||
bcm2835_wr(bs, BCM2835_SPI_CS, bs->prepare_cs[spi->chip_select]);
|
||||
bcm2835_wr(bs, BCM2835_SPI_CS, slv->prepare_cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1188,17 +1152,81 @@ static int chip_match_name(struct gpio_chip *chip, void *data)
|
||||
return !strcmp(chip->label, data);
|
||||
}
|
||||
|
||||
static void bcm2835_spi_cleanup(struct spi_device *spi)
|
||||
{
|
||||
struct bcm2835_spidev *slv = spi_get_ctldata(spi);
|
||||
struct spi_controller *ctlr = spi->controller;
|
||||
|
||||
if (slv->clear_rx_desc)
|
||||
dmaengine_desc_free(slv->clear_rx_desc);
|
||||
|
||||
if (slv->clear_rx_addr)
|
||||
dma_unmap_single(ctlr->dma_rx->device->dev,
|
||||
slv->clear_rx_addr,
|
||||
sizeof(u32),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
kfree(slv);
|
||||
}
|
||||
|
||||
static int bcm2835_spi_setup_dma(struct spi_controller *ctlr,
|
||||
struct spi_device *spi,
|
||||
struct bcm2835_spi *bs,
|
||||
struct bcm2835_spidev *slv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!ctlr->dma_rx)
|
||||
return 0;
|
||||
|
||||
slv->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
|
||||
&slv->clear_rx_cs,
|
||||
sizeof(u32),
|
||||
DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(ctlr->dma_rx->device->dev, slv->clear_rx_addr)) {
|
||||
dev_err(&spi->dev, "cannot map clear_rx_cs\n");
|
||||
slv->clear_rx_addr = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
slv->clear_rx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_rx,
|
||||
slv->clear_rx_addr,
|
||||
sizeof(u32), 0,
|
||||
DMA_MEM_TO_DEV, 0);
|
||||
if (!slv->clear_rx_desc) {
|
||||
dev_err(&spi->dev, "cannot prepare clear_rx_desc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = dmaengine_desc_set_reuse(slv->clear_rx_desc);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "cannot reuse clear_rx_desc\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm2835_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct spi_controller *ctlr = spi->controller;
|
||||
struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
|
||||
struct bcm2835_spidev *slv = spi_get_ctldata(spi);
|
||||
struct gpio_chip *chip;
|
||||
int ret;
|
||||
u32 cs;
|
||||
|
||||
if (spi->chip_select >= BCM2835_SPI_NUM_CS) {
|
||||
dev_err(&spi->dev, "only %d chip-selects supported\n",
|
||||
BCM2835_SPI_NUM_CS - 1);
|
||||
return -EINVAL;
|
||||
if (!slv) {
|
||||
slv = kzalloc(ALIGN(sizeof(*slv), dma_get_cache_alignment()),
|
||||
GFP_KERNEL);
|
||||
if (!slv)
|
||||
return -ENOMEM;
|
||||
|
||||
spi_set_ctldata(spi, slv);
|
||||
|
||||
ret = bcm2835_spi_setup_dma(ctlr, spi, bs, slv);
|
||||
if (ret)
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1212,20 +1240,19 @@ static int bcm2835_spi_setup(struct spi_device *spi)
|
||||
cs |= BCM2835_SPI_CS_CPOL;
|
||||
if (spi->mode & SPI_CPHA)
|
||||
cs |= BCM2835_SPI_CS_CPHA;
|
||||
bs->prepare_cs[spi->chip_select] = cs;
|
||||
slv->prepare_cs = cs;
|
||||
|
||||
/*
|
||||
* Precalculate SPI slave's CS register value to clear RX FIFO
|
||||
* in case of a TX-only DMA transfer.
|
||||
*/
|
||||
if (ctlr->dma_rx) {
|
||||
bs->clear_rx_cs[spi->chip_select] = cs |
|
||||
BCM2835_SPI_CS_TA |
|
||||
BCM2835_SPI_CS_DMAEN |
|
||||
BCM2835_SPI_CS_CLEAR_RX;
|
||||
slv->clear_rx_cs = cs | BCM2835_SPI_CS_TA |
|
||||
BCM2835_SPI_CS_DMAEN |
|
||||
BCM2835_SPI_CS_CLEAR_RX;
|
||||
dma_sync_single_for_device(ctlr->dma_rx->device->dev,
|
||||
bs->clear_rx_addr,
|
||||
sizeof(bs->clear_rx_cs),
|
||||
slv->clear_rx_addr,
|
||||
sizeof(u32),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
@@ -1247,7 +1274,8 @@ static int bcm2835_spi_setup(struct spi_device *spi)
|
||||
*/
|
||||
dev_err(&spi->dev,
|
||||
"setup: only two native chip-selects are supported\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1268,14 +1296,20 @@ static int bcm2835_spi_setup(struct spi_device *spi)
|
||||
DRV_NAME,
|
||||
GPIO_LOOKUP_FLAGS_DEFAULT,
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(spi->cs_gpiod))
|
||||
return PTR_ERR(spi->cs_gpiod);
|
||||
if (IS_ERR(spi->cs_gpiod)) {
|
||||
ret = PTR_ERR(spi->cs_gpiod);
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
/* and set up the "mode" and level */
|
||||
dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n",
|
||||
spi->chip_select);
|
||||
|
||||
return 0;
|
||||
|
||||
err_cleanup:
|
||||
bcm2835_spi_cleanup(spi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bcm2835_spi_probe(struct platform_device *pdev)
|
||||
@@ -1284,8 +1318,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
|
||||
struct bcm2835_spi *bs;
|
||||
int err;
|
||||
|
||||
ctlr = devm_spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs),
|
||||
dma_get_cache_alignment()));
|
||||
ctlr = devm_spi_alloc_master(&pdev->dev, sizeof(*bs));
|
||||
if (!ctlr)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1296,6 +1329,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
|
||||
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||
ctlr->num_chipselect = 3;
|
||||
ctlr->setup = bcm2835_spi_setup;
|
||||
ctlr->cleanup = bcm2835_spi_cleanup;
|
||||
ctlr->transfer_one = bcm2835_spi_transfer_one;
|
||||
ctlr->handle_err = bcm2835_spi_handle_err;
|
||||
ctlr->prepare_message = bcm2835_spi_prepare_message;
|
||||
|
||||
@@ -384,7 +384,7 @@ static int bcm2835aux_spi_transfer_one(struct spi_master *master,
|
||||
bs->pending = 0;
|
||||
|
||||
/* Calculate the estimated time in us the transfer runs. Note that
|
||||
* there are are 2 idle clocks cycles after each chunk getting
|
||||
* there are 2 idle clocks cycles after each chunk getting
|
||||
* transferred - in our case the chunk size is 3 bytes, so we
|
||||
* approximate this by 9 cycles/byte. This is used to find the number
|
||||
* of Hz per byte per polling limit. E.g., we can transfer 1 byte in
|
||||
|
||||
@@ -56,7 +56,7 @@ struct dw_spi_mscc {
|
||||
/*
|
||||
* The Designware SPI controller (referred to as master in the documentation)
|
||||
* automatically deasserts chip select when the tx fifo is empty. The chip
|
||||
* selects then needs to be either driven as GPIOs or, for the first 4 using the
|
||||
* selects then needs to be either driven as GPIOs or, for the first 4 using
|
||||
* the SPI boot controller registers. the final chip select is an OR gate
|
||||
* between the Designware SPI controller and the SPI boot controller.
|
||||
*/
|
||||
|
||||
@@ -639,8 +639,8 @@ static irqreturn_t geni_spi_isr(int irq, void *data)
|
||||
complete(&mas->abort_done);
|
||||
|
||||
/*
|
||||
* It's safe or a good idea to Ack all of our our interrupts at the
|
||||
* end of the function. Specifically:
|
||||
* It's safe or a good idea to Ack all of our interrupts at the end
|
||||
* of the function. Specifically:
|
||||
* - M_CMD_DONE_EN / M_RX_FIFO_LAST_EN: Edge triggered interrupts and
|
||||
* clearing Acks. Clearing at the end relies on nobody else having
|
||||
* started a new transfer yet or else we could be clearing _their_
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user