spi: Updates for v6.13

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.
 
 The Rockchip cleanups
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmc7QdQACgkQJNaLcl1U
 h9A7KAf+Od8ORLheHKrokFYWEW1zuiR45EjqWylLk835d3TQn/VfLOouRDhOPKLw
 wmxy5PjjvI+CHa9JY4TXY6iRTCc8By6fkwRWFZN5KApSC2NQriWiqgTSItFfYiLv
 yUthZjfRhbfSpf6E/0hq4axpfn+6W/MIWUg7Ag08IEU+GhDd+um8gdpBKsP1BAJF
 s34Fn3oJNoze0Wwcq5tZ91S1MsP+2vGFGIGC2HA7G2GAXjGFqBZUnIL+zjC1US3j
 XILAoy4Vx4J0Nn+f+zdGL2m5cm6O49ztaKqUxamVFigwM4va5OSOEpcnFMEPZ8HY
 013dIg7tiayUTOTcByCpzfMDWuzHig==
 =jc6e
 -----END PGP SIGNATURE-----

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
commit f2ef39727a
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,
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,
as_ctrl = spi_controller_get_devdata(spi->controller);
txrx_buf = devm_kzalloc(as_ctrl->dev, SPI_NAND_CACHE_SIZE,
GFP_KERNEL);
if (!as_dev->txrx_buf)
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);

View File

