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

Pull spi updates from Mark Brown:
 "The only real core work we've got this time around is the completion
  of the transition to the new host/target naming for the core APIs,
  Kconfig still needs doing but that's a lot less invasive.

  Otherwise the big changes are the new drivers that have been added:

   - Completion of the conversion to spi_alloc_host()/_target() and
     removal of the old naming.

   - Cleanups for Rockchip drivers, these brought in a new logging
     helper in the driver core for warnings during probe.

   - Support for configuration of the word delay via spidev_test.

   - Support for AMD HID2 controllers, Apple SPI controller and Realtek
     SPI-NAND controllers"

* tag 'spi-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (58 commits)
  spi: imx: support word delay
  spi: imx: pass struct spi_transfer to prepare_transfer()
  spi: cs42l43: Add GPIO speaker id support to the bridge configuration
  spi: Delete useless checks
  spi: apple: Remove unnecessary .owner for apple_spi_driver
  spi: spidev_test: add support for word delay
  spi: apple: Add driver for Apple SPI controller
  spi: dt-bindings: apple,spi: Add binding for Apple SPI controllers
  spi: Use of_property_present() for non-boolean properties
  spi: zynqmp-gqspi: Undo runtime PM changes at driver exit time​
  spi: spi-mem: rtl-snand: Correctly handle DMA transfers
  spi: tegra210-quad: Avoid shift-out-of-bounds
  spi: axi-spi-engine: Emit trace events for spi transfers
  dt-bindings: spi: sprd,sc9860-spi: convert to YAML
  spi: Replace deprecated PCI functions
  spi: dt-bindings: samsung: Add a compatible for samsung,exynos8895-spi
  spi: spi-mem: Add Realtek SPI-NAND controller
  dt-bindings: spi: Add realtek,rtl9301-snand
  spi: make class structs const
  spi: dt-bindings: brcm,bcm2835-aux-spi: Convert to dtschema
  ...
This commit is contained in:
Linus Torvalds
2024-11-20 12:23:06 -08:00
126 changed files with 2188 additions and 491 deletions

View File

@@ -0,0 +1,20 @@
What: /sys/devices/.../intel_spi_protected
Date: Feb 2025
KernelVersion: 6.13
Contact: Alexander Usyskin <alexander.usyskin@intel.com>
Description: This attribute allows the userspace to check if the
Intel SPI flash controller is write protected from the host.
What: /sys/devices/.../intel_spi_locked
Date: Feb 2025
KernelVersion: 6.13
Contact: Alexander Usyskin <alexander.usyskin@intel.com>
Description: This attribute allows the user space to check if the
Intel SPI flash controller locks supported opcodes.
What: /sys/devices/.../intel_spi_bios_locked
Date: Feb 2025
KernelVersion: 6.13
Contact: Alexander Usyskin <alexander.usyskin@intel.com>
Description: This attribute allows the user space to check if the
Intel SPI flash controller BIOS region is locked for writes.

View File

@@ -0,0 +1,62 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/apple,spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Apple ARM SoC SPI controller
allOf:
- $ref: spi-controller.yaml#
maintainers:
- Hector Martin <marcan@marcan.st>
properties:
compatible:
items:
- enum:
- apple,t8103-spi
- apple,t8112-spi
- apple,t6000-spi
- const: apple,spi
reg:
maxItems: 1
clocks:
maxItems: 1
interrupts:
maxItems: 1
power-domains:
maxItems: 1
required:
- compatible
- reg
- clocks
- interrupts
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/apple-aic.h>
#include <dt-bindings/interrupt-controller/irq.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
spi@39b104000 {
compatible = "apple,t6000-spi", "apple,spi";
reg = <0x3 0x9b104000 0x0 0x4000>;
interrupt-parent = <&aic>;
interrupts = <AIC_IRQ 0 1107 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clk>;
};
};

View File

