spi: Updates for v6.10

The diffstat for this release is dominated by the new Airoha driver,
 mainly as a result of this being a generally quite quiet release.  There
 were a couple of cleanups in the core but nothing substantial, the
 updates here are almost all driver specific ones.
 
  - Support for multi-word mode in the OMAP2 McSPI driver.
  - Overhaul of the PXA2xx driver, mostly API updates.
  - A number of DT binding conversions.
  - Support for Airoha NAND controllers, Cirrus Logic CS35L56, Mobileye
    EYEQ5 and Renesas R8A779H0.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmZB2z0ACgkQJNaLcl1U
 h9CCxgf/ZSy6jKbUejdq/JtdrhVCamaEVQ1X5FAk18wlumQVwFC/Bsntr1hVWDjg
 Ai+G/UYWtfabyVePZKh1zCcoloSuZheHcxAMP+43un1doWcHps6leiPfb9yAysux
 VxeIBfSUOfeFbN697Jz8PDTIhxHMUh0R4QYqqIyrT1RSS0alRZoDyaQpTWied0Nt
 pOUWi9SVt0jm/G+X29a6Q/pFsr0oEJHxZgvriwlJAyzWr1OModFXdTfdK+qMS1Hn
 huafVu4bWCEognGlnXCQSRL94Fxo1nab1PvMuWK2VXNDL7xexqQ33cp4VILZvJo1
 qR9YtiRXpScAmO7f8ccGcSlz8vw5jQ==
 =x3Vz
 -----END PGP SIGNATURE-----

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

Pull spi updates from Mark Brown:
 "The diffstat for this release is dominated by the new Airoha driver,
  mainly as a result of this being a generally quite quiet release.
  There were a couple of cleanups in the core but nothing substantial,
  the updates here are almost all driver specific ones.

   - Support for multi-word mode in the OMAP2 McSPI driver

   - Overhaul of the PXA2xx driver, mostly API updates

   - A number of DT binding conversions

   - Support for Airoha NAND controllers, Cirrus Logic CS35L56, Mobileye
     EYEQ5 and Renesas R8A779H0"

* tag 'spi-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (87 commits)
  spi: dw: Bail out early on unsupported target mode
  spi: Remove unneded check for orig_nents
  MAINTAINERS: repair file entry in AIROHA SPI SNFI DRIVER
  spi: pxa2xx: Drop the stale entry in documentation TOC
  spi: pxa2xx: Don't provide struct chip_data for others
  spi: pxa2xx: Remove timeout field from struct chip_data
  spi: pxa2xx: Remove DMA parameters from struct chip_data
  spi: pxa2xx: Drop struct pxa2xx_spi_chip
  spi: pxa2xx: Don't use "proxy" headers
  spi: pxa2xx: Remove outdated documentation
  spi: pxa2xx: Move contents of linux/spi/pxa2xx_spi.h to a local one
  spi: pxa2xx: Provide num-cs for Sharp PDAs via device properties
  spi: pxa2xx: Allow number of chip select pins to be read from property
  spi: dt-bindings: ti,qspi: convert to dtschema
  spi: bitbang: Add missing MODULE_DESCRIPTION()
  spi: bitbang: Use NSEC_PER_*SEC rather than hard coding
  spi: dw: Drop default number of CS setting
  spi: dw: Convert dw_spi::num_cs to u32
  spi: dw: Add a number of native CS auto-detection
  spi: dw: Convert to using BITS_TO_BYTES() macro
  ...
This commit is contained in:
Linus Torvalds 2024-05-14 14:41:01 -07:00
commit e2b4a5bf32
63 changed files with 2224 additions and 928 deletions

View File

@ -0,0 +1,65 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/airoha,en7581-snand.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: SPI-NAND flash controller for Airoha ARM SoCs
maintainers:
- Lorenzo Bianconi <lorenzo@kernel.org>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
const: airoha,en7581-snand
reg:
items:
- description: spi base address
- description: nfi2spi base address
clocks:
maxItems: 1
clock-names:
items:
- const: spi
required:
- compatible
- reg
- clocks
- clock-names
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/en7523-clk.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
spi@1fa10000 {
compatible = "airoha,en7581-snand";
reg = <0x0 0x1fa10000 0x0 0x140>,
<0x0 0x1fa11000 0x0 0x160>;
clocks = <&scuclk EN7523_CLK_SPI>;
clock-names = "spi";
#address-cells = <1>;
#size-cells = <0>;
flash@0 {
compatible = "spi-nand";
reg = <0>;
spi-tx-bus-width = <1>;
spi-rx-bus-width = <2>;
};
};
};

View File

@ -68,12 +68,13 @@ properties:
- items: - items:
- enum: - enum:
- amd,pensando-elba-qspi - amd,pensando-elba-qspi
- ti,k2g-qspi
- ti,am654-ospi
- intel,lgm-qspi - intel,lgm-qspi
- xlnx,versal-ospi-1.0
- intel,socfpga-qspi - intel,socfpga-qspi
- mobileye,eyeq5-ospi
- starfive,jh7110-qspi - starfive,jh7110-qspi
- ti,am654-ospi
- ti,k2g-qspi
- xlnx,versal-ospi-1.0
- const: cdns,qspi-nor - const: cdns,qspi-nor
- const: cdns,qspi-nor - const: cdns,qspi-nor
@ -145,7 +146,6 @@ required:
- reg - reg
- interrupts - interrupts
- clocks - clocks
- cdns,fifo-depth
- cdns,fifo-width - cdns,fifo-width
- cdns,trigger-address - cdns,trigger-address
- '#address-cells' - '#address-cells'

View File

@ -0,0 +1,55 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/marvell,armada-3700-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell Armada 3700 SPI Controller
description:
The SPI controller on Marvell Armada 3700 SoC.
maintainers:
- Kousik Sanagavarapu <five231003@gmail.com>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
const: marvell,armada-3700-spi
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
num-cs:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
spi0: spi@10600 {
compatible = "marvell,armada-3700-spi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x10600 0x5d>;
clocks = <&nb_perih_clk 7>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
num-cs = <4>;
};
...

View File

@ -54,6 +54,7 @@ properties:
- renesas,msiof-r8a779a0 # R-Car V3U - renesas,msiof-r8a779a0 # R-Car V3U
- renesas,msiof-r8a779f0 # R-Car S4-8 - renesas,msiof-r8a779f0 # R-Car S4-8
- renesas,msiof-r8a779g0 # R-Car V4H - renesas,msiof-r8a779g0 # R-Car V4H
- renesas,msiof-r8a779h0 # R-Car V4M
- const: renesas,rcar-gen4-msiof # generic R-Car Gen4 - const: renesas,rcar-gen4-msiof # generic R-Car Gen4
# compatible device # compatible device
- items: - items:

View File

@ -1,25 +0,0 @@
* Marvell Armada 3700 SPI Controller
Required Properties:
- compatible: should be "marvell,armada-3700-spi"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: The interrupt number. The interrupt specifier format depends on
the interrupt controller and of its driver.
- clocks: Must contain the clock source, usually from the North Bridge clocks.
- num-cs: The number of chip selects that is supported by this SPI Controller
- #address-cells: should be 1.
- #size-cells: should be 0.
Example:
spi0: spi@10600 {
compatible = "marvell,armada-3700-spi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x10600 0x5d>;
clocks = <&nb_perih_clk 7>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
num-cs = <4>;
};

View File

@ -0,0 +1,96 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/ti,qspi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI QSPI controller
maintainers:
- Kousik Sanagavarapu <five231003@gmail.com>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
enum:
- ti,am4372-qspi
- ti,dra7xxx-qspi
reg:
items:
- description: base registers
- description: mapped memory
reg-names:
items:
- const: qspi_base
- const: qspi_mmap
clocks:
maxItems: 1
clock-names:
items:
- const: fck
interrupts:
maxItems: 1
num-cs:
minimum: 1
maximum: 4
default: 1
ti,hwmods:
description:
Name of the hwmod associated to the QSPI. This is for legacy
platforms only.
$ref: /schemas/types.yaml#/definitions/string
deprecated: true
syscon-chipselects:
description:
Handle to system control region containing QSPI chipselect register
and offset of that register.
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: phandle to system control register
- description: register offset
spi-max-frequency:
description: Maximum SPI clocking speed of the controller in Hz.
$ref: /schemas/types.yaml#/definitions/uint32
required:
- compatible
- reg
- reg-names
- clocks
- clock-names
- interrupts
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/dra7.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
spi@4b300000 {
compatible = "ti,dra7xxx-qspi";
reg = <0x4b300000 0x100>,
<0x5c000000 0x4000000>;
reg-names = "qspi_base", "qspi_mmap";
syscon-chipselects = <&scm_conf 0x558>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&l4per2_clkctrl DRA7_L4PER2_QSPI_CLKCTRL 25>;
clock-names = "fck";
num-cs = <4>;
spi-max-frequency = <48000000>;
interrupts = <GIC_SPI 343 IRQ_TYPE_LEVEL_HIGH>;
};
...

View File

@ -1,53 +0,0 @@
TI QSPI controller.
Required properties:
- compatible : should be "ti,dra7xxx-qspi" or "ti,am4372-qspi".
- reg: Should contain QSPI registers location and length.
- reg-names: Should contain the resource reg names.
- qspi_base: Qspi configuration register Address space
- qspi_mmap: Memory mapped Address space
- (optional) qspi_ctrlmod: Control module Address space
- interrupts: should contain the qspi interrupt number.
- #address-cells, #size-cells : Must be present if the device has sub-nodes
- ti,hwmods: Name of the hwmod associated to the QSPI
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Optional properties:
- syscon-chipselects: Handle to system control region contains QSPI
chipselect register and offset of that register.
NOTE: TI QSPI controller requires different pinmux and IODelay
parameters for Mode-0 and Mode-3 operations, which needs to be set up by
the bootloader (U-Boot). Default configuration only supports Mode-0
operation. Hence, "spi-cpol" and "spi-cpha" DT properties cannot be
specified in the slave nodes of TI QSPI controller without appropriate
modification to bootloader.
Example:
For am4372:
qspi: qspi@47900000 {
compatible = "ti,am4372-qspi";
reg = <0x47900000 0x100>, <0x30000000 0x4000000>;
reg-names = "qspi_base", "qspi_mmap";
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <25000000>;
ti,hwmods = "qspi";
};
For dra7xx:
qspi: qspi@4b300000 {
compatible = "ti,dra7xxx-qspi";
reg = <0x4b300000 0x100>,
<0x5c000000 0x4000000>,
reg-names = "qspi_base", "qspi_mmap";
syscon-chipselects = <&scm_conf 0x558>;
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <48000000>;
ti,hwmods = "qspi";
};

View File

@ -10,7 +10,6 @@ Serial Peripheral Interface (SPI)
spi-summary spi-summary
spidev spidev
butterfly butterfly
pxa2xx
spi-lm70llp spi-lm70llp
spi-sc18is602 spi-sc18is602

View File

@ -1,211 +0,0 @@
==============================
PXA2xx SPI on SSP driver HOWTO
==============================
This a mini HOWTO on the pxa2xx_spi driver. The driver turns a PXA2xx
synchronous serial port into an SPI host controller
(see Documentation/spi/spi-summary.rst). The driver has the following features
- Support for any PXA2xx and compatible SSP.
- SSP PIO and SSP DMA data transfers.
- External and Internal (SSPFRM) chip selects.
- Per peripheral device (chip) configuration.
- Full suspend, freeze, resume support.
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 host controllers
---------------------------------
Typically, for a legacy platform, an SPI host controller is defined in the
arch/.../mach-*/board-*.c as a "platform device". The host controller 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
peripheral devices (chips) attached to this SPI host controller.
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 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 HOST SAMPLE
----------------
Below is a sample configuration using the PXA255 NSSP for a legacy platform::
static struct resource pxa_spi_nssp_resources[] = {
[0] = {
.start = __PREG(SSCR0_P(2)), /* Start address of NSSP */
.end = __PREG(SSCR0_P(2)) + 0x2c, /* Range of registers */
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_NSSP, /* NSSP IRQ */
.end = IRQ_NSSP,
.flags = IORESOURCE_IRQ,
},
};
static struct pxa2xx_spi_controller pxa_nssp_controller_info = {
.num_chipselect = 1, /* Matches the number of chips attached to NSSP */
.enable_dma = 1, /* Enables NSSP DMA */
};
static struct platform_device pxa_spi_nssp = {
.name = "pxa2xx-spi", /* MUST BE THIS VALUE, so device match driver */
.id = 2, /* Bus number, MUST MATCH SSP number 1..n */
.resource = pxa_spi_nssp_resources,
.num_resources = ARRAY_SIZE(pxa_spi_nssp_resources),
.dev = {
.platform_data = &pxa_nssp_controller_info, /* Passed to driver */
},
};
static struct platform_device *devices[] __initdata = {
&pxa_spi_nssp,
};
static void __init board_init(void)
{
(void)platform_add_device(devices, ARRAY_SIZE(devices));
}
Declaring peripheral devices
----------------------------
Typically, for a legacy platform, each SPI peripheral device (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 peripheral device (chip) attached to the PXA2xx must provide specific chip configuration
information via the structure "pxa2xx_spi_chip" found in
"include/linux/spi/pxa2xx_spi.h". The PXA2xx host controller driver will use
the configuration whenever the driver communicates with the peripheral
device. All fields are optional.
::
struct pxa2xx_spi_chip {
u8 tx_threshold;
u8 rx_threshold;
u8 dma_burst_size;
u32 timeout;
};
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
performance of pxa2xx_spi driver and misconfiguration will result in rx
FIFO overruns (especially in PIO mode transfers). Good default values are::
.tx_threshold = 8,
.rx_threshold = 8,
The range is 1 to 16 where zero indicates "use default".
The "pxa2xx_spi_chip.dma_burst_size" field is used to configure PXA2xx DMA
engine and is related the "spi_device.bits_per_word" field. Read and understand
the PXA2xx "Developer Manual" sections on the DMA controller and SSP Controllers
to determine the correct value. An SSP configured for byte-wide transfers would
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
dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
peripheral device. Please note that the PXA2xx SSP 1 does not support trailing byte
timeouts and must busy-wait any trailing bytes.
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 a descriptor)
to accommodate these chips.
NSSP PERIPHERAL SAMPLE
----------------------
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.
::
static struct pxa2xx_spi_chip cs8415a_chip_info = {
.tx_threshold = 8, /* SSP hardware FIFO threshold */
.rx_threshold = 8, /* SSP hardware FIFO threshold */
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
.timeout = 235, /* See Intel documentation */
};
static struct pxa2xx_spi_chip cs8405a_chip_info = {
.tx_threshold = 8, /* SSP hardware FIFO threshold */
.rx_threshold = 8, /* SSP hardware FIFO threshold */
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
.timeout = 235, /* See Intel documentation */
};
static struct spi_board_info streetracer_spi_board_info[] __initdata = {
{
.modalias = "cs8415a", /* Name of spi_driver for this device */
.max_speed_hz = 3686400, /* Run SSP as fast a possible */
.bus_num = 2, /* Framework bus number */
.chip_select = 0, /* Framework chip select */
.platform_data = NULL; /* No spi_driver specific config */
.controller_data = &cs8415a_chip_info, /* Host controller config */
.irq = STREETRACER_APCI_IRQ, /* Peripheral device interrupt */
},
{
.modalias = "cs8405a", /* Name of spi_driver for this device */
.max_speed_hz = 3686400, /* Run SSP as fast a possible */
.bus_num = 2, /* Framework bus number */
.chip_select = 1, /* Framework chip select */
.controller_data = &cs8405a_chip_info, /* Host controller config */
.irq = STREETRACER_APCI_IRQ, /* Peripheral device interrupt */
},
};
static void __init streetracer_init(void)
{
spi_register_board_info(streetracer_spi_board_info,
ARRAY_SIZE(streetracer_spi_board_info));
}
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.
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
a per "spi_transfer" basis::
if spi_message.len > 65536 then
if spi_message.is_dma_mapped or rx_dma_buf != 0 or tx_dma_buf != 0 then
reject premapped transfers
print "rate limited" warning
use PIO transfers
if enable_dma and the size is in the range [DMA burst size..65536] then
use streaming DMA mode
otherwise
use PIO transfer
THANKS TO
---------
David Brownell and others for mentoring the development of this driver.

View File