@ -7,12 +7,14 @@
// Author: Sanjay R Mehta <sanju.mehta@amd.com>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/iopoll.h>
#include <linux/spi/spi-mem.h>
#define AMD_SPI_CTRL0_REG 0x00
@ -33,10 +35,12 @@
#define AMD_SPI_TX_COUNT_REG 0x48
#define AMD_SPI_RX_COUNT_REG 0x4B
#define AMD_SPI_STATUS_REG 0x4C
#define AMD_SPI_ADDR32CTRL_REG 0x50
#define AMD_SPI_FIFO_SIZE 70
#define AMD_SPI_MEM_SIZE 200
#define AMD_SPI_MAX_DATA 64
#define AMD_SPI_HID2_DMA_SIZE 4096
#define AMD_SPI_ENA_REG 0x20
#define AMD_SPI_ALT_SPD_SHIFT 20
@ -47,17 +51,46 @@
#define AMD_SPI_SPD7_SHIFT 8
#define AMD_SPI_SPD7_MASK GENMASK(13, AMD_SPI_SPD7_SHIFT)
#define AMD_SPI_HID2_INPUT_RING_BUF0 0X100
#define AMD_SPI_HID2_CNTRL 0x150
#define AMD_SPI_HID2_INT_STATUS 0x154
#define AMD_SPI_HID2_CMD_START 0x156
#define AMD_SPI_HID2_INT_MASK 0x158
#define AMD_SPI_HID2_READ_CNTRL0 0x170
#define AMD_SPI_HID2_READ_CNTRL1 0x174
#define AMD_SPI_HID2_READ_CNTRL2 0x180
#define AMD_SPI_MAX_HZ 100000000
#define AMD_SPI_MIN_HZ 800000
#define AMD_SPI_IO_SLEEP_US 20
#define AMD_SPI_IO_TIMEOUT_US 2000000
/* SPI read command opcodes */
#define AMD_SPI_OP_READ 0x03 /* Read data bytes (low frequency) */
#define AMD_SPI_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
#define AMD_SPI_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */
#define AMD_SPI_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */
#define AMD_SPI_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */
#define AMD_SPI_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */
/* SPI read command opcodes - 4B address */
#define AMD_SPI_OP_READ_FAST_4B 0x0c /* Read data bytes (high frequency) */
#define AMD_SPI_OP_READ_1_1_2_4B 0x3c /* Read data bytes (Dual Output SPI) */
#define AMD_SPI_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */
#define AMD_SPI_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */
#define AMD_SPI_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */
/**
* enum amd_spi_versions - SPI controller versions
* @AMD_SPI_V1: AMDI0061 hardware version
* @AMD_SPI_V2: AMDI0062 hardware version
* @AMD_HID2_SPI: AMDI0063 hardware version
*/
enum amd_spi_versions {
AMD_SPI_V1 = 1,
AMD_SPI_V2,
AMD_HID2_SPI,
};
enum amd_spi_speed {
@ -88,23 +121,27 @@ struct amd_spi_freq {
/**
* struct amd_spi - SPI driver instance
* @io_remap_addr: Start address of the SPI controller registers
* @phy_dma_buf: Physical address of DMA buffer
* @dma_virt_addr: Virtual address of DMA buffer
* @version: SPI controller hardware version
* @speed_hz: Device frequency
*/
struct amd_spi {
void __iomem *io_remap_addr;
dma_addr_t phy_dma_buf;
void *dma_virt_addr;
enum amd_spi_versions version;
unsigned int speed_hz;
};
static inline u8 amd_spi_readreg8(struct amd_spi *amd_spi, int idx)
{
return ioread8((u8 __iomem *)amd_spi->io_remap_addr + idx);
return readb((u8 __iomem *)amd_spi->io_remap_addr + idx);
}
static inline void amd_spi_writereg8(struct amd_spi *amd_spi, int idx, u8 val)
{
iowrite8(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
writeb(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
}
static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 clear)
@ -115,14 +152,34 @@ static void amd_spi_setclear_reg8(struct amd_spi *amd_spi, int idx, u8 set, u8 c
amd_spi_writereg8(amd_spi, idx, tmp);
}
static inline u16 amd_spi_readreg16(struct amd_spi *amd_spi, int idx)
{
return readw((u8 __iomem *)amd_spi->io_remap_addr + idx);
}
static inline void amd_spi_writereg16(struct amd_spi *amd_spi, int idx, u16 val)
{
writew(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
}
static inline u32 amd_spi_readreg32(struct amd_spi *amd_spi, int idx)
{
return ioread32((u8 __iomem *)amd_spi->io_remap_addr + idx);
return readl((u8 __iomem *)amd_spi->io_remap_addr + idx);
}
static inline void amd_spi_writereg32(struct amd_spi *amd_spi, int idx, u32 val)
{
iowrite32(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
writel(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
}
static inline u64 amd_spi_readreg64(struct amd_spi *amd_spi, int idx)
{
return readq((u8 __iomem *)amd_spi->io_remap_addr + idx);
}
static inline void amd_spi_writereg64(struct amd_spi *amd_spi, int idx, u64 val)
{
writeq(val, ((u8 __iomem *)amd_spi->io_remap_addr + idx));
}
static inline void amd_spi_setclear_reg32(struct amd_spi *amd_spi, int idx, u32 set, u32 clear)
@ -156,6 +213,7 @@ static int amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode)
AMD_SPI_OPCODE_MASK);
return 0;
case AMD_SPI_V2:
case AMD_HID2_SPI:
amd_spi_writereg8(amd_spi, AMD_SPI_OPCODE_REG, cmd_opcode);
return 0;
default:
@ -165,12 +223,12 @@ static int amd_spi_set_opcode(struct amd_spi *amd_spi, u8 cmd_opcode)
static inline void amd_spi_set_rx_count(struct amd_spi *amd_spi, u8 rx_count)
{
amd_spi_setclear_reg8(amd_spi, AMD_SPI_RX_COUNT_REG, rx_count, 0xff);
amd_spi_writereg8(amd_spi, AMD_SPI_RX_COUNT_REG, rx_count);
}
static inline void amd_spi_set_tx_count(struct amd_spi *amd_spi, u8 tx_count)
{
amd_spi_setclear_reg8(amd_spi, AMD_SPI_TX_COUNT_REG, tx_count, 0xff);
amd_spi_writereg8(amd_spi, AMD_SPI_TX_COUNT_REG, tx_count);
}
static int amd_spi_busy_wait(struct amd_spi *amd_spi)
@ -183,6 +241,7 @@ static int amd_spi_busy_wait(struct amd_spi *amd_spi)
reg = AMD_SPI_CTRL0_REG;
break;
case AMD_SPI_V2:
case AMD_HID2_SPI:
reg = AMD_SPI_STATUS_REG;
break;
default:
@ -208,6 +267,7 @@ static int amd_spi_execute_opcode(struct amd_spi *amd_spi)
AMD_SPI_EXEC_CMD);
return 0;
case AMD_SPI_V2:
case AMD_HID2_SPI:
/* Trigger the command execution */
amd_spi_setclear_reg8(amd_spi, AMD_SPI_CMD_TRIGGER_REG,
AMD_SPI_TRIGGER_CMD, AMD_SPI_TRIGGER_CMD);
@ -349,6 +409,7 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
case AMD_SPI_V1:
break;
case AMD_SPI_V2:
case AMD_HID2_SPI:
amd_spi_clear_chip(amd_spi, spi_get_chipselect(message->spi, 0));
break;
default:
@ -360,20 +421,82 @@ static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
return message->status;
}
static inline bool amd_is_spi_read_cmd_4b(const u16 op)
{
switch (op) {
case AMD_SPI_OP_READ_FAST_4B:
case AMD_SPI_OP_READ_1_1_2_4B:
case AMD_SPI_OP_READ_1_2_2_4B:
case AMD_SPI_OP_READ_1_1_4_4B:
case AMD_SPI_OP_READ_1_4_4_4B:
return true;
default:
return false;
}
}
static inline bool amd_is_spi_read_cmd(const u16 op)
{
switch (op) {
case AMD_SPI_OP_READ:
case AMD_SPI_OP_READ_FAST:
case AMD_SPI_OP_READ_1_1_2:
case AMD_SPI_OP_READ_1_2_2:
case AMD_SPI_OP_READ_1_1_4:
case AMD_SPI_OP_READ_1_4_4:
return true;
default:
return amd_is_spi_read_cmd_4b(op);
}
}
static bool amd_spi_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
struct amd_spi *amd_spi = spi_controller_get_devdata(mem->spi->controller);
/* 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)
if (op->cmd.buswidth > 1 || op->addr.buswidth > 4)
return false;
/* AMD SPI controllers support quad mode only for read operations */
if (amd_is_spi_read_cmd(op->cmd.opcode)) {
if (op->data.buswidth > 4)
return false;
/*
* HID2 SPI controller supports DMA read up to 4K bytes and
* doesn't support 4-byte address commands.
*/
if (amd_spi->version == AMD_HID2_SPI) {
if (amd_is_spi_read_cmd_4b(op->cmd.opcode) ||
op->data.nbytes > AMD_SPI_HID2_DMA_SIZE)
return false;
} else if (op->data.nbytes > AMD_SPI_MAX_DATA) {
return false;
}
} else if (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)
{
struct amd_spi *amd_spi = spi_controller_get_devdata(mem->spi->controller);
/*
* HID2 SPI controller DMA read mode supports reading up to 4k
* bytes in single transaction, where as SPI0 and HID2 SPI
* controller index mode supports maximum of 64 bytes in a single
* transaction.
*/
if (amd_spi->version == AMD_HID2_SPI && amd_is_spi_read_cmd(op->cmd.opcode))
op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_HID2_DMA_SIZE);
else
op->data.nbytes = clamp_val(op->data.nbytes, 0, AMD_SPI_MAX_DATA);
return 0;
}
@ -397,15 +520,23 @@ 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;
u64 *buf_64 = (u64 *)op->data.buf.out;
u32 nbytes = op->data.nbytes;
u32 left_data = nbytes;
u8 *buf;
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]);
for (i = 0; left_data >= 8; i++, left_data -= 8)
amd_spi_writereg64(amd_spi, base_addr + op->dummy.nbytes + (i * 8), *buf_64++);
buf = (u8 *)buf_64;
for (i = 0; i < left_data; i++) {
amd_spi_writereg8(amd_spi, base_addr + op->dummy.nbytes + nbytes + i - left_data,
buf[i]);
}
amd_spi_set_tx_count(amd_spi, op->addr.nbytes + op->data.nbytes);
amd_spi_set_rx_count(amd_spi, 0);
@ -413,26 +544,128 @@ static void amd_spi_mem_data_out(struct amd_spi *amd_spi,
amd_spi_execute_opcode(amd_spi);
}
static void amd_spi_hiddma_read(struct amd_spi *amd_spi, const struct spi_mem_op *op)
{
u16 hid_cmd_start, val;
u32 hid_regval;
/* Set the opcode in hid2_read_control0 register */
hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL0);
hid_regval = (hid_regval & ~GENMASK(7, 0)) | op->cmd.opcode;
/*
* Program the address in the hid2_read_control0 register [8:31]. The address should
* be written starting from the 8th bit of the register, requiring an 8-bit shift.
* Additionally, to convert a 2-byte spinand address to a 3-byte address, another
* 8-bit shift is needed. Therefore, a total shift of 16 bits is required.
*/
hid_regval = (hid_regval & ~GENMASK(31, 8)) | (op->addr.val << 16);
amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL0, hid_regval);
/* Configure dummy clock cycles for fast read, dual, quad I/O commands */
hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL2);
/* Fast read dummy cycle */
hid_regval &= ~GENMASK(4, 0);
/* Fast read Dual I/O dummy cycle */
hid_regval &= ~GENMASK(12, 8);
/* Fast read Quad I/O dummy cycle */
hid_regval = (hid_regval & ~GENMASK(20, 16)) | BIT(17);
/* Set no of preamble bytecount */
hid_regval &= ~GENMASK(27, 24);
amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL2, hid_regval);
/*
* Program the HID2 Input Ring Buffer0. 4k aligned buf_memory_addr[31:12],
* buf_size[4:0], end_input_ring[5].
*/
hid_regval = amd_spi->phy_dma_buf | BIT(5) | BIT(0);
amd_spi_writereg32(amd_spi, AMD_SPI_HID2_INPUT_RING_BUF0, hid_regval);
/* Program max read length(no of DWs) in hid2_read_control1 register */
hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_READ_CNTRL1);
hid_regval = (hid_regval & ~GENMASK(15, 0)) | ((op->data.nbytes / 4) - 1);
amd_spi_writereg32(amd_spi, AMD_SPI_HID2_READ_CNTRL1, hid_regval);
/* Set cmd start bit in hid2_cmd_start register to trigger HID basic read operation */
hid_cmd_start = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_CMD_START);
amd_spi_writereg16(amd_spi, AMD_SPI_HID2_CMD_START, (hid_cmd_start | BIT(3)));
/* Check interrupt status of HIDDMA basic read operation in hid2_int_status register */
readw_poll_timeout(amd_spi->io_remap_addr + AMD_SPI_HID2_INT_STATUS, val,
(val & BIT(3)), AMD_SPI_IO_SLEEP_US, AMD_SPI_IO_TIMEOUT_US);
/* Clear the interrupts by writing to hid2_int_status register */
val = amd_spi_readreg16(amd_spi, AMD_SPI_HID2_INT_STATUS);
amd_spi_writereg16(amd_spi, AMD_SPI_HID2_INT_STATUS, val);
}
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;
int base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes;
u64 *buf_64 = (u64 *)op->data.buf.in;
u32 nbytes = op->data.nbytes;
int base_addr, i;
u32 left_data = nbytes;
u32 data;
u8 *buf;
int i;
base_addr = AMD_SPI_FIFO_BASE + op->addr.nbytes + offset;
/*
* Condition for using HID read mode. Only for reading complete page data, use HID read.
* Use index mode otherwise.
*/
if (amd_spi->version == AMD_HID2_SPI && amd_is_spi_read_cmd(op->cmd.opcode)) {
amd_spi_hiddma_read(amd_spi, op);
for (i = 0; left_data >= 8; i++, left_data -= 8)
*buf_64++ = readq((u8 __iomem *)amd_spi->dma_virt_addr + (i * 8));
buf = (u8 *)buf_64;
for (i = 0; i < left_data; i++)
buf[i] = readb((u8 __iomem *)amd_spi->dma_virt_addr +
(nbytes - left_data + i));
/* Reset HID RX memory logic */
data = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_CNTRL);
amd_spi_writereg32(amd_spi, AMD_SPI_HID2_CNTRL, data | BIT(5));
} else {
/* Index mode */
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_set_tx_count(amd_spi, op->addr.nbytes + op->dummy.nbytes);
for (i = 0; i < op->dummy.nbytes; i++)
amd_spi_writereg8(amd_spi, (base_addr + i), 0xff);
amd_spi_set_rx_count(amd_spi, op->data.nbytes);
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);
for (i = 0; left_data >= 8; i++, left_data -= 8)
*buf_64++ = amd_spi_readreg64(amd_spi, base_addr + op->dummy.nbytes +
(i * 8));
buf = (u8 *)buf_64;
for (i = 0; i < left_data; i++)
buf[i] = amd_spi_readreg8(amd_spi, base_addr + op->dummy.nbytes +
nbytes + i - left_data);
}
}
static void amd_set_spi_addr_mode(struct amd_spi *amd_spi,
const struct spi_mem_op *op)
{
u32 val = amd_spi_readreg32(amd_spi, AMD_SPI_ADDR32CTRL_REG);
if (amd_is_spi_read_cmd_4b(op->cmd.opcode))
amd_spi_writereg32(amd_spi, AMD_SPI_ADDR32CTRL_REG, val | BIT(0));
else
amd_spi_writereg32(amd_spi, AMD_SPI_ADDR32CTRL_REG, val & ~BIT(0));
}
static int amd_spi_exec_mem_op(struct spi_mem *mem,
@ -447,6 +680,9 @@ static int amd_spi_exec_mem_op(struct spi_mem *mem,
if (ret)
return ret;
if (amd_spi->version == AMD_SPI_V2)
amd_set_spi_addr_mode(amd_spi, op);
switch (op->data.dir) {
case SPI_MEM_DATA_IN:
amd_spi_mem_data_in(amd_spi, op);
@ -489,6 +725,31 @@ static size_t amd_spi_max_transfer_size(struct spi_device *spi)
return AMD_SPI_FIFO_SIZE;
}
static int amd_spi_setup_hiddma(struct amd_spi *amd_spi, struct device *dev)
{
u32 hid_regval;
/* Allocate DMA buffer to use for HID basic read operation */
amd_spi->dma_virt_addr = dma_alloc_coherent(dev, AMD_SPI_HID2_DMA_SIZE,
&amd_spi->phy_dma_buf, GFP_KERNEL);
if (!amd_spi->dma_virt_addr)
return -ENOMEM;
/*
* Enable interrupts and set mask bits in hid2_int_mask register to generate interrupt
* properly for HIDDMA basic read operations.
*/
hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_INT_MASK);
hid_regval = (hid_regval & GENMASK(31, 8)) | BIT(19);
amd_spi_writereg32(amd_spi, AMD_SPI_HID2_INT_MASK, hid_regval);
/* Configure buffer unit(4k) in hid2_control register */
hid_regval = amd_spi_readreg32(amd_spi, AMD_SPI_HID2_CNTRL);
amd_spi_writereg32(amd_spi, AMD_SPI_HID2_CNTRL, hid_regval & ~BIT(3));
return 0;
}
static int amd_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -512,9 +773,9 @@ static int amd_spi_probe(struct platform_device *pdev)
amd_spi->version = (uintptr_t) device_get_match_data(dev);
/* Initialize the spi_controller fields */
host->bus_num = 0;
host->bus_num = (amd_spi->version == AMD_HID2_SPI) ? 2 : 0;
host->num_chipselect = 4;
host->mode_bits = 0;
host->mode_bits = SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD;
host->flags = SPI_CONTROLLER_HALF_DUPLEX;
host->max_speed_hz = AMD_SPI_MAX_HZ;
host->min_speed_hz = AMD_SPI_MIN_HZ;
@ -529,13 +790,17 @@ static int amd_spi_probe(struct platform_device *pdev)
if (err)
return dev_err_probe(dev, err, "error registering SPI controller\n");
return 0;
if (amd_spi->version == AMD_HID2_SPI)
err = amd_spi_setup_hiddma(amd_spi, dev);
return err;
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id spi_acpi_match[] = {
{ "AMDI0061", AMD_SPI_V1 },
{ "AMDI0062", AMD_SPI_V2 },
{ "AMDI0063", AMD_HID2_SPI },
{},
};
MODULE_DEVICE_TABLE(acpi, spi_acpi_match);

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

@ -0,0 +1,529 @@
// SPDX-License-Identifier: GPL-2.0
//
// Apple SoC SPI device driver
//
// Copyright The Asahi Linux Contributors
//
// Based on spi-sifive.c, Copyright 2018 SiFive, Inc.
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#define APPLE_SPI_CTRL 0x000
#define APPLE_SPI_CTRL_RUN BIT(0)
#define APPLE_SPI_CTRL_TX_RESET BIT(2)
#define APPLE_SPI_CTRL_RX_RESET BIT(3)
#define APPLE_SPI_CFG 0x004
#define APPLE_SPI_CFG_CPHA BIT(1)
#define APPLE_SPI_CFG_CPOL BIT(2)
#define APPLE_SPI_CFG_MODE GENMASK(6, 5)
#define APPLE_SPI_CFG_MODE_POLLED 0
#define APPLE_SPI_CFG_MODE_IRQ 1
#define APPLE_SPI_CFG_MODE_DMA 2
#define APPLE_SPI_CFG_IE_RXCOMPLETE BIT(7)
#define APPLE_SPI_CFG_IE_TXRXTHRESH BIT(8)
#define APPLE_SPI_CFG_LSB_FIRST BIT(13)
#define APPLE_SPI_CFG_WORD_SIZE GENMASK(16, 15)
#define APPLE_SPI_CFG_WORD_SIZE_8B 0
#define APPLE_SPI_CFG_WORD_SIZE_16B 1
#define APPLE_SPI_CFG_WORD_SIZE_32B 2
#define APPLE_SPI_CFG_FIFO_THRESH GENMASK(18, 17)
#define APPLE_SPI_CFG_FIFO_THRESH_8B 0
#define APPLE_SPI_CFG_FIFO_THRESH_4B 1
#define APPLE_SPI_CFG_FIFO_THRESH_1B 2
#define APPLE_SPI_CFG_IE_TXCOMPLETE BIT(21)
#define APPLE_SPI_STATUS 0x008
#define APPLE_SPI_STATUS_RXCOMPLETE BIT(0)
#define APPLE_SPI_STATUS_TXRXTHRESH BIT(1)
#define APPLE_SPI_STATUS_TXCOMPLETE BIT(2)
#define APPLE_SPI_PIN 0x00c
#define APPLE_SPI_PIN_KEEP_MOSI BIT(0)
#define APPLE_SPI_PIN_CS BIT(1)
#define APPLE_SPI_TXDATA 0x010
#define APPLE_SPI_RXDATA 0x020
#define APPLE_SPI_CLKDIV 0x030
#define APPLE_SPI_CLKDIV_MAX 0x7ff
#define APPLE_SPI_RXCNT 0x034
#define APPLE_SPI_WORD_DELAY 0x038
#define APPLE_SPI_TXCNT 0x04c
#define APPLE_SPI_FIFOSTAT 0x10c
#define APPLE_SPI_FIFOSTAT_TXFULL BIT(4)
#define APPLE_SPI_FIFOSTAT_LEVEL_TX GENMASK(15, 8)
#define APPLE_SPI_FIFOSTAT_RXEMPTY BIT(20)
#define APPLE_SPI_FIFOSTAT_LEVEL_RX GENMASK(31, 24)
#define APPLE_SPI_IE_XFER 0x130
#define APPLE_SPI_IF_XFER 0x134
#define APPLE_SPI_XFER_RXCOMPLETE BIT(0)
#define APPLE_SPI_XFER_TXCOMPLETE BIT(1)
#define APPLE_SPI_IE_FIFO 0x138
#define APPLE_SPI_IF_FIFO 0x13c
#define APPLE_SPI_FIFO_RXTHRESH BIT(4)
#define APPLE_SPI_FIFO_TXTHRESH BIT(5)
#define APPLE_SPI_FIFO_RXFULL BIT(8)
#define APPLE_SPI_FIFO_TXEMPTY BIT(9)
#define APPLE_SPI_FIFO_RXUNDERRUN BIT(16)
#define APPLE_SPI_FIFO_TXOVERFLOW BIT(17)
#define APPLE_SPI_SHIFTCFG 0x150
#define APPLE_SPI_SHIFTCFG_CLK_ENABLE BIT(0)
#define APPLE_SPI_SHIFTCFG_CS_ENABLE BIT(1)
#define APPLE_SPI_SHIFTCFG_AND_CLK_DATA BIT(8)
#define APPLE_SPI_SHIFTCFG_CS_AS_DATA BIT(9)
#define APPLE_SPI_SHIFTCFG_TX_ENABLE BIT(10)
#define APPLE_SPI_SHIFTCFG_RX_ENABLE BIT(11)
#define APPLE_SPI_SHIFTCFG_BITS GENMASK(21, 16)
#define APPLE_SPI_SHIFTCFG_OVERRIDE_CS BIT(24)
#define APPLE_SPI_PINCFG 0x154
#define APPLE_SPI_PINCFG_KEEP_CLK BIT(0)
#define APPLE_SPI_PINCFG_KEEP_CS BIT(1)
#define APPLE_SPI_PINCFG_KEEP_MOSI BIT(2)
#define APPLE_SPI_PINCFG_CLK_IDLE_VAL BIT(8)
#define APPLE_SPI_PINCFG_CS_IDLE_VAL BIT(9)
#define APPLE_SPI_PINCFG_MOSI_IDLE_VAL BIT(10)
#define APPLE_SPI_DELAY_PRE 0x160
#define APPLE_SPI_DELAY_POST 0x168
#define APPLE_SPI_DELAY_ENABLE BIT(0)
#define APPLE_SPI_DELAY_NO_INTERBYTE BIT(1)
#define APPLE_SPI_DELAY_SET_SCK BIT(4)
#define APPLE_SPI_DELAY_SET_MOSI BIT(6)
#define APPLE_SPI_DELAY_SCK_VAL BIT(8)
#define APPLE_SPI_DELAY_MOSI_VAL BIT(12)
#define APPLE_SPI_FIFO_DEPTH 16
/*
* The slowest refclock available is 24MHz, the highest divider is 0x7ff,
* the largest word size is 32 bits, the FIFO depth is 16, the maximum
* intra-word delay is 0xffff refclocks. So the maximum time a transfer
* cycle can take is:
*
* (0x7ff * 32 + 0xffff) * 16 / 24e6 Hz ~= 87ms
*
* Double it and round it up to 200ms for good measure.
*/
#define APPLE_SPI_TIMEOUT_MS 200
struct apple_spi {
void __iomem *regs; /* MMIO register address */
struct clk *clk; /* bus clock */
struct completion done; /* wake-up from interrupt */
};
static inline void reg_write(struct apple_spi *spi, int offset, u32 value)
{
writel_relaxed(value, spi->regs + offset);
}
static inline u32 reg_read(struct apple_spi *spi, int offset)
{
return readl_relaxed(spi->regs + offset);
}
static inline void reg_mask(struct apple_spi *spi, int offset, u32 clear, u32 set)
{
u32 val = reg_read(spi, offset);
val &= ~clear;
val |= set;
reg_write(spi, offset, val);
}
static void apple_spi_init(struct apple_spi *spi)
{
/* Set CS high (inactive) and disable override and auto-CS */
reg_write(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS);
reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_OVERRIDE_CS, 0);
reg_mask(spi, APPLE_SPI_PINCFG, APPLE_SPI_PINCFG_CS_IDLE_VAL, APPLE_SPI_PINCFG_KEEP_CS);
/* Reset FIFOs */
reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET);
/* Configure defaults */
reg_write(spi, APPLE_SPI_CFG,
FIELD_PREP(APPLE_SPI_CFG_FIFO_THRESH, APPLE_SPI_CFG_FIFO_THRESH_8B) |
FIELD_PREP(APPLE_SPI_CFG_MODE, APPLE_SPI_CFG_MODE_IRQ) |
FIELD_PREP(APPLE_SPI_CFG_WORD_SIZE, APPLE_SPI_CFG_WORD_SIZE_8B));
/* Disable IRQs */
reg_write(spi, APPLE_SPI_IE_FIFO, 0);
reg_write(spi, APPLE_SPI_IE_XFER, 0);
/* Disable delays */
reg_write(spi, APPLE_SPI_DELAY_PRE, 0);
reg_write(spi, APPLE_SPI_DELAY_POST, 0);
}
static int apple_spi_prepare_message(struct spi_controller *ctlr, struct spi_message *msg)
{
struct apple_spi *spi = spi_controller_get_devdata(ctlr);
struct spi_device *device = msg->spi;
u32 cfg = ((device->mode & SPI_CPHA ? APPLE_SPI_CFG_CPHA : 0) |
(device->mode & SPI_CPOL ? APPLE_SPI_CFG_CPOL : 0) |
(device->mode & SPI_LSB_FIRST ? APPLE_SPI_CFG_LSB_FIRST : 0));
/* Update core config */
reg_mask(spi, APPLE_SPI_CFG,
APPLE_SPI_CFG_CPHA | APPLE_SPI_CFG_CPOL | APPLE_SPI_CFG_LSB_FIRST, cfg);
return 0;
}
static void apple_spi_set_cs(struct spi_device *device, bool is_high)
{
struct apple_spi *spi = spi_controller_get_devdata(device->controller);
reg_mask(spi, APPLE_SPI_PIN, APPLE_SPI_PIN_CS, is_high ? APPLE_SPI_PIN_CS : 0);
}
static bool apple_spi_prep_transfer(struct apple_spi *spi, struct spi_transfer *t)
{
u32 cr, fifo_threshold;
/* Calculate and program the clock rate */
cr = DIV_ROUND_UP(clk_get_rate(spi->clk), t->speed_hz);
reg_write(spi, APPLE_SPI_CLKDIV, min_t(u32, cr, APPLE_SPI_CLKDIV_MAX));
/* Update bits per word */
reg_mask(spi, APPLE_SPI_SHIFTCFG, APPLE_SPI_SHIFTCFG_BITS,
FIELD_PREP(APPLE_SPI_SHIFTCFG_BITS, t->bits_per_word));
/* We will want to poll if the time we need to wait is
* less than the context switching time.
* Let's call that threshold 5us. The operation will take:
* bits_per_word * fifo_threshold / hz <= 5 * 10^-6
* 200000 * bits_per_word * fifo_threshold <= hz
*/
fifo_threshold = APPLE_SPI_FIFO_DEPTH / 2;
return (200000 * t->bits_per_word * fifo_threshold) <= t->speed_hz;
}
static irqreturn_t apple_spi_irq(int irq, void *dev_id)
{
struct apple_spi *spi = dev_id;
u32 fifo = reg_read(spi, APPLE_SPI_IF_FIFO) & reg_read(spi, APPLE_SPI_IE_FIFO);
u32 xfer = reg_read(spi, APPLE_SPI_IF_XFER) & reg_read(spi, APPLE_SPI_IE_XFER);
if (fifo || xfer) {
/* Disable interrupts until next transfer */
reg_write(spi, APPLE_SPI_IE_XFER, 0);
reg_write(spi, APPLE_SPI_IE_FIFO, 0);
complete(&spi->done);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static int apple_spi_wait(struct apple_spi *spi, u32 fifo_bit, u32 xfer_bit, int poll)
{
int ret = 0;
if (poll) {
u32 fifo, xfer;
unsigned long timeout = jiffies + APPLE_SPI_TIMEOUT_MS * HZ / 1000;
do {
fifo = reg_read(spi, APPLE_SPI_IF_FIFO);
xfer = reg_read(spi, APPLE_SPI_IF_XFER);
if (time_after(jiffies, timeout)) {
ret = -ETIMEDOUT;
break;
}
} while (!((fifo & fifo_bit) || (xfer & xfer_bit)));
} else {
reinit_completion(&spi->done);
reg_write(spi, APPLE_SPI_IE_XFER, xfer_bit);
reg_write(spi, APPLE_SPI_IE_FIFO, fifo_bit);
if (!wait_for_completion_timeout(&spi->done,
msecs_to_jiffies(APPLE_SPI_TIMEOUT_MS)))
ret = -ETIMEDOUT;
reg_write(spi, APPLE_SPI_IE_XFER, 0);
reg_write(spi, APPLE_SPI_IE_FIFO, 0);
}
return ret;
}
static void apple_spi_tx(struct apple_spi *spi, const void **tx_ptr, u32 *left,
unsigned int bytes_per_word)
{
u32 inuse, words, wrote;
if (!*tx_ptr)
return;
inuse = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_TX, reg_read(spi, APPLE_SPI_FIFOSTAT));
words = wrote = min_t(u32, *left, APPLE_SPI_FIFO_DEPTH - inuse);
if (!words)
return;
*left -= words;
switch (bytes_per_word) {
case 1: {
const u8 *p = *tx_ptr;
while (words--)
reg_write(spi, APPLE_SPI_TXDATA, *p++);
break;
}
case 2: {
const u16 *p = *tx_ptr;
while (words--)
reg_write(spi, APPLE_SPI_TXDATA, *p++);
break;
}
case 4: {
const u32 *p = *tx_ptr;
while (words--)
reg_write(spi, APPLE_SPI_TXDATA, *p++);
break;
}
default:
WARN_ON(1);
}
*tx_ptr = ((u8 *)*tx_ptr) + bytes_per_word * wrote;
}
static void apple_spi_rx(struct apple_spi *spi, void **rx_ptr, u32 *left,
unsigned int bytes_per_word)
{
u32 words, read;
if (!*rx_ptr)
return;
words = read = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_RX, reg_read(spi, APPLE_SPI_FIFOSTAT));
WARN_ON(words > *left);
if (!words)
return;
*left -= min_t(u32, *left, words);
switch (bytes_per_word) {
case 1: {
u8 *p = *rx_ptr;
while (words--)
*p++ = reg_read(spi, APPLE_SPI_RXDATA);
break;
}
case 2: {
u16 *p = *rx_ptr;
while (words--)
*p++ = reg_read(spi, APPLE_SPI_RXDATA);
break;
}
case 4: {
u32 *p = *rx_ptr;
while (words--)
*p++ = reg_read(spi, APPLE_SPI_RXDATA);
break;
}
default:
WARN_ON(1);
}
*rx_ptr = ((u8 *)*rx_ptr) + bytes_per_word * read;
}
static int apple_spi_transfer_one(struct spi_controller *ctlr, struct spi_device *device,
struct spi_transfer *t)
{
struct apple_spi *spi = spi_controller_get_devdata(ctlr);
bool poll = apple_spi_prep_transfer(spi, t);
const void *tx_ptr = t->tx_buf;
void *rx_ptr = t->rx_buf;
unsigned int bytes_per_word;
u32 words, remaining_tx, remaining_rx;
u32 xfer_flags = 0;
u32 fifo_flags;
int retries = 100;
int ret = 0;
if (t->bits_per_word > 16)
bytes_per_word = 4;
else if (t->bits_per_word > 8)
bytes_per_word = 2;
else
bytes_per_word = 1;
words = t->len / bytes_per_word;
remaining_tx = tx_ptr ? words : 0;
remaining_rx = rx_ptr ? words : 0;
/* Reset FIFOs */
reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET);
/* Clear IRQ flags */
reg_write(spi, APPLE_SPI_IF_XFER, ~0);
reg_write(spi, APPLE_SPI_IF_FIFO, ~0);
/* Determine transfer completion flags we wait for */
if (tx_ptr)
xfer_flags |= APPLE_SPI_XFER_TXCOMPLETE;
if (rx_ptr)
xfer_flags |= APPLE_SPI_XFER_RXCOMPLETE;
/* Set transfer length */
reg_write(spi, APPLE_SPI_TXCNT, remaining_tx);
reg_write(spi, APPLE_SPI_RXCNT, remaining_rx);
/* Prime transmit FIFO */
apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word);
/* Start transfer */
reg_write(spi, APPLE_SPI_CTRL, APPLE_SPI_CTRL_RUN);
/* TX again since a few words get popped off immediately */
apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word);
while (xfer_flags) {
fifo_flags = 0;
if (remaining_tx)
fifo_flags |= APPLE_SPI_FIFO_TXTHRESH;
if (remaining_rx)
fifo_flags |= APPLE_SPI_FIFO_RXTHRESH;
/* Wait for anything to happen */
ret = apple_spi_wait(spi, fifo_flags, xfer_flags, poll);
if (ret) {
dev_err(&ctlr->dev, "transfer timed out (remaining %d tx, %d rx)\n",
remaining_tx, remaining_rx);
goto err;
}
/* Stop waiting on transfer halves once they complete */
xfer_flags &= ~reg_read(spi, APPLE_SPI_IF_XFER);
/* Transmit and receive everything we can */
apple_spi_tx(spi, &tx_ptr, &remaining_tx, bytes_per_word);
apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word);
}
/*
* Sometimes the transfer completes before the last word is in the RX FIFO.
* Normally one retry is all it takes to get the last word out.
*/
while (remaining_rx && retries--)
apple_spi_rx(spi, &rx_ptr, &remaining_rx, bytes_per_word);
if (remaining_tx)
dev_err(&ctlr->dev, "transfer completed with %d words left to transmit\n",
remaining_tx);
if (remaining_rx)
dev_err(&ctlr->dev, "transfer completed with %d words left to receive\n",
remaining_rx);
err:
fifo_flags = reg_read(spi, APPLE_SPI_IF_FIFO);
WARN_ON(fifo_flags & APPLE_SPI_FIFO_TXOVERFLOW);
WARN_ON(fifo_flags & APPLE_SPI_FIFO_RXUNDERRUN);
/* Stop transfer */
reg_write(spi, APPLE_SPI_CTRL, 0);
return ret;
}
static int apple_spi_probe(struct platform_device *pdev)
{
struct apple_spi *spi;
int ret, irq;
struct spi_controller *ctlr;
ctlr = devm_spi_alloc_host(&pdev->dev, sizeof(struct apple_spi));
if (!ctlr)
return -ENOMEM;
spi = spi_controller_get_devdata(ctlr);
init_completion(&spi->done);
spi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(spi->regs))
return PTR_ERR(spi->regs);
spi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
if (IS_ERR(spi->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk),
"Unable to find or enable bus clock\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = devm_request_irq(&pdev->dev, irq, apple_spi_irq, 0,
dev_name(&pdev->dev), spi);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Unable to bind to interrupt\n");
ctlr->dev.of_node = pdev->dev.of_node;
ctlr->bus_num = pdev->id;
ctlr->num_chipselect = 1;
ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
ctlr->prepare_message = apple_spi_prepare_message;
ctlr->set_cs = apple_spi_set_cs;
ctlr->transfer_one = apple_spi_transfer_one;
ctlr->auto_runtime_pm = true;
pm_runtime_set_active(&pdev->dev);
ret = devm_pm_runtime_enable(&pdev->dev);
if (ret < 0)
return ret;
apple_spi_init(spi);
ret = devm_spi_register_controller(&pdev->dev, ctlr);
if (ret < 0)
return dev_err_probe(&pdev->dev, ret, "devm_spi_register_controller failed\n");
return 0;
}
static const struct of_device_id apple_spi_of_match[] = {
{ .compatible = "apple,spi", },
{}
};
MODULE_DEVICE_TABLE(of, apple_spi_of_match);
static struct platform_driver apple_spi_driver = {
.probe = apple_spi_probe,
.driver = {
.name = "apple-spi",
.of_match_table = apple_spi_of_match,
},
};
module_platform_driver(apple_spi_driver);
MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
MODULE_DESCRIPTION("Apple SoC SPI driver");
MODULE_LICENSE("GPL");