@@ -1,38 +0,0 @@
Broadcom BCM2835 auxiliary SPI1/2 controller
The BCM2835 contains two forms of SPI master controller, one known simply as
SPI0, and the other known as the "Universal SPI Master"; part of the
auxiliary block. This binding applies to the SPI1/2 controller.
Required properties:
- compatible: Should be "brcm,bcm2835-aux-spi".
- reg: Should contain register location and length for the spi block
- interrupts: Should contain shared interrupt of the aux block
- clocks: The clock feeding the SPI controller - needs to
point to the auxiliary clock driver of the bcm2835,
as this clock will enable the output gate for the specific
clock.
- cs-gpios: the cs-gpios (native cs is NOT supported)
see also spi-bus.txt
Example:
spi1@7e215080 {
compatible = "brcm,bcm2835-aux-spi";
reg = <0x7e215080 0x40>;
interrupts = <1 29>;
clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI1>;
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&gpio 18>, <&gpio 17>, <&gpio 16>;
};
spi2@7e2150c0 {
compatible = "brcm,bcm2835-aux-spi";
reg = <0x7e2150c0 0x40>;
interrupts = <1 29>;
clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI2>;
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&gpio 43>, <&gpio 44>, <&gpio 45>;
};

View File

@@ -0,0 +1,53 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/brcm,bcm2835-aux-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom BCM2835 Auxiliary SPI1/2 Controller
maintainers:
- Karan Sanghavi <karansanghvi98@gmail.com>
description:
The BCM2835 contains two forms of SPI master controller. One is known simply
as SPI0, and the other as the "Universal SPI Master," which is part of the
auxiliary block. This binding applies to the SPI1 and SPI2 auxiliary
controllers.
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
enum:
- brcm,bcm2835-aux-spi
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/bcm2835-aux.h>
spi@7e215080 {
compatible = "brcm,bcm2835-aux-spi";
reg = <0x7e215080 0x40>;
interrupts = <1 29>;
clocks = <&aux_clocks BCM2835_AUX_CLOCK_SPI1>;
#address-cells = <1>;
#size-cells = <0>;
};

View File

@@ -0,0 +1,62 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/realtek,rtl9301-snand.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: SPI-NAND Flash Controller for Realtek RTL9300 SoCs
maintainers:
- Chris Packham <chris.packham@alliedtelesis.co.nz>
description:
The Realtek RTL9300 SoCs have a built in SPI-NAND controller. It supports
typical SPI-NAND page cache operations in single, dual or quad IO mode.
properties:
compatible:
oneOf:
- items:
- enum:
- realtek,rtl9302b-snand
- realtek,rtl9302c-snand
- realtek,rtl9303-snand
- const: realtek,rtl9301-snand
- const: realtek,rtl9301-snand
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
allOf:
- $ref: /schemas/spi/spi-controller.yaml#
unevaluatedProperties: false
examples:
- |
spi@1a400 {
compatible = "realtek,rtl9302c-snand", "realtek,rtl9301-snand";
reg = <0x1a400 0x44>;
interrupt-parent = <&intc>;
interrupts = <19>;
clocks = <&lx_clk>;
#address-cells = <1>;
#size-cells = <0>;
flash@0 {
compatible = "spi-nand";
reg = <0>;
};
};

View File

@@ -26,6 +26,10 @@ properties:
- samsung,exynos850-spi
- samsung,exynosautov9-spi
- tesla,fsd-spi
- items:
- enum:
- samsung,exynos8895-spi
- const: samsung,exynos850-spi
- const: samsung,exynos7-spi
deprecated: true

View File

@@ -1,33 +0,0 @@
Spreadtrum SPI Controller
Required properties:
- compatible: Should be "sprd,sc9860-spi".
- reg: Offset and length of SPI controller register space.
- interrupts: Should contain SPI interrupt.
- clock-names: Should contain following entries:
"spi" for SPI clock,
"source" for SPI source (parent) clock,
"enable" for SPI module enable clock.
- clocks: List of clock input name strings sorted in the same order
as the clock-names property.
- #address-cells: The number of cells required to define a chip select
address on the SPI bus. Should be set to 1.
- #size-cells: Should be set to 0.
Optional properties:
dma-names: Should contain names of the SPI used DMA channel.
dmas: Should contain DMA channels and DMA slave ids which the SPI used
sorted in the same order as the dma-names property.
Example:
spi0: spi@70a00000{
compatible = "sprd,sc9860-spi";
reg = <0 0x70a00000 0 0x1000>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
clock-names = "spi", "source","enable";
clocks = <&clk_spi0>, <&ext_26m>, <&clk_ap_apb_gates 5>;
dma-names = "rx_chn", "tx_chn";
dmas = <&apdma 11 11>, <&apdma 12 12>;
#address-cells = <1>;
#size-cells = <0>;
};