@ -348,7 +348,6 @@ SPI protocol drivers somewhat resemble platform device drivers::
static struct spi_driver CHIP_driver = { static struct spi_driver CHIP_driver = {
.driver = { .driver = {
.name = "CHIP", .name = "CHIP",
.owner = THIS_MODULE,
.pm = &CHIP_pm_ops, .pm = &CHIP_pm_ops,
}, },
@ -419,10 +418,6 @@ any more such messages.
to make extra copies unless the hardware requires it (e.g. working to make extra copies unless the hardware requires it (e.g. working
around hardware errata that force the use of bounce buffering). around hardware errata that force the use of bounce buffering).
If standard dma_map_single() handling of these buffers is inappropriate,
you can use spi_message.is_dma_mapped to tell the controller driver
that you've already provided the relevant DMA addresses.
- The basic I/O primitive is spi_async(). Async requests may be - The basic I/O primitive is spi_async(). Async requests may be
issued in any context (irq handler, task, etc) and completion issued in any context (irq handler, task, etc) and completion
is reported using a callback provided with the message. is reported using a callback provided with the message.

View File

@ -653,6 +653,15 @@ S: Supported
F: fs/aio.c F: fs/aio.c
F: include/linux/*aio*.h F: include/linux/*aio*.h
AIROHA SPI SNFI DRIVER
M: Lorenzo Bianconi <lorenzo@kernel.org>
M: Ray Liu <ray.liu@airoha.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-spi@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/spi/airoha,en7581-snand.yaml
F: drivers/spi/spi-airoha-snfi.c
AIRSPY MEDIA DRIVER AIRSPY MEDIA DRIVER
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
S: Orphan S: Orphan
@ -21915,7 +21924,7 @@ F: Documentation/devicetree/bindings/sound/tas2552.txt
F: Documentation/devicetree/bindings/sound/tas2562.yaml F: Documentation/devicetree/bindings/sound/tas2562.yaml
F: Documentation/devicetree/bindings/sound/tas2770.yaml F: Documentation/devicetree/bindings/sound/tas2770.yaml
F: Documentation/devicetree/bindings/sound/tas27xx.yaml F: Documentation/devicetree/bindings/sound/tas27xx.yaml
F: Documentation/devicetree/bindings/sound/ti,pcm1681.txt F: Documentation/devicetree/bindings/sound/ti,pcm1681.yaml
F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml
F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml
F: Documentation/devicetree/bindings/sound/tlv320adcx140.yaml F: Documentation/devicetree/bindings/sound/tlv320adcx140.yaml

View File

@ -7,7 +7,6 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/platform_data/i2c-pxa.h> #include <linux/platform_data/i2c-pxa.h>
#include <linux/soc/pxa/cpu.h> #include <linux/soc/pxa/cpu.h>
@ -665,23 +664,6 @@ struct platform_device pxa27x_device_gpio = {
.resource = pxa_resource_gpio, .resource = pxa_resource_gpio,
}; };
/* pxa2xx-spi platform-device ID equals respective SSP platform-device ID + 1.
* See comment in arch/arm/mach-pxa/ssp.c::ssp_probe() */
void __init pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_controller *info)
{
struct platform_device *pd;
pd = platform_device_alloc("pxa2xx-spi", id);
if (pd == NULL) {
printk(KERN_ERR "pxa2xx-spi: failed to allocate device id %d\n",
id);
return;
}
pd->dev.platform_data = info;
platform_device_add(pd);
}
static struct resource pxa_dma_resource[] = { static struct resource pxa_dma_resource[] = {
[0] = { [0] = {
.start = 0x40000000, .start = 0x40000000,

View File

@ -18,10 +18,10 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/platform_data/i2c-pxa.h> #include <linux/platform_data/i2c-pxa.h>
#include <linux/platform_data/pca953x.h> #include <linux/platform_data/pca953x.h>
#include <linux/property.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/ads7846.h> #include <linux/spi/ads7846.h>
#include <linux/spi/corgi_lcd.h> #include <linux/spi/corgi_lcd.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/mtd/sharpsl.h> #include <linux/mtd/sharpsl.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/input-event-codes.h> #include <linux/input-event-codes.h>
@ -569,10 +569,6 @@ static struct spi_board_info spitz_spi_devices[] = {
}, },
}; };
static struct pxa2xx_spi_controller spitz_spi_info = {
.num_chipselect = 3,
};
static struct gpiod_lookup_table spitz_spi_gpio_table = { static struct gpiod_lookup_table spitz_spi_gpio_table = {
.dev_id = "spi2", .dev_id = "spi2",
.table = { .table = {
@ -583,8 +579,21 @@ static struct gpiod_lookup_table spitz_spi_gpio_table = {
}, },
}; };
static const struct property_entry spitz_spi_properties[] = {
PROPERTY_ENTRY_U32("num-cs", 3),
{ }
};
static const struct software_node spitz_spi_node = {
.properties = spitz_spi_properties,
};
static void __init spitz_spi_init(void) static void __init spitz_spi_init(void)
{ {
struct platform_device *pd;
int id = 2;
int err;
if (machine_is_akita()) if (machine_is_akita())
gpiod_add_lookup_table(&akita_lcdcon_gpio_table); gpiod_add_lookup_table(&akita_lcdcon_gpio_table);
else else
@ -592,7 +601,21 @@ static void __init spitz_spi_init(void)
gpiod_add_lookup_table(&spitz_ads7846_gpio_table); gpiod_add_lookup_table(&spitz_ads7846_gpio_table);
gpiod_add_lookup_table(&spitz_spi_gpio_table); gpiod_add_lookup_table(&spitz_spi_gpio_table);
pxa2xx_set_spi_info(2, &spitz_spi_info);
/* pxa2xx-spi platform-device ID equals respective SSP platform-device ID + 1 */
pd = platform_device_alloc("pxa2xx-spi", id);
if (pd == NULL) {
pr_err("pxa2xx-spi: failed to allocate device id %d\n", id);
} else {
err = device_add_software_node(&pd->dev, &spitz_spi_node);
if (err) {
platform_device_put(pd);
pr_err("pxa2xx-spi: failed to add software node\n");
} else {
platform_device_add(pd);
}
}
spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices)); spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices));
} }
#else #else

View File

@ -103,6 +103,15 @@ config GPIO_REGMAP
select REGMAP select REGMAP
tristate tristate
config GPIO_SWNODE_UNDEFINED
bool
help
This adds a special place holder for software nodes to contain an
undefined GPIO reference, this is primarily used by SPI to allow a
list of GPIO chip selects to mark a certain chip select as being
controlled the SPI device's internal chip select mechanism and not
a GPIO.
# put drivers in the right section, in alphabetical order # put drivers in the right section, in alphabetical order
# This symbol is selected by both I2C and SPI expanders # This symbol is selected by both I2C and SPI expanders

View File

@ -4,8 +4,13 @@
* *
* Copyright 2022 Google LLC * Copyright 2022 Google LLC
*/ */
#define pr_fmt(fmt) "gpiolib: swnode: " fmt
#include <linux/err.h> #include <linux/err.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/property.h> #include <linux/property.h>
@ -17,6 +22,8 @@
#include "gpiolib.h" #include "gpiolib.h"
#include "gpiolib-swnode.h" #include "gpiolib-swnode.h"
#define GPIOLIB_SWNODE_UNDEFINED_NAME "swnode-gpio-undefined"
static void swnode_format_propname(const char *con_id, char *propname, static void swnode_format_propname(const char *con_id, char *propname,
size_t max_size) size_t max_size)
{ {
@ -40,6 +47,14 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode)
if (!gdev_node || !gdev_node->name) if (!gdev_node || !gdev_node->name)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
/*
* Check for a special node that identifies undefined GPIOs, this is
* primarily used as a key for internal chip selects in SPI bindings.
*/
if (IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) &&
!strcmp(gdev_node->name, GPIOLIB_SWNODE_UNDEFINED_NAME))
return ERR_PTR(-ENOENT);
gdev = gpio_device_find_by_label(gdev_node->name); gdev = gpio_device_find_by_label(gdev_node->name);
return gdev ?: ERR_PTR(-EPROBE_DEFER); return gdev ?: ERR_PTR(-EPROBE_DEFER);
} }
@ -121,3 +136,32 @@ int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id)
return count ?: -ENOENT; return count ?: -ENOENT;
} }
#if IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED)
/*
* A special node that identifies undefined GPIOs, this is primarily used as
* a key for internal chip selects in SPI bindings.
*/
const struct software_node swnode_gpio_undefined = {
.name = GPIOLIB_SWNODE_UNDEFINED_NAME,
};
EXPORT_SYMBOL_NS_GPL(swnode_gpio_undefined, GPIO_SWNODE);
static int __init swnode_gpio_init(void)
{
int ret;
ret = software_node_register(&swnode_gpio_undefined);
if (ret < 0)
pr_err("failed to register swnode: %d\n", ret);
return ret;
}
subsys_initcall(swnode_gpio_init);
static void __exit swnode_gpio_cleanup(void)
{
software_node_unregister(&swnode_gpio_undefined);
}
__exitcall(swnode_gpio_cleanup);
#endif

View File

@ -25,7 +25,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/pxa2xx_ssp.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>

View File

@ -57,6 +57,16 @@ config SPI_MEM
comment "SPI Master Controller Drivers" comment "SPI Master Controller Drivers"
config SPI_AIROHA_SNFI
tristate "Airoha SPI NAND Flash Interface"
depends on ARCH_AIROHA || COMPILE_TEST
depends on SPI_MASTER
select REGMAP_MMIO
help
This enables support for SPI-NAND mode on the Airoha NAND
Flash Interface found on Airoha ARM SoCs. This controller
is implemented as a SPI-MEM controller.
config SPI_ALTERA config SPI_ALTERA
tristate "Altera SPI Controller platform driver" tristate "Altera SPI Controller platform driver"
select SPI_ALTERA_CORE select SPI_ALTERA_CORE
@ -216,11 +226,11 @@ config SPI_BCMBCA_HSSPI
explicitly. explicitly.
config SPI_BITBANG config SPI_BITBANG
tristate "Utilities for Bitbanging SPI masters" tristate "Utilities for Bitbanging SPI host controllers"
help help
With a few GPIO pins, your system can bitbang the SPI protocol. With a few GPIO pins, your system can bitbang the SPI protocol.
Select this to get SPI support through I/O pins (GPIO, parallel Select this to get SPI support through I/O pins (GPIO, parallel
port, etc). Or, some systems' SPI master controller drivers use port, etc). Or, some systems' SPI host controller drivers use
this code to manage the per-word or per-transfer accesses to the this code to manage the per-word or per-transfer accesses to the
hardware shift registers. hardware shift registers.
@ -246,7 +256,7 @@ config SPI_CADENCE
config SPI_CADENCE_QUADSPI config SPI_CADENCE_QUADSPI
tristate "Cadence Quad SPI controller" tristate "Cadence Quad SPI controller"
depends on OF && (ARM || ARM64 || X86 || RISCV || COMPILE_TEST) depends on OF && (ARM || ARM64 || X86 || RISCV || MIPS || COMPILE_TEST)
help help
Enable support for the Cadence Quad SPI Flash controller. Enable support for the Cadence Quad SPI Flash controller.
@ -284,6 +294,7 @@ config SPI_COLDFIRE_QSPI
config SPI_CS42L43 config SPI_CS42L43
tristate "Cirrus Logic CS42L43 SPI controller" tristate "Cirrus Logic CS42L43 SPI controller"
depends on MFD_CS42L43 && PINCTRL_CS42L43 depends on MFD_CS42L43 && PINCTRL_CS42L43
select GPIO_SWNODE_UNDEFINED
help help
This enables support for the SPI controller inside the Cirrus Logic This enables support for the SPI controller inside the Cirrus Logic
CS42L43 audio codec. CS42L43 audio codec.
@ -817,12 +828,11 @@ config SPI_PPC4xx
config SPI_PXA2XX config SPI_PXA2XX
tristate "PXA2xx SSP SPI master" tristate "PXA2xx SSP SPI master"
depends on ARCH_PXA || ARCH_MMP || PCI || ACPI || COMPILE_TEST depends on ARCH_PXA || ARCH_MMP || (X86 && (PCI || ACPI)) || COMPILE_TEST
select PXA_SSP if ARCH_PXA || ARCH_MMP select PXA_SSP if ARCH_PXA || ARCH_MMP
help help
This enables using a PXA2xx or Sodaville SSP port as a SPI master This enables using a PXA2xx or Sodaville SSP port as a SPI master
controller. The driver can be configured to use any SSP port and controller. The driver can be configured to use any SSP port.
additional documentation can be found a Documentation/spi/pxa2xx.rst.
config SPI_PXA2XX_PCI config SPI_PXA2XX_PCI
def_tristate SPI_PXA2XX && PCI && COMMON_CLK def_tristate SPI_PXA2XX && PCI && COMMON_CLK

View File

@ -14,6 +14,7 @@ obj-$(CONFIG_SPI_SPIDEV) += spidev.o
obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o obj-$(CONFIG_SPI_LOOPBACK_TEST) += spi-loopback-test.o
# SPI master controller drivers (bus) # SPI master controller drivers (bus)
obj-$(CONFIG_SPI_AIROHA_SNFI) += spi-airoha-snfi.o
obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o
obj-$(CONFIG_SPI_ALTERA_CORE) += spi-altera-core.o obj-$(CONFIG_SPI_ALTERA_CORE) += spi-altera-core.o
obj-$(CONFIG_SPI_ALTERA_DFL) += spi-altera-dfl.o obj-$(CONFIG_SPI_ALTERA_DFL) += spi-altera-dfl.o

File diff suppressed because it is too large Load Diff

View File

@ -169,4 +169,3 @@ module_platform_driver(altera_spi_driver);
MODULE_DESCRIPTION("Altera SPI driver"); MODULE_DESCRIPTION("Altera SPI driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>"); MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -13,6 +13,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/spi/spi-mem.h>
#define AMD_SPI_CTRL0_REG 0x00 #define AMD_SPI_CTRL0_REG 0x00
#define AMD_SPI_EXEC_CMD BIT(16) #define AMD_SPI_EXEC_CMD BIT(16)
@ -35,6 +36,7 @@
#define AMD_SPI_FIFO_SIZE 70 #define AMD_SPI_FIFO_SIZE 70
#define AMD_SPI_MEM_SIZE 200 #define AMD_SPI_MEM_SIZE 200
#define AMD_SPI_MAX_DATA 64
#define AMD_SPI_ENA_REG 0x20 #define AMD_SPI_ENA_REG 0x20
#define AMD_SPI_ALT_SPD_SHIFT 20 #define AMD_SPI_ALT_SPD_SHIFT 20
@ -358,6 +360,115 @@ fin_msg:
return message->status; return message->status;
} }
static bool amd_spi_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
/* bus width is number of IO lines used to transmit */
if (op->cmd.buswidth > 1 || op->addr.buswidth > 1 ||
op->data.buswidth > 1 || op->data.nbytes > AMD_SPI_MAX_DATA)
return false;
return spi_mem_default_supports_op(mem, op);
}
static int amd_spi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
{
op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_MAX_DATA);
return 0;
}
static void amd_spi_set_addr(struct amd_spi *amd_spi,
const struct spi_mem_op *op)
{
u8 nbytes = op->addr.nbytes;
u64 addr_val = op->addr.val;
int base_addr, i;
base_addr = AMD_SPI_FIFO_BASE + nbytes;
for (i = 0; i < nbytes; i++) {
amd_spi_writereg8(amd_spi, base_addr - i - 1, addr_val &
GENMASK(7, 0));
addr_val >>= 8;
}
}
static void amd_spi_mem_data_out(struct amd_spi *amd_spi,
const struct spi_mem_op *op)
{
int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes;
u8 *buf = (u8 *)op->data.buf.out;
u32 nbytes = op->data.nbytes;
int i;
amd_spi_set_opcode(amd_spi, op->cmd.opcode);
amd_spi_set_addr(amd_spi, op);
for (i = 0; i < nbytes; i++)
amd_spi_writereg8(amd_spi, (base_addr + i), buf[i]);
amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->data.nbytes);
amd_spi_set_rx_count(amd_spi, 0);
amd_spi_clear_fifo_ptr(amd_spi);
amd_spi_execute_opcode(amd_spi);
}
static void amd_spi_mem_data_in(struct amd_spi *amd_spi,
const struct spi_mem_op *op)
{
int offset = (op->addr.nbytes == 0) ? 0 : 1;
u8 *buf = (u8 *)op->data.buf.in;
u32 nbytes = op->data.nbytes;
int base_addr, i;
base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes + offset;
amd_spi_set_opcode(amd_spi, op->cmd.opcode);
amd_spi_set_addr(amd_spi, op);
amd_spi_set_tx_count(amd_spi, op->addr.nbytes);
amd_spi_set_rx_count(amd_spi, op->data.nbytes + 1);
amd_spi_clear_fifo_ptr(amd_spi);
amd_spi_execute_opcode(amd_spi);
amd_spi_busy_wait(amd_spi);
for (i = 0; i < nbytes; i++)
buf[i] = amd_spi_readreg8(amd_spi, base_addr + i);
}
static int amd_spi_exec_mem_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct amd_spi *amd_spi;
int ret;
amd_spi = spi_controller_get_devdata(mem->spi->controller);
ret = amd_set_spi_freq(amd_spi, mem->spi->max_speed_hz);
if (ret)
return ret;
switch (op->data.dir) {
case SPI_MEM_DATA_IN:
amd_spi_mem_data_in(amd_spi, op);
break;
case SPI_MEM_DATA_OUT:
fallthrough;
case SPI_MEM_NO_DATA:
amd_spi_mem_data_out(amd_spi, op);
break;
default:
ret = -EOPNOTSUPP;
}
return ret;
}
static const struct spi_controller_mem_ops amd_spi_mem_ops = {
.exec_op = amd_spi_exec_mem_op,
.adjust_op_size = amd_spi_adjust_op_size,
.supports_op = amd_spi_supports_op,
};
static int amd_spi_host_transfer(struct spi_controller *host, static int amd_spi_host_transfer(struct spi_controller *host,
struct spi_message *msg) struct spi_message *msg)
{ {
@ -409,6 +520,7 @@ static int amd_spi_probe(struct platform_device *pdev)
host->min_speed_hz = AMD_SPI_MIN_HZ; host->min_speed_hz = AMD_SPI_MIN_HZ;
host->setup = amd_spi_host_setup; host->setup = amd_spi_host_setup;
host->transfer_one_message = amd_spi_host_transfer; host->transfer_one_message = amd_spi_host_transfer;
host->mem_ops = &amd_spi_mem_ops;
host->max_transfer_size = amd_spi_max_transfer_size; host->max_transfer_size = amd_spi_max_transfer_size;
host->max_message_size = amd_spi_max_transfer_size; host->max_message_size = amd_spi_max_transfer_size;

View File

@ -339,7 +339,7 @@ static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id)
static bool a3700_spi_wait_completion(struct spi_device *spi) static bool a3700_spi_wait_completion(struct spi_device *spi)
{ {
struct a3700_spi *a3700_spi; struct a3700_spi *a3700_spi;
unsigned int timeout; unsigned long time_left;
unsigned int ctrl_reg; unsigned int ctrl_reg;
unsigned long timeout_jiffies; unsigned long timeout_jiffies;
@ -361,12 +361,12 @@ static bool a3700_spi_wait_completion(struct spi_device *spi)
a3700_spi->wait_mask); a3700_spi->wait_mask);
timeout_jiffies = msecs_to_jiffies(A3700_SPI_TIMEOUT); timeout_jiffies = msecs_to_jiffies(A3700_SPI_TIMEOUT);
timeout = wait_for_completion_timeout(&a3700_spi->done, time_left = wait_for_completion_timeout(&a3700_spi->done,
timeout_jiffies); timeout_jiffies);
a3700_spi->wait_mask = 0; a3700_spi->wait_mask = 0;
if (timeout) if (time_left)
return true; return true;
/* there might be the case that right after we checked the /* there might be the case that right after we checked the

View File

@ -987,8 +987,6 @@ static void atmel_spi_pdc_next_xfer(struct spi_controller *host,
* For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma: * For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma:
* - The buffer is either valid for CPU access, else NULL * - The buffer is either valid for CPU access, else NULL
* - If the buffer is valid, so is its DMA address * - If the buffer is valid, so is its DMA address
*
* This driver manages the dma address unless message->is_dma_mapped.
*/ */
static int static int
atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
@ -1374,8 +1372,7 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
* DMA map early, for performance (empties dcache ASAP) and * DMA map early, for performance (empties dcache ASAP) and
* better fault reporting. * better fault reporting.
*/ */
if ((!host->cur_msg->is_dma_mapped) if (as->use_pdc) {
&& as->use_pdc) {
if (atmel_spi_dma_map_xfer(as, xfer) < 0) if (atmel_spi_dma_map_xfer(as, xfer) < 0)
return -ENOMEM; return -ENOMEM;
} }
@ -1454,8 +1451,7 @@ static int atmel_spi_one_transfer(struct spi_controller *host,
} }
} }
if (!host->cur_msg->is_dma_mapped if (as->use_pdc)
&& as->use_pdc)
atmel_spi_dma_unmap_xfer(host, xfer); atmel_spi_dma_unmap_xfer(host, xfer);
if (as->use_pdc) if (as->use_pdc)