View File

@ -223,7 +223,7 @@ static struct platform_driver ar934x_spi_driver = {
.of_match_table = ar934x_spi_match,
},
.probe = ar934x_spi_probe,
.remove_new = ar934x_spi_remove,
.remove = ar934x_spi_remove,
};
module_platform_driver(ar934x_spi_driver);

View File

@ -1189,7 +1189,7 @@ MODULE_DEVICE_TABLE(of, aspeed_spi_matches);
static struct platform_driver aspeed_spi_driver = {
.probe = aspeed_spi_probe,
.remove_new = aspeed_spi_remove,
.remove = aspeed_spi_remove,
.driver = {
.name = DEVICE_NAME,
.of_match_table = aspeed_spi_matches,

View File

@ -650,7 +650,7 @@ static struct platform_driver at91_usart_spi_driver = {
.pm = &at91_usart_spi_pm_ops,
},
.probe = at91_usart_spi_probe,
.remove_new = at91_usart_spi_remove,
.remove = at91_usart_spi_remove,
};
module_platform_driver(at91_usart_spi_driver);

View File

@ -253,7 +253,7 @@ MODULE_DEVICE_TABLE(of, ath79_spi_of_match);
static struct platform_driver ath79_spi_driver = {
.probe = ath79_spi_probe,
.remove_new = ath79_spi_remove,
.remove = ath79_spi_remove,
.shutdown = ath79_spi_shutdown,
.driver = {
.name = DRV_NAME,

View File

@ -1781,7 +1781,7 @@ static struct platform_driver atmel_spi_driver = {
.of_match_table = atmel_spi_dt_ids,
},
.probe = atmel_spi_probe,
.remove_new = atmel_spi_remove,
.remove = atmel_spi_remove,
};
module_platform_driver(atmel_spi_driver);

View File

@ -940,7 +940,7 @@ MODULE_ALIAS("platform:au1550-spi");
static struct platform_driver au1550_spi_drv = {
.probe = au1550_spi_probe,
.remove_new = au1550_spi_remove,
.remove = au1550_spi_remove,
.driver = {
.name = "au1550-spi",
},

View File

@ -15,6 +15,7 @@
#include <linux/overflow.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <trace/events/spi.h>
#define SPI_ENGINE_REG_RESET 0x40
@ -590,6 +591,13 @@ static int spi_engine_transfer_one_message(struct spi_controller *host,
reinit_completion(&spi_engine->msg_complete);
if (trace_spi_transfer_start_enabled()) {
struct spi_transfer *xfer;
list_for_each_entry(xfer, &msg->transfers, transfer_list)
trace_spi_transfer_start(msg, xfer);
}
spin_lock_irqsave(&spi_engine->lock, flags);
if (spi_engine_write_cmd_fifo(spi_engine, msg))
@ -617,6 +625,13 @@ static int spi_engine_transfer_one_message(struct spi_controller *host,
msg->status = -ETIMEDOUT;
}
if (trace_spi_transfer_stop_enabled()) {
struct spi_transfer *xfer;
list_for_each_entry(xfer, &msg->transfers, transfer_list)
trace_spi_transfer_stop(msg, xfer);
}
spi_finalize_current_message(host);
return msg->status;

View File

@ -1435,7 +1435,7 @@ static struct platform_driver bcm2835_spi_driver = {
.of_match_table = bcm2835_spi_match,
},
.probe = bcm2835_spi_probe,
.remove_new = bcm2835_spi_remove,
.remove = bcm2835_spi_remove,
.shutdown = bcm2835_spi_remove,
};
module_platform_driver(bcm2835_spi_driver);

View File

@ -577,7 +577,7 @@ static struct platform_driver bcm2835aux_spi_driver = {
.of_match_table = bcm2835aux_spi_match,
},
.probe = bcm2835aux_spi_probe,
.remove_new = bcm2835aux_spi_remove,
.remove = bcm2835aux_spi_remove,
};
module_platform_driver(bcm2835aux_spi_driver);

View File

@ -944,7 +944,7 @@ static struct platform_driver bcm63xx_hsspi_driver = {
.of_match_table = bcm63xx_hsspi_of_match,
},
.probe = bcm63xx_hsspi_probe,
.remove_new = bcm63xx_hsspi_remove,
.remove = bcm63xx_hsspi_remove,
};
module_platform_driver(bcm63xx_hsspi_driver);

View File

@ -656,7 +656,7 @@ static struct platform_driver bcm63xx_spi_driver = {
},
.id_table = bcm63xx_spi_dev_match,
.probe = bcm63xx_spi_probe,
.remove_new = bcm63xx_spi_remove,
.remove = bcm63xx_spi_remove,
};
module_platform_driver(bcm63xx_spi_driver);