View File

@@ -9,9 +9,6 @@ title: Xilinx Zynq UltraScale+ MPSoC GQSPI controller
maintainers:
- Michal Simek <michal.simek@amd.com>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
enum:
@@ -19,6 +16,7 @@ properties:
- xlnx,zynqmp-qspi-1.0
reg:
minItems: 1
maxItems: 2
interrupts:
@@ -47,6 +45,24 @@ required:
unevaluatedProperties: false
allOf:
- $ref: spi-controller.yaml#
- if:
properties:
compatible:
contains:
const: xlnx,zynqmp-qspi-1.0
then:
properties:
reg:
minItems: 2
else:
properties:
reg:
maxItems: 1
examples:
- |
#include <dt-bindings/clock/xlnx-zynqmp-clk.h>

View File

@@ -0,0 +1,72 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/sprd,sc9860-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Spreadtrum SC9860 SPI Controller
maintainers:
- Orson Zhai <orsonzhai@gmail.com>
- Baolin Wang <baolin.wang7@gmail.com>
- Chunyan Zhang <zhang.lyra@gmail.com>
properties:
compatible:
const: sprd,sc9860-spi
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: SPI clock
- description: SPI source (parent) clock
- description: SPI module enable clock
clock-names:
items:
- const: spi
- const: source
- const: enable
dmas:
maxItems: 2
dma-names:
items:
- const: rx_chn
- const: tx_chn
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
allOf:
- $ref: spi-controller.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi@70a00000 {
compatible = "sprd,sc9860-spi";
reg = <0x70a00000 0x1000>;
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_spi0>, <&ext_26m>, <&clk_ap_apb_gates 5>;
clock-names = "spi", "source", "enable";
dmas = <&apdma 11 11>, <&apdma 12 12>;
dma-names = "rx_chn", "tx_chn";
#address-cells = <1>;
#size-cells = <0>;
};
...

View File

@@ -462,8 +462,8 @@ SLAVE DMA ENGINE
devm_acpi_dma_controller_free()
SPI
devm_spi_alloc_master()
devm_spi_alloc_slave()
devm_spi_alloc_host()
devm_spi_alloc_target()
devm_spi_optimize_message()
devm_spi_register_controller()
devm_spi_register_host()

View File

