ASoC: Updates for v7.4

There's an awful lot of cleanup work in this pull request, lots from Bui
 Duc Phuc, Pengpeng Hou, HyeongJun An and Chancel Liu cleaning up detail
 issues in drivers in addition to Mormoto-san's ongoing framework work.
 This time Morimoto-san's work included enabling auto_selectable_formats
 so there's less manual configuration required for DAI links.
 
 There's also been a huge amount of upstreaming activity from Qualcomm,
 some pain there but hopefully enough has now landed for things to be
 smoother in future.
 
  - Use auto_selectable_formats in most drivers to reduce the amount of
    manual configuration required for DAI links.
  - Support for compressed audio on SOF IPC4 systems.
  - Support for AMD ACP 7.B and 7.F, AmLogic A9 and T7, Airoha AN7581,
    ESS Technology ES9039Q2M, Intel Cherry Trail with RT5688, Nuvoton
    NAU83G60, nVidia systems with WM8994, Qualcomm QAIF, Senary I2S, WCD9378
    and various platforms, Realtek RT766 and RT767, Senary SN624x
 
 I also mistakenly merged some SPI changes in here then applied more
 patches on top before I noticed (it looks like this was b4's base
 selection logic picking a bad base for some ASoC work), highlights there
 are:
 
  - Improvements for spidev_test to cover additional use cases, plus be a
    bit easier to use.
  - Push more Tegra210 QSPI handling into interrupt context for
    performance improvements.
  - Support for Qualcomm QPIC SNAND v2 and RealTek RTD1625 NOR.
  - Documentation clarifications.
  - Fixes for some runtime PM and error handling issues.
  - Support for R-Car Gen5.
 
 (this should also be going in via my SPI pull request)
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQReagvpf3TrrA7BoYYv73Ows9A4iQUCatYeBwAKCRAv73Ows9A4
 iZGkAP42Kan4kjk94MkmNDLX76vzffRYznFmexPQGrFqwkzt/gD+Kd5NDbDs5U4m
 D5rPlU6xLbRAl+8VztbWX2lhTWZPKwA=
 =MEqI
 -----END PGP SIGNATURE-----

Merge tag 'asoc-v7.4' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Updates for v7.4

There's an awful lot of cleanup work in this pull request, lots from Bui
Duc Phuc, Pengpeng Hou, HyeongJun An and Chancel Liu cleaning up detail
issues in drivers in addition to Mormoto-san's ongoing framework work.
This time Morimoto-san's work included enabling auto_selectable_formats
so there's less manual configuration required for DAI links.

There's also been a huge amount of upstreaming activity from Qualcomm,
some pain there but hopefully enough has now landed for things to be
smoother in future.

 - Use auto_selectable_formats in most drivers to reduce the amount of
   manual configuration required for DAI links.
 - Support for compressed audio on SOF IPC4 systems.
 - Support for AMD ACP 7.B and 7.F, AmLogic A9 and T7, Airoha AN7581,
   ESS Technology ES9039Q2M, Intel Cherry Trail with RT5688, Nuvoton
   NAU83G60, nVidia systems with WM8994, Qualcomm QAIF, Senary I2S, WCD9378
   and various platforms, Realtek RT766 and RT767, Senary SN624x

I also mistakenly merged some SPI changes in here then applied more
patches on top before I noticed (it looks like this was b4's base
selection logic picking a bad base for some ASoC work), highlights there
are:

 - Improvements for spidev_test to cover additional use cases, plus be a
   bit easier to use.
 - Push more Tegra210 QSPI handling into interrupt context for
   performance improvements.
 - Support for Qualcomm QPIC SNAND v2 and RealTek RTD1625 NOR.
 - Documentation clarifications.
 - Fixes for some runtime PM and error handling issues.
 - Support for R-Car Gen5.

(this should also be going in via my SPI pull request)
This commit is contained in:
Takashi Iwai 2026-10-19 19:58:10 +02:00
commit 31fd009c28
689 changed files with 34055 additions and 5870 deletions

View File

@ -17,7 +17,8 @@ Description: (WO) Instantiate a new SPI device on bus B, where B
with delete_device; platform and DT devices are not
affected.
Example:
Example::
# echo spidev 0 > /sys/class/spi_master/spi0/new_device
# echo spidev 0 10000000 > /sys/class/spi_master/spi0/new_device
# echo spidev 0 10000000 3 > /sys/class/spi_master/spi0/new_device
@ -30,5 +31,6 @@ Description: (WO) Remove a SPI device previously created via
new_device. Takes a single parameter: the chip select
number of the device to remove.
Example:
Example::
# echo 0 > /sys/class/spi_master/spi0/delete_device

View File

@ -52,11 +52,11 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
audio-codec@3c {
compatible = "adi,adau1372";
reg = <0x3c>;
#sound-dai-cells = <0>;
clock-names = "mclk";
clocks = <&adau1372z_xtal>;
compatible = "adi,adau1372";
reg = <0x3c>;
#sound-dai-cells = <0>;
clock-names = "mclk";
clocks = <&adau1372z_xtal>;
};
};

View File

@ -68,20 +68,20 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
adau7118_codec: audio-codec@14 {
compatible = "adi,adau7118";
reg = <0x14>;
#sound-dai-cells = <0>;
iovdd-supply = <&supply>;
dvdd-supply = <&supply>;
adi,pdm-clk-map = <1 1 0 0>;
adi,decimation-ratio = <16>;
compatible = "adi,adau7118";
reg = <0x14>;
#sound-dai-cells = <0>;
iovdd-supply = <&supply>;
dvdd-supply = <&supply>;
adi,pdm-clk-map = <1 1 0 0>;
adi,decimation-ratio = <16>;
};
};
/* example with hw standalone mode */
adau7118_codec_hw: adau7118-codec-hw {
compatible = "adi,adau7118";
#sound-dai-cells = <0>;
iovdd-supply = <&supply>;
dvdd-supply = <&supply>;
compatible = "adi,adau7118";
#sound-dai-cells = <0>;
iovdd-supply = <&supply>;
dvdd-supply = <&supply>;
};

View File

@ -0,0 +1,41 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/airoha,an7581-afe.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Airoha AFE PCM controller for AN7581
maintainers:
- Christian Marangi <ansuelsmth@gmail.com>
properties:
compatible:
const: airoha,an7581-afe
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
afe@1fbe2200 {
compatible = "airoha,an7581-afe";
reg = <0x1fbe2200 0x9000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
};
...

View File

@ -0,0 +1,71 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/airoha,an7581-wm8960.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Airoha AN7581 sound card with WM8960 codec
maintainers:
- Christian Marangi <ansuelsmth@gmail.com>
allOf:
- $ref: sound-card-common.yaml#
properties:
compatible:
const: airoha,an7581-wm8960-sound
platform:
type: object
additionalProperties: false
properties:
sound-dai:
items:
- description: The phandle of AN7581 platform.
required:
- sound-dai
codec:
type: object
additionalProperties: false
properties:
sound-dai:
items:
- description: The phandle of WM8960 i2c codec.
required:
- sound-dai
required:
- compatible
- audio-routing
- platform
- codec
unevaluatedProperties: false
examples:
- |
sound {
compatible = "airoha,an7581-wm8960-sound";
model = "an7581-wm8960";
audio-routing =
"Headphone", "HP_L",
"Headphone", "HP_R",
"LINPUT1", "AMIC",
"RINPUT1", "AMIC";
platform {
sound-dai = <&afe>;
};
codec {
sound-dai = <&wm8960>;
};
};

View File

@ -94,20 +94,20 @@ examples:
audio-routing = "I2S ENCODER I2S IN", "I2S FIFO Playback";
dai-link-0 {
sound-dai = <&i2s_fifo>;
sound-dai = <&i2s_fifo>;
};
dai-link-1 {
sound-dai = <&i2s_encoder>;
dai-format = "i2s";
mclk-fs = <256>;
sound-dai = <&i2s_encoder>;
dai-format = "i2s";
mclk-fs = <256>;
codec-0 {
sound-dai = <&codec0>;
};
codec-0 {
sound-dai = <&codec0>;
};
codec-1 {
sound-dai = <&codec1>;
};
codec-1 {
sound-dai = <&codec1>;
};
};
};

View File

@ -34,6 +34,12 @@ properties:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
powerdown-gpios:
maxItems: 1
description:
GPIO connected to the 'PDN' pin, if any. Needs to be set low to
power down the codec, hence the GPIO must be GPIO_ACTIVE_LOW.
required:
- compatible
- reg
@ -42,6 +48,8 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
@ -49,14 +57,16 @@ examples:
compatible = "asahi-kasei,ak4619";
reg = <0x10>;
powerdown-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
clocks = <&rcar_sound>;
clock-names = "mclk";
#sound-dai-cells = <0>;
port {
ak4619_endpoint: endpoint {
remote-endpoint = <&rsnd_endpoint>;
};
ak4619_endpoint: endpoint {
remote-endpoint = <&rsnd_endpoint>;
};
};
};
};

View File

@ -39,6 +39,7 @@ definitions:
allOf:
- $ref: /schemas/graph.yaml#/$defs/endpoint-base
- $ref: /schemas/sound/dai-params.yaml#
- $ref: /schemas/sound/tdm-slot.yaml#
properties:
mclk-fs:
$ref: simple-card.yaml#/definitions/mclk-fs
@ -48,6 +49,9 @@ definitions:
bitclock-inversion:
description: dai-link uses bit clock inversion
$ref: /schemas/types.yaml#/definitions/flag
continuous-clock:
description: dai-link bit clock runs continuously rather than gated
$ref: /schemas/types.yaml#/definitions/flag
frame-master:
description: Indicates dai-link frame master.
oneOf:
@ -82,12 +86,6 @@ definitions:
- msb
- lsb
dai-tdm-slot-num:
description: Number of slots in use.
$ref: /schemas/types.yaml#/definitions/uint32
dai-tdm-slot-width:
description: Width in bits for each slot.
$ref: /schemas/types.yaml#/definitions/uint32
dai-tdm-slot-width-map:
description: Mapping of sample widths to slot widths. For hardware
that cannot support a fixed slot width or a slot width always

View File

@ -53,6 +53,76 @@ properties:
maximum: 3
default: 2
cirrus,sync-lsw-txid:
description:
Transmitter ID to use for long software (LSW) data packets
on the SYNC bus.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
default: 0
cirrus,sync-sw-txid:
description:
Transmitter ID to use for short software (SW) data packets
on the SYNC bus.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 7
default: 0
cirrus,ldpm-group1-boost-select:
type: boolean
description:
When in a valid group 1 level dependent power management (LDPM) state
the integrated boost converter will enter the configured low power mode.
cirrus,boost-low-power-mode:
description:
Configures the integrated boost converter reaction to a low power mode
request.
0 = No reaction
1 = Force boost DCM low power mode
2 = Force boost static bypass
$ref: /schemas/types.yaml#/definitions/uint32
default: 2
enum:
- 0
- 1
- 2
cirrus,ldpm-group1-amp-select:
type: boolean
description:
When in a valid group 1 level dependent power management (LDPM) state
the amplifier will enter the configured low power mode.
cirrus,amplifier-low-power-mode:
description:
Configures the amplifier output stage reaction to a low power mode
request.
0 = Stop output switching (noise gate mode)
1 = Noise floor reduction mode
$ref: /schemas/types.yaml#/definitions/uint32
default: 1
enum:
- 0
- 1
cirrus,ldpm-group2-vmon-select:
type: boolean
description:
When in a valid group 2 level dependent power management (LDPM) state
the voltage monitor (VMON) circuit is put into a low power operational
state.
cirrus,ldpm-group2-imon-select:
type: boolean
description:
When in a valid group 2 level dependent power management (LDPM) state
the current monitor (IMON) circuit is put into a low power operational
state.
patternProperties:
"^cirrus,gpio-ctrl[1-3]$":
description:
@ -121,6 +191,30 @@ patternProperties:
minimum: 0
maximum: 7
default: 0
"^cirrus,ldpm-group[1-2]-pcm-threshold-db$":
description:
Amplifier level dependent power management (LDPM) threshold. Input
referred threshold of the PCM audio signal in which the level is low
enough for the LDPM group to engage after entry delay. A value of dB
-2147483648 is assumed to mean true zero data with an LSB dither.
$ref: /schemas/types.yaml#/definitions/int32-array
minItems: 1
maxItems: 1
items:
enum: [-2147483648, -102, -96, -90, -84, -78, -72, -66]
"^cirrus,ldpm-group[1-2]-delay-ms$":
description:
Amplifier level dependent power management (LDPM) state entry delay.
Time that the incoming audio signal must be below the PCM threshold
before the LDPM group engages.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 1
items:
enum: [5, 10, 25, 50, 100, 250, 500, 1000]
required:
- compatible
- reg
@ -135,25 +229,37 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
cs35l45: cs35l45@2 {
#sound-dai-cells = <1>;
compatible = "cirrus,cs35l45";
reg = <2>;
spi-max-frequency = <5000000>;
vdd-a-supply = <&dummy_vreg>;
vdd-batt-supply = <&dummy_vreg>;
reset-gpios = <&gpio 110 0>;
cirrus,asp-sdout-hiz-ctrl = <(CS35L45_ASP_TX_HIZ_UNUSED |
CS35L45_ASP_TX_HIZ_DISABLED)>;
cirrus,gpio-ctrl1 {
gpio-ctrl = <0x2>;
};
cirrus,gpio-ctrl2 {
gpio-ctrl = <0x2>;
};
cirrus,gpio-ctrl3 {
gpio-ctrl = <0x1>;
gpio-dir = <0x1>;
};
cs35l45: audio-codec@2 {
#sound-dai-cells = <1>;
compatible = "cirrus,cs35l45";
reg = <2>;
spi-max-frequency = <5000000>;
vdd-a-supply = <&dummy_vreg>;
vdd-batt-supply = <&dummy_vreg>;
reset-gpios = <&gpio 110 0>;
cirrus,asp-sdout-hiz-ctrl = <(CS35L45_ASP_TX_HIZ_UNUSED |
CS35L45_ASP_TX_HIZ_DISABLED)>;
cirrus,sync-lsw-txid = <0x1>;
cirrus,sync-sw-txid = <0x1>;
cirrus,ldpm-group1-pcm-threshold-db = <(-66)>;
cirrus,ldpm-group1-delay-ms = <500>;
cirrus,ldpm-group1-boost-select;
cirrus,boost-low-power-mode = <CS35L45_BST_LPMODE_DCM_MODE>;
cirrus,ldpm-group1-amp-select;
cirrus,amplifier-low-power-mode = <CS35L45_AMP_LPMODE_NFR_MODE>;
cirrus,ldpm-group2-pcm-threshold-db = <(-102)>;
cirrus,ldpm-group2-delay-ms = <1000>;
cirrus,ldpm-group2-vmon-select;
cirrus,ldpm-group2-imon-select;
cirrus,gpio-ctrl1 {
gpio-ctrl = <0x2>;
};
cirrus,gpio-ctrl2 {
gpio-ctrl = <0x2>;
};
cirrus,gpio-ctrl3 {
gpio-ctrl = <0x1>;
gpio-dir = <0x1>;
};
};
};

View File

@ -49,11 +49,11 @@ unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
codec@48 {
compatible = "cirrus,cs4270";
reg = <0x48>;
};
codec@48 {
compatible = "cirrus,cs4270";
reg = <0x48>;
};
};

View File

@ -199,28 +199,28 @@ examples:
- |
#include <dt-bindings/sound/cs42l42.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
cs42l42: cs42l42@48 {
compatible = "cirrus,cs42l42";
reg = <0x48>;
VA-supply = <&dummy_vreg>;
VP-supply = <&dummy_vreg>;
VCP-supply = <&dummy_vreg>;
VD_FILT-supply = <&dummy_vreg>;
VL-supply = <&dummy_vreg>;
audio-codec@48 {
compatible = "cirrus,cs42l42";
reg = <0x48>;
VA-supply = <&dummy_vreg>;
VP-supply = <&dummy_vreg>;
VCP-supply = <&dummy_vreg>;
VD_FILT-supply = <&dummy_vreg>;
VL-supply = <&dummy_vreg>;
reset-gpios = <&axi_gpio_0 1 0>;
interrupt-parent = <&gpio0>;
interrupts = <55 8>;
reset-gpios = <&axi_gpio_0 1 0>;
interrupt-parent = <&gpio0>;
interrupts = <55 8>;
cirrus,ts-inv = <CS42L42_TS_INV_DIS>;
cirrus,ts-dbnc-rise = <CS42L42_TS_DBNCE_1000>;
cirrus,ts-dbnc-fall = <CS42L42_TS_DBNCE_0>;
cirrus,btn-det-init-dbnce = <100>;
cirrus,btn-det-event-dbnce = <10>;
cirrus,bias-lvls = <0x0F 0x08 0x04 0x01>;
cirrus,hs-bias-ramp-rate = <CS42L42_HSBIAS_RAMP_SLOW>;
};
cirrus,ts-inv = <CS42L42_TS_INV_DIS>;
cirrus,ts-dbnc-rise = <CS42L42_TS_DBNCE_1000>;
cirrus,ts-dbnc-fall = <CS42L42_TS_DBNCE_0>;
cirrus,btn-det-init-dbnce = <100>;
cirrus,btn-det-event-dbnce = <10>;
cirrus,bias-lvls = <0x0F 0x08 0x04 0x01>;
cirrus,hs-bias-ramp-rate = <CS42L42_HSBIAS_RAMP_SLOW>;
};
};

View File

@ -43,14 +43,14 @@ examples:
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
jack_codec: codec@4b {
compatible = "cirrus,cs42l84";
reg = <0x4b>;
reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_LOW>;
interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>;
#sound-dai-cells = <0>;
};
jack_codec: codec@4b {
compatible = "cirrus,cs42l84";
reg = <0x4b>;
reset-gpios = <&pinctrl_nub 4 GPIO_ACTIVE_LOW>;
interrupts-extended = <&pinctrl_ap 180 IRQ_TYPE_LEVEL_LOW>;
#sound-dai-cells = <0>;
};
};

View File

@ -75,37 +75,37 @@ unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
codec@48 {
compatible = "cirrus,cs42888";
reg = <0x48>;
clocks = <&codec_mclk 0>;
clock-names = "mclk";
VA-supply = <&reg_audio>;
VD-supply = <&reg_audio>;
VLS-supply = <&reg_audio>;
VLC-supply = <&reg_audio>;
reset-gpios = <&gpio 1>;
};
codec@48 {
compatible = "cirrus,cs42888";
reg = <0x48>;
clocks = <&codec_mclk 0>;
clock-names = "mclk";
VA-supply = <&reg_audio>;
VD-supply = <&reg_audio>;
VLS-supply = <&reg_audio>;
VLC-supply = <&reg_audio>;
reset-gpios = <&gpio 1>;
};
};
spi {
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&gpio 8 0>;
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&gpio 8 0>;
codec@0 {
compatible = "cirrus,cs42888";
reg = <0>;
spi-max-frequency = <6000000>;
clocks = <&codec_mclk 0>;
clock-names = "mclk";
VA-supply = <&reg_audio>;
VD-supply = <&reg_audio>;
VLS-supply = <&reg_audio>;
VLC-supply = <&reg_audio>;
reset-gpios = <&gpio 1>;
};
codec@0 {
compatible = "cirrus,cs42888";
reg = <0>;
spi-max-frequency = <6000000>;
clocks = <&codec_mclk 0>;
clock-names = "mclk";
VA-supply = <&reg_audio>;
VD-supply = <&reg_audio>;
VLS-supply = <&reg_audio>;
VLC-supply = <&reg_audio>;
reset-gpios = <&gpio 1>;
};
};

View File

@ -1,49 +0,0 @@
* Texas Instruments SoC audio setups with TLV320AIC3X Codec
Required properties:
- compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx
- ti,model : The user-visible name of this sound complex.
- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
- ti,mcasp-controller : The phandle of the McASP controller
- ti,audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources and
sinks are the codec's pins, and the jacks on the board:
Optional properties:
- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec.
- clocks : Reference to the master clock
- clock-names : The clock should be named "mclk"
- Either codec-clock-rate or the codec-clock reference has to be defined. If
the both are defined the driver attempts to set referenced clock to the
defined rate and takes the rate from the clock reference.
Board connectors:
* Headphone Jack
* Line Out
* Mic Jack
* Line In
Example:
sound {
compatible = "ti,da830-evm-audio";
ti,model = "DA830 EVM";
ti,audio-codec = <&tlv320aic3x>;
ti,mcasp-controller = <&mcasp1>;
ti,codec-clock-rate = <12000000>;
ti,audio-routing =
"Headphone Jack", "HPLOUT",
"Headphone Jack", "HPROUT",
"Line Out", "LLOUT",
"Line Out", "RLOUT",
"MIC3L", "Mic Bias 2V",
"MIC3R", "Mic Bias 2V",
"Mic Bias 2V", "Mic Jack",
"LINE1L", "Line In",
"LINE2L", "Line In",
"LINE1R", "Line In",
"LINE2R", "Line In";
};

View File

@ -195,44 +195,44 @@ examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
#address-cells = <1>;
#size-cells = <0>;
codec: da7219@1a {
compatible = "dlg,da7219";
reg = <0x1a>;
codec: audio-codec@1a {
compatible = "dlg,da7219";
reg = <0x1a>;
interrupt-parent = <&gpio6>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
interrupt-parent = <&gpio6>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
VDD-supply = <&vdd_reg>;
VDDMIC-supply = <&vddmic_reg>;
VDDIO-supply = <&vddio_reg>;
VDD-supply = <&vdd_reg>;
VDDMIC-supply = <&vddmic_reg>;
VDDIO-supply = <&vddio_reg>;
#clock-cells = <1>;
clock-output-names = "da7219-dai-wclk", "da7219-dai-bclk";
#clock-cells = <1>;
clock-output-names = "da7219-dai-wclk", "da7219-dai-bclk";
clocks = <&clks 201>;
clock-names = "mclk";
clocks = <&clks 201>;
clock-names = "mclk";
dlg,micbias-lvl = <2600>;
dlg,mic-amp-in-sel = "diff";
dlg,micbias-lvl = <2600>;
dlg,mic-amp-in-sel = "diff";
da7219_aad {
dlg,btn-cfg = <50>;
dlg,mic-det-thr = <500>;
dlg,jack-ins-deb = <20>;
dlg,jack-ins-det-pty = "low";
dlg,jack-det-rate = "32_64";
dlg,jack-rem-deb = <1>;
da7219_aad {
dlg,btn-cfg = <50>;
dlg,mic-det-thr = <500>;
dlg,jack-ins-deb = <20>;
dlg,jack-ins-det-pty = "low";
dlg,jack-det-rate = "32_64";
dlg,jack-rem-deb = <1>;
dlg,a-d-btn-thr = <0xa>;
dlg,d-b-btn-thr = <0x16>;
dlg,b-c-btn-thr = <0x21>;
dlg,c-mic-btn-thr = <0x3E>;
dlg,a-d-btn-thr = <0xa>;
dlg,d-b-btn-thr = <0x16>;
dlg,b-c-btn-thr = <0x21>;
dlg,c-mic-btn-thr = <0x3E>;
dlg,btn-avg = <4>;
dlg,adc-1bit-rpt = <1>;
};
};
dlg,btn-avg = <4>;
dlg,adc-1bit-rpt = <1>;
};
};
};