View File

@ -314,11 +314,8 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
hw->tx = t->tx_buf; hw->tx = t->tx_buf;
hw->rx = t->rx_buf; hw->rx = t->rx_buf;
dma_tx_addr = t->tx_dma;
dma_rx_addr = t->rx_dma;
/* /*
* check if buffers are already dma mapped, map them otherwise:
* - first map the TX buffer, so cache data gets written to memory * - first map the TX buffer, so cache data gets written to memory
* - then map the RX buffer, so that cache entries (with * - then map the RX buffer, so that cache entries (with
* soon-to-be-stale data) get removed * soon-to-be-stale data) get removed
@ -326,23 +323,17 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
* use temp rx buffer (preallocated or realloc to fit) for rx dma * use temp rx buffer (preallocated or realloc to fit) for rx dma
*/ */
if (t->tx_buf) { if (t->tx_buf) {
if (t->tx_dma == 0) { /* if DMA_ADDR_INVALID, map it */ dma_tx_addr = dma_map_single(hw->dev, (void *)t->tx_buf,
dma_tx_addr = dma_map_single(hw->dev, t->len, DMA_TO_DEVICE);
(void *)t->tx_buf, if (dma_mapping_error(hw->dev, dma_tx_addr))
t->len, DMA_TO_DEVICE); dev_err(hw->dev, "tx dma map error\n");
if (dma_mapping_error(hw->dev, dma_tx_addr))
dev_err(hw->dev, "tx dma map error\n");
}
} }
if (t->rx_buf) { if (t->rx_buf) {
if (t->rx_dma == 0) { /* if DMA_ADDR_INVALID, map it */ dma_rx_addr = dma_map_single(hw->dev, (void *)t->rx_buf,
dma_rx_addr = dma_map_single(hw->dev, t->len, DMA_FROM_DEVICE);
(void *)t->rx_buf, if (dma_mapping_error(hw->dev, dma_rx_addr))
t->len, DMA_FROM_DEVICE); dev_err(hw->dev, "rx dma map error\n");
if (dma_mapping_error(hw->dev, dma_rx_addr))
dev_err(hw->dev, "rx dma map error\n");
}
} else { } else {
if (t->len > hw->dma_rx_tmpbuf_size) { if (t->len > hw->dma_rx_tmpbuf_size) {
int ret; int ret;
@ -398,10 +389,10 @@ static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
} }
/* unmap buffers if mapped above */ /* unmap buffers if mapped above */
if (t->rx_buf && t->rx_dma == 0) if (t->rx_buf)
dma_unmap_single(hw->dev, dma_rx_addr, t->len, dma_unmap_single(hw->dev, dma_rx_addr, t->len,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
if (t->tx_buf && t->tx_dma == 0) if (t->tx_buf)
dma_unmap_single(hw->dev, dma_tx_addr, t->len, dma_unmap_single(hw->dev, dma_tx_addr, t->len,
DMA_TO_DEVICE); DMA_TO_DEVICE);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* polling/bitbanging SPI master controller driver utilities * Polling/bitbanging SPI host controller controller driver utilities
*/ */
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -11,6 +11,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/time64.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h> #include <linux/spi/spi_bitbang.h>
@ -168,8 +169,8 @@ int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if (!hz) if (!hz)
hz = spi->max_speed_hz; hz = spi->max_speed_hz;
if (hz) { if (hz) {
cs->nsecs = (1000000000/2) / hz; cs->nsecs = (NSEC_PER_SEC / 2) / hz;
if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000)) if (cs->nsecs > (MAX_UDELAY_MS * NSEC_PER_MSEC))
return -EINVAL; return -EINVAL;
} }
@ -393,12 +394,12 @@ int spi_bitbang_init(struct spi_bitbang *bitbang)
EXPORT_SYMBOL_GPL(spi_bitbang_init); EXPORT_SYMBOL_GPL(spi_bitbang_init);
/** /**
* spi_bitbang_start - start up a polled/bitbanging SPI master driver * spi_bitbang_start - start up a polled/bitbanging SPI host controller driver
* @bitbang: driver handle * @bitbang: driver handle
* *
* Caller should have zero-initialized all parts of the structure, and then * Caller should have zero-initialized all parts of the structure, and then
* provided callbacks for chip selection and I/O loops. If the master has * provided callbacks for chip selection and I/O loops. If the host controller has
* a transfer method, its final step should call spi_bitbang_transfer; or, * a transfer method, its final step should call spi_bitbang_transfer(); or,
* that's the default if the transfer routine is not initialized. It should * that's the default if the transfer routine is not initialized. It should
* also set up the bus number and number of chipselects. * also set up the bus number and number of chipselects.
* *
@ -406,9 +407,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_init);
* hardware that basically exposes a shift register) or per-spi_transfer * hardware that basically exposes a shift register) or per-spi_transfer
* (which takes better advantage of hardware like fifos or DMA engines). * (which takes better advantage of hardware like fifos or DMA engines).
* *
* Drivers using per-word I/O loops should use (or call) spi_bitbang_setup, * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup(),
* spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi * spi_bitbang_cleanup() and spi_bitbang_setup_transfer() to handle those SPI
* master methods. Those methods are the defaults if the bitbang->txrx_bufs * host controller methods. Those methods are the defaults if the bitbang->txrx_bufs
* routine isn't initialized. * routine isn't initialized.
* *
* This routine registers the spi_controller, which will process requests in a * This routine registers the spi_controller, which will process requests in a
@ -417,7 +418,7 @@ EXPORT_SYMBOL_GPL(spi_bitbang_init);
* *
* On success, this routine will take a reference to the controller. The caller * On success, this routine will take a reference to the controller. The caller
* is responsible for calling spi_bitbang_stop() to decrement the reference and * is responsible for calling spi_bitbang_stop() to decrement the reference and
* spi_controller_put() as counterpart of spi_alloc_master() to prevent a memory * spi_controller_put() as counterpart of spi_alloc_host() to prevent a memory
* leak. * leak.
*/ */
int spi_bitbang_start(struct spi_bitbang *bitbang) int spi_bitbang_start(struct spi_bitbang *bitbang)
@ -450,4 +451,4 @@ void spi_bitbang_stop(struct spi_bitbang *bitbang)
EXPORT_SYMBOL_GPL(spi_bitbang_stop); EXPORT_SYMBOL_GPL(spi_bitbang_stop);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Utilities for Bitbanging SPI host controllers");

View File

@ -42,6 +42,7 @@ static_assert(CQSPI_MAX_CHIPSELECT <= SPI_CS_CNT_MAX);
#define CQSPI_NO_SUPPORT_WR_COMPLETION BIT(3) #define CQSPI_NO_SUPPORT_WR_COMPLETION BIT(3)
#define CQSPI_SLOW_SRAM BIT(4) #define CQSPI_SLOW_SRAM BIT(4)
#define CQSPI_NEEDS_APB_AHB_HAZARD_WAR BIT(5) #define CQSPI_NEEDS_APB_AHB_HAZARD_WAR BIT(5)
#define CQSPI_RD_NO_IRQ BIT(6)
/* Capabilities */ /* Capabilities */
#define CQSPI_SUPPORTS_OCTAL BIT(0) #define CQSPI_SUPPORTS_OCTAL BIT(0)
@ -102,6 +103,8 @@ struct cqspi_st {
bool apb_ahb_hazard; bool apb_ahb_hazard;
bool is_jh7110; /* Flag for StarFive JH7110 SoC */ bool is_jh7110; /* Flag for StarFive JH7110 SoC */
const struct cqspi_driver_platdata *ddata;
}; };
struct cqspi_driver_platdata { struct cqspi_driver_platdata {
@ -117,6 +120,7 @@ struct cqspi_driver_platdata {
/* Operation timeout value */ /* Operation timeout value */
#define CQSPI_TIMEOUT_MS 500 #define CQSPI_TIMEOUT_MS 500
#define CQSPI_READ_TIMEOUT_MS 10 #define CQSPI_READ_TIMEOUT_MS 10
#define CQSPI_BUSYWAIT_TIMEOUT_US 500
/* Runtime_pm autosuspend delay */ /* Runtime_pm autosuspend delay */
#define CQSPI_AUTOSUSPEND_TIMEOUT 2000 #define CQSPI_AUTOSUSPEND_TIMEOUT 2000
@ -295,13 +299,27 @@ struct cqspi_driver_platdata {
#define CQSPI_REG_VERSAL_DMA_VAL 0x602 #define CQSPI_REG_VERSAL_DMA_VAL 0x602
static int cqspi_wait_for_bit(void __iomem *reg, const u32 mask, bool clr) static int cqspi_wait_for_bit(const struct cqspi_driver_platdata *ddata,
void __iomem *reg, const u32 mask, bool clr,
bool busywait)
{ {
u64 timeout_us = CQSPI_TIMEOUT_MS * USEC_PER_MSEC;
u32 val; u32 val;
if (busywait) {
int ret = readl_relaxed_poll_timeout(reg, val,
(((clr ? ~val : val) & mask) == mask),
0, CQSPI_BUSYWAIT_TIMEOUT_US);
if (ret != -ETIMEDOUT)
return ret;
timeout_us -= CQSPI_BUSYWAIT_TIMEOUT_US;
}
return readl_relaxed_poll_timeout(reg, val, return readl_relaxed_poll_timeout(reg, val,
(((clr ? ~val : val) & mask) == mask), (((clr ? ~val : val) & mask) == mask),
10, CQSPI_TIMEOUT_MS * 1000); 10, timeout_us);
} }
static bool cqspi_is_idle(struct cqspi_st *cqspi) static bool cqspi_is_idle(struct cqspi_st *cqspi)
@ -334,11 +352,8 @@ static u32 cqspi_get_versal_dma_status(struct cqspi_st *cqspi)
static irqreturn_t cqspi_irq_handler(int this_irq, void *dev) static irqreturn_t cqspi_irq_handler(int this_irq, void *dev)
{ {
struct cqspi_st *cqspi = dev; struct cqspi_st *cqspi = dev;
const struct cqspi_driver_platdata *ddata = cqspi->ddata;
unsigned int irq_status; unsigned int irq_status;
struct device *device = &cqspi->pdev->dev;
const struct cqspi_driver_platdata *ddata;
ddata = of_device_get_match_data(device);
/* Read interrupt status */ /* Read interrupt status */
irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS); irq_status = readl(cqspi->iobase + CQSPI_REG_IRQSTATUS);
@ -434,8 +449,8 @@ static int cqspi_exec_flash_cmd(struct cqspi_st *cqspi, unsigned int reg)
writel(reg, reg_base + CQSPI_REG_CMDCTRL); writel(reg, reg_base + CQSPI_REG_CMDCTRL);
/* Polling for completion. */ /* Polling for completion. */
ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_CMDCTRL, ret = cqspi_wait_for_bit(cqspi->ddata, reg_base + CQSPI_REG_CMDCTRL,
CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1); CQSPI_REG_CMDCTRL_INPROGRESS_MASK, 1, true);
if (ret) { if (ret) {
dev_err(&cqspi->pdev->dev, dev_err(&cqspi->pdev->dev,
"Flash command execution timed out.\n"); "Flash command execution timed out.\n");
@ -492,8 +507,11 @@ static int cqspi_enable_dtr(struct cqspi_flash_pdata *f_pdata,
if (ret) if (ret)
return ret; return ret;
} else { } else {
reg &= ~CQSPI_REG_CONFIG_DTR_PROTO; unsigned int mask = CQSPI_REG_CONFIG_DTR_PROTO | CQSPI_REG_CONFIG_DUAL_OPCODE;
reg &= ~CQSPI_REG_CONFIG_DUAL_OPCODE; /* Shortcut if DTR is already disabled. */
if ((reg & mask) == 0)
return 0;
reg &= ~mask;
} }
writel(reg, reg_base + CQSPI_REG_CONFIG); writel(reg, reg_base + CQSPI_REG_CONFIG);
@ -700,6 +718,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
const size_t n_rx) const size_t n_rx)
{ {
struct cqspi_st *cqspi = f_pdata->cqspi; struct cqspi_st *cqspi = f_pdata->cqspi;
bool use_irq = !(cqspi->ddata && cqspi->ddata->quirks & CQSPI_RD_NO_IRQ);
struct device *dev = &cqspi->pdev->dev; struct device *dev = &cqspi->pdev->dev;
void __iomem *reg_base = cqspi->iobase; void __iomem *reg_base = cqspi->iobase;
void __iomem *ahb_base = cqspi->ahb_base; void __iomem *ahb_base = cqspi->ahb_base;
@ -723,17 +742,20 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
* all the read interrupts disabled for max performance. * all the read interrupts disabled for max performance.
*/ */
if (!cqspi->slow_sram) if (use_irq && cqspi->slow_sram)
writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);
else if (use_irq)
writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK); writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK);
else else
writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); writel(0, reg_base + CQSPI_REG_IRQMASK);
reinit_completion(&cqspi->transfer_complete); reinit_completion(&cqspi->transfer_complete);
writel(CQSPI_REG_INDIRECTRD_START_MASK, writel(CQSPI_REG_INDIRECTRD_START_MASK,
reg_base + CQSPI_REG_INDIRECTRD); reg_base + CQSPI_REG_INDIRECTRD);
while (remaining > 0) { while (remaining > 0) {
if (!wait_for_completion_timeout(&cqspi->transfer_complete, if (use_irq &&
!wait_for_completion_timeout(&cqspi->transfer_complete,
msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS)))
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
@ -775,7 +797,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
bytes_to_read = cqspi_get_rd_sram_level(cqspi); bytes_to_read = cqspi_get_rd_sram_level(cqspi);
} }
if (remaining > 0) { if (use_irq && remaining > 0) {
reinit_completion(&cqspi->transfer_complete); reinit_completion(&cqspi->transfer_complete);
if (cqspi->slow_sram) if (cqspi->slow_sram)
writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK);
@ -783,8 +805,8 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
} }
/* Check indirect done status */ /* Check indirect done status */
ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTRD, ret = cqspi_wait_for_bit(cqspi->ddata, reg_base + CQSPI_REG_INDIRECTRD,
CQSPI_REG_INDIRECTRD_DONE_MASK, 0); CQSPI_REG_INDIRECTRD_DONE_MASK, 0, true);
if (ret) { if (ret) {
dev_err(dev, "Indirect read completion error (%i)\n", ret); dev_err(dev, "Indirect read completion error (%i)\n", ret);
goto failrd; goto failrd;
@ -1084,8 +1106,8 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata,
} }
/* Check indirect done status */ /* Check indirect done status */
ret = cqspi_wait_for_bit(reg_base + CQSPI_REG_INDIRECTWR, ret = cqspi_wait_for_bit(cqspi->ddata, reg_base + CQSPI_REG_INDIRECTWR,
CQSPI_REG_INDIRECTWR_DONE_MASK, 0); CQSPI_REG_INDIRECTWR_DONE_MASK, 0, false);
if (ret) { if (ret) {
dev_err(dev, "Indirect write completion error (%i)\n", ret); dev_err(dev, "Indirect write completion error (%i)\n", ret);
goto failwr; goto failwr;
@ -1358,16 +1380,13 @@ static ssize_t cqspi_read(struct cqspi_flash_pdata *f_pdata,
const struct spi_mem_op *op) const struct spi_mem_op *op)
{ {
struct cqspi_st *cqspi = f_pdata->cqspi; struct cqspi_st *cqspi = f_pdata->cqspi;
struct device *dev = &cqspi->pdev->dev; const struct cqspi_driver_platdata *ddata = cqspi->ddata;
const struct cqspi_driver_platdata *ddata;
loff_t from = op->addr.val; loff_t from = op->addr.val;
size_t len = op->data.nbytes; size_t len = op->data.nbytes;
u_char *buf = op->data.buf.in; u_char *buf = op->data.buf.in;
u64 dma_align = (u64)(uintptr_t)buf; u64 dma_align = (u64)(uintptr_t)buf;
int ret; int ret;
ddata = of_device_get_match_data(dev);
ret = cqspi_read_setup(f_pdata, op); ret = cqspi_read_setup(f_pdata, op);
if (ret) if (ret)
return ret; return ret;
@ -1511,8 +1530,8 @@ static int cqspi_of_get_pdata(struct cqspi_st *cqspi)
cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs"); cqspi->is_decoded_cs = of_property_read_bool(np, "cdns,is-decoded-cs");
if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) { if (of_property_read_u32(np, "cdns,fifo-depth", &cqspi->fifo_depth)) {
dev_err(dev, "couldn't determine fifo-depth\n"); /* Zero signals FIFO depth should be runtime detected. */
return -ENXIO; cqspi->fifo_depth = 0;
} }
if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) { if (of_property_read_u32(np, "cdns,fifo-width", &cqspi->fifo_width)) {
@ -1542,8 +1561,6 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
{ {
u32 reg; u32 reg;
cqspi_controller_enable(cqspi, 0);
/* Configure the remap address register, no remap */ /* Configure the remap address register, no remap */
writel(0, cqspi->iobase + CQSPI_REG_REMAP); writel(0, cqspi->iobase + CQSPI_REG_REMAP);
@ -1577,8 +1594,29 @@ static void cqspi_controller_init(struct cqspi_st *cqspi)
reg |= CQSPI_REG_CONFIG_DMA_MASK; reg |= CQSPI_REG_CONFIG_DMA_MASK;
writel(reg, cqspi->iobase + CQSPI_REG_CONFIG); writel(reg, cqspi->iobase + CQSPI_REG_CONFIG);
} }
}
cqspi_controller_enable(cqspi, 1); static void cqspi_controller_detect_fifo_depth(struct cqspi_st *cqspi)
{
struct device *dev = &cqspi->pdev->dev;
u32 reg, fifo_depth;
/*
* Bits N-1:0 are writable while bits 31:N are read as zero, with 2^N
* the FIFO depth.
*/
writel(U32_MAX, cqspi->iobase + CQSPI_REG_SRAMPARTITION);
reg = readl(cqspi->iobase + CQSPI_REG_SRAMPARTITION);
fifo_depth = reg + 1;
/* FIFO depth of zero means no value from devicetree was provided. */
if (cqspi->fifo_depth == 0) {
cqspi->fifo_depth = fifo_depth;
dev_dbg(dev, "using FIFO depth of %u\n", fifo_depth);
} else if (fifo_depth != cqspi->fifo_depth) {
dev_warn(dev, "detected FIFO depth (%u) different from config (%u)\n",
fifo_depth, cqspi->fifo_depth);
}
} }
static int cqspi_request_mmap_dma(struct cqspi_st *cqspi) static int cqspi_request_mmap_dma(struct cqspi_st *cqspi)
@ -1731,6 +1769,7 @@ static int cqspi_probe(struct platform_device *pdev)
cqspi->pdev = pdev; cqspi->pdev = pdev;
cqspi->host = host; cqspi->host = host;
cqspi->is_jh7110 = false; cqspi->is_jh7110 = false;
cqspi->ddata = ddata = of_device_get_match_data(dev);
platform_set_drvdata(pdev, cqspi); platform_set_drvdata(pdev, cqspi);
/* Obtain configuration from OF. */ /* Obtain configuration from OF. */
@ -1822,7 +1861,6 @@ static int cqspi_probe(struct platform_device *pdev)
/* write completion is supported by default */ /* write completion is supported by default */
cqspi->wr_completion = true; cqspi->wr_completion = true;
ddata = of_device_get_match_data(dev);
if (ddata) { if (ddata) {
if (ddata->quirks & CQSPI_NEEDS_WR_DELAY) if (ddata->quirks & CQSPI_NEEDS_WR_DELAY)
cqspi->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, cqspi->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC,
@ -1864,7 +1902,10 @@ static int cqspi_probe(struct platform_device *pdev)
} }
cqspi_wait_idle(cqspi); cqspi_wait_idle(cqspi);
cqspi_controller_enable(cqspi, 0);
cqspi_controller_detect_fifo_depth(cqspi);
cqspi_controller_init(cqspi); cqspi_controller_init(cqspi);
cqspi_controller_enable(cqspi, 1);
cqspi->current_cs = -1; cqspi->current_cs = -1;
cqspi->sclk = 0; cqspi->sclk = 0;
@ -1947,7 +1988,9 @@ static int cqspi_runtime_resume(struct device *dev)
clk_prepare_enable(cqspi->clk); clk_prepare_enable(cqspi->clk);
cqspi_wait_idle(cqspi); cqspi_wait_idle(cqspi);
cqspi_controller_enable(cqspi, 0);
cqspi_controller_init(cqspi); cqspi_controller_init(cqspi);
cqspi_controller_enable(cqspi, 1);
cqspi->current_cs = -1; cqspi->current_cs = -1;
cqspi->sclk = 0; cqspi->sclk = 0;
@ -2012,6 +2055,12 @@ static const struct cqspi_driver_platdata pensando_cdns_qspi = {
.quirks = CQSPI_NEEDS_APB_AHB_HAZARD_WAR | CQSPI_DISABLE_DAC_MODE, .quirks = CQSPI_NEEDS_APB_AHB_HAZARD_WAR | CQSPI_DISABLE_DAC_MODE,
}; };
static const struct cqspi_driver_platdata mobileye_eyeq5_ospi = {
.hwcaps_mask = CQSPI_SUPPORTS_OCTAL,
.quirks = CQSPI_DISABLE_DAC_MODE | CQSPI_NO_SUPPORT_WR_COMPLETION |
CQSPI_RD_NO_IRQ,
};
static const struct of_device_id cqspi_dt_ids[] = { static const struct of_device_id cqspi_dt_ids[] = {
{ {
.compatible = "cdns,qspi-nor", .compatible = "cdns,qspi-nor",
@ -2045,6 +2094,10 @@ static const struct of_device_id cqspi_dt_ids[] = {
.compatible = "amd,pensando-elba-qspi", .compatible = "amd,pensando-elba-qspi",
.data = &pensando_cdns_qspi, .data = &pensando_cdns_qspi,
}, },
{
.compatible = "mobileye,eyeq5-ospi",
.data = &mobileye_eyeq5_ospi,
},
{ /* end of table */ } { /* end of table */ }
}; };

View File

@ -486,20 +486,14 @@ static irqreturn_t cdns_xspi_irq_handler(int this_irq, void *dev)
static int cdns_xspi_of_get_plat_data(struct platform_device *pdev) static int cdns_xspi_of_get_plat_data(struct platform_device *pdev)
{ {
struct device_node *node_prop = pdev->dev.of_node; struct device_node *node_prop = pdev->dev.of_node;
struct device_node *node_child;
unsigned int cs; unsigned int cs;
for_each_child_of_node(node_prop, node_child) { for_each_available_child_of_node_scoped(node_prop, node_child) {
if (!of_device_is_available(node_child))
continue;
if (of_property_read_u32(node_child, "reg", &cs)) { if (of_property_read_u32(node_child, "reg", &cs)) {
dev_err(&pdev->dev, "Couldn't get memory chip select\n"); dev_err(&pdev->dev, "Couldn't get memory chip select\n");
of_node_put(node_child);
return -ENXIO; return -ENXIO;
} else if (cs >= CDNS_XSPI_MAX_BANKS) { } else if (cs >= CDNS_XSPI_MAX_BANKS) {
dev_err(&pdev->dev, "reg (cs) parameter value too large\n"); dev_err(&pdev->dev, "reg (cs) parameter value too large\n");
of_node_put(node_child);
return -ENXIO; return -ENXIO;
} }
} }

View File

@ -500,7 +500,6 @@ static const struct dev_pm_ops mcfqspi_pm = {
static struct platform_driver mcfqspi_driver = { static struct platform_driver mcfqspi_driver = {
.driver.name = DRIVER_NAME, .driver.name = DRIVER_NAME,
.driver.owner = THIS_MODULE,
.driver.pm = &mcfqspi_pm, .driver.pm = &mcfqspi_pm,
.probe = mcfqspi_probe, .probe = mcfqspi_probe,
.remove_new = mcfqspi_remove, .remove_new = mcfqspi_remove,

View File

@ -5,10 +5,14 @@
// Copyright (C) 2022-2023 Cirrus Logic, Inc. and // Copyright (C) 2022-2023 Cirrus Logic, Inc. and
// Cirrus Logic International Semiconductor Ltd. // Cirrus Logic International Semiconductor Ltd.
#include <linux/acpi.h>
#include <linux/array_size.h>
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
#include <linux/mfd/cs42l43.h> #include <linux/mfd/cs42l43.h>
#include <linux/mfd/cs42l43-regs.h> #include <linux/mfd/cs42l43-regs.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
@ -16,6 +20,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/units.h> #include <linux/units.h>
@ -39,6 +44,44 @@ static const unsigned int cs42l43_clock_divs[] = {
2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
}; };
static const struct software_node ampl = {
.name = "cs35l56-left",
};
static const struct software_node ampr = {
.name = "cs35l56-right",
};
static struct spi_board_info ampl_info = {
.modalias = "cs35l56",
.max_speed_hz = 20 * HZ_PER_MHZ,
.chip_select = 0,
.mode = SPI_MODE_0,
.swnode = &ampl,
};
static struct spi_board_info ampr_info = {
.modalias = "cs35l56",
.max_speed_hz = 20 * HZ_PER_MHZ,
.chip_select = 1,
.mode = SPI_MODE_0,
.swnode = &ampr,
};
static const struct software_node cs42l43_gpiochip_swnode = {
.name = "cs42l43-pinctrl",
};
static const struct software_node_ref_args cs42l43_cs_refs[] = {
SOFTWARE_NODE_REFERENCE(&cs42l43_gpiochip_swnode, 0, GPIO_ACTIVE_LOW),
SOFTWARE_NODE_REFERENCE(&swnode_gpio_undefined),
};
static const struct property_entry cs42l43_cs_props[] = {
PROPERTY_ENTRY_REF_ARRAY("cs-gpios", cs42l43_cs_refs),
{}
};
static int cs42l43_spi_tx(struct regmap *regmap, const u8 *buf, unsigned int len) static int cs42l43_spi_tx(struct regmap *regmap, const u8 *buf, unsigned int len)
{ {
const u8 *end = buf + len; const u8 *end = buf + len;
@ -203,16 +246,59 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi)
return CS42L43_SPI_MAX_LENGTH; return CS42L43_SPI_MAX_LENGTH;
} }
static bool cs42l43_has_sidecar(struct fwnode_handle *fwnode)
{
static const u32 func_smart_amp = 0x1;
struct fwnode_handle *child_fwnode, *ext_fwnode;
unsigned int val;
u32 function;
int ret;
fwnode_for_each_child_node(fwnode, child_fwnode) {
acpi_handle handle = ACPI_HANDLE_FWNODE(child_fwnode);
ret = acpi_get_local_address(handle, &function);
if (ret || function != func_smart_amp)
continue;
ext_fwnode = fwnode_get_named_child_node(child_fwnode,
"mipi-sdca-function-expansion-subproperties");
if (!ext_fwnode)
continue;
ret = fwnode_property_read_u32(ext_fwnode,
"01fa-sidecar-instances",
&val);
fwnode_handle_put(ext_fwnode);
if (ret)
continue;
fwnode_handle_put(child_fwnode);
return !!val;
}
return false;
}
static void cs42l43_release_of_node(void *data) static void cs42l43_release_of_node(void *data)
{ {
fwnode_handle_put(data); fwnode_handle_put(data);
} }
static void cs42l43_release_sw_node(void *data)
{
software_node_unregister(&cs42l43_gpiochip_swnode);
}
static int cs42l43_spi_probe(struct platform_device *pdev) static int cs42l43_spi_probe(struct platform_device *pdev)
{ {
struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent); struct cs42l43 *cs42l43 = dev_get_drvdata(pdev->dev.parent);
struct cs42l43_spi *priv; struct cs42l43_spi *priv;
struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev); struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev);
bool has_sidecar = cs42l43_has_sidecar(fwnode);
int ret; int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@ -259,21 +345,45 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
if (is_of_node(fwnode)) { if (is_of_node(fwnode)) {
fwnode = fwnode_get_named_child_node(fwnode, "spi"); fwnode = fwnode_get_named_child_node(fwnode, "spi");
ret = devm_add_action(priv->dev, cs42l43_release_of_node, fwnode); ret = devm_add_action_or_reset(priv->dev, cs42l43_release_of_node, fwnode);
if (ret) { if (ret)
fwnode_handle_put(fwnode);
return ret; return ret;
}
} }
device_set_node(&priv->ctlr->dev, fwnode); if (has_sidecar) {
ret = software_node_register(&cs42l43_gpiochip_swnode);
if (ret)
return dev_err_probe(priv->dev, ret,
"Failed to register gpio swnode\n");
ret = devm_add_action_or_reset(priv->dev, cs42l43_release_sw_node, NULL);
if (ret)
return ret;
ret = device_create_managed_software_node(&priv->ctlr->dev,
cs42l43_cs_props, NULL);
if (ret)
return dev_err_probe(priv->dev, ret, "Failed to add swnode\n");
} else {
device_set_node(&priv->ctlr->dev, fwnode);
}
ret = devm_spi_register_controller(priv->dev, priv->ctlr); ret = devm_spi_register_controller(priv->dev, priv->ctlr);
if (ret) { if (ret)
dev_err(priv->dev, "Failed to register SPI controller: %d\n", ret); return dev_err_probe(priv->dev, ret,
"Failed to register SPI controller\n");
if (has_sidecar) {
if (!spi_new_device(priv->ctlr, &ampl_info))
return dev_err_probe(priv->dev, -ENODEV,
"Failed to create left amp slave\n");
if (!spi_new_device(priv->ctlr, &ampr_info))
return dev_err_probe(priv->dev, -ENODEV,
"Failed to create right amp slave\n");
} }
return ret; return 0;
} }
static const struct platform_device_id cs42l43_spi_id_table[] = { static const struct platform_device_id cs42l43_spi_id_table[] = {
@ -291,6 +401,7 @@ static struct platform_driver cs42l43_spi_driver = {
}; };
module_platform_driver(cs42l43_spi_driver); module_platform_driver(cs42l43_spi_driver);
MODULE_IMPORT_NS(GPIO_SWNODE);
MODULE_DESCRIPTION("CS42L43 SPI Driver"); MODULE_DESCRIPTION("CS42L43 SPI Driver");
MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>"); MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
MODULE_AUTHOR("Maciej Strozek <mstrozek@opensource.cirrus.com>"); MODULE_AUTHOR("Maciej Strozek <mstrozek@opensource.cirrus.com>");

View File

@ -6,6 +6,7 @@
*/ */
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
@ -421,10 +422,7 @@ static int dw_spi_transfer_one(struct spi_controller *host,
int ret; int ret;
dws->dma_mapped = 0; dws->dma_mapped = 0;
dws->n_bytes = dws->n_bytes = roundup_pow_of_two(BITS_TO_BYTES(transfer->bits_per_word));
roundup_pow_of_two(DIV_ROUND_UP(transfer->bits_per_word,
BITS_PER_BYTE));
dws->tx = (void *)transfer->tx_buf; dws->tx = (void *)transfer->tx_buf;
dws->tx_len = transfer->len / dws->n_bytes; dws->tx_len = transfer->len / dws->n_bytes;
dws->rx = transfer->rx_buf; dws->rx = transfer->rx_buf;
@ -836,6 +834,20 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
DW_SPI_GET_BYTE(dws->ver, 1)); DW_SPI_GET_BYTE(dws->ver, 1));
} }
/*
* Try to detect the number of native chip-selects if the platform
* driver didn't set it up. There can be up to 16 lines configured.
*/
if (!dws->num_cs) {
u32 ser;
dw_writel(dws, DW_SPI_SER, 0xffff);
ser = dw_readl(dws, DW_SPI_SER);
dw_writel(dws, DW_SPI_SER, 0);
dws->num_cs = hweight16(ser);
}
/* /*
* Try to detect the FIFO depth if not set by interface driver, * Try to detect the FIFO depth if not set by interface driver,
* the depth could be from 2 to 256 from HW spec * the depth could be from 2 to 256 from HW spec

View File

@ -320,7 +320,11 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
struct resource *mem; struct resource *mem;
struct dw_spi *dws; struct dw_spi *dws;
int ret; int ret;
int num_cs;
if (device_property_read_bool(&pdev->dev, "spi-slave")) {
dev_warn(&pdev->dev, "spi-slave is not yet supported\n");
return -ENODEV;
}
dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio), dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_mmio),
GFP_KERNEL); GFP_KERNEL);
@ -364,11 +368,8 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
&dws->reg_io_width)) &dws->reg_io_width))
dws->reg_io_width = 4; dws->reg_io_width = 4;
num_cs = 4; /* Rely on the auto-detection if no property specified */
device_property_read_u32(&pdev->dev, "num-cs", &dws->num_cs);
device_property_read_u32(&pdev->dev, "num-cs", &num_cs);
dws->num_cs = num_cs;
init_func = device_get_match_data(&pdev->dev); init_func = device_get_match_data(&pdev->dev);
if (init_func) { if (init_func) {

View File

@ -164,8 +164,8 @@ struct dw_spi {
u32 max_freq; /* max bus freq supported */ u32 max_freq; /* max bus freq supported */
u32 reg_io_width; /* DR I/O width in bytes */ u32 reg_io_width; /* DR I/O width in bytes */
u32 num_cs; /* chip select lines */
u16 bus_num; u16 bus_num;
u16 num_cs; /* supported slave numbers */
void (*set_cs)(struct spi_device *spi, bool enable); void (*set_cs)(struct spi_device *spi, bool enable);
/* Current message transfer state info */ /* Current message transfer state info */

View File

@ -98,19 +98,13 @@ static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR); mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
} }
int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t)
struct spi_transfer *t, bool is_dma_mapped)
{ {
struct device *dev = mspi->dev; struct device *dev = mspi->dev;
struct fsl_spi_reg __iomem *reg_base = mspi->reg_base; struct fsl_spi_reg __iomem *reg_base = mspi->reg_base;
if (is_dma_mapped) { mspi->map_tx_dma = 1;
mspi->map_tx_dma = 0; mspi->map_rx_dma = 1;
mspi->map_rx_dma = 0;
} else {
mspi->map_tx_dma = 1;
mspi->map_rx_dma = 1;
}
if (!t->tx_buf) { if (!t->tx_buf) {
mspi->tx_dma = mspi->dma_dummy_tx; mspi->tx_dma = mspi->dma_dummy_tx;
@ -147,7 +141,7 @@ int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
return -ENOMEM; return -ENOMEM;
} }
} else if (t->tx_buf) { } else if (t->tx_buf) {
mspi->tx_dma = t->tx_dma; mspi->tx_dma = 0;
} }
if (mspi->map_rx_dma) { if (mspi->map_rx_dma) {

View File

@ -20,7 +20,7 @@
#ifdef CONFIG_FSL_SOC #ifdef CONFIG_FSL_SOC
extern void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi); extern void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi);
extern int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, extern int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
struct spi_transfer *t, bool is_dma_mapped); struct spi_transfer *t);
extern void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi); extern void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi);
extern void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events); extern void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events);
extern int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi); extern int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi);
@ -28,8 +28,7 @@ extern void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi);
#else #else
static inline void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi) { } static inline void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi) { }
static inline int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi, static inline int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
struct spi_transfer *t, struct spi_transfer *t) { return 0; }
bool is_dma_mapped) { return 0; }
static inline void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) { } static inline void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) { }
static inline void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) { } static inline void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events) { }
static inline int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) { return 0; } static inline int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi) { return 0; }