@@ -19504,6 +19504,12 @@ S: Maintained
F: Documentation/devicetree/bindings/net/dsa/realtek.yaml
F: drivers/net/dsa/realtek/*
REALTEK SPI-NAND
M: Chris Packham <chris.packham@alliedtelesis.co.nz>
S: Maintained
F: Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml
F: drivers/spi/spi-realtek-rtl-snand.c
REALTEK WIRELESS DRIVER (rtlwifi family)
M: Ping-Ke Shih <pkshih@realtek.com>
L: linux-wireless@vger.kernel.org

View File

@@ -5012,6 +5012,49 @@ define_dev_printk_level(_dev_info, KERN_INFO);
#endif
static void __dev_probe_failed(const struct device *dev, int err, bool fatal,
const char *fmt, va_list vargsp)
{
struct va_format vaf;
va_list vargs;
/*
* On x86_64 and possibly on other architectures, va_list is actually a
* size-1 array containing a structure. As a result, function parameter
* vargsp decays from T[1] to T*, and &vargsp has type T** rather than
* T(*)[1], which is expected by its assignment to vaf.va below.
*
* One standard way to solve this mess is by creating a copy in a local
* variable of type va_list and then using a pointer to that local copy
* instead, which is the approach employed here.
*/
va_copy(vargs, vargsp);
vaf.fmt = fmt;
vaf.va = &vargs;
switch (err) {
case -EPROBE_DEFER:
device_set_deferred_probe_reason(dev, &vaf);
dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
break;
case -ENOMEM:
/* Don't print anything on -ENOMEM, there's already enough output */
break;
default:
/* Log fatal final failures as errors, otherwise produce warnings */
if (fatal)
dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
else
dev_warn(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
break;
}
va_end(vargs);
}
/**
* dev_err_probe - probe error check and log helper
* @dev: the pointer to the struct device
@@ -5024,7 +5067,7 @@ define_dev_printk_level(_dev_info, KERN_INFO);
* -EPROBE_DEFER and propagate error upwards.
* In case of -EPROBE_DEFER it sets also defer probe reason, which can be
* checked later by reading devices_deferred debugfs attribute.
* It replaces code sequence::
* It replaces the following code sequence::
*
* if (err != -EPROBE_DEFER)
* dev_err(dev, ...);
@@ -5036,48 +5079,78 @@ define_dev_printk_level(_dev_info, KERN_INFO);
*
* return dev_err_probe(dev, err, ...);
*
* Using this helper in your probe function is totally fine even if @err is
* known to never be -EPROBE_DEFER.
* Using this helper in your probe function is totally fine even if @err
* is known to never be -EPROBE_DEFER.
* The benefit compared to a normal dev_err() is the standardized format
* of the error code, it being emitted symbolically (i.e. you get "EAGAIN"
* instead of "-35") and the fact that the error code is returned which allows
* more compact error paths.
* of the error code, which is emitted symbolically (i.e. you get "EAGAIN"
* instead of "-35"), and having the error code returned allows more
* compact error paths.
*
* Returns @err.
*/
int dev_err_probe(const struct device *dev, int err, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_list vargs;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
va_start(vargs, fmt);
switch (err) {
case -EPROBE_DEFER:
device_set_deferred_probe_reason(dev, &vaf);
dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
break;
/* Use dev_err() for logging when err doesn't equal -EPROBE_DEFER */
__dev_probe_failed(dev, err, true, fmt, vargs);
case -ENOMEM:
/*
* We don't print anything on -ENOMEM, there is already enough
* output.
*/
break;
default:
dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
break;
}
va_end(args);
va_end(vargs);
return err;
}
EXPORT_SYMBOL_GPL(dev_err_probe);
/**
* dev_warn_probe - probe error check and log helper
* @dev: the pointer to the struct device
* @err: error value to test
* @fmt: printf-style format string
* @...: arguments as specified in the format string
*
* This helper implements common pattern present in probe functions for error
* checking: print debug or warning message depending if the error value is
* -EPROBE_DEFER and propagate error upwards.
* In case of -EPROBE_DEFER it sets also defer probe reason, which can be
* checked later by reading devices_deferred debugfs attribute.
* It replaces the following code sequence::
*
* if (err != -EPROBE_DEFER)
* dev_warn(dev, ...);
* else
* dev_dbg(dev, ...);
* return err;
*
* with::
*
* return dev_warn_probe(dev, err, ...);
*
* Using this helper in your probe function is totally fine even if @err
* is known to never be -EPROBE_DEFER.
* The benefit compared to a normal dev_warn() is the standardized format
* of the error code, which is emitted symbolically (i.e. you get "EAGAIN"
* instead of "-35"), and having the error code returned allows more
* compact error paths.
*
* Returns @err.
*/
int dev_warn_probe(const struct device *dev, int err, const char *fmt, ...)
{
va_list vargs;
va_start(vargs, fmt);
/* Use dev_warn() for logging when err doesn't equal -EPROBE_DEFER */
__dev_probe_failed(dev, err, false, fmt, vargs);
va_end(vargs);
return err;
}
EXPORT_SYMBOL_GPL(dev_warn_probe);
static inline bool fwnode_is_primary(struct fwnode_handle *fwnode)
{
return fwnode && !IS_ERR(fwnode->secondary);

View File

@@ -175,11 +175,11 @@ int netup_spi_init(struct netup_unidvb_dev *ndev)
struct spi_controller *ctlr;
struct netup_spi *nspi;
ctlr = devm_spi_alloc_master(&ndev->pci_dev->dev,
sizeof(struct netup_spi));
ctlr = devm_spi_alloc_host(&ndev->pci_dev->dev,
sizeof(struct netup_spi));
if (!ctlr) {
dev_err(&ndev->pci_dev->dev,
"%s(): unable to alloc SPI master\n", __func__);
"%s(): unable to alloc SPI host\n", __func__);
return -EINVAL;
}
nspi = spi_controller_get_devdata(ctlr);