View File

@ -0,0 +1,94 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/esstech,es9039q2m.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ESS Technology ES9039Q2M audio DAC
maintainers:
- Karl Asseily <karl@asseily.com>
description:
The ES9039Q2M is a 32-bit two-channel audio DAC supporting PCM to 768 kHz,
DSD64 to DSD1024, DoP and S/PDIF. It is controlled over I2C or SPI when the
MODE pin selects software mode; this binding covers the I2C interface. The
part contains an asynchronous sample rate converter, so the system clock need
not be synchronous with the audio bit or frame clocks.
The four supplies are all nominally 3.3V and the datasheet requires a set
order - AVDD first, then VCCA about 200us later, then AVCC_DAC1 and
AVCC_DAC2, and the reverse on the way down. DVDD, the part's 1.2V rail, is
on-chip and needs only its decoupling capacitor - it is not a supply input
and has no property here.
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: esstech,es9039q2m
reg:
description:
I2C address, selected by the ADDR0 and ADDR1 pins - 0x48, 0x49, 0x4a or
0x4b for GND/GND, GND/AVDD, AVDD/GND and AVDD/AVDD respectively.
enum: [ 0x48, 0x49, 0x4a, 0x4b ]
clocks:
maxItems: 1
clock-names:
const: mclk
avdd-supply:
description:
3.3V supply for the part's internal digital regulator, pin AVDD. It is
the first rail up and the last down, per the ordering described above.
vcca-supply:
description: 3.3V analogue supply, pin VCCA.
avcc-dac1-supply:
description:
3.3V reference supply for the channel 1 analogue output stage, pin
AVCC_DAC1. The datasheet allows this rail to move by up to 15% where a
calibrating regulator tracks the DAC's output impedance.
avcc-dac2-supply:
description:
3.3V reference supply for the channel 2 analogue output stage, pin
AVCC_DAC2, with the same 15% allowance as channel 1.
"#sound-dai-cells":
const: 0
required:
- compatible
- reg
- avdd-supply
- vcca-supply
- avcc-dac1-supply
- avcc-dac2-supply
- "#sound-dai-cells"
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
audio-codec@48 {
compatible = "esstech,es9039q2m";
reg = <0x48>;
#sound-dai-cells = <0>;
clocks = <&dac_mclk>;
clock-names = "mclk";
avdd-supply = <&dac_3v3>;
vcca-supply = <&dac_3v3>;
avcc-dac1-supply = <&dac_avcc1>;
avcc-dac2-supply = <&dac_avcc2>;
};
};

View File

@ -84,6 +84,11 @@ properties:
"#sound-dai-cells":
const: 0
everest,jack-detect-inverted:
$ref: /schemas/types.yaml#/definitions/flag
description:
Defined to invert the jack detection.
required:
- compatible
- reg

View File

@ -63,7 +63,7 @@ properties:
a. Register initialization settings
b. DSP effect parameters
c. Multi-scene sound effect configurations(optional)
It's gernerated by FourSemi's tuning tool.
It's generated by FourSemi's tuning tool.
required:
- compatible

View File

@ -55,6 +55,14 @@ properties:
- const: imx/easrc/easrc-imx8mn.bin
description: The coefficient table for the filters
ports:
$ref: /schemas/graph.yaml#/properties/ports
patternProperties:
"^port@[0-3]$":
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: port for an independent conversion path
fsl,asrc-rate:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 8000
@ -106,4 +114,41 @@ examples:
firmware-name = "imx/easrc/easrc-imx8mn.bin";
fsl,asrc-rate = <8000>;
fsl,asrc-format = <2>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
playback-only;
endpoint {
remote-endpoint = <&fe00_ep>;
};
};
port@1 {
reg = <1>;
playback-only;
endpoint {
remote-endpoint = <&fe01_ep>;
};
};
port@2 {
reg = <2>;
capture-only;
endpoint {
remote-endpoint = <&fe02_ep>;
};
};
port@3 {
reg = <3>;
capture-only;
endpoint {
remote-endpoint = <&fe03_ep>;
};
};
};
};

View File

@ -78,9 +78,19 @@ properties:
power-domains:
maxItems: 1
ports:
$ref: /schemas/graph.yaml#/properties/ports
patternProperties:
"^port@[0-2]$":
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
description: port for an independent conversion path
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
deprecated: true
description: deprecated, use ports instead
fsl,asrc-rate:
$ref: /schemas/types.yaml#/definitions/uint32
@ -125,6 +135,10 @@ required:
- fsl,asrc-width
allOf:
- not:
required:
- port
- ports
- $ref: dai-common.yaml#
- if:
properties:
@ -180,11 +194,32 @@ examples:
fsl,asrc-rate = <48000>;
fsl,asrc-width = <16>;
port {
playback-only;
ports {
#address-cells = <1>;
#size-cells = <0>;
asrc_endpoint: endpoint {
remote-endpoint = <&fe00_ep>;
port@0 {
reg = <0>;
playback-only;
endpoint {
remote-endpoint = <&fe00_ep>;
};
};
};
port@1 {
reg = <1>;
capture-only;
endpoint {
remote-endpoint = <&fe01_ep>;
};
};
port@2 {
reg = <2>;
capture-only;
endpoint {
remote-endpoint = <&fe02_ep>;
};
};
};
};

View File

@ -260,13 +260,13 @@ examples:
playback-only;
sai1_endpoint0: endpoint {
dai-tdm-slot-num = <8>;
dai-tdm-slot-width = <32>;
dai-tdm-slot-width-map = <32 8 32>;
dai-format = "dsp_a";
bitclock-master;
frame-master;
remote-endpoint = <&mcodec01_ep>;
dai-tdm-slot-num = <8>;
dai-tdm-slot-width = <32>;
dai-tdm-slot-width-map = <32 8 32>;
dai-format = "dsp_a";
bitclock-master;
frame-master;
remote-endpoint = <&mcodec01_ep>;
};
};

View File

@ -48,6 +48,10 @@ properties:
The dai cell indexes reference the following interfaces:
0: S2 interface
ports:
$ref: audio-graph-port.yaml#/definitions/ports
unevaluatedProperties: false
required:
- compatible
- reg

View File

@ -105,10 +105,10 @@ examples:
format = "i2s";
fsl,mclk-equal-bclk;
cpu {
sound-dai = <&sai1>;
sound-dai = <&sai1>;
};
codec {
sound-dai = <&ak4458_1>, <&ak4458_2>;
sound-dai = <&ak4458_1>, <&ak4458_2>;
};
};
fe-dai-link {

View File

@ -101,10 +101,10 @@ examples:
mux-ssi1 {
fsl,audmux-port = <0>;
fsl,port-config = <
IMX_AUDMUX_V2_PTCR_SYN 0
IMX_AUDMUX_V2_PTCR_TFSEL(2) 0
IMX_AUDMUX_V2_PTCR_TCSEL(2) 0
IMX_AUDMUX_V2_PTCR_TFSDIR 0
IMX_AUDMUX_V2_PTCR_SYN 0
IMX_AUDMUX_V2_PTCR_TFSEL(2) 0
IMX_AUDMUX_V2_PTCR_TCSEL(2) 0
IMX_AUDMUX_V2_PTCR_TFSDIR 0
IMX_AUDMUX_V2_PTCR_TCLKDIR IMX_AUDMUX_V2_PDCR_RXDSEL(2)
>;
};

View File

@ -42,10 +42,10 @@ examples:
compatible = "invensense,ics43432";
port {
endpoint {
remote-endpoint = <&i2s1_endpoint>;
dai-format = "i2s";
};
endpoint {
remote-endpoint = <&i2s1_endpoint>;
dai-format = "i2s";
};
};
};

View File

@ -79,7 +79,7 @@ examples:
sound-dai = <&i2s>;
};
codec {
sound-dai = <&es8323>;
sound-dai = <&es8323>;
};
};
@ -104,6 +104,6 @@ examples:
};
codec {
sound-dai = <&es8388>;
sound-dai = <&es8388>;
};
};

View File

@ -32,7 +32,7 @@ properties:
maxItems: 1
clocks:
minItems: 34
minItems: 33
items:
- description: audio infra sys clock
- description: top audio mux 1
@ -74,7 +74,7 @@ properties:
- description: audio APLL root pd
clock-names:
minItems: 34
minItems: 33
items:
- const: infra_sys_audio_clk
- const: top_audio_mux1_sel
@ -132,8 +132,10 @@ allOf:
then:
properties:
clocks:
maxItems: 34
minItems: 33
maxItems: 33
clock-names:
maxItems: 34
minItems: 33
maxItems: 33
additionalProperties: false

View File

@ -84,15 +84,15 @@ examples:
<&topckgen CLK_TOP_I2S2_M_SEL>,
<&topckgen CLK_TOP_I2S3_M_SEL>,
<&topckgen CLK_TOP_I2S3_B_SEL>;
clock-names = "infra_sys_audio_clk",
"top_pdn_audio",
"top_pdn_aud_intbus",
"bck0",
"bck1",
"i2s0_m",
"i2s1_m",
"i2s2_m",
"i2s3_m",
"i2s3_b";
memory-region = <&afe_dma_mem>;
clock-names = "infra_sys_audio_clk",
"top_pdn_audio",
"top_pdn_aud_intbus",
"bck0",
"bck1",
"i2s0_m",
"i2s1_m",
"i2s2_m",
"i2s3_m",
"i2s3_b";
memory-region = <&afe_dma_mem>;
};

View File

@ -182,47 +182,47 @@ examples:
<&topckgen CLK_TOP_APLL12_DIV4>,
<&topckgen CLK_TOP_APLL12_DIVB>,
<&clk26m>;
clock-names = "aud_afe_clk",
"aud_dac_clk",
"aud_dac_predis_clk",
"aud_adc_clk",
"aud_adc_adda6_clk",
"aud_apll22m_clk",
"aud_apll24m_clk",
"aud_apll1_tuner_clk",
"aud_apll2_tuner_clk",
"aud_i2s1_bclk_sw",
"aud_i2s2_bclk_sw",
"aud_i2s3_bclk_sw",
"aud_i2s4_bclk_sw",
"aud_tdm_clk",
"aud_tml_clk",
"aud_infra_clk",
"mtkaif_26m_clk",
"top_mux_audio",
"top_mux_aud_intbus",
"top_syspll_d2_d4",
"top_mux_aud_1",
"top_apll1_ck",
"top_mux_aud_2",
"top_apll2_ck",
"top_mux_aud_eng1",
"top_apll1_d8",
"top_mux_aud_eng2",
"top_apll2_d8",
"top_i2s0_m_sel",
"top_i2s1_m_sel",
"top_i2s2_m_sel",
"top_i2s3_m_sel",
"top_i2s4_m_sel",
"top_i2s5_m_sel",
"top_apll12_div0",
"top_apll12_div1",
"top_apll12_div2",
"top_apll12_div3",
"top_apll12_div4",
"top_apll12_divb",
"top_clk26m_clk";
clock-names = "aud_afe_clk",
"aud_dac_clk",
"aud_dac_predis_clk",
"aud_adc_clk",
"aud_adc_adda6_clk",
"aud_apll22m_clk",
"aud_apll24m_clk",
"aud_apll1_tuner_clk",
"aud_apll2_tuner_clk",
"aud_i2s1_bclk_sw",
"aud_i2s2_bclk_sw",
"aud_i2s3_bclk_sw",
"aud_i2s4_bclk_sw",
"aud_tdm_clk",
"aud_tml_clk",
"aud_infra_clk",
"mtkaif_26m_clk",
"top_mux_audio",
"top_mux_aud_intbus",
"top_syspll_d2_d4",
"top_mux_aud_1",
"top_apll1_ck",
"top_mux_aud_2",
"top_apll2_ck",
"top_mux_aud_eng1",
"top_apll1_d8",
"top_mux_aud_eng2",
"top_apll2_d8",
"top_i2s0_m_sel",
"top_i2s1_m_sel",
"top_i2s2_m_sel",
"top_i2s3_m_sel",
"top_i2s4_m_sel",
"top_i2s5_m_sel",
"top_apll12_div0",
"top_apll12_div1",
"top_apll12_div2",
"top_apll12_div3",
"top_apll12_div4",
"top_apll12_divb",
"top_clk26m_clk";
};
...

View File

@ -167,30 +167,30 @@ examples:
"HDMI1", "TX";
hs-playback-dai-link {
link-name = "I2S0";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&da7219>;
};
link-name = "I2S0";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&da7219>;
};
};
hs-capture-dai-link {
link-name = "I2S1";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&da7219>;
};
link-name = "I2S1";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&da7219>;
};
};
spk-dp-playback-dai-link {
link-name = "I2S3";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&anx_bridge_dp>, <&max98357a>;
};
link-name = "I2S3";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&anx_bridge_dp>, <&max98357a>;
};
};
};

View File

@ -171,30 +171,30 @@ examples:
"HDMI1", "TX";
hs-playback-dai-link {
link-name = "I2S0";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt5682s 0>;
};
link-name = "I2S0";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt5682s 0>;
};
};
hs-capture-dai-link {
link-name = "I2S1";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt5682s 0>;
};
link-name = "I2S1";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt5682s 0>;
};
};
spk-hdmi-playback-dai-link {
link-name = "I2S3";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&it6505dptx>, <&rt1019p>;
};
link-name = "I2S3";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&it6505dptx>, <&rt1019p>;
};
};
};

View File

@ -165,38 +165,38 @@ examples:
"Speakers", "Speaker";
spk-playback-dai-link {
link-name = "I2S3";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt1015p>;
};
link-name = "I2S3";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt1015p>;
};
};
hs-playback-dai-link {
link-name = "I2S8";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt5682 0>;
};
link-name = "I2S8";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt5682 0>;
};
};
hs-capture-dai-link {
link-name = "I2S9";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt5682 0>;
};
link-name = "I2S9";
dai-format = "i2s";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&rt5682 0>;
};
};
displayport-dai-link {
link-name = "TDM";
dai-format = "dsp_a";
codec {
sound-dai = <&anx_bridge_dp>;
};
link-name = "TDM";
dai-format = "dsp_a";
codec {
sound-dai = <&anx_bridge_dp>;
};
};
};

View File

@ -156,46 +156,46 @@ examples:
"Ext Spk", "Speaker";
mm-dai-link {
link-name = "ETDM1_IN_BE";
mediatek,clk-provider = "cpu";
link-name = "ETDM1_IN_BE";
mediatek,clk-provider = "cpu";
};
hs-playback-dai-link {
link-name = "ETDM1_OUT_BE";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&headset_codec>;
};
link-name = "ETDM1_OUT_BE";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&headset_codec>;
};
};
hs-capture-dai-link {
link-name = "ETDM2_IN_BE";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&headset_codec>;
};
link-name = "ETDM2_IN_BE";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&headset_codec>;
};
};
spk-playback-dai-link {
link-name = "ETDM2_OUT_BE";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&spk_amplifier>;
};
link-name = "ETDM2_OUT_BE";
mediatek,clk-provider = "cpu";
codec {
sound-dai = <&spk_amplifier>;
};
};
hdmi-dai-link {
link-name = "ETDM3_OUT_BE";
codec {
sound-dai = <&hdmi_tx>;
};
link-name = "ETDM3_OUT_BE";
codec {
sound-dai = <&hdmi_tx>;
};
};
displayport-dai-link {
link-name = "DPTX_BE";
codec {
sound-dai = <&dp_tx>;
};
link-name = "DPTX_BE";
codec {
sound-dai = <&dp_tx>;
};
};
};

View File

@ -0,0 +1,115 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nuvoton,nau8360.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Nuvoton NAU83G60 Stereo Class-D Amplifier with DSP
description:
Stereo Class-D Amplifier with DSP and I/V-sense.
This device supports I2C.
maintainers:
- Neo Chang <YLCHANG2@nuvoton.com>
properties:
compatible:
enum:
- nuvoton,nau8360
reg:
description: The I2C address is determined by the hardware pins.
enum: [0x1a, 0x1b, 0x4a, 0x4b]
"#sound-dai-cells":
const: 0
clocks:
maxItems: 1
clock-names:
const: mclk
firmware-name:
description:
List of DSP core firmware filenames. Both Left and Right DSP firmware
must be provided and loaded. In PBTL mode, the Left DSP must use the
same binary file as the Right DSP.
items:
- description: Left DSP core firmware filename.
- description: Right DSP core firmware filename.
nuvoton,pbtl-enable:
type: boolean
description: NAU83G60 supports PBTL mode for mono output.
nuvoton,dac-cur-enable:
type: boolean
description:
Adjust DAC output current to match speaker impedance and prevent
hardware damage. +3.2dB when present, 0dB by default.
nuvoton,dsp-rx-slot-mapping:
description:
Configures the TDM slot routing for DSP RX functions.
Each integer assigns a specific DSP internal function to a TDM slot.
The indices of the array correspond to the following hardware functions
(0) DACL
(1) DACR
(2) ANCL
(3) ANCR
Assigned slots must be unique, except 255 which disables the function.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 4
maxItems: 4
items:
enum: [ 0, 1, 2, 3, 4, 5, 6, 7, 255 ]
nuvoton,dsp-tx-slot-mapping:
description:
Configures the TDM slot routing for DSP TX functions.
Each integer assigns a specific DSP internal function to a TDM slot.
The indices of the array correspond to the following hardware functions
(0) AECL (Acoustic echo cancellation left)
(1) AECR (Acoustic echo cancellation right)
(2) ISNSL (Current sense left)
(3) ISNSR (Current sense right)
(4) VSNSL (Voltage sense left)
(5) VSNSR (Voltage sense right)
(6) TJ (Junction temperature)
(7) VBAT (Battery voltage)
Assigned slots must be unique, except 255 which disables the function.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 8
maxItems: 8
items:
enum: [ 0, 1, 2, 3, 4, 5, 6, 7, 255 ]
required:
- compatible
- reg
- firmware-name
allOf:
- $ref: dai-common.yaml#
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1a {
compatible = "nuvoton,nau8360";
reg = <0x1a>;
#sound-dai-cells = <0>;
firmware-name = "NAU83G60.kcs.bin.l", "NAU83G60.kcs.bin.r";
nuvoton,dac-cur-enable;
nuvoton,pbtl-enable;
nuvoton,dsp-rx-slot-mapping = <0 1 2 3>;
nuvoton,dsp-tx-slot-mapping = <0 1 2 3 4 5 6 7>;
};
};

View File

@ -48,6 +48,11 @@ properties:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of audio codec
nvidia,aux-devs:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: List of phandles pointing to auxiliary devices,
such as amplifiers or dsp, to be added to the sound card.
nvidia,spkr-en-gpios:
maxItems: 1
description: The GPIO that enables the speakers

View File

@ -0,0 +1,110 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nvidia,tegra-audio-wm8994.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NVIDIA Tegra audio complex with WM8994 CODEC
maintainers:
- Svyatoslav Ryhel <clamor95@gmail.com>
allOf:
- $ref: nvidia,tegra-audio-common.yaml#
properties:
compatible:
items:
- pattern: '^[a-z0-9]+,tegra-audio-wm8994(-[a-z0-9]+)+$'
- const: nvidia,tegra-audio-wm8994
nvidia,audio-routing:
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
description: |
A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources and
sinks are the pins (documented in the binding document),
and the jacks on the board.
minItems: 2
items:
enum:
# Board Connectors
- Headphone Jack
- Int Spk
- Earpiece
- Line Out
- Mic Jack
- Int Mic
- Internal Mic 1
- Internal Mic 2
- FM Radio
# CODEC Pins
- SPKOUTLP
- SPKOUTLN
- SPKOUTRP
- SPKOUTRN
- HPOUT1L
- HPOUT1R
- HPOUT2P
- HPOUT2N
- LINEOUT1P
- LINEOUT1N
- LINEOUT2P
- LINEOUT2N
- IN1LN
- IN1LP
- IN2LN
- IN2LP:VXRN
- IN1RN
- IN1RP
- IN2RN
- IN2RP:VXRP
- DMIC1DAT
- DMIC2DAT
- MICBIAS1
- MICBIAS2
required:
- nvidia,i2s-controller
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/tegra20-car.h>
#include <dt-bindings/gpio/gpio.h>
sound {
compatible = "lg,tegra-audio-wm8994-star",
"nvidia,tegra-audio-wm8994";
nvidia,model = "LG Optimus 2X WM8994";
nvidia,audio-routing =
"Headphone Jack", "HPOUT1L",
"Headphone Jack", "HPOUT1R",
"Int Spk", "SPKOUTLN",
"Int Spk", "SPKOUTLP",
"Earpiece", "HPOUT2N",
"Earpiece", "HPOUT2P",
"IN2RN", "MICBIAS2",
"IN2RN", "Mic Jack",
"IN1LN", "MICBIAS1",
"IN1LN", "Internal Mic 1",
"IN1RN", "MICBIAS1",
"IN1RN", "Internal Mic 2";
nvidia,i2s-controller = <&tegra_i2s1>;
nvidia,audio-codec = <&wm8994>;
nvidia,hp-det-gpios = <&gpio 51 GPIO_ACTIVE_HIGH>;
nvidia,mic-det-gpios = <&gpio 27 GPIO_ACTIVE_HIGH>;
nvidia,ext-mic-en-gpios = <&gpio 57 GPIO_ACTIVE_HIGH>;
nvidia,coupled-mic-hp-det;
clocks = <&tegra_car TEGRA20_CLK_PLL_A>,
<&tegra_car TEGRA20_CLK_PLL_A_OUT0>,
<&tegra_car TEGRA20_CLK_CDEV1>;
clock-names = "pll_a", "pll_a_out0", "mclk";
};

View File