View File

@ -633,7 +633,7 @@ static struct platform_driver bcmbca_hsspi_driver = {
.of_match_table = bcmbca_hsspi_of_match,
},
.probe = bcmbca_hsspi_probe,
.remove_new = bcmbca_hsspi_remove,
.remove = bcmbca_hsspi_remove,
};
module_platform_driver(bcmbca_hsspi_driver);

View File

@ -28,7 +28,7 @@ static void brcmstb_qspi_remove(struct platform_device *pdev)
static struct platform_driver brcmstb_qspi_driver = {
.probe = brcmstb_qspi_probe,
.remove_new = brcmstb_qspi_remove,
.remove = brcmstb_qspi_remove,
.driver = {
.name = "brcmstb_qspi",
.pm = &bcm_qspi_pm_ops,

View File

@ -2112,7 +2112,7 @@ MODULE_DEVICE_TABLE(of, cqspi_dt_ids);
static struct platform_driver cqspi_platform_driver = {
.probe = cqspi_probe,
.remove_new = cqspi_remove,
.remove = cqspi_remove,
.driver = {
.name = CQSPI_NAME,
.pm = pm_ptr(&cqspi_dev_pm_ops),

View File

@ -806,7 +806,7 @@ MODULE_DEVICE_TABLE(of, cdns_spi_of_match);
/* cdns_spi_driver - This structure defines the SPI subsystem platform driver */
static struct platform_driver cdns_spi_driver = {
.probe = cdns_spi_probe,
.remove_new = cdns_spi_remove,
.remove = cdns_spi_remove,
.driver = {
.name = CDNS_SPI_NAME,
.of_match_table = cdns_spi_of_match,

View File

@ -90,7 +90,7 @@ static struct platform_driver octeon_spi_driver = {
.of_match_table = octeon_spi_match,
},
.probe = octeon_spi_probe,
.remove_new = octeon_spi_remove,
.remove = octeon_spi_remove,
};
module_platform_driver(octeon_spi_driver);

View File

@ -152,7 +152,7 @@ static int ch341_probe(struct usb_interface *intf,
if (ret)
return ret;
ctrl = devm_spi_alloc_master(&udev->dev, sizeof(struct ch341_spi_dev));
ctrl = devm_spi_alloc_host(&udev->dev, sizeof(struct ch341_spi_dev));
if (!ctrl)
return -ENOMEM;

View File

@ -502,7 +502,7 @@ static struct platform_driver mcfqspi_driver = {
.driver.name = DRIVER_NAME,
.driver.pm = &mcfqspi_pm,
.probe = mcfqspi_probe,
.remove_new = mcfqspi_remove,
.remove = mcfqspi_remove,
};
module_platform_driver(mcfqspi_driver);

View File

@ -12,6 +12,7 @@
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/property.h>
#include <linux/mfd/cs42l43.h>
@ -229,6 +230,33 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi)
return CS42L43_SPI_MAX_LENGTH;
}
static int cs42l43_get_speaker_id_gpios(struct cs42l43_spi *priv, int *result)
{
struct gpio_descs *descs;
u32 spkid;
int i, ret;
descs = gpiod_get_array_optional(priv->dev, "spk-id", GPIOD_IN);
if (IS_ERR_OR_NULL(descs))
return PTR_ERR(descs);
spkid = 0;
for (i = 0; i < descs->ndescs; i++) {
ret = gpiod_get_value_cansleep(descs->desc[i]);
if (ret < 0)
goto err;
spkid |= (ret << i);
}
dev_dbg(priv->dev, "spk-id-gpios = %d\n", spkid);
*result = spkid;
err:
gpiod_put_array(descs);
return ret;
}
static struct fwnode_handle *cs42l43_find_xu_node(struct fwnode_handle *fwnode)
{
static const u32 func_smart_amp = 0x1;
@ -306,6 +334,7 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev);
struct fwnode_handle *xu_fwnode __free(fwnode_handle) = cs42l43_find_xu_node(fwnode);
int nsidecars = 0;
int spkid = -EINVAL;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@ -360,6 +389,18 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
fwnode_property_read_u32(xu_fwnode, "01fa-sidecar-instances", &nsidecars);
if (nsidecars) {
ret = fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid);
if (!ret) {
dev_dbg(priv->dev, "01fa-spk-id-val = %d\n", spkid);
} else if (ret != -EINVAL) {
return dev_err_probe(priv->dev, ret, "Failed to get spk-id-val\n");
} else {
ret = cs42l43_get_speaker_id_gpios(priv, &spkid);
if (ret < 0)
return dev_err_probe(priv->dev, ret,
"Failed to get spk-id-gpios\n");
}
ret = software_node_register(&cs42l43_gpiochip_swnode);
if (ret)
return dev_err_probe(priv->dev, ret,
@ -385,11 +426,6 @@ static int cs42l43_spi_probe(struct platform_device *pdev)
if (nsidecars) {
struct spi_board_info *ampl_info;
struct spi_board_info *ampr_info;
int spkid = -EINVAL;
fwnode_property_read_u32(xu_fwnode, "01fa-spk-id-val", &spkid);
dev_dbg(priv->dev, "Found speaker ID %d\n", spkid);
ampl_info = cs42l43_create_bridge_amp(priv, "cs35l56-left", 0, spkid);
if (!ampl_info)

View File

@ -1039,7 +1039,7 @@ static struct platform_driver davinci_spi_driver = {
.of_match_table = of_match_ptr(davinci_spi_of_match),
},
.probe = davinci_spi_probe,
.remove_new = davinci_spi_remove,
.remove = davinci_spi_remove,
};
module_platform_driver(davinci_spi_driver);

View File

@ -871,7 +871,7 @@ static struct platform_driver spi_dln2_driver = {
.pm = &dln2_spi_pm,
},
.probe = dln2_spi_probe,
.remove_new = dln2_spi_remove,
.remove = dln2_spi_remove,
};
module_platform_driver(spi_dln2_driver);

View File

@ -317,7 +317,7 @@ MODULE_DEVICE_TABLE(of, dw_spi_bt1_of_match);
static struct platform_driver dw_spi_bt1_driver = {
.probe = dw_spi_bt1_probe,
.remove_new = dw_spi_bt1_remove,
.remove = dw_spi_bt1_remove,
.driver = {
.name = "bt1-sys-ssi",
.of_match_table = dw_spi_bt1_of_match,

View File

@ -433,7 +433,7 @@ MODULE_DEVICE_TABLE(acpi, dw_spi_mmio_acpi_match);
static struct platform_driver dw_spi_mmio_driver = {
.probe = dw_spi_mmio_probe,
.remove_new = dw_spi_mmio_remove,
.remove = dw_spi_mmio_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = dw_spi_mmio_of_match,

View File

@ -98,15 +98,14 @@ static int dw_spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *en
dws->paddr = pci_resource_start(pdev, pci_bar);
pci_set_master(pdev);
ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev));
if (ret)
return ret;
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
if (ret < 0)
return ret;
dws->regs = pcim_iomap_table(pdev)[pci_bar];
dws->regs = pcim_iomap_region(pdev, pci_bar, pci_name(pdev));
if (IS_ERR(dws->regs))
return PTR_ERR(dws->regs);
dws->irq = pci_irq_vector(pdev, 0);
/*

View File

@ -729,7 +729,7 @@ static struct platform_driver ep93xx_spi_driver = {
.of_match_table = ep93xx_spi_of_ids,
},
.probe = ep93xx_spi_probe,
.remove_new = ep93xx_spi_remove,
.remove = ep93xx_spi_remove,
};
module_platform_driver(ep93xx_spi_driver);

View File

@ -280,25 +280,25 @@ static void dspi_native_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
static void dspi_8on32_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
{
*txdata = cpu_to_be32(*(u32 *)dspi->tx);
*txdata = (__force u32)cpu_to_be32(*(u32 *)dspi->tx);
dspi->tx += sizeof(u32);
}
static void dspi_8on32_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
{
*(u32 *)dspi->rx = be32_to_cpu(rxdata);
*(u32 *)dspi->rx = be32_to_cpu((__force __be32)rxdata);
dspi->rx += sizeof(u32);
}
static void dspi_8on16_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
{
*txdata = cpu_to_be16(*(u16 *)dspi->tx);
*txdata = (__force u32)cpu_to_be16(*(u16 *)dspi->tx);
dspi->tx += sizeof(u16);
}
static void dspi_8on16_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
{
*(u16 *)dspi->rx = be16_to_cpu(rxdata);
*(u16 *)dspi->rx = be16_to_cpu((__force __be16)rxdata);
dspi->rx += sizeof(u16);
}
@ -1473,7 +1473,7 @@ static struct platform_driver fsl_dspi_driver = {
.driver.of_match_table = fsl_dspi_dt_ids,
.driver.pm = &dspi_pm,
.probe = dspi_probe,
.remove_new = dspi_remove,
.remove = dspi_remove,
.shutdown = dspi_shutdown,
};
module_platform_driver(fsl_dspi_driver);

View File

@ -835,7 +835,7 @@ static struct platform_driver fsl_espi_driver = {
.pm = &espi_pm,
},
.probe = of_fsl_espi_probe,
.remove_new = of_fsl_espi_remove,
.remove = of_fsl_espi_remove,
};
module_platform_driver(fsl_espi_driver);

View File

@ -92,6 +92,7 @@ struct lpspi_config {
u8 prescale;
u16 mode;
u32 speed_hz;
u32 effective_speed_hz;
};
struct fsl_lpspi_data {
@ -315,9 +316,10 @@ static void fsl_lpspi_set_watermark(struct fsl_lpspi_data *fsl_lpspi)
static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
{
struct lpspi_config config = fsl_lpspi->config;
unsigned int perclk_rate, scldiv, div;
unsigned int perclk_rate, div;
u8 prescale_max;
u8 prescale;
int scldiv;
perclk_rate = clk_get_rate(fsl_lpspi->clk_per);
prescale_max = fsl_lpspi->devtype_data->prescale_max;
@ -338,19 +340,22 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
for (prescale = 0; prescale <= prescale_max; prescale++) {
scldiv = div / (1 << prescale) - 2;
if (scldiv < 256) {
if (scldiv >= 0 && scldiv < 256) {
fsl_lpspi->config.prescale = prescale;
break;
}
}
if (scldiv >= 256)
if (scldiv < 0 || scldiv >= 256)
return -EINVAL;
writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16),
fsl_lpspi->base + IMX7ULP_CCR);
dev_dbg(fsl_lpspi->dev, "perclk=%d, speed=%d, prescale=%d, scldiv=%d\n",
fsl_lpspi->config.effective_speed_hz = perclk_rate / (scldiv + 2) *
(1 << prescale);
dev_dbg(fsl_lpspi->dev, "perclk=%u, speed=%u, prescale=%u, scldiv=%d\n",
perclk_rate, config.speed_hz, prescale, scldiv);
return 0;
@ -749,6 +754,8 @@ static int fsl_lpspi_transfer_one(struct spi_controller *controller,
if (ret < 0)
return ret;
t->effective_speed_hz = fsl_lpspi->config.effective_speed_hz;
fsl_lpspi_set_cmd(fsl_lpspi);
fsl_lpspi->is_first_byte = false;
@ -891,7 +898,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
return ret;
}
ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, 0,
ret = devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, IRQF_NO_AUTOEN,
dev_name(&pdev->dev), fsl_lpspi);
if (ret) {
dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret);
@ -948,14 +955,10 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller);
if (ret == -EPROBE_DEFER)
goto out_pm_get;
if (ret < 0)
if (ret < 0) {
dev_warn(&pdev->dev, "dma setup error %d, use pio\n", ret);
else
/*
* disable LPSPI module IRQ when enable DMA mode successfully,
* to prevent the unexpected LPSPI module IRQ events.
*/
disable_irq(irq);
enable_irq(irq);
}
ret = devm_spi_register_controller(&pdev->dev, controller);
if (ret < 0) {
@ -1024,7 +1027,7 @@ static struct platform_driver fsl_lpspi_driver = {
.pm = pm_ptr(&fsl_lpspi_pm_ops),
},
.probe = fsl_lpspi_probe,
.remove_new = fsl_lpspi_remove,
.remove = fsl_lpspi_remove,
};
module_platform_driver(fsl_lpspi_driver);

View File

@ -997,7 +997,7 @@ static struct platform_driver fsl_qspi_driver = {
.pm = &fsl_qspi_pm_ops,
},
.probe = fsl_qspi_probe,
.remove_new = fsl_qspi_remove,
.remove = fsl_qspi_remove,
};
module_platform_driver(fsl_qspi_driver);

View File

@ -714,7 +714,7 @@ static struct platform_driver of_fsl_spi_driver = {
.of_match_table = of_fsl_spi_match,
},
.probe = of_fsl_spi_probe,
.remove_new = of_fsl_spi_remove,
.remove = of_fsl_spi_remove,
};
#ifdef CONFIG_MPC832x_RDB
@ -757,7 +757,7 @@ static void plat_mpc8xxx_spi_remove(struct platform_device *pdev)
MODULE_ALIAS("platform:mpc8xxx_spi");
static struct platform_driver mpc8xxx_spi_driver = {
.probe = plat_mpc8xxx_spi_probe,
.remove_new = plat_mpc8xxx_spi_remove,
.remove = plat_mpc8xxx_spi_remove,
.driver = {
.name = "mpc8xxx_spi",
},

View File

@ -542,7 +542,7 @@ MODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match);
static struct platform_driver hisi_spi_driver = {
.probe = hisi_spi_probe,
.remove_new = hisi_spi_remove,
.remove = hisi_spi_remove,
.driver = {
.name = "hisi-kunpeng-spi",
.acpi_match_table = hisi_spi_acpi_match,

View File

@ -40,7 +40,7 @@
/* Common definition of interrupt bit masks */
#define HISI_SFC_V3XX_INT_MASK_ALL (0x1ff) /* all the masks */
#define HISI_SFC_V3XX_INT_MASK_CPLT BIT(0) /* command execution complete */
#define HISI_SFC_V3XX_INT_MASK_PP_ERR BIT(2) /* page progrom error */
#define HISI_SFC_V3XX_INT_MASK_PP_ERR BIT(2) /* page program error */
#define HISI_SFC_V3XX_INT_MASK_IACCES BIT(5) /* error visiting inaccessible/
* protected address
*/

View File

@ -756,7 +756,7 @@ static struct platform_driver img_spfi_driver = {
.of_match_table = of_match_ptr(img_spfi_of_match),
},
.probe = img_spfi_probe,
.remove_new = img_spfi_remove,
.remove = img_spfi_remove,
};
module_platform_driver(img_spfi_driver);

View File

@ -3,6 +3,7 @@
// Copyright (C) 2008 Juergen Beisert
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
@ -13,7 +14,10 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/math.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@ -71,7 +75,8 @@ struct spi_imx_data;
struct spi_imx_devtype_data {
void (*intctrl)(struct spi_imx_data *spi_imx, int enable);
int (*prepare_message)(struct spi_imx_data *spi_imx, struct spi_message *msg);
int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi);
int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi,
struct spi_transfer *t);
void (*trigger)(struct spi_imx_data *spi_imx);
int (*rx_available)(struct spi_imx_data *spi_imx);
void (*reset)(struct spi_imx_data *spi_imx);
@ -301,6 +306,18 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
#define MX51_ECSPI_STAT 0x18
#define MX51_ECSPI_STAT_RR (1 << 3)
#define MX51_ECSPI_PERIOD 0x1c
#define MX51_ECSPI_PERIOD_MASK 0x7fff
/*
* As measured on the i.MX6, the SPI host controller inserts a 4 SPI-Clock
* (SCLK) delay after each burst if the PERIOD reg is 0x0. This value will be
* called MX51_ECSPI_PERIOD_MIN_DELAY_SCK.
*
* If the PERIOD register is != 0, the controller inserts a delay of
* MX51_ECSPI_PERIOD_MIN_DELAY_SCK + register value + 1 SCLK after each burst.
*/
#define MX51_ECSPI_PERIOD_MIN_DELAY_SCK 4
#define MX51_ECSPI_TESTREG 0x20
#define MX51_ECSPI_TESTREG_LBC BIT(31)
@ -407,7 +424,7 @@ static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
static void mx53_ecspi_rx_target(struct spi_imx_data *spi_imx)
{
u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA));
u32 val = ioread32be(spi_imx->base + MXC_CSPIRXDATA);
if (spi_imx->rx_buf) {
int n_bytes = spi_imx->target_burst % sizeof(val);
@ -436,13 +453,12 @@ static void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx)
if (spi_imx->tx_buf) {
memcpy(((u8 *)&val) + sizeof(val) - n_bytes,
spi_imx->tx_buf, n_bytes);
val = cpu_to_be32(val);
spi_imx->tx_buf += n_bytes;
}
spi_imx->count -= n_bytes;
writel(val, spi_imx->base + MXC_CSPITXDATA);
iowrite32be(val, spi_imx->base + MXC_CSPITXDATA);
}
/* MX51 eCSPI */
@ -649,9 +665,10 @@ static void mx51_configure_cpha(struct spi_imx_data *spi_imx,
}
static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
struct spi_device *spi)
struct spi_device *spi, struct spi_transfer *t)
{
u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
u64 word_delay_sck;
u32 clk;
/* Clear BL field and set the right value */
@ -683,6 +700,49 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
/* calculate word delay in SPI Clock (SCLK) cycles */
if (t->word_delay.value == 0) {
word_delay_sck = 0;
} else if (t->word_delay.unit == SPI_DELAY_UNIT_SCK) {
word_delay_sck = t->word_delay.value;
if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK)
word_delay_sck = 0;
else if (word_delay_sck <= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1)
word_delay_sck = 1;
else
word_delay_sck -= MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1;
} else {
int word_delay_ns;
word_delay_ns = spi_delay_to_ns(&t->word_delay, t);
if (word_delay_ns < 0)
return word_delay_ns;
if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC,
MX51_ECSPI_PERIOD_MIN_DELAY_SCK,
spi_imx->spi_bus_clk)) {
word_delay_sck = 0;
} else if (word_delay_ns <= mul_u64_u32_div(NSEC_PER_SEC,
MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1,
spi_imx->spi_bus_clk)) {
word_delay_sck = 1;
} else {
word_delay_ns -= mul_u64_u32_div(NSEC_PER_SEC,
MX51_ECSPI_PERIOD_MIN_DELAY_SCK + 1,
spi_imx->spi_bus_clk);
word_delay_sck = DIV_U64_ROUND_UP((u64)word_delay_ns * spi_imx->spi_bus_clk,
NSEC_PER_SEC);
}
}
if (!FIELD_FIT(MX51_ECSPI_PERIOD_MASK, word_delay_sck))
return -EINVAL;
writel(FIELD_PREP(MX51_ECSPI_PERIOD_MASK, word_delay_sck),
spi_imx->base + MX51_ECSPI_PERIOD);
return 0;
}
@ -774,7 +834,7 @@ static int mx31_prepare_message(struct spi_imx_data *spi_imx,
}
static int mx31_prepare_transfer(struct spi_imx_data *spi_imx,
struct spi_device *spi)
struct spi_device *spi, struct spi_transfer *t)
{
unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_HOST;
unsigned int clk;
@ -878,7 +938,7 @@ static int mx21_prepare_message(struct spi_imx_data *spi_imx,
}
static int mx21_prepare_transfer(struct spi_imx_data *spi_imx,
struct spi_device *spi)
struct spi_device *spi, struct spi_transfer *t)
{
unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_HOST;
unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
@ -953,7 +1013,7 @@ static int mx1_prepare_message(struct spi_imx_data *spi_imx,
}
static int mx1_prepare_transfer(struct spi_imx_data *spi_imx,
struct spi_device *spi)
struct spi_device *spi, struct spi_transfer *t)
{
unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_HOST;
unsigned int clk;
@ -1263,11 +1323,13 @@ static int spi_imx_setupxfer(struct spi_device *spi,
/*
* Initialize the functions for transfer. To transfer non byte-aligned
* words, we have to use multiple word-size bursts, we can't use
* dynamic_burst in that case.
* words, we have to use multiple word-size bursts. To insert word
* delay, the burst size has to equal the word size. We can't use
* dynamic_burst in these cases.
*/
if (spi_imx->devtype_data->dynamic_burst && !spi_imx->target_mode &&
!(spi->mode & SPI_CS_WORD) &&
!(t->word_delay.value) &&
(spi_imx->bits_per_word == 8 ||
spi_imx->bits_per_word == 16 ||
spi_imx->bits_per_word == 32)) {
@ -1304,7 +1366,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
spi_imx->target_burst = t->len;
}
spi_imx->devtype_data->prepare_transfer(spi_imx, spi);
spi_imx->devtype_data->prepare_transfer(spi_imx, spi, t);
return 0;
}
@ -1610,12 +1672,30 @@ static int spi_imx_pio_transfer_target(struct spi_device *spi,
return ret;
}
static unsigned int spi_imx_transfer_estimate_time_us(struct spi_transfer *transfer)
{
u64 result;
result = DIV_U64_ROUND_CLOSEST((u64)USEC_PER_SEC * transfer->len * BITS_PER_BYTE,
transfer->effective_speed_hz);
if (transfer->word_delay.value) {
unsigned int word_delay_us;
unsigned int words;
words = DIV_ROUND_UP(transfer->len * BITS_PER_BYTE, transfer->bits_per_word);
word_delay_us = DIV_ROUND_CLOSEST(spi_delay_to_ns(&transfer->word_delay, transfer),
NSEC_PER_USEC);
result += words * word_delay_us;
}
return min(result, U32_MAX);
}
static int spi_imx_transfer_one(struct spi_controller *controller,
struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
unsigned long hz_per_byte, byte_limit;
spi_imx_setupxfer(spi, transfer);
transfer->effective_speed_hz = spi_imx->spi_bus_clk;
@ -1634,15 +1714,10 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
*/
if (spi_imx->usedma)
return spi_imx_dma_transfer(spi_imx, transfer);
/*
* Calculate the estimated time in us the transfer runs. Find
* the number of Hz per byte per polling limit.
*/
hz_per_byte = polling_limit_us ? ((8 + 4) * USEC_PER_SEC) / polling_limit_us : 0;
byte_limit = hz_per_byte ? transfer->effective_speed_hz / hz_per_byte : 1;
/* run in polling mode for short transfers */
if (transfer->len < byte_limit)
if (transfer->len == 1 || (polling_limit_us &&
spi_imx_transfer_estimate_time_us(transfer) < polling_limit_us))
return spi_imx_poll_transfer(spi, transfer);
return spi_imx_pio_transfer(spi, transfer);
@ -1956,7 +2031,7 @@ static struct platform_driver spi_imx_driver = {
.pm = pm_ptr(&imx_spi_pm),
},
.probe = spi_imx_probe,
.remove_new = spi_imx_remove,
.remove = spi_imx_remove,
};
module_platform_driver(spi_imx_driver);

View File

@ -94,6 +94,7 @@ static struct pci_driver intel_spi_pci_driver = {
.name = "intel-spi",
.id_table = intel_spi_pci_ids,
.probe = intel_spi_pci_probe,
.dev_groups = intel_spi_groups,
};
module_pci_driver(intel_spi_pci_driver);

View File

@ -28,6 +28,7 @@ static struct platform_driver intel_spi_platform_driver = {
.probe = intel_spi_platform_probe,
.driver = {
.name = "intel-spi",
.dev_groups = intel_spi_groups,
},
};

View File

@ -148,6 +148,8 @@
* @pr_num: Maximum number of protected range registers
* @chip0_size: Size of the first flash chip in bytes
* @locked: Is SPI setting locked
* @protected: Whether the regions are write protected
* @bios_locked: Is BIOS region locked
* @swseq_reg: Use SW sequencer in register reads/writes
* @swseq_erase: Use SW sequencer in erase operation
* @atomic_preopcode: Holds preopcode when atomic sequence is requested
@ -166,6 +168,8 @@ struct intel_spi {
size_t pr_num;
size_t chip0_size;
bool locked;
bool protected;
bool bios_locked;
bool swseq_reg;
bool swseq_erase;
u8 atomic_preopcode;
@ -1109,10 +1113,13 @@ static int intel_spi_init(struct intel_spi *ispi)
return -EINVAL;
}
/* Try to disable write protection if user asked to do so */
if (writeable && !intel_spi_set_writeable(ispi)) {
ispi->bios_locked = true;
/* Try to disable BIOS write protection if user asked to do so */
if (writeable) {
if (intel_spi_set_writeable(ispi))
ispi->bios_locked = false;
else
dev_warn(ispi->dev, "can't disable chip write protection\n");
writeable = false;
}
/* Disable #SMI generation from HW sequencer */
@ -1247,8 +1254,10 @@ static void intel_spi_fill_partition(struct intel_spi *ispi,
* Also if the user did not ask the chip to be writeable
* mask the bit too.
*/
if (!writeable || intel_spi_is_protected(ispi, base, limit))
if (!writeable || intel_spi_is_protected(ispi, base, limit)) {
part->mask_flags |= MTD_WRITEABLE;
ispi->protected = true;
}
end = (limit << 12) + 4096;
if (end > part->size)
@ -1411,6 +1420,50 @@ static int intel_spi_populate_chip(struct intel_spi *ispi)
return 0;
}
static ssize_t intel_spi_protected_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_spi *ispi = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", ispi->protected);
}
static DEVICE_ATTR_ADMIN_RO(intel_spi_protected);
static ssize_t intel_spi_locked_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_spi *ispi = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", ispi->locked);
}
static DEVICE_ATTR_ADMIN_RO(intel_spi_locked);
static ssize_t intel_spi_bios_locked_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_spi *ispi = dev_get_drvdata(dev);
return sysfs_emit(buf, "%d\n", ispi->bios_locked);
}
static DEVICE_ATTR_ADMIN_RO(intel_spi_bios_locked);
static struct attribute *intel_spi_attrs[] = {
&dev_attr_intel_spi_protected.attr,
&dev_attr_intel_spi_locked.attr,
&dev_attr_intel_spi_bios_locked.attr,
NULL
};
static const struct attribute_group intel_spi_attr_group = {
.attrs = intel_spi_attrs,
};
const struct attribute_group *intel_spi_groups[] = {
&intel_spi_attr_group,
NULL
};
EXPORT_SYMBOL_GPL(intel_spi_groups);
/**
* intel_spi_probe() - Probe the Intel SPI flash controller
* @dev: Pointer to the parent device
@ -1451,6 +1504,7 @@ int intel_spi_probe(struct device *dev, struct resource *mem,
if (ret)
return ret;
dev_set_drvdata(dev, ispi);
return intel_spi_populate_chip(ispi);
}
EXPORT_SYMBOL_GPL(intel_spi_probe);

View File

@ -13,6 +13,8 @@
struct resource;
extern const struct attribute_group *intel_spi_groups[];
int intel_spi_probe(struct device *dev, struct resource *mem,
const struct intel_spi_boardinfo *info);

View File

@ -138,7 +138,7 @@ MODULE_DEVICE_TABLE(of, bcm_iproc_of_match);
static struct platform_driver bcm_iproc_driver = {
.probe = bcm_iproc_probe,
.remove_new = bcm_iproc_remove,
.remove = bcm_iproc_remove,
.driver = {
.name = "bcm_iproc",
.pm = &bcm_qspi_pm_ops,

View File

@ -139,7 +139,7 @@
#define LTQ_SPI_FGPO_CLROUTN_S 0
#define LTQ_SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */
#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */
#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Receive to-do value */
#define LTQ_SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */
#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */
@ -1029,7 +1029,7 @@ static void lantiq_ssc_remove(struct platform_device *pdev)
static struct platform_driver lantiq_ssc_driver = {
.probe = lantiq_ssc_probe,
.remove_new = lantiq_ssc_remove,
.remove = lantiq_ssc_remove,
.driver = {
.name = "spi-lantiq-ssc",
.of_match_table = lantiq_ssc_match,

View File

@ -19,12 +19,11 @@ static int loongson_spi_pci_register(struct pci_dev *pdev,
if (ret < 0)
return dev_err_probe(dev, ret, "cannot enable pci device\n");
ret = pcim_iomap_regions(pdev, BIT(pci_bar), pci_name(pdev));
reg_base = pcim_iomap_region(pdev, pci_bar, pci_name(pdev));
ret = PTR_ERR_OR_ZERO(reg_base);
if (ret)
return dev_err_probe(dev, ret, "failed to request and remap memory\n");
reg_base = pcim_iomap_table(pdev)[pci_bar];
ret = loongson_spi_init_controller(dev, reg_base);
if (ret)
return dev_err_probe(dev, ret, "failed to initialize controller\n");

View File

@ -949,7 +949,7 @@ MODULE_DEVICE_TABLE(of, meson_spicc_of_match);
static struct platform_driver meson_spicc_driver = {
.probe = meson_spicc_probe,
.remove_new = meson_spicc_remove,
.remove = meson_spicc_remove,
.driver = {
.name = "meson-spicc",
.of_match_table = of_match_ptr(meson_spicc_of_match),

View File

@ -429,7 +429,7 @@ MODULE_DEVICE_TABLE(of, meson_spifc_dt_match);
static struct platform_driver meson_spifc_driver = {
.probe = meson_spifc_probe,
.remove_new = meson_spifc_remove,
.remove = meson_spifc_remove,
.driver = {
.name = "meson-spifc",
.of_match_table = of_match_ptr(meson_spifc_dt_match),

View File

@ -575,7 +575,7 @@ static struct platform_driver mchp_coreqspi_driver = {
.name = "microchip,coreqspi",
.of_match_table = mchp_coreqspi_of_match,
},
.remove_new = mchp_coreqspi_remove,
.remove = mchp_coreqspi_remove,
};
module_platform_driver(mchp_coreqspi_driver);

View File

@ -622,7 +622,7 @@ static struct platform_driver mchp_corespi_driver = {
.pm = MICROCHIP_SPI_PM_OPS,
.of_match_table = of_match_ptr(mchp_corespi_dt_ids),
},
.remove_new = mchp_corespi_remove,
.remove = mchp_corespi_remove,
};
module_platform_driver(mchp_corespi_driver);
MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver");

View File

@ -107,7 +107,7 @@ static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
struct mpc52xx_psc_spi *mps = spi_controller_get_devdata(spi->controller);
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo;
unsigned rb = 0; /* number of bytes receieved */
unsigned rb = 0; /* number of bytes received */
unsigned sb = 0; /* number of bytes sent */
unsigned char *rx_buf = (unsigned char *)t->rx_buf;
unsigned char *tx_buf = (unsigned char *)t->tx_buf;
@ -325,7 +325,7 @@ static int mpc52xx_psc_spi_of_probe(struct platform_device *pdev)
if (IS_ERR(mps->psc))
return dev_err_probe(dev, PTR_ERR(mps->psc), "could not ioremap I/O port range\n");
/* On the 5200, fifo regs are immediately ajacent to the psc regs */
/* On the 5200, fifo regs are immediately adjacent to the psc regs */
mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc);
mps->irq = platform_get_irq(pdev, 0);

View File

@ -544,6 +544,6 @@ static struct platform_driver mpc52xx_spi_of_driver = {
.of_match_table = mpc52xx_spi_match,
},
.probe = mpc52xx_spi_probe,
.remove_new = mpc52xx_spi_remove,
.remove = mpc52xx_spi_remove,
};
module_platform_driver(mpc52xx_spi_of_driver);

View File

@ -1432,7 +1432,7 @@ static struct platform_driver mtk_spi_driver = {
.of_match_table = mtk_spi_of_match,
},
.probe = mtk_spi_probe,
.remove_new = mtk_spi_remove,
.remove = mtk_spi_remove,
};
module_platform_driver(mtk_spi_driver);

View File

@ -998,7 +998,7 @@ static struct platform_driver mtk_nor_driver = {
.pm = &mtk_nor_pm_ops,
},
.probe = mtk_nor_probe,
.remove_new = mtk_nor_remove,
.remove = mtk_nor_remove,
};
module_platform_driver(mtk_nor_driver);

View File

@ -1477,7 +1477,7 @@ static void mtk_snand_remove(struct platform_device *pdev)
static struct platform_driver mtk_snand_driver = {
.probe = mtk_snand_probe,
.remove_new = mtk_snand_remove,
.remove = mtk_snand_remove,
.driver = {
.name = "mtk-snand",
.of_match_table = mtk_snand_ids,

View File

@ -836,7 +836,7 @@ MODULE_DEVICE_TABLE(of, mxic_spi_of_ids);
static struct platform_driver mxic_spi_driver = {
.probe = mxic_spi_probe,
.remove_new = mxic_spi_remove,
.remove = mxic_spi_remove,
.driver = {
.name = "mxic-spi",
.of_match_table = mxic_spi_of_ids,

View File

@ -657,7 +657,7 @@ static void mxs_spi_remove(struct platform_device *pdev)
static struct platform_driver mxs_spi_driver = {
.probe = mxs_spi_probe,
.remove_new = mxs_spi_remove,
.remove = mxs_spi_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = mxs_spi_dt_ids,

View File

@ -771,7 +771,7 @@ static struct platform_driver npcm_fiu_driver = {
.of_match_table = npcm_fiu_dt_ids,
},
.probe = npcm_fiu_probe,
.remove_new = npcm_fiu_remove,
.remove = npcm_fiu_remove,
};
module_platform_driver(npcm_fiu_driver);

View File

@ -452,7 +452,7 @@ static struct platform_driver npcm_pspi_driver = {
.of_match_table = npcm_pspi_match,
},
.probe = npcm_pspi_probe,
.remove_new = npcm_pspi_remove,
.remove = npcm_pspi_remove,
};
module_platform_driver(npcm_pspi_driver);

View File

@ -1331,7 +1331,7 @@ static struct platform_driver nxp_fspi_driver = {
.pm = &nxp_fspi_pm_ops,
},
.probe = nxp_fspi_probe,
.remove_new = nxp_fspi_remove,
.remove = nxp_fspi_remove,
};
module_platform_driver(nxp_fspi_driver);

View File

@ -288,7 +288,7 @@ MODULE_DEVICE_TABLE(of, tiny_spi_match);
static struct platform_driver tiny_spi_driver = {
.probe = tiny_spi_probe,
.remove_new = tiny_spi_remove,
.remove = tiny_spi_remove,
.driver = {
.name = DRV_NAME,
.pm = NULL,

View File

@ -523,7 +523,7 @@ static struct platform_driver uwire_driver = {
.name = "omap_uwire",
},
.probe = uwire_probe,
.remove_new = uwire_remove,
.remove = uwire_remove,
// suspend ... unuse ck
// resume ... use ck
};

View File

@ -1654,7 +1654,7 @@ static struct platform_driver omap2_mcspi_driver = {
.of_match_table = omap_mcspi_of_match,
},
.probe = omap2_mcspi_probe,
.remove_new = omap2_mcspi_remove,
.remove = omap2_mcspi_remove,
};
module_platform_driver(omap2_mcspi_driver);

View File

@ -846,7 +846,7 @@ static struct platform_driver orion_spi_driver = {
.of_match_table = of_match_ptr(orion_spi_of_match_table),
},
.probe = orion_spi_probe,
.remove_new = orion_spi_remove,
.remove = orion_spi_remove,
};
module_platform_driver(orion_spi_driver);

View File

@ -226,7 +226,7 @@ static irqreturn_t pic32_sqi_isr(int irq, void *dev_id)
if (status & PESQI_PKTCOMP) {
/* mask all interrupts */
enable = 0;
/* complete trasaction */
/* complete transaction */
complete(&sqi->xfer_done);
}
@ -682,7 +682,7 @@ static struct platform_driver pic32_sqi_driver = {
.of_match_table = of_match_ptr(pic32_sqi_of_ids),
},
.probe = pic32_sqi_probe,
.remove_new = pic32_sqi_remove,
.remove = pic32_sqi_remove,
};
module_platform_driver(pic32_sqi_driver);

View File

@ -859,7 +859,7 @@ static struct platform_driver pic32_spi_driver = {
.of_match_table = of_match_ptr(pic32_spi_of_match),
},
.probe = pic32_spi_probe,
.remove_new = pic32_spi_remove,
.remove = pic32_spi_remove,
};
module_platform_driver(pic32_spi_driver);