View File

@@ -1219,8 +1219,8 @@ static int msi2500_probe(struct usb_interface *intf,
goto err_free_mem;
}
/* SPI master adapter */
ctlr = spi_alloc_master(dev->dev, 0);
/* SPI host adapter */
ctlr = spi_alloc_host(dev->dev, 0);
if (ctlr == NULL) {
ret = -ENOMEM;
goto err_unregister_v4l2_dev;

View File

@@ -96,6 +96,17 @@ config SPI_AMLOGIC_SPIFC_A1
This enables master mode support for the SPIFC (SPI flash
controller) available in Amlogic A1 (A113L SoC).
config SPI_APPLE
tristate "Apple SoC SPI Controller platform driver"
depends on ARCH_APPLE || COMPILE_TEST
help
This enables support for the SPI controller present on
many Apple SoCs, including the t8103 (M1), t8112 (M2)
and t600x (M1 Pro/Max/Ultra). Multiple SPI controller
instances are present on the SoC and each connects usually
to a single device like spi-nor (nvram), input device controller
or fingerprint sensor.
config SPI_AR934X
tristate "Qualcomm Atheros AR934X/QCA95XX SPI controller driver"
depends on ATH79 || COMPILE_TEST
@@ -843,6 +854,17 @@ config SPI_PXA2XX
config SPI_PXA2XX_PCI
def_tristate SPI_PXA2XX && PCI && COMMON_CLK
config SPI_REALTEK_SNAND
tristate "Realtek SPI-NAND Flash Controller"
depends on MACH_REALTEK_RTL || COMPILE_TEST
select REGMAP
help
This enables support for the SPI-NAND Flash controller on
Realtek SoCs.
This driver does not support generic SPI. The implementation
only supports the spi-mem interface.
config SPI_ROCKCHIP
tristate "Rockchip SPI controller driver"
depends on ARCH_ROCKCHIP || COMPILE_TEST

View File

@@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_ALTERA) += spi-altera-platform.o
obj-$(CONFIG_SPI_ALTERA_CORE) += spi-altera-core.o
obj-$(CONFIG_SPI_ALTERA_DFL) += spi-altera-dfl.o
obj-$(CONFIG_SPI_AMLOGIC_SPIFC_A1) += spi-amlogic-spifc-a1.o
obj-$(CONFIG_SPI_APPLE) += spi-apple.o
obj-$(CONFIG_SPI_AR934X) += spi-ar934x.o
obj-$(CONFIG_SPI_ARMADA_3700) += spi-armada-3700.o
obj-$(CONFIG_SPI_ASPEED_SMC) += spi-aspeed-smc.o
@@ -119,6 +120,7 @@ obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o
obj-$(CONFIG_SPI_REALTEK_SNAND) += spi-realtek-rtl-snand.o
obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o

View File