@ -1,88 +0,0 @@
NVIDIA Tegra30 AHUB (Audio Hub)
Required properties:
- compatible : For Tegra30, must contain "nvidia,tegra30-ahub". For Tegra114,
must contain "nvidia,tegra114-ahub". For Tegra124, must contain
"nvidia,tegra124-ahub". Otherwise, must contain "nvidia,<chip>-ahub",
plus at least one of the above, where <chip> is tegra132.
- reg : Should contain the register physical address and length for each of
the AHUB's register blocks.
- Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks.
- Tegra114 requires an additional entry, for the APBIF2 register block.
- interrupts : Should contain AHUB interrupt
- clocks : Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names : Must include the following entries:
- d_audio
- apbif
- resets : Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details.
- reset-names : Must include the following entries:
Tegra30 and later:
- d_audio
- apbif
- i2s0
- i2s1
- i2s2
- i2s3
- i2s4
- dam0
- dam1
- dam2
- spdif
Tegra114 and later additionally require:
- amx
- adx
Tegra124 and later additionally require:
- amx1
- adx1
- afc0
- afc1
- afc2
- afc3
- afc4
- afc5
- ranges : The bus address mapping for the configlink register bus.
Can be empty since the mapping is 1:1.
- dmas : Must contain an entry for each entry in clock-names.
See ../dma/dma.txt for details.
- dma-names : Must include the following entries:
- rx0 .. rx<n>
- tx0 .. tx<n>
... where n is:
Tegra30: 3
Tegra114, Tegra124: 9
- #address-cells : For the configlink bus. Should be <1>;
- #size-cells : For the configlink bus. Should be <1>.
AHUB client modules need to specify the IDs of their CIFs (Client InterFaces).
For RX CIFs, the numbers indicate the register number within AHUB routing
register space (APBIF 0..3 RX, I2S 0..5 RX, DAM 0..2 RX 0..1, SPDIF RX 0..1).
For TX CIFs, the numbers indicate the bit position within the AHUB routing
registers (APBIF 0..3 TX, I2S 0..5 TX, DAM 0..2 TX, SPDIF TX 0..1).
Example:
ahub@70080000 {
compatible = "nvidia,tegra30-ahub";
reg = <0x70080000 0x200 0x70080200 0x100>;
interrupts = < 0 103 0x04 >;
nvidia,dma-request-selector = <&apbdma 1>;
clocks = <&tegra_car 106>, <&tegra_car 107>;
clock-names = "d_audio", "apbif";
resets = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>,
<&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>,
<&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>,
<&tegra_car 110>, <&tegra_car 10>;
reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
"i2s3", "i2s4", "dam0", "dam1", "dam2",
"spdif";
dmas = <&apbdma 1>, <&apbdma 1>;
<&apbdma 2>, <&apbdma 2>;
<&apbdma 3>, <&apbdma 3>;
<&apbdma 4>, <&apbdma 4>;
dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", "rx3", "tx3";
ranges;
#address-cells = <1>;
#size-cells = <1>;
};

View File

@ -0,0 +1,289 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nvidia,tegra30-ahub.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NVIDIA Tegra30 AHUB (Audio Hub)
maintainers:
- Thierry Reding <thierry.reding@gmail.com>
- Jon Hunter <jonathanh@nvidia.com>
description:
AHUB client modules need to specify the IDs of their CIFs (Client
InterFaces). For RX CIFs, the numbers indicate the register number within
AHUB routing register space (APBIF 0..3 RX, I2S 0..5 RX, DAM 0..2 RX 0..1,
SPDIF RX 0..1). For TX CIFs, the numbers indicate the bit position within
the AHUB routing registers (APBIF 0..3 TX, I2S 0..5 TX, DAM 0..2 TX, SPDIF
TX 0..1).
properties:
compatible:
oneOf:
- const: nvidia,tegra30-ahub
- const: nvidia,tegra114-ahub
- const: nvidia,tegra124-ahub
- items:
- const: nvidia,tegra132-ahub
- const: nvidia,tegra124-ahub
reg:
minItems: 2
maxItems: 3
interrupts:
maxItems: 1
clocks:
items:
- description: digital audio clock
- description: module clock
clock-names:
items:
- const: d_audio
- const: apbif
resets:
minItems: 11
maxItems: 21
reset-names:
minItems: 11
maxItems: 21
ranges: true
dmas:
minItems: 8
maxItems: 20
dma-names:
minItems: 8
maxItems: 20
"#address-cells":
enum: [1, 2]
"#size-cells":
enum: [1, 2]
patternProperties:
"^i2s@[0-9a-f]+$":
type: object
required:
- compatible
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- resets
- reset-names
- ranges
- dmas
- dma-names
- "#address-cells"
- "#size-cells"
allOf:
- if:
properties:
compatible:
const: nvidia,tegra30-ahub
then:
properties:
reg:
items:
- description: APBIF registers
- description: AHUB/AUDIO registers
resets:
maxItems: 11
reset-names:
items:
- const: d_audio
- const: apbif
- const: i2s0
- const: i2s1
- const: i2s2
- const: i2s3
- const: i2s4
- const: dam0
- const: dam1
- const: dam2
- const: spdif
dmas:
maxItems: 8
dma-names:
items:
- const: rx0
- const: tx0
- const: rx1
- const: tx1
- const: rx2
- const: tx2
- const: rx3
- const: tx3
- if:
properties:
compatible:
const: nvidia,tegra114-ahub
then:
properties:
reg:
items:
- description: APBIF registers
- description: AHUB/AUDIO registers
- description: APBIF2 registers
resets:
minItems: 13
maxItems: 13
reset-names:
items:
- const: d_audio
- const: apbif
- const: i2s0
- const: i2s1
- const: i2s2
- const: i2s3
- const: i2s4
- const: dam0
- const: dam1
- const: dam2
- const: spdif
- const: amx
- const: adx
dmas:
minItems: 20
dma-names:
items:
- const: rx0
- const: tx0
- const: rx1
- const: tx1
- const: rx2
- const: tx2
- const: rx3
- const: tx3
- const: rx4
- const: tx4
- const: rx5
- const: tx5
- const: rx6
- const: tx6
- const: rx7
- const: tx7
- const: rx8
- const: tx8
- const: rx9
- const: tx9
- if:
properties:
compatible:
contains:
const: nvidia,tegra124-ahub
then:
properties:
reg:
items:
- description: APBIF registers
- description: AHUB/AUDIO registers
- description: APBIF2 registers
resets:
minItems: 21
reset-names:
items:
- const: d_audio
- const: apbif
- const: i2s0
- const: i2s1
- const: i2s2
- const: i2s3
- const: i2s4
- const: dam0
- const: dam1
- const: dam2
- const: spdif
- const: amx
- const: amx1
- const: adx
- const: adx1
- const: afc0
- const: afc1
- const: afc2
- const: afc3
- const: afc4
- const: afc5
dmas:
minItems: 20
dma-names:
items:
- const: rx0
- const: tx0
- const: rx1
- const: tx1
- const: rx2
- const: tx2
- const: rx3
- const: tx3
- const: rx4
- const: tx4
- const: rx5
- const: tx5
- const: rx6
- const: tx6
- const: rx7
- const: tx7
- const: rx8
- const: tx8
- const: rx9
- const: tx9
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/tegra30-car.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
ahub@70080000 {
compatible = "nvidia,tegra30-ahub";
reg = <0x70080000 0x200>,
<0x70080200 0x100>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_D_AUDIO>,
<&tegra_car TEGRA30_CLK_APBIF>;
clock-names = "d_audio", "apbif";
resets = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>,
<&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>,
<&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>,
<&tegra_car 110>, <&tegra_car 10>;
reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
"i2s3", "i2s4", "dam0", "dam1", "dam2",
"spdif";
dmas = <&apbdma 1>, <&apbdma 1>,
<&apbdma 2>, <&apbdma 2>,
<&apbdma 3>, <&apbdma 3>,
<&apbdma 4>, <&apbdma 4>;
dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", "rx3", "tx3";
ranges;
#address-cells = <1>;
#size-cells = <1>;
};

View File

@ -18,6 +18,7 @@ properties:
- items:
- enum:
- qcom,sdm660-wcd-digital-codec
- qcom,sdm670-wcd-digital-codec
- const: qcom,msm8916-wcd-digital-codec
- const: qcom,msm8916-wcd-digital-codec

View File

@ -20,9 +20,24 @@ properties:
minItems: 1
maxItems: 2
memory-region:
minItems: 1
items:
- description:
Control-path buffer (audio_heap_mem) for platforms where the DSP
runs in a stage-2 protected context (e.g. modem-DSP).
- description:
Data-path buffer pool from which per-stream DMA buffers are
allocated.
required:
- compatible
- iommus
oneOf:
- required:
- iommus
- required:
- memory-region
additionalProperties: false

View File

@ -75,11 +75,11 @@ examples:
#size-cells = <0>;
dai@10 {
reg = <PRIMARY_MI2S_RX>;
clocks = <&q6prmcc LPASS_CLK_ID_PRI_MI2S_IBIT
LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
<&q6prmcc LPASS_CLK_ID_MCLK_1
LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
clock-names = "bclk", "mclk";
reg = <PRIMARY_MI2S_RX>;
clocks = <&q6prmcc LPASS_CLK_ID_PRI_MI2S_IBIT
LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
<&q6prmcc LPASS_CLK_ID_MCLK_1
LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
clock-names = "bclk", "mclk";
};
};

View File

@ -108,10 +108,15 @@ patternProperties:
properties:
reg:
contains:
# TDM DAI ID range from PRIMARY_TDM_RX_0 - QUINARY_TDM_TX_7
# TDM DAI ID range from PRIMARY_TDM_RX_0 - QUINARY_TDM_TX_7 and
# AIF_TDM_RX_0 - AIF_TDM_TX_12
items:
minimum: 24
maximum: 103
oneOf:
- minimum: 24
maximum: 103
- minimum: 179
maximum: 204
then:
required:
- qcom,tdm-sync-mode
@ -127,7 +132,8 @@ patternProperties:
contains:
# MI2S DAI ID range PRIMARY_MI2S_RX - QUATERNARY_MI2S_TX and
# QUINARY_MI2S_RX - QUINARY_MI2S_TX and
# LPI_MI2S_RX_0 - LPI_MI2S_TX_6
# LPI_MI2S_RX_0 - LPI_MI2S_TX_6 and
# AIF_MI2S_RX_0 - AIF_MI2S_TX_12
items:
oneOf:
- minimum: 16
@ -136,6 +142,8 @@ patternProperties:
maximum: 128
- minimum: 137
maximum: 152
- minimum: 153
maximum: 178
then:
required:
- qcom,sd-lines

View File

@ -0,0 +1,290 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,shikra-qaif-cpu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Audio Interface (QAIF) CPU DAI Controller
maintainers:
- Harendra Gautam <harendra.gautam@oss.qualcomm.com>
description: |
The Qualcomm Audio Interface (QAIF) is a fully configurable DMA-based
audio subsystem controller. It serialises and deserialises PCM audio
between system memory and external serial audio peripherals (PCM, TDM,
I2S, MI2S) through the AIF path, and transfers parallel audio between
memory and an internal WCD codec through the CIF path.
AIF (Audio Interface): up to 13 multi-lane Unified Audio Interfaces,
each supporting up to 8 independent data lanes. Each lane is individually
configurable as TX (output/speaker) or RX (input/mic). All lanes of an
interface share a single bit clock and frame sync. Supported modes are
PCM (short/long sync), TDM, and MI2S (stereo/mono). Per-interface
configuration includes sync source (master/slave), sync mode, sync delay,
sync inversion, slot width (8/16/24/32-bit), sample width, active slot
masks (up to 32 slots), bits-per-lane frame size, lane enable/direction
masks, loopback, output-enable control, and full-cycle path support for
long chip-to-chip connections.
CIF (Codec Interface): up to 10 RDDMA (playback) and 10 WRDMA (capture)
channels connecting to an internal codec over a parallel bus. Each channel
supports active-channel enable mask (up to 16 channels), frame-sync
selection, frame-sync delay, frame-sync output gating, dynamic clock
gating, and 16-bit packing/unpacking.
Note on RX/TX naming convention: in QAIF, TX refers to the output
(speaker/playback) direction and RX refers to the input (mic/capture)
direction. This applies to both AIF lane directions and CIF slot/mask
properties.
DMA engine: RDDMA fetches audio from DDR/TCM/LPM into a shared SRAM
latency buffer (SHRAM) and drains it to the interface. WRDMA collects
data from the interface into SHRAM and writes it to memory. Each DMA
owns a private SHRAM region defined by start address and length registers.
Burst sizes of 1/2/4/8/16 beats (64-bit) are supported with up to 4
outstanding transactions per DMA. Two QSB master ports (QXM0 for TCM,
QXM1 for DDR/LPM) provide the memory interface.
Resources are partitioned among up to 5 Execution Engines (EEs) via
EE map registers. Each EE owns a set of DMAs, audio interfaces, and
interface groups, and receives its own independent interrupt output.
The interrupt hierarchy has a two-level structure: a summary register
identifies the event class (DMA period, underflow/overflow, error
response, audio interface underflow/overflow, group done, rate detector,
VFR), and per-resource status registers identify the specific channel.
Interface grouping (bonding) allows up to 6 groups of audio and codec
interfaces to start synchronously and align their DMA period interrupts
within half a frame duration using the RDDMA padding feature.
Two rate detector blocks measure the frequency of incoming frame sync or
word select signals and generate interrupts on rate change, undetected
rate, or sync timeout.
Block diagram::
System Memory (DDR / LPM / TCM)
+---------------------------------+
| Circular Buffers (ping-pong) |
+----------+----------+-----------+
| ^
64-bit AXI 64-bit AXI
| |
+----------v----------+-----------+
| QSB Master Ports |
| +----------+ +----------+ |
| | QXM0 | | QXM1 | |
| +----+-----+ +-----+----+ |
+-------|--------------|----------+
| |
+-------v--------------v----------+
| Shared RAM (SHRAM) |
| +------------+ +------------+ |
| | QXM0 Read | | QXM0 Write | |
| | SHRAM | | SHRAM | |
| +------------+ +------------+ |
| +------------+ +------------+ |
| | QXM1 Read | | QXM1 Write | |
| | SHRAM | | SHRAM | |
| +------------+ +------------+ |
+---+--------+--------+-------+---+
| | | |
+---v--+ +--v---+ +--v---+ +-v----+
|RDDMA | |RDDMA | |WRDMA | |WRDMA |
| AIF | | CIF | | AIF | | CIF |
|[0..n]| |[0..n]| |[0..n]| |[0..n]|
+--+---+ +--+---+ +--+---+ +-+----+
| | ^ ^
| TX | TX | RX | RX
v v | |
+--+--------------------+ +----+----------+
| Unified Audio Intf | | Codec DMA |
| (AIF 0..12) | | Interface |
| | | (CIF) |
| AUD_INTFa block: | | |
| - Serializer (TX) | | RDDMA: DDR -> |
| - De-serializer (RX) | | internal |
| - Sync gen/detect | | codec |
| - Up to 8 data lanes | | WRDMA: codec |
| - PCM / TDM / MI2S | | -> DDR |
| - Near Pad Logic | | Up to 16 ch |
+--+--------------------+ +----+----------+
| Lane 0..7 (TX/RX) | Parallel bus
| Bit clk + Frame sync | + Frame sync
v v
+--+--------+ +------+------+
| External | | Internal |
| Serial | | Digital |
| Peripherals| | Codec |
| (PCM/TDM/ | | (Bolero/ |
| MI2S) | | WCD) |
+-----------+ +-------------+
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: qcom,shikra-qaif-cpu
reg:
maxItems: 1
interrupts:
maxItems: 1
description:
QAIF summary interrupt for this Execution Engine.
iommus:
maxItems: 1
dma-coherent: true
clocks:
maxItems: 9
clock-names:
description:
Core clocks for register access and DMA, followed by one bit
clock per AIF interface.
items:
- const: lpass_config
- const: lpass_core_axim
- const: aud_dma
- const: aud_dma_mem
- const: bus
- const: aif_if0_ibit
- const: aif_if1_ibit
- const: aif_if2_ibit
- const: aif_if3_ibit
'#sound-dai-cells':
const: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
patternProperties:
'^aif@[0-9a-f]+$':
type: object
description:
QAIF AIF interface child node for PCM, TDM or MI2S configuration.
allOf:
- $ref: /schemas/sound/tdm-slot.yaml#
properties:
reg:
maxItems: 1
description:
DAI ID of the AIF interface (QAIF_MI2S_AIF* or QAIF_TDM_AIF*).
dai-format:
description: Serial audio interface format (MI2S, TDM or PCM).
enum: [i2s, dsp_a, dsp_b]
dai-tdm-slot-width:
enum: [8, 16, 24, 32]
dai-tdm-slot-num:
minimum: 1
maximum: 32
dai-tdm-slot-rx-mask:
minItems: 1
maxItems: 32
dai-tdm-slot-tx-mask:
minItems: 1
maxItems: 32
qcom,qaif-aif-lane-map:
$ref: /schemas/types.yaml#/definitions/uint32-array
description:
Per-lane direction map, one entry per lane starting from lane 0.
Use 0 for TX (output/speaker) and 1 for RX (input/mic).
minItems: 1
maxItems: 8
items:
enum: [0, 1]
required:
- reg
- dai-format
- qcom,qaif-aif-lane-map
if:
properties:
dai-format:
enum: [dsp_a, dsp_b]
then:
required:
- dai-tdm-slot-width
- dai-tdm-slot-num
- dai-tdm-slot-rx-mask
- dai-tdm-slot-tx-mask
unevaluatedProperties: false
required:
- compatible
- reg
- interrupts
- iommus
- clocks
- clock-names
- '#sound-dai-cells'
- '#address-cells'
- '#size-cells'
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
qaif_cpu: audio-controller@a000000 {
compatible = "qcom,shikra-qaif-cpu";
reg = <0x0 0x0a000000 0x0 0x20000>;
interrupts = <GIC_SPI 331 IRQ_TYPE_LEVEL_HIGH>;
iommus = <&apps_smmu 0x1c0 0x0>;
clocks = <&gcc 213>,
<&gcc 214>,
<&audiocorecc 15>,
<&audiocorecc 17>,
<&audiocorecc 18>,
<&audiocorecc 5>,
<&audiocorecc 8>,
<&audiocorecc 11>,
<&audiocorecc 14>;
clock-names = "lpass_config",
"lpass_core_axim",
"aud_dma",
"aud_dma_mem",
"bus",
"aif_if0_ibit",
"aif_if1_ibit",
"aif_if2_ibit",
"aif_if3_ibit";
#sound-dai-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
aif@b5 {
reg = <181>;
dai-format = "dsp_a";
dai-tdm-slot-width = <32>;
dai-tdm-slot-num = <2>;
dai-tdm-slot-rx-mask = <1 1>;
dai-tdm-slot-tx-mask = <1 1>;
qcom,qaif-aif-lane-map = <1 0>;
};
};
};

View File

@ -36,8 +36,10 @@ properties:
- ayaneo,pocket-s2-sndcard
- fairphone,fp4-sndcard
- fairphone,fp5-sndcard
- motorola,dubai-sndcard
- qcom,apq8096-sndcard
- qcom,glymur-sndcard
- qcom,nord-sndcard
- qcom,qcm6490-idp-sndcard
- qcom,qcs615-sndcard
- qcom,qcs6490-rb3gen2-sndcard
@ -54,6 +56,7 @@ properties:
- qcom,sm8250-sndcard
- qcom,sm8450-sndcard
- qcom,x1e80100-sndcard
- thundercomm,qcs6490-rubikpi3-sndcard
audio-routing:
$ref: /schemas/types.yaml#/definitions/non-unique-string-array

View File

@ -0,0 +1,105 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,wcd9378-sdw.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm WCD9378 (Tambora) SoundWire codec
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
description:
Qualcomm WCD9378 (Tambora) SoundWire codec. The same silicon can be
fused for a mobile (non-SDCA) mode or an SDCA-compliant mode; the
qcom,sdca-compliant property selects the latter and is required by
this driver.
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: sdw20217011000
reg:
maxItems: 1
qcom,sdca-compliant:
description:
Present when the codec is fused as SDCA-compliant. The mobile
(non-SDCA) variant carries the same class-ID compatible and is
handled by a different driver.
type: boolean
qcom,port-mapping:
description:
Each entry maps a slave data port to a master data port.
Entries are in order starting from slave port 1; slave port 0
is reserved and not represented. SDCA-compliant mode uses 8
entries covering DP1..DP8.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 8
maxItems: 8
reset-gpios:
description: GPIO used to release the codec from reset.
maxItems: 1
vdd-buck-supply:
description: 1.8 V analog buck supply.
vdd-rxtx-supply:
description: 1.8 V RX/TX supply.
vdd-io-supply:
description: Digital I/O supply.
vdd-mic-bias-supply:
description: Mic bias supply.
'#sound-dai-cells':
const: 1
required:
- compatible
- reg
- qcom,sdca-compliant
- qcom,port-mapping
- reset-gpios
- vdd-buck-supply
- vdd-rxtx-supply
- vdd-io-supply
- vdd-mic-bias-supply
- '#sound-dai-cells'
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
soundwire@7630000 {
reg = <0x07630000 0x10000>;
#address-cells = <2>;
#size-cells = <0>;
wcd9378c_sdw: audio-codec@0,3 {
compatible = "sdw20217011000";
reg = <0 3>;
qcom,sdca-compliant;
qcom,port-mapping = <2 2 3 4 5 6 7 8>;
reset-gpios = <&tlmm 191 GPIO_ACTIVE_LOW>;
vdd-buck-supply = <&vreg_l15b_1p8>;
vdd-rxtx-supply = <&vreg_l15b_1p8>;
vdd-io-supply = <&vreg_l18b_1p2>;
vdd-mic-bias-supply = <&vreg_bob1>;
#sound-dai-cells = <1>;
};
};
...

View File

@ -44,6 +44,14 @@ properties:
'#gpio-cells':
const: 2
clocks:
items:
- description: phandle and clock specifier for the codec MCLK1 input.
clock-names:
items:
- const: mclk1
realtek,pow-ldo2-gpio:
maxItems: 1
description: CODEC's POW_LDO2 pin.
@ -127,6 +135,8 @@ examples:
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
clocks = <&osc>;
clock-names = "mclk1";
realtek,pow-ldo2-gpio = <&gpio 3 GPIO_ACTIVE_HIGH>;
realtek,reset-gpio = <&gpio 3 GPIO_ACTIVE_LOW>;
realtek,in1-differential;

View File