View File

@ -899,7 +899,7 @@ static int configure_dma(struct pl022 *pl022)
break;
}
/* SPI pecularity: we need to read and write the same width */
/* SPI peculiarity: we need to read and write the same width */
if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
rx_conf.src_addr_width = tx_conf.dst_addr_width;
if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)

View File

@ -484,7 +484,7 @@ MODULE_DEVICE_TABLE(of, spi_ppc4xx_of_match);
static struct platform_driver spi_ppc4xx_of_driver = {
.probe = spi_ppc4xx_of_probe,
.remove_new = spi_ppc4xx_of_remove,
.remove = spi_ppc4xx_of_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = spi_ppc4xx_of_match,

View File

@ -273,10 +273,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
if (ret)
return ret;
ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI");
if (ret)
return ret;
pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
@ -284,7 +280,9 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
ssp = &pdata->ssp;
ssp->dev = &dev->dev;
ssp->phys_base = pci_resource_start(dev, 0);
ssp->mmio_base = pcim_iomap_table(dev)[0];
ssp->mmio_base = pcim_iomap_region(dev, 0, "PXA2xx SPI");
if (IS_ERR(ssp->mmio_base))
return PTR_ERR(ssp->mmio_base);
info = (struct pxa_spi_info *)ent->driver_data;
ret = info->setup(dev, pdata);

View File

@ -207,7 +207,7 @@ static struct platform_driver driver = {
.of_match_table = pxa2xx_spi_of_match,
},
.probe = pxa2xx_spi_platform_probe,
.remove_new = pxa2xx_spi_platform_remove,
.remove = pxa2xx_spi_platform_remove,
};
static int __init pxa2xx_spi_init(void)