View File

@ -1458,7 +1458,6 @@ static void dspi_shutdown(struct platform_device *pdev)
static struct platform_driver fsl_dspi_driver = { static struct platform_driver fsl_dspi_driver = {
.driver.name = DRIVER_NAME, .driver.name = DRIVER_NAME,
.driver.of_match_table = fsl_dspi_dt_ids, .driver.of_match_table = fsl_dspi_dt_ids,
.driver.owner = THIS_MODULE,
.driver.pm = &dspi_pm, .driver.pm = &dspi_pm,
.probe = dspi_probe, .probe = dspi_probe,
.remove_new = dspi_remove, .remove_new = dspi_remove,

View File

@ -553,7 +553,7 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
{ {
struct dma_async_tx_descriptor *desc_tx, *desc_rx; struct dma_async_tx_descriptor *desc_tx, *desc_rx;
unsigned long transfer_timeout; unsigned long transfer_timeout;
unsigned long timeout; unsigned long time_left;
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg; struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
int ret; int ret;
@ -594,9 +594,9 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
transfer->len); transfer->len);
/* Wait eDMA to finish the data transfer.*/ /* Wait eDMA to finish the data transfer.*/
timeout = wait_for_completion_timeout(&fsl_lpspi->dma_tx_completion, time_left = wait_for_completion_timeout(&fsl_lpspi->dma_tx_completion,
transfer_timeout); transfer_timeout);
if (!timeout) { if (!time_left) {
dev_err(fsl_lpspi->dev, "I/O Error in DMA TX\n"); dev_err(fsl_lpspi->dev, "I/O Error in DMA TX\n");
dmaengine_terminate_all(controller->dma_tx); dmaengine_terminate_all(controller->dma_tx);
dmaengine_terminate_all(controller->dma_rx); dmaengine_terminate_all(controller->dma_rx);
@ -604,9 +604,9 @@ static int fsl_lpspi_dma_transfer(struct spi_controller *controller,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
timeout = wait_for_completion_timeout(&fsl_lpspi->dma_rx_completion, time_left = wait_for_completion_timeout(&fsl_lpspi->dma_rx_completion,
transfer_timeout); transfer_timeout);
if (!timeout) { if (!time_left) {
dev_err(fsl_lpspi->dev, "I/O Error in DMA RX\n"); dev_err(fsl_lpspi->dev, "I/O Error in DMA RX\n");
dmaengine_terminate_all(controller->dma_tx); dmaengine_terminate_all(controller->dma_tx);
dmaengine_terminate_all(controller->dma_rx); dmaengine_terminate_all(controller->dma_rx);

View File

@ -249,8 +249,7 @@ static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
return 0; return 0;
} }
static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
bool is_dma_mapped)
{ {
struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(spi->controller); struct mpc8xxx_spi *mpc8xxx_spi = spi_controller_get_devdata(spi->controller);
struct fsl_spi_reg __iomem *reg_base; struct fsl_spi_reg __iomem *reg_base;
@ -274,7 +273,7 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
reinit_completion(&mpc8xxx_spi->done); reinit_completion(&mpc8xxx_spi->done);
if (mpc8xxx_spi->flags & SPI_CPM_MODE) if (mpc8xxx_spi->flags & SPI_CPM_MODE)
ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped); ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t);
else else
ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len); ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len);
if (ret) if (ret)
@ -353,7 +352,7 @@ static int fsl_spi_transfer_one(struct spi_controller *controller,
if (status < 0) if (status < 0)
return status; return status;
if (t->len) if (t->len)
status = fsl_spi_bufs(spi, t, !!t->tx_dma || !!t->rx_dma); status = fsl_spi_bufs(spi, t);
if (status > 0) if (status > 0)
return -EMSGSIZE; return -EMSGSIZE;

View File

@ -1405,7 +1405,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
{ {
struct dma_async_tx_descriptor *desc_tx, *desc_rx; struct dma_async_tx_descriptor *desc_tx, *desc_rx;
unsigned long transfer_timeout; unsigned long transfer_timeout;
unsigned long timeout; unsigned long time_left;
struct spi_controller *controller = spi_imx->controller; struct spi_controller *controller = spi_imx->controller;
struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg; struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents); struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
@ -1471,18 +1471,18 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len); transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
/* Wait SDMA to finish the data transfer.*/ /* Wait SDMA to finish the data transfer.*/
timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion, time_left = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
transfer_timeout); transfer_timeout);
if (!timeout) { if (!time_left) {
dev_err(spi_imx->dev, "I/O Error in DMA TX\n"); dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
dmaengine_terminate_all(controller->dma_tx); dmaengine_terminate_all(controller->dma_tx);
dmaengine_terminate_all(controller->dma_rx); dmaengine_terminate_all(controller->dma_rx);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
timeout = wait_for_completion_timeout(&spi_imx->dma_rx_completion, time_left = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
transfer_timeout); transfer_timeout);
if (!timeout) { if (!time_left) {
dev_err(&controller->dev, "I/O Error in DMA RX\n"); dev_err(&controller->dev, "I/O Error in DMA RX\n");
spi_imx->devtype_data->reset(spi_imx); spi_imx->devtype_data->reset(spi_imx);
dmaengine_terminate_all(controller->dma_rx); dmaengine_terminate_all(controller->dma_rx);
@ -1501,7 +1501,7 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
{ {
struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller); struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
unsigned long transfer_timeout; unsigned long transfer_timeout;
unsigned long timeout; unsigned long time_left;
spi_imx->tx_buf = transfer->tx_buf; spi_imx->tx_buf = transfer->tx_buf;
spi_imx->rx_buf = transfer->rx_buf; spi_imx->rx_buf = transfer->rx_buf;
@ -1517,9 +1517,9 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len); transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
timeout = wait_for_completion_timeout(&spi_imx->xfer_done, time_left = wait_for_completion_timeout(&spi_imx->xfer_done,
transfer_timeout); transfer_timeout);
if (!timeout) { if (!time_left) {
dev_err(&spi->dev, "I/O Error in PIO\n"); dev_err(&spi->dev, "I/O Error in PIO\n");
spi_imx->devtype_data->reset(spi_imx); spi_imx->devtype_data->reset(spi_imx);
return -ETIMEDOUT; return -ETIMEDOUT;

View File

@ -396,7 +396,6 @@ MODULE_DEVICE_TABLE(of, spi_loopback_test_of_match);
static struct spi_driver spi_loopback_test_driver = { static struct spi_driver spi_loopback_test_driver = {
.driver = { .driver = {
.name = "spi-loopback-test", .name = "spi-loopback-test",
.owner = THIS_MODULE,
.of_match_table = spi_loopback_test_of_match, .of_match_table = spi_loopback_test_of_match,
}, },
.probe = spi_loopback_test_probe, .probe = spi_loopback_test_probe,

View File

@ -748,7 +748,7 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
u32 cmd, reg_val, cnt, remainder, len; u32 cmd, reg_val, cnt, remainder, len;
struct spi_controller *host = dev_id; struct spi_controller *host = dev_id;
struct mtk_spi *mdata = spi_controller_get_devdata(host); struct mtk_spi *mdata = spi_controller_get_devdata(host);
struct spi_transfer *trans = mdata->cur_transfer; struct spi_transfer *xfer = mdata->cur_transfer;
reg_val = readl(mdata->base + SPI_STATUS0_REG); reg_val = readl(mdata->base + SPI_STATUS0_REG);
if (reg_val & MTK_SPI_PAUSE_INT_STATUS) if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
@ -762,42 +762,40 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
if (!host->can_dma(host, NULL, trans)) { if (!host->can_dma(host, NULL, xfer)) {
if (trans->rx_buf) { if (xfer->rx_buf) {
cnt = mdata->xfer_len / 4; cnt = mdata->xfer_len / 4;
ioread32_rep(mdata->base + SPI_RX_DATA_REG, ioread32_rep(mdata->base + SPI_RX_DATA_REG,
trans->rx_buf + mdata->num_xfered, cnt); xfer->rx_buf + mdata->num_xfered, cnt);
remainder = mdata->xfer_len % 4; remainder = mdata->xfer_len % 4;
if (remainder > 0) { if (remainder > 0) {
reg_val = readl(mdata->base + SPI_RX_DATA_REG); reg_val = readl(mdata->base + SPI_RX_DATA_REG);
memcpy(trans->rx_buf + memcpy(xfer->rx_buf + (cnt * 4) + mdata->num_xfered,
mdata->num_xfered +
(cnt * 4),
&reg_val, &reg_val,
remainder); remainder);
} }
} }
mdata->num_xfered += mdata->xfer_len; mdata->num_xfered += mdata->xfer_len;
if (mdata->num_xfered == trans->len) { if (mdata->num_xfered == xfer->len) {
spi_finalize_current_transfer(host); spi_finalize_current_transfer(host);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
len = trans->len - mdata->num_xfered; len = xfer->len - mdata->num_xfered;
mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len); mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len);
mtk_spi_setup_packet(host); mtk_spi_setup_packet(host);
if (trans->tx_buf) { if (xfer->tx_buf) {
cnt = mdata->xfer_len / 4; cnt = mdata->xfer_len / 4;
iowrite32_rep(mdata->base + SPI_TX_DATA_REG, iowrite32_rep(mdata->base + SPI_TX_DATA_REG,
trans->tx_buf + mdata->num_xfered, cnt); xfer->tx_buf + mdata->num_xfered, cnt);
remainder = mdata->xfer_len % 4; remainder = mdata->xfer_len % 4;
if (remainder > 0) { if (remainder > 0) {
reg_val = 0; reg_val = 0;
memcpy(&reg_val, memcpy(&reg_val,
trans->tx_buf + (cnt * 4) + mdata->num_xfered, xfer->tx_buf + (cnt * 4) + mdata->num_xfered,
remainder); remainder);
writel(reg_val, mdata->base + SPI_TX_DATA_REG); writel(reg_val, mdata->base + SPI_TX_DATA_REG);
} }
@ -809,21 +807,21 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
} }
if (mdata->tx_sgl) if (mdata->tx_sgl)
trans->tx_dma += mdata->xfer_len; xfer->tx_dma += mdata->xfer_len;
if (mdata->rx_sgl) if (mdata->rx_sgl)
trans->rx_dma += mdata->xfer_len; xfer->rx_dma += mdata->xfer_len;
if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) { if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) {
mdata->tx_sgl = sg_next(mdata->tx_sgl); mdata->tx_sgl = sg_next(mdata->tx_sgl);
if (mdata->tx_sgl) { if (mdata->tx_sgl) {
trans->tx_dma = sg_dma_address(mdata->tx_sgl); xfer->tx_dma = sg_dma_address(mdata->tx_sgl);
mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl); mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
} }
} }
if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) { if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) {
mdata->rx_sgl = sg_next(mdata->rx_sgl); mdata->rx_sgl = sg_next(mdata->rx_sgl);
if (mdata->rx_sgl) { if (mdata->rx_sgl) {
trans->rx_dma = sg_dma_address(mdata->rx_sgl); xfer->rx_dma = sg_dma_address(mdata->rx_sgl);
mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl); mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
} }
} }
@ -841,7 +839,7 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
mtk_spi_update_mdata_len(host); mtk_spi_update_mdata_len(host);
mtk_spi_setup_packet(host); mtk_spi_setup_packet(host);
mtk_spi_setup_dma_addr(host, trans); mtk_spi_setup_dma_addr(host, xfer);
mtk_spi_enable_transfer(host); mtk_spi_enable_transfer(host);
return IRQ_HANDLED; return IRQ_HANDLED;

View File

@ -52,6 +52,8 @@
#define MT7621_CPOL BIT(4) #define MT7621_CPOL BIT(4)
#define MT7621_LSB_FIRST BIT(3) #define MT7621_LSB_FIRST BIT(3)
#define MT7621_NATIVE_CS_COUNT 2
struct mt7621_spi { struct mt7621_spi {
struct spi_controller *host; struct spi_controller *host;
void __iomem *base; void __iomem *base;
@ -75,10 +77,11 @@ static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val)
iowrite32(val, rs->base + reg); iowrite32(val, rs->base + reg);
} }
static void mt7621_spi_set_cs(struct spi_device *spi, int enable) static void mt7621_spi_set_native_cs(struct spi_device *spi, bool enable)
{ {
struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); struct mt7621_spi *rs = spidev_to_mt7621_spi(spi);
int cs = spi_get_chipselect(spi, 0); int cs = spi_get_chipselect(spi, 0);
bool active = spi->mode & SPI_CS_HIGH ? enable : !enable;
u32 polar = 0; u32 polar = 0;
u32 host; u32 host;
@ -94,7 +97,7 @@ static void mt7621_spi_set_cs(struct spi_device *spi, int enable)
rs->pending_write = 0; rs->pending_write = 0;
if (enable) if (active)
polar = BIT(cs); polar = BIT(cs);
mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); mt7621_spi_write(rs, MT7621_SPI_POLAR, polar);
} }
@ -154,6 +157,23 @@ static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
static int mt7621_spi_prepare_message(struct spi_controller *host,
struct spi_message *m)
{
struct mt7621_spi *rs = spi_controller_get_devdata(host);
struct spi_device *spi = m->spi;
unsigned int speed = spi->max_speed_hz;
struct spi_transfer *t = NULL;
mt7621_spi_wait_till_ready(rs);
list_for_each_entry(t, &m->transfers, transfer_list)
if (t->speed_hz < speed)
speed = t->speed_hz;
return mt7621_spi_prepare(spi, speed);
}
static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs, static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs,
int rx_len, u8 *buf) int rx_len, u8 *buf)
{ {
@ -243,59 +263,30 @@ static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs,
} }
rs->pending_write = len; rs->pending_write = len;
mt7621_spi_flush(rs);
} }
static int mt7621_spi_transfer_one_message(struct spi_controller *host, static int mt7621_spi_transfer_one(struct spi_controller *host,
struct spi_message *m) struct spi_device *spi,
struct spi_transfer *t)
{ {
struct mt7621_spi *rs = spi_controller_get_devdata(host); struct mt7621_spi *rs = spi_controller_get_devdata(host);
struct spi_device *spi = m->spi;
unsigned int speed = spi->max_speed_hz;
struct spi_transfer *t = NULL;
int status = 0;
mt7621_spi_wait_till_ready(rs); if ((t->rx_buf) && (t->tx_buf)) {
/*
list_for_each_entry(t, &m->transfers, transfer_list) * This controller will shift some extra data out
if (t->speed_hz < speed) * of spi_opcode if (mosi_bit_cnt > 0) &&
speed = t->speed_hz; * (cmd_bit_cnt == 0). So the claimed full-duplex
* support is broken since we have no way to read
if (mt7621_spi_prepare(spi, speed)) { * the MISO value during that bit.
status = -EIO; */
goto msg_done; return -EIO;
} else if (t->rx_buf) {
mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf);
} else if (t->tx_buf) {
mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf);
} }
/* Assert CS */
mt7621_spi_set_cs(spi, 1);
m->actual_length = 0;
list_for_each_entry(t, &m->transfers, transfer_list) {
if ((t->rx_buf) && (t->tx_buf)) {
/*
* This controller will shift some extra data out
* of spi_opcode if (mosi_bit_cnt > 0) &&
* (cmd_bit_cnt == 0). So the claimed full-duplex
* support is broken since we have no way to read
* the MISO value during that bit.
*/
status = -EIO;
goto msg_done;
} else if (t->rx_buf) {
mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf);
} else if (t->tx_buf) {
mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf);
}
m->actual_length += t->len;
}
/* Flush data and deassert CS */
mt7621_spi_flush(rs);
mt7621_spi_set_cs(spi, 0);
msg_done:
m->status = status;
spi_finalize_current_message(host);
return 0; return 0;
} }
@ -353,10 +344,14 @@ static int mt7621_spi_probe(struct platform_device *pdev)
host->mode_bits = SPI_LSB_FIRST; host->mode_bits = SPI_LSB_FIRST;
host->flags = SPI_CONTROLLER_HALF_DUPLEX; host->flags = SPI_CONTROLLER_HALF_DUPLEX;
host->setup = mt7621_spi_setup; host->setup = mt7621_spi_setup;
host->transfer_one_message = mt7621_spi_transfer_one_message; host->prepare_message = mt7621_spi_prepare_message;
host->set_cs = mt7621_spi_set_native_cs;
host->transfer_one = mt7621_spi_transfer_one;
host->bits_per_word_mask = SPI_BPW_MASK(8); host->bits_per_word_mask = SPI_BPW_MASK(8);
host->dev.of_node = pdev->dev.of_node; host->dev.of_node = pdev->dev.of_node;
host->num_chipselect = 2; host->max_native_cs = MT7621_NATIVE_CS_COUNT;
host->num_chipselect = MT7621_NATIVE_CS_COUNT;
host->use_gpio_descriptors = true;
dev_set_drvdata(&pdev->dev, host); dev_set_drvdata(&pdev->dev, host);