@ -432,14 +432,14 @@ examples:
"ssi.1", "ssi.0";
rcar_sound,dvc {
dvc0: dvc-0 {
dmas = <&audma0 0xbc>;
dma-names = "tx";
};
dvc1: dvc-1 {
dmas = <&audma0 0xbe>;
dma-names = "tx";
};
dvc0: dvc-0 {
dmas = <&audma0 0xbc>;
dma-names = "tx";
};
dvc1: dvc-1 {
dmas = <&audma0 0xbe>;
dma-names = "tx";
};
};
rcar_sound,mix {

View File

@ -95,20 +95,20 @@ examples:
ssi0: ssi@10049c00 {
compatible = "renesas,r9a07g044-ssi",
"renesas,rz-ssi";
reg = <0x10049c00 0x400>;
interrupts = <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 327 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 328 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "int_req", "dma_rx", "dma_tx";
clocks = <&cpg CPG_MOD R9A07G044_SSI0_PCLK2>,
<&cpg CPG_MOD R9A07G044_SSI0_PCLK_SFR>,
<&audio_clk1>,
<&audio_clk2>;
clock-names = "ssi", "ssi_sfr", "audio_clk1", "audio_clk2";
power-domains = <&cpg>;
resets = <&cpg R9A07G044_SSI0_RST_M2_REG>;
dmas = <&dmac 0x2655>,
<&dmac 0x2656>;
dma-names = "tx", "rx";
#sound-dai-cells = <0>;
reg = <0x10049c00 0x400>;
interrupts = <GIC_SPI 326 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 327 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 328 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "int_req", "dma_rx", "dma_tx";
clocks = <&cpg CPG_MOD R9A07G044_SSI0_PCLK2>,
<&cpg CPG_MOD R9A07G044_SSI0_PCLK_SFR>,
<&audio_clk1>,
<&audio_clk2>;
clock-names = "ssi", "ssi_sfr", "audio_clk1", "audio_clk2";
power-domains = <&cpg>;
resets = <&cpg R9A07G044_SSI0_RST_M2_REG>;
dmas = <&dmac 0x2655>,
<&dmac 0x2656>;
dma-names = "tx", "rx";
#sound-dai-cells = <0>;
};

View File

@ -0,0 +1,96 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/stericsson,ux500-msp-i2s.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ST-Ericsson Ux500 Multichannel Serial Port
maintainers:
- Linus Walleij <linusw@kernel.org>
description:
The Ux500 Multichannel Serial Port (MSP) is a synchronous serial audio
interface supporting I2S and PCM/TDM protocols. Data is transferred to and
from memory using the Ux500 DMA controller.
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
const: stericsson,ux500-msp-i2s
reg:
maxItems: 1
interrupts:
maxItems: 1
v-ape-supply:
description: Analog power engine supply
dmas:
minItems: 1
maxItems: 2
dma-names:
minItems: 1
maxItems: 2
items:
enum: [ rx, tx ]
clocks:
items:
- description: MSP functional clock
- description: MSP APB bus clock
clock-names:
items:
- const: msp
- const: apb_pclk
resets:
maxItems: 1
'#sound-dai-cells':
const: 0
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- reg
- interrupts
- v-ape-supply
- dmas
- dma-names
- clocks
- clock-names
- resets
- '#sound-dai-cells'
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/reset/stericsson,db8500-prcc-reset.h>
msp@80123000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80123000 0x1000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
v-ape-supply = <&db8500_vape_reg>;
dmas = <&dma 31 0 0x12>, <&dma 31 0 0x10>;
dma-names = "rx", "tx";
clocks = <&prcc_kclk 1 3>, <&prcc_pclk 1 3>;
clock-names = "msp", "apb_pclk";
resets = <&prcc_reset DB8500_PRCC_1 DB8500_PRCC_1_RESET_MSP0>;
#sound-dai-cells = <0>;
};
...

View File

@ -0,0 +1,83 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,da830-evm-audio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments SoC audio setups with TLV320AIC3X Codec
maintainers:
- Eduard Bostina <egbostina@gmail.com>
properties:
compatible:
const: ti,da830-evm-audio
ti,model:
$ref: /schemas/types.yaml#/definitions/string
description: The user-visible name of this sound complex.
ti,audio-codec:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the TLV320AIC3x audio codec
ti,mcasp-controller:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the McASP controller
ti,audio-routing:
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
description:
A list of the connections between audio components. Each entry is a
pair of strings, the first being the connection's sink, the second
being the connection's source. Valid names for sources and sinks
are the codec's pins, and the jacks on the board (Headphone Jack,
Line Out, Mic Jack, Line In).
ti,codec-clock-rate:
$ref: /schemas/types.yaml#/definitions/uint32
description: The Codec Clock rate (in Hz) applied to the Codec.
clocks:
maxItems: 1
description: Reference to the master clock
clock-names:
const: mclk
required:
- compatible
- ti,model
- ti,audio-codec
- ti,mcasp-controller
- ti,audio-routing
anyOf:
- required:
- ti,codec-clock-rate
- required:
- clocks
additionalProperties: false
examples:
- |
sound {
compatible = "ti,da830-evm-audio";
ti,model = "DA830 EVM";
ti,audio-codec = <&tlv320aic3x>;
ti,mcasp-controller = <&mcasp1>;
ti,codec-clock-rate = <12000000>;
ti,audio-routing =
"Headphone Jack", "HPLOUT",
"Headphone Jack", "HPROUT",
"Line Out", "LLOUT",
"Line Out", "RLOUT",
"MIC3L", "Mic Bias 2V",
"MIC3R", "Mic Bias 2V",
"Mic Bias 2V", "Mic Jack",
"LINE1L", "Line In",
"LINE2L", "Line In",
"LINE1R", "Line In",
"LINE2R", "Line In";
};

View File

@ -21,6 +21,22 @@ properties:
reg:
maxItems: 1
clocks:
maxItems: 1
description: System clock (SCK)
clock-names:
const: sck
VCC1-supply:
description: 5V analog power supply
VCC2-supply:
description: 5V analog power supply
VDD-supply:
description: 3.3V digital power supply
"#sound-dai-cells":
const: 0

View File

@ -219,9 +219,7 @@ allOf:
- if:
properties:
compatible:
contains:
enum:
- ti,tas2781
const: ti,tas2781
then:
properties:
reg:

View File

@ -45,13 +45,13 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
tas5805m: tas5805m@2c {
reg = <0x2c>;
compatible = "ti,tas5805m";
reg = <0x2c>;
compatible = "ti,tas5805m";
pvdd-supply = <&audiopwr>;
pdn-gpios = <&tlmm 160 0>;
pvdd-supply = <&audiopwr>;
pdn-gpios = <&tlmm 160 0>;
ti,dsp-config-name = "mono_pbtl_48khz";
ti,dsp-config-name = "mono_pbtl_48khz";
};
};
...

View File

@ -121,6 +121,6 @@ examples:
AVDD-supply = <&regulator>;
IOVDD-supply = <&regulator>;
DVDD-supply = <&regulator>;
};
};
};

View File

@ -50,6 +50,6 @@ examples:
reg = <0x60>;
Vdd-supply = <&vmmc2>;
power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>;
};
};
};

View File

@ -1,39 +0,0 @@
* MOP500 Audio Machine Driver
This node is responsible for linking together all ux500 Audio Driver components.
Required properties:
- compatible : "stericsson,snd-soc-mop500"
Non-standard properties:
- stericsson,cpu-dai : Phandle to the CPU-side DAI
- stericsson,audio-codec : Phandle to the Audio CODEC
- stericsson,card-name : Over-ride default card name
Example:
sound {
compatible = "stericsson,snd-soc-mop500";
stericsson,cpu-dai = <&msp1 &msp3>;
stericsson,audio-codec = <&codec>;
};
msp1: msp@80124000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80124000 0x1000>;
interrupts = <0 62 0x4>;
v-ape-supply = <&db8500_vape_reg>;
};
msp3: msp@80125000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80125000 0x1000>;
interrupts = <0 62 0x4>;
v-ape-supply = <&db8500_vape_reg>;
};
codec: ab8500-codec {
compatible = "stericsson,ab8500-codec";
stericsson,earpeice-cmv = <950>; /* Units in mV. */
};

View File

@ -1,42 +0,0 @@
* ux500 MSP (CPU-side Digital Audio Interface)
Required properties:
- compatible :"stericsson,ux500-msp-i2s"
- reg : Physical base address and length of the device's registers.
Optional properties:
- interrupts : The interrupt output from the device.
- <name>-supply : Phandle to the regulator <name> supply
Example:
sound {
compatible = "stericsson,snd-soc-mop500";
stericsson,platform-pcm-dma = <&pcm>;
stericsson,cpu-dai = <&msp1 &msp3>;
stericsson,audio-codec = <&codec>;
};
pcm: ux500-pcm {
compatible = "stericsson,ux500-pcm";
};
msp1: msp@80124000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80124000 0x1000>;
interrupts = <0 62 0x4>;
v-ape-supply = <&db8500_vape_reg>;
};
msp3: msp@80125000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80125000 0x1000>;
interrupts = <0 62 0x4>;
v-ape-supply = <&db8500_vape_reg>;
};
codec: ab8500-codec {
compatible = "stericsson,ab8500-codec";
stericsson,earpeice-cmv = <950>; /* Units in mV. */
};

View File

@ -11,12 +11,11 @@ maintainers:
- Xianwei Zhao <xianwei.zhao@amlogic.com>
- Sunny Luo <sunny.luo@amlogic.com>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
const: amlogic,a4-spisg
enum:
- amlogic,a4-spisg
- amlogic,a9-spisg
reg:
maxItems: 1
@ -35,6 +34,16 @@ properties:
resets:
maxItems: 1
amlogic,mo-idle-output:
description: |
Controls the MOSI output level when the controller is idle.
0 - Drive MOSI low
1 - Drive MOSI high
2 - Follow the last transmitted bit
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2]
default: 0
required:
- compatible
- reg
@ -42,6 +51,19 @@ required:
- clocks
- clock-names
allOf:
- $ref: spi-controller.yaml#
- if:
not:
properties:
compatible:
contains:
enum:
- amlogic,a9-spisg
then:
properties:
amlogic,mo-idle-output: false
unevaluatedProperties: false
examples:

View File

@ -16,10 +16,15 @@ description: |
properties:
compatible:
enum:
- amlogic,meson-gx-spicc # SPICC controller on Amlogic GX and compatible SoCs
- amlogic,meson-axg-spicc # SPICC controller on Amlogic AXG and compatible SoCs
- amlogic,meson-g12a-spicc # SPICC controller on Amlogic G12A and compatible SoCs
oneOf:
- items:
- enum:
- amlogic,t7-spicc
- const: amlogic,meson-g12a-spicc
- enum:
- amlogic,meson-gx-spicc # SPICC controller on Amlogic GX and compatible SoCs
- amlogic,meson-axg-spicc # SPICC controller on Amlogic AXG and compatible SoCs
- amlogic,meson-g12a-spicc # SPICC controller on Amlogic G12A and compatible SoCs
interrupts:
maxItems: 1

View File

@ -0,0 +1,82 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/microchip,pic32mzda-spi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip PIC32MZDA SPI Controller
maintainers:
- Thomas Bogendoerfer <tsbogend@alpha.franken.de>
allOf:
- $ref: spi-controller.yaml#
properties:
compatible:
const: microchip,pic32mzda-spi
reg:
maxItems: 1
interrupts:
items:
- description: Fault interrupt
- description: Receive interrupt
- description: Transmit interrupt
interrupt-names:
items:
- const: fault
- const: rx
- const: tx
clocks:
maxItems: 1
clock-names:
items:
- const: mck0
cs-gpios:
maxItems: 1
dmas:
items:
- description: RX DMA channel
- description: TX DMA channel
dma-names:
items:
- const: spi-rx
- const: spi-tx
required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
- clock-names
- cs-gpios
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
spi@1f821000 {
compatible = "microchip,pic32mzda-spi";
reg = <0x1f821000 0x200>;
interrupts = <109 IRQ_TYPE_LEVEL_HIGH>,
<110 IRQ_TYPE_LEVEL_HIGH>,
<111 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "fault", "rx", "tx";
clocks = <&PBCLK2>;
clock-names = "mck0";
cs-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;
dmas = <&dma 134>, <&dma 135>;
dma-names = "spi-rx", "spi-tx";
};

View File

@ -1,34 +0,0 @@
Microchip PIC32 SPI Master controller
Required properties:
- compatible: Should be "microchip,pic32mzda-spi".
- reg: Address and length of register space for the device.
- interrupts: Should contain all three spi interrupts in sequence
of <fault-irq>, <receive-irq>, <transmit-irq>.
- interrupt-names: Should be "fault", "rx", "tx" in order.
- clocks: Phandle of the clock generating SPI clock on the bus.
- clock-names: Should be "mck0".
- cs-gpios: Specifies the gpio pins to be used for chipselects.
See: Documentation/devicetree/bindings/spi/spi-bus.txt
Optional properties:
- dmas: Two or more DMA channel specifiers following the convention outlined
in Documentation/devicetree/bindings/dma/dma.txt
- dma-names: Names for the dma channels. There must be at least one channel
named "spi-tx" for transmit and named "spi-rx" for receive.
Example:
spi1: spi@1f821000 {
compatible = "microchip,pic32mzda-spi";
reg = <0x1f821000 0x200>;
interrupts = <109 IRQ_TYPE_LEVEL_HIGH>,
<110 IRQ_TYPE_LEVEL_HIGH>,
<111 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "fault", "rx", "tx";
clocks = <&PBCLK2>;
clock-names = "mck0";
cs-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;
dmas = <&dma 134>, <&dma 135>;
dma-names = "spi-rx", "spi-tx";
};

View File

@ -0,0 +1,65 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/spi/realtek,rtd1625-nor.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek RTD1625 SPI NOR Flash Controller
maintainers:
- Jyan Chou <jyanchou@realtek.com>
- Yu-Chun Lin <eleanor.lin@realtek.com>
properties:
compatible:
enum:
- realtek,rtd1625-nor
reg:
maxItems: 3
reg-names:
items:
- const: ctrl
- const: dma
- const: dirmap
clocks:
maxItems: 1
resets:
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 0
required:
- compatible
- reg
- reg-names
- clocks
- resets
- "#address-cells"
- "#size-cells"
allOf:
- $ref: /schemas/spi/spi-controller.yaml#
unevaluatedProperties: false
examples:
- |
spi@14b000 {
compatible = "realtek,rtd1625-nor";
reg = <0x14b000 0x50>, <0x14bf00 0x30>, <0x88100000 0x2000000>;
reg-names = "ctrl", "dma", "dirmap";
clocks = <&cc 18>;
resets = <&cc 26>;
pinctrl-0 = <&spi_pins>;
pinctrl-names = "default";
#address-cells = <1>;
#size-cells = <0>;
};

View File

@ -54,6 +54,11 @@ properties:
- renesas,msiof-r8a779h0 # R-Car V4M
- const: renesas,rcar-gen4-msiof # generic R-Car Gen4
# compatible device
- items:
- enum:
- renesas,msiof-r8a78000 # R-Car X5H
- const: renesas,rcar-gen5-msiof # generic R-Car Gen5
# compatible device
- items:
- const: renesas,sh-msiof # deprecated
@ -100,11 +105,11 @@ properties:
dmas:
minItems: 2
maxItems: 4
maxItems: 6
dma-names:
minItems: 2
maxItems: 4
maxItems: 6
items:
enum: [ tx, rx ]

View File

@ -91,6 +91,14 @@ properties:
The delay from the default sample time before the actual
sample of the rxd input signal occurs.
This describes the board rather than the peripheral, namely the extra
delay this particular design needs, for example because of the flight time
of the clock and data signals between controller and peripheral.
Timing parameters of the peripheral itself, such as its
clock-to-output-valid time, are the same on every board using that chip
and should be described with the chip.
spi-tx-bus-width:
description:
Bus width to the SPI bus used for write transfers.

View File

@ -559,6 +559,8 @@ patternProperties:
description: Seiko Epson Corp.
"^esp,.*":
description: Espressif Systems Co. Ltd.
"^esstech,.*":
description: ESS Technology, Inc.
"^est,.*":
description: ESTeem Wireless Modems
"^eswin,.*":

View File

@ -460,8 +460,6 @@ SPI
devm_spi_alloc_target()
devm_spi_optimize_message()
devm_spi_register_controller()
devm_spi_register_host()
devm_spi_register_target()
WATCHDOG
devm_watchdog_register_device()

View File

@ -127,7 +127,7 @@ field to indicate which mode they want to use for a given transfer.
The possible values for this field have the following semantics:
- :c:macro:`SPI_MULTI_BUS_MODE_SINGLE`: Only use the first lane. Other lanes are
- :c:macro:`SPI_MULTI_LANE_MODE_SINGLE`: Only use the first lane. Other lanes are
ignored. This means that it is operating just like a conventional SPI
peripheral. This is the default, so it does not need to be explicitly set.
@ -149,7 +149,7 @@ The possible values for this field have the following semantics:
---------- ---------------- ----------
SDO 0 0-0-0-1-0-0-0-1 SDI 0
- :c:macro:`SPI_MULTI_BUS_MODE_MIRROR`: Send a single data word over all of the
- :c:macro:`SPI_MULTI_LANE_MODE_MIRROR`: Send a single data word over all of the
lanes at the same time. This only makes sense for writes and not
for reads.
@ -160,7 +160,7 @@ The possible values for this field have the following semantics:
struct spi_transfer xfer = {
.tx_buf = tx_buf,
.len = 1,
.multi_lane_mode = SPI_MULTI_BUS_MODE_MIRROR,
.multi_lane_mode = SPI_MULTI_LANE_MODE_MIRROR,
};
spi_sync_transfer(spi, &xfer, 1);
@ -172,7 +172,7 @@ The possible values for this field have the following semantics:
SDO 0 0-0-0-1-0-0-0-1 SDI 0
SDO 1 0-0-0-1-0-0-0-1 SDI 1
- :c:macro:`SPI_MULTI_BUS_MODE_STRIPE`: Send or receive two different data words
- :c:macro:`SPI_MULTI_LANE_MODE_STRIPE`: Send or receive two different data words
at the same time, one on each lane. This means that the buffer needs to be
sized to hold data for all lanes. Data is interleaved in the buffer, with
the first word corresponding to lane 0, the second to lane 1, and so on.
@ -185,7 +185,7 @@ The possible values for this field have the following semantics:
struct spi_transfer xfer = {
.rx_buf = rx_buf,
.len = 2,
.multi_lane_mode = SPI_MULTI_BUS_MODE_STRIPE,
.multi_lane_mode = SPI_MULTI_LANE_MODE_STRIPE,
};
spi_sync_transfer(spi, &xfer, 1);

View File

@ -767,6 +767,14 @@ F: Documentation/devicetree/bindings/phy/airoha,en7581-pcie-phy.yaml
F: drivers/phy/phy-airoha-pcie-regs.h
F: drivers/phy/phy-airoha-pcie.c
AIROHA SOUND DRIVER
M: Christian Marangi <ansuelsmth@gmail.com>
L: linux-sound@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/sound/airoha,an7581-afe.yaml
F: Documentation/devicetree/bindings/sound/airoha,an7581-wm8960.yaml
F: sound/soc/mediatek/an7581/*
AIROHA SPI SNFI DRIVER
M: Lorenzo Bianconi <lorenzo@kernel.org>
M: Ray Liu <ray.liu@airoha.com>
@ -9715,6 +9723,13 @@ S: Maintained
F: include/linux/errseq.h
F: lib/errseq.c
ES9039Q2M AUDIO CODEC DRIVER
M: Karl Asseily <karl@asseily.com>
L: linux-sound@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/sound/esstech,es9039q2m.yaml
F: sound/soc/codecs/es9039q2m.c
ESD CAN NETWORK DRIVERS
M: Stefan Mätje <stefan.maetje@esd.eu>
R: socketcan@esd.eu
@ -22150,6 +22165,15 @@ F: sound/soc/codecs/wcd93*.*
F: sound/soc/codecs/wsa88*.*
F: sound/soc/qcom/
QCOM AUDIO INTERFACE (QAIF) DRIVER
M: Harendra Gautam <harendra.gautam@oss.qualcomm.com>
M: Srinivas Kandagatla <srini@kernel.org>
L: linux-sound@vger.kernel.org
L: linux-arm-msm@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/sound/qcom,shikra-qaif-cpu.yaml
F: sound/soc/qcom/qaif*
QCOM EMBEDDED USB DEBUGGER (EUD)
M: Souradeep Chowdhury <quic_schowdhu@quicinc.com>
L: linux-arm-msm@vger.kernel.org
@ -23037,6 +23061,12 @@ S: Maintained
F: Documentation/devicetree/bindings/spi/realtek,rtl9301-snand.yaml
F: drivers/spi/spi-realtek-rtl-snand.c
REALTEK SPI-NOR
M: Jyan Chou <jyanchou@realtek.com>
M: Yu-Chun Lin <eleanor.lin@realtek.com>
S: Supported
F: drivers/spi/spi-rtk-nor.c
REALTEK SYSTIMER DRIVER
M: Hao-Wen Ting <haowen.ting@realtek.com>
S: Maintained
@ -30218,9 +30248,12 @@ F: tools/testing/selftests/cgroup/test_zswap.c
SENARYTECH AUDIO CODEC DRIVER
M: bo liu <bo.liu@senarytech.com>
M: qianghua.wang <qianghua.wang@senarytech.com>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
F: sound/hda/codecs/senarytech.c
F: sound/soc/codecs/sn624x*
F: sound/soc/sdw_utils/soc_sdw_senary*
ZTE DINGHAI ETHERNET DRIVER
M: Junyang Han <han.junyang@zte.com.cn>

View File

@ -322,6 +322,7 @@ static inline unsigned int regcache_get_index_by_order(const struct regmap *map,
}
struct regmap_ram_data {
unsigned int base_reg;
unsigned int *vals; /* Allocatd by caller */
bool *read;
bool *written;

View File

@ -963,7 +963,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
return 0;
err_domain:
/* Should really dispose of the domain but... */
irq_domain_remove(d->domain);
err_mutex:
mutex_destroy(&d->lock);
lockdep_unregister_key(&d->lock_key);

View File