View File

@ -771,7 +771,7 @@ static int qcom_qspi_probe(struct platform_device *pdev)
host->prepare_message = qcom_qspi_prepare_message;
host->transfer_one = qcom_qspi_transfer_one;
host->handle_err = qcom_qspi_handle_err;
if (of_property_read_bool(pdev->dev.of_node, "iommus"))
if (of_property_present(pdev->dev.of_node, "iommus"))
host->can_dma = qcom_qspi_can_dma;
host->auto_runtime_pm = true;
host->mem_ops = &qcom_qspi_mem_ops;
@ -908,7 +908,7 @@ static struct platform_driver qcom_qspi_driver = {
.of_match_table = qcom_qspi_dt_match,
},
.probe = qcom_qspi_probe,
.remove_new = qcom_qspi_remove,
.remove = qcom_qspi_remove,
};
module_platform_driver(qcom_qspi_driver);

View File

@ -1364,7 +1364,7 @@ static struct platform_driver spi_qup_driver = {
.of_match_table = spi_qup_dt_match,
},
.probe = spi_qup_probe,
.remove_new = spi_qup_remove,
.remove = spi_qup_remove,
};
module_platform_driver(spi_qup_driver);

View File

@ -196,7 +196,7 @@ MODULE_DEVICE_TABLE(of, rb4xx_spi_dt_match);
static struct platform_driver rb4xx_spi_drv = {
.probe = rb4xx_spi_probe,
.remove_new = rb4xx_spi_remove,
.remove = rb4xx_spi_remove,
.driver = {
.name = "rb4xx-spi",
.of_match_table = of_match_ptr(rb4xx_spi_dt_match),

View File

@ -0,0 +1,419 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
#define SNAFCFR 0x00
#define SNAFCFR_DMA_IE BIT(20)
#define SNAFCCR 0x04
#define SNAFWCMR 0x08
#define SNAFRCMR 0x0c
#define SNAFRDR 0x10
#define SNAFWDR 0x14
#define SNAFDTR 0x18
#define SNAFDRSAR 0x1c
#define SNAFDIR 0x20
#define SNAFDIR_DMA_IP BIT(0)
#define SNAFDLR 0x24
#define SNAFSR 0x40
#define SNAFSR_NFCOS BIT(3)
#define SNAFSR_NFDRS BIT(2)
#define SNAFSR_NFDWS BIT(1)
#define CMR_LEN(len) ((len) - 1)
#define CMR_WID(width) (((width) >> 1) << 28)
struct rtl_snand {
struct device *dev;
struct regmap *regmap;
struct completion comp;
};
static irqreturn_t rtl_snand_irq(int irq, void *data)
{
struct rtl_snand *snand = data;
u32 val = 0;
regmap_read(snand->regmap, SNAFSR, &val);
if (val & (SNAFSR_NFCOS | SNAFSR_NFDRS | SNAFSR_NFDWS))
return IRQ_NONE;
regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP);
complete(&snand->comp);
return IRQ_HANDLED;
}
static bool rtl_snand_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op)
{
if (!spi_mem_default_supports_op(mem, op))
return false;
if (op->cmd.nbytes != 1 || op->cmd.buswidth != 1)
return false;
return true;
}
static void rtl_snand_set_cs(struct rtl_snand *snand, int cs, bool active)
{
u32 val;
if (active)
val = ~(1 << (4 * cs));
else
val = ~0;
regmap_write(snand->regmap, SNAFCCR, val);
}
static int rtl_snand_wait_ready(struct rtl_snand *snand)
{
u32 val;
return regmap_read_poll_timeout(snand->regmap, SNAFSR, val, !(val & SNAFSR_NFCOS),
0, 2 * USEC_PER_MSEC);
}
static int rtl_snand_xfer_head(struct rtl_snand *snand, int cs, const struct spi_mem_op *op)
{
int ret;
u32 val, len = 0;
rtl_snand_set_cs(snand, cs, true);
val = op->cmd.opcode << 24;
len = 1;
if (op->addr.nbytes && op->addr.buswidth == 1) {
val |= op->addr.val << ((3 - op->addr.nbytes) * 8);
len += op->addr.nbytes;
}
ret = rtl_snand_wait_ready(snand);
if (ret)
return ret;
ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(len));
if (ret)
return ret;
ret = regmap_write(snand->regmap, SNAFWDR, val);
if (ret)
return ret;
ret = rtl_snand_wait_ready(snand);
if (ret)
return ret;
if (op->addr.buswidth > 1) {
val = op->addr.val << ((3 - op->addr.nbytes) * 8);
len = op->addr.nbytes;
ret = regmap_write(snand->regmap, SNAFWCMR,
CMR_WID(op->addr.buswidth) | CMR_LEN(len));
if (ret)
return ret;
ret = regmap_write(snand->regmap, SNAFWDR, val);
if (ret)
return ret;
ret = rtl_snand_wait_ready(snand);
if (ret)
return ret;
}
if (op->dummy.nbytes) {
val = 0;
ret = regmap_write(snand->regmap, SNAFWCMR,
CMR_WID(op->dummy.buswidth) | CMR_LEN(op->dummy.nbytes));
if (ret)
return ret;
ret = regmap_write(snand->regmap, SNAFWDR, val);
if (ret)
return ret;
ret = rtl_snand_wait_ready(snand);
if (ret)
return ret;
}
return 0;
}
static void rtl_snand_xfer_tail(struct rtl_snand *snand, int cs)
{
rtl_snand_set_cs(snand, cs, false);
}
static int rtl_snand_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op)
{
unsigned int pos, nbytes;
int ret;
u32 val, len = 0;
ret = rtl_snand_xfer_head(snand, cs, op);
if (ret)
goto out_deselect;
if (op->data.dir == SPI_MEM_DATA_IN) {
pos = 0;
len = op->data.nbytes;
while (pos < len) {
nbytes = len - pos;
if (nbytes > 4)
nbytes = 4;
ret = rtl_snand_wait_ready(snand);
if (ret)
goto out_deselect;
ret = regmap_write(snand->regmap, SNAFRCMR,
CMR_WID(op->data.buswidth) | CMR_LEN(nbytes));
if (ret)
goto out_deselect;
ret = rtl_snand_wait_ready(snand);
if (ret)
goto out_deselect;
ret = regmap_read(snand->regmap, SNAFRDR, &val);
if (ret)
goto out_deselect;
memcpy(op->data.buf.in + pos, &val, nbytes);
pos += nbytes;
}
} else if (op->data.dir == SPI_MEM_DATA_OUT) {
pos = 0;
len = op->data.nbytes;
while (pos < len) {
nbytes = len - pos;
if (nbytes > 4)
nbytes = 4;
memcpy(&val, op->data.buf.out + pos, nbytes);
pos += nbytes;
ret = regmap_write(snand->regmap, SNAFWCMR, CMR_LEN(nbytes));
if (ret)
goto out_deselect;
ret = regmap_write(snand->regmap, SNAFWDR, val);
if (ret)
goto out_deselect;
ret = rtl_snand_wait_ready(snand);
if (ret)
goto out_deselect;
}
}
out_deselect:
rtl_snand_xfer_tail(snand, cs);
if (ret)
dev_err(snand->dev, "transfer failed %d\n", ret);
return ret;
}
static int rtl_snand_dma_xfer(struct rtl_snand *snand, int cs, const struct spi_mem_op *op)
{
unsigned int pos, nbytes;
int ret;
dma_addr_t buf_dma;
enum dma_data_direction dir;
u32 trig, len, maxlen;
ret = rtl_snand_xfer_head(snand, cs, op);
if (ret)
goto out_deselect;
if (op->data.dir == SPI_MEM_DATA_IN) {
maxlen = 2080;
dir = DMA_FROM_DEVICE;
trig = 0;
} else if (op->data.dir == SPI_MEM_DATA_OUT) {
maxlen = 520;
dir = DMA_TO_DEVICE;
trig = 1;
} else {
ret = -EOPNOTSUPP;
goto out_deselect;
}
buf_dma = dma_map_single(snand->dev, op->data.buf.in, op->data.nbytes, dir);
ret = dma_mapping_error(snand->dev, buf_dma);
if (ret)
goto out_deselect;
ret = regmap_write(snand->regmap, SNAFDIR, SNAFDIR_DMA_IP);
if (ret)
goto out_unmap;
ret = regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, SNAFCFR_DMA_IE);
if (ret)
goto out_unmap;
pos = 0;
len = op->data.nbytes;
while (pos < len) {
nbytes = len - pos;
if (nbytes > maxlen)
nbytes = maxlen;
reinit_completion(&snand->comp);
ret = regmap_write(snand->regmap, SNAFDRSAR, buf_dma + pos);
if (ret)
goto out_disable_int;
pos += nbytes;
ret = regmap_write(snand->regmap, SNAFDLR,
CMR_WID(op->data.buswidth) | nbytes);
if (ret)
goto out_disable_int;
ret = regmap_write(snand->regmap, SNAFDTR, trig);
if (ret)
goto out_disable_int;
if (!wait_for_completion_timeout(&snand->comp, usecs_to_jiffies(20000)))
ret = -ETIMEDOUT;
if (ret)
goto out_disable_int;
}
out_disable_int:
regmap_update_bits(snand->regmap, SNAFCFR, SNAFCFR_DMA_IE, 0);
out_unmap:
dma_unmap_single(snand->dev, buf_dma, op->data.nbytes, dir);
out_deselect:
rtl_snand_xfer_tail(snand, cs);
if (ret)
dev_err(snand->dev, "transfer failed %d\n", ret);
return ret;
}
static bool rtl_snand_dma_op(const struct spi_mem_op *op)
{
switch (op->data.dir) {
case SPI_MEM_DATA_IN:
case SPI_MEM_DATA_OUT:
return op->data.nbytes > 32;
default:
return false;
}
}
static int rtl_snand_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct rtl_snand *snand = spi_controller_get_devdata(mem->spi->controller);
int cs = spi_get_chipselect(mem->spi, 0);
dev_dbg(snand->dev, "cs %d op cmd %02x %d:%d, dummy %d:%d, addr %08llx@%d:%d, data %d:%d\n",
cs, op->cmd.opcode,
op->cmd.buswidth, op->cmd.nbytes, op->dummy.buswidth,
op->dummy.nbytes, op->addr.val, op->addr.buswidth,
op->addr.nbytes, op->data.buswidth, op->data.nbytes);
if (rtl_snand_dma_op(op))
return rtl_snand_dma_xfer(snand, cs, op);
else
return rtl_snand_xfer(snand, cs, op);
}
static const struct spi_controller_mem_ops rtl_snand_mem_ops = {
.supports_op = rtl_snand_supports_op,
.exec_op = rtl_snand_exec_op,
};
static const struct of_device_id rtl_snand_match[] = {
{ .compatible = "realtek,rtl9301-snand" },
{ .compatible = "realtek,rtl9302b-snand" },
{ .compatible = "realtek,rtl9302c-snand" },
{ .compatible = "realtek,rtl9303-snand" },
{},
};
MODULE_DEVICE_TABLE(of, rtl_snand_match);
static int rtl_snand_probe(struct platform_device *pdev)
{
struct rtl_snand *snand;
struct device *dev = &pdev->dev;
struct spi_controller *ctrl;
void __iomem *base;
const struct regmap_config rc = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.cache_type = REGCACHE_NONE,
};
int irq, ret;
ctrl = devm_spi_alloc_host(dev, sizeof(*snand));
if (!ctrl)
return -ENOMEM;
snand = spi_controller_get_devdata(ctrl);
snand->dev = dev;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
snand->regmap = devm_regmap_init_mmio(dev, base, &rc);
if (IS_ERR(snand->regmap))
return PTR_ERR(snand->regmap);
init_completion(&snand->comp);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = dma_set_mask(snand->dev, DMA_BIT_MASK(32));
if (ret)
return dev_err_probe(dev, ret, "failed to set DMA mask\n");
ret = devm_request_irq(dev, irq, rtl_snand_irq, 0, "rtl-snand", snand);
if (ret)
return dev_err_probe(dev, ret, "failed to request irq\n");
ctrl->num_chipselect = 2;
ctrl->mem_ops = &rtl_snand_mem_ops;
ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD;
device_set_node(&ctrl->dev, dev_fwnode(dev));
return devm_spi_register_controller(dev, ctrl);
}
static struct platform_driver rtl_snand_driver = {
.driver = {
.name = "realtek-rtl-snand",
.of_match_table = rtl_snand_match,
},
.probe = rtl_snand_probe,
};
module_platform_driver(rtl_snand_driver);
MODULE_DESCRIPTION("Realtek SPI-NAND Flash Controller Driver");
MODULE_LICENSE("GPL");