@@ -516,21 +516,45 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi)
struct spi_controller *ctrl = spi->controller;
struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
unsigned long clk_rate;
u32 cs_inactive;
u32 cs_setup;
u32 cs_hold;
int delay;
int ret;
delay = spi_delay_to_ns(&spi->cs_setup, NULL);
if (delay <= 0)
return delay;
clk_rate = clk_get_rate(aq->pclk);
if (!clk_rate)
return -EINVAL;
/* hold */
delay = spi_delay_to_ns(&spi->cs_hold, NULL);
if (aq->mr & QSPI_MR_SMM) {
if (delay > 0)
dev_warn(&aq->pdev->dev,
"Ignoring cs_hold, must be 0 in Serial Memory Mode.\n");
cs_hold = 0;
} else {
delay = spi_delay_to_ns(&spi->cs_hold, NULL);
if (delay < 0)
return delay;
cs_hold = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 32000);
}
/* setup */
delay = spi_delay_to_ns(&spi->cs_setup, NULL);
if (delay < 0)
return delay;
cs_setup = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)),
1000);
/* inactive */
delay = spi_delay_to_ns(&spi->cs_inactive, NULL);
if (delay < 0)
return delay;
cs_inactive = DIV_ROUND_UP((delay * DIV_ROUND_UP(clk_rate, 1000000)), 1000);
ret = pm_runtime_resume_and_get(ctrl->dev.parent);
if (ret < 0)
return ret;
@@ -539,6 +563,10 @@ static int atmel_qspi_set_cs_timing(struct spi_device *spi)
aq->scr |= QSPI_SCR_DLYBS(cs_setup);
atmel_qspi_write(aq->scr, aq, QSPI_SCR);
aq->mr &= ~(QSPI_MR_DLYBCT_MASK | QSPI_MR_DLYCS_MASK);
aq->mr |= QSPI_MR_DLYBCT(cs_hold) | QSPI_MR_DLYCS(cs_inactive);
atmel_qspi_write(aq->mr, aq, QSPI_MR);
pm_runtime_mark_last_busy(ctrl->dev.parent);
pm_runtime_put_autosuspend(ctrl->dev.parent);
@@ -840,7 +868,7 @@ static struct platform_driver atmel_qspi_driver = {
.pm = pm_ptr(&atmel_qspi_pm_ops),
},
.probe = atmel_qspi_probe,
.remove_new = atmel_qspi_remove,
.remove = atmel_qspi_remove,
};
module_platform_driver(atmel_qspi_driver);

View File