@ -11,6 +11,8 @@
#define BLOCK_TEST_SIZE 12
#define HIGH_BIT_REG ((UINT_MAX / 2) - 3)
KUNIT_DEFINE_ACTION_WRAPPER(regmap_exit_action, regmap_exit, struct regmap *);
struct regmap_test_priv {
@ -23,6 +25,7 @@ struct regmap_test_param {
enum regcache_type cache;
enum regmap_endian val_endian;
unsigned int base_reg;
unsigned int from_reg;
bool fast_io;
};
@ -204,7 +207,8 @@ static struct regmap *gen_regmap(struct kunit *test,
config->max_register += (BLOCK_TEST_SIZE * config->reg_stride);
}
size = array_size(config->max_register + 1, sizeof(*buf));
size = array_size(config->max_register - param->base_reg + 1,
sizeof(*buf));
buf = kmalloc(size, GFP_KERNEL);
if (!buf)
return ERR_PTR(-ENOMEM);
@ -215,6 +219,7 @@ static struct regmap *gen_regmap(struct kunit *test,
if (!(*data))
goto out_free;
(*data)->vals = buf;
(*data)->base_reg = param->base_reg;
if (config->num_reg_defaults) {
defaults = kunit_kcalloc(test,
@ -227,8 +232,8 @@ static struct regmap *gen_regmap(struct kunit *test,
config->reg_defaults = defaults;
for (i = 0; i < config->num_reg_defaults; i++) {
defaults[i].reg = param->from_reg + (i * config->reg_stride);
defaults[i].def = buf[param->from_reg + (i * config->reg_stride)];
defaults[i].reg = param->from_reg - param->base_reg + (i * config->reg_stride);
defaults[i].def = buf[param->from_reg - param->base_reg + (i * config->reg_stride)];
}
}
@ -1648,6 +1653,92 @@ static void cache_write_zero(struct kunit *test)
KUNIT_ASSERT_FALSE(test, regcache_reg_cached(map, 1));
}
static const struct regmap_test_param high_bit_cache_types_list[] = {
{ .cache = REGCACHE_RBTREE, .from_reg = HIGH_BIT_REG,
.base_reg = HIGH_BIT_REG },
{ .cache = REGCACHE_MAPLE, .from_reg = HIGH_BIT_REG,
.base_reg = HIGH_BIT_REG },
};
KUNIT_ARRAY_PARAM(high_bit_cache_types, high_bit_cache_types_list, param_to_desc);
/*
* Dynamically allocated cache types should support registers with the
* high bit set, the backend will return an error for any operation on
* a register below the expected window.
*/
static void cache_high_bit_reg(struct kunit *test)
{
const struct regmap_test_param *param = test->param_value;
struct regmap_ram_data *data;
struct regmap_config config;
struct regmap *map;
unsigned int val[BLOCK_TEST_SIZE], rval;
int i;
config = test_regmap_config;
map = gen_regmap(test, &config, &data);
KUNIT_ASSERT_FALSE(test, IS_ERR(map));
if (IS_ERR(map))
return;
get_random_bytes(&val, sizeof(val));
/* No defaults so no registers cached */
for (i = 0; i < BLOCK_TEST_SIZE; i++)
KUNIT_EXPECT_FALSE(test, regcache_reg_cached(map, param->from_reg + i));
/* Writes should reach the device */
for (i = 0; i < BLOCK_TEST_SIZE; i++)
KUNIT_EXPECT_EQ(test, 0, regmap_write(map, param->from_reg + i,
val[i]));
for (i = 0; i < BLOCK_TEST_SIZE; i++) {
KUNIT_EXPECT_TRUE(test, data->written[i]);
KUNIT_EXPECT_EQ(test, val[i], data->vals[i]);
}
/* Reads should be satisfied from the cache */
for (i = 0; i < BLOCK_TEST_SIZE; i++) {
KUNIT_EXPECT_TRUE(test, regcache_reg_cached(map, param->from_reg + i));
KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg + i,
&rval));
KUNIT_EXPECT_EQ(test, val[i], rval);
KUNIT_EXPECT_FALSE(test, data->read[i]);
}
/* Trash the data on the device then resync */
regcache_mark_dirty(map);
for (i = 0; i < BLOCK_TEST_SIZE; i++) {
data->vals[i] = 0;
data->written[i] = false;
}
KUNIT_EXPECT_EQ(test, 0, regcache_sync(map));
/* Did we just write the correct data out? */
for (i = 0; i < BLOCK_TEST_SIZE; i++) {
KUNIT_EXPECT_TRUE(test, data->written[i]);
KUNIT_EXPECT_EQ(test, val[i], data->vals[i]);
}
/* Drop some registers */
KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, param->from_reg + 3,
param->from_reg + 5));
for (i = 0; i < BLOCK_TEST_SIZE; i++)
KUNIT_EXPECT_EQ(test, i < 3 || i > 5,
regcache_reg_cached(map, param->from_reg + i));
/* Reread and check only the dropped registers hit the device */
for (i = 0; i < BLOCK_TEST_SIZE; i++)
data->read[i] = false;
for (i = 0; i < BLOCK_TEST_SIZE; i++) {
KUNIT_EXPECT_EQ(test, 0, regmap_read(map, param->from_reg + i,
&rval));
KUNIT_EXPECT_EQ(test, val[i], rval);
KUNIT_EXPECT_EQ(test, i >= 3 && i <= 5, data->read[i]);
}
}
/* Check that caching the window register works with sync */
static void cache_range_window_reg(struct kunit *test)
{
@ -2168,6 +2259,7 @@ static struct kunit_case regmap_test_cases[] = {
KUNIT_CASE_PARAM(cache_drop_all_and_sync_has_defaults, sparse_cache_types_gen_params),
KUNIT_CASE_PARAM(cache_present, sparse_cache_types_gen_params),
KUNIT_CASE_PARAM(cache_write_zero, sparse_cache_types_gen_params),
KUNIT_CASE_PARAM(cache_high_bit_reg, high_bit_cache_types_gen_params),
KUNIT_CASE_PARAM(cache_range_window_reg, real_cache_types_only_gen_params),
KUNIT_CASE_PARAM(raw_read_defaults_single, raw_test_types_gen_params),

View File

@ -20,8 +20,11 @@ static int regmap_ram_write(void *context, unsigned int reg, unsigned int val)
{
struct regmap_ram_data *data = context;
data->vals[reg] = val;
data->written[reg] = true;
if (reg < data->base_reg)
return -EINVAL;
data->vals[reg - data->base_reg] = val;
data->written[reg - data->base_reg] = true;
return 0;
}
@ -30,8 +33,11 @@ static int regmap_ram_read(void *context, unsigned int reg, unsigned int *val)
{
struct regmap_ram_data *data = context;
*val = data->vals[reg];
data->read[reg] = true;
if (reg < data->base_reg)
return -EINVAL;
*val = data->vals[reg - data->base_reg];
data->read[reg - data->base_reg] = true;
return 0;
}
@ -60,17 +66,25 @@ struct regmap *__regmap_init_ram(struct device *dev,
const char *lock_name)
{
struct regmap *map;
unsigned int num_regs;
if (!config->max_register) {
pr_crit("No max_register specified for RAM regmap\n");
return ERR_PTR(-EINVAL);
}
data->read = kzalloc_objs(bool, config->max_register + 1);
if (data->base_reg > config->max_register) {
pr_crit("base_reg above max_register for RAM regmap\n");
return ERR_PTR(-EINVAL);
}
num_regs = config->max_register - data->base_reg + 1;
data->read = kzalloc_objs(bool, num_regs);
if (!data->read)
return ERR_PTR(-ENOMEM);
data->written = kzalloc_objs(bool, config->max_register + 1);
data->written = kzalloc_objs(bool, num_regs);
if (!data->written) {
kfree(data->read);
return ERR_PTR(-ENOMEM);

View File

@ -16,14 +16,17 @@
#include "internal.h"
static unsigned int decode_reg(enum regmap_endian endian, const void *reg)
static unsigned int decode_reg(struct regmap_ram_data *data, const void *reg)
{
const u16 *r = reg;
unsigned int decode;
if (endian == REGMAP_ENDIAN_BIG)
return be16_to_cpu(*r);
if (data->reg_endian == REGMAP_ENDIAN_BIG)
decode = be16_to_cpu(*r);
else
return le16_to_cpu(*r);
decode = le16_to_cpu(*r);
return decode - data->base_reg;
}
static int regmap_raw_ram_gather_write(void *context,
@ -40,7 +43,7 @@ static int regmap_raw_ram_gather_write(void *context,
if (val_len % 2)
return -EINVAL;
r = decode_reg(data->reg_endian, reg);
r = decode_reg(data, reg);
if (data->noinc_reg && data->noinc_reg(data, r)) {
memcpy(&our_buf[r], val + val_len - 2, 2);
data->written[r] = true;
@ -74,7 +77,7 @@ static int regmap_raw_ram_read(void *context,
if (val_len % 2)
return -EINVAL;
r = decode_reg(data->reg_endian, reg);
r = decode_reg(data, reg);
if (data->noinc_reg && data->noinc_reg(data, r)) {
for (i = 0; i < val_len; i += 2)
memcpy(val + i, &our_buf[r], 2);
@ -114,6 +117,7 @@ struct regmap *__regmap_init_raw_ram(struct device *dev,
const char *lock_name)
{
struct regmap *map;
unsigned int regs;
if (config->reg_bits != 16)
return ERR_PTR(-EINVAL);
@ -123,11 +127,12 @@ struct regmap *__regmap_init_raw_ram(struct device *dev,
return ERR_PTR(-EINVAL);
}
data->read = kzalloc_objs(bool, config->max_register + 1);
regs = config->max_register - data->base_reg + 1;
data->read = kzalloc_objs(bool, regs);
if (!data->read)
return ERR_PTR(-ENOMEM);
data->written = kzalloc_objs(bool, config->max_register + 1);
data->written = kzalloc_objs(bool, regs);
if (!data->written)
return ERR_PTR(-ENOMEM);

View File

@ -2722,7 +2722,7 @@ EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed);
* If supported by the underlying bus the write will be scheduled
* asynchronously, helping maximise I/O speed on higher speed buses
* like SPI. regmap_async_complete() can be called to ensure that all
* asynchrnous writes have been completed.
* asynchronous writes have been completed.
*
* A value of zero will be returned on success, a negative errno will
* be returned in error cases.

View File

@ -2960,6 +2960,8 @@ int cs_dsp_run(struct cs_dsp *dsp)
return 0;
err:
dsp->running = false;
if (dsp->ops->stop_core)
dsp->ops->stop_core(dsp);
if (dsp->ops->disable_core)
@ -3505,7 +3507,7 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_write, "FW_CS_DSP");
*
* As cs_dsp_chunk_write only writes data when a whole DSP word is ready to
* be written out it is possible that some data will remain in the cache, this
* function will pad that data with zeros upto a whole DSP word and write out.
* function will pad that data with zeros up to a whole DSP word and write out.
*
* Return: Zero for success, a negative number on error.
*/

View File

@ -36,6 +36,8 @@ struct cs_dsp_test_local {
int num_post_stop;
int num_watchdog_expired;
bool fail_post_run;
struct cs_dsp_coeff_ctl *passed_ctl[16];
struct cs_dsp *passed_dsp;
};
@ -106,6 +108,9 @@ static int cs_dsp_test_post_run_callback(struct cs_dsp *dsp)
local->passed_dsp = dsp;
local->num_post_run++;
if (local->fail_post_run)
return -EIO;
return 0;
}
@ -198,6 +203,33 @@ static void cs_dsp_test_run_stop_callbacks(struct kunit *test)
local->passed_dsp = NULL;
}
static void cs_dsp_test_run_error_clears_running(struct kunit *test)
{
struct cs_dsp_test *priv = test->priv;
struct cs_dsp_test_local *local = priv->local;
struct firmware *wmfw;
wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
0);
/*
* By the time the post_run hook runs, the core has been started. A
* failure there stops and disables the core again, so the DSP must not
* be left looking like it is running.
*/
local->fail_post_run = true;
KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), -EIO);
KUNIT_EXPECT_FALSE(test, priv->dsp->running);
/* and the next run must be able to start it again */
local->fail_post_run = false;
KUNIT_EXPECT_EQ(test, cs_dsp_run(priv->dsp), 0);
KUNIT_EXPECT_TRUE(test, priv->dsp->running);
}
static void cs_dsp_test_ctl_v1_callbacks(struct kunit *test)
{
struct cs_dsp_test *priv = test->priv;
@ -609,6 +641,7 @@ KUNIT_ARRAY_PARAM(cs_dsp_no_callbacks,
static struct kunit_case cs_dsp_callbacks_adsp2_wmfwv1_test_cases[] = {
KUNIT_CASE_PARAM(cs_dsp_test_run_stop_callbacks, cs_dsp_callbacks_ops_gen_params),
KUNIT_CASE_PARAM(cs_dsp_test_run_error_clears_running, cs_dsp_callbacks_ops_gen_params),
KUNIT_CASE_PARAM(cs_dsp_test_ctl_v1_callbacks, cs_dsp_callbacks_ops_gen_params),
KUNIT_CASE_PARAM(cs_dsp_test_no_callbacks, cs_dsp_no_callbacks_gen_params),
@ -617,6 +650,7 @@ static struct kunit_case cs_dsp_callbacks_adsp2_wmfwv1_test_cases[] = {
static struct kunit_case cs_dsp_callbacks_adsp2_wmfwv2_test_cases[] = {
KUNIT_CASE_PARAM(cs_dsp_test_run_stop_callbacks, cs_dsp_callbacks_ops_gen_params),
KUNIT_CASE_PARAM(cs_dsp_test_run_error_clears_running, cs_dsp_callbacks_ops_gen_params),
KUNIT_CASE_PARAM(cs_dsp_test_ctl_v2_callbacks, cs_dsp_callbacks_ops_gen_params),
KUNIT_CASE_PARAM(cs_dsp_test_no_callbacks, cs_dsp_no_callbacks_gen_params),
@ -625,6 +659,7 @@ static struct kunit_case cs_dsp_callbacks_adsp2_wmfwv2_test_cases[] = {
static struct kunit_case cs_dsp_callbacks_halo_test_cases[] = {
KUNIT_CASE_PARAM(cs_dsp_test_run_stop_callbacks, cs_dsp_callbacks_ops_gen_params),
KUNIT_CASE_PARAM(cs_dsp_test_run_error_clears_running, cs_dsp_callbacks_ops_gen_params),
KUNIT_CASE_PARAM(cs_dsp_test_ctl_v2_callbacks, cs_dsp_callbacks_ops_gen_params),
KUNIT_CASE_PARAM(cs_dsp_test_no_callbacks, cs_dsp_no_callbacks_gen_params),

View File

@ -1458,11 +1458,15 @@ static int fmh_gpib_attach_impl(struct gpib_board *board, const struct gpib_boar
e_priv->irq = irq;
if (acquire_dma) {
e_priv->dma_channel = dma_request_slave_channel(board->dev, "rxtx");
if (!e_priv->dma_channel) {
struct dma_chan *tmp_chan;
tmp_chan = dma_request_chan(board->dev, "rxtx");
retval = PTR_ERR_OR_ZERO(tmp_chan);
if (retval) {
dev_err(board->dev, "failed to acquire dma channel \"rxtx\".\n");
return -EIO;
return retval;
}
e_priv->dma_channel = tmp_chan;
}
/*
* in the future we might want to know the half-fifo size

View File

@ -63,7 +63,6 @@ comment "SPI Master Controller Drivers"
config SPI_AIROHA_SNFI
tristate "Airoha SPI NAND Flash Interface"
depends on ARCH_AIROHA || COMPILE_TEST
depends on SPI_MASTER
select REGMAP_MMIO
help
This enables support for SPI-NAND mode on the Airoha NAND
@ -92,6 +91,14 @@ config SPI_ALTERA_DFL
Altera SPI master controller. The SPI master is connected
to a SPI slave to Avalon bridge in a Intel MAX BMC.
config SPI_AMD
tristate "AMD SPI controller"
depends on PCI
depends on X86 || COMPILE_TEST
depends on SPI_MEM
help
Enables SPI controller driver for AMD SoC.
config SPI_AMLOGIC_SPIFC_A1
tristate "Amlogic A1 SPIFC controller"
depends on ARCH_MESON || COMPILE_TEST
@ -136,6 +143,13 @@ config SPI_AR934X
This enables support for the SPI controller present on the
Qualcomm Atheros AR934X/QCA95XX SoCs.
config SPI_ARMADA_3700
tristate "Marvell Armada 3700 SPI Controller"
depends on (ARCH_MVEBU && OF) || COMPILE_TEST
help
This enables support for the SPI controller present on the
Marvell Armada 3700 SoCs.
config SPI_ATCSPI200
tristate "Andes ATCSPI200 SPI controller"
depends on ARCH_ANDES || COMPILE_TEST
@ -153,13 +167,6 @@ config SPI_ATH79
This enables support for the SPI controller present on the
Atheros AR71XX/AR724X/AR913X SoCs.
config SPI_ARMADA_3700
tristate "Marvell Armada 3700 SPI Controller"
depends on (ARCH_MVEBU && OF) || COMPILE_TEST
help
This enables support for the SPI controller present on the
Marvell Armada 3700 SoCs.
config SPI_ASPEED_SMC
tristate "Aspeed flash controllers in SPI mode"
depends on ARCH_ASPEED || COMPILE_TEST
@ -333,7 +340,7 @@ config SPI_CADENCE_XSPI
config SPI_CH341
tristate "CH341 USB2SPI adapter"
depends on SPI_MASTER && USB
depends on USB
help
Enables the SPI controller on the CH341a USB to serial chip
@ -388,14 +395,14 @@ config SPI_DW_MMIO
endif
config SPI_DLN2
tristate "Diolan DLN-2 USB SPI adapter"
depends on MFD_DLN2
help
If you say yes to this option, support will be included for Diolan
DLN2, a USB to SPI interface.
tristate "Diolan DLN-2 USB SPI adapter"
depends on MFD_DLN2
help
If you say yes to this option, support will be included for Diolan
DLN2, a USB to SPI interface.
This driver can also be built as a module. If so, the module
will be called spi-dln2.
This driver can also be built as a module. If so, the module
will be called spi-dln2.
config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller"
@ -420,6 +427,22 @@ config SPI_FSI
This enables support for the driver for FSI bus attached SPI
controllers.
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select REGMAP_MMIO
depends on ARCH_MXC || ARCH_NXP || M5441x || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
mode. S32, VF610, LS1021A and ColdFire platforms uses the controller.
config SPI_FSL_ESPI
tristate "Freescale eSPI controller"
depends on FSL_SOC
help
This enables using the Freescale eSPI controllers in master mode.
From MPC8536, 85xx platform uses the controller, and all P10xx,
P20xx, P30xx,P40xx, P50xx uses this controller.
config SPI_FSL_LPSPI
tristate "Freescale i.MX LPSPI controller"
depends on ARCH_MXC || COMPILE_TEST
@ -438,6 +461,26 @@ config SPI_FSL_QUADSPI
This controller does not support generic SPI messages. It only
supports the high-level SPI memory interface.
config SPI_FSL_LIB
tristate
depends on OF
config SPI_FSL_CPM
tristate
depends on FSL_SOC
config SPI_FSL_SPI
tristate "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller"
depends on OF
select SPI_FSL_LIB
select SPI_FSL_CPM if FSL_SOC
help
This enables using the Freescale SPI controllers in master mode.
MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
This also enables using the Aeroflex Gaisler GRLIB SPI controller in
master mode.
config SPI_GXP
tristate "GXP SPI driver"
depends on ARCH_HPE || COMPILE_TEST
@ -463,27 +506,6 @@ config SPI_HISI_SFC_V3XX
This enables support for HiSilicon v3xx SPI NOR flash controller
found in hi16xx chipsets.
config SPI_NXP_FLEXSPI
tristate "NXP Flex SPI controller"
depends on ARCH_LAYERSCAPE || ARCH_MXC || COMPILE_TEST
depends on HAS_IOMEM
help
This enables support for the Flex SPI controller in master mode.
Up to four slave devices can be connected on two buses with two
chipselects each.
This controller does not support generic SPI messages and only
supports the high-level SPI memory interface.
config SPI_NXP_XSPI
tristate "NXP xSPI controller"
depends on ARCH_MXC || COMPILE_TEST
depends on HAS_IOMEM
help
This enables support for the xSPI controller. Up to two devices
can be connected to one host.
This controller does not support generic SPI messages and only
supports the high-level SPI memory interface.
config SPI_GPIO
tristate "GPIO-based bitbanging SPI Master"
depends on GPIOLIB || COMPILE_TEST
@ -581,6 +603,25 @@ config SPI_KSPI2
This driver can also be built as a module. If so, the module
will be called spi-kspi2.
config SPI_LANTIQ_SSC
tristate "Lantiq SSC SPI controller"
depends on LANTIQ || X86 || COMPILE_TEST
help
This driver supports the Lantiq SSC SPI controller in master
mode. This controller is found on Intel (former Lantiq) SoCs like
the Danube, Falcon, xRX200, xRX300, Lightning Mountain.
config SPI_LJCA
tristate "Intel La Jolla Cove Adapter SPI support"
depends on USB_LJCA
default USB_LJCA
help
Select this option to enable SPI driver for the Intel
La Jolla Cove Adapter (LJCA) board.
This driver can also be built as a module. If so, the module
will be called spi-ljca.
config SPI_LM70_LLP
tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
depends on PARPORT
@ -626,74 +667,6 @@ config SPI_LP8841_RTC
Say N here unless you plan to run the kernel on an ICP DAS
LP-8x4x industrial computer.
config SPI_MPC52xx
tristate "Freescale MPC52xx SPI (non-PSC) controller support"
depends on PPC_MPC52xx
help
This drivers supports the MPC52xx SPI controller in master SPI
mode.
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
depends on PPC_MPC52xx
help
This enables using the Freescale MPC52xx Programmable Serial
Controller in master SPI mode.
config SPI_MPC512x_PSC
tristate "Freescale MPC512x PSC SPI controller"
depends on PPC_MPC512x
help
This enables using the Freescale MPC5121 Programmable Serial
Controller in SPI master mode.
config SPI_FSL_LIB
tristate
depends on OF
config SPI_FSL_CPM
tristate
depends on FSL_SOC
config SPI_FSL_SPI
tristate "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller"
depends on OF
select SPI_FSL_LIB
select SPI_FSL_CPM if FSL_SOC
help
This enables using the Freescale SPI controllers in master mode.
MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
This also enables using the Aeroflex Gaisler GRLIB SPI controller in
master mode.
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select REGMAP_MMIO
depends on ARCH_MXC || ARCH_NXP || M5441x || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
mode. S32, VF610, LS1021A and ColdFire platforms uses the controller.
config SPI_FSL_ESPI
tristate "Freescale eSPI controller"
depends on FSL_SOC
help
This enables using the Freescale eSPI controllers in master mode.
From MPC8536, 85xx platform uses the controller, and all P10xx,
P20xx, P30xx,P40xx, P50xx uses this controller.
config SPI_LJCA
tristate "Intel La Jolla Cove Adapter SPI support"
depends on USB_LJCA
default USB_LJCA
help
Select this option to enable SPI driver for the Intel
La Jolla Cove Adapter (LJCA) board.
This driver can also be built as a module. If so, the module
will be called spi-ljca.
config SPI_MA35D1_QSPI
tristate "Nuvoton MA35D1 QSPI controller"
depends on ARCH_MA35 || COMPILE_TEST
@ -722,7 +695,6 @@ config SPI_MESON_SPIFC
config SPI_MICROCHIP_CORE_QSPI
tristate "Microchip FPGA QSPI controllers"
depends on SPI_MASTER
help
This enables the QSPI driver for Microchip FPGA QSPI controllers.
Say Y or M here if you want to use the QSPI controllers on
@ -731,13 +703,33 @@ config SPI_MICROCHIP_CORE_QSPI
config SPI_MICROCHIP_CORE_SPI
tristate "Microchip FPGA CoreSPI controller"
depends on SPI_MASTER
help
This enables the SPI driver for Microchip FPGA CoreSPI controller.
Say Y or M here if you want to use the "soft" controllers on
PolarFire SoC.
If built as a module, it will be called spi-microchip-core-spi.
config SPI_MPC52xx
tristate "Freescale MPC52xx SPI (non-PSC) controller support"
depends on PPC_MPC52xx
help
This drivers supports the MPC52xx SPI controller in master SPI
mode.
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
depends on PPC_MPC52xx
help
This enables using the Freescale MPC52xx Programmable Serial
Controller in master SPI mode.
config SPI_MPC512x_PSC
tristate "Freescale MPC512x PSC SPI controller"
depends on PPC_MPC512x
help
This enables using the Freescale MPC5121 Programmable Serial
Controller in SPI master mode.
config SPI_MT65XX
tristate "MediaTek SPI controller"
depends on ARCH_MEDIATEK || COMPILE_TEST
@ -773,6 +765,19 @@ config SPI_MTK_SNFI
is implemented as a SPI-MEM controller with pipelined ECC
capability.
config SPI_MXIC
tristate "Macronix MX25F0A SPI controller"
imply MTD_NAND_ECC_MXIC
help
This selects the Macronix MX25F0A SPI controller driver.
config SPI_MXS
tristate "Freescale MXS SPI controller"
depends on ARCH_MXS
select STMP_DEVICE
help
SPI driver for Freescale MXS devices.
config SPI_WPCM_FIU
tristate "Nuvoton WPCM450 Flash Interface Unit"
depends on ARCH_NPCM || COMPILE_TEST
@ -801,13 +806,26 @@ config SPI_NPCM_PSPI
This driver provides support for Nuvoton NPCM BMC
Peripheral SPI controller in master mode.
config SPI_LANTIQ_SSC
tristate "Lantiq SSC SPI controller"
depends on LANTIQ || X86 || COMPILE_TEST
config SPI_NXP_FLEXSPI
tristate "NXP Flex SPI controller"
depends on ARCH_LAYERSCAPE || ARCH_MXC || COMPILE_TEST
depends on HAS_IOMEM
help
This driver supports the Lantiq SSC SPI controller in master
mode. This controller is found on Intel (former Lantiq) SoCs like
the Danube, Falcon, xRX200, xRX300, Lightning Mountain.
This enables support for the Flex SPI controller in master mode.
Up to four slave devices can be connected on two buses with two
chipselects each.
This controller does not support generic SPI messages and only
supports the high-level SPI memory interface.
config SPI_NXP_XSPI
tristate "NXP xSPI controller"
depends on ARCH_MXC || COMPILE_TEST
depends on HAS_IOMEM
help
This enables support for the xSPI controller. Up to two devices
can be connected to one host.
This controller does not support generic SPI messages and only
supports the high-level SPI memory interface.
config SPI_OC_TINY
tristate "OpenCores tiny SPI"
@ -838,14 +856,6 @@ config SPI_OMAP24XX
SPI master controller for OMAP24XX and later Multichannel SPI
(McSPI) modules.
config SPI_TI_QSPI
tristate "DRA7xxx QSPI controller support"
depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
QSPI master controller for DRA7xxx used for flash devices.
This device supports single, dual and quad read support, while
it only supports single write mode.
config SPI_ORION
tristate "Orion SPI master"
depends on PLAT_ORION || ARCH_MVEBU || COMPILE_TEST
@ -887,7 +897,6 @@ config SPI_PL022
config SPI_POLARFIRE_SOC
tristate "Microchip FPGA SPI controllers"
depends on SPI_MASTER
depends on ARCH_MICROCHIP || COMPILE_TEST
help
This enables the SPI driver for Microchip FPGA SPI controllers.
@ -950,7 +959,7 @@ config SPI_ROCKCHIP_SFC
config SPI_RB4XX
tristate "Mikrotik RB4XX SPI master"
depends on SPI_MASTER && (ATH79 || COMPILE_TEST)
depends on ATH79 || COMPILE_TEST
depends on OF
help
SPI controller driver for the Mikrotik RB4xx series boards.
@ -967,6 +976,16 @@ config SPI_RSPI
help
SPI driver for Renesas RSPI and QSPI blocks.
config SPI_RTK_NOR
tristate "Realtek SPI-NOR flash controller"
depends on ARCH_REALTEK || COMPILE_TEST
depends on SPI_MEM
help
This enables support for the SPI NOR Flash Controller found on
Realtek DHC SoCs. The controller supports single and dual I/O
transfers and offloads the payload to an integrated DMA engine.
Say Y or M here if you are building a kernel for a Realtek DHC SoC
config SPI_RZV2H_RSPI
tristate "Renesas RZ/V2H RSPI controller"
depends on ARCH_RENESAS || COMPILE_TEST
@ -1035,12 +1054,14 @@ config SPI_SC18IS602
help
SPI driver for NXP SC18IS602/602B/603 I2C to SPI bridge.
config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on HAVE_CLK
depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST
config SPI_SG2044_NOR
tristate "SG2044 SPI NOR Controller"
depends on ARCH_SOPHGO || COMPILE_TEST
help
SPI driver for SuperH and SH Mobile MSIOF blocks.
This enables support for the SG2044 SPI NOR controller,
which supports Dual/Quad read and write operations while
also supporting 3Byte address devices and 4Byte address
devices.
config SPI_SH
tristate "SuperH SPI controller"
@ -1048,6 +1069,19 @@ config SPI_SH
help
SPI driver for SuperH SPI blocks.
config SPI_SH_HSPI
tristate "SuperH HSPI controller"
depends on ARCH_RENESAS || COMPILE_TEST
help
SPI driver for SuperH HSPI blocks.
config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on HAVE_CLK
depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST
help
SPI driver for SuperH and SH Mobile MSIOF blocks.
config SPI_SH_SCI
tristate "SuperH SCI SPI controller"
depends on SUPERH
@ -1055,28 +1089,12 @@ config SPI_SH_SCI
help
SPI driver for SuperH SCI blocks.
config SPI_SH_HSPI
tristate "SuperH HSPI controller"
depends on ARCH_RENESAS || COMPILE_TEST
help
SPI driver for SuperH HSPI blocks.
config SPI_SIFIVE
tristate "SiFive SPI controller"
depends on HAS_IOMEM
help
This exposes the SPI controller IP from SiFive.
config SPI_SLAVE_MT27XX
tristate "MediaTek SPI slave device"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on SPI_SLAVE
help
This selects the MediaTek(R) SPI slave device driver.
If you want to use MediaTek(R) SPI slave interface,
say Y or M here.If you are not sure, say N.
SPI slave drivers for Mediatek MT27XX series ARM SoCs.
config SPI_SN_F_OSPI
tristate "Socionext F_OSPI SPI flash controller"
depends on OF && HAS_IOMEM
@ -1086,15 +1104,6 @@ config SPI_SN_F_OSPI
for connecting an SPI Flash memory over up to 8-bit wide bus.
It supports indirect access mode only.
config SPI_SG2044_NOR
tristate "SG2044 SPI NOR Controller"
depends on ARCH_SOPHGO || COMPILE_TEST
help
This enables support for the SG2044 SPI NOR controller,
which supports Dual/Quad read and write operations while
also supporting 3Byte address devices and 4Byte address
devices.
config SPI_SPACEMIT_K1
tristate "K1 SPI Controller"
depends on ARCH_SPACEMIT || COMPILE_TEST
@ -1189,20 +1198,6 @@ config SPI_SYNQUACER
It also supports the new dual-bit and quad-bit SPI protocol.
config SPI_MXIC
tristate "Macronix MX25F0A SPI controller"
depends on SPI_MASTER
imply MTD_NAND_ECC_MXIC
help
This selects the Macronix MX25F0A SPI controller driver.
config SPI_MXS
tristate "Freescale MXS SPI controller"
depends on ARCH_MXS
select STMP_DEVICE
help
SPI driver for Freescale MXS devices.
config SPI_TEGRA210_QUAD
tristate "NVIDIA Tegra QSPI Controller"
depends on ARCH_TEGRA || COMPILE_TEST
@ -1244,6 +1239,23 @@ config SPI_THUNDERX
SPI host driver for the hardware found on Cavium ThunderX
SOCs.
config SPI_TI_QSPI
tristate "DRA7xxx QSPI controller support"
depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
QSPI master controller for DRA7xxx used for flash devices.
This device supports single, dual and quad read support, while
it only supports single write mode.
config SPI_TLE62X0
tristate "Infineon TLE62X0 (for power switching)"
depends on SYSFS
help
SPI driver for Infineon TLE62X0 series line driver chips,
such as the TLE6220, TLE6230 and TLE6240. This provides a
sysfs interface, with each line presented as a kind of GPIO
exposing both switch control and diagnostic feedback.
config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI && (X86_32 || MIPS || COMPILE_TEST)
@ -1270,7 +1282,7 @@ config SPI_UNIPHIER
config SPI_VIRTIO
tristate "Virtio SPI Controller"
depends on SPI_MASTER && VIRTIO
depends on VIRTIO
help
If you say yes to this option, support will be included for the virtio
SPI controller driver. The hardware can be emulated by any device model
@ -1336,14 +1348,6 @@ config SPI_ZYNQMP_GQSPI
Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC.
This controller only supports SPI memory interface.
config SPI_AMD
tristate "AMD SPI controller"
depends on PCI
depends on SPI_MASTER || X86 || COMPILE_TEST
depends on SPI_MEM
help
Enables SPI controller driver for AMD SoC.
#
# Add new SPI master controllers in alphabetical order above this line
#
@ -1392,15 +1396,6 @@ config SPI_LOOPBACK_TEST
primarily used for development of spi_master drivers
and to detect regressions
config SPI_TLE62X0
tristate "Infineon TLE62X0 (for power switching)"
depends on SYSFS
help
SPI driver for Infineon TLE62X0 series line driver chips,
such as the TLE6220, TLE6230 and TLE6240. This provides a
sysfs interface, with each line presented as a kind of GPIO
exposing both switch control and diagnostic feedback.
#
# Add new SPI protocol masters in alphabetical order above this line
#
@ -1431,6 +1426,15 @@ config SPI_SLAVE_SYSTEM_CONTROL
SPI slave handler to allow remote control of system reboot, power
off, halt, and suspend.
config SPI_SLAVE_MT27XX
tristate "MediaTek SPI slave device"
depends on ARCH_MEDIATEK || COMPILE_TEST
help
This selects the MediaTek(R) SPI slave device driver.
If you want to use MediaTek(R) SPI slave interface,
say Y or M here.If you are not sure, say N.
SPI slave drivers for Mediatek MT27XX series ARM SoCs.
endif # SPI_SLAVE
config SPI_DYNAMIC

View File

@ -133,6 +133,7 @@ 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_RTK_NOR) += spi-rtk-nor.o
obj-$(CONFIG_SPI_RZV2H_RSPI) += spi-rzv2h-rspi.o
obj-$(CONFIG_SPI_RZV2M_CSI) += spi-rzv2m-csi.o
obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o

View File

@ -37,6 +37,12 @@
#define CFG_HW_POS BIT(6)
/* start on vsync falling */
#define CFG_HW_NEG BIT(7)
#define CFG_WORD_GAP GENMASK(9, 8)
#define CFG_MO_IDLE_OUTPUT GENMASK(11, 10)
/* cs hold time in pclk */
#define CFG_CS_HOLD GENMASK(26, 12)
/* high 4 bits of cs setup time in sclk */
#define CFG_CS_SETUP_EXTEND GENMASK(30, 27)
#define SPISG_REG_CFG_START 0x08
#define CFG_BLOCK_NUM GENMASK(19, 0)
@ -95,7 +101,7 @@
#define SPISG_MAX_REG 0x40
#define SPISG_BLOCK_MAX 0x100000
#define SPISG_BLOCK_MAX 0xFFFFF
#define SPISG_OP_MODE_WRITE_CMD 0
#define SPISG_OP_MODE_READ_STS 1
@ -143,6 +149,13 @@ struct spisg_descriptor_extra {
int rx_ccsg_len;
};
struct aml_spisg_data {
bool mo_idle_output_ctrl;
bool word_gap_ctrl;
bool cs_hold_ctrl;
bool cs_setup_extend_ctrl;
};
struct spisg_device {
struct spi_controller *controller;
struct platform_device *pdev;
@ -152,6 +165,7 @@ struct spisg_device {
struct clk *sclk;
struct clk_div_table *tbl;
struct completion completion;
const struct aml_spisg_data *data;
u32 status;
u32 speed_hz;
u32 effective_speed_hz;
@ -175,7 +189,7 @@ static int spi_delay_to_sclk(u32 slck_speed_hz, struct spi_delay *delay)
if (ns < 0)
return 0;
return DIV_ROUND_UP_ULL(slck_speed_hz * ns, NSEC_PER_SEC);
return DIV_ROUND_UP_ULL((u64)slck_speed_hz * ns, NSEC_PER_SEC);
}
static inline u32 aml_spisg_sem_down_read(struct spisg_device *spisg)
@ -424,7 +438,8 @@ static void aml_spisg_setup_null_desc(struct spisg_device *spisg,
static void aml_spisg_pending(struct spisg_device *spisg,
dma_addr_t desc_paddr,
bool trig,
bool irq_en)
bool irq_en,
u32 delay)
{
u32 desc_l, desc_h, cfg_spi, irq_enable;
@ -437,6 +452,13 @@ static void aml_spisg_pending(struct spisg_device *spisg,
#endif
cfg_spi = spisg->cfg_spi;
if (spisg->data && spisg->data->word_gap_ctrl) {
if (delay > 3)
delay = 3;
cfg_spi |= FIELD_PREP(CFG_WORD_GAP, delay);
}
if (trig)
cfg_spi |= CFG_HW_POS;
else
@ -483,13 +505,16 @@ static int aml_spisg_transfer_one_message(struct spi_controller *ctlr,
{
struct spisg_device *spisg = spi_controller_get_devdata(ctlr);
struct device *dev = &spisg->pdev->dev;
const struct aml_spisg_data *data = spisg->data;
unsigned long long ms = 0;
struct spi_transfer *xfer;
struct spisg_descriptor *descs, *desc;
struct spisg_descriptor_extra *exdescs, *exdesc;
dma_addr_t descs_paddr;
int desc_num = 1, descs_len;
bool last_xfer_keep_ss = false;
u32 cs_hold_in_sclk = 0;
u32 val, delay = 0;
int ret = -EIO;
if (!aml_spisg_sem_down_read(spisg)) {
@ -523,15 +548,27 @@ static int aml_spisg_transfer_one_message(struct spi_controller *ctlr,
goto end;
}
/* calculate cs-setup delay with the first xfer speed */
if (list_is_first(&xfer->transfer_list, &msg->transfers))
desc->cfg_bus |= FIELD_PREP(CFG_CS_SETUP,
spi_delay_to_sclk(xfer->effective_speed_hz, &msg->spi->cs_setup));
/* calculate cs-setup delay with the first xfer speed and word dealy*/
if (list_is_first(&xfer->transfer_list, &msg->transfers)) {
val = spi_delay_to_sclk(xfer->effective_speed_hz, &msg->spi->cs_setup);
if (data && data->cs_setup_extend_ctrl) {
val = min_t(u32, 0xFF, val);
desc->cfg_bus |= FIELD_PREP(CFG_CS_SETUP, val & 0xF);
FIELD_MODIFY(CFG_CS_SETUP_EXTEND, &spisg->cfg_spi, val >> 4);
} else {
val = min_t(u32, 0xF, val);
desc->cfg_bus |= FIELD_PREP(CFG_CS_SETUP, val);
}
delay = spi_delay_to_sclk(xfer->effective_speed_hz, &msg->spi->word_delay);
}
/* calculate cs-hold delay with the last xfer speed */
if (list_is_last(&xfer->transfer_list, &msg->transfers))
if (list_is_last(&xfer->transfer_list, &msg->transfers)) {
cs_hold_in_sclk =
spi_delay_to_sclk(xfer->effective_speed_hz, &msg->spi->cs_hold);
last_xfer_keep_ss = xfer->cs_change;
}
desc++;
exdesc++;
@ -539,13 +576,23 @@ static int aml_spisg_transfer_one_message(struct spi_controller *ctlr,
xfer->effective_speed_hz);
}
if (cs_hold_in_sclk)
if (data && data->cs_hold_ctrl) {
cs_hold_in_sclk = cs_hold_in_sclk ? : 1;
val = cs_hold_in_sclk * (FIELD_GET(CFG_CLK_DIV, spisg->cfg_bus) + 1);
val = min_t(u32, 0x7FFF, val);
FIELD_MODIFY(CFG_CS_HOLD, &spisg->cfg_spi, val);
desc--;
} else if (cs_hold_in_sclk) {
/* additional null-descriptor to achieve the cs-hold delay */
aml_spisg_setup_null_desc(spisg, desc, cs_hold_in_sclk);
else
desc--;
desc->cfg_bus |= FIELD_PREP(CFG_KEEP_SS, 1);
desc++;
} else {
desc--;
}
desc->cfg_bus |= FIELD_PREP(CFG_KEEP_SS, 0);
FIELD_MODIFY(CFG_KEEP_SS, &desc->cfg_bus, last_xfer_keep_ss);
desc->cfg_start |= FIELD_PREP(CFG_EOC, 1);
/* some tolerances */
@ -562,13 +609,16 @@ static int aml_spisg_transfer_one_message(struct spi_controller *ctlr,
}
reinit_completion(&spisg->completion);
aml_spisg_pending(spisg, descs_paddr, false, true);
aml_spisg_pending(spisg, descs_paddr, false, true, delay);
if (wait_for_completion_timeout(&spisg->completion,
spi_controller_is_target(spisg->controller) ?
MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(ms)))
MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(ms))) {
ret = spisg->status ? -EIO : 0;
else
} else {
/* stop transfer */
regmap_write(spisg->map, SPISG_REG_DESC_LIST_H, 0);
ret = -ETIMEDOUT;
}
dma_unmap_single(dev, descs_paddr, descs_len, DMA_TO_DEVICE);
end:
@ -704,7 +754,9 @@ static int aml_spisg_clk_init(struct spisg_device *spisg, void __iomem *base)
return PTR_ERR(spisg->sclk);
}
clk_prepare_enable(spisg->sclk);
ret = clk_prepare_enable(spisg->sclk);
if (ret)
return ret;
return 0;
}
@ -715,6 +767,7 @@ static int aml_spisg_probe(struct platform_device *pdev)
struct spisg_device *spisg;
struct device *dev = &pdev->dev;
void __iomem *base;
u32 val = 0;
int ret, irq;
const struct regmap_config aml_regmap_config = {
@ -733,6 +786,7 @@ static int aml_spisg_probe(struct platform_device *pdev)
spisg = spi_controller_get_devdata(ctlr);
spisg->controller = ctlr;
spisg->data = (struct aml_spisg_data *)of_device_get_match_data(dev);
spisg->pdev = pdev;
platform_set_drvdata(pdev, spisg);
@ -763,6 +817,14 @@ static int aml_spisg_probe(struct platform_device *pdev)
spisg->cfg_spi = FIELD_PREP(CFG_SFLASH_WP, 1) |
FIELD_PREP(CFG_SFLASH_HD, 1);
if (spisg->data && spisg->data->mo_idle_output_ctrl) {
if (!of_property_read_u32(dev->of_node, "amlogic,mo-idle-output", &val))
spisg->cfg_spi |= FIELD_PREP(CFG_MO_IDLE_OUTPUT, val);
else
spisg->cfg_spi |= FIELD_PREP(CFG_MO_IDLE_OUTPUT, 0);
}
if (spi_controller_is_target(ctlr)) {
spisg->cfg_spi |= FIELD_PREP(CFG_SLAVE_EN, 1);
spisg->cfg_bus = FIELD_PREP(CFG_TX_TUNING, 0xf);
@ -841,14 +903,30 @@ static int spisg_suspend_runtime(struct device *dev)
static int spisg_resume_runtime(struct device *dev)
{
struct spisg_device *spisg = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(spisg->core);
if (ret)
return ret;
ret = clk_prepare_enable(spisg->sclk);
if (ret) {
clk_disable_unprepare(spisg->core);
return ret;
}
clk_prepare_enable(spisg->core);
clk_prepare_enable(spisg->sclk);
pinctrl_pm_select_default_state(&spisg->pdev->dev);
return 0;
}
static const struct aml_spisg_data a9_spisg_data = {
.mo_idle_output_ctrl = true,
.word_gap_ctrl = true,
.cs_hold_ctrl = true,
.cs_setup_extend_ctrl = true,
};
static const struct dev_pm_ops amlogic_spisg_pm_ops = {
.runtime_suspend = spisg_suspend_runtime,
.runtime_resume = spisg_resume_runtime,
@ -858,6 +936,10 @@ static const struct of_device_id amlogic_spisg_of_match[] = {
{
.compatible = "amlogic,a4-spisg",
},
{
.compatible = "amlogic,a9-spisg",
.data = &a9_spisg_data,
},
{ /* sentinel */ }
};

View File

@ -197,23 +197,13 @@ static int ar934x_spi_probe(struct platform_device *pdev)
SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
ctlr->num_chipselect = 3;
dev_set_drvdata(&pdev->dev, ctlr);
sp = spi_controller_get_devdata(ctlr);
sp->base = base;
sp->clk = clk;
sp->clk_freq = clk_get_rate(clk);
sp->ctlr = ctlr;
return spi_register_controller(ctlr);
}
static void ar934x_spi_remove(struct platform_device *pdev)
{
struct spi_controller *ctlr;
ctlr = dev_get_drvdata(&pdev->dev);
spi_unregister_controller(ctlr);
return devm_spi_register_controller(&pdev->dev, ctlr);
}
static struct platform_driver ar934x_spi_driver = {
@ -222,7 +212,6 @@ static struct platform_driver ar934x_spi_driver = {
.of_match_table = ar934x_spi_match,
},
.probe = ar934x_spi_probe,
.remove = ar934x_spi_remove,
};
module_platform_driver(ar934x_spi_driver);

View File

@ -239,8 +239,8 @@ static int at91_usart_spi_dma_transfer(struct spi_controller *ctlr,
if (dma_submit_error(cookie))
goto at91_usart_spi_err_dma;
rxchan->device->device_issue_pending(rxchan);
txchan->device->device_issue_pending(txchan);
dma_async_issue_pending(rxchan);
dma_async_issue_pending(txchan);
return 0;

View File

@ -877,8 +877,8 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_controller *host,
cookie = txdesc->tx_submit(txdesc);
if (dma_submit_error(cookie))
goto err_dma;
rxchan->device->device_issue_pending(rxchan);
txchan->device->device_issue_pending(txchan);
dma_async_issue_pending(rxchan);
dma_async_issue_pending(txchan);
return 0;

View File

@ -527,7 +527,7 @@ static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr,
| BCM2835_SPI_CS_CLEAR_TX
| BCM2835_SPI_CS_DONE);
dma_sync_single_for_device(ctlr->dma_rx->device->dev,
dma_sync_single_for_device(dmaengine_get_dma_device(ctlr->dma_rx),
sg_dma_address(&tfr->rx_sg.sgl[0]),
bs->rx_prologue, DMA_FROM_DEVICE);
@ -871,7 +871,7 @@ static void bcm2835_dma_release(struct spi_controller *ctlr,
dmaengine_desc_free(bs->fill_tx_desc);
if (bs->fill_tx_addr)
dma_unmap_page_attrs(ctlr->dma_tx->device->dev,
dma_unmap_page_attrs(dmaengine_get_dma_device(ctlr->dma_tx),
bs->fill_tx_addr, sizeof(u32),
DMA_TO_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
@ -891,6 +891,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
struct bcm2835_spi *bs)
{
struct dma_slave_config slave_config;
struct device *tx_dma_dev;
const __be32 *addr;
dma_addr_t dma_reg_base;
int ret;
@ -932,11 +933,13 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev,
if (ret)
goto err_config;
bs->fill_tx_addr = dma_map_page_attrs(ctlr->dma_tx->device->dev,
tx_dma_dev = dmaengine_get_dma_device(ctlr->dma_tx);
bs->fill_tx_addr = dma_map_page_attrs(tx_dma_dev,
ZERO_PAGE(0), 0, sizeof(u32),
DMA_TO_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
if (dma_mapping_error(ctlr->dma_tx->device->dev, bs->fill_tx_addr)) {
if (dma_mapping_error(tx_dma_dev, bs->fill_tx_addr)) {
dev_err(dev, "cannot map zero page - not using DMA mode\n");
bs->fill_tx_addr = 0;
ret = -ENOMEM;
@ -1157,7 +1160,7 @@ static void bcm2835_spi_cleanup(struct spi_device *spi)
dmaengine_desc_free(target->clear_rx_desc);
if (target->clear_rx_addr)
dma_unmap_single(ctlr->dma_rx->device->dev,
dma_unmap_single(dmaengine_get_dma_device(ctlr->dma_rx),
target->clear_rx_addr,
sizeof(u32),
DMA_TO_DEVICE);
@ -1174,16 +1177,16 @@ static int bcm2835_spi_setup_dma(struct spi_controller *ctlr,
struct bcm2835_spi *bs,
struct bcm2835_spidev *target)
{
struct device *rx_dev;
int ret;
if (!ctlr->dma_rx)
return 0;
target->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev,
&target->clear_rx_cs,
sizeof(u32),
DMA_TO_DEVICE);
if (dma_mapping_error(ctlr->dma_rx->device->dev, target->clear_rx_addr)) {
rx_dev = dmaengine_get_dma_device(ctlr->dma_rx);
target->clear_rx_addr = dma_map_single(rx_dev, &target->clear_rx_cs,
sizeof(u32), DMA_TO_DEVICE);
if (dma_mapping_error(rx_dev, target->clear_rx_addr)) {
dev_err(&spi->dev, "cannot map clear_rx_cs\n");
target->clear_rx_addr = 0;
return -ENOMEM;
@ -1268,7 +1271,7 @@ static int bcm2835_spi_setup(struct spi_device *spi)
target->clear_rx_cs = cs | BCM2835_SPI_CS_TA |
BCM2835_SPI_CS_DMAEN |
BCM2835_SPI_CS_CLEAR_RX;
dma_sync_single_for_device(ctlr->dma_rx->device->dev,
dma_sync_single_for_device(dmaengine_get_dma_device(ctlr->dma_rx),
target->clear_rx_addr,
sizeof(u32),
DMA_TO_DEVICE);
@ -1297,7 +1300,9 @@ static int bcm2835_spi_setup(struct spi_device *spi)
}
for (i = 0; i < ARRAY_SIZE(pinctrl_compats); i++) {
if (of_find_compatible_node(NULL, NULL, pinctrl_compats[i]))
struct device_node *np __free(device_node) =
of_find_compatible_node(NULL, NULL, pinctrl_compats[i]);
if (np)
break;
}

View File

@ -413,7 +413,7 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
struct bcm63xx_spi *bs = spi_controller_get_devdata(host);
u8 intr;
/* Read interupts and clear them immediately */
/* Read interrupts and clear them immediately */
intr = bcm_spi_readb(bs, SPI_INT_STATUS);
bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
bcm_spi_writeb(bs, 0, SPI_INT_MASK);

View File

@ -1381,7 +1381,7 @@ static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata,
return 0;
}
ddev = cqspi->rx_chan->device->dev;
ddev = dmaengine_get_dma_device(cqspi->rx_chan);
dma_dst = dma_map_single(ddev, buf, len, DMA_FROM_DEVICE);
if (dma_mapping_error(ddev, dma_dst)) {
dev_err(dev, "dma mapping failed\n");

View File

@ -275,7 +275,7 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
{
struct spi_controller *ctlr = dev_id;
struct dw_spi *dws = spi_controller_get_devdata(ctlr);
u16 irq_status = dw_readl(dws, DW_SPI_ISR) & DW_SPI_INT_MASK;
u16 irq_status = dw_readl(dws, DW_SPI_ISR);
if (!irq_status)
return IRQ_NONE;
@ -937,6 +937,15 @@ static void dw_spi_enh_write_cmd_addr(struct dw_spi *dws, const struct spi_mem_o
dw_spi_set_cs(mem->spi, false);
}
/*
* FIXME: The exact reason for this delay is not fully understood,
* but empirical testing shows it significantly improves the stability
* of read/write operations. Without this delay, occasional transfer
* errors or timeouts may occur under certain conditions.
* Keeping it as a safeguard based on practical validation.
*/
udelay(5);
}
static int dw_spi_exec_enh_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
@ -948,6 +957,8 @@ static int dw_spi_exec_enh_mem_op(struct spi_mem *mem, const struct spi_mem_op *
unsigned long long ms;
int ret;
dws->dma_mapped = false;
switch (op->data.buswidth) {
case 0:
case 1:
@ -971,10 +982,13 @@ static int dw_spi_exec_enh_mem_op(struct spi_mem *mem, const struct spi_mem_op *
cfg.dfs = 8;
cfg.freq = clamp(op->max_freq, 0U, dws->max_mem_freq);
cfg.ndf = op->data.nbytes;
if (op->data.dir == SPI_MEM_DATA_IN)
if (op->data.dir == SPI_MEM_DATA_IN) {
cfg.tmode = DW_SPI_CTRLR0_TMOD_RO;
else
dws->tx_dir = false;
} else {
cfg.tmode = DW_SPI_CTRLR0_TMOD_TO;
dws->tx_dir = true;
}
if (op->data.buswidth == op->addr.buswidth &&
op->data.buswidth == op->cmd.buswidth)
@ -1010,47 +1024,61 @@ static int dw_spi_exec_enh_mem_op(struct spi_mem *mem, const struct spi_mem_op *
}
}
dw_spi_enh_write_cmd_addr(dws, op, mem);
/*
* FIXME: The exact reason for this delay is not fully understood,
* but empirical testing shows it significantly improves the stability
* of read/write operations. Without this delay, occasional transfer
* errors or timeouts may occur under certain conditions.
* Keeping it as a safeguard based on practical validation.
*/
udelay(5);
dw_spi_enh_irq_setup(dws);
/* Use timeout calculation from spi_transfer_wait() */
ms = 8LL * MSEC_PER_SEC * (dws->rx_len ? dws->rx_len : dws->tx_len);
do_div(ms, dws->current_freq);
/*
* Increase it twice and add 200 ms tolerance, use
* predefined maximum in case of overflow.
*/
ms += ms + 200;
if (ms > UINT_MAX)
ms = UINT_MAX;
ms = wait_for_completion_timeout(&ctlr->xfer_completion,
msecs_to_jiffies(ms));
if (ms == 0) {
dw_spi_mask_intr(dws, 0xff);
synchronize_irq(dws->irq);
dws->rx = NULL;
dws->tx = NULL;
dws->rx_len = 0;
dws->tx_len = 0;
dw_spi_stop_mem_op(dws, mem->spi);
return -EIO;
if (dws->dma_nr_chans && dws->dma_ops->dma_enh_mem_get_chan &&
op->data.nbytes > dws->fifo_len) {
ret = dws->dma_ops->dma_enh_mem_get_chan(ctlr->dev.parent, dws);
if (ret) {
/* fall back to the PIO/IRQ path */
dev_dbg(&ctlr->dev, "DMA enh mem channel unavailable (%d)\n", ret);
} else if (dws->dma_ops->can_dma_enh_mem(ctlr)) {
ret = dws->dma_ops->dma_enh_mem_setup(dws);
if (ret)
dev_err(&ctlr->dev, "DMA enh mem setup failed (%d)\n", ret);
else
dws->dma_mapped = true;
}
}
ret = dw_spi_wait_mem_op_done(dws);
if (dws->dma_mapped) {
dw_spi_enh_write_cmd_addr(dws, op, mem);
dw_spi_stop_mem_op(dws, mem->spi);
ret = dws->dma_ops->dma_enh_mem_transfer(mem, op);
dw_spi_stop_mem_op(dws, mem->spi);
} else {
dw_spi_enh_write_cmd_addr(dws, op, mem);
dw_spi_enh_irq_setup(dws);
/* Use timeout calculation from spi_transfer_wait() */
ms = 8LL * MSEC_PER_SEC * (dws->rx_len ? dws->rx_len : dws->tx_len);
do_div(ms, dws->current_freq);
/*
* Increase it twice and add 200 ms tolerance, use
* predefined maximum in case of overflow.
*/
ms += ms + 200;
if (ms > UINT_MAX)
ms = UINT_MAX;
ms = wait_for_completion_timeout(&ctlr->xfer_completion,
msecs_to_jiffies(ms));
if (ms == 0) {
dw_spi_mask_intr(dws, 0xff);
synchronize_irq(dws->irq);
dws->rx = NULL;
dws->tx = NULL;
dws->rx_len = 0;
dws->tx_len = 0;
dw_spi_stop_mem_op(dws, mem->spi);
return -EIO;
}
ret = dw_spi_wait_mem_op_done(dws);
dw_spi_stop_mem_op(dws, mem->spi);
}
return ret;
}
@ -1104,12 +1132,13 @@ static int dw_spi_setup(struct spi_device *spi)
if (!chip)
return -ENOMEM;
spi_set_ctldata(spi, chip);
/* Get specific / default rx-sample-delay */
if (device_property_read_u32(&spi->dev,
"rx-sample-delay-ns",
&rx_sample_dly_ns) != 0)
/* Use default controller value */
rx_sample_dly_ns = dws->def_rx_sample_dly_ns;
/*
* Use the per-device value the core parsed from the peripheral
* node, and fall back to the controller-wide default when the
* device does not ask for a delay of its own.
*/
rx_sample_dly_ns = spi->rx_sample_delay_ns ?:
dws->def_rx_sample_dly_ns;
chip->rx_sample_dly = DIV_ROUND_CLOSEST(rx_sample_dly_ns,
NSEC_PER_SEC /
dws->max_freq);
@ -1360,6 +1389,9 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws)
goto err_free_irq;
} else if (ret) {
dev_warn(dev, "DMA init failed\n");
} else if (dws->dma_nr_chans == 1) {
/* Full-duplex DMA transfers need both channels */
dev_info(dev, "Single DMA channel, full-duplex DMA disabled\n");
} else {
ctlr->can_dma = dws->dma_ops->can_dma;
ctlr->flags |= SPI_CONTROLLER_MUST_TX;

View File

@ -42,14 +42,19 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws)
def_burst = dws->fifo_len / 2;
ret = dma_get_slave_caps(dws->rxchan, &caps);
if (!ret && caps.max_burst)
max_burst = caps.max_burst;
else
max_burst = DW_SPI_RX_BURST_LEVEL;
if (dws->rxchan) {
ret = dma_get_slave_caps(dws->rxchan, &caps);
if (!ret && caps.max_burst)
max_burst = caps.max_burst;
else
max_burst = DW_SPI_RX_BURST_LEVEL;
dws->rxburst = min(max_burst, def_burst);
dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1);
dws->rxburst = min(max_burst, def_burst);
dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1);
}
if (!dws->txchan)
return;
ret = dma_get_slave_caps(dws->txchan, &caps);
if (!ret && caps.max_burst)
@ -74,20 +79,39 @@ static void dw_spi_dma_maxburst_init(struct dw_spi *dws)
static int dw_spi_dma_caps_init(struct dw_spi *dws)
{
struct dma_slave_caps tx, rx;
struct dma_slave_caps tx = {}, rx = {};
int ret;
ret = dma_get_slave_caps(dws->txchan, &tx);
if (ret)
return ret;
if (dws->txchan) {
ret = dma_get_slave_caps(dws->txchan, &tx);
if (ret)
return ret;
ret = dma_get_slave_caps(dws->rxchan, &rx);
if (ret)
return ret;
if (!(tx.directions & BIT(DMA_MEM_TO_DEV)))
return -ENXIO;
}
if (!(tx.directions & BIT(DMA_MEM_TO_DEV) &&
rx.directions & BIT(DMA_DEV_TO_MEM)))
return -ENXIO;
if (dws->rxchan) {
ret = dma_get_slave_caps(dws->rxchan, &rx);
if (ret)
return ret;
if (!(rx.directions & BIT(DMA_DEV_TO_MEM)))
return -ENXIO;
}
/* With a single channel only one direction is available at a time */
if (!dws->rxchan) {
dws->dma_sg_burst = tx.max_sg_burst;
dws->dma_addr_widths = tx.dst_addr_widths;
return 0;
}
if (!dws->txchan) {
dws->dma_sg_burst = rx.max_sg_burst;
dws->dma_addr_widths = rx.src_addr_widths;
return 0;
}
if (tx.max_sg_burst > 0 && rx.max_sg_burst > 0)
dws->dma_sg_burst = min(tx.max_sg_burst, rx.max_sg_burst);
@ -169,40 +193,54 @@ static int dw_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
{
int ret;
dws->dma_nr_chans = 0;
dws->rxchan = dma_request_chan(dev, "rx");
if (IS_ERR(dws->rxchan)) {
ret = PTR_ERR(dws->rxchan);
dws->rxchan = NULL;
goto err_exit;
}
dws->dma_nr_chans++;
/*
* Some platforms have only one DMA channel for the controller. Keep
* the Rx channel in that case, it can still serve half-duplex
* transfers.
*/
dws->txchan = dma_request_chan(dev, "tx");
if (IS_ERR(dws->txchan)) {
ret = PTR_ERR(dws->txchan);
dws->txchan = NULL;
goto free_rxchan;
if (ret == -EPROBE_DEFER)
goto free_rxchan;
} else {
dws->dma_nr_chans++;
}
dws->ctlr->dma_rx = dws->rxchan;
dws->ctlr->dma_tx = dws->txchan;
init_completion(&dws->dma_completion);
ret = dw_spi_dma_caps_init(dws);
if (ret)
goto free_txchan;
dw_spi_dma_maxburst_init(dws);
init_completion(&dws->dma_completion);
dws->ctlr->dma_rx = dws->rxchan;
dws->ctlr->dma_tx = dws->txchan;
return 0;
free_txchan:
dma_release_channel(dws->txchan);
dws->txchan = NULL;
if (dws->txchan) {
dma_release_channel(dws->txchan);
dws->txchan = NULL;
}
free_rxchan:
dma_release_channel(dws->rxchan);
dws->rxchan = NULL;
err_exit:
dws->dma_nr_chans = 0;
return ret;
}
@ -286,19 +324,27 @@ static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
(DW_SPI_SR_BUSY | DW_SPI_SR_TF_EMPT)) != DW_SPI_SR_TF_EMPT;
}
static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
struct spi_transfer *xfer)
static int dw_spi_dma_wait_tx_done(struct dw_spi *dws, u32 speed_hz)
{
int retry = DW_SPI_WAIT_RETRIES;
struct spi_delay delay;
unsigned long ns, us;
u32 nents;
nents = dw_readl(dws, DW_SPI_TXFLR);
delay.unit = SPI_DELAY_UNIT_SCK;
delay.value = nents * dws->n_bytes * BITS_PER_BYTE;
ns = DIV_ROUND_UP(NSEC_PER_SEC, speed_hz) * nents *
dws->n_bytes * BITS_PER_BYTE;
if (ns <= NSEC_PER_USEC) {
delay.unit = SPI_DELAY_UNIT_NSECS;
delay.value = ns;
} else {
us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
delay.unit = SPI_DELAY_UNIT_USECS;
delay.value = clamp_val(us, 0, USHRT_MAX);
}
while (dw_spi_dma_tx_busy(dws) && retry--)
spi_delay_exec(&delay, xfer);
spi_delay_exec(&delay, NULL);
if (retry < 0) {
dev_err(&dws->ctlr->dev, "Tx hanged up\n");
@ -659,7 +705,7 @@ static int dw_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
return ret;
if (dws->ctlr->cur_msg->status == -EINPROGRESS) {
ret = dw_spi_dma_wait_tx_done(dws, xfer);
ret = dw_spi_dma_wait_tx_done(dws, xfer->effective_speed_hz);
if (ret)
return ret;
}
@ -682,6 +728,183 @@ static void dw_spi_dma_stop(struct dw_spi *dws)
}
}
/*
* The enhanced SPI memory operations are half-duplex, so a single DMA channel
* is enough for them. On a platform with only one channel, the channel is
* bound to a direction by its "tx"/"rx" DMA specifier, and whichever channel
* is currently held tells which direction it serves. Keep it across
* operations and swap it only when the transfer direction changes.
*/
static int dw_spi_enh_mem_dma_get_chan(struct device *dev, struct dw_spi *dws)
{
struct dma_chan **chan, **other;
const char *name;
int ret;
if (dws->dma_nr_chans == 2)
return 0;
if (dws->tx_dir) {
chan = &dws->txchan;
other = &dws->rxchan;
name = "tx";
} else {
chan = &dws->rxchan;
other = &dws->txchan;
name = "rx";
}
if (*chan)
return 0;
dws->ctlr->dma_tx = NULL;
dws->ctlr->dma_rx = NULL;
/*
* With a single physical channel, the held channel must be released
* before it can be requested again with the handshake of the other
* direction. On failure both stay NULL, and the next operation
* retries the request and falls back to PIO meanwhile.
*/
if (*other) {
dma_release_channel(*other);
*other = NULL;
}
*chan = dma_request_chan(dev, name);
if (IS_ERR(*chan)) {
ret = PTR_ERR(*chan);
*chan = NULL;
return ret;
}
ret = dw_spi_dma_caps_init(dws);
if (ret) {
dma_release_channel(*chan);
*chan = NULL;
return ret;
}
dw_spi_dma_maxburst_init(dws);
dws->ctlr->dma_tx = dws->txchan;
dws->ctlr->dma_rx = dws->rxchan;
return 0;
}
static int dw_spi_enh_mem_dma_setup(struct dw_spi *dws)
{
u16 dma_ctrl, level;
int ret;
/* Setup DMA channels */
if (dws->tx_dir) {
ret = dw_spi_dma_config_tx(dws);
if (ret)
return ret;
dma_ctrl = DW_SPI_DMACR_TDMAE;
} else {
ret = dw_spi_dma_config_rx(dws);
if (ret)
return ret;
dma_ctrl = DW_SPI_DMACR_RDMAE;
}
dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
/* Clear stale error status, it is checked after the transfer */
dw_readl(dws, DW_SPI_ICR);
reinit_completion(&dws->dma_completion);
level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len);
dw_writel(dws, DW_SPI_TXFTLR, level);
level = min_t(unsigned int, dws->fifo_len / 2, dws->rx_len);
dw_writel(dws, DW_SPI_RXFTLR, level ? level - 1 : 0);
return 0;
}
static bool dw_spi_enh_mem_can_dma(struct spi_controller *ctlr)
{
struct dw_spi *dws = spi_controller_get_devdata(ctlr);
unsigned int len = dws->tx_dir ? dws->tx_len : dws->rx_len;
enum dma_slave_buswidth dma_bus_width;
if (len <= dws->fifo_len)
return false;
dma_bus_width = dw_spi_dma_convert_width(dws->n_bytes);
return dws->dma_addr_widths & BIT(dma_bus_width);
}
static void dw_spi_enh_mem_dma_stop(struct dw_spi *dws)
{
if (dws->tx_dir) {
if (test_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy)) {
dmaengine_terminate_sync(dws->txchan);
clear_bit(DW_SPI_TX_BUSY, &dws->dma_chan_busy);
}
} else {
if (test_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy)) {
dmaengine_terminate_sync(dws->rxchan);
clear_bit(DW_SPI_RX_BUSY, &dws->dma_chan_busy);
}
}
}
static int dw_spi_enh_mem_dma_transfer(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct spi_controller *ctlr = mem->spi->controller;
struct dw_spi *dws = spi_controller_get_devdata(ctlr);
struct sg_table sgt;
int ret;
ret = spi_controller_dma_map_mem_op_data(ctlr, op, &sgt);
if (ret)
goto out_clear_dmac;
if (dws->tx_dir) {
ret = dw_spi_dma_submit_tx(dws, sgt.sgl, sgt.nents);
if (ret)
goto out_unmap;
dma_async_issue_pending(dws->txchan);
ret = dw_spi_dma_wait(dws, dws->tx_len, dws->current_freq);
if (!ret)
ret = dw_spi_dma_wait_tx_done(dws, dws->current_freq);
} else {
ret = dw_spi_dma_submit_rx(dws, sgt.sgl, sgt.nents);
if (ret)
goto out_unmap;
dma_async_issue_pending(dws->rxchan);
ret = dw_spi_dma_wait(dws, dws->rx_len, dws->current_freq);
if (!ret)
ret = dw_spi_dma_wait_rx_done(dws);
}
if (ret)
dw_spi_enh_mem_dma_stop(dws);
else
ret = dw_spi_check_status(dws, true);
out_unmap:
spi_controller_dma_unmap_mem_op_data(ctlr, op, &sgt);
out_clear_dmac:
dw_writel(dws, DW_SPI_DMACR, 0);
return ret;
}
static const struct dw_spi_dma_ops dw_spi_dma_mfld_ops = {
.dma_init = dw_spi_dma_init_mfld,
.dma_exit = dw_spi_dma_exit,
@ -704,6 +927,11 @@ static const struct dw_spi_dma_ops dw_spi_dma_generic_ops = {
.can_dma = dw_spi_can_dma,
.dma_transfer = dw_spi_dma_transfer,
.dma_stop = dw_spi_dma_stop,
.dma_enh_mem_get_chan = dw_spi_enh_mem_dma_get_chan,
.dma_enh_mem_setup = dw_spi_enh_mem_dma_setup,
.can_dma_enh_mem = dw_spi_enh_mem_can_dma,
.dma_enh_mem_transfer = dw_spi_enh_mem_dma_transfer,
};
void dw_spi_dma_setup_generic(struct dw_spi *dws)

View File

@ -363,6 +363,8 @@ static int dw_spi_jhb100_init(struct platform_device *pdev,
dw_spi_jhb100_mask_intr(&dwsmmio->dws, 0xff);
dw_spi_dma_setup_generic(&dwsmmio->dws);
return 0;
}

View File

@ -183,6 +183,12 @@ struct dw_spi_dma_ops {
struct spi_transfer *xfer);
int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer);
void (*dma_stop)(struct dw_spi *dws);
/* enh mem dma ops */
int (*dma_enh_mem_get_chan)(struct device *dev, struct dw_spi *dws);
int (*dma_enh_mem_setup)(struct dw_spi *dws);
bool (*can_dma_enh_mem)(struct spi_controller *ctlr);
int (*dma_enh_mem_transfer)(struct spi_mem *mem, const struct spi_mem_op *op);
};
struct dw_spi {
@ -227,6 +233,8 @@ struct dw_spi {
u32 txburst;
struct dma_chan *rxchan;
u32 rxburst;
unsigned int dma_nr_chans;
bool tx_dir;
u32 dma_sg_burst;
u32 dma_addr_widths;
unsigned long dma_chan_busy;

View File

@ -273,6 +273,7 @@ ep93xx_spi_dma_prepare(struct spi_controller *host,
struct dma_async_tx_descriptor *txd;
enum dma_slave_buswidth buswidth;
struct dma_slave_config conf;
struct device *dma_dev;
struct scatterlist *sg;
struct sg_table *sgt;
struct dma_chan *chan;
@ -348,14 +349,15 @@ ep93xx_spi_dma_prepare(struct spi_controller *host,
return ERR_PTR(-EINVAL);
}
nents = dma_map_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
dma_dev = dmaengine_get_dma_device(chan);
nents = dma_map_sg(dma_dev, sgt->sgl, sgt->nents, dir);
if (!nents)
return ERR_PTR(-ENOMEM);
txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, conf.direction,
DMA_CTRL_ACK);
if (!txd) {
dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
dma_unmap_sg(dma_dev, sgt->sgl, sgt->nents, dir);
return ERR_PTR(-ENOMEM);
}
return txd;
@ -384,7 +386,7 @@ static void ep93xx_spi_dma_finish(struct spi_controller *host,
sgt = &espi->tx_sgt;
}
dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
dma_unmap_sg(dmaengine_get_dma_device(chan), sgt->sgl, sgt->nents, dir);
}
static void ep93xx_spi_dma_callback(void *callback_param)

View File

@ -670,6 +670,7 @@ static void dspi_dma_xfer(struct fsl_dspi *dspi)
static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
{
struct device *dev = &dspi->pdev->dev;
struct device *tx_dev, *rx_dev;
struct dma_slave_config cfg;
struct fsl_dspi_dma *dma;
int ret;
@ -688,20 +689,23 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
goto err_tx_channel;
}
tx_dev = dmaengine_get_dma_device(dma->chan_tx);
rx_dev = dmaengine_get_dma_device(dma->chan_rx);
if (spi_controller_is_target(dspi->ctlr)) {
/*
* In target mode we have to be ready to receive the maximum
* that can possibly be transferred at once by EDMA without any
* FIFO underflows.
*/
dma->bufsize = min(dma_get_max_seg_size(dma->chan_rx->device->dev),
dma_get_max_seg_size(dma->chan_tx->device->dev)) *
dma->bufsize = min(dma_get_max_seg_size(rx_dev),
dma_get_max_seg_size(tx_dev)) *
DMA_SLAVE_BUSWIDTH_4_BYTES;
} else {
dma->bufsize = PAGE_SIZE;
}
dma->tx_dma_buf = dma_alloc_noncoherent(dma->chan_tx->device->dev,
dma->tx_dma_buf = dma_alloc_noncoherent(tx_dev,
dma->bufsize, &dma->tx_dma_phys,
DMA_TO_DEVICE, GFP_KERNEL);
if (!dma->tx_dma_buf) {
@ -709,7 +713,7 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
goto err_tx_dma_buf;
}
dma->rx_dma_buf = dma_alloc_noncoherent(dma->chan_rx->device->dev,
dma->rx_dma_buf = dma_alloc_noncoherent(rx_dev,
dma->bufsize, &dma->rx_dma_phys,
DMA_FROM_DEVICE, GFP_KERNEL);
if (!dma->rx_dma_buf) {
@ -746,12 +750,11 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
return 0;
err_slave_config:
dma_free_noncoherent(dma->chan_rx->device->dev, dma->bufsize,
dma->rx_dma_buf, dma->rx_dma_phys,
DMA_FROM_DEVICE);
dma_free_noncoherent(rx_dev, dma->bufsize, dma->rx_dma_buf,
dma->rx_dma_phys, DMA_FROM_DEVICE);
err_rx_dma_buf:
dma_free_noncoherent(dma->chan_tx->device->dev, dma->bufsize,
dma->tx_dma_buf, dma->tx_dma_phys, DMA_TO_DEVICE);
dma_free_noncoherent(tx_dev, dma->bufsize, dma->tx_dma_buf,
dma->tx_dma_phys, DMA_TO_DEVICE);
err_tx_dma_buf:
dma_release_channel(dma->chan_tx);
err_tx_channel:
@ -771,16 +774,18 @@ static void dspi_release_dma(struct fsl_dspi *dspi)
return;
if (dma->chan_tx) {
dma_free_noncoherent(dma->chan_tx->device->dev, dma->bufsize,
dma->tx_dma_buf, dma->tx_dma_phys,
DMA_TO_DEVICE);
struct device *tx_dev = dmaengine_get_dma_device(dma->chan_tx);
dma_free_noncoherent(tx_dev, dma->bufsize, dma->tx_dma_buf,
dma->tx_dma_phys, DMA_TO_DEVICE);
dma_release_channel(dma->chan_tx);
}
if (dma->chan_rx) {
dma_free_noncoherent(dma->chan_rx->device->dev, dma->bufsize,
dma->rx_dma_buf, dma->rx_dma_phys,
DMA_FROM_DEVICE);
struct device *rx_dev = dmaengine_get_dma_device(dma->chan_rx);
dma_free_noncoherent(rx_dev, dma->bufsize, dma->rx_dma_buf,
dma->rx_dma_phys, DMA_FROM_DEVICE);
dma_release_channel(dma->chan_rx);
}
}

View File

@ -12,8 +12,10 @@
#include <linux/dma/qcom-gpi-dma.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/panic_notifier.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
@ -115,6 +117,7 @@ struct spi_geni_master {
struct dma_chan *rx;
int cur_xfer_mode;
const struct geni_spi_desc *dev_data;
struct notifier_block panic_nb;
};
static void spi_slv_setup(struct spi_geni_master *mas)
@ -363,8 +366,8 @@ static int geni_spi_set_clock_and_bw(struct geni_se *se,
return 0;
}
static int setup_fifo_params(struct spi_device *spi_slv,
struct spi_controller *spi)
static void setup_spi_params(struct spi_device *spi_slv,
struct spi_controller *spi)
{
struct spi_geni_master *mas = spi_controller_get_devdata(spi);
struct geni_se *se = &mas->se;
@ -390,8 +393,6 @@ static int setup_fifo_params(struct spi_device *spi_slv,
trace_geni_spi_setup_params(mas->dev, chipselect, spi_slv->mode,
mode_changed, cs_changed);
return 0;
}
static void
@ -554,17 +555,14 @@ static int spi_geni_prepare_message(struct spi_controller *spi,
struct spi_message *spi_msg)
{
struct spi_geni_master *mas = spi_controller_get_devdata(spi);
int ret;
switch (mas->cur_xfer_mode) {
case GENI_SE_FIFO:
case GENI_SE_DMA:
if (spi_geni_is_abort_still_pending(mas))
return -EBUSY;
ret = setup_fifo_params(spi_msg->spi, spi);
if (ret)
dev_err(mas->dev, "Couldn't select mode %d\n", ret);
return ret;
setup_spi_params(spi_msg->spi, spi);
return 0;
case GENI_GPI_DMA:
/* nothing to do for GPI DMA */
@ -700,7 +698,7 @@ static int spi_geni_init(struct spi_geni_master *mas)
case 0:
mas->cur_xfer_mode = GENI_SE_FIFO;
geni_se_select_mode(se, GENI_SE_FIFO);
/* setup_fifo_params assumes that these registers start with a zero value */
/* setup_spi_params assumes that these registers start with a zero value */
writel(0, se->base + SE_SPI_LOOPBACK);
writel(0, se->base + SE_SPI_DEMUX_SEL);
writel(0, se->base + SE_SPI_CPHA);
@ -1066,6 +1064,69 @@ static int spi_geni_target_abort(struct spi_controller *spi)
return 0;
}
static void spi_geni_shutdown(struct platform_device *pdev)
{
struct spi_controller *spi = platform_get_drvdata(pdev);
spi_controller_suspend(spi);
}
static int spi_geni_panic_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
struct spi_geni_master *mas = container_of(nb, struct spi_geni_master, panic_nb);
struct spi_controller *spi = dev_get_drvdata(mas->dev);
struct geni_se *se = &mas->se;
u32 val;
if (!pm_runtime_active(mas->dev))
return NOTIFY_OK;
if (mas->cur_xfer_mode == GENI_GPI_DMA) {
dmaengine_terminate_async(mas->tx);
dmaengine_terminate_async(mas->rx);
return NOTIFY_OK;
}
if (!(readl_relaxed(se->base + SE_GENI_STATUS) & M_GENI_CMD_ACTIVE))
return NOTIFY_OK;
if (!spi->target) {
geni_se_cancel_m_cmd(se);
if (!readl_poll_timeout_atomic(se->base + SE_GENI_M_IRQ_STATUS, val,
val & M_CMD_CANCEL_EN, 10, 50000)) {
writel_relaxed(M_CMD_CANCEL_EN, se->base + SE_GENI_M_IRQ_CLEAR);
return NOTIFY_OK;
}
}
geni_se_abort_m_cmd(se);
if (!readl_poll_timeout_atomic(se->base + SE_GENI_M_IRQ_STATUS, val,
val & M_CMD_ABORT_EN, 10, 50000))
writel_relaxed(M_CMD_ABORT_EN, se->base + SE_GENI_M_IRQ_CLEAR);
if (mas->cur_xfer_mode == GENI_SE_DMA) {
writel_relaxed(1, se->base + SE_DMA_TX_FSM_RST);
readl_poll_timeout_atomic(se->base + SE_DMA_TX_IRQ_STAT, val,
val & TX_RESET_DONE, 10, 50000);
writel_relaxed(val, se->base + SE_DMA_TX_IRQ_CLR);
writel_relaxed(1, se->base + SE_DMA_RX_FSM_RST);
readl_poll_timeout_atomic(se->base + SE_DMA_RX_IRQ_STAT, val,
val & RX_RESET_DONE, 10, 50000);
writel_relaxed(val, se->base + SE_DMA_RX_IRQ_CLR);
}
return NOTIFY_OK;
}
static void spi_geni_unregister_notifiers(void *data)
{
struct spi_geni_master *mas = data;
atomic_notifier_chain_unregister(&panic_notifier_list, &mas->panic_nb);
}
static int spi_geni_probe(struct platform_device *pdev)
{
int ret, irq;
@ -1154,6 +1215,15 @@ static int spi_geni_probe(struct platform_device *pdev)
if (ret)
return ret;
mas->panic_nb.notifier_call = spi_geni_panic_notifier;
ret = atomic_notifier_chain_register(&panic_notifier_list, &mas->panic_nb);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, spi_geni_unregister_notifiers, mas);
if (ret)
return ret;
return devm_spi_register_controller(dev, spi);
}
@ -1241,7 +1311,8 @@ static const struct of_device_id spi_geni_dt_match[] = {
MODULE_DEVICE_TABLE(of, spi_geni_dt_match);
static struct platform_driver spi_geni_driver = {
.probe = spi_geni_probe,
.probe = spi_geni_probe,
.shutdown = spi_geni_shutdown,
.driver = {
.name = "geni_spi",
.pm = pm_ptr(&spi_geni_pm_ops),

View File

@ -673,7 +673,7 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
* propagate into the hardware. It takes exactly one tick of the
* SCLK clock, but we will wait two SCLK clock just to be sure. The
* effect of the delay it takes for the hardware to apply changes
* is noticable if the SCLK clock run very slow. In such a case, if
* is noticeable if the SCLK clock run very slow. In such a case, if
* the polarity of SCLK should be inverted, the GPIO ChipSelect might
* be asserted before the SCLK polarity changes, which would disrupt
* the SPI communication as the device on the other end would consider
@ -1467,8 +1467,8 @@ static int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
static void spi_imx_dma_unmap(struct spi_imx_data *spi_imx,
struct dma_data_package *dma_data)
{
struct device *tx_dev = spi_imx->controller->dma_tx->device->dev;
struct device *rx_dev = spi_imx->controller->dma_rx->device->dev;
struct device *tx_dev = dmaengine_get_dma_device(spi_imx->controller->dma_tx);
struct device *rx_dev = dmaengine_get_dma_device(spi_imx->controller->dma_rx);
dma_unmap_single(tx_dev, dma_data->dma_tx_addr,
DMA_CACHE_ALIGNED_LEN(dma_data->dma_len),
@ -1526,8 +1526,8 @@ static int spi_imx_dma_map(struct spi_imx_data *spi_imx,
struct dma_data_package *dma_data)
{
struct spi_controller *controller = spi_imx->controller;
struct device *tx_dev = controller->dma_tx->device->dev;
struct device *rx_dev = controller->dma_rx->device->dev;
struct device *tx_dev = dmaengine_get_dma_device(controller->dma_tx);
struct device *rx_dev = dmaengine_get_dma_device(controller->dma_rx);
int ret;
dma_data->dma_tx_addr = dma_map_single(tx_dev, dma_data->dma_tx_buf,
@ -1919,7 +1919,7 @@ static int spi_imx_dma_package_transfer(struct spi_imx_data *spi_imx,
return ret;
/* Trim the DMA RX buffer and copy the actual data to rx_buf */
dma_sync_single_for_cpu(controller->dma_rx->device->dev, dma_data->dma_rx_addr,
dma_sync_single_for_cpu(dmaengine_get_dma_device(controller->dma_rx), dma_data->dma_rx_addr,
dma_data->dma_len, DMA_FROM_DEVICE);
spi_imx_dma_rx_data_handle(spi_imx, dma_data, transfer->rx_buf + spi_imx->rx_offset,
word_delay);

View File

@ -164,10 +164,8 @@ spi_ingenic_prepare_dma(struct spi_controller *ctlr, struct dma_chan *chan,
cookie = dmaengine_submit(desc);
ret = dma_submit_error(cookie);
if (ret) {
dmaengine_desc_free(desc);
if (ret)
return ERR_PTR(ret);
}
return desc;
}
@ -186,7 +184,6 @@ static int spi_ingenic_dma_tx(struct spi_controller *ctlr,
&xfer->tx_sg, DMA_MEM_TO_DEV, bits);
if (IS_ERR(tx_desc)) {
dmaengine_terminate_async(ctlr->dma_rx);
dmaengine_desc_free(rx_desc);
return PTR_ERR(tx_desc);
}
@ -354,8 +351,11 @@ static int spi_ingenic_request_dma(struct spi_controller *ctlr,
ctlr->dma_tx = chan;
chan = dma_request_chan(dev, "rx");
if (IS_ERR(chan))
if (IS_ERR(chan)) {
dma_release_channel(ctlr->dma_tx);
ctlr->dma_tx = NULL;
return PTR_ERR(chan);
}
ctlr->dma_rx = chan;
ctlr->can_dma = spi_ingenic_can_dma;

View File

@ -633,18 +633,23 @@ static int nuvoton_qspi_probe(struct platform_device *pdev)
return dev_err_probe(dev, ret, "failed to deassert reset\n");
ret = device_property_read_u32(dev, "num-cs", &num_cs);
if (ret && ret != -EINVAL)
return dev_err_probe(dev, ret, "failed to read num-cs\n");
if (ret && ret != -EINVAL) {
ret = dev_err_probe(dev, ret, "failed to read num-cs\n");
goto err_assert;
}
if (!num_cs || num_cs > NUVOTON_QSPI_MAX_NUM_CS)
return dev_err_probe(dev, -EINVAL, "invalid num-cs %u\n",
if (!num_cs || num_cs > NUVOTON_QSPI_MAX_NUM_CS) {
ret = dev_err_probe(dev, -EINVAL, "invalid num-cs %u\n",
num_cs);
goto err_assert;
}
ctlr->num_chipselect = num_cs;
ctlr->max_transfer_size = nuvoton_qspi_max_transfer_size;
ctlr->max_message_size = nuvoton_qspi_max_message_size;
ctlr->mem_ops = &nuvoton_qspi_mem_ops;
ctlr->mem_caps = &nuvoton_qspi_mem_caps;
ctlr->dtr_caps = true;
ctlr->set_cs = nuvoton_qspi_set_cs;
ctlr->transfer_one = nuvoton_qspi_transfer_one;
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
@ -655,14 +660,20 @@ static int nuvoton_qspi_probe(struct platform_device *pdev)
ret = nuvoton_qspi_hw_init(qspi);
if (ret)
return ret;
goto err_assert;
ret = devm_spi_register_controller(dev, ctlr);
if (ret)
return dev_err_probe(dev, ret,
"failed to register spi controller\n");
if (ret) {
ret = dev_err_probe(dev, ret,
"failed to register spi controller\n");
goto err_assert;
}
return 0;
err_assert:
reset_control_assert(rst);
return ret;
}
static const struct of_device_id nuvoton_qspi_of_match[] = {

View File

@ -46,9 +46,9 @@ int spi_controller_dma_map_mem_op_data(struct spi_controller *ctlr,
return -EINVAL;
if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx)
dmadev = ctlr->dma_tx->device->dev;
dmadev = dmaengine_get_dma_device(ctlr->dma_tx);
else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx)
dmadev = ctlr->dma_rx->device->dev;
dmadev = dmaengine_get_dma_device(ctlr->dma_rx);
else
dmadev = ctlr->dev.parent;
@ -92,9 +92,9 @@ void spi_controller_dma_unmap_mem_op_data(struct spi_controller *ctlr,
return;
if (op->data.dir == SPI_MEM_DATA_OUT && ctlr->dma_tx)
dmadev = ctlr->dma_tx->device->dev;
dmadev = dmaengine_get_dma_device(ctlr->dma_tx);
else if (op->data.dir == SPI_MEM_DATA_IN && ctlr->dma_rx)
dmadev = ctlr->dma_rx->device->dev;
dmadev = dmaengine_get_dma_device(ctlr->dma_rx);
else
dmadev = ctlr->dev.parent;
@ -172,7 +172,7 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr;
if (op_is_dtr) {
if (!spi_mem_controller_is_capable(ctlr, dtr))
if (!spi_mem_controller_is_capable(ctlr, dtr) && !ctlr->dtr_caps)
return false;
if (op->data.swap16 && !spi_mem_controller_is_capable(ctlr, swap16))
@ -461,6 +461,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].len = op->cmd.nbytes;
xfers[xferpos].tx_nbits = op->cmd.buswidth;
xfers[xferpos].speed_hz = op->max_freq;
xfers[xferpos].dtr_mode = op->cmd.dtr;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen++;
@ -476,6 +477,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].len = op->addr.nbytes;
xfers[xferpos].tx_nbits = op->addr.buswidth;
xfers[xferpos].speed_hz = op->max_freq;
xfers[xferpos].dtr_mode = op->addr.dtr;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->addr.nbytes;
@ -488,6 +490,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].tx_nbits = op->dummy.buswidth;
xfers[xferpos].dummy_data = 1;
xfers[xferpos].speed_hz = op->max_freq;
xfers[xferpos].dtr_mode = op->dummy.dtr;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->dummy.nbytes;
@ -504,6 +507,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].len = op->data.nbytes;
xfers[xferpos].speed_hz = op->max_freq;
xfers[xferpos].dtr_mode = op->data.dtr;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->data.nbytes;

View File

@ -929,6 +929,7 @@ static int mtk_nor_probe(struct platform_device *pdev)
return 0;
err_probe:
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);

View File

@ -744,7 +744,13 @@ static int mxic_spi_runtime_resume(struct device *dev)
return ret;
}
return mxic_spi_clk_enable(mxic);
ret = mxic_spi_clk_enable(mxic);
if (ret) {
clk_disable_unprepare(mxic->ps_clk);
return ret;
}
return 0;
}
static const struct dev_pm_ops mxic_spi_dev_pm_ops = {

View File

@ -841,23 +841,23 @@ static int nxp_xspi_ahb_dma_read(struct nxp_xspi *xspi,
{
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = xspi->dma_rx;
struct device *dma_dev = dmaengine_get_dma_device(chan);
unsigned long timeout;
dma_addr_t src_addr, dst_addr;
int ret = 0;
dst_addr = dma_map_single(chan->device->dev,
op->data.buf.in, op->data.nbytes,
dst_addr = dma_map_single(dma_dev, op->data.buf.in, op->data.nbytes,
DMA_FROM_DEVICE);
if (dma_mapping_error(chan->device->dev, dst_addr)) {
if (dma_mapping_error(dma_dev, dst_addr)) {
dev_err(xspi->dev, "failed to map DMA dst buffer\n");
return -ENOMEM;
}
src_addr = dma_map_resource(chan->device->dev,
src_addr = dma_map_resource(dma_dev,
(phys_addr_t)xspi->memmap_phy + op->addr.val,
op->data.nbytes,
DMA_TO_DEVICE, 0);
if (dma_mapping_error(chan->device->dev, src_addr)) {
if (dma_mapping_error(dma_dev, src_addr)) {
dev_err(xspi->dev, "failed to map DMA src resource\n");
ret = -ENOMEM;
goto err_unmap_dst;
@ -886,12 +886,10 @@ static int nxp_xspi_ahb_dma_read(struct nxp_xspi *xspi,
}
err_unmap_src:
dma_unmap_resource(chan->device->dev, src_addr,
op->data.nbytes, DMA_TO_DEVICE, 0);
dma_unmap_resource(dma_dev, src_addr, op->data.nbytes, DMA_TO_DEVICE, 0);
err_unmap_dst:
dma_unmap_single(chan->device->dev, dst_addr,
op->data.nbytes, DMA_FROM_DEVICE);
dma_unmap_single(dma_dev, dst_addr, op->data.nbytes, DMA_FROM_DEVICE);
return ret;
}

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