View File

@ -111,7 +111,7 @@
#define SFC_VER_4 0x4
#define SFC_VER_5 0x5
/* Delay line controller resiter */
/* Delay line controller register */
#define SFC_DLL_CTRL0 0x3C
#define SFC_DLL_CTRL0_SCLK_SMP_DLL BIT(15)
#define SFC_DLL_CTRL0_DLL_MAX_VER4 0xFFU
@ -580,19 +580,16 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
return PTR_ERR(sfc->regbase);
sfc->clk = devm_clk_get(&pdev->dev, "clk_sfc");
if (IS_ERR(sfc->clk)) {
dev_err(&pdev->dev, "Failed to get sfc interface clk\n");
return PTR_ERR(sfc->clk);
}
if (IS_ERR(sfc->clk))
return dev_err_probe(&pdev->dev, PTR_ERR(sfc->clk),
"Failed to get sfc interface clk\n");
sfc->hclk = devm_clk_get(&pdev->dev, "hclk_sfc");
if (IS_ERR(sfc->hclk)) {
dev_err(&pdev->dev, "Failed to get sfc ahb clk\n");
return PTR_ERR(sfc->hclk);
}
if (IS_ERR(sfc->hclk))
return dev_err_probe(&pdev->dev, PTR_ERR(sfc->hclk),
"Failed to get sfc ahb clk\n");
sfc->use_dma = !of_property_read_bool(sfc->dev->of_node,
"rockchip,sfc-no-dma");
sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, "rockchip,sfc-no-dma");
if (sfc->use_dma) {
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
@ -602,8 +599,7 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
}
sfc->buffer = dmam_alloc_coherent(dev, SFC_MAX_IOSIZE_VER3,
&sfc->dma_buffer,
GFP_KERNEL);
&sfc->dma_buffer, GFP_KERNEL);
if (!sfc->buffer)
return -ENOMEM;
}
@ -629,7 +625,6 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
0, pdev->name, sfc);
if (ret) {
dev_err(dev, "Failed to request irq\n");
goto err_irq;
}
@ -677,7 +672,7 @@ static struct platform_driver rockchip_sfc_driver = {
.of_match_table = rockchip_sfc_dt_ids,
},
.probe = rockchip_sfc_probe,
.remove_new = rockchip_sfc_remove,
.remove = rockchip_sfc_remove,
};
module_platform_driver(rockchip_sfc_driver);