View File

@ -68,6 +68,8 @@ static int spi_mux_select(struct spi_device *spi)
priv->current_cs = spi_get_chipselect(spi, 0); priv->current_cs = spi_get_chipselect(spi, 0);
spi_setup(priv->spi);
return 0; return 0;
} }

View File

@ -184,8 +184,6 @@ static irqreturn_t tiny_spi_irq(int irq, void *dev)
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
#include <linux/of_gpio.h>
static int tiny_spi_of_probe(struct platform_device *pdev) static int tiny_spi_of_probe(struct platform_device *pdev)
{ {
struct tiny_spi *hw = platform_get_drvdata(pdev); struct tiny_spi *hw = platform_get_drvdata(pdev);

View File

@ -131,6 +131,7 @@ struct omap2_mcspi {
unsigned int pin_dir:1; unsigned int pin_dir:1;
size_t max_xfer_len; size_t max_xfer_len;
u32 ref_clk_hz; u32 ref_clk_hz;
bool use_multi_mode;
}; };
struct omap2_mcspi_cs { struct omap2_mcspi_cs {
@ -256,10 +257,15 @@ static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
l = mcspi_cached_chconf0(spi); l = mcspi_cached_chconf0(spi);
if (enable) /* Only enable chip select manually if single mode is used */
if (mcspi->use_multi_mode) {
l &= ~OMAP2_MCSPI_CHCONF_FORCE; l &= ~OMAP2_MCSPI_CHCONF_FORCE;
else } else {
l |= OMAP2_MCSPI_CHCONF_FORCE; if (enable)
l &= ~OMAP2_MCSPI_CHCONF_FORCE;
else
l |= OMAP2_MCSPI_CHCONF_FORCE;
}
mcspi_write_chconf0(spi, l); mcspi_write_chconf0(spi, l);
@ -283,7 +289,12 @@ static void omap2_mcspi_set_mode(struct spi_controller *ctlr)
l |= (OMAP2_MCSPI_MODULCTRL_MS); l |= (OMAP2_MCSPI_MODULCTRL_MS);
} else { } else {
l &= ~(OMAP2_MCSPI_MODULCTRL_MS); l &= ~(OMAP2_MCSPI_MODULCTRL_MS);
l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
/* Enable single mode if needed */
if (mcspi->use_multi_mode)
l &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
else
l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
} }
mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, l); mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, l);
@ -1175,13 +1186,6 @@ static int omap2_mcspi_transfer_one(struct spi_controller *ctlr,
t->bits_per_word == spi->bits_per_word) t->bits_per_word == spi->bits_per_word)
par_override = 0; par_override = 0;
} }
if (cd && cd->cs_per_word) {
chconf = mcspi->ctx.modulctrl;
chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, chconf);
mcspi->ctx.modulctrl =
mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
}
chconf = mcspi_cached_chconf0(spi); chconf = mcspi_cached_chconf0(spi);
chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
@ -1240,14 +1244,6 @@ out:
status = omap2_mcspi_setup_transfer(spi, NULL); status = omap2_mcspi_setup_transfer(spi, NULL);
} }
if (cd && cd->cs_per_word) {
chconf = mcspi->ctx.modulctrl;
chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, chconf);
mcspi->ctx.modulctrl =
mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
}
omap2_mcspi_set_enable(spi, 0); omap2_mcspi_set_enable(spi, 0);
if (spi_get_csgpiod(spi, 0)) if (spi_get_csgpiod(spi, 0))
@ -1265,15 +1261,72 @@ static int omap2_mcspi_prepare_message(struct spi_controller *ctlr,
struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_regs *ctx = &mcspi->ctx;
struct omap2_mcspi_cs *cs; struct omap2_mcspi_cs *cs;
struct spi_transfer *tr;
u8 bits_per_word;
/* Only a single channel can have the FORCE bit enabled /*
* The conditions are strict, it is mandatory to check each transfer of the list to see if
* multi-mode is applicable.
*/
mcspi->use_multi_mode = true;
list_for_each_entry(tr, &msg->transfers, transfer_list) {
if (!tr->bits_per_word)
bits_per_word = msg->spi->bits_per_word;
else
bits_per_word = tr->bits_per_word;
/*
* Check if this transfer contains only one word;
* OR contains 1 to 4 words, with bits_per_word == 8 and no delay between each word
* OR contains 1 to 2 words, with bits_per_word == 16 and no delay between each word
*
* If one of the two last case is true, this also change the bits_per_word of this
* transfer to make it a bit faster.
* It's not an issue to change the bits_per_word here even if the multi-mode is not
* applicable for this message, the signal on the wire will be the same.
*/
if (bits_per_word < 8 && tr->len == 1) {
/* multi-mode is applicable, only one word (1..7 bits) */
} else if (tr->word_delay.value == 0 && bits_per_word == 8 && tr->len <= 4) {
/* multi-mode is applicable, only one "bigger" word (8,16,24,32 bits) */
tr->bits_per_word = tr->len * bits_per_word;
} else if (tr->word_delay.value == 0 && bits_per_word == 16 && tr->len <= 2) {
/* multi-mode is applicable, only one "bigger" word (16,32 bits) */
tr->bits_per_word = tr->len * bits_per_word / 2;
} else if (bits_per_word >= 8 && tr->len == bits_per_word / 8) {
/* multi-mode is applicable, only one word (9..15,17..32 bits) */
} else {
/* multi-mode is not applicable: more than one word in the transfer */
mcspi->use_multi_mode = false;
}
/* Check if transfer asks to change the CS status after the transfer */
if (!tr->cs_change)
mcspi->use_multi_mode = false;
/*
* If at least one message is not compatible, switch back to single mode
*
* The bits_per_word of certain transfer can be different, but it will have no
* impact on the signal itself.
*/
if (!mcspi->use_multi_mode)
break;
}
omap2_mcspi_set_mode(ctlr);
/* In single mode only a single channel can have the FORCE bit enabled
* in its chconf0 register. * in its chconf0 register.
* Scan all channels and disable them except the current one. * Scan all channels and disable them except the current one.
* A FORCE can remain from a last transfer having cs_change enabled * A FORCE can remain from a last transfer having cs_change enabled
*
* In multi mode all FORCE bits must be disabled.
*/ */
list_for_each_entry(cs, &ctx->cs, node) { list_for_each_entry(cs, &ctx->cs, node) {
if (msg->spi->controller_state == cs) if (msg->spi->controller_state == cs && !mcspi->use_multi_mode) {
continue; continue;
}
if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) { if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) {
cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;

View File

@ -344,7 +344,7 @@ static int pic32_sqi_one_message(struct spi_controller *host,
struct spi_transfer *xfer; struct spi_transfer *xfer;
struct pic32_sqi *sqi; struct pic32_sqi *sqi;
int ret = 0, mode; int ret = 0, mode;
unsigned long timeout; unsigned long time_left;
u32 val; u32 val;
sqi = spi_controller_get_devdata(host); sqi = spi_controller_get_devdata(host);
@ -410,8 +410,8 @@ static int pic32_sqi_one_message(struct spi_controller *host,
writel(val, sqi->regs + PESQI_BD_CTRL_REG); writel(val, sqi->regs + PESQI_BD_CTRL_REG);
/* wait for xfer completion */ /* wait for xfer completion */
timeout = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ); time_left = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ);
if (timeout == 0) { if (time_left == 0) {
dev_err(&sqi->host->dev, "wait timedout/interrupted\n"); dev_err(&sqi->host->dev, "wait timedout/interrupted\n");
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
msg->status = ret; msg->status = ret;

View File

@ -498,7 +498,7 @@ static int pic32_spi_one_transfer(struct spi_controller *host,
{ {
struct pic32_spi *pic32s; struct pic32_spi *pic32s;
bool dma_issued = false; bool dma_issued = false;
unsigned long timeout; unsigned long time_left;
int ret; int ret;
pic32s = spi_controller_get_devdata(host); pic32s = spi_controller_get_devdata(host);
@ -545,8 +545,8 @@ static int pic32_spi_one_transfer(struct spi_controller *host,
} }
/* wait for completion */ /* wait for completion */
timeout = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ); time_left = wait_for_completion_timeout(&pic32s->xfer_done, 2 * HZ);
if (timeout == 0) { if (time_left == 0) {
dev_err(&spi->dev, "wait error/timedout\n"); dev_err(&spi->dev, "wait error/timedout\n");
if (dma_issued) { if (dma_issued) {
dmaengine_terminate_all(host->dma_rx); dmaengine_terminate_all(host->dma_rx);

View File

@ -6,17 +6,22 @@
* Author: Mika Westerberg <mika.westerberg@linux.intel.com> * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
*/ */
#include <linux/device.h> #include <linux/atomic.h>
#include <linux/dev_printk.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/errno.h>
#include <linux/irqreturn.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/sizes.h> #include <linux/string.h>
#include <linux/types.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include "spi-pxa2xx.h" #include "spi-pxa2xx.h"
struct device;
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data, static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
bool error) bool error)
{ {
@ -63,8 +68,6 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
enum dma_transfer_direction dir, enum dma_transfer_direction dir,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
struct chip_data *chip =
spi_get_ctldata(drv_data->controller->cur_msg->spi);
enum dma_slave_buswidth width; enum dma_slave_buswidth width;
struct dma_slave_config cfg; struct dma_slave_config cfg;
struct dma_chan *chan; struct dma_chan *chan;
@ -89,14 +92,14 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
if (dir == DMA_MEM_TO_DEV) { if (dir == DMA_MEM_TO_DEV) {
cfg.dst_addr = drv_data->ssp->phys_base + SSDR; cfg.dst_addr = drv_data->ssp->phys_base + SSDR;
cfg.dst_addr_width = width; cfg.dst_addr_width = width;
cfg.dst_maxburst = chip->dma_burst_size; cfg.dst_maxburst = drv_data->controller_info->dma_burst_size;
sgt = &xfer->tx_sg; sgt = &xfer->tx_sg;
chan = drv_data->controller->dma_tx; chan = drv_data->controller->dma_tx;
} else { } else {
cfg.src_addr = drv_data->ssp->phys_base + SSDR; cfg.src_addr = drv_data->ssp->phys_base + SSDR;
cfg.src_addr_width = width; cfg.src_addr_width = width;
cfg.src_maxburst = chip->dma_burst_size; cfg.src_maxburst = drv_data->controller_info->dma_burst_size;
sgt = &xfer->rx_sg; sgt = &xfer->rx_sg;
chan = drv_data->controller->dma_rx; chan = drv_data->controller->dma_rx;
@ -220,24 +223,3 @@ void pxa2xx_spi_dma_release(struct driver_data *drv_data)
controller->dma_tx = NULL; controller->dma_tx = NULL;
} }
} }
int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
struct spi_device *spi,
u8 bits_per_word, u32 *burst_code,
u32 *threshold)
{
struct pxa2xx_spi_chip *chip_info = spi->controller_data;
struct driver_data *drv_data = spi_controller_get_devdata(spi->controller);
u32 dma_burst_size = drv_data->controller_info->dma_burst_size;
/*
* If the DMA burst size is given in chip_info we use that,
* otherwise we use the default. Also we use the default FIFO
* thresholds for now.
*/
*burst_code = chip_info ? chip_info->dma_burst_size : dma_burst_size;
*threshold = SSCR1_RxTresh(RX_THRESH_DFLT)
| SSCR1_TxTresh(TX_THRESH_DFLT);
return 0;
}

View File

@ -6,15 +6,21 @@
* Copyright (C) 2016, 2021 Intel Corporation * Copyright (C) 2016, 2021 Intel Corporation
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/sprintf.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/platform_data/dma-dw.h> #include <linux/platform_data/dma-dw.h>
#include "spi-pxa2xx.h"
#define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0935 #define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0935
#define PCI_DEVICE_ID_INTEL_BYT 0x0f0e #define PCI_DEVICE_ID_INTEL_BYT 0x0f0e
#define PCI_DEVICE_ID_INTEL_MRFLD 0x1194 #define PCI_DEVICE_ID_INTEL_MRFLD 0x1194

View File

@ -5,27 +5,29 @@
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/atomic.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/kernel.h> #include <linux/math64.h>
#include <linux/module.h> #include <linux/minmax.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/of.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include "spi-pxa2xx.h" #include "spi-pxa2xx.h"
@ -64,6 +66,14 @@ MODULE_ALIAS("platform:pxa2xx-spi");
| CE4100_SSCR1_RFT | CE4100_SSCR1_TFT | SSCR1_MWDS \ | CE4100_SSCR1_RFT | CE4100_SSCR1_TFT | SSCR1_MWDS \
| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM) | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
struct chip_data {
u32 cr1;
u32 dds_rate;
u32 threshold;
u16 lpss_rx_threshold;
u16 lpss_tx_threshold;
};
#define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) #define LPSS_GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
#define LPSS_CS_CONTROL_SW_MODE BIT(0) #define LPSS_CS_CONTROL_SW_MODE BIT(0)
#define LPSS_CS_CONTROL_CS_HIGH BIT(1) #define LPSS_CS_CONTROL_CS_HIGH BIT(1)
@ -932,11 +942,11 @@ static bool pxa2xx_spi_can_dma(struct spi_controller *controller,
struct spi_device *spi, struct spi_device *spi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
struct chip_data *chip = spi_get_ctldata(spi); struct driver_data *drv_data = spi_controller_get_devdata(controller);
return chip->enable_dma && return drv_data->controller_info->enable_dma &&
xfer->len <= MAX_DMA_LEN && xfer->len <= MAX_DMA_LEN &&
xfer->len >= chip->dma_burst_size; xfer->len >= drv_data->controller_info->dma_burst_size;
} }
static int pxa2xx_spi_transfer_one(struct spi_controller *controller, static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
@ -944,11 +954,9 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
struct spi_transfer *transfer) struct spi_transfer *transfer)
{ {
struct driver_data *drv_data = spi_controller_get_devdata(controller); struct driver_data *drv_data = spi_controller_get_devdata(controller);
struct spi_message *message = controller->cur_msg;
struct chip_data *chip = spi_get_ctldata(spi); struct chip_data *chip = spi_get_ctldata(spi);
u32 dma_thresh = chip->dma_threshold;
u32 dma_burst = chip->dma_burst_size;
u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data); u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data);
u32 dma_thresh;
u32 clk_div; u32 clk_div;
u8 bits; u8 bits;
u32 speed; u32 speed;
@ -958,17 +966,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
int dma_mapped; int dma_mapped;
/* Check if we can DMA this transfer */ /* Check if we can DMA this transfer */
if (transfer->len > MAX_DMA_LEN && chip->enable_dma) { if (transfer->len > MAX_DMA_LEN && drv_data->controller_info->enable_dma) {
/* Reject already-mapped transfers; PIO won't always work */
if (message->is_dma_mapped
|| transfer->rx_dma || transfer->tx_dma) {
dev_err(&spi->dev,
"Mapped transfer length of %u is greater than %d\n",
transfer->len, MAX_DMA_LEN);
return -EINVAL;
}
/* Warn ... we force this to PIO mode */ /* Warn ... we force this to PIO mode */
dev_warn_ratelimited(&spi->dev, dev_warn_ratelimited(&spi->dev,
"DMA disabled for transfer length %u greater than %d\n", "DMA disabled for transfer length %u greater than %d\n",
@ -1004,19 +1002,8 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
drv_data->read = drv_data->rx ? u32_reader : null_reader; drv_data->read = drv_data->rx ? u32_reader : null_reader;
drv_data->write = drv_data->tx ? u32_writer : null_writer; drv_data->write = drv_data->tx ? u32_writer : null_writer;
} }
/*
* If bits per word is changed in DMA mode, then must check
* the thresholds and burst also.
*/
if (chip->enable_dma) {
if (pxa2xx_spi_set_dma_burst_and_threshold(chip,
spi,
bits, &dma_burst,
&dma_thresh))
dev_warn_ratelimited(&spi->dev,
"DMA burst size reduced to match bits_per_word\n");
}
dma_thresh = SSCR1_RxTresh(RX_THRESH_DFLT) | SSCR1_TxTresh(TX_THRESH_DFLT);
dma_mapped = controller->can_dma && dma_mapped = controller->can_dma &&
controller->can_dma(controller, spi, transfer) && controller->can_dma(controller, spi, transfer) &&
controller->cur_msg_mapped; controller->cur_msg_mapped;
@ -1079,7 +1066,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
pxa_ssp_disable(drv_data->ssp); pxa_ssp_disable(drv_data->ssp);
if (!pxa25x_ssp_comp(drv_data)) if (!pxa25x_ssp_comp(drv_data))
pxa2xx_spi_write(drv_data, SSTO, chip->timeout); pxa2xx_spi_write(drv_data, SSTO, TIMOUT_DFLT);
/* First set CR1 without interrupt and service enables */ /* First set CR1 without interrupt and service enables */
pxa2xx_spi_update(drv_data, SSCR1, change_mask, cr1); pxa2xx_spi_update(drv_data, SSCR1, change_mask, cr1);
@ -1163,7 +1150,6 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_controller *controller)
static int setup(struct spi_device *spi) static int setup(struct spi_device *spi)
{ {
struct pxa2xx_spi_chip *chip_info;
struct chip_data *chip; struct chip_data *chip;
const struct lpss_config *config; const struct lpss_config *config;
struct driver_data *drv_data = struct driver_data *drv_data =
@ -1209,42 +1195,19 @@ static int setup(struct spi_device *spi)
break; break;
} }
if (drv_data->ssp_type == CE4100_SSP) {
if (spi_get_chipselect(spi, 0) > 4) {
dev_err(&spi->dev, "failed setup: cs number must not be > 4.\n");
return -EINVAL;
}
}
/* Only allocate on the first setup */ /* Only allocate on the first setup */
chip = spi_get_ctldata(spi); chip = spi_get_ctldata(spi);
if (!chip) { if (!chip) {
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip) if (!chip)
return -ENOMEM; return -ENOMEM;
if (drv_data->ssp_type == CE4100_SSP) {
if (spi_get_chipselect(spi, 0) > 4) {
dev_err(&spi->dev,
"failed setup: cs number must not be > 4.\n");
kfree(chip);
return -EINVAL;
}
}
chip->enable_dma = drv_data->controller_info->enable_dma;
chip->timeout = TIMOUT_DFLT;
}
/*
* Protocol drivers may change the chip settings, so...
* if chip_info exists, use it.
*/
chip_info = spi->controller_data;
/* chip_info isn't always needed */
if (chip_info) {
if (chip_info->timeout)
chip->timeout = chip_info->timeout;
if (chip_info->tx_threshold)
tx_thres = chip_info->tx_threshold;
if (chip_info->tx_hi_threshold)
tx_hi_thres = chip_info->tx_hi_threshold;
if (chip_info->rx_threshold)
rx_thres = chip_info->rx_threshold;
chip->dma_threshold = 0;
} }
chip->cr1 = 0; chip->cr1 = 0;
@ -1266,25 +1229,6 @@ static int setup(struct spi_device *spi)
chip->lpss_tx_threshold = tx_thres; chip->lpss_tx_threshold = tx_thres;
} }
/*
* Set DMA burst and threshold outside of chip_info path so that if
* chip_info goes away after setting chip->enable_dma, the burst and
* threshold can still respond to changes in bits_per_word.
*/
if (chip->enable_dma) {
/* Set up legal burst and threshold for DMA */
if (pxa2xx_spi_set_dma_burst_and_threshold(chip, spi,
spi->bits_per_word,
&chip->dma_burst_size,
&chip->dma_threshold)) {
dev_warn(&spi->dev,
"in setup: DMA burst size reduced to match bits_per_word\n");
}
dev_dbg(&spi->dev,
"in setup: DMA burst size set to %u\n",
chip->dma_burst_size);
}
switch (drv_data->ssp_type) { switch (drv_data->ssp_type) {
case QUARK_X1000_SSP: case QUARK_X1000_SSP:
chip->threshold = (QUARK_X1000_SSCR1_RxTresh(rx_thres) chip->threshold = (QUARK_X1000_SSCR1_RxTresh(rx_thres)
@ -1326,19 +1270,52 @@ static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
return param == chan->device->dev; return param == chan->device->dev;
} }
static int
pxa2xx_spi_init_ssp(struct platform_device *pdev, struct ssp_device *ssp, enum pxa_ssp_type type)
{
struct device *dev = &pdev->dev;
struct resource *res;
int status;
u64 uid;
ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(ssp->mmio_base))
return PTR_ERR(ssp->mmio_base);
ssp->phys_base = res->start;
ssp->clk = devm_clk_get(dev, NULL);
if (IS_ERR(ssp->clk))
return PTR_ERR(ssp->clk);
ssp->irq = platform_get_irq(pdev, 0);
if (ssp->irq < 0)
return ssp->irq;
ssp->type = type;
ssp->dev = dev;
status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid);
if (status)
ssp->port_id = -1;
else
ssp->port_id = uid;
return 0;
}
static struct pxa2xx_spi_controller * static struct pxa2xx_spi_controller *
pxa2xx_spi_init_pdata(struct platform_device *pdev) pxa2xx_spi_init_pdata(struct platform_device *pdev)
{ {
struct pxa2xx_spi_controller *pdata; struct pxa2xx_spi_controller *pdata;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device *parent = dev->parent; struct device *parent = dev->parent;
struct ssp_device *ssp;
struct resource *res;
enum pxa_ssp_type type = SSP_UNDEFINED; enum pxa_ssp_type type = SSP_UNDEFINED;
struct ssp_device *ssp = NULL;
const void *match; const void *match;
bool is_lpss_priv; bool is_lpss_priv;
u32 num_cs = 1;
int status; int status;
u64 uid;
is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv"); is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv");
@ -1353,6 +1330,12 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
return ERR_PTR(status); return ERR_PTR(status);
type = (enum pxa_ssp_type)value; type = (enum pxa_ssp_type)value;
} else {
ssp = pxa_ssp_request(pdev->id, pdev->name);
if (ssp) {
type = ssp->type;
pxa_ssp_free(ssp);
}
} }
/* Validate the SSP type correctness */ /* Validate the SSP type correctness */
@ -1363,14 +1346,6 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
if (!pdata) if (!pdata)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ssp = &pdata->ssp;
ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(ssp->mmio_base))
return ERR_CAST(ssp->mmio_base);
ssp->phys_base = res->start;
/* Platforms with iDMA 64-bit */ /* Platforms with iDMA 64-bit */
if (is_lpss_priv) { if (is_lpss_priv) {
pdata->tx_param = parent; pdata->tx_param = parent;
@ -1378,28 +1353,22 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
pdata->dma_filter = pxa2xx_spi_idma_filter; pdata->dma_filter = pxa2xx_spi_idma_filter;
} }
ssp->clk = devm_clk_get(dev, NULL); /* Read number of chip select pins, if provided */
if (IS_ERR(ssp->clk)) device_property_read_u32(dev, "num-cs", &num_cs);
return ERR_CAST(ssp->clk);
ssp->irq = platform_get_irq(pdev, 0);
if (ssp->irq < 0)
return ERR_PTR(ssp->irq);
ssp->type = type;
ssp->dev = dev;
status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid);
if (status)
ssp->port_id = -1;
else
ssp->port_id = uid;
pdata->num_chipselect = num_cs;
pdata->is_target = device_property_read_bool(dev, "spi-slave"); pdata->is_target = device_property_read_bool(dev, "spi-slave");
pdata->num_chipselect = 1;
pdata->enable_dma = true; pdata->enable_dma = true;
pdata->dma_burst_size = 1; pdata->dma_burst_size = 1;
/* If SSP has been already enumerated, use it */
if (ssp)
return pdata;
status = pxa2xx_spi_init_ssp(pdev, &pdata->ssp, type);
if (status)
return ERR_PTR(status);
return pdata; return pdata;
} }
@ -1446,20 +1415,17 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
platform_info = dev_get_platdata(dev); platform_info = dev_get_platdata(dev);
if (!platform_info) { if (!platform_info) {
platform_info = pxa2xx_spi_init_pdata(pdev); platform_info = pxa2xx_spi_init_pdata(pdev);
if (IS_ERR(platform_info)) { if (IS_ERR(platform_info))
dev_err(&pdev->dev, "missing platform data\n"); return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n");
return PTR_ERR(platform_info);
}
} }
dev_dbg(dev, "DMA burst size set to %u\n", platform_info->dma_burst_size);
ssp = pxa_ssp_request(pdev->id, pdev->name); ssp = pxa_ssp_request(pdev->id, pdev->name);
if (!ssp) if (!ssp)
ssp = &platform_info->ssp; ssp = &platform_info->ssp;
if (!ssp->mmio_base) { if (!ssp->mmio_base)
dev_err(&pdev->dev, "failed to get SSP\n"); return dev_err_probe(dev, -ENODEV, "failed to get SSP\n");
return -ENODEV;
}
if (platform_info->is_target) if (platform_info->is_target)
controller = devm_spi_alloc_target(dev, sizeof(*drv_data)); controller = devm_spi_alloc_target(dev, sizeof(*drv_data));
@ -1467,8 +1433,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
controller = devm_spi_alloc_host(dev, sizeof(*drv_data)); controller = devm_spi_alloc_host(dev, sizeof(*drv_data));
if (!controller) { if (!controller) {
dev_err(&pdev->dev, "cannot alloc spi_controller\n"); status = dev_err_probe(dev, -ENOMEM, "cannot alloc spi_controller\n");
status = -ENOMEM;
goto out_error_controller_alloc; goto out_error_controller_alloc;
} }
drv_data = spi_controller_get_devdata(controller); drv_data = spi_controller_get_devdata(controller);
@ -1522,7 +1487,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev), status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
drv_data); drv_data);
if (status < 0) { if (status < 0) {
dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq); dev_err_probe(dev, status, "cannot get IRQ %d\n", ssp->irq);
goto out_error_controller_alloc; goto out_error_controller_alloc;
} }
@ -1638,7 +1603,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, drv_data); platform_set_drvdata(pdev, drv_data);
status = spi_register_controller(controller); status = spi_register_controller(controller);
if (status) { if (status) {
dev_err(&pdev->dev, "problem registering SPI controller\n"); dev_err_probe(dev, status, "problem registering SPI controller\n");
goto out_error_pm_runtime_enabled; goto out_error_pm_runtime_enabled;
} }
@ -1741,7 +1706,6 @@ static const struct dev_pm_ops pxa2xx_spi_pm_ops = {
RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend, pxa2xx_spi_runtime_resume, NULL) RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend, pxa2xx_spi_runtime_resume, NULL)
}; };
#ifdef CONFIG_ACPI
static const struct acpi_device_id pxa2xx_spi_acpi_match[] = { static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{ "80860F0E", LPSS_BYT_SSP }, { "80860F0E", LPSS_BYT_SSP },
{ "8086228E", LPSS_BSW_SSP }, { "8086228E", LPSS_BSW_SSP },
@ -1752,9 +1716,8 @@ static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
{} {}
}; };
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match); MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
#endif
static const struct of_device_id pxa2xx_spi_of_match[] __maybe_unused = { static const struct of_device_id pxa2xx_spi_of_match[] = {
{ .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP }, { .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP },
{} {}
}; };
@ -1764,8 +1727,8 @@ static struct platform_driver driver = {
.driver = { .driver = {
.name = "pxa2xx-spi", .name = "pxa2xx-spi",
.pm = pm_ptr(&pxa2xx_spi_pm_ops), .pm = pm_ptr(&pxa2xx_spi_pm_ops),
.acpi_match_table = ACPI_PTR(pxa2xx_spi_acpi_match), .acpi_match_table = pxa2xx_spi_acpi_match,
.of_match_table = of_match_ptr(pxa2xx_spi_of_match), .of_match_table = pxa2xx_spi_of_match,
}, },
.probe = pxa2xx_spi_probe, .probe = pxa2xx_spi_probe,
.remove_new = pxa2xx_spi_remove, .remove_new = pxa2xx_spi_remove,

View File

@ -7,15 +7,34 @@
#ifndef SPI_PXA2XX_H #ifndef SPI_PXA2XX_H
#define SPI_PXA2XX_H #define SPI_PXA2XX_H
#include <linux/interrupt.h> #include <linux/dmaengine.h>
#include <linux/io.h> #include <linux/irqreturn.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/pxa2xx_ssp.h> #include <linux/pxa2xx_ssp.h>
struct gpio_desc; struct gpio_desc;
struct pxa2xx_spi_controller;
/*
* The platform data for SSP controller devices
* (resides in device.platform_data).
*/
struct pxa2xx_spi_controller {
u8 num_chipselect;
u8 enable_dma;
u8 dma_burst_size;
bool is_target;
/* DMA engine specific config */
dma_filter_fn dma_filter;
void *tx_param;
void *rx_param;
/* For non-PXA arches */
struct ssp_device ssp;
};
struct spi_controller; struct spi_controller;
struct spi_device; struct spi_device;
struct spi_transfer; struct spi_transfer;
@ -56,18 +75,6 @@ struct driver_data {
struct gpio_desc *gpiod_ready; struct gpio_desc *gpiod_ready;
}; };
struct chip_data {
u32 cr1;
u32 dds_rate;
u32 timeout;
u8 enable_dma;
u32 dma_burst_size;
u32 dma_threshold;
u32 threshold;
u16 lpss_rx_threshold;
u16 lpss_tx_threshold;
};
static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg) static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data, u32 reg)
{ {
return pxa_ssp_read_reg(drv_data->ssp, reg); return pxa_ssp_read_reg(drv_data->ssp, reg);
@ -123,10 +130,5 @@ extern void pxa2xx_spi_dma_start(struct driver_data *drv_data);
extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data); extern void pxa2xx_spi_dma_stop(struct driver_data *drv_data);
extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data); extern int pxa2xx_spi_dma_setup(struct driver_data *drv_data);
extern void pxa2xx_spi_dma_release(struct driver_data *drv_data); extern void pxa2xx_spi_dma_release(struct driver_data *drv_data);
extern int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
struct spi_device *spi,
u8 bits_per_word,
u32 *burst_code,
u32 *threshold);
#endif /* SPI_PXA2XX_H */ #endif /* SPI_PXA2XX_H */