@@ -206,13 +206,6 @@ enum airoha_snand_cs {
SPI_CHIP_SEL_LOW,
};
struct airoha_snand_dev {
size_t buf_len;
u8 *txrx_buf;
dma_addr_t dma_addr;
};
struct airoha_snand_ctrl {
struct device *dev;
struct regmap *regmap_ctrl;
@@ -617,9 +610,9 @@ static bool airoha_snand_supports_op(struct spi_mem *mem,
static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
struct airoha_snand_dev *as_dev = spi_get_ctldata(desc->mem->spi);
u8 *txrx_buf = spi_get_ctldata(desc->mem->spi);
if (!as_dev->txrx_buf)
if (!txrx_buf)
return -EINVAL;
if (desc->info.offset + desc->info.length > U32_MAX)
@@ -634,10 +627,11 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc)
static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
struct spi_device *spi = desc->mem->spi;
struct airoha_snand_dev *as_dev = spi_get_ctldata(spi);
struct spi_mem_op *op = &desc->info.op_tmpl;
struct spi_device *spi = desc->mem->spi;
struct airoha_snand_ctrl *as_ctrl;
u8 *txrx_buf = spi_get_ctldata(spi);
dma_addr_t dma_addr;
u32 val, rd_mode;
int err;
@@ -662,14 +656,17 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
if (err)
return err;
dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr,
as_dev->buf_len, DMA_BIDIRECTIONAL);
dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE,
DMA_FROM_DEVICE);
err = dma_mapping_error(as_ctrl->dev, dma_addr);
if (err)
return err;
/* set dma addr */
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
as_dev->dma_addr);
dma_addr);
if (err)
return err;
goto error_dma_unmap;
/* set cust sec size */
val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num;
@@ -678,58 +675,58 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
REG_SPI_NFI_SNF_MISC_CTL2,
SPI_NFI_READ_DATA_BYTE_NUM, val);
if (err)
return err;
goto error_dma_unmap;
/* set read command */
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2,
op->cmd.opcode);
if (err)
return err;
goto error_dma_unmap;
/* set read mode */
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL,
FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, rd_mode));
if (err)
return err;
goto error_dma_unmap;
/* set read addr */
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, 0x0);
if (err)
return err;
goto error_dma_unmap;
/* set nfi read */
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_OPMODE,
FIELD_PREP(SPI_NFI_OPMODE, 6));
if (err)
return err;
goto error_dma_unmap;
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE);
if (err)
return err;
goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x0);
if (err)
return err;
goto error_dma_unmap;
/* trigger dma start read */
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
SPI_NFI_RD_TRIG);
if (err)
return err;
goto error_dma_unmap;
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
SPI_NFI_RD_TRIG);
if (err)
return err;
goto error_dma_unmap;
err = regmap_read_poll_timeout(as_ctrl->regmap_nfi,
REG_SPI_NFI_SNF_STA_CTL1, val,
(val & SPI_NFI_READ_FROM_CACHE_DONE),
0, 1 * USEC_PER_SEC);
if (err)
return err;
goto error_dma_unmap;
/*
* SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end
@@ -739,35 +736,41 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
SPI_NFI_READ_FROM_CACHE_DONE,
SPI_NFI_READ_FROM_CACHE_DONE);
if (err)
return err;
goto error_dma_unmap;
err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR,
val, (val & SPI_NFI_AHB_DONE), 0,
1 * USEC_PER_SEC);
if (err)
return err;
goto error_dma_unmap;
/* DMA read need delay for data ready from controller to DRAM */
udelay(1);
dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr,
as_dev->buf_len, DMA_BIDIRECTIONAL);
dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
DMA_FROM_DEVICE);
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
if (err < 0)
return err;
memcpy(buf, as_dev->txrx_buf + offs, len);
memcpy(buf, txrx_buf + offs, len);
return len;
error_dma_unmap:
dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
DMA_FROM_DEVICE);
return err;
}
static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, const void *buf)
{
struct spi_device *spi = desc->mem->spi;
struct airoha_snand_dev *as_dev = spi_get_ctldata(spi);
struct spi_mem_op *op = &desc->info.op_tmpl;
struct spi_device *spi = desc->mem->spi;
u8 *txrx_buf = spi_get_ctldata(spi);
struct airoha_snand_ctrl *as_ctrl;
dma_addr_t dma_addr;
u32 wr_mode, val;
int err;
@@ -776,19 +779,20 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
if (err < 0)
return err;
dma_sync_single_for_cpu(as_ctrl->dev, as_dev->dma_addr,
as_dev->buf_len, DMA_BIDIRECTIONAL);
memcpy(as_dev->txrx_buf + offs, buf, len);
dma_sync_single_for_device(as_ctrl->dev, as_dev->dma_addr,
as_dev->buf_len, DMA_BIDIRECTIONAL);
memcpy(txrx_buf + offs, buf, len);
dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE,
DMA_TO_DEVICE);
err = dma_mapping_error(as_ctrl->dev, dma_addr);
if (err)
return err;
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA);
if (err < 0)
return err;
goto error_dma_unmap;
err = airoha_snand_nfi_config(as_ctrl);
if (err)
return err;
goto error_dma_unmap;
if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD ||
op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD)
@@ -797,9 +801,9 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
wr_mode = 0;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR,
as_dev->dma_addr);
dma_addr);
if (err)
return err;
goto error_dma_unmap;
val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM,
as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num);
@@ -807,65 +811,65 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
REG_SPI_NFI_SNF_MISC_CTL2,
SPI_NFI_PROG_LOAD_BYTE_NUM, val);
if (err)
return err;
goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1,
FIELD_PREP(SPI_NFI_PG_LOAD_CMD,
op->cmd.opcode));
if (err)
return err;
goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL,
FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode));
if (err)
return err;
goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0);
if (err)
return err;
goto error_dma_unmap;
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_READ_MODE);
if (err)
return err;
goto error_dma_unmap;
err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_OPMODE,
FIELD_PREP(SPI_NFI_OPMODE, 3));
if (err)
return err;
goto error_dma_unmap;
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG,
SPI_NFI_DMA_MODE);
if (err)
return err;
goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CMD, 0x80);
if (err)
return err;
goto error_dma_unmap;
err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
SPI_NFI_WR_TRIG);
if (err)
return err;
goto error_dma_unmap;
err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON,
SPI_NFI_WR_TRIG);
if (err)
return err;
goto error_dma_unmap;
err = regmap_read_poll_timeout(as_ctrl->regmap_nfi, REG_SPI_NFI_INTR,
val, (val & SPI_NFI_AHB_DONE), 0,
1 * USEC_PER_SEC);
if (err)
return err;
goto error_dma_unmap;
err = regmap_read_poll_timeout(as_ctrl->regmap_nfi,
REG_SPI_NFI_SNF_STA_CTL1, val,
(val & SPI_NFI_LOAD_TO_CACHE_DONE),
0, 1 * USEC_PER_SEC);
if (err)
return err;
goto error_dma_unmap;
/*
* SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end
@@ -875,13 +879,20 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
SPI_NFI_LOAD_TO_CACHE_DONE,
SPI_NFI_LOAD_TO_CACHE_DONE);
if (err)
return err;
goto error_dma_unmap;
dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
DMA_TO_DEVICE);
err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL);
if (err < 0)
return err;
return len;
error_dma_unmap:
dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE,
DMA_TO_DEVICE);
return err;
}
static int airoha_snand_exec_op(struct spi_mem *mem,
@@ -956,42 +967,20 @@ static const struct spi_controller_mem_ops airoha_snand_mem_ops = {
static int airoha_snand_setup(struct spi_device *spi)
{
struct airoha_snand_ctrl *as_ctrl;
struct airoha_snand_dev *as_dev;
as_ctrl = spi_controller_get_devdata(spi->controller);
as_dev = devm_kzalloc(as_ctrl->dev, sizeof(*as_dev), GFP_KERNEL);
if (!as_dev)
return -ENOMEM;
u8 *txrx_buf;
/* prepare device buffer */
as_dev->buf_len = SPI_NAND_CACHE_SIZE;
as_dev->txrx_buf = devm_kzalloc(as_ctrl->dev, as_dev->buf_len,
GFP_KERNEL);
if (!as_dev->txrx_buf)
as_ctrl = spi_controller_get_devdata(spi->controller);
txrx_buf = devm_kzalloc(as_ctrl->dev, SPI_NAND_CACHE_SIZE,
GFP_KERNEL);
if (!txrx_buf)
return -ENOMEM;
as_dev->dma_addr = dma_map_single(as_ctrl->dev, as_dev->txrx_buf,
as_dev->buf_len, DMA_BIDIRECTIONAL);
if (dma_mapping_error(as_ctrl->dev, as_dev->dma_addr))
return -ENOMEM;
spi_set_ctldata(spi, as_dev);
spi_set_ctldata(spi, txrx_buf);
return 0;
}
static void airoha_snand_cleanup(struct spi_device *spi)
{
struct airoha_snand_dev *as_dev = spi_get_ctldata(spi);
struct airoha_snand_ctrl *as_ctrl;
as_ctrl = spi_controller_get_devdata(spi->controller);
dma_unmap_single(as_ctrl->dev, as_dev->dma_addr,
as_dev->buf_len, DMA_BIDIRECTIONAL);
spi_set_ctldata(spi, NULL);
}
static int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl)
{
u32 val, sec_size, sec_num;
@@ -1093,7 +1082,6 @@ static int airoha_snand_probe(struct platform_device *pdev)
ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
ctrl->mode_bits = SPI_RX_DUAL;
ctrl->setup = airoha_snand_setup;
ctrl->cleanup = airoha_snand_cleanup;
device_set_node(&ctrl->dev, dev_fwnode(dev));
err = airoha_snand_nfi_setup(as_ctrl);

File diff suppressed because it is too large Load Diff

529
drivers/spi/spi-apple.c Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More