View File

@ -192,7 +192,7 @@ struct rockchip_spi {
u8 rsd;
bool target_abort;
bool cs_inactive; /* spi target tansmition stop when cs inactive */
bool cs_inactive; /* spi target transmission stop when cs inactive */
bool cs_high_supported; /* native CS supports active-high polarity */
struct spi_transfer *xfer; /* Store xfer temporarily */
@ -742,22 +742,20 @@ static int rockchip_spi_setup(struct spi_device *spi)
static int rockchip_spi_probe(struct platform_device *pdev)
{
int ret;
struct rockchip_spi *rs;
struct spi_controller *ctlr;
struct resource *mem;
struct device_node *np = pdev->dev.of_node;
struct spi_controller *ctlr;
struct rockchip_spi *rs;
struct resource *mem;
u32 rsd_nsecs, num_cs;
bool target_mode;
int ret;
target_mode = of_property_read_bool(np, "spi-slave");
if (target_mode)
ctlr = spi_alloc_target(&pdev->dev,
sizeof(struct rockchip_spi));
ctlr = spi_alloc_target(&pdev->dev, sizeof(struct rockchip_spi));
else
ctlr = spi_alloc_host(&pdev->dev,
sizeof(struct rockchip_spi));
ctlr = spi_alloc_host(&pdev->dev, sizeof(struct rockchip_spi));
if (!ctlr)
return -ENOMEM;
@ -775,15 +773,15 @@ static int rockchip_spi_probe(struct platform_device *pdev)
rs->apb_pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk");
if (IS_ERR(rs->apb_pclk)) {
dev_err(&pdev->dev, "Failed to get apb_pclk\n");
ret = PTR_ERR(rs->apb_pclk);
ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->apb_pclk),
"Failed to get apb_pclk\n");
goto err_put_ctlr;
}
rs->spiclk = devm_clk_get_enabled(&pdev->dev, "spiclk");
if (IS_ERR(rs->spiclk)) {
dev_err(&pdev->dev, "Failed to get spi_pclk\n");
ret = PTR_ERR(rs->spiclk);
ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->spiclk),
"Failed to get spi_pclk\n");
goto err_put_ctlr;
}
@ -804,24 +802,22 @@ static int rockchip_spi_probe(struct platform_device *pdev)
if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
&rsd_nsecs)) {
/* rx sample delay is expressed in parent clock cycles (max 3) */
u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8),
1000000000 >> 8);
u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8), 1000000000 >> 8);
if (!rsd) {
dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay\n",
rs->freq, rsd_nsecs);
} else if (rsd > CR0_RSD_MAX) {
rsd = CR0_RSD_MAX;
dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns\n",
rs->freq, rsd_nsecs,
CR0_RSD_MAX * 1000000000U / rs->freq);
dev_warn(rs->dev,
"%u Hz are too fast to express %u ns delay, clamping at %u ns\n",
rs->freq, rsd_nsecs, CR0_RSD_MAX * 1000000000U / rs->freq);
}
rs->rsd = rsd;
}
rs->fifo_len = get_fifo_len(rs);
if (!rs->fifo_len) {
dev_err(&pdev->dev, "Failed to get fifo length\n");
ret = -EINVAL;
ret = dev_err_probe(&pdev->dev, -EINVAL, "Failed to get fifo length\n");
goto err_put_ctlr;
}
@ -861,22 +857,21 @@ static int rockchip_spi_probe(struct platform_device *pdev)
ctlr->dma_tx = dma_request_chan(rs->dev, "tx");
if (IS_ERR(ctlr->dma_tx)) {
/* Check tx to see if we need defer probing driver */
if (PTR_ERR(ctlr->dma_tx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
/* Check tx to see if we need to defer driver probing */
ret = dev_warn_probe(rs->dev, PTR_ERR(ctlr->dma_tx),
"Failed to request optional TX DMA channel\n");
if (ret == -EPROBE_DEFER)
goto err_disable_pm_runtime;
}
dev_warn(rs->dev, "Failed to request TX DMA channel\n");
ctlr->dma_tx = NULL;
}
ctlr->dma_rx = dma_request_chan(rs->dev, "rx");
if (IS_ERR(ctlr->dma_rx)) {
if (PTR_ERR(ctlr->dma_rx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
/* Check rx to see if we need to defer driver probing */
ret = dev_warn_probe(rs->dev, PTR_ERR(ctlr->dma_rx),
"Failed to request optional RX DMA channel\n");
if (ret == -EPROBE_DEFER)
goto err_free_dma_tx;
}
dev_warn(rs->dev, "Failed to request RX DMA channel\n");
ctlr->dma_rx = NULL;
}
@ -1036,7 +1031,7 @@ static struct platform_driver rockchip_spi_driver = {
.of_match_table = of_match_ptr(rockchip_spi_dt_match),
},
.probe = rockchip_spi_probe,
.remove_new = rockchip_spi_remove,
.remove = rockchip_spi_remove,
};
module_platform_driver(rockchip_spi_driver);

View File

@ -206,7 +206,7 @@ MODULE_DEVICE_TABLE(platform, rpc_if_spi_id_table);
static struct platform_driver rpcif_spi_driver = {
.probe = rpcif_spi_probe,
.remove_new = rpcif_spi_remove,
.remove = rpcif_spi_remove,
.id_table = rpc_if_spi_id_table,
.driver = {
.name = "rpc-if-spi",

View File

@ -1427,7 +1427,7 @@ static SIMPLE_DEV_PM_OPS(rspi_pm_ops, rspi_suspend, rspi_resume);
static struct platform_driver rspi_driver = {
.probe = rspi_probe,
.remove_new = rspi_remove,
.remove = rspi_remove,
.id_table = spi_driver_ids,
.driver = {
.name = "renesas_spi",

View File

@ -683,7 +683,7 @@ MODULE_DEVICE_TABLE(of, rzv2m_csi_match);
static struct platform_driver rzv2m_csi_drv = {
.probe = rzv2m_csi_probe,
.remove_new = rzv2m_csi_remove,
.remove = rzv2m_csi_remove,
.driver = {
.name = "rzv2m_csi",
.of_match_table = rzv2m_csi_match,

View File

@ -1353,7 +1353,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
/* Setup Deufult Mode */
/* Setup Default Mode */
s3c64xx_spi_hwinit(sdd);
spin_lock_init(&sdd->lock);
@ -1681,7 +1681,7 @@ static struct platform_driver s3c64xx_spi_driver = {
.of_match_table = of_match_ptr(s3c64xx_spi_dt_match),
},
.probe = s3c64xx_spi_probe,
.remove_new = s3c64xx_spi_remove,
.remove = s3c64xx_spi_remove,
.id_table = s3c64xx_spi_driver_ids,
};
MODULE_ALIAS("platform:s3c64xx-spi");

View File

@ -293,7 +293,7 @@ MODULE_DEVICE_TABLE(of, hspi_of_match);
static struct platform_driver hspi_driver = {
.probe = hspi_probe,
.remove_new = hspi_remove,
.remove = hspi_remove,
.driver = {
.name = "sh-hspi",
.of_match_table = hspi_of_match,

View File

@ -1429,7 +1429,7 @@ static SIMPLE_DEV_PM_OPS(sh_msiof_spi_pm_ops, sh_msiof_spi_suspend,
static struct platform_driver sh_msiof_spi_drv = {
.probe = sh_msiof_spi_probe,
.remove_new = sh_msiof_spi_remove,
.remove = sh_msiof_spi_remove,
.id_table = spi_driver_ids,
.driver = {
.name = "spi_sh_msiof",

View File

@ -183,7 +183,7 @@ static void sh_sci_spi_remove(struct platform_device *dev)
static struct platform_driver sh_sci_spi_drv = {
.probe = sh_sci_spi_probe,
.remove_new = sh_sci_spi_remove,
.remove = sh_sci_spi_remove,
.driver = {
.name = "spi_sh_sci",
},

View File

@ -459,7 +459,7 @@ static int spi_sh_probe(struct platform_device *pdev)
static struct platform_driver spi_sh_driver = {
.probe = spi_sh_probe,
.remove_new = spi_sh_remove,
.remove = spi_sh_remove,
.driver = {
.name = "sh_spi",
},

View File

@ -471,7 +471,7 @@ MODULE_DEVICE_TABLE(of, sifive_spi_of_match);
static struct platform_driver sifive_spi_driver = {
.probe = sifive_spi_probe,
.remove_new = sifive_spi_remove,
.remove = sifive_spi_remove,
.driver = {
.name = SIFIVE_SPI_DRIVER_NAME,
.pm = &sifive_spi_pm_ops,

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