View File

@ -24,7 +24,6 @@
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/sh_dma.h> #include <linux/sh_dma.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/rspi.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#define RSPI_SPCR 0x00 /* Control Register */ #define RSPI_SPCR 0x00 /* Control Register */
@ -1131,16 +1130,12 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev,
static int rspi_request_dma(struct device *dev, struct spi_controller *ctlr, static int rspi_request_dma(struct device *dev, struct spi_controller *ctlr,
const struct resource *res) const struct resource *res)
{ {
const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev);
unsigned int dma_tx_id, dma_rx_id; unsigned int dma_tx_id, dma_rx_id;
if (dev->of_node) { if (dev->of_node) {
/* In the OF case we will get the slave IDs from the DT */ /* In the OF case we will get the slave IDs from the DT */
dma_tx_id = 0; dma_tx_id = 0;
dma_rx_id = 0; dma_rx_id = 0;
} else if (rspi_pd && rspi_pd->dma_tx_id && rspi_pd->dma_rx_id) {
dma_tx_id = rspi_pd->dma_tx_id;
dma_rx_id = rspi_pd->dma_rx_id;
} else { } else {
/* The driver assumes no error. */ /* The driver assumes no error. */
return 0; return 0;
@ -1290,7 +1285,6 @@ static int rspi_probe(struct platform_device *pdev)
struct spi_controller *ctlr; struct spi_controller *ctlr;
struct rspi_data *rspi; struct rspi_data *rspi;
int ret; int ret;
const struct rspi_plat_data *rspi_pd;
const struct spi_ops *ops; const struct spi_ops *ops;
unsigned long clksrc; unsigned long clksrc;
@ -1305,11 +1299,7 @@ static int rspi_probe(struct platform_device *pdev)
goto error1; goto error1;
} else { } else {
ops = (struct spi_ops *)pdev->id_entry->driver_data; ops = (struct spi_ops *)pdev->id_entry->driver_data;
rspi_pd = dev_get_platdata(&pdev->dev); ctlr->num_chipselect = 2; /* default */
if (rspi_pd && rspi_pd->num_chipselect)
ctlr->num_chipselect = rspi_pd->num_chipselect;
else
ctlr->num_chipselect = 2; /* default */
} }
rspi = spi_controller_get_devdata(ctlr); rspi = spi_controller_get_devdata(ctlr);

View File

@ -950,7 +950,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata(
struct spi_device *spi) struct spi_device *spi)
{ {
struct s3c64xx_spi_csinfo *cs; struct s3c64xx_spi_csinfo *cs;
struct device_node *target_np, *data_np = NULL; struct device_node *target_np;
u32 fb_delay = 0; u32 fb_delay = 0;
target_np = spi->dev.of_node; target_np = spi->dev.of_node;
@ -963,7 +963,8 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata(
if (!cs) if (!cs)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
data_np = of_get_child_by_name(target_np, "controller-data"); struct device_node *data_np __free(device_node) =
of_get_child_by_name(target_np, "controller-data");
if (!data_np) { if (!data_np) {
dev_info(&spi->dev, "feedback delay set to default (0)\n"); dev_info(&spi->dev, "feedback delay set to default (0)\n");
return cs; return cs;
@ -971,7 +972,6 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_target_ctrldata(
of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay); of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay);
cs->fb_delay = fb_delay; cs->fb_delay = fb_delay;
of_node_put(data_np);
return cs; return cs;
} }

View File

@ -206,7 +206,8 @@ static int sun4i_spi_transfer_one(struct spi_controller *host,
struct spi_transfer *tfr) struct spi_transfer *tfr)
{ {
struct sun4i_spi *sspi = spi_controller_get_devdata(host); struct sun4i_spi *sspi = spi_controller_get_devdata(host);
unsigned int mclk_rate, div, timeout; unsigned int mclk_rate, div;
unsigned long time_left;
unsigned int start, end, tx_time; unsigned int start, end, tx_time;
unsigned int tx_len = 0; unsigned int tx_len = 0;
int ret = 0; int ret = 0;
@ -327,10 +328,10 @@ static int sun4i_spi_transfer_one(struct spi_controller *host,
tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U); tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
start = jiffies; start = jiffies;
timeout = wait_for_completion_timeout(&sspi->done, time_left = wait_for_completion_timeout(&sspi->done,
msecs_to_jiffies(tx_time)); msecs_to_jiffies(tx_time));
end = jiffies; end = jiffies;
if (!timeout) { if (!time_left) {
dev_warn(&host->dev, dev_warn(&host->dev,
"%s: timeout transferring %u bytes@%iHz for %i(%i)ms", "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
dev_name(&spi->dev), tfr->len, tfr->speed_hz, dev_name(&spi->dev), tfr->len, tfr->speed_hz,

View File

@ -277,7 +277,8 @@ static int sun6i_spi_transfer_one(struct spi_controller *host,
struct spi_transfer *tfr) struct spi_transfer *tfr)
{ {
struct sun6i_spi *sspi = spi_controller_get_devdata(host); struct sun6i_spi *sspi = spi_controller_get_devdata(host);
unsigned int div, div_cdr1, div_cdr2, timeout; unsigned int div, div_cdr1, div_cdr2;
unsigned long time_left;
unsigned int start, end, tx_time; unsigned int start, end, tx_time;
unsigned int trig_level; unsigned int trig_level;
unsigned int tx_len = 0, rx_len = 0, nbits = 0; unsigned int tx_len = 0, rx_len = 0, nbits = 0;
@ -488,26 +489,26 @@ static int sun6i_spi_transfer_one(struct spi_controller *host,
tx_time = spi_controller_xfer_timeout(host, tfr); tx_time = spi_controller_xfer_timeout(host, tfr);
start = jiffies; start = jiffies;
timeout = wait_for_completion_timeout(&sspi->done, time_left = wait_for_completion_timeout(&sspi->done,
msecs_to_jiffies(tx_time)); msecs_to_jiffies(tx_time));
if (!use_dma) { if (!use_dma) {
sun6i_spi_drain_fifo(sspi); sun6i_spi_drain_fifo(sspi);
} else { } else {
if (timeout && rx_len) { if (time_left && rx_len) {
/* /*
* Even though RX on the peripheral side has finished * Even though RX on the peripheral side has finished
* RX DMA might still be in flight * RX DMA might still be in flight
*/ */
timeout = wait_for_completion_timeout(&sspi->dma_rx_done, time_left = wait_for_completion_timeout(&sspi->dma_rx_done,
timeout); time_left);
if (!timeout) if (!time_left)
dev_warn(&host->dev, "RX DMA timeout\n"); dev_warn(&host->dev, "RX DMA timeout\n");
} }
} }
end = jiffies; end = jiffies;
if (!timeout) { if (!time_left) {
dev_warn(&host->dev, dev_warn(&host->dev,
"%s: timeout transferring %u bytes@%iHz for %i(%i)ms", "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
dev_name(&spi->dev), tfr->len, tfr->speed_hz, dev_name(&spi->dev), tfr->len, tfr->speed_hz,

View File

@ -270,7 +270,7 @@ static int xlp_spi_xfer_block(struct xlp_spi_priv *xs,
const unsigned char *tx_buf, const unsigned char *tx_buf,
unsigned char *rx_buf, int xfer_len, int cmd_cont) unsigned char *rx_buf, int xfer_len, int cmd_cont)
{ {
int timeout; unsigned long time_left;
u32 intr_mask = 0; u32 intr_mask = 0;
xs->tx_buf = tx_buf; xs->tx_buf = tx_buf;
@ -299,11 +299,11 @@ static int xlp_spi_xfer_block(struct xlp_spi_priv *xs,
intr_mask |= XLP_SPI_INTR_DONE; intr_mask |= XLP_SPI_INTR_DONE;
xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, intr_mask); xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, intr_mask);
timeout = wait_for_completion_timeout(&xs->done, time_left = wait_for_completion_timeout(&xs->done,
msecs_to_jiffies(1000)); msecs_to_jiffies(1000));
/* Disable interrupts */ /* Disable interrupts */
xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, 0x0); xlp_spi_reg_write(xs, xs->cs, XLP_SPI_INTR_EN, 0x0);
if (!timeout) { if (!time_left) {
dev_err(&xs->dev, "xfer timedout!\n"); dev_err(&xs->dev, "xfer timedout!\n");
goto out; goto out;
} }

View File

@ -312,7 +312,7 @@ static const struct attribute_group *spi_master_groups[] = {
static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pcpu_stats, static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pcpu_stats,
struct spi_transfer *xfer, struct spi_transfer *xfer,
struct spi_controller *ctlr) struct spi_message *msg)
{ {
int l2len = min(fls(xfer->len), SPI_STATISTICS_HISTO_SIZE) - 1; int l2len = min(fls(xfer->len), SPI_STATISTICS_HISTO_SIZE) - 1;
struct spi_statistics *stats; struct spi_statistics *stats;
@ -328,11 +328,9 @@ static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pc
u64_stats_inc(&stats->transfer_bytes_histo[l2len]); u64_stats_inc(&stats->transfer_bytes_histo[l2len]);
u64_stats_add(&stats->bytes, xfer->len); u64_stats_add(&stats->bytes, xfer->len);
if ((xfer->tx_buf) && if (spi_valid_txbuf(msg, xfer))
(xfer->tx_buf != ctlr->dummy_tx))
u64_stats_add(&stats->bytes_tx, xfer->len); u64_stats_add(&stats->bytes_tx, xfer->len);
if ((xfer->rx_buf) && if (spi_valid_rxbuf(msg, xfer))
(xfer->rx_buf != ctlr->dummy_rx))
u64_stats_add(&stats->bytes_rx, xfer->len); u64_stats_add(&stats->bytes_rx, xfer->len);
u64_stats_update_end(&stats->syncp); u64_stats_update_end(&stats->syncp);
@ -597,10 +595,16 @@ EXPORT_SYMBOL_GPL(spi_alloc_device);
static void spi_dev_set_name(struct spi_device *spi) static void spi_dev_set_name(struct spi_device *spi)
{ {
struct acpi_device *adev = ACPI_COMPANION(&spi->dev); struct device *dev = &spi->dev;
struct fwnode_handle *fwnode = dev_fwnode(dev);
if (adev) { if (is_acpi_device_node(fwnode)) {
dev_set_name(&spi->dev, "spi-%s", acpi_dev_name(adev)); dev_set_name(dev, "spi-%s", acpi_dev_name(to_acpi_device_node(fwnode)));
return;
}
if (is_software_node(fwnode)) {
dev_set_name(dev, "spi-%pfwP", fwnode);
return; return;
} }
@ -822,14 +826,10 @@ struct spi_device *spi_new_device(struct spi_controller *ctlr,
proxy->controller_data = chip->controller_data; proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL; proxy->controller_state = NULL;
/* /*
* spi->chip_select[i] gives the corresponding physical CS for logical CS i * By default spi->chip_select[0] will hold the physical CS number,
* logical CS number is represented by setting the ith bit in spi->cs_index_mask * so set bit 0 in spi->cs_index_mask.
* So, for example, if spi->cs_index_mask = 0x01 then logical CS number is 0 and
* spi->chip_select[0] will give the physical CS.
* By default spi->chip_select[0] will hold the physical CS number so, set
* spi->cs_index_mask as 0x01.
*/ */
proxy->cs_index_mask = 0x01; proxy->cs_index_mask = BIT(0);
if (chip->swnode) { if (chip->swnode) {
status = device_add_software_node(&proxy->dev, chip->swnode); status = device_add_software_node(&proxy->dev, chip->swnode);
@ -1022,20 +1022,45 @@ static void spi_res_release(struct spi_controller *ctlr, struct spi_message *mes
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#define spi_for_each_valid_cs(spi, idx) \
for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) \
if (!(spi->cs_index_mask & BIT(idx))) {} else
static inline bool spi_is_last_cs(struct spi_device *spi) static inline bool spi_is_last_cs(struct spi_device *spi)
{ {
u8 idx; u8 idx;
bool last = false; bool last = false;
for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) { spi_for_each_valid_cs(spi, idx) {
if (spi->cs_index_mask & BIT(idx)) { if (spi->controller->last_cs[idx] == spi_get_chipselect(spi, idx))
if (spi->controller->last_cs[idx] == spi_get_chipselect(spi, idx)) last = true;
last = true;
}
} }
return last; return last;
} }
static void spi_toggle_csgpiod(struct spi_device *spi, u8 idx, bool enable, bool activate)
{
/*
* Historically ACPI has no means of the GPIO polarity and
* thus the SPISerialBus() resource defines it on the per-chip
* basis. In order to avoid a chain of negations, the GPIO
* polarity is considered being Active High. Even for the cases
* when _DSD() is involved (in the updated versions of ACPI)
* the GPIO CS polarity must be defined Active High to avoid
* ambiguity. That's why we use enable, that takes SPI_CS_HIGH
* into account.
*/
if (has_acpi_companion(&spi->dev))
gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx), !enable);
else
/* Polarity handled by GPIO library */
gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx), activate);
if (activate)
spi_delay_exec(&spi->cs_setup, NULL);
else
spi_delay_exec(&spi->cs_inactive, NULL);
}
static void spi_set_cs(struct spi_device *spi, bool enable, bool force) static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
{ {
@ -1072,31 +1097,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
if (spi_is_csgpiod(spi)) { if (spi_is_csgpiod(spi)) {
if (!(spi->mode & SPI_NO_CS)) { if (!(spi->mode & SPI_NO_CS)) {
/* spi_for_each_valid_cs(spi, idx) {
* Historically ACPI has no means of the GPIO polarity and if (spi_get_csgpiod(spi, idx))
* thus the SPISerialBus() resource defines it on the per-chip spi_toggle_csgpiod(spi, idx, enable, activate);
* basis. In order to avoid a chain of negations, the GPIO
* polarity is considered being Active High. Even for the cases
* when _DSD() is involved (in the updated versions of ACPI)
* the GPIO CS polarity must be defined Active High to avoid
* ambiguity. That's why we use enable, that takes SPI_CS_HIGH
* into account.
*/
for (idx = 0; idx < SPI_CS_CNT_MAX; idx++) {
if ((spi->cs_index_mask & BIT(idx)) && spi_get_csgpiod(spi, idx)) {
if (has_acpi_companion(&spi->dev))
gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx),
!enable);
else
/* Polarity handled by GPIO library */
gpiod_set_value_cansleep(spi_get_csgpiod(spi, idx),
activate);
if (activate)
spi_delay_exec(&spi->cs_setup, NULL);
else
spi_delay_exec(&spi->cs_inactive, NULL);
}
} }
} }
/* Some SPI masters need both GPIO CS & slave_select */ /* Some SPI masters need both GPIO CS & slave_select */
@ -1205,12 +1208,10 @@ static void spi_unmap_buf_attrs(struct spi_controller *ctlr,
enum dma_data_direction dir, enum dma_data_direction dir,
unsigned long attrs) unsigned long attrs)
{ {
if (sgt->orig_nents) { dma_unmap_sgtable(dev, sgt, dir, attrs);
dma_unmap_sgtable(dev, sgt, dir, attrs); sg_free_table(sgt);
sg_free_table(sgt); sgt->orig_nents = 0;
sgt->orig_nents = 0; sgt->nents = 0;
sgt->nents = 0;
}
} }
void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev, void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev,
@ -1315,10 +1316,8 @@ static void spi_dma_sync_for_device(struct spi_controller *ctlr,
if (!ctlr->cur_msg_mapped) if (!ctlr->cur_msg_mapped)
return; return;
if (xfer->tx_sg.orig_nents) dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
if (xfer->rx_sg.orig_nents)
dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
} }
static void spi_dma_sync_for_cpu(struct spi_controller *ctlr, static void spi_dma_sync_for_cpu(struct spi_controller *ctlr,
@ -1330,10 +1329,8 @@ static void spi_dma_sync_for_cpu(struct spi_controller *ctlr,
if (!ctlr->cur_msg_mapped) if (!ctlr->cur_msg_mapped)
return; return;
if (xfer->rx_sg.orig_nents) dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
dma_sync_sgtable_for_cpu(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
if (xfer->tx_sg.orig_nents)
dma_sync_sgtable_for_cpu(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
} }
#else /* !CONFIG_HAS_DMA */ #else /* !CONFIG_HAS_DMA */
static inline int __spi_map_msg(struct spi_controller *ctlr, static inline int __spi_map_msg(struct spi_controller *ctlr,
@ -1613,8 +1610,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
list_for_each_entry(xfer, &msg->transfers, transfer_list) { list_for_each_entry(xfer, &msg->transfers, transfer_list) {
trace_spi_transfer_start(msg, xfer); trace_spi_transfer_start(msg, xfer);
spi_statistics_add_transfer_stats(statm, xfer, ctlr); spi_statistics_add_transfer_stats(statm, xfer, msg);
spi_statistics_add_transfer_stats(stats, xfer, ctlr); spi_statistics_add_transfer_stats(stats, xfer, msg);
if (!ctlr->ptp_sts_supported) { if (!ctlr->ptp_sts_supported) {
xfer->ptp_sts_word_pre = 0; xfer->ptp_sts_word_pre = 0;
@ -3709,9 +3706,6 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
* to the same values as *xferp, so tx_buf, rx_buf and len * to the same values as *xferp, so tx_buf, rx_buf and len
* are all identical (as well as most others) * are all identical (as well as most others)
* so we just have to fix up len and the pointers. * so we just have to fix up len and the pointers.
*
* This also includes support for the depreciated
* spi_message.is_dma_mapped interface.
*/ */
/* /*
@ -3725,12 +3719,8 @@ static int __spi_split_transfer_maxsize(struct spi_controller *ctlr,
/* Update rx_buf, tx_buf and DMA */ /* Update rx_buf, tx_buf and DMA */
if (xfers[i].rx_buf) if (xfers[i].rx_buf)
xfers[i].rx_buf += offset; xfers[i].rx_buf += offset;
if (xfers[i].rx_dma)
xfers[i].rx_dma += offset;
if (xfers[i].tx_buf) if (xfers[i].tx_buf)
xfers[i].tx_buf += offset; xfers[i].tx_buf += offset;
if (xfers[i].tx_dma)
xfers[i].tx_dma += offset;
/* Update length */ /* Update length */
xfers[i].len = min(maxsize, xfers[i].len - offset); xfers[i].len = min(maxsize, xfers[i].len - offset);

View File

@ -4,7 +4,11 @@
#include <linux/property.h> #include <linux/property.h>
struct software_node;
#define PROPERTY_ENTRY_GPIO(_name_, _chip_node_, _idx_, _flags_) \ #define PROPERTY_ENTRY_GPIO(_name_, _chip_node_, _idx_, _flags_) \
PROPERTY_ENTRY_REF(_name_, _chip_node_, _idx_, _flags_) PROPERTY_ENTRY_REF(_name_, _chip_node_, _idx_, _flags_)
extern const struct software_node swnode_gpio_undefined;
#endif /* __LINUX_GPIO_PROPERTY_H */ #endif /* __LINUX_GPIO_PROPERTY_H */

View File

@ -16,9 +16,6 @@ struct omap2_mcspi_platform_config {
struct omap2_mcspi_device_config { struct omap2_mcspi_device_config {
unsigned turbo_mode:1; unsigned turbo_mode:1;
/* toggle chip select after every word */
unsigned cs_per_word:1;
}; };
#endif #endif

View File

@ -217,9 +217,9 @@ enum pxa_ssp_type {
PXA27x_SSP, PXA27x_SSP,
PXA3xx_SSP, PXA3xx_SSP,
PXA168_SSP, PXA168_SSP,
MMP2_SSP,
PXA910_SSP, PXA910_SSP,
CE4100_SSP, CE4100_SSP,
MMP2_SSP,
MRFLD_SSP, MRFLD_SSP,
QUARK_X1000_SSP, QUARK_X1000_SSP,
/* Keep LPSS types sorted with lpss_platforms[] */ /* Keep LPSS types sorted with lpss_platforms[] */

View File

@ -1,56 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
*/
#ifndef __LINUX_SPI_PXA2XX_SPI_H
#define __LINUX_SPI_PXA2XX_SPI_H
#include <linux/dmaengine.h>
#include <linux/types.h>
#include <linux/pxa2xx_ssp.h>
struct dma_chan;
/*
* The platform data for SSP controller devices
* (resides in device.platform_data).
*/
struct pxa2xx_spi_controller {
u16 num_chipselect;
u8 enable_dma;
u8 dma_burst_size;
bool is_target;
/* DMA engine specific config */
dma_filter_fn dma_filter;
void *tx_param;
void *rx_param;
/* For non-PXA arches */
struct ssp_device ssp;
};
/*
* The controller specific data for SPI target devices
* (resides in spi_board_info.controller_data),
* copied to spi_device.platform_data ... mostly for
* DMA tuning.
*/
struct pxa2xx_spi_chip {
u8 tx_threshold;
u8 tx_hi_threshold;
u8 rx_threshold;
u8 dma_burst_size;
u32 timeout;
};
#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
#include <linux/clk.h>
extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_controller *info);
#endif
#endif /* __LINUX_SPI_PXA2XX_SPI_H */

View File

@ -1,18 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Renesas SPI driver
*
* Copyright (C) 2012 Renesas Solutions Corp.
*/
#ifndef __LINUX_SPI_RENESAS_SPI_H__
#define __LINUX_SPI_RENESAS_SPI_H__
struct rspi_plat_data {
unsigned int dma_tx_id;
unsigned int dma_rx_id;
u16 num_chipselect;
};
#endif

View File

@ -453,6 +453,7 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
* @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs. * @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs.
* @last_cs: the last chip_select that is recorded by set_cs, -1 on non chip * @last_cs: the last chip_select that is recorded by set_cs, -1 on non chip
* selected * selected
* @last_cs_index_mask: bit mask the last chip selects that were used
* @xfer_completion: used by core transfer_one_message() * @xfer_completion: used by core transfer_one_message()
* @busy: message pump is busy * @busy: message pump is busy
* @running: message pump is running * @running: message pump is running
@ -955,8 +956,8 @@ struct spi_res {
* struct spi_transfer - a read/write buffer pair * struct spi_transfer - a read/write buffer pair
* @tx_buf: data to be written (DMA-safe memory), or NULL * @tx_buf: data to be written (DMA-safe memory), or NULL
* @rx_buf: data to be read (DMA-safe memory), or NULL * @rx_buf: data to be read (DMA-safe memory), or NULL
* @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped * @tx_dma: DMA address of tx_buf, currently not for client use
* @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped * @rx_dma: DMA address of rx_buf, currently not for client use
* @tx_nbits: number of bits used for writing. If 0 the default * @tx_nbits: number of bits used for writing. If 0 the default
* (SPI_NBITS_SINGLE) is used. * (SPI_NBITS_SINGLE) is used.
* @rx_nbits: number of bits used for reading. If 0 the default * @rx_nbits: number of bits used for reading. If 0 the default
@ -1066,8 +1067,7 @@ struct spi_transfer {
/* /*
* It's okay if tx_buf == rx_buf (right?). * It's okay if tx_buf == rx_buf (right?).
* For MicroWire, one buffer must be NULL. * For MicroWire, one buffer must be NULL.
* Buffers must work with dma_*map_single() calls, unless * Buffers must work with dma_*map_single() calls.
* spi_message.is_dma_mapped reports a pre-existing mapping.
*/ */
const void *tx_buf; const void *tx_buf;
void *rx_buf; void *rx_buf;
@ -1111,8 +1111,6 @@ struct spi_transfer {
* struct spi_message - one multi-segment SPI transaction * struct spi_message - one multi-segment SPI transaction
* @transfers: list of transfer segments in this transaction * @transfers: list of transfer segments in this transaction
* @spi: SPI device to which the transaction is queued * @spi: SPI device to which the transaction is queued
* @is_dma_mapped: if true, the caller provided both DMA and CPU virtual
* addresses for each transfer buffer
* @pre_optimized: peripheral driver pre-optimized the message * @pre_optimized: peripheral driver pre-optimized the message
* @optimized: the message is in the optimized state * @optimized: the message is in the optimized state
* @prepared: spi_prepare_message was called for the this message * @prepared: spi_prepare_message was called for the this message
@ -1146,8 +1144,6 @@ struct spi_message {
struct spi_device *spi; struct spi_device *spi;
unsigned is_dma_mapped:1;
/* spi_optimize_message() was called for this message */ /* spi_optimize_message() was called for this message */
bool pre_optimized; bool pre_optimized;
/* __spi_optimize_message() was called for this message */ /* __spi_optimize_message() was called for this message */

View File

@ -2,19 +2,23 @@
#ifndef __LINUX_SPI_XILINX_SPI_H #ifndef __LINUX_SPI_XILINX_SPI_H
#define __LINUX_SPI_XILINX_SPI_H #define __LINUX_SPI_XILINX_SPI_H
#include <linux/types.h>
struct spi_board_info;
/** /**
* struct xspi_platform_data - Platform data of the Xilinx SPI driver * struct xspi_platform_data - Platform data of the Xilinx SPI driver
* @num_chipselect: Number of chip select by the IP.
* @little_endian: If registers should be accessed little endian or not.
* @bits_per_word: Number of bits per word.
* @devices: Devices to add when the driver is probed. * @devices: Devices to add when the driver is probed.
* @num_devices: Number of devices in the devices array. * @num_devices: Number of devices in the devices array.
* @num_chipselect: Number of chip select by the IP.
* @bits_per_word: Number of bits per word.
* @force_irq: If set, forces QSPI transaction requirements.
*/ */
struct xspi_platform_data { struct xspi_platform_data {
u16 num_chipselect;
u8 bits_per_word;
struct spi_board_info *devices; struct spi_board_info *devices;
u8 num_devices; u8 num_devices;
u8 num_chipselect;
u8 bits_per_word;
bool force_irq; bool force_irq;
}; };